📄 mkdosfs.c
字号:
/*
Filename: mkdosfs.c
Version: 0.3b (Yggdrasil)
Author: Dave Hudson
Started: 24th August 1994
Last Updated: 7th May 1998
Updated by: Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
Target O/S: Linux (2.x)
Description: Utility to allow an MS-DOS filesystem to be created
under Linux. A lot of the basic structure of this program has been
borrowed from Remy Card's "mke2fs" code.
As far as possible the aim here is to make the "mkdosfs" command
look almost identical to the other Linux filesystem make utilties,
eg bad blocks are still specified as blocks, not sectors, but when
it comes down to it, DOS is tied to the idea of a sector (512 bytes
as a rule), and not the block. For example the boot block does not
occupy a full cluster.
Fixes/additions May 1998 by Roman Hodek
<Roman.Hodek@informatik.uni-erlangen.de>:
- Atari format support
- New options -A, -S, -C
- Support for filesystems > 2GB
- FAT32 support
Port to work under Windows NT/2K/XP Dec 2002 by
Jens-Uwe Mager <jum@anubis.han.de>
Copying: Copyright 1993, 1994 David Hudson (dave@humbug.demon.co.uk)
Portions copyright 1992, 1993 Remy Card (card@masi.ibp.fr)
and 1991 Linus Torvalds (torvalds@klaava.helsinki.fi)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Include the header files */
#include "../version.h"
#ifdef _WIN32
#define _WIN32_WINNT 0x0400
#include <windows.h>
#include <winioctl.h>
#define __LITTLE_ENDIAN 1234
#define __BIG_ENDIAN 4321
#define __BYTE_ORDER __LITTLE_ENDIAN
#define inline
#define __attribute__(x)
#define BLOCK_SIZE 512
#else
#include <linux/hdreg.h>
#include <linux/fs.h>
#include <linux/fd.h>
#include <endian.h>
#include <mntent.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <unistd.h>
#endif
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#if __BYTE_ORDER == __BIG_ENDIAN
#include <asm/byteorder.h>
#ifdef __le16_to_cpu
/* ++roman: 2.1 kernel headers define these function, they're probably more
* efficient then coding the swaps machine-independently. */
#define CF_LE_W __le16_to_cpu
#define CF_LE_L __le32_to_cpu
#define CT_LE_W __cpu_to_le16
#define CT_LE_L __cpu_to_le32
#else
#define CF_LE_W(v) ((((v) & 0xff) << 8) | (((v) >> 8) & 0xff))
#define CF_LE_L(v) (((unsigned)(v)>>24) | (((unsigned)(v)>>8)&0xff00) | \
(((unsigned)(v)<<8)&0xff0000) | ((unsigned)(v)<<24))
#define CT_LE_W(v) CF_LE_W(v)
#define CT_LE_L(v) CF_LE_L(v)
#endif /* defined(__le16_to_cpu) */
#else
#define CF_LE_W(v) (v)
#define CF_LE_L(v) (v)
#define CT_LE_W(v) (v)
#define CT_LE_L(v) (v)
#endif /* __BIG_ENDIAN */
#ifdef _WIN32
typedef unsigned char __u8;
typedef unsigned short __u16;
typedef unsigned int __u32;
typedef unsigned __int64 __u64;
typedef __int64 loff_t;
typedef __int64 ll_t;
extern char *optarg;
extern int optind;
extern int opterr;
extern int optopt;
int getopt(int argc, char *const argv[], const char * optstring);
static int is_device = 0;
#define open WIN32open
#define close WIN32close
#define read WIN32read
#define write WIN32write
#define llseek WIN32llseek
#define O_SHORT_LIVED _O_SHORT_LIVED
#define O_ACCMODE 3
#define O_NONE 3
#define O_BACKUP 0x10000
#define O_SHARED 0x20000
static int WIN32open(const char *path, int oflag, ...)
{
HANDLE fh;
DWORD desiredAccess;
DWORD shareMode;
DWORD creationDisposition;
DWORD flagsAttributes = FILE_ATTRIBUTE_NORMAL;
SECURITY_ATTRIBUTES securityAttributes;
va_list ap;
int pmode;
int trunc = FALSE;
securityAttributes.nLength = sizeof(securityAttributes);
securityAttributes.lpSecurityDescriptor = NULL;
securityAttributes.bInheritHandle = oflag & O_NOINHERIT ? FALSE : TRUE;
switch (oflag & O_ACCMODE) {
case O_RDONLY:
desiredAccess = GENERIC_READ;
shareMode = FILE_SHARE_READ;
break;
case O_WRONLY:
desiredAccess = GENERIC_WRITE;
shareMode = 0;
break;
case O_RDWR:
desiredAccess = GENERIC_READ|GENERIC_WRITE;
shareMode = 0;
break;
case O_NONE:
desiredAccess = 0;
shareMode = FILE_SHARE_READ|FILE_SHARE_WRITE;
}
if (oflag & O_APPEND) {
desiredAccess |= FILE_APPEND_DATA|SYNCHRONIZE;
shareMode = FILE_SHARE_READ|FILE_SHARE_WRITE;
}
if (oflag & O_SHARED)
shareMode |= FILE_SHARE_READ|FILE_SHARE_WRITE;
switch (oflag & (O_CREAT|O_EXCL|O_TRUNC)) {
case 0:
case O_EXCL:
creationDisposition = OPEN_EXISTING;
break;
case O_CREAT:
creationDisposition = OPEN_ALWAYS;
break;
case O_CREAT|O_EXCL:
case O_CREAT|O_TRUNC|O_EXCL:
creationDisposition = CREATE_NEW;
break;
case O_TRUNC:
case O_TRUNC|O_EXCL:
creationDisposition = TRUNCATE_EXISTING;
break;
case O_CREAT|O_TRUNC:
creationDisposition = OPEN_ALWAYS;
trunc = TRUE;
break;
}
if (oflag & O_CREAT) {
va_start(ap, oflag);
pmode = va_arg(ap, int);
va_end(ap);
if ((pmode & 0222) == 0)
flagsAttributes |= FILE_ATTRIBUTE_READONLY;
}
if (oflag & O_TEMPORARY) {
flagsAttributes |= FILE_FLAG_DELETE_ON_CLOSE;
desiredAccess |= DELETE;
}
if (oflag & O_SHORT_LIVED)
flagsAttributes |= FILE_ATTRIBUTE_TEMPORARY;
if (oflag & O_SEQUENTIAL)
flagsAttributes |= FILE_FLAG_SEQUENTIAL_SCAN;
else if (oflag & O_RANDOM)
flagsAttributes |= FILE_FLAG_RANDOM_ACCESS;
if (oflag & O_BACKUP)
flagsAttributes |= FILE_FLAG_BACKUP_SEMANTICS;
if ((fh = CreateFile(path, desiredAccess, shareMode, &securityAttributes,
creationDisposition, flagsAttributes, NULL)) == INVALID_HANDLE_VALUE) {
errno = GetLastError();
return -1;
}
if (trunc) {
if (!SetEndOfFile(fh)) {
errno = GetLastError();
CloseHandle(fh);
DeleteFile(path);
return -1;
}
}
return (int)fh;
}
static int WIN32close(int fd)
{
if (!CloseHandle((HANDLE)fd)) {
errno = GetLastError();
return -1;
}
return 0;
}
static int WIN32read(int fd, void *buf, unsigned int len)
{
DWORD actualLen;
if (!ReadFile((HANDLE)fd, buf, (DWORD)len, &actualLen, NULL)) {
errno = GetLastError();
if (errno == ERROR_BROKEN_PIPE)
return 0;
else
return -1;
}
return (int)actualLen;
}
static int WIN32write(int fd, void *buf, unsigned int len)
{
DWORD actualLen;
if (!WriteFile((HANDLE)fd, buf, (DWORD)len, &actualLen, NULL)) {
errno = GetLastError();
return -1;
}
return (int)actualLen;
}
static loff_t WIN32llseek(int fd, loff_t offset, int whence)
{
long lo, hi;
DWORD err;
lo = offset & 0xffffffff;
hi = offset >> 32;
lo = SetFilePointer((HANDLE)fd, lo, &hi, whence);
if (lo == 0xFFFFFFFF && (err = GetLastError()) != NO_ERROR) {
errno = err;
return -1;
}
return ((loff_t)hi << 32) | (off_t)lo;
}
int fsctl(int fd, int code)
{
DWORD ret;
if (!DeviceIoControl((HANDLE)fd, code, NULL, 0, NULL, 0, &ret, NULL)) {
errno = GetLastError();
return -1;
}
return 0;
}
#else
#define O_NOINHERIT 0
#define O_TEMPORARY 0
#define O_SHORT_LIVED 0
#define O_SEQUENTIAL 0
#define O_RANDOM 0
#define O_BACKUP 0
#define O_SHARED 0
#ifndef O_NONE
# define O_NONE 0
#endif
typedef long long ll_t;
/* Use the _llseek system call directly, because there (once?) was a bug in
* the glibc implementation of it. */
#include <linux/unistd.h>
#if defined(__alpha) || defined(__ia64__)
/* On alpha, the syscall is simply lseek, because it's a 64 bit system. */
static loff_t llseek( int fd, loff_t offset, int whence )
{
return lseek(fd, offset, whence);
}
#else
# ifndef __NR__llseek
# error _llseek system call not present
# endif
static _syscall5( int, _llseek, uint, fd, ulong, hi, ulong, lo,
loff_t *, res, uint, wh );
static loff_t llseek( int fd, loff_t offset, int whence )
{
loff_t actual;
if (_llseek(fd, offset>>32, offset&0xffffffff, &actual, whence) != 0)
return (loff_t)-1;
return actual;
}
#endif
#endif
/* Constant definitions */
#define TRUE 1 /* Boolean constants */
#define FALSE 0
#define TEST_BUFFER_BLOCKS 16
#define HARD_SECTOR_SIZE 512
#define SECTORS_PER_BLOCK ( BLOCK_SIZE / HARD_SECTOR_SIZE )
/* Macro definitions */
/* Report a failure message and return a failure error code */
#define die( str ) fatal_error( "%s: " str "\n" )
/* Mark a cluster in the FAT as bad */
#define mark_sector_bad( sector ) mark_FAT_sector( sector, FAT_BAD )
/* Compute ceil(a/b) */
inline int
cdiv (int a, int b)
{
return (a + b - 1) / b;
}
/* MS-DOS filesystem structures -- I included them here instead of
including linux/msdos_fs.h since that doesn't include some fields we
need */
#define ATTR_RO 1 /* read-only */
#define ATTR_HIDDEN 2 /* hidden */
#define ATTR_SYS 4 /* system */
#define ATTR_VOLUME 8 /* volume label */
#define ATTR_DIR 16 /* directory */
#define ATTR_ARCH 32 /* archived */
#define ATTR_NONE 0 /* no attribute bits */
#define ATTR_UNUSED (ATTR_VOLUME | ATTR_ARCH | ATTR_SYS | ATTR_HIDDEN)
/* attribute bits that are copied "as is" */
/* FAT values */
#define FAT_EOF (atari_format ? 0x0fffffff : 0x0ffffff8)
#define FAT_BAD 0x0ffffff7
#define MSDOS_EXT_SIGN 0x29 /* extended boot sector signature */
#define MSDOS_FAT12_SIGN "FAT12 " /* FAT12 filesystem signature */
#define MSDOS_FAT16_SIGN "FAT16 " /* FAT16 filesystem signature */
#define MSDOS_FAT32_SIGN "FAT32 " /* FAT32 filesystem signature */
#define BOOT_SIGN 0xAA55 /* Boot sector magic number */
#define MAX_CLUST_12 ((1 << 12) - 16)
#define MAX_CLUST_16 ((1 << 16) - 16)
/* M$ says the high 4 bits of a FAT32 FAT entry are reserved and don't belong
* to the cluster number. So the max. cluster# is based on 2^28 */
#define MAX_CLUST_32 ((1 << 28) - 16)
#define FAT12_THRESHOLD 4078
#define OLDGEMDOS_MAX_SECTORS 32765
#define GEMDOS_MAX_SECTORS 65531
#define GEMDOS_MAX_SECTOR_SIZE (16*1024)
#define BOOTCODE_SIZE 448
#define BOOTCODE_FAT32_SIZE 420
/* __attribute__ ((packed)) is used on all structures to make gcc ignore any
* alignments */
#ifdef _WIN32
#pragma pack(push, 1)
#endif
struct msdos_volume_info {
__u8 drive_number; /* BIOS drive number */
__u8 RESERVED; /* Unused */
__u8 ext_boot_sign; /* 0x29 if fields below exist (DOS 3.3+) */
__u8 volume_id[4]; /* Volume ID number */
__u8 volume_label[11];/* Volume label */
__u8 fs_type[8]; /* Typically FAT12 or FAT16 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -