[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Patch] msdosfs: long names are not always long



Hi!

Situation...
 fat is mounted with ``long names'' support, getting list of directory
with >200 files. Some files are shown as their short names.

The problem...
 When all parts of ``long name'' is traversed and buffer (for storing
direntries) is totally filled with direntries msdosfs_readdir() returns
error and then is started from position where there are no ``long name''
parts, just short name.

The attached patch fixes it by saving offset where the first (WIN_LAST)
part of ``long name'' is and if buffer space is over it replaces current
offset with saved offset.

cd /usr/src/sys && patch -p0 < msdosfs.diff

-- 
Alexey V. Vatchenko
mailto: avv_(_at_)_mail_(_dot_)_zp_(_dot_)_ua
JID: avv_(_at_)_jabber_(_dot_)_zp_(_dot_)_ua
ICQ: 162799204
Index: msdosfs/msdosfs_vnops.c
===================================================================
RCS file: /cvs/src/sys/msdosfs/msdosfs_vnops.c,v
retrieving revision 1.53
diff -u -r1.53 msdosfs_vnops.c
--- msdosfs/msdosfs_vnops.c	14 Mar 2005 22:31:52 -0000	1.53
+++ msdosfs/msdosfs_vnops.c	20 Mar 2006 20:31:32 -0000
@@ -1479,6 +1479,7 @@
 	u_long *cookies = NULL;
 	int ncookies = 0;
 	off_t offset;
+	off_t wlast_off;	/* offset of WIN_LAST (in long names) */
 	int chksum = -1;
 
 #ifdef MSDOSFS_DEBUG
@@ -1513,6 +1514,8 @@
 	lost = uio->uio_resid - count;
 	uio->uio_resid = count;
 
+	wlast_off = -1;	/* doesn't point to any WIN_LAST direntry */
+
 	if (ap->a_ncookies) {
 		ncookies = uio->uio_resid / sizeof(struct direntry) + 3;
 		MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
@@ -1614,6 +1617,7 @@
 			 */
 			if (dentp->deName[0] == SLOT_DELETED) {
 				chksum = -1;
+				wlast_off = -1;
 				continue;
 			}
 
@@ -1623,7 +1627,11 @@
 			if (dentp->deAttributes == ATTR_WIN95) {
 				if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
 					continue;
-				chksum = win2unixfn((struct winentry *)dentp, &dirbuf, chksum);
+#define wep	((struct winentry *)dentp)
+				chksum = win2unixfn(wep, &dirbuf, chksum);
+				if (wep->weCnt & WIN_LAST)
+					wlast_off = offset;
+#undef wep
 				continue;
 			}
 
@@ -1632,6 +1640,7 @@
 			 */
 			if (dentp->deAttributes & ATTR_VOLUME) {
 				chksum = -1;
+				wlast_off = -1;
 				continue;
 			}
 
@@ -1681,8 +1690,12 @@
 			dirbuf.d_reclen = DIRENT_SIZE(&dirbuf);
 			if (uio->uio_resid < dirbuf.d_reclen) {
 				brelse(bp);
+				/* start from WIN_LAST next time */
+				if (wlast_off >= 0)
+					offset = wlast_off;
 				goto out;
 			}
+			wlast_off = -1;
 			error = uiomove((caddr_t) &dirbuf,
 					dirbuf.d_reclen, uio);
 			if (error) {



Visit your host, monkey.org