📄 mkdosfs.c
字号:
} __attribute__ ((packed));
struct msdos_boot_sector
{
__u8 boot_jump[3]; /* Boot strap short or near jump */
__u8 system_id[8]; /* Name - can be used to special case
partition manager volumes */
__u8 sector_size[2]; /* bytes per logical sector */
__u8 cluster_size; /* sectors/cluster */
__u16 reserved; /* reserved sectors */
__u8 fats; /* number of FATs */
__u8 dir_entries[2]; /* root directory entries */
__u8 sectors[2]; /* number of sectors */
__u8 media; /* media code (unused) */
__u16 fat_length; /* sectors/FAT */
__u16 secs_track; /* sectors per track */
__u16 heads; /* number of heads */
__u32 hidden; /* hidden sectors (unused) */
__u32 total_sect; /* number of sectors (if sectors == 0) */
union {
struct {
struct msdos_volume_info vi;
__u8 boot_code[BOOTCODE_SIZE];
} __attribute__ ((packed)) _oldfat;
struct {
__u32 fat32_length; /* sectors/FAT */
__u16 flags; /* bit 8: fat mirroring, low 4: active fat */
__u8 version[2]; /* major, minor filesystem version */
__u32 root_cluster; /* first cluster in root directory */
__u16 info_sector; /* filesystem info sector */
__u16 backup_boot; /* backup boot sector */
__u16 reserved2[6]; /* Unused */
struct msdos_volume_info vi;
__u8 boot_code[BOOTCODE_FAT32_SIZE];
} __attribute__ ((packed)) _fat32;
} __attribute__ ((packed)) fstype;
__u16 boot_sign;
} __attribute__ ((packed));
#define fat32 fstype._fat32
#define oldfat fstype._oldfat
struct fat32_fsinfo {
__u32 reserved1; /* Nothing as far as I can tell */
__u32 signature; /* 0x61417272L */
__u32 free_clusters; /* Free cluster count. -1 if unknown */
__u32 next_cluster; /* Most recently allocated cluster.
* Unused under Linux. */
__u32 reserved2[4];
};
struct msdos_dir_entry
{
char name[8], ext[3]; /* name and extension */
__u8 attr; /* attribute bits */
__u8 lcase; /* Case for base and extension */
__u8 ctime_ms; /* Creation time, milliseconds */
__u16 ctime; /* Creation time */
__u16 cdate; /* Creation date */
__u16 adate; /* Last access date */
__u16 starthi; /* high 16 bits of first cl. (FAT32) */
__u16 time, date, start; /* time, date and first cluster */
__u32 size; /* file size (in bytes) */
} __attribute__ ((packed));
#ifdef _WIN32
#pragma pack(pop)
#endif
/* The "boot code" we put into the filesystem... it writes a message and
tells the user to try again */
char dummy_boot_jump[3] = { 0xeb, 0x3c, 0x90 };
char dummy_boot_jump_m68k[2] = { 0x60, 0x1c };
char dummy_boot_code[BOOTCODE_SIZE] =
"\x0e" /* push cs */
"\x1f" /* pop ds */
"\xbe\x5b\x7c" /* mov si, offset message_txt */
/* write_msg: */
"\xac" /* lodsb */
"\x22\xc0" /* and al, al */
"\x74\x0b" /* jz key_press */
"\x56" /* push si */
"\xb4\x0e" /* mov ah, 0eh */
"\xbb\x07\x00" /* mov bx, 0007h */
"\xcd\x10" /* int 10h */
"\x5e" /* pop si */
"\xeb\xf0" /* jmp write_msg */
/* key_press: */
"\x32\xe4" /* xor ah, ah */
"\xcd\x16" /* int 16h */
"\xcd\x19" /* int 19h */
"\xeb\xfe" /* foo: jmp foo */
/* message_txt: */
"This is not a bootable disk. Please insert a bootable floppy and\r\n"
"press any key to try again ... \r\n";
#define MESSAGE_OFFSET 29 /* Offset of message in above code */
/* Global variables - the root of all evil :-) - see these and weep! */
static char *program_name = "mkdosfs"; /* Name of the program */
static char *device_name = NULL; /* Name of the device on which to create the filesystem */
static int atari_format = 0; /* Use Atari variation of MS-DOS FS format */
static int check = FALSE; /* Default to no readablity checking */
static int verbose = 0; /* Default to verbose mode off */
static long volume_id; /* Volume ID number */
static time_t create_time; /* Creation time */
static char volume_name[] = " "; /* Volume name */
static int blocks; /* Number of blocks in filesystem */
static int sector_size = 512; /* Size of a logical sector */
static int sector_size_set = 0; /* User selected sector size */
static int backup_boot = 0; /* Sector# of backup boot sector */
static int reserved_sectors = 0;/* Number of reserved sectors */
static int badblocks = 0; /* Number of bad blocks in the filesystem */
static int nr_fats = 2; /* Default number of FATs to produce */
static int size_fat = 0; /* Size in bits of FAT entries */
static int size_fat_by_user = 0; /* 1 if FAT size user selected */
static int dev = -1; /* FS block device file handle */
static int ignore_full_disk = 0; /* Ignore warning about 'full' disk devices */
static unsigned int currently_testing = 0; /* Block currently being tested (if autodetect bad blocks) */
static struct msdos_boot_sector bs; /* Boot sector data */
static int start_data_sector; /* Sector number for the start of the data area */
static int start_data_block; /* Block number for the start of the data area */
static unsigned char *fat; /* File allocation table */
static unsigned char *info_sector; /* FAT32 info sector */
static struct msdos_dir_entry *root_dir; /* Root directory */
static int size_root_dir; /* Size of the root directory in bytes */
static int sectors_per_cluster = 0; /* Number of sectors per disk cluster */
static int root_dir_entries = 0; /* Number of root directory entries */
static char *blank_sector; /* Blank sector - all zeros */
/* Function prototype definitions */
static void fatal_error (const char *fmt_string) __attribute__((noreturn));
static void mark_FAT_cluster (int cluster, unsigned int value);
static void mark_FAT_sector (int sector, unsigned int value);
static long do_check (char *buffer, int try, unsigned int current_block);
static void alarm_intr (int alnum);
static void check_blocks (void);
static void get_list_blocks (char *filename);
static int valid_offset (int fd, loff_t offset);
static int count_blocks (char *filename);
static void check_mount (char *device_name);
#ifdef _WIN32
static void establish_params (void);
#else
static void establish_params (int device_num, int size);
#endif
static void setup_tables (void);
static void write_tables (void);
/* The function implementations */
/* Handle the reporting of fatal errors. Volatile to let gcc know that this doesn't return */
static void
fatal_error (const char *fmt_string)
{
fprintf (stderr, fmt_string, program_name, device_name);
exit (1); /* The error exit code is 1! */
}
/* Mark the specified cluster as having a particular value */
static void
mark_FAT_cluster (int cluster, unsigned int value)
{
switch( size_fat ) {
case 12:
value &= 0x0fff;
if (((cluster * 3) & 0x1) == 0)
{
fat[3 * cluster / 2] = (unsigned char) (value & 0x00ff);
fat[(3 * cluster / 2) + 1] = (unsigned char) ((fat[(3 * cluster / 2) + 1] & 0x00f0)
| ((value & 0x0f00) >> 8));
}
else
{
fat[3 * cluster / 2] = (unsigned char) ((fat[3 * cluster / 2] & 0x000f) | ((value & 0x000f) << 4));
fat[(3 * cluster / 2) + 1] = (unsigned char) ((value & 0x0ff0) >> 4);
}
break;
case 16:
value &= 0xffff;
fat[2 * cluster] = (unsigned char) (value & 0x00ff);
fat[(2 * cluster) + 1] = (unsigned char) (value >> 8);
break;
case 32:
value &= 0xfffffff;
fat[4 * cluster] = (unsigned char) (value & 0x000000ff);
fat[(4 * cluster) + 1] = (unsigned char) ((value & 0x0000ff00) >> 8);
fat[(4 * cluster) + 2] = (unsigned char) ((value & 0x00ff0000) >> 16);
fat[(4 * cluster) + 3] = (unsigned char) ((value & 0xff000000) >> 24);
break;
default:
die("Bad FAT size (not 12, 16, or 32)");
}
}
/* Mark a specified sector as having a particular value in it's FAT entry */
static void
mark_FAT_sector (int sector, unsigned int value)
{
int cluster;
cluster = (sector - start_data_sector) / (int) (bs.cluster_size) /
(sector_size/HARD_SECTOR_SIZE);
if (cluster < 0)
die ("Invalid cluster number in mark_FAT_sector: probably bug!");
mark_FAT_cluster (cluster, value);
}
/* Perform a test on a block. Return the number of blocks that could be read successfully */
static long
do_check (char *buffer, int try, unsigned int current_block)
{
long got;
if (llseek (dev, (loff_t)current_block * BLOCK_SIZE, SEEK_SET) /* Seek to the correct location */
!= (loff_t)current_block * BLOCK_SIZE)
die ("seek failed during testing for blocks");
got = read (dev, buffer, try * BLOCK_SIZE); /* Try reading! */
if (got < 0)
got = 0;
if (got & (BLOCK_SIZE - 1))
printf ("Unexpected values in do_check: probably bugs\n");
got /= BLOCK_SIZE;
return got;
}
#ifndef _WIN32
/* Alarm clock handler - display the status of the quest for bad blocks! Then retrigger the alarm for five senconds
later (so we can come here again) */
static void
alarm_intr (int alnum)
{
if (currently_testing >= blocks)
return;
signal (SIGALRM, alarm_intr);
alarm (5);
if (!currently_testing)
return;
printf ("%d... ", currently_testing);
fflush (stdout);
}
#endif
static void
check_blocks (void)
{
int try, got;
int i;
static char blkbuf[BLOCK_SIZE * TEST_BUFFER_BLOCKS];
if (verbose)
{
printf ("Searching for bad blocks ");
fflush (stdout);
}
currently_testing = 0;
#ifndef _WIN32
if (verbose)
{
signal (SIGALRM, alarm_intr);
alarm (5);
}
#endif
try = TEST_BUFFER_BLOCKS;
while (currently_testing < blocks)
{
if (currently_testing + try > blocks)
try = blocks - currently_testing;
got = do_check (blkbuf, try, currently_testing);
currently_testing += got;
if (got == try)
{
try = TEST_BUFFER_BLOCKS;
continue;
}
else
try = 1;
if (currently_testing < start_data_block)
die ("bad blocks before data-area: cannot make fs");
for (i = 0; i < SECTORS_PER_BLOCK; i++) /* Mark all of the sectors in the block as bad */
mark_sector_bad (currently_testing * SECTORS_PER_BLOCK + i);
badblocks++;
currently_testing++;
}
if (verbose)
printf ("\n");
if (badblocks)
printf ("%d bad block%s\n", badblocks,
(badblocks > 1) ? "s" : "");
}
static void
get_list_blocks (char *filename)
{
int i;
FILE *listfile;
unsigned long blockno;
listfile = fopen (filename, "r");
if (listfile == (FILE *) NULL)
die ("Can't open file of bad blocks");
while (!feof (listfile))
{
fscanf (listfile, "%ld\n", &blockno);
for (i = 0; i < SECTORS_PER_BLOCK; i++) /* Mark all of the sectors in the block as bad */
mark_sector_bad (blockno * SECTORS_PER_BLOCK + i);
badblocks++;
}
fclose (listfile);
if (badblocks)
printf ("%d bad block%s\n", badblocks,
(badblocks > 1) ? "s" : "");
}
#ifndef _WIN32
/* Given a file descriptor and an offset, check whether the offset is a valid offset for the file - return FALSE if it
isn't valid or TRUE if it is */
static int
valid_offset (int fd, loff_t offset)
{
char ch;
if (llseek (fd, offset, SEEK_SET) < 0)
return FALSE;
if (read (fd, &ch, 1) < 1)
return FALSE;
return TRUE;
}
#endif
/* Given a filename, look to see how many blocks of BLOCK_SIZE are present, returning the answer */
static int
count_blocks (char *filename)
{
#ifdef _WIN32
int fd;
DISK_GEOMETRY geom;
BY_HANDLE_FILE_INFORMATION hinfo;
DWORD ret;
loff_t len = 0;
if ((fd = open(filename, O_RDONLY)) < 0) {
perror(filename);
exit(1);
}
/*
* This should probably use IOCTL_DISK_GET_LENGTH_INFO here, but
* this ioctl is only available in XP and up.
*/
if (is_device) {
if (!DeviceIoControl((HANDLE)fd, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geom, sizeof(geom), &ret, NULL)) {
errno = GetLastError();
die("unable to get length for '%s'");
}
len = geom.Cylinders.QuadPart*geom.TracksPerCylinder*geom.SectorsPerTrack*BLOCK_SIZE;
} else {
if (!GetFileInformationByHandle((HANDLE)fd, &hinfo)) {
errno = GetLastError();
die("unable to get length for '%s'");
}
len = ((loff_t)hinfo.nFileSizeHigh << 32) | (loff_t)hinfo.nFileSizeLow;
}
close(fd);
return len/BLOCK_SIZE;
#else
loff_t high, low;
int fd;
if ((fd = open (filename, O_RDONLY)) < 0)
{
perror (filename);
exit (1);
}
low = 0;
for (high = 1; valid_offset (fd, high); high *= 2)
low = high;
while (low < high - 1)
{
const loff_t mid = (low + high) / 2;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -