summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlek Du <alek.du@intel.com>2010-02-08 10:54:31 +0800
committerH. Peter Anvin <hpa@zytor.com>2010-02-10 16:04:14 -0800
commitddd58320f422651a418731d6f8bd75f61df43293 (patch)
treec63f8150ecc665beaa386f9f3eb72023c1ee7d0c
parent7c503d3286ce0b562ef075480029338556b306d7 (diff)
downloadsyslinux-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.asm2
-rw-r--r--core/fs/fat/fat.c194
-rw-r--r--extlinux/fat.h62
-rw-r--r--extlinux/main.c53
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(&regs, 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, &regs, &regs);
+ 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, &regs, &regs);
@@ -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;
}