[Patch] Shorter patch for smbfs 2.2.16

klaus-georg.adams at rwg.de klaus-georg.adams at rwg.de
Wed Jun 28 06:55:20 GMT 2000


Am 27.06.2000 19:58:44 schrieb urban:
> On Tue, 27 Jun 2000 klaus-georg.adams at rwg.de wrote:
>
> >
> > Hi Andrew,
> > your patch from 2.2.15 to 2.2.16, backing out the older protocol levels
breaks
> > reading from an OS/2 LAN Server.
> > The appended patch fixes things for me (against 2.2.16).
>
> This backs out a lot of desired changes. For example I think that 'rm -rf'
> on large directories will no longer work if you apply this because you
> change the cache to the old behaviour.

Yes, this was simply going back to 2.2.15 and adding a fix for the same problem
mentioned in
the mail about 2.4.0-test2.

>
> > - *  Jan 2000, cpg at aladdin.de
> > - *           - added posix semantics for unlink
> > - *  March 2000, tridge
> > - *           - removed support for old protocol levels. It didn't work
anyway
> > and
> > - *             was cluttering things up a lot.
> > + *  20/03/00 (chrisp)
> > + *           - fixed FINDFIRST flags for OS/2 Server
> > + *           - added lastname/mask stuff back (OS/2 needs it)
>
> And you remove the nice "posix semantics for unlink".
>
> It looks like you have simply gone back to the 2.2.14/15 version, and then
> added findfirst/lastname things. Maybe you could make a smaller patch that
> only adds back the parts necessary for it to work with OS/2? (or not,
> Tridge can probably see that anyway).

That's what I hoped. I had only seen the ChangeLog entry from tridge regarding
older protocol levels. I hadn't realized that there were other fixes.
The parts that I need for reading from an OS/2 LANman server are:
- support for older protocols (I'm not sure which one exactly)
- the lastname/mask stuff
- the FINDFIRST flags in readdir_long

I have appended a shorter patch, which still works for me, but leaves in most
of the other stuff from 2.2.16

>
> Re: Your other email about listing long directories. I suggested something
> similar to your patch for fixing this in 2.2, but the preferred change was
> to use infolevel 260 instead of 259.

Note: my problem arises with an OS/2 server at a protocol level < NT1, thus
infolevel == 1

> 2.3/2.4-test hasn't received any of the changes that 2.2 has, including
> long dirs, posix unlink, rm -rf fixes. I have a patch vs 2.3.99-pre9 to
> upgrade smbfs to 2.2, that haven't made it past the maintainer yet.

Would you be so kind as to send it to me for testing?
Thanks!

PS: the same problem wrt reading long directories from an OS/2 server
existed in smbclient from samba 2.0.6.
Tridge has accepted a patch from Christoph Pfisterer to samba (which is the
equivalent to
what I posted above) into 2.0.7, so it can't be all wrong.

--
kga


Index: fs/smbfs/dir.c
===================================================================
RCS file: /usr/src/cvsroot/linux/fs/smbfs/dir.c,v
retrieving revision 1.1.1.5
diff -u -r1.1.1.5 dir.c
--- fs/smbfs/dir.c      2000/06/13 09:23:24     1.1.1.5
+++ fs/smbfs/dir.c      2000/06/28 06:36:12
@@ -178,6 +178,16 @@
 printk("smb_dir_open: (%s/%s)\n", dentry->d_parent->d_name.name,
 file->f_dentry->d_name.name);
 #endif
+       /*
+        * Directory timestamps in the core protocol aren't updated
+        * when a file is added, so we give them a very short TTL.
+        */
+       if (server->opt.protocol < SMB_PROTOCOL_LANMAN2)
+       {
+               unsigned long age = jiffies - dir->u.smbfs_i.oldmtime;
+               if (age > 2*HZ)
+                       smb_invalid_dir_cache(dir);
+       }

        if (server->conn_pid)
                error = smb_revalidate_inode(dentry);
@@ -420,6 +430,7 @@
 dentry->d_parent->d_name.name, dentry->d_name.name, mode);
 #endif

