Package: dosfstools Version: 3.0.6-1 Severity: normal Tags: patch FAT filesystems can contain volume labels in 2 different places: a reserved location in the boot sector, and a special directory entry in the root directory. Here's what various libraries and commands do:
FreeDOS label: only gets/sets directory entry libvolume_id (used by udev before v142): gets directory entry if present, otherwise boot sector libblkid (part of util-linux-ng; previously e2fsprogs; used by many commands): gets directory entry if present, otherwise boot sector mkdosfs -n: sets directory entry and boot sector dosfslabel: only sets boot sector dosfslabel is clearly the odd one out, not even consistent with mkdosfs from the same package. It should look for a directory entry with the volume label and update that if present, as well as updating the boot sector. Demonstration: 1. $ dd bs=512 count=2880 </dev/zero >foo 2880+0 records in 2880+0 records out 1474560 bytes (1.5 MB) copied, 0.0121247 s, 122 MB/s 2. $ /sbin/mkdosfs -n foo foo mkdosfs 3.0.0 (28 Sep 2008) 3. $ /sbin/dosfslabel foo bar 4. $ /sbin/blkid foo foo: SEC_TYPE="msdos" LABEL="foo" UUID="B63E-8D7A" TYPE="vfat" # I would hope to see LABEL="bar" I used the following changes on Fedora's v3.0.1 and they worked for me on FAT12, FAT16 and FAT32 filesystems created using mkdosfs. They appear to be applicable to the current Debian version. Ben. --- dosfstools-3.0.1.orig/src/boot.c +++ dosfstools-3.0.1/src/boot.c @@ -27,9 +27,11 @@ #include <string.h> #include <sys/types.h> #include <stdlib.h> +#include <time.h> #include "common.h" #include "dosfsck.h" +#include "fat.h" #include "io.h" #include "boot.h" @@ -415,14 +416,10 @@ if (verbose) dump_boot(fs,&b,logical_sector_size); } -void write_label(DOS_FS *fs, char *label) +static void write_boot_label(DOS_FS *fs, char *label) { struct boot_sector b; struct boot_sector_16 *b16 = (struct boot_sector_16 *)&b; - int l = strlen(label); - - while (l < 11) - label[l++] = ' '; fs_read(0, sizeof(b), &b); if (fs->fat_bits == 12 || fs->fat_bits == 16) { @@ -445,6 +442,68 @@ fs_write(fs->backupboot_start, sizeof(b), &b); } +static loff_t find_volume_de(DOS_FS *fs, DIR_ENT *de) +{ + unsigned long cluster; + loff_t offset; + int i; + + if (fs->root_cluster) { + for (cluster = fs->root_cluster; + cluster != 0 && cluster != -1; + cluster = next_cluster(fs, cluster)) { + offset = cluster_start(fs, cluster); + for (i = 0; i * sizeof(DIR_ENT) < fs->cluster_size; i++) { + fs_read(offset, sizeof(DIR_ENT), de); + if (de->attr & ATTR_VOLUME) + return offset; + offset += sizeof(DIR_ENT); + } + } + } else { + for (i = 0; i < fs->root_entries; i++) { + offset = fs->root_start + i * sizeof(DIR_ENT); + fs_read(offset, sizeof(DIR_ENT), de); + if (de->attr & ATTR_VOLUME) + return offset; + } + } + + return 0; +} + +static void write_volume_label(DOS_FS *fs, char *label) +{ + time_t now = time(NULL); + struct tm *mtime = localtime(&now); + loff_t offset; + DIR_ENT de; + + offset = find_volume_de(fs, &de); + if (offset == 0) + return; + + memcpy(de.name, label, 11); + de.time = CT_LE_W((unsigned short)((mtime->tm_sec >> 1) + + (mtime->tm_min << 5) + + (mtime->tm_hour << 11))); + de.date = CT_LE_W((unsigned short)(mtime->tm_mday + + ((mtime->tm_mon+1) << 5) + + ((mtime->tm_year-80) << 9))); + fs_write(offset, sizeof(DIR_ENT), &de); +} + +void write_label(DOS_FS *fs, char *label) +{ + int l = strlen(label); + + while (l < 11) + label[l++] = ' '; + + write_boot_label(fs, label); + write_volume_label(fs, label); +} + /* Local Variables: */ /* tab-width: 8 */ /* End: */ --- END --- -- System Information: Debian Release: squeeze/sid APT prefers unstable APT policy: (500, 'unstable'), (500, 'stable'), (1, 'experimental') Architecture: i386 (x86_64) Kernel: Linux 2.6.32-rc8-amd64 (SMP w/2 CPU cores) Locale: LANG=en_GB.UTF-8, LC_CTYPE=en_GB.UTF-8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/dash Versions of packages dosfstools depends on: ii libc6 2.10.2-2 GNU C Library: Shared libraries dosfstools recommends no packages. dosfstools suggests no packages. -- no debconf information -- To UNSUBSCRIBE, email to debian-bugs-dist-requ...@lists.debian.org with a subject of "unsubscribe". Trouble? Contact listmas...@lists.debian.org