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

Reply via email to