aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorSteve French <stevef@steveft21.ltcsamba>2004-07-26 20:02:46 -0500
committerSteve French <cifs.adm@hostme.bitkeeper.com>2004-07-26 20:02:46 -0500
commit5b64aaf91c597ab43817a5f347179cb69cc0a211 (patch)
tree71a47982d27fcdc9fd774d3cb889561b35b94c22 /fs
parent05a15ce59ffb7f96847f73b9b82bcf077bc2562b (diff)
downloadhistory-5b64aaf91c597ab43817a5f347179cb69cc0a211.tar.gz
[CIFS] xattr support part 4 add set EA support
Signed-off-by: Steve French (sfrench@us.ibm.com)
Diffstat (limited to 'fs')
-rw-r--r--fs/cifs/cifspdu.h2
-rw-r--r--fs/cifs/cifsproto.h8
-rw-r--r--fs/cifs/cifssmb.c115
-rw-r--r--fs/cifs/xattr.c27
4 files changed, 140 insertions, 12 deletions
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 20351015823d12..94646af9f84ddc 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -1046,6 +1046,8 @@ typedef union smb_com_transaction2 {
/* PathInfo/FileInfo infolevels */
#define SMB_INFO_STANDARD 1
+#define SMB_SET_FILE_EA 2
+#define SMB_QUERY_FILE_EA_SIZE 2
#define SMB_INFO_QUERY_EAS_FROM_LIST 3
#define SMB_INFO_QUERY_ALL_EAS 4
#define SMB_INFO_IS_NAME_VALID 6
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index e5ed8292cc9770..8273700778d3d9 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -128,10 +128,10 @@ extern int CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon,
const struct nls_table *nls_codepage);
extern int CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon,
- char *fileName, FILE_BASIC_INFO * data,
+ const char *fileName, const FILE_BASIC_INFO * data,
const struct nls_table *nls_codepage);
extern int CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon,
- char *fileName, __u64 size,int setAllocationSizeFlag,
+ const char *fileName, __u64 size,int setAllocationSizeFlag,
const struct nls_table *nls_codepage);
extern int CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon,
__u64 size, __u16 fileHandle,__u32 opener_pid, int AllocSizeFlag);
@@ -229,4 +229,8 @@ extern ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
const unsigned char * searchName,const unsigned char * ea_name,
unsigned char * ea_value, size_t buf_size,
const struct nls_table *nls_codepage);
+extern int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon,
+ const char *fileName, const char * ea_name,
+ const void * ea_value, const __u16 ea_value_len,
+ const struct nls_table *nls_codepage);
#endif /* _CIFSPROTO_H */
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 962adc7ab9daab..cb26572ce826d6 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -2287,7 +2287,7 @@ QFSInfoRetry:
}
int
-CIFSSMBQFSAttributeInfo(int xid, struct cifsTconInfo *tcon,
+CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon,
const struct nls_table *nls_codepage)
{
/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
@@ -2359,7 +2359,7 @@ QFSAttributeRetry:
}
int
-CIFSSMBQFSDeviceInfo(int xid, struct cifsTconInfo *tcon,
+CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon,
const struct nls_table *nls_codepage)
{
/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
@@ -2432,7 +2432,7 @@ QFSDeviceRetry:
}
int
-CIFSSMBQFSUnixInfo(int xid, struct cifsTconInfo *tcon,
+CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon,
const struct nls_table *nls_codepage)
{
/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
@@ -2512,7 +2512,7 @@ QFSUnixRetry:
in Samba which this routine can run into */
int
-CIFSSMBSetEOF(int xid, struct cifsTconInfo *tcon, char *fileName,
+CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
__u64 size, int SetAllocation, const struct nls_table *nls_codepage)
{
struct smb_com_transaction2_spi_req *pSMB = NULL;
@@ -2692,8 +2692,9 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
}
int
-CIFSSMBSetTimes(int xid, struct cifsTconInfo *tcon, char *fileName,
- FILE_BASIC_INFO * data, const struct nls_table *nls_codepage)
+CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
+ const FILE_BASIC_INFO * data,
+ const struct nls_table *nls_codepage)
{
TRANSACTION2_SPI_REQ *pSMB = NULL;
TRANSACTION2_SPI_RSP *pSMBr = NULL;
@@ -3290,4 +3291,106 @@ QEARetry:
return rc;
}
+int
+CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
+ const char * ea_name, const void * ea_value,
+ const __u16 ea_value_len, const struct nls_table *nls_codepage)
+{
+ struct smb_com_transaction2_spi_req *pSMB = NULL;
+ struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
+ struct fealist *parm_data;
+ int name_len;
+ int rc = 0;
+ int bytes_returned = 0;
+
+ cFYI(1, ("In SetEA"));
+SetEARetry:
+ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+ name_len =
+ cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530
+ /* find define for this maxpathcomponent */
+ , nls_codepage);
+ name_len++; /* trailing null */
+ name_len *= 2;
+ } else { /* BB improve the check for buffer overruns BB */
+ name_len = strnlen(fileName, 530);
+ name_len++; /* trailing null */
+ strncpy(pSMB->FileName, fileName, name_len);
+ }
+
+ pSMB->ParameterCount = 6 + name_len;
+
+ /* done calculating parms using name_len of file name,
+ now use name_len to calculate length of ea name
+ we are going to create in the inode xattrs */
+ if(ea_name == NULL)
+ name_len = 0;
+ else
+ name_len = strnlen(ea_name,255);
+
+ pSMB->DataCount = sizeof(*parm_data) + ea_value_len + name_len + 1;
+ pSMB->MaxParameterCount = cpu_to_le16(2);
+ pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
+ pSMB->MaxSetupCount = 0;
+ pSMB->Reserved = 0;
+ pSMB->Flags = 0;
+ pSMB->Timeout = 0;
+ pSMB->Reserved2 = 0;
+ pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req,
+ InformationLevel) - 4;
+ pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
+ pSMB->InformationLevel =
+ cpu_to_le16(SMB_SET_FILE_EA);
+
+ parm_data =
+ (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
+ pSMB->DataOffset);
+ pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
+ pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
+ pSMB->SetupCount = 1;
+ pSMB->Reserved3 = 0;
+ pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
+ pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount;
+ pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
+ parm_data->list_len = (__u32)(pSMB->DataCount);
+ parm_data->list[0].EA_flags = 0;
+ /* we checked above that name len is less than 255 */
+ parm_data->list[0].name_len = (__u8)name_len;;
+ /* EA names are always ASCII */
+ strncpy(parm_data->list[0].name,ea_name,name_len);
+ parm_data->list[0].name[name_len] = 0;
+ parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
+ /* caller ensures that ea_value_len is less than 64K but
+ we need to ensure that it fits within the smb */
+
+ /*BB add length check that it would fit in negotiated SMB buffer size BB */
+ /* if(ea_value_len > buffer_size - 512 (enough for header)) */
+ memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
+
+ pSMB->TotalDataCount = pSMB->DataCount;
+ pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
+ pSMB->TotalParameterCount = pSMB->ParameterCount;
+ pSMB->Reserved4 = 0;
+ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc) {
+ cFYI(1, ("SetPathInfo (EA) returned %d", rc));
+ }
+
+ if (pSMB)
+ cifs_buf_release(pSMB);
+
+ if (rc == -EAGAIN)
+ goto SetEARetry;
+
+ return rc;
+}
+
#endif
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c
index 0fd073d398eff5..0e6b36b4ec8710 100644
--- a/fs/cifs/xattr.c
+++ b/fs/cifs/xattr.c
@@ -26,6 +26,7 @@
#include "cifsproto.h"
#include "cifs_debug.h"
+#define MAX_EA_VALUE_SIZE 65535
#define CIFS_XATTR_DOS_ATTRIB "user.DOSATTRIB"
#define CIFS_XATTR_USER_PREFIX "user."
#define CIFS_XATTR_SYSTEM_PREFIX "system."
@@ -40,7 +41,7 @@ int cifs_removexattr(struct dentry * direntry, const char * name)
}
int cifs_setxattr(struct dentry * direntry, const char * ea_name,
- const void * ea_value, size_t buf_size, int flags)
+ const void * ea_value, size_t value_size, int flags)
{
int rc = -EOPNOTSUPP;
#ifdef CONFIG_CIFS_XATTR
@@ -75,8 +76,26 @@ int cifs_setxattr(struct dentry * direntry, const char * ea_name,
/* if proc/fs/cifs/streamstoxattr is set then
search server for EAs or streams to
returns as xattrs */
-/* rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,ea_value,buf_size,
- cifs_sb->local_nls);*/
+ if(value_size > MAX_EA_VALUE_SIZE) {
+ cFYI(1,("size of EA value too large"));
+ if(full_path)
+ kfree(full_path);
+ FreeXid(xid);
+ return -EOPNOTSUPP;
+ }
+
+ if(ea_name == NULL) {
+ cFYI(1,("Null xattr names not supported"));
+ } else if(strncmp(ea_name,CIFS_XATTR_USER_PREFIX,5)) {
+ cFYI(1,("illegal xattr namespace %s (only user namespace supported)",ea_name));
+ /* BB what if no namespace prefix? */
+ /* Should we just pass them to server, except for
+ system and perhaps security prefixes? */
+ } else {
+ ea_name+=5; /* skip past user. prefix */
+ rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,ea_value,
+ (__u16)value_size, cifs_sb->local_nls);
+ }
if (full_path)
kfree(full_path);
FreeXid(xid);
@@ -116,7 +135,7 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name,
}
/* return dos attributes as pseudo xattr */
/* return alt name if available as pseudo attr */
- if(memcmp(ea_name,CIFS_XATTR_USER_PREFIX,5)) {
+ if(strncmp(ea_name,CIFS_XATTR_USER_PREFIX,5)) {
cFYI(1,("illegal xattr namespace %s (only user namespace supported)",ea_name));
/* BB what if no namespace prefix? */
/* Should we just pass them to server, except for system? */