[syslinux:master] Add NTFS filesystem support to Linux and Windows installers

syslinux-bot for Paulo Alcantara pcacjr at gmail.com
Sat Dec 17 21:19:20 PST 2011


Commit-ID:  b0ac906b283b428ba1c7f35fe1e71a84b3d3d9c6
Gitweb:     http://www.syslinux.org/commit/b0ac906b283b428ba1c7f35fe1e71a84b3d3d9c6
Author:     Paulo Alcantara <pcacjr at gmail.com>
AuthorDate: Tue, 5 Jul 2011 21:32:51 +0000
Committer:  Paulo Alcantara <pcacjr at gmail.com>
CommitDate: Wed, 7 Sep 2011 07:19:05 +0000

Add NTFS filesystem support to Linux and Windows installers

Signed-off-by: Paulo Alcantara <pcacjr at gmail.com>

---
 dos/Makefile                                 |    2 +-
 dos/syslinux.c                               |    5 +-
 extlinux/Makefile                            |    2 +-
 extlinux/main.c                              |   59 ++++++++++---
 memdisk/dskprobe.h => extlinux/ntfs.h        |   14 ++--
 libinstaller/{fat.c => fs.c}                 |  120 ++++++++++++++++++--------
 libinstaller/linuxioctl.h                    |    5 +-
 libinstaller/setadv.c                        |    1 +
 libinstaller/syslinux.h                      |    4 +-
 libinstaller/syslxcom.c                      |    6 ++
 libinstaller/syslxcom.h                      |    9 --
 memdisk/dskprobe.h => libinstaller/syslxfs.h |   25 +++--
 libinstaller/syslxint.h                      |   70 ++++++++++++++--
 libinstaller/syslxmod.c                      |    2 +-
 libinstaller/syslxopt.c                      |    1 +
 linux/Makefile                               |    4 +-
 linux/syslinux.c                             |   24 ++++--
 mtools/Makefile                              |    2 +-
 mtools/syslinux.c                            |    5 +-
 win/syslinux.c                               |    9 ++-
 win32/Makefile                               |    2 +-
 win64/Makefile                               |    2 +-
 22 files changed, 261 insertions(+), 112 deletions(-)

diff --git a/dos/Makefile b/dos/Makefile
index 5e5fc63..f942008 100644
--- a/dos/Makefile
+++ b/dos/Makefile
@@ -27,7 +27,7 @@ INCLUDES = -include code16.h -nostdinc -iwithprefix include \
 	   -I. -I.. -I../libfat -I ../libinstaller -I ../libinstaller/getopt
 
 SRCS     = syslinux.c \
-	   ../libinstaller/fat.c \
+	   ../libinstaller/fs.c \
 	   ../libinstaller/syslxmod.c \
 	   ../libinstaller/syslxopt.c \
 	   ../libinstaller/setadv.c \
diff --git a/dos/syslinux.c b/dos/syslinux.c
index b5fdfc5..fa4bf38 100644
--- a/dos/syslinux.c
+++ b/dos/syslinux.c
@@ -31,6 +31,7 @@
 #include "sysexits.h"
 #include "syslxopt.h"
 #include "syslxint.h"
+#include "syslxfs.h"
 
 char *program = "syslinux.com";		/* Name of program */
 uint16_t dos_version;
@@ -638,7 +639,7 @@ int main(int argc, char *argv[])
     /*
      * Check to see that what we got was indeed an MS-DOS boot sector/superblock
      */
