• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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