1 /* io.c - Virtual disk input/output
2
3 Copyright (C) 1993 Werner Almesberger <werner.almesberger@lrc.di.epfl.ch>
4 Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
5
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.
10
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.
15
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/>.
18
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.
21 */
22
23 /*
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.
27 */
28
29 /* FAT32, VFAT, Atari format support, and various fixes additions May 1998
30 * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
31
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <unistd.h>
36 #include <sys/stat.h>
37 #include <sys/ioctl.h>
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <linux/fd.h>
41
42 #include "dosfsck.h"
43 #include "common.h"
44 #include "io.h"
45
46
47 typedef struct _change {
48 void *data;
49 loff_t pos;
50 int size;
51 struct _change *next;
52 } CHANGE;
53
54
55 static CHANGE *changes,*last;
56 static int fd,did_change = 0;
57
58 unsigned device_no;
59
60
61 #ifdef __DJGPP__
62 #include "volume.h" /* DOS lowlevel disk access functions */
63 #undef llseek
llseek(int fd,loff_t offset,int whence)64 static loff_t llseek( int fd, loff_t offset, int whence )
65 {
66 if ((whence != SEEK_SET) || (fd == 4711)) return -1; /* only those supported */
67 return VolumeSeek(offset);
68 }
69 #define open OpenVolume
70 #define close CloseVolume
71 #define read(a,b,c) ReadVolume(b,c)
72 #define write(a,b,c) WriteVolume(b,c)
73 #endif
74
fs_open(char * path,int rw)75 void fs_open(char *path,int rw)
76 {
77 struct stat stbuf;
78
79 if ((fd = open(path,rw ? O_RDWR : O_RDONLY)) < 0) {
80 perror("open");
81 exit(6);
82 }
83 changes = last = NULL;
84 did_change = 0;
85
86 #ifndef _DJGPP_
87 if (fstat(fd,&stbuf) < 0)
88 pdie("fstat %s",path);
89 device_no = S_ISBLK(stbuf.st_mode) ? (stbuf.st_rdev >> 8) & 0xff : 0;
90 #else
91 if (IsWorkingOnImageFile()) {
92 if (fstat(GetVolumeHandle(),&stbuf) < 0)
93 pdie("fstat image %s",path);
94 device_no = 0;
95 }
96 else {
97 /* return 2 for floppy, 1 for ramdisk, 7 for loopback */
98 /* used by boot.c in Atari mode: floppy always FAT12, */
99 /* loopback / ramdisk only FAT12 if usual floppy size, */
100 /* harddisk always FAT16 on Atari... */
101 device_no = (GetVolumeHandle() < 2) ? 2 : 1;
102 /* telling "floppy" for A:/B:, "ramdisk" for the rest */
103 }
104 #endif
105 }
106
107
fs_read(loff_t pos,int size,void * data)108 void fs_read(loff_t pos,int size,void *data)
109 {
110 CHANGE *walk;
111 int got;
112
113 if (llseek(fd,pos,0) != pos) pdie("Seek to %lld",pos);
114 if ((got = read(fd,data,size)) < 0) pdie("Read %d bytes at %lld",size,pos);
115 if (got != size) die("Got %d bytes instead of %d at %lld",got,size,pos);
116 for (walk = changes; walk; walk = walk->next) {
117 if (walk->pos < pos+size && walk->pos+walk->size > pos) {
118 if (walk->pos < pos)
119 memcpy(data,(char *) walk->data+pos-walk->pos,min(size,
120 walk->size-pos+walk->pos));
121 else memcpy((char *) data+walk->pos-pos,walk->data,min(walk->size,
122 size+pos-walk->pos));
123 }
124 }
125 }
126
127
fs_test(loff_t pos,int size)128 int fs_test(loff_t pos,int size)
129 {
130 void *scratch;
131 int okay;
132
133 if (llseek(fd,pos,0) != pos) pdie("Seek to %lld",pos);
134 scratch = alloc(size);
135 okay = read(fd,scratch,size) == size;
136 free(scratch);
137 return okay;
138 }
139
140
fs_write(loff_t pos,int size,void * data)141 void fs_write(loff_t pos,int size,void *data)
142 {
143 CHANGE *new;
144 int did;
145
146 if (write_immed) {
147 did_change = 1;
148 if (llseek(fd,pos,0) != pos) pdie("Seek to %lld",pos);
149 if ((did = write(fd,data,size)) == size) return;
150 if (did < 0) pdie("Write %d bytes at %lld",size,pos);
151 die("Wrote %d bytes instead of %d at %lld",did,size,pos);
152 }
153 new = alloc(sizeof(CHANGE));
154 new->pos = pos;
155 memcpy(new->data = alloc(new->size = size),data,size);
156 new->next = NULL;
157 if (last) last->next = new;
158 else changes = new;
159 last = new;
160 }
161
162
fs_flush(void)163 static void fs_flush(void)
164 {
165 CHANGE *this;
166 int size;
167
168 while (changes) {
169 this = changes;
170 changes = changes->next;
171 if (llseek(fd,this->pos,0) != this->pos)
172 fprintf(stderr,"Seek to %lld failed: %s\n Did not write %d bytes.\n",
173 (long long)this->pos,strerror(errno),this->size);
174 else if ((size = write(fd,this->data,this->size)) < 0)
175 fprintf(stderr,"Writing %d bytes at %lld failed: %s\n",this->size,
176 (long long)this->pos,strerror(errno));
177 else if (size != this->size)
178 fprintf(stderr,"Wrote %d bytes instead of %d bytes at %lld."
179 "\n",size,this->size,(long long)this->pos);
180 free(this->data);
181 free(this);
182 }
183 }
184
185
fs_close(int write)186 int fs_close(int write)
187 {
188 CHANGE *next;
189 int changed;
190
191 changed = !!changes;
192 if (write) fs_flush();
193 else while (changes) {
194 next = changes->next;
195 free(changes->data);
196 free(changes);
197 changes = next;
198 }
199 if (close(fd) < 0) pdie("closing file system");
200 return changed || did_change;
201 }
202
203
fs_changed(void)204 int fs_changed(void)
205 {
206 return !!changes || did_change;
207 }
208
209 /* Local Variables: */
210 /* tab-width: 8 */
211 /* End: */
212