-    if ((errmsg = syslinux_check_bootsect(sectbuf))) {
+    if ((errmsg = syslinux_check_bootsect(sectbuf, NULL))) {
 	unlock_device(0);
 	puts(errmsg);
 	putchar('\n');
@@ -749,7 +750,7 @@ int main(int argc, char *argv[])
     read_device(dev_fd, sectbuf, 1, 0);
 
     /* Copy the syslinux code into the boot sector */
-    syslinux_make_bootsect(sectbuf);
+    syslinux_make_bootsect(sectbuf, VFAT);
 
     /* Write new boot sector */
     if (opt.bootsecfile) {
diff --git a/extlinux/Makefile b/extlinux/Makefile
index 12213d8..865c7a6 100644
--- a/extlinux/Makefile
+++ b/extlinux/Makefile
@@ -11,7 +11,7 @@
 ## -----------------------------------------------------------------------
 
 ##
-## Linux vfat, ext2/ext3/ext4 and btrfs installer
+## Linux vfat, ntfs, ext2/ext3/ext4 and btrfs installer
 ##
 
 topdir = ..
diff --git a/extlinux/main.c b/extlinux/main.c
index e574051..d85d03c 100755
--- a/extlinux/main.c
+++ b/extlinux/main.c
@@ -14,7 +14,7 @@
 /*
  * extlinux.c
  *
- * Install the syslinux boot block on an fat, ext2/3/4 and btrfs filesystem
+ * Install the syslinux boot block on an fat, ntfs, ext2/3/4 and btrfs filesystem
  */
 
 #define  _GNU_SOURCE		/* Enable everything */
@@ -45,9 +45,11 @@
 
 #include "btrfs.h"
 #include "fat.h"
+#include "ntfs.h"
 #include "../version.h"
 #include "syslxint.h"
 #include "syslxcom.h" /* common functions shared with extlinux and syslinux */
+#include "syslxfs.h"
 #include "setadv.h"
 #include "syslxopt.h" /* unified options */
 
@@ -214,7 +216,7 @@ int patch_file_and_bootblock(int fd, const char *dir, int devfd)
     sector_t *sectp;
     uint64_t totalbytes, totalsectors;
     int nsect;
-    struct boot_sector *sbs;
+    struct fat_boot_sector *sbs;
     char *dirpath, *subpath, *xdirpath;
     int rv;
 
@@ -271,7 +273,7 @@ int patch_file_and_bootblock(int fd, const char *dir, int devfd)
        early bootstrap share code with the FAT version. */
     dprintf("heads = %u, sect = %u\n", geo.heads, geo.sectors);
 
-    sbs = (struct boot_sector *)syslinux_bootsect;
+    sbs = (struct fat_boot_sector *)syslinux_bootsect;
 
     totalsectors = totalbytes >> SECTOR_SHIFT;
     if (totalsectors >= 65536) {
@@ -292,7 +294,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(sector_t) * nsect);
-    if (fs_type == EXT2 || fs_type == VFAT) {
+    if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS) {
 	if (sectmap(fd, sectp, nsect)) {
 		perror("bmap");
 		exit(1);
@@ -323,7 +325,8 @@ int install_bootblock(int fd, const char *device)
 {
     struct ext2_super_block sb;
     struct btrfs_super_block sb2;
-    struct boot_sector sb3;
+    struct fat_boot_sector sb3;
+    struct ntfs_boot_sector sb4;
     bool ok = false;
 
     if (fs_type == EXT2) {
@@ -348,20 +351,39 @@ int install_bootblock(int fd, const char *device)
 	}
 	if (fat_check_sb_fields(&sb3))
 		ok = true;
+    } else if (fs_type == NTFS) {
+        if (xpread(fd, &sb4, sizeof(sb4), 0) != sizeof(sb4)) {
+            perror("reading ntfs superblock");
+            return 1;
+        }
+
+        if (ntfs_check_sb_fields(&sb4))
+             ok = true;
     }
     if (!ok) {
-	fprintf(stderr, "no fat, ext2/3/4 or btrfs superblock found on %s\n",
+	fprintf(stderr, "no fat, ntfs, ext2/3/4 or btrfs superblock found on %s\n",
 			device);
 	return 1;
     }
     if (fs_type == VFAT) {
-	struct boot_sector *sbs = (struct boot_sector *)syslinux_bootsect;
-        if (xpwrite(fd, &sbs->bsHead, bsHeadLen, 0) != bsHeadLen ||
-	    xpwrite(fd, &sbs->bsCode, bsCodeLen,
-		    offsetof(struct boot_sector, bsCode)) != bsCodeLen) {
+	struct fat_boot_sector *sbs = (struct fat_boot_sector *)syslinux_bootsect;
+        if (xpwrite(fd, &sbs->FAT_bsHead, FAT_bsHeadLen, 0) != FAT_bsHeadLen ||
+	    xpwrite(fd, &sbs->FAT_bsCode, FAT_bsCodeLen,
+		    offsetof(struct fat_boot_sector, FAT_bsCode)) != FAT_bsCodeLen) {
 	    perror("writing fat bootblock");
 	    return 1;
 	}
+    } else if (fs_type == NTFS) {
+        struct ntfs_boot_sector *sbs =
+                (struct ntfs_boot_sector *)syslinux_bootsect;
+        if (xpwrite(fd, &sbs->NTFS_bsHead,
+                    NTFS_bsHeadLen, 0) != NTFS_bsHeadLen ||
+                    xpwrite(fd, &sbs->NTFS_bsCode, NTFS_bsCodeLen,
+                    offsetof(struct ntfs_boot_sector,
+                    NTFS_bsCode)) != NTFS_bsCodeLen) {
+            perror("writing ntfs bootblock");
+            return 1;
+        }
     } else {
 	if (xpwrite(fd, syslinux_bootsect, syslinux_bootsect_len, 0)
 	    != syslinux_bootsect_len) {
@@ -754,7 +776,7 @@ static char * get_default_subvol(char * rootdir, char * subvol)
 
 int install_file(const char *path, int devfd, struct stat *rst)
 {
-	if (fs_type == EXT2 || fs_type == VFAT)
+	if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS)
 		return ext2_fat_install_file(path, devfd, rst);
 	else if (fs_type == BTRFS)
 		return btrfs_install_file(path, devfd, rst);
@@ -828,6 +850,16 @@ static const char *find_device(const char *mtab_file, dev_t dev)
 		    done = true;
 		    break;
 		}
+    case NTFS:
+        if ((!strcmp(mnt->mnt_type, "fuseblk") /* ntfs-3g */ ||
+             !strcmp(mnt->mnt_type, "ntfs")) &&
+            !stat(mnt->mnt_fsname, &dst) &&
+            dst.st_rdev == dev) {
+            done = true;
+            break;
+        }
+
+        break;
 	case NONE:
 	    break;
 	}
@@ -910,9 +942,12 @@ static int open_device(const char *path, struct stat *st, const char **_devname)
 	fs_type = BTRFS;
     else if (sfs.f_type == MSDOS_SUPER_MAGIC)
 	fs_type = VFAT;
+    else if (sfs.f_type == NTFS_SB_MAGIC ||
+                sfs.f_type == FUSE_SUPER_MAGIC /* ntfs-3g */)
+        fs_type = NTFS;
 
     if (!fs_type) {
-	fprintf(stderr, "%s: not a fat, ext2/3/4 or btrfs filesystem: %s\n",
+	fprintf(stderr, "%s: not a fat, ntfs, ext2/3/4 or btrfs filesystem: %s\n",
 		program, path);
 	return -1;
     }
diff --git a/memdisk/dskprobe.h b/extlinux/ntfs.h
similarity index 74%
copy from memdisk/dskprobe.h
copy to extlinux/ntfs.h
index 99bfa66..d907d45 100644
--- a/memdisk/dskprobe.h
+++ b/extlinux/ntfs.h
@@ -1,6 +1,6 @@
 /* ----------------------------------------------------------------------- *
  *
- *   Copyright 2009 Shao Miller - All Rights Reserved
+ *   Copyright 2011 Paulo Alcantara <pcacjr at gmail.com>
  *
  *   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
@@ -10,12 +10,10 @@
  *
  * ----------------------------------------------------------------------- */
 
-/*
- * dskprobe.h
- *
- * Routines for probing BIOS disk drives
- */
+#ifndef _NTFS_H_
+#define _NTFS_H_
 
-#include <stdint.h>
+#define NTFS_SB_MAGIC 0x5346544E
+#define FUSE_SUPER_MAGIC 0x65735546
 
-extern uint8_t probe_drive_range(uint8_t);
+#endif /* _NTFS_H_ */
diff --git a/libinstaller/fat.c b/libinstaller/fs.c
similarity index 52%
rename from libinstaller/fat.c
rename to libinstaller/fs.c
index 9cde00c..179629e 100644
--- a/libinstaller/fat.c
+++ b/libinstaller/fs.c
@@ -1,7 +1,8 @@
 /* ----------------------------------------------------------------------- *
  *
- *   Copyright 1998-2008 H. Peter Anvin - All Rights Reserved
- *   Copyright 2009-2010 Intel Corporation; author H. Peter Anvin
+ *   Copyright 1998-2011 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2009-2011 Intel Corporation; author H. Peter Anvin
+ *   Copyright 2011 Paulo Alcantara <pcacjr at gmail.com>
  *
  *   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
@@ -12,7 +13,7 @@
  * ----------------------------------------------------------------------- */
 
 /*
- * fat.c - Initial sanity check for FAT-based installers
+ * fs.c - Generic sanity check for FAT/NTFS-based installers
  */
 
 #define _XOPEN_SOURCE 500	/* Required on glibc 2.x */
@@ -25,45 +26,41 @@
 
 #include "syslinux.h"
 #include "syslxint.h"
+#include "syslxcom.h"
+#include "syslxfs.h"
 
-void syslinux_make_bootsect(void *bs)
+void syslinux_make_bootsect(void *bs, int fs_type)
 {
-    struct boot_sector *bootsect = bs;
-    const struct boot_sector *sbs =
-	(const struct boot_sector *)boot_sector;
-
-    memcpy(&bootsect->bsHead, &sbs->bsHead, bsHeadLen);
-    memcpy(&bootsect->bsCode, &sbs->bsCode, bsCodeLen);
+    if (fs_type == VFAT) {
+	struct fat_boot_sector *bootsect = bs;
+	const struct fat_boot_sector *sbs =
+	    (const struct fat_boot_sector *)boot_sector;
+
+	memcpy(&bootsect->FAT_bsHead, &sbs->FAT_bsHead, FAT_bsHeadLen);
+	memcpy(&bootsect->FAT_bsCode, &sbs->FAT_bsCode, FAT_bsCodeLen);
+    } else if (fs_type == NTFS) {
+	struct ntfs_boot_sector *bootsect = bs;
+	const struct ntfs_boot_sector *sbs =
+	    (const struct ntfs_boot_sector *)boot_sector;
+
+	memcpy(&bootsect->NTFS_bsHead, &sbs->NTFS_bsHead, NTFS_bsHeadLen);
+	memcpy(&bootsect->NTFS_bsCode, &sbs->NTFS_bsCode, NTFS_bsCodeLen);
+    }
 }
 
-/*
- * Check to see that what we got was indeed an MS-DOS boot sector/superblock;
- * Return NULL if OK and otherwise an error message;
- */
-const char *syslinux_check_bootsect(const void *bs)
+static const char *check_fat_bootsect(const void *bs, int *fs_type)
 {
     int sectorsize;
+    const struct fat_boot_sector *sectbuf = bs;
     long long sectors, fatsectors, dsectors;
     long long clusters;
     int rootdirents, clustersize;
-    const struct boot_sector *sectbuf = bs;
-
-    /* Must be 0xF0 or 0xF8..0xFF */
-    if (get_8(&sectbuf->bsMedia) != 0xF0 && get_8(&sectbuf->bsMedia) < 0xF8)
-	return "invalid media signature (not a FAT filesystem?)";
 
     sectorsize = get_16(&sectbuf->bsBytesPerSec);
-    if (sectorsize == SECTOR_SIZE)
-	;			/* ok */
-    else if (sectorsize >= 512 && sectorsize <= 4096 &&
-	     (sectorsize & (sectorsize - 1)) == 0)
-	return "unsupported sectors size";
-    else
-	return "impossible sector size";
 
     clustersize = get_8(&sectbuf->bsSecPerClust);
     if (clustersize == 0 || (clustersize & (clustersize - 1)))
-	return "impossible cluster size";
+	return "impossible cluster size on an FAT volume";
 
     sectors = get_16(&sectbuf->bsSectors);
     sectors = sectors ? sectors : get_32(&sectbuf->bsHugeSectors);
@@ -79,16 +76,19 @@ const char *syslinux_check_bootsect(const void *bs)
     dsectors -= (rootdirents + sectorsize / 32 - 1) / sectorsize;
 
     if (dsectors < 0)
-	return "negative number of data sectors";
-
-    if (fatsectors == 0)
-	return "zero FAT sectors";
+	return "negative number of data sectors on an FAT volume";
 
     clusters = dsectors / clustersize;
 
+    fatsectors = get_16(&sectbuf->bsFATsecs);
+    fatsectors = fatsectors ? fatsectors : get_32(&sectbuf->bs32.FATSz32);
+    fatsectors *= get_8(&sectbuf->bsFATs);
+
+    if (!fatsectors)
+	return "zero FAT sectors";
+
     if (clusters < 0xFFF5) {
 	/* FAT12 or FAT16 */
-
 	if (!get_16(&sectbuf->bsFATsecs))
 	    return "zero FAT sectors (FAT12/16)";
 
@@ -100,10 +100,10 @@ const char *syslinux_check_bootsect(const void *bs)
 		if (clusters < 0xFF5)
 		    return "less than 4084 clusters but claims FAT16";
 	    } else if (!memcmp(&sectbuf->bs16.FileSysType, "FAT32   ", 8)) {
-		    return "less than 65525 clusters but claims FAT32";
+		return "less than 65525 clusters but claims FAT32";
 	    } else if (memcmp(&sectbuf->bs16.FileSysType, "FAT     ", 8)) {
-		static char fserr[] =
-		    "filesystem type \"????????\" not supported";
+		static char fserr[] = "filesystem type \"????????\" not "
+		    "supported";
 		memcpy(fserr + 17, &sectbuf->bs16.FileSysType, 8);
 		return fserr;
 	    }
@@ -119,8 +119,54 @@ const char *syslinux_check_bootsect(const void *bs)
 	    memcmp(&sectbuf->bs32.FileSysType, "FAT32   ", 8))
 	    return "missing FAT32 signature";
     } else {
-	return "impossibly large number of clusters";
+	return "impossibly large number of clusters on an FAT volume";
     }
 
+    if (fs_type)
+	*fs_type = VFAT;
+
+    return NULL;
+}
+
+static const char *check_ntfs_bootsect(const void *bs, int *fs_type)
+{
+    const struct ntfs_boot_sector *sectbuf = bs;
+
+    if (memcmp(&sectbuf->bsOemName, "NTFS    ", 8) &&
+	memcmp(&sectbuf->bsOemName, "MSWIN4.0", 8) &&
+	memcmp(&sectbuf->bsOemName, "MSWIN4.1", 8))
+	return "unknown OEM name but claims NTFS";
+
+    if (fs_type)
+	*fs_type = NTFS;
+
     return NULL;
 }
+
+const char *syslinux_check_bootsect(const void *bs, int *fs_type)
+{
+    uint8_t media_sig;
+    int sectorsize;
+    const struct fat_boot_sector *sectbuf = bs;
+    const char *retval;
+
+    media_sig = get_8(&sectbuf->bsMedia);
+    /* Must be 0xF0 or 0xF8-0xFF for FAT/NTFS volumes */
+    if (media_sig != 0xF0 && media_sig < 0xF8)
+	return "invalid media signature (not an FAT/NTFS volume?)";
+
+    sectorsize = get_16(&sectbuf->bsBytesPerSec);
+    if (sectorsize == SECTOR_SIZE) ;	/* ok */
+    else if (sectorsize >= 512 && sectorsize <= 4096 &&
+	     (sectorsize & (sectorsize - 1)) == 0)
+	return "unsupported sectors size";
+    else
+	return "impossible sector size";
+
+    if (ntfs_check_zero_fields((struct ntfs_boot_sector *)bs))
+	retval = check_ntfs_bootsect(bs, fs_type);
+    else
+	retval = check_fat_bootsect(bs, fs_type);
+
+    return retval;
+}
diff --git a/libinstaller/linuxioctl.h b/libinstaller/linuxioctl.h
index 7ef919a..c339480 100644
--- a/libinstaller/linuxioctl.h
+++ b/libinstaller/linuxioctl.h
@@ -15,7 +15,6 @@
 #include <linux/hdreg.h>	/* Hard disk geometry */
 
 #include <linux/fs.h>		/* FIGETBSZ, FIBMAP, FS_IOC_FIEMAP */
-#include <linux/msdos_fs.h>	/* FAT_IOCTL_SET_ATTRIBUTES */
 
 #undef SECTOR_SIZE		/* Defined in msdos_fs.h for no good reason */
 #undef SECTOR_BITS
@@ -25,9 +24,7 @@
 # define FAT_IOCTL_GET_ATTRIBUTES	_IOR('r', 0x10, __u32)
 #endif
 
-#ifndef FAT_IOCTL_SET_ATTRIBUTES
-# define FAT_IOCTL_SET_ATTRIBUTES	_IOW('r', 0x11, __u32)
-#endif
+#define FAT_IOCTL_SET_ATTRIBUTES	_IOW('r', 0x11, __u32)
 
 #include <linux/fiemap.h>	/* FIEMAP definitions */
 
diff --git a/libinstaller/setadv.c b/libinstaller/setadv.c
index 9cf6f18..214f7fc 100644
--- a/libinstaller/setadv.c
+++ b/libinstaller/setadv.c
@@ -30,6 +30,7 @@
 #include <errno.h>
 #include "syslxint.h"
 #include "syslxcom.h"
+#include "syslxfs.h"
 
 unsigned char syslinux_adv[2 * ADV_SIZE];
 
diff --git a/libinstaller/syslinux.h b/libinstaller/syslinux.h
index 710d30e..8b86f88 100644
--- a/libinstaller/syslinux.h
+++ b/libinstaller/syslinux.h
@@ -40,10 +40,10 @@ extern const int syslinux_mbr_mtime;
 #define SECTOR_SIZE	(1 << SECTOR_SHIFT)
 
 /* This takes a boot sector and merges in the syslinux fields */
-void syslinux_make_bootsect(void *);
+void syslinux_make_bootsect(void *bs, int fs_type);
 
 /* Check to see that what we got was indeed an MS-DOS boot sector/superblock */
-const char *syslinux_check_bootsect(const void *bs);
+const char *syslinux_check_bootsect(const void *bs, int *fs_type);
 
 /* This patches the boot sector and ldlinux.sys based on a sector map */
 typedef uint64_t sector_t;
diff --git a/libinstaller/syslxcom.c b/libinstaller/syslxcom.c
index 1de85aa..651f982 100644
--- a/libinstaller/syslxcom.c
+++ b/libinstaller/syslxcom.c
@@ -30,8 +30,10 @@
 #include <sys/types.h>
 #include <sys/mount.h>
 #include <sys/vfs.h>
+
 #include "linuxioctl.h"
 #include "syslxcom.h"
+#include "syslxfs.h"
 
 const char *program;
 
@@ -133,6 +135,8 @@ void clear_attributes(int fd)
 	    ioctl(fd, FAT_IOCTL_SET_ATTRIBUTES, &attr);
 	    break;
 	}
+    case NTFS:
+        break;
 	default:
 	    break;
 	}
@@ -163,6 +167,8 @@ void set_attributes(int fd)
 	    ioctl(fd, FAT_IOCTL_SET_ATTRIBUTES, &attr);
 	    break;
 	}
+    case NTFS:
+        break;
 	default:
 	    break;
 	}
diff --git a/libinstaller/syslxcom.h b/libinstaller/syslxcom.h
index bf186ca..8b3b461 100644
--- a/libinstaller/syslxcom.h
+++ b/libinstaller/syslxcom.h
@@ -3,15 +3,6 @@
 
 #include "syslinux.h"
 
-/* Global fs_type for handling fat, ext2/3/4 and btrfs */
-enum filesystem {
-    NONE,
-    EXT2,
-    BTRFS,
-    VFAT,
-};
-
-extern int fs_type;
 extern const char *program;
 ssize_t xpread(int fd, void *buf, size_t count, off_t offset);
 ssize_t xpwrite(int fd, const void *buf, size_t count, off_t offset);
diff --git a/memdisk/dskprobe.h b/libinstaller/syslxfs.h
similarity index 61%
copy from memdisk/dskprobe.h
copy to libinstaller/syslxfs.h
index 99bfa66..7a23146 100644
--- a/memdisk/dskprobe.h
+++ b/libinstaller/syslxfs.h
@@ -1,6 +1,5 @@
-/* ----------------------------------------------------------------------- *
- *
- *   Copyright 2009 Shao Miller - All Rights Reserved
+/*
+ *   Copyright 2011 Paulo Alcantara <pcacjr at gmail.com>
  *
  *   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
@@ -10,12 +9,18 @@
  *
  * ----------------------------------------------------------------------- */
 
-/*
- * dskprobe.h
- *
- * Routines for probing BIOS disk drives
- */
+#ifndef _SYSLXFS_H_
+#define _SYSLXFS_H_
+
+/* Global fs_type for handling fat, ntfs, ext2/3/4 and btrfs */
+enum filesystem {
+    NONE,
+    EXT2,
+    BTRFS,
+    VFAT,
+    NTFS,
+};
 
-#include <stdint.h>
+extern int fs_type;
 
-extern uint8_t probe_drive_range(uint8_t);
+#endif /* _SYSLXFS_H_ */
diff --git a/libinstaller/syslxint.h b/libinstaller/syslxint.h
index 7c9da51..2e317d0 100644
--- a/libinstaller/syslxint.h
+++ b/libinstaller/syslxint.h
@@ -2,6 +2,7 @@
  *
  *   Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
  *   Copyright 2009-2011 Intel Corporation; author: H. Peter Anvin
+ *   Copyright 2011 Paulo Alcantara <pcacjr at gmail.com>
  *
  *   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
@@ -192,7 +193,7 @@ struct syslinux_extent {
 } __attribute__((packed));
 
 /* FAT bootsector format, also used by other disk-based derivatives */
-struct boot_sector {
+struct fat_boot_sector {
     uint8_t bsJump[3];
     char bsOemName[8];
     uint16_t bsBytesPerSec;
@@ -241,13 +242,68 @@ struct boot_sector {
     uint16_t bsSignature;
 } __attribute__ ((packed));
 
-#define bsHead      bsJump
-#define bsHeadLen   offsetof(struct boot_sector, bsBytesPerSec)
-#define bsCode	    bs32.Code	/* The common safe choice */
-#define bsCodeLen   (offsetof(struct boot_sector, bsSignature) - \
-		     offsetof(struct boot_sector, bsCode))
+/* NTFS bootsector format */
+struct ntfs_boot_sector {
+    uint8_t bsJump[3];
+    char bsOemName[8];
+    uint16_t bsBytesPerSec;
+    uint8_t bsSecPerClust;
+    uint16_t bsResSectors;
+    uint8_t bsZeroed_0[3];
+    uint16_t bsZeroed_1;
+    uint8_t bsMedia;
+    uint16_t bsZeroed_2;
+    uint16_t bsUnused_0;
+    uint16_t bsUnused_1;
+    uint32_t bsUnused_2;
+    uint32_t bsZeroed_3;
+    uint32_t bsUnused_3;
+    uint64_t bsTotalSectors;
+    uint64_t bsMFTLogicalClustNr;
+    uint64_t bsMFTMirrLogicalClustNr;
+    uint8_t bsClustPerMFTrecord;
+    uint8_t bsUnused_4[3];
+    uint8_t bsClustPerIdxBuf;
+    uint8_t bsUnused_5[3];
+    uint64_t bsVolSerialNr;
+    uint32_t bsUnused_6;
+
+    uint8_t Code[420];
+
+    uint32_t bsMagic;
+    uint16_t bsForwardPtr;
+    uint16_t bsSignature;
+} __attribute__((packed));
+
+#define FAT_bsHead      bsJump
+#define FAT_bsHeadLen   offsetof(struct fat_boot_sector, bsBytesPerSec)
+#define FAT_bsCode	    bs32.Code	/* The common safe choice */
+#define FAT_bsCodeLen   (offsetof(struct fat_boot_sector, bsSignature) - \
+		     offsetof(struct fat_boot_sector, FAT_bsCode))
+
+#define NTFS_bsHead     bsJump
+#define NTFS_bsHeadLen  offsetof(struct ntfs_boot_sector, bsOemName)
+#define NTFS_bsCode     Code
+#define NTFS_bsCodeLen  (offsetof(struct ntfs_boot_sector, bsSignature) - \
+                            offsetof(struct ntfs_boot_sector, NTFS_bsCode))
+
+/* Check if there are specific zero fields in an NTFS boot sector */
+static inline int ntfs_check_zero_fields(const struct ntfs_boot_sector *sb)
+{
+    return !sb->bsResSectors && (!sb->bsZeroed_0[0] && !sb->bsZeroed_0[1] &&
+            !sb->bsZeroed_0[2]) && !sb->bsZeroed_1 && !sb->bsZeroed_2 &&
+            !sb->bsZeroed_3;
+}
+
+static inline int ntfs_check_sb_fields(const struct ntfs_boot_sector *sb)
+{
+    return ntfs_check_zero_fields(sb) &&
+            (!memcmp(sb->bsOemName, "NTFS    ", 8) ||
+             !memcmp(sb->bsOemName, "MSWIN4.0", 8) ||
+             !memcmp(sb->bsOemName, "MSWIN4.1", 8));
+}
 
-static inline int fat_check_sb_fields(const struct boot_sector *sb)
+static inline int fat_check_sb_fields(const struct fat_boot_sector *sb)
 {
     return sb->bsResSectors && sb->bsFATs &&
             (!memcmp(sb->bs16.FileSysType, "FAT12   ", 8) ||
diff --git a/libinstaller/syslxmod.c b/libinstaller/syslxmod.c
index 8847b73..2436845 100644
--- a/libinstaller/syslxmod.c
+++ b/libinstaller/syslxmod.c
@@ -109,7 +109,7 @@ int syslinux_patch(const sector_t *sectp, int nsectors,
     int nsect = ((boot_image_len + SECTOR_SIZE - 1) >> SECTOR_SHIFT) + 2;
     uint32_t csum;
     int i, dw, nptrs;
-    struct boot_sector *sbs = (struct boot_sector *)boot_sector;
+    struct fat_boot_sector *sbs = (struct fat_boot_sector *)boot_sector;
     uint64_t *advptrs;
 
     if (nsectors < nsect)
diff --git a/libinstaller/syslxopt.c b/libinstaller/syslxopt.c
index 7ceb3ba..e081a00 100644
--- a/libinstaller/syslxopt.c
+++ b/libinstaller/syslxopt.c
@@ -25,6 +25,7 @@
 #include <sysexits.h>
 #include "../version.h"
 #include "syslxcom.h"
+#include "syslxfs.h"
 #include "syslxopt.h"
 
 /* These are the options we can set their values */
diff --git a/linux/Makefile b/linux/Makefile
index 82bf111..08a3ed4 100644
--- a/linux/Makefile
+++ b/linux/Makefile
@@ -11,7 +11,7 @@
 ## -----------------------------------------------------------------------
 
 ##
-## Linux FAT installer
+## Linux FAT/NTFS installer
 ##
 
 topdir = ..
@@ -28,7 +28,7 @@ SRCS     = syslinux.c \
 	   ../libinstaller/syslxcom.c \
 	   ../libinstaller/setadv.c \
 	   ../libinstaller/advio.c \
-           ../libinstaller/fat.c \
+           ../libinstaller/fs.c \
            ../libinstaller/syslxmod.c \
 	   ../libinstaller/bootsect_bin.c \
 	   ../libinstaller/ldlinux_bin.c
diff --git a/linux/syslinux.c b/linux/syslinux.c
index c7a9ecc..4b13b7f 100755
--- a/linux/syslinux.c
+++ b/linux/syslinux.c
@@ -69,6 +69,7 @@
 #include <getopt.h>
 #include <sysexits.h>
 #include "syslxcom.h"
+#include "syslxfs.h"
 #include "setadv.h"
 #include "syslxopt.h" /* unified options */
 
@@ -294,14 +295,14 @@ int main(int argc, char *argv[])
 	die("can't combine an offset with a block device");
     }
 
-    fs_type = VFAT;
     xpread(dev_fd, sectbuf, SECTOR_SIZE, opt.offset);
     fsync(dev_fd);
 
     /*
-     * Check to see that what we got was indeed an MS-DOS boot sector/superblock
+     * Check to see that what we got was indeed an FAT/NTFS
+     * boot sector/superblock
      */
-    if ((errmsg = syslinux_check_bootsect(sectbuf))) {
+    if ((errmsg = syslinux_check_bootsect(sectbuf, &fs_type))) {
 	fprintf(stderr, "%s: %s\n", opt.device, errmsg);
 	exit(1);
     }
@@ -357,10 +358,17 @@ int main(int argc, char *argv[])
 	mntpath = mntname;
     }
 
-    if (do_mount(dev_fd, &mnt_cookie, mntpath, "vfat") &&
-	do_mount(dev_fd, &mnt_cookie, mntpath, "msdos")) {
-	rmdir(mntpath);
-	die("mount failed");
+    if (fs_type == VFAT) {
+        if (do_mount(dev_fd, &mnt_cookie, mntpath, "vfat") &&
+            do_mount(dev_fd, &mnt_cookie, mntpath, "msdos")) {
+            rmdir(mntpath);
+            die("failed on mounting fat volume");
+        }
+    } else if (fs_type == NTFS) {
+        if (do_mount(dev_fd, &mnt_cookie, mntpath, "ntfs-3g")) {
+            rmdir(mntpath);
+            die("failed on mounting ntfs volume");
+        }
     }
 
     ldlinux_path = alloca(strlen(mntpath) + strlen(subdir) + 1);
@@ -474,7 +482,7 @@ umount:
     xpread(dev_fd, sectbuf, SECTOR_SIZE, opt.offset);
 
     /* Copy the syslinux code into the boot sector */
-    syslinux_make_bootsect(sectbuf);
+    syslinux_make_bootsect(sectbuf, fs_type);
 
     /* Write new boot sector */
     xpwrite(dev_fd, sectbuf, SECTOR_SIZE, opt.offset);
diff --git a/mtools/Makefile b/mtools/Makefile
index 3e172fd..78cea1e 100755
--- a/mtools/Makefile
+++ b/mtools/Makefile
@@ -8,7 +8,7 @@ CFLAGS	 = $(GCCWARN) -D_FILE_OFFSET_BITS=64 $(OPTFLAGS) $(INCLUDES)
 LDFLAGS	 = 
 
 SRCS     = syslinux.c \
-	   ../libinstaller/fat.c \
+	   ../libinstaller/fs.c \
 	   ../libinstaller/syslxmod.c \
 	   ../libinstaller/syslxopt.c \
 	   ../libinstaller/setadv.c \
diff --git a/mtools/syslinux.c b/mtools/syslinux.c
index ac189c6..c65021b 100755
--- a/mtools/syslinux.c
+++ b/mtools/syslinux.c
@@ -41,6 +41,7 @@
 #include "libfat.h"
 #include "setadv.h"
 #include "syslxopt.h"
+#include "syslxfs.h"
 
 char *program;			/* Name of program */
 pid_t mypid;
@@ -197,7 +198,7 @@ int main(int argc, char *argv[])
     /*
      * Check to see that what we got was indeed an MS-DOS boot sector/superblock
      */
-    if ((errmsg = syslinux_check_bootsect(sectbuf))) {
+    if ((errmsg = syslinux_check_bootsect(sectbuf, NULL))) {
 	die(errmsg);
     }
 
@@ -356,7 +357,7 @@ int main(int argc, char *argv[])
     xpread(dev_fd, sectbuf, SECTOR_SIZE, opt.offset);
 
     /* Copy the syslinux code into the boot sector */
-    syslinux_make_bootsect(sectbuf);
+    syslinux_make_bootsect(sectbuf, VFAT);
 
     /* Write new boot sector */
     xpwrite(dev_fd, sectbuf, SECTOR_SIZE, opt.offset);
diff --git a/win/syslinux.c b/win/syslinux.c
index 0e833d8..4e4435e 100644
--- a/win/syslinux.c
+++ b/win/syslinux.c
@@ -254,6 +254,7 @@ int main(int argc, char *argv[])
     int ldlinux_sectors;
     uint32_t ldlinux_cluster;
     int nsectors;
+    int fs_type;
 
     if (!checkver()) {
 	fprintf(stderr,
@@ -326,8 +327,10 @@ int main(int argc, char *argv[])
 	exit(1);
     }
 
-    /* Check to see that what we got was indeed an MS-DOS boot sector/superblock */
-    if ((errmsg = syslinux_check_bootsect(sectbuf))) {
+    /* Check to see that what we got was indeed an FAT/NTFS
+     * boot sector/superblock
+     */
+    if ((errmsg = syslinux_check_bootsect(sectbuf, &fs_type))) {
 	fprintf(stderr, "%s\n", errmsg);
 	exit(1);
     }
@@ -472,7 +475,7 @@ int main(int argc, char *argv[])
     }
 
     /* Make the syslinux boot sector */
-    syslinux_make_bootsect(sectbuf);
+    syslinux_make_bootsect(sectbuf, fs_type);
 
     /* Write the syslinux boot sector into the boot sector */
     if (opt.bootsecfile) {
diff --git a/win32/Makefile b/win32/Makefile
index d4133ff..cdb18f2 100644
--- a/win32/Makefile
+++ b/win32/Makefile
@@ -49,7 +49,7 @@ WINCC_IS_GOOD := $(shell $(WINCC) $(WINCFLAGS) $(WINLDFLAGS) \
 
 SRCS     = ../win/syslinux.c
 OBJS     = $(patsubst %.c,%.obj,$(notdir $(SRCS)))
-LIBSRC   = ../libinstaller/fat.c \
+LIBSRC   = ../libinstaller/fs.c \
 	   ../libinstaller/syslxmod.c \
 	   ../libinstaller/syslxopt.c \
 	   ../libinstaller/setadv.c \
diff --git a/win64/Makefile b/win64/Makefile
index 0bc746d..6853fb2 100644
--- a/win64/Makefile
+++ b/win64/Makefile
@@ -39,7 +39,7 @@ WINCC_IS_GOOD := $(shell $(WINCC) $(WINCFLAGS) $(WINLDFLAGS) \
 
 SRCS     = ../win/syslinux.c
 OBJS     = $(patsubst %.c,%.obj,$(notdir $(SRCS)))
-LIBSRC   = ../libinstaller/fat.c \
+LIBSRC   = ../libinstaller/fs.c \
 	   ../libinstaller/syslxmod.c \
 	   ../libinstaller/syslxopt.c \
 	   ../libinstaller/setadv.c \


More information about the Syslinux-commits mailing list