[PATCH] cifs: add support for chattr/lsattr in new CIFS POSIX extensions
authorSteve French <smfrench@austin.rr.com>
Fri, 29 Apr 2005 05:41:04 +0000 (22:41 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Fri, 29 Apr 2005 05:41:04 +0000 (22:41 -0700)
Signed-off-by: Steve French (sfrench@us.ibm.com)
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
fs/cifs/CHANGES
fs/cifs/cifsfs.h
fs/cifs/cifspdu.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/ioctl.c

index 5316c8d..7fd0269 100644 (file)
@@ -1,7 +1,14 @@
-Version 1.31
+Version 1.32
 ------------
 Fix oops in ls when Transact2 FindFirst (or FindNext) returns more than one
 transact response for an SMB request and search entry split across two frames.
+Add support for lsattr (getting ext2/ext3/reiserfs attr flags from the server)
+as new protocol extensions. Do not send Get/Set calls for POSIX ACLs
+unless server explicitly claims to support them in CIFS Unix extensions
+POSIX ACL capability bit.
+
+Version 1.31
+------------
 Fix updates of DOS attributes and time fields so that files on NT4 servers
 do not get marked delete on close. Display sizes of cifs buffer pools in
 cifs stats. Fix oops in unmount when cifsd thread being killed by 
index 451f18a..e0e46f4 100644 (file)
@@ -91,8 +91,10 @@ extern int cifs_symlink(struct inode *inode, struct dentry *direntry,
                        const char *symname);
 extern int     cifs_removexattr(struct dentry *, const char *);
 extern int     cifs_setxattr(struct dentry *, const char *, const void *,
-                        size_t, int);
+                       size_t, int);
 extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t);
 extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
-#define CIFS_VERSION   "1.31"
+extern int cifs_ioctl (struct inode * inode, struct file * filep,
+                      unsigned int command, unsigned long arg);
+#define CIFS_VERSION   "1.32"
 #endif                         /* _CIFSFS_H */
index bcd4a61..085109d 100644 (file)
@@ -762,6 +762,16 @@ typedef struct smb_com_lock_req {
        LOCKING_ANDX_RANGE Locks[1];
 } LOCK_REQ;
 
