ReactOS 0.4.16-dev-306-g647d351
mkdosfs.c
Go to the documentation of this file.
1/*
2 Filename: mkdosfs.c
3 Version: 0.3b (Yggdrasil)
4 Author: Dave Hudson
5 Started: 24th August 1994
6 Last Updated: 7th May 1998
7 Updated by: Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
8 Target O/S: Linux (2.x)
10 Description: Utility to allow an MS-DOS filesystem to be created
11 under Linux. A lot of the basic structure of this program has been
12 borrowed from Remy Card's "mke2fs" code.
14 As far as possible the aim here is to make the "mkdosfs" command
15 look almost identical to the other Linux filesystem make utilties,
16 eg bad blocks are still specified as blocks, not sectors, but when
17 it comes down to it, DOS is tied to the idea of a sector (512 bytes
18 as a rule), and not the block. For example the boot block does not
19 occupy a full cluster.
20
21 Fixes/additions May 1998 by Roman Hodek
22 <Roman.Hodek@informatik.uni-erlangen.de>:
23 - Atari format support
24 - New options -A, -S, -C
25 - Support for filesystems > 2GB
26 - FAT32 support
27
28 Port to work under Windows NT/2K/XP Dec 2002 by
29 Jens-Uwe Mager <jum@anubis.han.de>
30
31 Copying: Copyright 1993, 1994 David Hudson (dave@humbug.demon.co.uk)
32
33 Portions copyright 1992, 1993 Remy Card (card@masi.ibp.fr)
34 and 1991 Linus Torvalds (torvalds@klaava.helsinki.fi)
35
36 This program is free software; you can redistribute it and/or modify
37 it under the terms of the GNU General Public License as published by
38 the Free Software Foundation; either version 2, or (at your option)
39 any later version.
40
41 This program is distributed in the hope that it will be useful,
42 but WITHOUT ANY WARRANTY; without even the implied warranty of
43 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
44 GNU General Public License for more details.
45
46 You should have received a copy of the GNU General Public License
47 along with this program; if not, write to the Free Software
48 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
49
50
51/* Include the header files */
52
53#include "../version.h"
54
55#ifdef _WIN32
56#define _WIN32_WINNT 0x0400
57#include <windows.h>
58#include <winioctl.h>
59#define __LITTLE_ENDIAN 1234
60#define __BIG_ENDIAN 4321
61#define __BYTE_ORDER __LITTLE_ENDIAN
62#define inline
63#define __attribute__(x)
64#define BLOCK_SIZE 512
65#else
66#include <linux/hdreg.h>
67#include <linux/fs.h>
68#include <linux/fd.h>
69#include <endian.h>
70#include <mntent.h>
71#include <signal.h>
72#include <sys/ioctl.h>
73#include <unistd.h>
74#endif
75#include <fcntl.h>
76#include <string.h>
77#include <stdio.h>
78#include <stdlib.h>
79#include <sys/stat.h>
80#include <sys/types.h>
81#include <time.h>
82
83#if __BYTE_ORDER == __BIG_ENDIAN
84
85#include <asm/byteorder.h>
86#ifdef __le16_to_cpu
87/* ++roman: 2.1 kernel headers define these function, they're probably more
88 * efficient then coding the swaps machine-independently. */
89#define CF_LE_W __le16_to_cpu
90#define CF_LE_L __le32_to_cpu
91#define CT_LE_W __cpu_to_le16
92#define CT_LE_L __cpu_to_le32
93#else
94#define CF_LE_W(v) ((((v) & 0xff) << 8) | (((v) >> 8) & 0xff))
95#define CF_LE_L(v) (((unsigned)(v)>>24) | (((unsigned)(v)>>8)&0xff00) | \
96 (((unsigned)(v)<<8)&0xff0000) | ((unsigned)(v)<<24))
97#define CT_LE_W(v) CF_LE_W(v)
98#define CT_LE_L(v) CF_LE_L(v)
99#endif /* defined(__le16_to_cpu) */
100
101#else
102
103#define CF_LE_W(v) (v)
104#define CF_LE_L(v) (v)
105#define CT_LE_W(v) (v)
106#define CT_LE_L(v) (v)
107
108#endif /* __BIG_ENDIAN */
109
110#ifdef _WIN32
111
112typedef unsigned char __u8;
113typedef unsigned short __u16;
114typedef unsigned int __u32;
115typedef unsigned __int64 __u64;
116typedef __int64 loff_t;
117typedef __int64 ll_t;
118
119extern char *optarg;
120extern int optind;
121extern int opterr;
122extern int optopt;
123int getopt(int argc, char *const argv[], const char * optstring);
124
125static int is_device = 0;
126
127#define open WIN32open
128#define close WIN32close
129#define read WIN32read
130#define write WIN32write
131#define llseek WIN32llseek
132
133#define O_SHORT_LIVED _O_SHORT_LIVED
134#define O_ACCMODE 3
135#define O_NONE 3
136#define O_BACKUP 0x10000
137#define O_SHARED 0x20000
138
139static int WIN32open(const char *path, int oflag, ...)
140{
141 HANDLE fh;
142 DWORD desiredAccess;
143 DWORD shareMode;
144 DWORD creationDisposition;
145 DWORD flagsAttributes = FILE_ATTRIBUTE_NORMAL;
146 SECURITY_ATTRIBUTES securityAttributes;
147 va_list ap;
148 int pmode;
149 int trunc = FALSE;
150
151 securityAttributes.nLength = sizeof(securityAttributes);
152 securityAttributes.lpSecurityDescriptor = NULL;
153 securityAttributes.bInheritHandle = oflag & O_NOINHERIT ? FALSE : TRUE;
154 switch (oflag & O_ACCMODE) {
155 case O_RDONLY:
156 desiredAccess = GENERIC_READ;
157 shareMode = FILE_SHARE_READ;
158 break;
159 case O_WRONLY:
160 desiredAccess = GENERIC_WRITE;
161 shareMode = 0;
162 break;
163 case O_RDWR:
164 desiredAccess = GENERIC_READ|GENERIC_WRITE;
165 shareMode = 0;
166 break;
167 case O_NONE:
168 desiredAccess = 0;
170 }
171 if (oflag & O_APPEND) {
172 desiredAccess |= FILE_APPEND_DATA|SYNCHRONIZE;
174 }
175 if (oflag & O_SHARED)
177 switch (oflag & (O_CREAT|O_EXCL|O_TRUNC)) {
178 case 0:
179 case O_EXCL:
180 creationDisposition = OPEN_EXISTING;
181 break;
182 case O_CREAT:
183 creationDisposition = OPEN_ALWAYS;
184 break;
185 case O_CREAT|O_EXCL:
187 creationDisposition = CREATE_NEW;
188 break;
189 case O_TRUNC:
190 case O_TRUNC|O_EXCL:
191 creationDisposition = TRUNCATE_EXISTING;
192 break;
193 case O_CREAT|O_TRUNC:
194 creationDisposition = OPEN_ALWAYS;
195 trunc = TRUE;
196 break;
197 }
198 if (oflag & O_CREAT) {
199 va_start(ap, oflag);
200 pmode = va_arg(ap, int);
201 va_end(ap);
202 if ((pmode & 0222) == 0)
203 flagsAttributes |= FILE_ATTRIBUTE_READONLY;
204 }
205 if (oflag & O_TEMPORARY) {
206 flagsAttributes |= FILE_FLAG_DELETE_ON_CLOSE;
207 desiredAccess |= DELETE;
208 }
209 if (oflag & O_SHORT_LIVED)
210 flagsAttributes |= FILE_ATTRIBUTE_TEMPORARY;
211 if (oflag & O_SEQUENTIAL)
212 flagsAttributes |= FILE_FLAG_SEQUENTIAL_SCAN;
213 else if (oflag & O_RANDOM)
214 flagsAttributes |= FILE_FLAG_RANDOM_ACCESS;
215 if (oflag & O_BACKUP)
216 flagsAttributes |= FILE_FLAG_BACKUP_SEMANTICS;
217 if ((fh = CreateFile(path, desiredAccess, shareMode, &securityAttributes,
218 creationDisposition, flagsAttributes, NULL)) == INVALID_HANDLE_VALUE) {
220 return -1;
221 }
222 if (trunc) {
223 if (!SetEndOfFile(fh)) {
225 CloseHandle(fh);
227 return -1;
228 }
229 }
230 return (int)fh;
231}
232
233static int WIN32close(int fd)
234{
235 if (!CloseHandle((HANDLE)fd)) {
237 return -1;
238 }
239 return 0;
240}
241
242static int WIN32read(int fd, void *buf, unsigned int len)
243{
244 DWORD actualLen;
245
246 if (!ReadFile((HANDLE)fd, buf, (DWORD)len, &actualLen, NULL)) {
249 return 0;
250 else
251 return -1;
252 }
253 return (int)actualLen;
254}
255
256static int WIN32write(int fd, void *buf, unsigned int len)
257{
258 DWORD actualLen;
259
260 if (!WriteFile((HANDLE)fd, buf, (DWORD)len, &actualLen, NULL)) {
262 return -1;
263 }
264 return (int)actualLen;
265}
266
267static loff_t WIN32llseek(int fd, loff_t offset, int whence)
268{
269 long lo, hi;
270 DWORD err;
271
272 lo = offset & 0xffffffff;
273 hi = offset >> 32;
274 lo = SetFilePointer((HANDLE)fd, lo, &hi, whence);
275 if (lo == 0xFFFFFFFF && (err = GetLastError()) != NO_ERROR) {
276 errno = err;
277 return -1;
278 }
279 return ((loff_t)hi << 32) | (off_t)lo;
280}
281
282int fsctl(int fd, int code)
283{
284 DWORD ret;
285 if (!DeviceIoControl((HANDLE)fd, code, NULL, 0, NULL, 0, &ret, NULL)) {
287 return -1;
288 }
289 return 0;
290}
291
292#else
293
294#define O_NOINHERIT 0
295#define O_TEMPORARY 0
296#define O_SHORT_LIVED 0
297#define O_SEQUENTIAL 0
298#define O_RANDOM 0
299#define O_BACKUP 0
300#define O_SHARED 0
301#ifndef O_NONE
302# define O_NONE 0
303#endif
304
305typedef long long ll_t;
306/* Use the _llseek system call directly, because there (once?) was a bug in
307 * the glibc implementation of it. */
308#include <linux/unistd.h>
309#if defined(__alpha) || defined(__ia64__)
310/* On alpha, the syscall is simply lseek, because it's a 64 bit system. */
311static loff_t llseek( int fd, loff_t offset, int whence )
312{
313 return lseek(fd, offset, whence);
314}
315#else
316# ifndef __NR__llseek
317# error _llseek system call not present
318# endif
319static _syscall5( int, _llseek, uint, fd, ulong, hi, ulong, lo,
320 loff_t *, res, uint, wh );
321static loff_t llseek( int fd, loff_t offset, int whence )
322{
323 loff_t actual;
324
325 if (_llseek(fd, offset>>32, offset&0xffffffff, &actual, whence) != 0)
326 return (loff_t)-1;
327 return actual;
328}
329#endif
330
331#endif
332
333/* Constant definitions */
334
335#define TRUE 1 /* Boolean constants */
336#define FALSE 0
337
338#define TEST_BUFFER_BLOCKS 16
339#define HARD_SECTOR_SIZE 512
340#define SECTORS_PER_BLOCK ( BLOCK_SIZE / HARD_SECTOR_SIZE )
341
342
343/* Macro definitions */
344
345/* Report a failure message and return a failure error code */
346
347#define die( str ) fatal_error( "%s: " str "\n" )
348
349
350/* Mark a cluster in the FAT as bad */
351
352#define mark_sector_bad( sector ) mark_FAT_sector( sector, FAT_BAD )
353
354/* Compute ceil(a/b) */
355
356inline int
357cdiv (int a, int b)
358{
359 return (a + b - 1) / b;
360}
361
362/* MS-DOS filesystem structures -- I included them here instead of
363 including linux/msdos_fs.h since that doesn't include some fields we
364 need */
365
366#define ATTR_RO 1 /* read-only */
367#define ATTR_HIDDEN 2 /* hidden */
368#define ATTR_SYS 4 /* system */
369#define ATTR_VOLUME 8 /* volume label */
370#define ATTR_DIR 16 /* directory */
371#define ATTR_ARCH 32 /* archived */
372
373#define ATTR_NONE 0 /* no attribute bits */
374#define ATTR_UNUSED (ATTR_VOLUME | ATTR_ARCH | ATTR_SYS | ATTR_HIDDEN)
375 /* attribute bits that are copied "as is" */
376
377/* FAT values */
378#define FAT_EOF (atari_format ? 0x0fffffff : 0x0ffffff8)
379#define FAT_BAD 0x0ffffff7
380
381#define MSDOS_EXT_SIGN 0x29 /* extended boot sector signature */
382#define MSDOS_FAT12_SIGN "FAT12 " /* FAT12 filesystem signature */
383#define MSDOS_FAT16_SIGN "FAT16 " /* FAT16 filesystem signature */
384#define MSDOS_FAT32_SIGN "FAT32 " /* FAT32 filesystem signature */
385
386#define BOOT_SIGN 0xAA55 /* Boot sector magic number */
387
388#define MAX_CLUST_12 ((1 << 12) - 16)
389#define MAX_CLUST_16 ((1 << 16) - 16)
390/* M$ says the high 4 bits of a FAT32 FAT entry are reserved and don't belong
391 * to the cluster number. So the max. cluster# is based on 2^28 */
392#define MAX_CLUST_32 ((1 << 28) - 16)
393
394#define FAT12_THRESHOLD 4078
395
396#define OLDGEMDOS_MAX_SECTORS 32765
397#define GEMDOS_MAX_SECTORS 65531
398#define GEMDOS_MAX_SECTOR_SIZE (16*1024)
399
400#define BOOTCODE_SIZE 448
401#define BOOTCODE_FAT32_SIZE 420
402
403/* __attribute__ ((packed)) is used on all structures to make gcc ignore any
404 * alignments */
405
406#ifdef _WIN32
407#pragma pack(push, 1)
408#endif
410 __u8 drive_number; /* BIOS drive number */
411 __u8 RESERVED; /* Unused */
412 __u8 ext_boot_sign; /* 0x29 if fields below exist (DOS 3.3+) */
413 __u8 volume_id[4]; /* Volume ID number */
414 __u8 volume_label[11];/* Volume label */
415 __u8 fs_type[8]; /* Typically FAT12 or FAT16 */
417
419{
420 __u8 boot_jump[3]; /* Boot strap short or near jump */
421 __u8 system_id[8]; /* Name - can be used to special case
422 partition manager volumes */
423 __u8 sector_size[2]; /* bytes per logical sector */
424 __u8 cluster_size; /* sectors/cluster */
425 __u16 reserved; /* reserved sectors */
426 __u8 fats; /* number of FATs */
427 __u8 dir_entries[2]; /* root directory entries */
428 __u8 sectors[2]; /* number of sectors */
429 __u8 media; /* media code (unused) */
430 __u16 fat_length; /* sectors/FAT */
431 __u16 secs_track; /* sectors per track */
432 __u16 heads; /* number of heads */
433 __u32 hidden; /* hidden sectors (unused) */
434 __u32 total_sect; /* number of sectors (if sectors == 0) */
435 union {
436 struct {
439 } __attribute__ ((packed)) _oldfat;
440 struct {
441 __u32 fat32_length; /* sectors/FAT */
442 __u16 flags; /* bit 8: fat mirroring, low 4: active fat */
443 __u8 version[2]; /* major, minor filesystem version */
444 __u32 root_cluster; /* first cluster in root directory */
445 __u16 info_sector; /* filesystem info sector */
446 __u16 backup_boot; /* backup boot sector */
447 __u16 reserved2[6]; /* Unused */
448 struct msdos_volume_info vi;
450 } __attribute__ ((packed)) _fat32;
451 } __attribute__ ((packed)) fstype;
452 __u16 boot_sign;
454#define fat32 fstype._fat32
455#define oldfat fstype._oldfat
456
458 __u32 reserved1; /* Nothing as far as I can tell */
459 __u32 signature; /* 0x61417272L */
460 __u32 free_clusters; /* Free cluster count. -1 if unknown */
461 __u32 next_cluster; /* Most recently allocated cluster.
462 * Unused under Linux. */
465
467 {
468 char name[8], ext[3]; /* name and extension */
469 __u8 attr; /* attribute bits */
470 __u8 lcase; /* Case for base and extension */
471 __u8 ctime_ms; /* Creation time, milliseconds */
472 __u16 ctime; /* Creation time */
473 __u16 cdate; /* Creation date */
474 __u16 adate; /* Last access date */
475 __u16 starthi; /* high 16 bits of first cl. (FAT32) */
476 __u16 time, date, start; /* time, date and first cluster */
477 __u32 size; /* file size (in bytes) */
478 } __attribute__ ((packed));
479
480#ifdef _WIN32
481#pragma pack(pop)
482#endif
483
484/* The "boot code" we put into the filesystem... it writes a message and
485 tells the user to try again */
486
487char dummy_boot_jump[3] = { 0xeb, 0x3c, 0x90 };
488
489char dummy_boot_jump_m68k[2] = { 0x60, 0x1c };
490
492 "\x0e" /* push cs */
493 "\x1f" /* pop ds */
494 "\xbe\x5b\x7c" /* mov si, offset message_txt */
495 /* write_msg: */
496 "\xac" /* lodsb */
497 "\x22\xc0" /* and al, al */
498 "\x74\x0b" /* jz key_press */
499 "\x56" /* push si */
500 "\xb4\x0e" /* mov ah, 0eh */
501 "\xbb\x07\x00" /* mov bx, 0007h */
502 "\xcd\x10" /* int 10h */
503 "\x5e" /* pop si */
504 "\xeb\xf0" /* jmp write_msg */
505 /* key_press: */
506 "\x32\xe4" /* xor ah, ah */
507 "\xcd\x16" /* int 16h */
508 "\xcd\x19" /* int 19h */
509 "\xeb\xfe" /* foo: jmp foo */
510 /* message_txt: */
511
512 "This is not a bootable disk. Please insert a bootable floppy and\r\n"
513 "press any key to try again ... \r\n";
514
515#define MESSAGE_OFFSET 29 /* Offset of message in above code */
516
517/* Global variables - the root of all evil :-) - see these and weep! */
518
519static char *program_name = "mkdosfs"; /* Name of the program */
520static char *device_name = NULL; /* Name of the device on which to create the filesystem */
521static int atari_format = 0; /* Use Atari variation of MS-DOS FS format */
522static int check = FALSE; /* Default to no readablity checking */
523static int verbose = 0; /* Default to verbose mode off */
524static long volume_id; /* Volume ID number */
525static time_t create_time; /* Creation time */
526static char volume_name[] = " "; /* Volume name */
527static int blocks; /* Number of blocks in filesystem */
528static int sector_size = 512; /* Size of a logical sector */
529static int sector_size_set = 0; /* User selected sector size */
530static int backup_boot = 0; /* Sector# of backup boot sector */
531static int reserved_sectors = 0;/* Number of reserved sectors */
532static int badblocks = 0; /* Number of bad blocks in the filesystem */
533static int nr_fats = 2; /* Default number of FATs to produce */
534static int size_fat = 0; /* Size in bits of FAT entries */
535static int size_fat_by_user = 0; /* 1 if FAT size user selected */
536static int dev = -1; /* FS block device file handle */
537static int ignore_full_disk = 0; /* Ignore warning about 'full' disk devices */
538static unsigned int currently_testing = 0; /* Block currently being tested (if autodetect bad blocks) */
539static struct msdos_boot_sector bs; /* Boot sector data */
540static int start_data_sector; /* Sector number for the start of the data area */
541static int start_data_block; /* Block number for the start of the data area */
542static unsigned char *fat; /* File allocation table */
543static unsigned char *info_sector; /* FAT32 info sector */
544static struct msdos_dir_entry *root_dir; /* Root directory */
545static int size_root_dir; /* Size of the root directory in bytes */
546static int sectors_per_cluster = 0; /* Number of sectors per disk cluster */
547static int root_dir_entries = 0; /* Number of root directory entries */
548static char *blank_sector; /* Blank sector - all zeros */
549
550
551/* Function prototype definitions */
552
553static void fatal_error (const char *fmt_string) __attribute__((noreturn));
554static void mark_FAT_cluster (int cluster, unsigned int value);
555static void mark_FAT_sector (int sector, unsigned int value);
556static long do_check (char *buffer, int try, unsigned int current_block);
557static void alarm_intr (int alnum);
558static void check_blocks (void);
559static void get_list_blocks (char *filename);
560static int valid_offset (int fd, loff_t offset);
561static int count_blocks (char *filename);
562static void check_mount (char *device_name);
563#ifdef _WIN32
564static void establish_params (void);
565#else
566static void establish_params (int device_num, int size);
567#endif
568static void setup_tables (void);
569static void write_tables (void);
570
571
572/* The function implementations */
573
574/* Handle the reporting of fatal errors. Volatile to let gcc know that this doesn't return */
575
576static void
577fatal_error (const char *fmt_string)
578{
579 fprintf (stderr, fmt_string, program_name, device_name);
580 exit (1); /* The error exit code is 1! */
581}
582
583
584/* Mark the specified cluster as having a particular value */
585
586static void
587mark_FAT_cluster (int cluster, unsigned int value)
588{
589 switch( size_fat ) {
590 case 12:
591 value &= 0x0fff;
592 if (((cluster * 3) & 0x1) == 0)
593 {
594 fat[3 * cluster / 2] = (unsigned char) (value & 0x00ff);
595 fat[(3 * cluster / 2) + 1] = (unsigned char) ((fat[(3 * cluster / 2) + 1] & 0x00f0)
596 | ((value & 0x0f00) >> 8));
597 }
598 else
599 {
600 fat[3 * cluster / 2] = (unsigned char) ((fat[3 * cluster / 2] & 0x000f) | ((value & 0x000f) << 4));
601 fat[(3 * cluster / 2) + 1] = (unsigned char) ((value & 0x0ff0) >> 4);
602 }
603 break;
604
605 case 16:
606 value &= 0xffff;
607 fat[2 * cluster] = (unsigned char) (value & 0x00ff);
608 fat[(2 * cluster) + 1] = (unsigned char) (value >> 8);
609 break;
610
611 case 32:
612 value &= 0xfffffff;
613 fat[4 * cluster] = (unsigned char) (value & 0x000000ff);
614 fat[(4 * cluster) + 1] = (unsigned char) ((value & 0x0000ff00) >> 8);
615 fat[(4 * cluster) + 2] = (unsigned char) ((value & 0x00ff0000) >> 16);
616 fat[(4 * cluster) + 3] = (unsigned char) ((value & 0xff000000) >> 24);
617 break;
618
619 default:
620 die("Bad FAT size (not 12, 16, or 32)");
621 }
622}
623
624
625/* Mark a specified sector as having a particular value in it's FAT entry */
626
627static void
628mark_FAT_sector (int sector, unsigned int value)
629{
630 int cluster;
631
632 cluster = (sector - start_data_sector) / (int) (bs.cluster_size) /
634 if (cluster < 0)
635 die ("Invalid cluster number in mark_FAT_sector: probably bug!");
636
637 mark_FAT_cluster (cluster, value);
638}
639
640
641/* Perform a test on a block. Return the number of blocks that could be read successfully */
642
643static long
644do_check (char *buffer, int try, unsigned int current_block)
645{
646 long got;
647
648 if (llseek (dev, (loff_t)current_block * BLOCK_SIZE, SEEK_SET) /* Seek to the correct location */
649 != (loff_t)current_block * BLOCK_SIZE)
650 die ("seek failed during testing for blocks");
651
652 got = read (dev, buffer, try * BLOCK_SIZE); /* Try reading! */
653 if (got < 0)
654 got = 0;
655
656 if (got & (BLOCK_SIZE - 1))
657 printf ("Unexpected values in do_check: probably bugs\n");
658 got /= BLOCK_SIZE;
659
660 return got;
661}
662
663#ifndef _WIN32
664/* Alarm clock handler - display the status of the quest for bad blocks! Then retrigger the alarm for five senconds
665 later (so we can come here again) */
666
667static void
668alarm_intr (int alnum)
669{
671 return;
672
673 signal (SIGALRM, alarm_intr);
674 alarm (5);
676 return;
677
678 printf ("%d... ", currently_testing);
679 fflush (stdout);
680}
681#endif
682
683static void
685{
686 int try, got;
687 int i;
688 static char blkbuf[BLOCK_SIZE * TEST_BUFFER_BLOCKS];
689
690 if (verbose)
691 {
692 printf ("Searching for bad blocks ");
693 fflush (stdout);
694 }
696#ifndef _WIN32
697 if (verbose)
698 {
699 signal (SIGALRM, alarm_intr);
700 alarm (5);
701 }
702#endif
703 try = TEST_BUFFER_BLOCKS;
704 while (currently_testing < blocks)
705 {
706 if (currently_testing + try > blocks)
708 got = do_check (blkbuf, try, currently_testing);
709 currently_testing += got;
710 if (got == try)
711 {
712 try = TEST_BUFFER_BLOCKS;
713 continue;
714 }
715 else
716 try = 1;
718 die ("bad blocks before data-area: cannot make fs");
719
720 for (i = 0; i < SECTORS_PER_BLOCK; i++) /* Mark all of the sectors in the block as bad */
722 badblocks++;
724 }
725
726 if (verbose)
727 printf ("\n");
728
729 if (badblocks)
730 printf ("%d bad block%s\n", badblocks,
731 (badblocks > 1) ? "s" : "");
732}
733
734
735static void
737{
738 int i;
739 FILE *listfile;
740 unsigned long blockno;
741
742 listfile = fopen (filename, "r");
743 if (listfile == (FILE *) NULL)
744 die ("Can't open file of bad blocks");
745
746 while (!feof (listfile))
747 {
748 fscanf (listfile, "%ld\n", &blockno);
749 for (i = 0; i < SECTORS_PER_BLOCK; i++) /* Mark all of the sectors in the block as bad */
750 mark_sector_bad (blockno * SECTORS_PER_BLOCK + i);
751 badblocks++;
752 }
753 fclose (listfile);
754
755 if (badblocks)
756 printf ("%d bad block%s\n", badblocks,
757 (badblocks > 1) ? "s" : "");
758}
759
760
761#ifndef _WIN32
762/* Given a file descriptor and an offset, check whether the offset is a valid offset for the file - return FALSE if it
763 isn't valid or TRUE if it is */
764
765static int
767{
768 char ch;
769
770 if (llseek (fd, offset, SEEK_SET) < 0)
771 return FALSE;
772 if (read (fd, &ch, 1) < 1)
773 return FALSE;
774 return TRUE;
775}
776#endif
777
778
779/* Given a filename, look to see how many blocks of BLOCK_SIZE are present, returning the answer */
780
781static int
783{
784#ifdef _WIN32
785 int fd;
786 DISK_GEOMETRY geom;
788 DWORD ret;
789 loff_t len = 0;
790
791 if ((fd = open(filename, O_RDONLY)) < 0) {
793 exit(1);
794 }
795 /*
796 * This should probably use IOCTL_DISK_GET_LENGTH_INFO here, but
797 * this ioctl is only available in XP and up.
798 */
799 if (is_device) {
800 if (!DeviceIoControl((HANDLE)fd, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geom, sizeof(geom), &ret, NULL)) {
802 die("unable to get length for '%s'");
803 }
805 } else {
806 if (!GetFileInformationByHandle((HANDLE)fd, &hinfo)) {
808 die("unable to get length for '%s'");
809 }
810 len = ((loff_t)hinfo.nFileSizeHigh << 32) | (loff_t)hinfo.nFileSizeLow;
811 }
812 close(fd);
813 return len/BLOCK_SIZE;
814#else
815 loff_t high, low;
816 int fd;
817
818 if ((fd = open (filename, O_RDONLY)) < 0)
819 {
821 exit (1);
822 }
823 low = 0;
824
825 for (high = 1; valid_offset (fd, high); high *= 2)
826 low = high;
827 while (low < high - 1)
828 {
829 const loff_t mid = (low + high) / 2;
830
831 if (valid_offset (fd, mid))
832 low = mid;
833 else
834 high = mid;
835 }
836 valid_offset (fd, 0);
837 close (fd);
838
839 return (low + 1) / BLOCK_SIZE;
840#endif
841}
842
843
844/* Check to see if the specified device is currently mounted - abort if it is */
845
846static void
848{
849#ifndef _WIN32
850 FILE *f;
851 struct mntent *mnt;
852
853 if ((f = setmntent (MOUNTED, "r")) == NULL)
854 return;
855 while ((mnt = getmntent (f)) != NULL)
856 if (strcmp (device_name, mnt->mnt_fsname) == 0)
857 die ("%s contains a mounted file system.");
858 endmntent (f);
859#endif
860}
861
862
863/* Establish the geometry and media parameters for the device */
864#ifdef _WIN32
865static void
866establish_params (void)
867{
868 DISK_GEOMETRY geometry;
869 DWORD ret;
870
871 if (!is_device) {
872 bs.media = (char) 0xf8; /* Set up the media descriptor for a hard drive */
873 bs.dir_entries[0] = (char) 0;
874 bs.dir_entries[1] = (char) 2;
875 /* For FAT32, use 4k clusters on sufficiently large file systems,
876 * otherwise 1 sector per cluster. This is also what M$'s format
877 * command does for FAT32. */
878 bs.cluster_size = (char)
879 (size_fat == 32 ?
880 ((ll_t)blocks*SECTORS_PER_BLOCK >= 512*1024 ? 8 : 1) :
881 4); /* FAT12 and FAT16: start at 4 sectors per cluster */
882 return;
883 }
884 if (!DeviceIoControl((HANDLE)dev, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geometry, sizeof(geometry), &ret, NULL)) {
886 die ("unable to get geometry for '%s'");
887 }
888 bs.secs_track = geometry.SectorsPerTrack;
889 bs.heads = geometry.TracksPerCylinder;
890 switch (geometry.MediaType) {
891 case F3_1Pt44_512:
892 bs.media = (char) 0xf9;
893 bs.cluster_size = (char) 2;
894 bs.dir_entries[0] = (char) 112;
895 bs.dir_entries[1] = (char) 0;
896 break;
897 case F3_2Pt88_512:
898 bs.media = (char) 0xf0;
899 bs.cluster_size = (char)(atari_format ? 2 : 1);
900 bs.dir_entries[0] = (char) 224;
901 bs.dir_entries[1] = (char) 0;
902 break;
903 case F3_720_512:
904 bs.media = (char) 0xfd;
905 bs.cluster_size = (char) 2;
906 bs.dir_entries[0] = (char) 112;
907 bs.dir_entries[1] = (char) 0;
908 break;
909 default:
910 bs.media = (char) 0xf8; /* Set up the media descriptor for a hard drive */
911 bs.dir_entries[0] = (char) 0;
912 bs.dir_entries[1] = (char) 2;
913 /* For FAT32, use 4k clusters on sufficiently large file systems,
914 * otherwise 1 sector per cluster. This is also what M$'s format
915 * command does for FAT32. */
916 bs.cluster_size = (char)
917 (size_fat == 32 ?
918 ((ll_t)blocks*SECTORS_PER_BLOCK >= 512*1024 ? 8 : 1) :
919 4); /* FAT12 and FAT16: start at 4 sectors per cluster */
920 }
921}
922#else
923static void
924establish_params (int device_num,int size)
925{
926 long loop_size;
927 struct hd_geometry geometry;
928 struct floppy_struct param;
929
930 if ((0 == device_num) || ((device_num & 0xff00) == 0x0200))
931 /* file image or floppy disk */
932 {
933 if (0 == device_num)
934 {
935 param.size = size/512;
936 switch(param.size)
937 {
938 case 720:
939 param.sect = 9 ;
940 param.head = 2;
941 break;
942 case 1440:
943 param.sect = 9;
944 param.head = 2;
945 break;
946 case 2400:
947 param.sect = 15;
948 param.head = 2;
949 break;
950 case 2880:
951 param.sect = 18;
952 param.head = 2;
953 break;
954 case 5760:
955 param.sect = 36;
956 param.head = 2;
957 break;
958 default:
959 /* fake values */
960 param.sect = 32;
961 param.head = 64;
962 break;
963 }
964
965 }
966 else /* is a floppy diskette */
967 {
968 if (ioctl (dev, FDGETPRM, &param)) /* Can we get the diskette geometry? */
969 die ("unable to get diskette geometry for '%s'");
970 }
971 bs.secs_track = CT_LE_W(param.sect); /* Set up the geometry information */
972 bs.heads = CT_LE_W(param.head);
973 switch (param.size) /* Set up the media descriptor byte */
974 {
975 case 720: /* 5.25", 2, 9, 40 - 360K */
976 bs.media = (char) 0xfd;
977 bs.cluster_size = (char) 2;
978 bs.dir_entries[0] = (char) 112;
979 bs.dir_entries[1] = (char) 0;
980 break;
981
982 case 1440: /* 3.5", 2, 9, 80 - 720K */
983 bs.media = (char) 0xf9;
984 bs.cluster_size = (char) 2;
985 bs.dir_entries[0] = (char) 112;
986 bs.dir_entries[1] = (char) 0;
987 break;
988
989 case 2400: /* 5.25", 2, 15, 80 - 1200K */
990 bs.media = (char) 0xf9;
991 bs.cluster_size = (char)(atari_format ? 2 : 1);
992 bs.dir_entries[0] = (char) 224;
993 bs.dir_entries[1] = (char) 0;
994 break;
995
996 case 5760: /* 3.5", 2, 36, 80 - 2880K */
997 bs.media = (char) 0xf0;
998 bs.cluster_size = (char) 2;
999 bs.dir_entries[0] = (char) 224;
1000 bs.dir_entries[1] = (char) 0;
1001 break;
1002
1003 case 2880: /* 3.5", 2, 18, 80 - 1440K */
1004 floppy_default:
1005 bs.media = (char) 0xf0;
1006 bs.cluster_size = (char)(atari_format ? 2 : 1);
1007 bs.dir_entries[0] = (char) 224;
1008 bs.dir_entries[1] = (char) 0;
1009 break;
1010
1011 default: /* Anything else */
1012 if (0 == device_num)
1013 goto def_hd_params;
1014 else
1015 goto floppy_default;
1016 }
1017 }
1018 else if ((device_num & 0xff00) == 0x0700) /* This is a loop device */
1019 {
1020 /* Can we get the loop geometry? This is in 512 byte blocks, always? */
1021 if (ioctl (dev, BLKGETSIZE, &loop_size))
1022 die ("unable to get loop geometry for '%s'");
1023 loop_size = loop_size >> 1;
1024
1025 switch (loop_size) /* Assuming the loop device -> floppy later */
1026 {
1027 case 720: /* 5.25", 2, 9, 40 - 360K */
1028 bs.secs_track = CF_LE_W(9);
1029 bs.heads = CF_LE_W(2);
1030 bs.media = (char) 0xfd;
1031 bs.cluster_size = (char) 2;
1032 bs.dir_entries[0] = (char) 112;
1033 bs.dir_entries[1] = (char) 0;
1034 break;
1035
1036 case 1440: /* 3.5", 2, 9, 80 - 720K */
1037 bs.secs_track = CF_LE_W(9);
1038 bs.heads = CF_LE_W(2);
1039 bs.media = (char) 0xf9;
1040 bs.cluster_size = (char) 2;
1041 bs.dir_entries[0] = (char) 112;
1042 bs.dir_entries[1] = (char) 0;
1043 break;
1044
1045 case 2400: /* 5.25", 2, 15, 80 - 1200K */
1046 bs.secs_track = CF_LE_W(15);
1047 bs.heads = CF_LE_W(2);
1048 bs.media = (char) 0xf9;
1049 bs.cluster_size = (char)(atari_format ? 2 : 1);
1050 bs.dir_entries[0] = (char) 224;
1051 bs.dir_entries[1] = (char) 0;
1052 break;
1053
1054 case 5760: /* 3.5", 2, 36, 80 - 2880K */
1055 bs.secs_track = CF_LE_W(36);
1056 bs.heads = CF_LE_W(2);
1057 bs.media = (char) 0xf0;
1058 bs.cluster_size = (char) 2;
1059 bs.dir_entries[0] = (char) 224;
1060 bs.dir_entries[1] = (char) 0;
1061 break;
1062
1063 case 2880: /* 3.5", 2, 18, 80 - 1440K */
1064 bs.secs_track = CF_LE_W(18);
1065 bs.heads = CF_LE_W(2);
1066 bs.media = (char) 0xf0;
1067 bs.cluster_size = (char)(atari_format ? 2 : 1);
1068 bs.dir_entries[0] = (char) 224;
1069 bs.dir_entries[1] = (char) 0;
1070 break;
1071
1072 default: /* Anything else: default hd setup */
1073 printf("Loop device does not match a floppy size, using "
1074 "default hd params\n");
1075 bs.secs_track = CT_LE_W(32); /* these are fake values... */
1076 bs.heads = CT_LE_W(64);
1077 goto def_hd_params;
1078 }
1079 }
1080 else
1081 /* Must be a hard disk then! */
1082 {
1083 /* Can we get the drive geometry? (Note I'm not too sure about */
1084 /* whether to use HDIO_GETGEO or HDIO_REQ) */
1085 if (ioctl (dev, HDIO_GETGEO, &geometry))
1086 die ("unable to get drive geometry for '%s'");
1087 bs.secs_track = CT_LE_W(geometry.sectors); /* Set up the geometry information */
1088 bs.heads = CT_LE_W(geometry.heads);
1089 def_hd_params:
1090 bs.media = (char) 0xf8; /* Set up the media descriptor for a hard drive */
1091 bs.dir_entries[0] = (char) 0; /* Default to 512 entries */
1092 bs.dir_entries[1] = (char) 2;
1093 /* For FAT32, use 4k clusters on sufficiently large file systems,
1094 * otherwise 1 sector per cluster. This is also what M$'s format
1095 * command does for FAT32. */
1096 bs.cluster_size = (char)
1097 (size_fat == 32 ?
1098 ((ll_t)blocks*SECTORS_PER_BLOCK >= 512*1024 ? 8 : 1) :
1099 4); /* FAT12 and FAT16: start at 4 sectors per cluster */
1100 }
1101}
1102#endif
1103
1104
1105/* Create the filesystem data tables */
1106
1107static void
1109{
1110 unsigned num_sectors;
1111 unsigned cluster_count = 0, fat_length;
1112 unsigned fatdata; /* Sectors for FATs + data area */
1113 struct tm *ctime;
1114 struct msdos_volume_info *vi = (size_fat == 32 ? &bs.fat32.vi : &bs.oldfat.vi);
1115
1116 if (atari_format)
1117 /* On Atari, the first few bytes of the boot sector are assigned
1118 * differently: The jump code is only 2 bytes (and m68k machine code
1119 * :-), then 6 bytes filler (ignored), then 3 byte serial number. */
1120 strncpy( bs.system_id-1, "mkdosf", 6 );
1121 else
1122 strcpy (bs.system_id, "mkdosfs");
1124 bs.cluster_size = (char) sectors_per_cluster;
1125 if (size_fat == 32)
1126 {
1127 /* Under FAT32, the root dir is in a cluster chain, and this is
1128 * signalled by bs.dir_entries being 0. */
1129 bs.dir_entries[0] = bs.dir_entries[1] = (char) 0;
1130 root_dir_entries = 0;
1131 }
1132 else if (root_dir_entries)
1133 {
1134 /* Override default from establish_params() */
1135 bs.dir_entries[0] = (char) (root_dir_entries & 0x00ff);
1136 bs.dir_entries[1] = (char) ((root_dir_entries & 0xff00) >> 8);
1137 }
1138 else
1139 root_dir_entries = bs.dir_entries[0] + (bs.dir_entries[1] << 8);
1140
1141 if (atari_format) {
1142 bs.system_id[5] = (unsigned char) (volume_id & 0x000000ff);
1143 bs.system_id[6] = (unsigned char) ((volume_id & 0x0000ff00) >> 8);
1144 bs.system_id[7] = (unsigned char) ((volume_id & 0x00ff0000) >> 16);
1145 }
1146 else {
1147 vi->volume_id[0] = (unsigned char) (volume_id & 0x000000ff);
1148 vi->volume_id[1] = (unsigned char) ((volume_id & 0x0000ff00) >> 8);
1149 vi->volume_id[2] = (unsigned char) ((volume_id & 0x00ff0000) >> 16);
1150 vi->volume_id[3] = (unsigned char) (volume_id >> 24);
1151 }
1152
1153 if (!atari_format) {
1154 memcpy(vi->volume_label, volume_name, 11);
1155
1156 memcpy(bs.boot_jump, dummy_boot_jump, 3);
1157 /* Patch in the correct offset to the boot code */
1158 bs.boot_jump[1] = ((size_fat == 32 ?
1159 (char *)&bs.fat32.boot_code :
1160 (char *)&bs.oldfat.boot_code) -
1161 (char *)&bs) - 2;
1162
1163 if (size_fat == 32) {
1165 printf ("Warning: message too long; truncated\n");
1167 memcpy(bs.fat32.boot_code, dummy_boot_code, BOOTCODE_FAT32_SIZE);
1168 }
1169 else {
1170 memcpy(bs.oldfat.boot_code, dummy_boot_code, BOOTCODE_SIZE);
1171 }
1172 bs.boot_sign = CT_LE_W(BOOT_SIGN);
1173 }
1174 else {
1175 memcpy(bs.boot_jump, dummy_boot_jump_m68k, 2);
1176 }
1177 if (verbose >= 2)
1178 printf( "Boot jump code is %02x %02x\n",
1179 bs.boot_jump[0], bs.boot_jump[1] );
1180
1181 if (!reserved_sectors)
1182 reserved_sectors = (size_fat == 32) ? 32 : 1;
1183 else {
1184 if (size_fat == 32 && reserved_sectors < 2)
1185 die("On FAT32 at least 2 reserved sectors are needed.");
1186 }
1187 bs.reserved = CT_LE_W(reserved_sectors);
1188 if (verbose >= 2)
1189 printf( "Using %d reserved sectors\n", reserved_sectors );
1190 bs.fats = (char) nr_fats;
1191 if (!atari_format || size_fat == 32)
1192 bs.hidden = CT_LE_L(0);
1193 else
1194 /* In Atari format, hidden is a 16 bit field */
1195 memset( &bs.hidden, 0, 2 );
1196
1197 num_sectors = (ll_t)blocks*BLOCK_SIZE/sector_size;
1198 if (!atari_format) {
1199 unsigned fatlength12, fatlength16, fatlength32;
1200 unsigned maxclust12, maxclust16, maxclust32;
1201 unsigned clust12, clust16, clust32;
1202 int maxclustsize;
1203
1204 fatdata = num_sectors - cdiv (root_dir_entries * 32, sector_size) -
1206
1208 bs.cluster_size = maxclustsize = sectors_per_cluster;
1209 else
1210 /* An initial guess for bs.cluster_size should already be set */
1211 maxclustsize = 128;
1212
1213 if (verbose >= 2)
1214 printf( "%d sectors for FAT+data, starting with %d sectors/cluster\n",
1215 fatdata, bs.cluster_size );
1216 do {
1217 if (verbose >= 2)
1218 printf( "Trying with %d sectors/cluster:\n", bs.cluster_size );
1219
1220 /* The factor 2 below avoids cut-off errors for nr_fats == 1.
1221 * The "nr_fats*3" is for the reserved first two FAT entries */
1222 clust12 = 2*((ll_t) fatdata *sector_size + nr_fats*3) /
1223 (2*(int) bs.cluster_size * sector_size + nr_fats*3);
1224 fatlength12 = cdiv (((clust12+2) * 3 + 1) >> 1, sector_size);
1225 /* Need to recalculate number of clusters, since the unused parts of the
1226 * FATS and data area together could make up space for an additional,
1227 * not really present cluster. */
1228 clust12 = (fatdata - nr_fats*fatlength12)/bs.cluster_size;
1229 maxclust12 = (fatlength12 * 2 * sector_size) / 3;
1230 if (maxclust12 > MAX_CLUST_12)
1231 maxclust12 = MAX_CLUST_12;
1232 if (verbose >= 2)
1233 printf( "FAT12: #clu=%u, fatlen=%u, maxclu=%u, limit=%u\n",
1234 clust12, fatlength12, maxclust12, MAX_CLUST_12 );
1235 if (clust12 > maxclust12-2) {
1236 clust12 = 0;
1237 if (verbose >= 2)
1238 printf( "FAT12: too much clusters\n" );
1239 }
1240
1241 clust16 = ((ll_t) fatdata *sector_size + nr_fats*4) /
1242 ((int) bs.cluster_size * sector_size + nr_fats*2);
1243 fatlength16 = cdiv ((clust16+2) * 2, sector_size);
1244 /* Need to recalculate number of clusters, since the unused parts of the
1245 * FATS and data area together could make up space for an additional,
1246 * not really present cluster. */
1247 clust16 = (fatdata - nr_fats*fatlength16)/bs.cluster_size;
1248 maxclust16 = (fatlength16 * sector_size) / 2;
1249 if (maxclust16 > MAX_CLUST_16)
1250 maxclust16 = MAX_CLUST_16;
1251 if (verbose >= 2)
1252 printf( "FAT16: #clu=%u, fatlen=%u, maxclu=%u, limit=%u\n",
1253 clust16, fatlength16, maxclust16, MAX_CLUST_16 );
1254 if (clust16 > maxclust16-2) {
1255 if (verbose >= 2)
1256 printf( "FAT16: too much clusters\n" );
1257 clust16 = 0;
1258 }
1259 /* The < 4078 avoids that the filesystem will be misdetected as having a
1260 * 12 bit FAT. */
1261 if (clust16 < FAT12_THRESHOLD && !(size_fat_by_user && size_fat == 16)) {
1262 if (verbose >= 2)
1263 printf( clust16 < FAT12_THRESHOLD ?
1264 "FAT16: would be misdetected as FAT12\n" :
1265 "FAT16: too much clusters\n" );
1266 clust16 = 0;
1267 }
1268
1269 clust32 = ((ll_t) fatdata *sector_size + nr_fats*8) /
1270 ((int) bs.cluster_size * sector_size + nr_fats*4);
1271 fatlength32 = cdiv ((clust32+2) * 4, sector_size);
1272 /* Need to recalculate number of clusters, since the unused parts of the
1273 * FATS and data area together could make up space for an additional,
1274 * not really present cluster. */
1275 clust32 = (fatdata - nr_fats*fatlength32)/bs.cluster_size;
1276 maxclust32 = (fatlength32 * sector_size) / 4;
1277 if (maxclust32 > MAX_CLUST_32)
1278 maxclust32 = MAX_CLUST_32;
1279 if (verbose >= 2)
1280 printf( "FAT32: #clu=%u, fatlen=%u, maxclu=%u, limit=%u\n",
1281 clust32, fatlength32, maxclust32, MAX_CLUST_32 );
1282 if (clust32 > maxclust32) {
1283 clust32 = 0;
1284 if (verbose >= 2)
1285 printf( "FAT32: too much clusters\n" );
1286 }
1287
1288 if ((clust12 && (size_fat == 0 || size_fat == 12)) ||
1289 (clust16 && (size_fat == 0 || size_fat == 16)) ||
1290 (clust32 && size_fat == 32))
1291 break;
1292
1293 bs.cluster_size <<= 1;
1294 } while (bs.cluster_size && bs.cluster_size <= maxclustsize);
1295
1296 /* Use the optimal FAT size if not specified;
1297 * FAT32 is (not yet) choosen automatically */
1298 if (!size_fat) {
1299 size_fat = (clust16 > clust12) ? 16 : 12;
1300 if (verbose >= 2)
1301 printf( "Choosing %d bits for FAT\n", size_fat );
1302 }
1303
1304 switch (size_fat) {
1305 case 12:
1306 cluster_count = clust12;
1307 fat_length = fatlength12;
1308 bs.fat_length = CT_LE_W(fatlength12);
1309 memcpy(vi->fs_type, MSDOS_FAT12_SIGN, 8);
1310 break;
1311
1312 case 16:
1313 if (clust16 < FAT12_THRESHOLD) {
1314 if (size_fat_by_user) {
1315 fprintf( stderr, "WARNING: Not enough clusters for a "
1316 "16 bit FAT! The filesystem will be\n"
1317 "misinterpreted as having a 12 bit FAT without "
1318 "mount option \"fat=16\".\n" );
1319 }
1320 else {
1321 fprintf( stderr, "This filesystem has an unfortunate size. "
1322 "A 12 bit FAT cannot provide\n"
1323 "enough clusters, but a 16 bit FAT takes up a little "
1324 "bit more space so that\n"
1325 "the total number of clusters becomes less than the "
1326 "threshold value for\n"
1327 "distinction between 12 and 16 bit FATs.\n" );
1328 die( "Make the file system a bit smaller manually." );
1329 }
1330 }
1331 cluster_count = clust16;
1332 fat_length = fatlength16;
1333 bs.fat_length = CT_LE_W(fatlength16);
1334 memcpy(vi->fs_type, MSDOS_FAT16_SIGN, 8);
1335 break;
1336
1337 case 32:
1338 cluster_count = clust32;
1339 fat_length = fatlength32;
1340 bs.fat_length = CT_LE_W(0);
1341 bs.fat32.fat32_length = CT_LE_L(fatlength32);
1342 memcpy(vi->fs_type, MSDOS_FAT32_SIGN, 8);
1343 break;
1344
1345 default:
1346 die("FAT not 12, 16 or 32 bits");
1347 }
1348 }
1349 else {
1350 unsigned clusters, maxclust;
1351
1352 /* GEMDOS always uses a 12 bit FAT on floppies, and always a 16 bit FAT on
1353 * hard disks. So use 12 bit if the size of the file system suggests that
1354 * this fs is for a floppy disk, if the user hasn't explicitly requested a
1355 * size.
1356 */
1357 if (!size_fat)
1358 size_fat = (num_sectors == 1440 || num_sectors == 2400 ||
1359 num_sectors == 2880 || num_sectors == 5760) ? 12 : 16;
1360 if (verbose >= 2)
1361 printf( "Choosing %d bits for FAT\n", size_fat );
1362
1363 /* Atari format: cluster size should be 2, except explicitly requested by
1364 * the user, since GEMDOS doesn't like other cluster sizes very much.
1365 * Instead, tune the sector size for the FS to fit.
1366 */
1367 bs.cluster_size = sectors_per_cluster ? sectors_per_cluster : 2;
1368 if (!sector_size_set) {
1369 while( num_sectors > GEMDOS_MAX_SECTORS ) {
1370 num_sectors >>= 1;
1371 sector_size <<= 1;
1372 }
1373 }
1374 if (verbose >= 2)
1375 printf( "Sector size must be %d to have less than %d log. sectors\n",
1377
1378 /* Check if there are enough FAT indices for how much clusters we have */
1379 do {
1380 fatdata = num_sectors - cdiv (root_dir_entries * 32, sector_size) -
1382 /* The factor 2 below avoids cut-off errors for nr_fats == 1 and
1383 * size_fat == 12
1384 * The "2*nr_fats*size_fat/8" is for the reserved first two FAT entries
1385 */
1386 clusters = (2*((ll_t)fatdata*sector_size - 2*nr_fats*size_fat/8)) /
1387 (2*((int)bs.cluster_size*sector_size + nr_fats*size_fat/8));
1388 fat_length = cdiv( (clusters+2)*size_fat/8, sector_size );
1389 /* Need to recalculate number of clusters, since the unused parts of the
1390 * FATS and data area together could make up space for an additional,
1391 * not really present cluster. */
1392 clusters = (fatdata - nr_fats*fat_length)/bs.cluster_size;
1393 maxclust = (fat_length*sector_size*8)/size_fat;
1394 if (verbose >= 2)
1395 printf( "ss=%d: #clu=%d, fat_len=%d, maxclu=%d\n",
1396 sector_size, clusters, fat_length, maxclust );
1397
1398 /* last 10 cluster numbers are special (except FAT32: 4 high bits rsvd);
1399 * first two numbers are reserved */
1400 if (maxclust <= (size_fat == 32 ? MAX_CLUST_32 : (1<<size_fat)-0x10) &&
1401 clusters <= maxclust-2)
1402 break;
1403 if (verbose >= 2)
1404 printf( clusters > maxclust-2 ?
1405 "Too many clusters\n" : "FAT too big\n" );
1406
1407 /* need to increment sector_size once more to */
1408 if (sector_size_set)
1409 die( "With this sector size, the maximum number of FAT entries "
1410 "would be exceeded." );
1411 num_sectors >>= 1;
1412 sector_size <<= 1;
1413 } while( sector_size <= GEMDOS_MAX_SECTOR_SIZE );
1414
1416 die( "Would need a sector size > 16k, which GEMDOS can't work with");
1417
1418 cluster_count = clusters;
1419 if (size_fat != 32)
1420 bs.fat_length = CT_LE_W(fat_length);
1421 else {
1422 bs.fat_length = 0;
1423 bs.fat32.fat32_length = CT_LE_L(fat_length);
1424 }
1425 }
1426
1427 bs.sector_size[0] = (char) (sector_size & 0x00ff);
1428 bs.sector_size[1] = (char) ((sector_size & 0xff00) >> 8);
1429
1430 if (size_fat == 32)
1431 {
1432 /* set up additional FAT32 fields */
1433 bs.fat32.flags = CT_LE_W(0);
1434 bs.fat32.version[0] = 0;
1435 bs.fat32.version[1] = 0;
1436 bs.fat32.root_cluster = CT_LE_L(2);
1437 bs.fat32.info_sector = CT_LE_W(1);
1438 if (!backup_boot)
1439 backup_boot = (reserved_sectors >= 7) ? 6 :
1440 (reserved_sectors >= 2) ? reserved_sectors-1 : 0;
1441 else
1442 {
1443 if (backup_boot == 1)
1444 die("Backup boot sector must be after sector 1");
1445 else if (backup_boot >= reserved_sectors)
1446 die("Backup boot sector must be a reserved sector");
1447 }
1448 if (verbose >= 2)
1449 printf( "Using sector %d as backup boot sector (0 = none)\n",
1450 backup_boot );
1451 bs.fat32.backup_boot = CT_LE_W(backup_boot);
1452 memset( &bs.fat32.reserved2, 0, sizeof(bs.fat32.reserved2) );
1453 }
1454
1455 if (atari_format) {
1456 /* Just some consistency checks */
1457 if (num_sectors >= GEMDOS_MAX_SECTORS)
1458 die( "GEMDOS can't handle more than 65531 sectors" );
1459 else if (num_sectors >= OLDGEMDOS_MAX_SECTORS)
1460 printf( "Warning: More than 32765 sector need TOS 1.04 "
1461 "or higher.\n" );
1462 }
1463 if (num_sectors >= 65536)
1464 {
1465 bs.sectors[0] = (char) 0;
1466 bs.sectors[1] = (char) 0;
1467 bs.total_sect = CT_LE_L(num_sectors);
1468 }
1469 else
1470 {
1471 bs.sectors[0] = (char) (num_sectors & 0x00ff);
1472 bs.sectors[1] = (char) ((num_sectors & 0xff00) >> 8);
1473 if (!atari_format)
1474 bs.total_sect = CT_LE_L(0);
1475 }
1476
1477 if (!atari_format)
1478 vi->ext_boot_sign = MSDOS_EXT_SIGN;
1479
1480 if (!cluster_count)
1481 {
1482 if (sectors_per_cluster) /* If yes, die if we'd spec'd sectors per cluster */
1483 die ("Too many clusters for file system - try more sectors per cluster");
1484 else
1485 die ("Attempting to create a too large file system");
1486 }
1487
1488
1489 /* The two following vars are in hard sectors, i.e. 512 byte sectors! */
1494
1495 if (blocks < start_data_block + 32) /* Arbitrary undersize file system! */
1496 die ("Too few blocks for viable file system");
1497
1498 if (verbose)
1499 {
1500 printf("%s has %d head%s and %d sector%s per track,\n",
1501 device_name, CF_LE_W(bs.heads), (CF_LE_W(bs.heads) != 1) ? "s" : "",
1502 CF_LE_W(bs.secs_track), (CF_LE_W(bs.secs_track) != 1) ? "s" : "");
1503 printf("logical sector size is %d,\n",sector_size);
1504 printf("using 0x%02x media descriptor, with %d sectors;\n",
1505 (int) (bs.media), num_sectors);
1506 printf("file system has %d %d-bit FAT%s and %d sector%s per cluster.\n",
1507 (int) (bs.fats), size_fat, (bs.fats != 1) ? "s" : "",
1508 (int) (bs.cluster_size), (bs.cluster_size != 1) ? "s" : "");
1509 printf ("FAT size is %d sector%s, and provides %d cluster%s.\n",
1510 fat_length, (fat_length != 1) ? "s" : "",
1511 cluster_count, (cluster_count != 1) ? "s" : "");
1512 if (size_fat != 32)
1513 printf ("Root directory contains %d slots.\n",
1514 (int) (bs.dir_entries[0]) + (int) (bs.dir_entries[1]) * 256);
1515 printf ("Volume ID is %08lx, ", volume_id &
1516 (atari_format ? 0x00ffffff : 0xffffffff));
1517 if ( strcmp(volume_name, " ") )
1518 printf("volume label %s.\n", volume_name);
1519 else
1520 printf("no volume label.\n");
1521 }
1522
1523 /* Make the file allocation tables! */
1524
1525 if ((fat = (unsigned char *) malloc (fat_length * sector_size)) == NULL)
1526 die ("unable to allocate space for FAT image in memory");
1527
1529
1530 mark_FAT_cluster (0, 0xffffffff); /* Initial fat entries */
1531 mark_FAT_cluster (1, 0xffffffff);
1532 fat[0] = (unsigned char) bs.media; /* Put media type in first byte! */
1533 if (size_fat == 32) {
1534 /* Mark cluster 2 as EOF (used for root dir) */
1536 }
1537
1538 /* Make the root directory entries */
1539
1540 size_root_dir = (size_fat == 32) ?
1541 bs.cluster_size*sector_size :
1542 (((int)bs.dir_entries[1]*256+(int)bs.dir_entries[0]) *
1543 sizeof (struct msdos_dir_entry));
1544 if ((root_dir = (struct msdos_dir_entry *) malloc (size_root_dir)) == NULL)
1545 {
1546 free (fat); /* Tidy up before we die! */
1547 die ("unable to allocate space for root directory in memory");
1548 }
1549
1551 if ( memcmp(volume_name, " ", 11) )
1552 {
1553 struct msdos_dir_entry *de = &root_dir[0];
1554 memcpy(de->name, volume_name, 11);
1555 de->attr = ATTR_VOLUME;
1557 de->time = CT_LE_W((unsigned short)((ctime->tm_sec >> 1) +
1558 (ctime->tm_min << 5) + (ctime->tm_hour << 11)));
1559 de->date = CT_LE_W((unsigned short)(ctime->tm_mday +
1560 ((ctime->tm_mon+1) << 5) +
1561 ((ctime->tm_year-80) << 9)));
1562 de->ctime_ms = 0;
1563 de->ctime = de->time;
1564 de->cdate = de->date;
1565 de->adate = de->date;
1566 de->starthi = CT_LE_W(0);
1567 de->start = CT_LE_W(0);
1568 de->size = CT_LE_L(0);
1569 }
1570
1571 if (size_fat == 32) {
1572 /* For FAT32, create an info sector */
1573 struct fat32_fsinfo *info;
1574
1575 if (!(info_sector = malloc( sector_size )))
1576 die("Out of memory");
1578 /* fsinfo structure is at offset 0x1e0 in info sector by observation */
1579 info = (struct fat32_fsinfo *)(info_sector + 0x1e0);
1580
1581 /* Info sector magic */
1582 info_sector[0] = 'R';
1583 info_sector[1] = 'R';
1584 info_sector[2] = 'a';
1585 info_sector[3] = 'A';
1586
1587 /* Magic for fsinfo structure */
1588 info->signature = CT_LE_L(0x61417272);
1589 /* We've allocated cluster 2 for the root dir. */
1590 info->free_clusters = CT_LE_L(cluster_count - 1);
1591 info->next_cluster = CT_LE_L(2);
1592
1593 /* Info sector also must have boot sign */
1594 *(__u16 *)(info_sector + 0x1fe) = CT_LE_W(BOOT_SIGN);
1595 }
1596
1597 if (!(blank_sector = malloc( sector_size )))
1598 die( "Out of memory" );
1600}
1601
1602
1603/* Write the new filesystem's data tables to wherever they're going to end up! */
1604
1605#define error(str) \
1606 do { \
1607 free (fat); \
1608 if (info_sector) free (info_sector); \
1609 free (root_dir); \
1610 die (str); \
1611 } while(0)
1612
1613#define seekto(pos,errstr) \
1614 do { \
1615 loff_t __pos = (pos); \
1616 if (llseek (dev, __pos, SEEK_SET) != __pos) \
1617 error ("seek to " errstr " failed whilst writing tables"); \
1618 } while(0)
1619
1620#define writebuf(buf,size,errstr) \
1621 do { \
1622 int __size = (size); \
1623 if (write (dev, buf, __size) != __size) \
1624 error ("failed whilst writing " errstr); \
1625 } while(0)
1626
1627
1628static void
1630{
1631 int x;
1632 int fat_length;
1633#ifdef _WIN32
1634 int blk;
1635#endif
1636
1637 fat_length = (size_fat == 32) ?
1638 CF_LE_L(bs.fat32.fat32_length) : CF_LE_W(bs.fat_length);
1639
1640 seekto( 0, "start of device" );
1641 /* clear all reserved sectors */
1642 for( x = 0; x < reserved_sectors; ++x )
1643 writebuf( blank_sector, sector_size, "reserved sector" );
1644 /* seek back to sector 0 and write the boot sector */
1645 seekto( 0, "boot sector" );
1646 writebuf( (char *) &bs, sizeof (struct msdos_boot_sector), "boot sector" );
1647 /* on FAT32, write the info sector and backup boot sector */
1648 if (size_fat == 32)
1649 {
1650 seekto( CF_LE_W(bs.fat32.info_sector)*sector_size, "info sector" );
1651 writebuf( info_sector, 512, "info sector" );
1652 if (backup_boot != 0)
1653 {
1654 seekto( backup_boot*sector_size, "backup boot sector" );
1655 writebuf( (char *) &bs, sizeof (struct msdos_boot_sector),
1656 "backup boot sector" );
1657 }
1658 }
1659 /* seek to start of FATS and write them all */
1660 seekto( reserved_sectors*sector_size, "first FAT" );
1661 for (x = 1; x <= nr_fats; x++)
1662#ifdef _WIN32
1663 /*
1664 * WIN32 appearently has problems writing very large chunks directly
1665 * to disk devices. To not produce errors because of resource shortages
1666 * split up the write in sector size chunks.
1667 */
1668 for (blk = 0; blk < fat_length; blk++)
1670#else
1671 writebuf( fat, fat_length * sector_size, "FAT" );
1672#endif
1673 /* Write the root directory directly after the last FAT. This is the root
1674 * dir area on FAT12/16, and the first cluster on FAT32. */
1675 writebuf( (char *) root_dir, size_root_dir, "root directory" );
1676
1678 free (root_dir); /* Free up the root directory space from setup_tables */
1679 free (fat); /* Free up the fat table space reserved during setup_tables */
1680}
1681
1682
1683/* Report the command usage and return a failure error code */
1684
1685void
1686usage (void)
1687{
1688 fatal_error("\
1689Usage: mkdosfs [-A] [-c] [-C] [-v] [-I] [-l bad-block-file] [-b backup-boot-sector]\n\
1690 [-m boot-msg-file] [-n volume-name] [-i volume-id]\n\
1691 [-s sectors-per-cluster] [-S logical-sector-size] [-f number-of-FATs]\n\
1692 [-F fat-size] [-r root-dir-entries] [-R reserved-sectors]\n\
1693 /dev/name [blocks]\n");
1694}
1695
1696/*
1697 * ++roman: On m68k, check if this is an Atari; if yes, turn on Atari variant
1698 * of MS-DOS filesystem by default.
1699 */
1700static void check_atari( void )
1701{
1702#ifdef __mc68000__
1703 FILE *f;
1704 char line[128], *p;
1705
1706 if (!(f = fopen( "/proc/hardware", "r" ))) {
1707 perror( "/proc/hardware" );
1708 return;
1709 }
1710
1711 while( fgets( line, sizeof(line), f ) ) {
1712 if (strncmp( line, "Model:", 6 ) == 0) {
1713 p = line + 6;
1714 p += strspn( p, " \t" );
1715 if (strncmp( p, "Atari ", 6 ) == 0)
1716 atari_format = 1;
1717 break;
1718 }
1719 }
1720 fclose( f );
1721#endif
1722}
1723
1724/* The "main" entry point into the utility - we pick up the options and attempt to process them in some sort of sensible
1725 way. In the event that some/all of the options are invalid we need to tell the user so that something can be done! */
1726
1727int
1728main (int argc, char **argv)
1729{
1730 int c;
1731 char *tmp;
1732 char *listfile = NULL;
1733 FILE *msgfile;
1734#ifdef _WIN32
1735 static char dev_buf[] = "\\\\.\\X:";
1736#else
1737 struct stat statbuf;
1738#endif
1739 int i = 0, pos, ch;
1740 int create = 0;
1741
1742 if (argc && *argv) { /* What's the program name? */
1743 char *p;
1744 program_name = *argv;
1745#ifdef _WIN32
1746 if ((p = strrchr( program_name, '\\' )))
1747#else
1748 if ((p = strrchr( program_name, '/' )))
1749#endif
1750 program_name = p+1;
1751 }
1752
1753 time(&create_time);
1754 volume_id = (long)create_time; /* Default volume ID = creation time */
1755 check_atari();
1756
1757 printf ("%s " VERSION " (" VERSION_DATE ")\n"
1758#ifdef _WIN32
1759 "Win32 port by Jens-Uwe Mager <jum@anubis.han.de>\n"
1760#endif
1761 , program_name);
1762
1763 while ((c = getopt (argc, argv, "AcCf:F:Ii:l:m:n:r:R:s:S:v")) != EOF)
1764 /* Scan the command line for options */
1765 switch (c)
1766 {
1767 case 'A': /* toggle Atari format */
1769 break;
1770
1771 case 'b': /* b : location of backup boot sector */
1772 backup_boot = (int) strtol (optarg, &tmp, 0);
1773 if (*tmp || backup_boot < 2 || backup_boot > 0xffff)
1774 {
1775 printf ("Bad location for backup boot sector : %s\n", optarg);
1776 usage ();
1777 }
1778 break;
1779
1780 case 'c': /* c : Check FS as we build it */
1781 check = TRUE;
1782 break;
1783
1784 case 'C': /* C : Create a new file */
1785 create = TRUE;
1786 break;
1787
1788 case 'f': /* f : Choose number of FATs */
1789 nr_fats = (int) strtol (optarg, &tmp, 0);
1790 if (*tmp || nr_fats < 1 || nr_fats > 4)
1791 {
1792 printf ("Bad number of FATs : %s\n", optarg);
1793 usage ();
1794 }
1795 break;
1796
1797 case 'F': /* F : Choose FAT size */
1798 size_fat = (int) strtol (optarg, &tmp, 0);
1799 if (*tmp || (size_fat != 12 && size_fat != 16 && size_fat != 32))
1800 {
1801 printf ("Bad FAT type : %s\n", optarg);
1802 usage ();
1803 }
1804 size_fat_by_user = 1;
1805 break;
1806
1807 case 'I':
1808 ignore_full_disk = 1;
1809 break;
1810
1811 case 'i': /* i : specify volume ID */
1812 volume_id = strtol(optarg, &tmp, 16);
1813 if ( *tmp )
1814 {
1815 printf("Volume ID must be a hexadecimal number\n");
1816 usage();
1817 }
1818 break;
1819
1820 case 'l': /* l : Bad block filename */
1821 listfile = optarg;
1822 break;
1823
1824 case 'm': /* m : Set boot message */
1825 if ( strcmp(optarg, "-") )
1826 {
1827 msgfile = fopen(optarg, "r");
1828 if ( !msgfile )
1829 perror(optarg);
1830 }
1831 else
1832 msgfile = stdin;
1833
1834 if ( msgfile )
1835 {
1836 /* The boot code ends at offset 448 and needs a null terminator */
1837 i = MESSAGE_OFFSET;
1838 pos = 0; /* We are at beginning of line */
1839 do
1840 {
1841 ch = getc(msgfile);
1842 switch (ch)
1843 {
1844 case '\r': /* Ignore CRs */
1845 case '\0': /* and nulls */
1846 break;
1847
1848 case '\n': /* LF -> CR+LF if necessary */
1849 if ( pos ) /* If not at beginning of line */
1850 {
1851 dummy_boot_code[i++] = '\r';
1852 pos = 0;
1853 }
1854 dummy_boot_code[i++] = '\n';
1855 break;
1856
1857 case '\t': /* Expand tabs */
1858 do
1859 {
1860 dummy_boot_code[i++] = ' ';
1861 pos++;
1862 }
1863 while ( pos % 8 && i < BOOTCODE_SIZE-1 );
1864 break;
1865
1866 case EOF:
1867 dummy_boot_code[i++] = '\0'; /* Null terminator */
1868 break;
1869
1870 default:
1871 dummy_boot_code[i++] = ch; /* Store character */
1872 pos++; /* Advance position */
1873 break;
1874 }
1875 }
1876 while ( ch != EOF && i < BOOTCODE_SIZE-1 );
1877
1878 /* Fill up with zeros */
1879 while( i < BOOTCODE_SIZE-1 )
1880 dummy_boot_code[i++] = '\0';
1881 dummy_boot_code[BOOTCODE_SIZE-1] = '\0'; /* Just in case */
1882
1883 if ( ch != EOF )
1884 printf ("Warning: message too long; truncated\n");
1885
1886 if ( msgfile != stdin )
1887 fclose(msgfile);
1888 }
1889 break;
1890
1891 case 'n': /* n : Volume name */
1892 sprintf(volume_name, "%-11.11s", optarg);
1893 break;
1894
1895 case 'r': /* r : Root directory entries */
1896 root_dir_entries = (int) strtol (optarg, &tmp, 0);
1897 if (*tmp || root_dir_entries < 16 || root_dir_entries > 32768)
1898 {
1899 printf ("Bad number of root directory entries : %s\n", optarg);
1900 usage ();
1901 }
1902 break;
1903
1904 case 'R': /* R : number of reserved sectors */
1905 reserved_sectors = (int) strtol (optarg, &tmp, 0);
1906 if (*tmp || reserved_sectors < 1 || reserved_sectors > 0xffff)
1907 {
1908 printf ("Bad number of reserved sectors : %s\n", optarg);
1909 usage ();
1910 }
1911 break;
1912
1913 case 's': /* s : Sectors per cluster */
1914 sectors_per_cluster = (int) strtol (optarg, &tmp, 0);
1915 if (*tmp || (sectors_per_cluster != 1 && sectors_per_cluster != 2
1918 && sectors_per_cluster != 64 && sectors_per_cluster != 128))
1919 {
1920 printf ("Bad number of sectors per cluster : %s\n", optarg);
1921 usage ();
1922 }
1923 break;
1924
1925 case 'S': /* S : Sector size */
1926 sector_size = (int) strtol (optarg, &tmp, 0);
1927 if (*tmp || (sector_size != 512 && sector_size != 1024 &&
1928 sector_size != 2048 && sector_size != 4096 &&
1929 sector_size != 8192 && sector_size != 16384 &&
1930 sector_size != 32768))
1931 {
1932 printf ("Bad logical sector size : %s\n", optarg);
1933 usage ();
1934 }
1935 sector_size_set = 1;
1936 break;
1937
1938 case 'v': /* v : Verbose execution */
1939 ++verbose;
1940 break;
1941
1942 default:
1943 printf( "Unknown option: %c\n", c );
1944 usage ();
1945 }
1946
1947 if (optind >= argc)
1948 usage();
1949 device_name = argv[optind]; /* Determine the number of blocks in the FS */
1950#ifdef _WIN32
1951 if (device_name[1] == ':' && device_name[2] == '\0') {
1952 dev_buf[4] = device_name[0];
1953 device_name = dev_buf;
1954 is_device = 1;
1955 }
1956#endif
1957 if (!create)
1958 i = count_blocks (device_name); /* Have a look and see! */
1959 if (optind == argc - 2) /* Either check the user specified number */
1960 {
1961 blocks = (int) strtol (argv[optind + 1], &tmp, 0);
1962 if (!create && blocks != i)
1963 {
1964 fprintf (stderr, "Warning: block count mismatch: ");
1965 fprintf (stderr, "found %d but assuming %d.\n",i,blocks);
1966 }
1967 }
1968 else if (optind == argc - 1) /* Or use value found */
1969 {
1970 if (create)
1971 die( "Need intended size with -C." );
1972 blocks = i;
1973 tmp = "";
1974 }
1975 else
1976 usage ();
1977 if (*tmp)
1978 {
1979 printf ("Bad block count : %s\n", argv[optind + 1]);
1980 usage ();
1981 }
1982
1983 if (check && listfile) /* Auto and specified bad block handling are mutually */
1984 die ("-c and -l are incompatible"); /* exclusive of each other! */
1985
1986 if (!create) {
1987 check_mount (device_name); /* Is the device already mounted? */
1988 dev = open (device_name, O_RDWR|O_SHARED); /* Is it a suitable device to build the FS on? */
1989 if (dev < 0)
1990 die ("unable to open %s");
1991#ifdef _WIN32
1992 if (is_device) {
1993 if (fsctl(dev, FSCTL_LOCK_VOLUME) == -1)
1994 die("unable to lock %s");
1995 }
1996#endif
1997 }
1998 else {
2000 char null = 0;
2001 /* create the file */
2003 if (dev < 0)
2004 die("unable to create %s");
2005 /* seek to the intended end-1, and write one byte. this creates a
2006 * sparse-as-possible file of appropriate size. */
2007 if (llseek( dev, offset, SEEK_SET ) != offset)
2008 die( "seek failed" );
2009 if (write( dev, &null, 1 ) < 0)
2010 die( "write failed" );
2011 if (llseek( dev, 0, SEEK_SET ) != 0)
2012 die( "seek failed" );
2013 }
2014
2015#ifdef _WIN32
2016 if (!is_device)
2017 check = 0;
2019#else
2020 if (fstat (dev, &statbuf) < 0)
2021 die ("unable to stat %s");
2022 if (!S_ISBLK (statbuf.st_mode)) {
2023 statbuf.st_rdev = 0;
2024 check = 0;
2025 }
2026 else
2027 /*
2028 * Ignore any 'full' fixed disk devices, if -I is not given.
2029 * On a MO-disk one doesn't need partitions. The filesytem can go
2030 * directly to the whole disk. Under other OSes this is known as
2031 * the 'superfloppy' format. As I don't know how to find out if
2032 * this is a MO disk I introduce a -I (ignore) switch. -Joey
2033 */
2034 if (!ignore_full_disk && (
2035 (statbuf.st_rdev & 0xff3f) == 0x0300 || /* hda, hdb */
2036 (statbuf.st_rdev & 0xff0f) == 0x0800 || /* sd */
2037 (statbuf.st_rdev & 0xff3f) == 0x0d00 || /* xd */
2038 (statbuf.st_rdev & 0xff3f) == 0x1600 ) /* hdc, hdd */
2039 )
2040 die ("Will not try to make filesystem on '%s'");
2041
2042 establish_params (statbuf.st_rdev,statbuf.st_size);
2043 /* Establish the media parameters */
2044#endif
2045
2046 setup_tables (); /* Establish the file system tables */
2047
2048 if (check) /* Determine any bad block locations and mark them */
2049 check_blocks ();
2050 else if (listfile)
2051 get_list_blocks (listfile);
2052
2053 write_tables (); /* Write the file system tables away! */
2054
2055#ifdef _WIN32
2056 if (is_device) {
2057 if (fsctl(dev, FSCTL_DISMOUNT_VOLUME) == -1)
2058 die("unable to dismount %s");
2059 if (fsctl(dev, FSCTL_UNLOCK_VOLUME) == -1)
2060 die("unable to unlock %s");
2061 }
2062#endif
2063 exit (0); /* Terminate with no errors! */
2064}
2065
2066
2067/* That's All Folks */
2068/* Local Variables: */
2069/* tab-width: 8 */
2070/* End: */
static int argc
Definition: ServiceArgs.c:12
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
char * strncpy(char *DstString, const char *SrcString, ACPI_SIZE Count)
Definition: utclib.c:427
char * va_list
Definition: acmsvcex.h:78
#define va_end(ap)
Definition: acmsvcex.h:90
#define va_start(ap, A)
Definition: acmsvcex.h:91
#define va_arg(ap, T)
Definition: acmsvcex.h:89
#define O_WRONLY
Definition: acwin.h:111
#define O_CREAT
Definition: acwin.h:110
#define read
Definition: acwin.h:96
#define O_RDONLY
Definition: acwin.h:108
#define open
Definition: acwin.h:95
#define close
Definition: acwin.h:98
#define fstat
Definition: acwin.h:100
#define write
Definition: acwin.h:97
#define O_TRUNC
Definition: acwin.h:112
#define VERSION
Definition: rdesktop.h:45
int optopt
Definition: getopt.c:48
int getopt(int nargc, char *const *nargv, const char *ostr)
Definition: getopt.c:55
const char * optarg
Definition: getopt.c:49
int optind
Definition: getopt.c:47
int opterr
Definition: getopt.c:46
int null(void)
Definition: ftp.c:1794
#define __int64
Definition: basetyps.h:16
u16 __u16
Definition: btrfs.h:18
u8 __u8
Definition: btrfs.h:17
u32 __u32
Definition: btrfs.h:19
#define IOCTL_DISK_GET_DRIVE_GEOMETRY
Definition: cdrw_usr.h:169
#define NO_ERROR
Definition: dderror.h:5
#define free
Definition: debug_ros.c:5
#define malloc
Definition: debug_ros.c:4
BOOL WINAPI DeviceIoControl(IN HANDLE hDevice, IN DWORD dwIoControlCode, IN LPVOID lpInBuffer OPTIONAL, IN DWORD nInBufferSize OPTIONAL, OUT LPVOID lpOutBuffer OPTIONAL, IN DWORD nOutBufferSize OPTIONAL, OUT LPDWORD lpBytesReturned OPTIONAL, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: deviceio.c:136
#define BLOCK_SIZE
Definition: dlist.c:220
#define NULL
Definition: types.h:112
UINT32 uint
Definition: types.h:83
#define CloseHandle
Definition: compat.h:739
#define OPEN_EXISTING
Definition: compat.h:775
#define ReadFile(a, b, c, d, e)
Definition: compat.h:742
#define SetFilePointer
Definition: compat.h:743
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
#define GENERIC_READ
Definition: compat.h:135
#define FILE_ATTRIBUTE_NORMAL
Definition: compat.h:137
#define FILE_SHARE_READ
Definition: compat.h:136
static const WCHAR version[]
Definition: asmname.c:66
BOOL WINAPI GetFileInformationByHandle(HANDLE hFile, LPBY_HANDLE_FILE_INFORMATION lpFileInformation)
Definition: fileinfo.c:458
BOOL WINAPI SetEndOfFile(HANDLE hFile)
Definition: fileinfo.c:1004
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
unsigned char
Definition: typeof.h:29
#define off_t
Definition: dosfsck.h:5
unsigned __int64 loff_t
Definition: types.h:84
int main()
Definition: test.c:6
unsigned long ulong
Definition: linux.h:275
__kernel_time_t time_t
Definition: linux.h:252
#define S_ISBLK(m)
Definition: ext2fs.h:375
unsigned long DWORD
Definition: ntddk_ex.h:95
#define printf
Definition: freeldr.h:97
uint32_t fat32_length
Definition: fsck.fat.h:17
uint8_t reserved2[12]
Definition: fsck.fat.h:23
uint32_t root_cluster
Definition: fsck.fat.h:20
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
GLsizeiptr size
Definition: glext.h:5919
GLuint res
Definition: glext.h:9613
GLuint buffer
Definition: glext.h:5915
const GLubyte * c
Definition: glext.h:8905
GLfloat f
Definition: glext.h:7540
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLbitfield flags
Definition: glext.h:7161
GLfloat GLfloat p
Definition: glext.h:8902
GLfloat param
Definition: glext.h:5796
GLenum GLsizei len
Definition: glext.h:6722
GLboolean GLboolean GLboolean GLboolean a
Definition: glext.h:6204
GLuint GLenum GLsizei GLsizei GLint GLint GLboolean packed
Definition: glext.h:9271
GLintptr offset
Definition: glext.h:5920
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define O_ACCMODE
Definition: fcntl.h:48
#define O_EXCL
Definition: fcntl.h:40
#define O_RDWR
Definition: fcntl.h:36
#define O_APPEND
Definition: fcntl.h:37
#define stdout
Definition: stdio.h:99
_Check_return_ _CRTIMP int __cdecl getc(_Inout_ FILE *_File)
_CRTIMP void __cdecl perror(_In_opt_z_ const char *_ErrMsg)
#define EOF
Definition: stdio.h:24
#define stderr
Definition: stdio.h:100
_Check_return_ _CRTIMP int __cdecl feof(_In_ FILE *_File)
_Check_return_ _CRTIMP int __cdecl fscanf(_Inout_ FILE *_File, _In_z_ _Scanf_format_string_ const char *_Format,...)
_Check_return_opt_ _CRTIMP int __cdecl fprintf(_Inout_ FILE *_File, _In_z_ _Printf_format_string_ const char *_Format,...)
_Check_return_opt_ _CRTIMP int __cdecl fflush(_Inout_opt_ FILE *_File)
_Check_return_ _CRTIMP FILE *__cdecl fopen(_In_z_ const char *_Filename, _In_z_ const char *_Mode)
#define stdin
Definition: stdio.h:98
_Check_return_opt_ _CRTIMP char *__cdecl fgets(_Out_writes_z_(_MaxCount) char *_Buf, _In_ int _MaxCount, _Inout_ FILE *_File)
_Check_return_opt_ _CRTIMP int __cdecl fclose(_Inout_ FILE *_File)
_Check_return_ long __cdecl strtol(_In_z_ const char *_Str, _Out_opt_ _Deref_post_z_ char **_EndPtr, _In_ int _Radix)
const char * filename
Definition: ioapi.h:137
uint32_t sector
Definition: isohybrid.c:61
#define SEEK_SET
Definition: jmemansi.c:26
#define f
Definition: ke_i.h:83
#define c
Definition: ke_i.h:80
#define b
Definition: ke_i.h:79
LONG WINAPI _llseek(HFILE hFile, LONG lOffset, int iOrigin)
Definition: lfile.c:149
#define lseek
Definition: syshdrs.h:47
if(dx< 0)
Definition: linetemp.h:194
#define blk
Definition: linetest.c:70
double __cdecl trunc(double)
__u8 sector_size[2]
Definition: mkdosfs.c:3
static int nr_fats
Definition: mkdosfs.c:533
#define O_BACKUP
Definition: mkdosfs.c:299
#define MSDOS_FAT16_SIGN
Definition: mkdosfs.c:383
__u16 fat_length
Definition: mkdosfs.c:10
static char volume_name[]
Definition: mkdosfs.c:526
static int verbose
Definition: mkdosfs.c:523
static int size_fat_by_user
Definition: mkdosfs.c:535
#define MESSAGE_OFFSET
Definition: mkdosfs.c:515
static int start_data_block
Definition: mkdosfs.c:541
__u8 volume_id[4]
Definition: mkdosfs.c:3
static unsigned int currently_testing
Definition: mkdosfs.c:538
#define CF_LE_W(v)
Definition: mkdosfs.c:94
#define O_RANDOM
Definition: mkdosfs.c:298
static void setup_tables(void)
Definition: mkdosfs.c:1108
static int sectors_per_cluster
Definition: mkdosfs.c:546
static time_t create_time
Definition: mkdosfs.c:525
static int dev
Definition: mkdosfs.c:536
char dummy_boot_jump[3]
Definition: mkdosfs.c:487
static char * program_name
Definition: mkdosfs.c:519
static void check_atari(void)
Definition: mkdosfs.c:1700
static int count_blocks(char *filename)
Definition: mkdosfs.c:782
#define HARD_SECTOR_SIZE
Definition: mkdosfs.c:339
#define TEST_BUFFER_BLOCKS
Definition: mkdosfs.c:338
#define O_SHARED
Definition: mkdosfs.c:300
#define SECTORS_PER_BLOCK
Definition: mkdosfs.c:340
__u16 ctime
Definition: mkdosfs.c:4
#define CT_LE_L(v)
Definition: mkdosfs.c:98
static int ignore_full_disk
Definition: mkdosfs.c:537
static int reserved_sectors
Definition: mkdosfs.c:531
#define mark_sector_bad(sector)
Definition: mkdosfs.c:352
static void mark_FAT_cluster(int cluster, unsigned int value)
Definition: mkdosfs.c:587
static char * device_name
Definition: mkdosfs.c:520
#define seekto(pos, errstr)
Definition: mkdosfs.c:1613
#define GEMDOS_MAX_SECTORS
Definition: mkdosfs.c:397
#define BOOT_SIGN
Definition: mkdosfs.c:386
static int start_data_sector
Definition: mkdosfs.c:540
static unsigned char * info_sector
Definition: mkdosfs.c:543
#define O_NONE
Definition: mkdosfs.c:302
static int check
Definition: mkdosfs.c:522
#define MAX_CLUST_12
Definition: mkdosfs.c:388
__u8 boot_code[BOOTCODE_SIZE]
Definition: mkdosfs.c:441
#define O_NOINHERIT
Definition: mkdosfs.c:294
#define FAT_EOF
Definition: mkdosfs.c:378
int cdiv(int a, int b)
Definition: mkdosfs.c:357
#define FAT12_THRESHOLD
Definition: mkdosfs.c:394
static long do_check(char *buffer, int try, unsigned int current_block)
Definition: mkdosfs.c:644
static struct msdos_boot_sector bs
Definition: mkdosfs.c:539
#define MSDOS_EXT_SIGN
Definition: mkdosfs.c:381
#define CF_LE_L(v)
Definition: mkdosfs.c:95
static int size_fat
Definition: mkdosfs.c:534
#define die(str)
Definition: mkdosfs.c:347
static _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, loff_t *, res, uint, wh)
static int badblocks
Definition: mkdosfs.c:532
#define MAX_CLUST_16
Definition: mkdosfs.c:389
#define MSDOS_FAT32_SIGN
Definition: mkdosfs.c:384
__u16 time
Definition: mkdosfs.c:8
static void mark_FAT_sector(int sector, unsigned int value)
Definition: mkdosfs.c:628
static struct msdos_dir_entry * root_dir
Definition: mkdosfs.c:544
static void write_tables(void)
Definition: mkdosfs.c:1629
#define MSDOS_FAT12_SIGN
Definition: mkdosfs.c:382
static int atari_format
Definition: mkdosfs.c:521
#define TRUE
Definition: mkdosfs.c:335
#define FALSE
Definition: mkdosfs.c:336
static void get_list_blocks(char *filename)
Definition: mkdosfs.c:736
char dummy_boot_code[BOOTCODE_SIZE]
Definition: mkdosfs.c:491
#define BOOTCODE_FAT32_SIZE
Definition: mkdosfs.c:401
static void check_mount(char *device_name)
Definition: mkdosfs.c:847
char dummy_boot_jump_m68k[2]
Definition: mkdosfs.c:489
#define GEMDOS_MAX_SECTOR_SIZE
Definition: mkdosfs.c:398
static void establish_params(int device_num, int size)
Definition: mkdosfs.c:924
#define MAX_CLUST_32
Definition: mkdosfs.c:392
static int blocks
Definition: mkdosfs.c:527
struct fat32_fsinfo __attribute__
static int backup_boot
Definition: mkdosfs.c:530
#define BOOTCODE_SIZE
Definition: mkdosfs.c:400
long long ll_t
Definition: mkdosfs.c:305
#define CT_LE_W(v)
Definition: mkdosfs.c:97
static void check_blocks(void)
Definition: mkdosfs.c:684
#define writebuf(buf, size, errstr)
Definition: mkdosfs.c:1620
#define ATTR_VOLUME
Definition: mkdosfs.c:369
static int root_dir_entries
Definition: mkdosfs.c:547
static unsigned char * fat
Definition: mkdosfs.c:542
struct msdos_volume_info vi
Definition: mkdosfs.c:440
#define O_SEQUENTIAL
Definition: mkdosfs.c:297
#define OLDGEMDOS_MAX_SECTORS
Definition: mkdosfs.c:396
void usage(void)
Definition: mkdosfs.c:1686
static int sector_size_set
Definition: mkdosfs.c:529
static char * blank_sector
Definition: mkdosfs.c:548
static int valid_offset(int fd, loff_t offset)
Definition: mkdosfs.c:766
#define O_SHORT_LIVED
Definition: mkdosfs.c:296
static void fatal_error(const char *fmt_string) __attribute__((noreturn))
Definition: mkdosfs.c:577
static int size_root_dir
Definition: mkdosfs.c:545
static void alarm_intr(int alnum)
Definition: mkdosfs.c:668
static loff_t llseek(int fd, loff_t offset, int whence)
Definition: mkdosfs.c:321
#define O_TEMPORARY
Definition: mkdosfs.c:295
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define TRUNCATE_EXISTING
Definition: disk.h:71
#define FILE_FLAG_BACKUP_SEMANTICS
Definition: disk.h:41
#define FILE_FLAG_RANDOM_ACCESS
Definition: disk.h:44
#define FILE_FLAG_DELETE_ON_CLOSE
Definition: disk.h:42
#define CREATE_NEW
Definition: disk.h:69
#define OPEN_ALWAYS
Definition: disk.h:70
#define FILE_FLAG_SEQUENTIAL_SCAN
Definition: disk.h:43
#define sprintf(buf, format,...)
Definition: sprintf.c:55
static const struct access_res create[16]
Definition: package.c:7505
#define argv
Definition: mplay32.c:18
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
#define SYNCHRONIZE
Definition: nt_native.h:61
#define FILE_ATTRIBUTE_READONLY
Definition: nt_native.h:702
#define FSCTL_LOCK_VOLUME
Definition: nt_native.h:832
#define FILE_APPEND_DATA
Definition: nt_native.h:634
#define FSCTL_UNLOCK_VOLUME
Definition: nt_native.h:833
#define DELETE
Definition: nt_native.h:57
#define FSCTL_DISMOUNT_VOLUME
Definition: nt_native.h:834
#define GENERIC_WRITE
Definition: nt_native.h:90
#define FILE_ATTRIBUTE_TEMPORARY
Definition: nt_native.h:708
@ F3_1Pt44_512
Definition: ntdddisk.h:373
@ F3_720_512
Definition: ntdddisk.h:376
@ F3_2Pt88_512
Definition: ntdddisk.h:374
#define long
Definition: qsort.c:33
#define err(...)
#define errno
Definition: errno.h:18
_Check_return_ _CRTIMP size_t __cdecl strspn(_In_z_ const char *_Str, _In_z_ const char *_Control)
_CRT_RESTORE_GCC_WARNINGS _CRT_DISABLE_GCC_WARNINGS _Check_return_ _CRTIMP _CONST_RETURN char *__cdecl strrchr(_In_z_ const char *_Str, _In_ int _Ch)
_CRTIMP struct tm *__cdecl localtime(const time_t *_Time)
Definition: time.h:416
#define exit(n)
Definition: config.h:202
int signal
Definition: except.c:84
#define __u64
Definition: types.h:17
#define __u16
Definition: types.h:13
#define __u32
Definition: types.h:15
#define __u8
Definition: types.h:12
static int fd
Definition: io.c:51
#define memset(x, y, z)
Definition: compat.h:39
LARGE_INTEGER Cylinders
Definition: ntdddisk.h:400
ULONG TracksPerCylinder
Definition: ntdddisk.h:402
ULONG SectorsPerTrack
Definition: ntdddisk.h:403
LPVOID lpSecurityDescriptor
Definition: compat.h:193
Definition: inflate.c:139
__u32 next_cluster
Definition: mkdosfs.c:461
__u32 signature
Definition: mkdosfs.c:459
__u32 free_clusters
Definition: mkdosfs.c:460
__u32 reserved1
Definition: mkdosfs.c:458
__u32 reserved2[4]
Definition: mkdosfs.c:463
Definition: parser.c:49
struct msdos_volume_info vi
Definition: mkdosfs.c:437
__u16 fat_length
Definition: mkdosfs.c:430
__u8 sector_size[2]
Definition: mkdosfs.c:423
__u32 total_sect
Definition: mkdosfs.c:434
__u8 dir_entries[2]
Definition: mkdosfs.c:427
__u8 boot_code[BOOTCODE_SIZE]
Definition: mkdosfs.c:438
__u16 secs_track
Definition: mkdosfs.c:431
__u8 system_id[8]
Definition: mkdosfs.c:421
__u8 boot_jump[3]
Definition: mkdosfs.c:420
__u8 sectors[2]
Definition: mkdosfs.c:428
Definition: mkdosfs.c:467
__u16 date
Definition: mkdosfs.c:476
__u16 ctime
Definition: mkdosfs.c:472
__u16 start
Definition: mkdosfs.c:476
__u8 lcase
Definition: mkdosfs.c:470
__u8 attr
Definition: mkdosfs.c:469
__u8 ctime_ms
Definition: mkdosfs.c:471
char name[8]
Definition: mkdosfs.c:468
__u16 time
Definition: mkdosfs.c:476
__u32 size
Definition: mkdosfs.c:477
__u16 starthi
Definition: mkdosfs.c:475
__u16 adate
Definition: mkdosfs.c:474
char ext[3]
Definition: mkdosfs.c:468
__u16 cdate
Definition: mkdosfs.c:473
__u8 volume_label[11]
Definition: mkdosfs.c:414
__u8 volume_id[4]
Definition: mkdosfs.c:413
__u8 fs_type[8]
Definition: mkdosfs.c:415
__u8 ext_boot_sign
Definition: mkdosfs.c:412
Definition: name.c:39
Definition: stat.h:55
unsigned short st_mode
Definition: stat.h:58
_dev_t st_rdev
Definition: stat.h:62
_off_t st_size
Definition: stat.h:63
Definition: time.h:68
LONGLONG QuadPart
Definition: typedefs.h:114
Definition: pdh_main.c:94
int ret
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define DeleteFile
Definition: winbase.h:3789
#define CreateFile
Definition: winbase.h:3774
#define ERROR_BROKEN_PIPE
Definition: winerror.h:183
void int int ULONGLONG int va_list * ap
Definition: winesup.h:36
#define ioctl
Definition: wintirpc.h:60