1 /* io.c - Virtual disk input/output
3 Copyright (C) 1993 Werner Almesberger <werner.almesberger@lrc.di.epfl.ch>
4 Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 On Debian systems, the complete text of the GNU General Public License
20 can be found in /usr/share/common-licenses/GPL-3 file.
24 * Thu Feb 26 01:15:36 CET 1998: Martin Schulze <joey@infodrom.north.de>
25 * Fixed nasty bug that caused every file with a name like
26 * xxxxxxxx.xxx to be treated as bad name that needed to be fixed.
29 /* FAT32, VFAT, Atari format support, and various fixes additions May 1998
30 * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
32 #define _LARGEFILE64_SOURCE
33 #include <sys/types.h>
39 #include <sys/ioctl.h>
49 typedef struct _change {
57 static CHANGE *changes,*last;
58 static int fd,did_change = 0;
64 #include "volume.h" /* DOS lowlevel disk access functions */
65 loff_t llseek(int fd, loff_t offset, int whence)
67 if ((whence != SEEK_SET) || (fd == 4711)) return -1; /* only those supported */
68 return VolumeSeek(offset);
70 #define open OpenVolume
71 #define close CloseVolume
72 #define read(a,b,c) ReadVolume(b,c)
73 #define write(a,b,c) WriteVolume(b,c)
75 loff_t llseek(int fd, loff_t offset, int whence)
77 return (loff_t) lseek64(fd, (off64_t)offset, whence);
81 void fs_open(char *path,int rw)
85 if ((fd = open(path,rw ? O_RDWR : O_RDONLY)) < 0) {
89 changes = last = NULL;
93 if (fstat(fd,&stbuf) < 0)
94 pdie("fstat %s",path);
95 device_no = S_ISBLK(stbuf.st_mode) ? (stbuf.st_rdev >> 8) & 0xff : 0;
97 if (IsWorkingOnImageFile()) {
98 if (fstat(GetVolumeHandle(),&stbuf) < 0)
99 pdie("fstat image %s",path);
103 /* return 2 for floppy, 1 for ramdisk, 7 for loopback */
104 /* used by boot.c in Atari mode: floppy always FAT12, */
105 /* loopback / ramdisk only FAT12 if usual floppy size, */
106 /* harddisk always FAT16 on Atari... */
107 device_no = (GetVolumeHandle() < 2) ? 2 : 1;
108 /* telling "floppy" for A:/B:, "ramdisk" for the rest */
115 * Read data from the partition, accounting for any pending updates that are
116 * queued for writing.
118 * @param[in] pos Byte offset, relative to the beginning of the partition,
120 * @param[in] size Number of bytes to read
121 * @param[out] data Where to put the data read
123 void fs_read(loff_t pos,int size,void *data)
128 if (llseek(fd,pos,0) != pos) pdie("Seek to %lld",pos);
129 if ((got = read(fd,data,size)) < 0) pdie("Read %d bytes at %lld",size,pos);
130 if (got != size) die("Got %d bytes instead of %d at %lld",got,size,pos);
131 for (walk = changes; walk; walk = walk->next) {
132 if (walk->pos < pos+size && walk->pos+walk->size > pos) {
134 memcpy(data,(char *) walk->data+pos-walk->pos,min(size,
135 walk->size-pos+walk->pos));
136 else memcpy((char *) data+walk->pos-pos,walk->data,min(walk->size,
137 size+pos-walk->pos));
143 int fs_test(loff_t pos,int size)
148 if (llseek(fd,pos,0) != pos) pdie("Seek to %lld",pos);
149 scratch = alloc(size);
150 okay = read(fd,scratch,size) == size;
156 void fs_write(loff_t pos,int size,void *data)
163 if (llseek(fd,pos,0) != pos) pdie("Seek to %lld",pos);
164 if ((did = write(fd,data,size)) == size) return;
165 if (did < 0) pdie("Write %d bytes at %lld",size,pos);
166 die("Wrote %d bytes instead of %d at %lld",did,size,pos);
168 new = alloc(sizeof(CHANGE));
170 memcpy(new->data = alloc(new->size = size),data,size);
172 if (last) last->next = new;
178 static void fs_flush(void)
185 changes = changes->next;
186 if (llseek(fd,this->pos,0) != this->pos)
187 fprintf(stderr,"Seek to %lld failed: %s\n Did not write %d bytes.\n",
188 (long long)this->pos,strerror(errno),this->size);
189 else if ((size = write(fd,this->data,this->size)) < 0)
190 fprintf(stderr,"Writing %d bytes at %lld failed: %s\n",this->size,
191 (long long)this->pos,strerror(errno));
192 else if (size != this->size)
193 fprintf(stderr,"Wrote %d bytes instead of %d bytes at %lld."
194 "\n",size,this->size,(long long)this->pos);
201 int fs_close(int write)
207 if (write) fs_flush();
208 else while (changes) {
209 next = changes->next;
214 if (close(fd) < 0) pdie("closing file system");
215 return changed || did_change;
221 return !!changes || did_change;