+
+typedef struct cifs_posix_lock {
+       __le16  lock_type;  /* 0 = Read, 1 = Write, 2 = Unlock */
+       __le16  lock_flags; /* 1 = Wait (only valid for setlock) */
+       __le32  pid;
+       __le64  start;
+       __le64  length;
+       /* BB what about additional owner info to identify network client */
+} CIFS_POSIX_LOCK;
+
 typedef struct smb_com_lock_rsp {
        struct smb_hdr hdr;     /* wct = 2 */
        __u8 AndXCommand;
@@ -1098,6 +1108,8 @@ struct smb_t2_rsp {
 #define SMB_QUERY_POSIX_ACL             0x204
 #define SMB_QUERY_XATTR                 0x205
 #define SMB_QUERY_ATTR_FLAGS            0x206  /* append,immutable etc. */
+#define SMB_QUERY_POSIX_PERMISSION      0x207
+#define SMB_QUERY_POSIX_LOCK            0x208
 #define SMB_QUERY_FILE_INTERNAL_INFO    0x3ee
 #define SMB_QUERY_FILE_ACCESS_INFO      0x3f0
 #define SMB_QUERY_FILE_NAME_INFO2       0x3f1 /* 0x30 bytes */
@@ -1116,6 +1128,7 @@ struct smb_t2_rsp {
 #define SMB_SET_POSIX_ACL               0x204
 #define SMB_SET_XATTR                   0x205
 #define SMB_SET_ATTR_FLAGS              0x206  /* append, immutable etc. */
+#define SMB_SET_POSIX_LOCK              0x208
 #define SMB_SET_FILE_BASIC_INFO2        0x3ec
 #define SMB_SET_FILE_RENAME_INFORMATION 0x3f2 /* BB check if qpathinfo level too */
 #define SMB_FILE_ALL_INFO2              0x3fa
@@ -1237,9 +1250,27 @@ struct smb_com_transaction2_sfi_rsp {
        struct smb_hdr hdr;     /* wct = 10 + SetupCount */
        struct trans2_resp t2;
        __u16 ByteCount;
-       __u16 Reserved2;        /* parameter word reserved - present for infolevels > 100 */
+       __u16 Reserved2;        /* parameter word reserved - 
+                                       present for infolevels > 100 */
+};
+
+struct smb_t2_qfi_req {
+        struct smb_hdr hdr;
+        struct trans2_req t2;
+       __u8    Pad;
+       __u16   Pad1;
+       __u16   Fid;
+       __le16  InformationLevel;
+       __u16   Pad2;
 };
 
+struct smb_t2_qfi_rsp {
+        struct smb_hdr hdr;     /* wct = 10 + SetupCount */
+        struct trans2_resp t2;
+        __u16 ByteCount;
+        __u16 Reserved2;        /* parameter word reserved - 
+                                       present for infolevels > 100 */
+};
 
 /*
  * Flags on T2 FINDFIRST and FINDNEXT 
@@ -1524,8 +1555,9 @@ typedef struct {
 } FILE_SYSTEM_UNIX_INFO;       /* Unix extensions info, level 0x200 */
 /* Linux/Unix extensions capability flags */
 #define CIFS_UNIX_FCNTL_CAP             0x00000001 /* support for fcntl locks */
-#define CIFS_UNIX_POSIX_ACL_CAP         0x00000002
-#define CIFS_UNIX_XATTR_CAP             0x00000004 /*support for new namespace*/
+#define CIFS_UNIX_POSIX_ACL_CAP         0x00000002 /* support getfacl/setfacl */
+#define CIFS_UNIX_XATTR_CAP             0x00000004 /* support new namespace   */
+#define CIFS_UNIX_EXTATTR_CAP           0x00000008 /* support chattr/chflag   */
 
 typedef struct {
        /* For undefined recommended transfer size return -1 in that field */
@@ -1971,14 +2003,39 @@ struct xsymlink {
        char path[1024];  
 };
 
-typedef struct {
+typedef struct file_xattr_info {
        /* BB do we need another field for flags? BB */
        __u32 xattr_name_len;
        __u32 xattr_value_len;
        char  xattr_name[0];
        /* followed by xattr_value[xattr_value_len], no pad */
-} FILE_XATTR_INFO;     /* extended attribute, info level 205 */
-
+} FILE_XATTR_INFO;     /* extended attribute, info level 0x205 */
+
+
+/* flags for chattr command */
+#define EXT_SECURE_DELETE              0x00000001 /* EXT3_SECRM_FL */
+#define EXT_ENABLE_UNDELETE            0x00000002 /* EXT3_UNRM_FL */
+/* Reserved for compress file 0x4 */
+#define EXT_SYNCHRONOUS                        0x00000008 /* EXT3_SYNC_FL */
+#define EXT_IMMUTABLE_FL               0x00000010 /* EXT3_IMMUTABLE_FL */
+#define EXT_OPEN_APPEND_ONLY           0x00000020 /* EXT3_APPEND_FL */
+#define EXT_DO_NOT_BACKUP              0x00000040 /* EXT3_NODUMP_FL */
+#define EXT_NO_UPDATE_ATIME            0x00000080 /* EXT3_NOATIME_FL */
+/* 0x100 through 0x800 reserved for compression flags and are GET-ONLY */
+#define EXT_HASH_TREE_INDEXED_DIR      0x00001000 /* GET-ONLY EXT3_INDEX_FL */
+/* 0x2000 reserved for IMAGIC_FL */
+#define EXT_JOURNAL_THIS_FILE  0x00004000 /* GET-ONLY EXT3_JOURNAL_DATA_FL */
+/* 0x8000 reserved for EXT3_NOTAIL_FL */
+#define EXT_SYNCHRONOUS_DIR            0x00010000 /* EXT3_DIRSYNC_FL */
+#define EXT_TOPDIR                     0x00020000 /* EXT3_TOPDIR_FL */
+
+#define EXT_SET_MASK                   0x000300FF
+#define EXT_GET_MASK                   0x0003DFFF
+
+typedef struct file_chattr_info {
+       __le64  mask; /* list of all possible attribute bits */
+       __le64  mode; /* list of actual attribute bits on this inode */
+} FILE_CHATTR_INFO;  /* ext attributes (chattr, chflags) level 0x206 */
 
 #endif 
 
index 787eef4..82ae59d 100644 (file)
@@ -264,6 +264,8 @@ extern int CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
                const unsigned char *fileName,
                const char *local_acl, const int buflen, const int acl_type,
                const struct nls_table *nls_codepage);
-int cifs_ioctl (struct inode * inode, struct file * filep,
+extern int CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
+                const int netfid, __u64 * pExtAttrBits, __u64 *pMask);
+extern int cifs_ioctl (struct inode * inode, struct file * filep,
                 unsigned int command, unsigned long arg);
 #endif                 /* _CIFSPROTO_H */
index df6a619..36d3c12 100644 (file)
@@ -2072,7 +2072,91 @@ setACLerrorExit:
        return rc;
 }
 
-#endif
+/* BB fix tabs in this function FIXME BB */
+int
+CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
+                const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
+{
+        int rc = 0;
+        struct smb_t2_qfi_req *pSMB = NULL;
+        struct smb_t2_qfi_rsp *pSMBr = NULL;
+        int bytes_returned;
+        __u16 params, byte_count;
+
+        cFYI(1,("In GetExtAttr"));
+        if(tcon == NULL)
+                return -ENODEV;
+
+GetExtAttrRetry:
+        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+                      (void **) &pSMBr);
+        if (rc)
+                return rc;
+
+        params = 2 /* level */ +2 /* fid */ + 2 /* rsrvd */;
+        pSMB->t2.TotalDataCount = 0;
+        pSMB->t2.MaxParameterCount = cpu_to_le16(2);
+        /* BB find exact max data count below from sess structure BB */
+        pSMB->t2.MaxDataCount = cpu_to_le16(4000);
+        pSMB->t2.MaxSetupCount = 0;
+        pSMB->t2.Reserved = 0;
+        pSMB->t2.Flags = 0;
+        pSMB->t2.Timeout = 0;
+        pSMB->t2.Reserved2 = 0;
+        pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(
+                struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+        pSMB->t2.DataCount = 0;
+        pSMB->t2.DataOffset = 0;
+        pSMB->t2.SetupCount = 1;
+        pSMB->t2.Reserved3 = 0;
+        pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
+        byte_count = params + 3 /* pad */ ;
+        pSMB->t2.TotalParameterCount = cpu_to_le16(params);
+        pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
+        pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
+        pSMB->Pad1 = 0;
+       pSMB->Pad2 = 0;
+       pSMB->Fid = netfid;
+        pSMB->hdr.smb_buf_length += byte_count;
+        pSMB->t2.ByteCount = cpu_to_le16(byte_count);
+
+        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+                (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+        if (rc) {
+                cFYI(1, ("error %d in GetExtAttr", rc));
+        } else {
+                /* decode response */
+                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+                if (rc || (pSMBr->ByteCount < 2))
+                /* BB also check enough total bytes returned */
+                        /* If rc should we check for EOPNOSUPP and
+                        disable the srvino flag? or in caller? */
+                        rc = -EIO;      /* bad smb */
+                else {
+                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
+                        __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
+                        struct file_chattr_info * pfinfo;
+                        /* BB Do we need a cast or hash here ? */
+                        if(count != 16) {
+                                cFYI(1, ("Illegal size ret in GetExtAttr"));
+                                rc = -EIO;
+                                goto GetExtAttrOut;
+                        }
+                        pfinfo = (struct file_chattr_info *)
+                                (data_offset + (char *) &pSMBr->hdr.Protocol);
+                        *pExtAttrBits = le64_to_cpu(pfinfo->mode);
+                       *pMask = le64_to_cpu(pfinfo->mask);
+                }
+        }
+GetExtAttrOut:
+        cifs_buf_release(pSMB);
+        if (rc == -EAGAIN)
+                goto GetExtAttrRetry;
+        return rc;
+}
+
+
+#endif /* CONFIG_POSIX */
 
 int
 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
index b4b8e20..7b84b2b 100644 (file)
@@ -20,6 +20,7 @@
  *   along with this library; if not, write to the Free Software
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
+
 #include <linux/fs.h>
 #include <linux/ext2_fs.h>
 #include "cifspdu.h"
@@ -32,18 +33,63 @@ int cifs_ioctl (struct inode * inode, struct file * filep,
 {
        int rc = -ENOTTY; /* strange error - but the precedent */
 #ifdef CONFIG_CIFS_POSIX
+       __u64   ExtAttrBits = 0;
+       __u64   ExtAttrMask = 0;
+       __u64   caps;
+#endif /* CONFIG_CIFS_POSIX */
+       int xid;
+       struct cifs_sb_info *cifs_sb;
+       struct cifsTconInfo *tcon;
+       struct cifsFileInfo *pSMBFile =
+               (struct cifsFileInfo *)filep->private_data;
+
+       xid = GetXid();
+
+       cifs_sb = CIFS_SB(inode->i_sb);
+       tcon = cifs_sb->tcon;
+       if (pSMBFile == NULL)
+               goto cifs_ioctl_out;
+
+#ifdef CONFIG_CIFS_POSIX
+       if(tcon)
+               caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
+       else {
+               rc = -EIO;
+               goto cifs_ioctl_out;
+       }
+
        cFYI(1,("ioctl file %p  cmd %u  arg %lu",filep,command,arg));
        switch(command) {
                case EXT2_IOC_GETFLAGS:
-                       cFYI(1,("get flags not implemented yet"));
-                       return -EOPNOTSUPP;
+                       if(CIFS_UNIX_EXTATTR_CAP & caps) {
+                               rc = CIFSGetExtAttr(xid, tcon, pSMBFile->netfid,
+                                       &ExtAttrBits, &ExtAttrMask);
+                               if(rc == 0)
+                                       rc = put_user(ExtAttrBits &
+                                               EXT2_FL_USER_VISIBLE,
+                                               (int __user *)arg);
+                       }
+                       break;
+
                case EXT2_IOC_SETFLAGS:
+                       if(CIFS_UNIX_EXTATTR_CAP & caps) {
+                               if(get_user(ExtAttrBits,(int __user *)arg)) {
+                                       rc = -EFAULT;
+                                       goto cifs_ioctl_out;
+                               }
+                         /* rc = CIFSGetExtAttr(xid, tcon, pSMBFile->netfid,
+                                       extAttrBits, &ExtAttrMask);*/
+                               
+                       }
                        cFYI(1,("set flags not implemented yet"));
-                       return -EOPNOTSUPP;
+                       break;
                default:
                        cFYI(1,("unsupported ioctl"));
                        return rc;
        }
 #endif /* CONFIG_CIFS_POSIX */
+
+cifs_ioctl_out:
+       FreeXid(xid);
        return rc;
 }