All of lore.kernel.org
 help / color / mirror / Atom feed
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

  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.