[syslinux:pathbased] pathbased: Add FAT support to extlinux and let FAT be "true" pathbased

syslinux-bot for Alek Du alek.du at intel.com
Wed Feb 10 16:06:11 PST 2010


Commit-ID:  ddd58320f422651a418731d6f8bd75f61df43293
Gitweb:     http://syslinux.zytor.com/commit/ddd58320f422651a418731d6f8bd75f61df43293
Author:     Alek Du <alek.du at intel.com>
AuthorDate: Mon, 8 Feb 2010 10:54:31 +0800
Committer:  H. Peter Anvin <hpa at zytor.com>
CommitDate: Wed, 10 Feb 2010 16:04:14 -0800

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 at intel.com>
Signed-off-by: H. Peter Anvin <hpa at zytor.com>


---
 core/extlinux.asm |    2 +
 core/fs/fat/fat.c |  194 ++++++++++++++++++++++++++++-------------------------
 extlinux/fat.h    |   62 +++++++++++++++++
 extlinux/main.c   |   53 +++++++++++---
 4 files changed, 207 insertions(+), 104 deletions(-)

diff --git a/core/extlinux.asm b/core/extlinux.asm
index 1ac749b..9538576 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 13cf674..d723f28 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 0000000..dd5a362
--- /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 c28f190..aed265f 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;
     }



More information about the Syslinux-commits mailing list