+       smb_invalid_dir_cache(dir);
        error = smb_proc_create(dentry, 0, CURRENT_TIME, &fileid);
        if (!error)
        {
@@ -440,6 +451,7 @@
 {
        int error;

+       smb_invalid_dir_cache(dir);
        error = smb_proc_mkdir(dentry);
        if (!error)
        {
@@ -466,6 +478,7 @@
        if (!list_empty(&dentry->d_hash))
                goto out;

+       smb_invalid_dir_cache(dir);
        error = smb_proc_rmdir(dentry);

 out:
@@ -482,6 +495,7 @@
         */
        smb_close(dentry->d_inode);

+       smb_invalid_dir_cache(dir);
        error = smb_proc_unlink(dentry);
        if (!error)
        {
@@ -519,6 +533,8 @@
                d_delete(new_dentry);
        }

+       smb_invalid_dir_cache(old_dir);
+       smb_invalid_dir_cache(new_dir);
        error = smb_proc_mv(old_dentry, new_dentry);
        if (!error)
        {
Index: fs/smbfs/inode.c
===================================================================
RCS file: /usr/src/cvsroot/linux/fs/smbfs/inode.c,v
retrieving revision 1.1.1.3
diff -u -r1.1.1.3 inode.c
--- fs/smbfs/inode.c    2000/06/13 09:23:24     1.1.1.3
+++ fs/smbfs/inode.c    2000/06/28 06:36:12
@@ -276,6 +276,8 @@
 #endif
                if (!S_ISDIR(inode->i_mode))
                        invalidate_inode_pages(inode);
+               else
+                       smb_invalid_dir_cache(inode);
        }
 out:
        return error;
@@ -379,6 +381,13 @@
        mnt->dir_mode  &= (S_IRWXU | S_IRWXG | S_IRWXO);
        mnt->dir_mode  |= S_IFDIR;
        sb->u.smbfs_sb.mnt = mnt;
+       /*
+        * Display the enabled options
+        */
+       if (mnt->version & SMB_FIX_OLDATTR)
+               printk("SMBFS: Using core getattr (Win 95 speedup)\n");
+       else if (mnt->version & SMB_FIX_DIRATTR)
+               printk("SMBFS: Using dir ff getattr\n");

        /*
         * Keep the super block locked while we get the root inode.
@@ -501,7 +510,9 @@
        if ((attr->ia_valid & ATTR_ATIME) != 0)
        {
                fattr.f_atime = attr->ia_atime;
-               changed = 1;
+               /* Earlier protocols don't have an access time */
+               if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2)
+                       changed = 1;
        }
        if (changed)
        {
Index: fs/smbfs/proc.c
===================================================================
RCS file: /usr/src/cvsroot/linux/fs/smbfs/proc.c,v
retrieving revision 1.1.1.4
diff -u -r1.1.1.4 proc.c
--- fs/smbfs/proc.c     2000/06/13 09:23:25     1.1.1.4
+++ fs/smbfs/proc.c     2000/06/28 06:36:12
@@ -14,9 +14,9 @@
  *           - got rid of resume_key
  *  Jan 2000, cpg at aladdin.de
  *           - added posix semantics for unlink
- *  March 2000, tridge
- *           - removed support for old protocol levels. It didn't work anyway
and
- *             was cluttering things up a lot.
+ *  20/03/00 (chrisp)
+ *           - fixed FINDFIRST flags for OS/2 Server
+ *           - added lastname/mask stuff back (OS/2 needs it)
  */

 #include <linux/types.h>
@@ -62,6 +62,28 @@
 static int
 smb_proc_do_getattr(struct dentry *dir, struct smb_fattr *fattr,struct
smb_sb_info *server);

+static void
+str_upper(char *name, int len)
+{
+       while (len--)
+       {
+               if (*name >= 'a' && *name <= 'z')
+                       *name -= ('a' - 'A');
+               name++;
+       }
+}
+
+static void
+str_lower(char *name, int len)
+{
+       while (len--)
+       {
+               if (*name >= 'A' && *name <= 'Z')
+                       *name += ('a' - 'A');
+               name++;
+       }
+}
+
 /* reverse a string inline. This is used by the dircache walking routines */
 static void reverse_string(char *buf, int len) {
        char c;
@@ -149,8 +171,13 @@
 static char *smb_encode_path(struct smb_sb_info *server, char *buf,
                             struct dentry *dir, struct qstr *name)
 {
+       char *start = buf;
+
        buf += smb_build_path(dir, name, buf);

+       if (server->opt.protocol <= SMB_PROTOCOL_COREPLUS)
+               str_upper(start, buf - start);
+
        return buf;
 }

@@ -625,11 +652,6 @@
            !capable(CAP_SYS_ADMIN))
                goto out;

-       if (opt->protocol < SMB_PROTOCOL_NT1) {
-               printk(KERN_NOTICE " smbfs: protocols older than NT1 are not
suppported\n");
-               goto out;
-       }
-
        error = -EBADF;
        filp = fget(opt->fd);
        if (!filp)
@@ -652,7 +674,8 @@

        /* now that we have an established connection we can detect the server
           type and enable bug workarounds */
-       if ((server->opt.max_xmit < 0x1000) &&
+       if (server->opt.protocol == SMB_PROTOCOL_NT1 &&
+           (server->opt.max_xmit < 0x1000) &&
            !(server->opt.capabilities & SMB_CAP_NT_SMBS)) {
                server->mnt->version |= SMB_FIX_WIN95;
 #ifdef SMBFS_DEBUG_VERBOSE
@@ -706,8 +729,11 @@
        WSET(buf, smb_uid, server->opt.server_uid);
        WSET(buf, smb_mid, 1);

-       *(buf+smb_flg) = 0x8;
-       WSET(buf, smb_flg2, 0x3);
+       if (server->opt.protocol > SMB_PROTOCOL_CORE)
+       {
+               *(buf+smb_flg) = 0x8;
+               WSET(buf, smb_flg2, 0x3);
+       }
        *p++ = wct;             /* wct */
        p += 2 * wct;
        WSET(p, 0, bcc);
@@ -893,7 +919,9 @@
                 * If the file is open with write permissions,
                 * update the time stamps to sync mtime and atime.
                 */
-               if (ino->u.smbfs_i.access != SMB_O_RDONLY) {
+               if ((server->opt.protocol >= SMB_PROTOCOL_LANMAN2) &&
+                   !(ino->u.smbfs_i.access == SMB_O_RDONLY))
+               {
                        struct smb_fattr fattr;
                        smb_get_inode_attr(ino, &fattr);
                        smb_proc_setattr_ext(server, ino, &fattr);
@@ -903,8 +931,11 @@
                                                ino->i_mtime);
                ino->u.smbfs_i.cache_valid &= ~SMB_F_LOCALWRITE;
                /*
-                * Force a revalidation after closing
+                * Force a revalidation after closing ... some servers
+                * don't post the size until the file has been closed.
                 */
+               if (server->opt.protocol < SMB_PROTOCOL_NT1)
+                       ino->u.smbfs_i.oldmtime = 0;
                ino->u.smbfs_i.closed = jiffies;
        }
        return result;
@@ -1310,8 +1341,177 @@


 /*
- * Interpret a long filename structure using info level 260
+ * Note that we are now returning the name as a reference to avoid
+ * an extra copy, and that the upper/lower casing is done in place.
+ *
+ * Bugs Noted:
+ * (1) Pathworks servers may pad the name with extra spaces.
+ */
+static __u8 *
+smb_decode_dirent(struct smb_sb_info *server, __u8 *p,
+                       struct cache_dirent *entry)
+{
+       int len;
+
+       /*
+        * SMB doesn't have a concept of inode numbers ...
+        */
+       entry->ino = 0;
+
+       p += SMB_STATUS_SIZE;   /* reserved (search_status) */
+       entry->name = p + 9;
+       len = strlen(entry->name);
+       if (len > 12)
+       {
+               len = 12;
+       }
+       /*
+        * Trim trailing blanks for Pathworks servers
+        */
+       while (len > 2 && entry->name[len-1] == ' ')
+               len--;
+       entry->len = len;
+
+       switch (server->opt.case_handling)
+       {
+       case SMB_CASE_UPPER:
+               str_upper(entry->name, len);
+               break;
+       case SMB_CASE_LOWER:
+               str_lower(entry->name, len);
+               break;
+       default:
+               break;
+       }
+       pr_debug("smb_decode_dirent: len=%d, name=%s\n", len, entry->name);
+       return p + 22;
+}
+
+/* This routine is used to read in directory entries from the network.
+   Note that it is for short directory name seeks, i.e.: protocol <
+   SMB_PROTOCOL_LANMAN2 */
+
+static int
+smb_proc_readdir_short(struct smb_sb_info *server, struct dentry *dir, int
fpos,
+                      void *cachep)
+{
+       char *p;
+       int result;
+       int i, first, entries_seen, entries;
+       int entries_asked = (server->opt.max_xmit - 100) / SMB_DIRINFO_SIZE;
+       __u16 bcc;
+       __u16 count;
+       char status[SMB_STATUS_SIZE];
+       static struct qstr mask = { "*.*", 3, 0 };
+
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_proc_readdir_short: %s/%s, pos=%d\n",
+       DENTRY_PATH(dir), fpos);
+#endif
+
+       smb_lock_server(server);
+
+       /* N.B. We need to reinitialize the cache to restart */
+      retry:
+       smb_init_dircache(cachep);
+       first = 1;
+       entries = 0;
+       entries_seen = 2; /* implicit . and .. */
+
+       while (1)
+       {
+               p = smb_setup_header(server, SMBsearch, 2, 0);
+               WSET(server->packet, smb_vwv0, entries_asked);
+               WSET(server->packet, smb_vwv1, aDIR);
+               *p++ = 4;
+               if (first == 1)
+               {
+                       p = smb_encode_path(server, p, dir, &mask);
+                       *p++ = 5;
+                       WSET(p, 0, 0);
+                       p += 2;
+                       first = 0;
+               } else
+               {
+                       *p++ = 0;
+                       *p++ = 5;
+                       WSET(p, 0, SMB_STATUS_SIZE);
+                       p += 2;
+                       memcpy(p, status, SMB_STATUS_SIZE);
+                       p += SMB_STATUS_SIZE;
+               }
+
+               smb_setup_bcc(server, p);
+
+               result = smb_request_ok(server, SMBsearch, 1, -1);
+               if (result < 0)
+               {
+                       if ((server->rcls == ERRDOS) &&
+                           (server->err  == ERRnofiles))
+                               break;
+                       if (smb_retry(server))
+                               goto retry;
+                       goto unlock_return;
+               }
+               p = SMB_VWV(server->packet);
+               count = WVAL(p, 0);
+               if (count <= 0)
+                       break;
+
+               result = -EIO;
+               bcc = WVAL(p, 2);
+               if (bcc != count * SMB_DIRINFO_SIZE + 3)
+                       goto unlock_return;
+               p += 7;
+
+               /* Read the last entry into the status field. */
+               memcpy(status,
+                      SMB_BUF(server->packet) + 3 +
+                      (count - 1) * SMB_DIRINFO_SIZE,
+                      SMB_STATUS_SIZE);
+
+               /* Now we are ready to parse smb directory entries. */
+
+               for (i = 0; i < count; i++)
+               {
+                       struct cache_dirent this_ent, *entry = &this_ent;
+
+                       p = smb_decode_dirent(server, p, entry);
+                       if (entries_seen == 2 && entry->name[0] == '.')
+                       {
+                               if (entry->len == 1)
+                                       continue;
+                               if (entry->name[1] == '.' && entry->len == 2)
+                                       continue;
+                       }
+                       if (entries_seen >= fpos)
+                       {
+                               pr_debug("smb_proc_readdir: fpos=%u\n",
+                                       entries_seen);
+                               smb_add_to_cache(cachep, entry, entries_seen);
+                               entries++;
+                       } else
+                       {
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_proc_readdir: skipped, seen=%d, i=%d, fpos=%d\n",
+entries_seen, i, fpos);
+#endif
+                       }
+                       entries_seen++;
+               }
+       }
+       result = entries;
+
+    unlock_return:
+       smb_unlock_server(server);
+       return result;
+}

+/*
+ * Interpret a long filename structure using the specified info level:
+ *   level 1 for anything below NT1 protocol
+ *   level 260 for NT1 protocol
+ *
  * We return a reference to the name string to avoid copying, and perform
  * any needed upper/lower casing in place.

@@ -1320,7 +1520,7 @@
  */
 static char *
 smb_decode_long_dirent(struct smb_sb_info *server, char *p,
-                      struct cache_dirent *entry)
+                       struct cache_dirent *entry, int level)
 {
        char *result;
        unsigned int len = 0;
@@ -1330,19 +1530,47 @@
         */
        entry->ino = 0;

-       result = p + WVAL(p, 0);
-       len = DVAL(p, 60);
-       if (len > 255) len = 255;
-       /* NT4 null terminates */
-       entry->name = p + 94;
-       if (len && entry->name[len-1] == '\0')
-               len--;
-       entry->len = len;
+       switch (level)
+       {
+       case 1:
+               len = *((unsigned char *) p + 22);
+               entry->len = len;
+               entry->name = p + 23;
+               result = p + 24 + len;
+               break;
+
+       case 260: /* SMB_FIND_FILE_BOTH_DIRECTORY_INFO = 0x104 */
+               result = p + WVAL(p, 0);
+               len = DVAL(p, 60);
+               if (len > 255) len = 255;
+               /* NT4 null terminates */
+               entry->name = p + 94;
+               if (len && entry->name[len-1] == '\0')
+                       len--;
+               entry->len = len;
 #ifdef SMBFS_DEBUG_VERBOSE
        printk(KERN_DEBUG "smb_decode_long_dirent: info 260 at %p, len=%d,
name=%s\n",
               p, entry->len, entry->name);
 #endif
+               break;

+       default:
+               printk("smb_decode_long_dirent: Unknown level %d\n", level);
+               result = p + WVAL(p, 0);
+       }
+
+       switch (server->opt.case_handling)
+       {
+       case SMB_CASE_UPPER:
+               str_upper(entry->name, len);
+               break;
+       case SMB_CASE_LOWER:
+               str_lower(entry->name, len);
+               break;
+       default:
+               break;
+       }
+
        return result;
 }

@@ -1366,6 +1594,8 @@
        char *p, *mask, *param = server->temp_buf;
        __u16 command;
        int first, entries, entries_seen;
+
+       /* Both NT and OS/2 accept info level 1 (but see note below). */
        int info_level = 260;
        const int max_matches = 512;

@@ -1375,11 +1605,18 @@
        int resp_param_len = 0;
        int ff_searchcount = 0;
        int ff_eos = 0;
+       int ff_lastname = 0;
        int ff_dir_handle = 0;
        int loop_count = 0;
        int mask_len, i, result;
        static struct qstr star = { "*", 1, 0 };

+       /*
+        * use info level 1 for older servers that don't do 260
+        */
+       if (server->opt.protocol < SMB_PROTOCOL_NT1)
+               info_level = 1;
+
        smb_lock_server(server);

       retry:
@@ -1416,16 +1653,11 @@
                        command = TRANSACT2_FINDFIRST;
                        WSET(param, 0, aSYSTEM | aHIDDEN | aDIR);
                        WSET(param, 2, max_matches);    /* max count */
-                       WSET(param, 4,
-                            SMB_CONTINUE_BIT|SMB_CLOSE_IF_END);
+                       WSET(param, 4, SMB_CLOSE_IF_END);
                        WSET(param, 6, info_level);
                        DSET(param, 8, 0);
                } else
                {
-                       /* we don't need the mask after the first bit */
-                       mask_len = 0;
-                       mask[0] = 0;
-
                        command = TRANSACT2_FINDNEXT;
 #ifdef SMBFS_DEBUG_VERBOSE
 printk(KERN_DEBUG "smb_proc_readdir_long: handle=0x%X, mask=%s\n",
@@ -1485,10 +1717,12 @@
                        ff_dir_handle = WVAL(resp_param, 0);
                        ff_searchcount = WVAL(resp_param, 2);
                        ff_eos = WVAL(resp_param, 4);
+                       ff_lastname = WVAL(resp_param, 8);
                } else
                {
                        ff_searchcount = WVAL(resp_param, 0);
                        ff_eos = WVAL(resp_param, 2);
+                       ff_lastname = WVAL(resp_param, 6);
                }

                if (ff_searchcount == 0)
@@ -1496,6 +1730,18 @@
                        break;
                }

+               if (ff_lastname > 0 && info_level == 1)
+               {
+                       mask_len = *(resp_data + ff_lastname);
+                       memcpy(mask, resp_data + ff_lastname + 1,
+                              mask_len);
+                       mask[mask_len] = 0;
+               } else
+               {
+                       mask_len = 0;
+                       mask[0] = 0;
+               }
+
                /* Now we are ready to parse smb directory entries. */

                /* point to the data bytes */
@@ -1504,7 +1750,8 @@
                {
                        struct cache_dirent this_ent, *entry = &this_ent;

-                       p = smb_decode_long_dirent(server, p, entry);
+                       p = smb_decode_long_dirent(server, p, entry,
+                                                       info_level);

                        /* ignore . and .. from the server */
                        if (entries_seen == 2 && entry->name[0] == '.')
@@ -1540,7 +1787,98 @@
        struct smb_sb_info *server;

        server = server_from_dentry(dir);
-       return smb_proc_readdir_long(server, dir, fpos, cachep);
+       if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2)
+               return smb_proc_readdir_long(server, dir, fpos, cachep);
+       else
+               return smb_proc_readdir_short(server, dir, fpos, cachep);
+}
+
+/*
+ * This version uses the trans2 TRANSACT2_FINDFIRST message
+ * to get the attribute data.
+ * Note: called with the server locked.
+ *
+ * Bugs Noted:
+ */
+static int
+smb_proc_getattr_ff(struct smb_sb_info *server, struct dentry *dentry,
+                       struct smb_fattr *fattr)
+{
+       char *param = server->temp_buf, *mask = param + 12;
+       __u16 date, time;
+       unsigned char *resp_data = NULL;
+       unsigned char *resp_param = NULL;
+       int resp_data_len = 0;
+       int resp_param_len = 0;
+       int mask_len, result;
+
+retry:
+       mask_len = smb_encode_path(server, mask, dentry, NULL) - mask;
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_proc_getattr_ff: name=%s, len=%d\n", mask, mask_len);
+#endif
+       WSET(param, 0, aSYSTEM | aHIDDEN | aDIR);
+       WSET(param, 2, 1);      /* max count */
+       WSET(param, 4, 1);      /* close after this call */
+       WSET(param, 6, 1);      /* info_level */
+       DSET(param, 8, 0);
+
+       result = smb_trans2_request(server, TRANSACT2_FINDFIRST,
+                                   0, NULL, 12 + mask_len + 1, param,
+                                   &resp_data_len, &resp_data,
+                                   &resp_param_len, &resp_param);
+       if (result < 0)
+       {
+               if (smb_retry(server))
+                       goto retry;
+               goto out;
+       }
+       if (server->rcls != 0)
+       {
+               result = -smb_errno(server);
+#ifdef SMBFS_PARANOIA
+if (result != -ENOENT)
+printk("smb_proc_getattr_ff: error for %s, rcls=%d, err=%d\n",
+mask, server->rcls, server->err);
+#endif
+               goto out;
+       }
+       /* Make sure we got enough data ... */
+       result = -EINVAL;
+       if (resp_data_len < 22 || WVAL(resp_param, 2) != 1)
+       {
+#ifdef SMBFS_PARANOIA
+printk("smb_proc_getattr_ff: bad result for %s, len=%d, count=%d\n",
+mask, resp_data_len, WVAL(resp_param, 2));
+#endif
+               goto out;
+       }
+
+       /*
+        * Decode the response into the fattr ...
+        */
+       date = WVAL(resp_data, 0);
+       time = WVAL(resp_data, 2);
+       fattr->f_ctime = date_dos2unix(server, date, time);
+
+       date = WVAL(resp_data, 4);
+       time = WVAL(resp_data, 6);
+       fattr->f_atime = date_dos2unix(server, date, time);
+
+       date = WVAL(resp_data, 8);
+       time = WVAL(resp_data, 10);
+       fattr->f_mtime = date_dos2unix(server, date, time);
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_proc_getattr_ff: name=%s, date=%x, time=%x, mtime=%ld\n",
+mask, date, time, fattr->f_mtime);
+#endif
+       fattr->f_size = DVAL(resp_data, 12);
+       /* ULONG allocation size */
+       fattr->attr = WVAL(resp_data, 20);
+       result = 0;
+
+out:
+       return result;
 }

 /*
@@ -1687,12 +2025,20 @@

        /*
         * Select whether to use core or trans2 getattr.
-        * Win 95 appears to break with the trans2 getattr.
-        */
-       if (server->mnt->version & SMB_FIX_WIN95) {
-               result = smb_proc_getattr_core(server, dir, fattr);
+        */
+       if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2) {
+               /*
+                * Win 95 appears to break with the trans2 getattr.
+                */
+               if (server->mnt->version & (SMB_FIX_OLDATTR|SMB_FIX_WIN95))
+                       goto core_attr;
+               if (server->mnt->version & SMB_FIX_DIRATTR)
+                       result = smb_proc_getattr_ff(server, dir, fattr);
+               else
+                       result = smb_proc_getattr_trans2(server, dir, fattr);
        } else {
-               result = smb_proc_getattr_trans2(server, dir, fattr);
+       core_attr:
+               result = smb_proc_getattr_core(server, dir, fattr);
        }

        smb_finish_dirent(server, fattr);
@@ -1906,7 +2252,8 @@
 #endif
        smb_lock_server(server);
        /* setting the time on a Win95 server fails (tridge) */
-       if (!(server->mnt->version & SMB_FIX_WIN95))
+       if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2 &&
+           !(server->mnt->version & SMB_FIX_WIN95))
        {
                if (smb_is_open(inode) &&


More information about the samba mailing list