示例#1
0
文件: fat_find.c 项目: atiti/minifs
uint32_t
volume_id_read_file(
		struct volume_id *id,
		struct volume_id_file *file,
		int outfd)
{
	struct libfat_filesystem *fs = id->fat;
	libfat_sector_t s = libfat_clustertosector(fs, file->cluster);
	uint32_t size = file->size;

	while (size) {
		if (s == 0)
			return -2; /* Not found */
		else if (s == (libfat_sector_t) -1)
			return -1; /* Error */

		uint8_t * block = libfat_get_sector(fs, s);
		if (!block)
			return -1; /* Read error */
		uint32_t data = size > LIBFAT_SECTOR_SIZE ? LIBFAT_SECTOR_SIZE : size;

	//	printf("Writing %d\n", data);
		write(outfd, block, data);
		size -= data;

		s = libfat_nextsector(fs, s);
	}
	ftruncate(outfd, file->size - size);

	return size;
}
示例#2
0
int32_t libfat_searchdir(struct libfat_filesystem *fs, int32_t dirclust,
			 const void *name, struct libfat_direntry *direntry)
{
    struct fat_dirent *dep;
    int nent;
    libfat_sector_t s = libfat_clustertosector(fs, dirclust);

    while (1) {
	if (s == 0)
	    return -2;		/* Not found */
	else if (s == (libfat_sector_t) - 1)
	    return -1;		/* Error */

	dep = libfat_get_sector(fs, s);
	if (!dep)
	    return -1;		/* Read error */

	for (nent = 0; nent < LIBFAT_SECTOR_SIZE;
	     nent += sizeof(struct fat_dirent)) {
	    if (!memcmp(dep->name, name, 11)) {
		if (direntry) {
		    memcpy(direntry->entry, dep, sizeof(*dep));
		    direntry->sector = s;
		    direntry->offset = nent;
		}
		if (read32(&dep->size) == 0)
		    return 0;	/* An empty file has no clusters */
		else
		    return read16(&dep->clustlo) +
			(read16(&dep->clusthi) << 16);
	    }

	    if (dep->name[0] == 0)
		return -2;	/* Hit high water mark */

	    dep++;
	}

	s = libfat_nextsector(fs, s);
    }
}
示例#3
0
int main(int argc, char *argv[])
{
  static unsigned char sectbuf[512];
  int dev_fd;
  struct stat st;
  int status;
  char **argp, *opt;
  char mtools_conf[] = "/tmp/syslinux-mtools-XXXXXX";
  const char *subdir = NULL;
  int mtc_fd;
  FILE *mtc, *mtp;
  struct libfat_filesystem *fs;
  libfat_sector_t s, *secp, sectors[65]; /* 65 is maximum possible */
  int32_t ldlinux_cluster;
  int nsectors;
  const char *errmsg;

  int force = 0;              /* -f (force) option */
  int stupid = 0;             /* -s (stupid) option */
  int raid_mode = 0;          /* -r (RAID) option */

  (void)argc;			/* Unused */

  mypid = getpid();
  program = argv[0];

  device = NULL;

  for ( argp = argv+1 ; *argp ; argp++ ) {
    if ( **argp == '-' ) {
      opt = *argp + 1;
      if ( !*opt )
	usage();

      while ( *opt ) {
	if ( *opt == 's' ) {
	  stupid = 1;
	} else if ( *opt == 'r' ) {
	  raid_mode = 1;
	} else if ( *opt == 'f' ) {
	  force = 1;		/* Force install */
	} else if ( *opt == 'd' && argp[1] ) {
	  subdir = *++argp;
	} else if ( *opt == 'o' && argp[1] ) {
	  filesystem_offset = (off_t)strtoull(*++argp, NULL, 0); /* Byte offset */
	} else {
	  usage();
	}
	opt++;
      }
    } else {
      if ( device )
	usage();
      device = *argp;
    }
  }

  if ( !device )
    usage();

  /*
   * First make sure we can open the device at all, and that we have
   * read/write permission.
   */
  dev_fd = open(device, O_RDWR);
  if ( dev_fd < 0 || fstat(dev_fd, &st) < 0 ) {
    perror(device);
    exit(1);
  }

  if ( !force && !S_ISBLK(st.st_mode) && !S_ISREG(st.st_mode) ) {
    fprintf(stderr, "%s: not a block device or regular file (use -f to override)\n", device);
    exit(1);
  }

  xpread(dev_fd, sectbuf, 512, filesystem_offset);

  /*
   * Check to see that what we got was indeed an MS-DOS boot sector/superblock
   */
  if( (errmsg = syslinux_check_bootsect(sectbuf)) ) {
    die(errmsg);
  }

  /*
   * Create an mtools configuration file
   */
  mtc_fd = mkstemp(mtools_conf);
  if ( mtc_fd < 0 || !(mtc = fdopen(mtc_fd, "w")) ) {
    perror(program);
    exit(1);
  }
  fprintf(mtc,
	  /* "MTOOLS_NO_VFAT=1\n" */
	  "MTOOLS_SKIP_CHECK=1\n" /* Needed for some flash memories */
	  "drive s:\n"
	  "  file=\"/proc/%lu/fd/%d\"\n"
	  "  offset=%llu\n",
	  (unsigned long)mypid,
	  dev_fd,
	  (unsigned long long)filesystem_offset);
  fclose(mtc);

  /*
   * Run mtools to create the LDLINUX.SYS file
   */
  if ( setenv("MTOOLSRC", mtools_conf, 1) ) {
    perror(program);
    exit(1);
  }

  /* This command may fail legitimately */
  system("mattrib -h -r -s s:/ldlinux.sys 2>/dev/null");

  mtp = popen("mcopy -D o -D O -o - s:/ldlinux.sys", "w");
  if ( !mtp ||
       (fwrite(syslinux_ldlinux, 1, syslinux_ldlinux_len, mtp)
	!= syslinux_ldlinux_len) ||
       (status = pclose(mtp), !WIFEXITED(status) || WEXITSTATUS(status)) ) {
    die("failed to create ldlinux.sys");
  }

  /*
   * Now, use libfat to create a block map
   */
  fs = libfat_open(libfat_xpread, dev_fd);
  ldlinux_cluster = libfat_searchdir(fs, 0, "LDLINUX SYS", NULL);
  secp = sectors;
  nsectors = 0;
  s = libfat_clustertosector(fs, ldlinux_cluster);
  while ( s && nsectors < 65 ) {
    *secp++ = s;
    nsectors++;
    s = libfat_nextsector(fs, s);
  }
  libfat_close(fs);

  /* Patch ldlinux.sys and the boot sector */
  syslinux_patch(sectors, nsectors, stupid, raid_mode);

  /* Write the now-patched first sector of ldlinux.sys */
  xpwrite(dev_fd, syslinux_ldlinux, 512,
	  filesystem_offset + ((off_t)sectors[0] << 9));

  /* Move ldlinux.sys to the desired location */
  if (subdir) {
    char target_file[4096], command[5120];
    char *cp = target_file, *ep = target_file+sizeof target_file-16;
    const char *sd;
    int slash = 1;

    cp += sprintf(cp, "'s:/");
    for (sd = subdir; *sd; sd++) {
      if (*sd == '/' || *sd == '\\') {
	if (slash)
	  continue;		/* Remove duplicated slashes */
	slash = 1;
      } else if (*sd == '\'' || *sd == '!') {
	slash = 0;
	if (cp < ep) *cp++ = '\'';
	if (cp < ep) *cp++ = '\\';
	if (cp < ep) *cp++ = *sd;
	if (cp < ep) *cp++ = '\'';
	continue;
      } else {
	slash = 0;
      }

      if (cp < ep)
	*cp++ = *sd;
    }
    if (!slash)
      *cp++ = '/';
    strcpy(cp, "ldlinux.sys'");

    /* This command may fail legitimately */
    sprintf(command, "mattrib -h -r -s %s 2>/dev/null", target_file);
    system(command);

    sprintf(command, "mmove -D o -D O s:/ldlinux.sys %s", target_file);
    status = system(command);

    if ( !WIFEXITED(status) || WEXITSTATUS(status) ) {
      fprintf(stderr,
	      "%s: warning: unable to move ldlinux.sys\n",
	    program);

      status = system("mattrib +r +h +s s:/ldlinux.sys");
    } else {
      sprintf(command, "mattrib +r +h +s %s", target_file);
      status = system(command);
    }
  } else {
    status = system("mattrib +r +h +s s:/ldlinux.sys");
  }

  if ( !WIFEXITED(status) || WEXITSTATUS(status) ) {
    fprintf(stderr,
	    "%s: warning: failed to set system bit on ldlinux.sys\n",
	    program);
  }


  /*
   * Cleanup
   */
  unlink(mtools_conf);

  /*
   * To finish up, write the boot sector
   */

  /* Read the superblock again since it might have changed while mounted */
  xpread(dev_fd, sectbuf, 512, filesystem_offset);

  /* Copy the syslinux code into the boot sector */
  syslinux_make_bootsect(sectbuf);

  /* Write new boot sector */
  xpwrite(dev_fd, sectbuf, 512, filesystem_offset);

  close(dev_fd);
  sync();

  /* Done! */

  return 0;
}
示例#4
0
文件: fat_find.c 项目: atiti/minifs
int32_t
volume_id_read_dir(
		struct libfat_filesystem *fs,
		int32_t dirclust,
		struct volume_id_dir * dir)
{
	struct fat_dirent *dep;
	int nent;
	libfat_sector_t s = libfat_clustertosector(fs, dirclust);

