diff -Nau fs/cifs/asn1.c fs/cifs.new-mm/asn1.c --- fs/cifs/asn1.c 2005-01-14 09:33:50.000000000 -0600 +++ fs/cifs.new-mm/asn1.c 2005-02-06 22:30:07.538012384 -0600 @@ -210,7 +210,7 @@ { unsigned char ch; - if (eoc == 0) { + if (eoc == NULL) { if (!asn1_octet_decode(ctx, &ch)) return 0; diff -Nau fs/cifs/AUTHORS fs/cifs.new-mm/AUTHORS --- fs/cifs/AUTHORS 2005-01-14 09:33:50.000000000 -0600 +++ fs/cifs.new-mm/AUTHORS 2005-02-06 22:30:07.440027280 -0600 @@ -25,6 +25,8 @@ Richard Hughes Yury Umanets Mark Hamzy +Domen Puncer +Jesper Juhl Test case and Bug Report contributors ------------------------------------- diff -Nau fs/cifs/CHANGES fs/cifs.new-mm/CHANGES --- fs/cifs/CHANGES 2005-01-14 09:33:50.000000000 -0600 +++ fs/cifs.new-mm/CHANGES 2005-02-06 22:30:07.496018768 -0600 @@ -1,3 +1,59 @@ +Version 1.29 +------------ +Fix default mode in sysfs of cifs module parms. Remove old readdir routine. +Fix capabilities flags for large readx so as to allow reads larger than 64K. + +Version 1.28 +------------ +Add module init parm for large SMB buffer size (to allow it to be changed +from its default of 16K) which is especially useful for large file copy +when mounting with the directio mount option. Fix oops after +returning from mount when experimental ExtendedSecurity enabled and +SpnegoNegotiated returning invalid error. Fix case to retry better when +peek returns from 1 to 3 bytes on socket which should have more data. +Fixed path based calls (such as cifs lookup) to handle path names +longer than 530 (now can handle PATH_MAX). Fix pass through authentication +from Samba server to DC (Samba required dummy LM password). + +Version 1.27 +------------ +Turn off DNOTIFY (directory change notification support) by default +(unless built with the experimental flag) to fix hang with KDE +file browser. Fix DNOTIFY flag mappings. Fix hang (in wait_event +waiting on an SMB response) in SendReceive when session dies but +reconnects quickly from another task. Add module init parms for +minimum number of large and small network buffers in the buffer pools, +and for the maximum number of simultaneous requests. + +Version 1.26 +------------ +Add setfacl support to allow setting of ACLs remotely to Samba 3.10 and later +and other POSIX CIFS compliant servers. Fix error mapping for getfacl +to EOPNOTSUPP when server does not support posix acls on the wire. Fix +improperly zeroed buffer in CIFS Unix extensions set times call. + +Version 1.25 +------------ +Fix internationlization problem in cifs readdir with filenames that map to +longer UTF8 strings than the string on the wire was in Unicode. Add workaround +for readdir to netapp servers. Fix search rewind (seek into readdir to return +non-consecutive entries). Do not do readdir when server negotiates +buffer size to small to fit filename. Add support for reading POSIX ACLs from +the server (add also acl and noacl mount options). + +Version 1.24 +------------ +Optionally allow using server side inode numbers, rather than client generated +ones by specifying mount option "serverino" - this is required for some apps +to work which double check hardlinked files and have persistent inode numbers. + +Version 1.23 +------------ +Multiple bigendian fixes. On little endian systems (for reconnect after +network failure) fix tcp session reconnect code so we do not try first +to reconnect on reverse of port 445. Treat reparse points (NTFS junctions) +as directories rather than symlinks because we can do follow link on them. + Version 1.22 ------------ Add config option to enable XATTR (extended attribute) support, mapping @@ -7,8 +63,8 @@ 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 +Add new mount parm to control whether mode check (generic_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 diff -Nau fs/cifs/cifs_debug.c fs/cifs.new-mm/cifs_debug.c --- fs/cifs/cifs_debug.c 2004-08-14 00:36:57.000000000 -0500 +++ fs/cifs.new-mm/cifs_debug.c 2005-02-06 22:30:07.539012232 -0600 @@ -126,26 +126,28 @@ i = 0; read_lock(&GlobalSMBSeslock); list_for_each(tmp, &GlobalTreeConnectionList) { + __u32 dev_type; i++; tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); + dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType); length = sprintf(buf, "\n%d) %s Uses: %d Type: %s Characteristics: 0x%x Attributes: 0x%x\nPathComponentMax: %d Status: %d", i, tcon->treeName, atomic_read(&tcon->useCount), tcon->nativeFileSystem, - tcon->fsDevInfo.DeviceCharacteristics, - tcon->fsAttrInfo.Attributes, - tcon->fsAttrInfo.MaxPathNameComponentLength,tcon->tidStatus); + le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics), + le32_to_cpu(tcon->fsAttrInfo.Attributes), + le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength), + tcon->tidStatus); buf += length; - if (tcon->fsDevInfo.DeviceType == FILE_DEVICE_DISK) + if (dev_type == FILE_DEVICE_DISK) length = sprintf(buf, " type: DISK "); - else if (tcon->fsDevInfo.DeviceType == FILE_DEVICE_CD_ROM) + else if (dev_type == FILE_DEVICE_CD_ROM) length = sprintf(buf, " type: CDROM "); else length = - sprintf(buf, " type: %d ", - tcon->fsDevInfo.DeviceType); + sprintf(buf, " type: %d ", dev_type); buf += length; if(tcon->tidStatus == CifsNeedReconnect) { buf += sprintf(buf, "\tDISCONNECTED "); @@ -199,7 +201,12 @@ sprintf(buf,"SMB Request/Response Buffer: %d\n", bufAllocCount.counter); length += item_length; - buf += item_length; + buf += item_length; + item_length = + sprintf(buf,"SMB Small Req/Resp Buffer: %d\n", + smBufAllocCount.counter); + length += item_length; + buf += item_length; item_length = sprintf(buf,"Operations (MIDs): %d\n", midCount.counter); @@ -335,7 +342,7 @@ if (pde) pde->write_proc = oplockEnabled_write; - pde = create_proc_read_entry("QuotaEnabled", 0, proc_fs_cifs, + pde = create_proc_read_entry("ReenableOldCifsReaddirCode", 0, proc_fs_cifs, quotaEnabled_read, NULL); if (pde) pde->write_proc = quotaEnabled_write; @@ -394,7 +401,7 @@ remove_proc_entry("ExtendedSecurity",proc_fs_cifs); remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs); - remove_proc_entry("QuotaEnabled",proc_fs_cifs); + remove_proc_entry("ReenableOldCifsReaddirCode",proc_fs_cifs); remove_proc_entry("LookupCacheEnabled",proc_fs_cifs); remove_proc_entry("cifs", proc_root_fs); } @@ -483,7 +490,7 @@ { int len; - len = sprintf(page, "%d\n", quotaEnabled); + len = sprintf(page, "%d\n", experimEnabled); /* could also check if quotas are enabled in kernel as a whole first */ len -= off; @@ -510,9 +517,9 @@ if (rc) return rc; if (c == '0' || c == 'n' || c == 'N') - quotaEnabled = 0; + experimEnabled = 0; else if (c == '1' || c == 'y' || c == 'Y') - quotaEnabled = 1; + experimEnabled = 1; return count; } diff -Nau fs/cifs/cifsencrypt.c fs/cifs.new-mm/cifsencrypt.c --- fs/cifs/cifsencrypt.c 2005-01-14 09:33:50.000000000 -0600 +++ fs/cifs.new-mm/cifsencrypt.c 2005-02-06 22:30:07.541011928 -0600 @@ -61,7 +61,7 @@ if((cifs_pdu == NULL) || (ses == NULL)) return -EINVAL; - if((le32_to_cpu(cifs_pdu->Flags2) & SMBFLG2_SECURITY_SIGNATURE) == 0) + if((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0) return rc; spin_lock(&GlobalMid_Lock); @@ -107,13 +107,11 @@ if(memcmp(cifs_pdu->Signature.SecuritySignature,"BSRSPYL ",8)==0) cFYI(1,("dummy signature received for smb command 0x%x",cifs_pdu->Command)); - expected_sequence_number = cpu_to_le32(expected_sequence_number); - /* save off the origiginal signature so we can modify the smb and check its signature against what the server sent */ memcpy(server_response_sig,cifs_pdu->Signature.SecuritySignature,8); - cifs_pdu->Signature.Sequence.SequenceNumber = expected_sequence_number; + cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(expected_sequence_number); cifs_pdu->Signature.Sequence.Reserved = 0; rc = cifs_calculate_signature(cifs_pdu, mac_key, diff -Nau fs/cifs/cifsfs.c fs/cifs.new-mm/cifsfs.c --- fs/cifs/cifsfs.c 2005-01-14 09:33:50.000000000 -0600 +++ fs/cifs.new-mm/cifsfs.c 2005-02-06 22:32:12.272049928 -0600 @@ -50,15 +50,27 @@ int cifsERROR = 1; int traceSMB = 0; unsigned int oplockEnabled = 1; -unsigned int quotaEnabled = 0; +unsigned int experimEnabled = 0; unsigned int linuxExtEnabled = 1; unsigned int lookupCacheEnabled = 1; unsigned int multiuser_mount = 0; unsigned int extended_security = 0; unsigned int ntlmv2_support = 0; unsigned int sign_CIFS_PDUs = 1; -unsigned int CIFSMaximumBufferSize = CIFS_MAX_MSGSIZE; struct task_struct * oplockThread = NULL; +unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE; +module_param(CIFSMaxBufSize, int, 0); +MODULE_PARM_DESC(CIFSMaxBufSize,"Network buffer size (not including header). Default: 16384 Range: 8192 to 130048"); +unsigned int cifs_min_rcv = CIFS_MIN_RCV_POOL; +module_param(cifs_min_rcv, int, 0); +MODULE_PARM_DESC(cifs_min_rcv,"Network buffers in pool. Default: 4 Range: 1 to 64"); +unsigned int cifs_min_small = 30; +module_param(cifs_min_small, int, 0); +MODULE_PARM_DESC(cifs_small_rcv,"Small network buffers in pool. Default: 30 Range: 2 to 256"); +unsigned int cifs_max_pending = CIFS_MAX_REQ; +module_param(cifs_max_pending, int, 0); +MODULE_PARM_DESC(cifs_max_pending,"Simultaneous requests to server. Default: 50 Range: 2 to 256"); + extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, const char *); @@ -207,6 +219,8 @@ static kmem_cache_t *cifs_req_cachep; static kmem_cache_t *cifs_mid_cachep; kmem_cache_t *cifs_oplock_cachep; +static kmem_cache_t *cifs_sm_req_cachep; +mempool_t *cifs_sm_req_poolp; mempool_t *cifs_req_poolp; mempool_t *cifs_mid_poolp; @@ -431,6 +445,20 @@ return -EIO; cFYI(1,("In read_wrapper size %zd at %lld",read_size,*poffset)); + +#ifdef CONFIG_CIFS_EXPERIMENTAL + /* check whether we can cache writes locally */ + if(file->f_dentry->d_sb) { + struct cifs_sb_info *cifs_sb; + cifs_sb = CIFS_SB(file->f_dentry->d_sb); + if(cifs_sb != NULL) { + if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) + return cifs_user_read(file,read_data, + read_size,poffset); + } + } +#endif /* CIFS_EXPERIMENTAL */ + if(CIFS_I(file->f_dentry->d_inode)->clientCanCacheRead) { return generic_file_read(file,read_data,read_size,poffset); } else { @@ -463,7 +491,19 @@ cFYI(1,("In write_wrapper size %zd at %lld",write_size,*poffset)); +#ifdef CONFIG_CIFS_EXPERIMENTAL /* BB fixme - fix user char * to kernel char * mapping here BB */ /* check whether we can cache writes locally */ + if(file->f_dentry->d_sb) { + struct cifs_sb_info *cifs_sb; + cifs_sb = CIFS_SB(file->f_dentry->d_sb); + if(cifs_sb != NULL) { + if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) { + return cifs_user_write(file,write_data, + write_size,poffset); + } + } + } +#endif /* CIFS_EXPERIMENTAL */ written = generic_file_write(file,write_data,write_size,poffset); if(!CIFS_I(file->f_dentry->d_inode)->clientCanCacheAll) { if(file->f_dentry->d_inode->i_mapping) { @@ -495,6 +535,12 @@ .setattr = cifs_setattr, .symlink = cifs_symlink, .mknod = cifs_mknod, +#ifdef CONFIG_CIFS_XATTR + .setxattr = cifs_setxattr, + .getxattr = cifs_getxattr, + .listxattr = cifs_listxattr, + .removexattr = cifs_removexattr, +#endif }; struct inode_operations cifs_file_inode_ops = { @@ -537,14 +583,18 @@ .flush = cifs_flush, .mmap = cifs_file_mmap, .sendfile = generic_file_sendfile, +#ifdef CONFIG_CIFS_EXPERIMENTAL .dir_notify = cifs_dir_notify, +#endif /* CONFIG_CIFS_EXPERIMENTAL */ }; struct file_operations cifs_dir_ops = { .readdir = cifs_readdir, .release = cifs_closedir, .read = generic_read_dir, +#ifdef CONFIG_CIFS_EXPERIMENTAL .dir_notify = cifs_dir_notify, +#endif /* CONFIG_CIFS_EXPERIMENTAL */ }; static void @@ -582,14 +632,31 @@ static int cifs_init_request_bufs(void) { + if(CIFSMaxBufSize < 8192) { + /* Buffer size can not be smaller than 2 * PATH_MAX since maximum + Unicode path name has to fit in any SMB/CIFS path based frames */ + CIFSMaxBufSize = 8192; + } else if (CIFSMaxBufSize > 1024*127) { + CIFSMaxBufSize = 1024 * 127; + } else { + CIFSMaxBufSize &= 0x1FE00; /* Round size to even 512 byte mult*/ + } +/* cERROR(1,("CIFSMaxBufSize %d 0x%x",CIFSMaxBufSize,CIFSMaxBufSize)); */ cifs_req_cachep = kmem_cache_create("cifs_request", - CIFS_MAX_MSGSIZE + + CIFSMaxBufSize + MAX_CIFS_HDR_SIZE, 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if (cifs_req_cachep == NULL) return -ENOMEM; - cifs_req_poolp = mempool_create(CIFS_MIN_RCV_POOL, + if(cifs_min_rcv < 1) + cifs_min_rcv = 1; + else if (cifs_min_rcv > 64) { + cifs_min_rcv = 64; + cFYI(1,("cifs_min_rcv set to maximum (64)")); + } + + cifs_req_poolp = mempool_create(cifs_min_rcv, mempool_alloc_slab, mempool_free_slab, cifs_req_cachep); @@ -598,6 +665,40 @@ kmem_cache_destroy(cifs_req_cachep); return -ENOMEM; } + /* 256 (MAX_CIFS_HDR_SIZE bytes is enough for most SMB responses and + almost all handle based requests (but not write response, nor is it + sufficient for path based requests). A smaller size would have + been more efficient (compacting multiple slab items on one 4k page) + for the case in which debug was on, but this larger size allows + more SMBs to use small buffer alloc and is still much more + efficient to alloc 1 per page off the slab compared to 17K (5page) + alloc of large cifs buffers even when page debugging is on */ + cifs_sm_req_cachep = kmem_cache_create("cifs_small_rq", + MAX_CIFS_HDR_SIZE, 0, SLAB_HWCACHE_ALIGN, NULL, NULL); + if (cifs_sm_req_cachep == NULL) { + mempool_destroy(cifs_req_poolp); + kmem_cache_destroy(cifs_req_cachep); + return -ENOMEM; + } + + if(cifs_min_small < 2) + cifs_min_small = 2; + else if (cifs_min_small > 256) { + cifs_min_small = 256; + cFYI(1,("cifs_min_small set to maximum (256)")); + } + + cifs_sm_req_poolp = mempool_create(cifs_min_small, + mempool_alloc_slab, + mempool_free_slab, + cifs_sm_req_cachep); + + if(cifs_sm_req_poolp == NULL) { + mempool_destroy(cifs_req_poolp); + kmem_cache_destroy(cifs_req_cachep); + kmem_cache_destroy(cifs_sm_req_cachep); + return -ENOMEM; + } return 0; } @@ -609,6 +710,10 @@ if (kmem_cache_destroy(cifs_req_cachep)) printk(KERN_WARNING "cifs_destroy_request_cache: error not all structures were freed\n"); + mempool_destroy(cifs_sm_req_poolp); + if (kmem_cache_destroy(cifs_sm_req_cachep)) + printk(KERN_WARNING + "cifs_destroy_request_cache: cifs_small_rq free error\n"); } static int @@ -748,8 +853,16 @@ GlobalCurrentXid = 0; GlobalTotalActiveXid = 0; GlobalMaxActiveXid = 0; - GlobalSMBSeslock = RW_LOCK_UNLOCKED; - GlobalMid_Lock = SPIN_LOCK_UNLOCKED; + rwlock_init(&GlobalSMBSeslock); + spin_lock_init(&GlobalMid_Lock); + + if(cifs_max_pending < 2) { + cifs_max_pending = 2; + cFYI(1,("cifs_max_pending set to min of 2")); + } else if(cifs_max_pending > 256) { + cifs_max_pending = 256; + cFYI(1,("cifs_max_pending set to max of 256")); + } rc = cifs_init_inodecache(); if (!rc) { diff -Nau fs/cifs/cifsfs.h fs/cifs.new-mm/cifsfs.h --- fs/cifs/cifsfs.h 2005-01-14 09:33:50.000000000 -0600 +++ fs/cifs.new-mm/cifsfs.h 2005-02-06 22:30:07.541011928 -0600 @@ -63,10 +63,10 @@ extern int cifs_open(struct inode *inode, struct file *file); extern int cifs_close(struct inode *inode, struct file *file); extern int cifs_closedir(struct inode *inode, struct file *file); -extern ssize_t cifs_read(struct file *file, char *read_data, +extern ssize_t cifs_user_read(struct file *file, char __user *read_data, size_t read_size, loff_t * poffset); -extern ssize_t cifs_write(struct file *file, const char *write_data, - size_t write_size, loff_t * poffset); +extern ssize_t cifs_user_write(struct file *file, const char __user *write_data, + size_t write_size, loff_t * poffset); extern int cifs_lock(struct file *, int, struct file_lock *); extern int cifs_fsync(struct file *, struct dentry *, int); extern int cifs_flush(struct file *); @@ -90,5 +90,5 @@ 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.20" +#define CIFS_VERSION "1.29" #endif /* _CIFSFS_H */ diff -Nau fs/cifs/cifs_fs_sb.h fs/cifs.new-mm/cifs_fs_sb.h --- fs/cifs/cifs_fs_sb.h 2004-08-14 00:36:32.000000000 -0500 +++ fs/cifs.new-mm/cifs_fs_sb.h 2005-02-06 22:30:07.539012232 -0600 @@ -1,7 +1,7 @@ /* * fs/cifs/cifs_fs_sb.h * - * Copyright (c) International Business Machines Corp., 2002 + * Copyright (c) International Business Machines Corp., 2002,2004 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -18,8 +18,10 @@ #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_NO_PERM 1 /* do not do client vfs_perm check */ #define CIFS_MOUNT_SET_UID 2 /* set current->euid in create etc. */ +#define CIFS_MOUNT_SERVER_INUM 4 /* inode numbers from uniqueid from server */ +#define CIFS_MOUNT_DIRECT_IO 8 /* do not write nor read through page cache */ struct cifs_sb_info { struct cifsTconInfo *tcon; /* primary mount */ diff -Nau fs/cifs/cifsglob.h fs/cifs.new-mm/cifsglob.h --- fs/cifs/cifsglob.h 2005-01-14 09:33:50.000000000 -0600 +++ fs/cifs.new-mm/cifsglob.h 2005-02-06 22:30:07.541011928 -0600 @@ -240,6 +240,20 @@ /* * One of these for each open instance of a file */ +struct cifs_search_info { + loff_t index_of_last_entry; + __u16 entries_in_buffer; + __u16 info_level; + __u32 resume_key; + char * ntwrk_buf_start; + char * srch_entries_start; + char * presume_name; + unsigned int resume_name_len; + unsigned endOfSearch:1; + unsigned emptyDir:1; + unsigned unicode:1; +}; + struct cifsFileInfo { struct list_head tlist; /* pointer to next fid owned by tcon */ struct list_head flist; /* next fid (file instance) for this inode */ @@ -250,14 +264,12 @@ /* lock scope id (0 if none) */ struct file * pfile; /* needed for writepage */ struct inode * pInode; /* needed for oplock break */ - unsigned endOfSearch:1; /* we have reached end of search */ unsigned closePend:1; /* file is marked to close */ - unsigned emptyDir:1; unsigned invalidHandle:1; /* file closed via session abend */ struct semaphore fh_sem; /* prevents reopen race after dead ses*/ - char * search_resume_name; - unsigned int resume_name_length; - __u32 resume_key; + char * search_resume_name; /* BB removeme BB */ + unsigned int resume_name_length; /* BB removeme - field renamed and moved BB */ + struct cifs_search_info srch_inf; }; /* @@ -317,6 +329,8 @@ #define MID_REQUEST_SUBMITTED 2 #define MID_RESPONSE_RECEIVED 4 #define MID_RETRY_NEEDED 8 /* session closed while this request out */ +#define MID_NO_RESP_NEEDED 0x10 +#define MID_SMALL_BUFFER 0x20 /* 112 byte response buffer instead of 4K */ /* ***************************************************************** @@ -399,6 +413,7 @@ /* Various Debug counters to remove someday (BB) */ GLOBAL_EXTERN atomic_t bufAllocCount; +GLOBAL_EXTERN atomic_t smBufAllocCount; GLOBAL_EXTERN atomic_t midCount; /* Misc globals */ @@ -407,11 +422,15 @@ have the uid/password or Kerberos credential or equivalent for current user */ GLOBAL_EXTERN unsigned int oplockEnabled; -GLOBAL_EXTERN unsigned int quotaEnabled; +GLOBAL_EXTERN unsigned int experimEnabled; GLOBAL_EXTERN unsigned int lookupCacheEnabled; GLOBAL_EXTERN unsigned int extended_security; /* if on, session setup sent with more secure ntlmssp2 challenge/resp */ GLOBAL_EXTERN unsigned int ntlmv2_support; /* better optional password hash */ GLOBAL_EXTERN unsigned int sign_CIFS_PDUs; /* enable smb packet signing */ -GLOBAL_EXTERN unsigned int linuxExtEnabled; /* enable Linux/Unix CIFS extensions */ +GLOBAL_EXTERN unsigned int linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/ +GLOBAL_EXTERN unsigned int CIFSMaxBufSize; /* max size not including hdr */ +GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */ +GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */ +GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/ diff -Nau fs/cifs/cifspdu.h fs/cifs.new-mm/cifspdu.h --- fs/cifs/cifspdu.h 2005-01-14 09:33:50.000000000 -0600 +++ fs/cifs.new-mm/cifspdu.h 2005-02-06 22:30:07.541011928 -0600 @@ -28,27 +28,30 @@ #define BAD_PROT CIFS_PROT+1 /* SMB command codes */ -#define SMB_COM_CREATE_DIRECTORY 0x00 -#define SMB_COM_DELETE_DIRECTORY 0x01 -#define SMB_COM_CLOSE 0x04 -#define SMB_COM_DELETE 0x06 -#define SMB_COM_RENAME 0x07 -#define SMB_COM_LOCKING_ANDX 0x24 -#define SMB_COM_COPY 0x29 +/* Some commands have minimal (wct=0,bcc=0), or uninteresting, responses + (ie which include no useful data other than the SMB error code itself). + Knowing this helps avoid response buffer allocations and copy in some cases */ +#define SMB_COM_CREATE_DIRECTORY 0x00 /* trivial response */ +#define SMB_COM_DELETE_DIRECTORY 0x01 /* trivial response */ +#define SMB_COM_CLOSE 0x04 /* triv req/rsp, timestamp ignored */ +#define SMB_COM_DELETE 0x06 /* trivial response */ +#define SMB_COM_RENAME 0x07 /* trivial response */ +#define SMB_COM_LOCKING_ANDX 0x24 /* trivial response */ +#define SMB_COM_COPY 0x29 /* trivial rsp, fail filename ignrd*/ #define SMB_COM_READ_ANDX 0x2E #define SMB_COM_WRITE_ANDX 0x2F #define SMB_COM_TRANSACTION2 0x32 #define SMB_COM_TRANSACTION2_SECONDARY 0x33 -#define SMB_COM_FIND_CLOSE2 0x34 -#define SMB_COM_TREE_DISCONNECT 0x71 +#define SMB_COM_FIND_CLOSE2 0x34 /* trivial response */ +#define SMB_COM_TREE_DISCONNECT 0x71 /* trivial response */ #define SMB_COM_NEGOTIATE 0x72 #define SMB_COM_SESSION_SETUP_ANDX 0x73 -#define SMB_COM_LOGOFF_ANDX 0x74 +#define SMB_COM_LOGOFF_ANDX 0x74 /* trivial response */ #define SMB_COM_TREE_CONNECT_ANDX 0x75 #define SMB_COM_NT_TRANSACT 0xA0 #define SMB_COM_NT_TRANSACT_SECONDARY 0xA1 #define SMB_COM_NT_CREATE_ANDX 0xA2 -#define SMB_COM_NT_RENAME 0xA5 +#define SMB_COM_NT_RENAME 0xA5 /* trivial response */ /* Transact2 subcommand codes */ #define TRANS2_OPEN 0x00 @@ -137,15 +140,15 @@ /* * SMB flag2 definitions */ -#define SMBFLG2_KNOWS_LONG_NAMES 0x0001 /* can send long (non-8.3) path names in response */ -#define SMBFLG2_KNOWS_EAS 0x0002 -#define SMBFLG2_SECURITY_SIGNATURE 0x0004 -#define SMBFLG2_IS_LONG_NAME 0x0040 -#define SMBFLG2_EXT_SEC 0x0800 -#define SMBFLG2_DFS 0x1000 -#define SMBFLG2_PAGING_IO 0x2000 -#define SMBFLG2_ERR_STATUS 0x4000 -#define SMBFLG2_UNICODE 0x8000 +#define SMBFLG2_KNOWS_LONG_NAMES cpu_to_le16(1) /* can send long (non-8.3) path names in response */ +#define SMBFLG2_KNOWS_EAS cpu_to_le16(2) +#define SMBFLG2_SECURITY_SIGNATURE cpu_to_le16(4) +#define SMBFLG2_IS_LONG_NAME cpu_to_le16(0x40) +#define SMBFLG2_EXT_SEC cpu_to_le16(0x800) +#define SMBFLG2_DFS cpu_to_le16(0x1000) +#define SMBFLG2_PAGING_IO cpu_to_le16(0x2000) +#define SMBFLG2_ERR_STATUS cpu_to_le16(0x4000) +#define SMBFLG2_UNICODE cpu_to_le16(0x8000) /* * These are the file access permission bits defined in CIFS for the @@ -303,23 +306,23 @@ struct { __u8 ErrorClass; __u8 Reserved; - __u16 Error; /* note: treated as little endian (le) on wire */ + __le16 Error; } DosError; - __u32 CifsError; /* note: le */ + __le32 CifsError; } Status; __u8 Flags; - __u16 Flags2; /* note: le */ - __u16 PidHigh; /* note: le */ + __le16 Flags2; /* note: le */ + __le16 PidHigh; union { struct { - __u32 SequenceNumber; /* le */ + __le32 SequenceNumber; /* le */ __u32 Reserved; /* zero */ } Sequence; __u8 SecuritySignature[8]; /* le */ } Signature; __u8 pad[2]; __u16 Tid; - __u16 Pid; /* note: le */ + __le16 Pid; __u16 Uid; __u16 Mid; __u8 WordCount; @@ -328,7 +331,7 @@ #define BCC(smb_var) ( *(__u16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) ) /* given a pointer to an smb_hdr retrieve the pointer to the byte area */ -#define pByteArea(smb_var) ((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) + 2 ) +#define pByteArea(smb_var) ((unsigned char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) + 2 ) /* * Computer Name Length @@ -373,23 +376,23 @@ typedef struct negotiate_req { struct smb_hdr hdr; /* wct = 0 */ - __u16 ByteCount; + __le16 ByteCount; unsigned char DialectsArray[1]; } NEGOTIATE_REQ; typedef struct negotiate_rsp { struct smb_hdr hdr; /* wct = 17 */ - __u16 DialectIndex; + __le16 DialectIndex; __u8 SecurityMode; - __u16 MaxMpxCount; - __u16 MaxNumberVcs; - __u32 MaxBufferSize; - __u32 MaxRawSize; - __u32 SessionKey; - __u32 Capabilities; /* see below */ - __u32 SystemTimeLow; - __u32 SystemTimeHigh; - __u16 ServerTimeZone; + __le16 MaxMpxCount; + __le16 MaxNumberVcs; + __le32 MaxBufferSize; + __le32 MaxRawSize; + __le32 SessionKey; + __le32 Capabilities; /* see below */ + __le32 SystemTimeLow; + __le32 SystemTimeHigh; + __le16 ServerTimeZone; __u8 EncryptionKeyLength; __u16 ByteCount; union { @@ -436,15 +439,15 @@ struct smb_hdr hdr; /* wct = 12 */ __u8 AndXCommand; __u8 AndXReserved; - __u16 AndXOffset; - __u16 MaxBufferSize; - __u16 MaxMpxCount; - __u16 VcNumber; + __le16 AndXOffset; + __le16 MaxBufferSize; + __le16 MaxMpxCount; + __le16 VcNumber; __u32 SessionKey; - __u16 SecurityBlobLength; + __le16 SecurityBlobLength; __u32 Reserved; - __u32 Capabilities; /* see below */ - __u16 ByteCount; + __le32 Capabilities; /* see below */ + __le16 ByteCount; unsigned char SecurityBlob[1]; /* followed by */ /* STRING NativeOS */ /* STRING NativeLanMan */ @@ -454,16 +457,16 @@ struct smb_hdr hdr; /* wct = 13 */ __u8 AndXCommand; __u8 AndXReserved; - __u16 AndXOffset; - __u16 MaxBufferSize; - __u16 MaxMpxCount; - __u16 VcNumber; + __le16 AndXOffset; + __le16 MaxBufferSize; + __le16 MaxMpxCount; + __le16 VcNumber; __u32 SessionKey; - __u16 CaseInsensitivePasswordLength; /* ASCII password length */ - __u16 CaseSensitivePasswordLength; /* Unicode password length */ + __le16 CaseInsensitivePasswordLength; /* ASCII password length */ + __le16 CaseSensitivePasswordLength; /* Unicode password length */ __u32 Reserved; /* see below */ - __u32 Capabilities; - __u16 ByteCount; + __le32 Capabilities; + __le16 ByteCount; unsigned char CaseInsensitivePassword[1]; /* followed by: */ /* unsigned char * CaseSensitivePassword; */ /* STRING AccountName */ @@ -476,9 +479,9 @@ struct smb_hdr hdr; /* wct = 4 */ __u8 AndXCommand; __u8 AndXReserved; - __u16 AndXOffset; - __u16 Action; /* see below */ - __u16 SecurityBlobLength; + __le16 AndXOffset; + __le16 Action; /* see below */ + __le16 SecurityBlobLength; __u16 ByteCount; unsigned char SecurityBlob[1]; /* followed by */ /* unsigned char * NativeOS; */ @@ -490,14 +493,14 @@ struct smb_hdr hdr; /* wct = 10 */ __u8 AndXCommand; __u8 AndXReserved; - __u16 AndXOffset; - __u16 MaxBufferSize; - __u16 MaxMpxCount; - __u16 VcNumber; + __le16 AndXOffset; + __le16 MaxBufferSize; + __le16 MaxMpxCount; + __le16 VcNumber; __u32 SessionKey; - __u16 PassswordLength; + __le16 PassswordLength; __u32 Reserved; - __u16 ByteCount; + __le16 ByteCount; unsigned char AccountPassword[1]; /* followed by */ /* STRING AccountName */ /* STRING PrimaryDomain */ @@ -509,8 +512,8 @@ struct smb_hdr hdr; /* wct = 3 */ __u8 AndXCommand; __u8 AndXReserved; - __u16 AndXOffset; - __u16 Action; /* see below */ + __le16 AndXOffset; + __le16 Action; /* see below */ __u16 ByteCount; unsigned char NativeOS[1]; /* followed by */ /* unsigned char * NativeLanMan; */ @@ -537,10 +540,10 @@ struct smb_hdr hdr; /* wct = 4 */ __u8 AndXCommand; __u8 AndXReserved; - __u16 AndXOffset; - __u16 Flags; /* see below */ - __u16 PasswordLength; - __u16 ByteCount; + __le16 AndXOffset; + __le16 Flags; /* see below */ + __le16 PasswordLength; + __le16 ByteCount; unsigned char Password[1]; /* followed by */ /* STRING Path *//* \\server\share name */ /* STRING Service */ @@ -550,8 +553,8 @@ struct smb_hdr hdr; /* wct = 3 *//* note that Win2000 has sent wct=7 in some cases on responses. Four unspecified words followed OptionalSupport */ __u8 AndXCommand; __u8 AndXReserved; - __u16 AndXOffset; - __u16 OptionalSupport; /* see below */ + __le16 AndXOffset; + __le16 OptionalSupport; /* see below */ __u16 ByteCount; unsigned char Service[1]; /* always ASCII, not Unicode */ /* STRING NativeFileSystem */ @@ -565,7 +568,6 @@ #define SMB_SHARE_IS_IN_DFS 0x0002 typedef struct smb_com_logoff_andx_req { - struct smb_hdr hdr; /* wct = 2 */ __u8 AndXCommand; __u8 AndXReserved; @@ -619,20 +621,20 @@ struct smb_hdr hdr; /* wct = 24 */ __u8 AndXCommand; __u8 AndXReserved; - __u16 AndXOffset; + __le16 AndXOffset; __u8 Reserved; /* Must Be Zero */ - __u16 NameLength; - __u32 OpenFlags; - __u32 RootDirectoryFid; - __u32 DesiredAccess; - __u64 AllocationSize; - __u32 FileAttributes; - __u32 ShareAccess; - __u32 CreateDisposition; - __u32 CreateOptions; - __u32 ImpersonationLevel; + __le16 NameLength; + __le32 OpenFlags; + __le32 RootDirectoryFid; + __le32 DesiredAccess; + __le64 AllocationSize; + __le32 FileAttributes; + __le32 ShareAccess; + __le32 CreateDisposition; + __le32 CreateOptions; + __le32 ImpersonationLevel; __u8 SecurityFlags; - __u16 ByteCount; + __le16 ByteCount; char fileName[1]; } OPEN_REQ; @@ -649,19 +651,19 @@ struct smb_hdr hdr; /* wct = 34 BB */ __u8 AndXCommand; __u8 AndXReserved; - __u16 AndXOffset; + __le16 AndXOffset; __u8 OplockLevel; __u16 Fid; - __u32 CreateAction; - __u64 CreationTime; - __u64 LastAccessTime; - __u64 LastWriteTime; - __u64 ChangeTime; - __u32 FileAttributes; - __u64 AllocationSize; - __u64 EndOfFile; - __u16 FileType; - __u16 DeviceState; + __le32 CreateAction; + __le64 CreationTime; + __le64 LastAccessTime; + __le64 LastWriteTime; + __le64 ChangeTime; + __le32 FileAttributes; + __le64 AllocationSize; + __le64 EndOfFile; + __le16 FileType; + __le16 DeviceState; __u8 DirectoryFlag; __u16 ByteCount; /* bct = 0 */ } OPEN_RSP; @@ -670,29 +672,30 @@ struct smb_hdr hdr; /* wct = 14 */ __u8 AndXCommand; __u8 AndXReserved; - __u16 AndXOffset; + __le16 AndXOffset; __u16 Fid; - __u32 OffsetLow; + __le32 OffsetLow; __u32 Reserved; - __u16 WriteMode; - __u16 Remaining; - __u16 DataLengthHigh; - __u16 DataLengthLow; - __u16 DataOffset; - __u32 OffsetHigh; - __u16 ByteCount; + __le16 WriteMode; + __le16 Remaining; + __le16 DataLengthHigh; + __le16 DataLengthLow; + __le16 DataOffset; + __le32 OffsetHigh; + __le16 ByteCount; __u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */ - char Data[1]; + char Data[0]; } WRITE_REQ; typedef struct smb_com_write_rsp { struct smb_hdr hdr; /* wct = 6 */ __u8 AndXCommand; __u8 AndXReserved; - __u16 AndXOffset; - __u16 Count; - __u16 Remaining; - __u32 Reserved; + __le16 AndXOffset; + __le16 Count; + __le16 Remaining; + __le16 CountHigh; + __u16 Reserved; __u16 ByteCount; } WRITE_RSP; @@ -700,28 +703,28 @@ struct smb_hdr hdr; /* wct = 12 */ __u8 AndXCommand; __u8 AndXReserved; - __u16 AndXOffset; + __le16 AndXOffset; __u16 Fid; - __u32 OffsetLow; - __u16 MaxCount; - __u16 MinCount; /* obsolete */ - __u32 MaxCountHigh; - __u16 Remaining; - __u32 OffsetHigh; - __u16 ByteCount; + __le32 OffsetLow; + __le16 MaxCount; + __le16 MinCount; /* obsolete */ + __le32 MaxCountHigh; + __le16 Remaining; + __le32 OffsetHigh; + __le16 ByteCount; } READ_REQ; typedef struct smb_com_read_rsp { struct smb_hdr hdr; /* wct = 12 */ __u8 AndXCommand; __u8 AndXReserved; - __u16 AndXOffset; - __u16 Remaining; - __u16 DataCompactionMode; - __u16 Reserved; - __u16 DataLength; - __u16 DataOffset; - __u16 DataLengthHigh; + __le16 AndXOffset; + __le16 Remaining; + __le16 DataCompactionMode; + __le16 Reserved; + __le16 DataLength; + __le16 DataOffset; + __le16 DataLengthHigh; __u64 Reserved2; __u16 ByteCount; __u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */ @@ -729,12 +732,12 @@ } READ_RSP; typedef struct locking_andx_range { - __u16 Pid; - __u16 Pad; - __u32 OffsetHigh; - __u32 OffsetLow; - __u32 LengthHigh; - __u32 LengthLow; + __le16 Pid; + __le16 Pad; + __le32 OffsetHigh; + __le32 OffsetLow; + __le32 LengthHigh; + __le32 LengthLow; } LOCKING_ANDX_RANGE; #define LOCKING_ANDX_SHARED_LOCK 0x01 @@ -747,14 +750,14 @@ struct smb_hdr hdr; /* wct = 8 */ __u8 AndXCommand; __u8 AndXReserved; - __u16 AndXOffset; + __le16 AndXOffset; __u16 Fid; __u8 LockType; __u8 OplockLevel; - __u32 Timeout; - __u16 NumberOfUnlocks; - __u16 NumberOfLocks; - __u16 ByteCount; + __le32 Timeout; + __le16 NumberOfUnlocks; + __le16 NumberOfLocks; + __le16 ByteCount; LOCKING_ANDX_RANGE Locks[1]; } LOCK_REQ; @@ -762,14 +765,14 @@ struct smb_hdr hdr; /* wct = 2 */ __u8 AndXCommand; __u8 AndXReserved; - __u16 AndXOffset; + __le16 AndXOffset; __u16 ByteCount; } LOCK_RSP; typedef struct smb_com_rename_req { struct smb_hdr hdr; /* wct = 1 */ - __u16 SearchAttributes; /* target file attributes */ - __u16 ByteCount; + __le16 SearchAttributes; /* target file attributes */ + __le16 ByteCount; __u8 BufferFormat; /* 4 = ASCII or Unicode */ unsigned char OldFileName[1]; /* followed by __u8 BufferFormat2 */ @@ -787,9 +790,9 @@ typedef struct smb_com_copy_req { struct smb_hdr hdr; /* wct = 3 */ __u16 Tid2; - __u16 OpenFunction; - __u16 Flags; - __u16 ByteCount; + __le16 OpenFunction; + __le16 Flags; + __le16 ByteCount; __u8 BufferFormat; /* 4 = ASCII or Unicode */ unsigned char OldFileName[1]; /* followed by __u8 BufferFormat2 */ @@ -798,7 +801,7 @@ typedef struct smb_com_copy_rsp { struct smb_hdr hdr; /* wct = 1 */ - __u16 CopyCount; /* number of files copied */ + __le16 CopyCount; /* number of files copied */ __u16 ByteCount; /* may be zero */ __u8 BufferFormat; /* 0x04 - only present if errored file follows */ unsigned char ErrorFileName[1]; /* only present if error in copy */ @@ -810,10 +813,10 @@ typedef struct smb_com_nt_rename_req { /* A5 - also used for create hardlink */ struct smb_hdr hdr; /* wct = 4 */ - __u16 SearchAttributes; /* target file attributes */ - __u16 Flags; /* spec says Information Level */ - __u32 ClusterCount; - __u16 ByteCount; + __le16 SearchAttributes; /* target file attributes */ + __le16 Flags; /* spec says Information Level */ + __le32 ClusterCount; + __le16 ByteCount; __u8 BufferFormat; /* 4 = ASCII or Unicode */ unsigned char OldFileName[1]; /* followed by __u8 BufferFormat2 */ @@ -827,8 +830,8 @@ typedef struct smb_com_delete_file_req { struct smb_hdr hdr; /* wct = 1 */ - __u16 SearchAttributes; - __u16 ByteCount; + __le16 SearchAttributes; + __le16 ByteCount; __u8 BufferFormat; /* 4 = ASCII */ unsigned char fileName[1]; } DELETE_FILE_REQ; @@ -840,7 +843,7 @@ typedef struct smb_com_delete_directory_req { struct smb_hdr hdr; /* wct = 0 */ - __u16 ByteCount; + __le16 ByteCount; __u8 BufferFormat; /* 4 = ASCII */ unsigned char DirName[1]; } DELETE_DIRECTORY_REQ; @@ -852,7 +855,7 @@ typedef struct smb_com_create_directory_req { struct smb_hdr hdr; /* wct = 0 */ - __u16 ByteCount; + __le16 ByteCount; __u8 BufferFormat; /* 4 = ASCII */ unsigned char DirName[1]; } CREATE_DIRECTORY_REQ; @@ -870,22 +873,22 @@ struct smb_hdr hdr; /* wct = 23 */ __u8 MaxSetupCount; __u16 Reserved; - __u32 TotalParameterCount; - __u32 TotalDataCount; - __u32 MaxParameterCount; - __u32 MaxDataCount; - __u32 ParameterCount; - __u32 ParameterOffset; - __u32 DataCount; - __u32 DataOffset; + __le32 TotalParameterCount; + __le32 TotalDataCount; + __le32 MaxParameterCount; + __le32 MaxDataCount; + __le32 ParameterCount; + __le32 ParameterOffset; + __le32 DataCount; + __le32 DataOffset; __u8 SetupCount; /* four setup words follow subcommand */ /* SNIA spec incorrectly included spurious pad here */ - __u16 SubCommand;/* 2 = IOCTL/FSCTL */ - __u32 FunctionCode; + __le16 SubCommand;/* 2 = IOCTL/FSCTL */ + __le32 FunctionCode; __u16 Fid; __u8 IsFsctl; /* 1 = File System Control, 0 = device control (IOCTL)*/ __u8 IsRootFlag; /* 1 = apply command to root of share (must be DFS share)*/ - __u16 ByteCount; + __le16 ByteCount; __u8 Pad[3]; __u8 Data[1]; } TRANSACT_IOCTL_REQ; @@ -893,16 +896,16 @@ typedef struct smb_com_transaction_ioctl_rsp { struct smb_hdr hdr; /* wct = 19 */ __u8 Reserved[3]; - __u32 TotalParameterCount; - __u32 TotalDataCount; - __u32 ParameterCount; - __u32 ParameterOffset; - __u32 ParameterDisplacement; - __u32 DataCount; - __u32 DataOffset; - __u32 DataDisplacement; + __le32 TotalParameterCount; + __le32 TotalDataCount; + __le32 ParameterCount; + __le32 ParameterOffset; + __le32 ParameterDisplacement; + __le32 DataCount; + __le32 DataOffset; + __le32 DataDisplacement; __u8 SetupCount; /* 1 */ - __u16 ReturnedDataLen; + __le16 ReturnedDataLen; __u16 ByteCount; __u8 Pad[3]; } TRANSACT_IOCTL_RSP; @@ -911,22 +914,22 @@ struct smb_hdr hdr; /* wct = 23 */ __u8 MaxSetupCount; __u16 Reserved; - __u32 TotalParameterCount; - __u32 TotalDataCount; - __u32 MaxParameterCount; - __u32 MaxDataCount; - __u32 ParameterCount; - __u32 ParameterOffset; - __u32 DataCount; - __u32 DataOffset; + __le32 TotalParameterCount; + __le32 TotalDataCount; + __le32 MaxParameterCount; + __le32 MaxDataCount; + __le32 ParameterCount; + __le32 ParameterOffset; + __le32 DataCount; + __le32 DataOffset; __u8 SetupCount; /* four setup words follow subcommand */ /* SNIA spec incorrectly included spurious pad here */ - __u16 SubCommand;/* 4 = Change Notify */ - __u32 CompletionFilter; /* operation to monitor */ + __le16 SubCommand;/* 4 = Change Notify */ + __le32 CompletionFilter; /* operation to monitor */ __u16 Fid; __u8 WatchTree; /* 1 = Monitor subdirectories */ __u8 Reserved2; - __u16 ByteCount; + __le16 ByteCount; /* __u8 Pad[3];*/ /* __u8 Data[1];*/ } TRANSACT_CHANGE_NOTIFY_REQ; @@ -934,14 +937,14 @@ typedef struct smb_com_transaction_change_notify_rsp { struct smb_hdr hdr; /* wct = 18 */ __u8 Reserved[3]; - __u32 TotalParameterCount; - __u32 TotalDataCount; - __u32 ParameterCount; - __u32 ParameterOffset; - __u32 ParameterDisplacement; - __u32 DataCount; - __u32 DataOffset; - __u32 DataDisplacement; + __le32 TotalParameterCount; + __le32 TotalDataCount; + __le32 ParameterCount; + __le32 ParameterOffset; + __le32 ParameterDisplacement; + __le32 DataCount; + __le32 DataOffset; + __le32 DataDisplacement; __u8 SetupCount; /* 0 */ __u16 ByteCount; /* __u8 Pad[3]; */ @@ -972,10 +975,10 @@ /* response contains array of the following structures */ struct file_notify_information { - __u32 NextEntryOffset; - __u32 Action; - __u32 FileNameLength; - __u8 FileName[1]; + __le32 NextEntryOffset; + __le32 Action; + __le32 FileNameLength; + __u8 FileName[0]; }; struct reparse_data { @@ -1004,45 +1007,55 @@ #define QUOTA_LIST_START 0x100 #define QUOTA_FOR_SID 0x101 -typedef union smb_com_transaction2 { - struct { - struct smb_hdr hdr; /* wct = 14+ */ - __u16 TotalParameterCount; - __u16 TotalDataCount; - __u16 MaxParameterCount; - __u16 MaxDataCount; - __u8 MaxSetupCount; - __u8 Reserved; - __u16 Flags; - __u32 Timeout; - __u16 Reserved2; - __u16 ParameterCount; - __u16 ParameterOffset; - __u16 DataCount; - __u16 DataOffset; - __u8 SetupCount; - __u8 Reserved3; - __u16 SubCommand; /* 1st setup word - can be followed by SetupCount words */ - __u16 ByteCount; /* careful - setupcount is not always one */ - } req; - struct { - struct smb_hdr hdr; /* wct = 0 */ - __u16 TotalParameterCount; - __u16 TotalDataCount; - __u16 Reserved; - __u16 ParameterCount; - __u16 ParamterOffset; - __u16 ParameterDisplacement; - __u16 DataCount; - __u16 DataOffset; - __u16 DataDisplacement; - __u8 SetupCount; - __u8 Reserved1; /* should be zero setup words following */ - __u16 ByteCount; - __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */ - /* data area follows */ - } resp; -} TRANSACTION2; +struct trans2_req { + /* struct smb_hdr hdr precedes. Set wct = 14+ */ + __le16 TotalParameterCount; + __le16 TotalDataCount; + __le16 MaxParameterCount; + __le16 MaxDataCount; + __u8 MaxSetupCount; + __u8 Reserved; + __le16 Flags; + __le32 Timeout; + __u16 Reserved2; + __le16 ParameterCount; + __le16 ParameterOffset; + __le16 DataCount; + __le16 DataOffset; + __u8 SetupCount; + __u8 Reserved3; + __le16 SubCommand; /* 1st setup word - SetupCount words follow */ + __le16 ByteCount; +}; + +struct smb_t2_req { + struct smb_hdr hdr; + struct trans2_req t2_req; +}; + +struct trans2_resp { + /* struct smb_hdr hdr precedes. Note wct = 10 + setup count */ + __le16 TotalParameterCount; + __le16 TotalDataCount; + __u16 Reserved; + __le16 ParameterCount; + __le16 ParameterOffset; + __le16 ParameterDisplacement; + __le16 DataCount; + __le16 DataOffset; + __le16 DataDisplacement; + __u8 SetupCount; + __u8 Reserved1; + /* SetupWords[SetupCount]; + __u16 ByteCount; + __u16 Reserved2;*/ + /* data area follows */ +}; + +struct smb_t2_rsp { + struct smb_hdr hdr; + struct trans2_resp t2_rsp; +}; /* PathInfo/FileInfo infolevels */ #define SMB_INFO_STANDARD 1 @@ -1063,6 +1076,15 @@ #define SMB_QUERY_FILE_COMPRESSION_INFO 0x10B #define SMB_QUERY_FILE_UNIX_BASIC 0x200 #define SMB_QUERY_FILE_UNIX_LINK 0x201 +#define SMB_QUERY_POSIX_ACL 0x204 +#define SMB_QUERY_XATTR 0x205 +#define SMB_QUERY_FILE_INTERNAL_INFO 0x3ee +#define SMB_QUERY_FILE_ACCESS_INFO 0x3f0 +#define SMB_QUERY_FILE_NAME_INFO2 0x3f1 /* 0x30 bytes */ +#define SMB_QUERY_FILE_POSITION_INFO 0x3f6 +#define SMB_QUERY_FILE_MODE_INFO 0x3f8 +#define SMB_QUERY_FILE_ALGN_INFO 0x3f9 + #define SMB_SET_FILE_BASIC_INFO 0x101 #define SMB_SET_FILE_DISPOSITION_INFO 0x102 @@ -1071,8 +1093,10 @@ #define SMB_SET_FILE_UNIX_BASIC 0x200 #define SMB_SET_FILE_UNIX_LINK 0x201 #define SMB_SET_FILE_UNIX_HLINK 0x203 +#define SMB_SET_POSIX_ACL 0x204 +#define SMB_SET_XATTR 0x205 #define SMB_SET_FILE_BASIC_INFO2 0x3ec -#define SMB_SET_FILE_RENAME_INFORMATION 0x3f2 +#define SMB_SET_FILE_RENAME_INFORMATION 0x3f2 /* BB check if qpathinfo level too */ #define SMB_FILE_ALL_INFO2 0x3fa #define SMB_SET_FILE_ALLOCATION_INFO2 0x3fb #define SMB_SET_FILE_END_OF_FILE_INFO2 0x3fc @@ -1086,139 +1110,111 @@ #define SMB_FIND_FILE_FULL_DIRECTORY_INFO 0x102 #define SMB_FIND_FILE_NAMES_INFO 0x103 #define SMB_FIND_FILE_BOTH_DIRECTORY_INFO 0x104 +#define SMB_FIND_FILE_ID_FULL_DIR_INFO 0x105 +#define SMB_FIND_FILE_ID_BOTH_DIR_INFO 0x106 #define SMB_FIND_FILE_UNIX 0x202 typedef struct smb_com_transaction2_qpi_req { struct smb_hdr hdr; /* wct = 14+ */ - __u16 TotalParameterCount; - __u16 TotalDataCount; - __u16 MaxParameterCount; - __u16 MaxDataCount; + __le16 TotalParameterCount; + __le16 TotalDataCount; + __le16 MaxParameterCount; + __le16 MaxDataCount; __u8 MaxSetupCount; __u8 Reserved; - __u16 Flags; - __u32 Timeout; + __le16 Flags; + __le32 Timeout; __u16 Reserved2; - __u16 ParameterCount; - __u16 ParameterOffset; - __u16 DataCount; - __u16 DataOffset; + __le16 ParameterCount; + __le16 ParameterOffset; + __le16 DataCount; + __le16 DataOffset; __u8 SetupCount; __u8 Reserved3; - __u16 SubCommand; /* one setup word */ - __u16 ByteCount; + __le16 SubCommand; /* one setup word */ + __le16 ByteCount; __u8 Pad; - __u16 InformationLevel; + __le16 InformationLevel; __u32 Reserved4; char FileName[1]; } TRANSACTION2_QPI_REQ; typedef struct smb_com_transaction2_qpi_rsp { struct smb_hdr hdr; /* wct = 10 + SetupCount */ - __u16 TotalParameterCount; - __u16 TotalDataCount; - __u16 Reserved; - __u16 ParameterCount; - __u16 ParameterOffset; - __u16 ParameterDisplacement; - __u16 DataCount; - __u16 DataOffset; - __u16 DataDisplacement; - __u8 SetupCount; - __u8 Reserved1; /* should be zero setup words following */ + struct trans2_resp t2; __u16 ByteCount; __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */ } TRANSACTION2_QPI_RSP; typedef struct smb_com_transaction2_spi_req { struct smb_hdr hdr; /* wct = 15 */ - __u16 TotalParameterCount; - __u16 TotalDataCount; - __u16 MaxParameterCount; - __u16 MaxDataCount; + __le16 TotalParameterCount; + __le16 TotalDataCount; + __le16 MaxParameterCount; + __le16 MaxDataCount; __u8 MaxSetupCount; __u8 Reserved; - __u16 Flags; - __u32 Timeout; + __le16 Flags; + __le32 Timeout; __u16 Reserved2; - __u16 ParameterCount; - __u16 ParameterOffset; - __u16 DataCount; - __u16 DataOffset; + __le16 ParameterCount; + __le16 ParameterOffset; + __le16 DataCount; + __le16 DataOffset; __u8 SetupCount; __u8 Reserved3; - __u16 SubCommand; /* one setup word */ - __u16 ByteCount; + __le16 SubCommand; /* one setup word */ + __le16 ByteCount; __u8 Pad; __u16 Pad1; - __u16 InformationLevel; + __le16 InformationLevel; __u32 Reserved4; char FileName[1]; } TRANSACTION2_SPI_REQ; typedef struct smb_com_transaction2_spi_rsp { struct smb_hdr hdr; /* wct = 10 + SetupCount */ - __u16 TotalParameterCount; - __u16 TotalDataCount; - __u16 Reserved; - __u16 ParameterCount; - __u16 ParameterOffset; - __u16 ParameterDisplacement; - __u16 DataCount; - __u16 DataOffset; - __u16 DataDisplacement; - __u8 SetupCount; - __u8 Reserved1; /* should be zero setup words following */ + struct trans2_resp t2; __u16 ByteCount; __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */ } TRANSACTION2_SPI_RSP; struct set_file_rename { - __u32 overwrite; /* 1 = overwrite dest */ + __le32 overwrite; /* 1 = overwrite dest */ __u32 root_fid; /* zero */ - __u32 target_name_len; + __le32 target_name_len; char target_name[0]; /* Must be unicode */ }; struct smb_com_transaction2_sfi_req { struct smb_hdr hdr; /* wct = 15 */ - __u16 TotalParameterCount; - __u16 TotalDataCount; - __u16 MaxParameterCount; - __u16 MaxDataCount; + __le16 TotalParameterCount; + __le16 TotalDataCount; + __le16 MaxParameterCount; + __le16 MaxDataCount; __u8 MaxSetupCount; __u8 Reserved; - __u16 Flags; - __u32 Timeout; + __le16 Flags; + __le32 Timeout; __u16 Reserved2; - __u16 ParameterCount; - __u16 ParameterOffset; - __u16 DataCount; - __u16 DataOffset; + __le16 ParameterCount; + __le16 ParameterOffset; + __le16 DataCount; + __le16 DataOffset; __u8 SetupCount; __u8 Reserved3; - __u16 SubCommand; /* one setup word */ - __u16 ByteCount; + __le16 SubCommand; /* one setup word */ + __le16 ByteCount; __u8 Pad; __u16 Pad1; __u16 Fid; - __u16 InformationLevel; + __le16 InformationLevel; __u16 Reserved4; }; struct smb_com_transaction2_sfi_rsp { struct smb_hdr hdr; /* wct = 10 + SetupCount */ - __u16 TotalParameterCount; - __u16 TotalDataCount; - __u16 Reserved; - __u16 ParameterCount; - __u16 ParameterOffset; - __u16 ParameterDisplacement; - __u16 DataCount; - __u16 DataOffset; - __u16 DataDisplacement; - __u8 SetupCount; - __u8 Reserved1; /* should be zero setup words following */ + struct trans2_resp t2; __u16 ByteCount; __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */ }; @@ -1240,105 +1236,85 @@ typedef struct smb_com_transaction2_ffirst_req { struct smb_hdr hdr; /* wct = 15 */ - __u16 TotalParameterCount; - __u16 TotalDataCount; - __u16 MaxParameterCount; - __u16 MaxDataCount; + __le16 TotalParameterCount; + __le16 TotalDataCount; + __le16 MaxParameterCount; + __le16 MaxDataCount; __u8 MaxSetupCount; __u8 Reserved; - __u16 Flags; - __u32 Timeout; + __le16 Flags; + __le32 Timeout; __u16 Reserved2; - __u16 ParameterCount; - __u16 ParameterOffset; - __u16 DataCount; - __u16 DataOffset; + __le16 ParameterCount; + __le16 ParameterOffset; + __le16 DataCount; + __le16 DataOffset; __u8 SetupCount; /* one */ __u8 Reserved3; - __u16 SubCommand; /* TRANS2_FIND_FIRST */ - __u16 ByteCount; + __le16 SubCommand; /* TRANS2_FIND_FIRST */ + __le16 ByteCount; __u8 Pad; - __u16 SearchAttributes; - __u16 SearchCount; - __u16 SearchFlags; - __u16 InformationLevel; - __u32 SearchStorageType; + __le16 SearchAttributes; + __le16 SearchCount; + __le16 SearchFlags; + __le16 InformationLevel; + __le32 SearchStorageType; char FileName[1]; } TRANSACTION2_FFIRST_REQ; typedef struct smb_com_transaction2_ffirst_rsp { struct smb_hdr hdr; /* wct = 10 */ - __u16 TotalParameterCount; - __u16 TotalDataCount; - __u16 Reserved; - __u16 ParameterCount; - __u16 ParameterOffset; - __u16 ParameterDisplacement; - __u16 DataCount; - __u16 DataOffset; - __u16 DataDisplacement; - __u8 SetupCount; - __u8 Reserved1; /* should be zero setup words following */ + struct trans2_resp t2; __u16 ByteCount; } TRANSACTION2_FFIRST_RSP; typedef struct smb_com_transaction2_ffirst_rsp_parms { __u16 SearchHandle; - __u16 SearchCount; - __u16 EndofSearch; - __u16 EAErrorOffset; - __u16 LastNameOffset; + __le16 SearchCount; + __le16 EndofSearch; + __le16 EAErrorOffset; + __le16 LastNameOffset; } T2_FFIRST_RSP_PARMS; typedef struct smb_com_transaction2_fnext_req { struct smb_hdr hdr; /* wct = 15 */ - __u16 TotalParameterCount; - __u16 TotalDataCount; - __u16 MaxParameterCount; - __u16 MaxDataCount; + __le16 TotalParameterCount; + __le16 TotalDataCount; + __le16 MaxParameterCount; + __le16 MaxDataCount; __u8 MaxSetupCount; __u8 Reserved; - __u16 Flags; - __u32 Timeout; + __le16 Flags; + __le32 Timeout; __u16 Reserved2; - __u16 ParameterCount; - __u16 ParameterOffset; - __u16 DataCount; - __u16 DataOffset; + __le16 ParameterCount; + __le16 ParameterOffset; + __le16 DataCount; + __le16 DataOffset; __u8 SetupCount; /* one */ __u8 Reserved3; - __u16 SubCommand; /* TRANS2_FIND_NEXT */ - __u16 ByteCount; + __le16 SubCommand; /* TRANS2_FIND_NEXT */ + __le16 ByteCount; __u8 Pad; __u16 SearchHandle; - __u16 SearchCount; - __u16 InformationLevel; + __le16 SearchCount; + __le16 InformationLevel; __u32 ResumeKey; - __u16 SearchFlags; + __le16 SearchFlags; char ResumeFileName[1]; } TRANSACTION2_FNEXT_REQ; typedef struct smb_com_transaction2_fnext_rsp { struct smb_hdr hdr; /* wct = 10 */ - __u16 TotalParameterCount; - __u16 TotalDataCount; - __u16 Reserved; - __u16 ParameterCount; - __u16 ParameterOffset; - __u16 ParameterDisplacement; - __u16 DataCount; - __u16 DataOffset; - __u16 DataDisplacement; - __u8 SetupCount; - __u8 Reserved1; /* should be zero setup words following */ + struct trans2_resp t2; __u16 ByteCount; } TRANSACTION2_FNEXT_RSP; typedef struct smb_com_transaction2_fnext_rsp_parms { - __u16 SearchCount; - __u16 EndofSearch; - __u16 EAErrorOffset; - __u16 LastNameOffset; + __le16 SearchCount; + __le16 EndofSearch; + __le16 EAErrorOffset; + __le16 LastNameOffset; } T2_FNEXT_RSP_PARMS; /* QFSInfo Levels */ @@ -1351,101 +1327,83 @@ #define SMB_QUERY_CIFS_UNIX_INFO 0x200 #define SMB_QUERY_LABEL_INFO 0x3ea #define SMB_QUERY_FS_QUOTA_INFO 0x3ee +#define SMB_QUERY_FS_FULL_SIZE_INFO 0x3ef +#define SMB_QUERY_OBJECTID_INFO 0x3f0 typedef struct smb_com_transaction2_qfsi_req { struct smb_hdr hdr; /* wct = 14+ */ - __u16 TotalParameterCount; - __u16 TotalDataCount; - __u16 MaxParameterCount; - __u16 MaxDataCount; + __le16 TotalParameterCount; + __le16 TotalDataCount; + __le16 MaxParameterCount; + __le16 MaxDataCount; __u8 MaxSetupCount; __u8 Reserved; - __u16 Flags; - __u32 Timeout; + __le16 Flags; + __le32 Timeout; __u16 Reserved2; - __u16 ParameterCount; - __u16 ParameterOffset; - __u16 DataCount; - __u16 DataOffset; + __le16 ParameterCount; + __le16 ParameterOffset; + __le16 DataCount; + __le16 DataOffset; __u8 SetupCount; __u8 Reserved3; - __u16 SubCommand; /* one setup word */ - __u16 ByteCount; + __le16 SubCommand; /* one setup word */ + __le16 ByteCount; __u8 Pad; - __u16 InformationLevel; + __le16 InformationLevel; } TRANSACTION2_QFSI_REQ; typedef struct smb_com_transaction_qfsi_rsp { struct smb_hdr hdr; /* wct = 10 + SetupCount */ - __u16 TotalParameterCount; - __u16 TotalDataCount; - __u16 Reserved; - __u16 ParameterCount; - __u16 ParameterOffset; - __u16 ParameterDisplacement; - __u16 DataCount; - __u16 DataOffset; - __u16 DataDisplacement; - __u8 SetupCount; - __u8 Reserved1; /* should be zero setup words following */ + struct trans2_resp t2; __u16 ByteCount; __u8 Pad; /* may be three bytes *//* followed by data area */ } TRANSACTION2_QFSI_RSP; typedef struct smb_com_transaction2_get_dfs_refer_req { struct smb_hdr hdr; /* wct = 15 */ - __u16 TotalParameterCount; - __u16 TotalDataCount; - __u16 MaxParameterCount; - __u16 MaxDataCount; + __le16 TotalParameterCount; + __le16 TotalDataCount; + __le16 MaxParameterCount; + __le16 MaxDataCount; __u8 MaxSetupCount; __u8 Reserved; - __u16 Flags; - __u32 Timeout; + __le16 Flags; + __le32 Timeout; __u16 Reserved2; - __u16 ParameterCount; - __u16 ParameterOffset; - __u16 DataCount; - __u16 DataOffset; + __le16 ParameterCount; + __le16 ParameterOffset; + __le16 DataCount; + __le16 DataOffset; __u8 SetupCount; __u8 Reserved3; - __u16 SubCommand; /* one setup word */ - __u16 ByteCount; + __le16 SubCommand; /* one setup word */ + __le16 ByteCount; __u8 Pad[3]; /* Win2K has sent 0x0F01 (max resp length perhaps?) followed by one byte pad - doesn't seem to matter though */ - __u16 MaxReferralLevel; + __le16 MaxReferralLevel; char RequestFileName[1]; } TRANSACTION2_GET_DFS_REFER_REQ; typedef struct dfs_referral_level_3 { - __u16 VersionNumber; - __u16 ReferralSize; - __u16 ServerType; /* 0x0001 = CIFS server */ - __u16 ReferralFlags; /* or proximity - not clear which since always set to zero - SNIA spec says 0x01 means strip off PathConsumed chars before submitting RequestFileName to remote node */ - __u16 TimeToLive; - __u16 Proximity; - __u16 DfsPathOffset; - __u16 DfsAlternatePathOffset; - __u16 NetworkAddressOffset; + __le16 VersionNumber; + __le16 ReferralSize; + __le16 ServerType; /* 0x0001 = CIFS server */ + __le16 ReferralFlags; /* or proximity - not clear which since always set to zero - SNIA spec says 0x01 means strip off PathConsumed chars before submitting RequestFileName to remote node */ + __le16 TimeToLive; + __le16 Proximity; + __le16 DfsPathOffset; + __le16 DfsAlternatePathOffset; + __le16 NetworkAddressOffset; } REFERRAL3; typedef struct smb_com_transaction_get_dfs_refer_rsp { struct smb_hdr hdr; /* wct = 10 */ - __u16 TotalParameterCount; - __u16 TotalDataCount; - __u16 Reserved; - __u16 ParameterCount; - __u16 ParameterOffset; - __u16 ParameterDisplacement; - __u16 DataCount; - __u16 DataOffset; - __u16 DataDisplacement; - __u8 SetupCount; - __u8 Reserved1; /* zero setup words following */ + struct trans2_resp t2; __u16 ByteCount; __u8 Pad; - __u16 PathConsumed; - __u16 NumberOfReferrals; - __u16 DFSFlags; + __le16 PathConsumed; + __le16 NumberOfReferrals; + __le16 DFSFlags; __u16 Pad2; REFERRAL3 referrals[1]; /* array of level 3 dfs_referral structures */ /* followed by the strings pointed to by the referral structures */ @@ -1531,20 +1489,21 @@ }; typedef struct { - __u64 TotalAllocationUnits; - __u64 FreeAllocationUnits; - __u32 SectorsPerAllocationUnit; - __u32 BytesPerSector; + __le64 TotalAllocationUnits; + __le64 FreeAllocationUnits; + __le32 SectorsPerAllocationUnit; + __le32 BytesPerSector; } FILE_SYSTEM_INFO; /* size info, level 0x103 */ typedef struct { - __u16 MajorVersionNumber; - __u16 MinorVersionNumber; - __u64 Capability; + __le16 MajorVersionNumber; + __le16 MinorVersionNumber; + __le64 Capability; } 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*/ /* DeviceType Flags */ #define FILE_DEVICE_CD_ROM 0x00000002 @@ -1567,73 +1526,43 @@ #define FILE_DEVICE_NETWORK_REDIRECTOR 0x00000028 typedef struct { - __u32 DeviceType; - __u32 DeviceCharacteristics; + __le32 DeviceType; + __le32 DeviceCharacteristics; } FILE_SYSTEM_DEVICE_INFO; /* device info, level 0x104 */ typedef struct { - __u32 Attributes; - __u32 MaxPathNameComponentLength; - __u32 FileSystemNameLen; - char FileSystemName[52]; /* do not really need to save this - so potentially get only subset of name */ + __le32 Attributes; + __le32 MaxPathNameComponentLength; + __le32 FileSystemNameLen; + char FileSystemName[52]; /* do not really need to save this - so potentially get only subset of name */ } FILE_SYSTEM_ATTRIBUTE_INFO; -typedef struct { /* data block encoding of response to level 263 QPathInfo */ - __u64 CreationTime; - __u64 LastAccessTime; - __u64 LastWriteTime; - __u64 ChangeTime; - __u32 Attributes; +/******************************************************************************/ +/* QueryFileInfo/QueryPathinfo (also for SetPath/SetFile) data buffer formats */ +/******************************************************************************/ +typedef struct { /* data block encoding of response to level 263 QPathInfo */ + __le64 CreationTime; + __le64 LastAccessTime; + __le64 LastWriteTime; + __le64 ChangeTime; + __le32 Attributes; __u32 Pad1; - __u64 AllocationSize; - __u64 EndOfFile; /* size ie offset to first free byte in file */ - __u32 NumberOfLinks; /* hard links */ + __le64 AllocationSize; + __le64 EndOfFile; /* size ie offset to first free byte in file */ + __le32 NumberOfLinks; /* hard links */ __u8 DeletePending; __u8 Directory; __u16 Pad2; __u64 IndexNumber; - __u32 EASize; - __u32 AccessFlags; + __le32 EASize; + __le32 AccessFlags; __u64 IndexNumber1; - __u64 CurrentByteOffset; - __u32 Mode; - __u32 AlignmentRequirement; - __u32 FileNameLength; + __le64 CurrentByteOffset; + __le32 Mode; + __le32 AlignmentRequirement; + __le32 FileNameLength; char FileName[1]; -} FILE_ALL_INFO; /* level 263 QPathInfo */ - -typedef struct { - __u64 EndOfFile; - __u64 NumOfBytes; - __u64 LastStatusChange; /*SNIA spec says DCE time for the three time fields */ - __u64 LastAccessTime; - __u64 LastModificationTime; - __u64 Uid; - __u64 Gid; - __u32 Type; - __u64 DevMajor; - __u64 DevMinor; - __u64 UniqueId; - __u64 Permissions; - __u64 Nlinks; -} FILE_UNIX_BASIC_INFO; /* level 512 QPathInfo */ - -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 */ +} FILE_ALL_INFO; /* level 0x107 QPathInfo */ /* defines for enumerating possible values of the Unix type field below */ #define UNIX_FILE 0 @@ -1643,56 +1572,224 @@ #define UNIX_BLOCKDEV 4 #define UNIX_FIFO 5 #define UNIX_SOCKET 6 - typedef struct { - __u32 NextEntryOffset; - __u32 ResumeKey; - __u64 EndOfFile; - __u64 NumOfBytes; - __u64 LastStatusChange; /*SNIA spec says DCE time for the three time fields */ - __u64 LastAccessTime; - __u64 LastModificationTime; - __u64 Uid; - __u64 Gid; - __u32 Type; - __u64 DevMajor; - __u64 DevMinor; + __le64 EndOfFile; + __le64 NumOfBytes; + __le64 LastStatusChange; /*SNIA specs DCE time for the 3 time fields */ + __le64 LastAccessTime; + __le64 LastModificationTime; + __le64 Uid; + __le64 Gid; + __le32 Type; + __le64 DevMajor; + __le64 DevMinor; __u64 UniqueId; - __u64 Permissions; - __u64 Nlinks; - char FileName[1]; -} FILE_UNIX_INFO; + __le64 Permissions; + __le64 Nlinks; +} FILE_UNIX_BASIC_INFO; /* level 0x200 QPathInfo */ typedef struct { - __u64 CreationTime; - __u64 LastAccessTime; - __u64 LastWriteTime; - __u64 ChangeTime; - __u32 Attributes; + char LinkDest[1]; +} FILE_UNIX_LINK_INFO; /* level 0x201 QPathInfo */ + +/* The following three structures are needed only for + setting time to NT4 and some older servers via + the primitive DOS time format */ +typedef struct { + __u16 Day:5; + __u16 Month:4; + __u16 Year:7; +} SMB_DATE; + +typedef struct { + __u16 TwoSeconds:5; + __u16 Minutes:6; + __u16 Hours:5; +} SMB_TIME; + +typedef struct { + __le16 CreationDate; /* SMB Date see above */ + __le16 CreationTime; /* SMB Time */ + __le16 LastAccessDate; + __le16 LastAccessTime; + __le16 LastWriteDate; + __le16 LastWriteTime; + __le32 DataSize; /* File Size (EOF) */ + __le32 AllocationSize; + __le16 Attributes; /* verify not u32 */ + __le32 EASize; +} FILE_INFO_STANDARD; /* level 1 SetPath/FileInfo */ + +typedef struct { + __le64 CreationTime; + __le64 LastAccessTime; + __le64 LastWriteTime; + __le64 ChangeTime; + __le32 Attributes; __u32 Pad; } FILE_BASIC_INFO; /* size info, level 0x101 */ struct file_allocation_info { - __u64 AllocationSize; -}; /* size info, level 0x103 */ + __le64 AllocationSize; /* Note old Samba srvr rounds this up too much */ +}; /* size used on disk, level 0x103 for set, 0x105 for query */ struct file_end_of_file_info { - __u64 FileSize; /* offset to end of file */ -}; /* size info, level 0x104 */ + __le64 FileSize; /* offset to end of file */ +}; /* size info, level 0x104 for set, 0x106 for query */ + +struct file_alt_name_info { + __u8 alt_name[1]; +}; /* level 0x0108 */ + +struct file_stream_info { + __le32 number_of_streams; /* BB check sizes and verify location */ + /* followed by info on streams themselves + u64 size; + u64 allocation_size + stream info */ +}; /* level 0x109 */ + +struct file_compression_info { + __le64 compressed_size; + __le16 format; + __u8 unit_shift; + __u8 ch_shift; + __u8 cl_shift; + __u8 pad[3]; +}; /* level 0x10b */ + +/* POSIX ACL set/query path info structures */ +#define CIFS_ACL_VERSION 1 +struct cifs_posix_ace { /* access control entry (ACE) */ + __u8 cifs_e_tag; + __u8 cifs_e_perm; + __le64 cifs_uid; /* or gid */ +}; + +struct cifs_posix_acl { /* access conrol list (ACL) */ + __le16 version; + __le16 access_entry_count; /* access ACL - count of entries */ + __le16 default_entry_count; /* default ACL - count of entries */ + struct cifs_posix_ace ace_array[0]; + /* followed by + struct cifs_posix_ace default_ace_arraay[] */ +}; /* level 0x204 */ + +/* types of access control entries already defined in posix_acl.h */ +/* #define CIFS_POSIX_ACL_USER_OBJ 0x01 +#define CIFS_POSIX_ACL_USER 0x02 +#define CIFS_POSIX_ACL_GROUP_OBJ 0x04 +#define CIFS_POSIX_ACL_GROUP 0x08 +#define CIFS_POSIX_ACL_MASK 0x10 +#define CIFS_POSIX_ACL_OTHER 0x20 */ + +/* types of perms */ +/* #define CIFS_POSIX_ACL_EXECUTE 0x01 +#define CIFS_POSIX_ACL_WRITE 0x02 +#define CIFS_POSIX_ACL_READ 0x04 */ + +/* end of POSIX ACL definitions */ + +struct file_internal_info { + __u64 UniqueId; /* inode number */ +}; /* level 0x3ee */ +struct file_mode_info { + __le32 Mode; +}; /* level 0x3f8 */ + +struct file_attrib_tag { + __le32 Attribute; + __le32 ReparseTag; +}; /* level 0x40b */ + + +/********************************************************/ +/* FindFirst/FindNext transact2 data buffer formats */ +/********************************************************/ typedef struct { - __u32 NextEntryOffset; + __le32 NextEntryOffset; + __u32 ResumeKey; /* as with FileIndex - no need to convert */ + __le64 EndOfFile; + __le64 NumOfBytes; + __le64 LastStatusChange; /*SNIA specs DCE time for the 3 time fields */ + __le64 LastAccessTime; + __le64 LastModificationTime; + __le64 Uid; + __le64 Gid; + __le32 Type; + __le64 DevMajor; + __le64 DevMinor; + __u64 UniqueId; + __le64 Permissions; + __le64 Nlinks; + char FileName[1]; +} FILE_UNIX_INFO; /* level 0x202 */ + +typedef struct { + __le32 NextEntryOffset; __u32 FileIndex; - __u64 CreationTime; - __u64 LastAccessTime; - __u64 LastWriteTime; - __u64 ChangeTime; - __u64 EndOfFile; - __u64 AllocationSize; - __u32 ExtFileAttributes; - __u32 FileNameLength; + __le64 CreationTime; + __le64 LastAccessTime; + __le64 LastWriteTime; + __le64 ChangeTime; + __le64 EndOfFile; + __le64 AllocationSize; + __le32 ExtFileAttributes; + __le32 FileNameLength; char FileName[1]; -} FILE_DIRECTORY_INFO; /* level 257 FF response data area */ +} FILE_DIRECTORY_INFO; /* level 0x101 FF response data area */ + +typedef struct { + __le32 NextEntryOffset; + __u32 FileIndex; + __le64 CreationTime; + __le64 LastAccessTime; + __le64 LastWriteTime; + __le64 ChangeTime; + __le64 EndOfFile; + __le64 AllocationSize; + __le32 ExtFileAttributes; + __le32 FileNameLength; + __le32 EaSize; /* length of the xattrs */ + char FileName[1]; +} FILE_FULL_DIRECTORY_INFO; /* level 0x102 FF response data area */ + +typedef struct { + __le32 NextEntryOffset; + __u32 FileIndex; + __le64 CreationTime; + __le64 LastAccessTime; + __le64 LastWriteTime; + __le64 ChangeTime; + __le64 EndOfFile; + __le64 AllocationSize; + __le32 ExtFileAttributes; + __le32 FileNameLength; + __le32 EaSize; /* EA size */ + __le32 Reserved; + __u64 UniqueId; /* inode num - le since Samba puts ino in low 32 bit*/ + char FileName[1]; +} SEARCH_ID_FULL_DIR_INFO; /* level 0x105 FF response data area */ + +typedef struct { + __le32 NextEntryOffset; + __u32 FileIndex; + __le64 CreationTime; + __le64 LastAccessTime; + __le64 LastWriteTime; + __le64 ChangeTime; + __le64 EndOfFile; + __le64 AllocationSize; + __le32 ExtFileAttributes; + __le32 FileNameLength; + __le32 EaSize; /* length of the xattrs */ + __u8 ShortNameLength; + __u8 Reserved; + __u8 ShortName[12]; + char FileName[1]; +} FILE_BOTH_DIRECTORY_INFO; /* level 0x104 FF response data area */ + struct gea { unsigned char name_len; @@ -1707,7 +1804,7 @@ struct fea { unsigned char EA_flags; __u8 name_len; - __u16 value_len; + __le16 value_len; char name[1]; /* optionally followed by value */ }; @@ -1715,7 +1812,7 @@ #define FEA_NEEDEA 0x80 /* need EA bit */ struct fealist { - __u32 list_len; + __le32 list_len; struct fea list[1]; }; @@ -1830,6 +1927,15 @@ char path[1024]; }; +typedef struct { + /* 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 */ + + #endif #pragma pack() /* resume default structure packing */ diff -Nau fs/cifs/cifsproto.h fs/cifs.new-mm/cifsproto.h --- fs/cifs/cifsproto.h 2005-01-14 09:33:50.000000000 -0600 +++ fs/cifs.new-mm/cifsproto.h 2005-02-06 22:30:07.541011928 -0600 @@ -1,7 +1,7 @@ /* * fs/cifs/cifsproto.h * - * Copyright (c) International Business Machines Corp., 2002 + * Copyright (c) International Business Machines Corp., 2002,2004 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -32,6 +32,8 @@ extern struct smb_hdr *cifs_buf_get(void); extern void cifs_buf_release(void *); +extern struct smb_hdr *cifs_small_buf_get(void); +extern void cifs_small_buf_release(void *); extern int smb_send(struct socket *, struct smb_hdr *, unsigned int /* length */ , struct sockaddr *); extern unsigned int _GetXid(void); @@ -190,7 +192,8 @@ extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, const int netfid, const unsigned int count, const __u64 lseek, unsigned int *nbytes, - const char *buf, const int long_op); + const char *buf, const char __user *ubuf, + const int long_op); extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, const __u16 netfid, const __u64 len, const __u64 offset, const __u32 numUnlock, @@ -233,4 +236,12 @@ const char *fileName, const char * ea_name, const void * ea_value, const __u16 ea_value_len, const struct nls_table *nls_codepage); +extern int CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon, + const unsigned char *searchName, + char *acl_inf, const int buflen,const int acl_type, + const struct nls_table *nls_codepage); +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); #endif /* _CIFSPROTO_H */ diff -Nau fs/cifs/cifssmb.c fs/cifs.new-mm/cifssmb.c --- fs/cifs/cifssmb.c 2005-01-14 09:33:50.000000000 -0600 +++ fs/cifs.new-mm/cifssmb.c 2005-02-06 22:30:07.541011928 -0600 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include "cifspdu.h" #include "cifsglob.h" @@ -78,6 +79,97 @@ } static int +small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, + void **request_buf /* returned */) +{ + int rc = 0; + + /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so + check for tcp and smb session status done differently + for those three - in the calling routine */ + if(tcon) { + if((tcon->ses) && (tcon->ses->server)){ + struct nls_table *nls_codepage; + /* Give Demultiplex thread up to 10 seconds to + reconnect, should be greater than cifs socket + timeout which is 7 seconds */ + while(tcon->ses->server->tcpStatus == CifsNeedReconnect) { + wait_event_interruptible_timeout(tcon->ses->server->response_q, + (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ); + if(tcon->ses->server->tcpStatus == CifsNeedReconnect) { + /* on "soft" mounts we wait once */ + if((tcon->retry == FALSE) || + (tcon->ses->status == CifsExiting)) { + cFYI(1,("gave up waiting on reconnect in smb_init")); + return -EHOSTDOWN; + } /* else "hard" mount - keep retrying until + process is killed or server comes back up */ + } else /* TCP session is reestablished now */ + break; + + } + + nls_codepage = load_nls_default(); + /* need to prevent multiple threads trying to + simultaneously reconnect the same SMB session */ + down(&tcon->ses->sesSem); + if(tcon->ses->status == CifsNeedReconnect) + rc = cifs_setup_session(0, tcon->ses, nls_codepage); + if(!rc && (tcon->tidStatus == CifsNeedReconnect)) { + mark_open_files_invalid(tcon); + rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon, + nls_codepage); + up(&tcon->ses->sesSem); + if(rc == 0) + atomic_inc(&tconInfoReconnectCount); + + cFYI(1, ("reconnect tcon rc = %d", rc)); + /* Removed call to reopen open files here - + it is safer (and faster) to reopen files + one at a time as needed in read and write */ + + /* Check if handle based operation so we + know whether we can continue or not without + returning to caller to reset file handle */ + switch(smb_command) { + case SMB_COM_READ_ANDX: + case SMB_COM_WRITE_ANDX: + case SMB_COM_CLOSE: + case SMB_COM_FIND_CLOSE2: + case SMB_COM_LOCKING_ANDX: { + unload_nls(nls_codepage); + return -EAGAIN; + } + } + } else { + up(&tcon->ses->sesSem); + } + unload_nls(nls_codepage); + + } else { + return -EIO; + } + } + if(rc) + return rc; + + *request_buf = cifs_small_buf_get(); + if (*request_buf == NULL) { + /* BB should we add a retry in here if not a writepage? */ + return -ENOMEM; + } + + header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct); + +#ifdef CONFIG_CIFS_STATS + if(tcon != NULL) { + atomic_inc(&tcon->num_smbs_sent); + } +#endif /* CONFIG_CIFS_STATS */ + return rc; +} + +static int smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, void **request_buf /* returned */ , void **response_buf /* returned */ ) @@ -154,7 +246,7 @@ return rc; *request_buf = cifs_buf_get(); - if (*request_buf == 0) { + if (*request_buf == NULL) { /* BB should we add a retry in here if not a writepage? */ return -ENOMEM; } @@ -171,10 +263,42 @@ if(tcon != NULL) { atomic_inc(&tcon->num_smbs_sent); } -#endif +#endif /* CONFIG_CIFS_STATS */ return rc; } +static int validate_t2(struct smb_t2_rsp * pSMB) +{ + int rc = -EINVAL; + int total_size; + char * pBCC; + + /* check for plausible wct, bcc and t2 data and parm sizes */ + /* check for parm and data offset going beyond end of smb */ + if(pSMB->hdr.WordCount >= 10) { + if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) && + (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) { + /* check that bcc is at least as big as parms + data */ + /* check that bcc is less than negotiated smb buffer */ + total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount); + if(total_size < 512) { + total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount); + /* BCC le converted in SendReceive */ + pBCC = (pSMB->hdr.WordCount * 2) + sizeof(struct smb_hdr) + + (char *)pSMB; + if((total_size <= (*(u16 *)pBCC)) && + (total_size < + CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) { + return 0; + } + + } + } + } + cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB, + sizeof(struct smb_t2_rsp) + 16); + return rc; +} int CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) { @@ -183,6 +307,7 @@ int rc = 0; int bytes_returned; struct TCP_Server_Info * server; + u16 count; if(ses->server) server = ses->server; @@ -199,12 +324,12 @@ if (extended_security) pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; - pSMB->ByteCount = strlen(protocols[0].name) + 1; + count = strlen(protocols[0].name) + 1; strncpy(pSMB->DialectsArray, protocols[0].name, 30); /* null guaranteed to be at end of source and target buffers anyway */ - pSMB->hdr.smb_buf_length += pSMB->ByteCount; - pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + pSMB->hdr.smb_buf_length += count; + pSMB->ByteCount = cpu_to_le16(count); rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -216,7 +341,7 @@ /* probably no need to store and check maxvcs */ server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize), - (__u32) CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE); + (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); server->maxRw = le32_to_cpu(pSMBr->MaxRawSize); cFYI(0, ("Max buf = %d ", ses->server->maxBuf)); GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey); @@ -236,7 +361,7 @@ if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && (server->capabilities & CAP_EXTENDED_SECURITY)) { - __u16 count = le16_to_cpu(pSMBr->ByteCount); + count = pSMBr->ByteCount; if (count < 16) rc = -EIO; else if (count == 16) { @@ -264,6 +389,12 @@ SecurityBlob, count - 16, &server->secType); + if(rc == 1) { + /* BB Need to fill struct for sessetup here */ + rc = -EOPNOTSUPP; + } else { + rc = -EINVAL; + } } } else server->capabilities &= ~CAP_EXTENDED_SECURITY; @@ -287,7 +418,7 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon) { struct smb_hdr *smb_buffer; - struct smb_hdr *smb_buffer_response; + struct smb_hdr *smb_buffer_response; /* BB removeme BB */ int rc = 0; int length; @@ -317,24 +448,24 @@ return 0; } - if((tcon->ses == 0) || (tcon->ses->server == 0)) { + if((tcon->ses == NULL) || (tcon->ses->server == NULL)) { up(&tcon->tconSem); return -EIO; } - - rc = smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, - (void **) &smb_buffer, (void **) &smb_buffer_response); + rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, (void **)&smb_buffer); if (rc) { up(&tcon->tconSem); return rc; - } + } else { + smb_buffer_response = smb_buffer; /* BB removeme BB */ + } rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response, &length, 0); if (rc) cFYI(1, (" Tree disconnect failed %d", rc)); if (smb_buffer) - cifs_buf_release(smb_buffer); + cifs_small_buf_release(smb_buffer); up(&tcon->tconSem); /* No need to return error on this operation if tid invalidated and @@ -364,9 +495,8 @@ up(&ses->sesSem); return -EBUSY; } - - rc = smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL /* no tcon anymore */, - (void **) &pSMB, (void **) &smb_buffer_response); + rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB); + smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */ if(ses->server) { if(ses->server->secMode & @@ -394,7 +524,7 @@ } } if (pSMB) - cifs_buf_release(pSMB); + cifs_small_buf_release(pSMB); up(&ses->sesSem); /* if session dead then we do not need to do ulogoff, @@ -423,22 +553,21 @@ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->fileName, fileName, 530 + cifs_strtoUCS((wchar_t *) pSMB->fileName, fileName, PATH_MAX /* 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 = strnlen(fileName, PATH_MAX); name_len++; /* trailing null */ strncpy(pSMB->fileName, fileName, name_len); } pSMB->SearchAttributes = cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM); - pSMB->ByteCount = name_len + 1; pSMB->BufferFormat = 0x04; - pSMB->hdr.smb_buf_length += pSMB->ByteCount; - pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + pSMB->hdr.smb_buf_length += name_len + 1; + pSMB->ByteCount = cpu_to_le16(name_len + 1); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { @@ -476,21 +605,20 @@ return rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { - name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, dirName, 530 + name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, dirName, PATH_MAX /* 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(dirName, 530); + name_len = strnlen(dirName, PATH_MAX); name_len++; /* trailing null */ strncpy(pSMB->DirName, dirName, name_len); } - pSMB->ByteCount = name_len + 1; pSMB->BufferFormat = 0x04; - pSMB->hdr.smb_buf_length += pSMB->ByteCount; - pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + pSMB->hdr.smb_buf_length += name_len + 1; + pSMB->ByteCount = cpu_to_le16(name_len + 1); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { @@ -527,21 +655,20 @@ return rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { - name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, name, 530 + name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, name, PATH_MAX /* 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(name, 530); + name_len = strnlen(name, PATH_MAX); name_len++; /* trailing null */ strncpy(pSMB->DirName, name, name_len); } - pSMB->ByteCount = name_len + 1 /* for buf format */ ; pSMB->BufferFormat = 0x04; - pSMB->hdr.smb_buf_length += pSMB->ByteCount; - pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + pSMB->hdr.smb_buf_length += name_len + 1; + pSMB->ByteCount = cpu_to_le16(name_len + 1); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { @@ -571,6 +698,7 @@ OPEN_RSP *pSMBr = NULL; int bytes_returned; int name_len; + __u16 count; openRetry: rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB, @@ -581,18 +709,18 @@ pSMB->AndXCommand = 0xFF; /* none */ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { - pSMB->ByteCount = 1; /* account for one byte pad to word boundary */ + count = 1; /* account for one byte pad to word boundary */ name_len = cifs_strtoUCS((wchar_t *) (pSMB->fileName + 1), - fileName, 530 + fileName, PATH_MAX /* find define for this maxpathcomponent */ , nls_codepage); name_len++; /* trailing null */ name_len *= 2; pSMB->NameLength = cpu_to_le16(name_len); } else { /* BB improve the check for buffer overruns BB */ - pSMB->ByteCount = 0; /* no pad */ - name_len = strnlen(fileName, 530); + count = 0; /* no pad */ + name_len = strnlen(fileName, PATH_MAX); name_len++; /* trailing null */ pSMB->NameLength = cpu_to_le16(name_len); strncpy(pSMB->fileName, fileName, name_len); @@ -604,30 +732,29 @@ } pSMB->DesiredAccess = cpu_to_le32(access_flags); pSMB->AllocationSize = 0; - pSMB->FileAttributes = ATTR_NORMAL; + pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL); /* XP does not handle ATTR_POSIX_SEMANTICS */ /* but it helps speed up case sensitive checks for other servers such as Samba */ if (tcon->ses->capabilities & CAP_UNIX) - pSMB->FileAttributes |= ATTR_POSIX_SEMANTICS; + pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS); /* if ((omode & S_IWUGO) == 0) - pSMB->FileAttributes |= ATTR_READONLY;*/ + pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/ /* Above line causes problems due to vfs splitting create into two pieces - need to set mode after file created not while it is being created */ - pSMB->FileAttributes = cpu_to_le32(pSMB->FileAttributes); pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL); pSMB->CreateDisposition = cpu_to_le32(openDisposition); pSMB->CreateOptions = cpu_to_le32(create_options); pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION); /* BB ??*/ pSMB->SecurityFlags = - cpu_to_le32(SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY); + SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY; - pSMB->ByteCount += name_len; - pSMB->hdr.smb_buf_length += pSMB->ByteCount; + count += name_len; + pSMB->hdr.smb_buf_length += count; - pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + pSMB->ByteCount = cpu_to_le16(count); /* long_op set to 1 to allow for oplock break timeouts */ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 1); @@ -675,6 +802,8 @@ char *pReadData = NULL; int bytes_returned; + cFYI(1,("Reading %d bytes on fid %d",count,netfid)); + *nbytes = 0; rc = smb_init(SMB_COM_READ_ANDX, 12, tcon, (void **) &pSMB, (void **) &pSMBr); @@ -690,8 +819,8 @@ pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF); pSMB->OffsetHigh = cpu_to_le32(lseek >> 32); pSMB->Remaining = 0; - pSMB->MaxCount = cpu_to_le16(count); - pSMB->MaxCountHigh = 0; + pSMB->MaxCount = cpu_to_le16(count & 0xFFFF); + pSMB->MaxCountHigh = cpu_to_le32(count >> 16); pSMB->ByteCount = 0; /* no need to do le conversion since it is 0 */ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -699,24 +828,27 @@ if (rc) { cERROR(1, ("Send error in read = %d", rc)); } else { - pSMBr->DataLength = le16_to_cpu(pSMBr->DataLength); - *nbytes = pSMBr->DataLength; + int data_length = le16_to_cpu(pSMBr->DataLengthHigh); + data_length = data_length << 16; + data_length += le16_to_cpu(pSMBr->DataLength); + *nbytes = data_length; + /*check that DataLength would not go beyond end of SMB */ - if ((pSMBr->DataLength > CIFS_MAX_MSGSIZE) - || (pSMBr->DataLength > count)) { - cFYI(1,("bad length %d for count %d",pSMBr->DataLength,count)); + if ((data_length > CIFSMaxBufSize) + || (data_length > count)) { + cFYI(1,("bad length %d for count %d",data_length,count)); rc = -EIO; *nbytes = 0; } else { pReadData = (char *) (&pSMBr->hdr.Protocol) + le16_to_cpu(pSMBr->DataOffset); -/* if(rc = copy_to_user(buf, pReadData, pSMBr->DataLength)) { +/* if(rc = copy_to_user(buf, pReadData, data_length)) { cERROR(1,("Faulting on read rc = %d",rc)); rc = -EFAULT; }*/ /* can not use copy_to_user when using page cache*/ if(*buf) - memcpy(*buf,pReadData,pSMBr->DataLength); + memcpy(*buf,pReadData,data_length); } } if (pSMB) { @@ -735,13 +867,16 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, const int netfid, const unsigned int count, const __u64 offset, unsigned int *nbytes, const char *buf, - const int long_op) + const char __user * ubuf, const int long_op) { int rc = -EACCES; WRITE_REQ *pSMB = NULL; WRITE_RSP *pSMBr = NULL; int bytes_returned; + __u32 bytes_sent; + __u16 byte_count; + /* cFYI(1,("write at %lld %d bytes",offset,count));*/ rc = smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -754,39 +889,125 @@ pSMB->Fid = netfid; pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); pSMB->OffsetHigh = cpu_to_le32(offset >> 32); + pSMB->Reserved = 0xFFFFFFFF; + pSMB->WriteMode = 0; pSMB->Remaining = 0; - if (count > ((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00)) - pSMB->DataLengthLow = - (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00; - else - pSMB->DataLengthLow = count; - pSMB->DataLengthHigh = 0; + + /* Can increase buffer size if buffer is big enough in some cases - ie we + can send more if LARGE_WRITE_X capability returned by the server and if + our buffer is big enough or if we convert to iovecs on socket writes + and eliminate the copy to the CIFS buffer */ + if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) { + bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count); + } else { + bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) + & ~0xFF; + } + + if (bytes_sent > count) + bytes_sent = count; pSMB->DataOffset = cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4); + if(buf) + memcpy(pSMB->Data,buf,bytes_sent); + else if(ubuf) { + if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) { + if(pSMB) + cifs_buf_release(pSMB); + return -EFAULT; + } + } else { + /* No buffer */ + if(pSMB) + cifs_buf_release(pSMB); + return -EINVAL; + } - memcpy(pSMB->Data,buf,pSMB->DataLengthLow); - - pSMB->ByteCount += pSMB->DataLengthLow + 1 /* pad */ ; - pSMB->DataLengthLow = cpu_to_le16(pSMB->DataLengthLow); - pSMB->hdr.smb_buf_length += pSMB->ByteCount; - pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */ + pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF); + pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16); + pSMB->hdr.smb_buf_length += bytes_sent+1; + pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, long_op); if (rc) { cFYI(1, ("Send error in write = %d", rc)); *nbytes = 0; + } else { + *nbytes = le16_to_cpu(pSMBr->CountHigh); + *nbytes = (*nbytes) << 16; + *nbytes += le16_to_cpu(pSMBr->Count); + } + + if (pSMB) + cifs_buf_release(pSMB); + + /* Note: On -EAGAIN error only caller can retry on handle based calls + since file handle passed in no longer valid */ + + return rc; +} + +#ifdef CONFIG_CIFS_EXPERIMENTAL +int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, + const int netfid, const unsigned int count, + const __u64 offset, unsigned int *nbytes, const char __user *buf, + const int long_op) +{ + int rc = -EACCES; + WRITE_REQ *pSMB = NULL; + WRITE_RSP *pSMBr = NULL; + /*int bytes_returned;*/ + unsigned bytes_sent; + __u16 byte_count; + + rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB); + pSMBr = (WRITE_RSP *)pSMB; /* BB removeme BB */ + + if (rc) + return rc; + /* tcon and ses pointer are checked in smb_init */ + if (tcon->ses->server == NULL) + return -ECONNABORTED; + + pSMB->AndXCommand = 0xFF; /* none */ + pSMB->Fid = netfid; + pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); + pSMB->OffsetHigh = cpu_to_le32(offset >> 32); + pSMB->Reserved = 0xFFFFFFFF; + pSMB->WriteMode = 0; + pSMB->Remaining = 0; + bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & ~0xFF; + if (bytes_sent > count) + bytes_sent = count; + pSMB->DataLengthHigh = 0; + pSMB->DataOffset = + cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4); + + byte_count = bytes_sent + 1 /* pad */ ; + pSMB->DataLengthLow = cpu_to_le16(bytes_sent); + pSMB->DataLengthHigh = 0; + pSMB->hdr.smb_buf_length += byte_count; + pSMB->ByteCount = cpu_to_le16(byte_count); + +/* rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, buf, buflen, &bytes_returned, long_op); */ /* BB fixme BB */ + if (rc) { + cFYI(1, ("Send error in write2 (large write) = %d", rc)); + *nbytes = 0; } else *nbytes = le16_to_cpu(pSMBr->Count); if (pSMB) - cifs_buf_release(pSMB); + cifs_small_buf_release(pSMB); /* Note: On -EAGAIN error only caller can retry on handle based calls since file handle passed in no longer valid */ return rc; } +#endif /* CIFS_EXPERIMENTAL */ int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, @@ -812,7 +1033,7 @@ pSMB->Timeout = 0; } else if (waitFlag == TRUE) { timeout = 3; /* blocking operation, no timeout */ - pSMB->Timeout = -1; /* blocking - do not time out */ + pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */ } else { pSMB->Timeout = 0; } @@ -862,8 +1083,8 @@ cFYI(1, ("In CIFSSMBClose")); /* do not retry on dead session on close */ - rc = smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB, - (void **) &pSMBr); + rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB); + pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */ if(rc == -EAGAIN) return 0; if (rc) @@ -880,8 +1101,9 @@ cERROR(1, ("Send error in Close = %d", rc)); } } + if (pSMB) - cifs_buf_release(pSMB); + cifs_small_buf_release(pSMB); /* Since session is dead, file will be closed on server already */ if(rc == -EAGAIN) @@ -900,6 +1122,7 @@ RENAME_RSP *pSMBr = NULL; int bytes_returned; int name_len, name_len2; + __u16 count; cFYI(1, ("In CIFSSMBRename")); renameRetry: @@ -915,7 +1138,7 @@ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, 530 + cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, PATH_MAX /* find define for this maxpathcomponent */ , nls_codepage); name_len++; /* trailing null */ @@ -925,15 +1148,15 @@ pSMB->OldFileName[name_len + 1] = 0x00; name_len2 = cifs_strtoUCS((wchar_t *) & pSMB-> - OldFileName[name_len + 2], toName, 530, + OldFileName[name_len + 2], toName, PATH_MAX, nls_codepage); name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; name_len2 *= 2; /* convert to bytes */ } else { /* BB improve the check for buffer overruns BB */ - name_len = strnlen(fromName, 530); + name_len = strnlen(fromName, PATH_MAX); name_len++; /* trailing null */ strncpy(pSMB->OldFileName, fromName, name_len); - name_len2 = strnlen(toName, 530); + name_len2 = strnlen(toName, PATH_MAX); name_len2++; /* trailing null */ pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */ strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2); @@ -941,9 +1164,9 @@ name_len2++; /* signature byte */ } - pSMB->ByteCount = 1 /* 1st signature byte */ + name_len + name_len2; - pSMB->hdr.smb_buf_length += pSMB->ByteCount; - pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + count = 1 /* 1st signature byte */ + name_len + name_len2; + pSMB->hdr.smb_buf_length += count; + pSMB->ByteCount = cpu_to_le16(count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -977,6 +1200,7 @@ int rc = 0; int bytes_returned = 0; int len_of_str; + __u16 params, param_offset, offset, count, byte_count; cFYI(1, ("Rename to File by handle")); rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB, @@ -984,28 +1208,27 @@ if (rc) return rc; - pSMB->ParameterCount = 6; + params = 6; pSMB->MaxSetupCount = 0; pSMB->Reserved = 0; pSMB->Flags = 0; pSMB->Timeout = 0; pSMB->Reserved2 = 0; - pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_sfi_req, - Fid) - 4; - pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount; + param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; + offset = param_offset + params; - data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset; + data_offset = (char *) (&pSMB->hdr.Protocol) + offset; rename_info = (struct set_file_rename *) data_offset; pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */ pSMB->SetupCount = 1; pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); - pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount; - pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); + byte_count = 3 /* pad */ + params; + pSMB->ParameterCount = cpu_to_le16(params); pSMB->TotalParameterCount = pSMB->ParameterCount; - pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset); - pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); + pSMB->ParameterOffset = cpu_to_le16(param_offset); + pSMB->DataOffset = cpu_to_le16(offset); /* construct random name ".cifs_tmp" */ rename_info->overwrite = cpu_to_le32(1); rename_info->root_fid = 0; @@ -1014,19 +1237,19 @@ sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid); len_of_str = cifs_strtoUCS((wchar_t *) rename_info->target_name, dummy_string, 24, nls_codepage); } else { - len_of_str = cifs_strtoUCS((wchar_t *) rename_info->target_name, target_name, 530, nls_codepage); + len_of_str = cifs_strtoUCS((wchar_t *) rename_info->target_name, target_name, PATH_MAX, nls_codepage); } rename_info->target_name_len = cpu_to_le32(2 * len_of_str); - pSMB->DataCount = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2; - pSMB->ByteCount += pSMB->DataCount; - pSMB->DataCount = cpu_to_le16(pSMB->DataCount); + count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2; + byte_count += count; + pSMB->DataCount = cpu_to_le16(count); pSMB->TotalDataCount = pSMB->DataCount; pSMB->Fid = netfid; pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += pSMB->ByteCount; - pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + pSMB->hdr.smb_buf_length += byte_count; + pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { @@ -1056,6 +1279,7 @@ COPY_RSP *pSMBr = NULL; int bytes_returned; int name_len, name_len2; + __u16 count; cFYI(1, ("In CIFSSMBCopy")); copyRetry: @@ -1067,14 +1291,12 @@ pSMB->BufferFormat = 0x04; pSMB->Tid2 = target_tid; - if(flags & COPY_TREE) - pSMB->Flags |= COPY_TREE; - pSMB->Flags = cpu_to_le16(pSMB->Flags); + pSMB->Flags = cpu_to_le16(flags & COPY_TREE); if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, - 530 /* find define for this maxpathcomponent */, + PATH_MAX /* find define for this maxpathcomponent */, nls_codepage); name_len++; /* trailing null */ name_len *= 2; @@ -1082,15 +1304,15 @@ /* protocol requires ASCII signature byte on Unicode string */ pSMB->OldFileName[name_len + 1] = 0x00; name_len2 = cifs_strtoUCS((wchar_t *) & pSMB-> - OldFileName[name_len + 2], toName, 530, + OldFileName[name_len + 2], toName, PATH_MAX, nls_codepage); name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; name_len2 *= 2; /* convert to bytes */ } else { /* BB improve the check for buffer overruns BB */ - name_len = strnlen(fromName, 530); + name_len = strnlen(fromName, PATH_MAX); name_len++; /* trailing null */ strncpy(pSMB->OldFileName, fromName, name_len); - name_len2 = strnlen(toName, 530); + name_len2 = strnlen(toName, PATH_MAX); name_len2++; /* trailing null */ pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */ strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2); @@ -1098,15 +1320,15 @@ name_len2++; /* signature byte */ } - pSMB->ByteCount = 1 /* 1st signature byte */ + name_len + name_len2; - pSMB->hdr.smb_buf_length += pSMB->ByteCount; - pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + count = 1 /* 1st signature byte */ + name_len + name_len2; + pSMB->hdr.smb_buf_length += count; + pSMB->ByteCount = cpu_to_le16(count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { cFYI(1, ("Send error in copy = %d with %d files copied", - rc, pSMBr->CopyCount)); + rc, le16_to_cpu(pSMBr->CopyCount))); } if (pSMB) cifs_buf_release(pSMB); @@ -1129,6 +1351,7 @@ int name_len_target; int rc = 0; int bytes_returned = 0; + __u16 params, param_offset, offset, byte_count; cFYI(1, ("In Symlink Unix style")); createSymLinkRetry: @@ -1139,59 +1362,58 @@ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, fromName, 530 + cifs_strtoUCS((wchar_t *) pSMB->FileName, fromName, PATH_MAX /* 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(fromName, 530); + name_len = strnlen(fromName, PATH_MAX); name_len++; /* trailing null */ strncpy(pSMB->FileName, fromName, name_len); } - pSMB->ParameterCount = 6 + name_len; + params = 6 + name_len; pSMB->MaxSetupCount = 0; pSMB->Reserved = 0; pSMB->Flags = 0; pSMB->Timeout = 0; pSMB->Reserved2 = 0; - pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req, + param_offset = offsetof(struct smb_com_transaction2_spi_req, InformationLevel) - 4; - pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount; + offset = param_offset + params; - data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset; + data_offset = (char *) (&pSMB->hdr.Protocol) + offset; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len_target = - cifs_strtoUCS((wchar_t *) data_offset, toName, 530 + cifs_strtoUCS((wchar_t *) data_offset, toName, PATH_MAX /* find define for this maxpathcomponent */ , nls_codepage); name_len_target++; /* trailing null */ name_len_target *= 2; } else { /* BB improve the check for buffer overruns BB */ - name_len_target = strnlen(toName, 530); + name_len_target = strnlen(toName, PATH_MAX); name_len_target++; /* trailing null */ strncpy(data_offset, toName, name_len_target); } - pSMB->DataCount = name_len_target; pSMB->MaxParameterCount = cpu_to_le16(2); /* BB find exact max on data count below from sess */ pSMB->MaxDataCount = cpu_to_le16(1000); 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); + byte_count = 3 /* pad */ + params + name_len_target; + pSMB->DataCount = cpu_to_le16(name_len_target); + pSMB->ParameterCount = cpu_to_le16(params); pSMB->TotalDataCount = pSMB->DataCount; pSMB->TotalParameterCount = pSMB->ParameterCount; - pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset); - pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); + pSMB->ParameterOffset = cpu_to_le16(param_offset); + pSMB->DataOffset = cpu_to_le16(offset); pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += pSMB->ByteCount; - pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + pSMB->hdr.smb_buf_length += byte_count; + pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { @@ -1221,6 +1443,7 @@ int name_len_target; int rc = 0; int bytes_returned = 0; + __u16 params, param_offset, offset, byte_count; cFYI(1, ("In Create Hard link Unix style")); createHardLinkRetry: @@ -1230,59 +1453,58 @@ return rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { - name_len = cifs_strtoUCS((wchar_t *) pSMB->FileName, toName, 530 + name_len = cifs_strtoUCS((wchar_t *) pSMB->FileName, toName, PATH_MAX /* 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(toName, 530); + name_len = strnlen(toName, PATH_MAX); name_len++; /* trailing null */ strncpy(pSMB->FileName, toName, name_len); } - pSMB->ParameterCount = 6 + name_len; + params = 6 + name_len; pSMB->MaxSetupCount = 0; pSMB->Reserved = 0; pSMB->Flags = 0; pSMB->Timeout = 0; pSMB->Reserved2 = 0; - pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req, + param_offset = offsetof(struct smb_com_transaction2_spi_req, InformationLevel) - 4; - pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount; + offset = param_offset + params; - data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset; + data_offset = (char *) (&pSMB->hdr.Protocol) + offset; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len_target = - cifs_strtoUCS((wchar_t *) data_offset, fromName, 530 + cifs_strtoUCS((wchar_t *) data_offset, fromName, PATH_MAX /* find define for this maxpathcomponent */ , nls_codepage); name_len_target++; /* trailing null */ name_len_target *= 2; } else { /* BB improve the check for buffer overruns BB */ - name_len_target = strnlen(fromName, 530); + name_len_target = strnlen(fromName, PATH_MAX); name_len_target++; /* trailing null */ strncpy(data_offset, fromName, name_len_target); } - pSMB->DataCount = name_len_target; pSMB->MaxParameterCount = cpu_to_le16(2); /* BB find exact max on data count below from sess*/ pSMB->MaxDataCount = cpu_to_le16(1000); pSMB->SetupCount = 1; pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); - pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount; - pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); + byte_count = 3 /* pad */ + params + name_len_target; + pSMB->ParameterCount = cpu_to_le16(params); pSMB->TotalParameterCount = pSMB->ParameterCount; - pSMB->DataCount = cpu_to_le16(pSMB->DataCount); + pSMB->DataCount = cpu_to_le16(name_len_target); pSMB->TotalDataCount = pSMB->DataCount; - pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset); - pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); + pSMB->ParameterOffset = cpu_to_le16(param_offset); + pSMB->DataOffset = cpu_to_le16(offset); pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += pSMB->ByteCount; - pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + pSMB->hdr.smb_buf_length += byte_count; + pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { @@ -1307,6 +1529,7 @@ RENAME_RSP *pSMBr = NULL; int bytes_returned; int name_len, name_len2; + __u16 count; cFYI(1, ("In CIFSCreateHardLink")); winCreateHardLinkRetry: @@ -1326,7 +1549,7 @@ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, 530 + cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, PATH_MAX /* find define for this maxpathcomponent */ , nls_codepage); name_len++; /* trailing null */ @@ -1335,15 +1558,15 @@ pSMB->OldFileName[name_len + 1] = 0x04; name_len2 = cifs_strtoUCS((wchar_t *) & pSMB-> - OldFileName[name_len + 2], toName, 530, + OldFileName[name_len + 2], toName, PATH_MAX, nls_codepage); name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; name_len2 *= 2; /* convert to bytes */ } else { /* BB improve the check for buffer overruns BB */ - name_len = strnlen(fromName, 530); + name_len = strnlen(fromName, PATH_MAX); name_len++; /* trailing null */ strncpy(pSMB->OldFileName, fromName, name_len); - name_len2 = strnlen(toName, 530); + name_len2 = strnlen(toName, PATH_MAX); name_len2++; /* trailing null */ pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */ strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2); @@ -1351,9 +1574,9 @@ name_len2++; /* signature byte */ } - pSMB->ByteCount = 1 /* string type byte */ + name_len + name_len2; - pSMB->hdr.smb_buf_length += pSMB->ByteCount; - pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + count = 1 /* string type byte */ + name_len + name_len2; + pSMB->hdr.smb_buf_length += count; + pSMB->ByteCount = cpu_to_le16(count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -1380,6 +1603,7 @@ int rc = 0; int bytes_returned; int name_len; + __u16 params, byte_count; cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName)); @@ -1391,19 +1615,18 @@ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530 + cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX /* 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 = strnlen(searchName, PATH_MAX); name_len++; /* trailing null */ strncpy(pSMB->FileName, searchName, name_len); } - pSMB->TotalParameterCount = - 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ; + params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ; pSMB->TotalDataCount = 0; pSMB->MaxParameterCount = cpu_to_le16(2); /* BB find exact max data count below from sess structure BB */ @@ -1420,38 +1643,42 @@ 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); + byte_count = params + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(params); pSMB->ParameterCount = pSMB->TotalParameterCount; pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += pSMB->ByteCount; - pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + pSMB->hdr.smb_buf_length += byte_count; + pSMB->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, ("Send error in QuerySymLinkInfo = %d", rc)); - } else { /* decode response */ - pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); - pSMBr->DataCount = le16_to_cpu(pSMBr->DataCount); - if ((pSMBr->ByteCount < 2) || (pSMBr->DataOffset > 512)) + } else { + /* decode response */ + + rc = validate_t2((struct smb_t2_rsp *)pSMBr); + if (rc || (pSMBr->ByteCount < 2)) /* BB also check enough total bytes returned */ rc = -EIO; /* bad smb */ else { + __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); + __u16 count = le16_to_cpu(pSMBr->t2.DataCount); + if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = UniStrnlen((wchar_t *) ((char *) - &pSMBr->hdr.Protocol +pSMBr->DataOffset), - min_t(const int, buflen,pSMBr->DataCount) / 2); + &pSMBr->hdr.Protocol +data_offset), + min_t(const int, buflen,count) / 2); cifs_strfromUCS_le(symlinkinfo, (wchar_t *) ((char *)&pSMBr->hdr.Protocol + - pSMBr->DataOffset), + data_offset), name_len, nls_codepage); } else { strncpy(symlinkinfo, (char *) &pSMBr->hdr.Protocol + - pSMBr->DataOffset, - min_t(const int, buflen, pSMBr->DataCount)); + data_offset, + min_t(const int, buflen, count)); } symlinkinfo[buflen] = 0; /* just in case so calling code does not go off the end of buffer */ @@ -1550,6 +1777,304 @@ return rc; } +#ifdef CONFIG_CIFS_POSIX + +/*Convert an Access Control Entry from wire format to local POSIX xattr format*/ +static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace) +{ + /* u8 cifs fields do not need le conversion */ + ace->e_perm = (__u16)cifs_ace->cifs_e_perm; + ace->e_tag = (__u16)cifs_ace->cifs_e_tag; + ace->e_id = (__u32)le64_to_cpu(cifs_ace->cifs_uid); + /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */ + + return; +} + +/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */ +static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,const int acl_type,const int size_of_data_area) +{ + int size = 0; + int i; + __u16 count; + struct cifs_posix_ace * pACE; + struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src; + posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt; + + if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION) + return -EOPNOTSUPP; + + if(acl_type & ACL_TYPE_ACCESS) { + count = le16_to_cpu(cifs_acl->access_entry_count); + pACE = &cifs_acl->ace_array[0]; + size = sizeof(struct cifs_posix_acl); + size += sizeof(struct cifs_posix_ace) * count; + /* check if we would go beyond end of SMB */ + if(size_of_data_area < size) { + cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size)); + return -EINVAL; + } + } else if(acl_type & ACL_TYPE_DEFAULT) { + count = le16_to_cpu(cifs_acl->access_entry_count); + size = sizeof(struct cifs_posix_acl); + size += sizeof(struct cifs_posix_ace) * count; +/* skip past access ACEs to get to default ACEs */ + pACE = &cifs_acl->ace_array[count]; + count = le16_to_cpu(cifs_acl->default_entry_count); + size += sizeof(struct cifs_posix_ace) * count; + /* check if we would go beyond end of SMB */ + if(size_of_data_area < size) + return -EINVAL; + } else { + /* illegal type */ + return -EINVAL; + } + + size = posix_acl_xattr_size(count); + if((buflen == 0) || (local_acl == NULL)) { + /* used to query ACL EA size */ + } else if(size > buflen) { + return -ERANGE; + } else /* buffer big enough */ { + local_acl->a_version = POSIX_ACL_XATTR_VERSION; + for(i = 0;i < count ;i++) { + cifs_convert_ace(&local_acl->a_entries[i],pACE); + pACE ++; + } + } + return size; +} + +__u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace, + const posix_acl_xattr_entry * local_ace) +{ + __u16 rc = 0; /* 0 = ACL converted ok */ + + cifs_ace->cifs_e_perm = (__u8)cpu_to_le16(local_ace->e_perm); + cifs_ace->cifs_e_tag = (__u8)cpu_to_le16(local_ace->e_tag); + /* BB is there a better way to handle the large uid? */ + if(local_ace->e_id == -1) { + /* Probably no need to le convert -1 on any arch but can not hurt */ + cifs_ace->cifs_uid = cpu_to_le64(-1); + } else + cifs_ace->cifs_uid = (__u64)cpu_to_le32(local_ace->e_id); + /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/ + return rc; +} + +/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */ +__u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen, + const int acl_type) +{ + __u16 rc = 0; + struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data; + posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL; + int count; + int i; + + if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL)) + return 0; + + count = posix_acl_xattr_count((size_t)buflen); + cFYI(1,("setting acl with %d entries from buf of length %d and version of %d", + count,buflen,local_acl->a_version)); + if(local_acl->a_version != 2) { + cFYI(1,("unknown POSIX ACL version %d",local_acl->a_version)); + return 0; + } + cifs_acl->version = cpu_to_le16(1); + if(acl_type == ACL_TYPE_ACCESS) + cifs_acl->access_entry_count = count; + else if(acl_type == ACL_TYPE_DEFAULT) + cifs_acl->default_entry_count = count; + else { + cFYI(1,("unknown ACL type %d",acl_type)); + return 0; + } + for(i=0;iace_array[i], + &local_acl->a_entries[i]); + if(rc != 0) { + /* ACE not converted */ + break; + } + } + if(rc == 0) { + rc = (__u16)(count * sizeof(struct cifs_posix_ace)); + rc += sizeof(struct cifs_posix_acl); + /* BB add check to make sure ACL does not overflow SMB */ + } + return rc; +} + +int +CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon, + const unsigned char *searchName, + char *acl_inf, const int buflen, const int acl_type, + const struct nls_table *nls_codepage) +{ +/* SMB_QUERY_POSIX_ACL */ + TRANSACTION2_QPI_REQ *pSMB = NULL; + TRANSACTION2_QPI_RSP *pSMBr = NULL; + int rc = 0; + int bytes_returned; + int name_len; + __u16 params, byte_count; + + cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName)); + +queryAclRetry: + 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, PATH_MAX + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + pSMB->FileName[name_len] = 0; + pSMB->FileName[name_len+1] = 0; + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(searchName, PATH_MAX); + name_len++; /* trailing null */ + strncpy(pSMB->FileName, searchName, name_len); + } + + params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ; + pSMB->TotalDataCount = 0; + pSMB->MaxParameterCount = cpu_to_le16(2); + /* BB find exact max data count below from sess structure BB */ + pSMB->MaxDataCount = cpu_to_le16(4000); + 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); + byte_count = params + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(params); + pSMB->ParameterCount = pSMB->TotalParameterCount; + pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL); + pSMB->Reserved4 = 0; + pSMB->hdr.smb_buf_length += byte_count; + pSMB->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, ("Send error in Query POSIX ACL = %d", rc)); + } else { + /* decode response */ + + rc = validate_t2((struct smb_t2_rsp *)pSMBr); + if (rc || (pSMBr->ByteCount < 2)) + /* BB also check enough total bytes returned */ + rc = -EIO; /* bad smb */ + else { + __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); + __u16 count = le16_to_cpu(pSMBr->t2.DataCount); + rc = cifs_copy_posix_acl(acl_inf, + (char *)&pSMBr->hdr.Protocol+data_offset, + buflen,acl_type,count); + } + } + if (pSMB) + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto queryAclRetry; + return rc; +} + +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) +{ + struct smb_com_transaction2_spi_req *pSMB = NULL; + struct smb_com_transaction2_spi_rsp *pSMBr = NULL; + char *parm_data; + int name_len; + int rc = 0; + int bytes_returned = 0; + __u16 params, byte_count, data_count, param_offset, offset; + + cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName)); +setAclRetry: + 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, PATH_MAX + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(fileName, PATH_MAX); + name_len++; /* trailing null */ + strncpy(pSMB->FileName, fileName, name_len); + } + params = 6 + name_len; + 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; + param_offset = offsetof(struct smb_com_transaction2_spi_req, + InformationLevel) - 4; + offset = param_offset + params; + parm_data = ((char *) &pSMB->hdr.Protocol) + offset; + pSMB->ParameterOffset = cpu_to_le16(param_offset); + + /* convert to on the wire format for POSIX ACL */ + data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type); + + if(data_count == 0) { + rc = -EOPNOTSUPP; + goto setACLerrorExit; + } + pSMB->DataOffset = cpu_to_le16(offset); + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); + pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL); + byte_count = 3 /* pad */ + params + data_count; + pSMB->DataCount = cpu_to_le16(data_count); + pSMB->TotalDataCount = pSMB->DataCount; + pSMB->ParameterCount = cpu_to_le16(params); + pSMB->TotalParameterCount = pSMB->ParameterCount; + pSMB->Reserved4 = 0; + pSMB->hdr.smb_buf_length += byte_count; + pSMB->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, ("Set POSIX ACL returned %d", rc)); + } + +setACLerrorExit: + if (pSMB) + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto setAclRetry; + return rc; +} + +#endif + int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, @@ -1562,8 +2087,9 @@ int rc = 0; int bytes_returned; int name_len; + __u16 params, byte_count; - cFYI(1, ("In QPathInfo path %s", searchName)); +/* cFYI(1, ("In QPathInfo path %s", searchName)); */ QPathInfoRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); @@ -1572,19 +2098,18 @@ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530 + cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX /* 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 = strnlen(searchName, PATH_MAX); name_len++; /* trailing null */ strncpy(pSMB->FileName, searchName, name_len); } - pSMB->TotalParameterCount = 2 /* level */ + 4 /* reserved */ + - name_len /* includes null */ ; + params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ; 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 */ @@ -1600,29 +2125,28 @@ 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); + byte_count = params + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(params); pSMB->ParameterCount = pSMB->TotalParameterCount; pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += pSMB->ByteCount; - pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + pSMB->hdr.smb_buf_length += byte_count; + pSMB->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, ("Send error in QPathInfo = %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 < 40) || (pSMBr->DataOffset > 512)) + rc = validate_t2((struct smb_t2_rsp *)pSMBr); + + if (rc || (pSMBr->ByteCount < 40)) rc = -EIO; /* bad smb */ else if (pFindData){ + __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); memcpy((char *) pFindData, (char *) &pSMBr->hdr.Protocol + - pSMBr->DataOffset, sizeof (FILE_ALL_INFO)); + data_offset, sizeof (FILE_ALL_INFO)); } else rc = -ENOMEM; } @@ -1646,6 +2170,7 @@ int rc = 0; int bytes_returned = 0; int name_len; + __u16 params, byte_count; cFYI(1, ("In QPathInfo (Unix) the path %s", searchName)); UnixQPathInfoRetry: @@ -1656,19 +2181,18 @@ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530 + cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX /* 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 = strnlen(searchName, PATH_MAX); name_len++; /* trailing null */ strncpy(pSMB->FileName, searchName, name_len); } - pSMB->TotalParameterCount = 2 /* level */ + 4 /* reserved */ + - name_len /* includes null */ ; + params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ; pSMB->TotalDataCount = 0; pSMB->MaxParameterCount = cpu_to_le16(2); /* BB find exact max SMB PDU from sess structure BB */ @@ -1685,31 +2209,28 @@ 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); + byte_count = params + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(params); pSMB->ParameterCount = pSMB->TotalParameterCount; pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += pSMB->ByteCount; - pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + pSMB->hdr.smb_buf_length += byte_count; + pSMB->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, ("Send error in QPathInfo = %d", rc)); } else { /* decode response */ - pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); - /* BB also check if enough total bytes returned */ - if ((pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO)) || - (pSMBr->DataOffset > 512) || - (pSMBr->DataOffset < sizeof(struct smb_hdr))) { - cFYI(1,("UnixQPathinfo invalid data offset %d bytes returned %d", - (int)pSMBr->DataOffset,bytes_returned)); + rc = validate_t2((struct smb_t2_rsp *)pSMBr); + + if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) { rc = -EIO; /* bad smb */ } else { + __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); memcpy((char *) pFindData, (char *) &pSMBr->hdr.Protocol + - pSMBr->DataOffset, + data_offset, sizeof (FILE_UNIX_BASIC_INFO)); } } @@ -1721,6 +2242,7 @@ return rc; } +#ifdef CONFIG_CIFS_EXPERIMENTAL /* function unused at present */ int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon, const char *searchName, FILE_ALL_INFO * findData, @@ -1732,6 +2254,7 @@ int rc = 0; int bytes_returned; int name_len; + __u16 params, byte_count; cFYI(1, ("In FindUnique")); findUniqueRetry: @@ -1742,18 +2265,18 @@ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530 + cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX /* 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 = strnlen(searchName, PATH_MAX); name_len++; /* trailing null */ strncpy(pSMB->FileName, searchName, name_len); } - pSMB->TotalParameterCount = 12 + name_len /* includes null */ ; + params = 12 + name_len /* includes null */ ; pSMB->TotalDataCount = 0; /* no EAs */ pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ @@ -1763,14 +2286,14 @@ pSMB->Timeout = 0; pSMB->Reserved2 = 0; pSMB->ParameterOffset = cpu_to_le16( - offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4); + offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4); pSMB->DataCount = 0; pSMB->DataOffset = 0; pSMB->SetupCount = 1; /* one byte, no need to le convert */ pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST); - pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; - pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalDataCount); + byte_count = params + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(params); pSMB->ParameterCount = pSMB->TotalParameterCount; pSMB->SearchAttributes = cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | @@ -1779,8 +2302,8 @@ pSMB->SearchFlags = cpu_to_le16(1); pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO); pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */ - pSMB->hdr.smb_buf_length += pSMB->ByteCount; - pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + pSMB->hdr.smb_buf_length += byte_count; + pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -1798,6 +2321,7 @@ return rc; } +#endif /* CIFS_EXPERIMENTAL */ int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, @@ -1813,6 +2337,7 @@ int rc = 0; int bytes_returned; int name_len; + __u16 params, byte_count; cFYI(1, ("In FindFirst")); findFirstRetry: @@ -1823,18 +2348,18 @@ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530 + cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX /* 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 = strnlen(searchName, PATH_MAX); name_len++; /* trailing null */ strncpy(pSMB->FileName, searchName, name_len); } - pSMB->TotalParameterCount = 12 + name_len /* includes null */ ; + params = 12 + name_len /* includes null */ ; pSMB->TotalDataCount = 0; /* no EAs */ pSMB->MaxParameterCount = cpu_to_le16(10); pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf - @@ -1844,11 +2369,11 @@ pSMB->Flags = 0; pSMB->Timeout = 0; pSMB->Reserved2 = 0; - pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; - pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount); + byte_count = params + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(params); pSMB->ParameterCount = pSMB->TotalParameterCount; - pSMB->ParameterOffset = cpu_to_le16(offsetof(struct - smb_com_transaction2_ffirst_req, SearchAttributes) - 4); + pSMB->ParameterOffset = cpu_to_le16( + offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4); pSMB->DataCount = 0; pSMB->DataOffset = 0; pSMB->SetupCount = 1; /* one byte no need to make endian neutral */ @@ -1857,7 +2382,7 @@ pSMB->SearchAttributes = cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY); - pSMB->SearchCount = cpu_to_le16(CIFS_MAX_MSGSIZE / sizeof (FILE_DIRECTORY_INFO)); /* should this be shrunk even more ? */ + pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_DIRECTORY_INFO)); /* should this be shrunk even more ? */ pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME); /* test for Unix extensions */ @@ -1870,33 +2395,33 @@ *pUnixFlag = FALSE; } pSMB->SearchStorageType = 0; /* BB what should we set this to? It is not clear if it matters BB */ - pSMB->hdr.smb_buf_length += pSMB->ByteCount; - pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + pSMB->hdr.smb_buf_length += byte_count; + pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { /* BB add logic to retry regular search if Unix search rejected unexpectedly by server */ cFYI(1, ("Error in FindFirst = %d", rc)); - } else { /* decode response */ + } else { + rc = validate_t2((struct smb_t2_rsp *)pSMBr); + if(!rc) { + /* decode response */ /* BB add safety checks for these memcpys */ - if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) - *pUnicodeFlag = TRUE; - else - *pUnicodeFlag = FALSE; - memcpy(findParms, - (char *) &pSMBr->hdr.Protocol + - le16_to_cpu(pSMBr->ParameterOffset), - sizeof (T2_FFIRST_RSP_PARMS)); - /* search handle can stay LE and EAoffset not needed so not converted */ - findParms->EndofSearch = le16_to_cpu(findParms->EndofSearch); - findParms->LastNameOffset = - le16_to_cpu(findParms->LastNameOffset); - findParms->SearchCount = le16_to_cpu(findParms->SearchCount); - response_data = - (char *) &pSMBr->hdr.Protocol + - le16_to_cpu(pSMBr->DataOffset); - memcpy(findData, response_data, le16_to_cpu(pSMBr->DataCount)); + if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) + *pUnicodeFlag = TRUE; + else + *pUnicodeFlag = FALSE; + memcpy(findParms, + (char *) &pSMBr->hdr.Protocol + + le16_to_cpu(pSMBr->t2.ParameterOffset), + sizeof (T2_FFIRST_RSP_PARMS)); + response_data = + (char *) &pSMBr->hdr.Protocol + + le16_to_cpu(pSMBr->t2.DataOffset); + memcpy(findData, response_data, + le16_to_cpu(pSMBr->t2.DataCount)); + } } if (pSMB) cifs_buf_release(pSMB); @@ -1907,6 +2432,256 @@ return rc; } +/* xid, tcon, searchName and codepage are input parms, rest are returned */ +int +CIFSFindFirst2(const int xid, struct cifsTconInfo *tcon, + const char *searchName, + const struct nls_table *nls_codepage, + __u16 * pnetfid, + struct cifs_search_info * psrch_inf) +{ +/* level 257 SMB_ */ + TRANSACTION2_FFIRST_REQ *pSMB = NULL; + TRANSACTION2_FFIRST_RSP *pSMBr = NULL; + T2_FFIRST_RSP_PARMS * parms; + int rc = 0; + int bytes_returned = 0; + int name_len; + __u16 params, byte_count; + + cFYI(1, ("In FindFirst2")); + +findFirst2Retry: + 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, + PATH_MAX, nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + pSMB->FileName[name_len] = 0; /* null terminate just in case */ + pSMB->FileName[name_len+1] = 0; + } else { /* BB add check for overrun of SMB buf BB */ + name_len = strnlen(searchName, PATH_MAX); + name_len++; /* trailing null */ +/* BB fix here and in unicode clause above ie + if(name_len > buffersize-header) + free buffer exit; BB */ + strncpy(pSMB->FileName, searchName, name_len); + pSMB->FileName[name_len] = 0; /* just in case */ + } + + params = 12 + name_len /* includes null */ ; + pSMB->TotalDataCount = 0; /* no EAs */ + pSMB->MaxParameterCount = cpu_to_le16(10); + pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf - + MAX_CIFS_HDR_SIZE) & 0xFFFFFF00); + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + byte_count = params + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(params); + pSMB->ParameterCount = pSMB->TotalParameterCount; + pSMB->ParameterOffset = cpu_to_le16( + offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4); + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */ + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST); + pSMB->SearchAttributes = + cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | + ATTR_DIRECTORY); + pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO)); + pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | + CIFS_SEARCH_RETURN_RESUME); + pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level); + + /* BB what should we set StorageType to? Does it matter? BB */ + pSMB->SearchStorageType = 0; + pSMB->hdr.smb_buf_length += byte_count; + pSMB->ByteCount = cpu_to_le16(byte_count); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + + if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */ + /* BB Add code to handle unsupported level rc */ + cFYI(1, ("Error in FindFirst = %d", rc)); + + if (pSMB) + cifs_buf_release(pSMB); + + /* BB eventually could optimize out free and realloc of buf */ + /* for this case */ + if (rc == -EAGAIN) + goto findFirst2Retry; + } else { /* decode response */ + /* BB remember to free buffer if error BB */ + rc = validate_t2((struct smb_t2_rsp *)pSMBr); + if(rc == 0) { + if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) + psrch_inf->unicode = TRUE; + else + psrch_inf->unicode = FALSE; + + psrch_inf->ntwrk_buf_start = (char *)pSMBr; + psrch_inf->srch_entries_start = + (char *) &pSMBr->hdr.Protocol + + le16_to_cpu(pSMBr->t2.DataOffset); + + parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol + + le16_to_cpu(pSMBr->t2.ParameterOffset)); + + if(parms->EndofSearch) + psrch_inf->endOfSearch = TRUE; + else + psrch_inf->endOfSearch = FALSE; + + psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount); + psrch_inf->index_of_last_entry = + psrch_inf->entries_in_buffer; +/*cFYI(1,("entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */ + *pnetfid = parms->SearchHandle; + } else { + if(pSMB) + cifs_buf_release(pSMB); + } + } + + return rc; +} + +int CIFSFindNext2(const int xid, struct cifsTconInfo *tcon, + __u16 searchHandle, struct cifs_search_info * psrch_inf) +{ + TRANSACTION2_FNEXT_REQ *pSMB = NULL; + TRANSACTION2_FNEXT_RSP *pSMBr = NULL; + T2_FNEXT_RSP_PARMS * parms; + char *response_data; + int rc = 0; + int bytes_returned, name_len; + __u16 params, byte_count; + + cFYI(1, ("In FindNext2")); + + if(psrch_inf->endOfSearch == TRUE) + return -ENOENT; + + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + params = 14; /* includes 2 bytes of null string, converted to LE below */ + byte_count = 0; + pSMB->TotalDataCount = 0; /* no EAs */ + pSMB->MaxParameterCount = cpu_to_le16(8); + pSMB->MaxDataCount = + cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00); + 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_fnext_req,SearchHandle) - 4); + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT); + pSMB->SearchHandle = searchHandle; /* always kept as le */ + pSMB->SearchCount = + cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO)); + /* test for Unix extensions */ +/* if (tcon->ses->capabilities & CAP_UNIX) { + pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX); + psrch_inf->info_level = SMB_FIND_FILE_UNIX; + } else { + pSMB->InformationLevel = + cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO); + psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO; + } */ + pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level); + pSMB->ResumeKey = psrch_inf->resume_key; + pSMB->SearchFlags = + cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME); + + name_len = psrch_inf->resume_name_len; + params += name_len; + if(name_len < PATH_MAX) { + memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len); + byte_count += name_len; + } else { + rc = -EINVAL; + goto FNext2_err_exit; + } + byte_count = params + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(params); + pSMB->ParameterCount = pSMB->TotalParameterCount; + pSMB->hdr.smb_buf_length += byte_count; + pSMB->ByteCount = cpu_to_le16(byte_count); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + + if (rc) { + if (rc == -EBADF) { + psrch_inf->endOfSearch = TRUE; + rc = 0; /* search probably was closed at end of search above */ + } else + cFYI(1, ("FindNext returned = %d", rc)); + } else { /* decode response */ + rc = validate_t2((struct smb_t2_rsp *)pSMBr); + + if(rc == 0) { + /* BB fixme add lock for file (srch_info) struct here */ + if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) + psrch_inf->unicode = TRUE; + else + psrch_inf->unicode = FALSE; + response_data = (char *) &pSMBr->hdr.Protocol + + le16_to_cpu(pSMBr->t2.ParameterOffset); + parms = (T2_FNEXT_RSP_PARMS *)response_data; + response_data = (char *)&pSMBr->hdr.Protocol + + le16_to_cpu(pSMBr->t2.DataOffset); + cifs_buf_release(psrch_inf->ntwrk_buf_start); + psrch_inf->srch_entries_start = response_data; + psrch_inf->ntwrk_buf_start = (char *)pSMB; + if(parms->EndofSearch) + psrch_inf->endOfSearch = TRUE; + else + psrch_inf->endOfSearch = FALSE; + + psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount); + psrch_inf->index_of_last_entry += + psrch_inf->entries_in_buffer; +/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */ + + /* BB fixme add unlock here */ + } + + } + + /* BB On error, should we leave previous search buf (and count and + last entry fields) intact or free the previous one? */ + + /* Note: On -EAGAIN error only caller can retry on handle based calls + since file handle passed in no longer valid */ +FNext2_err_exit: + if ((rc != 0) && pSMB) + cifs_buf_release(pSMB); + + return rc; +} + int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, FILE_DIRECTORY_INFO * findData, T2_FNEXT_RSP_PARMS * findParms, @@ -1919,6 +2694,7 @@ char *response_data; int rc = 0; int bytes_returned; + __u16 params, byte_count; cFYI(1, ("In FindNext")); @@ -1930,7 +2706,8 @@ if (rc) return rc; - pSMB->TotalParameterCount = 14; /* includes 2 bytes of null string, converted to LE below */ + params = 14; /* includes 2 bytes of null string, converted to LE below */ + byte_count = 0; pSMB->TotalDataCount = 0; /* no EAs */ pSMB->MaxParameterCount = cpu_to_le16(8); pSMB->MaxDataCount = @@ -1940,8 +2717,8 @@ pSMB->Flags = 0; pSMB->Timeout = 0; pSMB->Reserved2 = 0; - pSMB->ParameterOffset = cpu_to_le16(offsetof( - struct smb_com_transaction2_fnext_req,SearchHandle) - 4); + pSMB->ParameterOffset = cpu_to_le16( + offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4); pSMB->DataCount = 0; pSMB->DataOffset = 0; pSMB->SetupCount = 1; @@ -1950,7 +2727,7 @@ pSMB->SearchHandle = searchHandle; /* always kept as le */ findParms->SearchCount = 0; /* set to zero in case of error */ pSMB->SearchCount = - cpu_to_le16(CIFS_MAX_MSGSIZE / sizeof (FILE_DIRECTORY_INFO)); + cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO)); /* test for Unix extensions */ if (tcon->ses->capabilities & CAP_UNIX) { pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX); @@ -1964,17 +2741,17 @@ pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME); /* BB add check to make sure we do not cross end of smb */ - if(name_len < CIFS_MAX_MSGSIZE) { + if(name_len < PATH_MAX) { memcpy(pSMB->ResumeFileName, resume_file_name, name_len); - pSMB->ByteCount += name_len; + byte_count += name_len; } - pSMB->TotalParameterCount += name_len; - pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; - pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount); + params += name_len; + byte_count = params + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(params); pSMB->ParameterCount = pSMB->TotalParameterCount; /* BB improve error handling here */ - pSMB->hdr.smb_buf_length += pSMB->ByteCount; - pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + pSMB->hdr.smb_buf_length += byte_count; + pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -1985,23 +2762,23 @@ else cFYI(1, ("FindNext returned = %d", rc)); } else { /* decode response */ + rc = validate_t2((struct smb_t2_rsp *)pSMBr); + /* BB add safety checks for these memcpys */ - if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) - *pUnicodeFlag = TRUE; - else - *pUnicodeFlag = FALSE; - memcpy(findParms, - (char *) &pSMBr->hdr.Protocol + - le16_to_cpu(pSMBr->ParameterOffset), - sizeof (T2_FNEXT_RSP_PARMS)); - findParms->EndofSearch = le16_to_cpu(findParms->EndofSearch); - findParms->LastNameOffset = - le16_to_cpu(findParms->LastNameOffset); - findParms->SearchCount = le16_to_cpu(findParms->SearchCount); - response_data = - (char *) &pSMBr->hdr.Protocol + - le16_to_cpu(pSMBr->DataOffset); - memcpy(findData, response_data, le16_to_cpu(pSMBr->DataCount)); + if(rc == 0) { + if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) + *pUnicodeFlag = TRUE; + else + *pUnicodeFlag = FALSE; + memcpy(findParms, + (char *) &pSMBr->hdr.Protocol + + le16_to_cpu(pSMBr->t2.ParameterOffset), + sizeof (T2_FNEXT_RSP_PARMS)); + response_data = + (char *) &pSMBr->hdr.Protocol + + le16_to_cpu(pSMBr->t2.DataOffset); + memcpy(findData,response_data,le16_to_cpu(pSMBr->t2.DataCount)); + } } if (pSMB) cifs_buf_release(pSMB); @@ -2017,12 +2794,12 @@ { int rc = 0; FINDCLOSE_REQ *pSMB = NULL; - CLOSE_RSP *pSMBr = NULL; + CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */ int bytes_returned; cFYI(1, ("In CIFSSMBFindClose")); - rc = smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **) &pSMB, - (void **) &pSMBr); + rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB); + pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */ /* no sense returning error if session restarted file handle has been closed */ if(rc == -EAGAIN) @@ -2038,7 +2815,7 @@ cERROR(1, ("Send error in FindClose = %d", rc)); } if (pSMB) - cifs_buf_release(pSMB); + cifs_small_buf_release(pSMB); /* Since session is dead, search handle closed on server already */ if (rc == -EAGAIN) @@ -2047,6 +2824,39 @@ return rc; } +#ifdef CONFIG_CIFS_EXPERIMENTAL +int +CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, + const unsigned char *searchName, + __u64 * inode_number, + const struct nls_table *nls_codepage) +{ + int rc = 0; + TRANSACTION2_QPI_REQ *pSMB = NULL; + TRANSACTION2_QPI_RSP *pSMBr = NULL; + + cFYI(1,("In GetSrvInodeNumber for %s",searchName)); + if(tcon == NULL) + return -ENODEV; + + cFYI(1, ("In QPathInfo path %s", searchName)); +GetInodeNumberRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + +/* BB add missing code here */ + + if (pSMB) + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto GetInodeNumberRetry; + return rc; +} +#endif /* CIFS_EXPERIMENTAL */ + int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, const unsigned char *searchName, @@ -2063,6 +2873,7 @@ int name_len; unsigned int i; char * temp; + __u16 params, byte_count; *number_of_UNC_in_array = 0; *targetUNCs = NULL; @@ -2088,18 +2899,18 @@ pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; name_len = cifs_strtoUCS((wchar_t *) pSMB->RequestFileName, - searchName, 530 + searchName, PATH_MAX /* 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 = strnlen(searchName, PATH_MAX); name_len++; /* trailing null */ strncpy(pSMB->RequestFileName, searchName, name_len); } - pSMB->ParameterCount = 2 /* level */ + name_len /*includes null */ ; + params = 2 /* level */ + name_len /*includes null */ ; pSMB->TotalDataCount = 0; pSMB->DataCount = 0; pSMB->DataOffset = 0; @@ -2115,12 +2926,12 @@ pSMB->SetupCount = 1; pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL); - pSMB->ByteCount = pSMB->ParameterCount + 3 /* pad */ ; - pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); + byte_count = params + 3 /* pad */ ; + pSMB->ParameterCount = cpu_to_le16(params); pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->MaxReferralLevel = cpu_to_le16(3); - pSMB->hdr.smb_buf_length += pSMB->ByteCount; - pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + pSMB->hdr.smb_buf_length += byte_count; + pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -2128,20 +2939,24 @@ cFYI(1, ("Send error in GetDFSRefer = %d", rc)); } else { /* decode response */ /* BB Add logic to parse referrals here */ - pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); - pSMBr->DataCount = le16_to_cpu(pSMBr->DataCount); - cFYI(1, - ("Decoding GetDFSRefer response. BCC: %d Offset %d", - pSMBr->ByteCount, pSMBr->DataOffset)); - if ((pSMBr->ByteCount < 17) || (pSMBr->DataOffset > 512)) /* BB also check enough total bytes returned */ - rc = -EIO; /* bad smb */ + rc = validate_t2((struct smb_t2_rsp *)pSMBr); + + if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */ + rc = -EIO; /* bad smb */ else { + __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); + __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount); + + cFYI(1, + ("Decoding GetDFSRefer response. BCC: %d Offset %d", + pSMBr->ByteCount, data_offset)); referrals = (struct dfs_referral_level_3 *) (8 /* sizeof start of data block */ + - pSMBr->DataOffset + + data_offset + (char *) &pSMBr->hdr.Protocol); - cFYI(1,("num_referrals: %d dfs flags: 0x%x ... \nfor referral one refer size: 0x%x srv type: 0x%x refer flags: 0x%x ttl: 0x%x",pSMBr->NumberOfReferrals,pSMBr->DFSFlags, referrals->ReferralSize,referrals->ServerType,referrals->ReferralFlags,referrals->TimeToLive)); + cFYI(1,("num_referrals: %d dfs flags: 0x%x ... \nfor referral one refer size: 0x%x srv type: 0x%x refer flags: 0x%x ttl: 0x%x", + le16_to_cpu(pSMBr->NumberOfReferrals),le16_to_cpu(pSMBr->DFSFlags), le16_to_cpu(referrals->ReferralSize),le16_to_cpu(referrals->ServerType),le16_to_cpu(referrals->ReferralFlags),le16_to_cpu(referrals->TimeToLive))); /* BB This field is actually two bytes in from start of data block so we could do safety check that DataBlock begins at address of pSMBr->NumberOfReferrals */ @@ -2155,19 +2970,19 @@ name_len = 0; for(i=0;i<*number_of_UNC_in_array;i++) { /* make sure that DfsPathOffset not past end */ - referrals->DfsPathOffset = le16_to_cpu(referrals->DfsPathOffset); - if(referrals->DfsPathOffset > pSMBr->DataCount) { + __u16 offset = le16_to_cpu(referrals->DfsPathOffset); + if (offset > data_count) { /* if invalid referral, stop here and do not try to copy any more */ *number_of_UNC_in_array = i; break; } - temp = ((char *)referrals) + referrals->DfsPathOffset; + temp = ((char *)referrals) + offset; if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { - name_len += UniStrnlen((wchar_t *)temp,pSMBr->DataCount); + name_len += UniStrnlen((wchar_t *)temp,data_count); } else { - name_len += strnlen(temp,pSMBr->DataCount); + name_len += strnlen(temp,data_count); } referrals++; /* BB add check that referral pointer does not fall off end PDU */ @@ -2184,11 +2999,11 @@ referrals = (struct dfs_referral_level_3 *) (8 /* sizeof data hdr */ + - pSMBr->DataOffset + + data_offset + (char *) &pSMBr->hdr.Protocol); for(i=0;i<*number_of_UNC_in_array;i++) { - temp = ((char *)referrals) + referrals->DfsPathOffset; + temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset); if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { cifs_strfromUCS_le(*targetUNCs, (wchar_t *) temp, name_len, nls_codepage); @@ -2223,6 +3038,7 @@ FILE_SYSTEM_INFO *response_data; int rc = 0; int bytes_returned = 0; + __u16 params, byte_count; cFYI(1, ("In QFSInfo")); QFSInfoRetry: @@ -2231,7 +3047,7 @@ if (rc) return rc; - pSMB->TotalParameterCount = 2; /* level */ + params = 2; /* level */ pSMB->TotalDataCount = 0; pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ @@ -2240,8 +3056,8 @@ pSMB->Flags = 0; pSMB->Timeout = 0; pSMB->Reserved2 = 0; - pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; - pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount); + byte_count = params + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(params); pSMB->ParameterCount = pSMB->TotalParameterCount; pSMB->ParameterOffset = cpu_to_le16(offsetof( struct smb_com_transaction2_qfsi_req, InformationLevel) - 4); @@ -2251,25 +3067,28 @@ pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO); - pSMB->hdr.smb_buf_length += pSMB->ByteCount; - pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + pSMB->hdr.smb_buf_length += byte_count; + pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { cERROR(1, ("Send error in QFSInfo = %d", rc)); } else { /* decode response */ - pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); - cFYI(1, - ("Decoding qfsinfo response. BCC: %d Offset %d", - pSMBr->ByteCount, pSMBr->DataOffset)); - if ((pSMBr->ByteCount < 24) || (pSMBr->DataOffset > 512)) /* BB also check enough total bytes returned */ + rc = validate_t2((struct smb_t2_rsp *)pSMBr); + + if (rc || (pSMBr->ByteCount < 24)) /* BB alsO CHEck enough total bytes returned */ rc = -EIO; /* bad smb */ else { + __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); + cFYI(1, + ("Decoding qfsinfo response. BCC: %d Offset %d", + pSMBr->ByteCount, data_offset)); + response_data = (FILE_SYSTEM_INFO *) (((char *) &pSMBr->hdr.Protocol) + - pSMBr->DataOffset); + data_offset); FSData->f_bsize = le32_to_cpu(response_data->BytesPerSector) * le32_to_cpu(response_data-> @@ -2304,6 +3123,7 @@ FILE_SYSTEM_ATTRIBUTE_INFO *response_data; int rc = 0; int bytes_returned = 0; + __u16 params, byte_count; cFYI(1, ("In QFSAttributeInfo")); QFSAttributeRetry: @@ -2312,7 +3132,7 @@ if (rc) return rc; - pSMB->TotalParameterCount = 2; /* level */ + params = 2; /* level */ pSMB->TotalDataCount = 0; pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ @@ -2321,8 +3141,8 @@ pSMB->Flags = 0; pSMB->Timeout = 0; pSMB->Reserved2 = 0; - pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; - pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount); + byte_count = params + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(params); pSMB->ParameterCount = pSMB->TotalParameterCount; pSMB->ParameterOffset = cpu_to_le16(offsetof( struct smb_com_transaction2_qfsi_req, InformationLevel) - 4); @@ -2332,27 +3152,24 @@ pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO); - pSMB->hdr.smb_buf_length += pSMB->ByteCount; - pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + pSMB->hdr.smb_buf_length += byte_count; + pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { cERROR(1, ("Send error in QFSAttributeInfo = %d", rc)); } else { /* decode response */ - pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); - if ((pSMBr->ByteCount < 13) || (pSMBr->DataOffset > 512)) { /* BB also check enough bytes returned */ + rc = validate_t2((struct smb_t2_rsp *)pSMBr); + + if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */ rc = -EIO; /* bad smb */ } else { + __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); response_data = (FILE_SYSTEM_ATTRIBUTE_INFO *) (((char *) &pSMBr->hdr.Protocol) + - pSMBr->DataOffset); - response_data->Attributes = le32_to_cpu(response_data->Attributes); - response_data->MaxPathNameComponentLength = - le32_to_cpu(response_data->MaxPathNameComponentLength); - response_data->FileSystemNameLen = - le32_to_cpu(response_data->FileSystemNameLen); + data_offset); memcpy(&tcon->fsAttrInfo, response_data, sizeof (FILE_SYSTEM_ATTRIBUTE_INFO)); } @@ -2376,6 +3193,7 @@ FILE_SYSTEM_DEVICE_INFO *response_data; int rc = 0; int bytes_returned = 0; + __u16 params, byte_count; cFYI(1, ("In QFSDeviceInfo")); QFSDeviceRetry: @@ -2384,7 +3202,7 @@ if (rc) return rc; - pSMB->TotalParameterCount = 2; /* level */ + params = 2; /* level */ pSMB->TotalDataCount = 0; pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ @@ -2393,8 +3211,8 @@ pSMB->Flags = 0; pSMB->Timeout = 0; pSMB->Reserved2 = 0; - pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; - pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount); + byte_count = params + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(params); pSMB->ParameterCount = pSMB->TotalParameterCount; pSMB->ParameterOffset = cpu_to_le16(offsetof( struct smb_com_transaction2_qfsi_req, InformationLevel) - 4); @@ -2405,27 +3223,24 @@ pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO); - pSMB->hdr.smb_buf_length += pSMB->ByteCount; - pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + pSMB->hdr.smb_buf_length += byte_count; + pSMB->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, ("Send error in QFSDeviceInfo = %d", rc)); } else { /* decode response */ - pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); - if ((pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)) - || (pSMBr->DataOffset > 512)) + rc = validate_t2((struct smb_t2_rsp *)pSMBr); + + if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO))) rc = -EIO; /* bad smb */ else { + __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); response_data = (FILE_SYSTEM_DEVICE_INFO *) (((char *) &pSMBr->hdr.Protocol) + - pSMBr->DataOffset); - response_data->DeviceType = - le32_to_cpu(response_data->DeviceType); - response_data->DeviceCharacteristics = - le32_to_cpu(response_data->DeviceCharacteristics); + data_offset); memcpy(&tcon->fsDevInfo, response_data, sizeof (FILE_SYSTEM_DEVICE_INFO)); } @@ -2449,6 +3264,7 @@ FILE_SYSTEM_UNIX_INFO *response_data; int rc = 0; int bytes_returned = 0; + __u16 params, byte_count; cFYI(1, ("In QFSUnixInfo")); QFSUnixRetry: @@ -2457,7 +3273,7 @@ if (rc) return rc; - pSMB->ParameterCount = 2; /* level */ + params = 2; /* level */ pSMB->TotalDataCount = 0; pSMB->DataCount = 0; pSMB->DataOffset = 0; @@ -2468,8 +3284,8 @@ pSMB->Flags = 0; pSMB->Timeout = 0; pSMB->Reserved2 = 0; - pSMB->ByteCount = pSMB->ParameterCount + 1 /* pad */ ; - pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); + byte_count = params + 1 /* pad */ ; + pSMB->ParameterCount = cpu_to_le16(params); pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->ParameterOffset = cpu_to_le16(offsetof(struct smb_com_transaction2_qfsi_req, InformationLevel) - 4); @@ -2477,28 +3293,24 @@ pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO); - pSMB->hdr.smb_buf_length += pSMB->ByteCount; - pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + pSMB->hdr.smb_buf_length += byte_count; + pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { cERROR(1, ("Send error in QFSUnixInfo = %d", rc)); } else { /* decode response */ - pSMBr->DataOffset = cpu_to_le16(pSMBr->DataOffset); - if ((pSMBr->ByteCount < 13) || (pSMBr->DataOffset > 512)) { + rc = validate_t2((struct smb_t2_rsp *)pSMBr); + + if (rc || (pSMBr->ByteCount < 13)) { rc = -EIO; /* bad smb */ } else { + __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); response_data = (FILE_SYSTEM_UNIX_INFO *) (((char *) &pSMBr->hdr.Protocol) + - pSMBr->DataOffset); - response_data->MajorVersionNumber = - le16_to_cpu(response_data->MajorVersionNumber); - response_data->MinorVersionNumber = - le16_to_cpu(response_data->MinorVersionNumber); - response_data->Capability = - le64_to_cpu(response_data->Capability); + data_offset); memcpy(&tcon->fsUnixInfo, response_data, sizeof (FILE_SYSTEM_UNIX_INFO)); } @@ -2529,6 +3341,7 @@ int name_len; int rc = 0; int bytes_returned = 0; + __u16 params, byte_count, data_count, param_offset, offset; cFYI(1, ("In SetEOF")); SetEOFRetry: @@ -2539,18 +3352,18 @@ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530 + cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX /* 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 = strnlen(fileName, PATH_MAX); name_len++; /* trailing null */ strncpy(pSMB->FileName, fileName, name_len); } - pSMB->ParameterCount = 6 + name_len; - pSMB->DataCount = sizeof (struct file_end_of_file_info); + params = 6 + name_len; + data_count = sizeof (struct file_end_of_file_info); pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */ pSMB->MaxSetupCount = 0; @@ -2558,9 +3371,9 @@ pSMB->Flags = 0; pSMB->Timeout = 0; pSMB->Reserved2 = 0; - pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req, + param_offset = offsetof(struct smb_com_transaction2_spi_req, InformationLevel) - 4; - pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount; + offset = param_offset + params; if(SetAllocation) { if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) pSMB->InformationLevel = @@ -2579,21 +3392,21 @@ parm_data = (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) + - pSMB->DataOffset); - pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset); - pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); + offset); + pSMB->ParameterOffset = cpu_to_le16(param_offset); + pSMB->DataOffset = cpu_to_le16(offset); 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); + byte_count = 3 /* pad */ + params + data_count; + pSMB->DataCount = cpu_to_le16(data_count); pSMB->TotalDataCount = pSMB->DataCount; - pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); + pSMB->ParameterCount = cpu_to_le16(params); pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->hdr.smb_buf_length += byte_count; parm_data->FileSize = cpu_to_le64(size); - pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { @@ -2619,7 +3432,7 @@ struct file_end_of_file_info *parm_data; int rc = 0; int bytes_returned = 0; - __u32 tmp; + __u16 params, param_offset, offset, byte_count, count; cFYI(1, ("SetFileSize (via SetFileInfo) %lld", (long long)size)); @@ -2628,40 +3441,36 @@ if (rc) return rc; - tmp = cpu_to_le32(pid_of_opener); /* override pid of current process - so network fid will be valid */ - pSMB->hdr.Pid = tmp & 0xFFFF; - tmp >>= 16; - pSMB->hdr.PidHigh = tmp & 0xFFFF; + pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener); + pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16)); - pSMB->ParameterCount = 6; + params = 6; pSMB->MaxSetupCount = 0; pSMB->Reserved = 0; pSMB->Flags = 0; pSMB->Timeout = 0; pSMB->Reserved2 = 0; - pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_sfi_req, - Fid) - 4; - pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount; + param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; + offset = param_offset + params; - data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset; + data_offset = (char *) (&pSMB->hdr.Protocol) + offset; - pSMB->DataCount = sizeof(struct file_end_of_file_info); + count = sizeof(struct file_end_of_file_info); pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */ pSMB->SetupCount = 1; pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); - pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount; - pSMB->DataCount = cpu_to_le16(pSMB->DataCount); - pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); + byte_count = 3 /* pad */ + params + count; + pSMB->DataCount = cpu_to_le16(count); + pSMB->ParameterCount = cpu_to_le16(params); pSMB->TotalDataCount = pSMB->DataCount; pSMB->TotalParameterCount = pSMB->ParameterCount; - pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset); + pSMB->ParameterOffset = cpu_to_le16(param_offset); parm_data = (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) + - pSMB->DataOffset); - pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); /* now safe to change to le */ + offset); + pSMB->DataOffset = cpu_to_le16(offset); parm_data->FileSize = cpu_to_le64(size); pSMB->Fid = fid; if(SetAllocation) { @@ -2680,8 +3489,8 @@ cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO); } pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += pSMB->ByteCount; - pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + pSMB->hdr.smb_buf_length += byte_count; + pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { @@ -2710,6 +3519,7 @@ int rc = 0; int bytes_returned = 0; char *data_offset; + __u16 params, param_offset, offset, byte_count, count; cFYI(1, ("In SetTimes")); @@ -2721,19 +3531,19 @@ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530 + cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX /* 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 = strnlen(fileName, PATH_MAX); name_len++; /* trailing null */ strncpy(pSMB->FileName, fileName, name_len); } - pSMB->ParameterCount = 6 + name_len; - pSMB->DataCount = sizeof (FILE_BASIC_INFO); + params = 6 + name_len; + count = sizeof (FILE_BASIC_INFO); 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; @@ -2741,19 +3551,19 @@ pSMB->Flags = 0; pSMB->Timeout = 0; pSMB->Reserved2 = 0; - pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req, + param_offset = 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); + offset = param_offset + params; + data_offset = (char *) (&pSMB->hdr.Protocol) + offset; + pSMB->ParameterOffset = cpu_to_le16(param_offset); + pSMB->DataOffset = cpu_to_le16(offset); pSMB->SetupCount = 1; pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); - pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount; + byte_count = 3 /* pad */ + params + count; - pSMB->DataCount = cpu_to_le16(pSMB->DataCount); - pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); + pSMB->DataCount = cpu_to_le16(count); + pSMB->ParameterCount = cpu_to_le16(params); pSMB->TotalDataCount = pSMB->DataCount; pSMB->TotalParameterCount = pSMB->ParameterCount; if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) @@ -2761,9 +3571,9 @@ else pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->hdr.smb_buf_length += byte_count; memcpy(data_offset, data, sizeof (FILE_BASIC_INFO)); - pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { @@ -2779,17 +3589,18 @@ return rc; } - int CIFSSMBSetTimesLegacy(int xid, struct cifsTconInfo *tcon, char *fileName, - FILE_INFO_STANDARD * data, const struct nls_table *nls_codepage) + FILE_BASIC_INFO * data, const struct nls_table *nls_codepage) { TRANSACTION2_SPI_REQ *pSMB = NULL; TRANSACTION2_SPI_RSP *pSMBr = NULL; + FILE_INFO_STANDARD *pfinfo; int name_len; int rc = 0; int bytes_returned = 0; char *data_offset; + __u16 params, param_offset, count, offset, byte_count; cFYI(1, ("In SetTimesLegacy")); @@ -2801,20 +3612,19 @@ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530 + cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX /* 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 = strnlen(fileName, PATH_MAX); 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); + params = 6 + name_len; 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; @@ -2822,31 +3632,29 @@ pSMB->Flags = 0; pSMB->Timeout = 0; pSMB->Reserved2 = 0; - pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req, + param_offset = 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); + offset = param_offset + params; + data_offset = (char *) (&pSMB->hdr.Protocol) + offset; + pfinfo = (FILE_INFO_STANDARD *)data_offset; + /* BB add conversion for FILE_BASIC_INFO data struct to + FILE_INFO_STANDARD finfo struct */ + pSMB->ParameterOffset = cpu_to_le16(param_offset); + pSMB->DataOffset = cpu_to_le16(offset); pSMB->SetupCount = 1; pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); - pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount; + count = sizeof(FILE_INFO_STANDARD); + byte_count = 3 /* pad */ + params + count; - pSMB->DataCount = cpu_to_le16(pSMB->DataCount); - pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); + pSMB->DataCount = cpu_to_le16(count); + pSMB->ParameterCount = cpu_to_le16(params); 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->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); + pSMB->hdr.smb_buf_length += byte_count; + pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { @@ -2873,6 +3681,7 @@ int rc = 0; int bytes_returned = 0; FILE_UNIX_BASIC_INFO *data_offset; + __u16 params, param_offset, offset, count, byte_count; cFYI(1, ("In SetUID/GID/Mode")); setPermsRetry: @@ -2883,19 +3692,19 @@ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530 + cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX /* 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 = strnlen(fileName, PATH_MAX); name_len++; /* trailing null */ strncpy(pSMB->FileName, fileName, name_len); } - pSMB->ParameterCount = 6 + name_len; - pSMB->DataCount = sizeof (FILE_UNIX_BASIC_INFO); + params = 6 + name_len; + count = sizeof (FILE_UNIX_BASIC_INFO); 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; @@ -2903,25 +3712,26 @@ pSMB->Flags = 0; pSMB->Timeout = 0; pSMB->Reserved2 = 0; - pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req, + param_offset = offsetof(struct smb_com_transaction2_spi_req, InformationLevel) - 4; - pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount; + offset = param_offset + params; data_offset = (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol + - pSMB->DataOffset); - pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); - pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset); + offset); + memset(data_offset, 0, count); + pSMB->DataOffset = cpu_to_le16(offset); + pSMB->ParameterOffset = cpu_to_le16(param_offset); pSMB->SetupCount = 1; pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); - pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount; - pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); - pSMB->DataCount = cpu_to_le16(pSMB->DataCount); + byte_count = 3 /* pad */ + params + count; + pSMB->ParameterCount = cpu_to_le16(params); + pSMB->DataCount = cpu_to_le16(count); pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->TotalDataCount = pSMB->DataCount; pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->hdr.smb_buf_length += byte_count; data_offset->Uid = cpu_to_le64(uid); data_offset->Gid = cpu_to_le64(gid); /* better to leave device as zero when it is */ @@ -2945,7 +3755,7 @@ data_offset->Type = cpu_to_le32(UNIX_SOCKET); - pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { @@ -2994,9 +3804,8 @@ pSMB->Fid = netfid; /* file handle always le */ pSMB->ByteCount = 0; - pSMB->hdr.smb_buf_length += pSMB->ByteCount; rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, - (struct smb_hdr *) pSMBr, &bytes_returned, 0); + (struct smb_hdr *) pSMBr, &bytes_returned, -1); if (rc) { cFYI(1, ("Error in Notify = %d", rc)); } @@ -3021,6 +3830,7 @@ int name_len; struct fea * temp_fea; char * temp_ptr; + __u16 params, byte_count; cFYI(1, ("In Query All EAs path %s", searchName)); QAllEAsRetry: @@ -3031,19 +3841,18 @@ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530 + cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX /* 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 = strnlen(searchName, PATH_MAX); name_len++; /* trailing null */ strncpy(pSMB->FileName, searchName, name_len); } - pSMB->TotalParameterCount = 2 /* level */ + 4 /* reserved */ + - name_len /* includes null */ ; + params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ; 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 */ @@ -3059,46 +3868,46 @@ 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); + byte_count = params + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(params); 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); + pSMB->hdr.smb_buf_length += byte_count; + pSMB->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, ("Send error in QueryAllEAs = %d", rc)); } else { /* decode response */ - pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); + rc = validate_t2((struct smb_t2_rsp *)pSMBr); + /* 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)) + if (rc || (pSMBr->ByteCount < 4)) rc = -EIO; /* bad smb */ /* else if (pFindData){ memcpy((char *) pFindData, (char *) &pSMBr->hdr.Protocol + - pSMBr->DataOffset, kl); + data_offset, 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 */ + __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); struct fealist * ea_response_data; rc = 0; /* validate_trans2_offsets() */ - /* BB to check if(start of smb + pSMBr->DataOffset > &bcc+ bcc)*/ + /* BB to check if(start of smb + data_offset > &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; + data_offset); + name_len = le32_to_cpu(ea_response_data->list_len); + cFYI(1,("ea length %d", name_len)); if(name_len <= 8) { /* returned EA size zeroed at top of function */ cFYI(1,("empty EA list returned from server")); @@ -3108,6 +3917,7 @@ temp_fea = ea_response_data->list; temp_ptr = (char *)temp_fea; while(name_len > 0) { + __u16 value_len; name_len -= 4; temp_ptr += 4; rc += temp_fea->name_len; @@ -3133,9 +3943,9 @@ /* 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; + value_len = le16_to_cpu(temp_fea->value_len); + name_len -= value_len; + temp_ptr += 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 */ @@ -3164,6 +3974,7 @@ int name_len; struct fea * temp_fea; char * temp_ptr; + __u16 params, byte_count; cFYI(1, ("In Query EA path %s", searchName)); QEARetry: @@ -3174,19 +3985,18 @@ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530 + cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX /* 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 = strnlen(searchName, PATH_MAX); name_len++; /* trailing null */ strncpy(pSMB->FileName, searchName, name_len); } - pSMB->TotalParameterCount = 2 /* level */ + 4 /* reserved */ + - name_len /* includes null */ ; + params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ; 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 */ @@ -3202,46 +4012,46 @@ 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); + byte_count = params + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(params); 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); + pSMB->hdr.smb_buf_length += byte_count; + pSMB->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, ("Send error in Query EA = %d", rc)); } else { /* decode response */ - pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); + rc = validate_t2((struct smb_t2_rsp *)pSMBr); + /* 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)) + if (rc || (pSMBr->ByteCount < 4)) rc = -EIO; /* bad smb */ /* else if (pFindData){ memcpy((char *) pFindData, (char *) &pSMBr->hdr.Protocol + - pSMBr->DataOffset, kl); + data_offset, 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 */ + __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); struct fealist * ea_response_data; - rc = -ENOENT; + rc = -ENODATA; /* validate_trans2_offsets() */ - /* BB to check if(start of smb + pSMBr->DataOffset > &bcc+ bcc)*/ + /* BB to check if(start of smb + data_offset > &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; + data_offset); + name_len = le32_to_cpu(ea_response_data->list_len); + cFYI(1,("ea length %d", name_len)); if(name_len <= 8) { /* returned EA size zeroed at top of function */ cFYI(1,("empty EA list returned from server")); @@ -3253,15 +4063,16 @@ /* loop through checking if we have a matching name and then return the associated value */ while(name_len > 0) { + __u16 value_len; name_len -= 4; temp_ptr += 4; - temp_fea->value_len = cpu_to_le16(temp_fea->value_len); + value_len = le16_to_cpu(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; + rc = value_len; /* account for prefix user. and trailing null */ if(rc<=(int)buf_size) { memcpy(ea_value, @@ -3282,8 +4093,8 @@ /* account for trailing null */ name_len--; temp_ptr++; - name_len -= temp_fea->value_len; - temp_ptr += temp_fea->value_len; + name_len -= value_len; + temp_ptr += value_len; /* no trailing null to account for in value len */ /* go on to next EA */ temp_fea = (struct fea *)temp_ptr; @@ -3310,6 +4121,7 @@ int name_len; int rc = 0; int bytes_returned = 0; + __u16 params, param_offset, byte_count, offset, count; cFYI(1, ("In SetEA")); SetEARetry: @@ -3320,18 +4132,18 @@ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530 + cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX /* 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 = strnlen(fileName, PATH_MAX); name_len++; /* trailing null */ strncpy(pSMB->FileName, fileName, name_len); } - pSMB->ParameterCount = 6 + name_len; + params = 6 + name_len; /* done calculating parms using name_len of file name, now use name_len to calculate length of ea name @@ -3341,7 +4153,7 @@ else name_len = strnlen(ea_name,255); - pSMB->DataCount = sizeof(*parm_data) + ea_value_len + name_len + 1; + count = 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; @@ -3349,23 +4161,23 @@ pSMB->Flags = 0; pSMB->Timeout = 0; pSMB->Reserved2 = 0; - pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req, + param_offset = offsetof(struct smb_com_transaction2_spi_req, InformationLevel) - 4; - pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount; + offset = param_offset + params; 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); + offset); + pSMB->ParameterOffset = cpu_to_le16(param_offset); + pSMB->DataOffset = cpu_to_le16(offset); 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); + byte_count = 3 /* pad */ + params + count; + pSMB->DataCount = cpu_to_le16(count); + parm_data->list_len = cpu_to_le32(count); 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;; @@ -3382,11 +4194,11 @@ 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->ParameterCount = cpu_to_le16(params); pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += pSMB->ByteCount; - pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + pSMB->hdr.smb_buf_length += byte_count; + pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { diff -Nau fs/cifs/connect.c fs/cifs.new-mm/connect.c --- fs/cifs/connect.c 2005-01-14 09:34:00.000000000 -0600 +++ fs/cifs.new-mm/connect.c 2005-02-06 22:33:34.083612680 -0600 @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -58,6 +57,7 @@ char *domainname; char *UNC; char *UNCip; + char *in6_addr; /* ipv6 address as human readable form of in6_addr */ char *iocharset; /* local code page for mapping to and from Unicode */ char source_rfc1001_name[16]; /* netbios name of client */ uid_t linux_uid; @@ -69,6 +69,9 @@ unsigned intr:1; unsigned setuids:1; unsigned noperm:1; + unsigned no_psx_acl:1; /* set if posix acl support should be disabled */ + unsigned server_ino:1; /* use inode numbers from server ie UniqueId */ + unsigned direct_io:1; unsigned int rsize; unsigned int wsize; unsigned int sockopt; @@ -207,13 +210,13 @@ current->flags |= PF_MEMALLOC; server->tsk = current; /* save process info to wake at shutdown */ cFYI(1, ("Demultiplex PID: %d", current->pid)); - write_lock(&GlobalSMBSeslock); + 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, + length + cifs_min_rcv, GFP_KERNEL); } @@ -230,17 +233,12 @@ continue; } iov.iov_base = smb_buffer; - iov.iov_len = sizeof (struct smb_hdr) - 1; - /* 1 byte less above since wct is not always returned in error cases */ + iov.iov_len = 4; smb_msg.msg_control = NULL; smb_msg.msg_controllen = 0; - length = kernel_recvmsg(csocket, &smb_msg, - &iov, 1, - sizeof (struct smb_hdr) - - 1 /* RFC1001 header and SMB header */ , - MSG_PEEK /* flags see socket.h */ ); + &iov, 1, 4, 0 /* BB see socket.h flags */); if(server->tcpStatus == CifsExiting) { break; @@ -273,26 +271,16 @@ csocket = server->ssocket; wake_up(&server->response_q); continue; - } - - pdu_length = 4 + ntohl(smb_buffer->smb_buf_length); - /* Ony read pdu_length after below checks for too short (due + } else if (length > 3) { + pdu_length = ntohl(smb_buffer->smb_buf_length); + /* Only read pdu_length after below checks for too short (due to e.g. int overflow) and too long ie beyond end of buf */ - cFYI(1, ("Peek length rcvd: 0x%x beginning 0x%x)", length, pdu_length)); + cFYI(1,("rfc1002 length(big endian)0x%x)", pdu_length+4)); - temp = (char *) smb_buffer; - if (length > 3) { + temp = (char *) smb_buffer; if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) { - iov.iov_base = smb_buffer; - iov.iov_len = 4; - length = kernel_recvmsg(csocket, &smb_msg, - &iov, 1, 4, 0); cFYI(0,("Received 4 byte keep alive packet")); } else if (temp[0] == (char) RFC1002_POSITIVE_SESSION_RESPONSE) { - iov.iov_base = smb_buffer; - iov.iov_len = 4; - length = kernel_recvmsg(csocket, &smb_msg, - &iov, 1, 4, 0); cFYI(1,("Good RFC 1002 session rsp")); } else if ((temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) && (length == 5)) { @@ -326,32 +314,22 @@ csocket = server->ssocket; continue; } else { - if ((length != sizeof (struct smb_hdr) - 1) - || (pdu_length > - CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE) - || (pdu_length < - sizeof (struct smb_hdr) - 1) - || - (checkSMBhdr - (smb_buffer, smb_buffer->Mid))) { + if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) + || (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) { cERROR(1, - ("Invalid size or format for SMB found with length %d and pdu_lenght %d", - length, pdu_length)); - cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr)); - /* could we fix this network corruption by finding next - smb header (instead of killing the session) and - restart reading from next valid SMB found? */ + ("Invalid size SMB length %d and pdu_length %d", + length, pdu_length+4)); cifs_reconnect(server); csocket = server->ssocket; + wake_up(&server->response_q); continue; - } else { /* length ok */ - + } else { /* length ok */ length = 0; - iov.iov_base = smb_buffer; + iov.iov_base = 4 + (char *)smb_buffer; iov.iov_len = pdu_length; for (total_read = 0; total_read < pdu_length; - total_read += length) { + total_read += length) { length = kernel_recvmsg(csocket, &smb_msg, &iov, 1, pdu_length - total_read, 0); @@ -361,14 +339,16 @@ pdu_length - total_read)); cifs_reconnect(server); csocket = server->ssocket; + wake_up(&server->response_q); continue; } } + length += 4; /* account for rfc1002 hdr */ } dump_smb(smb_buffer, length); if (checkSMB - (smb_buffer, smb_buffer->Mid, total_read)) { + (smb_buffer, smb_buffer->Mid, total_read+4)) { cERROR(1, ("Bad SMB Received ")); continue; } @@ -400,17 +380,13 @@ } } } else { - cFYI(0, - ("Frame less than four bytes received %d bytes long.", + cFYI(1, + ("Frame less than four bytes received %d bytes long.", length)); - if (length > 0) { - length = kernel_recvmsg(csocket, &smb_msg, - &iov, 1, - length, 0); /* throw away junk frame */ - cFYI(1, - (" with junk 0x%x in it ", - *(__u32 *) smb_buffer)); - } + cifs_reconnect(server); + csocket = server->ssocket; + wake_up(&server->response_q); + continue; } } spin_lock(&GlobalMid_Lock); @@ -485,7 +461,7 @@ write_unlock(&GlobalSMBSeslock); if(length > 0) { mempool_resize(cifs_req_poolp, - length + CIFS_MIN_RCV_POOL, + length + cifs_min_rcv, GFP_KERNEL); } @@ -505,7 +481,7 @@ } static int -cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol) +cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) { char *value; char *data; @@ -692,7 +668,12 @@ vol->file_mode = simple_strtoul(value, &value, 0); } - } else if (strnicmp(data, "dir_mode", 3) == 0) { + } else if (strnicmp(data, "dir_mode", 4) == 0) { + if (value && *value) { + vol->dir_mode = + simple_strtoul(value, &value, 0); + } + } else if (strnicmp(data, "dirmode", 4) == 0) { if (value && *value) { vol->dir_mode = simple_strtoul(value, &value, 0); @@ -742,6 +723,8 @@ /* ignore */ } else if (strnicmp(data, "version", 3) == 0) { /* ignore */ + } else if (strnicmp(data, "guest",5) == 0) { + /* ignore */ } else if (strnicmp(data, "rw", 2) == 0) { vol->rw = TRUE; } else if ((strnicmp(data, "suid", 4) == 0) || @@ -780,6 +763,27 @@ vol->intr = 0; } else if (strnicmp(data, "intr", 4) == 0) { vol->intr = 1; + } else if (strnicmp(data, "serverino",7) == 0) { + vol->server_ino = 1; + } else if (strnicmp(data, "noserverino",9) == 0) { + vol->server_ino = 0; + } else if (strnicmp(data, "acl",3) == 0) { + vol->no_psx_acl = 0; + } else if (strnicmp(data, "noacl",5) == 0) { + vol->no_psx_acl = 1; + } else if (strnicmp(data, "direct",6) == 0) { + vol->direct_io = 1; + } else if (strnicmp(data, "forcedirectio",13) == 0) { + vol->direct_io = 1; + } else if (strnicmp(data, "in6_addr",8) == 0) { + if (!value || !*value) { + vol->in6_addr = NULL; + } else if (strnlen(value, 49) == 48) { + vol->in6_addr = value; + } else { + printk(KERN_WARNING "CIFS: ip v6 address not 48 characters long\n"); + return 1; + } } else if (strnicmp(data, "noac", 4) == 0) { printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n"); } else @@ -807,7 +811,7 @@ return 1; } } - if(vol->UNCip == 0) + if(vol->UNCip == NULL) vol->UNCip = &vol->UNC[2]; return 0; @@ -849,7 +853,7 @@ } static struct cifsTconInfo * -find_unc(__u32 new_target_ip_addr, char *uncName, char *userName) +find_unc(__be32 new_target_ip_addr, char *uncName, char *userName) { struct list_head *tmp; struct cifsTconInfo *tcon; @@ -968,7 +972,7 @@ { int rc = 0; int connected = 0; - unsigned short int orig_port = 0; + __be16 orig_port = 0; if(*csocket == NULL) { rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket); @@ -1076,7 +1080,7 @@ { int rc = 0; int connected = 0; - unsigned short int orig_port = 0; + __be16 orig_port = 0; if(*csocket == NULL) { rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket); @@ -1371,14 +1375,14 @@ /* search for existing tcon to this server share */ if (!rc) { - if((volume_info.rsize) && (volume_info.rsize + MAX_CIFS_HDR_SIZE < srvTcp->maxBuf)) + if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize)) cifs_sb->rsize = volume_info.rsize; else cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */ - if((volume_info.wsize) && (volume_info.wsize + MAX_CIFS_HDR_SIZE < srvTcp->maxBuf)) + if((volume_info.wsize) && (volume_info.wsize <= CIFSMaxBufSize)) cifs_sb->wsize = volume_info.wsize; else - cifs_sb->wsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */ + cifs_sb->wsize = CIFSMaxBufSize; /* default */ if(cifs_sb->rsize < PAGE_CACHE_SIZE) { cifs_sb->rsize = PAGE_CACHE_SIZE; cERROR(1,("Attempt to set readsize for mount to less than one page (4096)")); @@ -1393,6 +1397,12 @@ cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM; if(volume_info.setuids) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID; + if(volume_info.server_ino) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM; + if(volume_info.direct_io) { + cERROR(1,("mounting share using direct i/o")); + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; + } tcon = find_unc(sin_server.sin_addr.s_addr, volume_info.UNC, @@ -1444,6 +1454,8 @@ sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */ } +/* sb->s_time_gran = 100;*/ + /* on error free sesinfo and tcon struct if needed */ if (rc) { /* if session setup failed, use count is zero but @@ -1458,7 +1470,7 @@ /* If find_unc succeeded then rc == 0 so we can not end */ if (tcon) /* up accidently freeing someone elses tcon struct */ tconInfoFree(tcon); - if (existingCifsSes == 0) { + if (existingCifsSes == NULL) { if (pSesInfo) { if ((pSesInfo->server) && (pSesInfo->status == CifsGood)) { @@ -1482,8 +1494,16 @@ /* do not care if following two calls succeed - informational only */ CIFSSMBQFSDeviceInfo(xid, tcon, cifs_sb->local_nls); CIFSSMBQFSAttributeInfo(xid, tcon, cifs_sb->local_nls); - if (tcon->ses->capabilities & CAP_UNIX) - CIFSSMBQFSUnixInfo(xid, tcon, cifs_sb->local_nls); + if (tcon->ses->capabilities & CAP_UNIX) { + if(!CIFSSMBQFSUnixInfo(xid, tcon, cifs_sb->local_nls)) { + if(!volume_info.no_psx_acl) { + if(CIFS_UNIX_POSIX_ACL_CAP & + le64_to_cpu(tcon->fsUnixInfo.Capability)) + cFYI(1,("server negotiated posix acl support")); + sb->s_flags |= MS_POSIXACL; + } + } + } } /* volume_info.password is freed above when existing session found @@ -1512,6 +1532,8 @@ int remaining_words = 0; int bytes_returned = 0; int len; + __u32 capabilities; + __u16 count; cFYI(1, ("In sesssetup ")); if(ses == NULL) @@ -1519,7 +1541,7 @@ user = ses->userName; domain = ses->domainName; smb_buffer = cifs_buf_get(); - if (smb_buffer == 0) { + if (smb_buffer == NULL) { return -ENOMEM; } smb_buffer_response = smb_buffer; @@ -1536,30 +1558,29 @@ if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; - pSMB->req_no_secext.Capabilities = - CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS; + capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | CAP_LARGE_WRITE_X | CAP_LARGE_READ_X; if (ses->capabilities & CAP_UNICODE) { smb_buffer->Flags2 |= SMBFLG2_UNICODE; - pSMB->req_no_secext.Capabilities |= CAP_UNICODE; + capabilities |= CAP_UNICODE; } if (ses->capabilities & CAP_STATUS32) { smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; - pSMB->req_no_secext.Capabilities |= CAP_STATUS32; + capabilities |= CAP_STATUS32; } if (ses->capabilities & CAP_DFS) { smb_buffer->Flags2 |= SMBFLG2_DFS; - pSMB->req_no_secext.Capabilities |= CAP_DFS; + capabilities |= CAP_DFS; } - pSMB->req_no_secext.Capabilities = - cpu_to_le32(pSMB->req_no_secext.Capabilities); - /* pSMB->req_no_secext.CaseInsensitivePasswordLength = - CIFS_SESSION_KEY_SIZE; */ - pSMB->req_no_secext.CaseInsensitivePasswordLength = 0; + pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); + + pSMB->req_no_secext.CaseInsensitivePasswordLength = + cpu_to_le16(CIFS_SESSION_KEY_SIZE); + pSMB->req_no_secext.CaseSensitivePasswordLength = cpu_to_le16(CIFS_SESSION_KEY_SIZE); bcc_ptr = pByteArea(smb_buffer); - /* memcpy(bcc_ptr, (char *) lm_session_key, CIFS_SESSION_KEY_SIZE); - bcc_ptr += CIFS_SESSION_KEY_SIZE; */ + memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE); + bcc_ptr += CIFS_SESSION_KEY_SIZE; memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE); bcc_ptr += CIFS_SESSION_KEY_SIZE; @@ -1591,7 +1612,7 @@ 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32, + cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; @@ -1618,14 +1639,14 @@ } strcpy(bcc_ptr, "Linux version "); bcc_ptr += strlen("Linux version "); - strcpy(bcc_ptr, UTS_RELEASE); - bcc_ptr += strlen(UTS_RELEASE) + 1; + strcpy(bcc_ptr, system_utsname.release); + bcc_ptr += strlen(system_utsname.release) + 1; strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; } - BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer); - smb_buffer->smb_buf_length += BCC(smb_buffer); - BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer)); + count = (long) bcc_ptr - (long) pByteArea(smb_buffer); + smb_buffer->smb_buf_length += count; + pSMB->req_no_secext.ByteCount = cpu_to_le16(count); rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &bytes_returned, 1); @@ -1633,8 +1654,9 @@ /* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */ } else if ((smb_buffer_response->WordCount == 3) || (smb_buffer_response->WordCount == 4)) { - pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action); - if (pSMBr->resp.Action & GUEST_LOGIN) + __u16 action = le16_to_cpu(pSMBr->resp.Action); + __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); + if (action & GUEST_LOGIN) cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */ ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */ cFYI(1, ("UID = %d ", ses->Suid)); @@ -1642,11 +1664,9 @@ bcc_ptr = pByteArea(smb_buffer_response); if ((pSMBr->resp.hdr.WordCount == 3) || ((pSMBr->resp.hdr.WordCount == 4) - && (pSMBr->resp.SecurityBlobLength < - pSMBr->resp.ByteCount))) { + && (blob_len < pSMBr->resp.ByteCount))) { if (pSMBr->resp.hdr.WordCount == 4) - bcc_ptr += - pSMBr->resp.SecurityBlobLength; + bcc_ptr += blob_len; if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { if ((long) (bcc_ptr) % 2) { @@ -1764,6 +1784,8 @@ int remaining_words = 0; int bytes_returned = 0; int len; + __u32 capabilities; + __u16 count; cFYI(1, ("In spnego sesssetup ")); if(ses == NULL) @@ -1772,7 +1794,7 @@ domain = ses->domainName; smb_buffer = cifs_buf_get(); - if (smb_buffer == 0) { + if (smb_buffer == NULL) { return -ENOMEM; } smb_buffer_response = smb_buffer; @@ -1789,22 +1811,21 @@ if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; - pSMB->req.Capabilities = - CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | + capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | CAP_EXTENDED_SECURITY; if (ses->capabilities & CAP_UNICODE) { smb_buffer->Flags2 |= SMBFLG2_UNICODE; - pSMB->req.Capabilities |= CAP_UNICODE; + capabilities |= CAP_UNICODE; } if (ses->capabilities & CAP_STATUS32) { smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; - pSMB->req.Capabilities |= CAP_STATUS32; + capabilities |= CAP_STATUS32; } if (ses->capabilities & CAP_DFS) { smb_buffer->Flags2 |= SMBFLG2_DFS; - pSMB->req.Capabilities |= CAP_DFS; + capabilities |= CAP_DFS; } - pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities); + pSMB->req.Capabilities = cpu_to_le32(capabilities); pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength); bcc_ptr = pByteArea(smb_buffer); @@ -1835,7 +1856,7 @@ 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32, + cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; @@ -1860,14 +1881,14 @@ } strcpy(bcc_ptr, "Linux version "); bcc_ptr += strlen("Linux version "); - strcpy(bcc_ptr, UTS_RELEASE); - bcc_ptr += strlen(UTS_RELEASE) + 1; + strcpy(bcc_ptr, system_utsname.release); + bcc_ptr += strlen(system_utsname.release) + 1; strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; } - BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer); - smb_buffer->smb_buf_length += BCC(smb_buffer); - BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer)); + count = (long) bcc_ptr - (long) pByteArea(smb_buffer); + smb_buffer->smb_buf_length += count; + pSMB->req.ByteCount = cpu_to_le16(count); rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &bytes_returned, 1); @@ -1875,10 +1896,10 @@ /* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */ } else if ((smb_buffer_response->WordCount == 3) || (smb_buffer_response->WordCount == 4)) { - pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action); - pSMBr->resp.SecurityBlobLength = + __u16 action = le16_to_cpu(pSMBr->resp.Action); + __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); - if (pSMBr->resp.Action & GUEST_LOGIN) + if (action & GUEST_LOGIN) cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */ if (ses) { ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */ @@ -1889,14 +1910,14 @@ if ((pSMBr->resp.hdr.WordCount == 3) || ((pSMBr->resp.hdr.WordCount == 4) - && (pSMBr->resp.SecurityBlobLength < + && (blob_len < pSMBr->resp.ByteCount))) { if (pSMBr->resp.hdr.WordCount == 4) { bcc_ptr += - pSMBr->resp.SecurityBlobLength; + blob_len; cFYI(1, ("Security Blob Length %d ", - pSMBr->resp.SecurityBlobLength)); + blob_len)); } if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { @@ -2029,6 +2050,8 @@ int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE); PNEGOTIATE_MESSAGE SecurityBlob; PCHALLENGE_MESSAGE SecurityBlob2; + __u32 negotiate_flags, capabilities; + __u16 count; cFYI(1, ("In NTLMSSP sesssetup (negotiate) ")); if(ses == NULL) @@ -2036,7 +2059,7 @@ domain = ses->domainName; *pNTLMv2_flag = FALSE; smb_buffer = cifs_buf_get(); - if (smb_buffer == 0) { + if (smb_buffer == NULL) { return -ENOMEM; } smb_buffer_response = smb_buffer; @@ -2056,35 +2079,34 @@ if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; - pSMB->req.Capabilities = - CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | + capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | CAP_EXTENDED_SECURITY; if (ses->capabilities & CAP_UNICODE) { smb_buffer->Flags2 |= SMBFLG2_UNICODE; - pSMB->req.Capabilities |= CAP_UNICODE; + capabilities |= CAP_UNICODE; } if (ses->capabilities & CAP_STATUS32) { smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; - pSMB->req.Capabilities |= CAP_STATUS32; + capabilities |= CAP_STATUS32; } if (ses->capabilities & CAP_DFS) { smb_buffer->Flags2 |= SMBFLG2_DFS; - pSMB->req.Capabilities |= CAP_DFS; + capabilities |= CAP_DFS; } - pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities); + pSMB->req.Capabilities = cpu_to_le32(capabilities); bcc_ptr = (char *) &pSMB->req.SecurityBlob; SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr; strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8); SecurityBlob->MessageType = NtLmNegotiate; - SecurityBlob->NegotiateFlags = + negotiate_flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 | /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128; if(sign_CIFS_PDUs) - SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_SIGN; + negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN; if(ntlmv2_support) - SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLMV2; + negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2; /* setup pointers to domain name and workstation name */ bcc_ptr += SecurityBlobLength; @@ -2097,20 +2119,20 @@ SecurityBlob->DomainName.Length = 0; SecurityBlob->DomainName.MaximumLength = 0; } else { - SecurityBlob->NegotiateFlags |= - NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED; + __u16 len; + negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED; strncpy(bcc_ptr, domain, 63); - SecurityBlob->DomainName.Length = strnlen(domain, 64); + len = strnlen(domain, 64); SecurityBlob->DomainName.MaximumLength = - cpu_to_le16(SecurityBlob->DomainName.Length); + cpu_to_le16(len); SecurityBlob->DomainName.Buffer = cpu_to_le32((long) &SecurityBlob-> DomainString - (long) &SecurityBlob->Signature); - bcc_ptr += SecurityBlob->DomainName.Length; - SecurityBlobLength += SecurityBlob->DomainName.Length; + bcc_ptr += len; + SecurityBlobLength += len; SecurityBlob->DomainName.Length = - cpu_to_le16(SecurityBlob->DomainName.Length); + cpu_to_le16(len); } if (ses->capabilities & CAP_UNICODE) { if ((long) bcc_ptr % 2) { @@ -2123,7 +2145,7 @@ 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32, + cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; /* null terminate Linux version */ @@ -2140,35 +2162,34 @@ } else { /* ASCII */ strcpy(bcc_ptr, "Linux version "); bcc_ptr += strlen("Linux version "); - strcpy(bcc_ptr, UTS_RELEASE); - bcc_ptr += strlen(UTS_RELEASE) + 1; + strcpy(bcc_ptr, system_utsname.release); + bcc_ptr += strlen(system_utsname.release) + 1; strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; bcc_ptr++; /* empty domain field */ *bcc_ptr = 0; } - SecurityBlob->NegotiateFlags = - cpu_to_le32(SecurityBlob->NegotiateFlags); + SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags); pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength); - BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer); - smb_buffer->smb_buf_length += BCC(smb_buffer); - BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer)); + count = (long) bcc_ptr - (long) pByteArea(smb_buffer); + smb_buffer->smb_buf_length += count; + pSMB->req.ByteCount = cpu_to_le16(count); rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &bytes_returned, 1); if (smb_buffer_response->Status.CifsError == - (NT_STATUS_MORE_PROCESSING_REQUIRED)) + cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED)) rc = 0; if (rc) { /* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */ } else if ((smb_buffer_response->WordCount == 3) || (smb_buffer_response->WordCount == 4)) { - pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action); - pSMBr->resp.SecurityBlobLength = - le16_to_cpu(pSMBr->resp.SecurityBlobLength); - if (pSMBr->resp.Action & GUEST_LOGIN) + __u16 action = le16_to_cpu(pSMBr->resp.Action); + __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); + + if (action & GUEST_LOGIN) cFYI(1, (" Guest login")); /* Do we want to set anything in SesInfo struct when guest login? */ @@ -2185,14 +2206,14 @@ cFYI(1, ("UID = %d ", ses->Suid)); if ((pSMBr->resp.hdr.WordCount == 3) || ((pSMBr->resp.hdr.WordCount == 4) - && (pSMBr->resp.SecurityBlobLength < + && (blob_len < pSMBr->resp.ByteCount))) { + if (pSMBr->resp.hdr.WordCount == 4) { - bcc_ptr += - pSMBr->resp.SecurityBlobLength; + bcc_ptr += blob_len; cFYI(1, ("Security Blob Length %d ", - pSMBr->resp.SecurityBlobLength)); + blob_len)); } cFYI(1, ("NTLMSSP Challenge rcvd ")); @@ -2200,16 +2221,16 @@ memcpy(ses->server->cryptKey, SecurityBlob2->Challenge, CIFS_CRYPTO_KEY_SIZE); - if(SecurityBlob2->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLMV2) + if(SecurityBlob2->NegotiateFlags & cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2)) *pNTLMv2_flag = TRUE; if((SecurityBlob2->NegotiateFlags & - NTLMSSP_NEGOTIATE_ALWAYS_SIGN) + cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN)) || (sign_CIFS_PDUs > 1)) ses->server->secMode |= SECMODE_SIGN_REQUIRED; if ((SecurityBlob2->NegotiateFlags & - NTLMSSP_NEGOTIATE_SIGN) && (sign_CIFS_PDUs)) + cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs)) ses->server->secMode |= SECMODE_SIGN_ENABLED; @@ -2353,7 +2374,6 @@ return rc; } - static int CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, char *ntlm_session_key, int ntlmv2_flag, @@ -2372,6 +2392,8 @@ int len; int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE); PAUTHENTICATE_MESSAGE SecurityBlob; + __u32 negotiate_flags, capabilities; + __u16 count; cFYI(1, ("In NTLMSSPSessSetup (Authenticate)")); if(ses == NULL) @@ -2379,7 +2401,7 @@ user = ses->userName; domain = ses->domainName; smb_buffer = cifs_buf_get(); - if (smb_buffer == 0) { + if (smb_buffer == NULL) { return -ENOMEM; } smb_buffer_response = smb_buffer; @@ -2400,36 +2422,35 @@ if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; - pSMB->req.Capabilities = - CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | + capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | CAP_EXTENDED_SECURITY; if (ses->capabilities & CAP_UNICODE) { smb_buffer->Flags2 |= SMBFLG2_UNICODE; - pSMB->req.Capabilities |= CAP_UNICODE; + capabilities |= CAP_UNICODE; } if (ses->capabilities & CAP_STATUS32) { smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; - pSMB->req.Capabilities |= CAP_STATUS32; + capabilities |= CAP_STATUS32; } if (ses->capabilities & CAP_DFS) { smb_buffer->Flags2 |= SMBFLG2_DFS; - pSMB->req.Capabilities |= CAP_DFS; + capabilities |= CAP_DFS; } - pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities); + pSMB->req.Capabilities = cpu_to_le32(capabilities); bcc_ptr = (char *) &pSMB->req.SecurityBlob; SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr; strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8); SecurityBlob->MessageType = NtLmAuthenticate; bcc_ptr += SecurityBlobLength; - SecurityBlob->NegotiateFlags = + negotiate_flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO | 0x80000000 | NTLMSSP_NEGOTIATE_128; if(sign_CIFS_PDUs) - SecurityBlob->NegotiateFlags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN; + negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN; if(ntlmv2_flag) - SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLMV2; + negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2; /* setup pointers to domain name and workstation name */ @@ -2460,36 +2481,36 @@ SecurityBlob->DomainName.Length = 0; SecurityBlob->DomainName.MaximumLength = 0; } else { - SecurityBlob->DomainName.Length = + __u16 len = cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64, nls_codepage); - SecurityBlob->DomainName.Length *= 2; + len *= 2; SecurityBlob->DomainName.MaximumLength = - cpu_to_le16(SecurityBlob->DomainName.Length); + cpu_to_le16(len); SecurityBlob->DomainName.Buffer = cpu_to_le32(SecurityBlobLength); - bcc_ptr += SecurityBlob->DomainName.Length; - SecurityBlobLength += SecurityBlob->DomainName.Length; + bcc_ptr += len; + SecurityBlobLength += len; SecurityBlob->DomainName.Length = - cpu_to_le16(SecurityBlob->DomainName.Length); + cpu_to_le16(len); } if (user == NULL) { SecurityBlob->UserName.Buffer = 0; SecurityBlob->UserName.Length = 0; SecurityBlob->UserName.MaximumLength = 0; } else { - SecurityBlob->UserName.Length = + __u16 len = cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64, nls_codepage); - SecurityBlob->UserName.Length *= 2; + len *= 2; SecurityBlob->UserName.MaximumLength = - cpu_to_le16(SecurityBlob->UserName.Length); + cpu_to_le16(len); SecurityBlob->UserName.Buffer = cpu_to_le32(SecurityBlobLength); - bcc_ptr += SecurityBlob->UserName.Length; - SecurityBlobLength += SecurityBlob->UserName.Length; + bcc_ptr += len; + SecurityBlobLength += len; SecurityBlob->UserName.Length = - cpu_to_le16(SecurityBlob->UserName.Length); + cpu_to_le16(len); } /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage); @@ -2509,7 +2530,7 @@ 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32, + cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; /* null term version string */ @@ -2529,52 +2550,50 @@ SecurityBlob->DomainName.Length = 0; SecurityBlob->DomainName.MaximumLength = 0; } else { - SecurityBlob->NegotiateFlags |= - NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED; + __u16 len; + negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED; strncpy(bcc_ptr, domain, 63); - SecurityBlob->DomainName.Length = strnlen(domain, 64); + len = strnlen(domain, 64); SecurityBlob->DomainName.MaximumLength = - cpu_to_le16(SecurityBlob->DomainName.Length); + cpu_to_le16(len); SecurityBlob->DomainName.Buffer = cpu_to_le32(SecurityBlobLength); - bcc_ptr += SecurityBlob->DomainName.Length; - SecurityBlobLength += SecurityBlob->DomainName.Length; - SecurityBlob->DomainName.Length = - cpu_to_le16(SecurityBlob->DomainName.Length); + bcc_ptr += len; + SecurityBlobLength += len; + SecurityBlob->DomainName.Length = cpu_to_le16(len); } if (user == NULL) { SecurityBlob->UserName.Buffer = 0; SecurityBlob->UserName.Length = 0; SecurityBlob->UserName.MaximumLength = 0; } else { + __u16 len; strncpy(bcc_ptr, user, 63); - SecurityBlob->UserName.Length = strnlen(user, 64); + len = strnlen(user, 64); SecurityBlob->UserName.MaximumLength = - cpu_to_le16(SecurityBlob->UserName.Length); + cpu_to_le16(len); SecurityBlob->UserName.Buffer = cpu_to_le32(SecurityBlobLength); - bcc_ptr += SecurityBlob->UserName.Length; - SecurityBlobLength += SecurityBlob->UserName.Length; - SecurityBlob->UserName.Length = - cpu_to_le16(SecurityBlob->UserName.Length); + bcc_ptr += len; + SecurityBlobLength += len; + SecurityBlob->UserName.Length = cpu_to_le16(len); } /* BB fill in our workstation name if known BB */ strcpy(bcc_ptr, "Linux version "); bcc_ptr += strlen("Linux version "); - strcpy(bcc_ptr, UTS_RELEASE); - bcc_ptr += strlen(UTS_RELEASE) + 1; + strcpy(bcc_ptr, system_utsname.release); + bcc_ptr += strlen(system_utsname.release) + 1; strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; bcc_ptr++; /* null domain */ *bcc_ptr = 0; } - SecurityBlob->NegotiateFlags = - cpu_to_le32(SecurityBlob->NegotiateFlags); + SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags); pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength); - BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer); - smb_buffer->smb_buf_length += BCC(smb_buffer); - BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer)); + count = (long) bcc_ptr - (long) pByteArea(smb_buffer); + smb_buffer->smb_buf_length += count; + pSMB->req.ByteCount = cpu_to_le16(count); rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &bytes_returned, 1); @@ -2582,10 +2601,10 @@ /* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */ } else if ((smb_buffer_response->WordCount == 3) || (smb_buffer_response->WordCount == 4)) { - pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action); - pSMBr->resp.SecurityBlobLength = + __u16 action = le16_to_cpu(pSMBr->resp.Action); + __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); - if (pSMBr->resp.Action & GUEST_LOGIN) + if (action & GUEST_LOGIN) cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */ /* if(SecurityBlob2->MessageType != NtLm??){ cFYI("Unexpected message type on auth response is %d ")); @@ -2599,14 +2618,14 @@ /* response can have either 3 or 4 word count - Samba sends 3 */ if ((pSMBr->resp.hdr.WordCount == 3) || ((pSMBr->resp.hdr.WordCount == 4) - && (pSMBr->resp.SecurityBlobLength < + && (blob_len < pSMBr->resp.ByteCount))) { if (pSMBr->resp.hdr.WordCount == 4) { bcc_ptr += - pSMBr->resp.SecurityBlobLength; + blob_len; cFYI(1, ("Security Blob Length %d ", - pSMBr->resp.SecurityBlobLength)); + blob_len)); } cFYI(1, @@ -2747,15 +2766,16 @@ struct smb_hdr *smb_buffer_response; TCONX_REQ *pSMB; TCONX_RSP *pSMBr; - char *bcc_ptr; + unsigned char *bcc_ptr; int rc = 0; int length; + __u16 count; if (ses == NULL) return -EIO; smb_buffer = cifs_buf_get(); - if (smb_buffer == 0) { + if (smb_buffer == NULL) { return -ENOMEM; } smb_buffer_response = smb_buffer; @@ -2769,7 +2789,7 @@ pSMB->AndXCommand = 0xFF; pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO); pSMB->PasswordLength = cpu_to_le16(1); /* minimum */ - bcc_ptr = &(pSMB->Password[0]); + bcc_ptr = &pSMB->Password[0]; bcc_ptr++; /* skip password */ if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) @@ -2795,16 +2815,16 @@ strcpy(bcc_ptr, "?????"); bcc_ptr += strlen("?????"); bcc_ptr += 1; - BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer); - smb_buffer->smb_buf_length += BCC(smb_buffer); - BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer)); + count = bcc_ptr - &pSMB->Password[0]; + pSMB->hdr.smb_buf_length += count; + pSMB->ByteCount = cpu_to_le16(count); rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0); /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */ /* above now done in SendReceive */ if ((rc == 0) && (tcon != NULL)) { - tcon->tidStatus = CifsGood; + tcon->tidStatus = CifsGood; tcon->tid = smb_buffer_response->Tid; bcc_ptr = pByteArea(smb_buffer_response); length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2); @@ -2813,8 +2833,8 @@ strncpy(tcon->treeName, tree, MAX_TREE_SIZE); if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { length = UniStrnlen((wchar_t *) bcc_ptr, 512); - if (((long) bcc_ptr + (2 * length)) - - (long) pByteArea(smb_buffer_response) <= + if ((bcc_ptr + (2 * length)) - + pByteArea(smb_buffer_response) <= BCC(smb_buffer_response)) { if(tcon->nativeFileSystem) kfree(tcon->nativeFileSystem); @@ -2831,8 +2851,8 @@ /* else do not bother copying these informational fields */ } else { length = strnlen(bcc_ptr, 1024); - if (((long) bcc_ptr + length) - - (long) pByteArea(smb_buffer_response) <= + if ((bcc_ptr + length) - + pByteArea(smb_buffer_response) <= BCC(smb_buffer_response)) { if(tcon->nativeFileSystem) kfree(tcon->nativeFileSystem); diff -Nau fs/cifs/dir.c fs/cifs.new-mm/dir.c --- fs/cifs/dir.c 2004-08-14 00:37:15.000000000 -0500 +++ fs/cifs.new-mm/dir.c 2005-02-06 22:30:07.558009344 -0600 @@ -399,9 +399,6 @@ (" parent inode = 0x%p name is: %s and dentry = 0x%p", parent_dir_inode, direntry->d_name.name, direntry)); - if(nd) { /* BB removeme */ - cFYI(1,("In lookup nd flags 0x%x open intent flags 0x%x",nd->flags,nd->intent.open.flags)); - } /* BB removeme BB */ /* BB Add check of incoming data - e.g. frame not longer than maximum SMB - let server check the namelen BB */ /* check whether path exists */ diff -Nau fs/cifs/fcntl.c fs/cifs.new-mm/fcntl.c --- fs/cifs/fcntl.c 2004-08-14 00:37:29.000000000 -0500 +++ fs/cifs.new-mm/fcntl.c 2005-02-06 22:30:07.558009344 -0600 @@ -28,6 +28,44 @@ #include "cifs_unicode.h" #include "cifs_debug.h" +__u32 convert_to_cifs_notify_flags(unsigned long fcntl_notify_flags) +{ + __u32 cifs_ntfy_flags = 0; + + /* No way on Linux VFS to ask to monitor xattr + changes (and no stream support either */ + if(fcntl_notify_flags & DN_ACCESS) { + cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_LAST_ACCESS; + } + if(fcntl_notify_flags & DN_MODIFY) { + /* What does this mean on directories? */ + cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_LAST_WRITE | + FILE_NOTIFY_CHANGE_SIZE; + } + if(fcntl_notify_flags & DN_CREATE) { + cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_CREATION | + FILE_NOTIFY_CHANGE_LAST_WRITE; + } + if(fcntl_notify_flags & DN_DELETE) { + cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_LAST_WRITE; + } + if(fcntl_notify_flags & DN_RENAME) { + /* BB review this - checking various server behaviors */ + cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_DIR_NAME | + FILE_NOTIFY_CHANGE_FILE_NAME; + } + if(fcntl_notify_flags & DN_ATTRIB) { + cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_SECURITY | + FILE_NOTIFY_CHANGE_ATTRIBUTES; + } +/* if(fcntl_notify_flags & DN_MULTISHOT) { + cifs_ntfy_flags |= ; + } */ /* BB fixme - not sure how to handle this with CIFS yet */ + + + return cifs_ntfy_flags; +} + int cifs_dir_notify(struct file * file, unsigned long arg) { int xid; @@ -37,7 +75,7 @@ struct cifsTconInfo *pTcon; char *full_path = NULL; __u32 filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES; - __u16 netfid; + __u16 netfid; xid = GetXid(); cifs_sb = CIFS_SB(file->f_dentry->d_sb); @@ -50,20 +88,26 @@ if(full_path == NULL) { rc = -ENOMEM; } else { - cFYI(1,("cifs dir notify on file %s",full_path)); + cERROR(1,("cifs dir notify on file %s with arg 0x%lx",full_path,arg)); /* BB removeme BB */ rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ | SYNCHRONIZE, 0 /* create options */, &netfid, &oplock,NULL, cifs_sb->local_nls); /* BB fixme - add this handle to a notify handle list */ if(rc) { - cFYI(1,("Could not open directory for notify")); + cERROR(1,("Could not open directory for notify")); /* BB remove BB */ } else { - rc = CIFSSMBNotify(xid, pTcon, 1 /* subdirs */, netfid, - filter, cifs_sb->local_nls); + filter = convert_to_cifs_notify_flags(arg); + if(filter != 0) { + rc = CIFSSMBNotify(xid, pTcon, 0 /* no subdirs */, netfid, + filter, cifs_sb->local_nls); + } else { + rc = -EINVAL; + } /* BB add code to close file eventually (at unmount it would close automatically but may be a way to do it easily when inode freed or when notify info is cleared/changed */ + cERROR(1,("notify rc %d",rc)); } } diff -Nau fs/cifs/file.c fs/cifs.new-mm/file.c --- fs/cifs/file.c 2005-01-14 09:33:50.000000000 -0600 +++ fs/cifs.new-mm/file.c 2005-02-06 22:36:53.466301904 -0600 @@ -62,7 +62,7 @@ read_lock(&GlobalSMBSeslock); list_for_each(tmp, &pCifsInode->openFileList) { pCifsFile = list_entry(tmp,struct cifsFileInfo, flist); - if((pCifsFile->pfile == NULL)&& (pCifsFile->pid = current->pid)){ + if((pCifsFile->pfile == NULL)&& (pCifsFile->pid == current->tgid)){ /* mode set in cifs_create */ pCifsFile->pfile = file; /* needed for writepage */ file->private_data = pCifsFile; @@ -166,7 +166,7 @@ memset(file->private_data, 0, sizeof(struct cifsFileInfo)); pCifsFile = (struct cifsFileInfo *) file->private_data; pCifsFile->netfid = netfid; - pCifsFile->pid = current->pid; + pCifsFile->pid = current->tgid; init_MUTEX(&pCifsFile->fh_sem); pCifsFile->pfile = file; /* needed for writepage */ pCifsFile->pInode = inode; @@ -452,18 +452,44 @@ { int rc = 0; int xid; - struct cifsFileInfo *pSMBFileStruct = + struct cifsFileInfo *pCFileStruct = (struct cifsFileInfo *) file->private_data; + char * ptmp; cFYI(1, ("Closedir inode = 0x%p with ", inode)); xid = GetXid(); - if (pSMBFileStruct) { + if (pCFileStruct) { + struct cifsTconInfo *pTcon; + struct cifs_sb_info * cifs_sb = CIFS_SB(file->f_dentry->d_sb); + + pTcon = cifs_sb->tcon; + cFYI(1, ("Freeing private data in close dir")); + if(pCFileStruct->srch_inf.endOfSearch == FALSE) { + pCFileStruct->invalidHandle = TRUE; + rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid); + cFYI(1,("Closing uncompleted readdir with rc %d",rc)); + /* not much we can do if it fails anywway, ignore rc */ + rc = 0; + } + ptmp = pCFileStruct->srch_inf.ntwrk_buf_start; + if(ptmp) { + cFYI(1,("freeing smb buf in srch struct in closedir")); /* BB removeme BB */ + pCFileStruct->srch_inf.ntwrk_buf_start = NULL; + cifs_buf_release(ptmp); + } + ptmp = pCFileStruct->search_resume_name; + if(ptmp) { + cFYI(1,("freeing resume name in closedir")); /* BB removeme BB */ + pCFileStruct->search_resume_name = NULL; + kfree(ptmp); + } kfree(file->private_data); file->private_data = NULL; } + /* BB can we lock the filestruct while this is going on? */ FreeXid(xid); return rc; } @@ -570,12 +596,131 @@ pfLock->fl_start, numUnlock, numLock, lockType, wait_flag); if (rc == 0 && (pfLock->fl_flags & FL_POSIX)) - posix_lock_file(file, pfLock); + posix_lock_file_wait(file, pfLock); FreeXid(xid); return rc; } ssize_t +cifs_user_write(struct file * file, const char __user * write_data, + size_t write_size, loff_t * poffset) +{ + int rc = 0; + unsigned int bytes_written = 0; + unsigned int total_written; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + int xid, long_op; + struct cifsFileInfo * open_file; + + if(file->f_dentry == NULL) + return -EBADF; + + cifs_sb = CIFS_SB(file->f_dentry->d_sb); + if(cifs_sb == NULL) { + return -EBADF; + } + pTcon = cifs_sb->tcon; + + /*cFYI(1, + (" write %d bytes to offset %lld of %s", write_size, + *poffset, file->f_dentry->d_name.name)); */ + + if (file->private_data == NULL) { + return -EBADF; + } else { + open_file = (struct cifsFileInfo *) file->private_data; + } + + xid = GetXid(); + if(file->f_dentry->d_inode == NULL) { + FreeXid(xid); + return -EBADF; + } + + if (*poffset > file->f_dentry->d_inode->i_size) + long_op = 2; /* writes past end of file can take a long time */ + else + long_op = 1; + + for (total_written = 0; write_size > total_written; + total_written += bytes_written) { + rc = -EAGAIN; + while(rc == -EAGAIN) { + if(file->private_data == NULL) { + /* file has been closed on us */ + FreeXid(xid); + /* if we have gotten here we have written some data + and blocked, and the file has been freed on us + while we blocked so return what we managed to write */ + return total_written; + } + if(open_file->closePend) { + FreeXid(xid); + if(total_written) + return total_written; + else + return -EBADF; + } + if (open_file->invalidHandle) { + if((file->f_dentry == NULL) || + (file->f_dentry->d_inode == NULL)) { + FreeXid(xid); + return total_written; + } + /* we could deadlock if we called + filemap_fdatawait from here so tell + reopen_file not to flush data to server now */ + rc = cifs_reopen_file(file->f_dentry->d_inode, + file,FALSE); + if(rc != 0) + break; + } + + rc = CIFSSMBWrite(xid, pTcon, + open_file->netfid, + min_t(const int,cifs_sb->wsize,write_size - total_written), + *poffset, &bytes_written, + NULL, write_data + total_written, long_op); + } + if (rc || (bytes_written == 0)) { + if (total_written) + break; + else { + FreeXid(xid); + return rc; + } + } else + *poffset += bytes_written; + long_op = FALSE; /* subsequent writes fast - 15 seconds is plenty */ + } + +#ifdef CONFIG_CIFS_STATS + if(total_written > 0) { + atomic_inc(&pTcon->num_writes); + spin_lock(&pTcon->stat_lock); + pTcon->bytes_written += total_written; + spin_unlock(&pTcon->stat_lock); + } +#endif + + /* since the write may have blocked check these pointers again */ + if(file->f_dentry) { + if(file->f_dentry->d_inode) { + struct inode *inode = file->f_dentry->d_inode; + inode->i_ctime = inode->i_mtime = CURRENT_TIME; + if (total_written > 0) { + if (*poffset > file->f_dentry->d_inode->i_size) + i_size_write(file->f_dentry->d_inode, *poffset); + } + mark_inode_dirty_sync(file->f_dentry->d_inode); + } + } + FreeXid(xid); + return total_written; +} + +static ssize_t cifs_write(struct file * file, const char *write_data, size_t write_size, loff_t * poffset) { @@ -652,10 +797,10 @@ } rc = CIFSSMBWrite(xid, pTcon, - open_file->netfid, - write_size - total_written, *poffset, - &bytes_written, - write_data + total_written, long_op); + open_file->netfid, + min_t(const int,cifs_sb->wsize,write_size - total_written), + *poffset,&bytes_written, + write_data + total_written, NULL, long_op); } if (rc || (bytes_written == 0)) { if (total_written) @@ -797,7 +942,11 @@ int xid; xid = GetXid(); -/* call 16K write then Setpageuptodate */ + + /* Find contiguous pages then iterate through repeating */ +/* call 16K write then Setpageuptodate or if LARGE_WRITE_X +support then send larger writes via kevec so as to eliminate +a memcpy */ FreeXid(xid); return rc; } @@ -969,6 +1118,86 @@ ssize_t +cifs_user_read(struct file * file, char __user *read_data, size_t read_size, + loff_t * poffset) +{ + int rc = -EACCES; + unsigned int bytes_read = 0; + unsigned int total_read = 0; + unsigned int current_read_size; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + int xid; + struct cifsFileInfo * open_file; + char * smb_read_data; + char __user * current_offset; + struct smb_com_read_rsp * pSMBr; + + xid = GetXid(); + cifs_sb = CIFS_SB(file->f_dentry->d_sb); + pTcon = cifs_sb->tcon; + + if (file->private_data == NULL) { + FreeXid(xid); + return -EBADF; + } + open_file = (struct cifsFileInfo *)file->private_data; + + if((file->f_flags & O_ACCMODE) == O_WRONLY) { + cFYI(1,("attempting read on write only file instance")); + } + for (total_read = 0,current_offset=read_data; read_size > total_read; + total_read += bytes_read,current_offset+=bytes_read) { + current_read_size = min_t(const int,read_size - total_read,cifs_sb->rsize); + rc = -EAGAIN; + smb_read_data = NULL; + while(rc == -EAGAIN) { + if ((open_file->invalidHandle) && (!open_file->closePend)) { + rc = cifs_reopen_file(file->f_dentry->d_inode, + file,TRUE); + if(rc != 0) + break; + } + + rc = CIFSSMBRead(xid, pTcon, + open_file->netfid, + current_read_size, *poffset, + &bytes_read, &smb_read_data); + + pSMBr = (struct smb_com_read_rsp *)smb_read_data; + if(copy_to_user(current_offset,smb_read_data + 4/* RFC1001 hdr*/ + + le16_to_cpu(pSMBr->DataOffset), bytes_read)) { + rc = -EFAULT; + FreeXid(xid); + return rc; + } + if(smb_read_data) { + cifs_buf_release(smb_read_data); + smb_read_data = NULL; + } + } + if (rc || (bytes_read == 0)) { + if (total_read) { + break; + } else { + FreeXid(xid); + return rc; + } + } else { +#ifdef CONFIG_CIFS_STATS + atomic_inc(&pTcon->num_reads); + spin_lock(&pTcon->stat_lock); + pTcon->bytes_read += total_read; + spin_unlock(&pTcon->stat_lock); +#endif + *poffset += bytes_read; + } + } + FreeXid(xid); + return total_read; +} + +static ssize_t cifs_read(struct file * file, char *read_data, size_t read_size, loff_t * poffset) { @@ -1039,6 +1268,17 @@ struct dentry * dentry = file->f_dentry; int rc, xid; +#ifdef CIFS_EXPERIMENTAL /* BB fixme reenable when cifs_read_wrapper fixed */ + if(dentry->d_sb) { + struct cifs_sb_info *cifs_sb; + cifs_sb = CIFS_SB(sb); + if(cifs_sb != NULL) { + if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) + return -ENODEV + } + } +#endif /* CIFS_EXPERIMENTAL */ + xid = GetXid(); rc = cifs_revalidate(dentry); if (rc) { @@ -1199,8 +1439,6 @@ spin_unlock(&pTcon->stat_lock); #endif if((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) { - cFYI(1,("Partial page %d of %d read to cache",i++,num_pages)); - i++; /* account for partial page */ /* server copy of file can have smaller size than client */ @@ -1348,12 +1586,11 @@ { struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); + __u32 attr = le32_to_cpu(pfindData->ExtFileAttributes); + __u64 allocation_size = le64_to_cpu(pfindData->AllocationSize); + __u64 end_of_file = le64_to_cpu(pfindData->EndOfFile); - pfindData->ExtFileAttributes = - le32_to_cpu(pfindData->ExtFileAttributes); - pfindData->AllocationSize = le64_to_cpu(pfindData->AllocationSize); - pfindData->EndOfFile = le64_to_cpu(pfindData->EndOfFile); - cifsInfo->cifsAttrs = pfindData->ExtFileAttributes; + cifsInfo->cifsAttrs = attr; cifsInfo->time = jiffies; /* Linux can not store file creation time unfortunately so ignore it */ @@ -1376,24 +1613,23 @@ cFYI(0, ("CIFS FFIRST: Attributes came in as 0x%x", - pfindData->ExtFileAttributes)); - if (pfindData->ExtFileAttributes & ATTR_REPARSE) { - *pobject_type = DT_LNK; - /* BB can this and S_IFREG or S_IFDIR be set as in Windows? */ - tmp_inode->i_mode |= S_IFLNK; - } else if (pfindData->ExtFileAttributes & ATTR_DIRECTORY) { + attr)); + if (attr & ATTR_DIRECTORY) { *pobject_type = DT_DIR; /* override default perms since we do not lock dirs */ if(atomic_read(&cifsInfo->inUse) == 0) { tmp_inode->i_mode = cifs_sb->mnt_dir_mode; } tmp_inode->i_mode |= S_IFDIR; +/* we no longer mark these because we could not follow them */ +/* } else if (attr & ATTR_REPARSE) { + *pobject_type = DT_LNK; + tmp_inode->i_mode |= S_IFLNK;*/ } else { *pobject_type = DT_REG; tmp_inode->i_mode |= S_IFREG; - if(pfindData->ExtFileAttributes & ATTR_READONLY) + if(attr & ATTR_READONLY) tmp_inode->i_mode &= ~(S_IWUGO); - }/* could add code here - to validate if device or weird share type? */ /* can not fill in nlink here as in qpathinfo version and Unx search */ @@ -1404,14 +1640,14 @@ if(is_size_safe_to_change(cifsInfo)) { /* can not safely change the file size here if the client is writing to it due to potential races */ - i_size_write(tmp_inode,pfindData->EndOfFile); + i_size_write(tmp_inode,end_of_file); /* 512 bytes (2**9) is the fake blocksize that must be used */ /* for this calculation, even though the reported blocksize is larger */ - tmp_inode->i_blocks = (512 - 1 + pfindData->AllocationSize) >> 9; + tmp_inode->i_blocks = (512 - 1 + allocation_size) >> 9; } - if (pfindData->AllocationSize < pfindData->EndOfFile) + if (allocation_size < end_of_file) cFYI(1, ("Possible sparse file: allocation size less than end of file ")); cFYI(1, ("File Size %ld and blocks %ld and blocksize %ld", @@ -1441,6 +1677,9 @@ FILE_UNIX_INFO * pfindData, int *pobject_type) { struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); + __u32 type = le32_to_cpu(pfindData->Type); + __u64 num_of_bytes = le64_to_cpu(pfindData->NumOfBytes); + __u64 end_of_file = le64_to_cpu(pfindData->EndOfFile); cifsInfo->time = jiffies; atomic_inc(&cifsInfo->inUse); @@ -1452,30 +1691,29 @@ cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastStatusChange)); tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions); - pfindData->Type = le32_to_cpu(pfindData->Type); - if (pfindData->Type == UNIX_FILE) { + if (type == UNIX_FILE) { *pobject_type = DT_REG; tmp_inode->i_mode |= S_IFREG; - } else if (pfindData->Type == UNIX_SYMLINK) { + } else if (type == UNIX_SYMLINK) { *pobject_type = DT_LNK; tmp_inode->i_mode |= S_IFLNK; - } else if (pfindData->Type == UNIX_DIR) { + } else if (type == UNIX_DIR) { *pobject_type = DT_DIR; tmp_inode->i_mode |= S_IFDIR; - } else if (pfindData->Type == UNIX_CHARDEV) { + } else if (type == UNIX_CHARDEV) { *pobject_type = DT_CHR; tmp_inode->i_mode |= S_IFCHR; tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor), le64_to_cpu(pfindData->DevMinor) & MINORMASK); - } else if (pfindData->Type == UNIX_BLOCKDEV) { + } else if (type == UNIX_BLOCKDEV) { *pobject_type = DT_BLK; tmp_inode->i_mode |= S_IFBLK; tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor), le64_to_cpu(pfindData->DevMinor) & MINORMASK); - } else if (pfindData->Type == UNIX_FIFO) { + } else if (type == UNIX_FIFO) { *pobject_type = DT_FIFO; tmp_inode->i_mode |= S_IFIFO; - } else if (pfindData->Type == UNIX_SOCKET) { + } else if (type == UNIX_SOCKET) { *pobject_type = DT_SOCK; tmp_inode->i_mode |= S_IFSOCK; } @@ -1484,17 +1722,15 @@ tmp_inode->i_gid = le64_to_cpu(pfindData->Gid); tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks); - pfindData->NumOfBytes = le64_to_cpu(pfindData->NumOfBytes); if(is_size_safe_to_change(cifsInfo)) { /* can not safely change the file size here if the client is writing to it due to potential races */ - pfindData->EndOfFile = le64_to_cpu(pfindData->EndOfFile); - i_size_write(tmp_inode,pfindData->EndOfFile); + i_size_write(tmp_inode,end_of_file); /* 512 bytes (2**9) is the fake blocksize that must be used */ /* for this calculation, not the real blocksize */ - tmp_inode->i_blocks = (512 - 1 + pfindData->NumOfBytes) >> 9; + tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9; } if (S_ISREG(tmp_inode->i_mode)) { @@ -1517,13 +1753,16 @@ } } -static void +/* Returns one if new inode created (which therefore needs to be hashed) */ +/* Might check in the future if inode number changed so we can rehash inode */ +int construct_dentry(struct qstr *qstring, struct file *file, struct inode **ptmp_inode, struct dentry **pnew_dentry) { struct dentry *tmp_dentry; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; + int rc = 0; cFYI(1, ("For %s ", qstring->name)); cifs_sb = CIFS_SB(file->f_dentry->d_sb); @@ -1538,601 +1777,32 @@ if(*ptmp_inode == NULL) { *ptmp_inode = new_inode(file->f_dentry->d_sb); if(*ptmp_inode == NULL) - return; + return rc; + rc = 1; d_instantiate(tmp_dentry, *ptmp_inode); - insert_inode_hash(*ptmp_inode); } } else { tmp_dentry = d_alloc(file->f_dentry, qstring); if(tmp_dentry == NULL) { cERROR(1,("Failed allocating dentry")); *ptmp_inode = NULL; - return; + return rc; } *ptmp_inode = new_inode(file->f_dentry->d_sb); tmp_dentry->d_op = &cifs_dentry_ops; if(*ptmp_inode == NULL) - return; + return rc; + rc = 1; d_instantiate(tmp_dentry, *ptmp_inode); d_rehash(tmp_dentry); - insert_inode_hash(*ptmp_inode); } tmp_dentry->d_time = jiffies; *pnew_dentry = tmp_dentry; + return rc; } -static void reset_resume_key(struct file * dir_file, - unsigned char * filename, - unsigned int len,int Unicode,struct nls_table * nls_tab) { - struct cifsFileInfo *cifsFile; - - cifsFile = (struct cifsFileInfo *)dir_file->private_data; - if(cifsFile == NULL) - return; - if(cifsFile->search_resume_name) { - kfree(cifsFile->search_resume_name); - } - - if(Unicode) - len *= 2; - cifsFile->resume_name_length = len; - - cifsFile->search_resume_name = - kmalloc(cifsFile->resume_name_length, GFP_KERNEL); - - if(cifsFile->search_resume_name == NULL) { - cERROR(1,("failed new resume key allocate, length %d", - cifsFile->resume_name_length)); - return; - } - if(Unicode) - cifs_strtoUCS((wchar_t *) cifsFile->search_resume_name, - filename, len, nls_tab); - else - memcpy(cifsFile->search_resume_name, filename, - cifsFile->resume_name_length); - cFYI(1,("Reset resume key to: %s with len %d",filename,len)); - return; -} - - - -static int -cifs_filldir(struct qstr *pqstring, FILE_DIRECTORY_INFO * pfindData, - struct file *file, filldir_t filldir, void *direntry) -{ - struct inode *tmp_inode; - struct dentry *tmp_dentry; - int object_type,rc; - - pqstring->name = pfindData->FileName; - pqstring->len = pfindData->FileNameLength; - - construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry); - if((tmp_inode == NULL) || (tmp_dentry == NULL)) { - return -ENOMEM; - } - fill_in_inode(tmp_inode, pfindData, &object_type); - rc = filldir(direntry, pfindData->FileName, pqstring->len, file->f_pos, - tmp_inode->i_ino, object_type); - if(rc) { - /* due to readdir error we need to recalculate resume - key so next readdir will restart on right entry */ - cFYI(1,("Error %d on filldir of %s",rc ,pfindData->FileName)); - } - dput(tmp_dentry); - return rc; -} - -static int -cifs_filldir_unix(struct qstr *pqstring, - FILE_UNIX_INFO * pUnixFindData, struct file *file, - filldir_t filldir, void *direntry) -{ - struct inode *tmp_inode; - struct dentry *tmp_dentry; - int object_type, rc; - - pqstring->name = pUnixFindData->FileName; - pqstring->len = strnlen(pUnixFindData->FileName, MAX_PATHCONF); - - construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry); - if((tmp_inode == NULL) || (tmp_dentry == NULL)) { - return -ENOMEM; - } - - unix_fill_in_inode(tmp_inode, pUnixFindData, &object_type); - rc = filldir(direntry, pUnixFindData->FileName, pqstring->len, - file->f_pos, tmp_inode->i_ino, object_type); - if(rc) { - /* due to readdir error we need to recalculate resume - key so next readdir will restart on right entry */ - cFYI(1,("Error %d on filldir of %s",rc ,pUnixFindData->FileName)); - } - dput(tmp_dentry); - return rc; -} - -int -cifs_readdir(struct file *file, void *direntry, filldir_t filldir) -{ - int rc = 0; - int xid; - int Unicode = FALSE; - int UnixSearch = FALSE; - unsigned int bufsize, i; - __u16 searchHandle; - struct cifs_sb_info *cifs_sb; - struct cifsTconInfo *pTcon; - struct cifsFileInfo *cifsFile = NULL; - char *full_path = NULL; - char *data; - struct qstr qstring; - T2_FFIRST_RSP_PARMS findParms; - T2_FNEXT_RSP_PARMS findNextParms; - FILE_DIRECTORY_INFO *pfindData; - FILE_DIRECTORY_INFO *lastFindData; - FILE_UNIX_INFO *pfindDataUnix; - - xid = GetXid(); - - cifs_sb = CIFS_SB(file->f_dentry->d_sb); - pTcon = cifs_sb->tcon; - bufsize = pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; - if(bufsize > CIFS_MAX_MSGSIZE) { - FreeXid(xid); - return -EIO; - } - data = kmalloc(bufsize, GFP_KERNEL); - pfindData = (FILE_DIRECTORY_INFO *) data; - if(data == NULL) { - FreeXid(xid); - return -ENOMEM; - } - if(file->f_dentry == NULL) { - kfree(data); - FreeXid(xid); - return -EIO; - } - down(&file->f_dentry->d_sb->s_vfs_rename_sem); - full_path = build_wildcard_path_from_dentry(file->f_dentry); - up(&file->f_dentry->d_sb->s_vfs_rename_sem); - - if(full_path == NULL) { - kfree(data); - FreeXid(xid); - return -ENOMEM; - } - cFYI(1, ("Full path: %s start at: %lld ", full_path, file->f_pos)); - - switch ((int) file->f_pos) { - case 0: - if (filldir(direntry, ".", 1, file->f_pos, - file->f_dentry->d_inode->i_ino, DT_DIR) < 0) { - cERROR(1, ("Filldir for current dir failed ")); - break; - } - file->f_pos++; - /* fallthrough */ - case 1: - if (filldir(direntry, "..", 2, file->f_pos, - file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) { - cERROR(1, ("Filldir for parent dir failed ")); - break; - } - file->f_pos++; - /* fallthrough */ - case 2: - if (file->private_data != NULL) { - cifsFile = - (struct cifsFileInfo *) file->private_data; - if (cifsFile->endOfSearch) { - if(cifsFile->emptyDir) { - cFYI(1, ("End of search, empty dir")); - rc = 0; - break; - } - } else { - cifsFile->invalidHandle = TRUE; - CIFSFindClose(xid, pTcon, cifsFile->netfid); - } - if(cifsFile->search_resume_name) { - kfree(cifsFile->search_resume_name); - cifsFile->search_resume_name = NULL; - } - } - rc = CIFSFindFirst(xid, pTcon, full_path, pfindData, - &findParms, cifs_sb->local_nls, - &Unicode, &UnixSearch); - cFYI(1, ("Count: %d End: %d ", findParms.SearchCount, - findParms.EndofSearch)); - - if (rc == 0) { - searchHandle = findParms.SearchHandle; - if(file->private_data == NULL) - file->private_data = - kmalloc(sizeof(struct cifsFileInfo),GFP_KERNEL); - if (file->private_data) { - memset(file->private_data, 0, - sizeof (struct cifsFileInfo)); - cifsFile = - (struct cifsFileInfo *) file->private_data; - cifsFile->netfid = searchHandle; - cifsFile->invalidHandle = FALSE; - init_MUTEX(&cifsFile->fh_sem); - } else { - rc = -ENOMEM; - break; - } - - renew_parental_timestamps(file->f_dentry); - lastFindData = - (FILE_DIRECTORY_INFO *) ((char *) pfindData + - findParms.LastNameOffset); - if((char *)lastFindData > (char *)pfindData + bufsize) { - cFYI(1,("last search entry past end of packet")); - rc = -EIO; - break; - } - /* Offset of resume key same for levels 257 and 514 */ - cifsFile->resume_key = lastFindData->FileIndex; - if(UnixSearch == FALSE) { - cifsFile->resume_name_length = - le32_to_cpu(lastFindData->FileNameLength); - if(cifsFile->resume_name_length > bufsize - 64) { - cFYI(1,("Illegal resume file name length %d", - cifsFile->resume_name_length)); - rc = -ENOMEM; - break; - } - cifsFile->search_resume_name = - kmalloc(cifsFile->resume_name_length, GFP_KERNEL); - cFYI(1,("Last file: %s with name %d bytes long", - lastFindData->FileName, - cifsFile->resume_name_length)); - if(cifsFile->search_resume_name == NULL) { - rc = -ENOMEM; - break; - } - memcpy(cifsFile->search_resume_name, - lastFindData->FileName, - cifsFile->resume_name_length); - } else { - pfindDataUnix = (FILE_UNIX_INFO *)lastFindData; - if (Unicode == TRUE) { - for(i=0;(pfindDataUnix->FileName[i] - | pfindDataUnix->FileName[i+1]); - i+=2) { - if(i > bufsize-64) - break; - } - cifsFile->resume_name_length = i + 2; - } else { - cifsFile->resume_name_length = - strnlen(pfindDataUnix->FileName, - bufsize-63); - } - if(cifsFile->resume_name_length > bufsize - 64) { - cFYI(1,("Illegal resume file name length %d", - cifsFile->resume_name_length)); - rc = -ENOMEM; - break; - } - cifsFile->search_resume_name = - kmalloc(cifsFile->resume_name_length, GFP_KERNEL); - cFYI(1,("Last file: %s with name %d bytes long", - pfindDataUnix->FileName, - cifsFile->resume_name_length)); - if(cifsFile->search_resume_name == NULL) { - rc = -ENOMEM; - break; - } - memcpy(cifsFile->search_resume_name, - pfindDataUnix->FileName, - cifsFile->resume_name_length); - } - for (i = 2; i < (unsigned int)findParms.SearchCount + 2; i++) { - if (UnixSearch == FALSE) { - pfindData->FileNameLength = - le32_to_cpu(pfindData->FileNameLength); - if (Unicode == TRUE) - pfindData->FileNameLength = - cifs_strfromUCS_le - (pfindData->FileName, - (wchar_t *) - pfindData->FileName, - (pfindData-> - FileNameLength) / 2, - cifs_sb->local_nls); - qstring.len = pfindData->FileNameLength; - if (((qstring.len != 1) - || (pfindData->FileName[0] != '.')) - && ((qstring.len != 2) - || (pfindData-> - FileName[0] != '.') - || (pfindData-> - FileName[1] != '.'))) { - if(cifs_filldir(&qstring, - pfindData, - file, filldir, - direntry)) { - /* do not end search if - kernel not ready to take - remaining entries yet */ - reset_resume_key(file, pfindData->FileName,qstring.len, - Unicode, cifs_sb->local_nls); - findParms.EndofSearch = 0; - break; - } - file->f_pos++; - } - } else { /* UnixSearch */ - pfindDataUnix = - (FILE_UNIX_INFO *) pfindData; - if (Unicode == TRUE) - qstring.len = - cifs_strfromUCS_le - (pfindDataUnix->FileName, - (wchar_t *) - pfindDataUnix->FileName, - MAX_PATHCONF, - cifs_sb->local_nls); - else - qstring.len = - strnlen(pfindDataUnix-> - FileName, - MAX_PATHCONF); - if (((qstring.len != 1) - || (pfindDataUnix-> - FileName[0] != '.')) - && ((qstring.len != 2) - || (pfindDataUnix-> - FileName[0] != '.') - || (pfindDataUnix-> - FileName[1] != '.'))) { - if(cifs_filldir_unix(&qstring, - pfindDataUnix, - file, - filldir, - direntry)) { - /* do not end search if - kernel not ready to take - remaining entries yet */ - findParms.EndofSearch = 0; - reset_resume_key(file, pfindDataUnix->FileName, - qstring.len,Unicode,cifs_sb->local_nls); - break; - } - file->f_pos++; - } - } - /* works also for Unix ff struct since first field of both */ - pfindData = - (FILE_DIRECTORY_INFO *) ((char *) pfindData - + le32_to_cpu(pfindData->NextEntryOffset)); - /* BB also should check to make sure that pointer is not beyond the end of the SMB */ - /* if(pfindData > lastFindData) rc = -EIO; break; */ - } /* end for loop */ - if ((findParms.EndofSearch != 0) && cifsFile) { - cifsFile->endOfSearch = TRUE; - if(findParms.SearchCount == 2) - cifsFile->emptyDir = TRUE; - } - } else { - if (cifsFile) - cifsFile->endOfSearch = TRUE; - /* unless parent directory gone do not return error */ - rc = 0; - } - break; - default: - if (file->private_data == NULL) { - rc = -EBADF; - cFYI(1, - ("Readdir on closed srch, pos = %lld", - file->f_pos)); - } else { - cifsFile = (struct cifsFileInfo *) file->private_data; - if (cifsFile->endOfSearch) { - rc = 0; - cFYI(1, ("End of search ")); - break; - } - searchHandle = cifsFile->netfid; - rc = CIFSFindNext(xid, pTcon, pfindData, - &findNextParms, searchHandle, - cifsFile->search_resume_name, - cifsFile->resume_name_length, - cifsFile->resume_key, - &Unicode, &UnixSearch); - cFYI(1,("Count: %d End: %d ", - findNextParms.SearchCount, - findNextParms.EndofSearch)); - if ((rc == 0) && (findNextParms.SearchCount != 0)) { - /* BB save off resume key, key name and name length */ - lastFindData = - (FILE_DIRECTORY_INFO *) ((char *) pfindData - + findNextParms.LastNameOffset); - if((char *)lastFindData > (char *)pfindData + bufsize) { - cFYI(1,("last search entry past end of packet")); - rc = -EIO; - break; - } - /* Offset of resume key same for levels 257 and 514 */ - cifsFile->resume_key = lastFindData->FileIndex; - - if(UnixSearch == FALSE) { - cifsFile->resume_name_length = - le32_to_cpu(lastFindData->FileNameLength); - if(cifsFile->resume_name_length > bufsize - 64) { - cFYI(1,("Illegal resume file name length %d", - cifsFile->resume_name_length)); - rc = -ENOMEM; - break; - } - /* Free the memory allocated by previous findfirst - or findnext call - we can not reuse the memory since - the resume name may not be same string length */ - if(cifsFile->search_resume_name) - kfree(cifsFile->search_resume_name); - cifsFile->search_resume_name = - kmalloc(cifsFile->resume_name_length, GFP_KERNEL); - cFYI(1,("Last file: %s with name %d bytes long", - lastFindData->FileName, - cifsFile->resume_name_length)); - if(cifsFile->search_resume_name == NULL) { - rc = -ENOMEM; - break; - } - - memcpy(cifsFile->search_resume_name, - lastFindData->FileName, - cifsFile->resume_name_length); - } else { - pfindDataUnix = (FILE_UNIX_INFO *)lastFindData; - if (Unicode == TRUE) { - for(i=0;(pfindDataUnix->FileName[i] - | pfindDataUnix->FileName[i+1]); - i+=2) { - if(i > bufsize-64) - break; - } - cifsFile->resume_name_length = i + 2; - } else { - cifsFile->resume_name_length = - strnlen(pfindDataUnix-> - FileName, - MAX_PATHCONF); - } - if(cifsFile->resume_name_length > bufsize - 64) { - cFYI(1,("Illegal resume file name length %d", - cifsFile->resume_name_length)); - rc = -ENOMEM; - break; - } - /* Free the memory allocated by previous findfirst - or findnext call - we can not reuse the memory since - the resume name may not be same string length */ - if(cifsFile->search_resume_name) - kfree(cifsFile->search_resume_name); - cifsFile->search_resume_name = - kmalloc(cifsFile->resume_name_length, GFP_KERNEL); - cFYI(1,("fnext last file: %s with name %d bytes long", - pfindDataUnix->FileName, - cifsFile->resume_name_length)); - if(cifsFile->search_resume_name == NULL) { - rc = -ENOMEM; - break; - } - memcpy(cifsFile->search_resume_name, - pfindDataUnix->FileName, - cifsFile->resume_name_length); - } - - for (i = 0; i < findNextParms.SearchCount; i++) { - pfindData->FileNameLength = - le32_to_cpu(pfindData-> - FileNameLength); - if (UnixSearch == FALSE) { - if (Unicode == TRUE) - pfindData->FileNameLength = - cifs_strfromUCS_le - (pfindData->FileName, - (wchar_t *) - pfindData->FileName, - (pfindData->FileNameLength)/ 2, - cifs_sb->local_nls); - qstring.len = - pfindData->FileNameLength; - if (((qstring.len != 1) - || (pfindData->FileName[0] != '.')) - && ((qstring.len != 2) - || (pfindData->FileName[0] != '.') - || (pfindData->FileName[1] != - '.'))) { - if(cifs_filldir - (&qstring, - pfindData, - file, filldir, - direntry)) { - /* do not end search if - kernel not ready to take - remaining entries yet */ - findNextParms.EndofSearch = 0; - reset_resume_key(file, pfindData->FileName,qstring.len, - Unicode,cifs_sb->local_nls); - break; - } - file->f_pos++; - } - } else { /* UnixSearch */ - pfindDataUnix = - (FILE_UNIX_INFO *) - pfindData; - if (Unicode == TRUE) - qstring.len = - cifs_strfromUCS_le - (pfindDataUnix->FileName, - (wchar_t *) - pfindDataUnix->FileName, - MAX_PATHCONF, - cifs_sb->local_nls); - else - qstring.len = - strnlen - (pfindDataUnix-> - FileName, - MAX_PATHCONF); - if (((qstring.len != 1) - || (pfindDataUnix-> - FileName[0] != '.')) - && ((qstring.len != 2) - || (pfindDataUnix-> - FileName[0] != '.') - || (pfindDataUnix-> - FileName[1] != - '.'))) { - if(cifs_filldir_unix - (&qstring, - pfindDataUnix, - file, filldir, - direntry)) { - /* do not end search if - kernel not ready to take - remaining entries yet */ - findNextParms.EndofSearch = 0; - reset_resume_key(file, pfindDataUnix->FileName,qstring.len, - Unicode,cifs_sb->local_nls); - break; - } - file->f_pos++; - } - } - pfindData = (FILE_DIRECTORY_INFO *) ((char *) pfindData + - le32_to_cpu(pfindData->NextEntryOffset)); - /* works also for Unix find struct since first field of both */ - /* BB also should check to ensure pointer not beyond end of SMB */ - } /* end for loop */ - if (findNextParms.EndofSearch != 0) { - cifsFile->endOfSearch = TRUE; - } - } else { - cifsFile->endOfSearch = TRUE; - rc = 0; /* unless parent directory disappeared - do not - return error here (eg Access Denied or no more files) */ - } - } - } /* end switch */ - if (data) - kfree(data); - if (full_path) - kfree(full_path); - FreeXid(xid); - - return rc; -} int cifs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) { diff -Nau fs/cifs/inode.c fs/cifs.new-mm/inode.c --- fs/cifs/inode.c 2005-01-14 09:33:50.000000000 -0600 +++ fs/cifs.new-mm/inode.c 2005-02-06 22:37:55.475875016 -0600 @@ -76,12 +76,22 @@ } else { struct cifsInodeInfo *cifsInfo; + __u32 type = le32_to_cpu(findData.Type); + __u64 num_of_bytes = le64_to_cpu(findData.NumOfBytes); + __u64 end_of_file = le64_to_cpu(findData.EndOfFile); /* get new inode */ if (*pinode == NULL) { *pinode = new_inode(sb); if(*pinode == NULL) return -ENOMEM; + /* Is an i_ino of zero legal? */ + /* Are there sanity checks we can use to ensure that + the server is really filling in that field? */ + if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { + (*pinode)->i_ino = + (unsigned long)findData.UniqueId; + } /* note ino incremented to unique num in new_inode */ insert_inode_hash(*pinode); } @@ -101,37 +111,34 @@ inode->i_ctime = cifs_NTtimeToUnix(le64_to_cpu(findData.LastStatusChange)); inode->i_mode = le64_to_cpu(findData.Permissions); - findData.Type = le32_to_cpu(findData.Type); - if (findData.Type == UNIX_FILE) { + if (type == UNIX_FILE) { inode->i_mode |= S_IFREG; - } else if (findData.Type == UNIX_SYMLINK) { + } else if (type == UNIX_SYMLINK) { inode->i_mode |= S_IFLNK; - } else if (findData.Type == UNIX_DIR) { + } else if (type == UNIX_DIR) { inode->i_mode |= S_IFDIR; - } else if (findData.Type == UNIX_CHARDEV) { + } else if (type == UNIX_CHARDEV) { inode->i_mode |= S_IFCHR; inode->i_rdev = MKDEV(le64_to_cpu(findData.DevMajor), le64_to_cpu(findData.DevMinor) & MINORMASK); - } else if (findData.Type == UNIX_BLOCKDEV) { + } else if (type == UNIX_BLOCKDEV) { inode->i_mode |= S_IFBLK; inode->i_rdev = MKDEV(le64_to_cpu(findData.DevMajor), le64_to_cpu(findData.DevMinor) & MINORMASK); - } else if (findData.Type == UNIX_FIFO) { + } else if (type == UNIX_FIFO) { inode->i_mode |= S_IFIFO; - } else if (findData.Type == UNIX_SOCKET) { + } else if (type == UNIX_SOCKET) { inode->i_mode |= S_IFSOCK; } inode->i_uid = le64_to_cpu(findData.Uid); inode->i_gid = le64_to_cpu(findData.Gid); inode->i_nlink = le64_to_cpu(findData.Nlinks); - findData.NumOfBytes = le64_to_cpu(findData.NumOfBytes); - findData.EndOfFile = le64_to_cpu(findData.EndOfFile); if(is_size_safe_to_change(cifsInfo)) { /* can not safely change the file size here if the client is writing to it due to potential races */ - i_size_write(inode,findData.EndOfFile); + i_size_write(inode, end_of_file); /* blksize needs to be multiple of two. So safer to default to blksize and blkbits set in superblock so 2**blkbits and blksize will match */ /* inode->i_blksize = @@ -143,14 +150,14 @@ /* inode->i_blocks = - (inode->i_blksize - 1 + findData.NumOfBytes) >> inode->i_blkbits;*/ + (inode->i_blksize - 1 + num_of_bytes) >> inode->i_blkbits;*/ /* 512 bytes (2**9) is the fake blocksize that must be used */ /* for this calculation */ - inode->i_blocks = (512 - 1 + findData.NumOfBytes) >> 9; + inode->i_blocks = (512 - 1 + num_of_bytes) >> 9; } - if (findData.NumOfBytes < findData.EndOfFile) + if (num_of_bytes < end_of_file) cFYI(1, ("Server inconsistency Error: it says allocation size less than end of file ")); cFYI(1, ("Size %ld and blocks %ld ", @@ -237,18 +244,33 @@ } } else { struct cifsInodeInfo *cifsInfo; + __u32 attr = le32_to_cpu(pfindData->Attributes); /* get new inode */ if (*pinode == NULL) { *pinode = new_inode(sb); if(*pinode == NULL) return -ENOMEM; + /* Is an i_ino of zero legal? */ + /* Are there sanity checks we can use to ensure that + the server is really filling in that field? */ + + /* We can not use the IndexNumber from either + Windows or Samba as it is frequently set to zero */ + /* There may be higher info levels that work but + Are there Windows server or network appliances + for which IndexNumber field is not guaranteed unique? */ + + /* if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { + (*pinode)->i_ino = + (unsigned long)pfindData->IndexNumber; + } */ /*NB: ino incremented to unique num in new_inode*/ + insert_inode_hash(*pinode); } inode = *pinode; cifsInfo = CIFS_I(inode); - pfindData->Attributes = le32_to_cpu(pfindData->Attributes); - cifsInfo->cifsAttrs = pfindData->Attributes; + cifsInfo->cifsAttrs = attr; cFYI(1, (" Old time %ld ", cifsInfo->time)); cifsInfo->time = jiffies; cFYI(1, (" New time %ld ", cifsInfo->time)); @@ -266,17 +288,17 @@ inode->i_ctime = cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); cFYI(0, - (" Attributes came in as 0x%x ", pfindData->Attributes)); + (" Attributes came in as 0x%x ", attr)); /* set default mode. will override for dirs below */ if(atomic_read(&cifsInfo->inUse) == 0) /* new inode, can safely set these fields */ inode->i_mode = cifs_sb->mnt_file_mode; - if (pfindData->Attributes & ATTR_REPARSE) { - /* Can IFLNK be set as it basically is on windows with IFREG or IFDIR? */ - inode->i_mode |= S_IFLNK; - } else if (pfindData->Attributes & ATTR_DIRECTORY) { +/* if (attr & ATTR_REPARSE) */ +/* We no longer handle these as symlinks because we could not */ +/* follow them due to the absolute path with drive letter */ + if (attr & ATTR_DIRECTORY) { /* override default perms since we do not do byte range locking on dirs */ inode->i_mode = cifs_sb->mnt_dir_mode; inode->i_mode |= S_IFDIR; @@ -298,7 +320,6 @@ inode->i_blocks = (512 - 1 + le64_to_cpu(pfindData->AllocationSize)) >> 9; } - pfindData->AllocationSize = le64_to_cpu(pfindData->AllocationSize); inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks); @@ -951,7 +972,7 @@ } else time_buf.ChangeTime = 0; - if (set_time | time_buf.Attributes) { + if (set_time || time_buf.Attributes) { /* BB what if setting one attribute fails (such as size) but time setting works */ time_buf.CreationTime = 0; /* do not change */ @@ -959,6 +980,15 @@ via Handle (SetFileInfo) instead of by path */ rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf, cifs_sb->local_nls); + if(rc == -EOPNOTSUPP) { + cFYI(1,("OS2 level of SetPathInfo not implemented")); + /* For older servers converts time_buf into old DOS style + level which uses two second granularity */ + + /* return EOPNOTSUPP until function below is ready */ + /* CIFSSMBSetTimesLegacy(xid, pTcon, full_path, + &time_buf, cifs_sb->local_nls); */ + } } /* do not need local check to inode_check_ok since the server does that */ diff -Nau fs/cifs/Makefile fs/cifs.new-mm/Makefile --- fs/cifs/Makefile 2004-08-14 00:36:32.000000000 -0500 +++ fs/cifs.new-mm/Makefile 2005-02-06 22:30:07.496018768 -0600 @@ -3,4 +3,4 @@ # obj-$(CONFIG_CIFS) += cifs.o -cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o +cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o readdir.o diff -Nau fs/cifs/misc.c fs/cifs.new-mm/misc.c --- fs/cifs/misc.c 2005-01-14 09:33:50.000000000 -0600 +++ fs/cifs.new-mm/misc.c 2005-02-06 22:30:07.671992016 -0600 @@ -1,7 +1,7 @@ /* * fs/cifs/misc.c * - * Copyright (C) International Business Machines Corp., 2002,2003 + * Copyright (C) International Business Machines Corp., 2002,2004 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -29,6 +29,7 @@ #include "smberr.h" #include "nterr.h" +extern mempool_t *cifs_sm_req_poolp; extern mempool_t *cifs_req_poolp; extern struct task_struct * oplockThread; @@ -124,7 +125,7 @@ INIT_LIST_HEAD(&ret_buf->openFileList); init_MUTEX(&ret_buf->tconSem); #ifdef CONFIG_CIFS_STATS - ret_buf->stat_lock = SPIN_LOCK_UNLOCKED; + spin_lock_init(&ret_buf->stat_lock); #endif write_unlock(&GlobalSMBSeslock); } @@ -160,8 +161,9 @@ (struct smb_hdr *) mempool_alloc(cifs_req_poolp, SLAB_KERNEL | SLAB_NOFS); /* clear the first few header bytes */ + /* for most paths, more is cleared in header_assemble */ if (ret_buf) { - memset(ret_buf, 0, sizeof (struct smb_hdr)); + memset(ret_buf, 0, sizeof(struct smb_hdr) + 3); atomic_inc(&bufAllocCount); } @@ -173,7 +175,7 @@ { if (buf_to_free == NULL) { - cFYI(1, ("Null buffer passed to cifs_buf_release")); + /* cFYI(1, ("Null buffer passed to cifs_buf_release"));*/ return; } mempool_free(buf_to_free,cifs_req_poolp); @@ -182,21 +184,49 @@ return; } +struct smb_hdr * +cifs_small_buf_get(void) +{ + struct smb_hdr *ret_buf = NULL; + +/* We could use negotiated size instead of max_msgsize - + but it may be more efficient to always alloc same size + albeit slightly larger than necessary and maxbuffersize + defaults to this and can not be bigger */ + ret_buf = + (struct smb_hdr *) mempool_alloc(cifs_sm_req_poolp, SLAB_KERNEL | SLAB_NOFS); + if (ret_buf) { + /* No need to clear memory here, cleared in header assemble */ + /* memset(ret_buf, 0, sizeof(struct smb_hdr) + 27);*/ + atomic_inc(&smBufAllocCount); + } + return ret_buf; +} + +void +cifs_small_buf_release(void *buf_to_free) +{ + + if (buf_to_free == NULL) { + cFYI(1, ("Null buffer passed to cifs_small_buf_release")); + return; + } + mempool_free(buf_to_free,cifs_sm_req_poolp); + + atomic_dec(&smBufAllocCount); + return; +} + void header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , const struct cifsTconInfo *treeCon, int word_count - /* length of fixed section (word count) in two byte units */ - ) + /* length of fixed section (word count) in two byte units */) { - int i; - __u32 tmp; struct list_head* temp_item; struct cifsSesInfo * ses; char *temp = (char *) buffer; - for (i = 0; i < MAX_CIFS_HDR_SIZE; i++) { - temp[i] = 0; /* BB is this needed ?? */ - } + memset(temp,0,MAX_CIFS_HDR_SIZE); buffer->smb_buf_length = (2 * word_count) + sizeof (struct smb_hdr) - @@ -211,10 +241,8 @@ buffer->Command = smb_command; buffer->Flags = 0x00; /* case sensitive */ buffer->Flags2 = SMBFLG2_KNOWS_LONG_NAMES; - tmp = cpu_to_le32(current->tgid); - buffer->Pid = tmp & 0xFFFF; - tmp >>= 16; - buffer->PidHigh = tmp & 0xFFFF; + buffer->Pid = cpu_to_le16((__u16)current->tgid); + buffer->PidHigh = cpu_to_le16((__u16)(current->tgid >> 16)); spin_lock(&GlobalMid_Lock); GlobalMid++; buffer->Mid = GlobalMid; @@ -292,7 +320,7 @@ { /* Make sure that this really is an SMB, that it is a response, and that the message ids match */ - if ((*(unsigned int *) smb->Protocol == cpu_to_le32(0x424d53ff)) && + if ((*(__le32 *) smb->Protocol == cpu_to_le32(0x424d53ff)) && (mid == smb->Mid)) { if(smb->Flags & SMBFLG_RESPONSE) return 0; @@ -304,7 +332,7 @@ cERROR(1, ("Rcvd Request not response ")); } } else { /* bad signature or mid */ - if (*(unsigned int *) smb->Protocol != cpu_to_le32(0x424d53ff)) + if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff)) cERROR(1, ("Bad protocol string signature header %x ", *(unsigned int *) smb->Protocol)); @@ -318,12 +346,12 @@ int checkSMB(struct smb_hdr *smb, __u16 mid, int length) { + __u32 len = be32_to_cpu(smb->smb_buf_length); cFYI(0, ("Entering checkSMB with Length: %x, smb_buf_length: %x ", - length, ntohl(smb->smb_buf_length))); - if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) - || (ntohl(smb->smb_buf_length) > - CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE - 4)) { + length, len)); + if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) || + (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)) { if ((unsigned int)length < 2 + sizeof (struct smb_hdr)) { cERROR(1, ("Length less than 2 + sizeof smb_hdr ")); if (((unsigned int)length >= sizeof (struct smb_hdr) - 1) @@ -331,10 +359,9 @@ return 0; /* some error cases do not return wct and bcc */ } - if (ntohl(smb->smb_buf_length) > - CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE - 4) + if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) cERROR(1, - ("smb_buf_length greater than CIFS_MAX_MSGSIZE ... ")); + ("smb_buf_length greater than MaxBufSize")); cERROR(1, ("bad smb detected. Illegal length. The mid=%d", smb->Mid)); @@ -344,8 +371,8 @@ if (checkSMBhdr(smb, mid)) return 1; - if ((4 + ntohl(smb->smb_buf_length) != smbCalcSize(smb)) - || (4 + ntohl(smb->smb_buf_length) != (unsigned int)length)) { + if ((4 + len != smbCalcSize(smb)) + || (4 + len != (unsigned int)length)) { return 0; } else { cERROR(1, ("smbCalcSize %x ", smbCalcSize(smb))); @@ -363,8 +390,29 @@ struct cifsTconInfo *tcon; struct cifsFileInfo *netfile; - /* could add check for smb response flag 0x80 */ - cFYI(1,("Checking for oplock break")); + cFYI(1,("Checking for oplock break or dnotify response")); + if((pSMB->hdr.Command == SMB_COM_NT_TRANSACT) && + (pSMB->hdr.Flags & SMBFLG_RESPONSE)) { + struct smb_com_transaction_change_notify_rsp * pSMBr = + (struct smb_com_transaction_change_notify_rsp *)buf; + struct file_notify_information * pnotify; + __u32 data_offset = 0; + if(pSMBr->ByteCount > sizeof(struct file_notify_information)) { + data_offset = le32_to_cpu(pSMBr->DataOffset); + + pnotify = (struct file_notify_information *)((char *)&pSMBr->hdr.Protocol + + data_offset); + cFYI(1,("dnotify on %s with action: 0x%x",pnotify->FileName, + pnotify->Action)); /* BB removeme BB */ + /* cifs_dump_mem("Received notify Data is: ",buf,sizeof(struct smb_hdr)+60); */ + return TRUE; + } + if(pSMBr->hdr.Status.CifsError) { + cFYI(1,("notify err 0x%d",pSMBr->hdr.Status.CifsError)); + return TRUE; + } + return FALSE; + } if(pSMB->hdr.Command != SMB_COM_LOCKING_ANDX) return FALSE; if(pSMB->hdr.Flags & SMBFLG_RESPONSE) { diff -Nau fs/cifs/netmisc.c fs/cifs.new-mm/netmisc.c --- fs/cifs/netmisc.c 2004-08-14 00:37:40.000000000 -0500 +++ fs/cifs.new-mm/netmisc.c 2005-02-06 22:30:07.690989128 -0600 @@ -69,10 +69,12 @@ {ERRinvparm, -EINVAL}, {ERRdiskfull, -ENOSPC}, {ERRinvname, -ENOENT}, + {ERRinvlevel,-EOPNOTSUPP}, {ERRdirnotempty, -ENOTEMPTY}, {ERRnotlocked, -ENOLCK}, {ERRalreadyexists, -EEXIST}, {ERRmoredata, -EOVERFLOW}, + {ERReasnotsupported,-EOPNOTSUPP}, {ErrQuota, -EDQUOT}, {ErrNotALink, -ENOLINK}, {ERRnetlogonNotStarted,-ENOPROTOOPT}, @@ -187,8 +189,8 @@ if (value > addr_class_max[end - bytes]) return 0; - address.s_addr = *((int *) bytes) | htonl(value); - *((int *)dst) = address.s_addr; + address.s_addr = *((__be32 *) bytes) | htonl(value); + *((__be32 *)dst) = address.s_addr; return 1; /* success */ } @@ -287,7 +289,7 @@ ERRDOS, 87, NT_STATUS_BAD_WORKING_SET_LIMIT}, { ERRDOS, 87, NT_STATUS_INCOMPATIBLE_FILE_MAP}, { ERRDOS, 87, NT_STATUS_SECTION_PROTECTION}, { - ERRDOS, 282, NT_STATUS_EAS_NOT_SUPPORTED}, { + ERRDOS, ERReasnotsupported, NT_STATUS_EAS_NOT_SUPPORTED}, { ERRDOS, 255, NT_STATUS_EA_TOO_LARGE}, { ERRHRD, ERRgeneral, NT_STATUS_NONEXISTENT_EA_ENTRY}, { ERRHRD, ERRgeneral, NT_STATUS_NO_EAS_ON_FILE}, { @@ -752,7 +754,8 @@ ERRDOS, ERRnoaccess, 0xc000028e}, { ERRDOS, ERRnoaccess, 0xc000028f}, { ERRDOS, ERRnoaccess, 0xc0000290}, { -ERRDOS, ERRbadfunc, 0xc000029c},}; + ERRDOS, ERRbadfunc, 0xc000029c}, { + ERRDOS, ERRinvlevel, 0x007c0001}, }; /***************************************************************************** Print an error message from the status code @@ -810,16 +813,13 @@ if (smb->Flags2 & SMBFLG2_ERR_STATUS) { /* translate the newer STATUS codes to old style errors and then to POSIX errors */ - smb->Status.CifsError = le32_to_cpu(smb->Status.CifsError); + __u32 err = le32_to_cpu(smb->Status.CifsError); if(cifsFYI) - cifs_print_status(smb->Status.CifsError); - ntstatus_to_dos(smb->Status.CifsError, &smberrclass, - &smberrcode); + cifs_print_status(err); + ntstatus_to_dos(err, &smberrclass, &smberrcode); } else { smberrclass = smb->Status.DosError.ErrorClass; - smb->Status.DosError.Error = - le16_to_cpu(smb->Status.DosError.Error); - smberrcode = smb->Status.DosError.Error; + smberrcode = le16_to_cpu(smb->Status.DosError.Error); } /* old style errors */ diff -Nau fs/cifs/ntlmssp.h fs/cifs.new-mm/ntlmssp.h --- fs/cifs/ntlmssp.h 2004-08-14 00:36:13.000000000 -0500 +++ fs/cifs.new-mm/ntlmssp.h 2005-02-06 22:30:07.691988976 -0600 @@ -23,10 +23,10 @@ #define NTLMSSP_SIGNATURE "NTLMSSP" /* Message Types */ -#define NtLmNegotiate 1 -#define NtLmChallenge 2 -#define NtLmAuthenticate 3 -#define UnknownMessage 8 +#define NtLmNegotiate cpu_to_le32(1) +#define NtLmChallenge cpu_to_le32(2) +#define NtLmAuthenticate cpu_to_le32(3) +#define UnknownMessage cpu_to_le32(8) /* Negotiate Flags */ #define NTLMSSP_NEGOTIATE_UNICODE 0x01 // Text strings are in unicode @@ -60,15 +60,15 @@ /* appearance */ typedef struct _SECURITY_BUFFER { - __u16 Length; - __u16 MaximumLength; - __u32 Buffer; /* offset to buffer */ + __le16 Length; + __le16 MaximumLength; + __le32 Buffer; /* offset to buffer */ } SECURITY_BUFFER; typedef struct _NEGOTIATE_MESSAGE { __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; - __u32 MessageType; /* 1 */ - __u32 NegotiateFlags; + __le32 MessageType; /* 1 */ + __le32 NegotiateFlags; SECURITY_BUFFER DomainName; /* RFC 1001 style and ASCII */ SECURITY_BUFFER WorkstationName; /* RFC 1001 and ASCII */ char DomainString[0]; @@ -77,9 +77,9 @@ typedef struct _CHALLENGE_MESSAGE { __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; - __u32 MessageType; /* 2 */ + __le32 MessageType; /* 2 */ SECURITY_BUFFER TargetName; - __u32 NegotiateFlags; + __le32 NegotiateFlags; __u8 Challenge[CIFS_CRYPTO_KEY_SIZE]; __u8 Reserved[8]; SECURITY_BUFFER TargetInfoArray; @@ -87,14 +87,14 @@ typedef struct _AUTHENTICATE_MESSAGE { __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; - __u32 MessageType; /* 3 */ + __le32 MessageType; /* 3 */ SECURITY_BUFFER LmChallengeResponse; SECURITY_BUFFER NtChallengeResponse; SECURITY_BUFFER DomainName; SECURITY_BUFFER UserName; SECURITY_BUFFER WorkstationName; SECURITY_BUFFER SessionKey; - __u32 NegotiateFlags; + __le32 NegotiateFlags; char UserString[0]; } AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE; diff -Nau fs/cifs/readdir.c fs/cifs.new-mm/readdir.c --- fs/cifs/readdir.c 1969-12-31 18:00:00.000000000 -0600 +++ fs/cifs.new-mm/readdir.c 2005-02-06 22:30:07.734982440 -0600 @@ -0,0 +1,648 @@ +/* + * fs/cifs/readdir.c + * + * Directory search handling + * + * Copyright (C) International Business Machines Corp., 2004 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include "cifspdu.h" +#include "cifsglob.h" +#include "cifsproto.h" +#include "cifs_unicode.h" +#include "cifs_debug.h" +#include "cifs_fs_sb.h" + +extern int CIFSFindFirst2(const int xid, struct cifsTconInfo *tcon, + const char *searchName, const struct nls_table *nls_codepage, + __u16 *searchHandle, struct cifs_search_info * psrch_inf); + +extern int CIFSFindNext2(const int xid, struct cifsTconInfo *tcon, + __u16 searchHandle, struct cifs_search_info * psrch_inf); + +extern int construct_dentry(struct qstr *qstring, struct file *file, + struct inode **ptmp_inode, struct dentry **pnew_dentry); + +extern void fill_in_inode(struct inode *tmp_inode, + FILE_DIRECTORY_INFO * pfindData, int *pobject_type); + +extern void unix_fill_in_inode(struct inode *tmp_inode, + FILE_UNIX_INFO * pfindData, int *pobject_type); + + +/* BB fixme - add debug wrappers around this function to disable it fixme BB */ +/* static void dump_cifs_file_struct(struct file * file, char * label) +{ + struct cifsFileInfo * cf; + + if(file) { + cf = (struct cifsFileInfo *)file->private_data; + if(cf == NULL) { + cFYI(1,("empty cifs private file data")); + return; + } + if(cf->invalidHandle) { + cFYI(1,("invalid handle")); + } + if(cf->srch_inf.endOfSearch) { + cFYI(1,("end of search")); + } + if(cf->srch_inf.emptyDir) { + cFYI(1,("empty dir")); + } + + } +} */ + +static int initiate_cifs_search(const int xid, struct file * file) +{ + int rc = 0; + char * full_path; + struct cifsFileInfo * cifsFile; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + + if(file->private_data == NULL) { + file->private_data = + kmalloc(sizeof(struct cifsFileInfo),GFP_KERNEL); + } + + if(file->private_data == NULL) { + return -ENOMEM; + } else { + memset(file->private_data,0,sizeof(struct cifsFileInfo)); + } + cifsFile = (struct cifsFileInfo *)file->private_data; + cifsFile->invalidHandle = TRUE; + cifsFile->srch_inf.endOfSearch = FALSE; + + cifs_sb = CIFS_SB(file->f_dentry->d_sb); + if(cifs_sb == NULL) + return -EINVAL; + + pTcon = cifs_sb->tcon; + if(pTcon == NULL) + return -EINVAL; + + if(file->f_dentry == NULL) + return -ENOENT; + + down(&file->f_dentry->d_sb->s_vfs_rename_sem); + full_path = build_wildcard_path_from_dentry(file->f_dentry); + up(&file->f_dentry->d_sb->s_vfs_rename_sem); + + if(full_path == NULL) { + return -ENOMEM; + } + + cFYI(1, ("Full path: %s start at: %lld ", full_path, file->f_pos)); + + /* test for Unix extensions */ + if (pTcon->ses->capabilities & CAP_UNIX) { + cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX; + } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { + cifsFile->srch_inf.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO; + } else /* not srvinos - BB fixme add check for backlevel? */ { + cifsFile->srch_inf.info_level = SMB_FIND_FILE_DIRECTORY_INFO; + } + + rc = CIFSFindFirst2(xid, pTcon,full_path,cifs_sb->local_nls, + &cifsFile->netfid, &cifsFile->srch_inf); + if(rc == 0) + cifsFile->invalidHandle = FALSE; + if(full_path) + kfree(full_path); + return rc; +} + +/* return length of unicode string in bytes */ +static int cifs_unicode_bytelen(char * str) +{ + int len; + __le16 * ustr = (__le16 *)str; + + for(len=0;len <= PATH_MAX;len++) { + if(ustr[len] == 0) + return len << 1; + } + cFYI(1,("Unicode string longer than PATH_MAX found")); + return len << 1; +} + +static char * nxt_dir_entry(char * old_entry, char * end_of_smb) +{ + char * new_entry; + FILE_DIRECTORY_INFO * pDirInfo = (FILE_DIRECTORY_INFO *)old_entry; + + new_entry = old_entry + le32_to_cpu(pDirInfo->NextEntryOffset); + cFYI(1,("new entry %p old entry %p",new_entry,old_entry)); + /* validate that new_entry is not past end of SMB */ + if(new_entry >= end_of_smb) { + cFYI(1,("search entry %p began after end of SMB %p old entry %p", + new_entry,end_of_smb,old_entry)); + return NULL; + } else + return new_entry; + +} + +#define UNICODE_DOT cpu_to_le16(0x2e) + +/* return 0 if no match and 1 for . (current directory) and 2 for .. (parent) */ +static int cifs_entry_is_dot(char * current_entry, struct cifsFileInfo * cfile) +{ + int rc = 0; + char * filename = NULL; + int len = 0; + + if(cfile->srch_inf.info_level == 0x202) { + FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry; + filename = &pFindData->FileName[0]; + if(cfile->srch_inf.unicode) { + len = cifs_unicode_bytelen(filename); + } else { + /* BB should we make this strnlen of PATH_MAX? */ + len = strnlen(filename, 5); + } + } else if(cfile->srch_inf.info_level == 0x101) { + FILE_DIRECTORY_INFO * pFindData = + (FILE_DIRECTORY_INFO *)current_entry; + filename = &pFindData->FileName[0]; + len = le32_to_cpu(pFindData->FileNameLength); + } else if(cfile->srch_inf.info_level == 0x102) { + FILE_FULL_DIRECTORY_INFO * pFindData = + (FILE_FULL_DIRECTORY_INFO *)current_entry; + filename = &pFindData->FileName[0]; + len = le32_to_cpu(pFindData->FileNameLength); + } else if(cfile->srch_inf.info_level == 0x105) { + SEARCH_ID_FULL_DIR_INFO * pFindData = + (SEARCH_ID_FULL_DIR_INFO *)current_entry; + filename = &pFindData->FileName[0]; + len = le32_to_cpu(pFindData->FileNameLength); + } else if(cfile->srch_inf.info_level == 0x104) { + FILE_BOTH_DIRECTORY_INFO * pFindData = + (FILE_BOTH_DIRECTORY_INFO *)current_entry; + filename = &pFindData->FileName[0]; + len = le32_to_cpu(pFindData->FileNameLength); + } else { + cFYI(1,("Unknown findfirst level %d",cfile->srch_inf.info_level)); + } + + if(filename) { + if(cfile->srch_inf.unicode) { + __le16 *ufilename = (__le16 *)filename; + if(len == 2) { + /* check for . */ + if(ufilename[0] == UNICODE_DOT) + rc = 1; + } else if(len == 4) { + /* check for .. */ + if((ufilename[0] == UNICODE_DOT) + &&(ufilename[1] == UNICODE_DOT)) + rc = 2; + } + } else /* ASCII */ { + if(len == 1) { + if(filename[0] == '.') + rc = 1; + } else if(len == 2) { + if((filename[0] == '.') && (filename[1] == '.')) + rc = 2; + } + } + } + + return rc; +} + +/* find the corresponding entry in the search */ +/* Note that the SMB server returns search entries for . and .. which + complicates logic here if we choose to parse for them and we do not + assume that they are located in the findfirst return buffer.*/ +/* We start counting in the buffer with entry 2 and increment for every + entry (do not increment for . or .. entry) */ +static int find_cifs_entry(const int xid, struct cifsTconInfo * pTcon, + struct file * file, char ** ppCurrentEntry,int * num_to_ret) +{ + int rc = 0; + int pos_in_buf = 0; + loff_t first_entry_in_buffer; + loff_t index_to_find = file->f_pos; + struct cifsFileInfo * cifsFile = (struct cifsFileInfo *)file->private_data; + /* check if index in the buffer */ + + if((cifsFile == NULL) || (ppCurrentEntry == NULL) || (num_to_ret == NULL)) + return -ENOENT; + + *ppCurrentEntry = NULL; + first_entry_in_buffer = + cifsFile->srch_inf.index_of_last_entry - + cifsFile->srch_inf.entries_in_buffer; +/* dump_cifs_file_struct(file, "In fce ");*/ + if(index_to_find < first_entry_in_buffer) { + /* close and restart search */ + cFYI(1,("search backing up - close and restart search")); + cifsFile->invalidHandle = TRUE; + CIFSFindClose(xid, pTcon, cifsFile->netfid); + if(cifsFile->search_resume_name) { + kfree(cifsFile->search_resume_name); + cifsFile->search_resume_name = NULL; + } + if(cifsFile->srch_inf.ntwrk_buf_start) { + cFYI(1,("freeing SMB ff cache buf on search rewind")); + cifs_buf_release(cifsFile->srch_inf.ntwrk_buf_start); + } + rc = initiate_cifs_search(xid,file); + if(rc) { + cFYI(1,("error %d reinitiating a search on rewind",rc)); + return rc; + } + } + + while((index_to_find >= cifsFile->srch_inf.index_of_last_entry) && + (rc == 0) && (cifsFile->srch_inf.endOfSearch == FALSE)){ + cFYI(1,("calling findnext2")); + rc = CIFSFindNext2(xid,pTcon,cifsFile->netfid, &cifsFile->srch_inf); + if(rc) + return -ENOENT; + } + if(index_to_find < cifsFile->srch_inf.index_of_last_entry) { + /* we found the buffer that contains the entry */ + /* scan and find it */ + int i; + char * current_entry; + char * end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + + smbCalcSize((struct smb_hdr *)cifsFile->srch_inf.ntwrk_buf_start); +/* dump_cifs_file_struct(file,"found entry in fce "); */ + first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry - + cifsFile->srch_inf.entries_in_buffer; + pos_in_buf = index_to_find - first_entry_in_buffer; + cFYI(1,("found entry - pos_in_buf %d",pos_in_buf)); + current_entry = cifsFile->srch_inf.srch_entries_start; + for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) { + /* go entry to next entry figuring out which we need to start with */ + /* if( . or ..) + skip */ + rc = cifs_entry_is_dot(current_entry,cifsFile); + if(rc == 1) /* is . or .. so skip */ { + cFYI(1,("Entry is .")); /* BB removeme BB */ + /* continue; */ + } else if (rc == 2 ) { + cFYI(1,("Entry is ..")); /* BB removeme BB */ + /* continue; */ + } + current_entry = nxt_dir_entry(current_entry,end_of_smb); + } + if((current_entry == NULL) && (i < pos_in_buf)) { + cERROR(1,("reached end of buf searching for pos in buf %d index to find %lld rc %d",pos_in_buf,index_to_find,rc)); /* BB removeme BB */ + } + rc = 0; + *ppCurrentEntry = current_entry; + } else { + cFYI(1,("index not in buffer - could not findnext into it")); + return 0; + } + + if(pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) { + cFYI(1,("can not return entries when pos_in_buf beyond last entry")); + *num_to_ret = 0; + } else + *num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf; +/* dump_cifs_file_struct(file, "end fce ");*/ + + return rc; +} + +/* inode num, inode type and filename returned */ +static int cifs_get_name_from_search_buf(struct qstr * pqst,char * current_entry, + __u16 level,unsigned int unicode,struct nls_table * nlt, + ino_t * pinum) +{ + int rc = 0; + unsigned int len = 0; + char * filename; + + *pinum = 0; + + if(level == SMB_FIND_FILE_UNIX) { + FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry; + + filename = &pFindData->FileName[0]; + if(unicode) { + len = cifs_unicode_bytelen(filename); + } else { + /* BB should we make this strnlen of PATH_MAX? */ + len = strnlen(filename, PATH_MAX); + } + + /* BB fixme - hash low and high 32 bits if not 64 bit arch BB fixme */ + *pinum = pFindData->UniqueId; + } else if(level == SMB_FIND_FILE_DIRECTORY_INFO) { + FILE_DIRECTORY_INFO * pFindData = + (FILE_DIRECTORY_INFO *)current_entry; + filename = &pFindData->FileName[0]; + len = le32_to_cpu(pFindData->FileNameLength); + } else if(level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) { + FILE_FULL_DIRECTORY_INFO * pFindData = + (FILE_FULL_DIRECTORY_INFO *)current_entry; + filename = &pFindData->FileName[0]; + len = le32_to_cpu(pFindData->FileNameLength); + } else if(level == SMB_FIND_FILE_ID_FULL_DIR_INFO) { + SEARCH_ID_FULL_DIR_INFO * pFindData = + (SEARCH_ID_FULL_DIR_INFO *)current_entry; + filename = &pFindData->FileName[0]; + len = le32_to_cpu(pFindData->FileNameLength); + *pinum = pFindData->UniqueId; + } else if(level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) { + FILE_BOTH_DIRECTORY_INFO * pFindData = + (FILE_BOTH_DIRECTORY_INFO *)current_entry; + filename = &pFindData->FileName[0]; + len = le32_to_cpu(pFindData->FileNameLength); + } else { + cFYI(1,("Unknown findfirst level %d",level)); + return -EINVAL; + } + if(unicode) { + /* BB fixme - test with long names */ + /* Note converted filename can be longer than in unicode */ + pqst->len = cifs_strfromUCS_le((char *)pqst->name,(wchar_t *)filename,len/2,nlt); + } else { + pqst->name = filename; + pqst->len = len; + } + pqst->hash = full_name_hash(pqst->name,pqst->len); +/* cFYI(1,("filldir on %s",pqst->name)); */ + return rc; +} + + +static int +cifs_filldir(char * pfindEntry, struct file *file, + filldir_t filldir, void *direntry,char * scratch_buf) +{ + int rc = 0; + struct qstr qstring; + struct cifsFileInfo * pCifsF; + unsigned obj_type; + ino_t inum; + struct cifs_sb_info * cifs_sb; + struct inode *tmp_inode; + struct dentry *tmp_dentry; + + /* get filename and len into qstring */ + /* get dentry */ + /* decide whether to create and populate ionde */ + if((direntry == NULL) || (file == NULL)) + return -EINVAL; + + pCifsF = file->private_data; + + if((scratch_buf == NULL) || (pfindEntry == NULL) || (pCifsF == NULL)) + return -ENOENT; + + if(file->f_dentry == NULL) + return -ENOENT; + + cifs_sb = CIFS_SB(file->f_dentry->d_sb); + + qstring.name = scratch_buf; + rc = cifs_get_name_from_search_buf(&qstring,pfindEntry, + pCifsF->srch_inf.info_level, + pCifsF->srch_inf.unicode,cifs_sb->local_nls, + &inum /* returned */); + + if(rc) + return rc; + + rc = construct_dentry(&qstring,file,&tmp_inode, &tmp_dentry); + if((tmp_inode == NULL) || (tmp_dentry == NULL)) + return -ENOMEM; + + if(rc) { + /* inode created, we need to hash it with right inode number */ + if(inum != 0) { + /* BB fixme - hash the 2 32 quantities bits together if necessary BB */ + tmp_inode->i_ino = inum; + } + insert_inode_hash(tmp_inode); + } + + if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) { + unix_fill_in_inode(tmp_inode,(FILE_UNIX_INFO *)pfindEntry,&obj_type); + } else { + fill_in_inode(tmp_inode,(FILE_DIRECTORY_INFO *)pfindEntry,&obj_type); + } + + rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,tmp_inode->i_ino,obj_type); + if(rc) { + cFYI(1,("filldir rc = %d",rc)); + } + + dput(tmp_dentry); + return rc; +} + +int cifs_save_resume_key(const char * current_entry,struct cifsFileInfo * cifsFile) +{ + int rc = 0; + unsigned int len = 0; + __u16 level; + char * filename; + + if((cifsFile == NULL) || (current_entry == NULL)) + return -EINVAL; + + level = cifsFile->srch_inf.info_level; + + if(level == SMB_FIND_FILE_UNIX) { + FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry; + + filename = &pFindData->FileName[0]; + if(cifsFile->srch_inf.unicode) { + len = cifs_unicode_bytelen(filename); + } else { + /* BB should we make this strnlen of PATH_MAX? */ + len = strnlen(filename, PATH_MAX); + } + cifsFile->srch_inf.resume_key = pFindData->ResumeKey; + } else if(level == SMB_FIND_FILE_DIRECTORY_INFO) { + FILE_DIRECTORY_INFO * pFindData = + (FILE_DIRECTORY_INFO *)current_entry; + filename = &pFindData->FileName[0]; + len = le32_to_cpu(pFindData->FileNameLength); + cifsFile->srch_inf.resume_key = pFindData->FileIndex; + } else if(level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) { + FILE_FULL_DIRECTORY_INFO * pFindData = + (FILE_FULL_DIRECTORY_INFO *)current_entry; + filename = &pFindData->FileName[0]; + len = le32_to_cpu(pFindData->FileNameLength); + cifsFile->srch_inf.resume_key = pFindData->FileIndex; + } else if(level == SMB_FIND_FILE_ID_FULL_DIR_INFO) { + SEARCH_ID_FULL_DIR_INFO * pFindData = + (SEARCH_ID_FULL_DIR_INFO *)current_entry; + filename = &pFindData->FileName[0]; + len = le32_to_cpu(pFindData->FileNameLength); + cifsFile->srch_inf.resume_key = pFindData->FileIndex; + } else if(level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) { + FILE_BOTH_DIRECTORY_INFO * pFindData = + (FILE_BOTH_DIRECTORY_INFO *)current_entry; + filename = &pFindData->FileName[0]; + len = le32_to_cpu(pFindData->FileNameLength); + cifsFile->srch_inf.resume_key = pFindData->FileIndex; + } else { + cFYI(1,("Unknown findfirst level %d",level)); + return -EINVAL; + } + cifsFile->srch_inf.resume_name_len = len; + cifsFile->srch_inf.presume_name = filename; + return rc; +} + +int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) +{ + int rc = 0; + int xid,i; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + struct cifsFileInfo *cifsFile = NULL; + char * current_entry; + int num_to_fill = 0; + char * tmp_buf = NULL; + char * end_of_smb; + + xid = GetXid(); + + if(file->f_dentry == NULL) { + FreeXid(xid); + return -EIO; + } +/* dump_cifs_file_struct(file, "Begin rdir "); */ + + cifs_sb = CIFS_SB(file->f_dentry->d_sb); + pTcon = cifs_sb->tcon; + if(pTcon == NULL) + return -EINVAL; + +/* cFYI(1,("readdir2 pos: %lld",file->f_pos)); */ + + switch ((int) file->f_pos) { + case 0: + /*if (filldir(direntry, ".", 1, file->f_pos, + file->f_dentry->d_inode->i_ino, DT_DIR) < 0) { + cERROR(1, ("Filldir for current dir failed ")); + rc = -ENOMEM; + break; + } + file->f_pos++; */ + case 1: + /* if (filldir(direntry, "..", 2, file->f_pos, + file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) { + cERROR(1, ("Filldir for parent dir failed ")); + rc = -ENOMEM; + break; + } + file->f_pos++; */ + case 2: + /* 1) If search is active, + is in current search buffer? + if it before then restart search + if after then keep searching till find it */ + + if(file->private_data == NULL) { + rc = initiate_cifs_search(xid,file); + cFYI(1,("initiate cifs search rc %d",rc)); + if(rc) { + FreeXid(xid); + return rc; + } + } + default: + if(file->private_data == NULL) { + rc = -EINVAL; + FreeXid(xid); + return rc; + } + cifsFile = (struct cifsFileInfo *) file->private_data; + if (cifsFile->srch_inf.endOfSearch) { + if(cifsFile->srch_inf.emptyDir) { + cFYI(1, ("End of search, empty dir")); + rc = 0; + break; + } + } /* else { + cifsFile->invalidHandle = TRUE; + CIFSFindClose(xid, pTcon, cifsFile->netfid); + } + if(cifsFile->search_resume_name) { + kfree(cifsFile->search_resume_name); + cifsFile->search_resume_name = NULL; + } */ +/* BB account for . and .. in f_pos */ + /* dump_cifs_file_struct(file, "rdir after default ");*/ + + rc = find_cifs_entry(xid,pTcon, file, + ¤t_entry,&num_to_fill); + if(rc) { + cFYI(1,("fce error %d",rc)); + goto rddir2_exit; + } else if (current_entry != NULL) { + cFYI(1,("entry %lld found",file->f_pos)); + } else { + cFYI(1,("could not find entry")); + goto rddir2_exit; + } + cFYI(1,("loop through %d times filling dir for net buf %p", + num_to_fill,cifsFile->srch_inf.ntwrk_buf_start)); + end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + + smbCalcSize((struct smb_hdr *)cifsFile->srch_inf.ntwrk_buf_start); + tmp_buf = kmalloc(NAME_MAX+1,GFP_KERNEL); + for(i=0;(imnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) || + (cifsFile->srch_inf.info_level != something that supports server inodes)) { + create dentry + create inode + fill in inode new_inode (which makes number locally) + } + also create local inode for per reasons unless new mount parm says otherwise */ + rc = cifs_filldir(current_entry, file, + filldir, direntry,tmp_buf); + file->f_pos++; + if(file->f_pos == cifsFile->srch_inf.index_of_last_entry) { + cFYI(1,("last entry in buf at pos %lld %s",file->f_pos,tmp_buf)); /* BB removeme BB */ + cifs_save_resume_key(current_entry,cifsFile); + break; + } else + current_entry = nxt_dir_entry(current_entry,end_of_smb); + } + if(tmp_buf != NULL) + kfree(tmp_buf); + break; + } /* end switch */ + +rddir2_exit: + /* dump_cifs_file_struct(file, "end rdir "); */ + FreeXid(xid); + return rc; +} + diff -Nau fs/cifs/README fs/cifs.new-mm/README --- fs/cifs/README 2004-08-14 00:38:04.000000000 -0500 +++ fs/cifs.new-mm/README 2005-02-06 22:30:07.523014664 -0600 @@ -64,6 +64,13 @@ gcc samba/source/client/mount.cifs.c -o mount.cifs +If cifs is built as a module, then the size and number of network buffers +and maximum number of simultaneous requests to one server can be configured. +Changing these from their defaults is not recommended. By executing modinfo + modinfo kernel/fs/cifs/cifs.ko +on kernel/fs/cifs/cifs.ko the list of configuration changes that can be made +at module initialization time (by running insmod cifs.ko) can be seen. + Allowing User Mounts ==================== To permit users to mount and unmount over directories they own is possible @@ -115,11 +122,20 @@ 3.0.6 and later (also EA support works in all versions of Windows, at least to shares on NTFS filesystems). Extended Attribute (xattr) support is an optional feature of most Linux filesystems which may require enabling via -make menuconfig +make menuconfig. + +The CIFS client can get and set POSIX ACLs (getfacl, setfacl) to Samba servers +version 3.10 and later. Setting POSIX ACLs requires enabling both XATTR and +then POSIX support in the CIFS configuration options when building the cifs +module. Some administrators may want to change Samba's smb.conf "map archive" and -"create mask" parameters from the default. Creating special devices (mknod) -remotely may require specifying a mkdev function to Samba if you are not using +"create mask" parameters from the default. Unless the create mask is changed +newly created files can end up with an unnecessarily restrictive default mode, +which may not be what you want, although if the CIFS Unix extensions are +enabled on the server and client, subsequent setattr calls (e.g. chmod) can +fix the mode. Note that creating special devices (mknod) remotely +may require specifying a mkdev function to Samba if you are not using Samba 3.0.6 or later. For more information on these see the manual pages ("man smb.conf") on the Samba server system. Note that the cifs vfs, unlike the smbfs vfs, does not read the smb.conf on the client system @@ -191,7 +207,20 @@ by Samba and Windows NT version 4, 2000 and XP and many other SMB/CIFS servers) Servers must support either "pure-TCP" (port 445 TCP/IP CIFS connections) or RFC 1001/1002 support for "Netbios-Over-TCP/IP." Neither of these is likely to be a -problem as most servers support this. IPv6 support is planned for the future. +problem as most servers support this. IPv6 support is planned for the future, +and is almost complete. + +Valid filenames differ between Windows and Linux. Windows typically restricts +filenames which contain certain reserved characters (e.g.the character : +which is used to delimit the beginning of a stream name by Windows), while +Linux allows a slightly wider set of valid characters in filenames. Windows +servers can remap such characters when an explicit mapping is specified in +the Server's registry. Samba starting with version 3.10 will allow such +filenames (ie those which contain valid Linux characters, which normally +would be forbidden for Windows/CIFS semantics) as long as the server is +configured for Unix Extensions (and the client has not disabled +/proc/fs/cifs/LinuxExtensionsEnabled). + CIFS VFS Mount Options ====================== @@ -266,6 +295,10 @@ If you do not trust the servers in your network (your mount targets) it is recommended that you specify this option for greater security. + exec Permit execution of binaries on the mount. + noexec Do not permit execution of binaries on the mount. + dev Recognize block devices on the remote mount. + nodev Do not recognize devices on the remote mount. suid Allow remote files on this mountpoint with suid enabled to be executed (default for mounts when executed as root, nosuid is default for user mounts). @@ -292,6 +325,22 @@ 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). + serverino Use servers inode numbers instead of generating automatically + incrementing inode numbers on the client. Although this will + make it easier to spot hardlinked files (as they will have + the same inode numbers) and inode numbers may be persistent, + note that the server does not guarantee that the inode numbers + are unique if multiple server side mounts are exported under a + single share (since inode numbers on the servers might not + be unique if multiple filesystems are mounted under the same + shared higher level directory). Note that this requires that + the server support the CIFS Unix Extensions as other servers + do not return a unique IndexNumber on SMB FindFirst (most + servers return zero as the IndexNumber). Parameter has no + effect to Windows servers and others which do not support the + CIFS Unix Extensions. + noserverino Client generates inode numbers (rather than using the actual one + from the server) by default. 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 @@ -304,6 +353,23 @@ the client) set the uid and gid is the default. This parameter has no effect if the CIFS Unix Extensions are not negotiated. + netbiosname When mounting to servers via port 139, specifies the RFC1001 + source name to use to represent the client netbios machine + name when doing the RFC1001 netbios session initialize. + direct Do not do inode data caching on files opened on this mount. + This precludes mmaping files on this mount. In some cases + with fast networks and little or no caching benefits on the + client (e.g. when the application is doing large sequential + reads bigger than page size without rereading the same data) + this can provide better performance than the default + behavior which caches reads (reaadahead) and writes + (writebehind) through the local Linux client pagecache + if oplock (caching token) is granted and held. Note that + direct allows write operations larger than page size + to be sent to the server. + acl Allow setfacl and getfacl to manage posix ACLs if server + supports them. (default) + noacl Do not allow setfacl and getfacl calls on this mount The mount.cifs mount helper also accepts a few mount options before -o including: @@ -375,14 +441,14 @@ echo 1 > /proc/fs/cifs/traceSMB Two other experimental features are under development and to test -require enabling an ifdef (e.g. by adding "#define CIFS_FCNTL" in cifsglob.h) +require enabling CONFIG_CIFS_EXPERIMENTAL - CONFIG_CIFS_QUOTA + More efficient write operations and SMB buffer handling - CONFIG_CIFS_FCNTL (fcntl needed for support of directory change + DNOTIFY fcntl: needed for support of directory change notification and perhaps later for file leases) -Per share (per client mount) statistics are available in /proc/fs/cifs/DebugData +Per share (per client mount) statistics are available in /proc/fs/cifs/Stats if the kernel was configured with cifs statistics enabled. The statistics represent the number of successful (ie non-zero return code from the server) SMB responses to some of the more common commands (open, delete, mkdir etc.). diff -Nau fs/cifs/smberr.h fs/cifs.new-mm/smberr.h --- fs/cifs/smberr.h 2004-08-14 00:37:25.000000000 -0500 +++ fs/cifs.new-mm/smberr.h 2005-02-06 22:30:08.058933192 -0600 @@ -69,6 +69,7 @@ #define ERRpipeclosing 232 #define ERRnotconnected 233 #define ERRmoredata 234 +#define ERReasnotsupported 282 #define ErrQuota 0x200 /* The operation would cause a quota limit to be exceeded. */ #define ErrNotALink 0x201 /* A link operation was performed on a pathname that was not a link. */ Common subdirectories: fs/cifs/.tmp_versions and fs/cifs.new-mm/.tmp_versions diff -Nau fs/cifs/TODO fs/cifs.new-mm/TODO --- fs/cifs/TODO 2004-08-14 00:38:04.000000000 -0500 +++ fs/cifs.new-mm/TODO 2005-02-06 22:30:07.524014512 -0600 @@ -14,7 +14,7 @@ better) c) multi-user mounts - multiplexed sessionsetups over single vc -(ie tcp session) - prettying up needed +(ie tcp session) - prettying up needed, and more testing needed d) Kerberos/SPNEGO session setup support - (started) @@ -40,8 +40,8 @@ extra copy in/out of the socket buffers in some cases. l) finish support for IPv6. This is mostly complete but -needs a simple inet_pton like function to convert ipv6 -addresses in string representation. +needs a simple conversion of ipv6 to sin6_addr from the +address in string representation. m) Better optimize open (and pathbased setfilesize) to reduce the oplock breaks coming from windows srv. Piggyback identical file @@ -50,23 +50,24 @@ spurious oplock breaks). o) Improve performance of readpages by sending more than one read -at a time when 8 pages or more are requested. Evaluate whether -reads larger than 16K would be helpful. +at a time when 8 pages or more are requested. In conjuntion +add support for async_cifs_readpages. -p) For support of Windows9x/98 we need to retry failed mounts -to *SMBSERVER (default server name) with the uppercase hostname -in the RFC1001 session_init request. - -q) Add support for storing symlink and fifo info to Windows servers +p) Add support for storing symlink and fifo info to Windows servers in the Extended Attribute format their SFU clients would recognize. -r) Finish fcntl D_NOTIFY support so kde and gnome file list windows -will autorefresh +q) Finish fcntl D_NOTIFY support so kde and gnome file list windows +will autorefresh (started) + +r) Add GUI tool to configure /proc/fs/cifs settings and for display of +the CIFS statistics (started) + +q) implement support for security and trusted categories of xattrs +(requires minor protocol extension) to enable better support for SELINUX -s) Add GUI tool to configure /proc/fs/cifs settings and for display of -the CIFS statistics +r) Implement O_DIRECT flag on open (already supported on mount) -KNOWN BUGS (updated May 27, 2004) +KNOWN BUGS (updated December 10, 2004) ==================================== 1) existing symbolic links (Windows reparse points) are recognized but can not be created remotely. They are implemented for Samba and those that @@ -83,9 +84,6 @@ differences but worth investigating). Also debug Samba to see why lock test case 7 takes longer to complete to Samba than to Windows. -5) implement search rewind (seeking backward in a readdir), which is -necessary for one of the "special" subsection of posix file API -tests in the Connectathon nfs test suite. Misc testing to do ================== diff -Nau fs/cifs/transport.c fs/cifs.new-mm/transport.c --- fs/cifs/transport.c 2005-01-14 09:34:00.000000000 -0600 +++ fs/cifs.new-mm/transport.c 2005-02-06 22:30:08.059933040 -0600 @@ -123,12 +123,12 @@ int i = 0; struct msghdr smb_msg; struct kvec iov; - int len; + unsigned len = smb_buf_length + 4; if(ssocket == NULL) return -ENOTSOCK; /* BB eventually add reconnect code here */ iov.iov_base = smb_buffer; - iov.iov_len = smb_buf_length + 4; + iov.iov_len = len; smb_msg.msg_name = sin; smb_msg.msg_namelen = sizeof (struct sockaddr); @@ -143,10 +143,9 @@ smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); cFYI(1, ("Sending smb of length %d ", smb_buf_length)); - dump_smb(smb_buffer, smb_buf_length + 4); + dump_smb(smb_buffer, len); - len = smb_buf_length + 4; - while(iov.iov_len > 0) { + while (len > 0) { rc = kernel_sendmsg(ssocket, &smb_msg, &iov, 1, len); if ((rc == -ENOSPC) || (rc == -EAGAIN)) { i++; @@ -177,6 +176,208 @@ return rc; } +#ifdef CIFS_EXPERIMENTAL +/* BB finish off this function, adding support for writing set of pages as iovec */ +/* and also adding support for operations that need to parse the response smb */ + +int +smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer, + unsigned int smb_buf_length, struct kvec * write_vector /* page list */, struct sockaddr *sin) +{ + int rc = 0; + int i = 0; + struct msghdr smb_msg; + number_of_pages += 1; /* account for SMB header */ + struct kvec * piov = kmalloc(number_of_pages * sizeof(struct kvec)); + if(i=0;ismb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); + cFYI(1, ("Sending smb of length %d ", smb_buf_length)); + dump_smb(smb_buffer, len); + + while (len > 0) { + rc = kernel_sendmsg(ssocket, &smb_msg, &iov, number_of_pages, len?); + if ((rc == -ENOSPC) || (rc == -EAGAIN)) { + i++; + if(i > 60) { + cERROR(1, + ("sends on sock %p stuck for 30 seconds", + ssocket)); + rc = -EAGAIN; + break; + } + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/2); + continue; + } + if (rc < 0) + break; + iov.iov_base += rc; + iov.iov_len -= rc; + len -= rc; + } + + if (rc < 0) { + cERROR(1,("Error %d sending data on socket to server.", rc)); + } else { + rc = 0; + } + + return rc; +} + + +int +CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, + struct smb_hdr *in_buf, struct kvec * write_vector /* page list */, int *pbytes_returned, const int long_op) +{ + int rc = 0; + unsigned long timeout = 15 * HZ; + struct mid_q_entry *midQ = NULL; + + if (ses == NULL) { + cERROR(1,("Null smb session")); + return -EIO; + } + if(ses->server == NULL) { + cERROR(1,("Null tcp session")); + return -EIO; + } + if(pbytes_returned == NULL) + return -EIO; + else + *pbytes_returned = 0; + + + + /* Ensure that we do not send more than 50 overlapping requests + to the same server. We may make this configurable later or + use ses->maxReq */ + if(long_op == -1) { + /* oplock breaks must not be held up */ + atomic_inc(&ses->server->inFlight); + } else { + spin_lock(&GlobalMid_Lock); + while(1) { + if(atomic_read(&ses->server->inFlight) >= cifs_max_pending){ + spin_unlock(&GlobalMid_Lock); + wait_event(ses->server->request_q, + atomic_read(&ses->server->inFlight) + < cifs_max_pending); + spin_lock(&GlobalMid_Lock); + } else { + if(ses->server->tcpStatus == CifsExiting) { + spin_unlock(&GlobalMid_Lock); + return -ENOENT; + } + + /* can not count locking commands against total since + they are allowed to block on server */ + + if(long_op < 3) { + /* update # of requests on the wire to server */ + atomic_inc(&ses->server->inFlight); + } + spin_unlock(&GlobalMid_Lock); + break; + } + } + } + /* make sure that we sign in the same order that we send on this socket + and avoid races inside tcp sendmsg code that could cause corruption + of smb data */ + + down(&ses->server->tcpSem); + + if (ses->server->tcpStatus == CifsExiting) { + rc = -ENOENT; + goto cifs_out_label; + } else if (ses->server->tcpStatus == CifsNeedReconnect) { + cFYI(1,("tcp session dead - return to caller to retry")); + rc = -EAGAIN; + goto cifs_out_label; + } else if (ses->status != CifsGood) { + /* check if SMB session is bad because we are setting it up */ + if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && + (in_buf->Command != SMB_COM_NEGOTIATE)) { + rc = -EAGAIN; + goto cifs_out_label; + } /* else ok - we are setting up session */ + } + midQ = AllocMidQEntry(in_buf, ses); + if (midQ == NULL) { + up(&ses->server->tcpSem); + /* If not lock req, update # of requests on wire to server */ + if(long_op < 3) { + atomic_dec(&ses->server->inFlight); + wake_up(&ses->server->request_q); + } + return -ENOMEM; + } + + if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { + up(&ses->server->tcpSem); + cERROR(1, + ("Illegal length, greater than maximum frame, %d ", + in_buf->smb_buf_length)); + DeleteMidQEntry(midQ); + /* If not lock req, update # of requests on wire to server */ + if(long_op < 3) { + atomic_dec(&ses->server->inFlight); + wake_up(&ses->server->request_q); + } + return -EIO; + } + + /* BB can we sign efficiently in this path? */ + rc = cifs_sign_smb(in_buf, ses, &midQ->sequence_number); + + midQ->midState = MID_REQUEST_SUBMITTED; +/* rc = smb_sendv(ses->server->ssocket, in_buf, in_buf->smb_buf_length, piovec, + (struct sockaddr *) &(ses->server->addr.sockAddr));*/ + if(rc < 0) { + DeleteMidQEntry(midQ); + up(&ses->server->tcpSem); + /* If not lock req, update # of requests on wire to server */ + if(long_op < 3) { + atomic_dec(&ses->server->inFlight); + wake_up(&ses->server->request_q); + } + return rc; + } else + up(&ses->server->tcpSem); +cifs_out_label: + if(midQ) + DeleteMidQEntry(midQ); + + if(long_op < 3) { + atomic_dec(&ses->server->inFlight); + wake_up(&ses->server->request_q); + } + + return rc; +} + + +#endif /* CIFS_EXPERIMENTAL */ + int SendReceive(const unsigned int xid, struct cifsSesInfo *ses, struct smb_hdr *in_buf, struct smb_hdr *out_buf, @@ -205,11 +406,11 @@ } else { spin_lock(&GlobalMid_Lock); while(1) { - if(atomic_read(&ses->server->inFlight) >= CIFS_MAX_REQ){ + if(atomic_read(&ses->server->inFlight) >= cifs_max_pending){ spin_unlock(&GlobalMid_Lock); wait_event(ses->server->request_q, atomic_read(&ses->server->inFlight) - < CIFS_MAX_REQ); + < cifs_max_pending); spin_lock(&GlobalMid_Lock); } else { if(ses->server->tcpStatus == CifsExiting) { @@ -261,7 +462,7 @@ return -ENOMEM; } - if (in_buf->smb_buf_length > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE - 4) { + if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { up(&ses->server->tcpSem); cERROR(1, ("Illegal length, greater than maximum frame, %d ", @@ -275,9 +476,6 @@ return -EIO; } - if (in_buf->smb_buf_length > 12) - in_buf->Flags2 = cpu_to_le16(in_buf->Flags2); - rc = cifs_sign_smb(in_buf, ses, &midQ->sequence_number); midQ->midState = MID_REQUEST_SUBMITTED; @@ -311,20 +509,19 @@ /* if signal pending do not hold up user for full smb timeout but we still give response a change to complete */ timeout = 2 * HZ; - } /* No user interrupts in wait - wreaks havoc with performance */ if(timeout != MAX_SCHEDULE_TIMEOUT) { timeout += jiffies; wait_event(ses->server->response_q, - (midQ->midState & MID_RESPONSE_RECEIVED) || + (!(midQ->midState & MID_REQUEST_SUBMITTED)) || time_after(jiffies, timeout) || ((ses->server->tcpStatus != CifsGood) && (ses->server->tcpStatus != CifsNew))); } else { wait_event(ses->server->response_q, - (midQ->midState & MID_RESPONSE_RECEIVED) || + (!(midQ->midState & MID_REQUEST_SUBMITTED)) || ((ses->server->tcpStatus != CifsGood) && (ses->server->tcpStatus != CifsNew))); } @@ -332,7 +529,7 @@ spin_lock(&GlobalMid_Lock); if (midQ->resp_buf) { spin_unlock(&GlobalMid_Lock); - receive_len = be32_to_cpu(midQ->resp_buf->smb_buf_length); + receive_len = be32_to_cpu(*(__be32 *)midQ->resp_buf); } else { cERROR(1,("No response buffer")); if(midQ->midState == MID_REQUEST_SUBMITTED) { @@ -362,7 +559,7 @@ return rc; } - if (receive_len > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE) { + if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { cERROR(1, ("Frame too large received. Length: %d Xid: %d", receive_len, xid)); @@ -371,29 +568,20 @@ if (midQ->resp_buf && out_buf && (midQ->midState == MID_RESPONSE_RECEIVED)) { - memcpy(out_buf, midQ->resp_buf, - receive_len + - 4 /* include 4 byte RFC1001 header */ ); + out_buf->smb_buf_length = receive_len; + memcpy((char *)out_buf + 4, + (char *)midQ->resp_buf + 4, + receive_len); dump_smb(out_buf, 92); /* convert the length into a more usable form */ - out_buf->smb_buf_length = - be32_to_cpu(out_buf->smb_buf_length); - if((out_buf->smb_buf_length > 24) && + if((receive_len > 24) && (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) { rc = cifs_verify_signature(out_buf, ses->mac_signing_key,midQ->sequence_number); /* BB fix BB */ if(rc) cFYI(1,("Unexpected signature received from server")); } - if (out_buf->smb_buf_length > 12) - out_buf->Flags2 = le16_to_cpu(out_buf->Flags2); - if (out_buf->smb_buf_length > 28) - out_buf->Pid = le16_to_cpu(out_buf->Pid); - if (out_buf->smb_buf_length > 28) - out_buf->PidHigh = - le16_to_cpu(out_buf->PidHigh); - *pbytes_returned = out_buf->smb_buf_length; /* BB special case reconnect tid and reconnect uid here? */ diff -Nau fs/cifs/xattr.c fs/cifs.new-mm/xattr.c --- fs/cifs/xattr.c 2004-08-14 00:36:57.000000000 -0500 +++ fs/cifs.new-mm/xattr.c 2005-02-06 22:30:08.088928632 -0600 @@ -20,6 +20,7 @@ */ #include +#include #include "cifsfs.h" #include "cifspdu.h" #include "cifsglob.h" @@ -27,11 +28,16 @@ #include "cifs_debug.h" #define MAX_EA_VALUE_SIZE 65535 -#define CIFS_XATTR_DOS_ATTRIB "user.DOSATTRIB" +#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 */ +#define CIFS_XATTR_OS2_PREFIX "os2." +#define CIFS_XATTR_SECURITY_PREFIX ".security" +#define CIFS_XATTR_TRUSTED_PREFIX "trusted." +#define XATTR_TRUSTED_PREFIX_LEN 8 +#define XATTR_SECURITY_PREFIX_LEN 9 +/* BB need to add server (Samba e.g) support for security and trusted prefix */ + int cifs_removexattr(struct dentry * direntry, const char * ea_name) @@ -128,16 +134,47 @@ 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)); + } else if(strncmp(ea_name,CIFS_XATTR_USER_PREFIX,5) == 0) { + if(strncmp(ea_name,CIFS_XATTR_DOS_ATTRIB,14) == 0) { + cFYI(1,("attempt to set cifs inode metadata")); + } + ea_name += 5; /* skip past user. prefix */ + rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,ea_value, + (__u16)value_size, cifs_sb->local_nls); + } else if(strncmp(ea_name, CIFS_XATTR_OS2_PREFIX,4) == 0) { + ea_name += 4; /* skip past os2. prefix */ + rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,ea_value, + (__u16)value_size, cifs_sb->local_nls); + } else { + int temp; + temp = strncmp(ea_name,POSIX_ACL_XATTR_ACCESS, + strlen(POSIX_ACL_XATTR_ACCESS)); + if (temp == 0) { +#ifdef CONFIG_CIFS_POSIX + rc = CIFSSMBSetPosixACL(xid, pTcon,full_path,ea_value, + (const int)value_size, ACL_TYPE_ACCESS, + cifs_sb->local_nls); + cFYI(1,("set POSIX ACL rc %d",rc)); +#else + cFYI(1,("set POSIX ACL not supported")); +#endif + } else if(strncmp(ea_name,POSIX_ACL_XATTR_DEFAULT,strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) { +#ifdef CONFIG_CIFS_POSIX + rc = CIFSSMBSetPosixACL(xid, pTcon,full_path,ea_value, + (const int)value_size, ACL_TYPE_DEFAULT, + cifs_sb->local_nls); + cFYI(1,("set POSIX default ACL rc %d",rc)); +#else + cFYI(1,("set default POSIX ACL not supported")); +#endif + } else { + cFYI(1,("illegal xattr request %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); @@ -163,6 +200,7 @@ sb = direntry->d_inode->i_sb; if(sb == NULL) return -EIO; + xid = GetXid(); cifs_sb = CIFS_SB(sb); @@ -177,19 +215,54 @@ } /* 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? */ + if(ea_name == NULL) { + cFYI(1,("Null xattr names not supported")); + } else if(strncmp(ea_name,CIFS_XATTR_USER_PREFIX,5) == 0) { + if(strncmp(ea_name,CIFS_XATTR_DOS_ATTRIB,14) == 0) { + cFYI(1,("attempt to query cifs inode metadata")); + /* revalidate/getattr then populate from inode */ + } /* BB add else when above is implemented */ + ea_name += 5; /* skip past user. prefix */ + rc = CIFSSMBQueryEA(xid,pTcon,full_path,ea_name,ea_value, + buf_size, cifs_sb->local_nls); + } else if(strncmp(ea_name, CIFS_XATTR_OS2_PREFIX,4) == 0) { + ea_name += 4; /* skip past os2. prefix */ + rc = CIFSSMBQueryEA(xid,pTcon,full_path,ea_name,ea_value, + buf_size, cifs_sb->local_nls); + } else if(strncmp(ea_name,POSIX_ACL_XATTR_ACCESS,strlen(POSIX_ACL_XATTR_ACCESS)) == 0) { +#ifdef CONFIG_CIFS_POSIX + rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, + ea_value, buf_size, ACL_TYPE_ACCESS, + cifs_sb->local_nls); +#else + cFYI(1,("query POSIX ACL not supported yet")); +#endif /* CONFIG_CIFS_POSIX */ + } else if(strncmp(ea_name,POSIX_ACL_XATTR_DEFAULT,strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) { +#ifdef CONFIG_CIFS_POSIX + rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, + ea_value, buf_size, ACL_TYPE_DEFAULT, + cifs_sb->local_nls); +#else + cFYI(1,("query POSIX default ACL not supported yet")); +#endif + } else if(strncmp(ea_name, + CIFS_XATTR_TRUSTED_PREFIX,XATTR_TRUSTED_PREFIX_LEN) == 0) { + cFYI(1,("Trusted xattr namespace not supported yet")); + } else if(strncmp(ea_name, + CIFS_XATTR_SECURITY_PREFIX,XATTR_SECURITY_PREFIX_LEN) == 0) { + cFYI(1,("Security xattr namespace not supported yet")); } else { - /* We could add a check here + cFYI(1,("illegal xattr name request %s (only user namespace supported)",ea_name)); + } + + /* We could add an additional check for streams ie 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(rc == -EINVAL) + rc = -EOPNOTSUPP; + if (full_path) kfree(full_path); FreeXid(xid);