diff options
| -rw-r--r-- | fs/Kconfig | 16 | ||||
| -rw-r--r-- | fs/cifs/CHANGES | 18 | ||||
| -rw-r--r-- | fs/cifs/README | 28 | ||||
| -rw-r--r-- | fs/cifs/cifs_fs_sb.h | 4 | ||||
| -rw-r--r-- | fs/cifs/cifsfs.c | 13 | ||||
| -rw-r--r-- | fs/cifs/cifsfs.h | 4 | ||||
| -rw-r--r-- | fs/cifs/cifsglob.h | 4 | ||||
| -rw-r--r-- | fs/cifs/cifspdu.h | 23 | ||||
| -rw-r--r-- | fs/cifs/cifsproto.h | 44 | ||||
| -rw-r--r-- | fs/cifs/cifssmb.c | 401 | ||||
| -rw-r--r-- | fs/cifs/connect.c | 38 | ||||
| -rw-r--r-- | fs/cifs/dir.c | 23 | ||||
| -rw-r--r-- | fs/cifs/inode.c | 20 | ||||
| -rw-r--r-- | fs/cifs/smbencrypt.c | 2 | ||||
| -rw-r--r-- | fs/cifs/smberr.h | 3 | ||||
| -rw-r--r-- | fs/cifs/xattr.c | 172 | ||||
| -rw-r--r-- | net/sched/Kconfig | 3 |
17 files changed, 734 insertions, 82 deletions
diff --git a/fs/Kconfig b/fs/Kconfig index 5e7c10fa8f8f..82810094fdce 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -1652,6 +1652,22 @@ config CIFS_STATS Enabling this option will cause statistics for each server share mounted by the cifs client to be displayed in /proc/fs/cifs/Stats +config CIFS_XATTR + bool "CIFS extended attributes (EXPERIMENTAL)" + depends on CIFS + help + Extended attributes are name:value pairs associated with inodes by + the kernel or by users (see the attr(5) manual page, or visit + <http://acl.bestbits.at/> for details). CIFS maps the name of + extended attributes beginning with the user namespace prefix + to SMB/CIFS EAs. EAs are stored on Windows servers without the + user namespace prefix, but their names are seen by Linux cifs clients + prefaced by the user namespace prefix. The system namespace + (used by some filesystems to store ACLs) is not supported at + this time. + + If unsure, say N. + config CIFS_POSIX bool "CIFS POSIX Extensions (EXPERIMENTAL)" depends on CIFS diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 3f1663754388..a853ec02e494 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -1,3 +1,21 @@ +Version 1.22 +------------ +Add config option to enable XATTR (extended attribute) support, mapping +xattr names in the "user." namespace space to SMB/CIFS EAs. + +Version 1.21 +------------ +Add new mount parm to control whether mode check (vfs_permission) is done on +the client. If Unix extensions are enabled and the uids on the client +and server do not match, client permission checks are meaningless on +server uids that do not exist on the client (this does not affect the +normal ACL check which occurs on the server). Fix default uid +on mknod to match create and mkdir. Add optional mount parm to allow +override of the default uid behavior (in which the server sets the uid +and gid of newly created files). Normally for network filesystem mounts +user want the server to set the uid/gid on newly created files (rather than +using uid of the client processes you would in a local filesystem). + Version 1.20 ------------ Make transaction counts more consistent. Merge /proc/fs/cifs/SimultaneousOps diff --git a/fs/cifs/README b/fs/cifs/README index 59a00eea0b35..799530255b28 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -255,7 +255,33 @@ A partial list of the supported mount options follows: mount helper will not prompt the user for a password if guest is specified on the mount options. If no password is specified a null password will be used. - + perm Client does permission checks (vfs_permission check of uid + and gid of the file against the mode and desired operation), + Note that this is in addition to the normal ACL check on the + target machine done by the server software. + Client permission checking is enabled by default. + noperm Client does not do permission checks. This can expose + files on this mount to access by other users on the local + client system. It is typically only needed when the server + supports the CIFS Unix Extensions but the UIDs/GIDs on the + client and server system do not match closely enough to allow + access by the user doing the mount. + Note that this does not affect the normal ACL check on the + target machine done by the server software (of the server + ACL against the user name provided at mount time). + setuids If the CIFS Unix extensions are negotiated with the server + the client will attempt to set the effective uid and gid of + the local process on newly created files, directories, and + devices (create, mkdir, mknod). + nosetuids The client will not attempt to set the uid and gid on + on newly created files, directories, and devices (create, + mkdir, mknod) which will result in the server setting the + uid and gid to the default (usually the server uid of the + usern who mounted the share). Letting the server (rather than + the client) set the uid and gid is the default. This + parameter has no effect if the CIFS Unix Extensions are not + negotiated. + The mount.cifs mount helper also accepts a few mount options before -o including: diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index 8007c2e925f5..592af83bcb9c 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h @@ -18,6 +18,9 @@ #ifndef _CIFS_FS_SB_H #define _CIFS_FS_SB_H +#define CIFS_MOUNT_NO_PERM 1 /* do not do client vfs_perm check */ +#define CIFS_MOUNT_SET_UID 2 /* set current->euid in create etc. */ + struct cifs_sb_info { struct cifsTconInfo *tcon; /* primary mount */ struct list_head nested_tcon_q; @@ -28,5 +31,6 @@ struct cifs_sb_info { gid_t mnt_gid; mode_t mnt_file_mode; mode_t mnt_dir_mode; + int mnt_cifs_flags; }; #endif /* _CIFS_FS_SB_H */ diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 0170ad6bcd03..2607ce38a697 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -41,8 +41,6 @@ #include "cifs_fs_sb.h" #include <linux/mm.h> #define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */ -/* BB when mempool_resize is added back in, we will resize pool on new mount */ -#define CIFS_MIN_RCV_POOL 11 /* enough for progress to five servers */ #ifdef CONFIG_CIFS_QUOTA static struct quotactl_ops cifs_quotactl_ops; @@ -192,15 +190,11 @@ cifs_statfs(struct super_block *sb, struct kstatfs *buf) static int cifs_permission(struct inode * inode, int mask, struct nameidata *nd) { - struct cifs_sb_info *cifs_sb; + struct cifs_sb_info *cifs_sb; - cifs_sb = CIFS_SB(inode->i_sb); + cifs_sb = CIFS_SB(inode->i_sb); - if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) { - /* the server supports the Unix-like mode bits and does its - own permission checks, and therefore we do not allow the file - mode to be overriden on these mounts - so do not do perm - check on client side */ + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) { return 0; } else /* file mode might have been restricted at mount time on the client (above and beyond ACL on servers) for @@ -746,6 +740,7 @@ init_cifs(void) */ atomic_set(&sesInfoAllocCount, 0); atomic_set(&tconInfoAllocCount, 0); + atomic_set(&tcpSesAllocCount,0); atomic_set(&tcpSesReconnectCount, 0); atomic_set(&tconInfoReconnectCount, 0); diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index eb7809eefcfb..258442eea695 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -32,14 +32,10 @@ #define TRUE 1 #endif -extern int map_cifs_error(int error_class, int error_code, - int status_codes_negotiated); - extern struct address_space_operations cifs_addr_ops; /* Functions related to super block operations */ extern struct super_operations cifs_super_ops; -extern void cifs_put_inode(struct inode *); extern void cifs_read_inode(struct inode *); extern void cifs_delete_inode(struct inode *); /* extern void cifs_write_inode(struct inode *); *//* BB not needed yet */ diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index cfbfac7a74b6..21ac75cf02d7 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -32,6 +32,8 @@ termination then *2 for unicode versions */ #define MAX_PASSWORD_SIZE 16 +#define CIFS_MIN_RCV_POOL 4 + /* * MAX_REQ is the maximum number of requests that WE will send * on one socket concurently. It also matches the most common @@ -391,7 +393,7 @@ GLOBAL_EXTERN char Local_System_Name[15]; */ GLOBAL_EXTERN atomic_t sesInfoAllocCount; GLOBAL_EXTERN atomic_t tconInfoAllocCount; - +GLOBAL_EXTERN atomic_t tcpSesAllocCount; GLOBAL_EXTERN atomic_t tcpSesReconnectCount; GLOBAL_EXTERN atomic_t tconInfoReconnectCount; diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 067eb4e3eebb..94646af9f84d 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 @@ -1620,6 +1622,19 @@ typedef struct { char LinkDest[1]; } FILE_UNIX_LINK_INFO; /* level 513 QPathInfo */ +typedef struct { + __u16 CreationDate; + __u16 CreationTime; + __u16 LastAccessDate; + __u16 LastAccessTime; + __u16 LastWriteDate; + __u16 LastWriteTime; + __u32 DataSize; /* File Size (EOF) */ + __u32 AllocationSize; + __u16 Attributes; /* verify not u32 */ + __u32 EASize; +} FILE_INFO_STANDARD; /* level 1 SetPath/FileInfo */ + /* defines for enumerating possible values of the Unix type field below */ #define UNIX_FILE 0 #define UNIX_DIR 1 @@ -1680,12 +1695,12 @@ typedef struct { } FILE_DIRECTORY_INFO; /* level 257 FF response data area */ struct gea { - unsigned char cbName; - char szName[1]; + unsigned char name_len; + char name[1]; }; struct gealist { - unsigned long cbList; + unsigned long list_len; struct gea list[1]; }; @@ -1693,7 +1708,7 @@ struct fea { unsigned char EA_flags; __u8 name_len; __u16 value_len; - char szName[1]; + char name[1]; /* optionally followed by value */ }; /* flags for _FEA.fEA */ diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 215bbc1960bb..8273700778d3 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); @@ -213,31 +213,6 @@ extern int cifs_verify_signature(const struct smb_hdr *, const char * mac_key, extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass); extern void CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, struct nls_table *); extern void CalcNTLMv2_response(const struct cifsSesInfo *,char * ); - -extern int CIFSBuildServerList(int xid, char *serverBufferList, - int recordlength, int *entries, - int *totalEntries, int *topoChangedFlag); -extern int CIFSSMBQueryShares(int xid, struct cifsTconInfo *tcon, - struct shareInfo *shareList, int bufferLen, - int *entries, int *totalEntries); -extern int CIFSSMBQueryAlias(int xid, struct cifsTconInfo *tcon, - struct aliasInfo *aliasList, int bufferLen, - int *entries, int *totalEntries); -extern int CIFSSMBAliasInfo(int xid, struct cifsTconInfo *tcon, - char *aliasName, char *serverName, - char *shareName, char *comment); -extern int CIFSSMBGetShareInfo(int xid, struct cifsTconInfo *tcon, - char *share, char *comment); -extern int CIFSSMBGetUserPerms(int xid, struct cifsTconInfo *tcon, - char *userName, char *searchName, int *perms); -extern int CIFSSMBSync(int xid, struct cifsTconInfo *tcon, int netfid, int pid); - -extern int CIFSSMBSeek(int xid, - struct cifsTconInfo *tcon, - int netfid, - int pid, - int whence, unsigned long offset, long long *newoffset); - extern int CIFSSMBCopy(int xid, struct cifsTconInfo *source_tcon, const char *fromName, @@ -247,8 +222,15 @@ extern int CIFSSMBCopy(int xid, extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, const int notify_subdirs,const __u16 netfid,__u32 filter, const struct nls_table *nls_codepage); -extern int CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, - const unsigned char *searchName, - char * EAData, size_t size, - const struct nls_table *nls_codepage); +extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, + const unsigned char *searchName, char * EAData, + size_t bufsize, const struct nls_table *nls_codepage); +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 c748d158f060..dc9e0fd4edd9 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; @@ -2770,6 +2771,89 @@ SetTimesRetry: return rc; } + +int +CIFSSMBSetTimesLegacy(int xid, struct cifsTconInfo *tcon, char *fileName, + FILE_INFO_STANDARD * data, const struct nls_table *nls_codepage) +{ + TRANSACTION2_SPI_REQ *pSMB = NULL; + TRANSACTION2_SPI_RSP *pSMBr = NULL; + int name_len; + int rc = 0; + int bytes_returned = 0; + char *data_offset; + + cFYI(1, ("In SetTimesLegacy")); + +SetTimesRetryLegacy: + 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); + } +/* BB fixme - we have to map to FILE_STANDARD_INFO (level 1 info + in parent function, from the better and ususal FILE_BASIC_INFO */ + pSMB->ParameterCount = 6 + name_len; + pSMB->DataCount = sizeof (FILE_INFO_STANDARD); + pSMB->MaxParameterCount = cpu_to_le16(2); + pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ + 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; + data_offset = (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); + pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); + pSMB->TotalDataCount = pSMB->DataCount; + pSMB->TotalParameterCount = pSMB->ParameterCount; + /* I doubt that passthrough levels apply to this old + preNT info level */ +/* if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) + pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2); + else*/ + pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD); + pSMB->Reserved4 = 0; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + memcpy(data_offset, data, sizeof (FILE_INFO_STANDARD)); + 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 (times legacy) returned %d", rc)); + } + + if (pSMB) + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto SetTimesRetryLegacy; + + return rc; +} + int CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon, char *fileName, __u64 mode, __u64 uid, __u64 gid, @@ -2915,10 +2999,10 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, return rc; } #ifdef CONFIG_CIFS_XATTR -int +ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, - char * EAData, size_t size, + char * EAData, size_t buf_size, const struct nls_table *nls_codepage) { /* BB assumes one setup word */ @@ -2927,6 +3011,8 @@ CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, int rc = 0; int bytes_returned; int name_len; + struct fea * temp_fea; + char * temp_ptr; cFYI(1, ("In Query All EAs path %s", searchName)); QAllEAsRetry: @@ -2942,7 +3028,7 @@ QAllEAsRetry: , nls_codepage); name_len++; /* trailing null */ name_len *= 2; - } else { /* BB improve the check for buffer overruns BB */ + } else { /* BB improve the check for buffer overruns BB */ name_len = strnlen(searchName, 530); name_len++; /* trailing null */ strncpy(pSMB->FileName, searchName, name_len); @@ -3001,7 +3087,53 @@ QAllEAsRetry: ea_response_data = (struct fealist *) (((char *) &pSMBr->hdr.Protocol) + pSMBr->DataOffset); + ea_response_data->list_len = + cpu_to_le32(ea_response_data->list_len); cFYI(1,("ea length %d",ea_response_data->list_len)); + name_len = ea_response_data->list_len; + if(name_len <= 8) { + /* returned EA size zeroed at top of function */ + cFYI(1,("empty EA list returned from server")); + } else { + /* account for ea list len */ + name_len -= 4; + temp_fea = ea_response_data->list; + temp_ptr = (char *)temp_fea; + while(name_len > 0) { + name_len -= 4; + temp_ptr += 4; + rc += temp_fea->name_len; + /* account for prefix user. and trailing null */ + rc = rc + 5 + 1; + if(rc<buf_size) { + memcpy(EAData,"user.",5); + EAData+=5; + memcpy(EAData,temp_ptr,temp_fea->name_len); + EAData+=temp_fea->name_len; + /* null terminate name */ + *EAData = 0; + EAData = EAData + 1; + } else if(buf_size == 0) { + /* skip copy - calc size only */ + } else { + /* stop before overrun buffer */ + rc = -ERANGE; + break; + } + name_len -= temp_fea->name_len; + temp_ptr += temp_fea->name_len; + /* account for trailing null */ + name_len--; + temp_ptr++; + temp_fea->value_len = cpu_to_le16(temp_fea->value_len); + name_len -= temp_fea->value_len; + temp_ptr += temp_fea->value_len; + /* BB check that temp_ptr is still within smb BB*/ + /* no trailing null to account for in value len */ + /* go on to next EA */ + temp_fea = (struct fea *)temp_ptr; + } + } } } if (pSMB) @@ -3011,4 +3143,255 @@ QAllEAsRetry: return rc; } + +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) +{ + TRANSACTION2_QPI_REQ *pSMB = NULL; + TRANSACTION2_QPI_RSP *pSMBr = NULL; + int rc = 0; + int bytes_returned; + int name_len; + struct fea * temp_fea; + char * temp_ptr; + + cFYI(1, ("In Query EA path %s", searchName)); +QEARetry: + 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, searchName, 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(searchName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->FileName, searchName, name_len); + } + + pSMB->TotalParameterCount = 2 /* level */ + 4 /* reserved */ + + name_len /* includes null */ ; + pSMB->TotalDataCount = 0; + pSMB->MaxParameterCount = cpu_to_le16(2); + pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ParameterOffset = cpu_to_le16(offsetof( + struct smb_com_transaction2_qpi_req ,InformationLevel) - 4); + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); + pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount); + pSMB->ParameterCount = pSMB->TotalParameterCount; + pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS); + 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, ("Send error in Query EA = %d", rc)); + } else { /* decode response */ + pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); + /* BB also check enough total bytes returned */ + /* BB we need to improve the validity checking + of these trans2 responses */ + if ((pSMBr->ByteCount < 4) || (pSMBr->DataOffset > 512)) + rc = -EIO; /* bad smb */ + /* else if (pFindData){ + memcpy((char *) pFindData, + (char *) &pSMBr->hdr.Protocol + + pSMBr->DataOffset, kl); + }*/ else { + /* check that length of list is not more than bcc */ + /* check that each entry does not go beyond length + of list */ + /* check that each element of each entry does not + go beyond end of list */ + struct fealist * ea_response_data; + rc = -ENOENT; + /* validate_trans2_offsets() */ + /* BB to check if(start of smb + pSMBr->DataOffset > &bcc+ bcc)*/ + ea_response_data = (struct fealist *) + (((char *) &pSMBr->hdr.Protocol) + + pSMBr->DataOffset); + ea_response_data->list_len = + cpu_to_le32(ea_response_data->list_len); + cFYI(1,("ea length %d",ea_response_data->list_len)); + name_len = ea_response_data->list_len; + if(name_len <= 8) { + /* returned EA size zeroed at top of function */ + cFYI(1,("empty EA list returned from server")); + } else { + /* account for ea list len */ + name_len -= 4; + temp_fea = ea_response_data->list; + temp_ptr = (char *)temp_fea; + /* loop through checking if we have a matching + name and then return the associated value */ + while(name_len > 0) { + name_len -= 4; + temp_ptr += 4; + temp_fea->value_len = cpu_to_le16(temp_fea->value_len); + /* BB validate that value_len falls within SMB, + even though maximum for name_len is 255 */ + if(memcmp(temp_fea->name,ea_name, + temp_fea->name_len) == 0) { + /* found a match */ + rc = temp_fea->value_len; + /* account for prefix user. and trailing null */ + if(rc<=buf_size) { + memcpy(ea_value, + temp_fea->name+temp_fea->name_len+1, + rc); + /* ea values, unlike ea names, + are not null terminated */ + } else if(buf_size == 0) { + /* skip copy - calc size only */ + } else { + /* stop before overrun buffer */ + rc = -ERANGE; + } + break; + } + name_len -= temp_fea->name_len; + temp_ptr += temp_fea->name_len; + /* account for trailing null */ + name_len--; + temp_ptr++; + name_len -= temp_fea->value_len; + temp_ptr += temp_fea->value_len; + /* no trailing null to account for in value len */ + /* go on to next EA */ + temp_fea = (struct fea *)temp_ptr; + } + } + } + } + if (pSMB) + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto 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)) */ + if(ea_value_len) + 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/connect.c b/fs/cifs/connect.c index 5c84f9b86993..bb6b0f3b2fb2 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -28,6 +28,7 @@ #include <linux/pagemap.h> #include <linux/ctype.h> #include <linux/utsname.h> +#include <linux/mempool.h> #include <asm/uaccess.h> #include <asm/processor.h> #include "cifspdu.h" @@ -49,6 +50,8 @@ extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24); extern int cifs_inet_pton(int, const char *, void *dst); +extern mempool_t *cifs_req_poolp; + struct smb_vol { char *username; char *password; @@ -64,6 +67,8 @@ struct smb_vol { int rw:1; int retry:1; int intr:1; + int setuids:1; + int noperm:1; unsigned int rsize; unsigned int wsize; unsigned int sockopt; @@ -202,6 +207,15 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) current->flags |= PF_MEMALLOC; server->tsk = current; /* save process info to wake at shutdown */ cFYI(1, ("Demultiplex PID: %d", current->pid)); + write_lock(&GlobalSMBSeslock); + atomic_inc(&tcpSesAllocCount); + length = tcpSesAllocCount.counter; + write_unlock(&GlobalSMBSeslock); + if(length > 1) { + mempool_resize(cifs_req_poolp, + length + CIFS_MIN_RCV_POOL, + GFP_KERNEL); + } while (server->tcpStatus != CifsExiting) { if (smb_buffer == NULL) @@ -465,6 +479,16 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) } kfree(server); + write_lock(&GlobalSMBSeslock); + atomic_dec(&tcpSesAllocCount); + length = tcpSesAllocCount.counter; + write_unlock(&GlobalSMBSeslock); + if(length > 0) { + mempool_resize(cifs_req_poolp, + length + CIFS_MIN_RCV_POOL, + GFP_KERNEL); + } + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ/4); return 0; @@ -740,6 +764,14 @@ cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol vol->retry = 1; } else if (strnicmp(data, "soft", 4) == 0) { vol->retry = 0; + } else if (strnicmp(data, "perm", 4) == 0) { + vol->noperm = 0; + } else if (strnicmp(data, "noperm", 6) == 0) { + vol->noperm = 1; + } else if (strnicmp(data, "setuids", 7) == 0) { + vol->setuids = 1; + } else if (strnicmp(data, "nosetuids", 9) == 0) { + vol->setuids = 0; } else if (strnicmp(data, "nohard", 6) == 0) { vol->retry = 0; } else if (strnicmp(data, "nosoft", 6) == 0) { @@ -1314,6 +1346,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, cifs_sb->mnt_file_mode = volume_info.file_mode; cifs_sb->mnt_dir_mode = volume_info.dir_mode; cFYI(1,("file mode: 0x%x dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode)); + + if(volume_info.noperm) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM; + if(volume_info.setuids) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID; + tcon = find_unc(sin_server.sin_addr.s_addr, volume_info.UNC, volume_info.username); diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 95d68da2aaff..91567f61d6dd 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -243,11 +243,19 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, then we now have to set the mode if possible */ if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) && (oplock & CIFS_CREATE_ACTION)) - CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, + if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { + CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, + (__u64)current->euid, + (__u64)current->egid, + 0 /* dev */, + cifs_sb->local_nls); + } else { + CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, (__u64)-1, (__u64)-1, 0 /* dev */, cifs_sb->local_nls); + } else { /* BB implement via Windows security descriptors */ /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ @@ -348,9 +356,16 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev rc = -ENOMEM; if (full_path && (pTcon->ses->capabilities & CAP_UNIX)) { - rc = CIFSSMBUnixSetPerms(xid, pTcon, - full_path, mode, current->euid, current->egid, - device_number, cifs_sb->local_nls); + if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { + rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, + mode,(__u64)current->euid,(__u64)current->egid, + device_number, cifs_sb->local_nls); + } else { + rc = CIFSSMBUnixSetPerms(xid, pTcon, + full_path, mode, (__u64)-1, (__u64)-1, + device_number, cifs_sb->local_nls); + } + if(!rc) { rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb,xid); diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 8434166488b2..a2965cfd3559 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -480,12 +480,20 @@ cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) d_instantiate(direntry, newinode); if(direntry->d_inode) direntry->d_inode->i_nlink = 2; - if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) - CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, - (__u64)-1, - (__u64)-1, - 0 /* dev_t */, - cifs_sb->local_nls); + if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) + if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { + CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, + (__u64)current->euid, + (__u64)current->egid, + 0 /* dev_t */, + cifs_sb->local_nls); + } else { + CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, + (__u64)-1, + (__u64)-1, + 0 /* dev_t */, + cifs_sb->local_nls); + } else { /* BB to be implemented via Windows secrty descriptors*/ /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ } diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c index 18329601b5a9..c6dfc2277cbb 100644 --- a/fs/cifs/smbencrypt.c +++ b/fs/cifs/smbencrypt.c @@ -70,8 +70,6 @@ void SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8, void NTLMSSPOWFencrypt(unsigned char passwd[8], unsigned char *ntlmchalresp, unsigned char p24[24]); void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24); -int decode_pw_buffer(char in_buffer[516], char *new_pwrd, - int new_pwrd_size, __u32 * new_pw_len); /* This implements the X/Open SMB password encryption diff --git a/fs/cifs/smberr.h b/fs/cifs/smberr.h index 25a39bf34f58..8db20a0f7edf 100644 --- a/fs/cifs/smberr.h +++ b/fs/cifs/smberr.h @@ -1,7 +1,7 @@ /* * fs/cifs/smberr.h * - * Copyright (c) International Business Machines Corp., 2002 + * Copyright (c) International Business Machines Corp., 2002,2004 * Author(s): Steve French (sfrench@us.ibm.com) * * See Error Codes section of the SNIA CIFS Specification @@ -60,6 +60,7 @@ #define ERRinvparm 87 #define ERRdiskfull 112 #define ERRinvname 123 +#define ERRinvlevel 124 #define ERRdirnotempty 145 #define ERRnotlocked 158 #define ERRalreadyexists 183 diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index dd6a2c08cd73..5380c349b7db 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c @@ -26,27 +26,178 @@ #include "cifsproto.h" #include "cifs_debug.h" -int cifs_removexattr(struct dentry * direntry, const char * name) +#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." +#define CIFS_XATTR_OS2_PREFIX "OS2." /* BB should check for this someday */ +/* also note could add check for security prefix XATTR_SECURITY_PREFIX */ + + +int cifs_removexattr(struct dentry * direntry, const char * ea_name) { int rc = -EOPNOTSUPP; +#ifdef CONFIG_CIFS_XATTR + int xid; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + struct super_block * sb; + char * full_path; + + if(direntry == NULL) + return -EIO; + if(direntry->d_inode == NULL) + return -EIO; + sb = direntry->d_inode->i_sb; + if(sb == NULL) + return -EIO; + xid = GetXid(); + + cifs_sb = CIFS_SB(sb); + pTcon = cifs_sb->tcon; + + down(&sb->s_vfs_rename_sem); + full_path = build_path_from_dentry(direntry); + up(&sb->s_vfs_rename_sem); + if(full_path == NULL) { + FreeXid(xid); + return -ENOMEM; + } + 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,0, + (__u16)0, cifs_sb->local_nls); + } + if (full_path) + kfree(full_path); + FreeXid(xid); +#endif return rc; } -int cifs_setxattr(struct dentry * direntry, const char * name, - const void * value, size_t size, int flags) +int cifs_setxattr(struct dentry * direntry, const char * ea_name, + const void * ea_value, size_t value_size, int flags) { int rc = -EOPNOTSUPP; +#ifdef CONFIG_CIFS_XATTR + int xid; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + struct super_block * sb; + char * full_path; + + if(direntry == NULL) + return -EIO; + if(direntry->d_inode == NULL) + return -EIO; + sb = direntry->d_inode->i_sb; + if(sb == NULL) + return -EIO; + xid = GetXid(); + + cifs_sb = CIFS_SB(sb); + pTcon = cifs_sb->tcon; + + down(&sb->s_vfs_rename_sem); + full_path = build_path_from_dentry(direntry); + up(&sb->s_vfs_rename_sem); + if(full_path == NULL) { + FreeXid(xid); + return -ENOMEM; + } + /* return dos attributes as pseudo xattr */ + /* return alt name if available as pseudo attr */ + + /* if proc/fs/cifs/streamstoxattr is set then + search server for EAs or streams to + returns as xattrs */ + 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); +#endif return rc; } -ssize_t cifs_getxattr(struct dentry * direntry, const char * name, - void * value, size_t size) +ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name, + void * ea_value, size_t buf_size) { ssize_t rc = -EOPNOTSUPP; +#ifdef CONFIG_CIFS_XATTR + int xid; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + struct super_block * sb; + char * full_path; + + if(direntry == NULL) + return -EIO; + if(direntry->d_inode == NULL) + return -EIO; + sb = direntry->d_inode->i_sb; + if(sb == NULL) + return -EIO; + xid = GetXid(); + + cifs_sb = CIFS_SB(sb); + pTcon = cifs_sb->tcon; + + down(&sb->s_vfs_rename_sem); + full_path = build_path_from_dentry(direntry); + up(&sb->s_vfs_rename_sem); + if(full_path == NULL) { + FreeXid(xid); + return -ENOMEM; + } + /* return dos attributes as pseudo xattr */ + /* return alt name if available as pseudo attr */ + 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? */ + } else { + /* We could add a check here + if proc/fs/cifs/streamstoxattr is set then + search server for EAs or streams to + returns as xattrs */ + ea_name+=5; /* skip past user. */ + rc = CIFSSMBQueryEA(xid,pTcon,full_path,ea_name,ea_value, + buf_size, cifs_sb->local_nls); + } + if (full_path) + kfree(full_path); + FreeXid(xid); +#endif return rc; } -ssize_t cifs_listxattr(struct dentry * direntry, char * ea_data, size_t ea_size) +ssize_t cifs_listxattr(struct dentry * direntry, char * data, size_t buf_size) { ssize_t rc = -EOPNOTSUPP; #ifdef CONFIG_CIFS_XATTR @@ -55,6 +206,7 @@ ssize_t cifs_listxattr(struct dentry * direntry, char * ea_data, size_t ea_size) struct cifsTconInfo *pTcon; struct super_block * sb; char * full_path; + if(direntry == NULL) return -EIO; if(direntry->d_inode == NULL) @@ -74,13 +226,17 @@ ssize_t cifs_listxattr(struct dentry * direntry, char * ea_data, size_t ea_size) FreeXid(xid); return -ENOMEM; } - /* return dosattributes as pseudo xattr */ + /* return dos attributes as pseudo xattr */ /* return alt name if available as pseudo attr */ /* if proc/fs/cifs/streamstoxattr is set then search server for EAs or streams to returns as xattrs */ - rc = CIFSSMBQAllEAs(xid,pTcon,full_path,ea_data,ea_size,cifs_sb->local_nls); + rc = CIFSSMBQAllEAs(xid,pTcon,full_path,data,buf_size, + cifs_sb->local_nls); + + if (full_path) + kfree(full_path); FreeXid(xid); #endif return rc; diff --git a/net/sched/Kconfig b/net/sched/Kconfig index 57b2cc4761e3..08b8ebddefd3 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig @@ -37,7 +37,7 @@ config NET_SCH_CLK_GETTIMEOFDAY config NET_SCH_CLK_CPU bool "CPU cycle counter" - depends on X86_TSC || X86_64 || ALPHA || SPARC64 || PPC64 || IA64 + depends on X86_TSC || X86_64 || SPARC64 || PPC64 || IA64 help Say Y here if you want to use the CPU's cycle counter as clock source. This is a cheap and high resolution clock source, but on some @@ -47,7 +47,6 @@ config NET_SCH_CLK_CPU The useable cycle counters are: x86/x86_64 - Timestamp Counter - alpha - Cycle Counter sparc64 - %ticks register ppc64 - Time base ia64 - Interval Time Counter |
