diff options
Diffstat (limited to 'fs/cifs')
-rw-r--r-- | fs/cifs/AUTHORS | 55 | ||||
-rw-r--r-- | fs/cifs/CHANGES | 1065 | ||||
-rw-r--r-- | fs/cifs/Makefile | 2 | ||||
-rw-r--r-- | fs/cifs/README | 753 | ||||
-rw-r--r-- | fs/cifs/TODO | 129 | ||||
-rw-r--r-- | fs/cifs/cifs_unicode.h | 2 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 49 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 61 | ||||
-rw-r--r-- | fs/cifs/cifspdu.h | 11 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 12 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 110 | ||||
-rw-r--r-- | fs/cifs/connect.c | 43 | ||||
-rw-r--r-- | fs/cifs/dir.c | 59 | ||||
-rw-r--r-- | fs/cifs/file.c | 50 | ||||
-rw-r--r-- | fs/cifs/inode.c | 17 | ||||
-rw-r--r-- | fs/cifs/link.c | 24 | ||||
-rw-r--r-- | fs/cifs/misc.c | 13 | ||||
-rw-r--r-- | fs/cifs/readdir.c | 3 | ||||
-rw-r--r-- | fs/cifs/sess.c | 58 | ||||
-rw-r--r-- | fs/cifs/smb1ops.c | 44 | ||||
-rw-r--r-- | fs/cifs/smb2file.c | 25 | ||||
-rw-r--r-- | fs/cifs/smb2inode.c | 9 | ||||
-rw-r--r-- | fs/cifs/smb2misc.c | 186 | ||||
-rw-r--r-- | fs/cifs/smb2ops.c | 344 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.c | 135 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.h | 37 | ||||
-rw-r--r-- | fs/cifs/smb2proto.h | 5 | ||||
-rw-r--r-- | fs/cifs/smb2transport.c | 70 | ||||
-rw-r--r-- | fs/cifs/winucase.c | 663 |
29 files changed, 1599 insertions, 2435 deletions
diff --git a/fs/cifs/AUTHORS b/fs/cifs/AUTHORS deleted file mode 100644 index ea940b1db77..00000000000 --- a/fs/cifs/AUTHORS +++ /dev/null @@ -1,55 +0,0 @@ -Original Author -=============== -Steve French (sfrench@samba.org) - -The author wishes to express his appreciation and thanks to: -Andrew Tridgell (Samba team) for his early suggestions about smb/cifs VFS -improvements. Thanks to IBM for allowing me time and test resources to pursue -this project, to Jim McDonough from IBM (and the Samba Team) for his help, to -the IBM Linux JFS team for explaining many esoteric Linux filesystem features. -Jeremy Allison of the Samba team has done invaluable work in adding the server -side of the original CIFS Unix extensions and reviewing and implementing -portions of the newer CIFS POSIX extensions into the Samba 3 file server. Thank -Dave Boutcher of IBM Rochester (author of the OS/400 smb/cifs filesystem client) -for proving years ago that very good smb/cifs clients could be done on Unix-like -operating systems. Volker Lendecke, Andrew Tridgell, Urban Widmark, John -Newbigin and others for their work on the Linux smbfs module. Thanks to -the other members of the Storage Network Industry Association CIFS Technical -Workgroup for their work specifying this highly complex protocol and finally -thanks to the Samba team for their technical advice and encouragement. - -Patch Contributors ------------------- -Zwane Mwaikambo -Andi Kleen -Amrut Joshi -Shobhit Dayal -Sergey Vlasov -Richard Hughes -Yury Umanets -Mark Hamzy (for some of the early cifs IPv6 work) -Domen Puncer -Jesper Juhl (in particular for lots of whitespace/formatting cleanup) -Vince Negri and Dave Stahl (for finding an important caching bug) -Adrian Bunk (kcalloc cleanups) -Miklos Szeredi -Kazeon team for various fixes especially for 2.4 version. -Asser Ferno (Change Notify support) -Shaggy (Dave Kleikamp) for innumerable small fs suggestions and some good cleanup -Gunter Kukkukk (testing and suggestions for support of old servers) -Igor Mammedov (DFS support) -Jeff Layton (many, many fixes, as well as great work on the cifs Kerberos code) - -Test case and Bug Report contributors -------------------------------------- -Thanks to those in the community who have submitted detailed bug reports -and debug of problems they have found: Jochen Dolze, David Blaine, -Rene Scharfe, Martin Josefsson, Alexander Wild, Anthony Liguori, -Lars Muller, Urban Widmark, Massimiliano Ferrero, Howard Owen, -Olaf Kirch, Kieron Briggs, Nick Millington and others. Also special -mention to the Stanford Checker (SWAT) which pointed out many minor -bugs in error paths. Valuable suggestions also have come from Al Viro -and Dave Miller. - -And thanks to the IBM LTC and Power test teams and SuSE testers for -finding multiple bugs during excellent stress test runs. diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES deleted file mode 100644 index bc0025cdd1c..00000000000 --- a/fs/cifs/CHANGES +++ /dev/null @@ -1,1065 +0,0 @@ -Version 1.62 ------------- -Add sockopt=TCP_NODELAY mount option. EA (xattr) routines hardened -to more strictly handle corrupt frames. - -Version 1.61 ------------- -Fix append problem to Samba servers (files opened with O_APPEND could -have duplicated data). Fix oops in cifs_lookup. Workaround problem -mounting to OS/400 Netserve. Fix oops in cifs_get_tcp_session. -Disable use of server inode numbers when server only -partially supports them (e.g. for one server querying inode numbers on -FindFirst fails but QPathInfo queries works). Fix oops with dfs in -cifs_put_smb_ses. Fix mmap to work on directio mounts (needed -for OpenOffice when on forcedirectio mount e.g.) - -Version 1.60 -------------- -Fix memory leak in reconnect. Fix oops in DFS mount error path. -Set s_maxbytes to smaller (the max that vfs can handle) so that -sendfile will now work over cifs mounts again. Add noforcegid -and noforceuid mount parameters. Fix small mem leak when using -ntlmv2. Fix 2nd mount to same server but with different port to -be allowed (rather than reusing the 1st port) - only when the -user explicitly overrides the port on the 2nd mount. - -Version 1.59 ------------- -Client uses server inode numbers (which are persistent) rather than -client generated ones by default (mount option "serverino" turned -on by default if server supports it). Add forceuid and forcegid -mount options (so that when negotiating unix extensions specifying -which uid mounted does not immediately force the server's reported -uids to be overridden). Add support for scope mount parm. Improve -hard link detection to use same inode for both. Do not set -read-only dos attribute on directories (for chmod) since Windows -explorer special cases this attribute bit for directories for -a different purpose. - -Version 1.58 ------------- -Guard against buffer overruns in various UCS-2 to UTF-8 string conversions -when the UTF-8 string is composed of unusually long (more than 4 byte) converted -characters. Add support for mounting root of a share which redirects immediately -to DFS target. Convert string conversion functions from Unicode to more -accurately mark string length before allocating memory (which may help the -rare cases where a UTF-8 string is much larger than the UCS2 string that -we converted from). Fix endianness of the vcnum field used during -session setup to distinguish multiple mounts to same server from different -userids. Raw NTLMSSP fixed (it requires /proc/fs/cifs/experimental -flag to be set to 2, and mount must enable krb5 to turn on extended security). -Performance of file create to Samba improved (posix create on lookup -removes 1 of 2 network requests sent on file create) - -Version 1.57 ------------- -Improve support for multiple security contexts to the same server. We -used to use the same "vcnumber" for all connections which could cause -the server to treat subsequent connections, especially those that -are authenticated as guest, as reconnections, invalidating the earlier -user's smb session. This fix allows cifs to mount multiple times to the -same server with different userids without risking invalidating earlier -established security contexts. fsync now sends SMB Flush operation -to better ensure that we wait for server to write all of the data to -server disk (not just write it over the network). Add new mount -parameter to allow user to disable sending the (slow) SMB flush on -fsync if desired (fsync still flushes all cached write data to the server). -Posix file open support added (turned off after one attempt if server -fails to support it properly, as with Samba server versions prior to 3.3.2) -Fix "redzone overwritten" bug in cifs_put_tcon (CIFSTcon may allocate too -little memory for the "nativeFileSystem" field returned by the server -during mount). Endian convert inode numbers if necessary (makes it easier -to compare inode numbers on network files from big endian systems). - -Version 1.56 ------------- -Add "forcemandatorylock" mount option to allow user to use mandatory -rather than posix (advisory) byte range locks, even though server would -support posix byte range locks. Fix query of root inode when prefixpath -specified and user does not have access to query information about the -top of the share. Fix problem in 2.6.28 resolving DFS paths to -Samba servers (worked to Windows). Fix rmdir so that pending search -(readdir) requests do not get invalid results which include the now -removed directory. Fix oops in cifs_dfs_ref.c when prefixpath is not reachable -when using DFS. Add better file create support to servers which support -the CIFS POSIX protocol extensions (this adds support for new flags -on create, and improves semantics for write of locked ranges). - -Version 1.55 ------------- -Various fixes to make delete of open files behavior more predictable -(when delete of an open file fails we mark the file as "delete-on-close" -in a way that more servers accept, but only if we can first rename the -file to a temporary name). Add experimental support for more safely -handling fcntl(F_SETLEASE). Convert cifs to using blocking tcp -sends, and also let tcp autotune the socket send and receive buffers. -This reduces the number of EAGAIN errors returned by TCP/IP in -high stress workloads (and the number of retries on socket writes -when sending large SMBWriteX requests). Fix case in which a portion of -data can in some cases not get written to the file on the server before the -file is closed. Fix DFS parsing to properly handle path consumed field, -and to handle certain codepage conversions better. Fix mount and -umount race that can cause oops in mount or umount or reconnect. - -Version 1.54 ------------- -Fix premature write failure on congested networks (we would give up -on EAGAIN from the socket too quickly on large writes). -Cifs_mkdir and cifs_create now respect the setgid bit on parent dir. -Fix endian problems in acl (mode from/to cifs acl) on bigendian -architectures. Fix problems with preserving timestamps on copying open -files (e.g. "cp -a") to Windows servers. For mkdir and create honor setgid bit -on parent directory when server supports Unix Extensions but not POSIX -create. Update cifs.upcall version to handle new Kerberos sec flags -(this requires update of cifs.upcall program from Samba). Fix memory leak -on dns_upcall (resolving DFS referralls). Fix plain text password -authentication (requires setting SecurityFlags to 0x30030 to enable -lanman and plain text though). Fix writes to be at correct offset when -file is open with O_APPEND and file is on a directio (forcediretio) mount. -Fix bug in rewinding readdir directory searches. Add nodfs mount option. - -Version 1.53 ------------- -DFS support added (Microsoft Distributed File System client support needed -for referrals which enable a hierarchical name space among servers). -Disable temporary caching of mode bits to servers which do not support -storing of mode (e.g. Windows servers, when client mounts without cifsacl -mount option) and add new "dynperm" mount option to enable temporary caching -of mode (enable old behavior). Fix hang on mount caused when server crashes -tcp session during negotiate protocol. - -Version 1.52 ------------- -Fix oops on second mount to server when null auth is used. -Enable experimental Kerberos support. Return writebehind errors on flush -and sync so that events like out of disk space get reported properly on -cached files. Fix setxattr failure to certain Samba versions. Fix mount -of second share to disconnected server session (autoreconnect on this). -Add ability to modify cifs acls for handling chmod (when mounted with -cifsacl flag). Fix prefixpath path separator so we can handle mounts -with prefixpaths longer than one directory (one path component) when -mounted to Windows servers. Fix slow file open when cifsacl -enabled. Fix memory leak in FindNext when the SMB call returns -EBADF. - - -Version 1.51 ------------- -Fix memory leak in statfs when mounted to very old servers (e.g. -Windows 9x). Add new feature "POSIX open" which allows servers -which support the current POSIX Extensions to provide better semantics -(e.g. delete for open files opened with posix open). Take into -account umask on posix mkdir not just older style mkdir. Add -ability to mount to IPC$ share (which allows CIFS named pipes to be -opened, read and written as if they were files). When 1st tree -connect fails (e.g. due to signing negotiation failure) fix -leak that causes cifsd not to stop and rmmod to fail to cleanup -cifs_request_buffers pool. Fix problem with POSIX Open/Mkdir on -bigendian architectures. Fix possible memory corruption when -EAGAIN returned on kern_recvmsg. Return better error if server -requires packet signing but client has disabled it. When mounted -with cifsacl mount option - mode bits are approximated based -on the contents of the ACL of the file or directory. When cifs -mount helper is missing convert make sure that UNC name -has backslash (not forward slash) between ip address of server -and the share name. - -Version 1.50 ------------- -Fix NTLMv2 signing. NFS server mounted over cifs works (if cifs mount is -done with "serverino" mount option). Add support for POSIX Unlink -(helps with certain sharing violation cases when server such as -Samba supports newer POSIX CIFS Protocol Extensions). Add "nounix" -mount option to allow disabling the CIFS Unix Extensions for just -that mount. Fix hang on spinlock in find_writable_file (race when -reopening file after session crash). Byte range unlock request to -windows server could unlock more bytes (on server copy of file) -than intended if start of unlock request is well before start of -a previous byte range lock that we issued. - -Version 1.49 ------------- -IPv6 support. Enable ipv6 addresses to be passed on mount (put the ipv6 -address after the "ip=" mount option, at least until mount.cifs is fixed to -handle DNS host to ipv6 name translation). Accept override of uid or gid -on mount even when Unix Extensions are negotiated (it used to be ignored -when Unix Extensions were ignored). This allows users to override the -default uid and gid for files when they are certain that the uids or -gids on the server do not match those of the client. Make "sec=none" -mount override username (so that null user connection is attempted) -to match what documentation said. Support for very large reads, over 127K, -available to some newer servers (such as Samba 3.0.26 and later but -note that it also requires setting CIFSMaxBufSize at module install -time to a larger value which may hurt performance in some cases). -Make sign option force signing (or fail if server does not support it). - -Version 1.48 ------------- -Fix mtime bouncing around from local idea of last write times to remote time. -Fix hang (in i_size_read) when simultaneous size update of same remote file -on smp system corrupts sequence number. Do not reread unnecessarily partial page -(which we are about to overwrite anyway) when writing out file opened rw. -When DOS attribute of file on non-Unix server's file changes on the server side -from read-only back to read-write, reflect this change in default file mode -(we had been leaving a file's mode read-only until the inode were reloaded). -Allow setting of attribute back to ATTR_NORMAL (removing readonly dos attribute -when archive dos attribute not set and we are changing mode back to writeable -on server which does not support the Unix Extensions). Remove read only dos -attribute on chmod when adding any write permission (ie on any of -user/group/other (not all of user/group/other ie 0222) when -mounted to windows. Add support for POSIX MkDir (slight performance -enhancement and eliminates the network race between the mkdir and set -path info of the mode). - - -Version 1.47 ------------- -Fix oops in list_del during mount caused by unaligned string. -Fix file corruption which could occur on some large file -copies caused by writepages page i/o completion bug. -Seek to SEEK_END forces check for update of file size for non-cached -files. Allow file size to be updated on remote extend of locally open, -non-cached file. Fix reconnect to newer Samba servers (or other servers -which support the CIFS Unix/POSIX extensions) so that we again tell the -server the Unix/POSIX cifs capabilities which we support (SetFSInfo). -Add experimental support for new POSIX Open/Mkdir (which returns -stat information on the open, and allows setting the mode). - -Version 1.46 ------------- -Support deep tree mounts. Better support OS/2, Win9x (DOS) time stamps. -Allow null user to be specified on mount ("username="). Do not return -EINVAL on readdir when filldir fails due to overwritten blocksize -(fixes FC problem). Return error in rename 2nd attempt retry (ie report -if rename by handle also fails, after rename by path fails, we were -not reporting whether the retry worked or not). Fix NTLMv2 to -work to Windows servers (mount with option "sec=ntlmv2"). - -Version 1.45 ------------- -Do not time out lockw calls when using posix extensions. Do not -time out requests if server still responding reasonably fast -on requests on other threads. Improve POSIX locking emulation, -(lock cancel now works, and unlock of merged range works even -to Windows servers now). Fix oops on mount to lanman servers -(win9x, os/2 etc.) when null password. Do not send listxattr -(SMB to query all EAs) if nouser_xattr specified. Fix SE Linux -problem (instantiate inodes/dentries in right order for readdir). - -Version 1.44 ------------- -Rewritten sessionsetup support, including support for legacy SMB -session setup needed for OS/2 and older servers such as Windows 95 and 98. -Fix oops on ls to OS/2 servers. Add support for level 1 FindFirst -so we can do search (ls etc.) to OS/2. Do not send NTCreateX -or recent levels of FindFirst unless server says it supports NT SMBs -(instead use legacy equivalents from LANMAN dialect). Fix to allow -NTLMv2 authentication support (now can use stronger password hashing -on mount if corresponding /proc/fs/cifs/SecurityFlags is set (0x4004). -Allow override of global cifs security flags on mount via "sec=" option(s). - -Version 1.43 ------------- -POSIX locking to servers which support CIFS POSIX Extensions -(disabled by default controlled by proc/fs/cifs/Experimental). -Handle conversion of long share names (especially Asian languages) -to Unicode during mount. Fix memory leak in sess struct on reconnect. -Fix rare oops after acpi suspend. Fix O_TRUNC opens to overwrite on -cifs open which helps rare case when setpathinfo fails or server does -not support it. - -Version 1.42 ------------- -Fix slow oplock break when mounted to different servers at the same time and -the tids match and we try to find matching fid on wrong server. Fix read -looping when signing required by server (2.6.16 kernel only). Fix readdir -vs. rename race which could cause each to hang. Return . and .. even -if server does not. Allow searches to skip first three entries and -begin at any location. Fix oops in find_writeable_file. - -Version 1.41 ------------- -Fix NTLMv2 security (can be enabled in /proc/fs/cifs) so customers can -configure stronger authentication. Fix sfu symlinks so they can -be followed (not just recognized). Fix wraparound of bcc on -read responses when buffer size over 64K and also fix wrap of -max smb buffer size when CIFSMaxBufSize over 64K. Fix oops in -cifs_user_read and cifs_readpages (when EAGAIN on send of smb -on socket is returned over and over). Add POSIX (advisory) byte range -locking support (requires server with newest CIFS UNIX Extensions -to the protocol implemented). Slow down negprot slightly in port 139 -RFC1001 case to give session_init time on buggy servers. - -Version 1.40 ------------- -Use fsuid (fsgid) more consistently instead of uid (gid). Improve performance -of readpages by eliminating one extra memcpy. Allow update of file size -from remote server even if file is open for write as long as mount is -directio. Recognize share mode security and send NTLM encrypted password -on tree connect if share mode negotiated. - -Version 1.39 ------------- -Defer close of a file handle slightly if pending writes depend on that handle -(this reduces the EBADF bad file handle errors that can be logged under heavy -stress on writes). Modify cifs Kconfig options to expose CONFIG_CIFS_STATS2 -Fix SFU style symlinks and mknod needed for servers which do not support the -CIFS Unix Extensions. Fix setfacl/getfacl on bigendian. Timeout negative -dentries so files that the client sees as deleted but that later get created -on the server will be recognized. Add client side permission check on setattr. -Timeout stuck requests better (where server has never responded or sent corrupt -responses) - -Version 1.38 ------------- -Fix tcp socket retransmission timeouts (e.g. on ENOSPACE from the socket) -to be smaller at first (but increasing) so large write performance performance -over GigE is better. Do not hang thread on illegal byte range lock response -from Windows (Windows can send an RFC1001 size which does not match smb size) by -allowing an SMBs TCP length to be up to a few bytes longer than it should be. -wsize and rsize can now be larger than negotiated buffer size if server -supports large readx/writex, even when directio mount flag not specified. -Write size will in many cases now be 16K instead of 4K which greatly helps -file copy performance on lightly loaded networks. Fix oops in dnotify -when experimental config flag enabled. Make cifsFYI more granular. - -Version 1.37 ------------- -Fix readdir caching when unlink removes file in current search buffer, -and this is followed by a rewind search to just before the deleted entry. -Do not attempt to set ctime unless atime and/or mtime change requested -(most servers throw it away anyway). Fix length check of received smbs -to be more accurate. Fix big endian problem with mapchars mount option, -and with a field returned by statfs. - -Version 1.36 ------------- -Add support for mounting to older pre-CIFS servers such as Windows9x and ME. -For these older servers, add option for passing netbios name of server in -on mount (servernetbiosname). Add suspend support for power management, to -avoid cifsd thread preventing software suspend from working. -Add mount option for disabling the default behavior of sending byte range lock -requests to the server (necessary for certain applications which break with -mandatory lock behavior such as Evolution), and also mount option for -requesting case insensitive matching for path based requests (requesting -case sensitive is the default). - -Version 1.35 ------------- -Add writepage performance improvements. Fix path name conversions -for long filenames on mounts which were done with "mapchars" mount option -specified. Ensure multiplex ids do not collide. Fix case in which -rmmod can oops if done soon after last unmount. Fix truncated -search (readdir) output when resume filename was a long filename. -Fix filename conversion when mapchars mount option was specified and -filename was a long filename. - -Version 1.34 ------------- -Fix error mapping of the TOO_MANY_LINKS (hardlinks) case. -Do not oops if root user kills cifs oplock kernel thread or -kills the cifsd thread (NB: killing the cifs kernel threads is not -recommended, unmount and rmmod cifs will kill them when they are -no longer needed). Fix readdir to ASCII servers (ie older servers -which do not support Unicode) and also require asterisk. -Fix out of memory case in which data could be written one page -off in the page cache. - -Version 1.33 ------------- -Fix caching problem, in which readdir of directory containing a file -which was cached could cause the file's time stamp to be updated -without invalidating the readahead data (so we could get stale -file data on the client for that file even as the server copy changed). -Cleanup response processing so cifsd can not loop when abnormally -terminated. - - -Version 1.32 ------------- -Fix oops in ls when Transact2 FindFirst (or FindNext) returns more than one -transact response for an SMB request and search entry split across two frames. -Add support for lsattr (getting ext2/ext3/reiserfs attr flags from the server) -as new protocol extensions. Do not send Get/Set calls for POSIX ACLs -unless server explicitly claims to support them in CIFS Unix extensions -POSIX ACL capability bit. Fix packet signing when multiuser mounting with -different users from the same client to the same server. Fix oops in -cifs_close. Add mount option for remapping reserved characters in -filenames (also allow recognizing files with created by SFU which have any -of these seven reserved characters, except backslash, to be recognized). -Fix invalid transact2 message (we were sometimes trying to interpret -oplock breaks as SMB responses). Add ioctl for checking that the -current uid matches the uid of the mounter (needed by umount.cifs). -Reduce the number of large buffer allocations in cifs response processing -(significantly reduces memory pressure under heavy stress with multiple -processes accessing the same server at the same time). - -Version 1.31 ------------- -Fix updates of DOS attributes and time fields so that files on NT4 servers -do not get marked delete on close. Display sizes of cifs buffer pools in -cifs stats. Fix oops in unmount when cifsd thread being killed by -shutdown. Add generic readv/writev and aio support. Report inode numbers -consistently in readdir and lookup (when serverino mount option is -specified use the inode number that the server reports - for both lookup -and readdir, otherwise by default the locally generated inode number is used -for inodes created in either path since servers are not always able to -provide unique inode numbers when exporting multiple volumes from under one -sharename). - -Version 1.30 ------------- -Allow new nouser_xattr mount parm to disable xattr support for user namespace. -Do not flag user_xattr mount parm in dmesg. Retry failures setting file time -(mostly affects NT4 servers) by retry with handle based network operation. -Add new POSIX Query FS Info for returning statfs info more accurately. -Handle passwords with multiple commas in them. - -Version 1.29 ------------- -Fix default mode in sysfs of cifs module parms. Remove old readdir routine. -Fix capabilities flags for large readx so as to allow reads larger than 64K. - -Version 1.28 ------------- -Add module init parm for large SMB buffer size (to allow it to be changed -from its default of 16K) which is especially useful for large file copy -when mounting with the directio mount option. Fix oops after -returning from mount when experimental ExtendedSecurity enabled and -SpnegoNegotiated returning invalid error. Fix case to retry better when -peek returns from 1 to 3 bytes on socket which should have more data. -Fixed path based calls (such as cifs lookup) to handle path names -longer than 530 (now can handle PATH_MAX). Fix pass through authentication -from Samba server to DC (Samba required dummy LM password). - -Version 1.27 ------------- -Turn off DNOTIFY (directory change notification support) by default -(unless built with the experimental flag) to fix hang with KDE -file browser. Fix DNOTIFY flag mappings. Fix hang (in wait_event -waiting on an SMB response) in SendReceive when session dies but -reconnects quickly from another task. Add module init parms for -minimum number of large and small network buffers in the buffer pools, -and for the maximum number of simultaneous requests. - -Version 1.26 ------------- -Add setfacl support to allow setting of ACLs remotely to Samba 3.10 and later -and other POSIX CIFS compliant servers. Fix error mapping for getfacl -to EOPNOTSUPP when server does not support posix acls on the wire. Fix -improperly zeroed buffer in CIFS Unix extensions set times call. - -Version 1.25 ------------- -Fix internationalization problem in cifs readdir with filenames that map to -longer UTF-8 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 -xattr names in the "user." namespace space to SMB/CIFS EAs. Lots of -minor fixes pointed out by the Stanford SWAT checker (mostly missing -or out of order NULL pointer checks in little used error paths). - -Version 1.21 ------------- -Add new mount parm to control whether mode check (generic_permission) is done -on the client. If Unix extensions are enabled and the uids on the client -and server do not match, client permission checks are meaningless on -server uids that do not exist on the client (this does not affect the -normal ACL check which occurs on the server). Fix default uid -on mknod to match create and mkdir. Add optional mount parm to allow -override of the default uid behavior (in which the server sets the uid -and gid of newly created files). Normally for network filesystem mounts -user want the server to set the uid/gid on newly created files (rather than -using uid of the client processes you would in a local filesystem). - -Version 1.20 ------------- -Make transaction counts more consistent. Merge /proc/fs/cifs/SimultaneousOps -info into /proc/fs/cifs/DebugData. Fix oops in rare oops in readdir -(in build_wildcard_path_from_dentry). Fix mknod to pass type field -(block/char/fifo) properly. Remove spurious mount warning log entry when -credentials passed as mount argument. Set major/minor device number in -inode for block and char devices when unix extensions enabled. - -Version 1.19 ------------- -Fix /proc/fs/cifs/Stats and DebugData display to handle larger -amounts of return data. Properly limit requests to MAX_REQ (50 -is the usual maximum active multiplex SMB/CIFS requests per server). -Do not kill cifsd (and thus hurt the other SMB session) when more than one -session to the same server (but with different userids) exists and one -of the two user's smb sessions is being removed while leaving the other. -Do not loop reconnecting in cifsd demultiplex thread when admin -kills the thread without going through unmount. - -Version 1.18 ------------- -Do not rename hardlinked files (since that should be a noop). Flush -cached write behind data when reopening a file after session abend, -except when already in write. Grab per socket sem during reconnect -to avoid oops in sendmsg if overlapping with reconnect. Do not -reset cached inode file size on readdir for files open for write on -client. - - -Version 1.17 ------------- -Update number of blocks in file so du command is happier (in Linux a fake -blocksize of 512 is required for calculating number of blocks in inode). -Fix prepare write of partial pages to read in data from server if possible. -Fix race on tcpStatus field between unmount and reconnection code, causing -cifsd process sometimes to hang around forever. Improve out of memory -checks in cifs_filldir - -Version 1.16 ------------- -Fix incorrect file size in file handle based setattr on big endian hardware. -Fix oops in build_path_from_dentry when out of memory. Add checks for invalid -and closing file structs in writepage/partialpagewrite. Add statistics -for each mounted share (new menuconfig option). Fix endianness problem in -volume information displayed in /proc/fs/cifs/DebugData (only affects -affects big endian architectures). Prevent renames while constructing -path names for open, mkdir and rmdir. - -Version 1.15 ------------- -Change to mempools for alloc smb request buffers and multiplex structs -to better handle low memory problems (and potential deadlocks). - -Version 1.14 ------------- -Fix incomplete listings of large directories on Samba servers when Unix -extensions enabled. Fix oops when smb_buffer can not be allocated. Fix -rename deadlock when writing out dirty pages at same time. - -Version 1.13 ------------- -Fix open of files in which O_CREATE can cause the mode to change in -some cases. Fix case in which retry of write overlaps file close. -Fix PPC64 build error. Reduce excessive stack usage in smb password -hashing. Fix overwrite of Linux user's view of file mode to Windows servers. - -Version 1.12 ------------- -Fixes for large file copy, signal handling, socket retry, buffer -allocation and low memory situations. - -Version 1.11 ------------- -Better port 139 support to Windows servers (RFC1001/RFC1002 Session_Initialize) -also now allowing support for specifying client netbiosname. NT4 support added. - -Version 1.10 ------------- -Fix reconnection (and certain failed mounts) to properly wake up the -blocked users thread so it does not seem hung (in some cases was blocked -until the cifs receive timeout expired). Fix spurious error logging -to kernel log when application with open network files killed. - -Version 1.09 ------------- -Fix /proc/fs module unload warning message (that could be logged -to the kernel log). Fix intermittent failure in connectathon -test7 (hardlink count not immediately refreshed in case in which -inode metadata can be incorrectly kept cached when time near zero) - -Version 1.08 ------------- -Allow file_mode and dir_mode (specified at mount time) to be enforced -locally (the server already enforced its own ACLs too) for servers -that do not report the correct mode (do not support the -CIFS Unix Extensions). - -Version 1.07 ------------- -Fix some small memory leaks in some unmount error paths. Fix major leak -of cache pages in readpages causing multiple read oriented stress -testcases (including fsx, and even large file copy) to fail over time. - -Version 1.06 ------------- -Send NTCreateX with ATTR_POSIX if Linux/Unix extensions negotiated with server. -This allows files that differ only in case and improves performance of file -creation and file open to such servers. Fix semaphore conflict which causes -slow delete of open file to Samba (which unfortunately can cause an oplock -break to self while vfs_unlink held i_sem) which can hang for 20 seconds. - -Version 1.05 ------------- -fixes to cifs_readpages for fsx test case - -Version 1.04 ------------- -Fix caching data integrity bug when extending file size especially when no -oplock on file. Fix spurious logging of valid already parsed mount options -that are parsed outside of the cifs vfs such as nosuid. - - -Version 1.03 ------------- -Connect to server when port number override not specified, and tcp port -unitialized. Reset search to restart at correct file when kernel routine -filldir returns error during large directory searches (readdir). - -Version 1.02 ------------- -Fix caching problem when files opened by multiple clients in which -page cache could contain stale data, and write through did -not occur often enough while file was still open when read ahead -(read oplock) not allowed. Treat "sep=" when first mount option -as an override of comma as the default separator between mount -options. - -Version 1.01 ------------- -Allow passwords longer than 16 bytes. Allow null password string. - -Version 1.00 ------------- -Gracefully clean up failed mounts when attempting to mount to servers such as -Windows 98 that terminate tcp sessions during protocol negotiation. Handle -embedded commas in mount parsing of passwords. - -Version 0.99 ------------- -Invalidate local inode cached pages on oplock break and when last file -instance is closed so that the client does not continue using stale local -copy rather than later modified server copy of file. Do not reconnect -when server drops the tcp session prematurely before negotiate -protocol response. Fix oops in reopen_file when dentry freed. Allow -the support for CIFS Unix Extensions to be disabled via proc interface. - -Version 0.98 ------------- -Fix hang in commit_write during reconnection of open files under heavy load. -Fix unload_nls oops in a mount failure path. Serialize writes to same socket -which also fixes any possible races when cifs signatures are enabled in SMBs -being sent out of signature sequence number order. - -Version 0.97 ------------- -Fix byte range locking bug (endian problem) causing bad offset and -length. - -Version 0.96 ------------- -Fix oops (in send_sig) caused by CIFS unmount code trying to -wake up the demultiplex thread after it had exited. Do not log -error on harmless oplock release of closed handle. - -Version 0.95 ------------- -Fix unsafe global variable usage and password hash failure on gcc 3.3.1 -Fix problem reconnecting secondary mounts to same server after session -failure. Fix invalid dentry - race in mkdir when directory gets created -by another client between the lookup and mkdir. - -Version 0.94 ------------- -Fix to list processing in reopen_files. Fix reconnection when server hung -but tcpip session still alive. Set proper timeout on socket read. - -Version 0.93 ------------- -Add missing mount options including iocharset. SMP fixes in write and open. -Fix errors in reconnecting after TCP session failure. Fix module unloading -of default nls codepage - -Version 0.92 ------------- -Active smb transactions should never go negative (fix double FreeXid). Fix -list processing in file routines. Check return code on kmalloc in open. -Fix spinlock usage for SMP. - -Version 0.91 ------------- -Fix oops in reopen_files when invalid dentry. drop dentry on server rename -and on revalidate errors. Fix cases where pid is now tgid. Fix return code -on create hard link when server does not support them. - -Version 0.90 ------------- -Fix scheduling while atomic error in getting inode info on newly created file. -Fix truncate of existing files opened with O_CREAT but not O_TRUNC set. - -Version 0.89 ------------- -Fix oops on write to dead tcp session. Remove error log write for case when file open -O_CREAT but not O_EXCL - -Version 0.88 ------------- -Fix non-POSIX behavior on rename of open file and delete of open file by taking -advantage of trans2 SetFileInfo rename facility if available on target server. -Retry on ENOSPC and EAGAIN socket errors. - -Version 0.87 ------------- -Fix oops on big endian readdir. Set blksize to be even power of two (2**blkbits) to fix -allocation size miscalculation. After oplock token lost do not read through -cache. - -Version 0.86 ------------- -Fix oops on empty file readahead. Fix for file size handling for locally cached files. - -Version 0.85 ------------- -Fix oops in mkdir when server fails to return inode info. Fix oops in reopen_files -during auto reconnection to server after server recovered from failure. - -Version 0.84 ------------- -Finish support for Linux 2.5 open/create changes, which removes the -redundant NTCreate/QPathInfo/close that was sent during file create. -Enable oplock by default. Enable packet signing by default (needed to -access many recent Windows servers) - -Version 0.83 ------------- -Fix oops when mounting to long server names caused by inverted parms to kmalloc. -Fix MultiuserMount (/proc/fs/cifs configuration setting) so that when enabled -we will choose a cifs user session (smb uid) that better matches the local -uid if a) the mount uid does not match the current uid and b) we have another -session to the same server (ip address) for a different mount which -matches the current local uid. - -Version 0.82 ------------- -Add support for mknod of block or character devices. Fix oplock -code (distributed caching) to properly send response to oplock -break from server. - -Version 0.81 ------------- -Finish up CIFS packet digital signing for the default -NTLM security case. This should help Windows 2003 -network interoperability since it is common for -packet signing to be required now. Fix statfs (stat -f) -which recently started returning errors due to -invalid value (-1 instead of 0) being set in the -struct kstatfs f_ffiles field. - -Version 0.80 ------------ -Fix oops on stopping oplock thread when removing cifs when -built as module. - -Version 0.79 ------------- -Fix mount options for ro (readonly), uid, gid and file and directory mode. - -Version 0.78 ------------- -Fix errors displayed on failed mounts to be more understandable. -Fixed various incorrect or misleading smb to posix error code mappings. - -Version 0.77 ------------- -Fix display of NTFS DFS junctions to display as symlinks. -They are the network equivalent. Fix oops in -cifs_partialpagewrite caused by missing spinlock protection -of openfile linked list. Allow writebehind caching errors to -be returned to the application at file close. - -Version 0.76 ------------- -Clean up options displayed in /proc/mounts by show_options to -be more consistent with other filesystems. - -Version 0.75 ------------- -Fix delete of readonly file to Windows servers. Reflect -presence or absence of read only dos attribute in mode -bits for servers that do not support CIFS Unix extensions. -Fix shortened results on readdir of large directories to -servers supporting CIFS Unix extensions (caused by -incorrect resume key). - -Version 0.74 ------------- -Fix truncate bug (set file size) that could cause hangs e.g. running fsx - -Version 0.73 ------------- -unload nls if mount fails. - -Version 0.72 ------------- -Add resume key support to search (readdir) code to workaround -Windows bug. Add /proc/fs/cifs/LookupCacheEnable which -allows disabling caching of attribute information for -lookups. - -Version 0.71 ------------- -Add more oplock handling (distributed caching code). Remove -dead code. Remove excessive stack space utilization from -symlink routines. - -Version 0.70 ------------- -Fix oops in get dfs referral (triggered when null path sent in to -mount). Add support for overriding rsize at mount time. - -Version 0.69 ------------- -Fix buffer overrun in readdir which caused intermittent kernel oopses. -Fix writepage code to release kmap on write data. Allow "-ip=" new -mount option to be passed in on parameter distinct from the first part -(server name portion of) the UNC name. Allow override of the -tcp port of the target server via new mount option "-port=" - -Version 0.68 ------------- -Fix search handle leak on rewind. Fix setuid and gid so that they are -reflected in the local inode immediately. Cleanup of whitespace -to make 2.4 and 2.5 versions more consistent. - - -Version 0.67 ------------- -Fix signal sending so that captive thread (cifsd) exits on umount -(which was causing the warning in kmem_cache_free of the request buffers -at rmmod time). This had broken as a sideeffect of the recent global -kernel change to daemonize. Fix memory leak in readdir code which -showed up in "ls -R" (and applications that did search rewinding). - -Version 0.66 ------------- -Reconnect tids and fids after session reconnection (still do not -reconnect byte range locks though). Fix problem caching -lookup information for directory inodes, improving performance, -especially in deep directory trees. Fix various build warnings. - -Version 0.65 ------------- -Finish fixes to commit write for caching/readahead consistency. fsx -now works to Samba servers. Fix oops caused when readahead -was interrupted by a signal. - -Version 0.64 ------------- -Fix data corruption (in partial page after truncate) that caused fsx to -fail to Windows servers. Cleaned up some extraneous error logging in -common error paths. Add generic sendfile support. - -Version 0.63 ------------- -Fix memory leak in AllocMidQEntry. -Finish reconnection logic, so connection with server can be dropped -(or server rebooted) and the cifs client will reconnect. - -Version 0.62 ------------- -Fix temporary socket leak when bad userid or password specified -(or other SMBSessSetup failure). Increase maximum buffer size to slightly -over 16K to allow negotiation of up to Samba and Windows server default read -sizes. Add support for readpages - -Version 0.61 ------------- -Fix oops when username not passed in on mount. Extensive fixes and improvements -to error logging (strip redundant newlines, change debug macros to ensure newline -passed in and to be more consistent). Fix writepage wrong file handle problem, -a readonly file handle could be incorrectly used to attempt to write out -file updates through the page cache to multiply open files. This could cause -the iozone benchmark to fail on the fwrite test. Fix bug mounting two different -shares to the same Windows server when using different usernames -(doing this to Samba servers worked but Windows was rejecting it) - now it is -possible to use different userids when connecting to the same server from a -Linux client. Fix oops when treeDisconnect called during unmount on -previously freed socket. - -Version 0.60 ------------- -Fix oops in readpages caused by not setting address space operations in inode in -rare code path. - -Version 0.59 ------------- -Includes support for deleting of open files and renaming over existing files (per POSIX -requirement). Add readlink support for Windows junction points (directory symlinks). - -Version 0.58 ------------- -Changed read and write to go through pagecache. Added additional address space operations. -Memory mapped operations now working. - -Version 0.57 ------------- -Added writepage code for additional memory mapping support. Fixed leak in xids causing -the simultaneous operations counter (/proc/fs/cifs/SimultaneousOps) to increase on -every stat call. Additional formatting cleanup. - -Version 0.56 ------------- -Fix bigendian bug in order of time conversion. Merge 2.5 to 2.4 version. Formatting cleanup. - -Version 0.55 ------------- -Fixes from Zwane Mwaikambo for adding missing return code checking in a few places. -Also included a modified version of his fix to protect global list manipulation of -the smb session and tree connection and mid related global variables. - -Version 0.54 ------------- -Fix problem with captive thread hanging around at unmount time. Adjust to 2.5.42-pre -changes to superblock layout. Remove wasteful allocation of smb buffers (now the send -buffer is reused for responses). Add more oplock handling. Additional minor cleanup. - -Version 0.53 ------------- -More stylistic updates to better match kernel style. Add additional statistics -for filesystem which can be viewed via /proc/fs/cifs. Add more pieces of NTLMv2 -and CIFS Packet Signing enablement. - -Version 0.52 ------------- -Replace call to sleep_on with safer wait_on_event. -Make stylistic changes to better match kernel style recommendations. -Remove most typedef usage (except for the PDUs themselves). - -Version 0.51 ------------- -Update mount so the -unc mount option is no longer required (the ip address can be specified -in a UNC style device name. Implementation of readpage/writepage started. - -Version 0.50 ------------- -Fix intermittent problem with incorrect smb header checking on badly -fragmented tcp responses - -Version 0.49 ------------- -Fixes to setting of allocation size and file size. - -Version 0.48 ------------- -Various 2.5.38 fixes. Now works on 2.5.38 - -Version 0.47 ------------- -Prepare for 2.5 kernel merge. Remove ifdefs. - -Version 0.46 ------------- -Socket buffer management fixes. Fix dual free. - -Version 0.45 ------------- -Various big endian fixes for hardlinks and symlinks and also for dfs. - -Version 0.44 ------------- -Various big endian fixes for servers with Unix extensions such as Samba - -Version 0.43 ------------- -Various FindNext fixes for incorrect filenames on large directory searches on big endian -clients. basic posix file i/o tests now work on big endian machines, not just le - -Version 0.42 ------------- -SessionSetup and NegotiateProtocol now work from Big Endian machines. -Various Big Endian fixes found during testing on the Linux on 390. Various fixes for compatibility with older -versions of 2.4 kernel (now builds and works again on kernels at least as early as 2.4.7). - -Version 0.41 ------------- -Various minor fixes for Connectathon Posix "basic" file i/o test suite. Directory caching fixed so hardlinked -files now return the correct number of links on fstat as they are repeatedly linked and unlinked. - -Version 0.40 ------------- -Implemented "Raw" (i.e. not encapsulated in SPNEGO) NTLMSSP (i.e. the Security Provider Interface used to negotiate -session advanced session authentication). Raw NTLMSSP is preferred by Windows 2000 Professional and Windows XP. -Began implementing support for SPNEGO encapsulation of NTLMSSP based session authentication blobs -(which is the mechanism preferred by Windows 2000 server in the absence of Kerberos). - -Version 0.38 ------------- -Introduced optional mount helper utility mount.cifs and made coreq changes to cifs vfs to enable -it. Fixed a few bugs in the DFS code (e.g. bcc two bytes too short and incorrect uid in PDU). - -Version 0.37 ------------- -Rewrote much of connection and mount/unmount logic to handle bugs with -multiple uses to same share, multiple users to same server etc. - -Version 0.36 ------------- -Fixed major problem with dentry corruption (missing call to dput) - -Version 0.35 ------------- -Rewrite of readdir code to fix bug. Various fixes for bigendian machines. -Begin adding oplock support. Multiusermount and oplockEnabled flags added to /proc/fs/cifs -although corresponding function not fully implemented in the vfs yet - -Version 0.34 ------------- -Fixed dentry caching bug, misc. cleanup - -Version 0.33 ------------- -Fixed 2.5 support to handle build and configure changes as well as misc. 2.5 changes. Now can build -on current 2.5 beta version (2.5.24) of the Linux kernel as well as on 2.4 Linux kernels. -Support for STATUS codes (newer 32 bit NT error codes) added. DFS support begun to be added. - -Version 0.32 ------------- -Unix extensions (symlink, readlink, hardlink, chmod and some chgrp and chown) implemented -and tested against Samba 2.2.5 - - -Version 0.31 ------------- -1) Fixed lockrange to be correct (it was one byte too short) - -2) Fixed GETLK (i.e. the fcntl call to test a range of bytes in a file to see if locked) to correctly -show range as locked when there is a conflict with an existing lock. - -3) default file perms are now 2767 (indicating support for mandatory locks) instead of 777 for directories -in most cases. Eventually will offer optional ability to query server for the correct perms. - -3) Fixed eventual trap when mounting twice to different shares on the same server when the first succeeded -but the second one was invalid and failed (the second one was incorrectly disconnecting the tcp and smb -session) - -4) Fixed error logging of valid mount options - -5) Removed logging of password field. - -6) Moved negotiate, treeDisconnect and uloggoffX (only tConx and SessSetup remain in connect.c) to cifssmb.c -and cleaned them up and made them more consistent with other cifs functions. - -7) Server support for Unix extensions is now fully detected and FindFirst is implemented both ways -(with or without Unix extensions) but FindNext and QueryPathInfo with the Unix extensions are not completed, -nor is the symlink support using the Unix extensions - -8) Started adding the readlink and follow_link code - -Version 0.3 ------------ -Initial drop - diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile index aa0d68b086e..1964d212ab0 100644 --- a/fs/cifs/Makefile +++ b/fs/cifs/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_CIFS) += cifs.o cifs-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o \ link.o misc.o netmisc.o smbencrypt.o transport.o asn1.o \ cifs_unicode.o nterr.o xattr.o cifsencrypt.o \ - readdir.o ioctl.o sess.o export.o smb1ops.o + readdir.o ioctl.o sess.o export.o smb1ops.o winucase.o cifs-$(CONFIG_CIFS_ACL) += cifsacl.o diff --git a/fs/cifs/README b/fs/cifs/README deleted file mode 100644 index 2d5622f60e1..00000000000 --- a/fs/cifs/README +++ /dev/null @@ -1,753 +0,0 @@ -The CIFS VFS support for Linux supports many advanced network filesystem -features such as hierarchical dfs like namespace, hardlinks, locking and more. -It was designed to comply with the SNIA CIFS Technical Reference (which -supersedes the 1992 X/Open SMB Standard) as well as to perform best practice -practical interoperability with Windows 2000, Windows XP, Samba and equivalent -servers. This code was developed in participation with the Protocol Freedom -Information Foundation. - -Please see - http://protocolfreedom.org/ and - http://samba.org/samba/PFIF/ -for more details. - - -For questions or bug reports please contact: - sfrench@samba.org (sfrench@us.ibm.com) - -Build instructions: -================== -For Linux 2.4: -1) Get the kernel source (e.g.from http://www.kernel.org) -and download the cifs vfs source (see the project page -at http://us1.samba.org/samba/Linux_CIFS_client.html) -and change directory into the top of the kernel directory -then patch the kernel (e.g. "patch -p1 < cifs_24.patch") -to add the cifs vfs to your kernel configure options if -it has not already been added (e.g. current SuSE and UL -users do not need to apply the cifs_24.patch since the cifs vfs is -already in the kernel configure menu) and then -mkdir linux/fs/cifs and then copy the current cifs vfs files from -the cifs download to your kernel build directory e.g. - - cp <cifs_download_dir>/fs/cifs/* to <kernel_download_dir>/fs/cifs - -2) make menuconfig (or make xconfig) -3) select cifs from within the network filesystem choices -4) save and exit -5) make dep -6) make modules (or "make" if CIFS VFS not to be built as a module) - -For Linux 2.6: -1) Download the kernel (e.g. from http://www.kernel.org) -and change directory into the top of the kernel directory tree -(e.g. /usr/src/linux-2.5.73) -2) make menuconfig (or make xconfig) -3) select cifs from within the network filesystem choices -4) save and exit -5) make - - -Installation instructions: -========================= -If you have built the CIFS vfs as module (successfully) simply -type "make modules_install" (or if you prefer, manually copy the file to -the modules directory e.g. /lib/modules/2.4.10-4GB/kernel/fs/cifs/cifs.o). - -If you have built the CIFS vfs into the kernel itself, follow the instructions -for your distribution on how to install a new kernel (usually you -would simply type "make install"). - -If you do not have the utility mount.cifs (in the Samba 3.0 source tree and on -the CIFS VFS web site) copy it to the same directory in which mount.smbfs and -similar files reside (usually /sbin). Although the helper software is not -required, mount.cifs is recommended. Eventually the Samba 3.0 utility program -"net" may also be helpful since it may someday provide easier mount syntax for -users who are used to Windows e.g. - net use <mount point> <UNC name or cifs URL> -Note that running the Winbind pam/nss module (logon service) on all of your -Linux clients is useful in mapping Uids and Gids consistently across the -domain to the proper network user. The mount.cifs mount helper can be -trivially built from Samba 3.0 or later source e.g. by executing: - - gcc samba/source/client/mount.cifs.c -o mount.cifs - -If cifs is built as a module, then the size and number of network buffers -and maximum number of simultaneous requests to one server can be configured. -Changing these from their defaults is not recommended. By executing modinfo - modinfo kernel/fs/cifs/cifs.ko -on kernel/fs/cifs/cifs.ko the list of configuration changes that can be made -at module initialization time (by running insmod cifs.ko) can be seen. - -Allowing User Mounts -==================== -To permit users to mount and unmount over directories they own is possible -with the cifs vfs. A way to enable such mounting is to mark the mount.cifs -utility as suid (e.g. "chmod +s /sbin/mount.cifs). To enable users to -umount shares they mount requires -1) mount.cifs version 1.4 or later -2) an entry for the share in /etc/fstab indicating that a user may -unmount it e.g. -//server/usersharename /mnt/username cifs user 0 0 - -Note that when the mount.cifs utility is run suid (allowing user mounts), -in order to reduce risks, the "nosuid" mount flag is passed in on mount to -disallow execution of an suid program mounted on the remote target. -When mount is executed as root, nosuid is not passed in by default, -and execution of suid programs on the remote target would be enabled -by default. This can be changed, as with nfs and other filesystems, -by simply specifying "nosuid" among the mount options. For user mounts -though to be able to pass the suid flag to mount requires rebuilding -mount.cifs with the following flag: - - gcc samba/source/client/mount.cifs.c -DCIFS_ALLOW_USR_SUID -o mount.cifs - -There is a corresponding manual page for cifs mounting in the Samba 3.0 and -later source tree in docs/manpages/mount.cifs.8 - -Allowing User Unmounts -====================== -To permit users to ummount directories that they have user mounted (see above), -the utility umount.cifs may be used. It may be invoked directly, or if -umount.cifs is placed in /sbin, umount can invoke the cifs umount helper -(at least for most versions of the umount utility) for umount of cifs -mounts, unless umount is invoked with -i (which will avoid invoking a umount -helper). As with mount.cifs, to enable user unmounts umount.cifs must be marked -as suid (e.g. "chmod +s /sbin/umount.cifs") or equivalent (some distributions -allow adding entries to a file to the /etc/permissions file to achieve the -equivalent suid effect). For this utility to succeed the target path -must be a cifs mount, and the uid of the current user must match the uid -of the user who mounted the resource. - -Also note that the customary way of allowing user mounts and unmounts is -(instead of using mount.cifs and unmount.cifs as suid) to add a line -to the file /etc/fstab for each //server/share you wish to mount, but -this can become unwieldy when potential mount targets include many -or unpredictable UNC names. - -Samba Considerations -==================== -To get the maximum benefit from the CIFS VFS, we recommend using a server that -supports the SNIA CIFS Unix Extensions standard (e.g. Samba 2.2.5 or later or -Samba 3.0) but the CIFS vfs works fine with a wide variety of CIFS servers. -Note that uid, gid and file permissions will display default values if you do -not have a server that supports the Unix extensions for CIFS (such as Samba -2.2.5 or later). To enable the Unix CIFS Extensions in the Samba server, add -the line: - - unix extensions = yes - -to your smb.conf file on the server. Note that the following smb.conf settings -are also useful (on the Samba server) when the majority of clients are Unix or -Linux: - - case sensitive = yes - delete readonly = yes - ea support = yes - -Note that server ea support is required for supporting xattrs from the Linux -cifs client, and that EA support is present in later versions of Samba (e.g. -3.0.6 and later (also EA support works in all versions of Windows, at least to -shares on NTFS filesystems). Extended Attribute (xattr) support is an optional -feature of most Linux filesystems which may require enabling via -make menuconfig. Client support for extended attributes (user xattr) can be -disabled on a per-mount basis by specifying "nouser_xattr" on mount. - -The CIFS client can get and set POSIX ACLs (getfacl, setfacl) to Samba servers -version 3.10 and later. Setting POSIX ACLs requires enabling both XATTR and -then POSIX support in the CIFS configuration options when building the cifs -module. POSIX ACL support can be disabled on a per mount basic by specifying -"noacl" on mount. - -Some administrators may want to change Samba's smb.conf "map archive" and -"create mask" parameters from the default. Unless the create mask is changed -newly created files can end up with an unnecessarily restrictive default mode, -which may not be what you want, although if the CIFS Unix extensions are -enabled on the server and client, subsequent setattr calls (e.g. chmod) can -fix the mode. Note that creating special devices (mknod) remotely -may require specifying a mkdev function to Samba if you are not using -Samba 3.0.6 or later. For more information on these see the manual pages -("man smb.conf") on the Samba server system. Note that the cifs vfs, -unlike the smbfs vfs, does not read the smb.conf on the client system -(the few optional settings are passed in on mount via -o parameters instead). -Note that Samba 2.2.7 or later includes a fix that allows the CIFS VFS to delete -open files (required for strict POSIX compliance). Windows Servers already -supported this feature. Samba server does not allow symlinks that refer to files -outside of the share, so in Samba versions prior to 3.0.6, most symlinks to -files with absolute paths (ie beginning with slash) such as: - ln -s /mnt/foo bar -would be forbidden. Samba 3.0.6 server or later includes the ability to create -such symlinks safely by converting unsafe symlinks (ie symlinks to server -files that are outside of the share) to a samba specific format on the server -that is ignored by local server applications and non-cifs clients and that will -not be traversed by the Samba server). This is opaque to the Linux client -application using the cifs vfs. Absolute symlinks will work to Samba 3.0.5 or -later, but only for remote clients using the CIFS Unix extensions, and will -be invisbile to Windows clients and typically will not affect local -applications running on the same server as Samba. - -Use instructions: -================ -Once the CIFS VFS support is built into the kernel or installed as a module -(cifs.o), you can use mount syntax like the following to access Samba or Windows -servers: - - mount -t cifs //9.53.216.11/e$ /mnt -o user=myname,pass=mypassword - -Before -o the option -v may be specified to make the mount.cifs -mount helper display the mount steps more verbosely. -After -o the following commonly used cifs vfs specific options -are supported: - - user=<username> - pass=<password> - domain=<domain name> - -Other cifs mount options are described below. Use of TCP names (in addition to -ip addresses) is available if the mount helper (mount.cifs) is installed. If -you do not trust the server to which are mounted, or if you do not have -cifs signing enabled (and the physical network is insecure), consider use -of the standard mount options "noexec" and "nosuid" to reduce the risk of -running an altered binary on your local system (downloaded from a hostile server -or altered by a hostile router). - -Although mounting using format corresponding to the CIFS URL specification is -not possible in mount.cifs yet, it is possible to use an alternate format -for the server and sharename (which is somewhat similar to NFS style mount -syntax) instead of the more widely used UNC format (i.e. \\server\share): - mount -t cifs tcp_name_of_server:share_name /mnt -o user=myname,pass=mypasswd - -When using the mount helper mount.cifs, passwords may be specified via alternate -mechanisms, instead of specifying it after -o using the normal "pass=" syntax -on the command line: -1) By including it in a credential file. Specify credentials=filename as one -of the mount options. Credential files contain two lines - username=someuser - password=your_password -2) By specifying the password in the PASSWD environment variable (similarly -the user name can be taken from the USER environment variable). -3) By specifying the password in a file by name via PASSWD_FILE -4) By specifying the password in a file by file descriptor via PASSWD_FD - -If no password is provided, mount.cifs will prompt for password entry - -Restrictions -============ -Servers must support either "pure-TCP" (port 445 TCP/IP CIFS connections) or RFC -1001/1002 support for "Netbios-Over-TCP/IP." This is not likely to be a -problem as most servers support this. - -Valid filenames differ between Windows and Linux. Windows typically restricts -filenames which contain certain reserved characters (e.g.the character : -which is used to delimit the beginning of a stream name by Windows), while -Linux allows a slightly wider set of valid characters in filenames. Windows -servers can remap such characters when an explicit mapping is specified in -the Server's registry. Samba starting with version 3.10 will allow such -filenames (ie those which contain valid Linux characters, which normally -would be forbidden for Windows/CIFS semantics) as long as the server is -configured for Unix Extensions (and the client has not disabled -/proc/fs/cifs/LinuxExtensionsEnabled). - - -CIFS VFS Mount Options -====================== -A partial list of the supported mount options follows: - user The user name to use when trying to establish - the CIFS session. - password The user password. If the mount helper is - installed, the user will be prompted for password - if not supplied. - ip The ip address of the target server - unc The target server Universal Network Name (export) to - mount. - domain Set the SMB/CIFS workgroup name prepended to the - username during CIFS session establishment - forceuid Set the default uid for inodes to the uid - passed in on mount. For mounts to servers - which do support the CIFS Unix extensions, such as a - properly configured Samba server, the server provides - the uid, gid and mode so this parameter should not be - specified unless the server and clients uid and gid - numbering differ. If the server and client are in the - same domain (e.g. running winbind or nss_ldap) and - the server supports the Unix Extensions then the uid - and gid can be retrieved from the server (and uid - and gid would not have to be specifed on the mount. - For servers which do not support the CIFS Unix - extensions, the default uid (and gid) returned on lookup - of existing files will be the uid (gid) of the person - who executed the mount (root, except when mount.cifs - is configured setuid for user mounts) unless the "uid=" - (gid) mount option is specified. Also note that permission - checks (authorization checks) on accesses to a file occur - at the server, but there are cases in which an administrator - may want to restrict at the client as well. For those - servers which do not report a uid/gid owner - (such as Windows), permissions can also be checked at the - client, and a crude form of client side permission checking - can be enabled by specifying file_mode and dir_mode on - the client. (default) - forcegid (similar to above but for the groupid instead of uid) (default) - noforceuid Fill in file owner information (uid) by requesting it from - the server if possible. With this option, the value given in - the uid= option (on mount) will only be used if the server - can not support returning uids on inodes. - noforcegid (similar to above but for the group owner, gid, instead of uid) - uid Set the default uid for inodes, and indicate to the - cifs kernel driver which local user mounted. If the server - supports the unix extensions the default uid is - not used to fill in the owner fields of inodes (files) - unless the "forceuid" parameter is specified. - gid Set the default gid for inodes (similar to above). - file_mode If CIFS Unix extensions are not supported by the server - this overrides the default mode for file inodes. - fsc Enable local disk caching using FS-Cache (off by default). This - option could be useful to improve performance on a slow link, - heavily loaded server and/or network where reading from the - disk is faster than reading from the server (over the network). - This could also impact scalability positively as the - number of calls to the server are reduced. However, local - caching is not suitable for all workloads for e.g. read-once - type workloads. So, you need to consider carefully your - workload/scenario before using this option. Currently, local - disk caching is functional for CIFS files opened as read-only. - dir_mode If CIFS Unix extensions are not supported by the server - this overrides the default mode for directory inodes. - port attempt to contact the server on this tcp port, before - trying the usual ports (port 445, then 139). - iocharset Codepage used to convert local path names to and from - Unicode. Unicode is used by default for network path - names if the server supports it. If iocharset is - not specified then the nls_default specified - during the local client kernel build will be used. - If server does not support Unicode, this parameter is - unused. - rsize default read size (usually 16K). The client currently - can not use rsize larger than CIFSMaxBufSize. CIFSMaxBufSize - defaults to 16K and may be changed (from 8K to the maximum - kmalloc size allowed by your kernel) at module install time - for cifs.ko. Setting CIFSMaxBufSize to a very large value - will cause cifs to use more memory and may reduce performance - in some cases. To use rsize greater than 127K (the original - cifs protocol maximum) also requires that the server support - a new Unix Capability flag (for very large read) which some - newer servers (e.g. Samba 3.0.26 or later) do. rsize can be - set from a minimum of 2048 to a maximum of 130048 (127K or - CIFSMaxBufSize, whichever is smaller) - wsize default write size (default 57344) - maximum wsize currently allowed by CIFS is 57344 (fourteen - 4096 byte pages) - actimeo=n attribute cache timeout in seconds (default 1 second). - After this timeout, the cifs client requests fresh attribute - information from the server. This option allows to tune the - attribute cache timeout to suit the workload needs. Shorter - timeouts mean better the cache coherency, but increased number - of calls to the server. Longer timeouts mean reduced number - of calls to the server at the expense of less stricter cache - coherency checks (i.e. incorrect attribute cache for a short - period of time). - rw mount the network share read-write (note that the - server may still consider the share read-only) - ro mount network share read-only - version used to distinguish different versions of the - mount helper utility (not typically needed) - sep if first mount option (after the -o), overrides - the comma as the separator between the mount - parms. e.g. - -o user=myname,password=mypassword,domain=mydom - could be passed instead with period as the separator by - -o sep=.user=myname.password=mypassword.domain=mydom - this might be useful when comma is contained within username - or password or domain. This option is less important - when the cifs mount helper cifs.mount (version 1.1 or later) - is used. - nosuid Do not allow remote executables with the suid bit - program to be executed. This is only meaningful for mounts - to servers such as Samba which support the CIFS Unix Extensions. - 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). - credentials Although ignored by the cifs kernel component, it is used by - the mount helper, mount.cifs. When mount.cifs is installed it - opens and reads the credential file specified in order - to obtain the userid and password arguments which are passed to - the cifs vfs. - guest Although ignored by the kernel component, the mount.cifs - mount helper will not prompt the user for a password - if guest is specified on the mount options. If no - password is specified a null password will be used. - perm Client does permission checks (vfs_permission check of uid - and gid of the file against the mode and desired operation), - Note that this is in addition to the normal ACL check on the - target machine done by the server software. - Client permission checking is enabled by default. - noperm Client does not do permission checks. This can expose - files on this mount to access by other users on the local - client system. It is typically only needed when the server - supports the CIFS Unix Extensions but the UIDs/GIDs on the - client and server system do not match closely enough to allow - access by the user doing the mount, but it may be useful with - non CIFS Unix Extension mounts for cases in which the default - mode is specified on the mount but is not to be enforced on the - client (e.g. perhaps when MultiUserMount is enabled) - 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 server's 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 some older - (e.g. pre-Windows 2000) do not support returning UniqueIDs - or the CIFS Unix Extensions equivalent and for those - this mount option will have no effect. Exporting cifs mounts - under nfsd requires this mount option on the cifs mount. - This is now the default if server supports the - required network operation. - noserverino Client generates inode numbers (rather than using the actual one - from the server). These inode numbers will vary after - unmount or reboot which can confuse some applications, - but not all server filesystems support unique inode - numbers. - setuids If the CIFS Unix extensions are negotiated with the server - the client will attempt to set the effective uid and gid of - the local process on newly created files, directories, and - devices (create, mkdir, mknod). If the CIFS Unix Extensions - are not negotiated, for newly created files and directories - instead of using the default uid and gid specified on - the mount, cache the new file's uid and gid locally which means - that the uid for the file can change when the inode is - reloaded (or the user remounts the share). - nosetuids The client will not attempt to set the uid and gid on - on newly created files, directories, and devices (create, - mkdir, mknod) which will result in the server setting the - uid and gid to the default (usually the server uid of the - user who mounted the share). Letting the server (rather than - the client) set the uid and gid is the default. If the CIFS - Unix Extensions are not negotiated then the uid and gid for - new files will appear to be the uid (gid) of the mounter or the - uid (gid) parameter specified on the mount. - netbiosname When mounting to servers via port 139, specifies the RFC1001 - source name to use to represent the client netbios machine - name when doing the RFC1001 netbios session initialize. - direct Do not do inode data caching on files opened on this mount. - This precludes mmapping files on this mount. In some cases - with fast networks and little or no caching benefits on the - client (e.g. when the application is doing large sequential - reads bigger than page size without rereading the same data) - this can provide better performance than the default - behavior which caches reads (readahead) and writes - (writebehind) through the local Linux client pagecache - if oplock (caching token) is granted and held. Note that - direct allows write operations larger than page size - to be sent to the server. - strictcache Use for switching on strict cache mode. In this mode the - client read from the cache all the time it has Oplock Level II, - otherwise - read from the server. All written data are stored - in the cache, but if the client doesn't have Exclusive Oplock, - it writes the data to the server. - rwpidforward Forward pid of a process who opened a file to any read or write - operation on that file. This prevent applications like WINE - from failing on read and write if we use mandatory brlock style. - acl Allow setfacl and getfacl to manage posix ACLs if server - supports them. (default) - noacl Do not allow setfacl and getfacl calls on this mount - user_xattr Allow getting and setting user xattrs (those attributes whose - name begins with "user." or "os2.") as OS/2 EAs (extended - attributes) to the server. This allows support of the - setfattr and getfattr utilities. (default) - nouser_xattr Do not allow getfattr/setfattr to get/set/list xattrs - mapchars Translate six of the seven reserved characters (not backslash) - *?<>|: - to the remap range (above 0xF000), which also - allows the CIFS client to recognize files created with - such characters by Windows's POSIX emulation. This can - also be useful when mounting to most versions of Samba - (which also forbids creating and opening files - whose names contain any of these seven characters). - This has no effect if the server does not support - Unicode on the wire. - nomapchars Do not translate any of these seven characters (default). - nocase Request case insensitive path name matching (case - sensitive is the default if the server supports it). - (mount option "ignorecase" is identical to "nocase") - posixpaths If CIFS Unix extensions are supported, attempt to - negotiate posix path name support which allows certain - characters forbidden in typical CIFS filenames, without - requiring remapping. (default) - noposixpaths If CIFS Unix extensions are supported, do not request - posix path name support (this may cause servers to - reject creatingfile with certain reserved characters). - nounix Disable the CIFS Unix Extensions for this mount (tree - connection). This is rarely needed, but it may be useful - in order to turn off multiple settings all at once (ie - posix acls, posix locks, posix paths, symlink support - and retrieving uids/gids/mode from the server) or to - work around a bug in server which implement the Unix - Extensions. - nobrl Do not send byte range lock requests to the server. - This is necessary for certain applications that break - with cifs style mandatory byte range locks (and most - cifs servers do not yet support requesting advisory - byte range locks). - forcemandatorylock Even if the server supports posix (advisory) byte range - locking, send only mandatory lock requests. For some - (presumably rare) applications, originally coded for - DOS/Windows, which require Windows style mandatory byte range - locking, they may be able to take advantage of this option, - forcing the cifs client to only send mandatory locks - even if the cifs server would support posix advisory locks. - "forcemand" is accepted as a shorter form of this mount - option. - nostrictsync If this mount option is set, when an application does an - fsync call then the cifs client does not send an SMB Flush - to the server (to force the server to write all dirty data - for this file immediately to disk), although cifs still sends - all dirty (cached) file data to the server and waits for the - server to respond to the write. Since SMB Flush can be - very slow, and some servers may be reliable enough (to risk - delaying slightly flushing the data to disk on the server), - turning on this option may be useful to improve performance for - applications that fsync too much, at a small risk of server - crash. If this mount option is not set, by default cifs will - send an SMB flush request (and wait for a response) on every - fsync call. - nodfs Disable DFS (global name space support) even if the - server claims to support it. This can help work around - a problem with parsing of DFS paths with Samba server - versions 3.0.24 and 3.0.25. - remount remount the share (often used to change from ro to rw mounts - or vice versa) - cifsacl Report mode bits (e.g. on stat) based on the Windows ACL for - the file. (EXPERIMENTAL) - servern Specify the server 's netbios name (RFC1001 name) to use - when attempting to setup a session to the server. - This is needed for mounting to some older servers (such - as OS/2 or Windows 98 and Windows ME) since they do not - support a default server name. A server name can be up - to 15 characters long and is usually uppercased. - sfu When the CIFS Unix Extensions are not negotiated, attempt to - create device files and fifos in a format compatible with - Services for Unix (SFU). In addition retrieve bits 10-12 - of the mode via the SETFILEBITS extended attribute (as - SFU does). In the future the bottom 9 bits of the - mode also will be emulated using queries of the security - descriptor (ACL). - mfsymlinks Enable support for Minshall+French symlinks - (see http://wiki.samba.org/index.php/UNIX_Extensions#Minshall.2BFrench_symlinks) - This option is ignored when specified together with the - 'sfu' option. Minshall+French symlinks are used even if - the server supports the CIFS Unix Extensions. - sign Must use packet signing (helps avoid unwanted data modification - by intermediate systems in the route). Note that signing - does not work with lanman or plaintext authentication. - seal Must seal (encrypt) all data on this mounted share before - sending on the network. Requires support for Unix Extensions. - Note that this differs from the sign mount option in that it - causes encryption of data sent over this mounted share but other - shares mounted to the same server are unaffected. - locallease This option is rarely needed. Fcntl F_SETLEASE is - used by some applications such as Samba and NFSv4 server to - check to see whether a file is cacheable. CIFS has no way - to explicitly request a lease, but can check whether a file - is cacheable (oplocked). Unfortunately, even if a file - is not oplocked, it could still be cacheable (ie cifs client - could grant fcntl leases if no other local processes are using - the file) for cases for example such as when the server does not - support oplocks and the user is sure that the only updates to - the file will be from this client. Specifying this mount option - will allow the cifs client to check for leases (only) locally - for files which are not oplocked instead of denying leases - in that case. (EXPERIMENTAL) - sec Security mode. Allowed values are: - none attempt to connection as a null user (no name) - krb5 Use Kerberos version 5 authentication - krb5i Use Kerberos authentication and packet signing - ntlm Use NTLM password hashing (default) - ntlmi Use NTLM password hashing with signing (if - /proc/fs/cifs/PacketSigningEnabled on or if - server requires signing also can be the default) - ntlmv2 Use NTLMv2 password hashing - ntlmv2i Use NTLMv2 password hashing with packet signing - lanman (if configured in kernel config) use older - lanman hash -hard Retry file operations if server is not responding -soft Limit retries to unresponsive servers (usually only - one retry) before returning an error. (default) - -The mount.cifs mount helper also accepts a few mount options before -o -including: - - -S take password from stdin (equivalent to setting the environment - variable "PASSWD_FD=0" - -V print mount.cifs version - -? display simple usage information - -With most 2.6 kernel versions of modutils, the version of the cifs kernel -module can be displayed via modinfo. - -Misc /proc/fs/cifs Flags and Debug Info -======================================= -Informational pseudo-files: -DebugData Displays information about active CIFS sessions and - shares, features enabled as well as the cifs.ko - version. -Stats Lists summary resource usage information as well as per - share statistics, if CONFIG_CIFS_STATS in enabled - in the kernel configuration. - -Configuration pseudo-files: -PacketSigningEnabled If set to one, cifs packet signing is enabled - and will be used if the server requires - it. If set to two, cifs packet signing is - required even if the server considers packet - signing optional. (default 1) -SecurityFlags Flags which control security negotiation and - also packet signing. Authentication (may/must) - flags (e.g. for NTLM and/or NTLMv2) may be combined with - the signing flags. Specifying two different password - hashing mechanisms (as "must use") on the other hand - does not make much sense. Default flags are - 0x07007 - (NTLM, NTLMv2 and packet signing allowed). The maximum - allowable flags if you want to allow mounts to servers - using weaker password hashes is 0x37037 (lanman, - plaintext, ntlm, ntlmv2, signing allowed). Some - SecurityFlags require the corresponding menuconfig - options to be enabled (lanman and plaintext require - CONFIG_CIFS_WEAK_PW_HASH for example). Enabling - plaintext authentication currently requires also - enabling lanman authentication in the security flags - because the cifs module only supports sending - laintext passwords using the older lanman dialect - form of the session setup SMB. (e.g. for authentication - using plain text passwords, set the SecurityFlags - to 0x30030): - - may use packet signing 0x00001 - must use packet signing 0x01001 - may use NTLM (most common password hash) 0x00002 - must use NTLM 0x02002 - may use NTLMv2 0x00004 - must use NTLMv2 0x04004 - may use Kerberos security 0x00008 - must use Kerberos 0x08008 - may use lanman (weak) password hash 0x00010 - must use lanman password hash 0x10010 - may use plaintext passwords 0x00020 - must use plaintext passwords 0x20020 - (reserved for future packet encryption) 0x00040 - -cifsFYI If set to non-zero value, additional debug information - will be logged to the system error log. This field - contains three flags controlling different classes of - debugging entries. The maximum value it can be set - to is 7 which enables all debugging points (default 0). - Some debugging statements are not compiled into the - cifs kernel unless CONFIG_CIFS_DEBUG2 is enabled in the - kernel configuration. cifsFYI may be set to one or - nore of the following flags (7 sets them all): - - log cifs informational messages 0x01 - log return codes from cifs entry points 0x02 - log slow responses (ie which take longer than 1 second) - CONFIG_CIFS_STATS2 must be enabled in .config 0x04 - - -traceSMB If set to one, debug information is logged to the - system error log with the start of smb requests - and responses (default 0) -LookupCacheEnable If set to one, inode information is kept cached - for one second improving performance of lookups - (default 1) -OplockEnabled If set to one, safe distributed caching enabled. - (default 1) -LinuxExtensionsEnabled If set to one then the client will attempt to - use the CIFS "UNIX" extensions which are optional - protocol enhancements that allow CIFS servers - to return accurate UID/GID information as well - as support symbolic links. If you use servers - such as Samba that support the CIFS Unix - extensions but do not want to use symbolic link - support and want to map the uid and gid fields - to values supplied at mount (rather than the - actual values, then set this to zero. (default 1) - -These experimental features and tracing can be enabled by changing flags in -/proc/fs/cifs (after the cifs module has been installed or built into the -kernel, e.g. insmod cifs). To enable a feature set it to 1 e.g. to enable -tracing to the kernel message log type: - - echo 7 > /proc/fs/cifs/cifsFYI - -cifsFYI functions as a bit mask. Setting it to 1 enables additional kernel -logging of various informational messages. 2 enables logging of non-zero -SMB return codes while 4 enables logging of requests that take longer -than one second to complete (except for byte range lock requests). -Setting it to 4 requires defining CONFIG_CIFS_STATS2 manually in the -source code (typically by setting it in the beginning of cifsglob.h), -and setting it to seven enables all three. Finally, tracing -the start of smb requests and responses can be enabled via: - - echo 1 > /proc/fs/cifs/traceSMB - -Per share (per client mount) statistics are available in /proc/fs/cifs/Stats -if the kernel was configured with cifs statistics enabled. The statistics -represent the number of successful (ie non-zero return code from the server) -SMB responses to some of the more common commands (open, delete, mkdir etc.). -Also recorded is the total bytes read and bytes written to the server for -that share. Note that due to client caching effects this can be less than the -number of bytes read and written by the application running on the client. -The statistics for the number of total SMBs and oplock breaks are different in -that they represent all for that share, not just those for which the server -returned success. - -Also note that "cat /proc/fs/cifs/DebugData" will display information about -the active sessions and the shares that are mounted. - -Enabling Kerberos (extended security) works but requires version 1.2 or later -of the helper program cifs.upcall to be present and to be configured in the -/etc/request-key.conf file. The cifs.upcall helper program is from the Samba -project(http://www.samba.org). NTLM and NTLMv2 and LANMAN support do not -require this helper. Note that NTLMv2 security (which does not require the -cifs.upcall helper program), instead of using Kerberos, is sufficient for -some use cases. - -DFS support allows transparent redirection to shares in an MS-DFS name space. -In addition, DFS support for target shares which are specified as UNC -names which begin with host names (rather than IP addresses) requires -a user space helper (such as cifs.upcall) to be present in order to -translate host names to ip address, and the user space helper must also -be configured in the file /etc/request-key.conf. Samba, Windows servers and -many NAS appliances support DFS as a way of constructing a global name -space to ease network configuration and improve reliability. - -To use cifs Kerberos and DFS support, the Linux keyutils package should be -installed and something like the following lines should be added to the -/etc/request-key.conf file: - -create cifs.spnego * * /usr/local/sbin/cifs.upcall %k -create dns_resolver * * /usr/local/sbin/cifs.upcall %k - -CIFS kernel module parameters -============================= -These module parameters can be specified or modified either during the time of -module loading or during the runtime by using the interface - /proc/module/cifs/parameters/<param> - -i.e. echo "value" > /sys/module/cifs/parameters/<param> - -1. enable_oplocks - Enable or disable oplocks. Oplocks are enabled by default. - [Y/y/1]. To disable use any of [N/n/0]. - diff --git a/fs/cifs/TODO b/fs/cifs/TODO deleted file mode 100644 index 355abcdcda9..00000000000 --- a/fs/cifs/TODO +++ /dev/null @@ -1,129 +0,0 @@ -Version 1.53 May 20, 2008 - -A Partial List of Missing Features -================================== - -Contributions are welcome. There are plenty of opportunities -for visible, important contributions to this module. Here -is a partial list of the known problems and missing features: - -a) Support for SecurityDescriptors(Windows/CIFS ACLs) for chmod/chgrp/chown -so that these operations can be supported to Windows servers - -b) Mapping POSIX ACLs (and eventually NFSv4 ACLs) to CIFS -SecurityDescriptors - -c) Better pam/winbind integration (e.g. to handle uid mapping -better) - -d) Cleanup now unneeded SessSetup code in -fs/cifs/connect.c and add back in NTLMSSP code if any servers -need it - -e) fix NTLMv2 signing when two mounts with different users to same -server. - -f) Directory entry caching relies on a 1 second timer, rather than -using FindNotify or equivalent. - (started) - -g) quota support (needs minor kernel change since quota calls -to make it to network filesystems or deviceless filesystems) - -h) investigate sync behavior (including syncpage) and check -for proper behavior of intr/nointr - -i) improve support for very old servers (OS/2 and Win9x for example) -Including support for changing the time remotely (utimes command). - -j) hook lower into the sockets api (as NFS/SunRPC does) to avoid the -extra copy in/out of the socket buffers in some cases. - -k) Better optimize open (and pathbased setfilesize) to reduce the -oplock breaks coming from windows srv. Piggyback identical file -opens on top of each other by incrementing reference count rather -than resending (helps reduce server resource utilization and avoid -spurious oplock breaks). - -l) Improve performance of readpages by sending more than one read -at a time when 8 pages or more are requested. In conjuntion -add support for async_cifs_readpages. - -m) Add support for storing symlink info to Windows servers -in the Extended Attribute format their SFU clients would recognize. - -n) Finish fcntl D_NOTIFY support so kde and gnome file list windows -will autorefresh (partially complete by Asser). Needs minor kernel -vfs change to support removing D_NOTIFY on a file. - -o) Add GUI tool to configure /proc/fs/cifs settings and for display of -the CIFS statistics (started) - -p) implement support for security and trusted categories of xattrs -(requires minor protocol extension) to enable better support for SELINUX - -q) Implement O_DIRECT flag on open (already supported on mount) - -r) Create UID mapping facility so server UIDs can be mapped on a per -mount or a per server basis to client UIDs or nobody if no mapping -exists. This is helpful when Unix extensions are negotiated to -allow better permission checking when UIDs differ on the server -and client. Add new protocol request to the CIFS protocol -standard for asking the server for the corresponding name of a -particular uid. - -s) Add support for CIFS Unix and also the newer POSIX extensions to the -server side for Samba 4. - -t) In support for OS/2 (LANMAN 1.2 and LANMAN2.1 based SMB servers) -need to add ability to set time to server (utimes command) - -u) DOS attrs - returned as pseudo-xattr in Samba format (check VFAT and NTFS for this too) - -v) mount check for unmatched uids - -w) Add support for new vfs entry point for fallocate - -x) Fix Samba 3 server to handle Linux kernel aio so dbench with lots of -processes can proceed better in parallel (on the server) - -y) Fix Samba 3 to handle reads/writes over 127K (and remove the cifs mount -restriction of wsize max being 127K) - -KNOWN BUGS (updated April 24, 2007) -==================================== -See http://bugzilla.samba.org - search on product "CifsVFS" for -current bug list. - -1) existing symbolic links (Windows reparse points) are recognized but -can not be created remotely. They are implemented for Samba and those that -support the CIFS Unix extensions, although earlier versions of Samba -overly restrict the pathnames. -2) follow_link and readdir code does not follow dfs junctions -but recognizes them -3) create of new files to FAT partitions on Windows servers can -succeed but still return access denied (appears to be Windows -server not cifs client problem) and has not been reproduced recently. -NTFS partitions do not have this problem. -4) Unix/POSIX capabilities are reset after reconnection, and affect -a few fields in the tree connection but we do do not know which -superblocks to apply these changes to. We should probably walk -the list of superblocks to set these. Also need to check the -flags on the second mount to the same share, and see if we -can do the same trick that NFS does to remount duplicate shares. - -Misc testing to do -================== -1) check out max path names and max path name components against various server -types. Try nested symlinks (8 deep). Return max path name in stat -f information - -2) Modify file portion of ltp so it can run against a mounted network -share and run it against cifs vfs in automated fashion. - -3) Additional performance testing and optimization using iozone and similar - -there are some easy changes that can be done to parallelize sequential writes, -and when signing is disabled to request larger read sizes (larger than -negotiated size) and send larger write sizes to modern servers. - -4) More exhaustively test against less common servers. More testing -against Windows 9x, Windows ME servers. - diff --git a/fs/cifs/cifs_unicode.h b/fs/cifs/cifs_unicode.h index fe8d6276410..d8eac3b6cef 100644 --- a/fs/cifs/cifs_unicode.h +++ b/fs/cifs/cifs_unicode.h @@ -91,6 +91,8 @@ extern __le16 *cifs_strndup_to_utf16(const char *src, const int maxlen, #endif /* CONFIG_CIFS_SMB2 */ #endif +wchar_t cifs_toupper(wchar_t in); + /* * UniStrcat: Concatenate the second string to the first * diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 85ea98d139f..a16b4e58bcc 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -255,6 +255,7 @@ cifs_alloc_inode(struct super_block *sb) cifs_inode->server_eof = 0; cifs_inode->uniqueid = 0; cifs_inode->createtime = 0; + cifs_inode->epoch = 0; #ifdef CONFIG_CIFS_SMB2 get_random_bytes(cifs_inode->lease_key, SMB2_LEASE_KEY_SIZE); #endif @@ -357,6 +358,18 @@ cifs_show_cache_flavor(struct seq_file *s, struct cifs_sb_info *cifs_sb) seq_printf(s, "loose"); } +static void +cifs_show_nls(struct seq_file *s, struct nls_table *cur) +{ + struct nls_table *def; + + /* Display iocharset= option if it's not default charset */ + def = load_nls_default(); + if (def != cur) + seq_printf(s, ",iocharset=%s", cur->charset); + unload_nls(def); +} + /* * cifs_show_options() is for displaying mount options in /proc/mounts. * Not all settable options are displayed but most of the important @@ -418,6 +431,9 @@ cifs_show_options(struct seq_file *s, struct dentry *root) seq_printf(s, ",file_mode=0%ho,dir_mode=0%ho", cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode); + + cifs_show_nls(s, cifs_sb->local_nls); + if (tcon->seal) seq_printf(s, ",seal"); if (tcon->nocase) @@ -718,7 +734,7 @@ static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, written = generic_file_aio_write(iocb, iov, nr_segs, pos); - if (CIFS_I(inode)->clientCanCacheAll) + if (CIFS_CACHE_WRITE(CIFS_I(inode))) return written; rc = filemap_fdatawrite(inode->i_mapping); @@ -743,7 +759,7 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int whence) * We need to be sure that all dirty pages are written and the * server has the newest file length. */ - if (!CIFS_I(inode)->clientCanCacheRead && inode->i_mapping && + if (!CIFS_CACHE_READ(CIFS_I(inode)) && inode->i_mapping && inode->i_mapping->nrpages != 0) { rc = filemap_fdatawait(inode->i_mapping); if (rc) { @@ -767,8 +783,10 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int whence) static int cifs_setlease(struct file *file, long arg, struct file_lock **lease) { - /* note that this is called by vfs setlease with i_lock held - to protect *lease from going away */ + /* + * Note that this is called by vfs setlease with i_lock held to + * protect *lease from going away. + */ struct inode *inode = file_inode(file); struct cifsFileInfo *cfile = file->private_data; @@ -776,20 +794,19 @@ static int cifs_setlease(struct file *file, long arg, struct file_lock **lease) return -EINVAL; /* check if file is oplocked */ - if (((arg == F_RDLCK) && - (CIFS_I(inode)->clientCanCacheRead)) || - ((arg == F_WRLCK) && - (CIFS_I(inode)->clientCanCacheAll))) + if (((arg == F_RDLCK) && CIFS_CACHE_READ(CIFS_I(inode))) || + ((arg == F_WRLCK) && CIFS_CACHE_WRITE(CIFS_I(inode)))) return generic_setlease(file, arg, lease); else if (tlink_tcon(cfile->tlink)->local_lease && - !CIFS_I(inode)->clientCanCacheRead) - /* If the server claims to support oplock on this - file, then we still need to check oplock even - if the local_lease mount option is set, but there - are servers which do not support oplock for which - this mount option may be useful if the user - knows that the file won't be changed on the server - by anyone else */ + !CIFS_CACHE_READ(CIFS_I(inode))) + /* + * If the server claims to support oplock on this file, then we + * still need to check oplock even if the local_lease mount + * option is set, but there are servers which do not support + * oplock for which this mount option may be useful if the user + * knows that the file won't be changed on the server by anyone + * else. + */ return generic_setlease(file, arg, lease); else return -EAGAIN; diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 52ca861ed35..cfa14c80ef3 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -28,6 +28,7 @@ #include "cifsacl.h" #include <crypto/internal/hash.h> #include <linux/scatterlist.h> +#include <uapi/linux/cifs/cifs_mount.h> #ifdef CONFIG_CIFS_SMB2 #include "smb2pdu.h" #endif @@ -41,12 +42,7 @@ #define MAX_SES_INFO 2 #define MAX_TCON_INFO 4 -#define MAX_TREE_SIZE (2 + MAX_SERVER_SIZE + 1 + MAX_SHARE_SIZE + 1) -#define MAX_SERVER_SIZE 15 -#define MAX_SHARE_SIZE 80 -#define CIFS_MAX_DOMAINNAME_LEN 256 /* max domain name length */ -#define MAX_USERNAME_SIZE 256 /* reasonable maximum for current servers */ -#define MAX_PASSWORD_SIZE 512 /* max for windows seems to be 256 wide chars */ +#define MAX_TREE_SIZE (2 + CIFS_NI_MAXHOST + 1 + CIFS_MAX_SHARE_LEN + 1) #define CIFS_MIN_RCV_POOL 4 @@ -135,6 +131,7 @@ struct cifs_secmech { /* per smb session structure/fields */ struct ntlmssp_auth { + bool sesskey_per_smbsess; /* whether session key is per smb session */ __u32 client_flags; /* sent by client in type 1 ntlmsssp exchange */ __u32 server_flags; /* sent by server in type 2 ntlmssp exchange */ unsigned char ciphertext[CIFS_CPHTXT_SIZE]; /* sent to server */ @@ -308,6 +305,9 @@ struct smb_version_operations { int (*create_hardlink)(const unsigned int, struct cifs_tcon *, const char *, const char *, struct cifs_sb_info *); + /* query symlink target */ + int (*query_symlink)(const unsigned int, struct cifs_tcon *, + const char *, char **, struct cifs_sb_info *); /* open a file for non-posix mounts */ int (*open)(const unsigned int, struct cifs_open_parms *, __u32 *, FILE_ALL_INFO *); @@ -361,18 +361,24 @@ struct smb_version_operations { /* push brlocks from the cache to the server */ int (*push_mand_locks)(struct cifsFileInfo *); /* get lease key of the inode */ - void (*get_lease_key)(struct inode *, struct cifs_fid *fid); + void (*get_lease_key)(struct inode *, struct cifs_fid *); /* set lease key of the inode */ - void (*set_lease_key)(struct inode *, struct cifs_fid *fid); + void (*set_lease_key)(struct inode *, struct cifs_fid *); /* generate new lease key */ - void (*new_lease_key)(struct cifs_fid *fid); - /* The next two functions will need to be changed to per smb session */ - void (*generate_signingkey)(struct TCP_Server_Info *server); - int (*calc_signature)(struct smb_rqst *rqst, - struct TCP_Server_Info *server); - int (*query_mf_symlink)(const unsigned char *path, char *pbuf, - unsigned int *pbytes_read, struct cifs_sb_info *cifs_sb, - unsigned int xid); + void (*new_lease_key)(struct cifs_fid *); + int (*generate_signingkey)(struct cifs_ses *); + int (*calc_signature)(struct smb_rqst *, struct TCP_Server_Info *); + int (*query_mf_symlink)(const unsigned char *, char *, unsigned int *, + struct cifs_sb_info *, unsigned int); + /* if we can do cache read operations */ + bool (*is_read_op)(__u32); + /* set oplock level for the inode */ + void (*set_oplock_level)(struct cifsInodeInfo *, __u32, unsigned int, + bool *); + /* create lease context buffer for CREATE request */ + char * (*create_lease_buf)(u8 *, u8); + /* parse lease context buffer and return oplock/epoch info */ + __u8 (*parse_lease_buf)(void *, unsigned int *); }; struct smb_version_values { @@ -390,9 +396,9 @@ struct smb_version_values { unsigned int cap_unix; unsigned int cap_nt_find; unsigned int cap_large_files; - unsigned int oplock_read; __u16 signing_enabled; __u16 signing_required; + size_t create_lease_size; }; #define HEADER_SIZE(server) (server->vals->header_size) @@ -548,7 +554,6 @@ struct TCP_Server_Info { int timeAdj; /* Adjust for difference in server time zone in sec */ __u64 CurrentMid; /* multiplex id - rotating counter */ char cryptkey[CIFS_CRYPTO_KEY_SIZE]; /* used by ntlm, ntlmv2 etc */ - char smb3signingkey[SMB3_SIGN_KEY_SIZE]; /* for signing smb3 packets */ /* 16th byte of RFC1001 workstation name is always null */ char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; __u32 sequence_number; /* for signing, protected by srv_mutex */ @@ -731,6 +736,7 @@ struct cifs_ses { bool need_reconnect:1; /* connection reset, uid now invalid */ #ifdef CONFIG_CIFS_SMB2 __u16 session_flags; + char smb3signingkey[SMB3_SIGN_KEY_SIZE]; /* for signing smb3 packets */ #endif /* CONFIG_CIFS_SMB2 */ }; @@ -935,6 +941,8 @@ struct cifs_fid { __u8 lease_key[SMB2_LEASE_KEY_SIZE]; /* lease key for smb2 */ #endif struct cifs_pending_open *pending_open; + unsigned int epoch; + bool purge_cache; }; struct cifs_fid_locks { @@ -1032,6 +1040,17 @@ cifsFileInfo_get_locked(struct cifsFileInfo *cifs_file) struct cifsFileInfo *cifsFileInfo_get(struct cifsFileInfo *cifs_file); void cifsFileInfo_put(struct cifsFileInfo *cifs_file); +#define CIFS_CACHE_READ_FLG 1 +#define CIFS_CACHE_HANDLE_FLG 2 +#define CIFS_CACHE_RH_FLG (CIFS_CACHE_READ_FLG | CIFS_CACHE_HANDLE_FLG) +#define CIFS_CACHE_WRITE_FLG 4 +#define CIFS_CACHE_RW_FLG (CIFS_CACHE_READ_FLG | CIFS_CACHE_WRITE_FLG) +#define CIFS_CACHE_RHW_FLG (CIFS_CACHE_RW_FLG | CIFS_CACHE_HANDLE_FLG) + +#define CIFS_CACHE_READ(cinode) (cinode->oplock & CIFS_CACHE_READ_FLG) +#define CIFS_CACHE_HANDLE(cinode) (cinode->oplock & CIFS_CACHE_HANDLE_FLG) +#define CIFS_CACHE_WRITE(cinode) (cinode->oplock & CIFS_CACHE_WRITE_FLG) + /* * One of these for each file inode */ @@ -1043,8 +1062,8 @@ struct cifsInodeInfo { /* BB add in lists for dirty pages i.e. write caching info for oplock */ struct list_head openFileList; __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */ - bool clientCanCacheRead; /* read oplock */ - bool clientCanCacheAll; /* read and writebehind oplock */ + unsigned int oplock; /* oplock/lease level we have */ + unsigned int epoch; /* used to track lease state changes */ bool delete_pending; /* DELETE_ON_CLOSE is set */ bool invalid_mapping; /* pagecache is invalid */ unsigned long time; /* jiffies of last update of inode */ @@ -1502,7 +1521,7 @@ extern mempool_t *cifs_mid_poolp; extern struct smb_version_operations smb1_operations; extern struct smb_version_values smb1_values; #define SMB20_VERSION_STRING "2.0" -/*extern struct smb_version_operations smb20_operations; */ /* not needed yet */ +extern struct smb_version_operations smb20_operations; extern struct smb_version_values smb20_values; #define SMB21_VERSION_STRING "2.1" extern struct smb_version_operations smb21_operations; diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 11ca24a8e05..948676db8e2 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -1495,11 +1495,12 @@ struct reparse_data { __u32 ReparseTag; __u16 ReparseDataLength; __u16 Reserved; - __u16 AltNameOffset; - __u16 AltNameLen; - __u16 TargetNameOffset; - __u16 TargetNameLen; - char LinkNamesBuf[1]; + __u16 SubstituteNameOffset; + __u16 SubstituteNameLength; + __u16 PrintNameOffset; + __u16 PrintNameLength; + __u32 Flags; + char PathBuffer[0]; } __attribute__((packed)); struct cifs_quota_data { diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index b29a012bed3..b5ec2a268f5 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -357,13 +357,9 @@ extern int CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, const unsigned char *searchName, char **syminfo, const struct nls_table *nls_codepage); -#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL -extern int CIFSSMBQueryReparseLinkInfo(const unsigned int xid, - struct cifs_tcon *tcon, - const unsigned char *searchName, - char *symlinkinfo, const int buflen, __u16 fid, - const struct nls_table *nls_codepage); -#endif /* temporarily unused until cifs_symlink fixed */ +extern int CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, + __u16 fid, char **symlinkinfo, + const struct nls_table *nls_codepage); extern int CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon, const char *fileName, const int disposition, const int access_flags, const int omode, @@ -435,7 +431,7 @@ extern int setup_ntlm_response(struct cifs_ses *, const struct nls_table *); extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *); extern void cifs_crypto_shash_release(struct TCP_Server_Info *); extern int calc_seckey(struct cifs_ses *); -extern void generate_smb3signingkey(struct TCP_Server_Info *); +extern int generate_smb3signingkey(struct cifs_ses *); #ifdef CONFIG_CIFS_WEAK_PW_HASH extern int calc_lanman_hash(const char *password, const char *cryptkey, diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index a89c4cb4e6c..a3d74fea162 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -3067,7 +3067,6 @@ querySymLinkRetry: return rc; } -#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL /* * Recent Windows versions now create symlinks more frequently * and they use the "reparse point" mechanism below. We can of course @@ -3079,18 +3078,22 @@ querySymLinkRetry: * it is not compiled in by default until callers fixed up and more tested. */ int -CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon, - const unsigned char *searchName, - char *symlinkinfo, const int buflen, __u16 fid, - const struct nls_table *nls_codepage) +CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, + __u16 fid, char **symlinkinfo, + const struct nls_table *nls_codepage) { int rc = 0; int bytes_returned; struct smb_com_transaction_ioctl_req *pSMB; struct smb_com_transaction_ioctl_rsp *pSMBr; + bool is_unicode; + unsigned int sub_len; + char *sub_start; + struct reparse_data *reparse_buf; + __u32 data_offset, data_count; + char *end_of_smb; - cifs_dbg(FYI, "In Windows reparse style QueryLink for path %s\n", - searchName); + cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid); rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -3119,66 +3122,55 @@ CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc); - } else { /* decode response */ - __u32 data_offset = le32_to_cpu(pSMBr->DataOffset); - __u32 data_count = le32_to_cpu(pSMBr->DataCount); - if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) { - /* BB also check enough total bytes returned */ - rc = -EIO; /* bad smb */ - goto qreparse_out; - } - if (data_count && (data_count < 2048)) { - char *end_of_smb = 2 /* sizeof byte count */ + - get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount; - - struct reparse_data *reparse_buf = - (struct reparse_data *) - ((char *)&pSMBr->hdr.Protocol - + data_offset); - if ((char *)reparse_buf >= end_of_smb) { - rc = -EIO; - goto qreparse_out; - } - if ((reparse_buf->LinkNamesBuf + - reparse_buf->TargetNameOffset + - reparse_buf->TargetNameLen) > end_of_smb) { - cifs_dbg(FYI, "reparse buf beyond SMB\n"); - rc = -EIO; - goto qreparse_out; - } + goto qreparse_out; + } - if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { - cifs_from_ucs2(symlinkinfo, (__le16 *) - (reparse_buf->LinkNamesBuf + - reparse_buf->TargetNameOffset), - buflen, - reparse_buf->TargetNameLen, - nls_codepage, 0); - } else { /* ASCII names */ - strncpy(symlinkinfo, - reparse_buf->LinkNamesBuf + - reparse_buf->TargetNameOffset, - min_t(const int, buflen, - reparse_buf->TargetNameLen)); - } - } else { - rc = -EIO; - cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n"); - } - symlinkinfo[buflen] = 0; /* just in case so the caller - does not go off the end of the buffer */ - cifs_dbg(FYI, "readlink result - %s\n", symlinkinfo); + data_offset = le32_to_cpu(pSMBr->DataOffset); + data_count = le32_to_cpu(pSMBr->DataCount); + if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) { + /* BB also check enough total bytes returned */ + rc = -EIO; /* bad smb */ + goto qreparse_out; + } + if (!data_count || (data_count > 2048)) { + rc = -EIO; + cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n"); + goto qreparse_out; + } + end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount; + reparse_buf = (struct reparse_data *) + ((char *)&pSMBr->hdr.Protocol + data_offset); + if ((char *)reparse_buf >= end_of_smb) { + rc = -EIO; + goto qreparse_out; } + if ((reparse_buf->PathBuffer + reparse_buf->PrintNameOffset + + reparse_buf->PrintNameLength) > end_of_smb) { + cifs_dbg(FYI, "reparse buf beyond SMB\n"); + rc = -EIO; + goto qreparse_out; + } + sub_start = reparse_buf->SubstituteNameOffset + reparse_buf->PathBuffer; + sub_len = reparse_buf->SubstituteNameLength; + if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) + is_unicode = true; + else + is_unicode = false; + /* BB FIXME investigate remapping reserved chars here */ + *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode, + nls_codepage); + if (!*symlinkinfo) + rc = -ENOMEM; qreparse_out: cifs_buf_release(pSMB); - /* Note: On -EAGAIN error only caller can retry on handle based calls - since file handle passed in no longer valid */ - + /* + * Note: On -EAGAIN error only caller can retry on handle based calls + * since file handle passed in no longer valid. + */ return rc; } -#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */ #ifdef CONFIG_CIFS_POSIX diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index d67c550c498..a279ffc0bc2 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -379,6 +379,7 @@ cifs_reconnect(struct TCP_Server_Info *server) try_to_freeze(); /* we should try only the port we connected to before */ + mutex_lock(&server->srv_mutex); rc = generic_ip_connect(server); if (rc) { cifs_dbg(FYI, "reconnect error %d\n", rc); @@ -390,6 +391,7 @@ cifs_reconnect(struct TCP_Server_Info *server) server->tcpStatus = CifsNeedNegotiate; spin_unlock(&GlobalMid_Lock); } + mutex_unlock(&server->srv_mutex); } while (server->tcpStatus == CifsNeedReconnect); return rc; @@ -1114,7 +1116,7 @@ cifs_parse_smb_version(char *value, struct smb_vol *vol) break; #ifdef CONFIG_CIFS_SMB2 case Smb_20: - vol->ops = &smb21_operations; /* currently identical with 2.1 */ + vol->ops = &smb20_operations; vol->vals = &smb20_values; break; case Smb_21: @@ -1575,8 +1577,8 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, if (string == NULL) goto out_nomem; - if (strnlen(string, MAX_USERNAME_SIZE) > - MAX_USERNAME_SIZE) { + if (strnlen(string, CIFS_MAX_USERNAME_LEN) > + CIFS_MAX_USERNAME_LEN) { printk(KERN_WARNING "CIFS: username too long\n"); goto cifs_parse_mount_err; } @@ -2221,13 +2223,13 @@ static int match_session(struct cifs_ses *ses, struct smb_vol *vol) /* anything else takes username/password */ if (strncmp(ses->user_name, vol->username ? vol->username : "", - MAX_USERNAME_SIZE)) + CIFS_MAX_USERNAME_LEN)) return 0; if (strlen(vol->username) != 0 && ses->password != NULL && strncmp(ses->password, vol->password ? vol->password : "", - MAX_PASSWORD_SIZE)) + CIFS_MAX_PASSWORD_LEN)) return 0; } return 1; @@ -2352,7 +2354,7 @@ cifs_set_cifscreds(struct smb_vol *vol, struct cifs_ses *ses) } len = delim - payload; - if (len > MAX_USERNAME_SIZE || len <= 0) { + if (len > CIFS_MAX_USERNAME_LEN || len <= 0) { cifs_dbg(FYI, "Bad value from username search (len=%zd)\n", len); rc = -EINVAL; @@ -2369,7 +2371,7 @@ cifs_set_cifscreds(struct smb_vol *vol, struct cifs_ses *ses) cifs_dbg(FYI, "%s: username=%s\n", __func__, vol->username); len = key->datalen - (len + 1); - if (len > MAX_PASSWORD_SIZE || len <= 0) { + if (len > CIFS_MAX_PASSWORD_LEN || len <= 0) { cifs_dbg(FYI, "Bad len for password search (len=%zd)\n", len); rc = -EINVAL; kfree(vol->username); @@ -3826,33 +3828,8 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses, if (server->ops->sess_setup) rc = server->ops->sess_setup(xid, ses, nls_info); - if (rc) { + if (rc) cifs_dbg(VFS, "Send error in SessSetup = %d\n", rc); - } else { - mutex_lock(&server->srv_mutex); - if (!server->session_estab) { - server->session_key.response = ses->auth_key.response; - server->session_key.len = ses->auth_key.len; - server->sequence_number = 0x2; - server->session_estab = true; - ses->auth_key.response = NULL; - if (server->ops->generate_signingkey) - server->ops->generate_signingkey(server); - } - mutex_unlock(&server->srv_mutex); - - cifs_dbg(FYI, "CIFS Session Established successfully\n"); - spin_lock(&GlobalMid_Lock); - ses->status = CifsGood; - ses->need_reconnect = false; - spin_unlock(&GlobalMid_Lock); - } - - kfree(ses->auth_key.response); - ses->auth_key.response = NULL; - ses->auth_key.len = 0; - kfree(ses->ntlmssp); - ses->ntlmssp = NULL; return rc; } diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index d62ce0d4814..5384c2a640c 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -32,6 +32,7 @@ #include "cifsproto.h" #include "cifs_debug.h" #include "cifs_fs_sb.h" +#include "cifs_unicode.h" static void renew_parental_timestamps(struct dentry *direntry) @@ -499,6 +500,7 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry, if (server->ops->close) server->ops->close(xid, tcon, &fid); cifs_del_pending_open(&open); + fput(file); rc = -ENOMEM; } @@ -834,12 +836,17 @@ static int cifs_ci_hash(const struct dentry *dentry, struct qstr *q) { struct nls_table *codepage = CIFS_SB(dentry->d_sb)->local_nls; unsigned long hash; - int i; + wchar_t c; + int i, charlen; hash = init_name_hash(); - for (i = 0; i < q->len; i++) - hash = partial_name_hash(nls_tolower(codepage, q->name[i]), - hash); + for (i = 0; i < q->len; i += charlen) { + charlen = codepage->char2uni(&q->name[i], q->len - i, &c); + /* error out if we can't convert the character */ + if (unlikely(charlen < 0)) + return charlen; + hash = partial_name_hash(cifs_toupper(c), hash); + } q->hash = end_name_hash(hash); return 0; @@ -849,11 +856,47 @@ static int cifs_ci_compare(const struct dentry *parent, const struct dentry *den unsigned int len, const char *str, const struct qstr *name) { struct nls_table *codepage = CIFS_SB(parent->d_sb)->local_nls; + wchar_t c1, c2; + int i, l1, l2; - if ((name->len == len) && - (nls_strnicmp(codepage, name->name, str, len) == 0)) - return 0; - return 1; + /* + * We make the assumption here that uppercase characters in the local + * codepage are always the same length as their lowercase counterparts. + * + * If that's ever not the case, then this will fail to match it. + */ + if (name->len != len) + return 1; + + for (i = 0; i < len; i += l1) { + /* Convert characters in both strings to UTF-16. */ + l1 = codepage->char2uni(&str[i], len - i, &c1); + l2 = codepage->char2uni(&name->name[i], name->len - i, &c2); + + /* + * If we can't convert either character, just declare it to + * be 1 byte long and compare the original byte. + */ + if (unlikely(l1 < 0 && l2 < 0)) { + if (str[i] != name->name[i]) + return 1; + l1 = 1; + continue; + } + + /* + * Here, we again ass|u|me that upper/lowercase versions of + * a character are the same length in the local NLS. + */ + if (l1 != l2) + return 1; + + /* Now compare uppercase versions of these characters */ + if (cifs_toupper(c1) != cifs_toupper(c2)) + return 1; + } + + return 0; } const struct dentry_operations cifs_ci_dentry_ops = { diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 9d0dd952ad7..eb955b525e5 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -313,8 +313,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, * If the server returned a read oplock and we have mandatory brlocks, * set oplock level to None. */ - if (oplock == server->vals->oplock_read && - cifs_has_mand_locks(cinode)) { + if (server->ops->is_read_op(oplock) && cifs_has_mand_locks(cinode)) { cifs_dbg(FYI, "Reset oplock val from read to None due to mand locks\n"); oplock = 0; } @@ -324,6 +323,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, oplock = fid->pending_open->oplock; list_del(&fid->pending_open->olist); + fid->purge_cache = false; server->ops->set_fid(cfile, fid, oplock); list_add(&cfile->tlist, &tcon->openFileList); @@ -334,6 +334,9 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, list_add_tail(&cfile->flist, &cinode->openFileList); spin_unlock(&cifs_file_list_lock); + if (fid->purge_cache) + cifs_invalidate_mapping(inode); + file->private_data = cfile; return cfile; } @@ -1524,12 +1527,12 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type, * read won't conflict with non-overlapted locks due to * pagereading. */ - if (!CIFS_I(inode)->clientCanCacheAll && - CIFS_I(inode)->clientCanCacheRead) { + if (!CIFS_CACHE_WRITE(CIFS_I(inode)) && + CIFS_CACHE_READ(CIFS_I(inode))) { cifs_invalidate_mapping(inode); cifs_dbg(FYI, "Set no oplock for inode=%p due to mand locks\n", inode); - CIFS_I(inode)->clientCanCacheRead = false; + CIFS_I(inode)->oplock = 0; } rc = server->ops->mand_lock(xid, cfile, flock->fl_start, length, @@ -2213,7 +2216,7 @@ int cifs_strict_fsync(struct file *file, loff_t start, loff_t end, cifs_dbg(FYI, "Sync file - name: %s datasync: 0x%x\n", file->f_path.dentry->d_name.name, datasync); - if (!CIFS_I(inode)->clientCanCacheRead) { + if (!CIFS_CACHE_READ(CIFS_I(inode))) { rc = cifs_invalidate_mapping(inode); if (rc) { cifs_dbg(FYI, "rc: %d during invalidate phase\n", rc); @@ -2577,7 +2580,7 @@ cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov, struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); ssize_t written; - if (cinode->clientCanCacheAll) { + if (CIFS_CACHE_WRITE(cinode)) { if (cap_unix(tcon->ses) && (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) && ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) @@ -2591,7 +2594,7 @@ cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov, * these pages but not on the region from pos to ppos+len-1. */ written = cifs_user_writev(iocb, iov, nr_segs, pos); - if (written > 0 && cinode->clientCanCacheRead) { + if (written > 0 && CIFS_CACHE_READ(cinode)) { /* * Windows 7 server can delay breaking level2 oplock if a write * request comes - break it on the client to prevent reading @@ -2600,7 +2603,7 @@ cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov, cifs_invalidate_mapping(inode); cifs_dbg(FYI, "Set no oplock for inode=%p after a write operation\n", inode); - cinode->clientCanCacheRead = false; + cinode->oplock = 0; } return written; } @@ -2957,7 +2960,7 @@ cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov, * on pages affected by this read but not on the region from pos to * pos+len-1. */ - if (!cinode->clientCanCacheRead) + if (!CIFS_CACHE_READ(cinode)) return cifs_user_readv(iocb, iov, nr_segs, pos); if (cap_unix(tcon->ses) && @@ -3093,7 +3096,7 @@ int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma) xid = get_xid(); - if (!CIFS_I(inode)->clientCanCacheRead) { + if (!CIFS_CACHE_READ(CIFS_I(inode))) { rc = cifs_invalidate_mapping(inode); if (rc) return rc; @@ -3376,6 +3379,9 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, return rc; } +/* + * cifs_readpage_worker must be called with the page pinned + */ static int cifs_readpage_worker(struct file *file, struct page *page, loff_t *poffset) { @@ -3387,7 +3393,6 @@ static int cifs_readpage_worker(struct file *file, struct page *page, if (rc == 0) goto read_complete; - page_cache_get(page); read_data = kmap(page); /* for reads over a certain size could initiate async read ahead */ @@ -3414,7 +3419,7 @@ static int cifs_readpage_worker(struct file *file, struct page *page, io_error: kunmap(page); - page_cache_release(page); + unlock_page(page); read_complete: return rc; @@ -3439,8 +3444,6 @@ static int cifs_readpage(struct file *file, struct page *page) rc = cifs_readpage_worker(file, page, &offset); - unlock_page(page); - free_xid(xid); return rc; } @@ -3494,6 +3497,7 @@ static int cifs_write_begin(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned flags, struct page **pagep, void **fsdata) { + int oncethru = 0; pgoff_t index = pos >> PAGE_CACHE_SHIFT; loff_t offset = pos & (PAGE_CACHE_SIZE - 1); loff_t page_start = pos & PAGE_MASK; @@ -3503,6 +3507,7 @@ static int cifs_write_begin(struct file *file, struct address_space *mapping, cifs_dbg(FYI, "write_begin from %lld len %d\n", (long long)pos, len); +start: page = grab_cache_page_write_begin(mapping, index, flags); if (!page) { rc = -ENOMEM; @@ -3526,7 +3531,7 @@ static int cifs_write_begin(struct file *file, struct address_space *mapping, * is, when the page lies beyond the EOF, or straddles the EOF * and the write will cover all of the existing data. */ - if (CIFS_I(mapping->host)->clientCanCacheRead) { + if (CIFS_CACHE_READ(CIFS_I(mapping->host))) { i_size = i_size_read(mapping->host); if (page_start >= i_size || (offset == 0 && (pos + len) >= i_size)) { @@ -3544,13 +3549,16 @@ static int cifs_write_begin(struct file *file, struct address_space *mapping, } } - if ((file->f_flags & O_ACCMODE) != O_WRONLY) { + if ((file->f_flags & O_ACCMODE) != O_WRONLY && !oncethru) { /* * might as well read a page, it is fast enough. If we get * an error, we don't need to return it. cifs_write_end will * do a sync write instead since PG_uptodate isn't set. */ cifs_readpage_worker(file, page, &page_start); + page_cache_release(page); + oncethru = 1; + goto start; } else { /* we could try using another file handle if there is one - but how would we lock it to prevent close of that handle @@ -3609,20 +3617,20 @@ void cifs_oplock_break(struct work_struct *work) struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); int rc = 0; - if (!cinode->clientCanCacheAll && cinode->clientCanCacheRead && + if (!CIFS_CACHE_WRITE(cinode) && CIFS_CACHE_READ(cinode) && cifs_has_mand_locks(cinode)) { cifs_dbg(FYI, "Reset oplock to None for inode=%p due to mand locks\n", inode); - cinode->clientCanCacheRead = false; + cinode->oplock = 0; } if (inode && S_ISREG(inode->i_mode)) { - if (cinode->clientCanCacheRead) + if (CIFS_CACHE_READ(cinode)) break_lease(inode, O_RDONLY); else break_lease(inode, O_WRONLY); rc = filemap_fdatawrite(inode->i_mapping); - if (cinode->clientCanCacheRead == 0) { + if (!CIFS_CACHE_READ(cinode)) { rc = filemap_fdatawait(inode->i_mapping); mapping_set_error(inode->i_mapping, rc); cifs_invalidate_mapping(inode); diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 449b6cf09b0..f9ff9c173f7 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -101,7 +101,7 @@ cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr) } /* don't bother with revalidation if we have an oplock */ - if (cifs_i->clientCanCacheRead) { + if (CIFS_CACHE_READ(cifs_i)) { cifs_dbg(FYI, "%s: inode %llu is oplocked\n", __func__, cifs_i->uniqueid); return; @@ -549,6 +549,10 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, * when Unix extensions are disabled - fake it. */ fattr->cf_nlink = 2; + } else if (fattr->cf_cifsattrs & ATTR_REPARSE) { + fattr->cf_mode = S_IFLNK; + fattr->cf_dtype = DT_LNK; + fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks); } else { fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode; fattr->cf_dtype = DT_REG; @@ -646,7 +650,7 @@ cifs_get_inode_info(struct inode **inode, const char *full_path, cifs_dbg(FYI, "Getting info on %s\n", full_path); if ((data == NULL) && (*inode != NULL)) { - if (CIFS_I(*inode)->clientCanCacheRead) { + if (CIFS_CACHE_READ(CIFS_I(*inode))) { cifs_dbg(FYI, "No need to revalidate cached inode sizes\n"); goto cgii_exit; } @@ -1657,7 +1661,7 @@ cifs_inode_needs_reval(struct inode *inode) struct cifsInodeInfo *cifs_i = CIFS_I(inode); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); - if (cifs_i->clientCanCacheRead) + if (CIFS_CACHE_READ(cifs_i)) return false; if (!lookupCacheEnabled) @@ -1800,7 +1804,7 @@ int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, * We need to be sure that all dirty pages are written and the server * has actual ctime, mtime and file length. */ - if (!CIFS_I(inode)->clientCanCacheRead && inode->i_mapping && + if (!CIFS_CACHE_READ(CIFS_I(inode)) && inode->i_mapping && inode->i_mapping->nrpages != 0) { rc = filemap_fdatawait(inode->i_mapping); if (rc) { @@ -1852,14 +1856,11 @@ static int cifs_truncate_page(struct address_space *mapping, loff_t from) static void cifs_setsize(struct inode *inode, loff_t offset) { - loff_t oldsize; - spin_lock(&inode->i_lock); - oldsize = inode->i_size; i_size_write(inode, offset); spin_unlock(&inode->i_lock); - truncate_pagecache(inode, oldsize, offset); + truncate_pagecache(inode, offset); } static int diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 562044f700e..7e36ceba0c7 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -509,6 +509,7 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd) struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct tcon_link *tlink = NULL; struct cifs_tcon *tcon; + struct TCP_Server_Info *server; xid = get_xid(); @@ -519,25 +520,7 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd) goto out; } tcon = tlink_tcon(tlink); - - /* - * For now, we just handle symlinks with unix extensions enabled. - * Eventually we should handle NTFS reparse points, and MacOS - * symlink support. For instance... - * - * rc = CIFSSMBQueryReparseLinkInfo(...) - * - * For now, just return -EACCES when the server doesn't support posix - * extensions. Note that we still allow querying symlinks when posix - * extensions are manually disabled. We could disable these as well - * but there doesn't seem to be any harm in allowing the client to - * read them. - */ - if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) && - !cap_unix(tcon->ses)) { - rc = -EACCES; - goto out; - } + server = tcon->ses->server; full_path = build_path_from_dentry(direntry); if (!full_path) @@ -559,6 +542,9 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd) if ((rc != 0) && cap_unix(tcon->ses)) rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, &target_path, cifs_sb->local_nls); + else if (rc != 0 && server->ops->query_symlink) + rc = server->ops->query_symlink(xid, tcon, full_path, + &target_path, cifs_sb); kfree(full_path); out: diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index f7d4b2285ef..138a011633f 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -105,6 +105,7 @@ sesInfoFree(struct cifs_ses *buf_to_free) } kfree(buf_to_free->user_name); kfree(buf_to_free->domainName); + kfree(buf_to_free->auth_key.response); kfree(buf_to_free); } @@ -545,19 +546,15 @@ void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock) oplock &= 0xF; if (oplock == OPLOCK_EXCLUSIVE) { - cinode->clientCanCacheAll = true; - cinode->clientCanCacheRead = true; + cinode->oplock = CIFS_CACHE_WRITE_FLG | CIFS_CACHE_READ_FLG; cifs_dbg(FYI, "Exclusive Oplock granted on inode %p\n", &cinode->vfs_inode); } else if (oplock == OPLOCK_READ) { - cinode->clientCanCacheAll = false; - cinode->clientCanCacheRead = true; + cinode->oplock = CIFS_CACHE_READ_FLG; cifs_dbg(FYI, "Level II Oplock granted on inode %p\n", &cinode->vfs_inode); - } else { - cinode->clientCanCacheAll = false; - cinode->clientCanCacheRead = false; - } + } else + cinode->oplock = 0; } bool diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 69d2c826a23..42ef03be089 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -172,6 +172,9 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb) if (cifs_dfs_is_possible(cifs_sb) && (fattr->cf_cifsattrs & ATTR_REPARSE)) fattr->cf_flags |= CIFS_FATTR_NEED_REVAL; + } else if (fattr->cf_cifsattrs & ATTR_REPARSE) { + fattr->cf_mode = S_IFLNK; + fattr->cf_dtype = DT_LNK; } else { fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode; fattr->cf_dtype = DT_REG; diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 08dd37bb23a..5f99b7f19e7 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -226,7 +226,7 @@ static void unicode_ssetup_strings(char **pbcc_area, struct cifs_ses *ses, *(bcc_ptr+1) = 0; } else { bytes_ret = cifs_strtoUTF16((__le16 *) bcc_ptr, ses->user_name, - MAX_USERNAME_SIZE, nls_cp); + CIFS_MAX_USERNAME_LEN, nls_cp); } bcc_ptr += 2 * bytes_ret; bcc_ptr += 2; /* account for null termination */ @@ -246,8 +246,8 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifs_ses *ses, /* BB what about null user mounts - check that we do this BB */ /* copy user */ if (ses->user_name != NULL) { - strncpy(bcc_ptr, ses->user_name, MAX_USERNAME_SIZE); - bcc_ptr += strnlen(ses->user_name, MAX_USERNAME_SIZE); + strncpy(bcc_ptr, ses->user_name, CIFS_MAX_USERNAME_LEN); + bcc_ptr += strnlen(ses->user_name, CIFS_MAX_USERNAME_LEN); } /* else null user mount */ *bcc_ptr = 0; @@ -428,7 +428,8 @@ void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC; if (ses->server->sign) { flags |= NTLMSSP_NEGOTIATE_SIGN; - if (!ses->server->session_estab) + if (!ses->server->session_estab || + ses->ntlmssp->sesskey_per_smbsess) flags |= NTLMSSP_NEGOTIATE_KEY_XCH; } @@ -466,7 +467,8 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer, NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC; if (ses->server->sign) { flags |= NTLMSSP_NEGOTIATE_SIGN; - if (!ses->server->session_estab) + if (!ses->server->session_estab || + ses->ntlmssp->sesskey_per_smbsess) flags |= NTLMSSP_NEGOTIATE_KEY_XCH; } @@ -501,7 +503,7 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer, } else { int len; len = cifs_strtoUTF16((__le16 *)tmp, ses->domainName, - MAX_USERNAME_SIZE, nls_cp); + CIFS_MAX_USERNAME_LEN, nls_cp); len *= 2; /* unicode is 2 bytes each */ sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); sec_blob->DomainName.Length = cpu_to_le16(len); @@ -517,7 +519,7 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer, } else { int len; len = cifs_strtoUTF16((__le16 *)tmp, ses->user_name, - MAX_USERNAME_SIZE, nls_cp); + CIFS_MAX_USERNAME_LEN, nls_cp); len *= 2; /* unicode is 2 bytes each */ sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer); sec_blob->UserName.Length = cpu_to_le16(len); @@ -629,7 +631,8 @@ CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses, type = select_sectype(ses->server, ses->sectype); cifs_dbg(FYI, "sess setup type %d\n", type); if (type == Unspecified) { - cifs_dbg(VFS, "Unable to select appropriate authentication method!"); + cifs_dbg(VFS, + "Unable to select appropriate authentication method!"); return -EINVAL; } @@ -640,6 +643,8 @@ CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses, ses->ntlmssp = kmalloc(sizeof(struct ntlmssp_auth), GFP_KERNEL); if (!ses->ntlmssp) return -ENOMEM; + ses->ntlmssp->sesskey_per_smbsess = false; + } ssetup_ntlmssp_authenticate: @@ -815,8 +820,9 @@ ssetup_ntlmssp_authenticate: ses->auth_key.response = kmemdup(msg->data, msg->sesskey_len, GFP_KERNEL); if (!ses->auth_key.response) { - cifs_dbg(VFS, "Kerberos can't allocate (%u bytes) memory", - msg->sesskey_len); + cifs_dbg(VFS, + "Kerberos can't allocate (%u bytes) memory", + msg->sesskey_len); rc = -ENOMEM; goto ssetup_exit; } @@ -1005,5 +1011,37 @@ ssetup_exit: if ((phase == NtLmChallenge) && (rc == 0)) goto ssetup_ntlmssp_authenticate; + if (!rc) { + mutex_lock(&ses->server->srv_mutex); + if (!ses->server->session_estab) { + if (ses->server->sign) { + ses->server->session_key.response = + kmemdup(ses->auth_key.response, + ses->auth_key.len, GFP_KERNEL); + if (!ses->server->session_key.response) { + rc = -ENOMEM; + mutex_unlock(&ses->server->srv_mutex); + goto keycp_exit; + } + ses->server->session_key.len = + ses->auth_key.len; + } + ses->server->sequence_number = 0x2; + ses->server->session_estab = true; + } + mutex_unlock(&ses->server->srv_mutex); + + cifs_dbg(FYI, "CIFS session established successfully\n"); + spin_lock(&GlobalMid_Lock); + ses->status = CifsGood; + ses->need_reconnect = false; + spin_unlock(&GlobalMid_Lock); + } + +keycp_exit: + kfree(ses->auth_key.response); + ses->auth_key.response = NULL; + kfree(ses->ntlmssp); + return rc; } diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index 60943978aec..8233b174de3 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c @@ -700,7 +700,7 @@ cifs_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock) struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); cfile->fid.netfid = fid->netfid; cifs_set_oplock_level(cinode, oplock); - cinode->can_cache_brlcks = cinode->clientCanCacheAll; + cinode->can_cache_brlcks = CIFS_CACHE_WRITE(cinode); } static void @@ -837,7 +837,7 @@ cifs_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid, { return CIFSSMBLock(0, tcon, fid->netfid, current->tgid, 0, 0, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, false, - cinode->clientCanCacheRead ? 1 : 0); + CIFS_CACHE_READ(cinode) ? 1 : 0); } static int @@ -881,6 +881,43 @@ cifs_mand_lock(const unsigned int xid, struct cifsFileInfo *cfile, __u64 offset, (__u8)type, wait, 0); } +static int +cifs_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, + const char *full_path, char **target_path, + struct cifs_sb_info *cifs_sb) +{ + int rc; + int oplock = 0; + __u16 netfid; + + cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path); + + rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN, + FILE_READ_ATTRIBUTES, OPEN_REPARSE_POINT, &netfid, + &oplock, NULL, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + if (rc) + return rc; + + rc = CIFSSMBQuerySymLink(xid, tcon, netfid, target_path, + cifs_sb->local_nls); + if (rc) { + CIFSSMBClose(xid, tcon, netfid); + return rc; + } + + convert_delimiter(*target_path, '/'); + CIFSSMBClose(xid, tcon, netfid); + cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path); + return rc; +} + +static bool +cifs_is_read_op(__u32 oplock) +{ + return oplock == OPLOCK_READ; +} + struct smb_version_operations smb1_operations = { .send_cancel = send_nt_cancel, .compare_fids = cifs_compare_fids, @@ -927,6 +964,7 @@ struct smb_version_operations smb1_operations = { .rename_pending_delete = cifs_rename_pending_delete, .rename = CIFSSMBRename, .create_hardlink = CIFSCreateHardLink, + .query_symlink = cifs_query_symlink, .open = cifs_open_file, .set_fid = cifs_set_fid, .close = cifs_close_file, @@ -945,6 +983,7 @@ struct smb_version_operations smb1_operations = { .mand_unlock_range = cifs_unlock_range, .push_mand_locks = cifs_push_mandatory_locks, .query_mf_symlink = open_query_close_cifs_symlink, + .is_read_op = cifs_is_read_op, }; struct smb_version_values smb1_values = { @@ -960,7 +999,6 @@ struct smb_version_values smb1_values = { .cap_unix = CAP_UNIX, .cap_nt_find = CAP_NT_SMBS | CAP_NT_FIND, .cap_large_files = CAP_LARGE_FILES, - .oplock_read = OPLOCK_READ, .signing_enabled = SECMODE_SIGN_ENABLED, .signing_required = SECMODE_SIGN_REQUIRED, }; diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c index 04a81a4142c..3f17b455083 100644 --- a/fs/cifs/smb2file.c +++ b/fs/cifs/smb2file.c @@ -34,29 +34,6 @@ #include "fscache.h" #include "smb2proto.h" -void -smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock) -{ - oplock &= 0xFF; - if (oplock == SMB2_OPLOCK_LEVEL_NOCHANGE) - return; - if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE || - oplock == SMB2_OPLOCK_LEVEL_BATCH) { - cinode->clientCanCacheAll = true; - cinode->clientCanCacheRead = true; - cifs_dbg(FYI, "Exclusive Oplock granted on inode %p\n", - &cinode->vfs_inode); - } else if (oplock == SMB2_OPLOCK_LEVEL_II) { - cinode->clientCanCacheAll = false; - cinode->clientCanCacheRead = true; - cifs_dbg(FYI, "Level II Oplock granted on inode %p\n", - &cinode->vfs_inode); - } else { - cinode->clientCanCacheAll = false; - cinode->clientCanCacheRead = false; - } -} - int smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, __u32 *oplock, FILE_ALL_INFO *buf) @@ -86,7 +63,7 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, if (oparms->tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING) memcpy(smb2_oplock + 1, fid->lease_key, SMB2_LEASE_KEY_SIZE); - rc = SMB2_open(xid, oparms, smb2_path, smb2_oplock, smb2_data); + rc = SMB2_open(xid, oparms, smb2_path, smb2_oplock, smb2_data, NULL); if (rc) goto out; diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c index c6ec1633309..78ff88c467b 100644 --- a/fs/cifs/smb2inode.c +++ b/fs/cifs/smb2inode.c @@ -60,7 +60,7 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon, oparms.fid = &fid; oparms.reconnect = false; - rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL); + rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL); if (rc) { kfree(utf16_path); return rc; @@ -136,7 +136,8 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, return -ENOMEM; rc = smb2_open_op_close(xid, tcon, cifs_sb, full_path, - FILE_READ_ATTRIBUTES, FILE_OPEN, 0, smb2_data, + FILE_READ_ATTRIBUTES, FILE_OPEN, + OPEN_REPARSE_POINT, smb2_data, SMB2_OP_QUERY_INFO); if (rc) goto out; @@ -191,8 +192,8 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name, struct cifs_sb_info *cifs_sb) { return smb2_open_op_close(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN, - CREATE_DELETE_ON_CLOSE, NULL, - SMB2_OP_DELETE); + CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT, + NULL, SMB2_OP_DELETE); } static int diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c index b0c43345cd9..fb3966265b6 100644 --- a/fs/cifs/smb2misc.c +++ b/fs/cifs/smb2misc.c @@ -171,6 +171,10 @@ smb2_check_message(char *buf, unsigned int length) if (4 + len != clc_len) { cifs_dbg(FYI, "Calculated size %u length %u mismatch mid %llu\n", clc_len, 4 + len, mid); + /* create failed on symlink */ + if (command == SMB2_CREATE_HE && + hdr->Status == STATUS_STOPPED_ON_SYMLINK) + return 0; /* Windows 7 server returns 24 bytes more */ if (clc_len + 20 == len && command == SMB2_OPLOCK_BREAK_HE) return 0; @@ -376,23 +380,15 @@ cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb) __le32 smb2_get_lease_state(struct cifsInodeInfo *cinode) { - if (cinode->clientCanCacheAll) - return SMB2_LEASE_WRITE_CACHING | SMB2_LEASE_READ_CACHING; - else if (cinode->clientCanCacheRead) - return SMB2_LEASE_READ_CACHING; - return 0; -} - -__u8 smb2_map_lease_to_oplock(__le32 lease_state) -{ - if (lease_state & SMB2_LEASE_WRITE_CACHING) { - if (lease_state & SMB2_LEASE_HANDLE_CACHING) - return SMB2_OPLOCK_LEVEL_BATCH; - else - return SMB2_OPLOCK_LEVEL_EXCLUSIVE; - } else if (lease_state & SMB2_LEASE_READ_CACHING) - return SMB2_OPLOCK_LEVEL_II; - return 0; + __le32 lease = 0; + + if (CIFS_CACHE_WRITE(cinode)) + lease |= SMB2_LEASE_WRITE_CACHING; + if (CIFS_CACHE_HANDLE(cinode)) + lease |= SMB2_LEASE_HANDLE_CACHING; + if (CIFS_CACHE_READ(cinode)) + lease |= SMB2_LEASE_READ_CACHING; + return lease; } struct smb2_lease_break_work { @@ -417,96 +413,109 @@ cifs_ses_oplock_break(struct work_struct *work) } static bool -smb2_is_valid_lease_break(char *buffer, struct TCP_Server_Info *server) +smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp, + struct smb2_lease_break_work *lw) { - struct smb2_lease_break *rsp = (struct smb2_lease_break *)buffer; - struct list_head *tmp, *tmp1, *tmp2; - struct cifs_ses *ses; - struct cifs_tcon *tcon; - struct cifsInodeInfo *cinode; + bool found; + __u8 lease_state; + struct list_head *tmp; struct cifsFileInfo *cfile; + struct TCP_Server_Info *server = tcon->ses->server; struct cifs_pending_open *open; - struct smb2_lease_break_work *lw; - bool found; + struct cifsInodeInfo *cinode; int ack_req = le32_to_cpu(rsp->Flags & SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED); - lw = kmalloc(sizeof(struct smb2_lease_break_work), GFP_KERNEL); - if (!lw) - return false; + lease_state = le32_to_cpu(rsp->NewLeaseState); - INIT_WORK(&lw->lease_break, cifs_ses_oplock_break); - lw->lease_state = rsp->NewLeaseState; + list_for_each(tmp, &tcon->openFileList) { + cfile = list_entry(tmp, struct cifsFileInfo, tlist); + cinode = CIFS_I(cfile->dentry->d_inode); - cifs_dbg(FYI, "Checking for lease break\n"); + if (memcmp(cinode->lease_key, rsp->LeaseKey, + SMB2_LEASE_KEY_SIZE)) + continue; - /* look up tcon based on tid & uid */ - spin_lock(&cifs_tcp_ses_lock); - list_for_each(tmp, &server->smb_ses_list) { - ses = list_entry(tmp, struct cifs_ses, smb_ses_list); + cifs_dbg(FYI, "found in the open list\n"); + cifs_dbg(FYI, "lease key match, lease break 0x%d\n", + le32_to_cpu(rsp->NewLeaseState)); - spin_lock(&cifs_file_list_lock); - list_for_each(tmp1, &ses->tcon_list) { - tcon = list_entry(tmp1, struct cifs_tcon, tcon_list); + server->ops->set_oplock_level(cinode, lease_state, 0, NULL); - cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks); - list_for_each(tmp2, &tcon->openFileList) { - cfile = list_entry(tmp2, struct cifsFileInfo, - tlist); - cinode = CIFS_I(cfile->dentry->d_inode); + if (ack_req) + cfile->oplock_break_cancelled = false; + else + cfile->oplock_break_cancelled = true; - if (memcmp(cinode->lease_key, rsp->LeaseKey, - SMB2_LEASE_KEY_SIZE)) - continue; + queue_work(cifsiod_wq, &cfile->oplock_break); + kfree(lw); + return true; + } - cifs_dbg(FYI, "found in the open list\n"); - cifs_dbg(FYI, "lease key match, lease break 0x%d\n", - le32_to_cpu(rsp->NewLeaseState)); + found = false; + list_for_each_entry(open, &tcon->pending_opens, olist) { + if (memcmp(open->lease_key, rsp->LeaseKey, + SMB2_LEASE_KEY_SIZE)) + continue; + + if (!found && ack_req) { + found = true; + memcpy(lw->lease_key, open->lease_key, + SMB2_LEASE_KEY_SIZE); + lw->tlink = cifs_get_tlink(open->tlink); + queue_work(cifsiod_wq, &lw->lease_break); + } - smb2_set_oplock_level(cinode, - smb2_map_lease_to_oplock(rsp->NewLeaseState)); + cifs_dbg(FYI, "found in the pending open list\n"); + cifs_dbg(FYI, "lease key match, lease break 0x%d\n", + le32_to_cpu(rsp->NewLeaseState)); - if (ack_req) - cfile->oplock_break_cancelled = false; - else - cfile->oplock_break_cancelled = true; + open->oplock = lease_state; + } + return found; +} - queue_work(cifsiod_wq, &cfile->oplock_break); +static bool +smb2_is_valid_lease_break(char *buffer) +{ + struct smb2_lease_break *rsp = (struct smb2_lease_break *)buffer; + struct list_head *tmp, *tmp1, *tmp2; + struct TCP_Server_Info *server; + struct cifs_ses *ses; + struct cifs_tcon *tcon; + struct smb2_lease_break_work *lw; - spin_unlock(&cifs_file_list_lock); - spin_unlock(&cifs_tcp_ses_lock); - return true; - } + lw = kmalloc(sizeof(struct smb2_lease_break_work), GFP_KERNEL); + if (!lw) + return false; - found = false; - list_for_each_entry(open, &tcon->pending_opens, olist) { - if (memcmp(open->lease_key, rsp->LeaseKey, - SMB2_LEASE_KEY_SIZE)) - continue; + INIT_WORK(&lw->lease_break, cifs_ses_oplock_break); + lw->lease_state = rsp->NewLeaseState; - if (!found && ack_req) { - found = true; - memcpy(lw->lease_key, open->lease_key, - SMB2_LEASE_KEY_SIZE); - lw->tlink = cifs_get_tlink(open->tlink); - queue_work(cifsiod_wq, - &lw->lease_break); - } + cifs_dbg(FYI, "Checking for lease break\n"); - cifs_dbg(FYI, "found in the pending open list\n"); - cifs_dbg(FYI, "lease key match, lease break 0x%d\n", - le32_to_cpu(rsp->NewLeaseState)); + /* look up tcon based on tid & uid */ + spin_lock(&cifs_tcp_ses_lock); + list_for_each(tmp, &cifs_tcp_ses_list) { + server = list_entry(tmp, struct TCP_Server_Info, tcp_ses_list); - open->oplock = - smb2_map_lease_to_oplock(rsp->NewLeaseState); - } - if (found) { - spin_unlock(&cifs_file_list_lock); - spin_unlock(&cifs_tcp_ses_lock); - return true; + list_for_each(tmp1, &server->smb_ses_list) { + ses = list_entry(tmp1, struct cifs_ses, smb_ses_list); + + spin_lock(&cifs_file_list_lock); + list_for_each(tmp2, &ses->tcon_list) { + tcon = list_entry(tmp2, struct cifs_tcon, + tcon_list); + cifs_stats_inc( + &tcon->stats.cifs_stats.num_oplock_brks); + if (smb2_tcon_has_lease(tcon, rsp, lw)) { + spin_unlock(&cifs_file_list_lock); + spin_unlock(&cifs_tcp_ses_lock); + return true; + } } + spin_unlock(&cifs_file_list_lock); } - spin_unlock(&cifs_file_list_lock); } spin_unlock(&cifs_tcp_ses_lock); kfree(lw); @@ -532,7 +541,7 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server) if (rsp->StructureSize != smb2_rsp_struct_sizes[SMB2_OPLOCK_BREAK_HE]) { if (le16_to_cpu(rsp->StructureSize) == 44) - return smb2_is_valid_lease_break(buffer, server); + return smb2_is_valid_lease_break(buffer); else return false; } @@ -560,14 +569,15 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server) cifs_dbg(FYI, "file id match, oplock break\n"); cinode = CIFS_I(cfile->dentry->d_inode); - if (!cinode->clientCanCacheAll && + if (!CIFS_CACHE_WRITE(cinode) && rsp->OplockLevel == SMB2_OPLOCK_LEVEL_NONE) cfile->oplock_break_cancelled = true; else cfile->oplock_break_cancelled = false; - smb2_set_oplock_level(cinode, - rsp->OplockLevel ? SMB2_OPLOCK_LEVEL_II : 0); + server->ops->set_oplock_level(cinode, + rsp->OplockLevel ? SMB2_OPLOCK_LEVEL_II : 0, + 0, NULL); queue_work(cifsiod_wq, &cfile->oplock_break); diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index f259e6cc835..861b3321414 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -24,6 +24,7 @@ #include "smb2proto.h" #include "cifsproto.h" #include "cifs_debug.h" +#include "cifs_unicode.h" #include "smb2status.h" #include "smb2glob.h" @@ -229,7 +230,7 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon, oparms.fid = &fid; oparms.reconnect = false; - rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL); + rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL); if (rc) { kfree(utf16_path); return rc; @@ -376,10 +377,13 @@ static void smb2_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock) { struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); + struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server; + cfile->fid.persistent_fid = fid->persistent_fid; cfile->fid.volatile_fid = fid->volatile_fid; - smb2_set_oplock_level(cinode, oplock); - cinode->can_cache_brlcks = cinode->clientCanCacheAll; + server->ops->set_oplock_level(cinode, oplock, fid->epoch, + &fid->purge_cache); + cinode->can_cache_brlcks = CIFS_CACHE_WRITE(cinode); } static void @@ -463,7 +467,7 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon, oparms.fid = fid; oparms.reconnect = false; - rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL); + rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL); kfree(utf16_path); if (rc) { cifs_dbg(VFS, "open dir failed\n"); @@ -530,7 +534,7 @@ smb2_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid, return SMB2_oplock_break(0, tcon, fid->persistent_fid, fid->volatile_fid, - cinode->clientCanCacheRead ? 1 : 0); + CIFS_CACHE_READ(cinode) ? 1 : 0); } static int @@ -550,7 +554,7 @@ smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon, oparms.fid = &fid; oparms.reconnect = false; - rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL); + rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL); if (rc) return rc; buf->f_type = SMB2_MAGIC_NUMBER; @@ -596,7 +600,245 @@ smb2_new_lease_key(struct cifs_fid *fid) get_random_bytes(fid->lease_key, SMB2_LEASE_KEY_SIZE); } -struct smb_version_operations smb21_operations = { +static int +smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, + const char *full_path, char **target_path, + struct cifs_sb_info *cifs_sb) +{ + int rc; + __le16 *utf16_path; + __u8 oplock = SMB2_OPLOCK_LEVEL_NONE; + struct cifs_open_parms oparms; + struct cifs_fid fid; + struct smb2_err_rsp *err_buf = NULL; + struct smb2_symlink_err_rsp *symlink; + unsigned int sub_len, sub_offset; + + cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path); + + utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb); + if (!utf16_path) + return -ENOMEM; + + oparms.tcon = tcon; + oparms.desired_access = FILE_READ_ATTRIBUTES; + oparms.disposition = FILE_OPEN; + oparms.create_options = 0; + oparms.fid = &fid; + oparms.reconnect = false; + + rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, &err_buf); + + if (!rc || !err_buf) { + kfree(utf16_path); + return -ENOENT; + } + /* open must fail on symlink - reset rc */ + rc = 0; + symlink = (struct smb2_symlink_err_rsp *)err_buf->ErrorData; + sub_len = le16_to_cpu(symlink->SubstituteNameLength); + sub_offset = le16_to_cpu(symlink->SubstituteNameOffset); + *target_path = cifs_strndup_from_utf16( + (char *)symlink->PathBuffer + sub_offset, + sub_len, true, cifs_sb->local_nls); + if (!(*target_path)) { + kfree(utf16_path); + return -ENOMEM; + } + convert_delimiter(*target_path, '/'); + cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path); + kfree(utf16_path); + return rc; +} + +static void +smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock, + unsigned int epoch, bool *purge_cache) +{ + oplock &= 0xFF; + if (oplock == SMB2_OPLOCK_LEVEL_NOCHANGE) + return; + if (oplock == SMB2_OPLOCK_LEVEL_BATCH) { + cinode->oplock = CIFS_CACHE_RHW_FLG; + cifs_dbg(FYI, "Batch Oplock granted on inode %p\n", + &cinode->vfs_inode); + } else if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE) { + cinode->oplock = CIFS_CACHE_RW_FLG; + cifs_dbg(FYI, "Exclusive Oplock granted on inode %p\n", + &cinode->vfs_inode); + } else if (oplock == SMB2_OPLOCK_LEVEL_II) { + cinode->oplock = CIFS_CACHE_READ_FLG; + cifs_dbg(FYI, "Level II Oplock granted on inode %p\n", + &cinode->vfs_inode); + } else + cinode->oplock = 0; +} + +static void +smb21_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock, + unsigned int epoch, bool *purge_cache) +{ + char message[5] = {0}; + + oplock &= 0xFF; + if (oplock == SMB2_OPLOCK_LEVEL_NOCHANGE) + return; + + cinode->oplock = 0; + if (oplock & SMB2_LEASE_READ_CACHING_HE) { + cinode->oplock |= CIFS_CACHE_READ_FLG; + strcat(message, "R"); + } + if (oplock & SMB2_LEASE_HANDLE_CACHING_HE) { + cinode->oplock |= CIFS_CACHE_HANDLE_FLG; + strcat(message, "H"); + } + if (oplock & SMB2_LEASE_WRITE_CACHING_HE) { + cinode->oplock |= CIFS_CACHE_WRITE_FLG; + strcat(message, "W"); + } + if (!cinode->oplock) + strcat(message, "None"); + cifs_dbg(FYI, "%s Lease granted on inode %p\n", message, + &cinode->vfs_inode); +} + +static void +smb3_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock, + unsigned int epoch, bool *purge_cache) +{ + unsigned int old_oplock = cinode->oplock; + + smb21_set_oplock_level(cinode, oplock, epoch, purge_cache); + + if (purge_cache) { + *purge_cache = false; + if (old_oplock == CIFS_CACHE_READ_FLG) { + if (cinode->oplock == CIFS_CACHE_READ_FLG && + (epoch - cinode->epoch > 0)) + *purge_cache = true; + else if (cinode->oplock == CIFS_CACHE_RH_FLG && + (epoch - cinode->epoch > 1)) + *purge_cache = true; + else if (cinode->oplock == CIFS_CACHE_RHW_FLG && + (epoch - cinode->epoch > 1)) + *purge_cache = true; + else if (cinode->oplock == 0 && + (epoch - cinode->epoch > 0)) + *purge_cache = true; + } else if (old_oplock == CIFS_CACHE_RH_FLG) { + if (cinode->oplock == CIFS_CACHE_RH_FLG && + (epoch - cinode->epoch > 0)) + *purge_cache = true; + else if (cinode->oplock == CIFS_CACHE_RHW_FLG && + (epoch - cinode->epoch > 1)) + *purge_cache = true; + } + cinode->epoch = epoch; + } +} + +static bool +smb2_is_read_op(__u32 oplock) +{ + return oplock == SMB2_OPLOCK_LEVEL_II; +} + +static bool +smb21_is_read_op(__u32 oplock) +{ + return (oplock & SMB2_LEASE_READ_CACHING_HE) && + !(oplock & SMB2_LEASE_WRITE_CACHING_HE); +} + +static __le32 +map_oplock_to_lease(u8 oplock) +{ + if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE) + return SMB2_LEASE_WRITE_CACHING | SMB2_LEASE_READ_CACHING; + else if (oplock == SMB2_OPLOCK_LEVEL_II) + return SMB2_LEASE_READ_CACHING; + else if (oplock == SMB2_OPLOCK_LEVEL_BATCH) + return SMB2_LEASE_HANDLE_CACHING | SMB2_LEASE_READ_CACHING | + SMB2_LEASE_WRITE_CACHING; + return 0; +} + +static char * +smb2_create_lease_buf(u8 *lease_key, u8 oplock) +{ + struct create_lease *buf; + + buf = kzalloc(sizeof(struct create_lease), GFP_KERNEL); + if (!buf) + return NULL; + + buf->lcontext.LeaseKeyLow = cpu_to_le64(*((u64 *)lease_key)); + buf->lcontext.LeaseKeyHigh = cpu_to_le64(*((u64 *)(lease_key + 8))); + buf->lcontext.LeaseState = map_oplock_to_lease(oplock); + + buf->ccontext.DataOffset = cpu_to_le16(offsetof + (struct create_lease, lcontext)); + buf->ccontext.DataLength = cpu_to_le32(sizeof(struct lease_context)); + buf->ccontext.NameOffset = cpu_to_le16(offsetof + (struct create_lease, Name)); + buf->ccontext.NameLength = cpu_to_le16(4); + buf->Name[0] = 'R'; + buf->Name[1] = 'q'; + buf->Name[2] = 'L'; + buf->Name[3] = 's'; + return (char *)buf; +} + +static char * +smb3_create_lease_buf(u8 *lease_key, u8 oplock) +{ + struct create_lease_v2 *buf; + + buf = kzalloc(sizeof(struct create_lease_v2), GFP_KERNEL); + if (!buf) + return NULL; + + buf->lcontext.LeaseKeyLow = cpu_to_le64(*((u64 *)lease_key)); + buf->lcontext.LeaseKeyHigh = cpu_to_le64(*((u64 *)(lease_key + 8))); + buf->lcontext.LeaseState = map_oplock_to_lease(oplock); + + buf->ccontext.DataOffset = cpu_to_le16(offsetof + (struct create_lease_v2, lcontext)); + buf->ccontext.DataLength = cpu_to_le32(sizeof(struct lease_context_v2)); + buf->ccontext.NameOffset = cpu_to_le16(offsetof + (struct create_lease_v2, Name)); + buf->ccontext.NameLength = cpu_to_le16(4); + buf->Name[0] = 'R'; + buf->Name[1] = 'q'; + buf->Name[2] = 'L'; + buf->Name[3] = 's'; + return (char *)buf; +} + +static __u8 +smb2_parse_lease_buf(void *buf, unsigned int *epoch) +{ + struct create_lease *lc = (struct create_lease *)buf; + + *epoch = 0; /* not used */ + if (lc->lcontext.LeaseFlags & SMB2_LEASE_FLAG_BREAK_IN_PROGRESS) + return SMB2_OPLOCK_LEVEL_NOCHANGE; + return le32_to_cpu(lc->lcontext.LeaseState); +} + +static __u8 +smb3_parse_lease_buf(void *buf, unsigned int *epoch) +{ + struct create_lease_v2 *lc = (struct create_lease_v2 *)buf; + + *epoch = le16_to_cpu(lc->lcontext.Epoch); + if (lc->lcontext.LeaseFlags & SMB2_LEASE_FLAG_BREAK_IN_PROGRESS) + return SMB2_OPLOCK_LEVEL_NOCHANGE; + return le32_to_cpu(lc->lcontext.LeaseState); +} + +struct smb_version_operations smb20_operations = { .compare_fids = smb2_compare_fids, .setup_request = smb2_setup_request, .setup_async_request = smb2_setup_async_request, @@ -638,6 +880,7 @@ struct smb_version_operations smb21_operations = { .unlink = smb2_unlink, .rename = smb2_rename_path, .create_hardlink = smb2_create_hardlink, + .query_symlink = smb2_query_symlink, .open = smb2_open_file, .set_fid = smb2_set_fid, .close = smb2_close_file, @@ -660,8 +903,82 @@ struct smb_version_operations smb21_operations = { .set_lease_key = smb2_set_lease_key, .new_lease_key = smb2_new_lease_key, .calc_signature = smb2_calc_signature, + .is_read_op = smb2_is_read_op, + .set_oplock_level = smb2_set_oplock_level, + .create_lease_buf = smb2_create_lease_buf, + .parse_lease_buf = smb2_parse_lease_buf, }; +struct smb_version_operations smb21_operations = { + .compare_fids = smb2_compare_fids, + .setup_request = smb2_setup_request, + .setup_async_request = smb2_setup_async_request, + .check_receive = smb2_check_receive, + .add_credits = smb2_add_credits, + .set_credits = smb2_set_credits, + .get_credits_field = smb2_get_credits_field, + .get_credits = smb2_get_credits, + .get_next_mid = smb2_get_next_mid, + .read_data_offset = smb2_read_data_offset, + .read_data_length = smb2_read_data_length, + .map_error = map_smb2_to_linux_error, + .find_mid = smb2_find_mid, + .check_message = smb2_check_message, + .dump_detail = smb2_dump_detail, + .clear_stats = smb2_clear_stats, + .print_stats = smb2_print_stats, + .is_oplock_break = smb2_is_valid_oplock_break, + .need_neg = smb2_need_neg, + .negotiate = smb2_negotiate, + .negotiate_wsize = smb2_negotiate_wsize, + .negotiate_rsize = smb2_negotiate_rsize, + .sess_setup = SMB2_sess_setup, + .logoff = SMB2_logoff, + .tree_connect = SMB2_tcon, + .tree_disconnect = SMB2_tdis, + .is_path_accessible = smb2_is_path_accessible, + .can_echo = smb2_can_echo, + .echo = SMB2_echo, + .query_path_info = smb2_query_path_info, + .get_srv_inum = smb2_get_srv_inum, + .query_file_info = smb2_query_file_info, + .set_path_size = smb2_set_path_size, + .set_file_size = smb2_set_file_size, + .set_file_info = smb2_set_file_info, + .mkdir = smb2_mkdir, + .mkdir_setinfo = smb2_mkdir_setinfo, + .rmdir = smb2_rmdir, + .unlink = smb2_unlink, + .rename = smb2_rename_path, + .create_hardlink = smb2_create_hardlink, + .query_symlink = smb2_query_symlink, + .open = smb2_open_file, + .set_fid = smb2_set_fid, + .close = smb2_close_file, + .flush = smb2_flush_file, + .async_readv = smb2_async_readv, + .async_writev = smb2_async_writev, + .sync_read = smb2_sync_read, + .sync_write = smb2_sync_write, + .query_dir_first = smb2_query_dir_first, + .query_dir_next = smb2_query_dir_next, + .close_dir = smb2_close_dir, + .calc_smb_size = smb2_calc_size, + .is_status_pending = smb2_is_status_pending, + .oplock_response = smb2_oplock_response, + .queryfs = smb2_queryfs, + .mand_lock = smb2_mand_lock, + .mand_unlock_range = smb2_unlock_range, + .push_mand_locks = smb2_push_mandatory_locks, + .get_lease_key = smb2_get_lease_key, + .set_lease_key = smb2_set_lease_key, + .new_lease_key = smb2_new_lease_key, + .calc_signature = smb2_calc_signature, + .is_read_op = smb21_is_read_op, + .set_oplock_level = smb21_set_oplock_level, + .create_lease_buf = smb2_create_lease_buf, + .parse_lease_buf = smb2_parse_lease_buf, +}; struct smb_version_operations smb30_operations = { .compare_fids = smb2_compare_fids, @@ -706,6 +1023,7 @@ struct smb_version_operations smb30_operations = { .unlink = smb2_unlink, .rename = smb2_rename_path, .create_hardlink = smb2_create_hardlink, + .query_symlink = smb2_query_symlink, .open = smb2_open_file, .set_fid = smb2_set_fid, .close = smb2_close_file, @@ -729,6 +1047,10 @@ struct smb_version_operations smb30_operations = { .new_lease_key = smb2_new_lease_key, .generate_signingkey = generate_smb3signingkey, .calc_signature = smb3_calc_signature, + .is_read_op = smb21_is_read_op, + .set_oplock_level = smb3_set_oplock_level, + .create_lease_buf = smb3_create_lease_buf, + .parse_lease_buf = smb3_parse_lease_buf, }; struct smb_version_values smb20_values = { @@ -746,9 +1068,9 @@ struct smb_version_values smb20_values = { .cap_unix = 0, .cap_nt_find = SMB2_NT_FIND, .cap_large_files = SMB2_LARGE_FILES, - .oplock_read = SMB2_OPLOCK_LEVEL_II, .signing_enabled = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED, .signing_required = SMB2_NEGOTIATE_SIGNING_REQUIRED, + .create_lease_size = sizeof(struct create_lease), }; struct smb_version_values smb21_values = { @@ -766,9 +1088,9 @@ struct smb_version_values smb21_values = { .cap_unix = 0, .cap_nt_find = SMB2_NT_FIND, .cap_large_files = SMB2_LARGE_FILES, - .oplock_read = SMB2_OPLOCK_LEVEL_II, .signing_enabled = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED, .signing_required = SMB2_NEGOTIATE_SIGNING_REQUIRED, + .create_lease_size = sizeof(struct create_lease), }; struct smb_version_values smb30_values = { @@ -786,9 +1108,9 @@ struct smb_version_values smb30_values = { .cap_unix = 0, .cap_nt_find = SMB2_NT_FIND, .cap_large_files = SMB2_LARGE_FILES, - .oplock_read = SMB2_OPLOCK_LEVEL_II, .signing_enabled = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED, .signing_required = SMB2_NEGOTIATE_SIGNING_REQUIRED, + .create_lease_size = sizeof(struct create_lease_v2), }; struct smb_version_values smb302_values = { @@ -806,7 +1128,7 @@ struct smb_version_values smb302_values = { .cap_unix = 0, .cap_nt_find = SMB2_NT_FIND, .cap_large_files = SMB2_LARGE_FILES, - .oplock_read = SMB2_OPLOCK_LEVEL_II, .signing_enabled = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED, .signing_required = SMB2_NEGOTIATE_SIGNING_REQUIRED, + .create_lease_size = sizeof(struct create_lease_v2), }; diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index abc9c2809b5..eba0efde66d 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -478,12 +478,20 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, } /* + * If we are here due to reconnect, free per-smb session key + * in case signing was required. + */ + kfree(ses->auth_key.response); + ses->auth_key.response = NULL; + + /* * If memory allocation is successful, caller of this function * frees it. */ ses->ntlmssp = kmalloc(sizeof(struct ntlmssp_auth), GFP_KERNEL); if (!ses->ntlmssp) return -ENOMEM; + ses->ntlmssp->sesskey_per_smbsess = true; /* FIXME: allow for other auth types besides NTLMSSP (e.g. krb5) */ ses->sectype = RawNTLMSSP; @@ -628,6 +636,40 @@ ssetup_exit: /* if ntlmssp, and negotiate succeeded, proceed to authenticate phase */ if ((phase == NtLmChallenge) && (rc == 0)) goto ssetup_ntlmssp_authenticate; + + if (!rc) { + mutex_lock(&server->srv_mutex); + if (server->sign && server->ops->generate_signingkey) { + rc = server->ops->generate_signingkey(ses); + kfree(ses->auth_key.response); + ses->auth_key.response = NULL; + if (rc) { + cifs_dbg(FYI, + "SMB3 session key generation failed\n"); + mutex_unlock(&server->srv_mutex); + goto keygen_exit; + } + } + if (!server->session_estab) { + server->sequence_number = 0x2; + server->session_estab = true; + } + mutex_unlock(&server->srv_mutex); + + cifs_dbg(FYI, "SMB2/3 session established successfully\n"); + spin_lock(&GlobalMid_Lock); + ses->status = CifsGood; + ses->need_reconnect = false; + spin_unlock(&GlobalMid_Lock); + } + +keygen_exit: + if (!server->sign) { + kfree(ses->auth_key.response); + ses->auth_key.response = NULL; + } + kfree(ses->ntlmssp); + return rc; } @@ -813,39 +855,6 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon) return rc; } -static struct create_lease * -create_lease_buf(u8 *lease_key, u8 oplock) -{ - struct create_lease *buf; - - buf = kzalloc(sizeof(struct create_lease), GFP_KERNEL); - if (!buf) - return NULL; - - buf->lcontext.LeaseKeyLow = cpu_to_le64(*((u64 *)lease_key)); - buf->lcontext.LeaseKeyHigh = cpu_to_le64(*((u64 *)(lease_key + 8))); - if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE) - buf->lcontext.LeaseState = SMB2_LEASE_WRITE_CACHING | - SMB2_LEASE_READ_CACHING; - else if (oplock == SMB2_OPLOCK_LEVEL_II) - buf->lcontext.LeaseState = SMB2_LEASE_READ_CACHING; - else if (oplock == SMB2_OPLOCK_LEVEL_BATCH) - buf->lcontext.LeaseState = SMB2_LEASE_HANDLE_CACHING | - SMB2_LEASE_READ_CACHING | - SMB2_LEASE_WRITE_CACHING; - - buf->ccontext.DataOffset = cpu_to_le16(offsetof - (struct create_lease, lcontext)); - buf->ccontext.DataLength = cpu_to_le32(sizeof(struct lease_context)); - buf->ccontext.NameOffset = cpu_to_le16(offsetof - (struct create_lease, Name)); - buf->ccontext.NameLength = cpu_to_le16(4); - buf->Name[0] = 'R'; - buf->Name[1] = 'q'; - buf->Name[2] = 'L'; - buf->Name[3] = 's'; - return buf; -} static struct create_durable * create_durable_buf(void) @@ -894,55 +903,49 @@ create_reconnect_durable_buf(struct cifs_fid *fid) } static __u8 -parse_lease_state(struct smb2_create_rsp *rsp) +parse_lease_state(struct TCP_Server_Info *server, struct smb2_create_rsp *rsp, + unsigned int *epoch) { char *data_offset; - struct create_lease *lc; - bool found = false; + struct create_context *cc; unsigned int next = 0; char *name; data_offset = (char *)rsp + 4 + le32_to_cpu(rsp->CreateContextsOffset); - lc = (struct create_lease *)data_offset; + cc = (struct create_context *)data_offset; do { - lc = (struct create_lease *)((char *)lc + next); - name = le16_to_cpu(lc->ccontext.NameOffset) + (char *)lc; - if (le16_to_cpu(lc->ccontext.NameLength) != 4 || + cc = (struct create_context *)((char *)cc + next); + name = le16_to_cpu(cc->NameOffset) + (char *)cc; + if (le16_to_cpu(cc->NameLength) != 4 || strncmp(name, "RqLs", 4)) { - next = le32_to_cpu(lc->ccontext.Next); + next = le32_to_cpu(cc->Next); continue; } - if (lc->lcontext.LeaseFlags & SMB2_LEASE_FLAG_BREAK_IN_PROGRESS) - return SMB2_OPLOCK_LEVEL_NOCHANGE; - found = true; - break; + return server->ops->parse_lease_buf(cc, epoch); } while (next != 0); - if (!found) - return 0; - - return smb2_map_lease_to_oplock(lc->lcontext.LeaseState); + return 0; } static int -add_lease_context(struct kvec *iov, unsigned int *num_iovec, __u8 *oplock) +add_lease_context(struct TCP_Server_Info *server, struct kvec *iov, + unsigned int *num_iovec, __u8 *oplock) { struct smb2_create_req *req = iov[0].iov_base; unsigned int num = *num_iovec; - iov[num].iov_base = create_lease_buf(oplock+1, *oplock); + iov[num].iov_base = server->ops->create_lease_buf(oplock+1, *oplock); if (iov[num].iov_base == NULL) return -ENOMEM; - iov[num].iov_len = sizeof(struct create_lease); + iov[num].iov_len = server->vals->create_lease_size; req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_LEASE; if (!req->CreateContextsOffset) req->CreateContextsOffset = cpu_to_le32( sizeof(struct smb2_create_req) - 4 + iov[num - 1].iov_len); - req->CreateContextsLength = cpu_to_le32( - le32_to_cpu(req->CreateContextsLength) + - sizeof(struct create_lease)); - inc_rfc1001_len(&req->hdr, sizeof(struct create_lease)); + le32_add_cpu(&req->CreateContextsLength, + server->vals->create_lease_size); + inc_rfc1001_len(&req->hdr, server->vals->create_lease_size); *num_iovec = num + 1; return 0; } @@ -967,9 +970,7 @@ add_durable_context(struct kvec *iov, unsigned int *num_iovec, req->CreateContextsOffset = cpu_to_le32(sizeof(struct smb2_create_req) - 4 + iov[1].iov_len); - req->CreateContextsLength = - cpu_to_le32(le32_to_cpu(req->CreateContextsLength) + - sizeof(struct create_durable)); + le32_add_cpu(&req->CreateContextsLength, sizeof(struct create_durable)); inc_rfc1001_len(&req->hdr, sizeof(struct create_durable)); *num_iovec = num + 1; return 0; @@ -977,7 +978,8 @@ add_durable_context(struct kvec *iov, unsigned int *num_iovec, int SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, - __u8 *oplock, struct smb2_file_all_info *buf) + __u8 *oplock, struct smb2_file_all_info *buf, + struct smb2_err_rsp **err_buf) { struct smb2_create_req *req; struct smb2_create_rsp *rsp; @@ -1048,11 +1050,11 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, if (!server->oplocks) *oplock = SMB2_OPLOCK_LEVEL_NONE; - if (!(tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING) || + if (!(server->capabilities & SMB2_GLOBAL_CAP_LEASING) || *oplock == SMB2_OPLOCK_LEVEL_NONE) req->RequestedOplockLevel = *oplock; else { - rc = add_lease_context(iov, &num_iovecs, oplock); + rc = add_lease_context(server, iov, &num_iovecs, oplock); if (rc) { cifs_small_buf_release(req); kfree(copy_path); @@ -1062,11 +1064,11 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, if (*oplock == SMB2_OPLOCK_LEVEL_BATCH) { /* need to set Next field of lease context if we request it */ - if (tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING) { + if (server->capabilities & SMB2_GLOBAL_CAP_LEASING) { struct create_context *ccontext = (struct create_context *)iov[num_iovecs-1].iov_base; ccontext->Next = - cpu_to_le32(sizeof(struct create_lease)); + cpu_to_le32(server->vals->create_lease_size); } rc = add_durable_context(iov, &num_iovecs, oparms); if (rc) { @@ -1082,6 +1084,9 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, if (rc != 0) { cifs_stats_fail_inc(tcon, SMB2_CREATE_HE); + if (err_buf) + *err_buf = kmemdup(rsp, get_rfc1002_length(rsp) + 4, + GFP_KERNEL); goto creat_exit; } @@ -1098,7 +1103,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, } if (rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE) - *oplock = parse_lease_state(rsp); + *oplock = parse_lease_state(server, rsp, &oparms->fid->epoch); else *oplock = rsp->OplockLevel; creat_exit: diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index 36b0d37ea69..b83d0118a75 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h @@ -150,6 +150,20 @@ struct smb2_err_rsp { __u8 ErrorData[1]; /* variable length */ } __packed; +struct smb2_symlink_err_rsp { + __le32 SymLinkLength; + __le32 SymLinkErrorTag; + __le32 ReparseTag; + __le16 ReparseDataLength; + __le16 UnparsedPathLength; + __le16 SubstituteNameOffset; + __le16 SubstituteNameLength; + __le16 PrintNameOffset; + __le16 PrintNameLength; + __le32 Flags; + __u8 PathBuffer[0]; +} __packed; + #define SMB2_CLIENT_GUID_SIZE 16 extern __u8 cifs_client_guid[SMB2_CLIENT_GUID_SIZE]; @@ -462,6 +476,10 @@ struct create_context { __u8 Buffer[0]; } __packed; +#define SMB2_LEASE_READ_CACHING_HE 0x01 +#define SMB2_LEASE_HANDLE_CACHING_HE 0x02 +#define SMB2_LEASE_WRITE_CACHING_HE 0x04 + #define SMB2_LEASE_NONE __constant_cpu_to_le32(0x00) #define SMB2_LEASE_READ_CACHING __constant_cpu_to_le32(0x01) #define SMB2_LEASE_HANDLE_CACHING __constant_cpu_to_le32(0x02) @@ -479,12 +497,31 @@ struct lease_context { __le64 LeaseDuration; } __packed; +struct lease_context_v2 { + __le64 LeaseKeyLow; + __le64 LeaseKeyHigh; + __le32 LeaseState; + __le32 LeaseFlags; + __le64 LeaseDuration; + __le64 ParentLeaseKeyLow; + __le64 ParentLeaseKeyHigh; + __le16 Epoch; + __le16 Reserved; +} __packed; + struct create_lease { struct create_context ccontext; __u8 Name[8]; struct lease_context lcontext; } __packed; +struct create_lease_v2 { + struct create_context ccontext; + __u8 Name[8]; + struct lease_context_v2 lcontext; + __u8 Pad[4]; +} __packed; + struct create_durable { struct create_context ccontext; __u8 Name[8]; diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index 1a5ecbed40e..e3fb4801ee9 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -53,7 +53,6 @@ extern int smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server); extern void smb2_echo_request(struct work_struct *work); extern __le32 smb2_get_lease_state(struct cifsInodeInfo *cinode); -extern __u8 smb2_map_lease_to_oplock(__le32 lease_state); extern bool smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv); @@ -87,7 +86,6 @@ extern int smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon, extern int smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, __u32 *oplock, FILE_ALL_INFO *buf); -extern void smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock); extern int smb2_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, const unsigned int xid); extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile); @@ -106,7 +104,8 @@ extern int SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, extern int SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon); extern int SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, __u8 *oplock, - struct smb2_file_all_info *buf); + struct smb2_file_all_info *buf, + struct smb2_err_rsp **err_buf); extern int SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid, u32 opcode, bool is_fsctl, char *in_data, u32 indatalen, diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c index 4f2300d020c..340abca3aa5 100644 --- a/fs/cifs/smb2transport.c +++ b/fs/cifs/smb2transport.c @@ -114,6 +114,23 @@ smb3_crypto_shash_allocate(struct TCP_Server_Info *server) return 0; } +static struct cifs_ses * +smb2_find_smb_ses(struct smb2_hdr *smb2hdr, struct TCP_Server_Info *server) +{ + struct cifs_ses *ses; + + spin_lock(&cifs_tcp_ses_lock); + list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { + if (ses->Suid != smb2hdr->SessionId) + continue; + spin_unlock(&cifs_tcp_ses_lock); + return ses; + } + spin_unlock(&cifs_tcp_ses_lock); + + return NULL; +} + int smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) @@ -124,6 +141,13 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) struct kvec *iov = rqst->rq_iov; int n_vec = rqst->rq_nvec; struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base; + struct cifs_ses *ses; + + ses = smb2_find_smb_ses(smb2_pdu, server); + if (!ses) { + cifs_dbg(VFS, "%s: Could not find session\n", __func__); + return 0; + } memset(smb2_signature, 0x0, SMB2_HMACSHA256_SIZE); memset(smb2_pdu->Signature, 0x0, SMB2_SIGNATURE_SIZE); @@ -135,7 +159,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) } rc = crypto_shash_setkey(server->secmech.hmacsha256, - server->session_key.response, SMB2_NTLMV2_SESSKEY_SIZE); + ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE); if (rc) { cifs_dbg(VFS, "%s: Could not update with response\n", __func__); return rc; @@ -198,8 +222,8 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) return rc; } -void -generate_smb3signingkey(struct TCP_Server_Info *server) +int +generate_smb3signingkey(struct cifs_ses *ses) { unsigned char zero = 0x0; __u8 i[4] = {0, 0, 0, 1}; @@ -209,90 +233,99 @@ generate_smb3signingkey(struct TCP_Server_Info *server) unsigned char *hashptr = prfhash; memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE); - memset(server->smb3signingkey, 0x0, SMB3_SIGNKEY_SIZE); + memset(ses->smb3signingkey, 0x0, SMB3_SIGNKEY_SIZE); - rc = smb3_crypto_shash_allocate(server); + rc = smb3_crypto_shash_allocate(ses->server); if (rc) { cifs_dbg(VFS, "%s: crypto alloc failed\n", __func__); goto smb3signkey_ret; } - rc = crypto_shash_setkey(server->secmech.hmacsha256, - server->session_key.response, SMB2_NTLMV2_SESSKEY_SIZE); + rc = crypto_shash_setkey(ses->server->secmech.hmacsha256, + ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE); if (rc) { cifs_dbg(VFS, "%s: Could not set with session key\n", __func__); goto smb3signkey_ret; } - rc = crypto_shash_init(&server->secmech.sdeschmacsha256->shash); + rc = crypto_shash_init(&ses->server->secmech.sdeschmacsha256->shash); if (rc) { cifs_dbg(VFS, "%s: Could not init sign hmac\n", __func__); goto smb3signkey_ret; } - rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash, + rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash, i, 4); if (rc) { cifs_dbg(VFS, "%s: Could not update with n\n", __func__); goto smb3signkey_ret; } - rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash, + rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash, "SMB2AESCMAC", 12); if (rc) { cifs_dbg(VFS, "%s: Could not update with label\n", __func__); goto smb3signkey_ret; } - rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash, + rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash, &zero, 1); if (rc) { cifs_dbg(VFS, "%s: Could not update with zero\n", __func__); goto smb3signkey_ret; } - rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash, + rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash, "SmbSign", 8); if (rc) { cifs_dbg(VFS, "%s: Could not update with context\n", __func__); goto smb3signkey_ret; } - rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash, + rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash, L, 4); if (rc) { cifs_dbg(VFS, "%s: Could not update with L\n", __func__); goto smb3signkey_ret; } - rc = crypto_shash_final(&server->secmech.sdeschmacsha256->shash, + rc = crypto_shash_final(&ses->server->secmech.sdeschmacsha256->shash, hashptr); if (rc) { cifs_dbg(VFS, "%s: Could not generate sha256 hash\n", __func__); goto smb3signkey_ret; } - memcpy(server->smb3signingkey, hashptr, SMB3_SIGNKEY_SIZE); + memcpy(ses->smb3signingkey, hashptr, SMB3_SIGNKEY_SIZE); smb3signkey_ret: - return; + return rc; } int smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) { - int i, rc; + int i; + int rc = 0; unsigned char smb3_signature[SMB2_CMACAES_SIZE]; unsigned char *sigptr = smb3_signature; struct kvec *iov = rqst->rq_iov; int n_vec = rqst->rq_nvec; struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base; + struct cifs_ses *ses; + + ses = smb2_find_smb_ses(smb2_pdu, server); + if (!ses) { + cifs_dbg(VFS, "%s: Could not find session\n", __func__); + return 0; + } memset(smb3_signature, 0x0, SMB2_CMACAES_SIZE); memset(smb2_pdu->Signature, 0x0, SMB2_SIGNATURE_SIZE); rc = crypto_shash_setkey(server->secmech.cmacaes, - server->smb3signingkey, SMB2_CMACAES_SIZE); + ses->smb3signingkey, SMB2_CMACAES_SIZE); + if (rc) { cifs_dbg(VFS, "%s: Could not set key for cmac aes\n", __func__); return rc; @@ -389,6 +422,7 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)rqst->rq_iov[0].iov_base; if ((smb2_pdu->Command == SMB2_NEGOTIATE) || + (smb2_pdu->Command == SMB2_SESSION_SETUP) || (smb2_pdu->Command == SMB2_OPLOCK_BREAK) || (!server->session_estab)) return 0; diff --git a/fs/cifs/winucase.c b/fs/cifs/winucase.c new file mode 100644 index 00000000000..1506d4fddb2 --- /dev/null +++ b/fs/cifs/winucase.c @@ -0,0 +1,663 @@ +/* + * fs/cifs/winucase.c + * + * Copyright (c) Jeffrey Layton <jlayton@redhat.com>, 2013 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * The const tables in this file were converted from the following info + * provided by Microsoft: + * + * 3.1.5.3 Mapping UTF-16 Strings to Upper Case: + * + * http://msdn.microsoft.com/en-us/library/hh877830.aspx + * http://www.microsoft.com/en-us/download/details.aspx?displaylang=en&id=10921 + * + * In particular, the table in "Windows 8 Upper Case Mapping Table.txt" was + * post-processed using the winucase_convert.pl script. + */ + +#include <linux/nls.h> + +wchar_t cifs_toupper(wchar_t in); /* quiet sparse */ + +static const wchar_t t2_00[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, + 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, + 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x0000, + 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x0178, +}; + +static const wchar_t t2_01[256] = { + 0x0000, 0x0100, 0x0000, 0x0102, 0x0000, 0x0104, 0x0000, 0x0106, + 0x0000, 0x0108, 0x0000, 0x010a, 0x0000, 0x010c, 0x0000, 0x010e, + 0x0000, 0x0110, 0x0000, 0x0112, 0x0000, 0x0114, 0x0000, 0x0116, + 0x0000, 0x0118, 0x0000, 0x011a, 0x0000, 0x011c, 0x0000, 0x011e, + 0x0000, 0x0120, 0x0000, 0x0122, 0x0000, 0x0124, 0x0000, 0x0126, + 0x0000, 0x0128, 0x0000, 0x012a, 0x0000, 0x012c, 0x0000, 0x012e, + 0x0000, 0x0000, 0x0000, 0x0132, 0x0000, 0x0134, 0x0000, 0x0136, + 0x0000, 0x0000, 0x0139, 0x0000, 0x013b, 0x0000, 0x013d, 0x0000, + 0x013f, 0x0000, 0x0141, 0x0000, 0x0143, 0x0000, 0x0145, 0x0000, + 0x0147, 0x0000, 0x0000, 0x014a, 0x0000, 0x014c, 0x0000, 0x014e, + 0x0000, 0x0150, 0x0000, 0x0152, 0x0000, 0x0154, 0x0000, 0x0156, + 0x0000, 0x0158, 0x0000, 0x015a, 0x0000, 0x015c, 0x0000, 0x015e, + 0x0000, 0x0160, 0x0000, 0x0162, 0x0000, 0x0164, 0x0000, 0x0166, + 0x0000, 0x0168, 0x0000, 0x016a, 0x0000, 0x016c, 0x0000, 0x016e, + 0x0000, 0x0170, 0x0000, 0x0172, 0x0000, 0x0174, 0x0000, 0x0176, + 0x0000, 0x0000, 0x0179, 0x0000, 0x017b, 0x0000, 0x017d, 0x0000, + 0x0243, 0x0000, 0x0000, 0x0182, 0x0000, 0x0184, 0x0000, 0x0000, + 0x0187, 0x0000, 0x0000, 0x0000, 0x018b, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0191, 0x0000, 0x0000, 0x01f6, 0x0000, 0x0000, + 0x0000, 0x0198, 0x023d, 0x0000, 0x0000, 0x0000, 0x0220, 0x0000, + 0x0000, 0x01a0, 0x0000, 0x01a2, 0x0000, 0x01a4, 0x0000, 0x0000, + 0x01a7, 0x0000, 0x0000, 0x0000, 0x0000, 0x01ac, 0x0000, 0x0000, + 0x01af, 0x0000, 0x0000, 0x0000, 0x01b3, 0x0000, 0x01b5, 0x0000, + 0x0000, 0x01b8, 0x0000, 0x0000, 0x0000, 0x01bc, 0x0000, 0x01f7, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x01c4, 0x0000, + 0x0000, 0x01c7, 0x0000, 0x0000, 0x01ca, 0x0000, 0x01cd, 0x0000, + 0x01cf, 0x0000, 0x01d1, 0x0000, 0x01d3, 0x0000, 0x01d5, 0x0000, + 0x01d7, 0x0000, 0x01d9, 0x0000, 0x01db, 0x018e, 0x0000, 0x01de, + 0x0000, 0x01e0, 0x0000, 0x01e2, 0x0000, 0x01e4, 0x0000, 0x01e6, + 0x0000, 0x01e8, 0x0000, 0x01ea, 0x0000, 0x01ec, 0x0000, 0x01ee, + 0x0000, 0x0000, 0x0000, 0x01f1, 0x0000, 0x01f4, 0x0000, 0x0000, + 0x0000, 0x01f8, 0x0000, 0x01fa, 0x0000, 0x01fc, 0x0000, 0x01fe, +}; + +static const wchar_t t2_02[256] = { + 0x0000, 0x0200, 0x0000, 0x0202, 0x0000, 0x0204, 0x0000, 0x0206, + 0x0000, 0x0208, 0x0000, 0x020a, 0x0000, 0x020c, 0x0000, 0x020e, + 0x0000, 0x0210, 0x0000, 0x0212, 0x0000, 0x0214, 0x0000, 0x0216, + 0x0000, 0x0218, 0x0000, 0x021a, 0x0000, 0x021c, 0x0000, 0x021e, + 0x0000, 0x0000, 0x0000, 0x0222, 0x0000, 0x0224, 0x0000, 0x0226, + 0x0000, 0x0228, 0x0000, 0x022a, 0x0000, 0x022c, 0x0000, 0x022e, + 0x0000, 0x0230, 0x0000, 0x0232, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x023b, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0241, 0x0000, 0x0000, 0x0000, 0x0000, 0x0246, + 0x0000, 0x0248, 0x0000, 0x024a, 0x0000, 0x024c, 0x0000, 0x024e, + 0x2c6f, 0x2c6d, 0x0000, 0x0181, 0x0186, 0x0000, 0x0189, 0x018a, + 0x0000, 0x018f, 0x0000, 0x0190, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0193, 0x0000, 0x0000, 0x0194, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0197, 0x0196, 0x0000, 0x2c62, 0x0000, 0x0000, 0x0000, 0x019c, + 0x0000, 0x2c6e, 0x019d, 0x0000, 0x0000, 0x019f, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2c64, 0x0000, 0x0000, + 0x01a6, 0x0000, 0x0000, 0x01a9, 0x0000, 0x0000, 0x0000, 0x0000, + 0x01ae, 0x0244, 0x01b1, 0x01b2, 0x0245, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x01b7, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +}; + +static const wchar_t t2_03[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0370, 0x0000, 0x0372, 0x0000, 0x0000, 0x0000, 0x0376, + 0x0000, 0x0000, 0x0000, 0x03fd, 0x03fe, 0x03ff, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0386, 0x0388, 0x0389, 0x038a, + 0x0000, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, + 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f, + 0x03a0, 0x03a1, 0x0000, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7, + 0x03a8, 0x03a9, 0x03aa, 0x03ab, 0x038c, 0x038e, 0x038f, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x03cf, + 0x0000, 0x03d8, 0x0000, 0x03da, 0x0000, 0x03dc, 0x0000, 0x03de, + 0x0000, 0x03e0, 0x0000, 0x03e2, 0x0000, 0x03e4, 0x0000, 0x03e6, + 0x0000, 0x03e8, 0x0000, 0x03ea, 0x0000, 0x03ec, 0x0000, 0x03ee, + 0x0000, 0x0000, 0x03f9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x03f7, 0x0000, 0x0000, 0x03fa, 0x0000, 0x0000, 0x0000, 0x0000, +}; + +static const wchar_t t2_04[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, + 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, + 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, + 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, + 0x0408, 0x0409, 0x040a, 0x040b, 0x040c, 0x040d, 0x040e, 0x040f, + 0x0000, 0x0460, 0x0000, 0x0462, 0x0000, 0x0464, 0x0000, 0x0466, + 0x0000, 0x0468, 0x0000, 0x046a, 0x0000, 0x046c, 0x0000, 0x046e, + 0x0000, 0x0470, 0x0000, 0x0472, 0x0000, 0x0474, 0x0000, 0x0476, + 0x0000, 0x0478, 0x0000, 0x047a, 0x0000, 0x047c, 0x0000, 0x047e, + 0x0000, 0x0480, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x048a, 0x0000, 0x048c, 0x0000, 0x048e, + 0x0000, 0x0490, 0x0000, 0x0492, 0x0000, 0x0494, 0x0000, 0x0496, + 0x0000, 0x0498, 0x0000, 0x049a, 0x0000, 0x049c, 0x0000, 0x049e, + 0x0000, 0x04a0, 0x0000, 0x04a2, 0x0000, 0x04a4, 0x0000, 0x04a6, + 0x0000, 0x04a8, 0x0000, 0x04aa, 0x0000, 0x04ac, 0x0000, 0x04ae, + 0x0000, 0x04b0, 0x0000, 0x04b2, 0x0000, 0x04b4, 0x0000, 0x04b6, + 0x0000, 0x04b8, 0x0000, 0x04ba, 0x0000, 0x04bc, 0x0000, 0x04be, + 0x0000, 0x0000, 0x04c1, 0x0000, 0x04c3, 0x0000, 0x04c5, 0x0000, + 0x04c7, 0x0000, 0x04c9, 0x0000, 0x04cb, 0x0000, 0x04cd, 0x04c0, + 0x0000, 0x04d0, 0x0000, 0x04d2, 0x0000, 0x04d4, 0x0000, 0x04d6, + 0x0000, 0x04d8, 0x0000, 0x04da, 0x0000, 0x04dc, 0x0000, 0x04de, + 0x0000, 0x04e0, 0x0000, 0x04e2, 0x0000, 0x04e4, 0x0000, 0x04e6, + 0x0000, 0x04e8, 0x0000, 0x04ea, 0x0000, 0x04ec, 0x0000, 0x04ee, + 0x0000, 0x04f0, 0x0000, 0x04f2, 0x0000, 0x04f4, 0x0000, 0x04f6, + 0x0000, 0x04f8, 0x0000, 0x04fa, 0x0000, 0x04fc, 0x0000, 0x04fe, +}; + +static const wchar_t t2_05[256] = { + 0x0000, 0x0500, 0x0000, 0x0502, 0x0000, 0x0504, 0x0000, 0x0506, + 0x0000, 0x0508, 0x0000, 0x050a, 0x0000, 0x050c, 0x0000, 0x050e, + 0x0000, 0x0510, 0x0000, 0x0512, 0x0000, 0x0514, 0x0000, 0x0516, + 0x0000, 0x0518, 0x0000, 0x051a, 0x0000, 0x051c, 0x0000, 0x051e, + 0x0000, 0x0520, 0x0000, 0x0522, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0531, 0x0532, 0x0533, 0x0534, 0x0535, 0x0536, 0x0537, + 0x0538, 0x0539, 0x053a, 0x053b, 0x053c, 0x053d, 0x053e, 0x053f, + 0x0540, 0x0541, 0x0542, 0x0543, 0x0544, 0x0545, 0x0546, 0x0547, + 0x0548, 0x0549, 0x054a, 0x054b, 0x054c, 0x054d, 0x054e, 0x054f, + 0x0550, 0x0551, 0x0552, 0x0553, 0x0554, 0x0555, 0x0556, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +}; + +static const wchar_t t2_1d[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xa77d, 0x0000, 0x0000, 0x0000, 0x2c63, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +}; + +static const wchar_t t2_1e[256] = { + 0x0000, 0x1e00, 0x0000, 0x1e02, 0x0000, 0x1e04, 0x0000, 0x1e06, + 0x0000, 0x1e08, 0x0000, 0x1e0a, 0x0000, 0x1e0c, 0x0000, 0x1e0e, + 0x0000, 0x1e10, 0x0000, 0x1e12, 0x0000, 0x1e14, 0x0000, 0x1e16, + 0x0000, 0x1e18, 0x0000, 0x1e1a, 0x0000, 0x1e1c, 0x0000, 0x1e1e, + 0x0000, 0x1e20, 0x0000, 0x1e22, 0x0000, 0x1e24, 0x0000, 0x1e26, + 0x0000, 0x1e28, 0x0000, 0x1e2a, 0x0000, 0x1e2c, 0x0000, 0x1e2e, + 0x0000, 0x1e30, 0x0000, 0x1e32, 0x0000, 0x1e34, 0x0000, 0x1e36, + 0x0000, 0x1e38, 0x0000, 0x1e3a, 0x0000, 0x1e3c, 0x0000, 0x1e3e, + 0x0000, 0x1e40, 0x0000, 0x1e42, 0x0000, 0x1e44, 0x0000, 0x1e46, + 0x0000, 0x1e48, 0x0000, 0x1e4a, 0x0000, 0x1e4c, 0x0000, 0x1e4e, + 0x0000, 0x1e50, 0x0000, 0x1e52, 0x0000, 0x1e54, 0x0000, 0x1e56, + 0x0000, 0x1e58, 0x0000, 0x1e5a, 0x0000, 0x1e5c, 0x0000, 0x1e5e, + 0x0000, 0x1e60, 0x0000, 0x1e62, 0x0000, 0x1e64, 0x0000, 0x1e66, + 0x0000, 0x1e68, 0x0000, 0x1e6a, 0x0000, 0x1e6c, 0x0000, 0x1e6e, + 0x0000, 0x1e70, 0x0000, 0x1e72, 0x0000, 0x1e74, 0x0000, 0x1e76, + 0x0000, 0x1e78, 0x0000, 0x1e7a, 0x0000, 0x1e7c, 0x0000, 0x1e7e, + 0x0000, 0x1e80, 0x0000, 0x1e82, 0x0000, 0x1e84, 0x0000, 0x1e86, + 0x0000, 0x1e88, 0x0000, 0x1e8a, 0x0000, 0x1e8c, 0x0000, 0x1e8e, + 0x0000, 0x1e90, 0x0000, 0x1e92, 0x0000, 0x1e94, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x1ea0, 0x0000, 0x1ea2, 0x0000, 0x1ea4, 0x0000, 0x1ea6, + 0x0000, 0x1ea8, 0x0000, 0x1eaa, 0x0000, 0x1eac, 0x0000, 0x1eae, + 0x0000, 0x1eb0, 0x0000, 0x1eb2, 0x0000, 0x1eb4, 0x0000, 0x1eb6, + 0x0000, 0x1eb8, 0x0000, 0x1eba, 0x0000, 0x1ebc, 0x0000, 0x1ebe, + 0x0000, 0x1ec0, 0x0000, 0x1ec2, 0x0000, 0x1ec4, 0x0000, 0x1ec6, + 0x0000, 0x1ec8, 0x0000, 0x1eca, 0x0000, 0x1ecc, 0x0000, 0x1ece, + 0x0000, 0x1ed0, 0x0000, 0x1ed2, 0x0000, 0x1ed4, 0x0000, 0x1ed6, + 0x0000, 0x1ed8, 0x0000, 0x1eda, 0x0000, 0x1edc, 0x0000, 0x1ede, + 0x0000, 0x1ee0, 0x0000, 0x1ee2, 0x0000, 0x1ee4, 0x0000, 0x1ee6, + 0x0000, 0x1ee8, 0x0000, 0x1eea, 0x0000, 0x1eec, 0x0000, 0x1eee, + 0x0000, 0x1ef0, 0x0000, 0x1ef2, 0x0000, 0x1ef4, 0x0000, 0x1ef6, + 0x0000, 0x1ef8, 0x0000, 0x1efa, 0x0000, 0x1efc, 0x0000, 0x1efe, +}; + +static const wchar_t t2_1f[256] = { + 0x1f08, 0x1f09, 0x1f0a, 0x1f0b, 0x1f0c, 0x1f0d, 0x1f0e, 0x1f0f, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x1f18, 0x1f19, 0x1f1a, 0x1f1b, 0x1f1c, 0x1f1d, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x1f28, 0x1f29, 0x1f2a, 0x1f2b, 0x1f2c, 0x1f2d, 0x1f2e, 0x1f2f, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x1f38, 0x1f39, 0x1f3a, 0x1f3b, 0x1f3c, 0x1f3d, 0x1f3e, 0x1f3f, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x1f48, 0x1f49, 0x1f4a, 0x1f4b, 0x1f4c, 0x1f4d, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x1f59, 0x0000, 0x1f5b, 0x0000, 0x1f5d, 0x0000, 0x1f5f, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x1f68, 0x1f69, 0x1f6a, 0x1f6b, 0x1f6c, 0x1f6d, 0x1f6e, 0x1f6f, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x1fba, 0x1fbb, 0x1fc8, 0x1fc9, 0x1fca, 0x1fcb, 0x1fda, 0x1fdb, + 0x1ff8, 0x1ff9, 0x1fea, 0x1feb, 0x1ffa, 0x1ffb, 0x0000, 0x0000, + 0x1f88, 0x1f89, 0x1f8a, 0x1f8b, 0x1f8c, 0x1f8d, 0x1f8e, 0x1f8f, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x1f98, 0x1f99, 0x1f9a, 0x1f9b, 0x1f9c, 0x1f9d, 0x1f9e, 0x1f9f, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x1fa8, 0x1fa9, 0x1faa, 0x1fab, 0x1fac, 0x1fad, 0x1fae, 0x1faf, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x1fb8, 0x1fb9, 0x0000, 0x1fbc, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x1fcc, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x1fd8, 0x1fd9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x1fe8, 0x1fe9, 0x0000, 0x0000, 0x0000, 0x1fec, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x1ffc, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +}; + +static const wchar_t t2_21[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2132, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x2160, 0x2161, 0x2162, 0x2163, 0x2164, 0x2165, 0x2166, 0x2167, + 0x2168, 0x2169, 0x216a, 0x216b, 0x216c, 0x216d, 0x216e, 0x216f, + 0x0000, 0x0000, 0x0000, 0x0000, 0x2183, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +}; + +static const wchar_t t2_24[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x24b6, 0x24b7, 0x24b8, 0x24b9, 0x24ba, 0x24bb, 0x24bc, 0x24bd, + 0x24be, 0x24bf, 0x24c0, 0x24c1, 0x24c2, 0x24c3, 0x24c4, 0x24c5, + 0x24c6, 0x24c7, 0x24c8, 0x24c9, 0x24ca, 0x24cb, 0x24cc, 0x24cd, + 0x24ce, 0x24cf, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +}; + +static const wchar_t t2_2c[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x2c00, 0x2c01, 0x2c02, 0x2c03, 0x2c04, 0x2c05, 0x2c06, 0x2c07, + 0x2c08, 0x2c09, 0x2c0a, 0x2c0b, 0x2c0c, 0x2c0d, 0x2c0e, 0x2c0f, + 0x2c10, 0x2c11, 0x2c12, 0x2c13, 0x2c14, 0x2c15, 0x2c16, 0x2c17, + 0x2c18, 0x2c19, 0x2c1a, 0x2c1b, 0x2c1c, 0x2c1d, 0x2c1e, 0x2c1f, + 0x2c20, 0x2c21, 0x2c22, 0x2c23, 0x2c24, 0x2c25, 0x2c26, 0x2c27, + 0x2c28, 0x2c29, 0x2c2a, 0x2c2b, 0x2c2c, 0x2c2d, 0x2c2e, 0x0000, + 0x0000, 0x2c60, 0x0000, 0x0000, 0x0000, 0x023a, 0x023e, 0x0000, + 0x2c67, 0x0000, 0x2c69, 0x0000, 0x2c6b, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x2c72, 0x0000, 0x0000, 0x2c75, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x2c80, 0x0000, 0x2c82, 0x0000, 0x2c84, 0x0000, 0x2c86, + 0x0000, 0x2c88, 0x0000, 0x2c8a, 0x0000, 0x2c8c, 0x0000, 0x2c8e, + 0x0000, 0x2c90, 0x0000, 0x2c92, 0x0000, 0x2c94, 0x0000, 0x2c96, + 0x0000, 0x2c98, 0x0000, 0x2c9a, 0x0000, 0x2c9c, 0x0000, 0x2c9e, + 0x0000, 0x2ca0, 0x0000, 0x2ca2, 0x0000, 0x2ca4, 0x0000, 0x2ca6, + 0x0000, 0x2ca8, 0x0000, 0x2caa, 0x0000, 0x2cac, 0x0000, 0x2cae, + 0x0000, 0x2cb0, 0x0000, 0x2cb2, 0x0000, 0x2cb4, 0x0000, 0x2cb6, + 0x0000, 0x2cb8, 0x0000, 0x2cba, 0x0000, 0x2cbc, 0x0000, 0x2cbe, + 0x0000, 0x2cc0, 0x0000, 0x2cc2, 0x0000, 0x2cc4, 0x0000, 0x2cc6, + 0x0000, 0x2cc8, 0x0000, 0x2cca, 0x0000, 0x2ccc, 0x0000, 0x2cce, + 0x0000, 0x2cd0, 0x0000, 0x2cd2, 0x0000, 0x2cd4, 0x0000, 0x2cd6, + 0x0000, 0x2cd8, 0x0000, 0x2cda, 0x0000, 0x2cdc, 0x0000, 0x2cde, + 0x0000, 0x2ce0, 0x0000, 0x2ce2, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +}; + +static const wchar_t t2_2d[256] = { + 0x10a0, 0x10a1, 0x10a2, 0x10a3, 0x10a4, 0x10a5, 0x10a6, 0x10a7, + 0x10a8, 0x10a9, 0x10aa, 0x10ab, 0x10ac, 0x10ad, 0x10ae, 0x10af, + 0x10b0, 0x10b1, 0x10b2, 0x10b3, 0x10b4, 0x10b5, 0x10b6, 0x10b7, + 0x10b8, 0x10b9, 0x10ba, 0x10bb, 0x10bc, 0x10bd, 0x10be, 0x10bf, + 0x10c0, 0x10c1, 0x10c2, 0x10c3, 0x10c4, 0x10c5, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +}; + +static const wchar_t t2_a6[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xa640, 0x0000, 0xa642, 0x0000, 0xa644, 0x0000, 0xa646, + 0x0000, 0xa648, 0x0000, 0xa64a, 0x0000, 0xa64c, 0x0000, 0xa64e, + 0x0000, 0xa650, 0x0000, 0xa652, 0x0000, 0xa654, 0x0000, 0xa656, + 0x0000, 0xa658, 0x0000, 0xa65a, 0x0000, 0xa65c, 0x0000, 0xa65e, + 0x0000, 0x0000, 0x0000, 0xa662, 0x0000, 0xa664, 0x0000, 0xa666, + 0x0000, 0xa668, 0x0000, 0xa66a, 0x0000, 0xa66c, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xa680, 0x0000, 0xa682, 0x0000, 0xa684, 0x0000, 0xa686, + 0x0000, 0xa688, 0x0000, 0xa68a, 0x0000, 0xa68c, 0x0000, 0xa68e, + 0x0000, 0xa690, 0x0000, 0xa692, 0x0000, 0xa694, 0x0000, 0xa696, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +}; + +static const wchar_t t2_a7[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xa722, 0x0000, 0xa724, 0x0000, 0xa726, + 0x0000, 0xa728, 0x0000, 0xa72a, 0x0000, 0xa72c, 0x0000, 0xa72e, + 0x0000, 0x0000, 0x0000, 0xa732, 0x0000, 0xa734, 0x0000, 0xa736, + 0x0000, 0xa738, 0x0000, 0xa73a, 0x0000, 0xa73c, 0x0000, 0xa73e, + 0x0000, 0xa740, 0x0000, 0xa742, 0x0000, 0xa744, 0x0000, 0xa746, + 0x0000, 0xa748, 0x0000, 0xa74a, 0x0000, 0xa74c, 0x0000, 0xa74e, + 0x0000, 0xa750, 0x0000, 0xa752, 0x0000, 0xa754, 0x0000, 0xa756, + 0x0000, 0xa758, 0x0000, 0xa75a, 0x0000, 0xa75c, 0x0000, 0xa75e, + 0x0000, 0xa760, 0x0000, 0xa762, 0x0000, 0xa764, 0x0000, 0xa766, + 0x0000, 0xa768, 0x0000, 0xa76a, 0x0000, 0xa76c, 0x0000, 0xa76e, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xa779, 0x0000, 0xa77b, 0x0000, 0x0000, 0xa77e, + 0x0000, 0xa780, 0x0000, 0xa782, 0x0000, 0xa784, 0x0000, 0xa786, + 0x0000, 0x0000, 0x0000, 0x0000, 0xa78b, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +}; + +static const wchar_t t2_ff[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xff21, 0xff22, 0xff23, 0xff24, 0xff25, 0xff26, 0xff27, + 0xff28, 0xff29, 0xff2a, 0xff2b, 0xff2c, 0xff2d, 0xff2e, 0xff2f, + 0xff30, 0xff31, 0xff32, 0xff33, 0xff34, 0xff35, 0xff36, 0xff37, + 0xff38, 0xff39, 0xff3a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +}; + +static const wchar_t *const toplevel[256] = { + t2_00, t2_01, t2_02, t2_03, t2_04, t2_05, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, t2_1d, t2_1e, t2_1f, + NULL, t2_21, NULL, NULL, t2_24, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, t2_2c, t2_2d, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, t2_a6, t2_a7, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, t2_ff, +}; + +/** + * cifs_toupper - convert a wchar_t from lower to uppercase + * @in: character to convert from lower to uppercase + * + * This function consults the static tables above to convert a wchar_t from + * lower to uppercase. In the event that there is no mapping, the original + * "in" character is returned. + */ +wchar_t +cifs_toupper(wchar_t in) +{ + unsigned char idx; + const wchar_t *tbl; + wchar_t out; + + /* grab upper byte */ + idx = (in & 0xff00) >> 8; + + /* find pointer to 2nd layer table */ + tbl = toplevel[idx]; + if (!tbl) + return in; + + /* grab lower byte */ + idx = in & 0xff; + + /* look up character in table */ + out = tbl[idx]; + if (out) + return out; + + return in; +} |