From: Ryan Lortie <desrt@desrt.ca>
To: linux-hotplug@vger.kernel.org
Subject: Re: support for vfat long filenames
Date: Wed, 23 May 2007 14:18:55 +0000 [thread overview]
Message-ID: <1179929935.6119.5.camel@moonpix.desrt.ca> (raw)
In-Reply-To: <1179900959.20773.3.camel@moonpix.desrt.ca>
[-- Attachment #1: Type: text/plain, Size: 1154 bytes --]
On Wed, 2007-23-05 at 08:42 +0200, Kay Sievers wrote:
> On 5/23/07, Ryan Lortie <desrt@desrt.ca> wrote:
> > here's a first go at a patch to implement long filename support for vfat
> > in libvolume_id.
> >
> > i'm not on the list, so please keep me cc:'d in on any discussion...
>
> Oh, does that mean that fat can have labels with long filenames? What
> tool can create these long labels, can you set such labels with
> Windows now?
i've been using the mtools package (specifically, "mlabel") to test my
work. it supports long labels in exactly the way you would expect.
desrt@moonpix:~$ sudo mdir -i /dev/sdc2 ::
Volume in drive : is My iPod has a very long name! (abbr=MY IPOD HAS)
i don't know about windows since i don't have access to a windows box,
but i assume it's true there too....?
> Can you use volume_id_set_unicode16() in utils.c, or is that different?
ah. i didn't know about this. done :)
> And please don't use assert(), just return no label if something goes wrong.
done -- this part is reworked a little to use memcpy anyway.
also fixed some small indentation and { placement issues.
thanks for the swift review.
cheers
[-- Attachment #2: vfat-lfn.patch --]
[-- Type: text/x-patch, Size: 4554 bytes --]
--- a/extras/volume_id/lib/fat.c 2007-03-28 14:47:26.000000000 -0400
+++ b/extras/volume_id/lib/fat.c 2007-05-23 10:16:50.000000000 -0400
@@ -34,6 +34,16 @@
#define FAT_ATTR_MASK 0x3f
#define FAT_ENTRY_FREE 0xe5
+#define VFAT_LFN_SEQ_MASK 0x3f
+#define VFAT_LFN_SEQ_LAST 0x40
+#define VFAT_LFN_SEQ_MAX 20
+#define VFAT_LFN_CHARS_PER_ENTRY (5 + 6 + 2)
+#define VFAT_LOWERCASE_NAME 0x10
+#define VFAT_LOWERCASE_EXT 0x08
+
+#define TRUE 1
+#define FALSE 0
+
struct vfat_super_block {
uint8_t boot_jump[3];
uint8_t sysid[8];
@@ -88,9 +98,10 @@
struct vfat_dir_entry {
uint8_t name[11];
uint8_t attr;
+ uint8_t lowercase;
+ uint8_t fine_time_creat;
uint16_t time_creat;
uint16_t date_creat;
- uint16_t time_acc;
uint16_t date_acc;
uint16_t cluster_high;
uint16_t time_write;
@@ -99,6 +110,110 @@
uint32_t size;
} PACKED;
+
+struct vfat_lfn_entry {
+ uint8_t seq;
+ uint16_t name0[5];
+ uint8_t attr;
+ uint8_t reserved;
+ uint8_t cksum;
+ uint16_t name1[6];
+ uint16_t cluster;
+ uint16_t name2[2];
+} PACKED;
+
+static uint8_t
+fat_lfn_checksum (const uint8_t name[11])
+{
+ uint8_t cksum = 0;
+ int i;
+
+ /* http://en.wikipedia.org/wiki/File_Allocation_Table */
+ for (i = 0; i < 11; i++)
+ cksum = ((cksum & 1) ? 0x80 : 0) + (cksum >> 1) + name[i];
+
+ return cksum;
+}
+
+static int
+fat_read_lfn (struct vfat_dir_entry *dir,
+ struct vfat_dir_entry *entry,
+ uint8_t *filename)
+{
+ uint8_t buffer[VFAT_LFN_SEQ_MAX*VFAT_LFN_CHARS_PER_ENTRY*2];
+ uint8_t expected_seq = 1;
+ uint8_t cksum;
+ int len = 0;
+
+ cksum = fat_lfn_checksum (entry->name);
+
+ while (--entry >= dir) {
+ struct vfat_lfn_entry *lfn = (struct vfat_lfn_entry *) entry;
+
+ if (expected_seq > VFAT_LFN_SEQ_MAX)
+ break;
+
+ if ((lfn->attr & FAT_ATTR_MASK) != FAT_ATTR_LONG_NAME)
+ break;
+
+ if (lfn->cksum != cksum)
+ break;
+
+ if ((lfn->seq & VFAT_LFN_SEQ_MASK) != expected_seq++)
+ break;
+
+ if (lfn->cluster != 0)
+ break;
+
+ /* extra paranoia -- should never happen */
+ if (len + sizeof lfn->name0 + sizeof sizeof lfn->name1 +
+ sizeof lfn->name2 > sizeof buffer)
+ break;
+
+ memcpy (&buffer[len], lfn->name0, sizeof lfn->name0);
+ len += sizeof lfn->name0;
+ memcpy (&buffer[len], lfn->name1, sizeof lfn->name1);
+ len += sizeof lfn->name1;
+ memcpy (&buffer[len], lfn->name2, sizeof lfn->name2);
+ len += sizeof lfn->name2;
+
+ if (lfn->seq & VFAT_LFN_SEQ_LAST) {
+ if (len > 510)
+ len = 510;
+
+ volume_id_set_unicode16 ((char *) filename, 3*255,
+ buffer, LE, len);
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static uint8_t *
+fat_read_filename (struct vfat_dir_entry *dir, struct vfat_dir_entry *entry)
+{
+ static uint8_t filename[3*255];
+ int i;
+
+ /* check if maybe we have LFN entries */
+ if (fat_read_lfn (dir, entry, filename))
+ return filename;
+
+ /* else, read the normal 8.3 name */
+ for (i = 0; i < 11; i++) {
+ if (entry->lowercase & ((i < 8) ? VFAT_LOWERCASE_NAME :
+ VFAT_LOWERCASE_EXT))
+ filename[i] = tolower (entry->name[i]);
+ else
+ filename[i] = entry->name[i];
+ }
+
+ return filename;
+}
+
+
static uint8_t *get_attr_volume_id(struct vfat_dir_entry *dir, unsigned int count)
{
unsigned int i;
@@ -124,7 +239,7 @@
continue;
dbg("found ATTR_VOLUME_ID id in root dir");
- return dir[i].name;
+ return fat_read_filename (dir, &dir[i]);
}
dbg("skip dir entry");
@@ -282,8 +397,13 @@
return -1;
if (label != NULL && memcmp(label, "NO NAME ", 11) != 0) {
- volume_id_set_label_raw(id, label, 11);
- volume_id_set_label_string(id, label, 11);
+ int length = strlen ((char *) label);
+
+ if (length > 64)
+ length = 64;
+
+ volume_id_set_label_raw(id, label, length);
+ volume_id_set_label_string(id, label, length);
} else if (memcmp(vs->type.fat.label, "NO NAME ", 11) != 0) {
volume_id_set_label_raw(id, vs->type.fat.label, 11);
volume_id_set_label_string(id, vs->type.fat.label, 11);
@@ -360,8 +480,13 @@
return -1;
if (label != NULL && memcmp(label, "NO NAME ", 11) != 0) {
- volume_id_set_label_raw(id, label, 11);
- volume_id_set_label_string(id, label, 11);
+ int length = strlen ((char *) label);
+
+ if (length > 64)
+ length = 64;
+
+ volume_id_set_label_raw(id, label, length);
+ volume_id_set_label_string(id, label, length);
} else if (memcmp(vs->type.fat32.label, "NO NAME ", 11) != 0) {
volume_id_set_label_raw(id, vs->type.fat32.label, 11);
volume_id_set_label_string(id, vs->type.fat32.label, 11);
[-- Attachment #3: Type: text/plain, Size: 286 bytes --]
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
[-- Attachment #4: Type: text/plain, Size: 226 bytes --]
_______________________________________________
Linux-hotplug-devel mailing list http://linux-hotplug.sourceforge.net
Linux-hotplug-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel
next prev parent reply other threads:[~2007-05-23 14:18 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-05-23 6:15 support for vfat long filenames Ryan Lortie
2007-05-23 6:42 ` Kay Sievers
2007-05-23 14:18 ` Ryan Lortie [this message]
2007-05-25 2:04 ` Kay Sievers
2007-05-25 2:15 ` Ryan Lortie
2007-05-25 2:26 ` Kay Sievers
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1179929935.6119.5.camel@moonpix.desrt.ca \
--to=desrt@desrt.ca \
--cc=linux-hotplug@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.