	struct volume_id_file file;
	memset(&file, 0, sizeof(file));

	while (1) {
		if (s == 0)
			return -2; /* Not found */
		else if (s == (libfat_sector_t) -1)
			return -1; /* Error */

		dep = libfat_get_sector(fs, s);
		if (!dep)
			return -1; /* Read error */

		for (nent = 0; nent < LIBFAT_SECTOR_SIZE; nent
				+= sizeof(struct fat_dirent), dep++) {

			if (dep->name[0] == 0)
				return dir->count; /* Hit high water mark */

			if (dep->name[0] == FAT_ENTRY_FREE)
				continue;

			/* long name */
			if ((dep->attribute & FAT_ATTR_MASK) == FAT_ATTR_LONG_NAME) {
				longname_extract((uint8_t*)dep, file.longname);
				continue;
			}

			if ((dep->attribute & (FAT_ATTR_VOLUME_ID | FAT_ATTR_DIR)) == FAT_ATTR_VOLUME_ID) {
				/* labels do not have file data */
				if (dep->clusthi != 0 || dep->clustlo != 0)
					continue;
				//res = dep->name;
			}

			shortname_extract((uint8_t*)dep, file.name);
			file.entry = *dep;
			file.sector = s;
			file.offset = nent;

			if ((file.size = read32(&dep->size)) == 0)
				file.cluster = 0; /* An empty file has no clusters */
			else
				file.cluster = read16(&dep->clustlo)
						+ (read16(&dep->clusthi) << 16);

			dir->entry = realloc(dir->entry, (dir->count+1) * sizeof(file));
			dir->entry[dir->count++] = file;
			memset(&file, 0, sizeof(file));
		}

		s = libfat_nextsector(fs, s);
	}
	return dir->count;
}
示例#5
0
int main(int argc, char *argv[])
{
    static unsigned char sectbuf[SECTOR_SIZE];
    int dev_fd, fd;
    struct stat st;
    int err = 0;
    char mntname[128];
    char *ldlinux_name;
    char *ldlinux_path;
    char *subdir;
    //sector_t *sectors = NULL;
    libfat_sector_t *sectors = NULL;
    int ldlinux_sectors = (boot_image_len + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
    const char *errmsg;
    int mnt_cookie;
    int patch_sectors;
    int i;
    
    printf("syslinux for Mac OS X; created by Geza Kovacs for UNetbootin unetbootin.sf.net\n");

    mypid = getpid();
    umask(077);
    parse_options(argc, argv, MODE_SYSLINUX);

    /* Note: subdir is guaranteed to start and end in / */
    if (opt.directory && opt.directory[0]) {
	int len = strlen(opt.directory);
	int rv = asprintf(&subdir, "%s%s%s",
			  opt.directory[0] == '/' ? "" : "/",
			  opt.directory,
			  opt.directory[len-1] == '/' ? "" : "/");
	if (rv < 0 || !subdir) {
	    perror(program);
	    exit(1);
	}
    } else {
	subdir = "/";
    }

    if (!opt.device || opt.install_mbr || opt.activate_partition)
	usage(EX_USAGE, MODE_SYSLINUX);

    /*
     * First make sure we can open the device at all, and that we have
     * read/write permission.
     */

    if (geteuid()) {
	die("This program needs root privilege");
    }
    char umountCommand[4096];
    memset(umountCommand, 0, 4096);
    strcat(umountCommand, "hdiutil unmount ");
    strcat(umountCommand, opt.device);
    system(umountCommand);
    
    dev_fd = open(opt.device, O_RDWR);
    if (dev_fd < 0 || fstat(dev_fd, &st) < 0) {
	perror("couldn't open device");
	exit(1);
    }

    if (!S_ISBLK(st.st_mode) && !S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode)) {
	die("not a device or regular file");
    }

    if (opt.offset && S_ISBLK(st.st_mode)) {
	die("can't combine an offset with a block device");
    }

    fs_type = VFAT;
    xpread(dev_fd, sectbuf, SECTOR_SIZE, opt.offset);
    fsync(dev_fd);
    close(dev_fd);

    /*
     * Check to see that what we got was indeed an MS-DOS boot sector/superblock
     */
    if ((errmsg = syslinux_check_bootsect(sectbuf))) {
	fprintf(stderr, "%s: %s\n", opt.device, errmsg);
	exit(1);
    }

    /*
     * Now mount the device.
     */
    if (geteuid()) {
	die("This program needs root privilege");
    }
#if 0
    else {
	int i = 0;
	struct stat dst;
	int rv;

	/* We're root or at least setuid.
	   Make a temp dir and pass all the gunky options to mount. */

	if (chdir(_PATH_TMP)) {
	    fprintf(stderr, "%s: Cannot access the %s directory.\n",
		    program, _PATH_TMP);
	    exit(1);
	}
#define TMP_MODE (S_IXUSR|S_IWUSR|S_IXGRP|S_IWGRP|S_IWOTH|S_IXOTH|S_ISVTX)

	if (stat(".", &dst) || !S_ISDIR(dst.st_mode) ||
	    (dst.st_mode & TMP_MODE) != TMP_MODE) {
	    die("possibly unsafe " _PATH_TMP " permissions");
	}

	for (i = 0;; i++) {
	    snprintf(mntname, sizeof mntname, "syslinux.mnt.%lu.%d",
		     (unsigned long)mypid, i);

	    if (lstat(mntname, &dst) != -1 || errno != ENOENT)
		continue;

	    rv = mkdir(mntname, 0000);

	    if (rv == -1) {
		if (errno == EEXIST || errno == EINTR)
		    continue;
		perror(program);
		exit(1);
	    }

	    if (lstat(mntname, &dst) || dst.st_mode != (S_IFDIR | 0000) ||
		dst.st_uid != 0) {
		die("someone is trying to symlink race us!");
	    }
	    break;		/* OK, got something... */
	}

	mntpath = mntname;
    }

    if (do_mount(dev_fd, &mnt_cookie, mntpath, "vfat") &&
	do_mount(dev_fd, &mnt_cookie, mntpath, "msdos")) {
	rmdir(mntpath);
	die("mount failed");
    }

#endif

    char mountCmd[4096];
    memset(mountCmd, 0, 4096);
    strcat(mountCmd, "hdiutil mount ");
    strcat(mountCmd, opt.device);
    system(mountCmd);
    
    char mountGrepCmd[4096];
    memset(mountGrepCmd, 0, 4096);
    strcat(mountGrepCmd, "echo `mount | grep ");
    strcat(mountGrepCmd, opt.device);
    strcat(mountGrepCmd, " | sed 's/ on /$/' | tr '$' '\n' | head -n 2 | tail -n 1 | tr '(' '\n' | head -n 1`");
    char mountPoint[4096];
    memset(mountPoint, 0, 4096);
    FILE *mountCmdOutput = popen(mountGrepCmd, "r");
    fgets(mountPoint, 4096, mountCmdOutput);
    mountPoint[strlen(mountPoint)-1] = 0; // removes trailing newline
    printf("mountpoint is %s\n", mountPoint);
    
    mntpath = mountPoint;
    ldlinux_path = alloca(strlen(mntpath) + strlen(subdir) + 1);
    sprintf(ldlinux_path, "%s%s", mntpath, subdir);

    ldlinux_name = alloca(strlen(ldlinux_path) + 14);
    if (!ldlinux_name) {
	perror(program);
	err = 1;
	goto umount;
    }
    sprintf(ldlinux_name, "%sldlinux.sys", ldlinux_path);

    /* update ADV only ? */
    if (opt.update_only == -1) {
	if (opt.reset_adv || opt.set_once) {
	    modify_existing_adv(ldlinux_path);
	    //do_umount(mntpath, mnt_cookie);
	    sync();
	    //rmdir(mntpath);
	    exit(0);
	} else {
	    fprintf(stderr, "%s: please specify --install or --update for the future\n", argv[0]);
	    opt.update_only = 0;
	}
    }

    printf("checkpoint1\n");

    /* Read a pre-existing ADV, if already installed */
    if (opt.reset_adv)
	syslinux_reset_adv(syslinux_adv);
    else if (read_adv(ldlinux_path, "ldlinux.sys") < 0)
	syslinux_reset_adv(syslinux_adv);
    if (modify_adv() < 0)
	exit(1);
	
	printf("checkpoint1.5\n");

    if ((fd = open(ldlinux_name, O_RDONLY)) >= 0) {
	uint32_t zero_attr = 0;
	//ioctl(fd, FAT_IOCTL_SET_ATTRIBUTES, &zero_attr);
	printf("checkpoint1.55bad\n");
	close(fd);
    }
    
    printf("checkpoint1.6\n");

    unlink(ldlinux_name);
    printf(ldlinux_name);
    printf(" ldlinuxname\n");
    fd = open(ldlinux_name, O_WRONLY | O_CREAT | O_TRUNC, 0444);
    if (fd < 0) {
	perror(opt.device);
	err = 1;
	goto umount;
    }
    
    printf("checkpoint2\n");

    /* Write it the first time */
    if (xpwrite(fd, boot_image, boot_image_len, 0) != (int)boot_image_len ||
	xpwrite(fd, syslinux_adv, 2 * ADV_SIZE,
		boot_image_len) != 2 * ADV_SIZE) {
	fprintf(stderr, "%s: write failure on %s\n", program, ldlinux_name);
	exit(1);
    }

    fsync(fd);
    /*
     * Set the attributes
     */
    {
	uint32_t attr = 0x07;	/* Hidden+System+Readonly */
	//ioctl(fd, FAT_IOCTL_SET_ATTRIBUTES, &attr);
    }
    
    printf("checkpoint3\n");

    /*
     * Create a block map.
     */
    
    ldlinux_sectors += 2; /* 2 ADV sectors */
    
    close(fd);
    sync();
    /*
    sectors = calloc(ldlinux_sectors, sizeof *sectors);
    if (sectmap(fd, sectors, ldlinux_sectors)) {
	perror("bmap");
	exit(1);
    }
    close(fd);
    sync();
    printf("checkpoint4\n");
    */
    
    /* Map the file (is there a better way to do this?) */
    //ldlinux_sectors = (syslinux_ldlinux_len + 2 * ADV_SIZE + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
    struct libfat_filesystem *fs;
    libfat_sector_t s;
    libfat_sector_t *secp;
    //libfat_sector_t *sectors;
    uint32_t ldlinux_cluster;
    
    sectors = calloc(ldlinux_sectors, sizeof *sectors);
    //fs = libfat_open(libfat_readfile, (intptr_t) d_handle);
    system(umountCommand);
    dev_fd = open(opt.device, O_RDWR);
    if (dev_fd < 0 || fstat(dev_fd, &st) < 0) {
	perror("couldn't open device");
	exit(1);
    }
    fs = libfat_open(libfat_readfile, dev_fd);
    if (fs == NULL) printf("null fs struct\n");
    ldlinux_cluster = libfat_searchdir(fs, 0, "LDLINUX SYS", NULL);
    
    printf("checkpoint4\n");
    
    secp = sectors;
    int nsectors;
    nsectors  = 0;
    s = libfat_clustertosector(fs, ldlinux_cluster);
    while (s && nsectors < ldlinux_sectors) {
	*secp++ = s;
	nsectors++;
	s = libfat_nextsector(fs, s);
    }
    libfat_close(fs);
    printf("checkpoint5\n");

umount:
    //do_umount(mntpath, mnt_cookie);
    sync();
    //rmdir(mntpath);

    if (err)
	exit(err);
	
	printf("checkpoint6\n");

    /*
     * Patch ldlinux.sys and the boot sector
     */
    i = syslinux_patch(sectors, ldlinux_sectors, opt.stupid_mode,
		       opt.raid_mode, subdir, NULL);
    patch_sectors = (i + SECTOR_SIZE - 1) >> SECTOR_SHIFT;

    /*
     * Write the now-patched first sectors of ldlinux.sys
     */
    for (i = 0; i < patch_sectors; i++) {
	xpwrite(dev_fd, boot_image + i * SECTOR_SIZE, SECTOR_SIZE,
		opt.offset + ((off_t) sectors[i] << SECTOR_SHIFT));
    }
    
    printf("checkpoint7\n");

    /*
     * To finish up, write the boot sector
     */

    /* Read the superblock again since it might have changed while mounted */
    xpread(dev_fd, sectbuf, SECTOR_SIZE, opt.offset);

    /* Copy the syslinux code into the boot sector */
    syslinux_make_bootsect(sectbuf);

    /* Write new boot sector */
    xpwrite(dev_fd, sectbuf, SECTOR_SIZE, opt.offset);
    
    printf("checkpoint8\n");

    close(dev_fd);
    sync();
    system(mountCmd);

    /* Done! */

    return 0;
}
示例#6
0
int main(int argc, char *argv[])
{
    static unsigned char sectbuf[SECTOR_SIZE];
    int dev_fd;
    struct stat st;
    int status;
    const char *tmpdir;
    char *mtools_conf;
    int mtc_fd;
    FILE *mtc, *mtp;
    struct libfat_filesystem *fs;
    libfat_sector_t s, *secp;
    libfat_sector_t *sectors;
    int32_t ldlinux_cluster;
    int nsectors;
    const char *errmsg;
    int ldlinux_sectors, patch_sectors;
    int i;

    (void)argc;			/* Unused */

    mypid = getpid();
    program = argv[0];

    parse_options(argc, argv, MODE_SYSLINUX);

    if (!opt.device)
	usage(EX_USAGE, MODE_SYSLINUX);

    if (opt.sectors || opt.heads || opt.reset_adv || opt.set_once
	|| (opt.update_only > 0) || opt.menu_save) {
	fprintf(stderr,
		"At least one specified option not yet implemented"
		" for this installer.\n");
	exit(1);
    }

    /*
     * Temp directory of choice...
     */
    tmpdir = getenv("TMPDIR");
    if (!tmpdir) {
#ifdef P_tmpdir
	tmpdir = P_tmpdir;
#elif defined(_PATH_TMP)
	tmpdir = _PATH_TMP;
#else
	tmpdir = "/tmp";
#endif
    }

    /*
     * First make sure we can open the device at all, and that we have
     * read/write permission.
     */
    dev_fd = open(opt.device, O_RDWR);
    if (dev_fd < 0 || fstat(dev_fd, &st) < 0) {
	die_err(opt.device);
	exit(1);
    }

    if (!opt.force && !S_ISBLK(st.st_mode) && !S_ISREG(st.st_mode)) {
	fprintf(stderr,
		"%s: not a block device or regular file (use -f to override)\n",
		opt.device);
	exit(1);
    }

    xpread(dev_fd, sectbuf, SECTOR_SIZE, opt.offset);

    /*
     * Check to see that what we got was indeed an MS-DOS boot sector/superblock
     */
    if ((errmsg = syslinux_check_bootsect(sectbuf, NULL))) {
	die(errmsg);
    }

    /*
     * Create an mtools configuration file
     */
    if (asprintf(&mtools_conf, "%s//syslinux-mtools-XXXXXX", tmpdir) < 0 ||
	!mtools_conf)
	die_err(tmpdir);

    mtc_fd = mkstemp(mtools_conf);
    if (mtc_fd < 0 || !(mtc = fdopen(mtc_fd, "w")))
	die_err(mtools_conf);

    fprintf(mtc,
	    /* These are needed for some flash memories */
	    "MTOOLS_SKIP_CHECK=1\n"
	    "MTOOLS_FAT_COMPATIBILITY=1\n"
	    "drive s:\n"
	    "  file=\"/proc/%lu/fd/%d\"\n"
	    "  offset=%llu\n",
	    (unsigned long)mypid,
	    dev_fd, (unsigned long long)opt.offset);

    if (ferror(mtc) || fclose(mtc))
	die_err(mtools_conf);

    /*
     * Run mtools to create the LDLINUX.SYS file
     */
    if (setenv("MTOOLSRC", mtools_conf, 1)) {
	perror(program);
	exit(1);
    }

    /*
     * Create a vacuous ADV in memory.  This should be smarter.
     */
    syslinux_reset_adv(syslinux_adv);

    /* This command may fail legitimately */
    status = system("mattrib -h -r -s s:/ldlinux.sys 2>/dev/null");
    (void)status;		/* Keep _FORTIFY_SOURCE happy */

    mtp = popen("mcopy -D o -D O -o - s:/ldlinux.sys", "w");
    if (!mtp ||
	fwrite((const void _force *)syslinux_ldlinux,
	       1, syslinux_ldlinux_len, mtp)
		!= syslinux_ldlinux_len ||
	fwrite((const void _force *)syslinux_adv,
	       1, 2 * ADV_SIZE, mtp)
		!= 2 * ADV_SIZE ||
	(status = pclose(mtp), !WIFEXITED(status) || WEXITSTATUS(status))) {
	die("failed to create ldlinux.sys");
    }

    /*
     * Now, use libfat to create a block map
     */
    ldlinux_sectors = (syslinux_ldlinux_len + 2 * ADV_SIZE
		       + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
    sectors = calloc(ldlinux_sectors, sizeof *sectors);
    fs = libfat_open(libfat_xpread, dev_fd);
    ldlinux_cluster = libfat_searchdir(fs, 0, "LDLINUX SYS", NULL);
    secp = sectors;
    nsectors = 0;
    s = libfat_clustertosector(fs, ldlinux_cluster);
    while (s && nsectors < ldlinux_sectors) {
	*secp++ = s;
	nsectors++;
	s = libfat_nextsector(fs, s);
    }
    libfat_close(fs);

    /* Patch ldlinux.sys and the boot sector */
    i = syslinux_patch(sectors, nsectors, opt.stupid_mode, opt.raid_mode,
		       opt.directory, NULL);
    patch_sectors = (i + SECTOR_SIZE - 1) >> SECTOR_SHIFT;

    /* Write the now-patched first sectors of ldlinux.sys */
    for (i = 0; i < patch_sectors; i++) {
	xpwrite(dev_fd, (const char _force *)syslinux_ldlinux
		+ i * SECTOR_SIZE, SECTOR_SIZE,
		opt.offset + ((off_t) sectors[i] << SECTOR_SHIFT));
    }

    /* Move ldlinux.sys to the desired location */
    if (opt.directory) {
	status = move_file("ldlinux.sys");
    } else {
	status = system("mattrib +r +h +s s:/ldlinux.sys");
    }

    if (!WIFEXITED(status) || WEXITSTATUS(status)) {
	fprintf(stderr,
		"%s: warning: failed to set system bit on ldlinux.sys\n",
		program);
    }

    /* This command may fail legitimately */
    status = system("mattrib -h -r -s s:/ldlinux.c32 2>/dev/null");
    (void)status;		/* Keep _FORTIFY_SOURCE happy */

    mtp = popen("mcopy -D o -D O -o - s:/ldlinux.c32", "w");
    if (!mtp ||	fwrite((const char _force *)syslinux_ldlinuxc32,
		       1, syslinux_ldlinuxc32_len, mtp)
	!= syslinux_ldlinuxc32_len ||
	(status = pclose(mtp), !WIFEXITED(status) || WEXITSTATUS(status))) {
	die("failed to create ldlinux.c32");
    }

    /* Move ldlinux.c32 to the desired location */
    if (opt.directory) {
	status = move_file("ldlinux.c32");
    } else {
	status = system("mattrib +r +h +s s:/ldlinux.c32");
    }

    if (!WIFEXITED(status) || WEXITSTATUS(status)) {
	fprintf(stderr,
		"%s: warning: failed to set system bit on ldlinux.c32\n",
		program);
    }

    /*
     * Cleanup
     */
    unlink(mtools_conf);

    /*
     * To finish up, write the boot sector
     */

    /* Read the superblock again since it might have changed while mounted */
    xpread(dev_fd, sectbuf, SECTOR_SIZE, opt.offset);

    /* Copy the syslinux code into the boot sector */
    syslinux_make_bootsect(sectbuf, VFAT);

    /* Write new boot sector */
    xpwrite(dev_fd, sectbuf, SECTOR_SIZE, opt.offset);

    close(dev_fd);
    sync();

    /* Done! */

    return 0;
}