public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* vfat patch for shortcut display as symlinks for 2.4.18
@ 2002-06-09  1:53 christoph
  2002-06-09 16:44 ` Jan Pazdziora
       [not found] ` <200206091158.43293.bodnar42@phalynx.dhs.org>
  0 siblings, 2 replies; 53+ messages in thread
From: christoph @ 2002-06-09  1:53 UTC (permalink / raw)
  To: linux-kernel; +Cc: adelton

I just tried the patch adding symlinks to the vfat fs. It was submitted
back at the end of last year but it does not seem to have made it into the
kernel sources. I was unable to find a discussion on this. Symlink support
in vfat is really useful when you are sharing a vfat volume on a dual
booted system. I tried patching a 2.5.X kernel but the page cache changes
mean that the patch needs reworking.

Do you have any updates to the patch Jan?

Here is the readme and the patch again:

------- readme -------------------------------------------------

Symlink support for VFAT filesystem for Linux 2.4

Jan Pazdziora, adelton@fi.muni.cz

October 31, 2001.

In Windows, there are so called shortcuts that provide ways of
referencing other files. We will use these to support symlinks on VFAT
partitions under Linux. This patch adds the support to fat/vfat
filesystem source.

Shortcuts are normal files with extension .lnk. That means that from
now on, no regular file on VFAT with symlinks support will be allowed
to have this extension.

The .lnk files not only point to other files but can also hold
information about ways of starting the referenced file, with which
program and parameters. Something like .pif was. The format is
rather complex, and is described by Jesse Hager at
http://www.wotsit.org/download.asp?f=shortcut.

There are three plus one fields of interest here:

1) Relative path -- if it is present we will use it to mean relative
   symlink, and when writing relative symlink, we will fill this
   field.
2) Network location, in a form \\hostname\path. We won't try to
   resolve it, except one special case, \\localhost\path, which will
   mean /path, absolute symlink.
3) Local location, in a form C:\path. We won't try to resolve this and
   we will never write this kind of link, because we don't know what
   the driver letters are.
4) Description field -- Cygwin seems to use it to store the absolute
   symlinks, we will write it to contain the symlink path (relative or
   absolute).

This patch makes symlink resolving the default. You can mount the
filesystem with an option -o nosymlinks, that will switch the symlink
support off and you will see the base .lnk files.

This patch was tested on Linux kernel 2.4.13 and on Windows ME.

Questions, requests for comment:

If we had the information about drive letter available, we would be
able to resolve the C:\Windows links correctly as well. Note that
inside one drive (shortcut from D: to some other location on D:), the
relative path seems to always be present, so it only starts to be
needed and interesting with links that go accross the Windows drive
boundary. Perhaps some /etc/windrives.conf file? Or a /proc support?
Suggestions welcome.

Cygwin doesn't seem to support the network and local symlinks under
Windows well. It is unhappy with the Network/local part. I believe
that it is a problem of Cygwin (do they do their own symlink
resolution?) and I might be able to get a patch to make Cygwin work
properly as well.

The patch adds minor tweaks into some common code, and also some
bigger functions for symlink creating and resolving. These could be
moved into separate file, from vfat/namei.c and fat/file.c. But due to
a way the fat/vfat/msdos filesystem sypport is structured, the support
(at least partial) will probably always need to be in the common fat
base.

Comments welcome.


diff -ru linux-2.4.13-orig/fs/fat/dir.c linux-2.4.13/fs/fat/dir.c
--- linux-2.4.13-orig/fs/fat/dir.c	Fri Oct 12 22:48:42 2001
+++ linux-2.4.13/fs/fat/dir.c	Mon Oct 29 22:05:43 2001
@@ -179,6 +179,13 @@
 	return len;
 }

+static int is_symlink(char *extension)
+{
+	if (strncmp(extension, "LNK", 3) == 0)
+		return 1;
+	return 0;
+}
+
 /*
  * Return values: negative -> error, 0 -> not found, positive -> found,
  * value is the total amount of slots, including the shortname entry.
@@ -197,6 +204,7 @@
 	char work[8], bufname[260];	/* 256 + 4 */
 	int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
 	int utf8 = MSDOS_SB(sb)->options.utf8;
+	int showsymlinks = MSDOS_SB(sb)->options.symlinks;
 	unsigned short opt_shortname = MSDOS_SB(sb)->options.shortname;
 	int ino, chl, i, j, last_u, res = 0;
 	loff_t cpos = 0;
