source: trunk/minix/commands/i386/mtools-3.9.7/init.c@ 10

Last change on this file since 10 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 8.8 KB
Line 
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
17extern int errno;
18
19
20#ifndef OS_Minix /* Minix is memory starved. */
21#define FULL_CYL
22#endif
23
24unsigned int num_clus; /* total number of cluster */
25
26
27/*
28 * Read the boot sector. We glean the disk parameters from this sector.
29 */
30static 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
43static int fs_flush(Stream_t *Stream)
44{
45 DeclareThis(Fs_t);
46
47 fat_write(This);
48 return 0;
49}
50
51Class_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
61static 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
80Stream_t *GetFs(Stream_t *Fs)
81{
82 while(Fs && Fs->Class != &FsClass)
83 Fs = Fs->Next;
84 return Fs;
85}
86
87Stream_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
220Stream_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
397char *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
407int 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}
Note: See TracBrowser for help on using the repository browser.