[PATCH] cifs: add support for chattr/lsattr in new CIFS POSIX extensions
Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
1da0c78b32
commit
f654bac222
6 changed files with 211 additions and 13 deletions
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,15 +2003,40 @@ 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
|
||||
|
||||
#pragma pack() /* resume default structure packing */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -2072,7 +2072,91 @@ CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
|
|||
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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue