1 | /*
|
---|
2 | * Initialize an MSDOS diskette. Read the boot sector, and switch to the
|
---|
3 | * proper floppy disk device to match the format on the disk. Sets a bunch
|
---|
4 | * of global variables. Returns 0 on success, or 1 on failure.
|
---|
5 | */
|
---|
6 |
|
---|
7 | #include "sysincludes.h"
|
---|
8 | #include "msdos.h"
|
---|
9 | #include "stream.h"
|
---|
10 | #include "mtools.h"
|
---|
11 | #include "fsP.h"
|
---|
12 | #include "plain_io.h"
|
---|
13 | #include "floppyd_io.h"
|
---|
14 | #include "xdf_io.h"
|
---|
15 | #include "buffer.h"
|
---|
16 |
|
---|
17 | extern int errno;
|
---|
18 |
|
---|
19 |
|
---|
20 | #ifndef OS_Minix /* Minix is memory starved. */
|
---|
21 | #define FULL_CYL
|
---|
22 | #endif
|
---|
23 |
|
---|
24 | unsigned int num_clus; /* total number of cluster */
|
---|
25 |
|
---|
26 |
|
---|
27 | /*
|
---|
28 | * Read the boot sector. We glean the disk parameters from this sector.
|
---|
29 | */
|
---|
30 | static int read_boot(Stream_t *Stream, struct bootsector * boot, int size)
|
---|
31 | {
|
---|
32 | /* read the first sector, or part of it */
|
---|
33 | if(!size)
|
---|
34 | size = BOOTSIZE;
|
---|
35 | if(size > 1024)
|
---|
36 | size = 1024;
|
---|
37 |
|
---|
38 | if (force_read(Stream, (char *) boot, 0, size) != size)
|
---|
39 | return -1;
|
---|
40 | return 0;
|
---|
41 | }
|
---|
42 |
|
---|
43 | static int fs_flush(Stream_t *Stream)
|
---|
44 | {
|
---|
45 | DeclareThis(Fs_t);
|
---|
46 |
|
---|
47 | fat_write(This);
|
---|
48 | return 0;
|
---|
49 | }
|
---|
50 |
|
---|
51 | Class_t FsClass = {
|
---|
52 | read_pass_through, /* read */
|
---|
53 | write_pass_through, /* write */
|
---|
54 | fs_flush,
|
---|
55 | fs_free, /* free */
|
---|
56 | 0, /* set geometry */
|
---|
57 | get_data_pass_through,
|
---|
58 | 0 /* pre allocate */
|
---|
59 | };
|
---|
60 |
|
---|
61 | static int get_media_type(Stream_t *St, struct bootsector *boot)
|
---|
62 | {
|
---|
63 | int media;
|
---|
64 |
|
---|
65 | media = boot->descr;
|
---|
66 | if(media < 0xf0){
|
---|
67 | char temp[512];
|
---|
68 | /* old DOS disk. Media descriptor in the first FAT byte */
|
---|
69 | /* old DOS disk always have 512-byte sectors */
|
---|
70 | if (force_read(St,temp,(mt_off_t) 512,512) == 512)
|
---|
71 | media = (unsigned char) temp[0];
|
---|
72 | else
|
---|
73 | media = 0;
|
---|
74 | } else
|
---|
75 | media += 0x100;
|
---|
76 | return media;
|
---|
77 | }
|
---|
78 |
|
---|
79 |
|
---|
80 | Stream_t *GetFs(Stream_t *Fs)
|
---|
81 | {
|
---|
82 | while(Fs && Fs->Class != &FsClass)
|
---|
83 | Fs = Fs->Next;
|
---|
84 | return Fs;
|
---|
85 | }
|
---|
86 |
|
---|
87 | Stream_t *find_device(char *drive, int mode, struct device *out_dev,
|
---|
88 | struct bootsector *boot,
|
---|
89 | char *name, int *media, mt_size_t *maxSize)
|
---|
90 | {
|
---|
91 | char errmsg[200];
|
---|
92 | Stream_t *Stream;
|
---|
93 | struct device *dev;
|
---|
94 | int r;
|
---|
95 | #ifdef OS_Minix
|
---|
96 | static char *devname;
|
---|
97 | struct device onedevice[2];
|
---|
98 | struct stat stbuf;
|
---|
99 |
|
---|
100 | free(devname);
|
---|
101 | devname = safe_malloc((9 + strlen(drive)) * sizeof(devname[0]));
|
---|
102 | strcpy(devname, "/dev/dosX");
|
---|
103 | if (isupper(drive[0]) && drive[1] == 0) {
|
---|
104 | /* single letter device name, use /dev/dos$drive */
|
---|
105 | devname[8]= drive[0];
|
---|
106 | } else
|
---|
107 | if (strchr(drive, '/') == NULL) {
|
---|
108 | /* a simple name, use /dev/$drive */
|
---|
109 | strcpy(devname+5, drive);
|
---|
110 | } else {
|
---|
111 | /* a pathname, use as is. */
|
---|
112 | strcpy(devname, drive);
|
---|
113 | }
|
---|
114 | if (stat(devname, &stbuf) != -1) {
|
---|
115 | memset(onedevice, 0, sizeof(onedevice));
|
---|
116 | onedevice[0].name = devname;
|
---|
117 | onedevice[0].drive = drive;
|
---|
118 | onedevice[1].name = NULL;
|
---|
119 | onedevice[1].drive = NULL;
|
---|
120 | dev = onedevice;
|
---|
121 | } else {
|
---|
122 | dev = devices;
|
---|
123 | }
|
---|
124 | #else
|
---|
125 | dev = devices;
|
---|
126 | #endif
|
---|
127 |
|
---|
128 | Stream = NULL;
|
---|
129 | sprintf(errmsg, "Drive '%s:' not supported", drive);
|
---|
130 | /* open the device */
|
---|
131 | for (; dev->name; dev++) {
|
---|
132 | FREE(&Stream);
|
---|
133 | if (strcmp(dev->drive, drive) != 0)
|
---|
134 | continue;
|
---|
135 | *out_dev = *dev;
|
---|
136 | expand(dev->name,name);
|
---|
137 | #ifdef USING_NEW_VOLD
|
---|
138 | strcpy(name, getVoldName(dev, name));
|
---|
139 | #endif
|
---|
140 |
|
---|
141 | Stream = 0;
|
---|
142 | #ifdef USE_XDF
|
---|
143 | Stream = XdfOpen(out_dev, name, mode, errmsg, 0);
|
---|
144 | if(Stream) {
|
---|
145 | out_dev->use_2m = 0x7f;
|
---|
146 | if(maxSize)
|
---|
147 | *maxSize = max_off_t_31;
|
---|
148 | }
|
---|
149 | #endif
|
---|
150 |
|
---|
151 | #ifdef USE_FLOPPYD
|
---|
152 | if(!Stream) {
|
---|
153 | Stream = FloppydOpen(out_dev, dev, name, mode, errmsg, 0, 1);
|
---|
154 | if(Stream && maxSize)
|
---|
155 | *maxSize = max_off_t_31;
|
---|
156 | }
|
---|
157 | #endif
|
---|
158 |
|
---|
159 | if (!Stream)
|
---|
160 | Stream = SimpleFileOpen(out_dev, dev, name, mode,
|
---|
161 | errmsg, 0, 1, maxSize);
|
---|
162 |
|
---|
163 | if( !Stream)
|
---|
164 | continue;
|
---|
165 |
|
---|
166 | /* read the boot sector */
|
---|
167 | if ((r=read_boot(Stream, boot, out_dev->blocksize)) < 0){
|
---|
168 | sprintf(errmsg,
|
---|
169 | "init %s: could not read boot sector",
|
---|
170 | drive);
|
---|
171 | continue;
|
---|
172 | }
|
---|
173 |
|
---|
174 | if((*media= get_media_type(Stream, boot)) <= 0xf0 ){
|
---|
175 | if (boot->jump[2]=='L')
|
---|
176 | sprintf(errmsg,
|
---|
177 | "diskette %s: is Linux LILO, not DOS",
|
---|
178 | drive);
|
---|
179 | else
|
---|
180 | sprintf(errmsg,"init %s: non DOS media", drive);
|
---|
181 | continue;
|
---|
182 | }
|
---|
183 |
|
---|
184 | /* set new parameters, if needed */
|
---|
185 | errno = 0;
|
---|
186 | if(SET_GEOM(Stream, out_dev, dev, *media, boot)){
|
---|
187 | if(errno)
|
---|
188 | #ifdef HAVE_SNPRINTF
|
---|
189 | snprintf(errmsg, 199,
|
---|
190 | "Can't set disk parameters for %s: %s",
|
---|
191 | drive, strerror(errno));
|
---|
192 | #else
|
---|
193 | sprintf(errmsg,
|
---|
194 | "Can't set disk parameters for %s: %s",
|
---|
195 | drive, strerror(errno));
|
---|
196 | #endif
|
---|
197 | else
|
---|
198 | sprintf(errmsg,
|
---|
199 | "Can't set disk parameters for %s",
|
---|
200 | drive);
|
---|
201 | continue;
|
---|
202 | }
|
---|
203 | break;
|
---|
204 | }
|
---|
205 |
|
---|
206 | /* print error msg if needed */
|
---|
207 | if ( dev->drive == 0 ){
|
---|
208 | FREE(&Stream);
|
---|
209 | fprintf(stderr,"%s\n",errmsg);
|
---|
210 | return NULL;
|
---|
211 | }
|
---|
212 | #ifdef OS_Minix
|
---|
213 | /* Minix can lseek up to 4G. */
|
---|
214 | if (maxSize) *maxSize = 0xFFFFFFFFUL;
|
---|
215 | #endif
|
---|
216 | return Stream;
|
---|
217 | }
|
---|
218 |
|
---|
219 |
|
---|
220 | Stream_t *fs_init(char *drive, int mode)
|
---|
221 | {
|
---|
222 | int blocksize;
|
---|
223 | int media,i;
|
---|
224 | int nhs;
|
---|
225 | int disk_size = 0; /* In case we don't happen to set this below */
|
---|
226 | size_t tot_sectors;
|
---|
227 | char name[EXPAND_BUF];
|
---|
228 | int cylinder_size;
|
---|
229 | struct device dev;
|
---|
230 | mt_size_t maxSize;
|
---|
231 |
|
---|
232 | struct bootsector boot0;
|
---|
233 | #define boot (&boot0)
|
---|
234 | Fs_t *This;
|
---|
235 |
|
---|
236 | This = New(Fs_t);
|
---|
237 | if (!This)
|
---|
238 | return NULL;
|
---|
239 |
|
---|
240 | This->Direct = NULL;
|
---|
241 | This->Next = NULL;
|
---|
242 | This->refs = 1;
|
---|
243 | This->Buffer = 0;
|
---|
244 | This->Class = &FsClass;
|
---|
245 | This->preallocatedClusters = 0;
|
---|
246 | This->lastFatSectorNr = 0;
|
---|
247 | This->lastFatAccessMode = 0;
|
---|
248 | This->lastFatSectorData = 0;
|
---|
249 | This->drive = drive;
|
---|
250 | This->last = 0;
|
---|
251 |
|
---|
252 | This->Direct = find_device(drive, mode, &dev, &boot0, name, &media,
|
---|
253 | &maxSize);
|
---|
254 | if(!This->Direct)
|
---|
255 | return NULL;
|
---|
256 |
|
---|
257 | This->sector_size = WORD(secsiz);
|
---|
258 | if(This->sector_size > MAX_SECTOR){
|
---|
259 | fprintf(stderr,"init %s: sector size too big\n", drive);
|
---|
260 | return NULL;
|
---|
261 | }
|
---|
262 |
|
---|
263 | i = log_2(This->sector_size);
|
---|
264 |
|
---|
265 | if(i == 24) {
|
---|
266 | fprintf(stderr,
|
---|
267 | "init %c: sector size (%d) not a small power of two\n",
|
---|
268 | drive, This->sector_size);
|
---|
269 | return NULL;
|
---|
270 | }
|
---|
271 | This->sectorShift = i;
|
---|
272 | This->sectorMask = This->sector_size - 1;
|
---|
273 |
|
---|
274 |
|
---|
275 | cylinder_size = dev.heads * dev.sectors;
|
---|
276 | if (!tot_sectors) tot_sectors = dev.tracks * cylinder_size;
|
---|
277 |
|
---|
278 | This->serialized = 0;
|
---|
279 | if ((media & ~7) == 0xf8){
|
---|
280 | i = media & 3;
|
---|
281 | This->cluster_size = old_dos[i].cluster_size;
|
---|
282 | tot_sectors = cylinder_size * old_dos[i].tracks;
|
---|
283 | This->fat_start = 1;
|
---|
284 | This->fat_len = old_dos[i].fat_len;
|
---|
285 | This->dir_len = old_dos[i].dir_len;
|
---|
286 | This->num_fat = 2;
|
---|
287 | This->sector_size = 512;
|
---|
288 | This->sectorShift = 9;
|
---|
289 | This->sectorMask = 511;
|
---|
290 | This->fat_bits = 12;
|
---|
291 | nhs = 0;
|
---|
292 | } else {
|
---|
293 | struct label_blk_t *labelBlock;
|
---|
294 | /*
|
---|
295 | * all numbers are in sectors, except num_clus
|
---|
296 | * (which is in clusters)
|
---|
297 | */
|
---|
298 | tot_sectors = WORD(psect);
|
---|
299 | if(!tot_sectors) {
|
---|
300 | tot_sectors = DWORD(bigsect);
|
---|
301 | nhs = DWORD(nhs);
|
---|
302 | } else
|
---|
303 | nhs = WORD(nhs);
|
---|
304 |
|
---|
305 |
|
---|
306 | This->cluster_size = boot0.clsiz;
|
---|
307 | This->fat_start = WORD(nrsvsect);
|
---|
308 | This->fat_len = WORD(fatlen);
|
---|
309 | This->dir_len = WORD(dirents) * MDIR_SIZE / This->sector_size;
|
---|
310 | This->num_fat = boot0.nfat;
|
---|
311 |
|
---|
312 | if (This->fat_len) {
|
---|
313 | labelBlock = &boot0.ext.old.labelBlock;
|
---|
314 | } else {
|
---|
315 | labelBlock = &boot0.ext.fat32.labelBlock;
|
---|
316 | }
|
---|
317 |
|
---|
318 | if(labelBlock->dos4 == 0x29) {
|
---|
319 | This->serialized = 1;
|
---|
320 | This->serial_number = _DWORD(labelBlock->serial);
|
---|
321 | }
|
---|
322 | }
|
---|
323 |
|
---|
324 | if (tot_sectors >= (maxSize >> This->sectorShift)) {
|
---|
325 | fprintf(stderr, "Big disks not supported on this architecture\n");
|
---|
326 | exit(1);
|
---|
327 | }
|
---|
328 |
|
---|
329 | #ifndef OS_Minix /* Strange check, MS-DOS isn't that picky. */
|
---|
330 |
|
---|
331 | if(!mtools_skip_check && (tot_sectors % dev.sectors)){
|
---|
332 | fprintf(stderr,
|
---|
333 | "Total number of sectors not a multiple of"
|
---|
334 | " sectors per track!\n");
|
---|
335 | fprintf(stderr,
|
---|
336 | "Add mtools_skip_check=1 to your .mtoolsrc file "
|
---|
337 | "to skip this test\n");
|
---|
338 | exit(1);
|
---|
339 | }
|
---|
340 | #endif
|
---|
341 |
|
---|
342 | /* full cylinder buffering */
|
---|
343 | #ifdef FULL_CYL
|
---|
344 | disk_size = (dev.tracks) ? cylinder_size : 512;
|
---|
345 | #else /* FULL_CYL */
|
---|
346 | disk_size = (dev.tracks) ? dev.sectors : 512;
|
---|
347 | #endif /* FULL_CYL */
|
---|
348 |
|
---|
349 | #if (defined OS_sysv4 && !defined OS_solaris)
|
---|
350 | /*
|
---|
351 | * The driver in Dell's SVR4 v2.01 is unreliable with large writes.
|
---|
352 | */
|
---|
353 | disk_size = 0;
|
---|
354 | #endif /* (defined sysv4 && !defined(solaris)) */
|
---|
355 |
|
---|
356 | #ifdef OS_linux
|
---|
357 | disk_size = cylinder_size;
|
---|
358 | #endif
|
---|
359 |
|
---|
360 | #if 1
|
---|
361 | if(disk_size > 256) {
|
---|
362 | disk_size = dev.sectors;
|
---|
363 | if(dev.sectors % 2)
|
---|
364 | disk_size <<= 1;
|
---|
365 | }
|
---|
366 | #endif
|
---|
367 | if (disk_size % 2)
|
---|
368 | disk_size *= 2;
|
---|
369 |
|
---|
370 | if(!dev.blocksize || dev.blocksize < This->sector_size)
|
---|
371 | blocksize = This->sector_size;
|
---|
372 | else
|
---|
373 | blocksize = dev.blocksize;
|
---|
374 | if (disk_size)
|
---|
375 | This->Next = buf_init(This->Direct,
|
---|
376 | 8 * disk_size * blocksize,
|
---|
377 | disk_size * blocksize,
|
---|
378 | This->sector_size);
|
---|
379 | else
|
---|
380 | This->Next = This->Direct;
|
---|
381 |
|
---|
382 | if (This->Next == NULL) {
|
---|
383 | perror("init: allocate buffer");
|
---|
384 | This->Next = This->Direct;
|
---|
385 | }
|
---|
386 |
|
---|
387 | /* read the FAT sectors */
|
---|
388 | if(fat_read(This, &boot0, dev.fat_bits, tot_sectors, dev.use_2m&0x7f)){
|
---|
389 | This->num_fat = 1;
|
---|
390 | FREE(&This->Next);
|
---|
391 | Free(This->Next);
|
---|
392 | return NULL;
|
---|
393 | }
|
---|
394 | return (Stream_t *) This;
|
---|
395 | }
|
---|
396 |
|
---|
397 | char *getDrive(Stream_t *Stream)
|
---|
398 | {
|
---|
399 | DeclareThis(Fs_t);
|
---|
400 |
|
---|
401 | if(This->Class != &FsClass)
|
---|
402 | return getDrive(GetFs(Stream));
|
---|
403 | else
|
---|
404 | return This->drive;
|
---|
405 | }
|
---|
406 |
|
---|
407 | int fsPreallocateClusters(Fs_t *Fs, long size)
|
---|
408 | {
|
---|
409 | if(size > 0 && getfreeMinClusters((Stream_t *)Fs, size) != 1)
|
---|
410 | return -1;
|
---|
411 |
|
---|
412 | Fs->preallocatedClusters += size;
|
---|
413 | return 0;
|
---|
414 | }
|
---|