Workaround for AFS bug

Francois Gouget fgouget at codeweavers.com
Mon May 30 05:50:24 CDT 2005


Francois Gouget wrote:
[...]
> So this patch sets d_reclen to 0 before the ioctl() and checks whether 
> it's still 0 afterwards.

Setting d_reclen to 0 is tricky because this is also the value which is 
returned to signal the EOF. It's ok for the first ioctl() on a directory 
(because there's always '.' and '..'), but this is not garanteed in 
read_directory_vfat(). If not at the beginning of the directory, then we 
cannot determine if d_reclen=0 is because of a legitimate EOF or the AFS 
bug.

d_reclen is an unsigned short but cannot have a value greater than 256 
because that's the size of the d_name array. So we can detect the AFS 
bug more reliably by setting d_reclen to 65535 and checking for a 
successful ioctl that leaves it unchanged.

Changelog:

  * dlls/ntdll/directory.c

    Francois Gouget <fgouget at codeweavers.com>
    On some systems (linux 2.6.8) AFS fails to set d_reclen to 0 or does 
not support VFAT_IOCTL_READDIR_BOTH but returns 0 (success) anyway. So 
set d_reclen to 65535 (an impossible value) before the ioctl() and check 
it afterwards to work around this bug.

-- 
Francois Gouget
fgouget at codeweavers.com

-------------- next part --------------
Index: dlls/ntdll/directory.c
===================================================================
RCS file: /var/cvs/wine/dlls/ntdll/directory.c,v
retrieving revision 1.28
diff -u -p -r1.28 directory.c
--- dlls/ntdll/directory.c	20 May 2005 19:24:07 -0000	1.28
+++ dlls/ntdll/directory.c	30 May 2005 10:32:01 -0000
@@ -831,8 +831,12 @@ static int read_directory_vfat( int fd, 
     {
         off_t old_pos = lseek( fd, 0, SEEK_CUR );
 
+        /* Set d_reclen to 65535 to work around an AFS kernel bug */
+        de[0].d_reclen=65535;
         res = ioctl( fd, VFAT_IOCTL_READDIR_BOTH, (long)de );
-        if (res == -1 && errno != ENOENT) return -1;  /* VFAT ioctl probably not supported */
+        if ((res == -1 && errno != ENOENT) ||
+            (res == 0 && de[0].d_reclen == 65535))
+            return -1;  /* VFAT ioctl probably not supported */
 
         while (res != -1)
         {
@@ -859,8 +863,12 @@ static int read_directory_vfat( int fd, 
     }
     else  /* we'll only return full entries, no need to worry about overflow */
     {
+        /* Set d_reclen to 65535 to work around an AFS kernel bug */
+        de[0].d_reclen=65535;
         res = ioctl( fd, VFAT_IOCTL_READDIR_BOTH, (long)de );
-        if (res == -1 && errno != ENOENT) return -1;  /* VFAT ioctl probably not supported */
+        if ((res == -1 && errno != ENOENT) ||
+            (res == 0 && de[0].d_reclen == 65535))
+            return -1;  /* VFAT ioctl probably not supported */
 
         while (res != -1)
         {
@@ -1161,7 +1169,10 @@ static NTSTATUS find_file_in_dir( char *
         {
             KERNEL_DIRENT de[2];
 
-            if (ioctl( fd, VFAT_IOCTL_READDIR_BOTH, (long)de ) != -1)
+            /* Set d_reclen to 65535 to work around an AFS kernel bug */
+            de[0].d_reclen=65535;
+            if (ioctl( fd, VFAT_IOCTL_READDIR_BOTH, (long)de ) != -1 &&
+                de[0].d_reclen != 65535)
             {
                 unix_name[pos - 1] = '/';
                 for (;;)


More information about the wine-patches mailing list