diff options
author | Alek Du <alek.du@intel.com> | 2010-02-08 10:54:31 +0800 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2010-02-10 16:04:14 -0800 |
commit | ddd58320f422651a418731d6f8bd75f61df43293 (patch) | |
tree | c63f8150ecc665beaa386f9f3eb72023c1ee7d0c | |
parent | 7c503d3286ce0b562ef075480029338556b306d7 (diff) | |
download | syslinux-ddd58320f422651a418731d6f8bd75f61df43293.tar.gz |
pathbased: Add FAT support to extlinux and let FAT be "true" pathbased
Now extlinux can install FAT partition now, and FAT honors patched
path area.
Signed-off-by: Alek Du <alek.du@intel.com>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r-- | core/extlinux.asm | 2 | ||||
-rw-r--r-- | core/fs/fat/fat.c | 194 | ||||
-rw-r--r-- | extlinux/fat.h | 62 | ||||
-rw-r--r-- | extlinux/main.c | 53 |
4 files changed, 207 insertions, 104 deletions
diff --git a/core/extlinux.asm b/core/extlinux.asm index 1ac749bc..95385765 100644 --- a/core/extlinux.asm +++ b/core/extlinux.asm @@ -27,6 +27,8 @@ my_id equ extlinux_id section .rodata alignz 4 ROOT_FS_OPS: + extern vfat_fs_ops + dd vfat_fs_ops extern ext2_fs_ops dd ext2_fs_ops extern btrfs_fs_ops diff --git a/core/fs/fat/fat.c b/core/fs/fat/fat.c index 13cf674d..d723f288 100644 --- a/core/fs/fat/fat.c +++ b/core/fs/fat/fat.c @@ -13,7 +13,7 @@ static struct inode * new_fat_inode(struct fs_info *fs) { struct inode *inode = alloc_inode(fs, 0, sizeof(struct fat_pvt_inode)); if (!inode) - malloc_error("inode structure"); + malloc_error("inode structure"); return inode; } @@ -44,7 +44,7 @@ static uint32_t get_next_cluster(struct fs_info *fs, uint32_t clust_num) int lo, hi; struct cache_struct *cs; uint32_t sector_mask = SECTOR_SIZE(fs) - 1; - + switch(FAT_SB(fs)->fat_type) { case FAT12: offset = clust_num + (clust_num >> 1); @@ -52,8 +52,8 @@ static uint32_t get_next_cluster(struct fs_info *fs, uint32_t clust_num) offset &= sector_mask; cs = get_fat_sector(fs, fat_sector); if (offset == sector_mask) { - /* - * we got the end of the one fat sector, + /* + * we got the end of the one fat sector, * but we have just one byte and we need two, * so store the low part, then read the next fat * sector, read the high part, then combine it. @@ -65,13 +65,13 @@ static uint32_t get_next_cluster(struct fs_info *fs, uint32_t clust_num) } else { next_cluster = *(uint16_t *)(cs->data + offset); } - + if (clust_num & 0x0001) next_cluster >>= 4; /* cluster number is ODD */ else next_cluster &= 0x0fff; /* cluster number is EVEN */ break; - + case FAT16: offset = clust_num << 1; fat_sector = offset >> SECTOR_SHIFT(fs); @@ -79,7 +79,7 @@ static uint32_t get_next_cluster(struct fs_info *fs, uint32_t clust_num) cs = get_fat_sector(fs, fat_sector); next_cluster = *(uint16_t *)(cs->data + offset); break; - + case FAT32: offset = clust_num << 2; fat_sector = offset >> SECTOR_SHIFT(fs); @@ -89,7 +89,7 @@ static uint32_t get_next_cluster(struct fs_info *fs, uint32_t clust_num) next_cluster &= 0x0fffffff; break; } - + return next_cluster; } @@ -101,7 +101,7 @@ static sector_t get_next_sector(struct fs_info* fs, uint32_t sector) sector_t data_sector; uint32_t cluster; int clust_shift = sbi->clust_shift; - + if (sector < data_area) { /* Root directory sector... */ sector++; @@ -109,7 +109,7 @@ static sector_t get_next_sector(struct fs_info* fs, uint32_t sector) sector = 0; /* Ran out of root directory, return EOF */ return sector; } - + data_sector = sector - data_area; if ((data_sector + 1) & sbi->clust_mask) /* Still in the same cluster */ return sector + 1; /* Next sector inside cluster */ @@ -120,7 +120,7 @@ static sector_t get_next_sector(struct fs_info* fs, uint32_t sector) if (cluster >= sbi->clusters) return 0; - + /* return the start of the new cluster */ sector = (cluster << clust_shift) + data_area; return sector; @@ -157,7 +157,7 @@ static sector_t get_the_right_sector(struct file *file) PVT(inode)->offset = sector_pos; PVT(inode)->here = sector; - + return sector; } @@ -184,19 +184,19 @@ static sector_t next_sector(struct file *file) * 64K boundaries. * */ -static void __getfssec(struct fs_info *fs, char *buf, +static void __getfssec(struct fs_info *fs, char *buf, struct file *file, uint32_t sectors) { sector_t curr_sector = get_the_right_sector(file); sector_t frag_start , next_sector; uint32_t con_sec_cnt; struct disk *disk = fs->fs_dev->disk; - + while (sectors) { /* get fragment */ con_sec_cnt = 0; frag_start = curr_sector; - + do { /* get consective sector count */ con_sec_cnt++; @@ -204,14 +204,14 @@ static void __getfssec(struct fs_info *fs, char *buf, next_sector = get_next_sector(fs, curr_sector); curr_sector++; } while (sectors && next_sector == curr_sector); - + PVT(file->inode)->offset += con_sec_cnt; PVT(file->inode)->here = next_sector; - + /* do read */ disk->rdwr_sectors(disk, buf, frag_start, con_sec_cnt, 0); buf += con_sec_cnt << SECTOR_SHIFT(fs);/* adjust buffer pointer */ - + curr_sector = next_sector; } } @@ -219,7 +219,7 @@ static void __getfssec(struct fs_info *fs, char *buf, /** - * get multiple sectors from a file + * get multiple sectors from a file * * @param: buf, the buffer to store the read data * @param: file, the file structure pointer @@ -236,26 +236,26 @@ static uint32_t vfat_getfssec(struct file *file, char *buf, int sectors, uint32_t bytes_left = file->inode->size - file->offset; uint32_t bytes_read = sectors << fs->sector_shift; int sector_left; - + sector_left = (bytes_left + SECTOR_SIZE(fs) - 1) >> fs->sector_shift; if (sectors > sector_left) sectors = sector_left; - + __getfssec(fs, buf, file, sectors); - + if (bytes_read >= bytes_left) { bytes_read = bytes_left; *have_more = 0; } else { *have_more = 1; - } + } file->offset += bytes_read; - + return bytes_read; } /* - * Mangle a filename pointed to by src into a buffer pointed to by dst; + * Mangle a filename pointed to by src into a buffer pointed to by dst; * ends on encountering any whitespace. * */ @@ -264,7 +264,7 @@ static void vfat_mangle_name(char *dst, const char *src) char *p = dst; char c; int i = FILENAME_MAX -1; - + /* * Copy the filename, converting backslash to slash and * collapsing duplicate separators. @@ -272,14 +272,14 @@ static void vfat_mangle_name(char *dst, const char *src) while (not_whitespace(c = *src)) { if (c == '\\') c = '/'; - + if (c == '/') { if (src[1] == '/' || src[1] == '\\') { src++; i--; continue; } - } + } i--; *dst++ = *src++; } @@ -292,7 +292,7 @@ static void vfat_mangle_name(char *dst, const char *src) break; if ((*(dst-1) != '/') && (*(dst-1) != '.')) break; - + dst--; i++; } @@ -306,17 +306,17 @@ static void vfat_mangle_name(char *dst, const char *src) * Mangle a normal style string to DOS style string. */ static void mangle_dos_name(char *mangle_buf, char *src) -{ +{ int i; - unsigned char c; - + unsigned char c; + i = 0; while (i < 11) { c = *src++; - - if ((c <= ' ') || (c == '/')) + + if ((c <= ' ') || (c == '/')) break; - + if (c == '.') { while (i < 8) mangle_buf[i++] = ' '; @@ -327,7 +327,7 @@ static void mangle_dos_name(char *mangle_buf, char *src) c = codepage.upper[c]; if (i == 0 && c == 0xe5) c = 0x05; /* Special hack for the first byte only! */ - + mangle_buf[i++] = c; } while (i < 11) @@ -422,7 +422,7 @@ static uint8_t get_checksum(char *dir_name) { int i; uint8_t sum = 0; - + for (i = 11; i; i--) sum = ((sum & 1) << 7) + (sum >> 1) + *dir_name++; return sum; @@ -436,7 +436,7 @@ static inline sector_t first_sector(struct fs_info *fs, const struct fat_sb_info *sbi = FAT_SB(fs); sector_t first_clust; sector_t sector; - + first_clust = (dir->first_cluster_high << 16) + dir->first_cluster_low; sector = ((first_clust - 2) << sbi->clust_shift) + sbi->data; @@ -451,7 +451,7 @@ static inline int get_inode_mode(uint8_t attr) return I_FILE; } - + static struct inode *vfat_find_entry(char *dname, struct inode *dir) { struct fs_info *fs = dir->fs; @@ -459,7 +459,7 @@ static struct inode *vfat_find_entry(char *dname, struct inode *dir) struct fat_dir_entry *de; struct fat_long_name_entry *long_de; struct cache_struct *cs; - + char mangled_name[12]; uint16_t long_name[260]; /* == 20*13 */ int long_len; @@ -471,7 +471,7 @@ static struct inode *vfat_find_entry(char *dname, struct inode *dir) int entries; int checksum; int long_match = 0; - + slots = (strlen(dname) + 12) / 13; if (slots > 20) return NULL; /* Name too long */ @@ -479,7 +479,7 @@ static struct inode *vfat_find_entry(char *dname, struct inode *dir) slots |= 0x40; vfat_init = vfat_next = slots; long_len = slots*13; - + /* Produce the shortname version, in case we need it. */ mangle_dos_name(mangled_name, dname); @@ -487,11 +487,11 @@ static struct inode *vfat_find_entry(char *dname, struct inode *dir) cs = get_cache_block(fs->fs_dev, dir_sector); de = (struct fat_dir_entry *)cs->data; entries = 1 << (fs->sector_shift - 5); - + while (entries--) { if (de->name[0] == 0) return NULL; - + if (de->attr == 0x0f) { /* * It's a long name entry. @@ -500,7 +500,7 @@ static struct inode *vfat_find_entry(char *dname, struct inode *dir) id = long_de->id; if (id != vfat_next) goto not_match; - + if (id & 0x40) { /* get the initial checksum value */ vfat_csum = long_de->checksum; @@ -513,13 +513,13 @@ static struct inode *vfat_find_entry(char *dname, struct inode *dir) if (long_de->checksum != vfat_csum) goto not_match; } - + vfat_next = --id; - + /* got the long entry name */ copy_long_chunk(long_name + id*13, de); - - /* + + /* * If we got the last entry, check it. * Or, go on with the next entry. */ @@ -532,14 +532,14 @@ static struct inode *vfat_find_entry(char *dname, struct inode *dir) continue; /* Try the next entry */ } else { /* - * It's a short entry + * It's a short entry */ if (de->attr & 0x08) /* ignore volume labels */ goto not_match; - + if (long_match) { - /* - * We already have a VFAT long name match. However, the + /* + * We already have a VFAT long name match. However, the * match is only valid if the checksum matches. */ checksum = get_checksum(de->name); @@ -550,25 +550,25 @@ static struct inode *vfat_find_entry(char *dname, struct inode *dir) goto found; } } - + not_match: vfat_next = vfat_init; long_match = 0; - + de++; } - + /* Try with the next sector */ dir_sector = get_next_sector(fs, dir_sector); } return NULL; /* Nothing found... */ - + found: inode = new_fat_inode(fs); inode->size = de->file_size; PVT(inode)->start = PVT(inode)->here = first_sector(fs, de); inode->mode = get_inode_mode(de->attr); - + return inode; } @@ -576,15 +576,15 @@ static struct inode *vfat_iget_root(struct fs_info *fs) { struct inode *inode = new_fat_inode(fs); int root_size = FAT_SB(fs)->root_size; - - /* + + /* * For FAT32, the only way to get the root directory size is to * follow the entire FAT chain to the end... which seems pointless. */ inode->size = root_size ? root_size << fs->sector_shift : ~0; PVT(inode)->start = PVT(inode)->here = FAT_SB(fs)->root; inode->mode = I_DIR; - + return inode; } @@ -600,9 +600,9 @@ static struct dirent * vfat_readdir(struct file *file) struct fat_dir_entry *de; struct fat_long_name_entry *long_de; struct cache_struct *cs; - + sector_t sector = get_the_right_sector(file); - + uint16_t long_name[261]; /* == 20*13 + 1 (to guarantee null) */ char filename[261]; @@ -612,27 +612,27 @@ static struct dirent * vfat_readdir(struct file *file) int checksum; int long_entry = 0; int sec_off = file->offset & ((1 << fs->sector_shift) - 1); - + cs = get_cache_block(fs->fs_dev, sector); de = (struct fat_dir_entry *)(cs->data + sec_off); entries_left = ((1 << fs->sector_shift) - sec_off) >> 5; vfat_next = vfat_csum = 0xff; - + while (1) { while(entries_left--) { if (de->name[0] == 0) return NULL; if ((uint8_t)de->name[0] == 0xe5) goto invalid; - + if (de->attr == 0x0f) { /* * It's a long name entry. */ long_de = (struct fat_long_name_entry *)de; id = long_de->id; - + if (id & 0x40) { /* init vfat_csum and vfat_init */ vfat_csum = long_de->checksum; @@ -641,7 +641,7 @@ static struct dirent * vfat_readdir(struct file *file) goto invalid; /* Too long! */ vfat_init = id; - + /* ZERO the long_name buffer */ memset(long_name, 0, sizeof long_name); } else { @@ -649,9 +649,9 @@ static struct dirent * vfat_readdir(struct file *file) id != vfat_next) goto invalid; } - + vfat_next = --id; - + /* got the long entry name */ copy_long_chunk(long_name + id*13, de); @@ -661,17 +661,17 @@ static struct dirent * vfat_readdir(struct file *file) if (longlen > 0 && longlen < sizeof(dirent->d_name)) long_entry = 1; } - + de++; file->offset += sizeof(struct fat_dir_entry); continue; /* Try the next entry */ } else { /* - * It's a short entry + * It's a short entry */ if (de->attr & 0x08) /* ignore volume labels */ goto invalid; - + if (long_entry == 1) { /* Got a long entry */ checksum = get_checksum(de->name); @@ -682,7 +682,7 @@ static struct dirent * vfat_readdir(struct file *file) int i; uint8_t c; char *p = filename; - + for (i = 0; i < 8; i++) { c = de->name[i]; if (c == ' ') @@ -703,16 +703,16 @@ static struct dirent * vfat_readdir(struct file *file) } } *p = '\0'; - + goto got; } } - + invalid: de++; file->offset += sizeof(struct fat_dir_entry); } - + /* Try with the next sector */ sector = next_sector(file); if (!sector) @@ -721,7 +721,7 @@ static struct dirent * vfat_readdir(struct file *file) de = (struct fat_dir_entry *)cs->data; entries_left = 1 << (fs->sector_shift - 5); } - + got: if (!(dirent = malloc(sizeof(*dirent)))) { malloc_error("dirent structure in vfat_readdir"); @@ -734,7 +734,7 @@ got: strcpy(dirent->d_name, filename); file->offset += sizeof(*de); /* Update for next reading */ - + return dirent; } @@ -750,12 +750,19 @@ static int vfat_load_config(void) char *p; int i = 0; - /* + /* * we use the ConfigName to pass the config path because * it is under the address 0xffff */ memset(®s, 0, sizeof regs); regs.edi.w[0] = OFFS_WRT(ConfigName, 0); + if (*CurrentDirName) { /* installed by extlinux not syslinux */ + sprintf(ConfigName, "%s/extlinux.conf", CurrentDirName); + call16(core_open, ®s, ®s); + strcpy(ConfigName, "extlinux.conf"); + return regs.eflags.l & EFLAGS_ZF; + } + /* installed by syslinux */ for (; i < 3; i++) { strcpy(ConfigName, syslinux_cfg[i]); call16(core_open, ®s, ®s); @@ -768,15 +775,15 @@ static int vfat_load_config(void) printf("no config file found\n"); return 1; /* no config file */ } - + strcpy(ConfigName, "syslinux.cfg"); strcpy(CurrentDirName, syslinux_cfg[i]); p = strrchr(CurrentDirName, '/'); *(p + 1) = '\0'; /* In case we met '/syslinux.cfg' */ - + return 0; } - + static inline __constfunc uint32_t bsr(uint32_t num) { asm("bsrl %1,%0" : "=r" (num) : "rm" (num)); @@ -792,31 +799,34 @@ static int vfat_fs_init(struct fs_info *fs) int sectors_per_fat; uint32_t clusters; sector_t total_sectors; - + fs->sector_shift = fs->block_shift = disk->sector_shift; fs->sector_size = 1 << fs->sector_shift; fs->block_size = 1 << fs->block_shift; disk->rdwr_sectors(disk, &fat, 0, 1, 0); - + + /* XXX: Find better sanity checks... */ + if (!fat.bxResSectors || !fat.bxFATs) + return -1; sbi = malloc(sizeof(*sbi)); if (!sbi) malloc_error("fat_sb_info structure"); fs->fs_info = sbi; - + sectors_per_fat = fat.bxFATsecs ? : fat.fat32.bxFATsecs_32; total_sectors = fat.bxSectors ? : fat.bsHugeSectors; - - sbi->fat = fat.bxResSectors; + + sbi->fat = fat.bxResSectors; sbi->root = sbi->fat + sectors_per_fat * fat.bxFATs; sbi->root_size = root_dir_size(fs, &fat); sbi->data = sbi->root + sbi->root_size; - + sbi->clust_shift = bsr(fat.bxSecPerClust); sbi->clust_byte_shift = sbi->clust_shift + fs->sector_shift; sbi->clust_mask = fat.bxSecPerClust - 1; sbi->clust_size = fat.bxSecPerClust << fs->sector_shift; - + clusters = (total_sectors - sbi->data) >> sbi->clust_shift; if (clusters <= 0xff4) { sbi->fat_type = FAT12; @@ -838,11 +848,11 @@ static int vfat_fs_init(struct fs_info *fs) + ((fat.fat32.root_cluster-2) << sbi->clust_shift); } sbi->clusters = clusters; - + /* for SYSLINUX, the cache is based on sector size */ return fs->sector_shift; } - + const struct fs_ops vfat_fs_ops = { .fs_name = "vfat", .fs_flags = FS_USEMEM | FS_THISIND, diff --git a/extlinux/fat.h b/extlinux/fat.h new file mode 100644 index 00000000..dd5a362a --- /dev/null +++ b/extlinux/fat.h @@ -0,0 +1,62 @@ +#ifndef _H_FAT_ +#define _H_FAT_ + +#define MSDOS_SUPER_MAGIC 0x4d44 /* MD */ +#if 0 +/* FAT bootsector format, also used by other disk-based derivatives */ +struct boot_sector { + uint8_t bsJump[3]; + char bsOemName[8]; + uint16_t bsBytesPerSec; + uint8_t bsSecPerClust; + uint16_t bsResSectors; + uint8_t bsFATs; + uint16_t bsRootDirEnts; + uint16_t bsSectors; + uint8_t bsMedia; + uint16_t bsFATsecs; + uint16_t bsSecPerTrack; + uint16_t bsHeads; + uint32_t bsHiddenSecs; + uint32_t bsHugeSectors; + + union { + struct { + uint8_t DriveNumber; + uint8_t Reserved1; + uint8_t BootSignature; + uint32_t VolumeID; + char VolumeLabel[11]; + char FileSysType[8]; + uint8_t Code[442]; + } __attribute__ ((packed)) bs16; + struct { + uint32_t FATSz32; + uint16_t ExtFlags; + uint16_t FSVer; + uint32_t RootClus; + uint16_t FSInfo; + uint16_t BkBootSec; + uint8_t Reserved0[12]; + uint8_t DriveNumber; + uint8_t Reserved1; + uint8_t BootSignature; + uint32_t VolumeID; + char VolumeLabel[11]; + char FileSysType[8]; + uint8_t Code[414]; + } __attribute__ ((packed)) bs32; + } __attribute__ ((packed)); + + uint32_t NextSector; /* Pointer to the first unused sector */ + uint16_t MaxTransfer; /* Max sectors per transfer */ + uint16_t bsSignature; +} __attribute__ ((packed)); + +#define bsHead bsJump +#define bsHeadLen offsetof(struct boot_sector, bsOemName) +#define bsCode bs32.Code /* The common safe choice */ +#define bsCodeLen (offsetof(struct boot_sector, bsSignature) - \ + offsetof(struct boot_sector, bsCode)) +#endif +#endif diff --git a/extlinux/main.c b/extlinux/main.c index c28f1907..aed265fe 100644 --- a/extlinux/main.c +++ b/extlinux/main.c @@ -14,7 +14,7 @@ /* * extlinux.c * - * Install the extlinux boot block on an ext2/3/4 and btrfs filesystem + * Install the extlinux boot block on an fat, ext2/3/4 and btrfs filesystem */ #define _GNU_SOURCE /* Enable everything */ @@ -30,6 +30,7 @@ typedef uint64_t u64; #include <mntent.h> #endif #include <stdbool.h> +#include <stddef.h> #include <stdlib.h> #include <string.h> #include <getopt.h> @@ -48,6 +49,7 @@ typedef uint64_t u64; #include "ext2_fs.h" #include "btrfs.h" +#include "fat.h" #include "../version.h" #include "syslxint.h" @@ -58,9 +60,10 @@ typedef uint64_t u64; #endif /* Global option handling */ -/* Global fs_type for handling ext2/3/4 vs btrfs */ +/* Global fs_type for handling fat, ext2/3/4 and btrfs */ #define EXT2 1 #define BTRFS 2 +#define VFAT 3 int fs_type; const char *program; @@ -444,7 +447,7 @@ int patch_file_and_bootblock(int fd, const char *dir, int devfd) nsect = (boot_image_len + SECTOR_SIZE - 1) >> SECTOR_SHIFT; nsect += 2; /* Two sectors for the ADV */ sectp = alloca(sizeof(uint32_t) * nsect); - if (fs_type == EXT2) { + if (fs_type == EXT2 || fs_type == VFAT) { if (sectmap(fd, sectp, nsect)) { perror("bmap"); exit(1); @@ -490,7 +493,7 @@ int patch_file_and_bootblock(int fd, const char *dir, int devfd) } strncpy((char *)boot_image + diroffset, subpath, dirlen); free(dirpath); - + /* write subvol info if we have */ subvoloffset = get_16(&patcharea->subvoloffset); subvollen = get_16(&patcharea->subvollen); @@ -502,7 +505,7 @@ int patch_file_and_bootblock(int fd, const char *dir, int devfd) /* Now produce a checksum */ set_32(&patcharea->checksum, 0); - + csum = LDLINUX_MAGIC; for (i = 0, wp = (uint32_t *) boot_image; i < dw; i++, wp++) csum -= get_32(wp); /* Negative checksum */ @@ -694,6 +697,7 @@ int install_bootblock(int fd, const char *device) { struct ext2_super_block sb; struct btrfs_super_block sb2; + struct boot_sector sb3; bool ok = false; if (fs_type == EXT2) { @@ -711,13 +715,29 @@ int install_bootblock(int fd, const char *device) } if (sb2.magic == *(u64 *)BTRFS_MAGIC) ok = true; + } else if (fs_type == VFAT) { + if (xpread(fd, &sb3, sizeof sb3, 0) != sizeof sb3) { + perror("reading fat superblock"); + return 1; + } + if (sb3.bsResSectors && sb3.bsFATs && + (strstr(sb3.bs16.FileSysType, "FAT") || + strstr(sb3.bs32.FileSysType, "FAT"))) + ok = true; } if (!ok) { - fprintf(stderr, "no ext2/3/4 or btrfs superblock found on %s\n", + fprintf(stderr, "no fat, ext2/3/4 or btrfs superblock found on %s\n", device); return 1; } - if (xpwrite(fd, boot_block, boot_block_len, 0) != boot_block_len) { + if (fs_type == VFAT) { + struct boot_sector *bs = (struct boot_sector *)extlinux_bootsect; + if (xpwrite(fd, &bs->bsHead, bsHeadLen, 0) != bsHeadLen || + xpwrite(fd, &bs->bsCode, bsCodeLen, + offsetof(struct boot_sector, bsCode)) != bsCodeLen) + perror("writing fat bootblock"); + return 1; + } else if (xpwrite(fd, boot_block, boot_block_len, 0) != boot_block_len) { perror("writing bootblock"); return 1; } @@ -725,7 +745,7 @@ int install_bootblock(int fd, const char *device) return 0; } -int ext2_install_file(const char *path, int devfd, struct stat *rst) +int ext2_fat_install_file(const char *path, int devfd, struct stat *rst) { char *file; int fd = -1, dirfd = -1, flags; @@ -751,7 +771,7 @@ int ext2_install_file(const char *path, int devfd, struct stat *rst) perror(file); goto bail; } - } else { + } else if (fs_type == EXT2) { /* If file exist, remove the immutable flag and set u+w mode */ if (!ioctl(fd, EXT2_IOC_GETFLAGS, &flags)) { flags &= ~EXT2_IMMUTABLE_FL; @@ -843,8 +863,8 @@ int btrfs_install_file(const char *path, int devfd, struct stat *rst) int install_file(const char *path, int devfd, struct stat *rst) { - if (fs_type == EXT2) - return ext2_install_file(path, devfd, rst); + if (fs_type == EXT2 || fs_type == VFAT) + return ext2_fat_install_file(path, devfd, rst); else if (fs_type == BTRFS) return btrfs_install_file(path, devfd, rst); return 1; @@ -930,6 +950,13 @@ static const char *find_device(const char *mtab_file, dev_t dev) done = true; break; } + case VFAT: + if ((!strcmp(mnt->mnt_type, "vfat")) && + !stat(mnt->mnt_fsname, &dst) && + dst.st_rdev == dev) { + done = true; + break; + } } if (done) { devname = strdup(mnt->mnt_fsname); @@ -1022,9 +1049,11 @@ static int open_device(const char *path, struct stat *st, const char **_devname) fs_type = EXT2; else if (sfs.f_type == BTRFS_SUPER_MAGIC) fs_type = BTRFS; + else if (sfs.f_type == MSDOS_SUPER_MAGIC) + fs_type = VFAT; if (!fs_type) { - fprintf(stderr, "%s: not an ext2/3/4 or btrfs filesystem: %s\n", + fprintf(stderr, "%s: not a fat, ext2/3/4 or btrfs filesystem: %s\n", program, path); return -1; } |