@@ -319,6 +327,9 @@
 		xlate_len = utf8
 			?utf8_wcstombs(bufname, bufuname, sizeof(bufname))
 			:uni16_to_x8(bufname, bufuname, uni_xlate, nls_io);
+		if (showsymlinks && (xlate_len == name_len + 4)
+					&& is_symlink(de->ext))
+				xlate_len -= 4;
 		if (xlate_len == name_len)
 			if ((!anycase && !memcmp(name, bufname, xlate_len)) ||
 			    (anycase && !fat_strnicmp(nls_io, name, bufname,
@@ -329,6 +340,9 @@
 			xlate_len = utf8
 				?utf8_wcstombs(bufname, unicode, sizeof(bufname))
 				:uni16_to_x8(bufname, unicode, uni_xlate, nls_io);
+			if (showsymlinks && (xlate_len == name_len + 4)
+						&& is_symlink(de->ext))
+				xlate_len -= 4;
 			if (xlate_len != name_len)
 				continue;
 			if ((!anycase && !memcmp(name, bufname, xlate_len)) ||
@@ -367,6 +381,7 @@
 	int isvfat = MSDOS_SB(sb)->options.isvfat;
 	int utf8 = MSDOS_SB(sb)->options.utf8;
 	int nocase = MSDOS_SB(sb)->options.nocase;
+	int showsymlinks = MSDOS_SB(sb)->options.symlinks;
 	unsigned short opt_shortname = MSDOS_SB(sb)->options.shortname;
 	int ino, inum, chi, chl, i, i2, j, last, last_u, dotoffset = 0;
 	loff_t cpos;
@@ -556,6 +571,8 @@
 	}

 	if (!long_slots||shortnames) {
+		if (showsymlinks && i > 4 && is_symlink(de->ext))
+			i -= 4;
 		if (both)
 			bufname[i] = '\0';
 		if (filldir(dirent, bufname, i, *furrfu, inum,
@@ -567,6 +584,8 @@
 			? utf8_wcstombs(longname, unicode, sizeof(longname))
 			: uni16_to_x8(longname, unicode, uni_xlate,
 				      nls_io);
+		if (showsymlinks && long_len > 4 && is_symlink(de->ext))
+			long_len -= 4;
 		if (both) {
 			memcpy(&longname[long_len+1], bufname, i);
 			long_len += i;
diff -ru linux-2.4.13-orig/fs/fat/file.c linux-2.4.13/fs/fat/file.c
--- linux-2.4.13-orig/fs/fat/file.c	Sun Aug 12 19:56:56 2001
+++ linux-2.4.13/fs/fat/file.c	Wed Oct 31 16:06:48 2001
@@ -16,6 +16,7 @@
 #include <linux/string.h>
 #include <linux/pagemap.h>
 #include <linux/fat_cvf.h>
+#include <linux/slab.h>

 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -36,6 +37,15 @@
 	setattr:	fat_notify_change,
 };

+int fat_readlink(struct dentry *dentry, char *buffer, int buflen);
+int fat_follow_link(struct dentry *dentry, struct nameidata *nd);
+
+struct inode_operations fat_symlink_inode_operations = {
+	readlink:       fat_readlink,
+	follow_link:    fat_follow_link,
+	setattr:	fat_notify_change,
+};
+
 ssize_t fat_file_read(
 	struct file *filp,
 	char *buf,
@@ -134,3 +144,201 @@
 	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
 	mark_inode_dirty(inode);
 }
+
+#define FAT_SYMLINK_SHELL_ITEM_LIST	0x01
+#define FAT_SYMLINK_FILE_LOCATION	0x02
+#define FAT_SYMLINK_RELATIVE		0x08
+#define FAT_SYMLINK_LOCAL		0x01
+#define FAT_SYMLINK_NETWORK		0x02
+#define FAT_SYMLINK_ABSOLUTE		"\\\\localhost\\"
+
+int fat_getlink(struct dentry *dentry, char *buffer, int buflen,
+		char **outbuffer)
+{
+	struct page * page;
+	struct address_space *mapping = dentry->d_inode->i_mapping;
+	char * ptr;
+	int ret = -EIO;
+	int offset = 76;
+	unsigned char flags;
+	*outbuffer = buffer;
+
+	page = read_cache_page(mapping, 0, (filler_t *)mapping->a_ops->readpage,
+		NULL);
+	if (IS_ERR(page))
+		goto sync_fail;
+	wait_on_page(page);
+	if (!Page_Uptodate(page))
+		goto async_fail;
+	ptr = kmap(page);
+
+	if (!(ptr && *ptr == 'L'))	/* FIXME: test cele signatury */
+		goto fail_and_free_page;
+
+	flags = *(ptr + 20);
+
+	if (flags & FAT_SYMLINK_RELATIVE) {
+		int i, len;
+		for (i = 0; i <= 2; i++) {
+			if (flags & (1 << i)) {
+				offset += CF_LE_W(*(__u16 *)(ptr + offset));
+				if (i == 0 || i == 2)
+					offset += 2;
+			}
+		}
+		len = CF_LE_W(*(__u16 *)(ptr + offset));
+		if (!buffer) {
+			*outbuffer = kmalloc(len + 1, GFP_KERNEL);
+			if (!(*outbuffer)) {
+				ret = -ENOMEM;
+				goto fail_and_free_page;
+			}
+			memcpy(*outbuffer, ptr + offset + 2, len);
+		} else {
+			if (len > buflen) {
+				len = buflen;
+			}
+			if (copy_to_user(buffer, ptr + offset + 2, len + 1)) {
+				ret = -EFAULT;
+				goto fail_and_free_page;
+			}
+		}
+		(*outbuffer)[len] = 0;
+		for (i = 0; i < len; i++) {
+			if ((*outbuffer)[i] == '\\')
+				(*outbuffer)[i] = '/';
+		}
+		ret = len;
+	} else if (flags & FAT_SYMLINK_FILE_LOCATION) {
+		unsigned char loc_flags;
+		char * first_part = NULL;
+		char * final_part = NULL;
+		int first_part_len, final_part_len;
+		int insert_slash = 0;
+		int total_len;
+
+		if (flags & FAT_SYMLINK_SHELL_ITEM_LIST) {
+			offset += CF_LE_W(*(__u16 *)(ptr + offset)) + 2;
+		}
+		loc_flags = *(ptr + offset + 8);
+
+		if (loc_flags & FAT_SYMLINK_NETWORK) {
+			int new_offset = offset
+				+ CF_LE_W(*(__u16 *)(ptr + offset + 20));
+			new_offset += CF_LE_W(*(__u16 *)(ptr + new_offset + 8));
+			first_part = ptr + new_offset;
+		} else if (loc_flags & FAT_SYMLINK_LOCAL) {
+			first_part = ptr + offset
+				+ CF_LE_W(*(__u16 *)(ptr + offset + 16));
+		}
+
+		if (!first_part)
+			goto fail_and_free_page;
+
+		first_part_len = strlen(first_part);
+		if (!strnicmp(first_part, FAT_SYMLINK_ABSOLUTE,
+			strlen(FAT_SYMLINK_ABSOLUTE))) {
+			first_part += strlen(FAT_SYMLINK_ABSOLUTE) - 1;
+			first_part_len += 1 - strlen(FAT_SYMLINK_ABSOLUTE);
+		}
+
+		final_part = ptr + offset
+				+ CF_LE_W(*(__u16 *)(ptr + offset + 24));
+		final_part_len = strlen(final_part);
+
+		if (final_part_len && (first_part[first_part_len - 1] != '\\'))
+			insert_slash = 1;
+
+		ret = total_len = first_part_len + insert_slash
+							+ final_part_len;
+		if (!buffer) {
+			int i;
+			*outbuffer = kmalloc(first_part_len + insert_slash
+				+ final_part_len + 1, GFP_KERNEL);
+			if (!(*outbuffer)) {
+				ret = -ENOMEM;
+				goto fail_and_free_page;
+			}
+
+			for (i = 0; i < first_part_len; i++) {
+				if (first_part[i] == '\\')
+					(*outbuffer)[i] = '/';
+				else
+					(*outbuffer)[i] = first_part[i];
+			}
+			if (insert_slash) {
+				(*outbuffer)[i] = '/';
+				i++;
+			}
+			for (i = 0; i < final_part_len; i++) {
+				if (final_part[i] == '\\')
+					(*outbuffer)[first_part_len
+						+ insert_slash + i] = '/';
+				else
+					(*outbuffer)[first_part_len
+					+ insert_slash + i] = final_part[i];
+			}
+			(*outbuffer)[first_part_len + insert_slash + i] = 0;
+		} else {
+			int i;
+			if (total_len > buflen)
+				total_len = buflen;
+			if (copy_to_user(buffer, first_part,
+				min(first_part_len, buflen))) {
+				ret = -EFAULT;
+				goto fail_and_free_page;
+			}
+			if (first_part_len + 1 < buflen) {
+				if (insert_slash
+					&& copy_to_user(buffer
+						+ first_part_len, "/", 1)) {
+					ret = -EFAULT;
+					goto fail_and_free_page;
+				}
+				if (copy_to_user(buffer + first_part_len
+					+ insert_slash, final_part,
+					min(final_part_len, buflen
+						- first_part_len
+						- insert_slash))) {
+					ret = -EFAULT;
+					goto fail_and_free_page;
+				}
+			}
+			for (i = 0; i < min(buflen, first_part_len
+				+ insert_slash + final_part_len); i++) {
+				if (buffer[i] == '\\')
+					buffer[i] = '/';
+			}
+			buffer[total_len] = '\000';
+		}
+	}
+
+fail_and_free_page:
+	kunmap(page);
+async_fail:
+        page_cache_release(page);
+sync_fail:
+        return ret;
+}
+
+int fat_readlink(struct dentry *dentry, char *buffer, int buflen)
+{
+	char * out;
+	if (dentry->d_inode->i_size > PAGE_SIZE)
+		return -ENAMETOOLONG;
+	return fat_getlink(dentry, buffer, buflen, &out);
+}
+
+int fat_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+	int res;
+	char * buffer;
+	if (dentry->d_inode->i_size > PAGE_SIZE)
+		return -ENAMETOOLONG;
+	fat_getlink(dentry, NULL, 0, &buffer);
+	res = vfs_follow_link(nd, buffer);
+	if (buffer)
+		kfree(buffer);
+	return res;
+}
+
diff -ru linux-2.4.13-orig/fs/fat/inode.c linux-2.4.13/fs/fat/inode.c
--- linux-2.4.13-orig/fs/fat/inode.c	Fri Oct 12 22:48:42 2001
+++ linux-2.4.13/fs/fat/inode.c	Mon Oct 29 22:18:42 2001
@@ -223,6 +223,7 @@
 	opts->nocase = 0;
 	opts->shortname = 0;
 	opts->utf8 = 0;
+	opts->symlinks = 0;
 	opts->iocharset = NULL;
 	*debug = *fat = 0;

@@ -852,6 +853,13 @@
 	return 0;
 }

+static int is_symlink(char *extension)
+{
+	if (strncmp(extension, "LNK", 3) == 0)
+		return 1;
+	return 0;
+}
+
 static int fat_writepage(struct page *page)
 {
 	return block_write_full_page(page,fat_get_block);
@@ -940,6 +948,12 @@
 		inode->i_size = CF_LE_L(de->size);
 	        inode->i_op = &fat_file_inode_operations;
 	        inode->i_fop = &fat_file_operations;
+		if (MSDOS_SB(sb)->options.symlinks && is_symlink(de->ext)) {
+			inode->i_mode &= ~ S_IFREG;
+			inode->i_mode |= S_IFLNK;
+			inode->i_op = &fat_symlink_inode_operations;
+			inode->i_fop = NULL;
+		}
 		inode->i_mapping->a_ops = &fat_aops;
 		MSDOS_I(inode)->mmu_private = inode->i_size;
 	}
diff -ru linux-2.4.13-orig/fs/vfat/namei.c linux-2.4.13/fs/vfat/namei.c
--- linux-2.4.13-orig/fs/vfat/namei.c	Fri Oct 12 22:48:42 2001
+++ linux-2.4.13/fs/vfat/namei.c	Thu Nov  1 09:14:43 2001
@@ -109,6 +109,7 @@
 	opts->numtail = 1;
 	opts->utf8 = 0;
 	opts->shortname = VFAT_SFN_DISPLAY_LOWER | VFAT_SFN_CREATE_WIN95;
+	opts->symlinks = 1;
 	/* for backward compatible */
 	if (opts->nocase) {
 		opts->nocase = 0;
@@ -155,6 +156,8 @@
 						| VFAT_SFN_CREATE_WIN95;
 			else
 				ret = 0;
+		} else if (!strcmp(this_char,"nosymlinks")) {
+			opts->symlinks = 0;
 		}
 		if (this_char != options)
 			*(this_char-1) = ',';
@@ -213,7 +216,9 @@
 	name = qstr->name;
 	while (len && name[len-1] == '.')
 		len--;
-
+	if (MSDOS_SB(dentry->d_inode->i_sb)->options.symlinks
+		&& len > 4 && strnicmp(name + len - 4, ".lnk", 4) == 0)
+		len -= 4;
 	qstr->hash = full_name_hash(name, len);

 	return 0;
@@ -236,6 +241,9 @@
 	name = qstr->name;
 	while (len && name[len-1] == '.')
 		len--;
+	if (MSDOS_SB(dentry->d_inode->i_sb)->options.symlinks
+		&& len > 4 && strnicmp(name + len - 4, ".lnk", 4) == 0)
+		len -= 4;

 	hash = init_name_hash();
 	while (len--)
@@ -1248,6 +1256,8 @@

 }

+static int vfat_symlink ( struct inode *dir, struct dentry *dentry,
+                 const char *symname);

 /* Public inode operations for the VFAT fs */
 struct inode_operations vfat_dir_inode_operations = {
@@ -1258,6 +1268,7 @@
 	rmdir:		vfat_rmdir,
 	rename:		vfat_rename,
 	setattr:	fat_notify_change,
+	symlink:	vfat_symlink,
 };

 struct super_block *vfat_read_super(struct super_block *sb,void *data,
@@ -1285,3 +1296,139 @@

 	return res;
 }
+
+/*
+ * Function vfat_symlink_fill takes a pointer to target of the
+ * new symlink and a pointer to buffer and creates correct content
+ * of the buffer, to be written as a file specifying the symlink.
+ * If however the buffer pointer is NULL, it doesn't write to it.
+ * In any case it returns the length of the new file, so this function
+ * should be called twice -- first with NULL as buffer and after
+ * allocating the exact memory, with the pointer to that buffer.
+ *
+ * The relative symlink is stored as relative symlink with the description
+ * the same as the symlink, the absolute symlink is stored as \\localhost\
+ * network symlink with description matching the symlink path.
+ */
+
+#define FAT_SYMLINK_FILE_START	"L\000\000\000\001\024\002\000\000\000\000\000\xc0\000\000\000\000\000\000\x46"
+#define FAT_SYMLINK_LOCALHOST	"\\\\localhost\\"
+
+static int vfat_symlink_fill(const char * symname, char * buffer)
+{
+	int res = 0;
+	int symnamelen = strlen(symname);
+
+	if (buffer) {
+		memcpy(buffer, FAT_SYMLINK_FILE_START, 20);
+		memset(buffer + 20, 0, 76 - 20);
+		*(__u32*)(buffer + 60) = CT_LE_L(1);
+	}
+
+	if (*symname == '/') {
+		res = 76 + symnamelen + 12 + 1 + 20 + 28 + 1 + symnamelen + 2;
+		if (buffer) {
+			int i;
+			*(__u32*)(buffer + 20) = CT_LE_L(6);
+			*(__u32*)(buffer + 76) = CT_LE_L(res - 76);
+			*(__u32*)(buffer + 80) = CT_LE_L(28);
+			*(__u32*)(buffer + 84) = CT_LE_L(2);
+			*(__u32*)(buffer + 96) = CT_LE_L(28);
+			*(__u32*)(buffer + 100) = CT_LE_L(28 + 20 + 13);
+			*(__u32*)(buffer + 104) = CT_LE_L(symnamelen + 12 + 1 + 20);
+			*(__u32*)(buffer + 112) = CT_LE_L(20);
+			memcpy(buffer + 124, FAT_SYMLINK_LOCALHOST, 13);
+			for (i = 1; i <= symnamelen; i++) {
+				if (*(symname + i) == '/')
+					*(buffer + 124 + 12 + i) = '\\';
+				else
+					*(buffer + 124 + 12 + i)
+							= *(symname + i);
+			}
+			*(__u32*)(buffer + 124 + 12 + symnamelen + 1)
+							= CT_LE_W(symnamelen);
+			memcpy(buffer + 124 + 12 + symnamelen + 1 + 2,
+				symname, symnamelen);
+		}
+	} else {
+		res = 76 + 2 + symnamelen + 2 + symnamelen + 1;
+		if (buffer) {
+			int i;
+			*(__u32*)(buffer + 20) = CT_LE_L(12);
+			*(__u16*)(buffer + 76) = CT_LE_W(symnamelen);
+			memcpy(buffer + 78, symname, symnamelen);
+
+			*(__u16*)(buffer + 78 + symnamelen)
+							= CT_LE_W(symnamelen);
+			for (i = 0; i < symnamelen; i++) {
+				if (*(symname + i) == '/')
+					*(buffer + 80 + symnamelen + i) = '\\';
+				else
+					*(buffer + 80 + symnamelen + i)
+							= *(symname + i);
+			}
+		}
+	}
+
+	return res;
+}
+
+/*
+ * Function vfat_symlink creates new symlink file on a vfat partition.
+ * First it adds the .lnk extension which on vfat will denote the symlink
+ * type. To do this, since we're making the name longer, we may need
+ * to allocate new d_name.name. Then we allocate buffer for the content
+ * of the symlink file, let vfat_symlink_fill to fill the buffer, create
+ * the file, release the buffer and are done.
+ */
+
+static int vfat_symlink ( struct inode *dir, struct dentry *dentry,
+                 const char *symname)
+{
+	char * buffer;
+        int ret, len;
+
+	int d_name_len = dentry->d_name.len;
+
+	if (d_name_len + 4 + 1 > sizeof(dentry->d_iname)) {
+		char * new_name = kmalloc(d_name_len + 4 + 1, GFP_KERNEL);
+		if (!new_name) {
+			ret = -ENOMEM;
+			goto out;
+		}
+		memcpy(new_name, dentry->d_name.name, d_name_len);
+		if (dentry->d_name.name != dentry->d_iname)
+			kfree(dentry->d_name.name);
+		dentry->d_name.name = new_name;
+	}
+	memcpy((unsigned char *)dentry->d_name.name + d_name_len, ".lnk", 5);
+	dentry->d_name.len += 4;
+
+        ret = vfat_create(dir, dentry, S_IFLNK | 0777);
+        if (ret) {
+                printk(KERN_WARNING "vfat_symlink: create failed (%d)\n", ret);
+                goto out;
+        }
+
+	buffer = kmalloc(vfat_symlink_fill(symname, NULL), GFP_KERNEL);
+	if (!buffer) {
+		ret = -ENOMEM;
+		goto out_unlink;
+	}
+
+	len = vfat_symlink_fill(symname, buffer);
+	ret = block_symlink(dentry->d_inode, buffer, len);
+	kfree(buffer);
+
+	if (ret < 0)
+		goto out_unlink;
+out:
+	return ret;
+
+out_unlink:
+	printk(KERN_WARNING "vfat_symlink: write failed, unlinking\n");
+	vfat_unlink (dir, dentry);
+	d_drop(dentry);
+	goto out;
+}
+
diff -ru linux-2.4.13-orig/include/linux/msdos_fs.h linux-2.4.13/include/linux/msdos_fs.h
--- linux-2.4.13-orig/include/linux/msdos_fs.h	Fri Oct 12 22:48:42 2001
+++ linux-2.4.13/include/linux/msdos_fs.h	Tue Oct 30 21:07:07 2001
@@ -56,7 +56,7 @@
 #define DELETED_FLAG 0xe5 /* marks file as deleted when in name[0] */
 #define IS_FREE(n) (!*(n) || *(const unsigned char *) (n) == DELETED_FLAG)

-#define MSDOS_VALID_MODE (S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO)
+#define MSDOS_VALID_MODE (S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO | S_IFLNK )
 	/* valid file mode bits */

 #define MSDOS_SB(s) (&((s)->u.msdos_sb))
@@ -271,6 +271,7 @@
 /* fat/file.c */
 extern struct file_operations fat_file_operations;
 extern struct inode_operations fat_file_inode_operations;
+extern struct inode_operations fat_symlink_inode_operations;
 extern ssize_t fat_file_read(struct file *filp, char *buf, size_t count,
 			     loff_t *ppos);
 extern int fat_get_block(struct inode *inode, long iblock,
@@ -278,6 +279,11 @@
 extern ssize_t fat_file_write(struct file *filp, const char *buf, size_t count,
 			      loff_t *ppos);
 extern void fat_truncate(struct inode *inode);
+/*
+extern int fat_readlink(struct dentry *dentry, char *buffer, int buflen);
+extern int fat_follow_link(struct dentry *, struct nameidata *);
+*/
+

 /* fat/inode.c */
 extern void fat_hash_init(void);
diff -ru linux-2.4.13-orig/include/linux/msdos_fs_sb.h linux-2.4.13/include/linux/msdos_fs_sb.h
--- linux-2.4.13-orig/include/linux/msdos_fs_sb.h	Fri Oct 12 22:48:42 2001
+++ linux-2.4.13/include/linux/msdos_fs_sb.h	Mon Oct 29 22:06:24 2001
@@ -26,7 +26,8 @@
 		 numtail:1,       /* Does first alias have a numeric '~1' type tail? */
 		 atari:1,         /* Use Atari GEMDOS variation of MS-DOS fs */
 		 fat32:1,	  /* Is this a FAT32 partition? */
-		 nocase:1;	  /* Does this need case conversion? 0=need case conversion*/
+		 nocase:1,	  /* Does this need case conversion? 0=need case conversion*/
+		 symlinks:1;	  /* Do we want to support symlinks? */
 };

 struct msdos_sb_info {



^ permalink raw reply	[flat|nested] 53+ messages in thread
* Re: vfat patch for shortcut display as symlinks for 2.4.18
@ 2002-06-11 14:31 Francois Gouget
  2002-06-12  0:30 ` Albert D. Cahalan
                   ` (2 more replies)
  0 siblings, 3 replies; 53+ messages in thread
From: Francois Gouget @ 2002-06-11 14:31 UTC (permalink / raw)
  To: linux-kernel


This looks like a bad idea. The reason is that the VFAT driver is the
wrong abstraction layer to support the '.lnk' files:

 * on Windows if you open("foo.lnk") you get the .lnk file, not the file
it 'links' to. On Linux you would get the file it points to instead
which is a different behavior.

 * Windows supports .lnk files on FAT, VFAT, NTFS, ISO9660, etc. So if
such support is added in the Linux kernel, it should be added to all of
the above filesystems. And then, there is no reason not to add it to
ext2, NFS, etc!

Other issues:

 * what happens if a Unix program tries to create a file called
'foo.lnk' that is not a .lnk file? I could create a text file called
'mylinks.lnk' to store bookmark stuff for instance.

 * there is no such thing as a dead .lnk file. If the specified path is
not found, Windows will use the file date, file size and whatnot to try
to find where the target went. Is it planned to add any such support
planned?

 * it has been mentionned that this makes it possible to extract source
tarballs that contain symlinks on a VFAT filesystem. While this sounds
cool I am not sure it is so useful.
   - for VFAT one could use the UMSDOS filesystem to do the same thing,
     and get many other features at the same time (at least while in
     Linux)
   - again, if it is useful on VFAT, then it would be useful for CD+RW
     filesystems (UDF?) (e.g. for archival), on NTFS (assuming write is
     well supported one day, etc.
   - if you switch back to Windows, no compiler is going to be able to
     use the '.lnk' files. That's because no compilers that I know of
     uses shell32.dll to read source files. So this would only work
     while on the Linux side and maybe in cygwin too.


This would also hurt Wine as:

 * it would prevent wine from reading the information in the '.lnk'
file... at least for 'supported' '.lnk' files

 * it's not entirely clear to me what is done with unsupported '.lnk'
files. Are they just dead symlinks (again !=windows) or can one read
their contents? In the first case Wine is dead in the water again, and
in the latter case we'll have to play games to know which kind we got.

 * it was suggested to implement a hack to let Wine access the '.lnk'
data. Why implement a hack which is going to be Linux specific when
doing nothing works just fine and on any Unix system? Plus this is going
to require Linux specific code in Wine if it is to be supported.

 * making it an option does not help Wine at all, especially if it is a
default one. Then we have to keep telling users that they have to modify
their fstab if they want Wine to work.


The right level to implement symlink support is:

 * in Wine. Of course! There we know what the drive mappings are, we
have access to the registry and can even use the native shell library.

 * in an LD_PRELOAD library. Then they would work for all filesystems,
be selectable on a per-user or even per-process basis. Of course it
would most likely not work with Wine (ld_preload libraries seldom do)
but we can at least easily disable such libraries using a wrapper
script.

 * as an option in the KDE/Gnome file browsers and related file access
methods. That's the layer which seems closest to the Windows shell
'layer'.


This looks like it could be the next 'unhide' thing. See:

 * isofs unhide option:  troubles with Wine
   http://www.uwsg.indiana.edu/hypermail/linux/kernel/0205.3/0267.html
   http://www.uwsg.indiana.edu/hypermail/linux/kernel/0206.0/0411.html
   http://www.uwsg.indiana.edu/hypermail/linux/kernel/0206.1/0246.html


--
Francois Gouget         fgouget@free.fr        http://fgouget.free.fr/
                Linux: It is now safe to turn on your computer.


^ permalink raw reply	[flat|nested] 53+ messages in thread
[parent not found: <Pine.GSO.4.21.0206130008390.18281-100000@weyl.math.psu.edu >]
[parent not found: <Pine.GSO.4.21.0206130454040.18281-100000@weyl.math.psu.edu >]

end of thread, other threads:[~2002-06-14  0:37 UTC | newest]

Thread overview: 53+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2002-06-09  1:53 vfat patch for shortcut display as symlinks for 2.4.18 christoph
2002-06-09 16:44 ` Jan Pazdziora
2002-06-09 17:44   ` Daniel Phillips
2002-06-09 18:53     ` Nicholas Miell
2002-06-09 20:05       ` Diego Calleja
2002-06-09 20:40         ` Thunder from the hill
2002-06-09 21:30           ` Nicholas Miell
2002-06-09 20:53       ` Albert D. Cahalan
2002-06-09 21:36         ` Nicholas Miell
2002-06-09 22:05           ` Albert D. Cahalan
2002-06-09 23:45             ` Nicholas Miell
2002-06-10  1:01               ` Albert D. Cahalan
2002-06-10  1:47                 ` Nicholas Miell
2002-06-10  1:58                   ` Albert D. Cahalan
2002-06-10  2:06                     ` Nicholas Miell
2002-06-10  2:20                       ` christoph
2002-06-09 22:06           ` christoph
2002-06-09 22:30             ` Nicholas Miell
2002-06-09 22:49               ` Thunder from the hill
2002-06-09 23:03                 ` Nicholas Miell
2002-06-10  0:04                   ` christoph
2002-06-10  0:01               ` christoph
2002-06-10  7:42             ` Joseph Mathewson
2002-06-10 10:23               ` Jan Pazdziora
2002-06-10 14:03               ` Thunder from the hill
2002-06-10 16:08               ` christoph
2002-06-11  9:47                 ` Banka
2002-06-11  4:43                   ` christoph
2002-06-10 11:00           ` Jan Pazdziora
2002-06-09 22:02       ` christoph
2002-06-10 11:06         ` Jan Pazdziora
     [not found] ` <200206091158.43293.bodnar42@phalynx.dhs.org>
     [not found]   ` <E17H8wh-0003ZO-00@starship>
2002-06-09 20:24     ` Ryan Cumming
  -- strict thread matches above, loose matches on Subject: below --
2002-06-11 14:31 Francois Gouget
2002-06-12  0:30 ` Albert D. Cahalan
2002-06-13  1:30   ` Francois Gouget
2002-06-13  1:50     ` Kurt Wall
2002-06-13  2:00       ` Alexander Viro
2002-06-13  2:25         ` Kurt Wall
2002-06-13  2:42           ` Ryan Cumming
2002-06-13  2:57             ` Kurt Wall
2002-06-13  3:04           ` Francois Gouget
2002-06-13  3:31           ` Alexander Viro
2002-06-13  2:05 ` Stevie O
2002-06-13  3:31   ` Francois Gouget
2002-06-13  4:09     ` Alexander Viro
2002-06-13  4:00 ` Tomas Szepe
     [not found]   ` <20020613103532.375d5dfe.arodland@noln.com>
2002-06-13 17:21     ` Tomas Szepe
     [not found] <Pine.GSO.4.21.0206130008390.18281-100000@weyl.math.psu.edu >
2002-06-13  4:27 ` Stevie O
2002-06-13  5:16   ` Alexander Viro
2002-06-13  7:00     ` Francois Gouget
2002-06-13  9:18       ` Alexander Viro
     [not found] <Pine.GSO.4.21.0206130454040.18281-100000@weyl.math.psu.edu >
2002-06-13 23:54 ` Stevie O
2002-06-14  0:37   ` Alexander Viro

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox