bk://cifs.bkbits.net/linux-2.5cifs cifs.adm@bkbits.net|ChangeSet|20041212212837|14552 cifs.adm # This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2004/12/12 00:06:48-06:00 sfrench@sambaltcdom.austin.ibm.com # [CIFS] Remove sparse warning in use of cifs_write function # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/file.c # 2004/12/12 00:06:24-06:00 sfrench@sambaltcdom.austin.ibm.com +122 -3 # remove sparse warning # # fs/cifs/cifssmb.c # 2004/12/12 00:06:23-06:00 sfrench@sambaltcdom.austin.ibm.com +15 -3 # remove sparse warning # # fs/cifs/cifsproto.h # 2004/12/12 00:06:23-06:00 sfrench@sambaltcdom.austin.ibm.com +2 -1 # remove sparse warning # # fs/cifs/cifsfs.h # 2004/12/12 00:06:23-06:00 sfrench@sambaltcdom.austin.ibm.com +2 -2 # remove sparse warning # # fs/cifs/cifsfs.c # 2004/12/12 00:06:23-06:00 sfrench@sambaltcdom.austin.ibm.com +1 -1 # remove sparse warning # # ChangeSet # 2004/12/11 17:04:11-06:00 sfrench@sambaltcdom.austin.ibm.com # [CIFS] remove sparse warning # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/file.c # 2004/12/11 17:04:03-06:00 sfrench@sambaltcdom.austin.ibm.com +3 -2 # remove sparse warning # # ChangeSet # 2004/12/11 16:27:16-06:00 stevef@smfhome.smfdom # Add support for module init parms for number of small and large cifs network # buffers and for maximum number of simultaneous requests. Fix directio of # userbuffers to use copy_to_user. # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/transport.c # 2004/12/11 16:27:08-06:00 stevef@smfhome.smfdom +4 -4 # Add support for module init parms for number of small and large cifs network # buffers and for maximum number of simultaneous requests. # # fs/cifs/file.c # 2004/12/11 16:27:07-06:00 stevef@smfhome.smfdom +76 -0 # Create safer routine for handling directio reads to user buffer for cifs # # fs/cifs/connect.c # 2004/12/11 16:27:07-06:00 stevef@smfhome.smfdom +2 -2 # Add support for module init parms for number of small and large cifs network # buffers and for maximum number of simultaneous requests. # # fs/cifs/cifsglob.h # 2004/12/11 16:27:07-06:00 stevef@smfhome.smfdom +5 -1 # Add support for module init parms for number of small and large cifs network # buffers and for maximum number of simultaneous requests. # # fs/cifs/cifsfs.h # 2004/12/11 16:27:07-06:00 stevef@smfhome.smfdom +1 -1 # Create safer routine for handling directio reads to user buffer for cifs # # fs/cifs/cifsfs.c # 2004/12/11 16:27:07-06:00 stevef@smfhome.smfdom +46 -5 # Add support for module init parms for number of small and large cifs network # buffers and for maximum number of simultaneous requests. # # fs/cifs/CHANGES # 2004/12/11 16:27:07-06:00 stevef@smfhome.smfdom +3 -1 # Update cifs change log # # ChangeSet # 2004/12/10 12:57:28-06:00 sfrench@sambaltcdom.austin.ibm.com # [CIFS] Allow peek to return less than smb header so we do not prematurely kill session to server when # socket stack is busy. # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/connect.c # 2004/12/10 12:57:20-06:00 sfrench@sambaltcdom.austin.ibm.com +3 -3 # Allow peek to return less than smb header so we do not prematurely kill session to server when socket stack is busy # # fs/cifs/TODO # 2004/12/10 12:57:19-06:00 sfrench@sambaltcdom.austin.ibm.com +16 -18 # update cifs todo/known restrictions # # fs/cifs/README # 2004/12/10 12:57:18-06:00 sfrench@sambaltcdom.austin.ibm.com +17 -4 # update cifs readme # # ChangeSet # 2004/12/10 10:46:32-06:00 stevef@smfhome.smfdom # [CIFS] Do not block on FindNotify response # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/misc.c # 2004/12/10 10:46:23-06:00 stevef@smfhome.smfdom +24 -3 # Do not block on FindNotify response # # fs/cifs/cifssmb.c # 2004/12/10 10:46:23-06:00 stevef@smfhome.smfdom +1 -1 # Do not block on FindNotify response # # fs/cifs/cifsfs.h # 2004/12/10 10:46:23-06:00 stevef@smfhome.smfdom +1 -1 # Update version for 1.27 # # fs/cifs/CHANGES # 2004/12/10 10:46:23-06:00 stevef@smfhome.smfdom +8 -0 # Update change log for 1.27 # # ChangeSet # 2004/12/09 18:50:28-06:00 sfrench@sambaltcdom.austin.ibm.com # [CIFS] Check right mid state on hung network responses. Fix remote # dnotify to be disabled by default. Fix dnotify endianness. # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/transport.c # 2004/12/09 18:50:07-06:00 sfrench@sambaltcdom.austin.ibm.com +2 -2 # Check right mid state on hung network responses # # fs/cifs/fcntl.c # 2004/12/09 18:50:07-06:00 sfrench@sambaltcdom.austin.ibm.com +48 -4 # fix remote dnotify code # # fs/cifs/cifspdu.h # 2004/12/09 18:50:07-06:00 sfrench@sambaltcdom.austin.ibm.com +17 -5 # Add new infolevels for QPathInfo, fix remote dnotify endianness # # fs/cifs/cifsfs.c # 2004/12/09 18:50:07-06:00 sfrench@sambaltcdom.austin.ibm.com +4 -0 # don not call remote notify by default # # ChangeSet # 2004/12/07 17:37:18-06:00 sfrench@sambaltcdom.austin.ibm.com # [CIFS] parse ipv6 addresses on mount (ipv6 support for cifs part 2) # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/connect.c # 2004/12/07 17:36:40-06:00 sfrench@sambaltcdom.austin.ibm.com +10 -0 # parse ipv6 addresses on mount # # ChangeSet # 2004/12/07 17:23:42-06:00 sfrench@sambaltcdom.austin.ibm.com # [CIFS] Increase size of small SMB pool (and decrease number) and # do not zero the beginning of the header twice. # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/misc.c # 2004/12/07 17:22:59-06:00 sfrench@sambaltcdom.austin.ibm.com +6 -18 # Increase size of small SMBs and do not zero the beginning of the header twice. # # fs/cifs/cifssmb.c # 2004/12/07 17:22:59-06:00 sfrench@sambaltcdom.austin.ibm.com +73 -26 # Add support for small cifs request buffers # # fs/cifs/cifsproto.h # 2004/12/07 17:22:59-06:00 sfrench@sambaltcdom.austin.ibm.com +0 -2 # Add support for small cifs request buffers # # fs/cifs/cifsglob.h # 2004/12/07 17:22:59-06:00 sfrench@sambaltcdom.austin.ibm.com +0 -2 # Add support for small cifs request buffers # # fs/cifs/cifsfs.c # 2004/12/07 17:22:59-06:00 sfrench@sambaltcdom.austin.ibm.com +10 -15 # Increase size of small SMBs (and reduce number of them) # # fs/cifs/cifs_debug.c # 2004/12/07 17:22:59-06:00 sfrench@sambaltcdom.austin.ibm.com +0 -2 # Add support for small cifs request buffers # # ChangeSet # 2004/12/07 00:28:46-06:00 sfrench@sambaltcdom.austin.ibm.com # [CIFS] add debug message for trusted and security xattrs # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/xattr.c # 2004/12/07 00:28:22-06:00 sfrench@sambaltcdom.austin.ibm.com +14 -3 # add debug message for trusted and security xattrs # # ChangeSet # 2004/12/06 23:48:54-06:00 sfrench@sambaltcdom.austin.ibm.com # [CIFS] cleanup various warning/debug messages # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/readdir.c # 2004/12/06 23:48:16-06:00 sfrench@sambaltcdom.austin.ibm.com +13 -24 # cleanup various warning/debug messages # # fs/cifs/cifspdu.h # 2004/12/06 23:48:16-06:00 sfrench@sambaltcdom.austin.ibm.com +1 -1 # misc struct cleanup # # ChangeSet # 2004/12/02 14:48:13-06:00 sfrench@sambaltcdom.austin.ibm.com # [CIFS] fix spelling of CONFIG_CIFS_EXPERIMENTAL ifdef in direct i/o write # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/connect.c # 2004/12/02 14:48:06-06:00 sfrench@sambaltcdom.austin.ibm.com +7 -2 # fix parsing of dir_mode vs. direct in mount options parsing # # fs/cifs/cifsfs.c # 2004/12/02 14:48:05-06:00 sfrench@sambaltcdom.austin.ibm.com +4 -3 # fix spelling of CONFIG_CIFS_EXPERIMENTAL ifdef in direct i/o write # # ChangeSet # 2004/12/02 14:38:34-06:00 stevef@stevef95.austin.ibm.com # [CIFS] zero more of SMB param area on SMB allocation # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/misc.c # 2004/12/02 14:38:24-06:00 stevef@stevef95.austin.ibm.com +4 -4 # zero more of SMB param area on SMB allocation # # fs/cifs/cifssmb.c # 2004/12/02 14:38:24-06:00 stevef@stevef95.austin.ibm.com +2 -0 # Init two unitialized rsrvd fields in write smb # # ChangeSet # 2004/12/01 23:34:34-06:00 stevef@smfhome.smfdom # add direct mount options to optionally bypass the page cache on reads and writes # # fs/cifs/file.c # 2004/12/01 23:34:25-06:00 stevef@smfhome.smfdom +11 -0 # [CIFS] add "direct" cifs mount options to allow bypass of the page cache on # reads and writes (currently only available when CIFS_EXPERIMENTAL config switch # is enabled). # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/connect.c # 2004/12/01 23:34:25-06:00 stevef@smfhome.smfdom +9 -0 # add direct mount options to optionally bypass the page cache on reads and writes # # fs/cifs/cifsfs.c # 2004/12/01 23:34:25-06:00 stevef@smfhome.smfdom +25 -0 # add direct mount options to optionally bypass the page cache on reads and writes # # fs/cifs/cifs_fs_sb.h # 2004/12/01 23:34:25-06:00 stevef@smfhome.smfdom +2 -1 # add direct mount options to bypass the page cache on reads and writes # # fs/cifs/README # 2004/12/01 23:34:25-06:00 stevef@smfhome.smfdom +30 -4 # update cifs readme for new cifs mount options # # ChangeSet # 2004/12/01 18:52:48-06:00 stevef@stevef95.austin.ibm.com # [CIFS] Fix endianness bug in new cifs_readdir2 in calculating dir entry name length. Fix "badness in" message on rmmod cifs caused by rename of # /proc/fs/cifs/NewReaddirEnabled config switch (pointed out by Shaggy). # # Fix improper clearing of UNIX_BASIC_INFO cifs struct. # Pointed out by Stefan Rompf. # # Signed-off-by: David Kleikamp (shaggy@austin.ibm.com) # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/readdir.c # 2004/12/01 18:52:38-06:00 stevef@stevef95.austin.ibm.com +13 -13 # Name length field not properly endian converted in new cifs_readdir code in non-Samba server case # (pointed out by Shaggy) # # fs/cifs/cifssmb.c # 2004/12/01 18:52:38-06:00 stevef@stevef95.austin.ibm.com +1 -0 # UnixSetTimes does not properly zero FILE_UNIX_BASIC_INFO struct (can leave junk in a few fields). Pointed out by Stefan Rompf. # # fs/cifs/cifs_debug.c # 2004/12/01 18:52:38-06:00 stevef@stevef95.austin.ibm.com +1 -1 # fix "badness in" message on rmmod cifs caused by rename of /proc/fs/cifs/NewReaddirEnabled config # switch (pointed out by Shaggy) # # fs/cifs/CHANGES # 2004/12/01 18:52:38-06:00 stevef@stevef95.austin.ibm.com +2 -1 # update cifs change log # # ChangeSet # 2004/12/01 01:32:43-06:00 stevef@smfhome.smfdom # [CIFS] Make new cifs readdir code the default and rename the proc entry # to /proc/fs/cifs/ReenableOldCifsReaddirCode (which is off by default, # causing the new cifs_readdir2 code to be executed by default) # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/file.c # 2004/12/01 01:32:34-06:00 stevef@smfhome.smfdom +1 -1 # Make new cifs readdir code the default and rename the proc entry to /proc/fs/cifs/ReenableOldCifsReaddirCode (which is off by default, causing the new cifs_readdir2 code to be executed by default) # # fs/cifs/cifs_debug.c # 2004/12/01 01:32:34-06:00 stevef@smfhome.smfdom +1 -1 # Make new cifs readdir code the default and rename the proc entry to /proc/fs/cifs/ReenableOldCifsReaddirCode (which is off by default, causing the new cifs_readdir2 code to be executed by default) # # ChangeSet # 2004/12/01 01:12:32-06:00 stevef@smfhome.smfdom # [CIFS] Add missing quote to cifs kconfig item # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/connect.c # 2004/12/01 01:12:23-06:00 stevef@smfhome.smfdom +6 -5 # Workaround weird Samba server behavior on passthrough authentication (which requires # bogus lanman password value) # # fs/Kconfig # 2004/12/01 01:12:23-06:00 stevef@smfhome.smfdom +1 -1 # Add missing quote # # ChangeSet # 2004/12/01 00:43:37-06:00 stevef@smfhome.smfdom # [CIFS] Update Kconfig to make CIFS POSIX ACLs dependent on xattrs and # fix related ifdef in fs/cifs/xattr.c # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/xattr.c # 2004/12/01 00:43:28-06:00 stevef@smfhome.smfdom +11 -6 # Update Kconfig to make POSIX ACLs dependent on xattrs # # fs/cifs/cifspdu.h # 2004/12/01 00:43:28-06:00 stevef@smfhome.smfdom +1 -1 # Fix little endian annotations regression which broke extended security enablement # (only happens if you enable proc/fs/cifs/ExtendedSecurity) # # fs/Kconfig # 2004/12/01 00:43:28-06:00 stevef@smfhome.smfdom +12 -2 # Update Kconfig to make POSIX ACLs dependent on xattrs # # ChangeSet # 2004/11/30 22:49:40-06:00 stevef@smfhome.smfdom # [CIFS] fix error mapping on getfacl to windows and old samba servers to map to EOPNOTSUPP # so the kernel's fall back mechanism works # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/xattr.c # 2004/11/30 22:49:31-06:00 stevef@smfhome.smfdom +3 -0 # fix error mapping on getfacl to windows and old samba servers to map to EOPNOTSUPP so the kernel's # fall back mechanism works # # fs/cifs/netmisc.c # 2004/11/30 22:49:31-06:00 stevef@smfhome.smfdom +1 -0 # fix error mapping on getfacl to windows and old samba servers to map to EOPNOTSUPP so the kernel's # fall back mechanism works # # fs/cifs/CHANGES # 2004/11/30 22:49:31-06:00 stevef@smfhome.smfdom +6 -0 # Update cifs vfs change log for version 1.26 # # ChangeSet # 2004/11/30 17:11:55-06:00 stevef@smfhome.smfdom # [CIFS] Set inode number properly on new cifs_readdir code to Windows servers # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/readdir.c # 2004/11/30 17:11:45-06:00 stevef@smfhome.smfdom +2 -1 # Set inode number properly on new readdir code to Windows servers # # ChangeSet # 2004/11/30 16:15:06-06:00 stevef@smfhome.smfdom # [CIFS] fix size of cifs small buffers to just barely fit within slab limit # (which appears to be 116 bytes), otherwise they take 1 page each. # Add them to cifs debug counters and optionally use them for SMBClose. # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/misc.c # 2004/11/30 16:14:57-06:00 stevef@smfhome.smfdom +2 -2 # change name of CIFS_EXPERIMENTAL ifdef to CONFIG_CIFS_EXPERIMENTAL so it can be added to Kconfig # # fs/cifs/cifssmb.c # 2004/11/30 16:14:57-06:00 stevef@smfhome.smfdom +108 -3 # add support to smb close to optionally use new small buffer allocation code # # fs/cifs/cifsproto.h # 2004/11/30 16:14:57-06:00 stevef@smfhome.smfdom +5 -1 # add missing extern in experimental buf allocation code # # fs/cifs/cifsglob.h # 2004/11/30 16:14:57-06:00 stevef@smfhome.smfdom +4 -1 # fix size of cifs small buffers to just barely fit within slab limit # (which appears to be 116 bytes), otherwise they take 1 page each. # # fs/cifs/cifsfs.h # 2004/11/30 16:14:57-06:00 stevef@smfhome.smfdom +1 -1 # update cifs version # # fs/cifs/cifsfs.c # 2004/11/30 16:14:57-06:00 stevef@smfhome.smfdom +9 -8 # fix size of cifs small buffers to just barely fit within slab limit # (which appears to be 116 bytes), otherwise they take 1 page each. # # fs/cifs/cifs_debug.c # 2004/11/30 16:14:57-06:00 stevef@smfhome.smfdom +8 -1 # show number of small smb buffers in debug output when cifs small buffers enabled. # # ChangeSet # 2004/11/30 14:46:29-06:00 stevef@smfhome.smfdom # [CIFS] minor cleanup to cifs buffer allocation code # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/cifsfs.c # 2004/11/30 14:46:20-06:00 stevef@smfhome.smfdom +1 -0 # minor cleanup to cifs buffer allocation code # # ChangeSet # 2004/11/30 14:34:40-06:00 stevef@smfhome.smfdom # [CIFS] CIFS buffer management improvements part 1 # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/misc.c # 2004/11/30 14:34:31-06:00 stevef@smfhome.smfdom +45 -2 # add cifs small buffers to make buffer allocation more efficient # # fs/cifs/connect.c # 2004/11/30 14:34:31-06:00 stevef@smfhome.smfdom +1 -1 # cleanup whitespace # # fs/cifs/cifspdu.h # 2004/11/30 14:34:31-06:00 stevef@smfhome.smfdom +1 -1 # clarify comment # # fs/cifs/cifsglob.h # 2004/11/30 14:34:31-06:00 stevef@smfhome.smfdom +1 -0 # add cifs small buffers to make buffer allocation more efficient # # fs/cifs/cifsfs.c # 2004/11/30 14:34:31-06:00 stevef@smfhome.smfdom +36 -0 # add cifs small buffers to make buffer allocation more efficient # # ChangeSet # 2004/11/30 02:04:25-06:00 sfrench@sambaltcdom.austin.ibm.com # [CIFS] cifs readdir rewrite fix resume key handling # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/readdir.c # 2004/11/30 02:04:17-06:00 sfrench@sambaltcdom.austin.ibm.com +69 -3 # cifs readdir rewrite fix resume key handling # # fs/cifs/file.c # 2004/11/30 02:04:17-06:00 sfrench@sambaltcdom.austin.ibm.com +3 -3 # cifs readdir rewrite fix resume key handling # # fs/cifs/cifssmb.c # 2004/11/30 02:04:17-06:00 sfrench@sambaltcdom.austin.ibm.com +23 -14 # cifs readdir rewrite fix resume key handling # # fs/cifs/cifspdu.h # 2004/11/30 02:04:17-06:00 sfrench@sambaltcdom.austin.ibm.com +1 -1 # cifs readdir rewrite fix resume key handling # # fs/cifs/cifsglob.h # 2004/11/30 02:04:17-06:00 sfrench@sambaltcdom.austin.ibm.com +4 -2 # cifs readdir rewrite fix resume key handling # # ChangeSet # 2004/11/29 16:21:48-06:00 stevef@smfhome1.smfdom # [CIFS] Add setfacl support to cifs # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/xattr.c # 2004/11/29 16:21:39-06:00 stevef@smfhome1.smfdom +13 -2 # Add set posix acl support to cifs # # fs/cifs/cifssmb.c # 2004/11/29 16:21:39-06:00 stevef@smfhome1.smfdom +152 -5 # Add set posix acl support to cifs # # fs/cifs/cifsproto.h # 2004/11/29 16:21:39-06:00 stevef@smfhome1.smfdom +4 -1 # Add set posix acl support to cifs # # ChangeSet # 2004/11/29 00:09:55-06:00 sfrench@sambaltcdom.austin.ibm.com # [CIFS] cifs readdir part 11. Also renames unused /proc/fs/cifs/QuotaEnabled config switch to NewReaddirEnabled for turning on testing of new readdir code # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/readdir.c # 2004/11/29 00:09:47-06:00 sfrench@sambaltcdom.austin.ibm.com +181 -88 # add support for windows servers to new search code, disable various debug code # # fs/cifs/file.c # 2004/11/29 00:09:47-06:00 sfrench@sambaltcdom.austin.ibm.com +37 -4 # rename unused quotaEnabled config swith to enable test for new readdir code # # fs/cifs/cifssmb.c # 2004/11/29 00:09:47-06:00 sfrench@sambaltcdom.austin.ibm.com +4 -14 # set info level on findfirst outside of CIFSSMBFindFirst so we can properly # tell when we want serverino numbers # # fs/cifs/cifsglob.h # 2004/11/29 00:09:47-06:00 sfrench@sambaltcdom.austin.ibm.com +2 -2 # rename unused quotaEnabled config swith to enable test for new readdir code # # fs/cifs/cifsfs.c # 2004/11/29 00:09:47-06:00 sfrench@sambaltcdom.austin.ibm.com +1 -1 # rename unused quotaEnabled config swith to enable test for new readdir code # # fs/cifs/cifs_debug.c # 2004/11/29 00:09:47-06:00 sfrench@sambaltcdom.austin.ibm.com +5 -5 # rename unused quotaEnabled config swith to enable test for new readdir code # # ChangeSet # 2004/11/26 17:06:07-06:00 sfrench@sambaltcdom.austin.ibm.com # [CIFS] fix ls -l warning on dirs when POSIX ACLs enabled. # Fixed by not returning -ERANCE error on null buffer on QueryACL # (getxattr for ACLs will null buffer, zero len queries size) # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/xattr.c # 2004/11/26 17:05:47-06:00 sfrench@sambaltcdom.austin.ibm.com +1 -1 # fix extra whitespace # # fs/cifs/cifssmb.c # 2004/11/26 17:05:46-06:00 sfrench@sambaltcdom.austin.ibm.com +9 -9 # fix -ERANCE error on null buffer on QueryACL (getxattr for ACLs) # # ChangeSet # 2004/11/26 16:15:35-06:00 sfrench@sambaltcdom.austin.ibm.com # [CIFS] cifs readdir changes part 10 remove unneeded debug function # # Signed-off- by: Steve French (sfrench@us.ibm.com) # # fs/cifs/dir.c # 2004/11/26 16:15:26-06:00 sfrench@sambaltcdom.austin.ibm.com +0 -3 # remove unneeded debug statement # # fs/cifs/cifssmb.c # 2004/11/26 16:15:26-06:00 sfrench@sambaltcdom.austin.ibm.com +5 -2 # fix FindFirst2 setting of last entry in buf # # fs/cifs/cifsglob.h # 2004/11/26 16:15:26-06:00 sfrench@sambaltcdom.austin.ibm.com +1 -0 # add mid flag # # ChangeSet # 2004/11/25 11:55:40-06:00 sfrench@sambaltcdom.austin.ibm.com # [CIFS] POSIX ACL support part 3 # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/xattr.c # 2004/11/25 11:55:31-06:00 sfrench@sambaltcdom.austin.ibm.com +8 -22 # fix ace conversion in cifs posix acl support # # fs/cifs/smberr.h # 2004/11/25 11:55:31-06:00 sfrench@sambaltcdom.austin.ibm.com +1 -0 # fix return code mapping on errors on xattr get # # fs/cifs/netmisc.c # 2004/11/25 11:55:31-06:00 sfrench@sambaltcdom.austin.ibm.com +2 -1 # fix return code mapping on errors on xattr get # # fs/cifs/cifssmb.c # 2004/11/25 11:55:31-06:00 sfrench@sambaltcdom.austin.ibm.com +71 -5 # Fix return code mapping on errors on xattr get. # Convert cifs posix access control entries to local posix acl xattr format # # fs/cifs/cifsproto.h # 2004/11/25 11:55:31-06:00 sfrench@sambaltcdom.austin.ibm.com +3 -3 # add support for get on default POSIX ACL via cifs # # fs/cifs/cifspdu.h # 2004/11/25 11:55:31-06:00 sfrench@sambaltcdom.austin.ibm.com +2 -2 # make cifs posix acl uid little endian # # fs/cifs/cifsfs.c # 2004/11/25 11:55:30-06:00 sfrench@sambaltcdom.austin.ibm.com +6 -0 # allow acl operations on directories # # ChangeSet # 2004/11/24 00:55:51-06:00 sfrench@sambaltcdom.austin.ibm.com # [CIFS] POSIX ACL support part 2 # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/xattr.c # 2004/11/24 00:55:32-06:00 sfrench@sambaltcdom.austin.ibm.com +33 -15 # cifs onthewire POSIX ACL support part two # # fs/cifs/connect.c # 2004/11/24 00:55:32-06:00 sfrench@sambaltcdom.austin.ibm.com +15 -2 # add acl and noacl mount options for cifs # # fs/cifs/cifsproto.h # 2004/11/24 00:55:32-06:00 sfrench@sambaltcdom.austin.ibm.com +5 -0 # cifs onthewire POSIX ACL support part two # # fs/cifs/cifspdu.h # 2004/11/24 00:55:32-06:00 sfrench@sambaltcdom.austin.ibm.com +21 -10 # cifs onthewire POSIX ACL support part two # # ChangeSet # 2004/11/24 00:27:37-06:00 sfrench@sambaltcdom.austin.ibm.com # [CIFS] cifs readdir rewrite part 9 - fix unicode strlen to be more readable following Shaggy's suggestion # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/readdir.c # 2004/11/24 00:27:17-06:00 sfrench@sambaltcdom.austin.ibm.com +14 -17 # fix unicode strlen to be more readable # # fs/cifs/CHANGES # 2004/11/24 00:27:17-06:00 sfrench@sambaltcdom.austin.ibm.com +9 -0 # Update cifs change log for 1.25 # # ChangeSet # 2004/11/23 01:16:05-06:00 sfrench@sambaltcdom.austin.ibm.com # [CIFS] cifs readdir rewrite part 8 # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/readdir.c # 2004/11/23 01:15:57-06:00 sfrench@sambaltcdom.austin.ibm.com +165 -23 # cifs readdir part 8 # # ChangeSet # 2004/11/22 01:43:48-06:00 sfrench@sambaltcdom.austin.ibm.com # [CIFS] cifs readdir changes part 7 # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/readdir.c # 2004/11/22 01:43:29-06:00 sfrench@sambaltcdom.austin.ibm.com +137 -9 # cifs readdir changes part 7 # # fs/cifs/cifssmb.c # 2004/11/22 01:43:29-06:00 sfrench@sambaltcdom.austin.ibm.com +5 -5 # rename search fields # # fs/cifs/cifsglob.h # 2004/11/22 01:43:29-06:00 sfrench@sambaltcdom.austin.ibm.com +2 -2 # rename search fields # # ChangeSet # 2004/11/19 12:53:07-06:00 sfrench@smft41.(none) # [CIFS] POSIX ACL support part 1 # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/xattr.c # 2004/11/19 12:52:57-06:00 sfrench@smft41.(none) +56 -17 # add suppor for query of posix acls # # fs/cifs/readdir.c # 2004/11/19 12:52:57-06:00 sfrench@smft41.(none) +1 -1 # cleanup compiler warning # # fs/cifs/cifssmb.c # 2004/11/19 12:52:57-06:00 sfrench@smft41.(none) +95 -5 # add suppor for query of posix acls # # fs/cifs/cifspdu.h # 2004/11/19 12:52:57-06:00 sfrench@smft41.(none) +23 -0 # add suppor for query of posix acls # # fs/cifs/cifsfs.h # 2004/11/19 12:52:56-06:00 sfrench@smft41.(none) +1 -1 # bump version number # # ChangeSet # 2004/11/19 09:08:50-06:00 sfrench@smft41.(none) # [CIFS] cifs readdir changes part 6 # # move cifs search specific file handle info into distinct struct, create new FindFirst SMB worker function # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/readdir.c # 2004/11/19 09:08:40-06:00 sfrench@smft41.(none) +42 -21 # move cifs search specific file handle info into distinct struct for new findfirst code # # fs/cifs/file.c # 2004/11/19 09:08:40-06:00 sfrench@smft41.(none) +19 -15 # move cifs search specific file handle info into distinct struct # # fs/cifs/cifssmb.c # 2004/11/19 09:08:40-06:00 sfrench@smft41.(none) +154 -33 # move cifs search specific file handle info into distinct struct # # fs/cifs/cifsglob.h # 2004/11/19 09:08:40-06:00 sfrench@smft41.(none) +12 -5 # move cifs search specific file handle info into distinct struct # # fs/cifs/Makefile # 2004/11/19 09:08:40-06:00 sfrench@smft41.(none) +1 -1 # Move cifs readdir code to new file # # ChangeSet # 2004/11/17 23:23:11-06:00 sfrench@smft41.(none) # [CIFS} cifs readdir part 5 # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/transport.c # 2004/11/17 23:23:01-06:00 sfrench@smft41.(none) +21 -8 # cleanup experimental new cifs send code # # fs/cifs/readdir.c # 2004/11/17 23:23:01-06:00 sfrench@smft41.(none) +29 -23 # cifs readdir part 5 # # fs/cifs/cifsglob.h # 2004/11/17 23:23:01-06:00 sfrench@smft41.(none) +1 -0 # cifs readdir part 5 # # ChangeSet # 2004/11/17 17:31:56-06:00 stevef@stevef95.austin.ibm.com # [CIFS] Improve SMB buffer allocation make SMB sending more efficient part 1 # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/transport.c # 2004/11/17 17:31:46-06:00 stevef@stevef95.austin.ibm.com +123 -0 # Create more efficient SMB send path # # fs/cifs/cifspdu.h # 2004/11/17 17:31:46-06:00 stevef@stevef95.austin.ibm.com +14 -11 # Improve SMB buffer allocation # # ChangeSet # 2004/11/17 10:59:24-06:00 sfrench@smft41.(none) # CIFS: additional smb trans2 cleanup # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/cifssmb.c # 2004/11/17 10:59:14-06:00 sfrench@smft41.(none) +88 -70 # additional smb trans2 cleanup # # ChangeSet # 2004/11/16 17:54:04-06:00 stevef@stevef95.austin.ibm.com # [CIFS] smb transact2 cleanup # # Signed-of-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/cifssmb.c # 2004/11/16 17:53:54-06:00 stevef@stevef95.austin.ibm.com +8 -8 # smb transact2 cleanup # # fs/cifs/cifspdu.h # 2004/11/16 17:53:54-06:00 stevef@stevef95.austin.ibm.com +5 -45 # smb transact2 cleanup # # ChangeSet # 2004/11/14 22:42:26-06:00 sfrench@smft41.(none) # [CIFS] Improve SMB transact2 error checking and fix typo in warning message # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/connect.c # 2004/11/14 22:42:17-06:00 sfrench@smft41.(none) +1 -1 # fix typo in warning message # # fs/cifs/cifssmb.c # 2004/11/14 22:42:17-06:00 sfrench@smft41.(none) +26 -3 # fixup SMB transact2 structures and improve transact2 error checking # # fs/cifs/cifspdu.h # 2004/11/14 22:42:17-06:00 sfrench@smft41.(none) +22 -22 # fixup SMB transact2 structures # # ChangeSet # 2004/11/14 16:30:21-06:00 sfrench@smft41.(none) # [CIFS] CIFS readdir fixes part 4 # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/cifssmb.c # 2004/11/14 16:30:11-06:00 sfrench@smft41.(none) +7 -7 # update transact2 structure definitions # # fs/cifs/cifspdu.h # 2004/11/14 16:30:11-06:00 sfrench@smft41.(none) +3 -23 # update transact2 structure definitions # # ChangeSet # 2004/11/13 17:54:03-06:00 sfrench@smft41.(none) # [CIFS] cifs readdir changes part 3 # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/cifssmb.c # 2004/11/13 17:53:53-06:00 sfrench@smft41.(none) +61 -15 # cifs readdir changes part 3 # # fs/cifs/cifspdu.h # 2004/11/13 17:53:53-06:00 sfrench@smft41.(none) +137 -90 # cifs readdir changes part 3 # # ChangeSet # 2004/11/12 18:15:15-06:00 stevef@stevef95.austin.ibm.com # cifs readdir fixes part 2 # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/readdir.c # 2004/11/12 18:15:03-06:00 stevef@stevef95.austin.ibm.com +51 -15 # cifs readdir fixes part 2 # # fs/cifs/cifsglob.h # 2004/11/12 18:15:03-06:00 stevef@stevef95.austin.ibm.com +5 -3 # cifs readdir fixes part 2 # # ChangeSet # 2004/11/11 16:40:47-06:00 stevef@stevef95.austin.ibm.com # [CIFS] cifs readdir fixes part 1 # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/readdir.c # 2004/11/11 16:40:37-06:00 stevef@stevef95.austin.ibm.com +169 -0 # # fs/cifs/readdir.c # 2004/11/11 16:40:37-06:00 stevef@stevef95.austin.ibm.com +0 -0 # BitKeeper file /home/stevef/linux-2.5cifs/fs/cifs/readdir.c # # fs/cifs/cifssmb.c # 2004/11/11 16:40:37-06:00 stevef@stevef95.austin.ibm.com +128 -0 # cifs readdir fixes part 1 # # ChangeSet # 2004/11/09 21:43:59-06:00 sfrench@smft41.(none) # [CIFS] level 261 findfirst part 2 # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/cifspdu.h # 2004/11/09 21:43:41-06:00 sfrench@smft41.(none) +5 -4 # fix level 258 and 261 findfirst layout # # ChangeSet # 2004/11/09 13:16:33-06:00 sfrench@smft41.(none) # [CIFS] level 261 findfirst part one (will help with returning stable # server inode numbers from Windows servers) # # Signed-of-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/cifspdu.h # 2004/11/09 13:16:23-06:00 sfrench@smft41.(none) +19 -1 # level 261 findfirst part one # # fs/cifs/README # 2004/11/09 13:16:23-06:00 sfrench@smft41.(none) +16 -0 # update description of cifs mount parms # # ChangeSet # 2004/11/07 19:40:43-06:00 sfrench@smft41.(none) # [CIFS] Add cifs serverino mount parm to allow use of inode numbers reported from # the server (rather than generated by the client). Some apps require inode # numbers to persist or inode numbers of hardlinked files to match and # this requires trusting the servers inode number. # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # # # fs/cifs/inode.c # 2004/11/07 19:40:36-06:00 sfrench@smft41.(none) +22 -0 # Add serverino mount parm to allow use of inode numbers reported from the server (rather than generated by the client) # # fs/cifs/file.c # 2004/11/07 19:40:36-06:00 sfrench@smft41.(none) +29 -9 # Add serverino mount parm to allow use of inode numbers reported from the server (rather than generated by the client) # # fs/cifs/fcntl.c # 2004/11/07 19:40:36-06:00 sfrench@smft41.(none) +1 -1 # fix whitespace # # fs/cifs/connect.c # 2004/11/07 19:40:36-06:00 sfrench@smft41.(none) +7 -0 # Add serverino mount parm to allow use of inode numbers reported from the server (rather than generated by the client) # # fs/cifs/cifspdu.h # 2004/11/07 19:40:36-06:00 sfrench@smft41.(none) +34 -0 # new trans2 findfirst info levels # # fs/cifs/cifsfs.h # 2004/11/07 19:40:36-06:00 sfrench@smft41.(none) +1 -1 # update cifs version to 1.24 # # fs/cifs/cifs_fs_sb.h # 2004/11/07 19:40:36-06:00 sfrench@smft41.(none) +2 -1 # Add serverino mount parm to allow use of inode numbers reported from the server (rather than generated by the client) # # fs/cifs/CHANGES # 2004/11/07 19:40:36-06:00 sfrench@smft41.(none) +6 -0 # Update cifs change log for cifs version 1.24 # # ChangeSet # 2004/10/21 22:36:00-05:00 sfrench@smft41.(none) # [CIFS] treat NTFS junctions (reparse points) as directories rather than symlinks since we can not follow them # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/inode.c # 2004/10/21 22:35:51-05:00 sfrench@smft41.(none) +4 -4 # treat NTFS junctions (reparse points) as directories rather than symlinks since we can not follow them # # fs/cifs/file.c # 2004/10/21 22:35:51-05:00 sfrench@smft41.(none) +5 -6 # treat NTFS junctions (reparse points) as directories rather than symlinks since we can not follow them # # fs/cifs/README # 2004/10/21 22:35:51-05:00 sfrench@smft41.(none) +4 -0 # Update readme for missing cifs mount options # # fs/cifs/CHANGES # 2004/10/21 22:35:51-05:00 sfrench@smft41.(none) +2 -1 # update cifs change log # # ChangeSet # 2004/10/19 17:59:37-05:00 sfrench@smft41.(none) # Merge bk://cifs.bkbits.net/linux-2.5cifs # into smft41.(none):/home/sfrench/linux-2.5cifs # # fs/cifs/CHANGES # 2004/10/19 17:59:29-05:00 sfrench@smft41.(none) +0 -0 # Auto merged # # ChangeSet # 2004/10/19 17:56:53-05:00 sfrench@smft41.(none) # [CIFS] ignore guest mount option do not log warning on it # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/connect.c # 2004/10/19 17:56:46-05:00 sfrench@smft41.(none) +2 -0 # ignore guest mount option do not log warning on it # # fs/cifs/cifspdu.h # 2004/10/19 17:56:46-05:00 sfrench@smft41.(none) +2 -0 # missing defines for a few info levels # # fs/cifs/cifsfs.h # 2004/10/19 17:56:46-05:00 sfrench@smft41.(none) +1 -1 # Update change log for version 1.23 of cifs vfs # # fs/cifs/CHANGES # 2004/10/19 17:56:46-05:00 sfrench@smft41.(none) +6 -0 # Update change log for version 1.23 of cifs vfs # diff -Nru a/fs/Kconfig b/fs/Kconfig --- a/fs/Kconfig 2004-12-12 17:58:37 -08:00 +++ b/fs/Kconfig 2004-12-12 17:58:37 -08:00 @@ -1718,12 +1718,22 @@ config CIFS_POSIX bool "CIFS POSIX Extensions (EXPERIMENTAL)" - depends on CIFS + depends on CIFS_XATTR help Enabling this option will cause the cifs client to attempt to negotiate a newer dialect with servers, such as Samba 3.0.5 or later, that optionally can handle more POSIX like (rather - than Windows like) file behavior. If unsure, say N. + than Windows like) file behavior. It also enables + support for POSIX ACLs (getfacl and setfacl) to servers + (such as Samba 3.10 and later) which can negotiate + CIFS POSIX ACL support. If unsure, say N. + +config CIFS_EXPERIMENTAL + bool "CIFS Experimental Features (EXPERIMENTAL)" + depends on CIFS + help + Enables cifs features under testing. These features + are highly experimental. If unsure, say N. config NCP_FS tristate "NCP file system support (to mount NetWare volumes)" diff -Nru a/fs/cifs/CHANGES b/fs/cifs/CHANGES --- a/fs/cifs/CHANGES 2004-12-12 17:58:37 -08:00 +++ b/fs/cifs/CHANGES 2004-12-12 17:58:37 -08:00 @@ -1,3 +1,42 @@ +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 diff -Nru a/fs/cifs/Makefile b/fs/cifs/Makefile --- a/fs/cifs/Makefile 2004-12-12 17:58:37 -08:00 +++ b/fs/cifs/Makefile 2004-12-12 17:58:37 -08:00 @@ -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 -Nru a/fs/cifs/README b/fs/cifs/README --- a/fs/cifs/README 2004-12-12 17:58:37 -08:00 +++ b/fs/cifs/README 2004-12-12 17:58:37 -08:00 @@ -115,11 +115,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 +200,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 +288,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 +318,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 +346,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 +434,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 -Nru a/fs/cifs/TODO b/fs/cifs/TODO --- a/fs/cifs/TODO 2004-12-12 17:58:37 -08:00 +++ b/fs/cifs/TODO 2004-12-12 17:58:37 -08:00 @@ -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 -Nru a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c --- a/fs/cifs/cifs_debug.c 2004-12-12 17:58:37 -08:00 +++ b/fs/cifs/cifs_debug.c 2004-12-12 17:58:37 -08:00 @@ -201,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); @@ -337,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; @@ -396,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); } @@ -485,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; @@ -512,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 -Nru a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h --- a/fs/cifs/cifs_fs_sb.h 2004-12-12 17:58:37 -08:00 +++ b/fs/cifs/cifs_fs_sb.h 2004-12-12 17:58:37 -08:00 @@ -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 -Nru a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c --- a/fs/cifs/cifsfs.c 2004-12-12 17:58:37 -08:00 +++ b/fs/cifs/cifsfs.c 2004-12-12 17:58:37 -08:00 @@ -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, CIFS_MAX_MSGSIZE); +MODULE_PARM_DESC(CIFSMaxBufSize,"Network buffer size (not including header). Default: 16384 Range: 4096 to 130048"); +unsigned int cifs_min_rcv = CIFS_MIN_RCV_POOL; +module_param(cifs_min_rcv, int, CIFS_MIN_RCV_POOL); +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, 30); +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, CIFS_MAX_REQ); +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,6 +632,13 @@ static int cifs_init_request_bufs(void) { + if(CIFSMaxBufSize < 4096) { + CIFSMaxBufSize = 4096; + cFYI(1,("Buffer size set to minimum of 1 page (4096)")); + } else if (CIFSMaxBufSize > 1024*127) { + CIFSMaxBufSize = 1024 * 127; + cFYI(1,("Buffer size set to maximum")); + } cifs_req_cachep = kmem_cache_create("cifs_request", CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE, 0, @@ -589,7 +646,14 @@ 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 +662,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 +707,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 @@ -750,6 +852,14 @@ GlobalMaxActiveXid = 0; GlobalSMBSeslock = RW_LOCK_UNLOCKED; GlobalMid_Lock = SPIN_LOCK_UNLOCKED; + + 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 -Nru a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h --- a/fs/cifs/cifsfs.h 2004-12-12 17:58:37 -08:00 +++ b/fs/cifs/cifsfs.h 2004-12-12 17:58:37 -08:00 @@ -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.27" #endif /* _CIFSFS_H */ diff -Nru a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h --- a/fs/cifs/cifsglob.h 2004-12-12 17:58:37 -08:00 +++ b/fs/cifs/cifsglob.h 2004-12-12 17:58:37 -08:00 @@ -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 -Nru a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h --- a/fs/cifs/cifspdu.h 2004-12-12 17:58:37 -08:00 +++ b/fs/cifs/cifspdu.h 2004-12-12 17:58:37 -08:00 @@ -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 @@ -141,7 +144,7 @@ #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(0x80) +#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) @@ -682,7 +685,7 @@ __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 { @@ -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,6 +1110,8 @@ #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 { @@ -1115,17 +1141,7 @@ typedef struct smb_com_transaction2_qpi_rsp { struct smb_hdr hdr; /* wct = 10 + SetupCount */ - __le16 TotalParameterCount; - __le16 TotalDataCount; - __le16 Reserved; - __le16 ParameterCount; - __le16 ParameterOffset; - __le16 ParameterDisplacement; - __le16 DataCount; - __le16 DataOffset; - __le16 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; @@ -1158,17 +1174,7 @@ typedef struct smb_com_transaction2_spi_rsp { struct smb_hdr hdr; /* wct = 10 + SetupCount */ - __le16 TotalParameterCount; - __le16 TotalDataCount; - __u16 Reserved; - __le16 ParameterCount; - __le16 ParameterOffset; - __le16 ParameterDisplacement; - __le16 DataCount; - __le16 DataOffset; - __le16 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; @@ -1208,17 +1214,7 @@ struct smb_com_transaction2_sfi_rsp { struct smb_hdr hdr; /* wct = 10 + SetupCount */ - __le16 TotalParameterCount; - __le16 TotalDataCount; - __u16 Reserved; - __le16 ParameterCount; - __le16 ParameterOffset; - __le16 ParameterDisplacement; - __le16 DataCount; - __le16 DataOffset; - __le16 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 */ }; @@ -1268,17 +1264,7 @@ typedef struct smb_com_transaction2_ffirst_rsp { struct smb_hdr hdr; /* wct = 10 */ - __le16 TotalParameterCount; - __le16 TotalDataCount; - __u16 Reserved; - __le16 ParameterCount; - __le16 ParameterOffset; - __le16 ParameterDisplacement; - __le16 DataCount; - __le16 DataOffset; - __le16 DataDisplacement; - __u8 SetupCount; - __u8 Reserved1; /* should be zero setup words following */ + struct trans2_resp t2; __u16 ByteCount; } TRANSACTION2_FFIRST_RSP; @@ -1320,17 +1306,7 @@ typedef struct smb_com_transaction2_fnext_rsp { struct smb_hdr hdr; /* wct = 10 */ - __le16 TotalParameterCount; - __le16 TotalDataCount; - __u16 Reserved; - __le16 ParameterCount; - __le16 ParameterOffset; - __le16 ParameterDisplacement; - __le16 DataCount; - __le16 DataOffset; - __le16 DataDisplacement; - __u8 SetupCount; - __u8 Reserved1; /* should be zero setup words following */ + struct trans2_resp t2; __u16 ByteCount; } TRANSACTION2_FNEXT_RSP; @@ -1351,6 +1327,8 @@ #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+ */ @@ -1377,17 +1355,7 @@ typedef struct smb_com_transaction_qfsi_rsp { struct smb_hdr hdr; /* wct = 10 + SetupCount */ - __le16 TotalParameterCount; - __le16 TotalDataCount; - __u16 Reserved; - __le16 ParameterCount; - __le16 ParameterOffset; - __le16 ParameterDisplacement; - __le16 DataCount; - __le16 DataOffset; - __le16 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; @@ -1430,17 +1398,7 @@ typedef struct smb_com_transaction_get_dfs_refer_rsp { struct smb_hdr hdr; /* wct = 10 */ - __le16 TotalParameterCount; - __le16 TotalDataCount; - __u16 Reserved; - __le16 ParameterCount; - __le16 ParameterOffset; - __le16 ParameterDisplacement; - __le16 DataCount; - __le16 DataOffset; - __le16 DataDisplacement; - __u8 SetupCount; - __u8 Reserved1; /* zero setup words following */ + struct trans2_resp t2; __u16 ByteCount; __u8 Pad; __le16 PathConsumed; @@ -1545,6 +1503,7 @@ /* 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 @@ -1575,10 +1534,13 @@ __le32 Attributes; __le32 MaxPathNameComponentLength; __le32 FileSystemNameLen; - char FileSystemName[52]; /* do not really need to save this - so potentially get only subset of name */ + 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 */ +/******************************************************************************/ +/* 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; @@ -1600,12 +1562,20 @@ __le32 AlignmentRequirement; __le32 FileNameLength; char FileName[1]; -} FILE_ALL_INFO; /* level 263 QPathInfo */ +} FILE_ALL_INFO; /* level 0x107 QPathInfo */ +/* defines for enumerating possible values of the Unix type field below */ +#define UNIX_FILE 0 +#define UNIX_DIR 1 +#define UNIX_SYMLINK 2 +#define UNIX_CHARDEV 3 +#define UNIX_BLOCKDEV 4 +#define UNIX_FIFO 5 +#define UNIX_SOCKET 6 typedef struct { __le64 EndOfFile; __le64 NumOfBytes; - __le64 LastStatusChange; /*SNIA spec says DCE time for the three time fields */ + __le64 LastStatusChange; /*SNIA specs DCE time for the 3 time fields */ __le64 LastAccessTime; __le64 LastModificationTime; __le64 Uid; @@ -1616,11 +1586,11 @@ __u64 UniqueId; __le64 Permissions; __le64 Nlinks; -} FILE_UNIX_BASIC_INFO; /* level 512 QPathInfo */ +} FILE_UNIX_BASIC_INFO; /* level 0x200 QPathInfo */ typedef struct { char LinkDest[1]; -} FILE_UNIX_LINK_INFO; /* level 513 QPathInfo */ +} FILE_UNIX_LINK_INFO; /* level 0x201 QPathInfo */ typedef struct { __u16 CreationDate; @@ -1635,21 +1605,99 @@ __u32 EASize; } FILE_INFO_STANDARD; /* level 1 SetPath/FileInfo */ -/* defines for enumerating possible values of the Unix type field below */ -#define UNIX_FILE 0 -#define UNIX_DIR 1 -#define UNIX_SYMLINK 2 -#define UNIX_CHARDEV 3 -#define UNIX_BLOCKDEV 4 -#define UNIX_FIFO 5 -#define UNIX_SOCKET 6 +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 { + __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 { + __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 { __le32 NextEntryOffset; - __le32 ResumeKey; + __u32 ResumeKey; /* as with FileIndex - no need to convert */ __le64 EndOfFile; __le64 NumOfBytes; - __le64 LastStatusChange; /*SNIA spec says DCE time for the three time fields */ + __le64 LastStatusChange; /*SNIA specs DCE time for the 3 time fields */ __le64 LastAccessTime; __le64 LastModificationTime; __le64 Uid; @@ -1657,28 +1705,40 @@ __le32 Type; __le64 DevMajor; __le64 DevMinor; - __le64 UniqueId; + __u64 UniqueId; __le64 Permissions; __le64 Nlinks; char FileName[1]; -} FILE_UNIX_INFO; +} FILE_UNIX_INFO; /* level 0x202 */ typedef struct { + __le32 NextEntryOffset; + __u32 FileIndex; __le64 CreationTime; __le64 LastAccessTime; __le64 LastWriteTime; __le64 ChangeTime; - __le32 Attributes; - __u32 Pad; -} FILE_BASIC_INFO; /* size info, level 0x101 */ - -struct file_allocation_info { + __le64 EndOfFile; __le64 AllocationSize; -}; /* size info, level 0x103 */ + __le32 ExtFileAttributes; + __le32 FileNameLength; + char FileName[1]; +} FILE_DIRECTORY_INFO; /* level 0x101 FF response data area */ -struct file_end_of_file_info { - __le64 FileSize; /* offset to end of file */ -}; /* size info, level 0x104 */ +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; @@ -1691,8 +1751,30 @@ __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]; -} FILE_DIRECTORY_INFO; /* level 257 FF response data area */ +} 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; @@ -1829,6 +1911,15 @@ /* if room left, then end with \n then 0x20s by convention but not required */ 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 diff -Nru a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h --- a/fs/cifs/cifsproto.h 2004-12-12 17:58:37 -08:00 +++ b/fs/cifs/cifsproto.h 2004-12-12 17:58:37 -08:00 @@ -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, @@ -232,5 +235,13 @@ extern int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName, const char * ea_name, const void * ea_value, const __u16 ea_value_len, + const struct nls_table *nls_codepage); +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 -Nru a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c --- a/fs/cifs/cifssmb.c 2004-12-12 17:58:37 -08:00 +++ b/fs/cifs/cifssmb.c 2004-12-12 17:58:37 -08:00 @@ -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 == 0) { + /* 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 */ ) @@ -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 < + CIFS_MAX_MSGSIZE+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) { @@ -288,7 +412,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; @@ -322,20 +446,20 @@ 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 @@ -365,9 +489,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 & @@ -395,7 +518,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, @@ -733,7 +856,7 @@ 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; @@ -754,15 +877,29 @@ 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; + /* BB can relax this 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 */ 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); - - memcpy(pSMB->Data,buf,bytes_sent); + if(buf) + memcpy(pSMB->Data,buf,bytes_sent); + else if(ubuf) + copy_from_user(pSMB->Data,ubuf,bytes_sent); + else { + /* No buffer */ + if(pSMB) + cifs_buf_release(pSMB); + return -EINVAL; + } byte_count = bytes_sent + 1 /* pad */ ; pSMB->DataLengthLow = cpu_to_le16(bytes_sent); @@ -787,6 +924,66 @@ 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_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, const __u16 smb_file_id, const __u64 len, @@ -861,8 +1058,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) @@ -879,8 +1076,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) @@ -1432,13 +1630,17 @@ (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc)); - } else { /* decode response */ - __u16 data_offset = le16_to_cpu(pSMBr->DataOffset); - __u16 count = le16_to_cpu(pSMBr->DataCount); - if ((pSMBr->ByteCount < 2) || (data_offset > 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 +data_offset), @@ -1550,6 +1752,306 @@ 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, 530 + /* BB fixme find define for this maxpathcomponent */ + , 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, 530 /* BB fixme */); + 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, 530 + /* BB fixme find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(fileName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->FileName, fileName, name_len); + } + 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, @@ -1564,7 +2066,7 @@ int name_len; __u16 params, byte_count; - cFYI(1, ("In QPathInfo path %s", searchName)); +/* cFYI(1, ("In QPathInfo path %s", searchName)); */ /* BB fixme BB */ QPathInfoRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); @@ -1613,13 +2115,12 @@ if (rc) { cFYI(1, ("Send error in QPathInfo = %d", rc)); } else { /* decode response */ - __u16 data_offset = 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) || (data_offset > 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 + data_offset, sizeof (FILE_ALL_INFO)); @@ -1698,15 +2199,12 @@ if (rc) { cFYI(1, ("Send error in QPathInfo = %d", rc)); } else { /* decode response */ - __u16 data_offset = le16_to_cpu(pSMBr->DataOffset); - /* BB also check if enough total bytes returned */ - if ((pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO)) || - (data_offset > 512) || - (data_offset < sizeof(struct smb_hdr))) { - cFYI(1,("UnixQPathinfo invalid data offset %d bytes returned %d", - (int)data_offset,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 + data_offset, @@ -1721,6 +2219,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, @@ -1764,7 +2263,7 @@ 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 */ @@ -1799,6 +2298,7 @@ return rc; } +#endif /* CIFS_EXPERIMENTAL */ int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, @@ -1849,8 +2349,8 @@ 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 */ @@ -1880,20 +2380,25 @@ 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)); - 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); @@ -1904,6 +2409,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(CIFS_MAX_MSGSIZE/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(CIFS_MAX_MSGSIZE / 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, @@ -1939,8 +2694,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; @@ -1949,7 +2704,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(CIFS_MAX_MSGSIZE / sizeof (FILE_UNIX_INFO)); /* test for Unix extensions */ if (tcon->ses->capabilities & CAP_UNIX) { pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX); @@ -1963,7 +2718,7 @@ 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); byte_count += name_len; } @@ -1984,19 +2739,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)); - 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); @@ -2012,12 +2771,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) @@ -2033,7 +2792,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) @@ -2042,6 +2801,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, @@ -2124,14 +2916,17 @@ cFYI(1, ("Send error in GetDFSRefer = %d", rc)); } else { /* decode response */ /* BB Add logic to parse referrals here */ - __u16 data_offset = le16_to_cpu(pSMBr->DataOffset); - __u16 data_count = le16_to_cpu(pSMBr->DataCount); - cFYI(1, - ("Decoding GetDFSRefer response. BCC: %d Offset %d", - pSMBr->ByteCount, data_offset)); - if ((pSMBr->ByteCount < 17) || (data_offset > 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 */ + @@ -2257,13 +3052,16 @@ if (rc) { cERROR(1, ("Send error in QFSInfo = %d", rc)); } else { /* decode response */ - __u16 data_offset = le16_to_cpu(pSMBr->DataOffset); - cFYI(1, - ("Decoding qfsinfo response. BCC: %d Offset %d", - pSMBr->ByteCount, data_offset)); - if ((pSMBr->ByteCount < 24) || (data_offset > 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) + @@ -2339,10 +3137,12 @@ if (rc) { cERROR(1, ("Send error in QFSAttributeInfo = %d", rc)); } else { /* decode response */ - __u16 data_offset = le16_to_cpu(pSMBr->DataOffset); - if ((pSMBr->ByteCount < 13) || (data_offset > 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) + @@ -2408,11 +3208,12 @@ if (rc) { cFYI(1, ("Send error in QFSDeviceInfo = %d", rc)); } else { /* decode response */ - __u16 data_offset = le16_to_cpu(pSMBr->DataOffset); - if ((pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)) - || (data_offset > 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) + @@ -2477,10 +3278,12 @@ if (rc) { cERROR(1, ("Send error in QFSUnixInfo = %d", rc)); } else { /* decode response */ - __u16 data_offset = le16_to_cpu(pSMBr->DataOffset); - if ((pSMBr->ByteCount < 13) || (data_offset > 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) + @@ -2894,6 +3697,7 @@ data_offset = (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol + offset); + memset(data_offset, 0, count); pSMB->DataOffset = cpu_to_le16(offset); pSMB->ParameterOffset = cpu_to_le16(param_offset); pSMB->SetupCount = 1; @@ -2980,7 +3784,7 @@ pSMB->ByteCount = 0; 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)); } @@ -3056,11 +3860,12 @@ if (rc) { cFYI(1, ("Send error in QueryAllEAs = %d", rc)); } else { /* decode response */ - __u16 data_offset = 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) || (data_offset > 512)) + if (rc || (pSMBr->ByteCount < 4)) rc = -EIO; /* bad smb */ /* else if (pFindData){ memcpy((char *) pFindData, @@ -3072,6 +3877,7 @@ 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() */ @@ -3198,11 +4004,12 @@ if (rc) { cFYI(1, ("Send error in Query EA = %d", rc)); } else { /* decode response */ - __u16 data_offset = 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) || (data_offset > 512)) + if (rc || (pSMBr->ByteCount < 4)) rc = -EIO; /* bad smb */ /* else if (pFindData){ memcpy((char *) pFindData, @@ -3214,8 +4021,9 @@ 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 + data_offset > &bcc+ bcc)*/ ea_response_data = (struct fealist *) diff -Nru a/fs/cifs/connect.c b/fs/cifs/connect.c --- a/fs/cifs/connect.c 2004-12-12 17:58:37 -08:00 +++ b/fs/cifs/connect.c 2004-12-12 17:58:37 -08:00 @@ -58,6 +58,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 +70,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; @@ -213,7 +217,7 @@ write_unlock(&GlobalSMBSeslock); if(length > 1) { mempool_resize(cifs_req_poolp, - length + CIFS_MIN_RCV_POOL, + length + cifs_min_rcv, GFP_KERNEL); } @@ -326,8 +330,8 @@ csocket = server->ssocket; continue; } else { - if ((length != sizeof (struct smb_hdr) - 1) - || (pdu_length > + if (/*(length != sizeof (struct smb_hdr) - 1) + ||*/ (pdu_length > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE) || (pdu_length < sizeof (struct smb_hdr) - 1) @@ -335,9 +339,9 @@ (checkSMBhdr (smb_buffer, smb_buffer->Mid))) { cERROR(1, - ("Invalid size or format for SMB found with length %d and pdu_lenght %d", + ("Invalid size or format for SMB found with length %d and pdu_length %d", length, pdu_length)); - cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr)); + cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr)+3); /* could we fix this network corruption by finding next smb header (instead of killing the session) and restart reading from next valid SMB found? */ @@ -485,7 +489,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 +509,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 +696,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 +751,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 +791,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 @@ -1393,6 +1425,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, @@ -1482,8 +1520,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 @@ -1552,14 +1598,15 @@ capabilities |= CAP_DFS; } pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); - /* pSMB->req_no_secext.CaseInsensitivePasswordLength = - CIFS_SESSION_KEY_SIZE; */ - pSMB->req_no_secext.CaseInsensitivePasswordLength = 0; + + 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; diff -Nru a/fs/cifs/dir.c b/fs/cifs/dir.c --- a/fs/cifs/dir.c 2004-12-12 17:58:37 -08:00 +++ b/fs/cifs/dir.c 2004-12-12 17:58:37 -08:00 @@ -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 -Nru a/fs/cifs/fcntl.c b/fs/cifs/fcntl.c --- a/fs/cifs/fcntl.c 2004-12-12 17:58:37 -08:00 +++ b/fs/cifs/fcntl.c 2004-12-12 17:58:37 -08:00 @@ -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 -Nru a/fs/cifs/file.c b/fs/cifs/file.c --- a/fs/cifs/file.c 2004-12-12 17:58:37 -08:00 +++ b/fs/cifs/file.c 2004-12-12 17:58:37 -08:00 @@ -35,6 +35,8 @@ #include "cifs_debug.h" #include "cifs_fs_sb.h" +extern int cifs_readdir2(struct file *file, void *direntry, filldir_t filldir); /* BB removeme BB */ + int cifs_open(struct inode *inode, struct file *file) { @@ -452,18 +454,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; } @@ -576,6 +604,125 @@ } 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, + 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) { + file->f_dentry->d_inode->i_ctime = file->f_dentry->d_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 +799,10 @@ } rc = CIFSSMBWrite(xid, pTcon, - open_file->netfid, + open_file->netfid, write_size - total_written, *poffset, &bytes_written, - write_data + total_written, long_op); + write_data + total_written, NULL, long_op); } if (rc || (bytes_written == 0)) { if (total_written) @@ -969,6 +1116,83 @@ 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; + copy_to_user(current_offset,smb_read_data + 4/* RFC1001 hdr*/ + + le16_to_cpu(pSMBr->DataOffset), bytes_read); + 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 +1263,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) { @@ -1376,23 +1611,22 @@ cFYI(0, ("CIFS FFIRST: Attributes came in as 0x%x", attr)); - if (attr & 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 (attr & ATTR_DIRECTORY) { + 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(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 */ @@ -1516,13 +1750,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); @@ -1537,29 +1774,30 @@ 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, @@ -1609,11 +1847,19 @@ pqstring->name = pfindData->FileName; /* pqstring->len is already set by caller */ - construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry); + rc = 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); + if(rc) { + /* We have no reliable way to get inode numbers + from servers w/o Unix extensions yet so we can not set + i_ino from pfindData yet */ + + /* new inode created, let us hash it */ + insert_inode_hash(tmp_inode); + } /* else if inode number changed do we rehash it? */ rc = filldir(direntry, pfindData->FileName, pqstring->len, file->f_pos, tmp_inode->i_ino, object_type); if(rc) { @@ -1637,11 +1883,19 @@ pqstring->name = pUnixFindData->FileName; pqstring->len = strnlen(pUnixFindData->FileName, MAX_PATHCONF); - construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry); + rc = construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry); if((tmp_inode == NULL) || (tmp_dentry == NULL)) { return -ENOMEM; - } + } + if(rc) { + struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); + if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { + tmp_inode->i_ino = + (unsigned long)pUnixFindData->UniqueId; + } + insert_inode_hash(tmp_inode); + } /* else if i_ino has changed should we rehash it? */ 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); @@ -1675,25 +1929,34 @@ FILE_DIRECTORY_INFO *lastFindData; FILE_UNIX_INFO *pfindDataUnix; + + /* BB removeme begin */ + if(!experimEnabled) + return cifs_readdir2(file,direntry,filldir); + /* BB removeme end */ + + xid = GetXid(); + if(file->f_dentry == NULL) { + rc = -EIO; + FreeXid(xid); + return rc; + } 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) { + rc = -EIO; FreeXid(xid); - return -EIO; + return rc; } data = kmalloc(bufsize, GFP_KERNEL); pfindData = (FILE_DIRECTORY_INFO *) data; if(data == NULL) { + rc = -ENOMEM; FreeXid(xid); - return -ENOMEM; - } - if(file->f_dentry == NULL) { - kfree(data); - FreeXid(xid); - return -EIO; + return rc; } down(&file->f_dentry->d_sb->s_vfs_rename_sem); full_path = build_wildcard_path_from_dentry(file->f_dentry); @@ -1727,8 +1990,8 @@ if (file->private_data != NULL) { cifsFile = (struct cifsFileInfo *) file->private_data; - if (cifsFile->endOfSearch) { - if(cifsFile->emptyDir) { + if (cifsFile->srch_inf.endOfSearch) { + if(cifsFile->srch_inf.emptyDir) { cFYI(1, ("End of search, empty dir")); rc = 0; break; @@ -1778,7 +2041,7 @@ break; } /* Offset of resume key same for levels 257 and 514 */ - cifsFile->resume_key = lastFindData->FileIndex; + cifsFile->srch_inf.resume_key = lastFindData->FileIndex; if(UnixSearch == FALSE) { cifsFile->resume_name_length = le32_to_cpu(lastFindData->FileNameLength); @@ -1915,13 +2178,13 @@ /* if(pfindData > lastFindData) rc = -EIO; break; */ } /* end for loop */ if ((findParms.EndofSearch != 0) && cifsFile) { - cifsFile->endOfSearch = TRUE; + cifsFile->srch_inf.endOfSearch = TRUE; if(findParms.SearchCount == cpu_to_le16(2)) - cifsFile->emptyDir = TRUE; + cifsFile->srch_inf.emptyDir = TRUE; } } else { if (cifsFile) - cifsFile->endOfSearch = TRUE; + cifsFile->srch_inf.endOfSearch = TRUE; /* unless parent directory gone do not return error */ rc = 0; } @@ -1934,7 +2197,7 @@ file->f_pos)); } else { cifsFile = (struct cifsFileInfo *) file->private_data; - if (cifsFile->endOfSearch) { + if (cifsFile->srch_inf.endOfSearch) { rc = 0; cFYI(1, ("End of search ")); break; @@ -1944,7 +2207,7 @@ &findNextParms, searchHandle, cifsFile->search_resume_name, cifsFile->resume_name_length, - cifsFile->resume_key, + cifsFile->srch_inf.resume_key, &Unicode, &UnixSearch); cFYI(1,("Count: %d End: %d ", le16_to_cpu(findNextParms.SearchCount), @@ -1961,7 +2224,7 @@ break; } /* Offset of resume key same for levels 257 and 514 */ - cifsFile->resume_key = lastFindData->FileIndex; + cifsFile->srch_inf.resume_key = lastFindData->FileIndex; if(UnixSearch == FALSE) { cifsFile->resume_name_length = @@ -2114,10 +2377,10 @@ /* BB also should check to ensure pointer not beyond end of SMB */ } /* end for loop */ if (findNextParms.EndofSearch != 0) { - cifsFile->endOfSearch = TRUE; + cifsFile->srch_inf.endOfSearch = TRUE; } } else { - cifsFile->endOfSearch = TRUE; + cifsFile->srch_inf.endOfSearch = TRUE; rc = 0; /* unless parent directory disappeared - do not return error here (eg Access Denied or no more files) */ } diff -Nru a/fs/cifs/inode.c b/fs/cifs/inode.c --- a/fs/cifs/inode.c 2004-12-12 17:58:37 -08:00 +++ b/fs/cifs/inode.c 2004-12-12 17:58:37 -08:00 @@ -85,6 +85,13 @@ *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); } @@ -244,6 +251,21 @@ *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; @@ -273,10 +295,10 @@ /* new inode, can safely set these fields */ inode->i_mode = cifs_sb->mnt_file_mode; - if (attr & ATTR_REPARSE) { - /* Can IFLNK be set as it basically is on windows with IFREG or IFDIR? */ - inode->i_mode |= S_IFLNK; - } else if (attr & 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; diff -Nru a/fs/cifs/misc.c b/fs/cifs/misc.c --- a/fs/cifs/misc.c 2004-12-12 17:58:37 -08:00 +++ b/fs/cifs/misc.c 2004-12-12 17:58:37 -08:00 @@ -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; @@ -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,20 +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; 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) - @@ -359,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 -Nru a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c --- a/fs/cifs/netmisc.c 2004-12-12 17:58:37 -08:00 +++ b/fs/cifs/netmisc.c 2004-12-12 17:58:37 -08:00 @@ -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}, @@ -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}, { diff -Nru a/fs/cifs/readdir.c b/fs/cifs/readdir.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/fs/cifs/readdir.c 2004-12-12 17:58:37 -08:00 @@ -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_filldir2(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_readdir2(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_filldir2(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 -Nru a/fs/cifs/smberr.h b/fs/cifs/smberr.h --- a/fs/cifs/smberr.h 2004-12-12 17:58:37 -08:00 +++ b/fs/cifs/smberr.h 2004-12-12 17:58:37 -08:00 @@ -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. */ diff -Nru a/fs/cifs/transport.c b/fs/cifs/transport.c --- a/fs/cifs/transport.c 2004-12-12 17:58:37 -08:00 +++ b/fs/cifs/transport.c 2004-12-12 17:58:37 -08:00 @@ -176,6 +176,143 @@ 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 +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 > CIFS_MAX_MSGSIZE + 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_send2(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, @@ -204,11 +341,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) { @@ -307,20 +444,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))); } diff -Nru a/fs/cifs/xattr.c b/fs/cifs/xattr.c --- a/fs/cifs/xattr.c 2004-12-12 17:58:37 -08:00 +++ b/fs/cifs/xattr.c 2004-12-12 17:58:37 -08:00 @@ -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);