bk://cifs.bkbits.net/linux-2.5cifs stevef@smfhome1.smfdom|ChangeSet|20041129222148|31159 stevef # This is a BitKeeper generated diff -Nru style patch. # # 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/cifs/CHANGES b/fs/cifs/CHANGES --- a/fs/cifs/CHANGES 2004-11-29 21:43:43 -08:00 +++ b/fs/cifs/CHANGES 2004-11-29 21:43:43 -08:00 @@ -1,3 +1,25 @@ +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-11-29 21:43:43 -08:00 +++ b/fs/cifs/Makefile 2004-11-29 21:43:43 -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-11-29 21:43:43 -08:00 +++ b/fs/cifs/README 2004-11-29 21:43:43 -08:00 @@ -266,6 +266,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 +296,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 diff -Nru a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c --- a/fs/cifs/cifs_debug.c 2004-11-29 21:43:43 -08:00 +++ b/fs/cifs/cifs_debug.c 2004-11-29 21:43:43 -08:00 @@ -337,7 +337,7 @@ if (pde) pde->write_proc = oplockEnabled_write; - pde = create_proc_read_entry("QuotaEnabled", 0, proc_fs_cifs, + pde = create_proc_read_entry("NewReaddirEnabled", 0, proc_fs_cifs, quotaEnabled_read, NULL); if (pde) pde->write_proc = quotaEnabled_write; @@ -396,7 +396,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("NewReaddirEnabled",proc_fs_cifs); remove_proc_entry("LookupCacheEnabled",proc_fs_cifs); remove_proc_entry("cifs", proc_root_fs); } @@ -485,7 +485,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 +512,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-11-29 21:43:43 -08:00 +++ b/fs/cifs/cifs_fs_sb.h 2004-11-29 21:43:43 -08:00 @@ -18,8 +18,9 @@ #ifndef _CIFS_FS_SB_H #define _CIFS_FS_SB_H -#define CIFS_MOUNT_NO_PERM 1 /* do not do client vfs_perm check */ +#define CIFS_MOUNT_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 */ 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-11-29 21:43:43 -08:00 +++ b/fs/cifs/cifsfs.c 2004-11-29 21:43:43 -08:00 @@ -50,7 +50,7 @@ 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; @@ -495,6 +495,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 = { diff -Nru a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h --- a/fs/cifs/cifsfs.h 2004-11-29 21:43:43 -08:00 +++ b/fs/cifs/cifsfs.h 2004-11-29 21:43:43 -08:00 @@ -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.25" #endif /* _CIFSFS_H */ diff -Nru a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h --- a/fs/cifs/cifsglob.h 2004-11-29 21:43:43 -08:00 +++ b/fs/cifs/cifsglob.h 2004-11-29 21:43:43 -08:00 @@ -240,6 +240,17 @@ /* * 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; + char * ntwrk_buf_start; + char * srch_entries_start; + 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 +261,13 @@ /* 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 BB */ + __u32 resume_key; /* BB removeme BB */ + struct cifs_search_info srch_inf; }; /* @@ -317,6 +327,7 @@ #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 /* ***************************************************************** @@ -407,7 +418,7 @@ 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 */ diff -Nru a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h --- a/fs/cifs/cifspdu.h 2004-11-29 21:43:43 -08:00 +++ b/fs/cifs/cifspdu.h 2004-11-29 21:43:43 -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 /* trivial 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 @@ -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,14 @@ #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_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 @@ -1070,9 +1091,10 @@ #define SMB_SET_FILE_END_OF_FILE_INFO 0x104 #define SMB_SET_FILE_UNIX_BASIC 0x200 #define SMB_SET_FILE_UNIX_LINK 0x201 +#define SMB_SET_POSIX_ACL 0x204 #define SMB_SET_FILE_UNIX_HLINK 0x203 #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 +1108,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 +1139,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 +1172,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 +1212,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 +1262,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 +1304,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 +1325,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 +1353,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 +1396,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; @@ -1575,10 +1531,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 +1559,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 +1583,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 +1602,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; __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 +1702,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 +1748,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]; +} 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_DIRECTORY_INFO; /* level 257 FF response data area */ +} FILE_BOTH_DIRECTORY_INFO; /* level 0x104 FF response data area */ + struct gea { unsigned char name_len; diff -Nru a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h --- a/fs/cifs/cifsproto.h 2004-11-29 21:43:43 -08:00 +++ b/fs/cifs/cifsproto.h 2004-11-29 21:43:43 -08:00 @@ -233,4 +233,12 @@ const char *fileName, const char * ea_name, const void * ea_value, const __u16 ea_value_len, const struct nls_table *nls_codepage); +extern int CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon, + const unsigned char *searchName, + char *acl_inf, const int buflen,const int acl_type, + const struct nls_table *nls_codepage); +extern int CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon, + const unsigned char *fileName, + const char *local_acl, const int buflen, const int acl_type, + const struct nls_table *nls_codepage); #endif /* _CIFSPROTO_H */ diff -Nru a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c --- a/fs/cifs/cifssmb.c 2004-11-29 21:43:43 -08:00 +++ b/fs/cifs/cifssmb.c 2004-11-29 21:43:43 -08:00 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include "cifspdu.h" #include "cifsglob.h" @@ -174,7 +175,38 @@ #endif 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) { @@ -1432,13 +1464,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 +1586,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 +1900,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 +1949,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 +2033,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 +2053,7 @@ return rc; } +#ifdef CIFS_EXPERIMENTAL /* function unused at present */ int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon, const char *searchName, FILE_ALL_INFO * findData, @@ -1764,7 +2097,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 +2132,7 @@ return rc; } +#endif /* CIFS_EXPERIMENTAL */ int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, @@ -1849,8 +2183,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 +2214,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 +2243,247 @@ 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; + __u16 params, byte_count; + + cFYI(1, ("In FindNext")); + + 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 = 0; /* BB fixme add resume_key BB */ + pSMB->SearchFlags = + cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME); + /* BB fixme check to make sure we do not cross end of smb with long resume name */ + +/* if(name_len < CIFS_MAX_MSGSIZE) { + memcpy(pSMB->ResumeFileName, resume_file_name, name_len); + byte_count += name_len; */ /* BB fixme - add resume file name processing BB */ +/* } + params += name_len; */ + 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) + 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.DataOffset); + parms = (T2_FNEXT_RSP_PARMS *)response_data; + 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 */ + + 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 +2519,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 +2529,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); @@ -1984,19 +2564,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); @@ -2042,6 +2626,39 @@ return rc; } +#ifdef 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 +2741,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 +2877,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 +2962,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 +3033,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 +3103,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) + @@ -3056,11 +3684,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 +3701,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 +3828,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 +3845,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-11-29 21:43:43 -08:00 +++ b/fs/cifs/connect.c 2004-11-29 21:43:43 -08:00 @@ -69,6 +69,8 @@ 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 int rsize; unsigned int wsize; unsigned int sockopt; @@ -335,7 +337,7 @@ (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)); /* could we fix this network corruption by finding next @@ -742,6 +744,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 +784,14 @@ 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, "noac", 4) == 0) { printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n"); } else @@ -1393,6 +1405,8 @@ 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; tcon = find_unc(sin_server.sin_addr.s_addr, volume_info.UNC, @@ -1482,8 +1496,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 diff -Nru a/fs/cifs/dir.c b/fs/cifs/dir.c --- a/fs/cifs/dir.c 2004-11-29 21:43:43 -08:00 +++ b/fs/cifs/dir.c 2004-11-29 21:43:43 -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-11-29 21:43:43 -08:00 +++ b/fs/cifs/fcntl.c 2004-11-29 21:43:43 -08:00 @@ -37,7 +37,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); diff -Nru a/fs/cifs/file.c b/fs/cifs/file.c --- a/fs/cifs/file.c 2004-11-29 21:43:43 -08:00 +++ b/fs/cifs/file.c 2004-11-29 21:43:43 -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; } @@ -1376,23 +1404,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 +1543,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 +1567,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 +1640,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 +1676,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 +1722,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 +1783,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; @@ -1915,13 +1971,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 +1990,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; @@ -2114,10 +2170,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-11-29 21:43:43 -08:00 +++ b/fs/cifs/inode.c 2004-11-29 21:43:43 -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/netmisc.c b/fs/cifs/netmisc.c --- a/fs/cifs/netmisc.c 2004-11-29 21:43:43 -08:00 +++ b/fs/cifs/netmisc.c 2004-11-29 21:43:43 -08:00 @@ -73,6 +73,7 @@ {ERRnotlocked, -ENOLCK}, {ERRalreadyexists, -EEXIST}, {ERRmoredata, -EOVERFLOW}, + {ERReasnotsupported,-EOPNOTSUPP}, {ErrQuota, -EDQUOT}, {ErrNotALink, -ENOLINK}, {ERRnetlogonNotStarted,-ENOPROTOOPT}, @@ -287,7 +288,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-11-29 21:43:43 -08:00 @@ -0,0 +1,592 @@ +/* + * 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; + + 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(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 + 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 is %p",new_entry,end_of_smb,old_entry)); /* BB removeme BB */ + 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 = 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 = 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 = 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 = 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")); /* BB removeme BB */ + 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; + } + } + +if(cifsFile->srch_inf.endOfSearch) { + cFYI(1,("end of search")); /* BB removeme BB */ +} + 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(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)); /* BB removeme BB */ + 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 -ENOENT; /* BB fixme - 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 = 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 = 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 = 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 = 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)); /* BB removeme BB */ + 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,inum,obj_type); + if(rc) { + cFYI(1,("filldir rc = %d",rc)); + } + + dput(tmp_dentry); + 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)); /* BB removeme BB */ + + 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)); /* BB removeme BB */ + goto rddir2_exit; + } else { + cFYI(1,("entry %lld found",file->f_pos)); + } + + + if(current_entry == NULL) { + cERROR(1,("current search entry null,exiting")); + goto rddir2_exit; + } + /* 2) initiate search, */ + /* 3) seek into search buffer */ + /* 4) if not found && later - FindNext */ + /* else if earlier in search, close search and + restart, continuing search till found or EndOfSearch */ + cFYI(1,("loop through %d times filling dir for net buf start %p",num_to_fill,cifsFile->srch_inf.ntwrk_buf_start)); /* BB removeme BB */ + 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); + cFYI(1,("end of smb %p and tmp_buf %p current_entry %p",end_of_smb,tmp_buf,current_entry)); /* BB removeme BB */ + 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++; + 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-11-29 21:43:43 -08:00 +++ b/fs/cifs/smberr.h 2004-11-29 21:43:43 -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-11-29 21:43:43 -08:00 +++ b/fs/cifs/transport.c 2004-11-29 21:43:43 -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_REQ){ + spin_unlock(&GlobalMid_Lock); + wait_event(ses->server->request_q, + atomic_read(&ses->server->inFlight) + < CIFS_MAX_REQ); + 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, @@ -307,7 +444,6 @@ /* 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 */ diff -Nru a/fs/cifs/xattr.c b/fs/cifs/xattr.c --- a/fs/cifs/xattr.c 2004-11-29 21:43:43 -08:00 +++ b/fs/cifs/xattr.c 2004-11-29 21:43:43 -08:00 @@ -20,6 +20,7 @@ */ #include +#include #include "cifsfs.h" #include "cifspdu.h" #include "cifsglob.h" @@ -27,10 +28,10 @@ #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 */ +#define CIFS_XATTR_OS2_PREFIX "os2." /* BB should check for this someday */ /* also note could add check for security prefix XATTR_SECURITY_PREFIX */ @@ -128,16 +129,41 @@ 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) { + cFYI(1,("set POSIX ACL not supported yet")); + 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)); /* BB removeme BB */ + } else if(strncmp(ea_name,POSIX_ACL_XATTR_DEFAULT,strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) { + cFYI(1,("set default POSIX ACL not supported yet")); + 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)); /* BB removeme BB */ + } 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); @@ -165,6 +191,8 @@ return -EIO; xid = GetXid(); + cFYI(1,("getxattr %s with size %d",ea_name,buf_size)); + cifs_sb = CIFS_SB(sb); pTcon = cifs_sb->tcon; @@ -177,19 +205,45 @@ } /* return dos attributes as pseudo xattr */ /* return alt name if available as pseudo attr */ - if(strncmp(ea_name,CIFS_XATTR_USER_PREFIX,5)) { - cFYI(1,("illegal xattr namespace %s (only user namespace supported)",ea_name)); - /* BB what if no namespace prefix? */ - /* Should we just pass them to server, except for system? */ - } else { - /* We could add a check here + if(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 { + 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 (full_path) kfree(full_path); FreeXid(xid);