summaryrefslogtreecommitdiff
path: root/release/src/linux/linux/fs
diff options
context:
space:
mode:
Diffstat (limited to 'release/src/linux/linux/fs')
-rw-r--r--release/src/linux/linux/fs/Config.in15
-rw-r--r--release/src/linux/linux/fs/Makefile3
-rw-r--r--release/src/linux/linux/fs/buffer.c5
-rw-r--r--release/src/linux/linux/fs/cifs/AUTHORS37
-rw-r--r--release/src/linux/linux/fs/cifs/CHANGES572
-rw-r--r--release/src/linux/linux/fs/cifs/Makefile10
-rw-r--r--release/src/linux/linux/fs/cifs/README356
-rw-r--r--release/src/linux/linux/fs/cifs/TODO106
-rw-r--r--release/src/linux/linux/fs/cifs/asn1.c614
-rw-r--r--release/src/linux/linux/fs/cifs/cifs_debug.c797
-rw-r--r--release/src/linux/linux/fs/cifs/cifs_debug.h66
-rw-r--r--release/src/linux/linux/fs/cifs/cifs_fs_sb.h32
-rw-r--r--release/src/linux/linux/fs/cifs/cifs_unicode.c87
-rw-r--r--release/src/linux/linux/fs/cifs/cifs_unicode.h353
-rw-r--r--release/src/linux/linux/fs/cifs/cifs_uniupr.h253
-rw-r--r--release/src/linux/linux/fs/cifs/cifsencrypt.c204
-rw-r--r--release/src/linux/linux/fs/cifs/cifserr.c70
-rw-r--r--release/src/linux/linux/fs/cifs/cifsfs.c769
-rw-r--r--release/src/linux/linux/fs/cifs/cifsfs.h97
-rw-r--r--release/src/linux/linux/fs/cifs/cifsglob.h413
-rw-r--r--release/src/linux/linux/fs/cifs/cifspdu.h1793
-rw-r--r--release/src/linux/linux/fs/cifs/cifsproto.h254
-rw-r--r--release/src/linux/linux/fs/cifs/cifssmb.c3016
-rw-r--r--release/src/linux/linux/fs/cifs/connect.c2925
-rw-r--r--release/src/linux/linux/fs/cifs/dir.c425
-rw-r--r--release/src/linux/linux/fs/cifs/file.c2185
-rw-r--r--release/src/linux/linux/fs/cifs/inode.c1079
-rw-r--r--release/src/linux/linux/fs/cifs/link.c328
-rw-r--r--release/src/linux/linux/fs/cifs/md4.c203
-rw-r--r--release/src/linux/linux/fs/cifs/md5.c363
-rw-r--r--release/src/linux/linux/fs/cifs/md5.h38
-rw-r--r--release/src/linux/linux/fs/cifs/misc.c463
-rw-r--r--release/src/linux/linux/fs/cifs/netmisc.c905
-rw-r--r--release/src/linux/linux/fs/cifs/nterr.c687
-rw-r--r--release/src/linux/linux/fs/cifs/nterr.h556
-rw-r--r--release/src/linux/linux/fs/cifs/ntlmssp.h101
-rw-r--r--release/src/linux/linux/fs/cifs/rfc1002pdu.h79
-rw-r--r--release/src/linux/linux/fs/cifs/smbdes.c408
-rw-r--r--release/src/linux/linux/fs/cifs/smbencrypt.c295
-rw-r--r--release/src/linux/linux/fs/cifs/smberr.c240
-rw-r--r--release/src/linux/linux/fs/cifs/smberr.h113
-rw-r--r--release/src/linux/linux/fs/cifs/transport.c434
-rw-r--r--release/src/linux/linux/fs/nls/Config.in1
-rw-r--r--release/src/linux/linux/fs/squashfs/LzmaDecode.c663
-rw-r--r--release/src/linux/linux/fs/squashfs/LzmaDecode.h100
-rw-r--r--release/src/linux/linux/fs/squashfs/Makefile6
-rw-r--r--release/src/linux/linux/fs/squashfs/inode.c2401
-rw-r--r--release/src/linux/linux/fs/squashfs/squashfs.h85
-rw-r--r--release/src/linux/linux/fs/squashfs/squashfs2_0.c751
49 files changed, 24826 insertions, 930 deletions
diff --git a/release/src/linux/linux/fs/Config.in b/release/src/linux/linux/fs/Config.in
index 1c4628a6..f535df59 100644
--- a/release/src/linux/linux/fs/Config.in
+++ b/release/src/linux/linux/fs/Config.in
@@ -48,13 +48,20 @@ if [ "$CONFIG_JFFS2_FS" = "y" -o "$CONFIG_JFFS2_FS" = "m" ] ; then
fi
tristate 'Compressed ROM file system support' CONFIG_CRAMFS
tristate 'Squashed file system support' CONFIG_SQUASHFS
+if [ "$CONFIG_SQUASHFS" = "y" -o "$CONFIG_SQUASHFS" = "m" ] ; then
+bool 'Additional options for memory constrained systems ' CONFIG_SQUASHFS_EMBEDDED
+fi
+if [ "$CONFIG_SQUASHFS_EMBEDDED" = "y" ] ; then
+int 'Number of fragments cached' CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE 3
+bool 'Use Vmalloc rather than Kmalloc' CONFIG_SQUASHFS_VMALLOC
+fi
bool 'Virtual memory file system support (former shm fs)' CONFIG_TMPFS
define_bool CONFIG_RAMFS y
-if [ "$CONFIG_CRAMFS" = "y" -o "$CONFIG_CRAMFS" = "m" ] ; then
+if [ "$CONFIG_CRAMFS" = "y" -o "$CONFIG_CRAMFS" = "m" -o "$CONFIG_SQUASHFS" = "y" -o "$CONFIG_SQUASHFS" = "m" ] ; then
choice 'Compression method' \
"ZLIB CONFIG_ZLIB_FS_INFLATE \
- LZMA CONFIG_LZMA_FS_INFLATE" ZLIB
+ LZMA CONFIG_LZMA_FS_INFLATE" LZMA
fi
tristate 'ISO 9660 CDROM file system support' CONFIG_ISO9660_FS
@@ -131,6 +138,10 @@ if [ "$CONFIG_NET" = "y" ]; then
define_bool CONFIG_LOCKD_V4 y
fi
+ dep_tristate 'CIFS support (advanced network filesystem for Samba, Window and other CIFS compliant servers)' CONFIG_CIFS $CONFIG_INET
+ dep_mbool ' CIFS statistics' CONFIG_CIFS_STATS $CONFIG_CIFS
+ dep_mbool ' CIFS POSIX Protocol Extensions' CONFIG_CIFS_POSIX $CONFIG_CIFS
+
dep_tristate 'SMB file system support (to mount Windows shares etc.)' CONFIG_SMB_FS $CONFIG_INET
if [ "$CONFIG_SMB_FS" != "n" ]; then
bool ' Use a default NLS' CONFIG_SMB_NLS_DEFAULT
diff --git a/release/src/linux/linux/fs/Makefile b/release/src/linux/linux/fs/Makefile
index 7d05f77f..951a6125 100644
--- a/release/src/linux/linux/fs/Makefile
+++ b/release/src/linux/linux/fs/Makefile
@@ -40,6 +40,7 @@ subdir-$(CONFIG_MSDOS_FS) += msdos
subdir-$(CONFIG_VFAT_FS) += vfat
subdir-$(CONFIG_BFS_FS) += bfs
subdir-$(CONFIG_ISO9660_FS) += isofs
+subdir-$(CONFIG_CIFS) += cifs
subdir-$(CONFIG_DEVFS_FS) += devfs
subdir-$(CONFIG_HFS_FS) += hfs
subdir-$(CONFIG_VXFS_FS) += freevxfs
@@ -67,8 +68,8 @@ subdir-$(CONFIG_REISERFS_FS) += reiserfs
subdir-$(CONFIG_DEVPTS_FS) += devpts
subdir-$(CONFIG_SUN_OPENPROMFS) += openpromfs
subdir-$(CONFIG_BEFS_FS) += befs
-subdir-$(CONFIG_JFS_FS) += jfs
subdir-$(CONFIG_SQUASHFS) += squashfs
+subdir-$(CONFIG_JFS_FS) += jfs
obj-$(CONFIG_BINFMT_AOUT) += binfmt_aout.o
diff --git a/release/src/linux/linux/fs/buffer.c b/release/src/linux/linux/fs/buffer.c
index 9ec1b055..3a691eeb 100644
--- a/release/src/linux/linux/fs/buffer.c
+++ b/release/src/linux/linux/fs/buffer.c
@@ -1824,7 +1824,7 @@ out:
* We may have to extend the file.
*/
-int cont_prepare_write(struct page *page, unsigned offset, unsigned to, get_block_t *get_block, unsigned long *bytes)
+int cont_prepare_write(struct page *page, unsigned offset, unsigned to, get_block_t *get_block, loff_t *bytes)
{
struct address_space *mapping = page->mapping;
struct inode *inode = mapping->host;
@@ -2808,6 +2808,8 @@ void wakeup_bdflush(void)
wake_up_interruptible(&bdflush_wait);
}
+EXPORT_SYMBOL(wakeup_bdflush);
+
/*
* Here we attempt to write back old buffers. We also try to flush inodes
* and supers as well, since this function is essentially "update", and
@@ -3009,4 +3011,3 @@ static int __init bdflush_init(void)
}
module_init(bdflush_init)
-
diff --git a/release/src/linux/linux/fs/cifs/AUTHORS b/release/src/linux/linux/fs/cifs/AUTHORS
new file mode 100644
index 00000000..43a7b653
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/AUTHORS
@@ -0,0 +1,37 @@
+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 the time and test resources to pursue
+this project. Jim McDonough from IBM (and the Samba Team) for his help.
+The IBM Linux JFS team for explaining many esoteric Linux filesystem features.
+Dave Boutcher of IBM Rochester (author of the OS/400 smb/cifs filesystem client)
+for proving years ago that a very good smb/cifs client could be done on a Unix like
+operating system. Volker Lendecke, Andrew Tridgell, Urban Widmark, John Newbigin
+and others for their work on the Linux smbfs module over the years. 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
+
+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.
+
+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/release/src/linux/linux/fs/cifs/CHANGES b/release/src/linux/linux/fs/cifs/CHANGES
new file mode 100644
index 00000000..3f166375
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/CHANGES
@@ -0,0 +1,572 @@
+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 overrride 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 prototocol 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 roepen_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 rumber 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 exentions) 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/release/src/linux/linux/fs/cifs/Makefile b/release/src/linux/linux/fs/cifs/Makefile
new file mode 100644
index 00000000..892af0ce
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for Linux CIFS VFS client
+#
+O_TARGET := cifs.o
+
+obj-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o cifsencrypt.o
+
+obj-m := $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
diff --git a/release/src/linux/linux/fs/cifs/README b/release/src/linux/linux/fs/cifs/README
new file mode 100644
index 00000000..59a00eea
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/README
@@ -0,0 +1,356 @@
+The CIFS VFS support for Linux supports many advanced network filesystem
+features such as heirarchical 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.
+
+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.5:
+1) Download the kernel (e.g. from http://www.kernel.org or from bitkeeper
+at bk://linux.bkbits.net/linux-2.5) 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
+
+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
+
+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 ea support is required for supporting Linux xattrs.
+Some administrators also change the "map archive" and the "create mask"
+parameters from their default values. Creating special devices (mknod)
+remotely may require specifying a mkdev function to Samba if you are not using
+Samba 3.0.5 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.5, most symlinks to
+files with absolute paths (ie beginning with slash) such as:
+ ln -s /mnt/foo bar
+would be forbidden. Samba 3.0.5 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).
+
+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 the NTLM SMB dialect (which is the most recent, supported
+by Samba and Windows NT version 4, 2000 and XP and many other SMB/CIFS servers)
+Servers must support either "pure-TCP" (port 445 TCP/IP CIFS connections) or RFC
+1001/1002 support for "Netbios-Over-TCP/IP." Neither of these is likely to be a
+problem as most servers support this. IPv6 support is planned for the future.
+
+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 it is 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
+ uid If CIFS Unix extensions are not supported by the server
+ this overrides the default uid for inodes. 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. For servers which do not support
+ the Unix extensions, the default uid (and gid) returned on
+ lookup of existing files is 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. For the uid (gid) of newly
+ created files and directories, ie files created since
+ the last mount of the server share, the expected uid
+ (gid) is cached as as long as the inode remains in
+ memory on the client. 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
+ gid If CIFS Unix extensions are not supported by the server
+ this overrides the default gid for inodes.
+ file_mode If CIFS Unix extensions are not supported by the server
+ this overrides the default mode for file inodes.
+ 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
+ wsize default write size
+ 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.
+ 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.
+
+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 recent 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.
+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:
+MultiuserMount If set to one, more than one CIFS session to
+ the same server ip address can be established
+ if more than one uid accesses the same mount
+ point and if the uids user/password mapping
+ information is available. (default is 0)
+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)
+cifsFYI If set to one, additional debug information is
+ logged to the system error log. (default 0)
+ExtendedSecurity If set to one, SPNEGO session establishment
+ is allowed which enables more advanced
+ secure CIFS session establishment (default 0)
+NTLMV2Enabled If set to one, more secure password hashes
+ are used when the server supports them and
+ when kerberos is not negotiated (default 0)
+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 1 > /proc/fs/cifs/cifsFYI
+
+and for more extensive tracing including the start of smb requests and responses
+
+ echo 1 > /proc/fs/cifs/traceSMB
+
+Three other experimental features are under development and to test
+require enabling an ifdef (e.g. by adding "#define CIFS_FCNTL" in cifsglob.h)
+
+ CONFIG_CIFS_QUOTA
+
+ CONFIG_CIFS_XATTR
+
+ CONFIG_CIFS_FCNTL (fcntl needed for support of directory change
+ notification and perhaps later for file leases)
+
+Per share (per client mount) statistics are available in /proc/fs/cifs/DebugData
+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. Note: NTLMv2 enablement
+will not work since they its implementation is not quite complete yet.
+Do not alter these configuration values unless you are doing specific testing.
+Enabling extended security works to Windows 2000 Workstations and XP but not to
+Windows 2000 server or Samba since it does not usually send "raw NTLMSSP"
+(instead it sends NTLMSSP encapsulated in SPNEGO/GSSAPI, which support is not
+complete in the CIFS VFS yet).
diff --git a/release/src/linux/linux/fs/cifs/TODO b/release/src/linux/linux/fs/cifs/TODO
new file mode 100644
index 00000000..51b230e0
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/TODO
@@ -0,0 +1,106 @@
+version 1.16 May 27, 2004
+
+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 for chmod/chgrp/chown so
+these can be supported for Windows servers
+
+b) Better pam/winbind integration
+
+c) multi-user mounts - multiplexed sessionsetups over single vc
+(ie tcp session) - prettying up needed
+
+d) Kerberos/SPNEGO session setup support - (started)
+
+e) NTLMv2 authentication (mostly implemented)
+
+f) MD5-HMAC signing SMB PDUs when SPNEGO style SessionSetup
+used (Kerberos or NTLMSSP). Signing alreadyimplemented for NTLM
+and raw NTLMSSP already. This is important when enabling
+extended security and mounting to Windows 2003 Servers
+
+f) Directory entry caching relies on a 1 second timer, rather than
+using FindNotify or equivalent. - (started)
+
+g) A few byte range testcases fail due to POSIX vs. Windows/CIFS
+style byte range lock differences
+
+h) quota support
+
+i) support for the Linux 2.5 kernel new feature get_xattr and set_xattr
+which will allow us to expose dos attributes as well as real
+ACLs. This support has been started in the current code, but is
+ifdeffed out.
+
+k) finish writepages support (multi-page write behind for improved
+performance) and syncpage
+
+l) hook lower into the sockets api (as NFS/SunRPC does) to avoid the
+extra copy in/out of the socket buffers in some cases.
+
+m) finish support for IPv6. This is mostly complete but
+needs a simple inet_pton like function to convert ipv6
+addresses in string representation.
+
+o) 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).
+
+p) Improve performance of readpages by sending more than one read
+at a time when 8 pages or more are requested. Evaluate whether
+reads larger than 16K would be helpful.
+
+q) For support of Windows9x/98 we need to retry failed mounts
+to *SMBSERVER (default server name) with the uppercase hostname
+in the RFC1001 session_init request.
+
+r) Add Extended Attributed support (for storing UID/GID info
+to Windows servers)
+
+s) Finish fcntl D_NOTIFY support so kde and gnome file list windows
+will autorefresh
+
+t) Add GUI tool to configure /proc/fs/cifs settings and for display of
+the CIFS statistics
+
+KNOWN BUGS (updated May 27, 2004)
+====================================
+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 but Samba has a bug currently handling
+symlink text beginning with slash
+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) debug connectathon lock test case 10 which fails against
+Samba (may be unmappable due to POSIX to Windows lock model
+differences but worth investigating). Also debug Samba to
+see why lock test case 7 takes longer to complete to Samba
+than to Windows.
+
+Misc testing to do
+==================
+1) check out max path names and max path name components against various server
+types. Try nested symlinks. 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.
+
+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 the recently added NT4 support against various
+NT4 service pack levels.
+
diff --git a/release/src/linux/linux/fs/cifs/asn1.c b/release/src/linux/linux/fs/cifs/asn1.c
new file mode 100644
index 00000000..cf3c0276
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/asn1.c
@@ -0,0 +1,614 @@
+/*
+ * The ASB.1/BER parsing code is derived from ip_nat_snmp_basic.c which was in
+ * turn derived from the gxsnmp package by Gregory McLean & Jochen Friedrich
+ *
+ * Copyright (c) 2000 RP Internet (www.rpi.net.au).
+ *
+ * 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
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifs_debug.h"
+
+/*****************************************************************************
+ *
+ * Basic ASN.1 decoding routines (gxsnmp author Dirk Wisse)
+ *
+ *****************************************************************************/
+
+/* Class */
+#define ASN1_UNI 0 /* Universal */
+#define ASN1_APL 1 /* Application */
+#define ASN1_CTX 2 /* Context */
+#define ASN1_PRV 3 /* Private */
+
+/* Tag */
+#define ASN1_EOC 0 /* End Of Contents or N/A */
+#define ASN1_BOL 1 /* Boolean */
+#define ASN1_INT 2 /* Integer */
+#define ASN1_BTS 3 /* Bit String */
+#define ASN1_OTS 4 /* Octet String */
+#define ASN1_NUL 5 /* Null */
+#define ASN1_OJI 6 /* Object Identifier */
+#define ASN1_OJD 7 /* Object Description */
+#define ASN1_EXT 8 /* External */
+#define ASN1_SEQ 16 /* Sequence */
+#define ASN1_SET 17 /* Set */
+#define ASN1_NUMSTR 18 /* Numerical String */
+#define ASN1_PRNSTR 19 /* Printable String */
+#define ASN1_TEXSTR 20 /* Teletext String */
+#define ASN1_VIDSTR 21 /* Video String */
+#define ASN1_IA5STR 22 /* IA5 String */
+#define ASN1_UNITIM 23 /* Universal Time */
+#define ASN1_GENTIM 24 /* General Time */
+#define ASN1_GRASTR 25 /* Graphical String */
+#define ASN1_VISSTR 26 /* Visible String */
+#define ASN1_GENSTR 27 /* General String */
+
+/* Primitive / Constructed methods*/
+#define ASN1_PRI 0 /* Primitive */
+#define ASN1_CON 1 /* Constructed */
+
+/*
+ * Error codes.
+ */
+#define ASN1_ERR_NOERROR 0
+#define ASN1_ERR_DEC_EMPTY 2
+#define ASN1_ERR_DEC_EOC_MISMATCH 3
+#define ASN1_ERR_DEC_LENGTH_MISMATCH 4
+#define ASN1_ERR_DEC_BADVALUE 5
+
+#define SPNEGO_OID_LEN 7
+#define NTLMSSP_OID_LEN 10
+unsigned long SPNEGO_OID[7] = { 1, 3, 6, 1, 5, 5, 2 };
+unsigned long NTLMSSP_OID[10] = { 1, 3, 6, 1, 4, 1, 311, 2, 2, 10 };
+
+/*
+ * ASN.1 context.
+ */
+struct asn1_ctx {
+ int error; /* Error condition */
+ unsigned char *pointer; /* Octet just to be decoded */
+ unsigned char *begin; /* First octet */
+ unsigned char *end; /* Octet after last octet */
+};
+
+/*
+ * Octet string (not null terminated)
+ */
+struct asn1_octstr {
+ unsigned char *data;
+ unsigned int len;
+};
+
+static void
+asn1_open(struct asn1_ctx *ctx, unsigned char *buf, unsigned int len)
+{
+ ctx->begin = buf;
+ ctx->end = buf + len;
+ ctx->pointer = buf;
+ ctx->error = ASN1_ERR_NOERROR;
+}
+
+static unsigned char
+asn1_octet_decode(struct asn1_ctx *ctx, unsigned char *ch)
+{
+ if (ctx->pointer >= ctx->end) {
+ ctx->error = ASN1_ERR_DEC_EMPTY;
+ return 0;
+ }
+ *ch = *(ctx->pointer)++;
+ return 1;
+}
+
+static unsigned char
+asn1_tag_decode(struct asn1_ctx *ctx, unsigned int *tag)
+{
+ unsigned char ch;
+
+ *tag = 0;
+
+ do {
+ if (!asn1_octet_decode(ctx, &ch))
+ return 0;
+ *tag <<= 7;
+ *tag |= ch & 0x7F;
+ } while ((ch & 0x80) == 0x80);
+ return 1;
+}
+
+static unsigned char
+asn1_id_decode(struct asn1_ctx *ctx,
+ unsigned int *cls, unsigned int *con, unsigned int *tag)
+{
+ unsigned char ch;
+
+ if (!asn1_octet_decode(ctx, &ch))
+ return 0;
+
+ *cls = (ch & 0xC0) >> 6;
+ *con = (ch & 0x20) >> 5;
+ *tag = (ch & 0x1F);
+
+ if (*tag == 0x1F) {
+ if (!asn1_tag_decode(ctx, tag))
+ return 0;
+ }
+ return 1;
+}
+
+static unsigned char
+asn1_length_decode(struct asn1_ctx *ctx, unsigned int *def, unsigned int *len)
+{
+ unsigned char ch, cnt;
+
+ if (!asn1_octet_decode(ctx, &ch))
+ return 0;
+
+ if (ch == 0x80)
+ *def = 0;
+ else {
+ *def = 1;
+
+ if (ch < 0x80)
+ *len = ch;
+ else {
+ cnt = (unsigned char) (ch & 0x7F);
+ *len = 0;
+
+ while (cnt > 0) {
+ if (!asn1_octet_decode(ctx, &ch))
+ return 0;
+ *len <<= 8;
+ *len |= ch;
+ cnt--;
+ }
+ }
+ }
+ return 1;
+}
+
+static unsigned char
+asn1_header_decode(struct asn1_ctx *ctx,
+ unsigned char **eoc,
+ unsigned int *cls, unsigned int *con, unsigned int *tag)
+{
+ unsigned int def, len;
+
+ if (!asn1_id_decode(ctx, cls, con, tag))
+ return 0;
+
+ if (!asn1_length_decode(ctx, &def, &len))
+ return 0;
+
+ if (def)
+ *eoc = ctx->pointer + len;
+ else
+ *eoc = NULL;
+ return 1;
+}
+
+static unsigned char
+asn1_eoc_decode(struct asn1_ctx *ctx, unsigned char *eoc)
+{
+ unsigned char ch;
+
+ if (eoc == 0) {
+ if (!asn1_octet_decode(ctx, &ch))
+ return 0;
+
+ if (ch != 0x00) {
+ ctx->error = ASN1_ERR_DEC_EOC_MISMATCH;
+ return 0;
+ }
+
+ if (!asn1_octet_decode(ctx, &ch))
+ return 0;
+
+ if (ch != 0x00) {
+ ctx->error = ASN1_ERR_DEC_EOC_MISMATCH;
+ return 0;
+ }
+ return 1;
+ } else {
+ if (ctx->pointer != eoc) {
+ ctx->error = ASN1_ERR_DEC_LENGTH_MISMATCH;
+ return 0;
+ }
+ return 1;
+ }
+}
+
+/* static unsigned char asn1_null_decode(struct asn1_ctx *ctx,
+ unsigned char *eoc)
+{
+ ctx->pointer = eoc;
+ return 1;
+}
+
+static unsigned char asn1_long_decode(struct asn1_ctx *ctx,
+ unsigned char *eoc, long *integer)
+{
+ unsigned char ch;
+ unsigned int len;
+
+ if (!asn1_octet_decode(ctx, &ch))
+ return 0;
+
+ *integer = (signed char) ch;
+ len = 1;
+
+ while (ctx->pointer < eoc) {
+ if (++len > sizeof(long)) {
+ ctx->error = ASN1_ERR_DEC_BADVALUE;
+ return 0;
+ }
+
+ if (!asn1_octet_decode(ctx, &ch))
+ return 0;
+
+ *integer <<= 8;
+ *integer |= ch;
+ }
+ return 1;
+}
+
+static unsigned char asn1_uint_decode(struct asn1_ctx *ctx,
+ unsigned char *eoc,
+ unsigned int *integer)
+{
+ unsigned char ch;
+ unsigned int len;
+
+ if (!asn1_octet_decode(ctx, &ch))
+ return 0;
+
+ *integer = ch;
+ if (ch == 0)
+ len = 0;
+ else
+ len = 1;
+
+ while (ctx->pointer < eoc) {
+ if (++len > sizeof(unsigned int)) {
+ ctx->error = ASN1_ERR_DEC_BADVALUE;
+ return 0;
+ }
+
+ if (!asn1_octet_decode(ctx, &ch))
+ return 0;
+
+ *integer <<= 8;
+ *integer |= ch;
+ }
+ return 1;
+}
+
+static unsigned char asn1_ulong_decode(struct asn1_ctx *ctx,
+ unsigned char *eoc,
+ unsigned long *integer)
+{
+ unsigned char ch;
+ unsigned int len;
+
+ if (!asn1_octet_decode(ctx, &ch))
+ return 0;
+
+ *integer = ch;
+ if (ch == 0)
+ len = 0;
+ else
+ len = 1;
+
+ while (ctx->pointer < eoc) {
+ if (++len > sizeof(unsigned long)) {
+ ctx->error = ASN1_ERR_DEC_BADVALUE;
+ return 0;
+ }
+
+ if (!asn1_octet_decode(ctx, &ch))
+ return 0;
+
+ *integer <<= 8;
+ *integer |= ch;
+ }
+ return 1;
+}
+
+static unsigned char
+asn1_octets_decode(struct asn1_ctx *ctx,
+ unsigned char *eoc,
+ unsigned char **octets, unsigned int *len)
+{
+ unsigned char *ptr;
+
+ *len = 0;
+
+ *octets = kmalloc(eoc - ctx->pointer, GFP_ATOMIC);
+ if (*octets == NULL) {
+ return 0;
+ }
+
+ ptr = *octets;
+ while (ctx->pointer < eoc) {
+ if (!asn1_octet_decode(ctx, (unsigned char *) ptr++)) {
+ kfree(*octets);
+ *octets = NULL;
+ return 0;
+ }
+ (*len)++;
+ }
+ return 1;
+} */
+
+static unsigned char
+asn1_subid_decode(struct asn1_ctx *ctx, unsigned long *subid)
+{
+ unsigned char ch;
+
+ *subid = 0;
+
+ do {
+ if (!asn1_octet_decode(ctx, &ch))
+ return 0;
+
+ *subid <<= 7;
+ *subid |= ch & 0x7F;
+ } while ((ch & 0x80) == 0x80);
+ return 1;
+}
+
+static unsigned char
+asn1_oid_decode(struct asn1_ctx *ctx,
+ unsigned char *eoc, unsigned long **oid, unsigned int *len)
+{
+ unsigned long subid;
+ unsigned int size;
+ unsigned long *optr;
+
+ size = eoc - ctx->pointer + 1;
+ *oid = kmalloc(size * sizeof (unsigned long), GFP_ATOMIC);
+ if (*oid == NULL) {
+ return 0;
+ }
+
+ optr = *oid;
+
+ if (!asn1_subid_decode(ctx, &subid)) {
+ kfree(*oid);
+ *oid = NULL;
+ return 0;
+ }
+
+ if (subid < 40) {
+ optr[0] = 0;
+ optr[1] = subid;
+ } else if (subid < 80) {
+ optr[0] = 1;
+ optr[1] = subid - 40;
+ } else {
+ optr[0] = 2;
+ optr[1] = subid - 80;
+ }
+
+ *len = 2;
+ optr += 2;
+
+ while (ctx->pointer < eoc) {
+ if (++(*len) > size) {
+ ctx->error = ASN1_ERR_DEC_BADVALUE;
+ kfree(*oid);
+ *oid = NULL;
+ return 0;
+ }
+
+ if (!asn1_subid_decode(ctx, optr++)) {
+ kfree(*oid);
+ *oid = NULL;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int
+compare_oid(unsigned long *oid1, unsigned int oid1len,
+ unsigned long *oid2, unsigned int oid2len)
+{
+ unsigned int i;
+
+ if (oid1len != oid2len)
+ return 0;
+ else {
+ for (i = 0; i < oid1len; i++) {
+ if (oid1[i] != oid2[i])
+ return 0;
+ }
+ return 1;
+ }
+}
+
+ /* BB check for endian conversion issues here */
+
+int
+decode_negTokenInit(unsigned char *security_blob, int length,
+ enum securityEnum *secType)
+{
+ struct asn1_ctx ctx;
+ unsigned char *end;
+ unsigned char *sequence_end;
+ unsigned long *oid;
+ unsigned int cls, con, tag, oidlen, rc;
+ int use_ntlmssp = FALSE;
+
+ *secType = NTLM; /* BB eventually make Kerberos or NLTMSSP the default */
+
+ /* cifs_dump_mem(" Received SecBlob ", security_blob, length); */
+
+ asn1_open(&ctx, security_blob, length);
+
+ if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
+ cFYI(1, ("Error decoding negTokenInit header "));
+ return 0;
+ } else if ((cls != ASN1_APL) || (con != ASN1_CON)
+ || (tag != ASN1_EOC)) {
+ cFYI(1, ("cls = %d con = %d tag = %d", cls, con, tag));
+ return 0;
+ } else {
+ /* remember to free obj->oid */
+ rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag);
+ if (rc) {
+ if ((tag == ASN1_OJI) && (cls == ASN1_PRI)) {
+ rc = asn1_oid_decode(&ctx, end, &oid, &oidlen);
+ if (rc) {
+ rc = compare_oid(oid, oidlen,
+ SPNEGO_OID,
+ SPNEGO_OID_LEN);
+ kfree(oid);
+ }
+ } else
+ rc = 0;
+ }
+
+ if (!rc) {
+ cFYI(1, ("Error decoding negTokenInit header"));
+ return 0;
+ }
+
+ if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
+ cFYI(1, ("Error decoding negTokenInit "));
+ return 0;
+ } else if ((cls != ASN1_CTX) || (con != ASN1_CON)
+ || (tag != ASN1_EOC)) {
+ cFYI(1,("cls = %d con = %d tag = %d end = %p (%d) exit 0",
+ cls, con, tag, end, *end));
+ return 0;
+ }
+
+ if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
+ cFYI(1, ("Error decoding negTokenInit "));
+ return 0;
+ } else if ((cls != ASN1_UNI) || (con != ASN1_CON)
+ || (tag != ASN1_SEQ)) {
+ cFYI(1,("cls = %d con = %d tag = %d end = %p (%d) exit 1",
+ cls, con, tag, end, *end));
+ return 0;
+ }
+
+ if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
+ cFYI(1, ("Error decoding 2nd part of negTokenInit "));
+ return 0;
+ } else if ((cls != ASN1_CTX) || (con != ASN1_CON)
+ || (tag != ASN1_EOC)) {
+ cFYI(1,
+ ("cls = %d con = %d tag = %d end = %p (%d) exit 0",
+ cls, con, tag, end, *end));
+ return 0;
+ }
+
+ if (asn1_header_decode
+ (&ctx, &sequence_end, &cls, &con, &tag) == 0) {
+ cFYI(1, ("Error decoding 2nd part of negTokenInit "));
+ return 0;
+ } else if ((cls != ASN1_UNI) || (con != ASN1_CON)
+ || (tag != ASN1_SEQ)) {
+ cFYI(1,
+ ("cls = %d con = %d tag = %d end = %p (%d) exit 1",
+ cls, con, tag, end, *end));
+ return 0;
+ }
+
+ while (!asn1_eoc_decode(&ctx, sequence_end)) {
+ rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag);
+ if (!rc) {
+ cFYI(1,
+ ("Error 1 decoding negTokenInit header exit 2"));
+ return 0;
+ }
+ if ((tag == ASN1_OJI) && (con == ASN1_PRI)) {
+ asn1_oid_decode(&ctx, end, &oid, &oidlen);
+ cFYI(1,
+ ("OID len = %d oid = 0x%lx 0x%lx 0x%lx 0x%lx",
+ oidlen, *oid, *(oid + 1), *(oid + 2),
+ *(oid + 3)));
+ rc = compare_oid(oid, oidlen, NTLMSSP_OID,
+ NTLMSSP_OID_LEN);
+ kfree(oid);
+ if (rc)
+ use_ntlmssp = TRUE;
+ } else {
+ cFYI(1,("This should be an oid what is going on? "));
+ }
+ }
+
+ if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
+ cFYI(1,
+ ("Error decoding last part of negTokenInit exit 3"));
+ return 0;
+ } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) { /* tag = 3 indicating mechListMIC */
+ cFYI(1,
+ ("Exit 4 cls = %d con = %d tag = %d end = %p (%d)",
+ cls, con, tag, end, *end));
+ return 0;
+ }
+ if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
+ cFYI(1,
+ ("Error decoding last part of negTokenInit exit 5"));
+ return 0;
+ } else if ((cls != ASN1_UNI) || (con != ASN1_CON)
+ || (tag != ASN1_SEQ)) {
+ cFYI(1,
+ ("Exit 6 cls = %d con = %d tag = %d end = %p (%d)",
+ cls, con, tag, end, *end));
+ }
+
+ if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
+ cFYI(1,
+ ("Error decoding last part of negTokenInit exit 7"));
+ return 0;
+ } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) {
+ cFYI(1,
+ ("Exit 8 cls = %d con = %d tag = %d end = %p (%d)",
+ cls, con, tag, end, *end));
+ return 0;
+ }
+ if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
+ cFYI(1,
+ ("Error decoding last part of negTokenInit exit 9"));
+ return 0;
+ } else if ((cls != ASN1_UNI) || (con != ASN1_PRI)
+ || (tag != ASN1_GENSTR)) {
+ cFYI(1,
+ ("Exit 10 cls = %d con = %d tag = %d end = %p (%d)",
+ cls, con, tag, end, *end));
+ return 0;
+ }
+ cFYI(1, ("Need to call asn1_octets_decode() function for this %s", ctx.pointer)); /* is this UTF-8 or ASCII? */
+ }
+
+ /* if (use_kerberos)
+ *secType = Kerberos
+ else */
+ if (use_ntlmssp) {
+ *secType = NTLMSSP;
+ }
+
+ return 1;
+}
diff --git a/release/src/linux/linux/fs/cifs/cifs_debug.c b/release/src/linux/linux/fs/cifs/cifs_debug.c
new file mode 100644
index 00000000..bdcca609
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/cifs_debug.c
@@ -0,0 +1,797 @@
+/*
+ * fs/cifs_debug.c
+ *
+ * Copyright (C) International Business Machines Corp., 2000,2003
+ *
+ * Modified by Steve French (sfrench@us.ibm.com)
+ *
+ * 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
+ */
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_debug.h"
+
+void
+cifs_dump_mem(char *label, void *data, int length)
+{
+ int i, j;
+ int *intptr = data;
+ char *charptr = data;
+ char buf[10], line[80];
+
+ printk(KERN_DEBUG "%s: dump of %d bytes of data at 0x%p\n\n",
+ label, length, data);
+ for (i = 0; i < length; i += 16) {
+ line[0] = 0;
+ for (j = 0; (j < 4) && (i + j * 4 < length); j++) {
+ sprintf(buf, " %08x", intptr[i / 4 + j]);
+ strcat(line, buf);
+ }
+ buf[0] = ' ';
+ buf[2] = 0;
+ for (j = 0; (j < 16) && (i + j < length); j++) {
+ buf[1] = isprint(charptr[i + j]) ? charptr[i + j] : '.';
+ strcat(line, buf);
+ }
+ printk(KERN_DEBUG "%s\n", line);
+ }
+}
+
+#ifdef CONFIG_PROC_FS
+int
+cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
+ int count, int *eof, void *data)
+{
+ struct list_head *tmp;
+ struct list_head *tmp1;
+ struct mid_q_entry * mid_entry;
+ struct cifsSesInfo *ses;
+ struct cifsTconInfo *tcon;
+ int i;
+ int length = 0;
+ char * original_buf = buf;
+
+ *beginBuffer = buf + offset;
+
+
+ length =
+ sprintf(buf,
+ "Display Internal CIFS Data Structures for Debugging\n"
+ "---------------------------------------------------\n");
+ buf += length;
+
+ length = sprintf(buf, "Servers:\n");
+ buf += length;
+
+ i = 0;
+ read_lock(&GlobalSMBSeslock);
+ list_for_each(tmp, &GlobalSMBSessionList) {
+ i++;
+ ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
+ length =
+ sprintf(buf,
+ "\n%d) Name: %s Domain: %s Mounts: %d ServerOS: %s \n\tServerNOS: %s\tCapabilities: 0x%x\n\tSMB session status: %d\tTCP status: %d",
+ i, ses->serverName, ses->serverDomain, atomic_read(&ses->inUse),
+ ses->serverOS, ses->serverNOS, ses->capabilities,ses->status,ses->server->tcpStatus);
+ buf += length;
+ if(ses->server) {
+ buf += sprintf(buf, "\n\tLocal Users To Server: %d SecMode: 0x%x Req Active: %d",
+ atomic_read(&ses->server->socketUseCount),
+ ses->server->secMode,
+ atomic_read(&ses->server->inFlight));
+
+ length = sprintf(buf, "\nMIDs: \n");
+ buf += length;
+
+ spin_lock(&GlobalMid_Lock);
+ list_for_each(tmp1, &ses->server->pending_mid_q) {
+ mid_entry = list_entry(tmp1, struct
+ mid_q_entry,
+ qhead);
+ if(mid_entry) {
+ length = sprintf(buf,"State: %d com: %d pid: %d tsk: %p mid %d\n",mid_entry->midState,mid_entry->command,mid_entry->pid,mid_entry->tsk,mid_entry->mid);
+ buf += length;
+ }
+ }
+ spin_unlock(&GlobalMid_Lock);
+ }
+
+ }
+ read_unlock(&GlobalSMBSeslock);
+ sprintf(buf, "\n");
+ buf++;
+
+ length = sprintf(buf, "\nShares:\n");
+ buf += length;
+
+ i = 0;
+ read_lock(&GlobalSMBSeslock);
+ list_for_each(tmp, &GlobalTreeConnectionList) {
+ i++;
+ tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
+ length =
+ sprintf(buf,
+ "\n%d) %s Uses: %d Type: %s Characteristics: 0x%x Attributes: 0x%x\nPathComponentMax: %d Status: %d",
+ i, tcon->treeName,
+ atomic_read(&tcon->useCount),
+ tcon->nativeFileSystem,
+ tcon->fsDevInfo.DeviceCharacteristics,
+ tcon->fsAttrInfo.Attributes,
+ tcon->fsAttrInfo.MaxPathNameComponentLength,tcon->tidStatus);
+ buf += length;
+ if (tcon->fsDevInfo.DeviceType == FILE_DEVICE_DISK)
+ length = sprintf(buf, " type: DISK ");
+ else if (tcon->fsDevInfo.DeviceType == FILE_DEVICE_CD_ROM)
+ length = sprintf(buf, " type: CDROM ");
+ else
+ length =
+ sprintf(buf, " type: %d ",
+ tcon->fsDevInfo.DeviceType);
+ buf += length;
+ if(tcon->tidStatus == CifsNeedReconnect) {
+ buf += sprintf(buf, "\tDISCONNECTED ");
+ length += 14;
+ }
+ }
+ read_unlock(&GlobalSMBSeslock);
+
+ length = sprintf(buf, "\n");
+ buf += length;
+
+ /* BB add code to dump additional info such as TCP session info now */
+ /* Now calculate total size of returned data */
+ length = buf - original_buf;
+
+ if(offset + count >= length)
+ *eof = 1;
+ if(length < offset) {
+ *eof = 1;
+ return 0;
+ } else {
+ length = length - offset;
+ }
+ if (length > count)
+ length = count;
+
+ return length;
+}
+
+#ifdef CONFIG_CIFS_STATS
+int
+cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
+ int count, int *eof, void *data)
+{
+ int item_length,i,length;
+ struct list_head *tmp;
+ struct cifsTconInfo *tcon;
+
+ *beginBuffer = buf + offset;
+
+ length = sprintf(buf,
+ "Resources in use\nCIFS Session: %d\n",
+ sesInfoAllocCount.counter);
+ buf += length;
+ item_length =
+ sprintf(buf,"Share (unique mount targets): %d\n",
+ tconInfoAllocCount.counter);
+ length += item_length;
+ buf += item_length;
+ item_length =
+ sprintf(buf,"SMB Request/Response Buffer: %d\n",
+ bufAllocCount.counter);
+ length += item_length;
+ buf += item_length;
+ item_length =
+ sprintf(buf,"Operations (MIDs): %d\n",
+ midCount.counter);
+ length += item_length;
+ buf += item_length;
+ item_length = sprintf(buf,
+ "\n%d session %d share reconnects\n",
+ tcpSesReconnectCount.counter,tconInfoReconnectCount.counter);
+ length += item_length;
+ buf += item_length;
+
+ item_length = sprintf(buf,
+ "Total vfs operations: %d maximum at one time: %d\n",
+ GlobalCurrentXid,GlobalMaxActiveXid);
+ length += item_length;
+ buf += item_length;
+
+ i = 0;
+ read_lock(&GlobalSMBSeslock);
+ list_for_each(tmp, &GlobalTreeConnectionList) {
+ i++;
+ tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
+ item_length = sprintf(buf,"\n%d) %s",i, tcon->treeName);
+ buf += item_length;
+ length += item_length;
+ if(tcon->tidStatus == CifsNeedReconnect) {
+ buf += sprintf(buf, "\tDISCONNECTED ");
+ length += 14;
+ }
+ item_length = sprintf(buf,"\nSMBs: %d Oplock Breaks: %d",
+ atomic_read(&tcon->num_smbs_sent),
+ atomic_read(&tcon->num_oplock_brks));
+ buf += item_length;
+ length += item_length;
+ item_length = sprintf(buf,"\nReads: %d Bytes %lld",
+ atomic_read(&tcon->num_reads),
+ (long long)(tcon->bytes_read));
+ buf += item_length;
+ length += item_length;
+ item_length = sprintf(buf,"\nWrites: %d Bytes: %lld",
+ atomic_read(&tcon->num_writes),
+ (long long)(tcon->bytes_written));
+ buf += item_length;
+ length += item_length;
+ item_length = sprintf(buf,
+ "\nOpens: %d Deletes: %d\nMkdirs: %d Rmdirs: %d",
+ atomic_read(&tcon->num_opens),
+ atomic_read(&tcon->num_deletes),
+ atomic_read(&tcon->num_mkdirs),
+ atomic_read(&tcon->num_rmdirs));
+ buf += item_length;
+ length += item_length;
+ item_length = sprintf(buf,
+ "\nRenames: %d T2 Renames %d",
+ atomic_read(&tcon->num_renames),
+ atomic_read(&tcon->num_t2renames));
+ buf += item_length;
+ length += item_length;
+ }
+ read_unlock(&GlobalSMBSeslock);
+
+ buf += sprintf(buf,"\n");
+ length++;
+
+ if(offset + count >= length)
+ *eof = 1;
+ if(length < offset) {
+ *eof = 1;
+ return 0;
+ } else {
+ length = length - offset;
+ }
+ if (length > count)
+ length = count;
+
+ return length;
+}
+#endif
+
+struct proc_dir_entry *proc_fs_cifs;
+read_proc_t cifs_txanchor_read;
+static read_proc_t cifsFYI_read;
+static write_proc_t cifsFYI_write;
+static read_proc_t oplockEnabled_read;
+static write_proc_t oplockEnabled_write;
+static read_proc_t lookupFlag_read;
+static write_proc_t lookupFlag_write;
+static read_proc_t traceSMB_read;
+static write_proc_t traceSMB_write;
+static read_proc_t multiuser_mount_read;
+static write_proc_t multiuser_mount_write;
+static read_proc_t extended_security_read;
+static write_proc_t extended_security_write;
+static read_proc_t ntlmv2_enabled_read;
+static write_proc_t ntlmv2_enabled_write;
+static read_proc_t packet_signing_enabled_read;
+static write_proc_t packet_signing_enabled_write;
+static read_proc_t quotaEnabled_read;
+static write_proc_t quotaEnabled_write;
+static read_proc_t linuxExtensionsEnabled_read;
+static write_proc_t linuxExtensionsEnabled_write;
+
+void
+cifs_proc_init(void)
+{
+ struct proc_dir_entry *pde;
+
+ proc_fs_cifs = proc_mkdir("cifs", proc_root_fs);
+ if (proc_fs_cifs == NULL)
+ return;
+
+ proc_fs_cifs->owner = THIS_MODULE;
+ create_proc_read_entry("DebugData", 0, proc_fs_cifs,
+ cifs_debug_data_read, NULL);
+
+#ifdef CONFIG_CIFS_STATS
+ create_proc_read_entry("Stats", 0, proc_fs_cifs,
+ cifs_stats_read, NULL);
+#endif
+ pde = create_proc_read_entry("cifsFYI", 0, proc_fs_cifs,
+ cifsFYI_read, NULL);
+ if (pde)
+ pde->write_proc = cifsFYI_write;
+
+ pde =
+ create_proc_read_entry("traceSMB", 0, proc_fs_cifs,
+ traceSMB_read, NULL);
+ if (pde)
+ pde->write_proc = traceSMB_write;
+
+ pde = create_proc_read_entry("OplockEnabled", 0, proc_fs_cifs,
+ oplockEnabled_read, NULL);
+ if (pde)
+ pde->write_proc = oplockEnabled_write;
+
+ pde = create_proc_read_entry("QuotaEnabled", 0, proc_fs_cifs,
+ quotaEnabled_read, NULL);
+ if (pde)
+ pde->write_proc = quotaEnabled_write;
+
+ pde = create_proc_read_entry("LinuxExtensionsEnabled", 0, proc_fs_cifs,
+ linuxExtensionsEnabled_read, NULL);
+ if (pde)
+ pde->write_proc = linuxExtensionsEnabled_write;
+
+ pde =
+ create_proc_read_entry("MultiuserMount", 0, proc_fs_cifs,
+ multiuser_mount_read, NULL);
+ if (pde)
+ pde->write_proc = multiuser_mount_write;
+
+ pde =
+ create_proc_read_entry("ExtendedSecurity", 0, proc_fs_cifs,
+ extended_security_read, NULL);
+ if (pde)
+ pde->write_proc = extended_security_write;
+
+ pde =
+ create_proc_read_entry("LookupCacheEnabled", 0, proc_fs_cifs,
+ lookupFlag_read, NULL);
+ if (pde)
+ pde->write_proc = lookupFlag_write;
+
+ pde =
+ create_proc_read_entry("NTLMV2Enabled", 0, proc_fs_cifs,
+ ntlmv2_enabled_read, NULL);
+ if (pde)
+ pde->write_proc = ntlmv2_enabled_write;
+
+ pde =
+ create_proc_read_entry("PacketSigningEnabled", 0, proc_fs_cifs,
+ packet_signing_enabled_read, NULL);
+ if (pde)
+ pde->write_proc = packet_signing_enabled_write;
+}
+
+void
+cifs_proc_clean(void)
+{
+ if (proc_fs_cifs == NULL)
+ return;
+
+ remove_proc_entry("DebugData", proc_fs_cifs);
+ remove_proc_entry("cifsFYI", proc_fs_cifs);
+ remove_proc_entry("traceSMB", proc_fs_cifs);
+#ifdef CONFIG_CIFS_STATS
+ remove_proc_entry("Stats", proc_fs_cifs);
+#endif
+ remove_proc_entry("MultiuserMount", proc_fs_cifs);
+ remove_proc_entry("OplockEnabled", proc_fs_cifs);
+ remove_proc_entry("NTLMV2Enabled",proc_fs_cifs);
+ remove_proc_entry("ExtendedSecurity",proc_fs_cifs);
+ remove_proc_entry("PacketSigningEnabled",proc_fs_cifs);
+ remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs);
+ remove_proc_entry("QuotaEnabled",proc_fs_cifs);
+ remove_proc_entry("LookupCacheEnabled",proc_fs_cifs);
+ remove_proc_entry("cifs", proc_root_fs);
+}
+
+static int
+cifsFYI_read(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ int len;
+
+ len = sprintf(page, "%d\n", cifsFYI);
+
+ len -= off;
+ *start = page + off;
+
+ if (len > count)
+ len = count;
+ else
+ *eof = 1;
+
+ if (len < 0)
+ len = 0;
+
+ return len;
+}
+static int
+cifsFYI_write(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ char c;
+ int rc;
+
+ rc = get_user(c, buffer);
+ if (rc)
+ return rc;
+ if (c == '0' || c == 'n' || c == 'N')
+ cifsFYI = 0;
+ else if (c == '1' || c == 'y' || c == 'Y')
+ cifsFYI = 1;
+
+ return count;
+}
+
+static int
+oplockEnabled_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len;
+
+ len = sprintf(page, "%d\n", oplockEnabled);
+
+ len -= off;
+ *start = page + off;
+
+ if (len > count)
+ len = count;
+ else
+ *eof = 1;
+
+ if (len < 0)
+ len = 0;
+
+ return len;
+}
+static int
+oplockEnabled_write(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ char c;
+ int rc;
+
+ rc = get_user(c, buffer);
+ if (rc)
+ return rc;
+ if (c == '0' || c == 'n' || c == 'N')
+ oplockEnabled = 0;
+ else if (c == '1' || c == 'y' || c == 'Y')
+ oplockEnabled = 1;
+
+ return count;
+}
+
+static int
+quotaEnabled_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len;
+
+ len = sprintf(page, "%d\n", quotaEnabled);
+/* could also check if quotas are enabled in kernel
+ as a whole first */
+ len -= off;
+ *start = page + off;
+
+ if (len > count)
+ len = count;
+ else
+ *eof = 1;
+
+ if (len < 0)
+ len = 0;
+
+ return len;
+}
+static int
+quotaEnabled_write(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ char c;
+ int rc;
+
+ rc = get_user(c, buffer);
+ if (rc)
+ return rc;
+ if (c == '0' || c == 'n' || c == 'N')
+ quotaEnabled = 0;
+ else if (c == '1' || c == 'y' || c == 'Y')
+ quotaEnabled = 1;
+
+ return count;
+}
+
+static int
+linuxExtensionsEnabled_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len;
+
+ len = sprintf(page, "%d\n", linuxExtEnabled);
+/* could also check if quotas are enabled in kernel
+ as a whole first */
+ len -= off;
+ *start = page + off;
+
+ if (len > count)
+ len = count;
+ else
+ *eof = 1;
+
+ if (len < 0)
+ len = 0;
+
+ return len;
+}
+static int
+linuxExtensionsEnabled_write(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ char c;
+ int rc;
+
+ rc = get_user(c, buffer);
+ if (rc)
+ return rc;
+ if (c == '0' || c == 'n' || c == 'N')
+ linuxExtEnabled = 0;
+ else if (c == '1' || c == 'y' || c == 'Y')
+ linuxExtEnabled = 1;
+
+ return count;
+}
+
+
+static int
+lookupFlag_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len;
+
+ len = sprintf(page, "%d\n", lookupCacheEnabled);
+
+ len -= off;
+ *start = page + off;
+
+ if (len > count)
+ len = count;
+ else
+ *eof = 1;
+
+ if (len < 0)
+ len = 0;
+
+ return len;
+}
+static int
+lookupFlag_write(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ char c;
+ int rc;
+
+ rc = get_user(c, buffer);
+ if (rc)
+ return rc;
+ if (c == '0' || c == 'n' || c == 'N')
+ lookupCacheEnabled = 0;
+ else if (c == '1' || c == 'y' || c == 'Y')
+ lookupCacheEnabled = 1;
+
+ return count;
+}
+static int
+traceSMB_read(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ int len;
+
+ len = sprintf(page, "%d\n", traceSMB);
+
+ len -= off;
+ *start = page + off;
+
+ if (len > count)
+ len = count;
+ else
+ *eof = 1;
+
+ if (len < 0)
+ len = 0;
+
+ return len;
+}
+static int
+traceSMB_write(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ char c;
+ int rc;
+
+ rc = get_user(c, buffer);
+ if (rc)
+ return rc;
+ if (c == '0' || c == 'n' || c == 'N')
+ traceSMB = 0;
+ else if (c == '1' || c == 'y' || c == 'Y')
+ traceSMB = 1;
+
+ return count;
+}
+
+static int
+multiuser_mount_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len;
+
+ len = sprintf(page, "%d\n", multiuser_mount);
+
+ len -= off;
+ *start = page + off;
+
+ if (len > count)
+ len = count;
+ else
+ *eof = 1;
+
+ if (len < 0)
+ len = 0;
+
+ return len;
+}
+static int
+multiuser_mount_write(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ char c;
+ int rc;
+
+ rc = get_user(c, buffer);
+ if (rc)
+ return rc;
+ if (c == '0' || c == 'n' || c == 'N')
+ multiuser_mount = 0;
+ else if (c == '1' || c == 'y' || c == 'Y')
+ multiuser_mount = 1;
+
+ return count;
+}
+
+static int
+extended_security_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len;
+
+ len = sprintf(page, "%d\n", extended_security);
+
+ len -= off;
+ *start = page + off;
+
+ if (len > count)
+ len = count;
+ else
+ *eof = 1;
+
+ if (len < 0)
+ len = 0;
+
+ return len;
+}
+static int
+extended_security_write(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ char c;
+ int rc;
+
+ rc = get_user(c, buffer);
+ if (rc)
+ return rc;
+ if (c == '0' || c == 'n' || c == 'N')
+ extended_security = 0;
+ else if (c == '1' || c == 'y' || c == 'Y')
+ extended_security = 1;
+
+ return count;
+}
+
+static int
+ntlmv2_enabled_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len;
+
+ len = sprintf(page, "%d\n", ntlmv2_support);
+
+ len -= off;
+ *start = page + off;
+
+ if (len > count)
+ len = count;
+ else
+ *eof = 1;
+
+ if (len < 0)
+ len = 0;
+
+ return len;
+}
+static int
+ntlmv2_enabled_write(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ char c;
+ int rc;
+
+ rc = get_user(c, buffer);
+ if (rc)
+ return rc;
+ if (c == '0' || c == 'n' || c == 'N')
+ ntlmv2_support = 0;
+ else if (c == '1' || c == 'y' || c == 'Y')
+ ntlmv2_support = 1;
+
+ return count;
+}
+
+static int
+packet_signing_enabled_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len;
+
+ len = sprintf(page, "%d\n", sign_CIFS_PDUs);
+
+ len -= off;
+ *start = page + off;
+
+ if (len > count)
+ len = count;
+ else
+ *eof = 1;
+
+ if (len < 0)
+ len = 0;
+
+ return len;
+}
+static int
+packet_signing_enabled_write(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ char c;
+ int rc;
+
+ rc = get_user(c, buffer);
+ if (rc)
+ return rc;
+ if (c == '0' || c == 'n' || c == 'N')
+ sign_CIFS_PDUs = 0;
+ else if (c == '1' || c == 'y' || c == 'Y')
+ sign_CIFS_PDUs = 1;
+ else if (c == '2')
+ sign_CIFS_PDUs = 2;
+
+ return count;
+}
+
+
+#endif
diff --git a/release/src/linux/linux/fs/cifs/cifs_debug.h b/release/src/linux/linux/fs/cifs/cifs_debug.h
new file mode 100644
index 00000000..bf24d282
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/cifs_debug.h
@@ -0,0 +1,66 @@
+/*
+ *
+ * Copyright (c) International Business Machines Corp., 2000,2002
+ * Modified by Steve French (sfrench@us.ibm.com)
+ *
+ * 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
+ *
+*/
+#define CIFS_DEBUG /* BB temporary */
+
+#ifndef _H_CIFS_DEBUG
+#define _H_CIFS_DEBUG
+
+void cifs_dump_mem(char *label, void *data, int length);
+extern int traceSMB; /* flag which enables the function below */
+void dump_smb(struct smb_hdr *, int);
+
+/*
+ * debug ON
+ * --------
+ */
+#ifdef CIFS_DEBUG
+
+
+/* information message: e.g., configuration, major event */
+extern int cifsFYI;
+#define cifsfyi(format,arg...) if (cifsFYI) printk(KERN_DEBUG " " __FILE__ ": " format "\n" "" , ## arg)
+
+#define cFYI(button,prspec) if (button) cifsfyi prspec
+
+#define cifswarn(format, arg...) printk(KERN_WARNING ": " format "\n" , ## arg)
+
+/* debug event message: */
+extern int cifsERROR;
+
+#define cEVENT(format,arg...) if (cifsERROR) printk(KERN_EVENT __FILE__ ": " format "\n" , ## arg)
+
+/* error event message: e.g., i/o error */
+#define cifserror(format,arg...) if (cifsERROR) printk(KERN_ERR " CIFS VFS: " format "\n" "" , ## arg)
+
+#define cERROR(button, prspec) if (button) cifserror prspec
+
+/*
+ * debug OFF
+ * ---------
+ */
+#else /* _CIFS_DEBUG */
+#define cERROR(button,prspec)
+#define cEVENT(format,arg...)
+#define cFYI(button, prspec)
+#define cifserror(format,arg...)
+#endif /* _CIFS_DEBUG */
+
+#endif /* _H_CIFS_DEBUG */
diff --git a/release/src/linux/linux/fs/cifs/cifs_fs_sb.h b/release/src/linux/linux/fs/cifs/cifs_fs_sb.h
new file mode 100644
index 00000000..8007c2e9
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/cifs_fs_sb.h
@@ -0,0 +1,32 @@
+/*
+ * fs/cifs/cifs_fs_sb.h
+ *
+ * Copyright (c) International Business Machines Corp., 2002
+ * Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU Lesser General Public License for more details.
+ *
+ */
+#ifndef _CIFS_FS_SB_H
+#define _CIFS_FS_SB_H
+
+struct cifs_sb_info {
+ struct cifsTconInfo *tcon; /* primary mount */
+ struct list_head nested_tcon_q;
+ struct nls_table *local_nls;
+ unsigned int rsize;
+ unsigned int wsize;
+ uid_t mnt_uid;
+ gid_t mnt_gid;
+ mode_t mnt_file_mode;
+ mode_t mnt_dir_mode;
+};
+#endif /* _CIFS_FS_SB_H */
diff --git a/release/src/linux/linux/fs/cifs/cifs_unicode.c b/release/src/linux/linux/fs/cifs/cifs_unicode.c
new file mode 100644
index 00000000..a17adf4c
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/cifs_unicode.c
@@ -0,0 +1,87 @@
+/*
+ * fs/cifs/cifs_unicode.c
+ *
+ * Copyright (c) International Business Machines Corp., 2000,2002
+ * Modified by Steve French (sfrench@us.ibm.com)
+ *
+ * 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
+ */
+#include <linux/fs.h>
+#include "cifs_unicode.h"
+#include "cifs_uniupr.h"
+#include "cifspdu.h"
+#include "cifs_debug.h"
+
+/*
+ * NAME: cifs_strfromUCS()
+ *
+ * FUNCTION: Convert little-endian unicode string to character string
+ *
+ */
+int
+cifs_strfromUCS_le(char *to, const wchar_t * from, /* LITTLE ENDIAN */
+ int len, const struct nls_table *codepage)
+{
+ int i;
+ int outlen = 0;
+
+ for (i = 0; (i < len) && from[i]; i++) {
+ int charlen;
+ /* 2.4.0 kernel or greater */
+ charlen =
+ codepage->uni2char(le16_to_cpu(from[i]), &to[outlen],
+ NLS_MAX_CHARSET_SIZE);
+ if (charlen > 0) {
+ outlen += charlen;
+ } else {
+ to[outlen++] = '?';
+ }
+ }
+ to[outlen] = 0;
+ return outlen;
+}
+
+/*
+ * NAME: cifs_strtoUCS()
+ *
+ * FUNCTION: Convert character string to unicode string
+ *
+ */
+int
+cifs_strtoUCS(wchar_t * to, const char *from, int len,
+ const struct nls_table *codepage)
+{
+ int charlen;
+ int i;
+
+ for (i = 0; len && *from; i++, from += charlen, len -= charlen) {
+
+ /* works for 2.4.0 kernel or later */
+ charlen = codepage->char2uni(from, len, &to[i]);
+ if (charlen < 1) {
+ cERROR(1,
+ ("cifs_strtoUCS: char2uni returned %d",
+ charlen));
+ to[i] = cpu_to_le16(0x003f); /* a question mark */
+ charlen = 1;
+ }
+ to[i] = cpu_to_le16(to[i]);
+
+ }
+
+ to[i] = 0;
+ return i;
+}
+
diff --git a/release/src/linux/linux/fs/cifs/cifs_unicode.h b/release/src/linux/linux/fs/cifs/cifs_unicode.h
new file mode 100644
index 00000000..da8dde96
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/cifs_unicode.h
@@ -0,0 +1,353 @@
+/*
+ * cifs_unicode: Unicode kernel case support
+ *
+ * Function:
+ * Convert a unicode character to upper or lower case using
+ * compressed tables.
+ *
+ * Copyright (c) International Business Machines Corp., 2000,2002
+ *
+ * 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
+ *
+ *
+ * Notes:
+ * These APIs are based on the C library functions. The semantics
+ * should match the C functions but with expanded size operands.
+ *
+ * The upper/lower functions are based on a table created by mkupr.
+ * This is a compressed table of upper and lower case conversion.
+ *
+ */
+
+#include <asm/byteorder.h>
+#include <linux/types.h>
+#include <linux/nls.h>
+
+#define UNIUPR_NOLOWER /* Example to not expand lower case tables */
+
+/* Just define what we want from uniupr.h. We don't want to define the tables
+ * in each source file.
+ */
+#ifndef UNICASERANGE_DEFINED
+struct UniCaseRange {
+ wchar_t start;
+ wchar_t end;
+ signed char *table;
+};
+#endif /* UNICASERANGE_DEFINED */
+
+#ifndef UNIUPR_NOUPPER
+extern signed char CifsUniUpperTable[512];
+extern const struct UniCaseRange CifsUniUpperRange[];
+#endif /* UNIUPR_NOUPPER */
+
+#ifndef UNIUPR_NOLOWER
+extern signed char UniLowerTable[512];
+extern struct UniCaseRange UniLowerRange[];
+#endif /* UNIUPR_NOLOWER */
+
+#ifdef __KERNEL__
+int cifs_strfromUCS_le(char *, const wchar_t *, int, const struct nls_table *);
+int cifs_strtoUCS(wchar_t *, const char *, int, const struct nls_table *);
+#endif
+
+/*
+ * UniStrcat: Concatenate the second string to the first
+ *
+ * Returns:
+ * Address of the first string
+ */
+static inline wchar_t *
+UniStrcat(wchar_t * ucs1, const wchar_t * ucs2)
+{
+ wchar_t *anchor = ucs1; /* save a pointer to start of ucs1 */
+
+ while (*ucs1++) ; /* To end of first string */
+ ucs1--; /* Return to the null */
+ while ((*ucs1++ = *ucs2++)) ; /* copy string 2 over */
+ return anchor;
+}
+
+/*
+ * UniStrchr: Find a character in a string
+ *
+ * Returns:
+ * Address of first occurrence of character in string
+ * or NULL if the character is not in the string
+ */
+static inline wchar_t *
+UniStrchr(const wchar_t * ucs, wchar_t uc)
+{
+ while ((*ucs != uc) && *ucs)
+ ucs++;
+
+ if (*ucs == uc)
+ return (wchar_t *) ucs;
+ return NULL;
+}
+
+/*
+ * UniStrcmp: Compare two strings
+ *
+ * Returns:
+ * < 0: First string is less than second
+ * = 0: Strings are equal
+ * > 0: First string is greater than second
+ */
+static inline int
+UniStrcmp(const wchar_t * ucs1, const wchar_t * ucs2)
+{
+ while ((*ucs1 == *ucs2) && *ucs1) {
+ ucs1++;
+ ucs2++;
+ }
+ return (int) *ucs1 - (int) *ucs2;
+}
+
+/*
+ * UniStrcpy: Copy a string
+ */
+static inline wchar_t *
+UniStrcpy(wchar_t * ucs1, const wchar_t * ucs2)
+{
+ wchar_t *anchor = ucs1; /* save the start of result string */
+
+ while ((*ucs1++ = *ucs2++)) ;
+ return anchor;
+}
+
+/*
+ * UniStrlen: Return the length of a string (in 16 bit Unicode chars not bytes)
+ */
+static inline size_t
+UniStrlen(const wchar_t * ucs1)
+{
+ int i = 0;
+
+ while (*ucs1++)
+ i++;
+ return i;
+}
+
+/*
+ * UniStrnlen: Return the length (in 16 bit Unicode chars not bytes) of a string (length limited)
+ */
+static inline size_t
+UniStrnlen(const wchar_t * ucs1, int maxlen)
+{
+ int i = 0;
+
+ while (*ucs1++) {
+ i++;
+ if (i >= maxlen)
+ break;
+ }
+ return i;
+}
+
+/*
+ * UniStrncat: Concatenate length limited string
+ */
+static inline wchar_t *
+UniStrncat(wchar_t * ucs1, const wchar_t * ucs2, size_t n)
+{
+ wchar_t *anchor = ucs1; /* save pointer to string 1 */
+
+ while (*ucs1++) ;
+ ucs1--; /* point to null terminator of s1 */
+ while (n-- && (*ucs1 = *ucs2)) { /* copy s2 after s1 */
+ ucs1++;
+ ucs2++;
+ }
+ *ucs1 = 0; /* Null terminate the result */
+ return (anchor);
+}
+
+/*
+ * UniStrncmp: Compare length limited string
+ */
+static inline int
+UniStrncmp(const wchar_t * ucs1, const wchar_t * ucs2, size_t n)
+{
+ if (!n)
+ return 0; /* Null strings are equal */
+ while ((*ucs1 == *ucs2) && *ucs1 && --n) {
+ ucs1++;
+ ucs2++;
+ }
+ return (int) *ucs1 - (int) *ucs2;
+}
+
+/*
+ * UniStrncmp_le: Compare length limited string - native to little-endian
+ */
+static inline int
+UniStrncmp_le(const wchar_t * ucs1, const wchar_t * ucs2, size_t n)
+{
+ if (!n)
+ return 0; /* Null strings are equal */
+ while ((*ucs1 == __le16_to_cpu(*ucs2)) && *ucs1 && --n) {
+ ucs1++;
+ ucs2++;
+ }
+ return (int) *ucs1 - (int) __le16_to_cpu(*ucs2);
+}
+
+/*
+ * UniStrncpy: Copy length limited string with pad
+ */
+static inline wchar_t *
+UniStrncpy(wchar_t * ucs1, const wchar_t * ucs2, size_t n)
+{
+ wchar_t *anchor = ucs1;
+
+ while (n-- && *ucs2) /* Copy the strings */
+ *ucs1++ = *ucs2++;
+
+ n++;
+ while (n--) /* Pad with nulls */
+ *ucs1++ = 0;
+ return anchor;
+}
+
+/*
+ * UniStrncpy_le: Copy length limited string with pad to little-endian
+ */
+static inline wchar_t *
+UniStrncpy_le(wchar_t * ucs1, const wchar_t * ucs2, size_t n)
+{
+ wchar_t *anchor = ucs1;
+
+ while (n-- && *ucs2) /* Copy the strings */
+ *ucs1++ = __le16_to_cpu(*ucs2++);
+
+ n++;
+ while (n--) /* Pad with nulls */
+ *ucs1++ = 0;
+ return anchor;
+}
+
+/*
+ * UniStrstr: Find a string in a string
+ *
+ * Returns:
+ * Address of first match found
+ * NULL if no matching string is found
+ */
+static inline wchar_t *
+UniStrstr(const wchar_t * ucs1, const wchar_t * ucs2)
+{
+ const wchar_t *anchor1 = ucs1;
+ const wchar_t *anchor2 = ucs2;
+
+ while (*ucs1) {
+ if (*ucs1 == *ucs2) { /* Partial match found */
+ ucs1++;
+ ucs2++;
+ } else {
+ if (!*ucs2) /* Match found */
+ return (wchar_t *) anchor1;
+ ucs1 = ++anchor1; /* No match */
+ ucs2 = anchor2;
+ }
+ }
+
+ if (!*ucs2) /* Both end together */
+ return (wchar_t *) anchor1; /* Match found */
+ return NULL; /* No match */
+}
+
+#ifndef UNIUPR_NOUPPER
+/*
+ * UniToupper: Convert a unicode character to upper case
+ */
+static inline wchar_t
+UniToupper(register wchar_t uc)
+{
+ register const struct UniCaseRange *rp;
+
+ if (uc < sizeof (CifsUniUpperTable)) { /* Latin characters */
+ return uc + CifsUniUpperTable[uc]; /* Use base tables */
+ } else {
+ rp = CifsUniUpperRange; /* Use range tables */
+ while (rp->start) {
+ if (uc < rp->start) /* Before start of range */
+ return uc; /* Uppercase = input */
+ if (uc <= rp->end) /* In range */
+ return uc + rp->table[uc - rp->start];
+ rp++; /* Try next range */
+ }
+ }
+ return uc; /* Past last range */
+}
+
+/*
+ * UniStrupr: Upper case a unicode string
+ */
+static inline wchar_t *
+UniStrupr(register wchar_t * upin)
+{
+ register wchar_t *up;
+
+ up = upin;
+ while (*up) { /* For all characters */
+ *up = UniToupper(*up);
+ up++;
+ }
+ return upin; /* Return input pointer */
+}
+#endif /* UNIUPR_NOUPPER */
+
+#ifndef UNIUPR_NOLOWER
+/*
+ * UniTolower: Convert a unicode character to lower case
+ */
+static inline wchar_t
+UniTolower(wchar_t uc)
+{
+ register struct UniCaseRange *rp;
+
+ if (uc < sizeof (UniLowerTable)) { /* Latin characters */
+ return uc + UniLowerTable[uc]; /* Use base tables */
+ } else {
+ rp = UniLowerRange; /* Use range tables */
+ while (rp->start) {
+ if (uc < rp->start) /* Before start of range */
+ return uc; /* Uppercase = input */
+ if (uc <= rp->end) /* In range */
+ return uc + rp->table[uc - rp->start];
+ rp++; /* Try next range */
+ }
+ }
+ return uc; /* Past last range */
+}
+
+/*
+ * UniStrlwr: Lower case a unicode string
+ */
+static inline wchar_t *
+UniStrlwr(register wchar_t * upin)
+{
+ register wchar_t *up;
+
+ up = upin;
+ while (*up) { /* For all characters */
+ *up = UniTolower(*up);
+ up++;
+ }
+ return upin; /* Return input pointer */
+}
+
+#endif
diff --git a/release/src/linux/linux/fs/cifs/cifs_uniupr.h b/release/src/linux/linux/fs/cifs/cifs_uniupr.h
new file mode 100644
index 00000000..272d72df
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/cifs_uniupr.h
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2000,2002
+ *
+ * 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
+ *
+ * uniupr.h - Unicode compressed case ranges
+ *
+*/
+
+#ifndef UNIUPR_NOUPPER
+/*
+ * Latin upper case
+ */
+signed char CifsUniUpperTable[512] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 030-03f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 040-04f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 050-05f */
+ 0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 060-06f */
+ -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, 0, 0, 0, 0, 0, /* 070-07f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 080-08f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 090-09f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0a0-0af */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0b0-0bf */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0c0-0cf */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0d0-0df */
+ -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 0e0-0ef */
+ -32, -32, -32, -32, -32, -32, -32, 0, -32, -32, -32, -32, -32, -32, -32, 121, /* 0f0-0ff */
+ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 100-10f */
+ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 110-11f */
+ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 120-12f */
+ 0, 0, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0, /* 130-13f */
+ -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, /* 140-14f */
+ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 150-15f */
+ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 160-16f */
+ 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0, /* 170-17f */
+ 0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, /* 180-18f */
+ 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, /* 190-19f */
+ 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, /* 1a0-1af */
+ -1, 0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, /* 1b0-1bf */
+ 0, 0, 0, 0, 0, -1, -2, 0, -1, -2, 0, -1, -2, 0, -1, 0, /* 1c0-1cf */
+ -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, -79, 0, -1, /* 1d0-1df */
+ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e0-1ef */
+ 0, 0, -1, -2, 0, -1, 0, 0, 0, -1, 0, -1, 0, -1, 0, -1, /* 1f0-1ff */
+};
+
+/* Upper case range - Greek */
+static signed char UniCaseRangeU03a0[47] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -38, -37, -37, -37, /* 3a0-3af */
+ 0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 3b0-3bf */
+ -32, -32, -31, -32, -32, -32, -32, -32, -32, -32, -32, -32, -64,
+ -63, -63,
+};
+
+/* Upper case range - Cyrillic */
+static signed char UniCaseRangeU0430[48] = {
+ -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 430-43f */
+ -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 440-44f */
+ 0, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, 0, -80, -80, /* 450-45f */
+};
+
+/* Upper case range - Extended cyrillic */
+static signed char UniCaseRangeU0490[61] = {
+ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 490-49f */
+ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 4a0-4af */
+ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 4b0-4bf */
+ 0, 0, -1, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1,
+};
+
+/* Upper case range - Extended latin and greek */
+static signed char UniCaseRangeU1e00[509] = {
+ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e00-1e0f */
+ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e10-1e1f */
+ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e20-1e2f */
+ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e30-1e3f */
+ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e40-1e4f */
+ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e50-1e5f */
+ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e60-1e6f */
+ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e70-1e7f */
+ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e80-1e8f */
+ 0, -1, 0, -1, 0, -1, 0, 0, 0, 0, 0, -59, 0, -1, 0, -1, /* 1e90-1e9f */
+ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ea0-1eaf */
+ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1eb0-1ebf */
+ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ec0-1ecf */
+ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ed0-1edf */
+ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ee0-1eef */
+ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, 0, 0, 0, 0, /* 1ef0-1eff */
+ 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f00-1f0f */
+ 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f10-1f1f */
+ 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f20-1f2f */
+ 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f30-1f3f */
+ 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f40-1f4f */
+ 0, 8, 0, 8, 0, 8, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f50-1f5f */
+ 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f60-1f6f */
+ 74, 74, 86, 86, 86, 86, 100, 100, 0, 0, 112, 112, 126, 126, 0, 0, /* 1f70-1f7f */
+ 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f80-1f8f */
+ 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f90-1f9f */
+ 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fa0-1faf */
+ 8, 8, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fb0-1fbf */
+ 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fc0-1fcf */
+ 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fd0-1fdf */
+ 8, 8, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fe0-1fef */
+ 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+/* Upper case range - Wide latin */
+static signed char UniCaseRangeUff40[27] = {
+ 0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* ff40-ff4f */
+ -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32,
+};
+
+/*
+ * Upper Case Range
+ */
+const struct UniCaseRange CifsUniUpperRange[] = {
+ {0x03a0, 0x03ce, UniCaseRangeU03a0},
+ {0x0430, 0x045f, UniCaseRangeU0430},
+ {0x0490, 0x04cc, UniCaseRangeU0490},
+ {0x1e00, 0x1ffc, UniCaseRangeU1e00},
+ {0xff40, 0xff5a, UniCaseRangeUff40},
+ {0, 0, NULL}
+};
+#endif
+
+#ifndef UNIUPR_NOLOWER
+/*
+ * Latin lower case
+ */
+static signed char CifsUniLowerTable[512] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 030-03f */
+ 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 040-04f */
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 0, 0, 0, 0, 0, /* 050-05f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 060-06f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 070-07f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 080-08f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 090-09f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0a0-0af */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0b0-0bf */
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 0c0-0cf */
+ 32, 32, 32, 32, 32, 32, 32, 0, 32, 32, 32, 32, 32, 32, 32, 0, /* 0d0-0df */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0e0-0ef */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0f0-0ff */
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 100-10f */
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 110-11f */
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 120-12f */
+ 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, /* 130-13f */
+ 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, /* 140-14f */
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 150-15f */
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 160-16f */
+ 1, 0, 1, 0, 1, 0, 1, 0, -121, 1, 0, 1, 0, 1, 0, 0, /* 170-17f */
+ 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 79, 0, /* 180-18f */
+ 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, /* 190-19f */
+ 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, /* 1a0-1af */
+ 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, /* 1b0-1bf */
+ 0, 0, 0, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 1, 0, 1, /* 1c0-1cf */
+ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, /* 1d0-1df */
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e0-1ef */
+ 0, 2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1f0-1ff */
+};
+
+/* Lower case range - Greek */
+static signed char UniCaseRangeL0380[44] = {
+ 0, 0, 0, 0, 0, 0, 38, 0, 37, 37, 37, 0, 64, 0, 63, 63, /* 380-38f */
+ 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 390-39f */
+ 32, 32, 0, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+};
+
+/* Lower case range - Cyrillic */
+static signed char UniCaseRangeL0400[48] = {
+ 0, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 0, 80, 80, /* 400-40f */
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 410-41f */
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 420-42f */
+};
+
+/* Lower case range - Extended cyrillic */
+static signed char UniCaseRangeL0490[60] = {
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 490-49f */
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 4a0-4af */
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 4b0-4bf */
+ 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1,
+};
+
+/* Lower case range - Extended latin and greek */
+static signed char UniCaseRangeL1e00[504] = {
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e00-1e0f */
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e10-1e1f */
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e20-1e2f */
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e30-1e3f */
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e40-1e4f */
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e50-1e5f */
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e60-1e6f */
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e70-1e7f */
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e80-1e8f */
+ 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 1e90-1e9f */
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ea0-1eaf */
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1eb0-1ebf */
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ec0-1ecf */
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ed0-1edf */
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ee0-1eef */
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, /* 1ef0-1eff */
+ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f00-1f0f */
+ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, 0, 0, /* 1f10-1f1f */
+ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f20-1f2f */
+ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f30-1f3f */
+ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, 0, 0, /* 1f40-1f4f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, -8, 0, -8, 0, -8, 0, -8, /* 1f50-1f5f */
+ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f60-1f6f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f70-1f7f */
+ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f80-1f8f */
+ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f90-1f9f */
+ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1fa0-1faf */
+ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -74, -74, -9, 0, 0, 0, /* 1fb0-1fbf */
+ 0, 0, 0, 0, 0, 0, 0, 0, -86, -86, -86, -86, -9, 0, 0, 0, /* 1fc0-1fcf */
+ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -100, -100, 0, 0, 0, 0, /* 1fd0-1fdf */
+ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -112, -112, -7, 0, 0, 0, /* 1fe0-1fef */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+/* Lower case range - Wide latin */
+static signed char UniCaseRangeLff20[27] = {
+ 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* ff20-ff2f */
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+};
+
+/*
+ * Lower Case Range
+ */
+const static struct UniCaseRange CifsUniLowerRange[] = {
+ 0x0380, 0x03ab, UniCaseRangeL0380,
+ 0x0400, 0x042f, UniCaseRangeL0400,
+ 0x0490, 0x04cb, UniCaseRangeL0490,
+ 0x1e00, 0x1ff7, UniCaseRangeL1e00,
+ 0xff20, 0xff3a, UniCaseRangeLff20,
+ 0, 0, 0
+};
+#endif
diff --git a/release/src/linux/linux/fs/cifs/cifsencrypt.c b/release/src/linux/linux/fs/cifs/cifsencrypt.c
new file mode 100644
index 00000000..8fdf3d79
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/cifsencrypt.c
@@ -0,0 +1,204 @@
+/*
+ * fs/cifs/cifsencrypt.c
+ *
+ * Copyright (C) International Business Machines Corp., 2003
+ * Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/fs.h>
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifs_debug.h"
+#include "md5.h"
+#include "cifs_unicode.h"
+
+/* Calculate and return the CIFS signature based on the mac key and the smb pdu */
+/* the 16 byte signature must be allocated by the caller */
+/* Note we only use the 1st eight bytes */
+/* Note that the smb header signature field on input contains the
+ sequence number before this function is called */
+
+extern void mdfour(unsigned char *out, unsigned char *in, int n);
+extern void E_md4hash(const unsigned char *passwd, unsigned char *p16);
+
+static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, const char * key, char * signature)
+{
+ struct MD5Context context;
+
+ if((cifs_pdu == NULL) || (signature == NULL))
+ return -EINVAL;
+
+ MD5Init(&context);
+ MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16);
+ MD5Update(&context,cifs_pdu->Protocol,cifs_pdu->smb_buf_length);
+ MD5Final(signature,&context);
+ return 0;
+}
+
+int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct cifsSesInfo * ses,
+ __u32 * pexpected_response_sequence_number)
+{
+ int rc = 0;
+ char smb_signature[20];
+
+ /* BB remember to initialize sequence number elsewhere and initialize mac_signing key elsewhere BB */
+ /* BB remember to add code to save expected sequence number in midQ entry BB */
+
+ if((cifs_pdu == NULL) || (ses == NULL))
+ return -EINVAL;
+
+ if((le32_to_cpu(cifs_pdu->Flags2) & SMBFLG2_SECURITY_SIGNATURE) == 0)
+ return rc;
+
+ spin_lock(&GlobalMid_Lock);
+ cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(ses->sequence_number);
+ cifs_pdu->Signature.Sequence.Reserved = 0;
+
+ *pexpected_response_sequence_number = ses->sequence_number++;
+ ses->sequence_number++;
+ spin_unlock(&GlobalMid_Lock);
+
+ rc = cifs_calculate_signature(cifs_pdu, ses->mac_signing_key,smb_signature);
+ if(rc)
+ memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
+ else
+ memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8);
+
+ return rc;
+}
+
+int cifs_verify_signature(struct smb_hdr * cifs_pdu, const char * mac_key,
+ __u32 expected_sequence_number)
+{
+ unsigned int rc;
+ char server_response_sig[8];
+ char what_we_think_sig_should_be[20];
+
+ if((cifs_pdu == NULL) || (mac_key == NULL))
+ return -EINVAL;
+
+ if (cifs_pdu->Command == SMB_COM_NEGOTIATE)
+ return 0;
+
+ if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) {
+ struct smb_com_lock_req * pSMB = (struct smb_com_lock_req *)cifs_pdu;
+ if(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE)
+ return 0;
+ }
+
+ /* BB what if signatures are supposed to be on for session but server does not
+ send one? BB */
+
+ /* Do not need to verify session setups with signature "BSRSPYL " */
+ if(memcmp(cifs_pdu->Signature.SecuritySignature,"BSRSPYL ",8)==0)
+ cFYI(1,("dummy signature received for smb command 0x%x",cifs_pdu->Command));
+
+ expected_sequence_number = cpu_to_le32(expected_sequence_number);
+
+ /* save off the origiginal signature so we can modify the smb and check
+ its signature against what the server sent */
+ memcpy(server_response_sig,cifs_pdu->Signature.SecuritySignature,8);
+
+ cifs_pdu->Signature.Sequence.SequenceNumber = expected_sequence_number;
+ cifs_pdu->Signature.Sequence.Reserved = 0;
+
+ rc = cifs_calculate_signature(cifs_pdu, mac_key,
+ what_we_think_sig_should_be);
+
+ if(rc)
+ return rc;
+
+
+/* cifs_dump_mem("what we think it should be: ",what_we_think_sig_should_be,16); */
+
+ if(memcmp(server_response_sig, what_we_think_sig_should_be, 8))
+ return -EACCES;
+ else
+ return 0;
+
+}
+
+/* We fill in key by putting in 40 byte array which was allocated by caller */
+int cifs_calculate_mac_key(char * key, const char * rn, const char * password)
+{
+ char temp_key[16];
+ if ((key == NULL) || (rn == NULL))
+ return -EINVAL;
+
+ E_md4hash(password, temp_key);
+ mdfour(key,temp_key,16);
+ memcpy(key+16,rn, CIFS_SESSION_KEY_SIZE);
+ return 0;
+}
+
+int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_info)
+{
+ char temp_hash[16];
+ struct HMACMD5Context ctx;
+ char * ucase_buf;
+ wchar_t * unicode_buf;
+ unsigned int i,user_name_len,dom_name_len;
+
+ if(ses)
+ return -EINVAL;
+
+ E_md4hash(ses->password, temp_hash);
+
+ hmac_md5_init_limK_to_64(temp_hash, 16, &ctx);
+ user_name_len = strlen(ses->userName);
+ if(user_name_len > MAX_USERNAME_SIZE)
+ return -EINVAL;
+ dom_name_len = strlen(ses->domainName);
+ if(dom_name_len > MAX_USERNAME_SIZE)
+ return -EINVAL;
+
+ ucase_buf = kmalloc((MAX_USERNAME_SIZE+1), GFP_KERNEL);
+ unicode_buf = kmalloc((MAX_USERNAME_SIZE+1)*4, GFP_KERNEL);
+
+ for(i=0;i<user_name_len;i++)
+ ucase_buf[i] = nls_info->charset2upper[(int)ses->userName[i]];
+ ucase_buf[i] = 0;
+ user_name_len = cifs_strtoUCS(unicode_buf, ucase_buf, MAX_USERNAME_SIZE*2, nls_info);
+ unicode_buf[user_name_len] = 0;
+ user_name_len++;
+
+ for(i=0;i<dom_name_len;i++)
+ ucase_buf[i] = nls_info->charset2upper[(int)ses->domainName[i]];
+ ucase_buf[i] = 0;
+ dom_name_len = cifs_strtoUCS(unicode_buf+user_name_len, ucase_buf, MAX_USERNAME_SIZE*2, nls_info);
+
+ unicode_buf[user_name_len + dom_name_len] = 0;
+ hmac_md5_update((const unsigned char *) unicode_buf,
+ (user_name_len+dom_name_len)*2,&ctx);
+
+ hmac_md5_final(ses->mac_signing_key,&ctx);
+ kfree(ucase_buf);
+ kfree(unicode_buf);
+ return 0;
+}
+void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_response)
+{
+ struct HMACMD5Context context;
+ memcpy(v2_session_response + 8, ses->server->cryptKey,8);
+ /* gen_blob(v2_session_response + 16); */
+ hmac_md5_init_limK_to_64(ses->mac_signing_key, 16, &context);
+
+ hmac_md5_update(ses->server->cryptKey,8,&context);
+/* hmac_md5_update(v2_session_response+16)client thing,8,&context); */ /* BB fix */
+
+ hmac_md5_final(v2_session_response,&context);
+}
diff --git a/release/src/linux/linux/fs/cifs/cifserr.c b/release/src/linux/linux/fs/cifs/cifserr.c
new file mode 100644
index 00000000..4c8eb7a0
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/cifserr.c
@@ -0,0 +1,70 @@
+/*
+ * fs/cifserr.c
+ *
+ * Copyright (c) International Business Machines Corp., 2002
+ * Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/smbno.h>
+#include "cifsfs.h"
+
+int map_cifs_error(int error_class, int error_code,
+ int status_codes_negotiated)
+{
+
+
+ if (status_codes_negotiated) {
+ switch (error_code) {
+ default:
+ return EIO;
+ }
+ } else
+ switch (error_class) {
+ case SUCCESS:
+ return 0;
+
+ case ERRDOS:
+ switch (error_code) {
+ case ERRbadfunc:
+ return EINVAL;
+ default:
+ return EIO;
+ }
+
+ case ERRSRV:
+ switch (error_code) {
+ default:
+ return EIO;
+ }
+
+ case ERRHRD:
+ switch (error_code) {
+ default:
+ return EIO;
+ }
+ default:
+ return EIO;
+ }
+ return 0;
+}
+
+int map_smb_error(int error_class, int error_code)
+{
+ return map_cifs_error(error_class, error_code, FALSE);
+}
diff --git a/release/src/linux/linux/fs/cifs/cifsfs.c b/release/src/linux/linux/fs/cifs/cifsfs.c
new file mode 100644
index 00000000..9e96b3b3
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/cifsfs.c
@@ -0,0 +1,769 @@
+/*
+ * fs/cifs/cifsfs.c
+ *
+ * Copyright (C) International Business Machines Corp., 2002,2004
+ * Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ * Common Internet FileSystem (CIFS) client
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* Note that BB means BUGBUG (ie something to fix eventually) */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/mount.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/list.h>
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,15))
+#include <linux/seq_file.h>
+#endif
+#include <linux/vfs.h>
+#include "cifsfs.h"
+#include "cifspdu.h"
+#define DECLARE_GLOBALS_HERE
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_debug.h"
+#include "cifs_fs_sb.h"
+#include <linux/mm.h>
+#define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */
+/* BB when mempool_resize is added back in, we will resize pool on new mount */
+#define CIFS_MIN_RCV_POOL 11 /* enough for progress to five servers */
+
+#ifdef CONFIG_CIFS_QUOTA
+static struct quotactl_ops cifs_quotactl_ops;
+#endif
+
+extern struct file_system_type cifs_fs_type;
+
+int cifsFYI = 0;
+int cifsERROR = 1;
+int traceSMB = 0;
+unsigned int oplockEnabled = 1;
+unsigned int quotaEnabled = 0;
+unsigned int linuxExtEnabled = 1;
+unsigned int lookupCacheEnabled = 1;
+unsigned int multiuser_mount = 0;
+unsigned int extended_security = 0;
+unsigned int ntlmv2_support = 0;
+unsigned int sign_CIFS_PDUs = 1;
+unsigned int CIFSMaximumBufferSize = CIFS_MAX_MSGSIZE;
+struct task_struct * oplockThread = NULL;
+
+extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
+ const char *);
+extern int cifs_umount(struct super_block *, struct cifs_sb_info *);
+void cifs_proc_init(void);
+void cifs_proc_clean(void);
+
+static DECLARE_COMPLETION(cifs_oplock_exited);
+
+
+struct super_block *
+cifs_read_super(struct super_block *sb, void *data, int silent)
+{
+ struct inode *inode;
+ struct cifs_sb_info *cifs_sb;
+ int rc = 0;
+
+ sb->s_flags |= MS_NODIRATIME; /* and probably even noatime */
+ cifs_sb = CIFS_SB(sb);
+ if(cifs_sb == NULL)
+ return 0;
+ else
+ memset(cifs_sb,0,sizeof(struct cifs_sb_info));
+
+
+ rc = cifs_mount(sb, cifs_sb, data, NULL);
+
+ if (rc) {
+ if (!silent)
+ cERROR(1,
+ ("cifs_mount failed w/return code = %d", rc));
+ goto out_mount_failed;
+ }
+
+ sb->s_magic = CIFS_MAGIC_NUMBER;
+ sb->s_op = &cifs_super_ops;
+/* if(cifs_sb->tcon->ses->server->maxBuf > MAX_CIFS_HDR_SIZE + 512)
+ sb->s_blocksize = cifs_sb->tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; */
+#ifdef CONFIG_CIFS_QUOTA
+ sb->s_qcop = &cifs_quotactl_ops;
+#endif
+ sb->s_blocksize = CIFS_MAX_MSGSIZE;
+ sb->s_blocksize_bits = 14; /* default 2**14 = CIFS_MAX_MSGSIZE */
+ inode = iget(sb, ROOT_I);
+
+ if (!inode) {
+ goto out_no_root;
+ }
+
+ sb->s_root = d_alloc_root(inode);
+
+ if (!sb->s_root) {
+ goto out_no_root;
+ }
+
+ return sb;
+
+out_no_root:
+ cERROR(1, ("cifs_read_super: get root inode failed"));
+ if (inode)
+ iput(inode);
+
+out_mount_failed:
+ if(cifs_sb->local_nls)
+ unload_nls(cifs_sb->local_nls);
+ sb->s_dev = 0;
+ return 0;
+}
+
+static void
+cifs_put_super(struct super_block *sb)
+{
+ int rc = 0;
+ struct cifs_sb_info *cifs_sb;
+
+ cFYI(1, ("In cifs_put_super"));
+ cifs_sb = CIFS_SB(sb);
+ if(cifs_sb == NULL) {
+ cFYI(1,("Empty cifs superblock info passed to unmount"));
+ return;
+ }
+ rc = cifs_umount(sb, cifs_sb);
+ if (rc) {
+ cERROR(1, ("cifs_umount failed with return code %d", rc));
+ }
+ unload_nls(cifs_sb->local_nls);
+ return;
+}
+
+static int
+cifs_statfs(struct super_block *sb, struct statfs *buf)
+{
+ int xid, rc;
+ struct cifs_sb_info *cifs_sb;
+ struct cifsTconInfo *pTcon;
+
+ xid = GetXid();
+
+ cifs_sb = CIFS_SB(sb);
+ pTcon = cifs_sb->tcon;
+
+ buf->f_type = CIFS_MAGIC_NUMBER;
+
+ /* instead could get the real value via SMB_QUERY_FS_ATTRIBUTE_INFO */
+ buf->f_namelen = PATH_MAX; /* PATH_MAX may be too long - it would presumably
+ be length of total path, note that some servers may be
+ able to support more than this, but best to be safe
+ since Win2k and others can not handle very long filenames */
+ buf->f_files = 0; /* undefined */
+ buf->f_ffree = 0; /* unlimited */
+
+ rc = CIFSSMBQFSInfo(xid, pTcon, buf, cifs_sb->local_nls);
+
+ /*
+ int f_type;
+ __fsid_t f_fsid;
+ int f_namelen; */
+ /* BB get from info put in tcon struct at mount time with call to QFSAttrInfo */
+ FreeXid(xid);
+ return 0; /* always return success? what if volume is no longer available? */
+}
+
+static int cifs_permission(struct inode * inode, int mask)
+{
+ /* the server does permission checks, we do not need to do it here */
+ return 0;
+}
+
+kmem_cache_t *cifs_req_cachep;
+kmem_cache_t *cifs_mid_cachep;
+kmem_cache_t *cifs_oplock_cachep;
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+static struct inode *
+cifs_alloc_inode(struct super_block *sb)
+{
+ struct cifsInodeInfo *cifs_inode;
+ cifs_inode =
+ (struct cifsInodeInfo *) kmem_cache_alloc(cifs_inode_cachep,
+ SLAB_KERNEL);
+ if (!cifs_inode)
+ return NULL;
+ cifs_inode->cifsAttrs = 0x20; /* default */
+ atomic_set(&cifs_inode->inUse, 0);
+ cifs_inode->time = 0;
+ /* Until the file is open and we have gotten oplock
+ info back from the server, can not assume caching of
+ file data or metadata */
+ cifs_inode->clientCanCacheRead = FALSE;
+ cifs_inode->clientCanCacheAll = FALSE;
+ INIT_LIST_HEAD(&cifs_inode->openFileList);
+ return &cifs_inode->vfs_inode;
+}
+
+static void
+cifs_destroy_inode(struct inode *inode)
+{
+ kmem_cache_free(cifs_inode_cachep, CIFS_I(inode));
+}
+#endif
+
+/*
+ * cifs_show_options() is for displaying mount options in /proc/mounts.
+ * Not all settable options are displayed but most of the important
+ * ones are.
+ */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,15))
+static int
+cifs_show_options(struct seq_file *s, struct vfsmount *m)
+{
+ struct cifs_sb_info *cifs_sb;
+
+ cifs_sb = CIFS_SB(m->mnt_sb);
+
+ if (cifs_sb) {
+ if (cifs_sb->tcon) {
+ seq_printf(s, ",unc=%s", cifs_sb->tcon->treeName);
+ if ((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->userName))
+ seq_printf(s, ",username=%s",
+ cifs_sb->tcon->ses->userName);
+ if(cifs_sb->tcon->ses->domainName)
+ seq_printf(s, ",domain=%s",
+ cifs_sb->tcon->ses->domainName);
+ }
+ seq_printf(s, ",rsize=%d",cifs_sb->rsize);
+ seq_printf(s, ",wsize=%d",cifs_sb->wsize);
+ }
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_CIFS_QUOTA
+int cifs_xquota_set(struct super_block * sb, int quota_type, qid_t qid,
+ struct fs_disk_quota * pdquota)
+{
+ int xid;
+ int rc = 0;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+ struct cifsTconInfo *pTcon;
+
+ if(cifs_sb)
+ pTcon = cifs_sb->tcon;
+ else
+ return -EIO;
+
+
+ xid = GetXid();
+ if(pTcon) {
+ cFYI(1,("set type: 0x%x id: %d",quota_type,qid));
+ } else {
+ return -EIO;
+ }
+
+ FreeXid(xid);
+ return rc;
+}
+
+int cifs_xquota_get(struct super_block * sb, int quota_type, qid_t qid,
+ struct fs_disk_quota * pdquota)
+{
+ int xid;
+ int rc = 0;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+ struct cifsTconInfo *pTcon;
+
+ if(cifs_sb)
+ pTcon = cifs_sb->tcon;
+ else
+ return -EIO;
+
+ xid = GetXid();
+ if(pTcon) {
+ cFYI(1,("set type: 0x%x id: %d",quota_type,qid));
+ } else {
+ rc = -EIO;
+ }
+
+ FreeXid(xid);
+ return rc;
+}
+
+int cifs_xstate_set(struct super_block * sb, unsigned int flags, int operation)
+{
+ int xid;
+ int rc = 0;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+ struct cifsTconInfo *pTcon;
+
+ if(cifs_sb)
+ pTcon = cifs_sb->tcon;
+ else
+ return -EIO;
+
+ xid = GetXid();
+ if(pTcon) {
+ cFYI(1,("flags: 0x%x operation: 0x%x",flags,operation));
+ } else {
+ rc = -EIO;
+ }
+
+ FreeXid(xid);
+ return rc;
+}
+
+int cifs_xstate_get(struct super_block * sb, struct fs_quota_stat *qstats)
+{
+ int xid;
+ int rc = 0;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+ struct cifsTconInfo *pTcon;
+
+ if(cifs_sb) {
+ pTcon = cifs_sb->tcon;
+ } else {
+ return -EIO;
+ }
+ xid = GetXid();
+ if(pTcon) {
+ cFYI(1,("pqstats %p",qstats));
+ } else {
+ rc = -EIO;
+ }
+
+ FreeXid(xid);
+ return rc;
+}
+
+static struct quotactl_ops cifs_quotactl_ops = {
+ .set_xquota = cifs_xquota_set,
+ .get_xquota = cifs_xquota_set,
+ .set_xstate = cifs_xstate_set,
+ .get_xstate = cifs_xstate_get,
+};
+#endif
+
+static int cifs_remount(struct super_block *sb, int *flags, char *data)
+{
+ *flags |= MS_NODIRATIME;
+ return 0;
+}
+
+struct super_operations cifs_super_ops = {
+ .read_inode = cifs_read_inode,
+ .put_super = cifs_put_super,
+ .statfs = cifs_statfs,
+/* .alloc_inode = cifs_alloc_inode,
+ .destroy_inode = cifs_destroy_inode, */
+/* .drop_inode = generic_delete_inode,
+ .delete_inode = cifs_delete_inode, *//* Do not need the above two functions
+ unless later we add lazy close of inodes or unless the kernel forgets to call
+ us with the same number of releases (closes) as opens */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,15))
+ .show_options = cifs_show_options,
+#endif
+/* .umount_begin = cifs_umount_begin, *//* consider adding in the future */
+};
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+static struct super_block *
+cifs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data)
+{
+ int rc;
+ struct super_block *sb = sget(fs_type, NULL, set_anon_super, NULL);
+
+ cFYI(1, ("Devname: %s flags: %d ", dev_name, flags));
+
+ if (IS_ERR(sb))
+ return sb;
+
+ sb->s_flags = flags;
+
+ rc = cifs_read_super(sb, data, dev_name, flags & MS_VERBOSE ? 1 : 0);
+ if (rc) {
+ up_write(&sb->s_umount);
+ deactivate_super(sb);
+ return ERR_PTR(rc);
+ }
+ sb->s_flags |= MS_ACTIVE;
+ return sb;
+}
+#endif
+
+static ssize_t
+cifs_read_wrapper(struct file * file, char *read_data, size_t read_size,
+ loff_t * poffset)
+{
+ if(file == NULL)
+ return -EIO;
+ else if(file->f_dentry == NULL)
+ return -EIO;
+ else if(file->f_dentry->d_inode == NULL)
+ return -EIO;
+
+ if(CIFS_I(file->f_dentry->d_inode)->clientCanCacheRead) {
+ return generic_file_read(file,read_data,read_size,poffset);
+ } else {
+ /* BB do we need to lock inode from here until after invalidate? */
+/* if(file->f_dentry->d_inode->i_mapping) {
+ filemap_fdatawrite(file->f_dentry->d_inode->i_mapping);
+ filemap_fdatawait(file->f_dentry->d_inode->i_mapping);
+ }*/
+/* cifs_revalidate(file->f_dentry);*/ /* BB fixme */
+
+ /* BB we should make timer configurable - perhaps
+ by simply calling cifs_revalidate here */
+ /* invalidate_remote_inode(file->f_dentry->d_inode);*/
+ return generic_file_read(file,read_data,read_size,poffset);
+ }
+}
+
+static ssize_t
+cifs_write_wrapper(struct file * file, const char *write_data,
+ size_t write_size, loff_t * poffset)
+{
+ ssize_t written;
+
+ if(file == NULL)
+ return -EIO;
+ else if(file->f_dentry == NULL)
+ return -EIO;
+ else if(file->f_dentry->d_inode == NULL)
+ return -EIO;
+
+ /* check whether we can cache writes locally */
+ written = generic_file_write(file,write_data,write_size,poffset);
+ if(!CIFS_I(file->f_dentry->d_inode)->clientCanCacheAll) {
+ if(file->f_dentry->d_inode->i_mapping) {
+ filemap_fdatasync(file->f_dentry->d_inode->i_mapping);
+ }
+ }
+ return written;
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+static struct file_system_type cifs_fs_type = {
+ .owner = THIS_MODULE,
+ .name = "cifs",
+ .get_sb = cifs_get_sb,
+ .kill_sb = kill_anon_super,
+ /* .fs_flags */
+};
+#endif
+
+static DECLARE_FSTYPE(cifs_fs_type, "cifs", cifs_read_super,0);
+
+
+struct inode_operations cifs_dir_inode_ops = {
+ .create = cifs_create,
+ .lookup = cifs_lookup,
+ .unlink = cifs_unlink,
+ .link = cifs_hardlink,
+ .mkdir = cifs_mkdir,
+ .rmdir = cifs_rmdir,
+ .rename = cifs_rename,
+ .permission = cifs_permission,
+ .revalidate = cifs_revalidate,
+ .setattr = cifs_setattr,
+ .symlink = cifs_symlink,
+ .mknod = cifs_mknod,
+};
+
+struct inode_operations cifs_file_inode_ops = {
+ .revalidate = cifs_revalidate,
+ .setattr = cifs_setattr,
+/* .getattr = cifs_getattr,*/
+ .rename = cifs_rename,
+ .permission = cifs_permission,
+#ifdef CONFIG_CIFS_XATTR
+ .setxattr = cifs_setxattr,
+ .getxattr = cifs_getxattr,
+ .listxattr = cifs_listxattr,
+ .removexattr = cifs_removexattr,
+#endif
+};
+
+struct inode_operations cifs_symlink_inode_ops = {
+ .readlink = cifs_readlink,
+ .follow_link = cifs_follow_link,
+ .permission = cifs_permission,
+ /* BB add the following two eventually */
+ /* revalidate: cifs_revalidate,
+ setattr: cifs_notify_change, *//* BB do we need notify change */
+#ifdef CONFIG_CIFS_XATTR
+ .setxattr = cifs_setxattr,
+ .getxattr = cifs_getxattr,
+ .listxattr = cifs_listxattr,
+ .removexattr = cifs_removexattr,
+#endif
+};
+
+struct file_operations cifs_file_ops = {
+ .read = cifs_read_wrapper,
+ .write = cifs_write_wrapper,
+ .open = cifs_open,
+ .release = cifs_close,
+ .lock = cifs_lock,
+ .fsync = cifs_fsync,
+ .flush = cifs_flush,
+ .mmap = cifs_file_mmap,
+/* .sendfile = generic_file_sendfile,*/
+#ifdef CONFIG_CIFS_FCNTL
+ .fcntl = cifs_fcntl,
+#endif
+};
+
+struct file_operations cifs_dir_ops = {
+ .readdir = cifs_readdir,
+ .release = cifs_closedir,
+ .read = generic_read_dir,
+#ifdef CONFIG_CIFS_FCNTL
+ .fcntl = cifs_fcntl,
+#endif
+};
+/*
+static void
+cifs_init_once(void *inode, kmem_cache_t * cachep, unsigned long flags)
+{
+ struct cifsInodeInfo *cifsi = (struct cifsInodeInfo *) inode;
+
+ if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR) {
+ inode_init_once(&cifsi->vfs_inode);
+ INIT_LIST_HEAD(&cifsi->lockList);
+ }
+}
+
+static int
+cifs_init_inodecache(void)
+{
+ cifs_inode_cachep = kmem_cache_create("cifs_inode_cache",
+ sizeof (struct cifsInodeInfo),
+ 0, SLAB_HWCACHE_ALIGN,
+ cifs_init_once, NULL);
+ if (cifs_inode_cachep == NULL)
+ return -ENOMEM;
+
+
+ return 0;
+}
+
+static void
+cifs_destroy_inodecache(void)
+{
+ if (kmem_cache_destroy(cifs_inode_cachep))
+ printk(KERN_WARNING "cifs_inode_cache: error freeing\n");
+} */
+
+static int
+cifs_init_request_bufs(void)
+{
+ cifs_req_cachep = kmem_cache_create("cifs_request",
+ CIFS_MAX_MSGSIZE +
+ MAX_CIFS_HDR_SIZE, 0,
+ SLAB_HWCACHE_ALIGN, NULL, NULL);
+ if (cifs_req_cachep == NULL)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void
+cifs_destroy_request_bufs(void)
+{
+ if (kmem_cache_destroy(cifs_req_cachep))
+ printk(KERN_WARNING
+ "cifs_destroy_request_cache: error not all structures were freed\n");
+}
+
+static int
+cifs_init_mids(void)
+{
+ cifs_mid_cachep = kmem_cache_create("cifs_mpx_ids",
+ sizeof (struct mid_q_entry), 0,
+ SLAB_HWCACHE_ALIGN, NULL, NULL);
+ if (cifs_mid_cachep == NULL)
+ return -ENOMEM;
+ cifs_oplock_cachep = kmem_cache_create("cifs_oplock_struct",
+ sizeof (struct oplock_q_entry), 0,
+ SLAB_HWCACHE_ALIGN, NULL, NULL);
+ if (cifs_oplock_cachep == NULL) {
+ kmem_cache_destroy(cifs_mid_cachep);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void
+cifs_destroy_mids(void)
+{
+ if (kmem_cache_destroy(cifs_mid_cachep))
+ printk(KERN_WARNING
+ "cifs_destroy_mids: error not all structures were freed\n");
+ if (kmem_cache_destroy(cifs_oplock_cachep))
+ printk(KERN_WARNING
+ "error not all oplock structures were freed\n");
+}
+
+static int cifs_oplock_thread(void * dummyarg)
+{
+ struct oplock_q_entry * oplock_item;
+ struct cifsTconInfo *pTcon;
+ struct inode * inode;
+ __u16 netfid;
+ int rc = 0;
+
+ daemonize();
+ sprintf(current->comm,"cifsoplockd");
+
+ oplockThread = current;
+ do {
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ schedule_timeout(1*HZ);
+ spin_lock(&GlobalMid_Lock);
+ if(list_empty(&GlobalOplock_Q)) {
+ spin_unlock(&GlobalMid_Lock);
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(39*HZ);
+ } else {
+ oplock_item = list_entry(GlobalOplock_Q.next,
+ struct oplock_q_entry, qhead);
+ if(oplock_item) {
+ cFYI(1,("found oplock item to write out"));
+ pTcon = oplock_item->tcon;
+ inode = oplock_item->pinode;
+ netfid = oplock_item->netfid;
+ spin_unlock(&GlobalMid_Lock);
+ DeleteOplockQEntry(oplock_item);
+ /* can not grab inode sem here since it would
+ deadlock when oplock received on delete
+ since vfs_unlink holds the i_sem across
+ the call */
+ /* down(&inode->i_sem);*/
+ if (S_ISREG(inode->i_mode)) {
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,17))
+ rc = filemap_fdatasync(inode->i_mapping);
+ if(rc)
+ CIFS_I(inode)->write_behind_rc = rc;
+#else
+ filemap_fdatasync(inode->i_mapping);
+#endif
+ if(CIFS_I(inode)->clientCanCacheRead == 0)
+ invalidate_inode_pages(inode);
+ } else
+ rc = 0;
+ /* releasing a stale oplock after recent reconnection
+ of smb session using a now incorrect file
+ handle is not a data integrity issue but do
+ not bother sending an oplock release if session
+ to server still is disconnected since oplock
+ already released by the server in that case */
+ if(pTcon->tidStatus != CifsNeedReconnect) {
+ rc = CIFSSMBLock(0, pTcon,
+ netfid,
+ 0 /* len */ , 0 /* offset */, 0,
+ 0, LOCKING_ANDX_OPLOCK_RELEASE,
+ 0 /* wait flag */);
+ cFYI(1,("Oplock release rc = %d ",rc));
+ }
+ } else
+ spin_unlock(&GlobalMid_Lock);
+ }
+ } while(!signal_pending(current));
+ complete_and_exit (&cifs_oplock_exited, 0);
+}
+
+static int __init
+init_cifs(void)
+{
+ int rc = 0;
+#if CONFIG_PROC_FS
+ cifs_proc_init();
+#endif
+ INIT_LIST_HEAD(&GlobalServerList); /* BB not implemented yet */
+ INIT_LIST_HEAD(&GlobalSMBSessionList);
+ INIT_LIST_HEAD(&GlobalTreeConnectionList);
+ INIT_LIST_HEAD(&GlobalOplock_Q);
+/*
+ * Initialize Global counters
+ */
+ atomic_set(&sesInfoAllocCount, 0);
+ atomic_set(&tconInfoAllocCount, 0);
+ atomic_set(&tcpSesReconnectCount, 0);
+ atomic_set(&tconInfoReconnectCount, 0);
+
+ atomic_set(&bufAllocCount, 0);
+ atomic_set(&midCount, 0);
+ GlobalCurrentXid = 0;
+ GlobalTotalActiveXid = 0;
+ GlobalMaxActiveXid = 0;
+ GlobalSMBSeslock = RW_LOCK_UNLOCKED;
+ GlobalMid_Lock = SPIN_LOCK_UNLOCKED;
+
+/* rc = cifs_init_inodecache();*/
+ if (!rc) {
+ rc = cifs_init_mids();
+ if (!rc) {
+ rc = cifs_init_request_bufs();
+ if (!rc) {
+ rc = register_filesystem(&cifs_fs_type);
+ if (!rc) {
+ kernel_thread(cifs_oplock_thread, NULL,
+ CLONE_FS | CLONE_FILES | CLONE_VM);
+ return rc; /* Success */
+ } else
+ cifs_destroy_request_bufs();
+ }
+ cifs_destroy_mids();
+ }
+/* cifs_destroy_inodecache(); */
+ }
+#if CONFIG_PROC_FS
+ cifs_proc_clean();
+#endif
+ return rc;
+}
+
+static void __exit
+exit_cifs(void)
+{
+ cFYI(0, ("In unregister ie exit_cifs"));
+#if CONFIG_PROC_FS
+ cifs_proc_clean();
+#endif
+ unregister_filesystem(&cifs_fs_type);
+/* cifs_destroy_inodecache();*/
+ cifs_destroy_mids();
+ cifs_destroy_request_bufs();
+ if(oplockThread) {
+ send_sig(SIGTERM, oplockThread, 1);
+ wait_for_completion(&cifs_oplock_exited);
+ }
+}
+
+MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>");
+MODULE_LICENSE("GPL"); /* combination of LGPL + GPL source behaves as GPL */
+MODULE_DESCRIPTION
+ ("VFS to access servers complying with the SNIA CIFS Specification e.g. Samba and Windows");
+module_init(init_cifs)
+module_exit(exit_cifs)
diff --git a/release/src/linux/linux/fs/cifs/cifsfs.h b/release/src/linux/linux/fs/cifs/cifsfs.h
new file mode 100644
index 00000000..4f2da1e7
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/cifsfs.h
@@ -0,0 +1,97 @@
+/*
+ * fs/cifs/cifsfs.h
+ *
+ * Copyright (c) International Business Machines Corp., 2002
+ * Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _CIFSFS_H
+#define _CIFSFS_H
+
+#define ROOT_I 2
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+extern int map_cifs_error(int error_class, int error_code,
+ int status_codes_negotiated);
+
+extern struct address_space_operations cifs_addr_ops;
+
+/* Functions related to super block operations */
+extern struct super_operations cifs_super_ops;
+extern void cifs_put_inode(struct inode *);
+extern void cifs_read_inode(struct inode *);
+extern void cifs_delete_inode(struct inode *);
+/* extern void cifs_write_inode(struct inode *); *//* BB not needed yet */
+
+/* Functions related to inodes */
+extern struct inode_operations cifs_dir_inode_ops;
+extern int cifs_create(struct inode *, struct dentry *, int);
+extern struct dentry *cifs_lookup(struct inode *, struct dentry *);
+extern int cifs_unlink(struct inode *, struct dentry *);
+extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *);
+extern int cifs_mknod(struct inode *, struct dentry *, int, int);
+extern int cifs_mkdir(struct inode *, struct dentry *, int);
+extern int cifs_rmdir(struct inode *, struct dentry *);
+extern int cifs_rename(struct inode *, struct dentry *, struct inode *,
+ struct dentry *);
+extern int cifs_revalidate(struct dentry *);
+extern int cifs_setattr(struct dentry *, struct iattr *);
+
+extern struct inode_operations cifs_file_inode_ops;
+extern void cifs_truncate_file(struct inode *);
+extern struct inode_operations cifs_symlink_inode_ops;
+
+/* Functions related to files and directories */
+extern struct file_operations cifs_file_ops;
+extern int cifs_open(struct inode *inode, struct file *file);
+extern int cifs_close(struct inode *inode, struct file *file);
+extern int cifs_closedir(struct inode *inode, struct file *file);
+extern ssize_t cifs_read(struct file *file, char *read_data,
+ size_t read_size, loff_t * poffset);
+extern ssize_t cifs_write(struct file *file, const char *write_data,
+ size_t write_size, loff_t * poffset);
+extern int cifs_lock(struct file *, int, struct file_lock *);
+extern int cifs_fsync(struct file *, struct dentry *, int);
+extern int cifs_flush(struct file *);
+extern int cifs_file_mmap(struct file * , struct vm_area_struct *);
+extern struct file_operations cifs_dir_ops;
+extern int cifs_dir_open(struct inode *inode, struct file *file);
+extern int cifs_readdir(struct file *file, void *direntry, filldir_t filldir);
+extern long cifs_fcntl(int, unsigned int, unsigned long, struct file *);
+
+/* Functions related to dir entries */
+extern struct dentry_operations cifs_dentry_ops;
+
+/* Functions related to symlinks */
+extern int cifs_follow_link(struct dentry *direntry, struct nameidata *nd);
+extern int cifs_readlink(struct dentry *direntry, char *buffer, int buflen);
+extern int cifs_symlink(struct inode *inode, struct dentry *direntry,
+ const char *symname);
+extern int cifs_removexattr(struct dentry *, const char *);
+extern int cifs_setxattr(struct dentry *, const char *, const void *,
+ size_t, int);
+extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t);
+extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
+#define CIFS_VERSION "1.20"
+#endif /* _CIFSFS_H */
diff --git a/release/src/linux/linux/fs/cifs/cifsglob.h b/release/src/linux/linux/fs/cifs/cifsglob.h
new file mode 100644
index 00000000..e8991b79
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/cifsglob.h
@@ -0,0 +1,413 @@
+/*
+ * fs/cifs/cifsglob.h
+ *
+ * Copyright (C) International Business Machines Corp., 2002,2003
+ * Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU Lesser General Public License for more details.
+ *
+ */
+#include <linux/in.h>
+#include <linux/in6.h>
+#include "cifs_fs_sb.h"
+/*
+ * The sizes of various internal tables and strings
+ */
+#define MAX_UID_INFO 16
+#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 64 /* used to be 20 - this should still be enough */
+#define MAX_USERNAME_SIZE 32 /* 32 is to allow for 15 char names + null
+ termination then *2 for unicode versions */
+#define MAX_PASSWORD_SIZE 16
+
+/*
+ * MAX_REQ is the maximum number of requests that WE will send
+ * on one socket concurently. It also matches the most common
+ * value of max multiplex returned by servers. We may
+ * eventually want to use the negotiated value (in case
+ * future servers can handle more) when we are more confident that
+ * we will not have problems oveloading the socket with pending
+ * write data.
+ */
+#define CIFS_MAX_REQ 50
+
+#define SERVER_NAME_LENGTH 15
+#define SERVER_NAME_LEN_WITH_NULL (SERVER_NAME_LENGTH + 1)
+
+/* used to define string lengths for reversing unicode strings */
+/* (256+1)*2 = 514 */
+/* (max path length + 1 for null) * 2 for unicode */
+#define MAX_NAME 514
+
+#include "cifspdu.h"
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef XATTR_DOS_ATTRIB
+#define XATTR_DOS_ATTRIB "user.DOSATTRIB"
+#endif
+
+/*
+ * This information is kept on every Server we know about.
+ *
+ * Some things to note:
+ *
+ */
+#define SERVER_NAME_LEN_WITH_NULL (SERVER_NAME_LENGTH + 1)
+
+/*
+ * CIFS vfs client Status information (based on what we know.)
+ */
+
+ /* associated with each tcp and smb session */
+enum statusEnum {
+ CifsNew = 0,
+ CifsGood,
+ CifsExiting,
+ CifsNeedReconnect
+};
+
+enum securityEnum {
+ NTLM = 0, /* Legacy NTLM012 auth with NTLM hash */
+ NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */
+ RawNTLMSSP, /* NTLMSSP without SPNEGO */
+ NTLMSSP, /* NTLMSSP via SPNEGO */
+ Kerberos /* Kerberos via SPNEGO */
+};
+
+enum protocolEnum {
+ IPV4 = 0,
+ IPV6,
+ SCTP
+ /* Netbios frames protocol not supported at this time */
+};
+
+/*
+ *****************************************************************
+ * Except the CIFS PDUs themselves all the
+ * globally interesting structs should go here
+ *****************************************************************
+ */
+
+struct TCP_Server_Info {
+ char server_Name[SERVER_NAME_LEN_WITH_NULL]; /* 15 chars + X'20'in 16th */
+ char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2]; /* Unicode version of server_Name */
+ struct socket *ssocket;
+ union {
+ struct sockaddr_in sockAddr;
+ struct sockaddr_in6 sockAddr6;
+ } addr;
+ wait_queue_head_t response_q;
+ wait_queue_head_t request_q; /* if more than maxmpx to srvr must block*/
+ struct list_head pending_mid_q;
+ void *Server_NlsInfo; /* BB - placeholder for future NLS info */
+ unsigned short server_codepage; /* codepage for the server */
+ unsigned long ip_address; /* IP addr for the server if known */
+ enum protocolEnum protocolType;
+ char versionMajor;
+ char versionMinor;
+ int svlocal:1; /* local server or remote */
+ atomic_t socketUseCount; /* number of open cifs sessions on socket */
+ atomic_t inFlight; /* number of requests on the wire to server */
+ enum statusEnum tcpStatus; /* what we think the status is */
+ struct semaphore tcpSem;
+ struct task_struct *tsk;
+ char server_GUID[16];
+ char secMode;
+ enum securityEnum secType;
+ unsigned int maxReq; /* Clients should submit no more */
+ /* than maxReq distinct unanswered SMBs to the server when using */
+ /* multiplexed reads or writes */
+ unsigned int maxBuf; /* maxBuf specifies the maximum */
+ /* message size the server can send or receive for non-raw SMBs */
+ unsigned int maxRw; /* maxRw specifies the maximum */
+ /* message size the server can send or receive for */
+ /* SMB_COM_WRITE_RAW or SMB_COM_READ_RAW. */
+ char sessid[4]; /* unique token id for this session */
+ /* (returned on Negotiate */
+ int capabilities; /* allow selective disabling of caps by smb sess */
+ __u16 timeZone;
+ char cryptKey[CIFS_CRYPTO_KEY_SIZE];
+ char workstation_RFC1001_name[16]; /* 16th byte is always zero */
+};
+
+/*
+ * The following is our shortcut to user information. We surface the uid,
+ * and name. We always get the password on the fly in case it
+ * has changed. We also hang a list of sessions owned by this user off here.
+ */
+struct cifsUidInfo {
+ struct list_head userList;
+ struct list_head sessionList; /* SMB sessions for this user */
+ uid_t linux_uid;
+ char user[MAX_USERNAME_SIZE + 1]; /* ascii name of user */
+ /* BB may need ptr or callback for PAM or WinBind info */
+};
+
+/*
+ * Session structure. One of these for each uid session with a particular host
+ */
+struct cifsSesInfo {
+ struct list_head cifsSessionList;
+ struct semaphore sesSem;
+ struct cifsUidInfo *uidInfo; /* pointer to user info */
+ struct TCP_Server_Info *server; /* pointer to server info */
+ atomic_t inUse; /* # of mounts (tree connections) on this ses */
+ enum statusEnum status;
+ __u32 sequence_number; /* needed for CIFS PDU signature */
+ __u16 ipc_tid; /* special tid for connection to IPC share */
+ char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16];
+ char *serverOS; /* name of operating system underlying the server */
+ char *serverNOS; /* name of network operating system that the server is running */
+ char *serverDomain; /* security realm of server */
+ int Suid; /* remote smb uid */
+ uid_t linux_uid; /* local Linux uid */
+ int capabilities;
+ char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for tcp names - will ipv6 and sctp addresses fit here?? */
+ char userName[MAX_USERNAME_SIZE + 1];
+ char domainName[MAX_USERNAME_SIZE + 1];
+ char * password;
+};
+
+/*
+ * there is one of these for each connection to a resource on a particular
+ * session
+ */
+struct cifsTconInfo {
+ struct list_head cifsConnectionList;
+ struct list_head openFileList;
+ struct semaphore tconSem;
+ struct cifsSesInfo *ses; /* pointer to session associated with */
+ char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource (in ASCII not UTF) */
+ char *nativeFileSystem;
+ __u16 tid; /* The 2 byte tree id */
+ __u16 Flags; /* optional support bits */
+ enum statusEnum tidStatus;
+ atomic_t useCount; /* how many mounts (explicit or implicit) to this share */
+#ifdef CONFIG_CIFS_STATS
+ atomic_t num_smbs_sent;
+ atomic_t num_writes;
+ atomic_t num_reads;
+ atomic_t num_oplock_brks;
+ atomic_t num_opens;
+ atomic_t num_deletes;
+ atomic_t num_mkdirs;
+ atomic_t num_rmdirs;
+ atomic_t num_renames;
+ atomic_t num_t2renames;
+ __u64 bytes_read;
+ __u64 bytes_written;
+ spinlock_t stat_lock;
+#endif
+ FILE_SYSTEM_DEVICE_INFO fsDevInfo;
+ FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if file system name truncated */
+ FILE_SYSTEM_UNIX_INFO fsUnixInfo;
+ int retry:1;
+ /* BB add field for back pointer to sb struct? */
+};
+
+/*
+ * This info hangs off the cifsFileInfo structure. This is used to track
+ * byte stream locks on the file
+ */
+struct cifsLockInfo {
+ struct cifsLockInfo *next;
+ int start;
+ int length;
+ int type;
+};
+
+/*
+ * One of these for each open instance of a file
+ */
+struct cifsFileInfo {
+ struct list_head tlist; /* pointer to next fid owned by tcon */
+ struct list_head flist; /* next fid (file instance) for this inode */
+ unsigned int uid; /* allows finding which FileInfo structure */
+ __u32 pid; /* process id who opened file */
+ __u16 netfid; /* file id from remote */
+ /* BB add lock scope info here if needed */ ;
+ /* lock scope id (0 if none) */
+ struct file * pfile; /* needed for writepage */
+ struct inode * pInode; /* needed for oplock break */
+ int endOfSearch:1; /* we have reached end of search */
+ int closePend:1; /* file is marked to close */
+ int emptyDir:1;
+ int invalidHandle:1; /* file closed via session abend */
+ struct semaphore fh_sem; /* prevents reopen race after dead ses*/
+ char * search_resume_name;
+ unsigned int resume_name_length;
+ __u32 resume_key;
+};
+
+/*
+ * One of these for each file inode
+ */
+
+struct cifsInodeInfo {
+ struct list_head lockList;
+ /* BB add in lists for dirty pages - i.e. write caching info for oplock */
+ struct list_head openFileList;
+ int write_behind_rc;
+ __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */
+ atomic_t inUse; /* num concurrent users (local openers cifs) of file*/
+ unsigned long time; /* jiffies of last update/check of inode */
+ int clientCanCacheRead:1; /* read oplock */
+ int clientCanCacheAll:1; /* read and writebehind oplock */
+ int oplockPending:1;
+ struct inode vfs_inode;
+};
+
+static inline struct cifsInodeInfo * CIFS_I(struct inode *inode)
+{
+ return (struct cifsInodeInfo *)&(inode->u);
+}
+
+static inline struct cifs_sb_info * CIFS_SB(struct super_block *sb)
+{
+ return (struct cifs_sb_info *) &(sb->u);
+}
+
+
+/* one of these for every pending CIFS request to the server */
+struct mid_q_entry {
+ struct list_head qhead; /* mids waiting on reply from this server */
+ __u16 mid; /* multiplex id */
+ __u16 pid; /* process id */
+ __u32 sequence_number; /* for CIFS signing */
+ __u16 command; /* smb command code */
+ struct timeval when_sent; /* time when smb sent */
+ struct cifsSesInfo *ses; /* smb was sent to this server */
+ struct task_struct *tsk; /* task waiting for response */
+ struct smb_hdr *resp_buf; /* response buffer */
+ int midState; /* wish this were enum but can not pass to wait_event */
+};
+
+struct oplock_q_entry {
+ struct list_head qhead;
+ struct inode * pinode;
+ struct cifsTconInfo * tcon;
+ __u16 netfid;
+};
+
+#define MID_FREE 0
+#define MID_REQUEST_ALLOCATED 1
+#define MID_REQUEST_SUBMITTED 2
+#define MID_RESPONSE_RECEIVED 4
+#define MID_RETRY_NEEDED 8 /* session closed while this request out */
+
+/*
+ *****************************************************************
+ * All constants go here
+ *****************************************************************
+ */
+
+#define UID_HASH (16)
+
+/*
+ * Note that ONE module should define _DECLARE_GLOBALS_HERE to cause the
+ * following to be declared.
+ */
+
+/****************************************************************************
+ * Locking notes. All updates to global variables and lists should be
+ * protected by spinlocks or semaphores.
+ *
+ * Spinlocks
+ * ---------
+ * GlobalMid_Lock protects:
+ * list operations on pending_mid_q and oplockQ
+ * updates to XID counters, multiplex id and SMB sequence numbers
+ * GlobalSMBSesLock protects:
+ * list operations on tcp and SMB session lists and tCon lists
+ * f_owner.lock protects certain per file struct operations
+ * mapping->page_lock protects certain per page operations
+ *
+ * Semaphores
+ * ----------
+ * sesSem operations on smb session
+ * tconSem operations on tree connection
+ * fh_sem file handle reconnection operations
+ *
+ ****************************************************************************/
+
+#ifdef DECLARE_GLOBALS_HERE
+#define GLOBAL_EXTERN
+#else
+#define GLOBAL_EXTERN extern
+#endif
+
+/*
+ * The list of servers that did not respond with NT LM 0.12.
+ * This list helps improve performance and eliminate the messages indicating
+ * that we had a communications error talking to the server in this list.
+ */
+GLOBAL_EXTERN struct servers_not_supported *NotSuppList; /*@z4a */
+
+/*
+ * The following is a hash table of all the users we know about.
+ */
+GLOBAL_EXTERN struct smbUidInfo *GlobalUidList[UID_HASH];
+
+GLOBAL_EXTERN struct list_head GlobalServerList; /* BB not implemented yet */
+GLOBAL_EXTERN struct list_head GlobalSMBSessionList;
+GLOBAL_EXTERN struct list_head GlobalTreeConnectionList;
+GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */
+
+GLOBAL_EXTERN struct list_head GlobalOplock_Q;
+
+/*
+ * Global transaction id (XID) information
+ */
+GLOBAL_EXTERN unsigned int GlobalCurrentXid; /* protected by GlobalMid_Sem */
+GLOBAL_EXTERN unsigned int GlobalTotalActiveXid; /* prot by GlobalMid_Sem */
+GLOBAL_EXTERN unsigned int GlobalMaxActiveXid; /* prot by GlobalMid_Sem */
+GLOBAL_EXTERN spinlock_t GlobalMid_Lock; /* protects above and list operations */
+ /* on midQ entries */
+GLOBAL_EXTERN char Local_System_Name[15];
+
+/*
+ * Global counters, updated atomically
+ */
+GLOBAL_EXTERN atomic_t sesInfoAllocCount;
+GLOBAL_EXTERN atomic_t tconInfoAllocCount;
+
+GLOBAL_EXTERN atomic_t tcpSesReconnectCount;
+GLOBAL_EXTERN atomic_t tconInfoReconnectCount;
+
+/* Various Debug counters to remove someday (BB) */
+GLOBAL_EXTERN atomic_t bufAllocCount;
+GLOBAL_EXTERN atomic_t midCount;
+
+/* Misc globals */
+GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions
+ to be established on existing mount if we
+ have the uid/password or Kerberos credential
+ or equivalent for current user */
+GLOBAL_EXTERN unsigned int oplockEnabled;
+GLOBAL_EXTERN unsigned int quotaEnabled;
+GLOBAL_EXTERN unsigned int lookupCacheEnabled;
+GLOBAL_EXTERN unsigned int extended_security; /* if on, session setup sent
+ with more secure ntlmssp2 challenge/resp */
+GLOBAL_EXTERN unsigned int ntlmv2_support; /* better optional password hash */
+GLOBAL_EXTERN unsigned int sign_CIFS_PDUs; /* enable smb packet signing */
+GLOBAL_EXTERN unsigned int linuxExtEnabled; /* enable Linux/Unix CIFS extensions */
+
diff --git a/release/src/linux/linux/fs/cifs/cifspdu.h b/release/src/linux/linux/fs/cifs/cifspdu.h
new file mode 100644
index 00000000..067eb4e3
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/cifspdu.h
@@ -0,0 +1,1793 @@
+/*
+ * fs/cifs/cifspdu.h
+ *
+ * Copyright (c) International Business Machines Corp., 2002
+ * Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _CIFSPDU_H
+#define _CIFSPDU_H
+
+#include <net/sock.h>
+
+#define CIFS_PROT 0
+#define BAD_PROT CIFS_PROT+1
+
+/* SMB command codes */
+#define SMB_COM_CREATE_DIRECTORY 0x00
+#define SMB_COM_DELETE_DIRECTORY 0x01
+#define SMB_COM_CLOSE 0x04
+#define SMB_COM_DELETE 0x06
+#define SMB_COM_RENAME 0x07
+#define SMB_COM_LOCKING_ANDX 0x24
+#define SMB_COM_COPY 0x29
+#define SMB_COM_READ_ANDX 0x2E
+#define SMB_COM_WRITE_ANDX 0x2F
+#define SMB_COM_TRANSACTION2 0x32
+#define SMB_COM_TRANSACTION2_SECONDARY 0x33
+#define SMB_COM_FIND_CLOSE2 0x34
+#define SMB_COM_TREE_DISCONNECT 0x71
+#define SMB_COM_NEGOTIATE 0x72
+#define SMB_COM_SESSION_SETUP_ANDX 0x73
+#define SMB_COM_LOGOFF_ANDX 0x74
+#define SMB_COM_TREE_CONNECT_ANDX 0x75
+#define SMB_COM_NT_TRANSACT 0xA0
+#define SMB_COM_NT_TRANSACT_SECONDARY 0xA1
+#define SMB_COM_NT_CREATE_ANDX 0xA2
+#define SMB_COM_NT_RENAME 0xA5
+
+/* Transact2 subcommand codes */
+#define TRANS2_OPEN 0x00
+#define TRANS2_FIND_FIRST 0x01
+#define TRANS2_FIND_NEXT 0x02
+#define TRANS2_QUERY_FS_INFORMATION 0x03
+#define TRANS2_QUERY_PATH_INFORMATION 0x05
+#define TRANS2_SET_PATH_INFORMATION 0x06
+#define TRANS2_QUERY_FILE_INFORMATION 0x07
+#define TRANS2_SET_FILE_INFORMATION 0x08
+#define TRANS2_GET_DFS_REFERRAL 0x10
+#define TRANS2_REPORT_DFS_INCOSISTENCY 0x11
+
+/* NT Transact subcommand codes */
+#define NT_TRANSACT_CREATE 0x01
+#define NT_TRANSACT_IOCTL 0x02
+#define NT_TRANSACT_SET_SECURITY_DESC 0x03
+#define NT_TRANSACT_NOTIFY_CHANGE 0x04
+#define NT_TRANSACT_RENAME 0x05
+#define NT_TRANSACT_QUERY_SECURITY_DESC 0x06
+#define NT_TRANSACT_GET_USER_QUOTA 0x07
+#define NT_TRANSACT_SET_USER_QUOTA 0x08
+
+#define MAX_CIFS_HDR_SIZE 256 /* chained NTCreateXReadX will probably be biggest */
+
+/* internal cifs vfs structures */
+/*****************************************************************
+ * All constants go here
+ *****************************************************************
+ */
+
+/*
+ * Starting value for maximum SMB size negotiation
+ */
+#define CIFS_MAX_MSGSIZE (4*4096)
+
+/*
+ * Size of encrypted user password in bytes
+ */
+#define CIFS_ENCPWD_SIZE (16)
+
+/*
+ * Size of the crypto key returned on the negotiate SMB in bytes
+ */
+#define CIFS_CRYPTO_KEY_SIZE (8)
+
+/*
+ * Size of the session key (crypto key encrypted with the password
+ */
+#define CIFS_SESSION_KEY_SIZE (24)
+
+/*
+ * Maximum user name length
+ */
+#define CIFS_UNLEN (20)
+
+/*
+ * Flags on SMB open
+ */
+#define SMBOPEN_WRITE_THROUGH 0x4000
+#define SMBOPEN_DENY_ALL 0x0010
+#define SMBOPEN_DENY_WRITE 0x0020
+#define SMBOPEN_DENY_READ 0x0030
+#define SMBOPEN_DENY_NONE 0x0040
+#define SMBOPEN_READ 0x0000
+#define SMBOPEN_WRITE 0x0001
+#define SMBOPEN_READWRITE 0x0002
+#define SMBOPEN_EXECUTE 0x0003
+
+#define SMBOPEN_OCREATE 0x0010
+#define SMBOPEN_OTRUNC 0x0002
+#define SMBOPEN_OAPPEND 0x0001
+
+/*
+ * SMB flag definitions
+ */
+#define SMBFLG_EXTD_LOCK 0x01 /* server supports lock-read write-unlock primitives */
+#define SMBFLG_RCV_POSTED 0x02 /* obsolete */
+#define SMBFLG_RSVD 0x04
+#define SMBFLG_CASELESS 0x08 /* all pathnames treated as caseless (off implies case sensitive file handling requested) */
+#define SMBFLG_CANONICAL_PATH_FORMAT 0x10 /* obsolete */
+#define SMBFLG_OLD_OPLOCK 0x20 /* obsolete */
+#define SMBFLG_OLD_OPLOCK_NOTIFY 0x40 /* obsolete */
+#define SMBFLG_RESPONSE 0x80 /* this PDU is a response from server */
+
+/*
+ * SMB flag2 definitions
+ */
+#define SMBFLG2_KNOWS_LONG_NAMES 0x0001 /* can send long (non-8.3) path names in response */
+#define SMBFLG2_KNOWS_EAS 0x0002
+#define SMBFLG2_SECURITY_SIGNATURE 0x0004
+#define SMBFLG2_IS_LONG_NAME 0x0040
+#define SMBFLG2_EXT_SEC 0x0800
+#define SMBFLG2_DFS 0x1000
+#define SMBFLG2_PAGING_IO 0x2000
+#define SMBFLG2_ERR_STATUS 0x4000
+#define SMBFLG2_UNICODE 0x8000
+
+/*
+ * These are the file access permission bits defined in CIFS for the
+ * NTCreateAndX as well as the level 0x107
+ * TRANS2_QUERY_PATH_INFORMATION API. The level 0x107, SMB_QUERY_FILE_ALL_INFO
+ * responds with the AccessFlags.
+ * The AccessFlags specifies the access permissions a caller has to the
+ * file and can have any suitable combination of the following values:
+ */
+
+#define FILE_READ_DATA 0x00000001 /* Data can be read from the file */
+#define FILE_WRITE_DATA 0x00000002 /* Data can be written to the file */
+#define FILE_APPEND_DATA 0x00000004 /* Data can be appended to the file */
+#define FILE_READ_EA 0x00000008 /* Extended attributes associated */
+ /* with the file can be read */
+#define FILE_WRITE_EA 0x00000010 /* Extended attributes associated */
+ /* with the file can be written */
+#define FILE_EXECUTE 0x00000020 /*Data can be read into memory from */
+ /* the file using system paging I/O */
+#define FILE_DELETE_CHILD 0x00000040
+#define FILE_READ_ATTRIBUTES 0x00000080 /* Attributes associated with the */
+ /* file can be read */
+#define FILE_WRITE_ATTRIBUTES 0x00000100 /* Attributes associated with the */
+ /* file can be written */
+#define DELETE 0x00010000 /* The file can be deleted */
+#define READ_CONTROL 0x00020000 /* The access control list and */
+ /* ownership associated with the */
+ /* file can be read */
+#define WRITE_DAC 0x00040000 /* The access control list and */
+ /* ownership associated with the */
+ /* file can be written. */
+#define WRITE_OWNER 0x00080000 /* Ownership information associated */
+ /* with the file can be written */
+#define SYNCHRONIZE 0x00100000 /* The file handle can waited on to */
+ /* synchronize with the completion */
+ /* of an input/output request */
+#define GENERIC_ALL 0x10000000
+#define GENERIC_EXECUTE 0x20000000
+#define GENERIC_WRITE 0x40000000
+#define GENERIC_READ 0x80000000
+ /* In summary - Relevant file */
+ /* access flags from CIFS are */
+ /* file_read_data, file_write_data */
+ /* file_execute, file_read_attributes */
+ /* write_dac, and delete. */
+
+/*
+ * Invalid readdir handle
+ */
+#define CIFS_NO_HANDLE 0xFFFF
+
+/* IPC$ in ASCII */
+#define CIFS_IPC_RESOURCE "\x49\x50\x43\x24"
+
+/* IPC$ in Unicode */
+#define CIFS_IPC_UNICODE_RESOURCE "\x00\x49\x00\x50\x00\x43\x00\x24\x00\x00"
+
+/* Unicode Null terminate 2 bytes of 0 */
+#define UNICODE_NULL "\x00\x00"
+#define ASCII_NULL 0x00
+
+/*
+ * Server type values (returned on EnumServer API
+ */
+#define CIFS_SV_TYPE_DC 0x00000008
+#define CIFS_SV_TYPE_BACKDC 0x00000010
+
+/*
+ * Alias type flags (From EnumAlias API call
+ */
+#define CIFS_ALIAS_TYPE_FILE 0x0001
+#define CIFS_SHARE_TYPE_FILE 0x0000
+
+/*
+ * File Attribute flags
+ */
+#define ATTR_READONLY 0x0001
+#define ATTR_HIDDEN 0x0002
+#define ATTR_SYSTEM 0x0004
+#define ATTR_VOLUME 0x0008
+#define ATTR_DIRECTORY 0x0010
+#define ATTR_ARCHIVE 0x0020
+#define ATTR_DEVICE 0x0040
+#define ATTR_NORMAL 0x0080
+#define ATTR_TEMPORARY 0x0100
+#define ATTR_SPARSE 0x0200
+#define ATTR_REPARSE 0x0400
+#define ATTR_COMPRESSED 0x0800
+#define ATTR_OFFLINE 0x1000 /* ie file not immediately available - offline storage */
+#define ATTR_NOT_CONTENT_INDEXED 0x2000
+#define ATTR_ENCRYPTED 0x4000
+#define ATTR_POSIX_SEMANTICS 0x01000000
+#define ATTR_BACKUP_SEMANTICS 0x02000000
+#define ATTR_DELETE_ON_CLOSE 0x04000000
+#define ATTR_SEQUENTIAL_SCAN 0x08000000
+#define ATTR_RANDOM_ACCESS 0x10000000
+#define ATTR_NO_BUFFERING 0x20000000
+#define ATTR_WRITE_THROUGH 0x80000000
+
+/* ShareAccess flags */
+#define FILE_NO_SHARE 0x00000000
+#define FILE_SHARE_READ 0x00000001
+#define FILE_SHARE_WRITE 0x00000002
+#define FILE_SHARE_DELETE 0x00000004
+#define FILE_SHARE_ALL 0x00000007
+
+/* CreateDisposition flags */
+#define FILE_SUPERSEDE 0x00000000
+#define FILE_OPEN 0x00000001
+#define FILE_CREATE 0x00000002
+#define FILE_OPEN_IF 0x00000003
+#define FILE_OVERWRITE 0x00000004
+#define FILE_OVERWRITE_IF 0x00000005
+
+/* CreateOptions */
+#define CREATE_NOT_FILE 0x00000001 /* if set must not be file */
+#define CREATE_WRITE_THROUGH 0x00000002
+#define CREATE_NOT_DIR 0x00000040 /* if set must not be directory */
+#define CREATE_RANDOM_ACCESS 0x00000800
+#define CREATE_DELETE_ON_CLOSE 0x00001000
+#define OPEN_REPARSE_POINT 0x00200000
+
+/* ImpersonationLevel flags */
+#define SECURITY_ANONYMOUS 0
+#define SECURITY_IDENTIFICATION 1
+#define SECURITY_IMPERSONATION 2
+#define SECURITY_DELEGATION 3
+
+/* SecurityFlags */
+#define SECURITY_CONTEXT_TRACKING 0x01
+#define SECURITY_EFFECTIVE_ONLY 0x02
+
+/*
+ * Default PID value, used in all SMBs where the PID is not important
+ */
+#define CIFS_DFT_PID 0x1234
+
+/*
+ * We use the same routine for Copy and Move SMBs. This flag is used to
+ * distinguish
+ */
+#define CIFS_COPY_OP 1
+#define CIFS_RENAME_OP 2
+
+#define GETU16(var) (*((__u16 *)var)) /* BB check for endian issues */
+#define GETU32(var) (*((__u32 *)var)) /* BB check for endian issues */
+
+#pragma pack(1)
+
+struct smb_hdr {
+ __u32 smb_buf_length; /* big endian on wire *//* BB length is only two or three bytes - with one or two byte type preceding it but that is always zero - we could mask the type byte off just in case BB */
+ __u8 Protocol[4];
+ __u8 Command;
+ union {
+ struct {
+ __u8 ErrorClass;
+ __u8 Reserved;
+ __u16 Error; /* note: treated as little endian (le) on wire */
+ } DosError;
+ __u32 CifsError; /* note: le */
+ } Status;
+ __u8 Flags;
+ __u16 Flags2; /* note: le */
+ __u16 PidHigh; /* note: le */
+ union {
+ struct {
+ __u32 SequenceNumber; /* le */
+ __u32 Reserved; /* zero */
+ } Sequence;
+ __u8 SecuritySignature[8]; /* le */
+ } Signature;
+ __u8 pad[2];
+ __u16 Tid;
+ __u16 Pid; /* note: le */
+ __u16 Uid;
+ __u16 Mid;
+ __u8 WordCount;
+};
+/* given a pointer to an smb_hdr retrieve the value of byte count */
+#define BCC(smb_var) ( *(__u16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) )
+
+/* given a pointer to an smb_hdr retrieve the pointer to the byte area */
+#define pByteArea(smb_var) ((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) + 2 )
+
+/*
+ * Computer Name Length
+ */
+#define CNLEN 15
+
+/*
+ * Share Name Length @S8A
+ * Note: This length is limited by the SMB used to get @S8A
+ * the Share info. NetShareEnum only returns 13 @S8A
+ * chars, including the null termination. @S8A
+ */
+#define SNLEN 12 /*@S8A */
+
+/*
+ * Comment Length
+ */
+#define MAXCOMMENTLEN 40
+
+/*
+ * The OS/2 maximum path name
+ */
+#define MAX_PATHCONF 256
+
+/*
+ * SMB frame definitions (following must be packed structs)
+ * See the SNIA CIFS Specification for details.
+ *
+ * The Naming convention is the lower case version of the
+ * smb command code name for the struct and this is typedef to the
+ * uppercase version of the same name with the prefix SMB_ removed
+ * for brevity. Although typedefs are not commonly used for
+ * structure definitions in the Linux kernel, their use in the
+ * CIFS standards document, which this code is based on, may
+ * make this one of the cases where typedefs for structures make
+ * sense to improve readability for readers of the standards doc.
+ * Typedefs can always be removed later if they are too distracting
+ * and they are only used for the CIFSs PDUs themselves, not
+ * internal cifs vfs structures
+ *
+ */
+
+typedef struct negotiate_req {
+ struct smb_hdr hdr; /* wct = 0 */
+ __u16 ByteCount;
+ unsigned char DialectsArray[1];
+} NEGOTIATE_REQ;
+
+typedef struct negotiate_rsp {
+ struct smb_hdr hdr; /* wct = 17 */
+ __u16 DialectIndex;
+ __u8 SecurityMode;
+ __u16 MaxMpxCount;
+ __u16 MaxNumberVcs;
+ __u32 MaxBufferSize;
+ __u32 MaxRawSize;
+ __u32 SessionKey;
+ __u32 Capabilities; /* see below */
+ __u32 SystemTimeLow;
+ __u32 SystemTimeHigh;
+ __u16 ServerTimeZone;
+ __u8 EncryptionKeyLength;
+ __u16 ByteCount;
+ union {
+ unsigned char EncryptionKey[1]; /* if cap extended security is off */
+ /* followed by Domain name - if extended security is off */
+ /* followed by 16 bytes of server GUID */
+ /* followed by security blob if cap_extended_security negotiated */
+ struct {
+ unsigned char GUID[16];
+ unsigned char SecurityBlob[1];
+ } extended_response;
+ } u;
+} NEGOTIATE_RSP;
+
+/* SecurityMode bits */
+#define SECMODE_USER 0x01 /* off indicates share level security */
+#define SECMODE_PW_ENCRYPT 0x02
+#define SECMODE_SIGN_ENABLED 0x04 /* SMB security signatures enabled */
+#define SECMODE_SIGN_REQUIRED 0x08 /* SMB security signatures required */
+
+/* Negotiate response Capabilities */
+#define CAP_RAW_MODE 0x00000001
+#define CAP_MPX_MODE 0x00000002
+#define CAP_UNICODE 0x00000004
+#define CAP_LARGE_FILES 0x00000008
+#define CAP_NT_SMBS 0x00000010 /* implies CAP_NT_FIND */
+#define CAP_RPC_REMOTE_APIS 0x00000020
+#define CAP_STATUS32 0x00000040
+#define CAP_LEVEL_II_OPLOCKS 0x00000080
+#define CAP_LOCK_AND_READ 0x00000100
+#define CAP_NT_FIND 0x00000200
+#define CAP_DFS 0x00001000
+#define CAP_INFOLEVEL_PASSTHRU 0x00002000
+#define CAP_LARGE_READ_X 0x00004000
+#define CAP_LARGE_WRITE_X 0x00008000
+#define CAP_UNIX 0x00800000
+#define CAP_RESERVED 0x02000000
+#define CAP_BULK_TRANSFER 0x20000000
+#define CAP_COMPRESSED_DATA 0x40000000
+#define CAP_EXTENDED_SECURITY 0x80000000
+
+typedef union smb_com_session_setup_andx {
+ struct { /* request format */
+ struct smb_hdr hdr; /* wct = 12 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __u16 AndXOffset;
+ __u16 MaxBufferSize;
+ __u16 MaxMpxCount;
+ __u16 VcNumber;
+ __u32 SessionKey;
+ __u16 SecurityBlobLength;
+ __u32 Reserved;
+ __u32 Capabilities; /* see below */
+ __u16 ByteCount;
+ unsigned char SecurityBlob[1]; /* followed by */
+ /* STRING NativeOS */
+ /* STRING NativeLanMan */
+ } req; /* NTLM request format (with extended security */
+
+ struct { /* request format */
+ struct smb_hdr hdr; /* wct = 13 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __u16 AndXOffset;
+ __u16 MaxBufferSize;
+ __u16 MaxMpxCount;
+ __u16 VcNumber;
+ __u32 SessionKey;
+ __u16 CaseInsensitivePasswordLength; /* ASCII password length */
+ __u16 CaseSensitivePasswordLength; /* Unicode password length */
+ __u32 Reserved; /* see below */
+ __u32 Capabilities;
+ __u16 ByteCount;
+ unsigned char CaseInsensitivePassword[1]; /* followed by: */
+ /* unsigned char * CaseSensitivePassword; */
+ /* STRING AccountName */
+ /* STRING PrimaryDomain */
+ /* STRING NativeOS */
+ /* STRING NativeLanMan */
+ } req_no_secext; /* NTLM request format (without extended security */
+
+ struct { /* default (NTLM) response format */
+ struct smb_hdr hdr; /* wct = 4 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __u16 AndXOffset;
+ __u16 Action; /* see below */
+ __u16 SecurityBlobLength;
+ __u16 ByteCount;
+ unsigned char SecurityBlob[1]; /* followed by */
+/* unsigned char * NativeOS; */
+/* unsigned char * NativeLanMan; */
+/* unsigned char * PrimaryDomain; */
+ } resp; /* NTLM response format (with or without extended security */
+
+ struct { /* request format */
+ struct smb_hdr hdr; /* wct = 10 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __u16 AndXOffset;
+ __u16 MaxBufferSize;
+ __u16 MaxMpxCount;
+ __u16 VcNumber;
+ __u32 SessionKey;
+ __u16 PassswordLength;
+ __u32 Reserved;
+ __u16 ByteCount;
+ unsigned char AccountPassword[1]; /* followed by */
+ /* STRING AccountName */
+ /* STRING PrimaryDomain */
+ /* STRING NativeOS */
+ /* STRING NativeLanMan */
+ } old_req; /* pre-NTLM (LANMAN2.1) request format */
+
+ struct { /* default (NTLM) response format */
+ struct smb_hdr hdr; /* wct = 3 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __u16 AndXOffset;
+ __u16 Action; /* see below */
+ __u16 ByteCount;
+ unsigned char NativeOS[1]; /* followed by */
+/* unsigned char * NativeLanMan; */
+/* unsigned char * PrimaryDomain; */
+ } old_resp; /* pre-NTLM (LANMAN2.1) response format */
+} SESSION_SETUP_ANDX;
+
+#define CIFS_NETWORK_OPSYS "CIFS VFS Client for Linux"
+
+/* Capabilities bits (for NTLM SessSetup request) */
+#define CAP_UNICODE 0x00000004
+#define CAP_LARGE_FILES 0x00000008
+#define CAP_NT_SMBS 0x00000010
+#define CAP_STATUS32 0x00000040
+#define CAP_LEVEL_II_OPLOCKS 0x00000080
+#define CAP_NT_FIND 0x00000200 /* reserved should be zero (presumably because NT_SMBs implies the same thing) */
+#define CAP_BULK_TRANSFER 0x20000000
+#define CAP_EXTENDED_SECURITY 0x80000000
+
+/* Action bits */
+#define GUEST_LOGIN 1
+
+typedef struct smb_com_tconx_req {
+ struct smb_hdr hdr; /* wct = 4 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __u16 AndXOffset;
+ __u16 Flags; /* see below */
+ __u16 PasswordLength;
+ __u16 ByteCount;
+ unsigned char Password[1]; /* followed by */
+/* STRING Path *//* \\server\share name */
+ /* STRING Service */
+} TCONX_REQ;
+
+typedef struct smb_com_tconx_rsp {
+ struct smb_hdr hdr; /* wct = 3 *//* note that Win2000 has sent wct=7 in some cases on responses. Four unspecified words followed OptionalSupport */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __u16 AndXOffset;
+ __u16 OptionalSupport; /* see below */
+ __u16 ByteCount;
+ unsigned char Service[1]; /* always ASCII, not Unicode */
+ /* STRING NativeFileSystem */
+} TCONX_RSP;
+
+/* tree connect Flags */
+#define DISCONNECT_TID 0x0001
+#define TCON_EXTENDED_SECINFO 0x0008
+/* OptionalSupport bits */
+#define SMB_SUPPORT_SEARCH_BITS 0x0001 /* must have bits (exclusive searches suppt. */
+#define SMB_SHARE_IS_IN_DFS 0x0002
+
+typedef struct smb_com_logoff_andx_req {
+
+ struct smb_hdr hdr; /* wct = 2 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __u16 AndXOffset;
+ __u16 ByteCount;
+} LOGOFF_ANDX_REQ;
+
+typedef struct smb_com_logoff_andx_rsp {
+ struct smb_hdr hdr; /* wct = 2 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __u16 AndXOffset;
+ __u16 ByteCount;
+} LOGOFF_ANDX_RSP;
+
+typedef union smb_com_tree_disconnect { /* as an altetnative can use flag on tree_connect PDU to effect disconnect *//* probably the simplest SMB PDU */
+ struct {
+ struct smb_hdr hdr; /* wct = 0 */
+ __u16 ByteCount; /* bcc = 0 */
+ } req;
+ struct {
+ struct smb_hdr hdr; /* wct = 0 */
+ __u16 ByteCount; /* bcc = 0 */
+ } resp;
+} TREE_DISCONNECT;
+
+typedef struct smb_com_close_req {
+ struct smb_hdr hdr; /* wct = 3 */
+ __u16 FileID;
+ __u32 LastWriteTime; /* should be zero */
+ __u16 ByteCount; /* 0 */
+} CLOSE_REQ;
+
+typedef struct smb_com_close_rsp {
+ struct smb_hdr hdr; /* wct = 0 */
+ __u16 ByteCount; /* bct = 0 */
+} CLOSE_RSP;
+
+typedef struct smb_com_findclose_req {
+ struct smb_hdr hdr; /* wct = 1 */
+ __u16 FileID;
+ __u16 ByteCount; /* 0 */
+} FINDCLOSE_REQ;
+
+/* OpenFlags */
+#define REQ_OPLOCK 0x00000002
+#define REQ_BATCHOPLOCK 0x00000004
+#define REQ_OPENDIRONLY 0x00000008
+
+typedef struct smb_com_open_req { /* also handles create */
+ struct smb_hdr hdr; /* wct = 24 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __u16 AndXOffset;
+ __u8 Reserved; /* Must Be Zero */
+ __u16 NameLength;
+ __u32 OpenFlags;
+ __u32 RootDirectoryFid;
+ __u32 DesiredAccess;
+ __u64 AllocationSize;
+ __u32 FileAttributes;
+ __u32 ShareAccess;
+ __u32 CreateDisposition;
+ __u32 CreateOptions;
+ __u32 ImpersonationLevel;
+ __u8 SecurityFlags;
+ __u16 ByteCount;
+ char fileName[1];
+} OPEN_REQ;
+
+/* open response: oplock levels */
+#define OPLOCK_NONE 0
+#define OPLOCK_EXCLUSIVE 1
+#define OPLOCK_BATCH 2
+#define OPLOCK_READ 3 /* level 2 oplock */
+
+/* open response for CreateAction shifted left */
+#define CIFS_CREATE_ACTION 0x20000 /* file created */
+
+typedef struct smb_com_open_rsp {
+ struct smb_hdr hdr; /* wct = 34 BB */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __u16 AndXOffset;
+ __u8 OplockLevel;
+ __u16 Fid;
+ __u32 CreateAction;
+ __u64 CreationTime;
+ __u64 LastAccessTime;
+ __u64 LastWriteTime;
+ __u64 ChangeTime;
+ __u32 FileAttributes;
+ __u64 AllocationSize;
+ __u64 EndOfFile;
+ __u16 FileType;
+ __u16 DeviceState;
+ __u8 DirectoryFlag;
+ __u16 ByteCount; /* bct = 0 */
+} OPEN_RSP;
+
+typedef struct smb_com_write_req {
+ struct smb_hdr hdr; /* wct = 14 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __u16 AndXOffset;
+ __u16 Fid;
+ __u32 OffsetLow;
+ __u32 Reserved;
+ __u16 WriteMode;
+ __u16 Remaining;
+ __u16 DataLengthHigh;
+ __u16 DataLengthLow;
+ __u16 DataOffset;
+ __u32 OffsetHigh;
+ __u16 ByteCount;
+ __u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */
+ char Data[1];
+} WRITE_REQ;
+
+typedef struct smb_com_write_rsp {
+ struct smb_hdr hdr; /* wct = 6 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __u16 AndXOffset;
+ __u16 Count;
+ __u16 Remaining;
+ __u32 Reserved;
+ __u16 ByteCount;
+} WRITE_RSP;
+
+typedef struct smb_com_read_req {
+ struct smb_hdr hdr; /* wct = 12 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __u16 AndXOffset;
+ __u16 Fid;
+ __u32 OffsetLow;
+ __u16 MaxCount;
+ __u16 MinCount; /* obsolete */
+ __u32 MaxCountHigh;
+ __u16 Remaining;
+ __u32 OffsetHigh;
+ __u16 ByteCount;
+} READ_REQ;
+
+typedef struct smb_com_read_rsp {
+ struct smb_hdr hdr; /* wct = 12 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __u16 AndXOffset;
+ __u16 Remaining;
+ __u16 DataCompactionMode;
+ __u16 Reserved;
+ __u16 DataLength;
+ __u16 DataOffset;
+ __u16 DataLengthHigh;
+ __u64 Reserved2;
+ __u16 ByteCount;
+ __u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */
+ char Data[1];
+} READ_RSP;
+
+typedef struct locking_andx_range {
+ __u16 Pid;
+ __u16 Pad;
+ __u32 OffsetHigh;
+ __u32 OffsetLow;
+ __u32 LengthHigh;
+ __u32 LengthLow;
+} LOCKING_ANDX_RANGE;
+
+#define LOCKING_ANDX_SHARED_LOCK 0x01
+#define LOCKING_ANDX_OPLOCK_RELEASE 0x02
+#define LOCKING_ANDX_CHANGE_LOCKTYPE 0x04
+#define LOCKING_ANDX_CANCEL_LOCK 0x08
+#define LOCKING_ANDX_LARGE_FILES 0x10 /* always on for us */
+
+typedef struct smb_com_lock_req {
+ struct smb_hdr hdr; /* wct = 8 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __u16 AndXOffset;
+ __u16 Fid;
+ __u8 LockType;
+ __u8 OplockLevel;
+ __u32 Timeout;
+ __u16 NumberOfUnlocks;
+ __u16 NumberOfLocks;
+ __u16 ByteCount;
+ LOCKING_ANDX_RANGE Locks[1];
+} LOCK_REQ;
+
+typedef struct smb_com_lock_rsp {
+ struct smb_hdr hdr; /* wct = 2 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __u16 AndXOffset;
+ __u16 ByteCount;
+} LOCK_RSP;
+
+typedef struct smb_com_rename_req {
+ struct smb_hdr hdr; /* wct = 1 */
+ __u16 SearchAttributes; /* target file attributes */
+ __u16 ByteCount;
+ __u8 BufferFormat; /* 4 = ASCII or Unicode */
+ unsigned char OldFileName[1];
+ /* followed by __u8 BufferFormat2 */
+ /* followed by NewFileName */
+} RENAME_REQ;
+
+ /* copy request flags */
+#define COPY_MUST_BE_FILE 0x0001
+#define COPY_MUST_BE_DIR 0x0002
+#define COPY_TARGET_MODE_ASCII 0x0004 /* if not set, binary */
+#define COPY_SOURCE_MODE_ASCII 0x0008 /* if not set, binary */
+#define COPY_VERIFY_WRITES 0x0010
+#define COPY_TREE 0x0020
+
+typedef struct smb_com_copy_req {
+ struct smb_hdr hdr; /* wct = 3 */
+ __u16 Tid2;
+ __u16 OpenFunction;
+ __u16 Flags;
+ __u16 ByteCount;
+ __u8 BufferFormat; /* 4 = ASCII or Unicode */
+ unsigned char OldFileName[1];
+ /* followed by __u8 BufferFormat2 */
+ /* followed by NewFileName string */
+} COPY_REQ;
+
+typedef struct smb_com_copy_rsp {
+ struct smb_hdr hdr; /* wct = 1 */
+ __u16 CopyCount; /* number of files copied */
+ __u16 ByteCount; /* may be zero */
+ __u8 BufferFormat; /* 0x04 - only present if errored file follows */
+ unsigned char ErrorFileName[1]; /* only present if error in copy */
+} COPY_RSP;
+
+#define CREATE_HARD_LINK 0x103
+#define MOVEFILE_COPY_ALLOWED 0x0002
+#define MOVEFILE_REPLACE_EXISTING 0x0001
+
+typedef struct smb_com_nt_rename_req { /* A5 - also used for create hardlink */
+ struct smb_hdr hdr; /* wct = 4 */
+ __u16 SearchAttributes; /* target file attributes */
+ __u16 Flags; /* spec says Information Level */
+ __u32 ClusterCount;
+ __u16 ByteCount;
+ __u8 BufferFormat; /* 4 = ASCII or Unicode */
+ unsigned char OldFileName[1];
+ /* followed by __u8 BufferFormat2 */
+ /* followed by NewFileName */
+} NT_RENAME_REQ;
+
+typedef struct smb_com_rename_rsp {
+ struct smb_hdr hdr; /* wct = 0 */
+ __u16 ByteCount; /* bct = 0 */
+} RENAME_RSP;
+
+typedef struct smb_com_delete_file_req {
+ struct smb_hdr hdr; /* wct = 1 */
+ __u16 SearchAttributes;
+ __u16 ByteCount;
+ __u8 BufferFormat; /* 4 = ASCII */
+ unsigned char fileName[1];
+} DELETE_FILE_REQ;
+
+typedef struct smb_com_delete_file_rsp {
+ struct smb_hdr hdr; /* wct = 0 */
+ __u16 ByteCount; /* bct = 0 */
+} DELETE_FILE_RSP;
+
+typedef struct smb_com_delete_directory_req {
+ struct smb_hdr hdr; /* wct = 0 */
+ __u16 ByteCount;
+ __u8 BufferFormat; /* 4 = ASCII */
+ unsigned char DirName[1];
+} DELETE_DIRECTORY_REQ;
+
+typedef struct smb_com_delete_directory_rsp {
+ struct smb_hdr hdr; /* wct = 0 */
+ __u16 ByteCount; /* bct = 0 */
+} DELETE_DIRECTORY_RSP;
+
+typedef struct smb_com_create_directory_req {
+ struct smb_hdr hdr; /* wct = 0 */
+ __u16 ByteCount;
+ __u8 BufferFormat; /* 4 = ASCII */
+ unsigned char DirName[1];
+} CREATE_DIRECTORY_REQ;
+
+typedef struct smb_com_create_directory_rsp {
+ struct smb_hdr hdr; /* wct = 0 */
+ __u16 ByteCount; /* bct = 0 */
+} CREATE_DIRECTORY_RSP;
+
+/***************************************************/
+/* NT Transact structure defintions follow */
+/* Currently only ioctl and notify are implemented */
+/***************************************************/
+typedef struct smb_com_transaction_ioctl_req {
+ struct smb_hdr hdr; /* wct = 23 */
+ __u8 MaxSetupCount;
+ __u16 Reserved;
+ __u32 TotalParameterCount;
+ __u32 TotalDataCount;
+ __u32 MaxParameterCount;
+ __u32 MaxDataCount;
+ __u32 ParameterCount;
+ __u32 ParameterOffset;
+ __u32 DataCount;
+ __u32 DataOffset;
+ __u8 SetupCount; /* four setup words follow subcommand */
+ /* SNIA spec incorrectly included spurious pad here */
+ __u16 SubCommand;/* 2 = IOCTL/FSCTL */
+ __u32 FunctionCode;
+ __u16 Fid;
+ __u8 IsFsctl; /* 1 = File System Control, 0 = device control (IOCTL)*/
+ __u8 IsRootFlag; /* 1 = apply command to root of share (must be DFS share)*/
+ __u16 ByteCount;
+ __u8 Pad[3];
+ __u8 Data[1];
+} TRANSACT_IOCTL_REQ;
+
+typedef struct smb_com_transaction_ioctl_rsp {
+ struct smb_hdr hdr; /* wct = 19 */
+ __u8 Reserved[3];
+ __u32 TotalParameterCount;
+ __u32 TotalDataCount;
+ __u32 ParameterCount;
+ __u32 ParameterOffset;
+ __u32 ParameterDisplacement;
+ __u32 DataCount;
+ __u32 DataOffset;
+ __u32 DataDisplacement;
+ __u8 SetupCount; /* 1 */
+ __u16 ReturnedDataLen;
+ __u16 ByteCount;
+ __u8 Pad[3];
+} TRANSACT_IOCTL_RSP;
+
+typedef struct smb_com_transaction_change_notify_req {
+ struct smb_hdr hdr; /* wct = 23 */
+ __u8 MaxSetupCount;
+ __u16 Reserved;
+ __u32 TotalParameterCount;
+ __u32 TotalDataCount;
+ __u32 MaxParameterCount;
+ __u32 MaxDataCount;
+ __u32 ParameterCount;
+ __u32 ParameterOffset;
+ __u32 DataCount;
+ __u32 DataOffset;
+ __u8 SetupCount; /* four setup words follow subcommand */
+ /* SNIA spec incorrectly included spurious pad here */
+ __u16 SubCommand;/* 4 = Change Notify */
+ __u32 CompletionFilter; /* operation to monitor */
+ __u16 Fid;
+ __u8 WatchTree; /* 1 = Monitor subdirectories */
+ __u8 Reserved2;
+ __u16 ByteCount;
+/* __u8 Pad[3];*/
+/* __u8 Data[1];*/
+} TRANSACT_CHANGE_NOTIFY_REQ;
+
+typedef struct smb_com_transaction_change_notify_rsp {
+ struct smb_hdr hdr; /* wct = 18 */
+ __u8 Reserved[3];
+ __u32 TotalParameterCount;
+ __u32 TotalDataCount;
+ __u32 ParameterCount;
+ __u32 ParameterOffset;
+ __u32 ParameterDisplacement;
+ __u32 DataCount;
+ __u32 DataOffset;
+ __u32 DataDisplacement;
+ __u8 SetupCount; /* 0 */
+ __u16 ByteCount;
+ /* __u8 Pad[3]; */
+} TRANSACT_CHANGE_NOTIFY_RSP;
+/* Completion Filter flags for Notify */
+#define FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001
+#define FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002
+#define FILE_NOTIFY_CHANGE_NAME 0x00000003
+#define FILE_NOTIFY_CHANGE_ATTRIBUTES 0x00000004
+#define FILE_NOTIFY_CHANGE_SIZE 0x00000008
+#define FILE_NOTIFY_CHANGE_LAST_WRITE 0x00000010
+#define FILE_NOTIFY_CHANGE_LAST_ACCESS 0x00000020
+#define FILE_NOTIFY_CHANGE_CREATION 0x00000040
+#define FILE_NOTIFY_CHANGE_EA 0x00000080
+#define FILE_NOTIFY_CHANGE_SECURITY 0x00000100
+#define FILE_NOTIFY_CHANGE_STREAM_NAME 0x00000200
+#define FILE_NOTIFY_CHANGE_STREAM_SIZE 0x00000400
+#define FILE_NOTIFY_CHANGE_STREAM_WRITE 0x00000800
+
+#define FILE_ACTION_ADDED 0x00000001
+#define FILE_ACTION_REMOVED 0x00000002
+#define FILE_ACTION_MODIFIED 0x00000003
+#define FILE_ACTION_RENAMED_OLD_NAME 0x00000004
+#define FILE_ACTION_RENAMED_NEW_NAME 0x00000005
+#define FILE_ACTION_ADDED_STREAM 0x00000006
+#define FILE_ACTION_REMOVED_STREAM 0x00000007
+#define FILE_ACTION_MODIFIED_STREAM 0x00000008
+
+/* response contains array of the following structures */
+struct file_notify_information {
+ __u32 NextEntryOffset;
+ __u32 Action;
+ __u32 FileNameLength;
+ __u8 FileName[1];
+};
+
+struct reparse_data {
+ __u32 ReparseTag;
+ __u16 ReparseDataLength;
+ __u16 Reserved;
+ __u16 AltNameOffset;
+ __u16 AltNameLen;
+ __u16 TargetNameOffset;
+ __u16 TargetNameLen;
+ char LinkNamesBuf[1];
+};
+
+struct cifs_quota_data {
+ __u32 rsrvd1; /* 0 */
+ __u32 sid_size;
+ __u64 rsrvd2; /* 0 */
+ __u64 space_used;
+ __u64 soft_limit;
+ __u64 hard_limit;
+ char sid[1]; /* variable size? */
+};
+
+/* quota sub commands */
+#define QUOTA_LIST_CONTINUE 0
+#define QUOTA_LIST_START 0x100
+#define QUOTA_FOR_SID 0x101
+
+typedef union smb_com_transaction2 {
+ struct {
+ struct smb_hdr hdr; /* wct = 14+ */
+ __u16 TotalParameterCount;
+ __u16 TotalDataCount;
+ __u16 MaxParameterCount;
+ __u16 MaxDataCount;
+ __u8 MaxSetupCount;
+ __u8 Reserved;
+ __u16 Flags;
+ __u32 Timeout;
+ __u16 Reserved2;
+ __u16 ParameterCount;
+ __u16 ParameterOffset;
+ __u16 DataCount;
+ __u16 DataOffset;
+ __u8 SetupCount;
+ __u8 Reserved3;
+ __u16 SubCommand; /* 1st setup word - can be followed by SetupCount words */
+ __u16 ByteCount; /* careful - setupcount is not always one */
+ } req;
+ struct {
+ struct smb_hdr hdr; /* wct = 0 */
+ __u16 TotalParameterCount;
+ __u16 TotalDataCount;
+ __u16 Reserved;
+ __u16 ParameterCount;
+ __u16 ParamterOffset;
+ __u16 ParameterDisplacement;
+ __u16 DataCount;
+ __u16 DataOffset;
+ __u16 DataDisplacement;
+ __u8 SetupCount;
+ __u8 Reserved1; /* should be zero setup words following */
+ __u16 ByteCount;
+ __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */
+ /* data area follows */
+ } resp;
+} TRANSACTION2;
+
+/* PathInfo/FileInfo infolevels */
+#define SMB_INFO_STANDARD 1
+#define SMB_INFO_QUERY_EAS_FROM_LIST 3
+#define SMB_INFO_QUERY_ALL_EAS 4
+#define SMB_INFO_IS_NAME_VALID 6
+#define SMB_QUERY_FILE_BASIC_INFO 0x101
+#define SMB_QUERY_FILE_STANDARD_INFO 0x102
+#define SMB_QUERY_FILE_EA_INFO 0x103
+#define SMB_QUERY_FILE_NAME_INFO 0x104
+#define SMB_QUERY_FILE_ALLOCATION_INFO 0x105
+#define SMB_QUERY_FILE_END_OF_FILEINFO 0x106
+#define SMB_QUERY_FILE_ALL_INFO 0x107
+#define SMB_QUERY_ALT_NAME_INFO 0x108
+#define SMB_QUERY_FILE_STREAM_INFO 0x109
+#define SMB_QUERY_FILE_COMPRESSION_INFO 0x10B
+#define SMB_QUERY_FILE_UNIX_BASIC 0x200
+#define SMB_QUERY_FILE_UNIX_LINK 0x201
+
+#define SMB_SET_FILE_BASIC_INFO 0x101
+#define SMB_SET_FILE_DISPOSITION_INFO 0x102
+#define SMB_SET_FILE_ALLOCATION_INFO 0x103
+#define SMB_SET_FILE_END_OF_FILE_INFO 0x104
+#define SMB_SET_FILE_UNIX_BASIC 0x200
+#define SMB_SET_FILE_UNIX_LINK 0x201
+#define SMB_SET_FILE_UNIX_HLINK 0x203
+#define SMB_SET_FILE_BASIC_INFO2 0x3ec
+#define SMB_SET_FILE_RENAME_INFORMATION 0x3f2
+#define SMB_FILE_ALL_INFO2 0x3fa
+#define SMB_SET_FILE_ALLOCATION_INFO2 0x3fb
+#define SMB_SET_FILE_END_OF_FILE_INFO2 0x3fc
+#define SMB_FILE_MOVE_CLUSTER_INFO 0x407
+#define SMB_FILE_QUOTA_INFO 0x408
+#define SMB_FILE_REPARSEPOINT_INFO 0x409
+#define SMB_FILE_MAXIMUM_INFO 0x40d
+
+/* Find File infolevels */
+#define SMB_FIND_FILE_DIRECTORY_INFO 0x101
+#define SMB_FIND_FILE_FULL_DIRECTORY_INFO 0x102
+#define SMB_FIND_FILE_NAMES_INFO 0x103
+#define SMB_FIND_FILE_BOTH_DIRECTORY_INFO 0x104
+#define SMB_FIND_FILE_UNIX 0x202
+
+typedef struct smb_com_transaction2_qpi_req {
+ struct smb_hdr hdr; /* wct = 14+ */
+ __u16 TotalParameterCount;
+ __u16 TotalDataCount;
+ __u16 MaxParameterCount;
+ __u16 MaxDataCount;
+ __u8 MaxSetupCount;
+ __u8 Reserved;
+ __u16 Flags;
+ __u32 Timeout;
+ __u16 Reserved2;
+ __u16 ParameterCount;
+ __u16 ParameterOffset;
+ __u16 DataCount;
+ __u16 DataOffset;
+ __u8 SetupCount;
+ __u8 Reserved3;
+ __u16 SubCommand; /* one setup word */
+ __u16 ByteCount;
+ __u8 Pad;
+ __u16 InformationLevel;
+ __u32 Reserved4;
+ char FileName[1];
+} TRANSACTION2_QPI_REQ;
+
+typedef struct smb_com_transaction2_qpi_rsp {
+ struct smb_hdr hdr; /* wct = 10 + SetupCount */
+ __u16 TotalParameterCount;
+ __u16 TotalDataCount;
+ __u16 Reserved;
+ __u16 ParameterCount;
+ __u16 ParameterOffset;
+ __u16 ParameterDisplacement;
+ __u16 DataCount;
+ __u16 DataOffset;
+ __u16 DataDisplacement;
+ __u8 SetupCount;
+ __u8 Reserved1; /* should be zero setup words following */
+ __u16 ByteCount;
+ __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */
+} TRANSACTION2_QPI_RSP;
+
+typedef struct smb_com_transaction2_spi_req {
+ struct smb_hdr hdr; /* wct = 15 */
+ __u16 TotalParameterCount;
+ __u16 TotalDataCount;
+ __u16 MaxParameterCount;
+ __u16 MaxDataCount;
+ __u8 MaxSetupCount;
+ __u8 Reserved;
+ __u16 Flags;
+ __u32 Timeout;
+ __u16 Reserved2;
+ __u16 ParameterCount;
+ __u16 ParameterOffset;
+ __u16 DataCount;
+ __u16 DataOffset;
+ __u8 SetupCount;
+ __u8 Reserved3;
+ __u16 SubCommand; /* one setup word */
+ __u16 ByteCount;
+ __u8 Pad;
+ __u16 Pad1;
+ __u16 InformationLevel;
+ __u32 Reserved4;
+ char FileName[1];
+} TRANSACTION2_SPI_REQ;
+
+typedef struct smb_com_transaction2_spi_rsp {
+ struct smb_hdr hdr; /* wct = 10 + SetupCount */
+ __u16 TotalParameterCount;
+ __u16 TotalDataCount;
+ __u16 Reserved;
+ __u16 ParameterCount;
+ __u16 ParameterOffset;
+ __u16 ParameterDisplacement;
+ __u16 DataCount;
+ __u16 DataOffset;
+ __u16 DataDisplacement;
+ __u8 SetupCount;
+ __u8 Reserved1; /* should be zero setup words following */
+ __u16 ByteCount;
+ __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */
+} TRANSACTION2_SPI_RSP;
+
+struct set_file_rename {
+ __u32 overwrite; /* 1 = overwrite dest */
+ __u32 root_fid; /* zero */
+ __u32 target_name_len;
+ char target_name[0]; /* Must be unicode */
+};
+
+struct smb_com_transaction2_sfi_req {
+ struct smb_hdr hdr; /* wct = 15 */
+ __u16 TotalParameterCount;
+ __u16 TotalDataCount;
+ __u16 MaxParameterCount;
+ __u16 MaxDataCount;
+ __u8 MaxSetupCount;
+ __u8 Reserved;
+ __u16 Flags;
+ __u32 Timeout;
+ __u16 Reserved2;
+ __u16 ParameterCount;
+ __u16 ParameterOffset;
+ __u16 DataCount;
+ __u16 DataOffset;
+ __u8 SetupCount;
+ __u8 Reserved3;
+ __u16 SubCommand; /* one setup word */
+ __u16 ByteCount;
+ __u8 Pad;
+ __u16 Pad1;
+ __u16 Fid;
+ __u16 InformationLevel;
+ __u16 Reserved4;
+};
+
+struct smb_com_transaction2_sfi_rsp {
+ struct smb_hdr hdr; /* wct = 10 + SetupCount */
+ __u16 TotalParameterCount;
+ __u16 TotalDataCount;
+ __u16 Reserved;
+ __u16 ParameterCount;
+ __u16 ParameterOffset;
+ __u16 ParameterDisplacement;
+ __u16 DataCount;
+ __u16 DataOffset;
+ __u16 DataDisplacement;
+ __u8 SetupCount;
+ __u8 Reserved1; /* should be zero setup words following */
+ __u16 ByteCount;
+ __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */
+};
+
+
+/*
+ * Flags on T2 FINDFIRST and FINDNEXT
+ */
+#define CIFS_SEARCH_CLOSE_ALWAYS 0x0001
+#define CIFS_SEARCH_CLOSE_AT_END 0x0002
+#define CIFS_SEARCH_RETURN_RESUME 0x0004
+#define CIFS_SEARCH_CONTINUE_FROM_LAST 0x0008
+#define CIFS_SEARCH_BACKUP_SEARCH 0x0010
+
+/*
+ * Size of the resume key on FINDFIRST and FINDNEXT calls
+ */
+#define CIFS_SMB_RESUME_KEY_SIZE 4
+
+typedef struct smb_com_transaction2_ffirst_req {
+ struct smb_hdr hdr; /* wct = 15 */
+ __u16 TotalParameterCount;
+ __u16 TotalDataCount;
+ __u16 MaxParameterCount;
+ __u16 MaxDataCount;
+ __u8 MaxSetupCount;
+ __u8 Reserved;
+ __u16 Flags;
+ __u32 Timeout;
+ __u16 Reserved2;
+ __u16 ParameterCount;
+ __u16 ParameterOffset;
+ __u16 DataCount;
+ __u16 DataOffset;
+ __u8 SetupCount; /* one */
+ __u8 Reserved3;
+ __u16 SubCommand; /* TRANS2_FIND_FIRST */
+ __u16 ByteCount;
+ __u8 Pad;
+ __u16 SearchAttributes;
+ __u16 SearchCount;
+ __u16 SearchFlags;
+ __u16 InformationLevel;
+ __u32 SearchStorageType;
+ char FileName[1];
+} TRANSACTION2_FFIRST_REQ;
+
+typedef struct smb_com_transaction2_ffirst_rsp {
+ struct smb_hdr hdr; /* wct = 10 */
+ __u16 TotalParameterCount;
+ __u16 TotalDataCount;
+ __u16 Reserved;
+ __u16 ParameterCount;
+ __u16 ParameterOffset;
+ __u16 ParameterDisplacement;
+ __u16 DataCount;
+ __u16 DataOffset;
+ __u16 DataDisplacement;
+ __u8 SetupCount;
+ __u8 Reserved1; /* should be zero setup words following */
+ __u16 ByteCount;
+} TRANSACTION2_FFIRST_RSP;
+
+typedef struct smb_com_transaction2_ffirst_rsp_parms {
+ __u16 SearchHandle;
+ __u16 SearchCount;
+ __u16 EndofSearch;
+ __u16 EAErrorOffset;
+ __u16 LastNameOffset;
+} T2_FFIRST_RSP_PARMS;
+
+typedef struct smb_com_transaction2_fnext_req {
+ struct smb_hdr hdr; /* wct = 15 */
+ __u16 TotalParameterCount;
+ __u16 TotalDataCount;
+ __u16 MaxParameterCount;
+ __u16 MaxDataCount;
+ __u8 MaxSetupCount;
+ __u8 Reserved;
+ __u16 Flags;
+ __u32 Timeout;
+ __u16 Reserved2;
+ __u16 ParameterCount;
+ __u16 ParameterOffset;
+ __u16 DataCount;
+ __u16 DataOffset;
+ __u8 SetupCount; /* one */
+ __u8 Reserved3;
+ __u16 SubCommand; /* TRANS2_FIND_NEXT */
+ __u16 ByteCount;
+ __u8 Pad;
+ __u16 SearchHandle;
+ __u16 SearchCount;
+ __u16 InformationLevel;
+ __u32 ResumeKey;
+ __u16 SearchFlags;
+ char ResumeFileName[1];
+} TRANSACTION2_FNEXT_REQ;
+
+typedef struct smb_com_transaction2_fnext_rsp {
+ struct smb_hdr hdr; /* wct = 10 */
+ __u16 TotalParameterCount;
+ __u16 TotalDataCount;
+ __u16 Reserved;
+ __u16 ParameterCount;
+ __u16 ParameterOffset;
+ __u16 ParameterDisplacement;
+ __u16 DataCount;
+ __u16 DataOffset;
+ __u16 DataDisplacement;
+ __u8 SetupCount;
+ __u8 Reserved1; /* should be zero setup words following */
+ __u16 ByteCount;
+} TRANSACTION2_FNEXT_RSP;
+
+typedef struct smb_com_transaction2_fnext_rsp_parms {
+ __u16 SearchCount;
+ __u16 EndofSearch;
+ __u16 EAErrorOffset;
+ __u16 LastNameOffset;
+} T2_FNEXT_RSP_PARMS;
+
+/* QFSInfo Levels */
+#define SMB_INFO_ALLOCATION 1
+#define SMB_INFO_VOLUME 2
+#define SMB_QUERY_FS_VOLUME_INFO 0x102
+#define SMB_QUERY_FS_SIZE_INFO 0x103
+#define SMB_QUERY_FS_DEVICE_INFO 0x104
+#define SMB_QUERY_FS_ATTRIBUTE_INFO 0x105
+#define SMB_QUERY_CIFS_UNIX_INFO 0x200
+#define SMB_QUERY_LABEL_INFO 0x3ea
+#define SMB_QUERY_FS_QUOTA_INFO 0x3ee
+
+typedef struct smb_com_transaction2_qfsi_req {
+ struct smb_hdr hdr; /* wct = 14+ */
+ __u16 TotalParameterCount;
+ __u16 TotalDataCount;
+ __u16 MaxParameterCount;
+ __u16 MaxDataCount;
+ __u8 MaxSetupCount;
+ __u8 Reserved;
+ __u16 Flags;
+ __u32 Timeout;
+ __u16 Reserved2;
+ __u16 ParameterCount;
+ __u16 ParameterOffset;
+ __u16 DataCount;
+ __u16 DataOffset;
+ __u8 SetupCount;
+ __u8 Reserved3;
+ __u16 SubCommand; /* one setup word */
+ __u16 ByteCount;
+ __u8 Pad;
+ __u16 InformationLevel;
+} TRANSACTION2_QFSI_REQ;
+
+typedef struct smb_com_transaction_qfsi_rsp {
+ struct smb_hdr hdr; /* wct = 10 + SetupCount */
+ __u16 TotalParameterCount;
+ __u16 TotalDataCount;
+ __u16 Reserved;
+ __u16 ParameterCount;
+ __u16 ParameterOffset;
+ __u16 ParameterDisplacement;
+ __u16 DataCount;
+ __u16 DataOffset;
+ __u16 DataDisplacement;
+ __u8 SetupCount;
+ __u8 Reserved1; /* should be zero setup words following */
+ __u16 ByteCount;
+ __u8 Pad; /* may be three bytes *//* followed by data area */
+} TRANSACTION2_QFSI_RSP;
+
+typedef struct smb_com_transaction2_get_dfs_refer_req {
+ struct smb_hdr hdr; /* wct = 15 */
+ __u16 TotalParameterCount;
+ __u16 TotalDataCount;
+ __u16 MaxParameterCount;
+ __u16 MaxDataCount;
+ __u8 MaxSetupCount;
+ __u8 Reserved;
+ __u16 Flags;
+ __u32 Timeout;
+ __u16 Reserved2;
+ __u16 ParameterCount;
+ __u16 ParameterOffset;
+ __u16 DataCount;
+ __u16 DataOffset;
+ __u8 SetupCount;
+ __u8 Reserved3;
+ __u16 SubCommand; /* one setup word */
+ __u16 ByteCount;
+ __u8 Pad[3]; /* Win2K has sent 0x0F01 (max resp length perhaps?) followed by one byte pad - doesn't seem to matter though */
+ __u16 MaxReferralLevel;
+ char RequestFileName[1];
+} TRANSACTION2_GET_DFS_REFER_REQ;
+
+typedef struct dfs_referral_level_3 {
+ __u16 VersionNumber;
+ __u16 ReferralSize;
+ __u16 ServerType; /* 0x0001 = CIFS server */
+ __u16 ReferralFlags; /* or proximity - not clear which since always set to zero - SNIA spec says 0x01 means strip off PathConsumed chars before submitting RequestFileName to remote node */
+ __u16 TimeToLive;
+ __u16 Proximity;
+ __u16 DfsPathOffset;
+ __u16 DfsAlternatePathOffset;
+ __u16 NetworkAddressOffset;
+} REFERRAL3;
+
+typedef struct smb_com_transaction_get_dfs_refer_rsp {
+ struct smb_hdr hdr; /* wct = 10 */
+ __u16 TotalParameterCount;
+ __u16 TotalDataCount;
+ __u16 Reserved;
+ __u16 ParameterCount;
+ __u16 ParameterOffset;
+ __u16 ParameterDisplacement;
+ __u16 DataCount;
+ __u16 DataOffset;
+ __u16 DataDisplacement;
+ __u8 SetupCount;
+ __u8 Reserved1; /* zero setup words following */
+ __u16 ByteCount;
+ __u8 Pad;
+ __u16 PathConsumed;
+ __u16 NumberOfReferrals;
+ __u16 DFSFlags;
+ __u16 Pad2;
+ REFERRAL3 referrals[1]; /* array of level 3 dfs_referral structures */
+ /* followed by the strings pointed to by the referral structures */
+} TRANSACTION2_GET_DFS_REFER_RSP;
+
+/* DFS Flags */
+#define DFSREF_REFERRAL_SERVER 0x0001
+#define DFSREF_STORAGE_SERVER 0x0002
+
+/* IOCTL information */
+/* List of ioctl function codes that look to be of interest to remote clients like this. */
+/* Need to do some experimentation to make sure they all work remotely. */
+/* Some of the following such as the encryption/compression ones would be */
+/* invoked from tools via a specialized hook into the VFS rather than via the */
+/* standard vfs entry points */
+#define FSCTL_REQUEST_OPLOCK_LEVEL_1 0x00090000
+#define FSCTL_REQUEST_OPLOCK_LEVEL_2 0x00090004
+#define FSCTL_REQUEST_BATCH_OPLOCK 0x00090008
+#define FSCTL_LOCK_VOLUME 0x00090018
+#define FSCTL_UNLOCK_VOLUME 0x0009001C
+#define FSCTL_GET_COMPRESSION 0x0009003C
+#define FSCTL_SET_COMPRESSION 0x0009C040
+#define FSCTL_REQUEST_FILTER_OPLOCK 0x0009008C
+#define FSCTL_FILESYS_GET_STATISTICS 0x00090090
+#define FSCTL_SET_REPARSE_POINT 0x000900A4
+#define FSCTL_GET_REPARSE_POINT 0x000900A8
+#define FSCTL_DELETE_REPARSE_POINT 0x000900AC
+#define FSCTL_SET_SPARSE 0x000900C4
+#define FSCTL_SET_ZERO_DATA 0x000900C8
+#define FSCTL_SET_ENCRYPTION 0x000900D7
+#define FSCTL_ENCRYPTION_FSCTL_IO 0x000900DB
+#define FSCTL_WRITE_RAW_ENCRYPTED 0x000900DF
+#define FSCTL_READ_RAW_ENCRYPTED 0x000900E3
+#define FSCTL_SIS_COPYFILE 0x00090100
+#define FSCTL_SIS_LINK_FILES 0x0009C104
+
+#define IO_REPARSE_TAG_MOUNT_POINT 0xA0000003
+#define IO_REPARSE_TAG_HSM 0xC0000004
+#define IO_REPARSE_TAG_SIS 0x80000007
+
+/*
+ ************************************************************************
+ * All structs for everything above the SMB PDUs themselves
+ * (such as the T2 level specific data) go here
+ ************************************************************************
+ */
+
+/*
+ * Information on a server
+ */
+
+struct serverInfo {
+ char name[16];
+ unsigned char versionMajor;
+ unsigned char versionMinor;
+ unsigned long type;
+ unsigned int commentOffset;
+};
+
+/*
+ * The following structure is the format of the data returned on a NetShareEnum
+ * with level "90" (x5A)
+ */
+
+struct shareInfo {
+ char shareName[13];
+ char pad;
+ unsigned short type;
+ unsigned int commentOffset;
+};
+
+struct aliasInfo {
+ char aliasName[9];
+ char pad;
+ unsigned int commentOffset;
+ unsigned char type[2];
+};
+
+struct aliasInfo92 {
+ int aliasNameOffset;
+ int serverNameOffset;
+ int shareNameOffset;
+};
+
+typedef struct {
+ __u64 TotalAllocationUnits;
+ __u64 FreeAllocationUnits;
+ __u32 SectorsPerAllocationUnit;
+ __u32 BytesPerSector;
+} FILE_SYSTEM_INFO; /* size info, level 0x103 */
+
+typedef struct {
+ __u16 MajorVersionNumber;
+ __u16 MinorVersionNumber;
+ __u64 Capability;
+} FILE_SYSTEM_UNIX_INFO; /* Unix extensions info, level 0x200 */
+/* Linux/Unix extensions capability flags */
+#define CIFS_UNIX_FCNTL_CAP 0x00000001 /* support for fcntl locks */
+#define CIFS_UNIX_POSIX_ACL_CAP 0x00000002
+
+/* DeviceType Flags */
+#define FILE_DEVICE_CD_ROM 0x00000002
+#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003
+#define FILE_DEVICE_DFS 0x00000006
+#define FILE_DEVICE_DISK 0x00000007
+#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008
+#define FILE_DEVICE_FILE_SYSTEM 0x00000009
+#define FILE_DEVICE_NAMED_PIPE 0x00000011
+#define FILE_DEVICE_NETWORK 0x00000012
+#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014
+#define FILE_DEVICE_NULL 0x00000015
+#define FILE_DEVICE_PARALLEL_PORT 0x00000016
+#define FILE_DEVICE_PRINTER 0x00000018
+#define FILE_DEVICE_SERIAL_PORT 0x0000001b
+#define FILE_DEVICE_STREAMS 0x0000001e
+#define FILE_DEVICE_TAPE 0x0000001f
+#define FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020
+#define FILE_DEVICE_VIRTUAL_DISK 0x00000024
+#define FILE_DEVICE_NETWORK_REDIRECTOR 0x00000028
+
+typedef struct {
+ __u32 DeviceType;
+ __u32 DeviceCharacteristics;
+} FILE_SYSTEM_DEVICE_INFO; /* device info, level 0x104 */
+
+typedef struct {
+ __u32 Attributes;
+ __u32 MaxPathNameComponentLength;
+ __u32 FileSystemNameLen;
+ char FileSystemName[52]; /* do not really need to save this - so potentially get only subset of name */
+} FILE_SYSTEM_ATTRIBUTE_INFO;
+
+typedef struct { /* data block encoding of response to level 263 QPathInfo */
+ __u64 CreationTime;
+ __u64 LastAccessTime;
+ __u64 LastWriteTime;
+ __u64 ChangeTime;
+ __u32 Attributes;
+ __u32 Pad1;
+ __u64 AllocationSize;
+ __u64 EndOfFile; /* size ie offset to first free byte in file */
+ __u32 NumberOfLinks; /* hard links */
+ __u8 DeletePending;
+ __u8 Directory;
+ __u16 Pad2;
+ __u64 IndexNumber;
+ __u32 EASize;
+ __u32 AccessFlags;
+ __u64 IndexNumber1;
+ __u64 CurrentByteOffset;
+ __u32 Mode;
+ __u32 AlignmentRequirement;
+ __u32 FileNameLength;
+ char FileName[1];
+} FILE_ALL_INFO; /* level 263 QPathInfo */
+
+typedef struct {
+ __u64 EndOfFile;
+ __u64 NumOfBytes;
+ __u64 LastStatusChange; /*SNIA spec says DCE time for the three time fields */
+ __u64 LastAccessTime;
+ __u64 LastModificationTime;
+ __u64 Uid;
+ __u64 Gid;
+ __u32 Type;
+ __u64 DevMajor;
+ __u64 DevMinor;
+ __u64 UniqueId;
+ __u64 Permissions;
+ __u64 Nlinks;
+} FILE_UNIX_BASIC_INFO; /* level 512 QPathInfo */
+
+typedef struct {
+ char LinkDest[1];
+} FILE_UNIX_LINK_INFO; /* level 513 QPathInfo */
+
+/* defines for enumerating possible values of the Unix type field below */
+#define UNIX_FILE 0
+#define UNIX_DIR 1
+#define UNIX_SYMLINK 2
+#define UNIX_CHARDEV 3
+#define UNIX_BLOCKDEV 4
+#define UNIX_FIFO 5
+#define UNIX_SOCKET 6
+
+typedef struct {
+ __u32 NextEntryOffset;
+ __u32 ResumeKey;
+ __u64 EndOfFile;
+ __u64 NumOfBytes;
+ __u64 LastStatusChange; /*SNIA spec says DCE time for the three time fields */
+ __u64 LastAccessTime;
+ __u64 LastModificationTime;
+ __u64 Uid;
+ __u64 Gid;
+ __u32 Type;
+ __u64 DevMajor;
+ __u64 DevMinor;
+ __u64 UniqueId;
+ __u64 Permissions;
+ __u64 Nlinks;
+ char FileName[1];
+} FILE_UNIX_INFO;
+
+typedef struct {
+ __u64 CreationTime;
+ __u64 LastAccessTime;
+ __u64 LastWriteTime;
+ __u64 ChangeTime;
+ __u32 Attributes;
+ __u32 Pad;
+} FILE_BASIC_INFO; /* size info, level 0x101 */
+
+struct file_allocation_info {
+ __u64 AllocationSize;
+}; /* size info, level 0x103 */
+
+struct file_end_of_file_info {
+ __u64 FileSize; /* offset to end of file */
+}; /* size info, level 0x104 */
+
+typedef struct {
+ __u32 NextEntryOffset;
+ __u32 FileIndex;
+ __u64 CreationTime;
+ __u64 LastAccessTime;
+ __u64 LastWriteTime;
+ __u64 ChangeTime;
+ __u64 EndOfFile;
+ __u64 AllocationSize;
+ __u32 ExtFileAttributes;
+ __u32 FileNameLength;
+ char FileName[1];
+} FILE_DIRECTORY_INFO; /* level 257 FF response data area */
+
+struct gea {
+ unsigned char cbName;
+ char szName[1];
+};
+
+struct gealist {
+ unsigned long cbList;
+ struct gea list[1];
+};
+
+struct fea {
+ unsigned char EA_flags;
+ __u8 name_len;
+ __u16 value_len;
+ char szName[1];
+ /* optionally followed by value */
+};
+/* flags for _FEA.fEA */
+#define FEA_NEEDEA 0x80 /* need EA bit */
+
+struct fealist {
+ __u32 list_len;
+ struct fea list[1];
+};
+
+/* used to hold an arbitrary blob of data */
+struct data_blob {
+ __u8 *data;
+ size_t length;
+ void (*free) (struct data_blob * data_blob);
+};
+
+#ifdef CONFIG_CIFS_POSIX
+/*
+ For better POSIX semantics from Linux client, (even better
+ than the existing CIFS Unix Extensions) we need updated PDUs for:
+
+ 1) PosixCreateX - to set and return the mode, inode#, device info and
+ perhaps add a CreateDevice - to create Pipes and other special .inodes
+ Also note POSIX open flags
+ 2) Close - to return the last write time to do cache across close more safely
+ 3) PosixQFSInfo - to return statfs info
+ 4) FindFirst return unique inode number - what about resume key, two forms short (matches readdir) and full (enough info to cache inodes)
+ 5) Mkdir - set mode
+
+ And under consideration:
+ 6) FindClose2 (return nanosecond timestamp ??)
+ 7) Use nanosecond timestamps throughout all time fields if
+ corresponding attribute flag is set
+ 8) sendfile - handle based copy
+ 9) Direct i/o
+ 10) "POSIX ACL" support
+ 11) Misc fcntls?
+
+ what about fixing 64 bit alignment
+
+ There are also various legacy SMB/CIFS requests used as is
+
+ From existing Lanman and NTLM dialects:
+ --------------------------------------
+ NEGOTIATE
+ SESSION_SETUP_ANDX (BB which?)
+ TREE_CONNECT_ANDX (BB which wct?)
+ TREE_DISCONNECT (BB add volume timestamp on response)
+ LOGOFF_ANDX
+ DELETE (note delete open file behavior)
+ DELETE_DIRECTORY
+ READ_AND_X
+ WRITE_AND_X
+ LOCKING_AND_X (note posix lock semantics)
+ RENAME (note rename across dirs and open file rename posix behaviors)
+ NT_RENAME (for hardlinks) Is this good enough for all features?
+ FIND_CLOSE2
+ TRANSACTION2 (18 cases)
+ SMB_SET_FILE_END_OF_FILE_INFO2 SMB_SET_PATH_END_OF_FILE_INFO2
+ (BB verify that never need to set allocation size)
+ SMB_SET_FILE_BASIC_INFO2 (setting times - BB can it be done via Unix ext?)
+
+ COPY (note support for copy across directories) - FUTURE, OPTIONAL
+ setting/getting OS/2 EAs - FUTURE (BB can this handle
+ setting Linux xattrs perfectly) - OPTIONAL
+ dnotify - FUTURE, OPTIONAL
+ quota - FUTURE, OPTIONAL
+
+ Note that various requests implemented for NT interop such as
+ NT_TRANSACT (IOCTL) QueryReparseInfo
+ are unneeded to servers compliant with the CIFS POSIX extensions
+
+ From CIFS Unix Extensions:
+ -------------------------
+ T2 SET_PATH_INFO (SMB_SET_FILE_UNIX_LINK) for symlinks
+ T2 SET_PATH_INFO (SMB_SET_FILE_BASIC_INFO2)
+ T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_LINK)
+ T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_BASIC) - BB check for missing inode fields
+ Actually need QUERY_FILE_UNIX_INFO since has inode num
+ BB what about a) blksize/blkbits/blocks
+ b) i_version
+ c) i_rdev
+ d) notify mask?
+ e) generation
+ f) size_seqcount
+ T2 FIND_FIRST/FIND_NEXT FIND_FILE_UNIX
+ TRANS2_GET_DFS_REFERRAL - OPTIONAL but recommended
+ T2_QFS_INFO QueryDevice/AttributeInfo - OPTIONAL
+
+
+ */
+#endif
+
+#pragma pack() /* resume default structure packing */
+
+#endif /* _CIFSPDU_H */
diff --git a/release/src/linux/linux/fs/cifs/cifsproto.h b/release/src/linux/linux/fs/cifs/cifsproto.h
new file mode 100644
index 00000000..530c554e
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/cifsproto.h
@@ -0,0 +1,254 @@
+/*
+ * fs/cifs/cifsproto.h
+ *
+ * Copyright (c) International Business Machines Corp., 2002
+ * Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef _CIFSPROTO_H
+#define _CIFSPROTO_H
+#include <linux/nls.h>
+
+struct statfs;
+
+/*
+ *****************************************************************
+ * All Prototypes
+ *****************************************************************
+ */
+
+extern struct smb_hdr *cifs_buf_get(void);
+extern void cifs_buf_release(void *);
+extern int smb_send(struct socket *, struct smb_hdr *,
+ unsigned int /* length */ , struct sockaddr *);
+extern unsigned int _GetXid(void);
+extern void _FreeXid(unsigned int);
+#define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__FUNCTION__, xid,current->fsuid));
+#define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__FUNCTION__,curr_xid,rc));}
+extern char *build_path_from_dentry(struct dentry *);
+extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
+extern void renew_parental_timestamps(struct dentry *direntry);
+extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
+ struct smb_hdr * /* input */ ,
+ struct smb_hdr * /* out */ ,
+ int * /* bytes returned */ , const int long_op);
+extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid);
+extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length);
+extern int is_valid_oplock_break(struct smb_hdr *smb);
+extern unsigned int smbCalcSize(struct smb_hdr *ptr);
+extern int decode_negTokenInit(unsigned char *security_blob, int length,
+ enum securityEnum *secType);
+extern int map_smb_to_linux_error(struct smb_hdr *smb);
+extern void header_assemble(struct smb_hdr *, char /* command */ ,
+ const struct cifsTconInfo *, int
+ /* length of fixed section (word count) in two byte units */
+ );
+struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, struct cifsTconInfo *);
+void DeleteOplockQEntry(struct oplock_q_entry *);
+extern time_t cifs_NTtimeToUnix(u64 /* utc nanoseconds since 1601 */ );
+extern u64 cifs_UnixTimeToNT(time_t);
+extern int cifs_get_inode_info(struct inode **pinode,
+ const unsigned char *search_path,
+ FILE_ALL_INFO * pfile_info,
+ struct super_block *sb, int xid);
+extern int cifs_get_inode_info_unix(struct inode **pinode,
+ const unsigned char *search_path,
+ struct super_block *sb,int xid);
+
+extern int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
+ struct nls_table * nls_info);
+extern int CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses);
+
+extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
+ const char *tree, struct cifsTconInfo *tcon,
+ const struct nls_table *);
+
+extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
+ const char *searchName,
+ FILE_DIRECTORY_INFO * findData,
+ T2_FFIRST_RSP_PARMS * findParms,
+ const struct nls_table *nls_codepage,
+ int *pUnicodeFlag,
+ int *pUnixFlag /* if Unix extensions used */ );
+extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
+ FILE_DIRECTORY_INFO * findData,
+ T2_FNEXT_RSP_PARMS * findParms,
+ const __u16 searchHandle, char * resume_name,
+ int name_length, __u32 resume_key,
+ int *UnicodeFlag, int *pUnixFlag);
+
+extern int CIFSFindClose(const int, struct cifsTconInfo *tcon,
+ const __u16 search_handle);
+
+extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
+ const unsigned char *searchName,
+ FILE_ALL_INFO * findData,
+ const struct nls_table *nls_codepage);
+
+extern int CIFSSMBUnixQPathInfo(const int xid,
+ struct cifsTconInfo *tcon,
+ const unsigned char *searchName,
+ FILE_UNIX_BASIC_INFO * pFindData,
+ const struct nls_table *nls_codepage);
+
+extern int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
+ const unsigned char *searchName,
+ unsigned char **targetUNCs,
+ unsigned int *number_of_UNC_in_array,
+ const struct nls_table *nls_codepage);
+
+extern int connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
+ const char *old_path,
+ const struct nls_table *nls_codepage);
+extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
+ const char *old_path, const struct nls_table *nls_codepage,
+ unsigned int *pnum_referrals, unsigned char ** preferrals);
+extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
+ struct statfs *FSData,
+ const struct nls_table *nls_codepage);
+extern int CIFSSMBQFSAttributeInfo(const int xid,
+ struct cifsTconInfo *tcon,
+ const struct nls_table *nls_codepage);
+extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon,
+ const struct nls_table *nls_codepage);
+extern int CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon,
+ const struct nls_table *nls_codepage);
+
+extern int CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon,
+ char *fileName, FILE_BASIC_INFO * data,
+ const struct nls_table *nls_codepage);
+extern int CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon,
+ char *fileName, __u64 size,int setAllocationSizeFlag,
+ const struct nls_table *nls_codepage);
+extern int CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon,
+ __u64 size, __u16 fileHandle,__u32 opener_pid, int AllocSizeFlag);
+extern int CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *pTcon,
+ char *full_path, __u64 mode, __u64 uid,
+ __u64 gid, dev_t dev, const struct nls_table *nls_codepage);
+
+extern int CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
+ const char *newName,
+ const struct nls_table *nls_codepage);
+extern int CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon,
+ const char *name, const struct nls_table *nls_codepage);
+
+extern int CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon,
+ const char *name,
+ const struct nls_table *nls_codepage);
+extern int CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
+ const char *fromName, const char *toName,
+ const struct nls_table *nls_codepage);
+extern int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
+ int netfid, char * target_name, const struct nls_table *nls_codepage);
+extern int CIFSCreateHardLink(const int xid,
+ struct cifsTconInfo *tcon,
+ const char *fromName, const char *toName,
+ const struct nls_table *nls_codepage);
+extern int CIFSUnixCreateHardLink(const int xid,
+ struct cifsTconInfo *tcon,
+ const char *fromName, const char *toName,
+ const struct nls_table *nls_codepage);
+extern int CIFSUnixCreateSymLink(const int xid,
+ struct cifsTconInfo *tcon,
+ const char *fromName, const char *toName,
+ const struct nls_table *nls_codepage);
+extern int CIFSSMBUnixQuerySymLink(const int xid,
+ struct cifsTconInfo *tcon,
+ const unsigned char *searchName,
+ char *syminfo, const int buflen,
+ const struct nls_table *nls_codepage);
+extern int CIFSSMBQueryReparseLinkInfo(const int xid,
+ struct cifsTconInfo *tcon,
+ const unsigned char *searchName,
+ char *symlinkinfo, const int buflen, __u16 fid,
+ const struct nls_table *nls_codepage);
+
+extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
+ const char *fileName, const int disposition,
+ const int access_flags, const int omode,
+ __u16 * netfid, int *pOplock, FILE_ALL_INFO *,
+ const struct nls_table *nls_codepage);
+extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon,
+ const int smb_file_id);
+
+extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
+ const int netfid, unsigned int count,
+ const __u64 lseek, unsigned int *nbytes, char **buf);
+extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
+ const int netfid, const unsigned int count,
+ const __u64 lseek, unsigned int *nbytes,
+ const char *buf, const int long_op);
+extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
+ const __u16 netfid, const __u64 len,
+ const __u64 offset, const __u32 numUnlock,
+ const __u32 numLock, const __u8 lockType,
+ const int waitFlag);
+
+extern int CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon);
+extern int CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses);
+
+extern struct cifsSesInfo *sesInfoAlloc(void);
+extern void sesInfoFree(struct cifsSesInfo *);
+extern struct cifsTconInfo *tconInfoAlloc(void);
+extern void tconInfoFree(struct cifsTconInfo *);
+
+extern int cifs_reconnect(struct TCP_Server_Info *server);
+
+extern int cifs_sign_smb(struct smb_hdr *, struct cifsSesInfo *,__u32 *);
+extern int cifs_verify_signature(const struct smb_hdr *, const char * mac_key,
+ __u32 expected_sequence_number);
+extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass);
+extern void CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, struct nls_table *);
+extern void CalcNTLMv2_response(const struct cifsSesInfo *,char * );
+
+extern int CIFSBuildServerList(int xid, char *serverBufferList,
+ int recordlength, int *entries,
+ int *totalEntries, int *topoChangedFlag);
+extern int CIFSSMBQueryShares(int xid, struct cifsTconInfo *tcon,
+ struct shareInfo *shareList, int bufferLen,
+ int *entries, int *totalEntries);
+extern int CIFSSMBQueryAlias(int xid, struct cifsTconInfo *tcon,
+ struct aliasInfo *aliasList, int bufferLen,
+ int *entries, int *totalEntries);
+extern int CIFSSMBAliasInfo(int xid, struct cifsTconInfo *tcon,
+ char *aliasName, char *serverName,
+ char *shareName, char *comment);
+extern int CIFSSMBGetShareInfo(int xid, struct cifsTconInfo *tcon,
+ char *share, char *comment);
+extern int CIFSSMBGetUserPerms(int xid, struct cifsTconInfo *tcon,
+ char *userName, char *searchName, int *perms);
+extern int CIFSSMBSync(int xid, struct cifsTconInfo *tcon, int netfid, int pid);
+
+extern int CIFSSMBSeek(int xid,
+ struct cifsTconInfo *tcon,
+ int netfid,
+ int pid,
+ int whence, unsigned long offset, long long *newoffset);
+
+extern int CIFSSMBCopy(int xid,
+ struct cifsTconInfo *source_tcon,
+ const char *fromName,
+ const __u16 target_tid,
+ const char *toName, const int flags,
+ const struct nls_table *nls_codepage);
+extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
+ const int notify_subdirs,const __u16 netfid,__u32 filter,
+ const struct nls_table *nls_codepage);
+extern int CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
+ const unsigned char *searchName,
+ char * EAData, size_t size,
+ const struct nls_table *nls_codepage);
+#endif /* _CIFSPROTO_H */
diff --git a/release/src/linux/linux/fs/cifs/cifssmb.c b/release/src/linux/linux/fs/cifs/cifssmb.c
new file mode 100644
index 00000000..ca4dedf7
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/cifssmb.c
@@ -0,0 +1,3016 @@
+/*
+ * fs/cifs/cifssmb.c
+ *
+ * Copyright (C) International Business Machines Corp., 2002,2003
+ * Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ * Contains the routines for constructing the SMB PDUs themselves
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+ /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
+ /* These are mostly routines that operate on a pathname, or on a tree id */
+ /* (mounted volume), but there are eight handle based routines which must be */
+ /* treated slightly different for reconnection purposes since we never want */
+ /* to reuse a stale file handle and the caller knows the file handle */
+
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/vfs.h>
+#include <asm/uaccess.h>
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_unicode.h"
+#include "cifs_debug.h"
+
+#ifdef CONFIG_CIFS_POSIX
+static struct {
+ int index;
+ char *name;
+} protocols[] = {
+ {CIFS_PROT, "\2NT LM 0.12"},
+ {CIFS_PROT, "\2POSIX 2"},
+ {BAD_PROT, "\2"}
+};
+#else
+static struct {
+ int index;
+ char *name;
+} protocols[] = {
+ {CIFS_PROT, "\2NT LM 0.12"},
+ {BAD_PROT, "\2"}
+};
+#endif
+
+
+/* Mark as invalid, all open files on tree connections since they
+ were closed when session to server was lost */
+static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
+{
+ struct cifsFileInfo *open_file = NULL;
+ struct list_head * tmp;
+ struct list_head * tmp1;
+
+/* list all files open on tree connection and mark them invalid */
+ write_lock(&GlobalSMBSeslock);
+ list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
+ open_file = list_entry(tmp,struct cifsFileInfo, tlist);
+ if(open_file) {
+ open_file->invalidHandle = TRUE;
+ }
+ }
+ write_unlock(&GlobalSMBSeslock);
+ /* BB Add call to invalidate_inodes(sb) for all superblocks mounted to this tcon */
+}
+
+static int
+smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
+ void **request_buf /* returned */ ,
+ void **response_buf /* returned */ )
+{
+ int rc = 0;
+ int timeout = 10 * HZ;
+
+ /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
+ check for tcp and smb session status done differently
+ for those three - in the calling routine */
+ if(tcon) {
+ if((tcon->ses) && (tcon->ses->server)){
+ struct nls_table *nls_codepage;
+ /* Give Demultiplex thread up to 10 seconds to
+ reconnect, should be greater than cifs socket
+ timeout which is 7 seconds */
+ while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
+ while ((tcon->ses->server->tcpStatus != CifsGood) && (timeout > 0)){
+ timeout = interruptible_sleep_on_timeout(&tcon->ses->server->response_q,timeout);
+ }
+ if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
+ /* on "soft" mounts we wait once */
+ if((tcon->retry == FALSE) ||
+ (tcon->ses->status == CifsExiting)) {
+ cFYI(1,("gave up waiting on reconnect in smb_init"));
+ return -EHOSTDOWN;
+ } /* else "hard" mount - keep retrying until
+ process is killed or server comes back up */
+ } else /* TCP session is reestablished now */
+ break;
+
+ }
+
+ nls_codepage = load_nls_default();
+ /* need to prevent multiple threads trying to
+ simultaneously reconnect the same SMB session */
+ down(&tcon->ses->sesSem);
+ if(tcon->ses->status == CifsNeedReconnect)
+ rc = cifs_setup_session(0, tcon->ses, nls_codepage);
+ if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
+ mark_open_files_invalid(tcon);
+ rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon,
+ nls_codepage);
+ up(&tcon->ses->sesSem);
+ if(rc == 0)
+ atomic_inc(&tconInfoReconnectCount);
+
+ cFYI(1, ("reconnect tcon rc = %d", rc));
+ /* Removed call to reopen open files here -
+ it is safer (and faster) to reopen files
+ one at a time as needed in read and write */
+
+ /* Check if handle based operation so we
+ know whether we can continue or not without
+ returning to caller to reset file handle */
+ switch(smb_command) {
+ case SMB_COM_READ_ANDX:
+ case SMB_COM_WRITE_ANDX:
+ case SMB_COM_CLOSE:
+ case SMB_COM_FIND_CLOSE2:
+ case SMB_COM_LOCKING_ANDX: {
+ unload_nls(nls_codepage);
+ return -EAGAIN;
+ }
+ }
+ } else {
+ up(&tcon->ses->sesSem);
+ }
+ unload_nls(nls_codepage);
+
+ } else {
+ return -EIO;
+ }
+ }
+ if(rc)
+ return rc;
+
+ *request_buf = cifs_buf_get();
+ if (*request_buf == 0) {
+ /* BB should we add a retry in here if not a writepage? */
+ return -ENOMEM;
+ }
+ /* Although the original thought was we needed the response buf for */
+ /* potential retries of smb operations it turns out we can determine */
+ /* from the mid flags when the request buffer can be resent without */
+ /* having to use a second distinct buffer for the response */
+ *response_buf = *request_buf;
+
+ header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
+ wct /*wct */ );
+
+#ifdef CONFIG_CIFS_STATS
+ if(tcon != NULL) {
+ atomic_inc(&tcon->num_smbs_sent);
+ }
+#endif
+ return rc;
+}
+
+int
+CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
+{
+ NEGOTIATE_REQ *pSMB;
+ NEGOTIATE_RSP *pSMBr;
+ int rc = 0;
+ int bytes_returned;
+ struct TCP_Server_Info * server;
+
+ if(ses->server)
+ server = ses->server;
+ else {
+ rc = -EIO;
+ return rc;
+ }
+ rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
+ (void **) &pSMB, (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
+ if (extended_security)
+ pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
+
+ pSMB->ByteCount = strlen(protocols[0].name) + 1;
+ strncpy(pSMB->DialectsArray, protocols[0].name, 30);
+ /* null guaranteed to be at end of source and target buffers anyway */
+
+ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+
+ rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc == 0) {
+ server->secMode = pSMBr->SecurityMode;
+ server->secType = NTLM; /* BB override default for NTLMv2 or krb*/
+ /* one byte - no need to convert this or EncryptionKeyLen from le,*/
+ server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
+ /* probably no need to store and check maxvcs */
+ server->maxBuf =
+ min(le32_to_cpu(pSMBr->MaxBufferSize),
+ (__u32) CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE);
+ server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
+ cFYI(0, ("Max buf = %d ", ses->server->maxBuf));
+ GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
+ server->capabilities = le32_to_cpu(pSMBr->Capabilities);
+ server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);
+ /* BB with UTC do we ever need to be using srvr timezone? */
+ if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
+ memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
+ CIFS_CRYPTO_KEY_SIZE);
+ } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
+ && (pSMBr->EncryptionKeyLength == 0)) {
+ /* decode security blob */
+ } else
+ rc = -EIO;
+
+ /* BB might be helpful to save off the domain of server here */
+
+ if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) {
+ if (pSMBr->ByteCount < 16)
+ rc = -EIO;
+ else if (pSMBr->ByteCount == 16) {
+ server->secType = RawNTLMSSP;
+ if (server->socketUseCount.counter > 1) {
+ if (memcmp
+ (server->server_GUID,
+ pSMBr->u.extended_response.
+ GUID, 16) != 0) {
+ cFYI(1,
+ ("UID of server does not match previous connection to same ip address"));
+ memcpy(server->
+ server_GUID,
+ pSMBr->u.
+ extended_response.
+ GUID, 16);
+ }
+ } else
+ memcpy(server->server_GUID,
+ pSMBr->u.extended_response.
+ GUID, 16);
+ } else {
+ rc = decode_negTokenInit(pSMBr->u.
+ extended_response.
+ SecurityBlob,
+ pSMBr->ByteCount -
+ 16, &server->secType);
+ }
+ } else
+ server->capabilities &= ~CAP_EXTENDED_SECURITY;
+ if(sign_CIFS_PDUs == FALSE) {
+ if(server->secMode & SECMODE_SIGN_REQUIRED)
+ cERROR(1,
+ ("Server requires /proc/fs/cifs/PacketSigningEnabled"));
+ server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
+ } else if(sign_CIFS_PDUs == 1) {
+ if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
+ server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
+ }
+
+ }
+ if (pSMB)
+ cifs_buf_release(pSMB);
+ return rc;
+}
+
+int
+CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
+{
+ struct smb_hdr *smb_buffer;
+ struct smb_hdr *smb_buffer_response;
+ int rc = 0;
+ int length;
+
+ cFYI(1, ("In tree disconnect"));
+ /*
+ * If last user of the connection and
+ * connection alive - disconnect it
+ * If this is the last connection on the server session disconnect it
+ * (and inside session disconnect we should check if tcp socket needs
+ * to be freed and kernel thread woken up).
+ */
+ if (tcon)
+ down(&tcon->tconSem);
+ else
+ return -EIO;
+
+ atomic_dec(&tcon->useCount);
+ if (atomic_read(&tcon->useCount) > 0) {
+ up(&tcon->tconSem);
+ return -EBUSY;
+ }
+
+ /* No need to return error on this operation if tid invalidated and
+ closed on server already e.g. due to tcp session crashing */
+ if(tcon->tidStatus == CifsNeedReconnect) {
+ up(&tcon->tconSem);
+ return 0;
+ }
+
+ if((tcon->ses == 0) || (tcon->ses->server == 0)) {
+ up(&tcon->tconSem);
+ return -EIO;
+ }
+
+ rc = smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
+ (void **) &smb_buffer, (void **) &smb_buffer_response);
+ if (rc) {
+ up(&tcon->tconSem);
+ return rc;
+ }
+ rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
+ &length, 0);
+ if (rc)
+ cFYI(1, (" Tree disconnect failed %d", rc));
+
+ if (smb_buffer)
+ cifs_buf_release(smb_buffer);
+ up(&tcon->tconSem);
+
+ /* No need to return error on this operation if tid invalidated and
+ closed on server already e.g. due to tcp session crashing */
+ if (rc == -EAGAIN)
+ rc = 0;
+
+ return rc;
+}
+
+int
+CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
+{
+ struct smb_hdr *smb_buffer_response;
+ LOGOFF_ANDX_REQ *pSMB;
+ int rc = 0;
+ int length;
+
+ cFYI(1, ("In SMBLogoff for session disconnect"));
+ if (ses)
+ down(&ses->sesSem);
+ else
+ return -EIO;
+
+ atomic_dec(&ses->inUse);
+ if (atomic_read(&ses->inUse) > 0) {
+ up(&ses->sesSem);
+ return -EBUSY;
+ }
+
+ rc = smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL /* no tcon anymore */,
+ (void **) &pSMB, (void **) &smb_buffer_response);
+
+ if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+ pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+
+ if (rc) {
+ up(&ses->sesSem);
+ return rc;
+ }
+
+ pSMB->hdr.Uid = ses->Suid;
+
+ pSMB->AndXCommand = 0xFF;
+ rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
+ smb_buffer_response, &length, 0);
+ if (ses->server) {
+ atomic_dec(&ses->server->socketUseCount);
+ if (atomic_read(&ses->server->socketUseCount) == 0) {
+ spin_lock(&GlobalMid_Lock);
+ ses->server->tcpStatus = CifsExiting;
+ spin_unlock(&GlobalMid_Lock);
+ rc = -ESHUTDOWN;
+ }
+ }
+ if (pSMB)
+ cifs_buf_release(pSMB);
+ up(&ses->sesSem);
+
+ /* if session dead then we do not need to do ulogoff,
+ since server closed smb session, no sense reporting
+ error */
+ if (rc == -EAGAIN)
+ rc = 0;
+ return rc;
+}
+
+int
+CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon,
+ const char *fileName, const struct nls_table *nls_codepage)
+{
+ DELETE_FILE_REQ *pSMB = NULL;
+ DELETE_FILE_RSP *pSMBr = NULL;
+ int rc = 0;
+ int bytes_returned;
+ int name_len;
+
+DelFileRetry:
+ rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+ name_len =
+ cifs_strtoUCS((wchar_t *) pSMB->fileName, fileName, 530
+ /* find define for this maxpathcomponent */
+ , nls_codepage);
+ name_len++; /* trailing null */
+ name_len *= 2;
+ } else { /* BB improve the check for buffer overruns BB */
+ name_len = strnlen(fileName, 530);
+ name_len++; /* trailing null */
+ strncpy(pSMB->fileName, fileName, name_len);
+ }
+ pSMB->SearchAttributes =
+ cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
+ pSMB->ByteCount = name_len + 1;
+ pSMB->BufferFormat = 0x04;
+ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc) {
+ cFYI(1, ("Error in RMFile = %d", rc));
+ }
+#ifdef CONFIG_CIFS_STATS
+ else {
+ atomic_inc(&tcon->num_deletes);
+ }
+#endif
+
+ if (pSMB)
+ cifs_buf_release(pSMB);
+ if (rc == -EAGAIN)
+ goto DelFileRetry;
+
+ return rc;
+}
+
+int
+CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon,
+ const char *dirName, const struct nls_table *nls_codepage)
+{
+ DELETE_DIRECTORY_REQ *pSMB = NULL;
+ DELETE_DIRECTORY_RSP *pSMBr = NULL;
+ int rc = 0;
+ int bytes_returned;
+ int name_len;
+
+ cFYI(1, ("In CIFSSMBRmDir"));
+RmDirRetry:
+ rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+ name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, dirName, 530
+ /* find define for this maxpathcomponent */
+ , nls_codepage);
+ name_len++; /* trailing null */
+ name_len *= 2;
+ } else { /* BB improve the check for buffer overruns BB */
+ name_len = strnlen(dirName, 530);
+ name_len++; /* trailing null */
+ strncpy(pSMB->DirName, dirName, name_len);
+ }
+
+ pSMB->ByteCount = name_len + 1;
+ pSMB->BufferFormat = 0x04;
+ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc) {
+ cFYI(1, ("Error in RMDir = %d", rc));
+ }
+#ifdef CONFIG_CIFS_STATS
+ else {
+ atomic_inc(&tcon->num_rmdirs);
+ }
+#endif
+
+ if (pSMB)
+ cifs_buf_release(pSMB);
+ if (rc == -EAGAIN)
+ goto RmDirRetry;
+ return rc;
+}
+
+int
+CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
+ const char *name, const struct nls_table *nls_codepage)
+{
+ int rc = 0;
+ CREATE_DIRECTORY_REQ *pSMB = NULL;
+ CREATE_DIRECTORY_RSP *pSMBr = NULL;
+ int bytes_returned;
+ int name_len;
+
+ cFYI(1, ("In CIFSSMBMkDir"));
+MkDirRetry:
+ rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+ name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, name, 530
+ /* find define for this maxpathcomponent */
+ , nls_codepage);
+ name_len++; /* trailing null */
+ name_len *= 2;
+ } else { /* BB improve the check for buffer overruns BB */
+ name_len = strnlen(name, 530);
+ name_len++; /* trailing null */
+ strncpy(pSMB->DirName, name, name_len);
+ }
+
+ pSMB->ByteCount = name_len + 1 /* for buf format */ ;
+ pSMB->BufferFormat = 0x04;
+ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc) {
+ cFYI(1, ("Error in Mkdir = %d", rc));
+ }
+#ifdef CONFIG_CIFS_STATS
+ else {
+ atomic_inc(&tcon->num_mkdirs);
+ }
+#endif
+ if (pSMB)
+ cifs_buf_release(pSMB);
+ if (rc == -EAGAIN)
+ goto MkDirRetry;
+ return rc;
+}
+
+int
+CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
+ const char *fileName, const int openDisposition,
+ const int access_flags, const int create_options, __u16 * netfid,
+ int *pOplock, FILE_ALL_INFO * pfile_info,
+ const struct nls_table *nls_codepage)
+{
+ int rc = -EACCES;
+ OPEN_REQ *pSMB = NULL;
+ OPEN_RSP *pSMBr = NULL;
+ int bytes_returned;
+ int name_len;
+
+openRetry:
+ rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ pSMB->AndXCommand = 0xFF; /* none */
+
+ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+ pSMB->ByteCount = 1; /* account for one byte pad to word boundary */
+ name_len =
+ cifs_strtoUCS((wchar_t *) (pSMB->fileName + 1),
+ fileName, 530
+ /* find define for this maxpathcomponent */
+ , nls_codepage);
+ name_len++; /* trailing null */
+ name_len *= 2;
+ pSMB->NameLength = cpu_to_le16(name_len);
+ } else { /* BB improve the check for buffer overruns BB */
+ pSMB->ByteCount = 0; /* no pad */
+ name_len = strnlen(fileName, 530);
+ name_len++; /* trailing null */
+ pSMB->NameLength = cpu_to_le16(name_len);
+ strncpy(pSMB->fileName, fileName, name_len);
+ }
+ if (*pOplock & REQ_OPLOCK)
+ pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
+ else if (*pOplock & REQ_BATCHOPLOCK) {
+ pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
+ }
+ pSMB->DesiredAccess = cpu_to_le32(access_flags);
+ pSMB->AllocationSize = 0;
+ pSMB->FileAttributes = ATTR_NORMAL;
+ /* XP does not handle ATTR_POSIX_SEMANTICS */
+ /* but it helps speed up case sensitive checks for other
+ servers such as Samba */
+ if (tcon->ses->capabilities & CAP_UNIX)
+ pSMB->FileAttributes |= ATTR_POSIX_SEMANTICS;
+
+ /* if ((omode & S_IWUGO) == 0)
+ pSMB->FileAttributes |= ATTR_READONLY;*/
+ /* Above line causes problems due to vfs splitting create into two
+ pieces - need to set mode after file created not while it is
+ being created */
+ pSMB->FileAttributes = cpu_to_le32(pSMB->FileAttributes);
+ pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
+ pSMB->CreateDisposition = cpu_to_le32(openDisposition);
+ pSMB->CreateOptions = cpu_to_le32(create_options);
+ pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION); /* BB ??*/
+ pSMB->SecurityFlags =
+ cpu_to_le32(SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY);
+
+ pSMB->ByteCount += name_len;
+ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+
+ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+ /* long_op set to 1 to allow for oplock break timeouts */
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 1);
+ if (rc) {
+ cFYI(1, ("Error in Open = %d", rc));
+ } else {
+ *pOplock = pSMBr->OplockLevel; /* one byte no need to le_to_cpu */
+ *netfid = pSMBr->Fid; /* cifs fid stays in le */
+ /* Let caller know file was created so we can set the mode. */
+ /* Do we care about the CreateAction in any other cases? */
+ if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
+ *pOplock |= CIFS_CREATE_ACTION;
+ if(pfile_info) {
+ memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
+ 36 /* CreationTime to Attributes */);
+ /* the file_info buf is endian converted by caller */
+ pfile_info->AllocationSize = pSMBr->AllocationSize;
+ pfile_info->EndOfFile = pSMBr->EndOfFile;
+ pfile_info->NumberOfLinks = cpu_to_le32(1);
+ }
+
+#ifdef CONFIG_CIFS_STATS
+ atomic_inc(&tcon->num_opens);
+#endif
+ }
+ if (pSMB)
+ cifs_buf_release(pSMB);
+ if (rc == -EAGAIN)
+ goto openRetry;
+ return rc;
+}
+
+/* If no buffer passed in, then caller wants to do the copy
+ as in the case of readpages so the SMB buffer must be
+ freed by the caller */
+
+int
+CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
+ const int netfid, const unsigned int count,
+ const __u64 lseek, unsigned int *nbytes, char **buf)
+{
+ int rc = -EACCES;
+ READ_REQ *pSMB = NULL;
+ READ_RSP *pSMBr = NULL;
+ char *pReadData = NULL;
+ int bytes_returned;
+
+ *nbytes = 0;
+ rc = smb_init(SMB_COM_READ_ANDX, 12, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ /* tcon and ses pointer are checked in smb_init */
+ if (tcon->ses->server == NULL)
+ return -ECONNABORTED;
+
+ pSMB->AndXCommand = 0xFF; /* none */
+ pSMB->Fid = netfid;
+ pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
+ pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
+ pSMB->Remaining = 0;
+ pSMB->MaxCount = cpu_to_le16(count);
+ pSMB->MaxCountHigh = 0;
+ pSMB->ByteCount = 0; /* no need to do le conversion since it is 0 */
+
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc) {
+ cERROR(1, ("Send error in read = %d", rc));
+ } else {
+ pSMBr->DataLength = le16_to_cpu(pSMBr->DataLength);
+ *nbytes = pSMBr->DataLength;
+ /*check that DataLength would not go beyond end of SMB */
+ if ((pSMBr->DataLength > CIFS_MAX_MSGSIZE)
+ || (pSMBr->DataLength > count)) {
+ cFYI(1,("bad length %d for count %d",pSMBr->DataLength,count));
+ rc = -EIO;
+ *nbytes = 0;
+ } else {
+ pReadData =
+ (char *) (&pSMBr->hdr.Protocol) +
+ le16_to_cpu(pSMBr->DataOffset);
+/* if(rc = copy_to_user(buf, pReadData, pSMBr->DataLength)) {
+ cERROR(1,("Faulting on read rc = %d",rc));
+ rc = -EFAULT;
+ }*/ /* can not use copy_to_user when using page cache*/
+ if(*buf)
+ memcpy(*buf,pReadData,pSMBr->DataLength);
+ }
+ }
+ if (pSMB) {
+ if(*buf)
+ cifs_buf_release(pSMB);
+ else
+ *buf = (char *)pSMB;
+ }
+
+ /* Note: On -EAGAIN error only caller can retry on handle based calls
+ since file handle passed in no longer valid */
+ return rc;
+}
+
+int
+CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
+ const int netfid, const unsigned int count,
+ const __u64 offset, unsigned int *nbytes, const char *buf,
+ const int long_op)
+{
+ int rc = -EACCES;
+ WRITE_REQ *pSMB = NULL;
+ WRITE_RSP *pSMBr = NULL;
+ int bytes_returned;
+
+ rc = smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+ /* tcon and ses pointer are checked in smb_init */
+ if (tcon->ses->server == NULL)
+ return -ECONNABORTED;
+
+ pSMB->AndXCommand = 0xFF; /* none */
+ pSMB->Fid = netfid;
+ pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
+ pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
+ pSMB->Remaining = 0;
+ if (count > ((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00))
+ pSMB->DataLengthLow =
+ (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00;
+ else
+ pSMB->DataLengthLow = count;
+ pSMB->DataLengthHigh = 0;
+ pSMB->DataOffset =
+ cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
+
+ memcpy(pSMB->Data,buf,pSMB->DataLengthLow);
+
+ pSMB->ByteCount += pSMB->DataLengthLow + 1 /* pad */ ;
+ pSMB->DataLengthLow = cpu_to_le16(pSMB->DataLengthLow);
+ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
+ if (rc) {
+ cFYI(1, ("Send error in write = %d", rc));
+ *nbytes = 0;
+ } else
+ *nbytes = le16_to_cpu(pSMBr->Count);
+
+ if (pSMB)
+ cifs_buf_release(pSMB);
+
+ /* Note: On -EAGAIN error only caller can retry on handle based calls
+ since file handle passed in no longer valid */
+
+ return rc;
+}
+
+int
+CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
+ const __u16 smb_file_id, const __u64 len,
+ const __u64 offset, const __u32 numUnlock,
+ const __u32 numLock, const __u8 lockType, const int waitFlag)
+{
+ int rc = 0;
+ LOCK_REQ *pSMB = NULL;
+ LOCK_RSP *pSMBr = NULL;
+ int bytes_returned;
+ int timeout = 0;
+ __u64 temp;
+
+ cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
+ rc = smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
+ timeout = -1; /* no response expected */
+ pSMB->Timeout = 0;
+ } else if (waitFlag == TRUE) {
+ timeout = 3; /* blocking operation, no timeout */
+ pSMB->Timeout = -1; /* blocking - do not time out */
+ } else {
+ pSMB->Timeout = 0;
+ }
+
+ pSMB->NumberOfLocks = cpu_to_le32(numLock);
+ pSMB->NumberOfUnlocks = cpu_to_le32(numUnlock);
+ pSMB->LockType = lockType;
+ pSMB->AndXCommand = 0xFF; /* none */
+ pSMB->Fid = smb_file_id; /* netfid stays le */
+
+ if(numLock != 0) {
+ pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
+ /* BB where to store pid high? */
+ temp = cpu_to_le64(len);
+ pSMB->Locks[0].LengthLow = (__u32)(temp & 0xFFFFFFFF);
+ pSMB->Locks[0].LengthHigh = (__u32)(temp>>32);
+ temp = cpu_to_le64(offset);
+ pSMB->Locks[0].OffsetLow = (__u32)(temp & 0xFFFFFFFF);
+ pSMB->Locks[0].OffsetHigh = (__u32)(temp>>32);
+ pSMB->ByteCount = sizeof (LOCKING_ANDX_RANGE);
+ } else {
+ /* oplock break */
+ pSMB->ByteCount = 0;
+ }
+ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
+
+ if (rc) {
+ cFYI(1, ("Send error in Lock = %d", rc));
+ }
+ if (pSMB)
+ cifs_buf_release(pSMB);
+
+ /* Note: On -EAGAIN error only caller can retry on handle based calls
+ since file handle passed in no longer valid */
+ return rc;
+}
+
+int
+CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
+{
+ int rc = 0;
+ CLOSE_REQ *pSMB = NULL;
+ CLOSE_RSP *pSMBr = NULL;
+ int bytes_returned;
+ cFYI(1, ("In CIFSSMBClose"));
+
+/* do not retry on dead session on close */
+ rc = smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if(rc == -EAGAIN)
+ return 0;
+ if (rc)
+ return rc;
+
+ pSMB->FileID = (__u16) smb_file_id;
+ pSMB->LastWriteTime = 0;
+ pSMB->ByteCount = 0;
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc) {
+ if(rc!=-EINTR) {
+ /* EINTR is expected when user ctl-c to kill app */
+ cERROR(1, ("Send error in Close = %d", rc));
+ }
+ }
+ if (pSMB)
+ cifs_buf_release(pSMB);
+
+ /* Since session is dead, file will be closed on server already */
+ if(rc == -EAGAIN)
+ rc = 0;
+
+ return rc;
+}
+
+int
+CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
+ const char *fromName, const char *toName,
+ const struct nls_table *nls_codepage)
+{
+ int rc = 0;
+ RENAME_REQ *pSMB = NULL;
+ RENAME_RSP *pSMBr = NULL;
+ int bytes_returned;
+ int name_len, name_len2;
+
+ cFYI(1, ("In CIFSSMBRename"));
+renameRetry:
+ rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ pSMB->BufferFormat = 0x04;
+ pSMB->SearchAttributes =
+ cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
+ ATTR_DIRECTORY);
+
+ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+ name_len =
+ cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, 530
+ /* find define for this maxpathcomponent */
+ , nls_codepage);
+ name_len++; /* trailing null */
+ name_len *= 2;
+ pSMB->OldFileName[name_len] = 0x04; /* pad */
+ /* protocol requires ASCII signature byte on Unicode string */
+ pSMB->OldFileName[name_len + 1] = 0x00;
+ name_len2 =
+ cifs_strtoUCS((wchar_t *) & pSMB->
+ OldFileName[name_len + 2], toName, 530,
+ nls_codepage);
+ name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
+ name_len2 *= 2; /* convert to bytes */
+ } else { /* BB improve the check for buffer overruns BB */
+ name_len = strnlen(fromName, 530);
+ name_len++; /* trailing null */
+ strncpy(pSMB->OldFileName, fromName, name_len);
+ name_len2 = strnlen(toName, 530);
+ name_len2++; /* trailing null */
+ pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
+ strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
+ name_len2++; /* trailing null */
+ name_len2++; /* signature byte */
+ }
+
+ pSMB->ByteCount = 1 /* 1st signature byte */ + name_len + name_len2;
+ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc) {
+ cFYI(1, ("Send error in rename = %d", rc));
+ }
+
+#ifdef CONFIG_CIFS_STATS
+ else {
+ atomic_inc(&tcon->num_renames);
+ }
+#endif
+
+ if (pSMB)
+ cifs_buf_release(pSMB);
+
+ if (rc == -EAGAIN)
+ goto renameRetry;
+
+ return rc;
+}
+
+int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
+ int netfid, char * target_name, const struct nls_table * nls_codepage)
+{
+ struct smb_com_transaction2_sfi_req *pSMB = NULL;
+ struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
+ struct set_file_rename * rename_info;
+ char *data_offset;
+ char dummy_string[30];
+ int rc = 0;
+ int bytes_returned = 0;
+ int len_of_str;
+
+ cFYI(1, ("Rename to File by handle"));
+ rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ pSMB->ParameterCount = 6;
+ pSMB->MaxSetupCount = 0;
+ pSMB->Reserved = 0;
+ pSMB->Flags = 0;
+ pSMB->Timeout = 0;
+ pSMB->Reserved2 = 0;
+ pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_sfi_req,
+ Fid) - 4;
+ pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
+
+ data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset;
+ rename_info = (struct set_file_rename *) data_offset;
+ pSMB->MaxParameterCount = cpu_to_le16(2);
+ pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
+ pSMB->SetupCount = 1;
+ pSMB->Reserved3 = 0;
+ pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
+ pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount;
+ pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
+ pSMB->TotalParameterCount = pSMB->ParameterCount;
+ pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
+ pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
+ /* construct random name ".cifs_tmp<inodenum><mid>" */
+ rename_info->overwrite = cpu_to_le32(1);
+ rename_info->root_fid = 0;
+ /* unicode only call */
+ if(target_name == NULL) {
+ sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
+ len_of_str = cifs_strtoUCS((wchar_t *) rename_info->target_name, dummy_string, 24, nls_codepage);
+ } else {
+ len_of_str = cifs_strtoUCS((wchar_t *) rename_info->target_name, target_name, 530, nls_codepage);
+ }
+ rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
+ pSMB->DataCount = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
+ pSMB->ByteCount += pSMB->DataCount;
+ pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
+ pSMB->TotalDataCount = pSMB->DataCount;
+ pSMB->Fid = netfid;
+ pSMB->InformationLevel =
+ cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
+ pSMB->Reserved4 = 0;
+ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+ rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc) {
+ cFYI(1,("Send error in Rename (by file handle) = %d", rc));
+ }
+#ifdef CONFIG_CIFS_STATS
+ else {
+ atomic_inc(&pTcon->num_t2renames);
+ }
+#endif
+ if (pSMB)
+ cifs_buf_release(pSMB);
+
+ /* Note: On -EAGAIN error only caller can retry on handle based calls
+ since file handle passed in no longer valid */
+
+ return rc;
+}
+
+int
+CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
+ const __u16 target_tid, const char *toName, const int flags,
+ const struct nls_table *nls_codepage)
+{
+ int rc = 0;
+ COPY_REQ *pSMB = NULL;
+ COPY_RSP *pSMBr = NULL;
+ int bytes_returned;
+ int name_len, name_len2;
+
+ cFYI(1, ("In CIFSSMBCopy"));
+copyRetry:
+ rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ pSMB->BufferFormat = 0x04;
+ pSMB->Tid2 = target_tid;
+
+ if(flags & COPY_TREE)
+ pSMB->Flags |= COPY_TREE;
+ pSMB->Flags = cpu_to_le16(pSMB->Flags);
+
+ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+ name_len = cifs_strtoUCS((wchar_t *) pSMB->OldFileName,
+ fromName,
+ 530 /* find define for this maxpathcomponent */,
+ nls_codepage);
+ name_len++; /* trailing null */
+ name_len *= 2;
+ pSMB->OldFileName[name_len] = 0x04; /* pad */
+ /* protocol requires ASCII signature byte on Unicode string */
+ pSMB->OldFileName[name_len + 1] = 0x00;
+ name_len2 = cifs_strtoUCS((wchar_t *) & pSMB->
+ OldFileName[name_len + 2], toName, 530,
+ nls_codepage);
+ name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
+ name_len2 *= 2; /* convert to bytes */
+ } else { /* BB improve the check for buffer overruns BB */
+ name_len = strnlen(fromName, 530);
+ name_len++; /* trailing null */
+ strncpy(pSMB->OldFileName, fromName, name_len);
+ name_len2 = strnlen(toName, 530);
+ name_len2++; /* trailing null */
+ pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
+ strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
+ name_len2++; /* trailing null */
+ name_len2++; /* signature byte */
+ }
+
+ pSMB->ByteCount = 1 /* 1st signature byte */ + name_len + name_len2;
+ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc) {
+ cFYI(1, ("Send error in copy = %d with %d files copied",
+ rc, pSMBr->CopyCount));
+ }
+ if (pSMB)
+ cifs_buf_release(pSMB);
+
+ if (rc == -EAGAIN)
+ goto copyRetry;
+
+ return rc;
+}
+
+int
+CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
+ const char *fromName, const char *toName,
+ const struct nls_table *nls_codepage)
+{
+ TRANSACTION2_SPI_REQ *pSMB = NULL;
+ TRANSACTION2_SPI_RSP *pSMBr = NULL;
+ char *data_offset;
+ int name_len;
+ int name_len_target;
+ int rc = 0;
+ int bytes_returned = 0;
+
+ cFYI(1, ("In Symlink Unix style"));
+createSymLinkRetry:
+ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+ name_len =
+ cifs_strtoUCS((wchar_t *) pSMB->FileName, fromName, 530
+ /* find define for this maxpathcomponent */
+ , nls_codepage);
+ name_len++; /* trailing null */
+ name_len *= 2;
+
+ } else { /* BB improve the check for buffer overruns BB */
+ name_len = strnlen(fromName, 530);
+ name_len++; /* trailing null */
+ strncpy(pSMB->FileName, fromName, name_len);
+ }
+ pSMB->ParameterCount = 6 + name_len;
+ pSMB->MaxSetupCount = 0;
+ pSMB->Reserved = 0;
+ pSMB->Flags = 0;
+ pSMB->Timeout = 0;
+ pSMB->Reserved2 = 0;
+ pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req,
+ InformationLevel) - 4;
+ pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
+
+ data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset;
+ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+ name_len_target =
+ cifs_strtoUCS((wchar_t *) data_offset, toName, 530
+ /* find define for this maxpathcomponent */
+ , nls_codepage);
+ name_len_target++; /* trailing null */
+ name_len_target *= 2;
+ } else { /* BB improve the check for buffer overruns BB */
+ name_len_target = strnlen(toName, 530);
+ name_len_target++; /* trailing null */
+ strncpy(data_offset, toName, name_len_target);
+ }
+
+ pSMB->DataCount = name_len_target;
+ pSMB->MaxParameterCount = cpu_to_le16(2);
+ /* BB find exact max on data count below from sess */
+ pSMB->MaxDataCount = cpu_to_le16(1000);
+ pSMB->SetupCount = 1;
+ pSMB->Reserved3 = 0;
+ pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
+ pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount;
+ pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
+ pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
+ pSMB->TotalDataCount = pSMB->DataCount;
+ pSMB->TotalParameterCount = pSMB->ParameterCount;
+ pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
+ pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
+ pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
+ pSMB->Reserved4 = 0;
+ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc) {
+ cFYI(1,
+ ("Send error in SetPathInfo (create symlink) = %d",
+ rc));
+ }
+
+ if (pSMB)
+ cifs_buf_release(pSMB);
+
+ if (rc == -EAGAIN)
+ goto createSymLinkRetry;
+
+ return rc;
+}
+
+int
+CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
+ const char *fromName, const char *toName,
+ const struct nls_table *nls_codepage)
+{
+ TRANSACTION2_SPI_REQ *pSMB = NULL;
+ TRANSACTION2_SPI_RSP *pSMBr = NULL;
+ char *data_offset;
+ int name_len;
+ int name_len_target;
+ int rc = 0;
+ int bytes_returned = 0;
+
+ cFYI(1, ("In Create Hard link Unix style"));
+createHardLinkRetry:
+ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+ name_len = cifs_strtoUCS((wchar_t *) pSMB->FileName, toName, 530
+ /* find define for this maxpathcomponent */
+ , nls_codepage);
+ name_len++; /* trailing null */
+ name_len *= 2;
+
+ } else { /* BB improve the check for buffer overruns BB */
+ name_len = strnlen(toName, 530);
+ name_len++; /* trailing null */
+ strncpy(pSMB->FileName, toName, name_len);
+ }
+ pSMB->ParameterCount = 6 + name_len;
+ pSMB->MaxSetupCount = 0;
+ pSMB->Reserved = 0;
+ pSMB->Flags = 0;
+ pSMB->Timeout = 0;
+ pSMB->Reserved2 = 0;
+ pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req,
+ InformationLevel) - 4;
+ pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
+
+ data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset;
+ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+ name_len_target =
+ cifs_strtoUCS((wchar_t *) data_offset, fromName, 530
+ /* find define for this maxpathcomponent */
+ , nls_codepage);
+ name_len_target++; /* trailing null */
+ name_len_target *= 2;
+ } else { /* BB improve the check for buffer overruns BB */
+ name_len_target = strnlen(fromName, 530);
+ name_len_target++; /* trailing null */
+ strncpy(data_offset, fromName, name_len_target);
+ }
+
+ pSMB->DataCount = name_len_target;
+ pSMB->MaxParameterCount = cpu_to_le16(2);
+ /* BB find exact max on data count below from sess*/
+ pSMB->MaxDataCount = cpu_to_le16(1000);
+ pSMB->SetupCount = 1;
+ pSMB->Reserved3 = 0;
+ pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
+ pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount;
+ pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
+ pSMB->TotalParameterCount = pSMB->ParameterCount;
+ pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
+ pSMB->TotalDataCount = pSMB->DataCount;
+ pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
+ pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
+ pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
+ pSMB->Reserved4 = 0;
+ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc) {
+ cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
+ }
+
+ if (pSMB)
+ cifs_buf_release(pSMB);
+ if (rc == -EAGAIN)
+ goto createHardLinkRetry;
+
+ return rc;
+}
+
+int
+CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
+ const char *fromName, const char *toName,
+ const struct nls_table *nls_codepage)
+{
+ int rc = 0;
+ NT_RENAME_REQ *pSMB = NULL;
+ RENAME_RSP *pSMBr = NULL;
+ int bytes_returned;
+ int name_len, name_len2;
+
+ cFYI(1, ("In CIFSCreateHardLink"));
+winCreateHardLinkRetry:
+
+ rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ pSMB->SearchAttributes =
+ cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
+ ATTR_DIRECTORY);
+ pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
+ pSMB->ClusterCount = 0;
+
+ pSMB->BufferFormat = 0x04;
+
+ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+ name_len =
+ cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, 530
+ /* find define for this maxpathcomponent */
+ , nls_codepage);
+ name_len++; /* trailing null */
+ name_len *= 2;
+ pSMB->OldFileName[name_len] = 0; /* pad */
+ pSMB->OldFileName[name_len + 1] = 0x04;
+ name_len2 =
+ cifs_strtoUCS((wchar_t *) & pSMB->
+ OldFileName[name_len + 2], toName, 530,
+ nls_codepage);
+ name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
+ name_len2 *= 2; /* convert to bytes */
+ } else { /* BB improve the check for buffer overruns BB */
+ name_len = strnlen(fromName, 530);
+ name_len++; /* trailing null */
+ strncpy(pSMB->OldFileName, fromName, name_len);
+ name_len2 = strnlen(toName, 530);
+ name_len2++; /* trailing null */
+ pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
+ strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
+ name_len2++; /* trailing null */
+ name_len2++; /* signature byte */
+ }
+
+ pSMB->ByteCount = 1 /* string type byte */ + name_len + name_len2;
+ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc) {
+ cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
+ }
+ if (pSMB)
+ cifs_buf_release(pSMB);
+ if (rc == -EAGAIN)
+ goto winCreateHardLinkRetry;
+
+ return rc;
+}
+
+int
+CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
+ const unsigned char *searchName,
+ char *symlinkinfo, const int buflen,
+ const struct nls_table *nls_codepage)
+{
+/* SMB_QUERY_FILE_UNIX_LINK */
+ TRANSACTION2_QPI_REQ *pSMB = NULL;
+ TRANSACTION2_QPI_RSP *pSMBr = NULL;
+ int rc = 0;
+ int bytes_returned;
+ int name_len;
+
+ cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
+
+querySymLinkRetry:
+ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+ name_len =
+ cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530
+ /* find define for this maxpathcomponent */
+ , nls_codepage);
+ name_len++; /* trailing null */
+ name_len *= 2;
+ } else { /* BB improve the check for buffer overruns BB */
+ name_len = strnlen(searchName, 530);
+ name_len++; /* trailing null */
+ strncpy(pSMB->FileName, searchName, name_len);
+ }
+
+ pSMB->TotalParameterCount =
+ 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
+ pSMB->TotalDataCount = 0;
+ pSMB->MaxParameterCount = cpu_to_le16(2);
+ /* BB find exact max data count below from sess structure BB */
+ pSMB->MaxDataCount = cpu_to_le16(4000);
+ pSMB->MaxSetupCount = 0;
+ pSMB->Reserved = 0;
+ pSMB->Flags = 0;
+ pSMB->Timeout = 0;
+ pSMB->Reserved2 = 0;
+ pSMB->ParameterOffset = cpu_to_le16(offsetof(
+ struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+ pSMB->DataCount = 0;
+ pSMB->DataOffset = 0;
+ pSMB->SetupCount = 1;
+ pSMB->Reserved3 = 0;
+ pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
+ pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
+ pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
+ pSMB->ParameterCount = pSMB->TotalParameterCount;
+ pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
+ pSMB->Reserved4 = 0;
+ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc) {
+ cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
+ } else { /* decode response */
+ pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
+ pSMBr->DataCount = le16_to_cpu(pSMBr->DataCount);
+ if ((pSMBr->ByteCount < 2) || (pSMBr->DataOffset > 512))
+ /* BB also check enough total bytes returned */
+ rc = -EIO; /* bad smb */
+ else {
+ if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
+ name_len = UniStrnlen((wchar_t *) ((char *)
+ &pSMBr->hdr.Protocol +pSMBr->DataOffset),
+ min_t(const int, buflen,pSMBr->DataCount) / 2);
+ cifs_strfromUCS_le(symlinkinfo,
+ (wchar_t *) ((char *)&pSMBr->hdr.Protocol +
+ pSMBr->DataOffset),
+ name_len, nls_codepage);
+ } else {
+ strncpy(symlinkinfo,
+ (char *) &pSMBr->hdr.Protocol +
+ pSMBr->DataOffset,
+ min_t(const int, buflen, pSMBr->DataCount));
+ }
+ symlinkinfo[buflen] = 0;
+ /* just in case so calling code does not go off the end of buffer */
+ }
+ }
+ if (pSMB)
+ cifs_buf_release(pSMB);
+ if (rc == -EAGAIN)
+ goto querySymLinkRetry;
+ return rc;
+}
+
+
+
+int
+CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
+ const unsigned char *searchName,
+ char *symlinkinfo, const int buflen,__u16 fid,
+ const struct nls_table *nls_codepage)
+{
+ int rc = 0;
+ int bytes_returned;
+ int name_len;
+ struct smb_com_transaction_ioctl_req * pSMB;
+ struct smb_com_transaction_ioctl_rsp * pSMBr;
+
+ cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
+ rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ pSMB->TotalParameterCount = 0 ;
+ pSMB->TotalDataCount = 0;
+ pSMB->MaxParameterCount = cpu_to_le32(2);
+ /* BB find exact data count max from sess structure BB */
+ pSMB->MaxDataCount = cpu_to_le32(4000);
+ pSMB->MaxSetupCount = 4;
+ pSMB->Reserved = 0;
+ pSMB->ParameterOffset = 0;
+ pSMB->DataCount = 0;
+ pSMB->DataOffset = 0;
+ pSMB->SetupCount = 4;
+ pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
+ pSMB->ParameterCount = pSMB->TotalParameterCount;
+ pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
+ pSMB->IsFsctl = 1; /* FSCTL */
+ pSMB->IsRootFlag = 0;
+ pSMB->Fid = fid; /* file handle always le */
+ pSMB->ByteCount = 0;
+
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc) {
+ cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
+ } else { /* decode response */
+ pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
+ pSMBr->DataCount = le16_to_cpu(pSMBr->DataCount);
+ if ((pSMBr->ByteCount < 2) || (pSMBr->DataOffset > 512))
+ /* BB also check enough total bytes returned */
+ rc = -EIO; /* bad smb */
+ else {
+ if(pSMBr->DataCount && (pSMBr->DataCount < 2048)) {
+ /* could also validate reparse tag && better check name length */
+ struct reparse_data * reparse_buf = (struct reparse_data *)
+ ((char *)&pSMBr->hdr.Protocol + pSMBr->DataOffset);
+ if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
+ name_len = UniStrnlen((wchar_t *)
+ (reparse_buf->LinkNamesBuf +
+ reparse_buf->TargetNameOffset),
+ min(buflen/2, reparse_buf->TargetNameLen / 2));
+ cifs_strfromUCS_le(symlinkinfo,
+ (wchar_t *) (reparse_buf->LinkNamesBuf +
+ reparse_buf->TargetNameOffset),
+ name_len, nls_codepage);
+ } else { /* ASCII names */
+ strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
+ reparse_buf->TargetNameOffset,
+ min_t(const int, buflen, reparse_buf->TargetNameLen));
+ }
+ } else {
+ rc = -EIO;
+ cFYI(1,("Invalid return data count on get reparse info ioctl"));
+ }
+ symlinkinfo[buflen] = 0; /* just in case so the caller
+ does not go off the end of the buffer */
+ cFYI(1,("readlink result - %s ",symlinkinfo));
+ }
+ }
+ if (pSMB)
+ cifs_buf_release(pSMB);
+
+ /* Note: On -EAGAIN error only caller can retry on handle based calls
+ since file handle passed in no longer valid */
+
+ return rc;
+}
+
+int
+CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
+ const unsigned char *searchName,
+ FILE_ALL_INFO * pFindData,
+ const struct nls_table *nls_codepage)
+{
+/* level 263 SMB_QUERY_FILE_ALL_INFO */
+ TRANSACTION2_QPI_REQ *pSMB = NULL;
+ TRANSACTION2_QPI_RSP *pSMBr = NULL;
+ int rc = 0;
+ int bytes_returned;
+ int name_len;
+
+ cFYI(1, ("In QPathInfo path %s", searchName));
+QPathInfoRetry:
+ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+ name_len =
+ cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530
+ /* find define for this maxpathcomponent */
+ , nls_codepage);
+ name_len++; /* trailing null */
+ name_len *= 2;
+ } else { /* BB improve the check for buffer overruns BB */
+ name_len = strnlen(searchName, 530);
+ name_len++; /* trailing null */
+ strncpy(pSMB->FileName, searchName, name_len);
+ }
+
+ pSMB->TotalParameterCount = 2 /* level */ + 4 /* reserved */ +
+ name_len /* includes null */ ;
+ pSMB->TotalDataCount = 0;
+ pSMB->MaxParameterCount = cpu_to_le16(2);
+ pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
+ pSMB->MaxSetupCount = 0;
+ pSMB->Reserved = 0;
+ pSMB->Flags = 0;
+ pSMB->Timeout = 0;
+ pSMB->Reserved2 = 0;
+ pSMB->ParameterOffset = cpu_to_le16(offsetof(
+ struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+ pSMB->DataCount = 0;
+ pSMB->DataOffset = 0;
+ pSMB->SetupCount = 1;
+ pSMB->Reserved3 = 0;
+ pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
+ pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
+ pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
+ pSMB->ParameterCount = pSMB->TotalParameterCount;
+ pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
+ pSMB->Reserved4 = 0;
+ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc) {
+ cFYI(1, ("Send error in QPathInfo = %d", rc));
+ } else { /* decode response */
+ pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
+ /* BB also check enough total bytes returned */
+ /* BB we need to improve the validity checking
+ of these trans2 responses */
+ if ((pSMBr->ByteCount < 40) || (pSMBr->DataOffset > 512))
+ rc = -EIO; /* bad smb */
+ else if (pFindData){
+ memcpy((char *) pFindData,
+ (char *) &pSMBr->hdr.Protocol +
+ pSMBr->DataOffset, sizeof (FILE_ALL_INFO));
+ } else
+ rc = -ENOMEM;
+ }
+ if (pSMB)
+ cifs_buf_release(pSMB);
+ if (rc == -EAGAIN)
+ goto QPathInfoRetry;
+
+ return rc;
+}
+
+int
+CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
+ const unsigned char *searchName,
+ FILE_UNIX_BASIC_INFO * pFindData,
+ const struct nls_table *nls_codepage)
+{
+/* SMB_QUERY_FILE_UNIX_BASIC */
+ TRANSACTION2_QPI_REQ *pSMB = NULL;
+ TRANSACTION2_QPI_RSP *pSMBr = NULL;
+ int rc = 0;
+ int bytes_returned = 0;
+ int name_len;
+
+ cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
+UnixQPathInfoRetry:
+ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+ name_len =
+ cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530
+ /* find define for this maxpathcomponent */
+ , nls_codepage);
+ name_len++; /* trailing null */
+ name_len *= 2;
+ } else { /* BB improve the check for buffer overruns BB */
+ name_len = strnlen(searchName, 530);
+ name_len++; /* trailing null */
+ strncpy(pSMB->FileName, searchName, name_len);
+ }
+
+ pSMB->TotalParameterCount = 2 /* level */ + 4 /* reserved */ +
+ name_len /* includes null */ ;
+ pSMB->TotalDataCount = 0;
+ pSMB->MaxParameterCount = cpu_to_le16(2);
+ /* BB find exact max SMB PDU from sess structure BB */
+ pSMB->MaxDataCount = cpu_to_le16(4000);
+ pSMB->MaxSetupCount = 0;
+ pSMB->Reserved = 0;
+ pSMB->Flags = 0;
+ pSMB->Timeout = 0;
+ pSMB->Reserved2 = 0;
+ pSMB->ParameterOffset = cpu_to_le16(offsetof(
+ struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+ pSMB->DataCount = 0;
+ pSMB->DataOffset = 0;
+ pSMB->SetupCount = 1;
+ pSMB->Reserved3 = 0;
+ pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
+ pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
+ pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
+ pSMB->ParameterCount = pSMB->TotalParameterCount;
+ pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
+ pSMB->Reserved4 = 0;
+ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc) {
+ cFYI(1, ("Send error in QPathInfo = %d", rc));
+ } else { /* decode response */
+ pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
+ /* BB also check if enough total bytes returned */
+ if ((pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO)) ||
+ (pSMBr->DataOffset > 512) ||
+ (pSMBr->DataOffset < sizeof(struct smb_hdr))) {
+ cFYI(1,("UnixQPathinfo invalid data offset %d bytes returned %d",
+ (int)pSMBr->DataOffset,bytes_returned));
+ rc = -EIO; /* bad smb */
+ } else {
+ memcpy((char *) pFindData,
+ (char *) &pSMBr->hdr.Protocol +
+ pSMBr->DataOffset,
+ sizeof (FILE_UNIX_BASIC_INFO));
+ }
+ }
+ if (pSMB)
+ cifs_buf_release(pSMB);
+ if (rc == -EAGAIN)
+ goto UnixQPathInfoRetry;
+
+ return rc;
+}
+
+int
+CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
+ const char *searchName, FILE_ALL_INFO * findData,
+ const struct nls_table *nls_codepage)
+{
+/* level 257 SMB_ */
+ TRANSACTION2_FFIRST_REQ *pSMB = NULL;
+ TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
+ int rc = 0;
+ int bytes_returned;
+ int name_len;
+
+ cFYI(1, ("In FindUnique"));
+findUniqueRetry:
+ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+ name_len =
+ cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530
+ /* find define for this maxpathcomponent */
+ , nls_codepage);
+ name_len++; /* trailing null */
+ name_len *= 2;
+ } else { /* BB improve the check for buffer overruns BB */
+ name_len = strnlen(searchName, 530);
+ name_len++; /* trailing null */
+ strncpy(pSMB->FileName, searchName, name_len);
+ }
+
+ pSMB->TotalParameterCount = 12 + name_len /* includes null */ ;
+ pSMB->TotalDataCount = 0; /* no EAs */
+ pSMB->MaxParameterCount = cpu_to_le16(2);
+ pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
+ pSMB->MaxSetupCount = 0;
+ pSMB->Reserved = 0;
+ pSMB->Flags = 0;
+ pSMB->Timeout = 0;
+ pSMB->Reserved2 = 0;
+ pSMB->ParameterOffset = cpu_to_le16(
+ offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
+ pSMB->DataCount = 0;
+ pSMB->DataOffset = 0;
+ pSMB->SetupCount = 1; /* one byte, no need to le convert */
+ pSMB->Reserved3 = 0;
+ pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
+ pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
+ pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalDataCount);
+ pSMB->ParameterCount = pSMB->TotalParameterCount;
+ pSMB->SearchAttributes =
+ cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
+ ATTR_DIRECTORY);
+ pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
+ pSMB->SearchFlags = cpu_to_le16(1);
+ pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
+ pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
+ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+
+ if (rc) {
+ cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
+ } else { /* decode response */
+
+ /* BB fill in */
+ }
+ if (pSMB)
+ cifs_buf_release(pSMB);
+ if (rc == -EAGAIN)
+ goto findUniqueRetry;
+
+ return rc;
+}
+
+int
+CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
+ const char *searchName, FILE_DIRECTORY_INFO * findData,
+ T2_FFIRST_RSP_PARMS * findParms,
+ const struct nls_table *nls_codepage, int *pUnicodeFlag,
+ int *pUnixFlag)
+{
+/* level 257 SMB_ */
+ TRANSACTION2_FFIRST_REQ *pSMB = NULL;
+ TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
+ char *response_data;
+ int rc = 0;
+ int bytes_returned;
+ int name_len;
+
+ cFYI(1, ("In FindFirst"));
+findFirstRetry:
+ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+ name_len =
+ cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530
+ /* find define for this maxpathcomponent */
+ , nls_codepage);
+ name_len++; /* trailing null */
+ name_len *= 2;
+ } else { /* BB improve the check for buffer overruns BB */
+ name_len = strnlen(searchName, 530);
+ name_len++; /* trailing null */
+ strncpy(pSMB->FileName, searchName, name_len);
+ }
+
+ pSMB->TotalParameterCount = 12 + name_len /* includes null */ ;
+ pSMB->TotalDataCount = 0; /* no EAs */
+ pSMB->MaxParameterCount = cpu_to_le16(10);
+ pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
+ MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
+ pSMB->MaxSetupCount = 0;
+ pSMB->Reserved = 0;
+ pSMB->Flags = 0;
+ pSMB->Timeout = 0;
+ pSMB->Reserved2 = 0;
+ pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
+ pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
+ pSMB->ParameterCount = pSMB->TotalParameterCount;
+ pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
+ smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
+ pSMB->DataCount = 0;
+ pSMB->DataOffset = 0;
+ pSMB->SetupCount = 1; /* one byte no need to make endian neutral */
+ pSMB->Reserved3 = 0;
+ pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
+ pSMB->SearchAttributes =
+ cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
+ ATTR_DIRECTORY);
+ pSMB->SearchCount = cpu_to_le16(CIFS_MAX_MSGSIZE / sizeof (FILE_DIRECTORY_INFO)); /* should this be shrunk even more ? */
+ pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
+
+ /* test for Unix extensions */
+ if (tcon->ses->capabilities & CAP_UNIX) {
+ pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
+ *pUnixFlag = TRUE;
+ } else {
+ pSMB->InformationLevel =
+ cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
+ *pUnixFlag = FALSE;
+ }
+ pSMB->SearchStorageType = 0; /* BB what should we set this to? It is not clear if it matters BB */
+ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+
+ if (rc) { /* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
+ cFYI(1, ("Error in FindFirst = %d", rc));
+ } else { /* decode response */
+ /* BB add safety checks for these memcpys */
+ if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
+ *pUnicodeFlag = TRUE;
+ else
+ *pUnicodeFlag = FALSE;
+ memcpy(findParms,
+ (char *) &pSMBr->hdr.Protocol +
+ le16_to_cpu(pSMBr->ParameterOffset),
+ sizeof (T2_FFIRST_RSP_PARMS));
+ /* search handle can stay LE and EAoffset not needed so not converted */
+ findParms->EndofSearch = le16_to_cpu(findParms->EndofSearch);
+ findParms->LastNameOffset =
+ le16_to_cpu(findParms->LastNameOffset);
+ findParms->SearchCount = le16_to_cpu(findParms->SearchCount);
+ response_data =
+ (char *) &pSMBr->hdr.Protocol +
+ le16_to_cpu(pSMBr->DataOffset);
+ memcpy(findData, response_data, le16_to_cpu(pSMBr->DataCount));
+ }
+ if (pSMB)
+ cifs_buf_release(pSMB);
+
+ if (rc == -EAGAIN)
+ goto findFirstRetry;
+
+ return rc;
+}
+
+int
+CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
+ FILE_DIRECTORY_INFO * findData, T2_FNEXT_RSP_PARMS * findParms,
+ const __u16 searchHandle, char * resume_file_name, int name_len,
+ __u32 resume_key, int *pUnicodeFlag, int *pUnixFlag)
+{
+/* level 257 SMB_ */
+ TRANSACTION2_FNEXT_REQ *pSMB = NULL;
+ TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
+ char *response_data;
+ int rc = 0;
+ int bytes_returned;
+
+ cFYI(1, ("In FindNext"));
+
+ if(resume_file_name == NULL) {
+ return -EIO;
+ }
+ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ pSMB->TotalParameterCount = 14; /* includes 2 bytes of null string, converted to LE below */
+ pSMB->TotalDataCount = 0; /* no EAs */
+ pSMB->MaxParameterCount = cpu_to_le16(8);
+ pSMB->MaxDataCount =
+ cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
+ pSMB->MaxSetupCount = 0;
+ pSMB->Reserved = 0;
+ pSMB->Flags = 0;
+ pSMB->Timeout = 0;
+ pSMB->Reserved2 = 0;
+ pSMB->ParameterOffset = cpu_to_le16(offsetof(
+ struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
+ pSMB->DataCount = 0;
+ pSMB->DataOffset = 0;
+ pSMB->SetupCount = 1;
+ pSMB->Reserved3 = 0;
+ pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
+ pSMB->SearchHandle = searchHandle; /* always kept as le */
+ findParms->SearchCount = 0; /* set to zero in case of error */
+ pSMB->SearchCount =
+ cpu_to_le16(CIFS_MAX_MSGSIZE / sizeof (FILE_DIRECTORY_INFO));
+ /* test for Unix extensions */
+ if (tcon->ses->capabilities & CAP_UNIX) {
+ pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
+ *pUnixFlag = TRUE;
+ } else {
+ pSMB->InformationLevel =
+ cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
+ *pUnixFlag = FALSE;
+ }
+ pSMB->ResumeKey = resume_key;
+ pSMB->SearchFlags =
+ cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
+ /* BB add check to make sure we do not cross end of smb */
+ if(name_len < CIFS_MAX_MSGSIZE) {
+ memcpy(pSMB->ResumeFileName, resume_file_name, name_len);
+ pSMB->ByteCount += name_len;
+ }
+ pSMB->TotalParameterCount += name_len;
+ pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
+ pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
+ pSMB->ParameterCount = pSMB->TotalParameterCount;
+ /* BB improve error handling here */
+ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+
+ if (rc) {
+ if (rc == -EBADF)
+ rc = 0; /* search probably was closed at end of search above */
+ else
+ cFYI(1, ("FindNext returned = %d", rc));
+ } else { /* decode response */
+ /* BB add safety checks for these memcpys */
+ if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
+ *pUnicodeFlag = TRUE;
+ else
+ *pUnicodeFlag = FALSE;
+ memcpy(findParms,
+ (char *) &pSMBr->hdr.Protocol +
+ le16_to_cpu(pSMBr->ParameterOffset),
+ sizeof (T2_FNEXT_RSP_PARMS));
+ findParms->EndofSearch = le16_to_cpu(findParms->EndofSearch);
+ findParms->LastNameOffset =
+ le16_to_cpu(findParms->LastNameOffset);
+ findParms->SearchCount = le16_to_cpu(findParms->SearchCount);
+ response_data =
+ (char *) &pSMBr->hdr.Protocol +
+ le16_to_cpu(pSMBr->DataOffset);
+ memcpy(findData, response_data, le16_to_cpu(pSMBr->DataCount));
+ }
+ if (pSMB)
+ cifs_buf_release(pSMB);
+
+ /* Note: On -EAGAIN error only caller can retry on handle based calls
+ since file handle passed in no longer valid */
+
+ return rc;
+}
+
+int
+CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
+{
+ int rc = 0;
+ FINDCLOSE_REQ *pSMB = NULL;
+ CLOSE_RSP *pSMBr = NULL;
+ int bytes_returned;
+
+ cFYI(1, ("In CIFSSMBFindClose"));
+ rc = smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ /* no sense returning error if session restarted
+ file handle has been closed */
+ if(rc == -EAGAIN)
+ return 0;
+ if (rc)
+ return rc;
+
+ pSMB->FileID = searchHandle;
+ pSMB->ByteCount = 0;
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc) {
+ cERROR(1, ("Send error in FindClose = %d", rc));
+ }
+ if (pSMB)
+ cifs_buf_release(pSMB);
+
+ /* Since session is dead, search handle closed on server already */
+ if (rc == -EAGAIN)
+ rc = 0;
+
+ return rc;
+}
+
+int
+CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
+ const unsigned char *searchName,
+ unsigned char **targetUNCs,
+ unsigned int *number_of_UNC_in_array,
+ const struct nls_table *nls_codepage)
+{
+/* TRANS2_GET_DFS_REFERRAL */
+ TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
+ TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
+ struct dfs_referral_level_3 * referrals = NULL;
+ int rc = 0;
+ int bytes_returned;
+ int name_len;
+ unsigned int i;
+ char * temp;
+ *number_of_UNC_in_array = 0;
+ *targetUNCs = NULL;
+
+ cFYI(1, ("In GetDFSRefer the path %s", searchName));
+ if (ses == NULL)
+ return -ENODEV;
+getDFSRetry:
+ rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ pSMB->hdr.Tid = ses->ipc_tid;
+ pSMB->hdr.Uid = ses->Suid;
+ if (ses->capabilities & CAP_STATUS32) {
+ pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
+ }
+ if (ses->capabilities & CAP_DFS) {
+ pSMB->hdr.Flags2 |= SMBFLG2_DFS;
+ }
+
+ if (ses->capabilities & CAP_UNICODE) {
+ pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
+ name_len =
+ cifs_strtoUCS((wchar_t *) pSMB->RequestFileName,
+ searchName, 530
+ /* find define for this maxpathcomponent */
+ , nls_codepage);
+ name_len++; /* trailing null */
+ name_len *= 2;
+ } else { /* BB improve the check for buffer overruns BB */
+ name_len = strnlen(searchName, 530);
+ name_len++; /* trailing null */
+ strncpy(pSMB->RequestFileName, searchName, name_len);
+ }
+
+ pSMB->ParameterCount = 2 /* level */ + name_len /*includes null */ ;
+ pSMB->TotalDataCount = 0;
+ pSMB->DataCount = 0;
+ pSMB->DataOffset = 0;
+ pSMB->MaxParameterCount = 0;
+ pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
+ pSMB->MaxSetupCount = 0;
+ pSMB->Reserved = 0;
+ pSMB->Flags = 0;
+ pSMB->Timeout = 0;
+ pSMB->Reserved2 = 0;
+ pSMB->ParameterOffset = cpu_to_le16(offsetof(
+ struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
+ pSMB->SetupCount = 1;
+ pSMB->Reserved3 = 0;
+ pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
+ pSMB->ByteCount = pSMB->ParameterCount + 3 /* pad */ ;
+ pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
+ pSMB->TotalParameterCount = pSMB->ParameterCount;
+ pSMB->MaxReferralLevel = cpu_to_le16(3);
+ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+
+ rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc) {
+ cFYI(1, ("Send error in GetDFSRefer = %d", rc));
+ } else { /* decode response */
+/* BB Add logic to parse referrals here */
+ pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
+ pSMBr->DataCount = le16_to_cpu(pSMBr->DataCount);
+ cFYI(1,
+ ("Decoding GetDFSRefer response. BCC: %d Offset %d",
+ pSMBr->ByteCount, pSMBr->DataOffset));
+ if ((pSMBr->ByteCount < 17) || (pSMBr->DataOffset > 512)) /* BB also check enough total bytes returned */
+ rc = -EIO; /* bad smb */
+ else {
+ referrals =
+ (struct dfs_referral_level_3 *)
+ (8 /* sizeof start of data block */ +
+ pSMBr->DataOffset +
+ (char *) &pSMBr->hdr.Protocol);
+ cFYI(1,("num_referrals: %d dfs flags: 0x%x ... \nfor referral one refer size: 0x%x srv type: 0x%x refer flags: 0x%x ttl: 0x%x",pSMBr->NumberOfReferrals,pSMBr->DFSFlags, referrals->ReferralSize,referrals->ServerType,referrals->ReferralFlags,referrals->TimeToLive));
+ /* BB This field is actually two bytes in from start of
+ data block so we could do safety check that DataBlock
+ begins at address of pSMBr->NumberOfReferrals */
+ *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
+
+ /* BB Fix below so can return more than one referral */
+ if(*number_of_UNC_in_array > 1)
+ *number_of_UNC_in_array = 1;
+
+ /* get the length of the strings describing refs */
+ name_len = 0;
+ for(i=0;i<*number_of_UNC_in_array;i++) {
+ /* make sure that DfsPathOffset not past end */
+ referrals->DfsPathOffset = le16_to_cpu(referrals->DfsPathOffset);
+ if(referrals->DfsPathOffset > pSMBr->DataCount) {
+ /* if invalid referral, stop here and do
+ not try to copy any more */
+ *number_of_UNC_in_array = i;
+ break;
+ }
+ temp = ((char *)referrals) + referrals->DfsPathOffset;
+
+ if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
+ name_len += UniStrnlen((wchar_t *)temp,pSMBr->DataCount);
+ } else {
+ name_len += strnlen(temp,pSMBr->DataCount);
+ }
+ referrals++;
+ /* BB add check that referral pointer does not fall off end PDU */
+
+ }
+ /* BB add check for name_len bigger than bcc */
+ *targetUNCs =
+ kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
+ /* copy the ref strings */
+ referrals =
+ (struct dfs_referral_level_3 *)
+ (8 /* sizeof data hdr */ +
+ pSMBr->DataOffset +
+ (char *) &pSMBr->hdr.Protocol);
+
+ for(i=0;i<*number_of_UNC_in_array;i++) {
+ temp = ((char *)referrals) + referrals->DfsPathOffset;
+ if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
+ cifs_strfromUCS_le(*targetUNCs,
+ (wchar_t *) temp, name_len, nls_codepage);
+ } else {
+ strncpy(*targetUNCs,temp,name_len);
+ }
+ /* BB update target_uncs pointers */
+ referrals++;
+ }
+ temp = *targetUNCs;
+ temp[name_len] = 0;
+ }
+
+ }
+ if (pSMB)
+ cifs_buf_release(pSMB);
+
+ if (rc == -EAGAIN)
+ goto getDFSRetry;
+
+ return rc;
+}
+
+int
+CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
+ struct statfs *FSData, const struct nls_table *nls_codepage)
+{
+/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
+ TRANSACTION2_QFSI_REQ *pSMB = NULL;
+ TRANSACTION2_QFSI_RSP *pSMBr = NULL;
+ FILE_SYSTEM_INFO *response_data;
+ int rc = 0;
+ int bytes_returned = 0;
+
+ cFYI(1, ("In QFSInfo"));
+QFSInfoRetry:
+ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ pSMB->TotalParameterCount = 2; /* level */
+ pSMB->TotalDataCount = 0;
+ pSMB->MaxParameterCount = cpu_to_le16(2);
+ pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
+ pSMB->MaxSetupCount = 0;
+ pSMB->Reserved = 0;
+ pSMB->Flags = 0;
+ pSMB->Timeout = 0;
+ pSMB->Reserved2 = 0;
+ pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
+ pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
+ pSMB->ParameterCount = pSMB->TotalParameterCount;
+ pSMB->ParameterOffset = cpu_to_le16(offsetof(
+ struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+ pSMB->DataCount = 0;
+ pSMB->DataOffset = 0;
+ pSMB->SetupCount = 1;
+ pSMB->Reserved3 = 0;
+ pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
+ pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
+ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc) {
+ cERROR(1, ("Send error in QFSInfo = %d", rc));
+ } else { /* decode response */
+ pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
+ cFYI(1,
+ ("Decoding qfsinfo response. BCC: %d Offset %d",
+ pSMBr->ByteCount, pSMBr->DataOffset));
+ if ((pSMBr->ByteCount < 24) || (pSMBr->DataOffset > 512)) /* BB also check enough total bytes returned */
+ rc = -EIO; /* bad smb */
+ else {
+ response_data =
+ (FILE_SYSTEM_INFO
+ *) (((char *) &pSMBr->hdr.Protocol) +
+ pSMBr->DataOffset);
+ FSData->f_bsize =
+ le32_to_cpu(response_data->BytesPerSector) *
+ le32_to_cpu(response_data->
+ SectorsPerAllocationUnit);
+ FSData->f_blocks =
+ le64_to_cpu(response_data->TotalAllocationUnits);
+ FSData->f_bfree = FSData->f_bavail =
+ le64_to_cpu(response_data->FreeAllocationUnits);
+ cFYI(1,
+ ("Blocks: %lld Free: %lld Block size %ld",
+ (unsigned long long)FSData->f_blocks,
+ (unsigned long long)FSData->f_bfree,
+ FSData->f_bsize));
+ }
+ }
+ if (pSMB)
+ cifs_buf_release(pSMB);
+
+ if (rc == -EAGAIN)
+ goto QFSInfoRetry;
+
+ return rc;
+}
+
+int
+CIFSSMBQFSAttributeInfo(int xid, struct cifsTconInfo *tcon,
+ const struct nls_table *nls_codepage)
+{
+/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
+ TRANSACTION2_QFSI_REQ *pSMB = NULL;
+ TRANSACTION2_QFSI_RSP *pSMBr = NULL;
+ FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
+ int rc = 0;
+ int bytes_returned = 0;
+
+ cFYI(1, ("In QFSAttributeInfo"));
+QFSAttributeRetry:
+ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ pSMB->TotalParameterCount = 2; /* level */
+ pSMB->TotalDataCount = 0;
+ pSMB->MaxParameterCount = cpu_to_le16(2);
+ pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
+ pSMB->MaxSetupCount = 0;
+ pSMB->Reserved = 0;
+ pSMB->Flags = 0;
+ pSMB->Timeout = 0;
+ pSMB->Reserved2 = 0;
+ pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
+ pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
+ pSMB->ParameterCount = pSMB->TotalParameterCount;
+ pSMB->ParameterOffset = cpu_to_le16(offsetof(
+ struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+ pSMB->DataCount = 0;
+ pSMB->DataOffset = 0;
+ pSMB->SetupCount = 1;
+ pSMB->Reserved3 = 0;
+ pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
+ pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
+ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc) {
+ cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
+ } else { /* decode response */
+ pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
+ if ((pSMBr->ByteCount < 13) || (pSMBr->DataOffset > 512)) { /* BB also check enough bytes returned */
+ rc = -EIO; /* bad smb */
+ } else {
+ response_data =
+ (FILE_SYSTEM_ATTRIBUTE_INFO
+ *) (((char *) &pSMBr->hdr.Protocol) +
+ pSMBr->DataOffset);
+ response_data->Attributes = le32_to_cpu(response_data->Attributes);
+ response_data->MaxPathNameComponentLength =
+ le32_to_cpu(response_data->MaxPathNameComponentLength);
+ response_data->FileSystemNameLen =
+ le32_to_cpu(response_data->FileSystemNameLen);
+ memcpy(&tcon->fsAttrInfo, response_data,
+ sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
+ }
+ }
+ if (pSMB)
+ cifs_buf_release(pSMB);
+
+ if (rc == -EAGAIN)
+ goto QFSAttributeRetry;
+
+ return rc;
+}
+
+int
+CIFSSMBQFSDeviceInfo(int xid, struct cifsTconInfo *tcon,
+ const struct nls_table *nls_codepage)
+{
+/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
+ TRANSACTION2_QFSI_REQ *pSMB = NULL;
+ TRANSACTION2_QFSI_RSP *pSMBr = NULL;
+ FILE_SYSTEM_DEVICE_INFO *response_data;
+ int rc = 0;
+ int bytes_returned = 0;
+
+ cFYI(1, ("In QFSDeviceInfo"));
+QFSDeviceRetry:
+ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ pSMB->TotalParameterCount = 2; /* level */
+ pSMB->TotalDataCount = 0;
+ pSMB->MaxParameterCount = cpu_to_le16(2);
+ pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
+ pSMB->MaxSetupCount = 0;
+ pSMB->Reserved = 0;
+ pSMB->Flags = 0;
+ pSMB->Timeout = 0;
+ pSMB->Reserved2 = 0;
+ pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
+ pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
+ pSMB->ParameterCount = pSMB->TotalParameterCount;
+ pSMB->ParameterOffset = cpu_to_le16(offsetof(
+ struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+
+ pSMB->DataCount = 0;
+ pSMB->DataOffset = 0;
+ pSMB->SetupCount = 1;
+ pSMB->Reserved3 = 0;
+ pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
+ pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
+ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc) {
+ cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
+ } else { /* decode response */
+ pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
+ if ((pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO))
+ || (pSMBr->DataOffset > 512))
+ rc = -EIO; /* bad smb */
+ else {
+ response_data =
+ (FILE_SYSTEM_DEVICE_INFO
+ *) (((char *) &pSMBr->hdr.Protocol) +
+ pSMBr->DataOffset);
+ response_data->DeviceType =
+ le32_to_cpu(response_data->DeviceType);
+ response_data->DeviceCharacteristics =
+ le32_to_cpu(response_data->DeviceCharacteristics);
+ memcpy(&tcon->fsDevInfo, response_data,
+ sizeof (FILE_SYSTEM_DEVICE_INFO));
+ }
+ }
+ if (pSMB)
+ cifs_buf_release(pSMB);
+
+ if (rc == -EAGAIN)
+ goto QFSDeviceRetry;
+
+ return rc;
+}
+
+int
+CIFSSMBQFSUnixInfo(int xid, struct cifsTconInfo *tcon,
+ const struct nls_table *nls_codepage)
+{
+/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
+ TRANSACTION2_QFSI_REQ *pSMB = NULL;
+ TRANSACTION2_QFSI_RSP *pSMBr = NULL;
+ FILE_SYSTEM_UNIX_INFO *response_data;
+ int rc = 0;
+ int bytes_returned = 0;
+
+ cFYI(1, ("In QFSUnixInfo"));
+QFSUnixRetry:
+ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ pSMB->ParameterCount = 2; /* level */
+ pSMB->TotalDataCount = 0;
+ pSMB->DataCount = 0;
+ pSMB->DataOffset = 0;
+ pSMB->MaxParameterCount = cpu_to_le16(2);
+ pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
+ pSMB->MaxSetupCount = 0;
+ pSMB->Reserved = 0;
+ pSMB->Flags = 0;
+ pSMB->Timeout = 0;
+ pSMB->Reserved2 = 0;
+ pSMB->ByteCount = pSMB->ParameterCount + 1 /* pad */ ;
+ pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
+ pSMB->TotalParameterCount = pSMB->ParameterCount;
+ pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
+ smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+ pSMB->SetupCount = 1;
+ pSMB->Reserved3 = 0;
+ pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
+ pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
+ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc) {
+ cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
+ } else { /* decode response */
+ pSMBr->DataOffset = cpu_to_le16(pSMBr->DataOffset);
+ if ((pSMBr->ByteCount < 13) || (pSMBr->DataOffset > 512)) {
+ rc = -EIO; /* bad smb */
+ } else {
+ response_data =
+ (FILE_SYSTEM_UNIX_INFO
+ *) (((char *) &pSMBr->hdr.Protocol) +
+ pSMBr->DataOffset);
+ response_data->MajorVersionNumber =
+ le16_to_cpu(response_data->MajorVersionNumber);
+ response_data->MinorVersionNumber =
+ le16_to_cpu(response_data->MinorVersionNumber);
+ response_data->Capability =
+ le64_to_cpu(response_data->Capability);
+ memcpy(&tcon->fsUnixInfo, response_data,
+ sizeof (FILE_SYSTEM_UNIX_INFO));
+ }
+ }
+ if (pSMB)
+ cifs_buf_release(pSMB);
+
+ if (rc == -EAGAIN)
+ goto QFSUnixRetry;
+
+
+ return rc;
+}
+
+/* We can not use write of zero bytes trick to
+ set file size due to need for large file support. Also note that
+ this SetPathInfo is preferred to SetFileInfo based method in next
+ routine which is only needed to work around a sharing violation bug
+ in Samba which this routine can run into */
+
+int
+CIFSSMBSetEOF(int xid, struct cifsTconInfo *tcon, char *fileName,
+ __u64 size, int SetAllocation, const struct nls_table *nls_codepage)
+{
+ struct smb_com_transaction2_spi_req *pSMB = NULL;
+ struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
+ struct file_end_of_file_info *parm_data;
+ int name_len;
+ int rc = 0;
+ int bytes_returned = 0;
+
+ cFYI(1, ("In SetEOF"));
+SetEOFRetry:
+ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+ name_len =
+ cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530
+ /* find define for this maxpathcomponent */
+ , nls_codepage);
+ name_len++; /* trailing null */
+ name_len *= 2;
+ } else { /* BB improve the check for buffer overruns BB */
+ name_len = strnlen(fileName, 530);
+ name_len++; /* trailing null */
+ strncpy(pSMB->FileName, fileName, name_len);
+ }
+ pSMB->ParameterCount = 6 + name_len;
+ pSMB->DataCount = sizeof (struct file_end_of_file_info);
+ pSMB->MaxParameterCount = cpu_to_le16(2);
+ pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
+ pSMB->MaxSetupCount = 0;
+ pSMB->Reserved = 0;
+ pSMB->Flags = 0;
+ pSMB->Timeout = 0;
+ pSMB->Reserved2 = 0;
+ pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req,
+ InformationLevel) - 4;
+ pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
+ if(SetAllocation) {
+ if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
+ pSMB->InformationLevel =
+ cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
+ else
+ pSMB->InformationLevel =
+ cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
+ } else /* Set File Size */ {
+ if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
+ pSMB->InformationLevel =
+ cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
+ else
+ pSMB->InformationLevel =
+ cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
+ }
+
+ parm_data =
+ (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
+ pSMB->DataOffset);
+ pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
+ pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
+ pSMB->SetupCount = 1;
+ pSMB->Reserved3 = 0;
+ pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
+ pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount;
+ pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
+ pSMB->TotalDataCount = pSMB->DataCount;
+ pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
+ pSMB->TotalParameterCount = pSMB->ParameterCount;
+ pSMB->Reserved4 = 0;
+ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+ parm_data->FileSize = cpu_to_le64(size);
+ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc) {
+ cFYI(1, ("SetPathInfo (file size) returned %d", rc));
+ }
+
+ if (pSMB)
+ cifs_buf_release(pSMB);
+
+ if (rc == -EAGAIN)
+ goto SetEOFRetry;
+
+ return rc;
+}
+
+int
+CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
+ __u16 fid, __u32 pid_of_opener, int SetAllocation)
+{
+ struct smb_com_transaction2_sfi_req *pSMB = NULL;
+ struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
+ char *data_offset;
+ struct file_end_of_file_info *parm_data;
+ int rc = 0;
+ int bytes_returned = 0;
+ __u32 tmp;
+
+ cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
+ (long long)size));
+ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ tmp = cpu_to_le32(pid_of_opener); /* override pid of current process
+ so network fid will be valid */
+ pSMB->hdr.Pid = tmp & 0xFFFF;
+ tmp >>= 16;
+ pSMB->hdr.PidHigh = tmp & 0xFFFF;
+
+ pSMB->ParameterCount = 6;
+ pSMB->MaxSetupCount = 0;
+ pSMB->Reserved = 0;
+ pSMB->Flags = 0;
+ pSMB->Timeout = 0;
+ pSMB->Reserved2 = 0;
+ pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_sfi_req,
+ Fid) - 4;
+ pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
+
+ data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset;
+
+ pSMB->DataCount = sizeof(struct file_end_of_file_info);
+ pSMB->MaxParameterCount = cpu_to_le16(2);
+ pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
+ pSMB->SetupCount = 1;
+ pSMB->Reserved3 = 0;
+ pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
+ pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount;
+ pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
+ pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
+ pSMB->TotalDataCount = pSMB->DataCount;
+ pSMB->TotalParameterCount = pSMB->ParameterCount;
+ pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
+ parm_data =
+ (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
+ pSMB->DataOffset);
+ pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); /* now safe to change to le */
+ parm_data->FileSize = cpu_to_le64(size);
+ pSMB->Fid = fid;
+ if(SetAllocation) {
+ if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
+ pSMB->InformationLevel =
+ cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
+ else
+ pSMB->InformationLevel =
+ cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
+ } else /* Set File Size */ {
+ if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
+ pSMB->InformationLevel =
+ cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
+ else
+ pSMB->InformationLevel =
+ cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
+ }
+ pSMB->Reserved4 = 0;
+ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc) {
+ cFYI(1,
+ ("Send error in SetFileInfo (SetFileSize) = %d",
+ rc));
+ }
+
+ if (pSMB)
+ cifs_buf_release(pSMB);
+
+ /* Note: On -EAGAIN error only caller can retry on handle based calls
+ since file handle passed in no longer valid */
+
+ return rc;
+}
+
+int
+CIFSSMBSetTimes(int xid, struct cifsTconInfo *tcon, char *fileName,
+ FILE_BASIC_INFO * data, const struct nls_table *nls_codepage)
+{
+ TRANSACTION2_SPI_REQ *pSMB = NULL;
+ TRANSACTION2_SPI_RSP *pSMBr = NULL;
+ int name_len;
+ int rc = 0;
+ int bytes_returned = 0;
+ char *data_offset;
+
+ cFYI(1, ("In SetTimes"));
+
+SetTimesRetry:
+ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+ name_len =
+ cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530
+ /* find define for this maxpathcomponent */
+ , nls_codepage);
+ name_len++; /* trailing null */
+ name_len *= 2;
+ } else { /* BB improve the check for buffer overruns BB */
+ name_len = strnlen(fileName, 530);
+ name_len++; /* trailing null */
+ strncpy(pSMB->FileName, fileName, name_len);
+ }
+
+ pSMB->ParameterCount = 6 + name_len;
+ pSMB->DataCount = sizeof (FILE_BASIC_INFO);
+ pSMB->MaxParameterCount = cpu_to_le16(2);
+ pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
+ pSMB->MaxSetupCount = 0;
+ pSMB->Reserved = 0;
+ pSMB->Flags = 0;
+ pSMB->Timeout = 0;
+ pSMB->Reserved2 = 0;
+ pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req,
+ InformationLevel) - 4;
+ pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
+ data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset;
+ pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
+ pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
+ pSMB->SetupCount = 1;
+ pSMB->Reserved3 = 0;
+ pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
+ pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount;
+
+ pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
+ pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
+ pSMB->TotalDataCount = pSMB->DataCount;
+ pSMB->TotalParameterCount = pSMB->ParameterCount;
+ if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
+ pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
+ else
+ pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
+ pSMB->Reserved4 = 0;
+ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+ memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
+ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc) {
+ cFYI(1, ("SetPathInfo (times) returned %d", rc));
+ }
+
+ if (pSMB)
+ cifs_buf_release(pSMB);
+
+ if (rc == -EAGAIN)
+ goto SetTimesRetry;
+
+ return rc;
+}
+
+int
+CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
+ char *fileName, __u64 mode, __u64 uid, __u64 gid,
+ dev_t device, const struct nls_table *nls_codepage)
+{
+ TRANSACTION2_SPI_REQ *pSMB = NULL;
+ TRANSACTION2_SPI_RSP *pSMBr = NULL;
+ int name_len;
+ int rc = 0;
+ int bytes_returned = 0;
+ FILE_UNIX_BASIC_INFO *data_offset;
+
+ cFYI(1, ("In SetUID/GID/Mode"));
+setPermsRetry:
+ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+ name_len =
+ cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530
+ /* find define for this maxpathcomponent */
+ , nls_codepage);
+ name_len++; /* trailing null */
+ name_len *= 2;
+ } else { /* BB improve the check for buffer overruns BB */
+ name_len = strnlen(fileName, 530);
+ name_len++; /* trailing null */
+ strncpy(pSMB->FileName, fileName, name_len);
+ }
+
+ pSMB->ParameterCount = 6 + name_len;
+ pSMB->DataCount = sizeof (FILE_UNIX_BASIC_INFO);
+ pSMB->MaxParameterCount = cpu_to_le16(2);
+ pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
+ pSMB->MaxSetupCount = 0;
+ pSMB->Reserved = 0;
+ pSMB->Flags = 0;
+ pSMB->Timeout = 0;
+ pSMB->Reserved2 = 0;
+ pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req,
+ InformationLevel) - 4;
+ pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
+ data_offset =
+ (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
+ pSMB->DataOffset);
+ pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
+ pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
+ pSMB->SetupCount = 1;
+ pSMB->Reserved3 = 0;
+ pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
+ pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount;
+ pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
+ pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
+ pSMB->TotalParameterCount = pSMB->ParameterCount;
+ pSMB->TotalDataCount = pSMB->DataCount;
+ pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
+ pSMB->Reserved4 = 0;
+ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+ data_offset->Uid = cpu_to_le64(uid);
+ data_offset->Gid = cpu_to_le64(gid);
+ /* better to leave device as zero when it is */
+ data_offset->DevMajor = cpu_to_le64(MAJOR(device));
+ data_offset->DevMinor = cpu_to_le64(MINOR(device));
+ data_offset->Permissions = cpu_to_le64(mode);
+
+ if(S_ISREG(mode))
+ data_offset->Type = cpu_to_le32(UNIX_FILE);
+ else if(S_ISDIR(mode))
+ data_offset->Type = cpu_to_le32(UNIX_DIR);
+ else if(S_ISLNK(mode))
+ data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
+ else if(S_ISCHR(mode))
+ data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
+ else if(S_ISBLK(mode))
+ data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
+ else if(S_ISFIFO(mode))
+ data_offset->Type = cpu_to_le32(UNIX_FIFO);
+ else if(S_ISSOCK(mode))
+ data_offset->Type = cpu_to_le32(UNIX_SOCKET);
+
+
+ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc) {
+ cFYI(1, ("SetPathInfo (perms) returned %d", rc));
+ }
+
+ if (pSMB)
+ cifs_buf_release(pSMB);
+ if (rc == -EAGAIN)
+ goto setPermsRetry;
+ return rc;
+}
+
+int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
+ const int notify_subdirs, const __u16 netfid,
+ __u32 filter, const struct nls_table *nls_codepage)
+{
+ int rc = 0;
+ struct smb_com_transaction_change_notify_req * pSMB = NULL;
+ struct smb_com_transaction_change_notify_rsp * pSMBr = NULL;
+ int bytes_returned;
+
+ cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
+ rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ pSMB->TotalParameterCount = 0 ;
+ pSMB->TotalDataCount = 0;
+ pSMB->MaxParameterCount = cpu_to_le32(2);
+ /* BB find exact data count max from sess structure BB */
+ pSMB->MaxDataCount = 0; /* same in little endian or be */
+ pSMB->MaxSetupCount = 4;
+ pSMB->Reserved = 0;
+ pSMB->ParameterOffset = 0;
+ pSMB->DataCount = 0;
+ pSMB->DataOffset = 0;
+ pSMB->SetupCount = 4; /* single byte does not need le conversion */
+ pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
+ pSMB->ParameterCount = pSMB->TotalParameterCount;
+ if(notify_subdirs)
+ pSMB->WatchTree = 1; /* one byte - no le conversion needed */
+ pSMB->Reserved2 = 0;
+ pSMB->CompletionFilter = cpu_to_le32(filter);
+ pSMB->Fid = netfid; /* file handle always le */
+ pSMB->ByteCount = 0;
+
+ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc) {
+ cFYI(1, ("Error in Notify = %d", rc));
+ }
+ if (pSMB)
+ cifs_buf_release(pSMB);
+/* if (rc == -EAGAIN)
+ goto NotifyRetry; */
+ return rc;
+}
+#ifdef CONFIG_CIFS_XATTR
+int
+CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
+ const unsigned char *searchName,
+ char * EAData, size_t size,
+ const struct nls_table *nls_codepage)
+{
+ /* BB assumes one setup word */
+ TRANSACTION2_QPI_REQ *pSMB = NULL;
+ TRANSACTION2_QPI_RSP *pSMBr = NULL;
+ int rc = 0;
+ int bytes_returned;
+ int name_len;
+
+ cFYI(1, ("In Query All EAs path %s", searchName));
+QAllEAsRetry:
+ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+ name_len =
+ cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530
+ /* find define for this maxpathcomponent */
+ , nls_codepage);
+ name_len++; /* trailing null */
+ name_len *= 2;
+ } else { /* BB improve the check for buffer overruns BB */
+ name_len = strnlen(searchName, 530);
+ name_len++; /* trailing null */
+ strncpy(pSMB->FileName, searchName, name_len);
+ }
+
+ pSMB->TotalParameterCount = 2 /* level */ + 4 /* reserved */ +
+ name_len /* includes null */ ;
+ pSMB->TotalDataCount = 0;
+ pSMB->MaxParameterCount = cpu_to_le16(2);
+ pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
+ pSMB->MaxSetupCount = 0;
+ pSMB->Reserved = 0;
+ pSMB->Flags = 0;
+ pSMB->Timeout = 0;
+ pSMB->Reserved2 = 0;
+ pSMB->ParameterOffset = cpu_to_le16(offsetof(
+ struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+ pSMB->DataCount = 0;
+ pSMB->DataOffset = 0;
+ pSMB->SetupCount = 1;
+ pSMB->Reserved3 = 0;
+ pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
+ pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
+ pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
+ pSMB->ParameterCount = pSMB->TotalParameterCount;
+ pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
+ pSMB->Reserved4 = 0;
+ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc) {
+ cFYI(1, ("Send error in QueryAllEAs = %d", rc));
+ } else { /* decode response */
+ pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
+ /* BB also check enough total bytes returned */
+ /* BB we need to improve the validity checking
+ of these trans2 responses */
+ if ((pSMBr->ByteCount < 4) || (pSMBr->DataOffset > 512))
+ rc = -EIO; /* bad smb */
+ /* else if (pFindData){
+ memcpy((char *) pFindData,
+ (char *) &pSMBr->hdr.Protocol +
+ pSMBr->DataOffset, kl);
+ }*/ else {
+ /* check that length of list is not more than bcc */
+ /* check that each entry does not go beyond length
+ of list */
+ /* check that each element of each entry does not
+ go beyond end of list */
+ struct fealist * ea_response_data;
+ rc = 0;
+ /* validate_trans2_offsets() */
+ /* BB to check if(start of smb + pSMBr->DataOffset > &bcc+ bcc)*/
+ ea_response_data = (struct fealist *)
+ (((char *) &pSMBr->hdr.Protocol) +
+ pSMBr->DataOffset);
+ cFYI(1,("ea length %d",ea_response_data->list_len));
+ }
+ }
+ if (pSMB)
+ cifs_buf_release(pSMB);
+ if (rc == -EAGAIN)
+ goto QAllEAsRetry;
+
+ return rc;
+}
+#endif
diff --git a/release/src/linux/linux/fs/cifs/connect.c b/release/src/linux/linux/fs/cifs/connect.c
new file mode 100644
index 00000000..76e4a04f
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/connect.c
@@ -0,0 +1,2925 @@
+/*
+ * fs/cifs/connect.c
+ *
+ * Copyright (C) International Business Machines Corp., 2002,2004
+ * Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/fs.h>
+#include <linux/net.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/wait.h>
+#include <linux/version.h>
+#include <linux/ipv6.h>
+#include <linux/pagemap.h>
+#include <linux/ctype.h>
+#include <linux/utsname.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_unicode.h"
+#include "cifs_debug.h"
+#include "cifs_fs_sb.h"
+#include "ntlmssp.h"
+#include "nterr.h"
+#include "rfc1002pdu.h"
+
+#define CIFS_PORT 445
+#define RFC1001_PORT 139
+
+extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
+ unsigned char *p24);
+extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
+ unsigned char *p24);
+extern int cifs_inet_pton(int, const char *, void *dst);
+
+struct smb_vol {
+ char *username;
+ char *password;
+ char *domainname;
+ char *UNC;
+ char *UNCip;
+ char *iocharset; /* local code page for mapping to and from Unicode */
+ char source_rfc1001_name[16]; /* netbios name of client */
+ uid_t linux_uid;
+ gid_t linux_gid;
+ mode_t file_mode;
+ mode_t dir_mode;
+ int rw:1;
+ int retry:1;
+ int intr:1;
+ unsigned int rsize;
+ unsigned int wsize;
+ unsigned int sockopt;
+ unsigned short int port;
+};
+
+static int ipv4_connect(struct sockaddr_in *psin_server,
+ struct socket **csocket,
+ char * netb_name);
+static int ipv6_connect(struct sockaddr_in6 *psin_server,
+ struct socket **csocket);
+
+
+ /*
+ * cifs tcp session reconnection
+ *
+ * mark tcp session as reconnecting so temporarily locked
+ * mark all smb sessions as reconnecting for tcp session
+ * reconnect tcp session
+ * wake up waiters on reconnection? - (not needed currently)
+ */
+
+int
+cifs_reconnect(struct TCP_Server_Info *server)
+{
+ int rc = 0;
+ struct list_head *tmp;
+ struct cifsSesInfo *ses;
+ struct cifsTconInfo *tcon;
+ struct mid_q_entry * mid_entry;
+
+ spin_lock(&GlobalMid_Lock);
+ if(server->tcpStatus == CifsExiting) {
+ /* the demux thread will exit normally
+ next time through the loop */
+ spin_unlock(&GlobalMid_Lock);
+ return rc;
+ } else
+ server->tcpStatus = CifsNeedReconnect;
+ spin_unlock(&GlobalMid_Lock);
+ server->maxBuf = 0;
+
+ cFYI(1, ("Reconnecting tcp session "));
+
+ /* before reconnecting the tcp session, mark the smb session (uid)
+ and the tid bad so they are not used until reconnected */
+ read_lock(&GlobalSMBSeslock);
+ list_for_each(tmp, &GlobalSMBSessionList) {
+ ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
+ if (ses->server) {
+ if (ses->server == server) {
+ ses->status = CifsNeedReconnect;
+ ses->ipc_tid = 0;
+ }
+ }
+ /* else tcp and smb sessions need reconnection */
+ }
+ list_for_each(tmp, &GlobalTreeConnectionList) {
+ tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
+ if((tcon) && (tcon->ses) && (tcon->ses->server == server)) {
+ tcon->tidStatus = CifsNeedReconnect;
+ }
+ }
+ read_unlock(&GlobalSMBSeslock);
+ /* do not want to be sending data on a socket we are freeing */
+ down(&server->tcpSem);
+ if(server->ssocket) {
+ cFYI(1,("State: 0x%x Flags: 0x%lx", server->ssocket->state,
+ server->ssocket->flags));
+ server->ssocket->ops->shutdown(server->ssocket,SEND_SHUTDOWN);
+ cFYI(1,("Post shutdown state: 0x%x Flags: 0x%lx", server->ssocket->state,
+ server->ssocket->flags));
+ sock_release(server->ssocket);
+ server->ssocket = NULL;
+ }
+
+ spin_lock(&GlobalMid_Lock);
+ list_for_each(tmp, &server->pending_mid_q) {
+ mid_entry = list_entry(tmp, struct
+ mid_q_entry,
+ qhead);
+ if(mid_entry) {
+ if(mid_entry->midState == MID_REQUEST_SUBMITTED) {
+ /* Mark other intransit requests as needing retry so
+ we do not immediately mark the session bad again
+ (ie after we reconnect below) as they timeout too */
+ mid_entry->midState = MID_RETRY_NEEDED;
+ }
+ }
+ }
+ spin_unlock(&GlobalMid_Lock);
+ up(&server->tcpSem);
+
+ while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood))
+ {
+ if(server->protocolType == IPV6) {
+ rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket);
+ } else {
+ rc = ipv4_connect(&server->addr.sockAddr,
+ &server->ssocket,
+ server->workstation_RFC1001_name);
+ }
+ if(rc) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(3 * HZ);
+ } else {
+ atomic_inc(&tcpSesReconnectCount);
+ spin_lock(&GlobalMid_Lock);
+ if(server->tcpStatus != CifsExiting)
+ server->tcpStatus = CifsGood;
+ spin_unlock(&GlobalMid_Lock);
+ /* atomic_set(&server->inFlight,0);*/
+ wake_up(&server->response_q);
+ }
+ }
+ return rc;
+}
+
+static int
+cifs_demultiplex_thread(struct TCP_Server_Info *server)
+{
+ int length;
+ unsigned int pdu_length, total_read;
+ struct smb_hdr *smb_buffer = NULL;
+ struct msghdr smb_msg;
+ mm_segment_t temp_fs;
+ struct iovec iov;
+ struct socket *csocket = server->ssocket;
+ struct list_head *tmp;
+ struct cifsSesInfo *ses;
+ struct task_struct *task_to_wake = NULL;
+ struct mid_q_entry *mid_entry;
+ char *temp;
+
+ daemonize();
+ sprintf(current->comm,"cifsd");
+ /* allow_signal(SIGKILL);*/
+ current->flags |= PF_MEMALLOC;
+ server->tsk = current; /* save process info to wake at shutdown */
+ cFYI(1, ("Demultiplex PID: %d", current->pid));
+
+ temp_fs = get_fs(); /* we must turn off socket api parm checking */
+ set_fs(get_ds());
+
+ while (server->tcpStatus != CifsExiting) {
+ if (smb_buffer == NULL)
+ smb_buffer = cifs_buf_get();
+ else
+ memset(smb_buffer, 0, sizeof (struct smb_hdr));
+
+ if (smb_buffer == NULL) {
+ cERROR(1,("Can not get memory for SMB response"));
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(HZ * 3); /* give system time to free memory */
+ continue;
+ }
+ iov.iov_base = smb_buffer;
+ iov.iov_len = sizeof (struct smb_hdr) - 1;
+ /* 1 byte less above since wct is not always returned in error cases */
+ smb_msg.msg_iov = &iov;
+ smb_msg.msg_iovlen = 1;
+ smb_msg.msg_control = NULL;
+ smb_msg.msg_controllen = 0;
+
+ length =
+ sock_recvmsg(csocket, &smb_msg,
+ sizeof (struct smb_hdr) -
+ 1 /* RFC1001 header and SMB header */ ,
+ MSG_PEEK /* flags see socket.h */ );
+
+ if(server->tcpStatus == CifsExiting) {
+ break;
+ } else if (server->tcpStatus == CifsNeedReconnect) {
+ cFYI(1,("Reconnecting after server stopped responding"));
+ cifs_reconnect(server);
+ cFYI(1,("call to reconnect done"));
+ csocket = server->ssocket;
+ continue;
+ } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(1); /* minimum sleep to prevent looping
+ allowing socket to clear and app threads to set
+ tcpStatus CifsNeedReconnect if server hung */
+ continue;
+ } else if (length <= 0) {
+ if(server->tcpStatus == CifsNew) {
+ cFYI(1,("tcp session abended prematurely (after SMBnegprot)"));
+ /* some servers kill tcp session rather than returning
+ smb negprot error in which case reconnecting here is
+ not going to help - return error to mount */
+ break;
+ }
+ if(length == -EINTR) {
+ cFYI(1,("cifsd thread killed"));
+ break;
+ }
+ cFYI(1,("Reconnecting after unexpected peek error %d",length));
+ cifs_reconnect(server);
+ csocket = server->ssocket;
+ wake_up(&server->response_q);
+ continue;
+ }
+
+ pdu_length = 4 + ntohl(smb_buffer->smb_buf_length);
+ /* Ony read pdu_length after below checks for too short (due
+ to e.g. int overflow) and too long ie beyond end of buf */
+ cFYI(1, ("Peek length rcvd: 0x%x beginning 0x%x)", length, pdu_length));
+
+ temp = (char *) smb_buffer;
+ if (length > 3) {
+ if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) {
+ iov.iov_base = smb_buffer;
+ iov.iov_len = 4;
+ length = sock_recvmsg(csocket, &smb_msg, 4, 0);
+ cFYI(0,("Received 4 byte keep alive packet"));
+ } else if (temp[0] == (char) RFC1002_POSITIVE_SESSION_RESPONSE) {
+ iov.iov_base = smb_buffer;
+ iov.iov_len = 4;
+ length = sock_recvmsg(csocket, &smb_msg, 4, 0);
+ cFYI(1,("Good RFC 1002 session rsp"));
+ } else if ((temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE)
+ && (length == 5)) {
+ /* we get this from Windows 98 instead of error on SMB negprot response */
+ cFYI(1,("Negative RFC 1002 Session Response Error 0x%x)",temp[4]));
+ if(server->tcpStatus == CifsNew) {
+ /* if nack on negprot (rather than
+ ret of smb negprot error) reconnecting
+ not going to help, ret error to mount */
+ break;
+ } else {
+ /* give server a second to
+ clean up before reconnect attempt */
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(HZ);
+ /* always try 445 first on reconnect
+ since we get NACK on some if we ever
+ connected to port 139 (the NACK is
+ since we do not begin with RFC1001
+ session initialize frame) */
+ server->addr.sockAddr.sin_port = CIFS_PORT;
+ cifs_reconnect(server);
+ csocket = server->ssocket;
+ wake_up(&server->response_q);
+ continue;
+ }
+ } else if (temp[0] != (char) 0) {
+ cERROR(1,("Unknown RFC 1002 frame"));
+ cifs_dump_mem(" Received Data: ", temp, length);
+ cifs_reconnect(server);
+ csocket = server->ssocket;
+ continue;
+ } else {
+ if ((length != sizeof (struct smb_hdr) - 1)
+ || (pdu_length >
+ CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE)
+ || (pdu_length <
+ sizeof (struct smb_hdr) - 1)
+ ||
+ (checkSMBhdr
+ (smb_buffer, smb_buffer->Mid))) {
+ cERROR(1,
+ ("Invalid size or format for SMB found with length %d and pdu_lenght %d",
+ length, pdu_length));
+ cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
+ /* could we fix this network corruption by finding next
+ smb header (instead of killing the session) and
+ restart reading from next valid SMB found? */
+ cifs_reconnect(server);
+ csocket = server->ssocket;
+ continue;
+ } else { /* length ok */
+
+ length = 0;
+ iov.iov_base = smb_buffer;
+ iov.iov_len = pdu_length;
+ for (total_read = 0;
+ total_read < pdu_length;
+ total_read += length) {
+ length = sock_recvmsg(csocket, &smb_msg,
+ pdu_length - total_read, 0);
+ if (length == 0) {
+ cERROR(1,
+ ("Zero length receive when expecting %d ",
+ pdu_length - total_read));
+ cifs_reconnect(server);
+ csocket = server->ssocket;
+ continue;
+ }
+ }
+ }
+
+ dump_smb(smb_buffer, length);
+ if (checkSMB
+ (smb_buffer, smb_buffer->Mid, total_read)) {
+ cERROR(1, ("Bad SMB Received "));
+ continue;
+ }
+
+ task_to_wake = NULL;
+ spin_lock(&GlobalMid_Lock);
+ list_for_each(tmp, &server->pending_mid_q) {
+ mid_entry = list_entry(tmp, struct
+ mid_q_entry,
+ qhead);
+
+ if ((mid_entry->mid == smb_buffer->Mid) && (mid_entry->midState == MID_REQUEST_SUBMITTED)) {
+ cFYI(1,
+ (" Mid 0x%x matched - waking up ",mid_entry->mid));
+ task_to_wake = mid_entry->tsk;
+ mid_entry->resp_buf =
+ smb_buffer;
+ mid_entry->midState =
+ MID_RESPONSE_RECEIVED;
+ }
+ }
+ spin_unlock(&GlobalMid_Lock);
+ if (task_to_wake) {
+ smb_buffer = NULL; /* will be freed by users thread after he is done */
+ wake_up_process(task_to_wake);
+ } else if (is_valid_oplock_break(smb_buffer) == FALSE) {
+ cERROR(1, ("No task to wake, unknown frame rcvd!"));
+ cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
+ }
+ }
+ } else {
+ cFYI(0,
+ ("Frame less than four bytes received %d bytes long.",
+ length));
+ if (length > 0) {
+ length = sock_recvmsg(csocket, &smb_msg, length, 0); /* throw away junk frame */
+ cFYI(1,
+ (" with junk 0x%x in it ",
+ *(__u32 *) smb_buffer));
+ }
+ }
+ }
+ spin_lock(&GlobalMid_Lock);
+ server->tcpStatus = CifsExiting;
+ server->tsk = NULL;
+ atomic_set(&server->inFlight, 0);
+ spin_unlock(&GlobalMid_Lock);
+ /* Although there should not be any requests blocked on
+ this queue it can not hurt to be paranoid and try to wake up requests
+ that may haven been blocked when more than 50 at time were on the wire
+ to the same server - they now will see the session is in exit state
+ and get out of SendReceive. */
+ wake_up_all(&server->request_q);
+ /* give those requests time to exit */
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(HZ/8);
+
+ if(server->ssocket) {
+ sock_release(csocket);
+ server->ssocket = NULL;
+ }
+ set_fs(temp_fs);
+ if (smb_buffer) /* buffer usually freed in free_mid - need to free it on error or exit */
+ cifs_buf_release(smb_buffer);
+
+ read_lock(&GlobalSMBSeslock);
+ if (list_empty(&server->pending_mid_q)) {
+ /* loop through server session structures attached to this and mark them dead */
+ list_for_each(tmp, &GlobalSMBSessionList) {
+ ses =
+ list_entry(tmp, struct cifsSesInfo,
+ cifsSessionList);
+ if (ses->server == server) {
+ ses->status = CifsExiting;
+ ses->server = NULL;
+ }
+ }
+ read_unlock(&GlobalSMBSeslock);
+ } else {
+ spin_lock(&GlobalMid_Lock);
+ list_for_each(tmp, &server->pending_mid_q) {
+ mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
+ if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
+ cFYI(1,
+ (" Clearing Mid 0x%x - waking up ",mid_entry->mid));
+ task_to_wake = mid_entry->tsk;
+ if(task_to_wake) {
+ wake_up_process(task_to_wake);
+ }
+ }
+ }
+ spin_unlock(&GlobalMid_Lock);
+ read_unlock(&GlobalSMBSeslock);
+ set_current_state(TASK_INTERRUPTIBLE);
+ /* 1/8th of sec is more than enough time for them to exit */
+ schedule_timeout(HZ/8);
+ }
+
+ if (list_empty(&server->pending_mid_q)) {
+ /* mpx threads have not exited yet give them
+ at least the smb send timeout time for long ops */
+ cFYI(1, ("Wait for exit from demultiplex thread"));
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(46 * HZ);
+ /* if threads still have not exited they are probably never
+ coming home not much else we can do but free the memory */
+ }
+ kfree(server);
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(HZ/4);
+ return 0;
+}
+
+static void *
+cifs_kcalloc(size_t size, int type)
+{
+ void *addr;
+ addr = kmalloc(size, type);
+ if (addr)
+ memset(addr, 0, size);
+ return addr;
+}
+
+static int
+cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol)
+{
+ char *value;
+ char *data;
+ unsigned int temp_len, i, j;
+ char separator[2];
+
+ separator[0] = ',';
+ separator[1] = 0;
+
+ memset(vol->source_rfc1001_name,0x20,15);
+ for(i=0;i < strnlen(system_utsname.nodename,15);i++) {
+ /* does not have to be a perfect mapping since the field is
+ informational, only used for servers that do not support
+ port 445 and it can be overridden at mount time */
+ vol->source_rfc1001_name[i] = toupper(system_utsname.nodename[i]);
+ }
+ vol->source_rfc1001_name[15] = 0;
+
+ vol->linux_uid = current->uid; /* current->euid instead? */
+ vol->linux_gid = current->gid;
+ vol->dir_mode = S_IRWXUGO;
+ /* 2767 perms indicate mandatory locking support */
+ vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);
+
+ /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
+ vol->rw = TRUE;
+
+ if (!options)
+ return 1;
+
+ if(strncmp(options,"sep=",4) == 0) {
+ if(options[4] != 0) {
+ separator[0] = options[4];
+ options += 5;
+ } else {
+ cFYI(1,("Null separator not allowed"));
+ }
+ }
+
+ while ((data = strsep(&options, separator)) != NULL) {
+ if (!*data)
+ continue;
+ if ((value = strchr(data, '=')) != NULL)
+ *value++ = '\0';
+ if (strnicmp(data, "user", 4) == 0) {
+ if (!value || !*value) {
+ printk(KERN_WARNING
+ "CIFS: invalid or missing username\n");
+ return 1; /* needs_arg; */
+ }
+ if (strnlen(value, 200) < 200) {
+ vol->username = value;
+ } else {
+ printk(KERN_WARNING "CIFS: username too long\n");
+ return 1;
+ }
+ } else if (strnicmp(data, "pass", 4) == 0) {
+ if (!value || !*value) {
+ vol->password = NULL;
+ continue;
+ }
+ temp_len = strlen(value);
+ /* removed password length check, NTLM passwords
+ can be arbitrarily long */
+
+ /* if comma in password, the string will be
+ prematurely null terminated. Commas in password are
+ specified across the cifs mount interface by a double
+ comma ie ,, and a comma used as in other cases ie ','
+ as a parameter delimiter/separator is single and due
+ to the strsep above is temporarily zeroed. */
+
+ /* NB: password legally can have multiple commas and
+ the only illegal character in a password is null */
+
+ if ((value[temp_len] == 0) && (value[temp_len+1] == separator[0])) {
+ /* reinsert comma */
+ value[temp_len] = separator[0];
+ temp_len+=2; /* move after the second comma */
+ while(value[temp_len] != 0) {
+ if((value[temp_len] == separator[0]) && (value[temp_len+1] != separator[0])) {
+ /* single comma indicating start of next parm */
+ break;
+ }
+ temp_len++;
+ }
+ if(value[temp_len] == 0) {
+ options = NULL;
+ } else {
+ value[temp_len] = 0;
+ /* move options to point to start of next parm */
+ options = value + temp_len + 1;
+ }
+ /* go from value to (value + temp_len) condensing double commas to singles */
+ vol->password = cifs_kcalloc(temp_len, GFP_KERNEL);
+ for(i=0,j=0;i<temp_len;i++,j++) {
+ vol->password[j] = value[i];
+ if(value[i] == separator[0] && value[i+1] == separator[0]) {
+ /* skip second comma */
+ i++;
+ }
+ }
+ /* value[temp_len] is zeroed above so
+ vol->password[temp_len] guaranteed to be null */
+ } else {
+ vol->password = cifs_kcalloc(temp_len + 1, GFP_KERNEL);
+ strcpy(vol->password, value);
+ }
+ } else if (strnicmp(data, "ip", 2) == 0) {
+ if (!value || !*value) {
+ vol->UNCip = NULL;
+ } else if (strnlen(value, 35) < 35) {
+ vol->UNCip = value;
+ } else {
+ printk(KERN_WARNING "CIFS: ip address too long\n");
+ return 1;
+ }
+ } else if ((strnicmp(data, "unc", 3) == 0)
+ || (strnicmp(data, "target", 6) == 0)
+ || (strnicmp(data, "path", 4) == 0)) {
+ if (!value || !*value) {
+ printk(KERN_WARNING
+ "CIFS: invalid path to network resource\n");
+ return 1; /* needs_arg; */
+ }
+ if ((temp_len = strnlen(value, 300)) < 300) {
+ vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
+ if(vol->UNC == NULL)
+ return 1;
+ strcpy(vol->UNC,value);
+ if (strncmp(vol->UNC, "//", 2) == 0) {
+ vol->UNC[0] = '\\';
+ vol->UNC[1] = '\\';
+ } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
+ printk(KERN_WARNING
+ "CIFS: UNC Path does not begin with // or \\\\ \n");
+ return 1;
+ }
+ } else {
+ printk(KERN_WARNING "CIFS: UNC name too long\n");
+ return 1;
+ }
+ } else if ((strnicmp(data, "domain", 3) == 0)
+ || (strnicmp(data, "workgroup", 5) == 0)) {
+ if (!value || !*value) {
+ printk(KERN_WARNING "CIFS: invalid domain name\n");
+ return 1; /* needs_arg; */
+ }
+ /* BB are there cases in which a comma can be valid in
+ a domain name and need special handling? */
+ if (strnlen(value, 65) < 65) {
+ vol->domainname = value;
+ cFYI(1, ("Domain name set"));
+ } else {
+ printk(KERN_WARNING "CIFS: domain name too long\n");
+ return 1;
+ }
+ } else if (strnicmp(data, "iocharset", 9) == 0) {
+ if (!value || !*value) {
+ printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
+ return 1; /* needs_arg; */
+ }
+ if (strnlen(value, 65) < 65) {
+ if(strnicmp(value,"default",7))
+ vol->iocharset = value;
+ /* if iocharset not set load_nls_default used by caller */
+ cFYI(1, ("iocharset set to %s",value));
+ } else {
+ printk(KERN_WARNING "CIFS: iocharset name too long.\n");
+ return 1;
+ }
+ } else if (strnicmp(data, "uid", 3) == 0) {
+ if (value && *value) {
+ vol->linux_uid =
+ simple_strtoul(value, &value, 0);
+ }
+ } else if (strnicmp(data, "gid", 3) == 0) {
+ if (value && *value) {
+ vol->linux_gid =
+ simple_strtoul(value, &value, 0);
+ }
+ } else if (strnicmp(data, "file_mode", 4) == 0) {
+ if (value && *value) {
+ vol->file_mode =
+ simple_strtoul(value, &value, 0);
+ }
+ } else if (strnicmp(data, "dir_mode", 3) == 0) {
+ if (value && *value) {
+ vol->dir_mode =
+ simple_strtoul(value, &value, 0);
+ }
+ } else if (strnicmp(data, "port", 4) == 0) {
+ if (value && *value) {
+ vol->port =
+ simple_strtoul(value, &value, 0);
+ }
+ } else if (strnicmp(data, "rsize", 5) == 0) {
+ if (value && *value) {
+ vol->rsize =
+ simple_strtoul(value, &value, 0);
+ }
+ } else if (strnicmp(data, "wsize", 5) == 0) {
+ if (value && *value) {
+ vol->wsize =
+ simple_strtoul(value, &value, 0);
+ }
+ } else if (strnicmp(data, "sockopt", 5) == 0) {
+ if (value && *value) {
+ vol->sockopt =
+ simple_strtoul(value, &value, 0);
+ }
+ } else if (strnicmp(data, "netbiosname", 4) == 0) {
+ if (!value || !*value || (*value == ' ')) {
+ cFYI(1,("invalid (empty) netbiosname specified"));
+ } else {
+ memset(vol->source_rfc1001_name,0x20,15);
+ for(i=0;i<15;i++) {
+ /* BB are there cases in which a comma can be
+ valid in this workstation netbios name (and need
+ special handling)? */
+
+ /* We do not uppercase netbiosname for user */
+ if (value[i]==0)
+ break;
+ else
+ vol->source_rfc1001_name[i] = value[i];
+ }
+ /* The string has 16th byte zero still from
+ set at top of the function */
+ if((i==15) && (value[i] != 0))
+ printk(KERN_WARNING "CIFS: netbiosname longer than 15 and was truncated.\n");
+ }
+ } else if (strnicmp(data, "credentials", 4) == 0) {
+ /* ignore */
+ } else if (strnicmp(data, "version", 3) == 0) {
+ /* ignore */
+ } else if (strnicmp(data, "rw", 2) == 0) {
+ vol->rw = TRUE;
+ } else if ((strnicmp(data, "suid", 4) == 0) ||
+ (strnicmp(data, "nosuid", 6) == 0) ||
+ (strnicmp(data, "exec", 4) == 0) ||
+ (strnicmp(data, "noexec", 6) == 0) ||
+ (strnicmp(data, "nodev", 5) == 0) ||
+ (strnicmp(data, "noauto", 6) == 0) ||
+ (strnicmp(data, "dev", 3) == 0)) {
+ /* The mount tool or mount.cifs helper (if present)
+ uses these opts to set flags, and the flags are read
+ by the kernel vfs layer before we get here (ie
+ before read super) so there is no point trying to
+ parse these options again and set anything and it
+ is ok to just ignore them */
+ continue;
+ } else if (strnicmp(data, "ro", 2) == 0) {
+ vol->rw = FALSE;
+ } else if (strnicmp(data, "hard", 4) == 0) {
+ vol->retry = 1;
+ } else if (strnicmp(data, "soft", 4) == 0) {
+ vol->retry = 0;
+ } else if (strnicmp(data, "nohard", 6) == 0) {
+ vol->retry = 0;
+ } else if (strnicmp(data, "nosoft", 6) == 0) {
+ vol->retry = 1;
+ } else if (strnicmp(data, "nointr", 6) == 0) {
+ vol->intr = 0;
+ } else if (strnicmp(data, "intr", 4) == 0) {
+ vol->intr = 1;
+ } else if (strnicmp(data, "noac", 4) == 0) {
+ printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
+ } else
+ printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data);
+ }
+ if (vol->UNC == NULL) {
+ if(devname == NULL) {
+ printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n");
+ return 1;
+ }
+ if ((temp_len = strnlen(devname, 300)) < 300) {
+ vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
+ if(vol->UNC == NULL)
+ return 1;
+ strcpy(vol->UNC,devname);
+ if (strncmp(vol->UNC, "//", 2) == 0) {
+ vol->UNC[0] = '\\';
+ vol->UNC[1] = '\\';
+ } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
+ printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n");
+ return 1;
+ }
+ } else {
+ printk(KERN_WARNING "CIFS: UNC name too long\n");
+ return 1;
+ }
+ }
+ if(vol->UNCip == 0)
+ vol->UNCip = &vol->UNC[2];
+
+ return 0;
+}
+
+static struct cifsSesInfo *
+cifs_find_tcp_session(__u32 new_target_ip_addr,
+ char *userName, struct TCP_Server_Info **psrvTcp)
+{
+ struct list_head *tmp;
+ struct cifsSesInfo *ses;
+
+ *psrvTcp = NULL;
+ read_lock(&GlobalSMBSeslock);
+ list_for_each(tmp, &GlobalSMBSessionList) {
+ ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
+ if (ses->server) {
+ if (ses->server->addr.sockAddr.sin_addr.s_addr ==
+ new_target_ip_addr) {
+ /* BB lock server and tcp session and increment use count here?? */
+ *psrvTcp = ses->server; /* found a match on the TCP session */
+ /* BB check if reconnection needed */
+ if (strncmp
+ (ses->userName, userName,
+ MAX_USERNAME_SIZE) == 0){
+ read_unlock(&GlobalSMBSeslock);
+ return ses; /* found exact match on both tcp and SMB sessions */
+ }
+ }
+ }
+ /* else tcp and smb sessions need reconnection */
+ }
+ read_unlock(&GlobalSMBSeslock);
+ return NULL;
+}
+
+static struct cifsTconInfo *
+find_unc(__u32 new_target_ip_addr, char *uncName, char *userName)
+{
+ struct list_head *tmp;
+ struct cifsTconInfo *tcon;
+
+ read_lock(&GlobalSMBSeslock);
+ list_for_each(tmp, &GlobalTreeConnectionList) {
+ cFYI(1, ("Next tcon - "));
+ tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
+ if (tcon->ses) {
+ if (tcon->ses->server) {
+ cFYI(1,
+ (" old ip addr: %x == new ip %x ?",
+ tcon->ses->server->addr.sockAddr.sin_addr.
+ s_addr, new_target_ip_addr));
+ if (tcon->ses->server->addr.sockAddr.sin_addr.
+ s_addr == new_target_ip_addr) {
+ /* BB lock tcon and server and tcp session and increment use count here? */
+ /* found a match on the TCP session */
+ /* BB check if reconnection needed */
+ cFYI(1,("Matched ip, old UNC: %s == new: %s ?",
+ tcon->treeName, uncName));
+ if (strncmp
+ (tcon->treeName, uncName,
+ MAX_TREE_SIZE) == 0) {
+ cFYI(1,
+ ("Matched UNC, old user: %s == new: %s ?",
+ tcon->treeName, uncName));
+ if (strncmp
+ (tcon->ses->userName,
+ userName,
+ MAX_USERNAME_SIZE) == 0) {
+ read_unlock(&GlobalSMBSeslock);
+ return tcon;/* also matched user (smb session)*/
+ }
+ }
+ }
+ }
+ }
+ }
+ read_unlock(&GlobalSMBSeslock);
+ return NULL;
+}
+
+int
+connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
+ const char *old_path, const struct nls_table *nls_codepage)
+{
+ unsigned char *referrals = NULL;
+ unsigned int num_referrals;
+ int rc = 0;
+
+ rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage,
+ &num_referrals, &referrals);
+
+ /* BB Add in code to: if valid refrl, if not ip address contact
+ the helper that resolves tcp names, mount to it, try to
+ tcon to it unmount it if fail */
+
+ if(referrals)
+ kfree(referrals);
+
+ return rc;
+}
+
+int
+get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
+ const char *old_path, const struct nls_table *nls_codepage,
+ unsigned int *pnum_referrals, unsigned char ** preferrals)
+{
+ char *temp_unc;
+ int rc = 0;
+
+ *pnum_referrals = 0;
+
+ if (pSesInfo->ipc_tid == 0) {
+ temp_unc = kmalloc(2 /* for slashes */ +
+ strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2)
+ + 1 + 4 /* slash IPC$ */ + 2,
+ GFP_KERNEL);
+ if (temp_unc == NULL)
+ return -ENOMEM;
+ temp_unc[0] = '\\';
+ temp_unc[1] = '\\';
+ strcpy(temp_unc + 2, pSesInfo->serverName);
+ strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
+ rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
+ cFYI(1,
+ ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
+ kfree(temp_unc);
+ }
+ if (rc == 0)
+ rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
+ pnum_referrals, nls_codepage);
+
+ return rc;
+}
+
+/* See RFC1001 section 14 on representation of Netbios names */
+static void rfc1002mangle(char * target,char * source, unsigned int length)
+{
+ unsigned int i,j;
+
+ for(i=0,j=0;i<(length);i++) {
+ /* mask a nibble at a time and encode */
+ target[j] = 'A' + (0x0F & (source[i] >> 4));
+ target[j+1] = 'A' + (0x0F & source[i]);
+ j+=2;
+ }
+
+}
+
+
+static int
+ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
+ char * netbios_name)
+{
+ int rc = 0;
+ int connected = 0;
+ unsigned short int orig_port = 0;
+
+ if(*csocket == NULL) {
+ rc = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
+ if (rc < 0) {
+ cERROR(1, ("Error %d creating socket",rc));
+ *csocket = NULL;
+ return rc;
+ } else {
+ /* BB other socket options to set KEEPALIVE, NODELAY? */
+ cFYI(1,("Socket created"));
+ (*csocket)->sk->allocation = GFP_NOFS;
+ (*csocket)->sk->keepopen = 1; // test jz
+ }
+ }
+
+ psin_server->sin_family = AF_INET;
+ if(psin_server->sin_port) { /* user overrode default port */
+ rc = (*csocket)->ops->connect(*csocket,
+ (struct sockaddr *) psin_server,
+ sizeof (struct sockaddr_in),0);
+ if (rc >= 0)
+ connected = 1;
+ }
+
+ if(!connected) {
+ /* save original port so we can retry user specified port
+ later if fall back ports fail this time */
+ orig_port = psin_server->sin_port;
+
+ /* do not retry on the same port we just failed on */
+ if(psin_server->sin_port != htons(CIFS_PORT)) {
+ psin_server->sin_port = htons(CIFS_PORT);
+
+ rc = (*csocket)->ops->connect(*csocket,
+ (struct sockaddr *) psin_server,
+ sizeof (struct sockaddr_in),0);
+ if (rc >= 0)
+ connected = 1;
+ }
+ }
+ if (!connected) {
+ psin_server->sin_port = htons(RFC1001_PORT);
+ rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
+ psin_server, sizeof (struct sockaddr_in),0);
+ if (rc >= 0)
+ connected = 1;
+ }
+
+ /* give up here - unless we want to retry on different
+ protocol families some day */
+ if (!connected) {
+ if(orig_port)
+ psin_server->sin_port = orig_port;
+ cFYI(1,("Error %d connecting to server via ipv4",rc));
+ sock_release(*csocket);
+ *csocket = NULL;
+ return rc;
+ }
+ /* Eventually check for other socket options to change from
+ the default. sock_setsockopt not used because it expects
+ user space buffer */
+ (*csocket)->sk->rcvtimeo = 7 * HZ;
+
+ /* send RFC1001 sessinit */
+
+ if(psin_server->sin_port == htons(139)) {
+ /* some servers require RFC1001 sessinit before sending
+ negprot - BB check reconnection in case where second
+ sessinit is sent but no second negprot */
+ struct rfc1002_session_packet * ses_init_buf;
+ struct smb_hdr * smb_buf;
+ ses_init_buf = cifs_kcalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL);
+ if(ses_init_buf) {
+ ses_init_buf->trailer.session_req.called_len = 32;
+ rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
+ DEFAULT_CIFS_CALLED_NAME,16);
+ ses_init_buf->trailer.session_req.calling_len = 32;
+ /* calling name ends in null (byte 16) from old smb
+ convention. */
+ if(netbios_name && (netbios_name[0] !=0)) {
+ rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
+ netbios_name,16);
+ } else {
+ rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
+ "LINUX_CIFS_CLNT",16);
+ }
+ ses_init_buf->trailer.session_req.scope1 = 0;
+ ses_init_buf->trailer.session_req.scope2 = 0;
+ smb_buf = (struct smb_hdr *)ses_init_buf;
+ /* sizeof RFC1002_SESSION_REQUEST with no scope */
+ smb_buf->smb_buf_length = 0x81000044;
+ rc = smb_send(*csocket, smb_buf, 0x44,
+ (struct sockaddr *)psin_server);
+ kfree(ses_init_buf);
+ }
+ /* else the negprot may still work without this
+ even though malloc failed */
+
+ }
+
+ return rc;
+}
+
+static int
+ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
+{
+ int rc = 0;
+ int connected = 0;
+
+ if(*csocket == NULL) {
+ rc = sock_create(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
+ if (rc < 0) {
+ cERROR(1, ("Error %d creating ipv6 socket",rc));
+ *csocket = NULL;
+ return rc;
+ } else {
+ /* BB other socket options to set KEEPALIVE, NODELAY? */
+ cFYI(1,("ipv6 Socket created"));
+ (*csocket)->sk->allocation = GFP_NOFS;
+ }
+ }
+
+ psin_server->sin6_family = AF_INET6;
+
+ if(psin_server->sin6_port) { /* user overrode default port */
+ rc = (*csocket)->ops->connect(*csocket,
+ (struct sockaddr *) psin_server,
+ sizeof (struct sockaddr_in6),0);
+ if (rc >= 0)
+ connected = 1;
+ }
+
+ if(!connected) {
+ /* do not retry on the same port we just failed on */
+ if(psin_server->sin6_port != htons(CIFS_PORT)) {
+ psin_server->sin6_port = htons(CIFS_PORT);
+
+ rc = (*csocket)->ops->connect(*csocket,
+ (struct sockaddr *) psin_server,
+ sizeof (struct sockaddr_in6),0);
+ if (rc >= 0)
+ connected = 1;
+ }
+ }
+ if (!connected) {
+ psin_server->sin6_port = htons(RFC1001_PORT);
+ rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
+ psin_server, sizeof (struct sockaddr_in6),0);
+ if (rc >= 0)
+ connected = 1;
+ }
+
+ /* give up here - unless we want to retry on different
+ protocol families some day */
+ if (!connected) {
+ cFYI(1,("Error %d connecting to server via ipv6",rc));
+ sock_release(*csocket);
+ *csocket = NULL;
+ return rc;
+ }
+ /* Eventually check for other socket options to change from
+ the default. sock_setsockopt not used because it expects
+ user space buffer */
+ (*csocket)->sk->rcvtimeo = 7 * HZ;
+
+ return rc;
+}
+
+int
+cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
+ char *mount_data, const char *devname)
+{
+ int rc = 0;
+ int xid;
+ struct socket *csocket = NULL;
+ struct sockaddr_in sin_server;
+ struct sockaddr_in6 sin_server6;
+ struct smb_vol volume_info;
+ struct cifsSesInfo *pSesInfo = NULL;
+ struct cifsSesInfo *existingCifsSes = NULL;
+ struct cifsTconInfo *tcon = NULL;
+ struct TCP_Server_Info *srvTcp = NULL;
+
+ xid = GetXid();
+
+ cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); /* BB removeme BB fixme */
+
+ memset(&volume_info,0,sizeof(struct smb_vol));
+ if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
+ if(volume_info.UNC)
+ kfree(volume_info.UNC);
+ if(volume_info.password)
+ kfree(volume_info.password);
+ FreeXid(xid);
+ return -EINVAL;
+ }
+
+ if (volume_info.username) {
+ cFYI(1, ("Username: %s ", volume_info.username));
+
+ } else {
+ cifserror("No username specified ");
+ /* In userspace mount helper we can get user name from alternate
+ locations such as env variables and files on disk */
+ if(volume_info.UNC)
+ kfree(volume_info.UNC);
+ if(volume_info.password)
+ kfree(volume_info.password);
+ FreeXid(xid);
+ return -EINVAL;
+ }
+
+ if (volume_info.UNCip && volume_info.UNC) {
+ rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr);
+
+ if(rc == 0) {
+ /* not ipv4 address, try ipv6 */
+ rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u);
+ }
+
+ if(rc != 1) {
+ /* we failed translating address */
+ if(volume_info.UNC)
+ kfree(volume_info.UNC);
+ if(volume_info.password)
+ kfree(volume_info.password);
+ FreeXid(xid);
+ return -EINVAL;
+ }
+
+ cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
+ /* success */
+ rc = 0;
+ } else if (volume_info.UNCip){
+ /* BB using ip addr as server name connect to the DFS root below */
+ cERROR(1,("Connecting to DFS root not implemented yet"));
+ if(volume_info.UNC)
+ kfree(volume_info.UNC);
+ if(volume_info.password)
+ kfree(volume_info.password);
+ FreeXid(xid);
+ return -EINVAL;
+ } else /* which servers DFS root would we conect to */ {
+ cERROR(1,
+ ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified "));
+ if(volume_info.UNC)
+ kfree(volume_info.UNC);
+ if(volume_info.password)
+ kfree(volume_info.password);
+ FreeXid(xid);
+ return -EINVAL;
+ }
+
+ /* this is needed for ASCII cp to Unicode converts */
+ if(volume_info.iocharset == NULL) {
+ cifs_sb->local_nls = load_nls_default();
+ /* load_nls_default can not return null */
+ } else {
+ cifs_sb->local_nls = load_nls(volume_info.iocharset);
+ if(cifs_sb->local_nls == NULL) {
+ cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
+ if(volume_info.UNC)
+ kfree(volume_info.UNC);
+ if(volume_info.password)
+ kfree(volume_info.password);
+ FreeXid(xid);
+ return -ELIBACC;
+ }
+ }
+
+ existingCifsSes =
+ cifs_find_tcp_session(sin_server.sin_addr.s_addr,
+ volume_info.username, &srvTcp);
+ if (srvTcp) {
+ cFYI(1, ("Existing tcp session with server found "));
+ } else { /* create socket */
+ if(volume_info.port)
+ sin_server.sin_port = htons(volume_info.port);
+ else
+ sin_server.sin_port = 0;
+ rc = ipv4_connect(&sin_server,&csocket,volume_info.source_rfc1001_name);
+ if (rc < 0) {
+ cERROR(1,
+ ("Error connecting to IPv4 socket. Aborting operation"));
+ if(csocket != NULL)
+ sock_release(csocket);
+ if(volume_info.UNC)
+ kfree(volume_info.UNC);
+ if(volume_info.password)
+ kfree(volume_info.password);
+ FreeXid(xid);
+ return rc;
+ }
+
+ srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
+ if (srvTcp == NULL) {
+ rc = -ENOMEM;
+ sock_release(csocket);
+ if(volume_info.UNC)
+ kfree(volume_info.UNC);
+ if(volume_info.password)
+ kfree(volume_info.password);
+ FreeXid(xid);
+ return rc;
+ } else {
+ memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
+ memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in));
+ atomic_set(&srvTcp->inFlight,0);
+ /* BB Add code for ipv6 case too */
+ srvTcp->ssocket = csocket;
+ srvTcp->protocolType = IPV4;
+ init_waitqueue_head(&srvTcp->response_q);
+ init_waitqueue_head(&srvTcp->request_q);
+ INIT_LIST_HEAD(&srvTcp->pending_mid_q);
+ /* at this point we are the only ones with the pointer
+ to the struct since the kernel thread not created yet
+ so no need to spinlock this init of tcpStatus */
+ srvTcp->tcpStatus = CifsNew;
+ init_MUTEX(&srvTcp->tcpSem);
+ kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
+ CLONE_FS | CLONE_FILES | CLONE_VM);
+ memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
+ }
+ }
+
+ if (existingCifsSes) {
+ pSesInfo = existingCifsSes;
+ cFYI(1, ("Existing smb sess found "));
+ if(volume_info.password)
+ kfree(volume_info.password);
+ /* volume_info.UNC freed at end of function */
+ } else if (!rc) {
+ cFYI(1, ("Existing smb sess not found "));
+ pSesInfo = sesInfoAlloc();
+ if (pSesInfo == NULL)
+ rc = -ENOMEM;
+ else {
+ pSesInfo->server = srvTcp;
+ sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
+ NIPQUAD(sin_server.sin_addr.s_addr));
+ }
+
+ if (!rc){
+ /* volume_info.password freed at unmount */
+ if (volume_info.password)
+ pSesInfo->password = volume_info.password;
+ if (volume_info.username)
+ strncpy(pSesInfo->userName,
+ volume_info.username,MAX_USERNAME_SIZE);
+ if (volume_info.domainname)
+ strncpy(pSesInfo->domainName,
+ volume_info.domainname,MAX_USERNAME_SIZE);
+ pSesInfo->linux_uid = volume_info.linux_uid;
+ down(&pSesInfo->sesSem);
+ rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
+ up(&pSesInfo->sesSem);
+ if(!rc)
+ atomic_inc(&srvTcp->socketUseCount);
+ } else
+ if(volume_info.password)
+ kfree(volume_info.password);
+ }
+
+ /* search for existing tcon to this server share */
+ if (!rc) {
+ if((volume_info.rsize) && (volume_info.rsize + MAX_CIFS_HDR_SIZE < srvTcp->maxBuf))
+ cifs_sb->rsize = volume_info.rsize;
+ else
+ cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
+ if((volume_info.wsize) && (volume_info.wsize + MAX_CIFS_HDR_SIZE < srvTcp->maxBuf))
+ cifs_sb->wsize = volume_info.wsize;
+ else
+ cifs_sb->wsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
+ if(cifs_sb->rsize < PAGE_CACHE_SIZE) {
+ cifs_sb->rsize = PAGE_CACHE_SIZE;
+ cERROR(1,("Attempt to set readsize for mount to less than one page (4096)"));
+ }
+ cifs_sb->mnt_uid = volume_info.linux_uid;
+ cifs_sb->mnt_gid = volume_info.linux_gid;
+ cifs_sb->mnt_file_mode = volume_info.file_mode;
+ cifs_sb->mnt_dir_mode = volume_info.dir_mode;
+ cFYI(1,("file mode: 0x%x dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
+ tcon =
+ find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
+ volume_info.username);
+ if (tcon) {
+ cFYI(1, ("Found match on UNC path "));
+ /* we can have only one retry value for a connection
+ to a share so for resources mounted more than once
+ to the same server share the last value passed in
+ for the retry flag is used */
+ tcon->retry = volume_info.retry;
+ } else {
+ tcon = tconInfoAlloc();
+ if (tcon == NULL)
+ rc = -ENOMEM;
+ else {
+ /* check for null share name ie connect to dfs root */
+
+ /* BB check if this works for exactly length three strings */
+ if ((strchr(volume_info.UNC + 3, '\\') == NULL)
+ && (strchr(volume_info.UNC + 3, '/') ==
+ NULL)) {
+ rc = connect_to_dfs_path(xid,
+ pSesInfo,
+ "",
+ cifs_sb->
+ local_nls);
+ if(volume_info.UNC)
+ kfree(volume_info.UNC);
+ FreeXid(xid);
+ return -ENODEV;
+ } else {
+ rc = CIFSTCon(xid, pSesInfo,
+ volume_info.UNC,
+ tcon, cifs_sb->local_nls);
+ cFYI(1, ("CIFS Tcon rc = %d", rc));
+ }
+ if (!rc) {
+ atomic_inc(&pSesInfo->inUse);
+ tcon->retry = volume_info.retry;
+ }
+ }
+ }
+ }
+ if(pSesInfo) {
+ if (pSesInfo->capabilities & CAP_LARGE_FILES) {
+ sb->s_maxbytes = (u64) 1 << 63;
+ } else
+ sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
+ }
+
+/* on error free sesinfo and tcon struct if needed */
+ if (rc) {
+ /* if session setup failed, use count is zero but
+ we still need to free cifsd thread */
+ if(atomic_read(&srvTcp->socketUseCount) == 0) {
+ spin_lock(&GlobalMid_Lock);
+ srvTcp->tcpStatus = CifsExiting;
+ spin_unlock(&GlobalMid_Lock);
+ if(srvTcp->tsk)
+ send_sig(SIGKILL,srvTcp->tsk,1);
+ }
+ /* If find_unc succeeded then rc == 0 so we can not end */
+ if (tcon) /* up accidently freeing someone elses tcon struct */
+ tconInfoFree(tcon);
+ if (existingCifsSes == 0) {
+ if (pSesInfo) {
+ if ((pSesInfo->server) &&
+ (pSesInfo->status == CifsGood)) {
+ int temp_rc;
+ temp_rc = CIFSSMBLogoff(xid, pSesInfo);
+ /* if the socketUseCount is now zero */
+ if((temp_rc == -ESHUTDOWN) &&
+ (pSesInfo->server->tsk))
+ send_sig(SIGKILL,pSesInfo->server->tsk,1);
+ } else
+ cFYI(1, ("No session or bad tcon"));
+ sesInfoFree(pSesInfo);
+ /* pSesInfo = NULL; */
+ }
+ }
+ } else {
+ atomic_inc(&tcon->useCount);
+ cifs_sb->tcon = tcon;
+ tcon->ses = pSesInfo;
+
+ /* do not care if following two calls succeed - informational only */
+ CIFSSMBQFSDeviceInfo(xid, tcon, cifs_sb->local_nls);
+ CIFSSMBQFSAttributeInfo(xid, tcon, cifs_sb->local_nls);
+ if (tcon->ses->capabilities & CAP_UNIX)
+ CIFSSMBQFSUnixInfo(xid, tcon, cifs_sb->local_nls);
+ }
+
+ /* volume_info.password is freed above when existing session found
+ (in which case it is not needed anymore) but when new sesion is created
+ the password ptr is put in the new session structure (in which case the
+ password will be freed at unmount time) */
+ if(volume_info.UNC)
+ kfree(volume_info.UNC);
+ FreeXid(xid);
+ return rc;
+}
+
+static int
+CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
+ char session_key[CIFS_SESSION_KEY_SIZE],
+ const struct nls_table *nls_codepage)
+{
+ struct smb_hdr *smb_buffer;
+ struct smb_hdr *smb_buffer_response;
+ SESSION_SETUP_ANDX *pSMB;
+ SESSION_SETUP_ANDX *pSMBr;
+ char *bcc_ptr;
+ char *user = ses->userName;
+ char *domain = ses->domainName;
+ int rc = 0;
+ int remaining_words = 0;
+ int bytes_returned = 0;
+ int len;
+
+ cFYI(1, ("In sesssetup "));
+
+ smb_buffer = cifs_buf_get();
+ if (smb_buffer == 0) {
+ return -ENOMEM;
+ }
+ smb_buffer_response = smb_buffer;
+ pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
+
+ /* send SMBsessionSetup here */
+ header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
+ NULL /* no tCon exists yet */ , 13 /* wct */ );
+
+ pSMB->req_no_secext.AndXCommand = 0xFF;
+ pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
+ pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
+
+ if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+ smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+
+ pSMB->req_no_secext.Capabilities =
+ CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS;
+ if (ses->capabilities & CAP_UNICODE) {
+ smb_buffer->Flags2 |= SMBFLG2_UNICODE;
+ pSMB->req_no_secext.Capabilities |= CAP_UNICODE;
+ }
+ if (ses->capabilities & CAP_STATUS32) {
+ smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
+ pSMB->req_no_secext.Capabilities |= CAP_STATUS32;
+ }
+ if (ses->capabilities & CAP_DFS) {
+ smb_buffer->Flags2 |= SMBFLG2_DFS;
+ pSMB->req_no_secext.Capabilities |= CAP_DFS;
+ }
+ pSMB->req_no_secext.Capabilities =
+ cpu_to_le32(pSMB->req_no_secext.Capabilities);
+ /* pSMB->req_no_secext.CaseInsensitivePasswordLength =
+ CIFS_SESSION_KEY_SIZE; */
+ pSMB->req_no_secext.CaseInsensitivePasswordLength = 0;
+ pSMB->req_no_secext.CaseSensitivePasswordLength =
+ cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+ bcc_ptr = pByteArea(smb_buffer);
+ /* memcpy(bcc_ptr, (char *) lm_session_key, CIFS_SESSION_KEY_SIZE);
+ bcc_ptr += CIFS_SESSION_KEY_SIZE; */
+ memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
+ bcc_ptr += CIFS_SESSION_KEY_SIZE;
+
+ if (ses->capabilities & CAP_UNICODE) {
+ if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
+ *bcc_ptr = 0;
+ bcc_ptr++;
+ }
+ if(user == NULL)
+ bytes_returned = 0; /* skill null user */
+ else
+ bytes_returned =
+ cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100,
+ nls_codepage);
+ bcc_ptr += 2 * bytes_returned; /* convert num 16 bit words to bytes */
+ bcc_ptr += 2; /* trailing null */
+ if (domain == NULL)
+ bytes_returned =
+ cifs_strtoUCS((wchar_t *) bcc_ptr,
+ "CIFS_LINUX_DOM", 32, nls_codepage);
+ else
+ bytes_returned =
+ cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
+ nls_codepage);
+ bcc_ptr += 2 * bytes_returned;
+ bcc_ptr += 2;
+ bytes_returned =
+ cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
+ 32, nls_codepage);
+ bcc_ptr += 2 * bytes_returned;
+ bytes_returned =
+ cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
+ nls_codepage);
+ bcc_ptr += 2 * bytes_returned;
+ bcc_ptr += 2;
+ bytes_returned =
+ cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
+ 64, nls_codepage);
+ bcc_ptr += 2 * bytes_returned;
+ bcc_ptr += 2;
+ } else {
+ if(user != NULL) {
+ strncpy(bcc_ptr, user, 200);
+ bcc_ptr += strnlen(user, 200);
+ }
+ *bcc_ptr = 0;
+ bcc_ptr++;
+ if (domain == NULL) {
+ strcpy(bcc_ptr, "CIFS_LINUX_DOM");
+ bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
+ } else {
+ strncpy(bcc_ptr, domain, 64);
+ bcc_ptr += strnlen(domain, 64);
+ *bcc_ptr = 0;
+ bcc_ptr++;
+ }
+ strcpy(bcc_ptr, "Linux version ");
+ bcc_ptr += strlen("Linux version ");
+ strcpy(bcc_ptr, UTS_RELEASE);
+ bcc_ptr += strlen(UTS_RELEASE) + 1;
+ strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
+ bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
+ }
+ BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
+ smb_buffer->smb_buf_length += BCC(smb_buffer);
+ BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
+
+ rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
+ &bytes_returned, 1);
+ if (rc) {
+/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
+ } else if ((smb_buffer_response->WordCount == 3)
+ || (smb_buffer_response->WordCount == 4)) {
+ pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action);
+ if (pSMBr->resp.Action & GUEST_LOGIN)
+ cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */
+ if (ses) {
+ ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
+ cFYI(1, ("UID = %d ", ses->Suid));
+ /* response can have either 3 or 4 word count - Samba sends 3 */
+ bcc_ptr = pByteArea(smb_buffer_response);
+ if ((pSMBr->resp.hdr.WordCount == 3)
+ || ((pSMBr->resp.hdr.WordCount == 4)
+ && (pSMBr->resp.SecurityBlobLength <
+ pSMBr->resp.ByteCount))) {
+ if (pSMBr->resp.hdr.WordCount == 4)
+ bcc_ptr +=
+ pSMBr->resp.SecurityBlobLength;
+
+ if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
+ if ((long) (bcc_ptr) % 2) {
+ remaining_words =
+ (BCC(smb_buffer_response)
+ - 1) / 2;
+ bcc_ptr++; /* Unicode strings must be word aligned */
+ } else {
+ remaining_words =
+ BCC
+ (smb_buffer_response) / 2;
+ }
+ len =
+ UniStrnlen((wchar_t *) bcc_ptr,
+ remaining_words - 1);
+/* We look for obvious messed up bcc or strings in response so we do not go off
+ the end since (at least) WIN2K and Windows XP have a major bug in not null
+ terminating last Unicode string in response */
+ ses->serverOS = cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
+ cifs_strfromUCS_le(ses->serverOS,
+ (wchar_t *)bcc_ptr, len,nls_codepage);
+ bcc_ptr += 2 * (len + 1);
+ remaining_words -= len + 1;
+ ses->serverOS[2 * len] = 0;
+ ses->serverOS[1 + (2 * len)] = 0;
+ if (remaining_words > 0) {
+ len = UniStrnlen((wchar_t *)bcc_ptr,
+ remaining_words
+ - 1);
+ ses->serverNOS =cifs_kcalloc(2 * (len + 1),GFP_KERNEL);
+ cifs_strfromUCS_le(ses->serverNOS,
+ (wchar_t *)bcc_ptr,len,nls_codepage);
+ bcc_ptr += 2 * (len + 1);
+ ses->serverNOS[2 * len] = 0;
+ ses->serverNOS[1 + (2 * len)] = 0;
+ remaining_words -= len + 1;
+ if (remaining_words > 0) {
+ len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
+ /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
+ ses->serverDomain =
+ cifs_kcalloc(2*(len+1),GFP_KERNEL);
+ cifs_strfromUCS_le(ses->serverDomain,
+ (wchar_t *)bcc_ptr,len,nls_codepage);
+ bcc_ptr += 2 * (len + 1);
+ ses->serverDomain[2*len] = 0;
+ ses->serverDomain[1+(2*len)] = 0;
+ } /* else no more room so create dummy domain string */
+ else
+ ses->serverDomain =
+ cifs_kcalloc(2,
+ GFP_KERNEL);
+ } else { /* no room so create dummy domain and NOS string */
+ ses->serverDomain =
+ cifs_kcalloc(2, GFP_KERNEL);
+ ses->serverNOS =
+ cifs_kcalloc(2, GFP_KERNEL);
+ }
+ } else { /* ASCII */
+ len = strnlen(bcc_ptr, 1024);
+ if (((long) bcc_ptr + len) - (long)
+ pByteArea(smb_buffer_response)
+ <= BCC(smb_buffer_response)) {
+ ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL);
+ strncpy(ses->serverOS,bcc_ptr, len);
+
+ bcc_ptr += len;
+ bcc_ptr[0] = 0; /* null terminate the string */
+ bcc_ptr++;
+
+ len = strnlen(bcc_ptr, 1024);
+ ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL);
+ strncpy(ses->serverNOS, bcc_ptr, len);
+ bcc_ptr += len;
+ bcc_ptr[0] = 0;
+ bcc_ptr++;
+
+ len = strnlen(bcc_ptr, 1024);
+ ses->serverDomain = cifs_kcalloc(len + 1,GFP_KERNEL);
+ strncpy(ses->serverDomain, bcc_ptr, len);
+ bcc_ptr += len;
+ bcc_ptr[0] = 0;
+ bcc_ptr++;
+ } else
+ cFYI(1,
+ ("Variable field of length %d extends beyond end of smb ",
+ len));
+ }
+ } else {
+ cERROR(1,
+ (" Security Blob Length extends beyond end of SMB"));
+ }
+ } else {
+ cERROR(1, ("No session structure passed in."));
+ }
+ } else {
+ cERROR(1,
+ (" Invalid Word count %d: ",
+ smb_buffer_response->WordCount));
+ rc = -EIO;
+ }
+
+ if (smb_buffer)
+ cifs_buf_release(smb_buffer);
+
+ return rc;
+}
+
+static int
+CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
+ char *SecurityBlob,int SecurityBlobLength,
+ const struct nls_table *nls_codepage)
+{
+ struct smb_hdr *smb_buffer;
+ struct smb_hdr *smb_buffer_response;
+ SESSION_SETUP_ANDX *pSMB;
+ SESSION_SETUP_ANDX *pSMBr;
+ char *bcc_ptr;
+ char *user = ses->userName;
+ char *domain = ses->domainName;
+ int rc = 0;
+ int remaining_words = 0;
+ int bytes_returned = 0;
+ int len;
+
+ cFYI(1, ("In spnego sesssetup "));
+
+ smb_buffer = cifs_buf_get();
+ if (smb_buffer == 0) {
+ return -ENOMEM;
+ }
+ smb_buffer_response = smb_buffer;
+ pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
+
+ /* send SMBsessionSetup here */
+ header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
+ NULL /* no tCon exists yet */ , 12 /* wct */ );
+ pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
+ pSMB->req.AndXCommand = 0xFF;
+ pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
+ pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
+
+ if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+ smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+
+ pSMB->req.Capabilities =
+ CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
+ CAP_EXTENDED_SECURITY;
+ if (ses->capabilities & CAP_UNICODE) {
+ smb_buffer->Flags2 |= SMBFLG2_UNICODE;
+ pSMB->req.Capabilities |= CAP_UNICODE;
+ }
+ if (ses->capabilities & CAP_STATUS32) {
+ smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
+ pSMB->req.Capabilities |= CAP_STATUS32;
+ }
+ if (ses->capabilities & CAP_DFS) {
+ smb_buffer->Flags2 |= SMBFLG2_DFS;
+ pSMB->req.Capabilities |= CAP_DFS;
+ }
+ pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities);
+
+ pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
+ bcc_ptr = pByteArea(smb_buffer);
+ memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength);
+ bcc_ptr += SecurityBlobLength;
+
+ if (ses->capabilities & CAP_UNICODE) {
+ if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode strings */
+ *bcc_ptr = 0;
+ bcc_ptr++;
+ }
+ bytes_returned =
+ cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage);
+ bcc_ptr += 2 * bytes_returned; /* convert num of 16 bit words to bytes */
+ bcc_ptr += 2; /* trailing null */
+ if (domain == NULL)
+ bytes_returned =
+ cifs_strtoUCS((wchar_t *) bcc_ptr,
+ "CIFS_LINUX_DOM", 32, nls_codepage);
+ else
+ bytes_returned =
+ cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
+ nls_codepage);
+ bcc_ptr += 2 * bytes_returned;
+ bcc_ptr += 2;
+ bytes_returned =
+ cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
+ 32, nls_codepage);
+ bcc_ptr += 2 * bytes_returned;
+ bytes_returned =
+ cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
+ nls_codepage);
+ bcc_ptr += 2 * bytes_returned;
+ bcc_ptr += 2;
+ bytes_returned =
+ cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
+ 64, nls_codepage);
+ bcc_ptr += 2 * bytes_returned;
+ bcc_ptr += 2;
+ } else {
+ strncpy(bcc_ptr, user, 200);
+ bcc_ptr += strnlen(user, 200);
+ *bcc_ptr = 0;
+ bcc_ptr++;
+ if (domain == NULL) {
+ strcpy(bcc_ptr, "CIFS_LINUX_DOM");
+ bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
+ } else {
+ strncpy(bcc_ptr, domain, 64);
+ bcc_ptr += strnlen(domain, 64);
+ *bcc_ptr = 0;
+ bcc_ptr++;
+ }
+ strcpy(bcc_ptr, "Linux version ");
+ bcc_ptr += strlen("Linux version ");
+ strcpy(bcc_ptr, UTS_RELEASE);
+ bcc_ptr += strlen(UTS_RELEASE) + 1;
+ strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
+ bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
+ }
+ BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
+ smb_buffer->smb_buf_length += BCC(smb_buffer);
+ BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
+
+ rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
+ &bytes_returned, 1);
+ if (rc) {
+/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
+ } else if ((smb_buffer_response->WordCount == 3)
+ || (smb_buffer_response->WordCount == 4)) {
+ pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action);
+ pSMBr->resp.SecurityBlobLength =
+ le16_to_cpu(pSMBr->resp.SecurityBlobLength);
+ if (pSMBr->resp.Action & GUEST_LOGIN)
+ cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
+ if (ses) {
+ ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
+ cFYI(1, ("UID = %d ", ses->Suid));
+ bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */
+
+ /* BB Fix below to make endian neutral !! */
+
+ if ((pSMBr->resp.hdr.WordCount == 3)
+ || ((pSMBr->resp.hdr.WordCount == 4)
+ && (pSMBr->resp.SecurityBlobLength <
+ pSMBr->resp.ByteCount))) {
+ if (pSMBr->resp.hdr.WordCount == 4) {
+ bcc_ptr +=
+ pSMBr->resp.SecurityBlobLength;
+ cFYI(1,
+ ("Security Blob Length %d ",
+ pSMBr->resp.SecurityBlobLength));
+ }
+
+ if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
+ if ((long) (bcc_ptr) % 2) {
+ remaining_words =
+ (BCC(smb_buffer_response)
+ - 1) / 2;
+ bcc_ptr++; /* Unicode strings must be word aligned */
+ } else {
+ remaining_words =
+ BCC
+ (smb_buffer_response) / 2;
+ }
+ len =
+ UniStrnlen((wchar_t *) bcc_ptr,
+ remaining_words - 1);
+/* We look for obvious messed up bcc or strings in response so we do not go off
+ the end since (at least) WIN2K and Windows XP have a major bug in not null
+ terminating last Unicode string in response */
+ ses->serverOS =
+ cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
+ cifs_strfromUCS_le(ses->serverOS,
+ (wchar_t *)
+ bcc_ptr, len,
+ nls_codepage);
+ bcc_ptr += 2 * (len + 1);
+ remaining_words -= len + 1;
+ ses->serverOS[2 * len] = 0;
+ ses->serverOS[1 + (2 * len)] = 0;
+ if (remaining_words > 0) {
+ len = UniStrnlen((wchar_t *)bcc_ptr,
+ remaining_words
+ - 1);
+ ses->serverNOS =
+ cifs_kcalloc(2 * (len + 1),
+ GFP_KERNEL);
+ cifs_strfromUCS_le(ses->serverNOS,
+ (wchar_t *)bcc_ptr,
+ len,
+ nls_codepage);
+ bcc_ptr += 2 * (len + 1);
+ ses->serverNOS[2 * len] = 0;
+ ses->serverNOS[1 + (2 * len)] = 0;
+ remaining_words -= len + 1;
+ if (remaining_words > 0) {
+ len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
+ /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
+ ses->serverDomain = cifs_kcalloc(2*(len+1),GFP_KERNEL);
+ cifs_strfromUCS_le(ses->serverDomain,
+ (wchar_t *)bcc_ptr,
+ len,
+ nls_codepage);
+ bcc_ptr += 2*(len+1);
+ ses->serverDomain[2*len] = 0;
+ ses->serverDomain[1+(2*len)] = 0;
+ } /* else no more room so create dummy domain string */
+ else
+ ses->serverDomain =
+ cifs_kcalloc(2,GFP_KERNEL);
+ } else { /* no room so create dummy domain and NOS string */
+ ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL);
+ ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL);
+ }
+ } else { /* ASCII */
+
+ len = strnlen(bcc_ptr, 1024);
+ if (((long) bcc_ptr + len) - (long)
+ pByteArea(smb_buffer_response)
+ <= BCC(smb_buffer_response)) {
+ ses->serverOS = cifs_kcalloc(len + 1, GFP_KERNEL);
+ strncpy(ses->serverOS, bcc_ptr, len);
+
+ bcc_ptr += len;
+ bcc_ptr[0] = 0; /* null terminate the string */
+ bcc_ptr++;
+
+ len = strnlen(bcc_ptr, 1024);
+ ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL);
+ strncpy(ses->serverNOS, bcc_ptr, len);
+ bcc_ptr += len;
+ bcc_ptr[0] = 0;
+ bcc_ptr++;
+
+ len = strnlen(bcc_ptr, 1024);
+ ses->serverDomain = cifs_kcalloc(len + 1, GFP_KERNEL);
+ strncpy(ses->serverDomain, bcc_ptr, len);
+ bcc_ptr += len;
+ bcc_ptr[0] = 0;
+ bcc_ptr++;
+ } else
+ cFYI(1,
+ ("Variable field of length %d extends beyond end of smb ",
+ len));
+ }
+ } else {
+ cERROR(1,
+ (" Security Blob Length extends beyond end of SMB"));
+ }
+ } else {
+ cERROR(1, ("No session structure passed in."));
+ }
+ } else {
+ cERROR(1,
+ (" Invalid Word count %d: ",
+ smb_buffer_response->WordCount));
+ rc = -EIO;
+ }
+
+ if (smb_buffer)
+ cifs_buf_release(smb_buffer);
+
+ return rc;
+}
+
+static int
+CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
+ struct cifsSesInfo *ses, int * pNTLMv2_flag,
+ const struct nls_table *nls_codepage)
+{
+ struct smb_hdr *smb_buffer;
+ struct smb_hdr *smb_buffer_response;
+ SESSION_SETUP_ANDX *pSMB;
+ SESSION_SETUP_ANDX *pSMBr;
+ char *bcc_ptr;
+ char *domain = ses->domainName;
+ int rc = 0;
+ int remaining_words = 0;
+ int bytes_returned = 0;
+ int len;
+ int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
+ PNEGOTIATE_MESSAGE SecurityBlob;
+ PCHALLENGE_MESSAGE SecurityBlob2;
+
+ cFYI(1, ("In NTLMSSP sesssetup (negotiate) "));
+ *pNTLMv2_flag = FALSE;
+ smb_buffer = cifs_buf_get();
+ if (smb_buffer == 0) {
+ return -ENOMEM;
+ }
+ smb_buffer_response = smb_buffer;
+ pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
+ pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
+
+ /* send SMBsessionSetup here */
+ header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
+ NULL /* no tCon exists yet */ , 12 /* wct */ );
+ pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
+ pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
+
+ pSMB->req.AndXCommand = 0xFF;
+ pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
+ pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
+
+ if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+ smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+
+ pSMB->req.Capabilities =
+ CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
+ CAP_EXTENDED_SECURITY;
+ if (ses->capabilities & CAP_UNICODE) {
+ smb_buffer->Flags2 |= SMBFLG2_UNICODE;
+ pSMB->req.Capabilities |= CAP_UNICODE;
+ }
+ if (ses->capabilities & CAP_STATUS32) {
+ smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
+ pSMB->req.Capabilities |= CAP_STATUS32;
+ }
+ if (ses->capabilities & CAP_DFS) {
+ smb_buffer->Flags2 |= SMBFLG2_DFS;
+ pSMB->req.Capabilities |= CAP_DFS;
+ }
+ pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities);
+
+ bcc_ptr = (char *) &pSMB->req.SecurityBlob;
+ SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
+ strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
+ SecurityBlob->MessageType = NtLmNegotiate;
+ SecurityBlob->NegotiateFlags =
+ NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
+ NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 |
+ /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
+ if(sign_CIFS_PDUs)
+ SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_SIGN;
+ if(ntlmv2_support)
+ SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLMV2;
+ /* setup pointers to domain name and workstation name */
+ bcc_ptr += SecurityBlobLength;
+
+ SecurityBlob->WorkstationName.Buffer = 0;
+ SecurityBlob->WorkstationName.Length = 0;
+ SecurityBlob->WorkstationName.MaximumLength = 0;
+
+ if (domain == NULL) {
+ SecurityBlob->DomainName.Buffer = 0;
+ SecurityBlob->DomainName.Length = 0;
+ SecurityBlob->DomainName.MaximumLength = 0;
+ } else {
+ SecurityBlob->NegotiateFlags |=
+ NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
+ strncpy(bcc_ptr, domain, 63);
+ SecurityBlob->DomainName.Length = strnlen(domain, 64);
+ SecurityBlob->DomainName.MaximumLength =
+ cpu_to_le16(SecurityBlob->DomainName.Length);
+ SecurityBlob->DomainName.Buffer =
+ cpu_to_le32((long) &SecurityBlob->
+ DomainString -
+ (long) &SecurityBlob->Signature);
+ bcc_ptr += SecurityBlob->DomainName.Length;
+ SecurityBlobLength += SecurityBlob->DomainName.Length;
+ SecurityBlob->DomainName.Length =
+ cpu_to_le16(SecurityBlob->DomainName.Length);
+ }
+ if (ses->capabilities & CAP_UNICODE) {
+ if ((long) bcc_ptr % 2) {
+ *bcc_ptr = 0;
+ bcc_ptr++;
+ }
+
+ bytes_returned =
+ cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
+ 32, nls_codepage);
+ bcc_ptr += 2 * bytes_returned;
+ bytes_returned =
+ cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
+ nls_codepage);
+ bcc_ptr += 2 * bytes_returned;
+ bcc_ptr += 2; /* null terminate Linux version */
+ bytes_returned =
+ cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
+ 64, nls_codepage);
+ bcc_ptr += 2 * bytes_returned;
+ *(bcc_ptr + 1) = 0;
+ *(bcc_ptr + 2) = 0;
+ bcc_ptr += 2; /* null terminate network opsys string */
+ *(bcc_ptr + 1) = 0;
+ *(bcc_ptr + 2) = 0;
+ bcc_ptr += 2; /* null domain */
+ } else { /* ASCII */
+ strcpy(bcc_ptr, "Linux version ");
+ bcc_ptr += strlen("Linux version ");
+ strcpy(bcc_ptr, UTS_RELEASE);
+ bcc_ptr += strlen(UTS_RELEASE) + 1;
+ strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
+ bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
+ bcc_ptr++; /* empty domain field */
+ *bcc_ptr = 0;
+ }
+ SecurityBlob->NegotiateFlags =
+ cpu_to_le32(SecurityBlob->NegotiateFlags);
+ pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
+ BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
+ smb_buffer->smb_buf_length += BCC(smb_buffer);
+ BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
+
+ rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
+ &bytes_returned, 1);
+
+ if (smb_buffer_response->Status.CifsError ==
+ (NT_STATUS_MORE_PROCESSING_REQUIRED))
+ rc = 0;
+
+ if (rc) {
+/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
+ } else if ((smb_buffer_response->WordCount == 3)
+ || (smb_buffer_response->WordCount == 4)) {
+ pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action);
+ pSMBr->resp.SecurityBlobLength =
+ le16_to_cpu(pSMBr->resp.SecurityBlobLength);
+ if (pSMBr->resp.Action & GUEST_LOGIN)
+ cFYI(1, (" Guest login"));
+ /* Do we want to set anything in SesInfo struct when guest login? */
+
+ bcc_ptr = pByteArea(smb_buffer_response);
+ /* response can have either 3 or 4 word count - Samba sends 3 */
+
+ SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
+ if (SecurityBlob2->MessageType != NtLmChallenge) {
+ cFYI(1,
+ ("Unexpected NTLMSSP message type received %d",
+ SecurityBlob2->MessageType));
+ } else if (ses) {
+ ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
+ cFYI(1, ("UID = %d ", ses->Suid));
+ if ((pSMBr->resp.hdr.WordCount == 3)
+ || ((pSMBr->resp.hdr.WordCount == 4)
+ && (pSMBr->resp.SecurityBlobLength <
+ pSMBr->resp.ByteCount))) {
+ if (pSMBr->resp.hdr.WordCount == 4) {
+ bcc_ptr +=
+ pSMBr->resp.SecurityBlobLength;
+ cFYI(1,
+ ("Security Blob Length %d ",
+ pSMBr->resp.SecurityBlobLength));
+ }
+
+ cFYI(1, ("NTLMSSP Challenge rcvd "));
+
+ memcpy(ses->server->cryptKey,
+ SecurityBlob2->Challenge,
+ CIFS_CRYPTO_KEY_SIZE);
+ if(SecurityBlob2->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLMV2)
+ *pNTLMv2_flag = TRUE;
+
+ if((SecurityBlob2->NegotiateFlags &
+ NTLMSSP_NEGOTIATE_ALWAYS_SIGN)
+ || (sign_CIFS_PDUs > 1))
+ ses->server->secMode |=
+ SECMODE_SIGN_REQUIRED;
+ if ((SecurityBlob2->NegotiateFlags &
+ NTLMSSP_NEGOTIATE_SIGN) && (sign_CIFS_PDUs))
+ ses->server->secMode |=
+ SECMODE_SIGN_ENABLED;
+
+ if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
+ if ((long) (bcc_ptr) % 2) {
+ remaining_words =
+ (BCC(smb_buffer_response)
+ - 1) / 2;
+ bcc_ptr++; /* Unicode strings must be word aligned */
+ } else {
+ remaining_words =
+ BCC
+ (smb_buffer_response) / 2;
+ }
+ len =
+ UniStrnlen((wchar_t *) bcc_ptr,
+ remaining_words - 1);
+/* We look for obvious messed up bcc or strings in response so we do not go off
+ the end since (at least) WIN2K and Windows XP have a major bug in not null
+ terminating last Unicode string in response */
+ ses->serverOS =
+ cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
+ cifs_strfromUCS_le(ses->serverOS,
+ (wchar_t *)
+ bcc_ptr, len,
+ nls_codepage);
+ bcc_ptr += 2 * (len + 1);
+ remaining_words -= len + 1;
+ ses->serverOS[2 * len] = 0;
+ ses->serverOS[1 + (2 * len)] = 0;
+ if (remaining_words > 0) {
+ len = UniStrnlen((wchar_t *)
+ bcc_ptr,
+ remaining_words
+ - 1);
+ ses->serverNOS =
+ cifs_kcalloc(2 * (len + 1),
+ GFP_KERNEL);
+ cifs_strfromUCS_le(ses->
+ serverNOS,
+ (wchar_t *)
+ bcc_ptr,
+ len,
+ nls_codepage);
+ bcc_ptr += 2 * (len + 1);
+ ses->serverNOS[2 * len] = 0;
+ ses->serverNOS[1 +
+ (2 * len)] = 0;
+ remaining_words -= len + 1;
+ if (remaining_words > 0) {
+ len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
+ /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
+ ses->serverDomain =
+ cifs_kcalloc(2 *
+ (len +
+ 1),
+ GFP_KERNEL);
+ cifs_strfromUCS_le
+ (ses->
+ serverDomain,
+ (wchar_t *)
+ bcc_ptr, len,
+ nls_codepage);
+ bcc_ptr +=
+ 2 * (len + 1);
+ ses->
+ serverDomain[2
+ * len]
+ = 0;
+ ses->
+ serverDomain[1
+ +
+ (2
+ *
+ len)]
+ = 0;
+ } /* else no more room so create dummy domain string */
+ else
+ ses->serverDomain =
+ cifs_kcalloc(2,
+ GFP_KERNEL);
+ } else { /* no room so create dummy domain and NOS string */
+ ses->serverDomain =
+ cifs_kcalloc(2, GFP_KERNEL);
+ ses->serverNOS =
+ cifs_kcalloc(2, GFP_KERNEL);
+ }
+ } else { /* ASCII */
+ len = strnlen(bcc_ptr, 1024);
+ if (((long) bcc_ptr + len) - (long)
+ pByteArea(smb_buffer_response)
+ <= BCC(smb_buffer_response)) {
+ ses->serverOS =
+ cifs_kcalloc(len + 1,
+ GFP_KERNEL);
+ strncpy(ses->serverOS,
+ bcc_ptr, len);
+
+ bcc_ptr += len;
+ bcc_ptr[0] = 0; /* null terminate string */
+ bcc_ptr++;
+
+ len = strnlen(bcc_ptr, 1024);
+ ses->serverNOS =
+ cifs_kcalloc(len + 1,
+ GFP_KERNEL);
+ strncpy(ses->serverNOS, bcc_ptr, len);
+ bcc_ptr += len;
+ bcc_ptr[0] = 0;
+ bcc_ptr++;
+
+ len = strnlen(bcc_ptr, 1024);
+ ses->serverDomain =
+ cifs_kcalloc(len + 1,
+ GFP_KERNEL);
+ strncpy(ses->serverDomain, bcc_ptr, len);
+ bcc_ptr += len;
+ bcc_ptr[0] = 0;
+ bcc_ptr++;
+ } else
+ cFYI(1,
+ ("Variable field of length %d extends beyond end of smb ",
+ len));
+ }
+ } else {
+ cERROR(1,
+ (" Security Blob Length extends beyond end of SMB"));
+ }
+ } else {
+ cERROR(1, ("No session structure passed in."));
+ }
+ } else {
+ cERROR(1,
+ (" Invalid Word count %d: ",
+ smb_buffer_response->WordCount));
+ rc = -EIO;
+ }
+
+ if (smb_buffer)
+ cifs_buf_release(smb_buffer);
+
+ return rc;
+}
+
+static int
+CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
+ char *ntlm_session_key, int ntlmv2_flag,
+ const struct nls_table *nls_codepage)
+{
+ struct smb_hdr *smb_buffer;
+ struct smb_hdr *smb_buffer_response;
+ SESSION_SETUP_ANDX *pSMB;
+ SESSION_SETUP_ANDX *pSMBr;
+ char *bcc_ptr;
+ char *user = ses->userName;
+ char *domain = ses->domainName;
+ int rc = 0;
+ int remaining_words = 0;
+ int bytes_returned = 0;
+ int len;
+ int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
+ PAUTHENTICATE_MESSAGE SecurityBlob;
+
+ cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
+
+ smb_buffer = cifs_buf_get();
+ if (smb_buffer == 0) {
+ return -ENOMEM;
+ }
+ smb_buffer_response = smb_buffer;
+ pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
+ pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
+
+ /* send SMBsessionSetup here */
+ header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
+ NULL /* no tCon exists yet */ , 12 /* wct */ );
+ pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
+ pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
+ pSMB->req.AndXCommand = 0xFF;
+ pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
+ pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
+
+ pSMB->req.hdr.Uid = ses->Suid;
+
+ if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+ smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+
+ pSMB->req.Capabilities =
+ CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
+ CAP_EXTENDED_SECURITY;
+ if (ses->capabilities & CAP_UNICODE) {
+ smb_buffer->Flags2 |= SMBFLG2_UNICODE;
+ pSMB->req.Capabilities |= CAP_UNICODE;
+ }
+ if (ses->capabilities & CAP_STATUS32) {
+ smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
+ pSMB->req.Capabilities |= CAP_STATUS32;
+ }
+ if (ses->capabilities & CAP_DFS) {
+ smb_buffer->Flags2 |= SMBFLG2_DFS;
+ pSMB->req.Capabilities |= CAP_DFS;
+ }
+ pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities);
+
+ bcc_ptr = (char *) &pSMB->req.SecurityBlob;
+ SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
+ strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
+ SecurityBlob->MessageType = NtLmAuthenticate;
+ bcc_ptr += SecurityBlobLength;
+ SecurityBlob->NegotiateFlags =
+ NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
+ NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
+ 0x80000000 | NTLMSSP_NEGOTIATE_128;
+ if(sign_CIFS_PDUs)
+ SecurityBlob->NegotiateFlags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
+ if(ntlmv2_flag)
+ SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLMV2;
+
+/* setup pointers to domain name and workstation name */
+
+ SecurityBlob->WorkstationName.Buffer = 0;
+ SecurityBlob->WorkstationName.Length = 0;
+ SecurityBlob->WorkstationName.MaximumLength = 0;
+ SecurityBlob->SessionKey.Length = 0;
+ SecurityBlob->SessionKey.MaximumLength = 0;
+ SecurityBlob->SessionKey.Buffer = 0;
+
+ SecurityBlob->LmChallengeResponse.Length = 0;
+ SecurityBlob->LmChallengeResponse.MaximumLength = 0;
+ SecurityBlob->LmChallengeResponse.Buffer = 0;
+
+ SecurityBlob->NtChallengeResponse.Length =
+ cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+ SecurityBlob->NtChallengeResponse.MaximumLength =
+ cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+ memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
+ SecurityBlob->NtChallengeResponse.Buffer =
+ cpu_to_le32(SecurityBlobLength);
+ SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
+ bcc_ptr += CIFS_SESSION_KEY_SIZE;
+
+ if (ses->capabilities & CAP_UNICODE) {
+ if (domain == NULL) {
+ SecurityBlob->DomainName.Buffer = 0;
+ SecurityBlob->DomainName.Length = 0;
+ SecurityBlob->DomainName.MaximumLength = 0;
+ } else {
+ SecurityBlob->DomainName.Length =
+ cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
+ nls_codepage);
+ SecurityBlob->DomainName.Length *= 2;
+ SecurityBlob->DomainName.MaximumLength =
+ cpu_to_le16(SecurityBlob->DomainName.Length);
+ SecurityBlob->DomainName.Buffer =
+ cpu_to_le32(SecurityBlobLength);
+ bcc_ptr += SecurityBlob->DomainName.Length;
+ SecurityBlobLength += SecurityBlob->DomainName.Length;
+ SecurityBlob->DomainName.Length =
+ cpu_to_le16(SecurityBlob->DomainName.Length);
+ }
+ if (user == NULL) {
+ SecurityBlob->UserName.Buffer = 0;
+ SecurityBlob->UserName.Length = 0;
+ SecurityBlob->UserName.MaximumLength = 0;
+ } else {
+ SecurityBlob->UserName.Length =
+ cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64,
+ nls_codepage);
+ SecurityBlob->UserName.Length *= 2;
+ SecurityBlob->UserName.MaximumLength =
+ cpu_to_le16(SecurityBlob->UserName.Length);
+ SecurityBlob->UserName.Buffer =
+ cpu_to_le32(SecurityBlobLength);
+ bcc_ptr += SecurityBlob->UserName.Length;
+ SecurityBlobLength += SecurityBlob->UserName.Length;
+ SecurityBlob->UserName.Length =
+ cpu_to_le16(SecurityBlob->UserName.Length);
+ }
+
+ /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage);
+ SecurityBlob->WorkstationName.Length *= 2;
+ SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
+ SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
+ bcc_ptr += SecurityBlob->WorkstationName.Length;
+ SecurityBlobLength += SecurityBlob->WorkstationName.Length;
+ SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */
+
+ if ((long) bcc_ptr % 2) {
+ *bcc_ptr = 0;
+ bcc_ptr++;
+ }
+ bytes_returned =
+ cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
+ 32, nls_codepage);
+ bcc_ptr += 2 * bytes_returned;
+ bytes_returned =
+ cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
+ nls_codepage);
+ bcc_ptr += 2 * bytes_returned;
+ bcc_ptr += 2; /* null term version string */
+ bytes_returned =
+ cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
+ 64, nls_codepage);
+ bcc_ptr += 2 * bytes_returned;
+ *(bcc_ptr + 1) = 0;
+ *(bcc_ptr + 2) = 0;
+ bcc_ptr += 2; /* null terminate network opsys string */
+ *(bcc_ptr + 1) = 0;
+ *(bcc_ptr + 2) = 0;
+ bcc_ptr += 2; /* null domain */
+ } else { /* ASCII */
+ if (domain == NULL) {
+ SecurityBlob->DomainName.Buffer = 0;
+ SecurityBlob->DomainName.Length = 0;
+ SecurityBlob->DomainName.MaximumLength = 0;
+ } else {
+ SecurityBlob->NegotiateFlags |=
+ NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
+ strncpy(bcc_ptr, domain, 63);
+ SecurityBlob->DomainName.Length = strnlen(domain, 64);
+ SecurityBlob->DomainName.MaximumLength =
+ cpu_to_le16(SecurityBlob->DomainName.Length);
+ SecurityBlob->DomainName.Buffer =
+ cpu_to_le32(SecurityBlobLength);
+ bcc_ptr += SecurityBlob->DomainName.Length;
+ SecurityBlobLength += SecurityBlob->DomainName.Length;
+ SecurityBlob->DomainName.Length =
+ cpu_to_le16(SecurityBlob->DomainName.Length);
+ }
+ if (user == NULL) {
+ SecurityBlob->UserName.Buffer = 0;
+ SecurityBlob->UserName.Length = 0;
+ SecurityBlob->UserName.MaximumLength = 0;
+ } else {
+ strncpy(bcc_ptr, user, 63);
+ SecurityBlob->UserName.Length = strnlen(user, 64);
+ SecurityBlob->UserName.MaximumLength =
+ cpu_to_le16(SecurityBlob->UserName.Length);
+ SecurityBlob->UserName.Buffer =
+ cpu_to_le32(SecurityBlobLength);
+ bcc_ptr += SecurityBlob->UserName.Length;
+ SecurityBlobLength += SecurityBlob->UserName.Length;
+ SecurityBlob->UserName.Length =
+ cpu_to_le16(SecurityBlob->UserName.Length);
+ }
+ /* BB fill in our workstation name if known BB */
+
+ strcpy(bcc_ptr, "Linux version ");
+ bcc_ptr += strlen("Linux version ");
+ strcpy(bcc_ptr, UTS_RELEASE);
+ bcc_ptr += strlen(UTS_RELEASE) + 1;
+ strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
+ bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
+ bcc_ptr++; /* null domain */
+ *bcc_ptr = 0;
+ }
+ SecurityBlob->NegotiateFlags =
+ cpu_to_le32(SecurityBlob->NegotiateFlags);
+ pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
+ BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
+ smb_buffer->smb_buf_length += BCC(smb_buffer);
+ BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
+
+ rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
+ &bytes_returned, 1);
+ if (rc) {
+/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
+ } else if ((smb_buffer_response->WordCount == 3)
+ || (smb_buffer_response->WordCount == 4)) {
+ pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action);
+ pSMBr->resp.SecurityBlobLength =
+ le16_to_cpu(pSMBr->resp.SecurityBlobLength);
+ if (pSMBr->resp.Action & GUEST_LOGIN)
+ cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
+/* if(SecurityBlob2->MessageType != NtLm??){
+ cFYI("Unexpected message type on auth response is %d "));
+ } */
+ if (ses) {
+ cFYI(1,
+ ("Does UID on challenge %d match auth response UID %d ",
+ ses->Suid, smb_buffer_response->Uid));
+ ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
+ bcc_ptr = pByteArea(smb_buffer_response);
+ /* response can have either 3 or 4 word count - Samba sends 3 */
+ if ((pSMBr->resp.hdr.WordCount == 3)
+ || ((pSMBr->resp.hdr.WordCount == 4)
+ && (pSMBr->resp.SecurityBlobLength <
+ pSMBr->resp.ByteCount))) {
+ if (pSMBr->resp.hdr.WordCount == 4) {
+ bcc_ptr +=
+ pSMBr->resp.SecurityBlobLength;
+ cFYI(1,
+ ("Security Blob Length %d ",
+ pSMBr->resp.SecurityBlobLength));
+ }
+
+ cFYI(1,
+ ("NTLMSSP response to Authenticate "));
+
+ if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
+ if ((long) (bcc_ptr) % 2) {
+ remaining_words =
+ (BCC(smb_buffer_response)
+ - 1) / 2;
+ bcc_ptr++; /* Unicode strings must be word aligned */
+ } else {
+ remaining_words = BCC(smb_buffer_response) / 2;
+ }
+ len =
+ UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
+/* We look for obvious messed up bcc or strings in response so we do not go off
+ the end since (at least) WIN2K and Windows XP have a major bug in not null
+ terminating last Unicode string in response */
+ ses->serverOS =
+ cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
+ cifs_strfromUCS_le(ses->serverOS,
+ (wchar_t *)
+ bcc_ptr, len,
+ nls_codepage);
+ bcc_ptr += 2 * (len + 1);
+ remaining_words -= len + 1;
+ ses->serverOS[2 * len] = 0;
+ ses->serverOS[1 + (2 * len)] = 0;
+ if (remaining_words > 0) {
+ len = UniStrnlen((wchar_t *)
+ bcc_ptr,
+ remaining_words
+ - 1);
+ ses->serverNOS =
+ cifs_kcalloc(2 * (len + 1),
+ GFP_KERNEL);
+ cifs_strfromUCS_le(ses->
+ serverNOS,
+ (wchar_t *)
+ bcc_ptr,
+ len,
+ nls_codepage);
+ bcc_ptr += 2 * (len + 1);
+ ses->serverNOS[2 * len] = 0;
+ ses->serverNOS[1+(2*len)] = 0;
+ remaining_words -= len + 1;
+ if (remaining_words > 0) {
+ len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
+ /* last string not always null terminated (e.g. for Windows XP & 2000) */
+ ses->serverDomain =
+ cifs_kcalloc(2 *
+ (len +
+ 1),
+ GFP_KERNEL);
+ cifs_strfromUCS_le
+ (ses->
+ serverDomain,
+ (wchar_t *)
+ bcc_ptr, len,
+ nls_codepage);
+ bcc_ptr +=
+ 2 * (len + 1);
+ ses->
+ serverDomain[2
+ * len]
+ = 0;
+ ses->
+ serverDomain[1
+ +
+ (2
+ *
+ len)]
+ = 0;
+ } /* else no more room so create dummy domain string */
+ else
+ ses->serverDomain = cifs_kcalloc(2,GFP_KERNEL);
+ } else { /* no room so create dummy domain and NOS string */
+ ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL);
+ ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL);
+ }
+ } else { /* ASCII */
+ len = strnlen(bcc_ptr, 1024);
+ if (((long) bcc_ptr + len) -
+ (long) pByteArea(smb_buffer_response)
+ <= BCC(smb_buffer_response)) {
+ ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL);
+ strncpy(ses->serverOS,bcc_ptr, len);
+
+ bcc_ptr += len;
+ bcc_ptr[0] = 0; /* null terminate the string */
+ bcc_ptr++;
+
+ len = strnlen(bcc_ptr, 1024);
+ ses->serverNOS = cifs_kcalloc(len+1,GFP_KERNEL);
+ strncpy(ses->serverNOS, bcc_ptr, len);
+ bcc_ptr += len;
+ bcc_ptr[0] = 0;
+ bcc_ptr++;
+
+ len = strnlen(bcc_ptr, 1024);
+ ses->serverDomain = cifs_kcalloc(len+1,GFP_KERNEL);
+ strncpy(ses->serverDomain, bcc_ptr, len);
+ bcc_ptr += len;
+ bcc_ptr[0] = 0;
+ bcc_ptr++;
+ } else
+ cFYI(1,
+ ("Variable field of length %d extends beyond end of smb ",
+ len));
+ }
+ } else {
+ cERROR(1,
+ (" Security Blob Length extends beyond end of SMB"));
+ }
+ } else {
+ cERROR(1, ("No session structure passed in."));
+ }
+ } else {
+ cERROR(1,
+ (" Invalid Word count %d: ",
+ smb_buffer_response->WordCount));
+ rc = -EIO;
+ }
+
+ if (smb_buffer)
+ cifs_buf_release(smb_buffer);
+
+ return rc;
+}
+
+int
+CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
+ const char *tree, struct cifsTconInfo *tcon,
+ const struct nls_table *nls_codepage)
+{
+ struct smb_hdr *smb_buffer;
+ struct smb_hdr *smb_buffer_response;
+ TCONX_REQ *pSMB;
+ TCONX_RSP *pSMBr;
+ char *bcc_ptr;
+ int rc = 0;
+ int length;
+
+ if (ses == NULL)
+ return -EIO;
+
+ smb_buffer = cifs_buf_get();
+ if (smb_buffer == 0) {
+ return -ENOMEM;
+ }
+ smb_buffer_response = smb_buffer;
+
+ header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
+ NULL /*no tid */ , 4 /*wct */ );
+ smb_buffer->Uid = ses->Suid;
+ pSMB = (TCONX_REQ *) smb_buffer;
+ pSMBr = (TCONX_RSP *) smb_buffer_response;
+
+ pSMB->AndXCommand = 0xFF;
+ pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
+ pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
+ bcc_ptr = &(pSMB->Password[0]);
+ bcc_ptr++; /* skip password */
+
+ if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+ smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+
+ if (ses->capabilities & CAP_STATUS32) {
+ smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
+ }
+ if (ses->capabilities & CAP_DFS) {
+ smb_buffer->Flags2 |= SMBFLG2_DFS;
+ }
+ if (ses->capabilities & CAP_UNICODE) {
+ smb_buffer->Flags2 |= SMBFLG2_UNICODE;
+ length =
+ cifs_strtoUCS((wchar_t *) bcc_ptr, tree, 100, nls_codepage);
+ bcc_ptr += 2 * length; /* convert num of 16 bit words to bytes */
+ bcc_ptr += 2; /* skip trailing null */
+ } else { /* ASCII */
+
+ strcpy(bcc_ptr, tree);
+ bcc_ptr += strlen(tree) + 1;
+ }
+ strcpy(bcc_ptr, "?????");
+ bcc_ptr += strlen("?????");
+ bcc_ptr += 1;
+ BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
+ smb_buffer->smb_buf_length += BCC(smb_buffer);
+ BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
+
+ rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
+
+ /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
+ /* above now done in SendReceive */
+ if ((rc == 0) && (tcon != NULL)) {
+ tcon->tidStatus = CifsGood;
+ tcon->tid = smb_buffer_response->Tid;
+ bcc_ptr = pByteArea(smb_buffer_response);
+ length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
+ /* skip service field (NB: this field is always ASCII) */
+ bcc_ptr += length + 1;
+ strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
+ if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
+ length = UniStrnlen((wchar_t *) bcc_ptr, 512);
+ if (((long) bcc_ptr + (2 * length)) -
+ (long) pByteArea(smb_buffer_response) <=
+ BCC(smb_buffer_response)) {
+ if(tcon->nativeFileSystem)
+ kfree(tcon->nativeFileSystem);
+ tcon->nativeFileSystem =
+ cifs_kcalloc(length + 2, GFP_KERNEL);
+ cifs_strfromUCS_le(tcon->nativeFileSystem,
+ (wchar_t *) bcc_ptr,
+ length, nls_codepage);
+ bcc_ptr += 2 * length;
+ bcc_ptr[0] = 0; /* null terminate the string */
+ bcc_ptr[1] = 0;
+ bcc_ptr += 2;
+ }
+ /* else do not bother copying these informational fields */
+ } else {
+ length = strnlen(bcc_ptr, 1024);
+ if (((long) bcc_ptr + length) -
+ (long) pByteArea(smb_buffer_response) <=
+ BCC(smb_buffer_response)) {
+ if(tcon->nativeFileSystem)
+ kfree(tcon->nativeFileSystem);
+ tcon->nativeFileSystem =
+ cifs_kcalloc(length + 1, GFP_KERNEL);
+ strncpy(tcon->nativeFileSystem, bcc_ptr,
+ length);
+ }
+ /* else do not bother copying these informational fields */
+ }
+ tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
+ cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
+ } else if ((rc == 0) && tcon == NULL) {
+ /* all we need to save for IPC$ connection */
+ ses->ipc_tid = smb_buffer_response->Tid;
+ }
+
+ if (smb_buffer)
+ cifs_buf_release(smb_buffer);
+ return rc;
+}
+
+int
+cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
+{
+ int rc = 0;
+ int xid;
+ struct cifsSesInfo *ses = NULL;
+ struct task_struct *cifsd_task;
+
+ xid = GetXid();
+
+ if (cifs_sb->tcon) {
+ ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
+ rc = CIFSSMBTDis(xid, cifs_sb->tcon);
+ if (rc == -EBUSY) {
+ FreeXid(xid);
+ return 0;
+ }
+ tconInfoFree(cifs_sb->tcon);
+ if ((ses) && (ses->server)) {
+ /* save off task so we do not refer to ses later */
+ cifsd_task = ses->server->tsk;
+ cFYI(1, ("About to do SMBLogoff "));
+ rc = CIFSSMBLogoff(xid, ses);
+ if (rc == -EBUSY) {
+ FreeXid(xid);
+ return 0;
+ } else if (rc == -ESHUTDOWN) {
+ cFYI(1,("Waking up socket by sending it signal"));
+ send_sig(SIGKILL,cifsd_task,1);
+ rc = 0;
+ } /* else - we have an smb session
+ left on this socket do not kill cifsd */
+ } else
+ cFYI(1, ("No session or bad tcon"));
+ }
+
+ cifs_sb->tcon = NULL;
+ if (ses) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(HZ / 2);
+ }
+ if (ses)
+ sesInfoFree(ses);
+
+ FreeXid(xid);
+ return rc; /* BB check if we should always return zero here */
+}
+
+int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
+ struct nls_table * nls_info)
+{
+ int rc = 0;
+ char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
+ int ntlmv2_flag = FALSE;
+
+ /* what if server changes its buffer size after dropping the session? */
+ if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
+ rc = CIFSSMBNegotiate(xid, pSesInfo);
+ if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
+ rc = CIFSSMBNegotiate(xid, pSesInfo);
+ if(rc == -EAGAIN)
+ rc = -EHOSTDOWN;
+ }
+ if(rc == 0) {
+ spin_lock(&GlobalMid_Lock);
+ if(pSesInfo->server->tcpStatus != CifsExiting)
+ pSesInfo->server->tcpStatus = CifsGood;
+ else
+ rc = -EHOSTDOWN;
+ spin_unlock(&GlobalMid_Lock);
+
+ }
+ }
+ if (!rc) {
+ pSesInfo->capabilities = pSesInfo->server->capabilities;
+ if(linuxExtEnabled == 0)
+ pSesInfo->capabilities &= (~CAP_UNIX);
+ pSesInfo->sequence_number = 0;
+ cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
+ pSesInfo->server->secMode,
+ pSesInfo->server->capabilities,
+ pSesInfo->server->timeZone));
+ if (extended_security
+ && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
+ && (pSesInfo->server->secType == NTLMSSP)) {
+ cFYI(1, ("New style sesssetup "));
+ rc = CIFSSpnegoSessSetup(xid, pSesInfo,
+ NULL /* security blob */,
+ 0 /* blob length */,
+ nls_info);
+ } else if (extended_security
+ && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
+ && (pSesInfo->server->secType == RawNTLMSSP)) {
+ cFYI(1, ("NTLMSSP sesssetup "));
+ rc = CIFSNTLMSSPNegotiateSessSetup(xid,
+ pSesInfo,
+ &ntlmv2_flag,
+ nls_info);
+ if (!rc) {
+ if(ntlmv2_flag) {
+ char * v2_response;
+ cFYI(1,("Can use more secure NTLM version 2 password hash"));
+ CalcNTLMv2_partial_mac_key(pSesInfo,
+ nls_info);
+ v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
+ if(v2_response) {
+ CalcNTLMv2_response(pSesInfo,v2_response);
+/* cifs_calculate_ntlmv2_mac_key(pSesInfo->mac_signing_key, response, ntlm_session_key, */
+ kfree(v2_response);
+ /* BB Put dummy sig in SessSetup PDU? */
+ } else
+ rc = -ENOMEM;
+
+ } else {
+ SMBNTencrypt(pSesInfo->password,
+ pSesInfo->server->cryptKey,
+ ntlm_session_key);
+
+ cifs_calculate_mac_key(pSesInfo->mac_signing_key,
+ ntlm_session_key,
+ pSesInfo->password);
+ }
+ /* for better security the weaker lanman hash not sent
+ in AuthSessSetup so we no longer calculate it */
+
+ rc = CIFSNTLMSSPAuthSessSetup(xid,
+ pSesInfo,
+ ntlm_session_key,
+ ntlmv2_flag,
+ nls_info);
+ }
+ } else { /* old style NTLM 0.12 session setup */
+ SMBNTencrypt(pSesInfo->password,
+ pSesInfo->server->cryptKey,
+ ntlm_session_key);
+
+ cifs_calculate_mac_key(pSesInfo->mac_signing_key,
+ ntlm_session_key, pSesInfo->password);
+ rc = CIFSSessSetup(xid, pSesInfo,
+ ntlm_session_key, nls_info);
+ }
+ if (rc) {
+ cERROR(1,("Send error in SessSetup = %d",rc));
+ } else {
+ cFYI(1,("CIFS Session Established successfully"));
+ pSesInfo->status = CifsGood;
+ }
+ }
+ return rc;
+}
+
diff --git a/release/src/linux/linux/fs/cifs/dir.c b/release/src/linux/linux/fs/cifs/dir.c
new file mode 100644
index 00000000..123b0a6d
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/dir.c
@@ -0,0 +1,425 @@
+/*
+ * fs/cifs/dir.c
+ *
+ * vfs operations that deal with dentries
+ *
+ * Copyright (C) International Business Machines Corp., 2002,2003
+ * Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/slab.h>
+#include "cifsfs.h"
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_debug.h"
+#include "cifs_fs_sb.h"
+
+void
+renew_parental_timestamps(struct dentry *direntry)
+{
+ /* BB check if there is a way to get the kernel to do this or if we really need this */
+ do {
+ direntry->d_time = jiffies;
+ direntry = direntry->d_parent;
+ } while (!IS_ROOT(direntry));
+}
+
+/* Note: caller must free return buffer */
+char *
+build_path_from_dentry(struct dentry *direntry)
+{
+ struct dentry *temp;
+ int namelen = 0;
+ char *full_path;
+
+ if(direntry == NULL)
+ return NULL; /* not much we can do if dentry is freed and
+ we need to reopen the file after it was closed implicitly
+ when the server crashed */
+
+cifs_bp_rename_retry:
+ for (temp = direntry; !IS_ROOT(temp);) {
+ namelen += (1 + temp->d_name.len);
+ temp = temp->d_parent;
+ if(temp == NULL) {
+ cERROR(1,("corrupt dentry"));
+ return NULL;
+ }
+ }
+
+ full_path = kmalloc(namelen+1, GFP_KERNEL);
+ if(full_path == NULL)
+ return full_path;
+ full_path[namelen] = 0; /* trailing null */
+
+ for (temp = direntry; !IS_ROOT(temp);) {
+ namelen -= 1 + temp->d_name.len;
+ if (namelen < 0) {
+ break;
+ } else {
+ full_path[namelen] = '\\';
+ strncpy(full_path + namelen + 1, temp->d_name.name,
+ temp->d_name.len);
+ cFYI(0, (" name: %s ", full_path + namelen));
+ }
+ temp = temp->d_parent;
+ if(temp == NULL) {
+ cERROR(1,("corrupt dentry"));
+ kfree(full_path);
+ return NULL;
+ }
+ }
+ if (namelen != 0) {
+ cERROR(1,
+ ("We did not end path lookup where we expected namelen is %d",
+ namelen));
+ /* presumably this is only possible if we were racing with a rename
+ of one of the parent directories (we can not lock the dentries
+ above us to prevent this, but retrying should be harmless) */
+ kfree(full_path);
+ namelen = 0;
+ goto cifs_bp_rename_retry;
+ }
+
+ return full_path;
+}
+
+/* Note: caller must free return buffer */
+char *
+build_wildcard_path_from_dentry(struct dentry *direntry)
+{
+ struct dentry *temp;
+ int namelen = 0;
+ char *full_path;
+
+ if(direntry == NULL)
+ return NULL; /* not much we can do if dentry is freed and
+ we need to reopen the file after it was closed implicitly
+ when the server crashed */
+
+cifs_bwp_rename_retry:
+ for (temp = direntry; !IS_ROOT(temp);) {
+ namelen += (1 + temp->d_name.len);
+ temp = temp->d_parent;
+ if(temp == NULL) {
+ cERROR(1,("corrupt dentry"));
+ return NULL;
+ }
+ }
+
+ full_path = kmalloc(namelen+3, GFP_KERNEL);
+ if(full_path == NULL)
+ return full_path;
+
+ full_path[namelen] = '\\';
+ full_path[namelen+1] = '*';
+ full_path[namelen+2] = 0; /* trailing null */
+
+ for (temp = direntry; !IS_ROOT(temp);) {
+ namelen -= 1 + temp->d_name.len;
+ if (namelen < 0) {
+ break;
+ } else {
+ full_path[namelen] = '\\';
+ strncpy(full_path + namelen + 1, temp->d_name.name,
+ temp->d_name.len);
+ cFYI(0, (" name: %s ", full_path + namelen));
+ }
+ temp = temp->d_parent;
+ if(temp == NULL) {
+ cERROR(1,("corrupt dentry"));
+ kfree(full_path);
+ return NULL;
+ }
+ }
+ if (namelen != 0) {
+ cERROR(1,
+ ("We did not end path lookup where we expected namelen is %d",
+ namelen));
+ /* presumably this is only possible if we were racing with a rename
+ of one of the parent directories (we can not lock the dentries
+ above us to prevent this, but retrying should be harmless) */
+ kfree(full_path);
+ namelen = 0;
+ goto cifs_bwp_rename_retry;
+ }
+
+ return full_path;
+}
+
+/* Inode operations in similar order to how they appear in the Linux file fs.h */
+
+int
+cifs_create(struct inode *inode, struct dentry *direntry, int mode)
+{
+ int rc = -ENOENT;
+ int xid;
+ int oplock = 0; /* no sense requested oplock if we are just going to
+ immediately close the file */
+ __u16 fileHandle;
+ struct cifs_sb_info *cifs_sb;
+ struct cifsTconInfo *pTcon;
+ char *full_path = NULL;
+ FILE_ALL_INFO * buf = NULL;
+ struct inode *newinode = NULL;
+
+ xid = GetXid();
+
+ cifs_sb = CIFS_SB(inode->i_sb);
+ pTcon = cifs_sb->tcon;
+
+ down(&direntry->d_sb->s_vfs_rename_sem);
+ full_path = build_path_from_dentry(direntry);
+ up(&direntry->d_sb->s_vfs_rename_sem);
+ if(full_path == NULL) {
+ FreeXid(xid);
+ return -ENOMEM;
+ }
+
+ /* BB add processing to set equivalent of mode - e.g. via CreateX with ACLs */
+
+ buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
+ rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OVERWRITE_IF,
+ GENERIC_WRITE, CREATE_NOT_DIR,
+ &fileHandle, &oplock, buf, cifs_sb->local_nls);
+ if (rc) {
+ cFYI(1, ("cifs_create returned 0x%x ", rc));
+ } else {
+ /* BB for case of overwriting existing file can we use the inode that was
+ passed in rather than creating new one?? */
+ if (pTcon->ses->capabilities & CAP_UNIX)
+ rc = cifs_get_inode_info_unix(&newinode, full_path,
+ inode->i_sb,xid);
+ else
+ rc = cifs_get_inode_info(&newinode, full_path,
+ buf, inode->i_sb,xid);
+
+ if (rc != 0) {
+ cFYI(1,("Create worked but get_inode_info failed with rc = %d",
+ rc));
+ } else {
+ direntry->d_op = &cifs_dentry_ops;
+ d_instantiate(direntry, newinode);
+ }
+ CIFSSMBClose(xid, pTcon, fileHandle);
+
+ if(newinode) {
+ newinode->i_mode = mode;
+ if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
+ CIFSSMBUnixSetPerms(xid, pTcon, full_path, inode->i_mode,
+ (__u64)-1,
+ (__u64)-1,
+ 0 /* dev */,
+ cifs_sb->local_nls);
+ else { /* BB implement via Windows security descriptors */
+ /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/
+ /* in the meantime could set r/o dos attribute when perms are eg:
+ mode & 0222 == 0 */
+ }
+ }
+ }
+
+ if (buf)
+ kfree(buf);
+ if (full_path)
+ kfree(full_path);
+ FreeXid(xid);
+
+ return rc;
+}
+
+int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, int device_number)
+{
+ int rc = -EPERM;
+ int xid;
+ struct cifs_sb_info *cifs_sb;
+ struct cifsTconInfo *pTcon;
+ char *full_path = NULL;
+ struct inode * newinode = NULL;
+
+ xid = GetXid();
+
+ cifs_sb = CIFS_SB(inode->i_sb);
+ pTcon = cifs_sb->tcon;
+
+ down(&direntry->d_sb->s_vfs_rename_sem);
+ full_path = build_path_from_dentry(direntry);
+ up(&direntry->d_sb->s_vfs_rename_sem);
+ if(full_path == NULL)
+ rc = -ENOMEM;
+
+ if (full_path && (pTcon->ses->capabilities & CAP_UNIX)) {
+ rc = CIFSSMBUnixSetPerms(xid, pTcon,
+ full_path, mode, current->euid, current->egid,
+ device_number, cifs_sb->local_nls);
+ if(!rc) {
+ rc = cifs_get_inode_info_unix(&newinode, full_path,
+ inode->i_sb,xid);
+ direntry->d_op = &cifs_dentry_ops;
+ if(rc == 0)
+ d_instantiate(direntry, newinode);
+ }
+ }
+
+ if (full_path)
+ kfree(full_path);
+ FreeXid(xid);
+
+ return rc;
+}
+
+
+struct dentry *
+cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry)
+{
+ int xid;
+ int rc = 0; /* to get around spurious gcc warning, set to zero here */
+ struct cifs_sb_info *cifs_sb;
+ struct cifsTconInfo *pTcon;
+ struct inode *newInode = NULL;
+ char *full_path = NULL;
+
+ xid = GetXid();
+
+ cFYI(1,
+ (" parent inode = 0x%p name is: %s and dentry = 0x%p",
+ parent_dir_inode, direntry->d_name.name, direntry));
+
+ /* BB Add check of incoming data - e.g. frame not longer than maximum SMB - let server check the namelen BB */
+
+ /* check whether path exists */
+
+ cifs_sb = CIFS_SB(parent_dir_inode->i_sb);
+ pTcon = cifs_sb->tcon;
+
+ /* can not grab the rename sem here since it would
+ deadlock in the cases (beginning of sys_rename itself)
+ in which we already have the sb rename sem */
+ full_path = build_path_from_dentry(direntry);
+ if(full_path == NULL) {
+ FreeXid(xid);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ if (direntry->d_inode != NULL) {
+ cFYI(1, (" non-NULL inode in lookup"));
+ } else {
+ cFYI(1, (" NULL inode in lookup"));
+ }
+ cFYI(1,
+ (" Full path: %s inode = 0x%p", full_path, direntry->d_inode));
+
+ if (pTcon->ses->capabilities & CAP_UNIX)
+ rc = cifs_get_inode_info_unix(&newInode, full_path,
+ parent_dir_inode->i_sb,xid);
+ else
+ rc = cifs_get_inode_info(&newInode, full_path, NULL,
+ parent_dir_inode->i_sb,xid);
+
+ if ((rc == 0) && (newInode != NULL)) {
+ direntry->d_op = &cifs_dentry_ops;
+ d_add(direntry, newInode);
+
+ /* since paths are not looked up by component - the parent directories are presumed to be good here */
+ renew_parental_timestamps(direntry);
+
+ } else if (rc == -ENOENT) {
+ rc = 0;
+ d_add(direntry, NULL);
+ } else {
+ cERROR(1,("Error 0x%x or on cifs_get_inode_info in lookup",rc));
+ /* BB special case check for Access Denied - watch security
+ exposure of returning dir info implicitly via different rc
+ if file exists or not but no access BB */
+ }
+
+ if (full_path)
+ kfree(full_path);
+ FreeXid(xid);
+ return ERR_PTR(rc);
+}
+
+int
+cifs_dir_open(struct inode *inode, struct file *file)
+{ /* NB: currently unused since searches are opened in readdir */
+ int rc = 0;
+ int xid;
+ struct cifs_sb_info *cifs_sb;
+ struct cifsTconInfo *pTcon;
+ char *full_path = NULL;
+
+ xid = GetXid();
+
+ cifs_sb = CIFS_SB(inode->i_sb);
+ pTcon = cifs_sb->tcon;
+
+ if(file->f_dentry) {
+ down(&file->f_dentry->d_sb->s_vfs_rename_sem);
+ full_path = build_wildcard_path_from_dentry(file->f_dentry);
+ up(&file->f_dentry->d_sb->s_vfs_rename_sem);
+ } else {
+ FreeXid(xid);
+ return -EIO;
+ }
+
+ cFYI(1, ("inode = 0x%p and full path is %s", inode, full_path));
+
+ if (full_path)
+ kfree(full_path);
+ FreeXid(xid);
+ return rc;
+}
+
+static int
+cifs_d_revalidate(struct dentry *direntry, int flags)
+{
+ int isValid = 1;
+
+/* lock_kernel(); *//* surely we do not want to lock the kernel for a whole network round trip which could take seconds */
+
+ if (direntry->d_inode) {
+ if (cifs_revalidate(direntry)) {
+ /* unlock_kernel(); */
+ return 0;
+ }
+ } else {
+ cFYI(1,
+ ("In cifs_d_revalidate with no inode but name = %s and dentry 0x%p",
+ direntry->d_name.name, direntry));
+ }
+
+/* unlock_kernel(); */
+
+ return isValid;
+}
+
+/* static int cifs_d_delete(struct dentry *direntry)
+{
+ int rc = 0;
+
+ cFYI(1, ("In cifs d_delete, name = %s", direntry->d_name.name));
+
+ return rc;
+} */
+
+struct dentry_operations cifs_dentry_ops = {
+ .d_revalidate = cifs_d_revalidate,
+/* d_delete: cifs_d_delete, *//* not needed except for debugging */
+ /* no need for d_hash, d_compare, d_release, d_iput ... yet. BB confirm this BB */
+};
diff --git a/release/src/linux/linux/fs/cifs/file.c b/release/src/linux/linux/fs/cifs/file.c
new file mode 100644
index 00000000..d7f3bac6
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/file.c
@@ -0,0 +1,2185 @@
+/*
+ * fs/cifs/file.c
+ *
+ * vfs operations that deal with files
+ *
+ * Copyright (C) International Business Machines Corp., 2002,2003
+ * Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/fcntl.h>
+#include <linux/version.h>
+#include <linux/pagemap.h>
+#include <linux/smp_lock.h>
+#include <linux/list.h>
+#include <asm/div64.h>
+#include <linux/mm.h>
+#include <linux/types.h>
+#include "cifsfs.h"
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_unicode.h"
+#include "cifs_debug.h"
+#include "cifs_fs_sb.h"
+
+int
+cifs_open(struct inode *inode, struct file *file)
+{
+ int rc = -EACCES;
+ int xid, oplock;
+ struct cifs_sb_info *cifs_sb;
+ struct cifsTconInfo *pTcon;
+ struct cifsFileInfo *pCifsFile;
+ struct cifsInodeInfo *pCifsInode;
+ char *full_path = NULL;
+ int desiredAccess = 0x20197;
+ int disposition;
+ __u16 netfid;
+ FILE_ALL_INFO * buf = NULL;
+ time_t temp;
+
+ xid = GetXid();
+
+ cifs_sb = CIFS_SB(inode->i_sb);
+ pTcon = cifs_sb->tcon;
+
+ down(&inode->i_sb->s_vfs_rename_sem);
+ full_path = build_path_from_dentry(file->f_dentry);
+ up(&inode->i_sb->s_vfs_rename_sem);
+ if(full_path == NULL) {
+ FreeXid(xid);
+ return -ENOMEM;
+ }
+
+ cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", inode, file->f_flags,full_path));
+ if ((file->f_flags & O_ACCMODE) == O_RDONLY)
+ desiredAccess = GENERIC_READ;
+ else if ((file->f_flags & O_ACCMODE) == O_WRONLY)
+ desiredAccess = GENERIC_WRITE;
+ else if ((file->f_flags & O_ACCMODE) == O_RDWR) {
+ /* GENERIC_ALL is too much permission to request */
+ /* can cause unnecessary access denied on create */
+ /* desiredAccess = GENERIC_ALL; */
+ desiredAccess = GENERIC_READ | GENERIC_WRITE;
+ }
+
+/*********************************************************************
+ * open flag mapping table:
+ *
+ * POSIX Flag CIFS Disposition
+ * ---------- ----------------
+ * O_CREAT FILE_OPEN_IF
+ * O_CREAT | O_EXCL FILE_CREATE
+ * O_CREAT | O_TRUNC FILE_OVERWRITE_IF
+ * O_TRUNC FILE_OVERWRITE
+ * none of the above FILE_OPEN
+ *
+ * Note that there is not a direct match between disposition
+ * FILE_SUPERSEDE (ie create whether or not file exists although
+ * O_CREAT | O_TRUNC is similar but truncates the existing
+ * file rather than creating a new file as FILE_SUPERSEDE does
+ * (which uses the attributes / metadata passed in on open call)
+ *?
+ *? O_SYNC is a reasonable match to CIFS writethrough flag
+ *? and the read write flags match reasonably. O_LARGEFILE
+ *? is irrelevant because largefile support is always used
+ *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
+ * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
+ *********************************************************************/
+
+ /* For 2.4 case, file was already checked for existence
+ before create by vfs lookup and created in create
+ entry point, we are now just opening the newly
+ created file with the right desiredAccess flags */
+
+ if((file->f_flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
+ disposition = FILE_OPEN_IF;
+ else if((file->f_flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
+ disposition = FILE_OVERWRITE_IF;
+ else if((file->f_flags & O_CREAT) == O_CREAT)
+ disposition = FILE_OPEN_IF;
+ else
+ disposition = FILE_OPEN;
+
+ if (oplockEnabled)
+ oplock = REQ_OPLOCK;
+ else
+ oplock = FALSE;
+
+ /* BB pass O_SYNC flag through on file attributes .. BB */
+
+ /* Also refresh inode by passing in file_info buf returned by SMBOpen
+ and calling get_inode_info with returned buf (at least
+ helps non-Unix server case */
+
+ /* BB we can not do this if this is the second open of a file
+ and the first handle has writebehind data, we might be
+ able to simply do a filemap_fdatawrite/filemap_fdatawait first */
+ buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
+ if(buf==0) {
+ if (full_path)
+ kfree(full_path);
+ FreeXid(xid);
+ return -ENOMEM;
+ }
+ rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
+ CREATE_NOT_DIR, &netfid, &oplock, buf, cifs_sb->local_nls);
+ if (rc) {
+ cFYI(1, ("cifs_open returned 0x%x ", rc));
+ cFYI(1, ("oplock: %d ", oplock));
+ } else {
+ file->private_data =
+ kmalloc(sizeof (struct cifsFileInfo), GFP_KERNEL);
+ if (file->private_data) {
+ memset(file->private_data, 0, sizeof(struct cifsFileInfo));
+ pCifsFile = (struct cifsFileInfo *) file->private_data;
+ pCifsFile->netfid = netfid;
+ pCifsFile->pid = current->pid;
+ init_MUTEX(&pCifsFile->fh_sem);
+ pCifsFile->pfile = file; /* needed for writepage */
+ pCifsFile->pInode = inode;
+ pCifsFile->invalidHandle = FALSE;
+ pCifsFile->closePend = FALSE;
+ write_lock(&GlobalSMBSeslock);
+ spin_lock(&files_lock);
+ list_add(&pCifsFile->tlist,&pTcon->openFileList);
+ pCifsInode = CIFS_I(file->f_dentry->d_inode);
+ if(pCifsInode) {
+ /* want handles we can use to read with first */
+ /* in the list so we do not have to walk the */
+ /* list to search for one in prepare_write */
+ if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
+ list_add_tail(&pCifsFile->flist,&pCifsInode->openFileList);
+ } else {
+ list_add(&pCifsFile->flist,&pCifsInode->openFileList);
+ }
+ spin_unlock(&files_lock);
+ write_unlock(&GlobalSMBSeslock);
+ if(pCifsInode->clientCanCacheRead) {
+ /* we have the inode open somewhere else
+ no need to discard cache data */
+ } else {
+ if(buf) {
+ /* BB need same check in cifs_create too? */
+
+ /* if not oplocked, invalidate inode pages if mtime
+ or file size changed */
+ temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime));
+ if((file->f_dentry->d_inode->i_mtime == temp) &&
+ (file->f_dentry->d_inode->i_size == (loff_t)le64_to_cpu(buf->EndOfFile))) {
+ cFYI(1,("inode unchanged on server"));
+ } else {
+ if(file->f_dentry->d_inode->i_mapping) {
+ /* BB no need to lock inode until after invalidate*/
+ /* since namei code should already have it locked?*/
+ filemap_fdatasync(file->f_dentry->d_inode->i_mapping);
+ }
+ cFYI(1,("invalidating remote inode since open detected it changed"));
+ invalidate_inode_pages(file->f_dentry->d_inode);
+ }
+ }
+ }
+ if (pTcon->ses->capabilities & CAP_UNIX)
+ rc = cifs_get_inode_info_unix(&file->f_dentry->d_inode,
+ full_path, inode->i_sb,xid);
+ else
+ rc = cifs_get_inode_info(&file->f_dentry->d_inode,
+ full_path, buf, inode->i_sb,xid);
+
+ if((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
+ pCifsInode->clientCanCacheAll = TRUE;
+ pCifsInode->clientCanCacheRead = TRUE;
+ cFYI(1,("Exclusive Oplock granted on inode %p",file->f_dentry->d_inode));
+ } else if((oplock & 0xF) == OPLOCK_READ)
+ pCifsInode->clientCanCacheRead = TRUE;
+ } else {
+ spin_unlock(&files_lock);
+ write_unlock(&GlobalSMBSeslock);
+ }
+ if(oplock & CIFS_CREATE_ACTION) {
+ /* time to set mode which we can not set earlier due
+ to problems creating new read-only files */
+ if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
+ CIFSSMBUnixSetPerms(xid, pTcon, full_path, inode->i_mode,
+ (__u64)-1,
+ (__u64)-1,
+ 0 /* dev */,
+ cifs_sb->local_nls);
+ else {/* BB implement via Windows security descriptors */
+ /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/
+ /* in the meantime could set r/o dos attribute when perms are eg:
+ mode & 0222 == 0 */
+ }
+ }
+ }
+ }
+
+ if (buf)
+ kfree(buf);
+ if (full_path)
+ kfree(full_path);
+ FreeXid(xid);
+ return rc;
+}
+
+/* Try to reaquire byte range locks that were released when session */
+/* to server was lost */
+static int cifs_relock_file(struct cifsFileInfo * cifsFile)
+{
+ int rc = 0;
+
+/* BB list all locks open on this file and relock */
+
+ return rc;
+}
+
+static int cifs_reopen_file(struct inode *inode, struct file *file, int can_flush)
+{
+ int rc = -EACCES;
+ int xid, oplock;
+ struct cifs_sb_info *cifs_sb;
+ struct cifsTconInfo *pTcon;
+ struct cifsFileInfo *pCifsFile;
+ struct cifsInodeInfo *pCifsInode;
+ char *full_path = NULL;
+ int desiredAccess = 0x20197;
+ int disposition = FILE_OPEN;
+ __u16 netfid;
+
+ if(inode == NULL)
+ return -EBADF;
+ if (file->private_data) {
+ pCifsFile = (struct cifsFileInfo *) file->private_data;
+ } else
+ return -EBADF;
+
+ xid = GetXid();
+ down(&pCifsFile->fh_sem);
+ if(pCifsFile->invalidHandle == FALSE) {
+ up(&pCifsFile->fh_sem);
+ FreeXid(xid);
+ return 0;
+ }
+
+ if(file->f_dentry == NULL) {
+ up(&pCifsFile->fh_sem);
+ cFYI(1,("failed file reopen, no valid name if dentry freed"));
+ FreeXid(xid);
+ return -EBADF;
+ }
+ cifs_sb = CIFS_SB(inode->i_sb);
+ pTcon = cifs_sb->tcon;
+/* can not grab rename sem here because various ops, including
+those that already have the rename sem can end up causing writepage
+to get called and if the server was down that means we end up here,
+and we can never tell if the caller already has the rename_sem */
+ full_path = build_path_from_dentry(file->f_dentry);
+ if(full_path == NULL) {
+ up(&pCifsFile->fh_sem);
+ FreeXid(xid);
+ return -ENOMEM;
+ }
+
+ cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", inode, file->f_flags,full_path));
+ if ((file->f_flags & O_ACCMODE) == O_RDONLY)
+ desiredAccess = GENERIC_READ;
+ else if ((file->f_flags & O_ACCMODE) == O_WRONLY)
+ desiredAccess = GENERIC_WRITE;
+ else if ((file->f_flags & O_ACCMODE) == O_RDWR) {
+ /* GENERIC_ALL is too much permission to request */
+ /* can cause unnecessary access denied on create */
+ /* desiredAccess = GENERIC_ALL; */
+ desiredAccess = GENERIC_READ | GENERIC_WRITE;
+ }
+
+ if (oplockEnabled)
+ oplock = REQ_OPLOCK;
+ else
+ oplock = FALSE;
+
+
+ /* Can not refresh inode by passing in file_info buf to be returned
+ by SMBOpen and then calling get_inode_info with returned buf
+ since file might have write behind data that needs to be flushed
+ and server version of file size can be stale. If we
+ knew for sure that inode was not dirty locally we could do this */
+
+/* buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
+ if(buf==0) {
+ up(&pCifsFile->fh_sem);
+ if (full_path)
+ kfree(full_path);
+ FreeXid(xid);
+ return -ENOMEM;
+ }*/
+ rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
+ CREATE_NOT_DIR, &netfid, &oplock, NULL, cifs_sb->local_nls);
+ if (rc) {
+ up(&pCifsFile->fh_sem);
+ cFYI(1, ("cifs_open returned 0x%x ", rc));
+ cFYI(1, ("oplock: %d ", oplock));
+ } else {
+ pCifsFile->netfid = netfid;
+ pCifsFile->invalidHandle = FALSE;
+ up(&pCifsFile->fh_sem);
+ pCifsInode = CIFS_I(inode);
+ if(pCifsInode) {
+ if(can_flush) {
+ filemap_fdatasync(inode->i_mapping);
+ filemap_fdatawait(inode->i_mapping);
+ /* temporarily disable caching while we
+ go to server to get inode info */
+ pCifsInode->clientCanCacheAll = FALSE;
+ pCifsInode->clientCanCacheRead = FALSE;
+ if (pTcon->ses->capabilities & CAP_UNIX)
+ rc = cifs_get_inode_info_unix(&inode,
+ full_path, inode->i_sb,xid);
+ else
+ rc = cifs_get_inode_info(&inode,
+ full_path, NULL, inode->i_sb,xid);
+ } /* else we are writing out data to server already
+ and could deadlock if we tried to flush data, and
+ since we do not know if we have data that would
+ invalidate the current end of file on the server
+ we can not go to the server to get the new
+ inod info */
+ if((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
+ pCifsInode->clientCanCacheAll = TRUE;
+ pCifsInode->clientCanCacheRead = TRUE;
+ cFYI(1,("Exclusive Oplock granted on inode %p",file->f_dentry->d_inode));
+ } else if((oplock & 0xF) == OPLOCK_READ) {
+ pCifsInode->clientCanCacheRead = TRUE;
+ pCifsInode->clientCanCacheAll = FALSE;
+ } else {
+ pCifsInode->clientCanCacheRead = FALSE;
+ pCifsInode->clientCanCacheAll = FALSE;
+ }
+ cifs_relock_file(pCifsFile);
+ }
+ }
+
+ if (full_path)
+ kfree(full_path);
+ FreeXid(xid);
+ return rc;
+}
+
+int
+cifs_close(struct inode *inode, struct file *file)
+{
+ int rc = 0;
+ int xid;
+ struct cifs_sb_info *cifs_sb;
+ struct cifsTconInfo *pTcon;
+ struct cifsFileInfo *pSMBFile =
+ (struct cifsFileInfo *) file->private_data;
+
+ xid = GetXid();
+
+ cifs_sb = CIFS_SB(inode->i_sb);
+ pTcon = cifs_sb->tcon;
+ if (pSMBFile) {
+ pSMBFile->closePend = TRUE;
+ spin_lock(&files_lock);
+ if(pTcon) {
+ /* no sense reconnecting to close a file that is
+ already closed */
+ if (pTcon->tidStatus != CifsNeedReconnect) {
+ spin_unlock(&files_lock);
+ rc = CIFSSMBClose(xid,pTcon,pSMBFile->netfid);
+ spin_lock(&files_lock);
+ }
+ }
+ list_del(&pSMBFile->flist);
+ list_del(&pSMBFile->tlist);
+ spin_unlock(&files_lock);
+ if(pSMBFile->search_resume_name)
+ kfree(pSMBFile->search_resume_name);
+ kfree(file->private_data);
+ file->private_data = NULL;
+ } else
+ rc = -EBADF;
+
+ if(list_empty(&(CIFS_I(inode)->openFileList))) {
+ cFYI(1,("closing last open instance for inode %p",inode));
+ /* if the file is not open we do not know if we can cache
+ info on this inode, much less write behind and read ahead */
+ CIFS_I(inode)->clientCanCacheRead = FALSE;
+ CIFS_I(inode)->clientCanCacheAll = FALSE;
+ }
+ if((rc ==0) && CIFS_I(inode)->write_behind_rc)
+ rc = CIFS_I(inode)->write_behind_rc;
+ FreeXid(xid);
+ return rc;
+}
+
+int
+cifs_closedir(struct inode *inode, struct file *file)
+{
+ int rc = 0;
+ int xid;
+ struct cifsFileInfo *pSMBFileStruct =
+ (struct cifsFileInfo *) file->private_data;
+
+ cFYI(1, ("Closedir inode = 0x%p with ", inode));
+
+ xid = GetXid();
+
+ if (pSMBFileStruct) {
+ cFYI(1, ("Freeing private data in close dir"));
+ kfree(file->private_data);
+ file->private_data = NULL;
+ }
+ FreeXid(xid);
+ return rc;
+}
+
+int
+cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
+{
+ int rc, xid;
+ __u32 lockType = LOCKING_ANDX_LARGE_FILES;
+ __u32 numLock = 0;
+ __u32 numUnlock = 0;
+ __u64 length;
+ int wait_flag = FALSE;
+ struct cifs_sb_info *cifs_sb;
+ struct cifsTconInfo *pTcon;
+ length = 1 + pfLock->fl_end - pfLock->fl_start;
+
+ rc = -EACCES;
+
+ xid = GetXid();
+
+ cFYI(1,
+ ("Lock parm: 0x%x flockflags: 0x%x flocktype: 0x%x start: %lld end: %lld",
+ cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
+ pfLock->fl_end));
+
+ if (pfLock->fl_flags & FL_POSIX)
+ cFYI(1, ("Posix "));
+ if (pfLock->fl_flags & FL_FLOCK)
+ cFYI(1, ("Flock "));
+/* if (pfLock->fl_flags & FL_SLEEP) {
+ cFYI(1, ("Blocking lock "));
+ wait_flag = TRUE;
+ } */
+ if (pfLock->fl_flags & FL_ACCESS)
+ cFYI(1, ("Process suspended by mandatory locking - not implemented yet "));
+ if (pfLock->fl_flags & FL_LEASE)
+ cFYI(1, ("Lease on file - not implemented yet"));
+ if (pfLock->fl_flags & (~(FL_POSIX | FL_FLOCK | FL_ACCESS | FL_LEASE)))
+ cFYI(1, ("Unknown lock flags 0x%x",pfLock->fl_flags));
+
+ if (pfLock->fl_type == F_WRLCK) {
+ cFYI(1, ("F_WRLCK "));
+ numLock = 1;
+ } else if (pfLock->fl_type == F_UNLCK) {
+ cFYI(1, ("F_UNLCK "));
+ numUnlock = 1;
+ } else if (pfLock->fl_type == F_RDLCK) {
+ cFYI(1, ("F_RDLCK "));
+ lockType |= LOCKING_ANDX_SHARED_LOCK;
+ numLock = 1;
+ } else if (pfLock->fl_type == F_EXLCK) {
+ cFYI(1, ("F_EXLCK "));
+ numLock = 1;
+ } else if (pfLock->fl_type == F_SHLCK) {
+ cFYI(1, ("F_SHLCK "));
+ lockType |= LOCKING_ANDX_SHARED_LOCK;
+ numLock = 1;
+ } else
+ cFYI(1, ("Unknown type of lock "));
+
+ cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+ pTcon = cifs_sb->tcon;
+
+ if (file->private_data == NULL) {
+ FreeXid(xid);
+ return -EBADF;
+ }
+
+ if (IS_GETLK(cmd)) {
+ rc = CIFSSMBLock(xid, pTcon,
+ ((struct cifsFileInfo *) file->
+ private_data)->netfid,
+ length,
+ pfLock->fl_start, 0, 1, lockType,
+ 0 /* wait flag */ );
+ if (rc == 0) {
+ rc = CIFSSMBLock(xid, pTcon,
+ ((struct cifsFileInfo *) file->
+ private_data)->netfid,
+ length,
+ pfLock->fl_start, 1 /* numUnlock */ ,
+ 0 /* numLock */ , lockType,
+ 0 /* wait flag */ );
+ pfLock->fl_type = F_UNLCK;
+ if (rc != 0)
+ cERROR(1,
+ ("Error unlocking previously locked range %d during test of lock ",
+ rc));
+ rc = 0;
+
+ } else {
+ /* if rc == ERR_SHARING_VIOLATION ? */
+ rc = 0; /* do not change lock type to unlock since range in use */
+ }
+
+ FreeXid(xid);
+ return rc;
+ }
+
+ rc = CIFSSMBLock(xid, pTcon,
+ ((struct cifsFileInfo *) file->private_data)->
+ netfid, length,
+ pfLock->fl_start, numUnlock, numLock, lockType,
+ wait_flag);
+ FreeXid(xid);
+ return rc;
+}
+
+ssize_t
+cifs_write(struct file * file, const char *write_data,
+ size_t write_size, loff_t * poffset)
+{
+ int rc = 0;
+ unsigned int bytes_written = 0;
+ unsigned int total_written;
+ struct cifs_sb_info *cifs_sb;
+ struct cifsTconInfo *pTcon;
+ int xid, long_op;
+ struct cifsFileInfo * open_file;
+
+ if(file->f_dentry == NULL)
+ return -EBADF;
+
+ cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+ if(cifs_sb == NULL) {
+ return -EBADF;
+ }
+ pTcon = cifs_sb->tcon;
+
+ /*cFYI(1,
+ (" write %d bytes to offset %lld of %s", write_size,
+ *poffset, file->f_dentry->d_name.name)); */
+
+ if (file->private_data == NULL) {
+ return -EBADF;
+ } else {
+ open_file = (struct cifsFileInfo *) file->private_data;
+ }
+
+ xid = GetXid();
+ if(file->f_dentry->d_inode == NULL) {
+ FreeXid(xid);
+ return -EBADF;
+ }
+
+ if (*poffset > file->f_dentry->d_inode->i_size)
+ long_op = 2; /* writes past end of file can take a long time */
+ else
+ long_op = 1;
+
+ for (total_written = 0; write_size > total_written;
+ total_written += bytes_written) {
+ rc = -EAGAIN;
+ while(rc == -EAGAIN) {
+ if(file->private_data == NULL) {
+ /* file has been closed on us */
+ FreeXid(xid);
+ /* if we have gotten here we have written some data
+ and blocked, and the file has been freed on us
+ while we blocked so return what we managed to write */
+ return total_written;
+ }
+ if(open_file->closePend) {
+ FreeXid(xid);
+ if(total_written)
+ return total_written;
+ else
+ return -EBADF;
+ }
+ if (open_file->invalidHandle) {
+ if((file->f_dentry == NULL) ||
+ (file->f_dentry->d_inode == NULL)) {
+ FreeXid(xid);
+ return total_written;
+ }
+ /* we could deadlock if we called
+ filemap_fdatawait from here so tell
+ reopen_file not to flush data to server now */
+ rc = cifs_reopen_file(file->f_dentry->d_inode,
+ file,FALSE);
+ if(rc != 0)
+ break;
+ }
+
+ rc = CIFSSMBWrite(xid, pTcon,
+ open_file->netfid,
+ write_size - total_written, *poffset,
+ &bytes_written,
+ write_data + total_written, long_op);
+ }
+ if (rc || (bytes_written == 0)) {
+ if (total_written)
+ break;
+ else {
+ FreeXid(xid);
+ return rc;
+ }
+ } else
+ *poffset += bytes_written;
+ long_op = FALSE; /* subsequent writes fast - 15 seconds is plenty */
+ }
+
+#ifdef CONFIG_CIFS_STATS
+ if(total_written > 0) {
+ atomic_inc(&pTcon->num_writes);
+ spin_lock(&pTcon->stat_lock);
+ pTcon->bytes_written += total_written;
+ spin_unlock(&pTcon->stat_lock);
+ }
+#endif
+
+ /* since the write may have blocked check these pointers again */
+ if(file->f_dentry) {
+ if(file->f_dentry->d_inode) {
+ file->f_dentry->d_inode->i_ctime = file->f_dentry->d_inode->i_mtime =
+ CURRENT_TIME;
+ if (total_written > 0) {
+ if (*poffset > file->f_dentry->d_inode->i_size)
+ file->f_dentry->d_inode->i_size = *poffset;
+ }
+ mark_inode_dirty_sync(file->f_dentry->d_inode);
+ }
+ }
+ FreeXid(xid);
+ return total_written;
+}
+
+static int
+cifs_partialpagewrite(struct page *page,unsigned from, unsigned to)
+{
+ struct address_space *mapping = page->mapping;
+ loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
+ char * write_data;
+ int rc = -EFAULT;
+ int bytes_written = 0;
+ struct cifs_sb_info *cifs_sb;
+ struct cifsTconInfo *pTcon;
+ struct inode *inode;
+ struct cifsInodeInfo *cifsInode;
+ struct cifsFileInfo *open_file = NULL;
+ struct list_head *tmp;
+ struct list_head *tmp1;
+
+ if (!mapping) {
+ return -EFAULT;
+ } else if(!mapping->host) {
+ return -EFAULT;
+ }
+
+ inode = page->mapping->host;
+ cifs_sb = CIFS_SB(inode->i_sb);
+ pTcon = cifs_sb->tcon;
+
+ offset += (loff_t)from;
+ write_data = kmap(page);
+ write_data += from;
+
+ if((to > PAGE_CACHE_SIZE) || (from > to)) {
+ kunmap(page);
+ return -EIO;
+ }
+
+ /* racing with truncate? */
+ if(offset > mapping->host->i_size) {
+ kunmap(page);
+ return 0; /* don't care */
+ }
+
+ /* check to make sure that we are not extending the file */
+ if(mapping->host->i_size - offset < (loff_t)to)
+ to = (unsigned)(mapping->host->i_size - offset);
+
+
+ cifsInode = CIFS_I(mapping->host);
+ read_lock(&GlobalSMBSeslock);
+ /* BB we should start at the end */
+ list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) {
+ open_file = list_entry(tmp,struct cifsFileInfo, flist);
+ if(open_file->closePend)
+ continue;
+ /* We check if file is open for writing first */
+ if((open_file->pfile) &&
+ ((open_file->pfile->f_flags & O_RDWR) ||
+ (open_file->pfile->f_flags & O_WRONLY))) {
+ read_unlock(&GlobalSMBSeslock);
+ bytes_written = cifs_write(open_file->pfile, write_data,
+ to-from, &offset);
+ read_lock(&GlobalSMBSeslock);
+ /* Does mm or vfs already set times? */
+ inode->i_atime = inode->i_mtime = CURRENT_TIME;
+ if ((bytes_written > 0) && (offset)) {
+ rc = 0;
+ } else if(bytes_written < 0) {
+ if(rc == -EBADF) {
+ /* have seen a case in which
+ kernel seemed to have closed/freed a file
+ even with writes active so we might as well
+ see if there are other file structs to try
+ for the same inode before giving up */
+ continue;
+ } else
+ rc = bytes_written;
+ }
+ break; /* now that we found a valid file handle
+ and tried to write to it we are done, no
+ sense continuing to loop looking for another */
+ }
+ if(tmp->next == NULL) {
+ cFYI(1,("File instance %p removed",tmp));
+ break;
+ }
+ }
+ read_unlock(&GlobalSMBSeslock);
+ if(open_file == NULL) {
+ cFYI(1,("No writeable filehandles for inode"));
+ rc = -EIO;
+ }
+
+ kunmap(page);
+ return rc;
+}
+
+#if 0
+static int
+cifs_writepages(struct address_space *mapping, struct writeback_control *wbc)
+{
+ int rc = -EFAULT;
+ int xid;
+
+ xid = GetXid();
+/* call 16K write then Setpageuptodate */
+ FreeXid(xid);
+ return rc;
+}
+#endif
+
+static int
+cifs_writepage(struct page* page)
+{
+ int rc = -EFAULT;
+ int xid;
+
+ xid = GetXid();
+/* BB add check for wbc flags */
+ page_cache_get(page);
+ if (!Page_Uptodate(page)) {
+ cFYI(1,("ppw - page not up to date"));
+ }
+
+ rc = cifs_partialpagewrite(page,0,PAGE_CACHE_SIZE);
+ SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20))
+ unlock_page(page);
+#else
+ UnlockPage(page);
+#endif
+ page_cache_release(page);
+ FreeXid(xid);
+ return rc;
+}
+
+static int
+cifs_commit_write(struct file *file, struct page *page, unsigned offset,
+ unsigned to)
+{
+ int xid;
+ int rc = 0;
+ struct inode *inode = page->mapping->host;
+ loff_t position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
+ char * page_data;
+
+ xid = GetXid();
+ cFYI(1,("commit write for page %p up to position %lld for %d",page,position,to));
+ if (position > inode->i_size){
+ inode->i_size = position;
+ /*if (file->private_data == NULL) {
+ rc = -EBADF;
+ } else {
+ open_file = (struct cifsFileInfo *)file->private_data;
+ cifs_sb = CIFS_SB(inode->i_sb);
+ rc = -EAGAIN;
+ while(rc == -EAGAIN) {
+ if((open_file->invalidHandle) &&
+ (!open_file->closePend)) {
+ rc = cifs_reopen_file(file->f_dentry->d_inode,file);
+ if(rc != 0)
+ break;
+ }
+ if(!open_file->closePend) {
+ rc = CIFSSMBSetFileSize(xid, cifs_sb->tcon,
+ position, open_file->netfid,
+ open_file->pid,FALSE);
+ } else {
+ rc = -EBADF;
+ break;
+ }
+ }
+ cFYI(1,(" SetEOF (commit write) rc = %d",rc));
+ }*/
+ }
+ if (!Page_Uptodate(page)) {
+ position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + offset;
+ /* can not rely on (or let) writepage write this data */
+ if(to < offset) {
+ cFYI(1,("Illegal offsets, can not copy from %d to %d",
+ offset,to));
+ FreeXid(xid);
+ return rc;
+ }
+ /* this is probably better than directly calling
+ partialpage_write since in this function
+ the file handle is known which we might as well
+ leverage */
+ /* BB check if anything else missing out of ppw */
+ /* such as updating last write time */
+ page_data = kmap(page);
+ rc = cifs_write(file, page_data+offset,to-offset,
+ &position);
+ if(rc > 0)
+ rc = 0;
+ /* else if rc < 0 should we set writebehind rc? */
+ kunmap(page);
+ } else {
+ set_page_dirty(page);
+ }
+
+ FreeXid(xid);
+ return rc;
+}
+
+int
+cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
+{
+ int xid;
+ int rc = 0;
+ struct inode * inode = file->f_dentry->d_inode;
+
+ xid = GetXid();
+
+ cFYI(1, ("Sync file - name: %s datasync: 0x%x ",
+ dentry->d_name.name, datasync));
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,17))
+ rc = filemap_fdatasync(inode->i_mapping);
+#else
+ filemap_fdatasync(inode->i_mapping);
+#endif
+ if(rc == 0)
+ CIFS_I(inode)->write_behind_rc = 0;
+ FreeXid(xid);
+ return rc;
+}
+
+static int
+cifs_sync_page(struct page *page)
+{
+ struct address_space *mapping;
+ struct inode *inode;
+ unsigned long index = page->index;
+ unsigned int rpages = 0;
+ int rc = 0;
+
+ cFYI(1,("sync page %p",page));
+ mapping = page->mapping;
+ if (!mapping)
+ return 0;
+ inode = mapping->host;
+ if (!inode)
+ return 0;
+
+/* fill in rpages then
+ result = cifs_pagein_inode(inode, index, rpages); *//* BB finish */
+
+ cFYI(1, ("rpages is %d for sync page of Index %ld ", rpages, index));
+
+ if (rc < 0)
+ return rc;
+ return 0;
+}
+
+/*
+ * As file closes, flush all cached write data for this inode checking
+ * for write behind errors.
+ *
+ */
+int cifs_flush(struct file *file)
+{
+ struct inode * inode = file->f_dentry->d_inode;
+ int rc = 0;
+
+ /* Rather than do the steps manually: */
+ /* lock the inode for writing */
+ /* loop through pages looking for write behind data (dirty pages) */
+ /* coalesce into contiguous 16K (or smaller) chunks to write to server */
+ /* send to server (prefer in parallel) */
+ /* deal with writebehind errors */
+ /* unlock inode for writing */
+ /* filemapfdatawrite appears easier for the time being */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,17))
+ rc = filemap_fdatasync(inode->i_mapping);
+#else
+ filemap_fdatasync(inode->i_mapping);
+#endif
+ if(rc == 0) /* reset wb rc if we were able to write out dirty pages */
+ CIFS_I(inode)->write_behind_rc = 0;
+
+ cFYI(1,("Flush inode %p file %p rc %d",inode,file,rc));
+
+ return rc;
+}
+
+
+ssize_t
+cifs_read(struct file * file, char *read_data, size_t read_size,
+ loff_t * poffset)
+{
+ int rc = -EACCES;
+ unsigned int bytes_read = 0;
+ unsigned int total_read;
+ unsigned int current_read_size;
+ struct cifs_sb_info *cifs_sb;
+ struct cifsTconInfo *pTcon;
+ int xid;
+ char * current_offset;
+ struct cifsFileInfo * open_file;
+
+ xid = GetXid();
+ cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+ pTcon = cifs_sb->tcon;
+
+ if (file->private_data == NULL) {
+ FreeXid(xid);
+ return -EBADF;
+ }
+ open_file = (struct cifsFileInfo *)file->private_data;
+
+ if((file->f_flags & O_ACCMODE) == O_WRONLY) {
+ cFYI(1,("attempting read on write only file instance"));
+ }
+
+ for (total_read = 0,current_offset=read_data; read_size > total_read;
+ total_read += bytes_read,current_offset+=bytes_read) {
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,15))
+ current_read_size = min_t(const int,read_size - total_read,cifs_sb->rsize);
+#else
+ current_read_size = min(read_size - total_read,cifs_sb->rsize);
+#endif
+ rc = -EAGAIN;
+ while(rc == -EAGAIN) {
+ if ((open_file->invalidHandle) && (!open_file->closePend)) {
+ rc = cifs_reopen_file(file->f_dentry->d_inode,
+ file,TRUE);
+ if(rc != 0)
+ break;
+ }
+
+ rc = CIFSSMBRead(xid, pTcon,
+ open_file->netfid,
+ current_read_size, *poffset,
+ &bytes_read, &current_offset);
+ }
+ if (rc || (bytes_read == 0)) {
+ if (total_read) {
+ break;
+ } else {
+ FreeXid(xid);
+ return rc;
+ }
+ } else {
+#ifdef CONFIG_CIFS_STATS
+ atomic_inc(&pTcon->num_reads);
+ spin_lock(&pTcon->stat_lock);
+ pTcon->bytes_read += total_read;
+ spin_unlock(&pTcon->stat_lock);
+#endif
+ *poffset += bytes_read;
+ }
+ }
+ FreeXid(xid);
+ return total_read;
+}
+
+int cifs_file_mmap(struct file * file, struct vm_area_struct * vma)
+{
+ struct dentry * dentry = file->f_dentry;
+ int rc, xid;
+
+ xid = GetXid();
+ rc = cifs_revalidate(dentry);
+ if (rc) {
+ cFYI(1,("Validation prior to mmap failed, error=%d", rc));
+ FreeXid(xid);
+ return rc;
+ }
+ rc = generic_file_mmap(file, vma);
+ FreeXid(xid);
+ return rc;
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+static void cifs_copy_cache_pages(struct address_space *mapping,
+ struct list_head *pages, int bytes_read,
+ char *data,struct pagevec * plru_pvec)
+{
+ struct page *page;
+ char * target;
+
+ while (bytes_read > 0) {
+ if(list_empty(pages))
+ break;
+
+ page = list_entry(pages->prev, struct page, lru);
+ list_del(&page->lru);
+
+ if (add_to_page_cache(page, mapping, page->index, GFP_KERNEL)) {
+ page_cache_release(page);
+ cFYI(1,("Add page cache failed"));
+ continue;
+ }
+
+ target = kmap_atomic(page,KM_USER0);
+
+ if(PAGE_CACHE_SIZE > bytes_read) {
+ memcpy(target,data,bytes_read);
+ /* zero the tail end of this partial page */
+ memset(target+bytes_read,0,PAGE_CACHE_SIZE-bytes_read);
+ bytes_read = 0;
+ } else {
+ memcpy(target,data,PAGE_CACHE_SIZE);
+ bytes_read -= PAGE_CACHE_SIZE;
+ }
+ kunmap_atomic(target,KM_USER0);
+
+ flush_dcache_page(page);
+ SetPageUptodate(page);
+ unlock_page(page);
+ if (!pagevec_add(plru_pvec, page))
+ __pagevec_lru_add(plru_pvec);
+ data += PAGE_CACHE_SIZE;
+ }
+ return;
+}
+
+
+static int
+cifs_readpages(struct file *file, struct address_space *mapping,
+ struct list_head *page_list, unsigned num_pages)
+{
+ int rc = -EACCES;
+ int xid;
+ loff_t offset;
+ struct page * page;
+ struct cifs_sb_info *cifs_sb;
+ struct cifsTconInfo *pTcon;
+ int bytes_read = 0;
+ unsigned int read_size,i;
+ char * smb_read_data = NULL;
+ struct smb_com_read_rsp * pSMBr;
+ struct pagevec lru_pvec;
+ struct cifsFileInfo * open_file;
+
+ xid = GetXid();
+ if (file->private_data == NULL) {
+ FreeXid(xid);
+ return -EBADF;
+ }
+ open_file = (struct cifsFileInfo *)file->private_data;
+ cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+ pTcon = cifs_sb->tcon;
+
+ pagevec_init(&lru_pvec, 0);
+
+ for(i = 0;i<num_pages;) {
+ unsigned contig_pages;
+ struct page * tmp_page;
+ unsigned long expected_index;
+
+ if(list_empty(page_list)) {
+ break;
+ }
+ page = list_entry(page_list->prev, struct page, lru);
+ offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
+
+ /* count adjacent pages that we will read into */
+ contig_pages = 0;
+ expected_index = list_entry(page_list->prev,struct page,lru)->index;
+ list_for_each_entry_reverse(tmp_page,page_list,lru) {
+ if(tmp_page->index == expected_index) {
+ contig_pages++;
+ expected_index++;
+ } else {
+ break;
+ }
+ }
+ if(contig_pages + i > num_pages) {
+ contig_pages = num_pages - i;
+ }
+
+ /* for reads over a certain size could initiate async read ahead */
+
+ read_size = contig_pages * PAGE_CACHE_SIZE;
+ /* Read size needs to be in multiples of one page */
+ read_size = min_t(const unsigned int,read_size,cifs_sb->rsize & PAGE_CACHE_MASK);
+
+ rc = -EAGAIN;
+ while(rc == -EAGAIN) {
+ if ((open_file->invalidHandle) && (!open_file->closePend)) {
+ rc = cifs_reopen_file(file->f_dentry->d_inode,
+ file, TRUE);
+ if(rc != 0)
+ break;
+ }
+
+ rc = CIFSSMBRead(xid, pTcon,
+ open_file->netfid,
+ read_size, offset,
+ &bytes_read, &smb_read_data);
+ /* BB need to check return code here */
+ if(rc== -EAGAIN) {
+ if(smb_read_data) {
+ cifs_buf_release(smb_read_data);
+ smb_read_data = NULL;
+ }
+ }
+ }
+ if ((rc < 0) || (smb_read_data == NULL)) {
+ cFYI(1,("Read error in readpages: %d",rc));
+ /* clean up remaing pages off list */
+ while (!list_empty(page_list) && (i < num_pages)) {
+ page = list_entry(page_list->prev, struct page, lru);
+ list_del(&page->lru);
+ page_cache_release(page);
+ }
+ break;
+ } else if (bytes_read > 0) {
+ pSMBr = (struct smb_com_read_rsp *)smb_read_data;
+ cifs_copy_cache_pages(mapping, page_list, bytes_read,
+ smb_read_data + 4 /* RFC1001 hdr */ +
+ le16_to_cpu(pSMBr->DataOffset), &lru_pvec);
+
+ i += bytes_read >> PAGE_CACHE_SHIFT;
+#ifdef CONFIG_CIFS_STATS
+ atomic_inc(&pTcon->num_reads);
+ spin_lock(&pTcon->stat_lock);
+ pTcon->bytes_read += bytes_read;
+ spin_unlock(&pTcon->stat_lock);
+#endif
+ if((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) {
+ cFYI(1,("Partial page %d of %d read to cache",i++,num_pages));
+
+ i++; /* account for partial page */
+
+ /* server copy of file can have smaller size than client */
+ /* BB do we need to verify this common case ? this case is ok -
+ if we are at server EOF we will hit it on next read */
+
+ /* while(!list_empty(page_list) && (i < num_pages)) {
+ page = list_entry(page_list->prev,struct page, list);
+ list_del(&page->list);
+ page_cache_release(page);
+ }
+ break; */
+ }
+ } else {
+ cFYI(1,("No bytes read (%d) at offset %lld . Cleaning remaining pages from readahead list",bytes_read,offset));
+ /* BB turn off caching and do new lookup on file size at server? */
+ while (!list_empty(page_list) && (i < num_pages)) {
+ page = list_entry(page_list->prev, struct page, lru);
+ list_del(&page->lru);
+ page_cache_release(page); /* BB removeme - replace with zero of page? */
+ }
+ break;
+ }
+ if(smb_read_data) {
+ cifs_buf_release(smb_read_data);
+ smb_read_data = NULL;
+ }
+ bytes_read = 0;
+ }
+
+ pagevec_lru_add(&lru_pvec);
+
+/* need to free smb_read_data buf before exit */
+ if(smb_read_data) {
+ cifs_buf_release(smb_read_data);
+ smb_read_data = NULL;
+ }
+
+ FreeXid(xid);
+ return rc;
+}
+#endif
+
+static int cifs_readpage_worker(struct file *file, struct page *page, loff_t * poffset)
+{
+ char * read_data;
+ int rc;
+
+ page_cache_get(page);
+ read_data = kmap(page);
+ /* for reads over a certain size could initiate async read ahead */
+
+ rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
+
+ if (rc < 0)
+ goto io_error;
+ else {
+ cFYI(1,("Bytes read %d ",rc));
+ }
+
+ file->f_dentry->d_inode->i_atime = CURRENT_TIME;
+
+ if(PAGE_CACHE_SIZE > rc) {
+ memset(read_data+rc, 0, PAGE_CACHE_SIZE - rc);
+ }
+ flush_dcache_page(page);
+ SetPageUptodate(page);
+ rc = 0;
+
+io_error:
+ kunmap(page);
+ page_cache_release(page);
+ return rc;
+}
+
+static int
+cifs_readpage(struct file *file, struct page *page)
+{
+ loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
+ int rc = -EACCES;
+ int xid;
+
+ xid = GetXid();
+
+ if (file->private_data == NULL) {
+ FreeXid(xid);
+ return -EBADF;
+ }
+
+ cFYI(1,("readpage %p at offset %d 0x%x\n",page,(int)offset,(int)offset));
+
+ rc = cifs_readpage_worker(file,page,&offset);
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20))
+ unlock_page(page);
+#else
+ UnlockPage(page);
+#endif
+
+ FreeXid(xid);
+ return rc;
+}
+
+/* We do not want to update the file size from server for inodes
+ open for write - to avoid races with writepage extending
+ the file - in the future we could consider allowing
+ refreshing the inode only on increases in the file size
+ but this is tricky to do without racing with writebehind
+ page caching in the current Linux kernel design */
+
+int is_size_safe_to_change(struct cifsInodeInfo * cifsInode)
+{
+ struct list_head *tmp;
+ struct list_head *tmp1;
+ struct cifsFileInfo *open_file = NULL;
+ int rc = TRUE;
+
+ if(cifsInode == NULL)
+ return rc;
+
+ read_lock(&GlobalSMBSeslock);
+ list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) {
+ open_file = list_entry(tmp,struct cifsFileInfo, flist);
+ if(open_file == NULL)
+ break;
+ if(open_file->closePend)
+ continue;
+ /* We check if file is open for writing,
+ BB we could supplement this with a check to see if file size
+ changes have been flushed to server - ie inode metadata dirty */
+ if((open_file->pfile) &&
+ ((open_file->pfile->f_flags & O_RDWR) ||
+ (open_file->pfile->f_flags & O_WRONLY))) {
+ rc = FALSE;
+ break;
+ }
+ if(tmp->next == NULL) {
+ cFYI(1,("File instance %p removed",tmp));
+ break;
+ }
+ }
+ read_unlock(&GlobalSMBSeslock);
+ return rc;
+}
+
+
+void
+fill_in_inode(struct inode *tmp_inode,
+ FILE_DIRECTORY_INFO * pfindData, int *pobject_type)
+{
+ struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
+
+ pfindData->ExtFileAttributes =
+ le32_to_cpu(pfindData->ExtFileAttributes);
+ pfindData->AllocationSize = le64_to_cpu(pfindData->AllocationSize);
+ pfindData->EndOfFile = le64_to_cpu(pfindData->EndOfFile);
+ cifsInfo->cifsAttrs = pfindData->ExtFileAttributes;
+ cifsInfo->time = jiffies;
+
+ /* Linux can not store file creation time unfortunately so ignore it */
+ tmp_inode->i_atime =
+ cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
+ tmp_inode->i_mtime =
+ cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
+ tmp_inode->i_ctime =
+ cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
+ /* treat dos attribute of read-only as read-only mode bit e.g. 555? */
+ /* 2767 perms - indicate mandatory locking */
+ /* BB fill in uid and gid here? with help from winbind?
+ or retrieve from NTFS stream extended attribute */
+ if(atomic_read(&cifsInfo->inUse) == 0) {
+ tmp_inode->i_uid = cifs_sb->mnt_uid;
+ tmp_inode->i_gid = cifs_sb->mnt_gid;
+ /* set default mode. will override for dirs below */
+ tmp_inode->i_mode = cifs_sb->mnt_file_mode;
+ }
+
+ cFYI(0,
+ ("CIFS FFIRST: Attributes came in as 0x%x",
+ pfindData->ExtFileAttributes));
+ if (pfindData->ExtFileAttributes & ATTR_REPARSE) {
+ *pobject_type = DT_LNK;
+ /* BB can this and S_IFREG or S_IFDIR be set as in Windows? */
+ tmp_inode->i_mode |= S_IFLNK;
+ } else if (pfindData->ExtFileAttributes & ATTR_DIRECTORY) {
+ *pobject_type = DT_DIR;
+ /* override default perms since we do not lock dirs */
+ if(atomic_read(&cifsInfo->inUse) == 0) {
+ tmp_inode->i_mode = cifs_sb->mnt_dir_mode;
+ }
+ tmp_inode->i_mode |= S_IFDIR;
+ } else {
+ *pobject_type = DT_REG;
+ tmp_inode->i_mode |= S_IFREG;
+ if(pfindData->ExtFileAttributes & ATTR_READONLY)
+ tmp_inode->i_mode &= ~(S_IWUGO);
+
+ }/* could add code here - to validate if device or weird share type? */
+
+ /* can not fill in nlink here as in qpathinfo version and Unx search */
+ if(atomic_read(&cifsInfo->inUse) == 0) {
+ atomic_set(&cifsInfo->inUse,1);
+ }
+ if(is_size_safe_to_change(cifsInfo)) {
+ /* can not safely change the file size here if the
+ client is writing to it due to potential races */
+ tmp_inode->i_size = pfindData->EndOfFile;
+
+ /* 512 bytes (2**9) is the fake blocksize that must be used */
+ /* for this calculation, even though the reported blocksize is larger */
+ tmp_inode->i_blocks = (512 - 1 + pfindData->AllocationSize) >> 9;
+ }
+
+ if (pfindData->AllocationSize < pfindData->EndOfFile)
+ cFYI(1, ("Possible sparse file: allocation size less than end of file "));
+ cFYI(1,
+ ("File Size %ld and blocks %ld and blocksize %ld",
+ (unsigned long) tmp_inode->i_size, tmp_inode->i_blocks,
+ tmp_inode->i_blksize));
+ if (S_ISREG(tmp_inode->i_mode)) {
+ cFYI(1, (" File inode "));
+ tmp_inode->i_op = &cifs_file_inode_ops;
+ tmp_inode->i_fop = &cifs_file_ops;
+ tmp_inode->i_data.a_ops = &cifs_addr_ops;
+ } else if (S_ISDIR(tmp_inode->i_mode)) {
+ cFYI(1, (" Directory inode"));
+ tmp_inode->i_op = &cifs_dir_inode_ops;
+ tmp_inode->i_fop = &cifs_dir_ops;
+ } else if (S_ISLNK(tmp_inode->i_mode)) {
+ cFYI(1, (" Symbolic Link inode "));
+ tmp_inode->i_op = &cifs_symlink_inode_ops;
+ } else {
+ cFYI(1, (" Init special inode "));
+ init_special_inode(tmp_inode, tmp_inode->i_mode,
+ kdev_t_to_nr(tmp_inode->i_rdev));
+ }
+}
+
+void
+unix_fill_in_inode(struct inode *tmp_inode,
+ FILE_UNIX_INFO * pfindData, int *pobject_type)
+{
+ struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
+ cifsInfo->time = jiffies;
+ atomic_inc(&cifsInfo->inUse);
+
+ tmp_inode->i_atime =
+ cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
+ tmp_inode->i_mtime =
+ cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastModificationTime));
+ tmp_inode->i_ctime =
+ cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastStatusChange));
+
+ tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions);
+ pfindData->Type = le32_to_cpu(pfindData->Type);
+ if (pfindData->Type == UNIX_FILE) {
+ *pobject_type = DT_REG;
+ tmp_inode->i_mode |= S_IFREG;
+ } else if (pfindData->Type == UNIX_SYMLINK) {
+ *pobject_type = DT_LNK;
+ tmp_inode->i_mode |= S_IFLNK;
+ } else if (pfindData->Type == UNIX_DIR) {
+ *pobject_type = DT_DIR;
+ tmp_inode->i_mode |= S_IFDIR;
+ } else if (pfindData->Type == UNIX_CHARDEV) {
+ *pobject_type = DT_CHR;
+ tmp_inode->i_mode |= S_IFCHR;
+ tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor),
+ le64_to_cpu(pfindData->DevMinor) & MINORMASK);
+ } else if (pfindData->Type == UNIX_BLOCKDEV) {
+ *pobject_type = DT_BLK;
+ tmp_inode->i_mode |= S_IFBLK;
+ tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor),
+ le64_to_cpu(pfindData->DevMinor) & MINORMASK);
+ } else if (pfindData->Type == UNIX_FIFO) {
+ *pobject_type = DT_FIFO;
+ tmp_inode->i_mode |= S_IFIFO;
+ } else if (pfindData->Type == UNIX_SOCKET) {
+ *pobject_type = DT_SOCK;
+ tmp_inode->i_mode |= S_IFSOCK;
+ }
+
+ tmp_inode->i_uid = le64_to_cpu(pfindData->Uid);
+ tmp_inode->i_gid = le64_to_cpu(pfindData->Gid);
+ tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks);
+
+ pfindData->NumOfBytes = le64_to_cpu(pfindData->NumOfBytes);
+ if(is_size_safe_to_change(cifsInfo)) {
+ /* can not safely change the file size here if the
+ client is writing to it due to potential races */
+ pfindData->EndOfFile = le64_to_cpu(pfindData->EndOfFile);
+ tmp_inode->i_size = pfindData->EndOfFile;
+
+ /* 512 bytes (2**9) is the fake blocksize that must be used */
+ /* for this calculation, not the real blocksize */
+ tmp_inode->i_blocks = (512 - 1 + pfindData->NumOfBytes) >> 9;
+ }
+
+ if (S_ISREG(tmp_inode->i_mode)) {
+ cFYI(1, ("File inode"));
+ tmp_inode->i_op = &cifs_file_inode_ops;
+ tmp_inode->i_fop = &cifs_file_ops;
+ tmp_inode->i_data.a_ops = &cifs_addr_ops;
+ } else if (S_ISDIR(tmp_inode->i_mode)) {
+ cFYI(1, ("Directory inode"));
+ tmp_inode->i_op = &cifs_dir_inode_ops;
+ tmp_inode->i_fop = &cifs_dir_ops;
+ } else if (S_ISLNK(tmp_inode->i_mode)) {
+ cFYI(1, ("Symbolic Link inode"));
+ tmp_inode->i_op = &cifs_symlink_inode_ops;
+/* tmp_inode->i_fop = *//* do not need to set to anything */
+ } else {
+ cFYI(1, ("Special inode"));
+ init_special_inode(tmp_inode, tmp_inode->i_mode,
+ kdev_t_to_nr(tmp_inode->i_rdev));
+ }
+}
+
+static void
+construct_dentry(struct qstr *qstring, struct file *file,
+ struct inode **ptmp_inode, struct dentry **pnew_dentry)
+{
+ struct dentry *tmp_dentry;
+ struct cifs_sb_info *cifs_sb;
+ struct cifsTconInfo *pTcon;
+ struct cifsInodeInfo *pCifsI;
+
+ cFYI(1, ("For %s ", qstring->name));
+ cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+ pTcon = cifs_sb->tcon;
+
+ qstring->hash = full_name_hash(qstring->name, qstring->len);
+ tmp_dentry = d_lookup(file->f_dentry, qstring);
+ if (tmp_dentry) {
+ cFYI(0, (" existing dentry with inode 0x%p", tmp_dentry->d_inode));
+ *ptmp_inode = tmp_dentry->d_inode;
+ /* BB overwrite the old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len ?? */
+ if(*ptmp_inode == NULL) {
+ *ptmp_inode = new_inode(file->f_dentry->d_sb);
+ if(*ptmp_inode == NULL)
+ return;
+ d_instantiate(tmp_dentry, *ptmp_inode);
+ insert_inode_hash(*ptmp_inode);
+ pCifsI = CIFS_I(*ptmp_inode);
+ INIT_LIST_HEAD(&pCifsI->openFileList);
+ /* can not enable caching for this inode
+ until a file instance is open and we
+ can check the oplock flag on the open
+ response */
+ (*ptmp_inode)->i_blksize = CIFS_MAX_MSGSIZE;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,15))
+ (*ptmp_inode)->i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */
+#endif
+ pCifsI->clientCanCacheRead = FALSE;
+ pCifsI->clientCanCacheAll = FALSE;
+ pCifsI->time = 0;
+ /* do not need to set cifs Attrs since
+ they are about to be overwritten
+ in fill_in_inode */
+ atomic_set(&pCifsI->inUse, 0);
+ }
+ } else {
+ tmp_dentry = d_alloc(file->f_dentry, qstring);
+ if(tmp_dentry == NULL) {
+ cERROR(1,("Failed allocating dentry"));
+ return;
+ }
+
+ if(ptmp_inode) {
+ *ptmp_inode = new_inode(file->f_dentry->d_sb);
+ if(*ptmp_inode == NULL)
+ return;
+ pCifsI = CIFS_I(*ptmp_inode);
+ insert_inode_hash(*ptmp_inode);
+ INIT_LIST_HEAD(&pCifsI->openFileList);
+ /* can not enable caching for this inode
+ until a file instance is open and we
+ can check the oplock flag on the open
+ response */
+ (*ptmp_inode)->i_blksize = CIFS_MAX_MSGSIZE;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,15))
+ (*ptmp_inode)->i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */
+#endif
+ pCifsI->clientCanCacheRead = FALSE;
+ pCifsI->clientCanCacheAll = FALSE;
+ pCifsI->time = 0;
+ /* do not need to set cifs Attrs since
+ they are about to be overwritten
+ in fill_in_inode */
+ atomic_set(&pCifsI->inUse, 0);
+ }
+ tmp_dentry->d_op = &cifs_dentry_ops;
+ d_instantiate(tmp_dentry, *ptmp_inode);
+ d_rehash(tmp_dentry);
+ }
+
+ tmp_dentry->d_time = jiffies;
+ *pnew_dentry = tmp_dentry;
+}
+
+static void reset_resume_key(struct file * dir_file,
+ unsigned char * filename,
+ unsigned int len,int Unicode,struct nls_table * nls_tab) {
+ struct cifsFileInfo *cifsFile;
+
+ cifsFile = (struct cifsFileInfo *)dir_file->private_data;
+ if(cifsFile == NULL)
+ return;
+ if(cifsFile->search_resume_name) {
+ kfree(cifsFile->search_resume_name);
+ }
+
+ if(Unicode)
+ len *= 2;
+ cifsFile->resume_name_length = len;
+
+ cifsFile->search_resume_name =
+ kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
+
+ if(cifsFile->search_resume_name == NULL) {
+ cERROR(1,("failed new resume key allocate, length %d",
+ cifsFile->resume_name_length));
+ return;
+ }
+ if(Unicode)
+ cifs_strtoUCS((wchar_t *) cifsFile->search_resume_name,
+ filename, len, nls_tab);
+ else
+ memcpy(cifsFile->search_resume_name, filename,
+ cifsFile->resume_name_length);
+ cFYI(1,("Reset resume key to: %s with len %d",filename,len));
+ return;
+}
+
+
+
+static int
+cifs_filldir(struct qstr *pqstring, FILE_DIRECTORY_INFO * pfindData,
+ struct file *file, filldir_t filldir, void *direntry)
+{
+ struct inode *tmp_inode;
+ struct dentry *tmp_dentry;
+ int object_type,rc;
+
+ pqstring->name = pfindData->FileName;
+ pqstring->len = pfindData->FileNameLength;
+
+ construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry);
+ if((tmp_inode == NULL) || (tmp_dentry == NULL)) {
+ return -ENOMEM;
+ }
+ fill_in_inode(tmp_inode, pfindData, &object_type);
+ rc = filldir(direntry, pfindData->FileName, pqstring->len, file->f_pos,
+ tmp_inode->i_ino, object_type);
+ if(rc) {
+ /* due to readdir error we need to recalculate resume
+ key so next readdir will restart on right entry */
+ cFYI(1,("Error %d on filldir of %s",rc ,pfindData->FileName));
+ }
+ dput(tmp_dentry);
+ return rc;
+}
+
+static int
+cifs_filldir_unix(struct qstr *pqstring,
+ FILE_UNIX_INFO * pUnixFindData, struct file *file,
+ filldir_t filldir, void *direntry)
+{
+ struct inode *tmp_inode;
+ struct dentry *tmp_dentry;
+ int object_type, rc;
+
+ pqstring->name = pUnixFindData->FileName;
+ pqstring->len = strnlen(pUnixFindData->FileName, MAX_PATHCONF);
+
+ construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry);
+ if((tmp_inode == NULL) || (tmp_dentry == NULL)) {
+ return -ENOMEM;
+ }
+
+ unix_fill_in_inode(tmp_inode, pUnixFindData, &object_type);
+ rc = filldir(direntry, pUnixFindData->FileName, pqstring->len,
+ file->f_pos, tmp_inode->i_ino, object_type);
+ if(rc) {
+ /* due to readdir error we need to recalculate resume
+ key so next readdir will restart on right entry */
+ cFYI(1,("Error %d on filldir of %s",rc ,pUnixFindData->FileName));
+ }
+ dput(tmp_dentry);
+ return rc;
+}
+
+int
+cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
+{
+ int rc = 0;
+ int xid;
+ int Unicode = FALSE;
+ int UnixSearch = FALSE;
+ unsigned int bufsize, i;
+ __u16 searchHandle;
+ struct cifs_sb_info *cifs_sb;
+ struct cifsTconInfo *pTcon;
+ struct cifsFileInfo *cifsFile = NULL;
+ char *full_path = NULL;
+ char *data;
+ struct qstr qstring;
+ T2_FFIRST_RSP_PARMS findParms;
+ T2_FNEXT_RSP_PARMS findNextParms;
+ FILE_DIRECTORY_INFO *pfindData;
+ FILE_DIRECTORY_INFO *lastFindData;
+ FILE_UNIX_INFO *pfindDataUnix;
+
+ xid = GetXid();
+
+ cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+ pTcon = cifs_sb->tcon;
+ bufsize = pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE;
+ if(bufsize > CIFS_MAX_MSGSIZE) {
+ FreeXid(xid);
+ return -EIO;
+ }
+ data = kmalloc(bufsize, GFP_KERNEL);
+ pfindData = (FILE_DIRECTORY_INFO *) data;
+
+ if(file->f_dentry == NULL) {
+ FreeXid(xid);
+ return -EIO;
+ }
+ down(&file->f_dentry->d_sb->s_vfs_rename_sem);
+ full_path = build_wildcard_path_from_dentry(file->f_dentry);
+ up(&file->f_dentry->d_sb->s_vfs_rename_sem);
+
+
+ cFYI(1, ("Full path: %s start at: %lld ", full_path, file->f_pos));
+
+ switch ((int) file->f_pos) {
+ case 0:
+ if (filldir(direntry, ".", 1, file->f_pos,
+ file->f_dentry->d_inode->i_ino, DT_DIR) < 0) {
+ cERROR(1, ("Filldir for current dir failed "));
+ break;
+ }
+ file->f_pos++;
+ /* fallthrough */
+ case 1:
+ if (filldir(direntry, "..", 2, file->f_pos,
+ file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) {
+ cERROR(1, ("Filldir for parent dir failed "));
+ break;
+ }
+ file->f_pos++;
+ /* fallthrough */
+ case 2:
+ if (file->private_data != NULL) {
+ cifsFile =
+ (struct cifsFileInfo *) file->private_data;
+ if (cifsFile->endOfSearch) {
+ if(cifsFile->emptyDir) {
+ cFYI(1, ("End of search, empty dir"));
+ rc = 0;
+ break;
+ }
+ } else {
+ cifsFile->invalidHandle = TRUE;
+ CIFSFindClose(xid, pTcon, cifsFile->netfid);
+ }
+ if(cifsFile->search_resume_name) {
+ kfree(cifsFile->search_resume_name);
+ cifsFile->search_resume_name = NULL;
+ }
+ }
+ rc = CIFSFindFirst(xid, pTcon, full_path, pfindData,
+ &findParms, cifs_sb->local_nls,
+ &Unicode, &UnixSearch);
+ cFYI(1, ("Count: %d End: %d ", findParms.SearchCount,
+ findParms.EndofSearch));
+
+ if (rc == 0) {
+ searchHandle = findParms.SearchHandle;
+ if(file->private_data == NULL)
+ file->private_data =
+ kmalloc(sizeof(struct cifsFileInfo),GFP_KERNEL);
+ if (file->private_data) {
+ memset(file->private_data, 0,
+ sizeof (struct cifsFileInfo));
+ cifsFile =
+ (struct cifsFileInfo *) file->private_data;
+ cifsFile->netfid = searchHandle;
+ cifsFile->invalidHandle = FALSE;
+ init_MUTEX(&cifsFile->fh_sem);
+ } else {
+ rc = -ENOMEM;
+ break;
+ }
+
+ renew_parental_timestamps(file->f_dentry);
+ lastFindData =
+ (FILE_DIRECTORY_INFO *) ((char *) pfindData +
+ findParms.LastNameOffset);
+ if((char *)lastFindData > (char *)pfindData + bufsize) {
+ cFYI(1,("last search entry past end of packet"));
+ rc = -EIO;
+ break;
+ }
+ /* Offset of resume key same for levels 257 and 514 */
+ cifsFile->resume_key = lastFindData->FileIndex;
+ if(UnixSearch == FALSE) {
+ cifsFile->resume_name_length =
+ le32_to_cpu(lastFindData->FileNameLength);
+ if(cifsFile->resume_name_length > bufsize - 64) {
+ cFYI(1,("Illegal resume file name length %d",
+ cifsFile->resume_name_length));
+ rc = -ENOMEM;
+ break;
+ }
+ cifsFile->search_resume_name =
+ kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
+ cFYI(1,("Last file: %s with name %d bytes long",
+ lastFindData->FileName,
+ cifsFile->resume_name_length));
+ memcpy(cifsFile->search_resume_name,
+ lastFindData->FileName,
+ cifsFile->resume_name_length);
+ } else {
+ pfindDataUnix = (FILE_UNIX_INFO *)lastFindData;
+ if (Unicode == TRUE) {
+ for(i=0;(pfindDataUnix->FileName[i]
+ | pfindDataUnix->FileName[i+1]);
+ i+=2) {
+ if(i > bufsize-64)
+ break;
+ }
+ cifsFile->resume_name_length = i + 2;
+ } else {
+ cifsFile->resume_name_length =
+ strnlen(pfindDataUnix->FileName,
+ bufsize-63);
+ }
+ if(cifsFile->resume_name_length > bufsize - 64) {
+ cFYI(1,("Illegal resume file name length %d",
+ cifsFile->resume_name_length));
+ rc = -ENOMEM;
+ break;
+ }
+ cifsFile->search_resume_name =
+ kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
+ cFYI(1,("Last file: %s with name %d bytes long",
+ pfindDataUnix->FileName,
+ cifsFile->resume_name_length));
+ memcpy(cifsFile->search_resume_name,
+ pfindDataUnix->FileName,
+ cifsFile->resume_name_length);
+ }
+ for (i = 2; i < (unsigned int)findParms.SearchCount + 2; i++) {
+ if (UnixSearch == FALSE) {
+ pfindData->FileNameLength =
+ le32_to_cpu(pfindData->FileNameLength);
+ if (Unicode == TRUE)
+ pfindData->FileNameLength =
+ cifs_strfromUCS_le
+ (pfindData->FileName,
+ (wchar_t *)
+ pfindData->FileName,
+ (pfindData->
+ FileNameLength) / 2,
+ cifs_sb->local_nls);
+ qstring.len = pfindData->FileNameLength;
+ if (((qstring.len != 1)
+ || (pfindData->FileName[0] != '.'))
+ && ((qstring.len != 2)
+ || (pfindData->
+ FileName[0] != '.')
+ || (pfindData->
+ FileName[1] != '.'))) {
+ if(cifs_filldir(&qstring,
+ pfindData,
+ file, filldir,
+ direntry)) {
+ /* do not end search if
+ kernel not ready to take
+ remaining entries yet */
+ reset_resume_key(file, pfindData->FileName,qstring.len,
+ Unicode, cifs_sb->local_nls);
+ findParms.EndofSearch = 0;
+ break;
+ }
+ file->f_pos++;
+ }
+ } else { /* UnixSearch */
+ pfindDataUnix =
+ (FILE_UNIX_INFO *) pfindData;
+ if (Unicode == TRUE)
+ qstring.len =
+ cifs_strfromUCS_le
+ (pfindDataUnix->FileName,
+ (wchar_t *)
+ pfindDataUnix->FileName,
+ MAX_PATHCONF,
+ cifs_sb->local_nls);
+ else
+ qstring.len =
+ strnlen(pfindDataUnix->
+ FileName,
+ MAX_PATHCONF);
+ if (((qstring.len != 1)
+ || (pfindDataUnix->
+ FileName[0] != '.'))
+ && ((qstring.len != 2)
+ || (pfindDataUnix->
+ FileName[0] != '.')
+ || (pfindDataUnix->
+ FileName[1] != '.'))) {
+ if(cifs_filldir_unix(&qstring,
+ pfindDataUnix,
+ file,
+ filldir,
+ direntry)) {
+ /* do not end search if
+ kernel not ready to take
+ remaining entries yet */
+ findParms.EndofSearch = 0;
+ reset_resume_key(file, pfindDataUnix->FileName,
+ qstring.len,Unicode,cifs_sb->local_nls);
+ break;
+ }
+ file->f_pos++;
+ }
+ }
+ /* works also for Unix ff struct since first field of both */
+ pfindData =
+ (FILE_DIRECTORY_INFO *) ((char *) pfindData
+ + le32_to_cpu(pfindData->NextEntryOffset));
+ /* BB also should check to make sure that pointer is not beyond the end of the SMB */
+ /* if(pfindData > lastFindData) rc = -EIO; break; */
+ } /* end for loop */
+ if ((findParms.EndofSearch != 0) && cifsFile) {
+ cifsFile->endOfSearch = TRUE;
+ if(findParms.SearchCount == 2)
+ cifsFile->emptyDir = TRUE;
+ }
+ } else {
+ if (cifsFile)
+ cifsFile->endOfSearch = TRUE;
+ /* unless parent directory gone do not return error */
+ rc = 0;
+ }
+ break;
+ default:
+ if (file->private_data == NULL) {
+ rc = -EBADF;
+ cFYI(1,
+ ("Readdir on closed srch, pos = %lld",
+ file->f_pos));
+ } else {
+ cifsFile = (struct cifsFileInfo *) file->private_data;
+ if (cifsFile->endOfSearch) {
+ rc = 0;
+ cFYI(1, ("End of search "));
+ break;
+ }
+ searchHandle = cifsFile->netfid;
+ rc = CIFSFindNext(xid, pTcon, pfindData,
+ &findNextParms, searchHandle,
+ cifsFile->search_resume_name,
+ cifsFile->resume_name_length,
+ cifsFile->resume_key,
+ &Unicode, &UnixSearch);
+ cFYI(1,("Count: %d End: %d ",
+ findNextParms.SearchCount,
+ findNextParms.EndofSearch));
+ if ((rc == 0) && (findNextParms.SearchCount != 0)) {
+ /* BB save off resume key, key name and name length */
+ lastFindData =
+ (FILE_DIRECTORY_INFO *) ((char *) pfindData
+ + findNextParms.LastNameOffset);
+ if((char *)lastFindData > (char *)pfindData + bufsize) {
+ cFYI(1,("last search entry past end of packet"));
+ rc = -EIO;
+ break;
+ }
+ /* Offset of resume key same for levels 257 and 514 */
+ cifsFile->resume_key = lastFindData->FileIndex;
+
+ if(UnixSearch == FALSE) {
+ cifsFile->resume_name_length =
+ le32_to_cpu(lastFindData->FileNameLength);
+ if(cifsFile->resume_name_length > bufsize - 64) {
+ cFYI(1,("Illegal resume file name length %d",
+ cifsFile->resume_name_length));
+ rc = -ENOMEM;
+ break;
+ }
+ /* Free the memory allocated by previous findfirst
+ or findnext call - we can not reuse the memory since
+ the resume name may not be same string length */
+ if(cifsFile->search_resume_name)
+ kfree(cifsFile->search_resume_name);
+ cifsFile->search_resume_name =
+ kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
+ cFYI(1,("Last file: %s with name %d bytes long",
+ lastFindData->FileName,
+ cifsFile->resume_name_length));
+ memcpy(cifsFile->search_resume_name,
+ lastFindData->FileName,
+ cifsFile->resume_name_length);
+ } else {
+ pfindDataUnix = (FILE_UNIX_INFO *)lastFindData;
+ if (Unicode == TRUE) {
+ for(i=0;(pfindDataUnix->FileName[i]
+ | pfindDataUnix->FileName[i+1]);
+ i+=2) {
+ if(i > bufsize-64)
+ break;
+ }
+ cifsFile->resume_name_length = i + 2;
+ } else {
+ cifsFile->resume_name_length =
+ strnlen(pfindDataUnix->
+ FileName,
+ MAX_PATHCONF);
+ }
+ if(cifsFile->resume_name_length > bufsize - 64) {
+ cFYI(1,("Illegal resume file name length %d",
+ cifsFile->resume_name_length));
+ rc = -ENOMEM;
+ break;
+ }
+ /* Free the memory allocated by previous findfirst
+ or findnext call - we can not reuse the memory since
+ the resume name may not be same string length */
+ if(cifsFile->search_resume_name)
+ kfree(cifsFile->search_resume_name);
+ cifsFile->search_resume_name =
+ kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
+ cFYI(1,("fnext last file: %s with name %d bytes long",
+ pfindDataUnix->FileName,
+ cifsFile->resume_name_length));
+ memcpy(cifsFile->search_resume_name,
+ pfindDataUnix->FileName,
+ cifsFile->resume_name_length);
+ }
+
+ for (i = 0; i < findNextParms.SearchCount; i++) {
+ pfindData->FileNameLength =
+ le32_to_cpu(pfindData->
+ FileNameLength);
+ if (UnixSearch == FALSE) {
+ if (Unicode == TRUE)
+ pfindData->FileNameLength =
+ cifs_strfromUCS_le
+ (pfindData->FileName,
+ (wchar_t *)
+ pfindData->FileName,
+ (pfindData->FileNameLength)/ 2,
+ cifs_sb->local_nls);
+ qstring.len =
+ pfindData->FileNameLength;
+ if (((qstring.len != 1)
+ || (pfindData->FileName[0] != '.'))
+ && ((qstring.len != 2)
+ || (pfindData->FileName[0] != '.')
+ || (pfindData->FileName[1] !=
+ '.'))) {
+ if(cifs_filldir
+ (&qstring,
+ pfindData,
+ file, filldir,
+ direntry)) {
+ /* do not end search if
+ kernel not ready to take
+ remaining entries yet */
+ findNextParms.EndofSearch = 0;
+ reset_resume_key(file, pfindData->FileName,qstring.len,
+ Unicode,cifs_sb->local_nls);
+ break;
+ }
+ file->f_pos++;
+ }
+ } else { /* UnixSearch */
+ pfindDataUnix =
+ (FILE_UNIX_INFO *)
+ pfindData;
+ if (Unicode == TRUE)
+ qstring.len =
+ cifs_strfromUCS_le
+ (pfindDataUnix->FileName,
+ (wchar_t *)
+ pfindDataUnix->FileName,
+ MAX_PATHCONF,
+ cifs_sb->local_nls);
+ else
+ qstring.len =
+ strnlen
+ (pfindDataUnix->
+ FileName,
+ MAX_PATHCONF);
+ if (((qstring.len != 1)
+ || (pfindDataUnix->
+ FileName[0] != '.'))
+ && ((qstring.len != 2)
+ || (pfindDataUnix->
+ FileName[0] != '.')
+ || (pfindDataUnix->
+ FileName[1] !=
+ '.'))) {
+ if(cifs_filldir_unix
+ (&qstring,
+ pfindDataUnix,
+ file, filldir,
+ direntry)) {
+ /* do not end search if
+ kernel not ready to take
+ remaining entries yet */
+ findNextParms.EndofSearch = 0;
+ reset_resume_key(file, pfindDataUnix->FileName,qstring.len,
+ Unicode,cifs_sb->local_nls);
+ break;
+ }
+ file->f_pos++;
+ }
+ }
+ pfindData = (FILE_DIRECTORY_INFO *) ((char *) pfindData + le32_to_cpu(pfindData->NextEntryOffset)); /* works also for Unix find struct since this is the first field of both */
+ /* BB also should check to make sure that pointer is not beyond the end of the SMB */
+ } /* end for loop */
+ if (findNextParms.EndofSearch != 0) {
+ cifsFile->endOfSearch = TRUE;
+ }
+ } else {
+ cifsFile->endOfSearch = TRUE;
+ rc = 0; /* unless parent directory disappeared - do not return error here (eg Access Denied or no more files) */
+ }
+ }
+ } /* end switch */
+ if (data)
+ kfree(data);
+ if (full_path)
+ kfree(full_path);
+ FreeXid(xid);
+
+ return rc;
+}
+int cifs_prepare_write(struct file *file, struct page *page,
+ unsigned from, unsigned to)
+{
+ int rc = 0;
+ loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
+ cFYI(1,("prepare write for page %p from %d to %d",page,from,to));
+ if (!Page_Uptodate(page)) {
+ /* if (to - from != PAGE_CACHE_SIZE) {
+ void *kaddr = kmap_atomic(page, KM_USER0);
+ memset(kaddr, 0, from);
+ memset(kaddr + to, 0, PAGE_CACHE_SIZE - to);
+ flush_dcache_page(page);
+ kunmap_atomic(kaddr, KM_USER0);
+ } */
+ /* If we are writing a full page it will be up to date,
+ no need to read from the server */
+ if((to==PAGE_CACHE_SIZE) && (from == 0))
+ SetPageUptodate(page);
+
+ /* might as well read a page, it is fast enough */
+ if((file->f_flags & O_ACCMODE) != O_WRONLY) {
+ rc = cifs_readpage_worker(file,page,&offset);
+ } else {
+ /* should we try using another
+ file handle if there is one - how would we lock it
+ to prevent close of that handle racing with this read? */
+ /* In any case this will be written out by commit_write */
+ }
+ }
+
+ /* BB should we pass any errors back? e.g. if we do not have read access to the file */
+ return 0;
+}
+
+
+struct address_space_operations cifs_addr_ops = {
+ .readpage = cifs_readpage,
+/* .readpages = cifs_readpages, */
+ .writepage = cifs_writepage,
+ .prepare_write = cifs_prepare_write,
+ .commit_write = cifs_commit_write,
+ .sync_page = cifs_sync_page,
+ /*.direct_IO = */
+};
diff --git a/release/src/linux/linux/fs/cifs/inode.c b/release/src/linux/linux/fs/cifs/inode.c
new file mode 100644
index 00000000..dce55552
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/inode.c
@@ -0,0 +1,1079 @@
+/*
+ * fs/cifs/inode.c
+ *
+ * Copyright (C) International Business Machines Corp., 2002,2003
+ * Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/pagemap.h>
+#include <linux/version.h>
+#include <asm/div64.h>
+#include "cifsfs.h"
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_debug.h"
+#include "cifs_fs_sb.h"
+
+extern int is_size_safe_to_change(struct cifsInodeInfo *);
+
+struct inode * get_cifs_inode(struct super_block * sb)
+{
+ struct inode * newinode;
+ newinode = new_inode(sb);
+ cFYI(1,("got new inode %p",newinode));
+ if(newinode) {
+ struct cifsInodeInfo * cifsInfo = CIFS_I(newinode);
+ cifsInfo->clientCanCacheRead = FALSE;
+ cifsInfo->clientCanCacheAll = FALSE;
+ INIT_LIST_HEAD(&cifsInfo->openFileList);
+ cifsInfo->cifsAttrs = 0x20; /* default */
+ newinode->i_blksize = CIFS_MAX_MSGSIZE;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,15))
+ newinode->i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */
+#endif
+ atomic_set(&cifsInfo->inUse, 0);
+ cifsInfo->time = 0;
+ insert_inode_hash(newinode);
+ }
+ return newinode;
+
+}
+
+int
+cifs_get_inode_info_unix(struct inode **pinode,
+ const unsigned char *search_path,
+ struct super_block *sb,int xid)
+{
+ int rc = 0;
+ FILE_UNIX_BASIC_INFO findData;
+ struct cifsTconInfo *pTcon;
+ struct inode *inode;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+ char *tmp_path;
+
+ pTcon = cifs_sb->tcon;
+ cFYI(1, (" Getting info on %s ", search_path));
+ /* we could have done a find first instead but this returns more info */
+ rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData,
+ cifs_sb->local_nls);
+ /* dump_mem("\nUnixQPathInfo return data", &findData, sizeof(findData)); */
+ if (rc) {
+ if (rc == -EREMOTE) {
+ tmp_path =
+ kmalloc(strnlen
+ (pTcon->treeName,
+ MAX_TREE_SIZE + 1) +
+ strnlen(search_path, MAX_PATHCONF) + 1,
+ GFP_KERNEL);
+ if (tmp_path == NULL) {
+ return -ENOMEM;
+ }
+ /* have to skip first of the double backslash of UNC name */
+ strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
+ strncat(tmp_path, search_path, MAX_PATHCONF);
+ rc = connect_to_dfs_path(xid, pTcon->ses,
+ /* treename + */ tmp_path,
+ cifs_sb->local_nls);
+ kfree(tmp_path);
+
+ /* BB fix up inode etc. */
+ } else if (rc) {
+ return rc;
+ }
+
+ } else {
+ struct cifsInodeInfo *cifsInfo;
+
+ /* get new inode */
+ if (*pinode == NULL) {
+ *pinode = get_cifs_inode(sb);
+ }
+ if(*pinode == NULL) {
+ return -ENOMEM;
+ }
+
+ inode = *pinode;
+ cifsInfo = CIFS_I(inode);
+
+ cFYI(1, (" Old time %ld ", cifsInfo->time));
+ cifsInfo->time = jiffies;
+ cFYI(1, (" New time %ld ", cifsInfo->time));
+ atomic_set(&cifsInfo->inUse,1); /* ok to set on every refresh of inode */
+
+ inode->i_atime =
+ cifs_NTtimeToUnix(le64_to_cpu(findData.LastAccessTime));
+ inode->i_mtime =
+ cifs_NTtimeToUnix(le64_to_cpu
+ (findData.LastModificationTime));
+ inode->i_ctime =
+ cifs_NTtimeToUnix(le64_to_cpu(findData.LastStatusChange));
+ inode->i_mode = le64_to_cpu(findData.Permissions);
+ findData.Type = le32_to_cpu(findData.Type);
+ if (findData.Type == UNIX_FILE) {
+ inode->i_mode |= S_IFREG;
+ } else if (findData.Type == UNIX_SYMLINK) {
+ inode->i_mode |= S_IFLNK;
+ } else if (findData.Type == UNIX_DIR) {
+ inode->i_mode |= S_IFDIR;
+ } else if (findData.Type == UNIX_CHARDEV) {
+ inode->i_mode |= S_IFCHR;
+ inode->i_rdev = MKDEV(le64_to_cpu(findData.DevMajor),
+ le64_to_cpu(findData.DevMinor) & MINORMASK);
+ } else if (findData.Type == UNIX_BLOCKDEV) {
+ inode->i_mode |= S_IFBLK;
+ inode->i_rdev = MKDEV(le64_to_cpu(findData.DevMajor),
+ le64_to_cpu(findData.DevMinor) & MINORMASK);
+ } else if (findData.Type == UNIX_FIFO) {
+ inode->i_mode |= S_IFIFO;
+ } else if (findData.Type == UNIX_SOCKET) {
+ inode->i_mode |= S_IFSOCK;
+ }
+ inode->i_uid = le64_to_cpu(findData.Uid);
+ inode->i_gid = le64_to_cpu(findData.Gid);
+ inode->i_nlink = le64_to_cpu(findData.Nlinks);
+ findData.NumOfBytes = le64_to_cpu(findData.NumOfBytes);
+ findData.EndOfFile = le64_to_cpu(findData.EndOfFile);
+
+ if(is_size_safe_to_change(cifsInfo)) {
+ /* can not safely change the file size here if the
+ client is writing to it due to potential races */
+ inode->i_size = findData.EndOfFile;
+/* blksize needs to be multiple of two. So safer to default to blksize
+ and blkbits set in superblock so 2**blkbits and blksize will match */
+/* inode->i_blksize =
+ (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
+
+ /* This seems incredibly stupid but it turns out that
+ i_blocks is not related to (i_size / i_blksize), instead a
+ size of 512 is required to be used for calculating num blocks */
+
+
+/* inode->i_blocks =
+ (inode->i_blksize - 1 + findData.NumOfBytes) >> inode->i_blkbits;*/
+
+ /* 512 bytes (2**9) is the fake blocksize that must be used */
+ /* for this calculation */
+ inode->i_blocks = (512 - 1 + findData.NumOfBytes) >> 9;
+ }
+
+ if (findData.NumOfBytes < findData.EndOfFile)
+ cFYI(1, ("Server inconsistency Error: it says allocation size less than end of file "));
+ cFYI(1,
+ ("Size %ld and blocks %ld ",
+ (unsigned long) inode->i_size, inode->i_blocks));
+ if (S_ISREG(inode->i_mode)) {
+ cFYI(1, (" File inode "));
+ inode->i_op = &cifs_file_inode_ops;
+ inode->i_fop = &cifs_file_ops;
+ inode->i_data.a_ops = &cifs_addr_ops;
+ } else if (S_ISDIR(inode->i_mode)) {
+ cFYI(1, (" Directory inode"));
+ inode->i_op = &cifs_dir_inode_ops;
+ inode->i_fop = &cifs_dir_ops;
+ } else if (S_ISLNK(inode->i_mode)) {
+ cFYI(1, (" Symbolic Link inode "));
+ inode->i_op = &cifs_symlink_inode_ops;
+/* tmp_inode->i_fop = *//* do not need to set to anything */
+ } else {
+ cFYI(1, (" Init special inode "));
+ init_special_inode(inode, inode->i_mode,
+ kdev_t_to_nr(inode->i_rdev));
+ }
+ }
+ return rc;
+}
+
+int
+cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path,
+ FILE_ALL_INFO * pfindData, struct super_block *sb, int xid)
+{
+ int rc = 0;
+ struct cifsTconInfo *pTcon;
+ struct inode *inode;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+ char *tmp_path;
+ char *buf = NULL;
+
+ pTcon = cifs_sb->tcon;
+ cFYI(1,("Getting info on %s ", search_path));
+
+ if((pfindData == NULL) && (*pinode != NULL)) {
+ if(CIFS_I(*pinode)->clientCanCacheRead) {
+ cFYI(1,("No need to revalidate inode sizes on cached file "));
+ return rc;
+ }
+ }
+
+ /* if file info not passed in then get it from server */
+ if(pfindData == NULL) {
+ buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
+ pfindData = (FILE_ALL_INFO *)buf;
+ /* could do find first instead but this returns more info */
+ rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData,
+ cifs_sb->local_nls);
+ }
+ /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
+ if (rc) {
+ if (rc == -EREMOTE) {
+ tmp_path =
+ kmalloc(strnlen
+ (pTcon->treeName,
+ MAX_TREE_SIZE + 1) +
+ strnlen(search_path, MAX_PATHCONF) + 1,
+ GFP_KERNEL);
+ if (tmp_path == NULL) {
+ if(buf)
+ kfree(buf);
+ return -ENOMEM;
+ }
+
+ strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
+ strncat(tmp_path, search_path, MAX_PATHCONF);
+ rc = connect_to_dfs_path(xid, pTcon->ses,
+ /* treename + */ tmp_path,
+ cifs_sb->local_nls);
+ kfree(tmp_path);
+ /* BB fix up inode etc. */
+ } else if (rc) {
+ if(buf)
+ kfree(buf);
+ return rc;
+ }
+ } else {
+ struct cifsInodeInfo *cifsInfo;
+
+ /* get new inode */
+ if (*pinode == NULL) {
+ *pinode = get_cifs_inode(sb);
+ }
+ if(*pinode == NULL)
+ return -ENOMEM;
+ inode = *pinode;
+ cifsInfo = CIFS_I(inode);
+ pfindData->Attributes = le32_to_cpu(pfindData->Attributes);
+ cifsInfo->cifsAttrs = pfindData->Attributes;
+ cFYI(1, (" Old time %ld ", cifsInfo->time));
+ cifsInfo->time = jiffies;
+ cFYI(1, (" New time %ld ", cifsInfo->time));
+
+/* blksize needs to be multiple of two. So safer to default to blksize
+ and blkbits set in superblock so 2**blkbits and blksize will match */
+/* inode->i_blksize =
+ (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
+
+ /* Linux can not store file creation time unfortunately so we ignore it */
+ inode->i_atime =
+ cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
+ inode->i_mtime =
+ cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
+ inode->i_ctime =
+ cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
+ cFYI(0,
+ (" Attributes came in as 0x%x ", pfindData->Attributes));
+
+ /* set default mode. will override for dirs below */
+ if(atomic_read(&cifsInfo->inUse) == 0)
+ /* new inode, can safely set these fields */
+ inode->i_mode = cifs_sb->mnt_file_mode;
+
+ if (pfindData->Attributes & ATTR_REPARSE) {
+ /* Can IFLNK be set as it basically is on windows with IFREG or IFDIR? */
+ inode->i_mode |= S_IFLNK;
+ } else if (pfindData->Attributes & ATTR_DIRECTORY) {
+ /* override default perms since we do not do byte range locking on dirs */
+ inode->i_mode = cifs_sb->mnt_dir_mode;
+ inode->i_mode |= S_IFDIR;
+ } else {
+ inode->i_mode |= S_IFREG;
+ /* treat the dos attribute of read-only as read-only mode e.g. 555 */
+ if(cifsInfo->cifsAttrs & ATTR_READONLY)
+ inode->i_mode &= ~(S_IWUGO);
+ /* BB add code here - validate if device or weird share or device type? */
+ }
+ if(is_size_safe_to_change(cifsInfo)) {
+ /* can not safely change the file size here if the
+ client is writing to it due to potential races */
+ inode->i_size = le64_to_cpu(pfindData->EndOfFile);
+
+ /* 512 bytes (2**9) is the fake blocksize that must be used */
+ /* for this calculation */
+ inode->i_blocks = (512 - 1 + pfindData->AllocationSize)
+ >> 9;
+ }
+ pfindData->AllocationSize = le64_to_cpu(pfindData->AllocationSize);
+
+ cFYI(1,
+ (" Size %ld and blocks %ld ",
+ (unsigned long) inode->i_size, inode->i_blocks));
+ inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks);
+
+ /* BB fill in uid and gid here? with help from winbind?
+ or retrieve from NTFS stream extended attribute */
+ if(atomic_read(&cifsInfo->inUse) == 0) {
+ inode->i_uid = cifs_sb->mnt_uid;
+ inode->i_gid = cifs_sb->mnt_gid;
+ /* set so we do not keep refreshing these fields with
+ bad data after user has changed them in memory */
+ atomic_set(&cifsInfo->inUse,1);
+ }
+
+ if (S_ISREG(inode->i_mode)) {
+ cFYI(1, (" File inode "));
+ inode->i_op = &cifs_file_inode_ops;
+ inode->i_fop = &cifs_file_ops;
+ inode->i_data.a_ops = &cifs_addr_ops;
+ } else if (S_ISDIR(inode->i_mode)) {
+ cFYI(1, (" Directory inode "));
+ inode->i_op = &cifs_dir_inode_ops;
+ inode->i_fop = &cifs_dir_ops;
+ } else if (S_ISLNK(inode->i_mode)) {
+ cFYI(1, (" Symbolic Link inode "));
+ inode->i_op = &cifs_symlink_inode_ops;
+ } else {
+ init_special_inode(inode, inode->i_mode,
+ kdev_t_to_nr(inode->i_rdev));
+ }
+ }
+ if(buf)
+ kfree(buf);
+ return rc;
+}
+
+void
+cifs_read_inode(struct inode *inode)
+{ /* gets root inode */
+ int xid;
+ struct cifs_sb_info *cifs_sb;
+ struct cifsInodeInfo *cifs_inode;
+
+ cifs_sb = CIFS_SB(inode->i_sb);
+ xid = GetXid();
+
+ cifs_inode = CIFS_I(inode);
+ cifs_inode->cifsAttrs = ATTR_DIRECTORY;
+ atomic_set(&cifs_inode->inUse, 0);
+ cifs_inode->time = 0;
+ inode->i_blksize = CIFS_MAX_MSGSIZE;
+ inode->i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */
+
+ INIT_LIST_HEAD(&cifs_inode->openFileList);
+
+ if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
+ cifs_get_inode_info_unix(&inode, "", inode->i_sb,xid);
+ else
+ cifs_get_inode_info(&inode, "", NULL, inode->i_sb,xid);
+ /* can not call macro FreeXid here since in a void func */
+ _FreeXid(xid);
+}
+
+int
+cifs_unlink(struct inode *inode, struct dentry *direntry)
+{
+ int rc = 0;
+ int xid;
+ struct cifs_sb_info *cifs_sb;
+ struct cifsTconInfo *pTcon;
+ char *full_path = NULL;
+ struct cifsInodeInfo *cifsInode;
+ FILE_BASIC_INFO * pinfo_buf;
+
+ cFYI(1, (" cifs_unlink, inode = 0x%p with ", inode));
+
+ xid = GetXid();
+
+ cifs_sb = CIFS_SB(inode->i_sb);
+ pTcon = cifs_sb->tcon;
+
+/* Unlink can be called from rename so we can not grab
+ the sem here since we deadlock otherwise */
+/* down(&direntry->d_sb->s_vfs_rename_sem);*/
+ full_path = build_path_from_dentry(direntry);
+/* up(&direntry->d_sb->s_vfs_rename_sem);*/
+ if(full_path == NULL) {
+ FreeXid(xid);
+ return -ENOMEM;
+ }
+ rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls);
+
+ if (!rc) {
+ direntry->d_inode->i_nlink--;
+ } else if (rc == -ENOENT) {
+ d_drop(direntry);
+ } else if (rc == -ETXTBSY) {
+ int oplock = FALSE;
+ __u16 netfid;
+
+ rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
+ CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
+ &netfid, &oplock, NULL, cifs_sb->local_nls);
+ if(rc==0) {
+ CIFSSMBRenameOpenFile(xid,pTcon,netfid,
+ NULL, cifs_sb->local_nls);
+ CIFSSMBClose(xid, pTcon, netfid);
+ direntry->d_inode->i_nlink--;
+ }
+ } else if (rc == -EACCES) {
+ /* try only if r/o attribute set in local lookup data? */
+ pinfo_buf = (FILE_BASIC_INFO *)kmalloc(sizeof(FILE_BASIC_INFO),GFP_KERNEL);
+ if(pinfo_buf) {
+ memset(pinfo_buf,0,sizeof(FILE_BASIC_INFO));
+ /* ATTRS set to normal clears r/o bit */
+ pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL);
+ rc = CIFSSMBSetTimes(xid, pTcon, full_path, pinfo_buf,
+ cifs_sb->local_nls);
+ kfree(pinfo_buf);
+ }
+ if(rc==0) {
+ rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls);
+ if (!rc) {
+ direntry->d_inode->i_nlink--;
+ } else if (rc == -ETXTBSY) {
+ int oplock = FALSE;
+ __u16 netfid;
+
+ rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
+ CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
+ &netfid, &oplock, NULL, cifs_sb->local_nls);
+ if(rc==0) {
+ CIFSSMBRenameOpenFile(xid,pTcon,netfid,NULL,cifs_sb->local_nls);
+ CIFSSMBClose(xid, pTcon, netfid);
+ direntry->d_inode->i_nlink--;
+ }
+ /* BB if rc = -ETXTBUSY goto the rename logic BB */
+ }
+ }
+ }
+ cifsInode = CIFS_I(direntry->d_inode);
+ cifsInode->time = 0; /* will force revalidate to get info when needed */
+ direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
+ CURRENT_TIME;
+ cifsInode = CIFS_I(inode);
+ cifsInode->time = 0; /* force revalidate of dir as well */
+
+ if (full_path)
+ kfree(full_path);
+ FreeXid(xid);
+ return rc;
+}
+
+int
+cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
+{
+ int rc = 0;
+ int xid;
+ struct cifs_sb_info *cifs_sb;
+ struct cifsTconInfo *pTcon;
+ char *full_path = NULL;
+ struct inode *newinode = NULL;
+
+ cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p ", mode, inode));
+
+ xid = GetXid();
+
+ cifs_sb = CIFS_SB(inode->i_sb);
+ pTcon = cifs_sb->tcon;
+
+ down(&inode->i_sb->s_vfs_rename_sem);
+ full_path = build_path_from_dentry(direntry);
+ up(&inode->i_sb->s_vfs_rename_sem);
+ if(full_path == NULL) {
+ FreeXid(xid);
+ return -ENOMEM;
+ }
+ /* BB add setting the equivalent of mode via CreateX w/ACLs */
+ rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls);
+ if (rc) {
+ cFYI(1, ("cifs_mkdir returned 0x%x ", rc));
+ d_drop(direntry);
+ } else {
+ inode->i_nlink++;
+ if (pTcon->ses->capabilities & CAP_UNIX)
+ rc = cifs_get_inode_info_unix(&newinode, full_path,
+ inode->i_sb,xid);
+ else
+ rc = cifs_get_inode_info(&newinode, full_path,NULL,
+ inode->i_sb,xid);
+
+ direntry->d_op = &cifs_dentry_ops;
+ d_instantiate(direntry, newinode);
+ if(direntry->d_inode)
+ direntry->d_inode->i_nlink = 2;
+ if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
+ CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
+ (__u64)-1,
+ (__u64)-1,
+ 0 /* dev_t */,
+ cifs_sb->local_nls);
+ else { /* BB to be implemented via Windows secrty descriptors*/
+ /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/
+ }
+ }
+ if (full_path)
+ kfree(full_path);
+ FreeXid(xid);
+
+ return rc;
+}
+
+int
+cifs_rmdir(struct inode *inode, struct dentry *direntry)
+{
+ int rc = 0;
+ int xid;
+ struct cifs_sb_info *cifs_sb;
+ struct cifsTconInfo *pTcon;
+ char *full_path = NULL;
+ struct cifsInodeInfo *cifsInode;
+
+ cFYI(1, (" cifs_rmdir, inode = 0x%p with ", inode));
+
+ xid = GetXid();
+
+ cifs_sb = CIFS_SB(inode->i_sb);
+ pTcon = cifs_sb->tcon;
+
+ down(&inode->i_sb->s_vfs_rename_sem);
+ full_path = build_path_from_dentry(direntry);
+ up(&inode->i_sb->s_vfs_rename_sem);
+ if(full_path == NULL) {
+ FreeXid(xid);
+ return -ENOMEM;
+ }
+
+ rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls);
+
+ if (!rc) {
+ inode->i_nlink--;
+ direntry->d_inode->i_size = 0;
+ direntry->d_inode->i_nlink = 0;
+ }
+
+ cifsInode = CIFS_I(direntry->d_inode);
+ cifsInode->time = 0; /* force revalidate to go get info when needed */
+ direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
+ CURRENT_TIME;
+
+ if (full_path)
+ kfree(full_path);
+ FreeXid(xid);
+ return rc;
+}
+
+int
+cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
+ struct inode *target_inode, struct dentry *target_direntry)
+{
+ char *fromName;
+ char *toName;
+ struct cifs_sb_info *cifs_sb_source;
+ struct cifs_sb_info *cifs_sb_target;
+ struct cifsTconInfo *pTcon;
+ int xid;
+ int rc = 0;
+
+ xid = GetXid();
+
+ cifs_sb_target = CIFS_SB(target_inode->i_sb);
+ cifs_sb_source = CIFS_SB(source_inode->i_sb);
+ pTcon = cifs_sb_source->tcon;
+
+ if (pTcon != cifs_sb_target->tcon) {
+ FreeXid(xid);
+ return -EXDEV; /* BB actually could be allowed if same server, but
+ different share. Might eventually add support for this */
+ }
+
+ /* we already have the rename sem so we do not need
+ to grab it again here to protect the path integrity */
+ fromName = build_path_from_dentry(source_direntry);
+ toName = build_path_from_dentry(target_direntry);
+ if((fromName == NULL) || (toName == NULL)) {
+ rc = -ENOMEM;
+ goto cifs_rename_exit;
+ }
+
+ rc = CIFSSMBRename(xid, pTcon, fromName, toName,
+ cifs_sb_source->local_nls);
+ if(rc == -EEXIST) {
+ /* check if they are the same file
+ because rename of hardlinked files is a noop */
+ FILE_UNIX_BASIC_INFO * info_buf_source;
+ FILE_UNIX_BASIC_INFO * info_buf_target;
+
+ info_buf_source =
+ kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO),GFP_KERNEL);
+ if(info_buf_source != NULL) {
+ info_buf_target = info_buf_source+1;
+ rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName,
+ info_buf_source, cifs_sb_source->local_nls);
+ if(rc == 0) {
+ rc = CIFSSMBUnixQPathInfo(xid,pTcon,toName,
+ info_buf_target,
+ cifs_sb_target->local_nls);
+ }
+ if((rc == 0) &&
+ (info_buf_source->UniqueId ==
+ info_buf_target->UniqueId)) {
+ /* do not rename since the files are hardlinked
+ which is a noop */
+ } else {
+ /* we either can not tell the files are hardlinked
+ (as with Windows servers) or files are not hardlinked
+ so delete the target manually before renaming to
+ follow POSIX rather than Windows semantics */
+ cifs_unlink(target_inode, target_direntry);
+ rc = CIFSSMBRename(xid, pTcon, fromName, toName,
+ cifs_sb_source->local_nls);
+ }
+ kfree(info_buf_source);
+ } /* if we can not get memory just leave rc as EEXIST */
+ }
+
+ if((rc == -EIO)||(rc == -EEXIST)) {
+ int oplock = FALSE;
+ __u16 netfid;
+
+ rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ,
+ CREATE_NOT_DIR,
+ &netfid, &oplock, NULL, cifs_sb_source->local_nls);
+ if(rc==0) {
+ CIFSSMBRenameOpenFile(xid,pTcon,netfid,
+ toName, cifs_sb_source->local_nls);
+ CIFSSMBClose(xid, pTcon, netfid);
+ }
+ }
+
+cifs_rename_exit:
+ if (fromName)
+ kfree(fromName);
+ if (toName)
+ kfree(toName);
+
+ FreeXid(xid);
+ return rc;
+}
+
+int
+cifs_revalidate(struct dentry *direntry)
+{
+ int xid;
+ int rc = 0;
+ char *full_path;
+ struct cifs_sb_info *cifs_sb;
+ struct cifsInodeInfo *cifsInode;
+ loff_t local_size;
+ time_t local_mtime;
+ int invalidate_inode = FALSE;
+
+ if(direntry->d_inode == NULL)
+ return -ENOENT;
+
+ cifsInode = CIFS_I(direntry->d_inode);
+
+ if(cifsInode == NULL)
+ return -ENOENT;
+
+ /* no sense revalidating inode info on file that no one can write */
+ if(CIFS_I(direntry->d_inode)->clientCanCacheRead)
+ return rc;
+
+ xid = GetXid();
+
+ cifs_sb = CIFS_SB(direntry->d_sb);
+
+ /* can not safely grab the rename sem here if
+ rename calls revalidate since that would deadlock */
+ full_path = build_path_from_dentry(direntry);
+ if(full_path == NULL) {
+ FreeXid(xid);
+ return -ENOMEM;
+ }
+ cFYI(1,
+ ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld jiffies %ld",
+ full_path, direntry->d_inode,
+ direntry->d_inode->i_count.counter, direntry,
+ direntry->d_time, jiffies));
+
+ if (cifsInode->time == 0){
+ /* was set to zero previously to force revalidate */
+ } else if (time_before(jiffies, cifsInode->time + HZ) && lookupCacheEnabled) {
+ if((S_ISREG(direntry->d_inode->i_mode) == 0) ||
+ (direntry->d_inode->i_nlink == 1)) {
+ if (full_path)
+ kfree(full_path);
+ FreeXid(xid);
+ return rc;
+ } else {
+ cFYI(1,("Have to revalidate file due to hardlinks"));
+ }
+ }
+
+ /* save mtime and size */
+ local_mtime = direntry->d_inode->i_mtime;
+ local_size = direntry->d_inode->i_size;
+
+ if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) {
+ rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path,
+ direntry->d_sb,xid);
+ if(rc) {
+ cFYI(1,("error on getting revalidate info %d",rc));
+/* if(rc != -ENOENT)
+ rc = 0; */ /* BB should we cache info on certain errors? */
+ }
+ } else {
+ rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL,
+ direntry->d_sb,xid);
+ if(rc) {
+ cFYI(1,("error on getting revalidate info %d",rc));
+/* if(rc != -ENOENT)
+ rc = 0; */ /* BB should we cache info on certain errors? */
+ }
+ }
+ /* should we remap certain errors, access denied?, to zero */
+
+ /* if not oplocked, we invalidate inode pages if mtime
+ or file size had changed on server */
+
+ if((local_mtime == direntry->d_inode->i_mtime) &&
+ (local_size == direntry->d_inode->i_size)) {
+ cFYI(1,("cifs_revalidate - inode unchanged"));
+ } else {
+ /* file may have changed on server */
+ if(cifsInode->clientCanCacheRead) {
+ /* no need to invalidate inode pages since we were
+ the only ones who could have modified the file and
+ the server copy is staler than ours */
+ } else {
+ invalidate_inode = TRUE;
+ }
+ }
+
+ /* can not grab this sem since kernel filesys locking
+ documentation indicates i_sem may be taken by the kernel
+ on lookup and rename which could deadlock if we grab
+ the i_sem here as well */
+/* down(&direntry->d_inode->i_sem);*/
+ /* need to write out dirty pages here */
+ if(direntry->d_inode->i_mapping) {
+ /* do we need to lock inode until after invalidate completes below? */
+ filemap_fdatasync(direntry->d_inode->i_mapping);
+ }
+ if(invalidate_inode) {
+ filemap_fdatawait(direntry->d_inode->i_mapping);
+ /* may eventually have to do this for open files too */
+ if(list_empty(&(cifsInode->openFileList))) {
+ /* Has changed on server - flush read ahead pages */
+ cFYI(1,("Invalidating read ahead data on closed file"));
+ invalidate_inode_pages(direntry->d_inode);
+ }
+ }
+/* up(&direntry->d_inode->i_sem);*/
+
+ if (full_path)
+ kfree(full_path);
+ FreeXid(xid);
+
+ return rc;
+}
+
+/* int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+{
+ int err = cifs_revalidate(dentry);
+ if (!err)
+ generic_fillattr(dentry->d_inode, stat);
+ return err;
+} */
+
+void
+cifs_truncate_file(struct inode *inode)
+{ /* BB remove - may not need this function after all BB */
+ int xid;
+ int rc = -EIO;
+ int found = FALSE;
+ struct cifsFileInfo *open_file = NULL;
+ struct cifs_sb_info *cifs_sb;
+ struct cifsTconInfo *pTcon;
+ struct cifsInodeInfo *cifsInode;
+ struct dentry *dirent;
+ struct list_head * tmp;
+ char *full_path = NULL;
+
+ xid = GetXid();
+
+ cifs_sb = CIFS_SB(inode->i_sb);
+ pTcon = cifs_sb->tcon;
+
+ /* To avoid spurious oplock breaks from server, in the case
+ of inodes that we already have open, avoid doing path
+ based setting of file size if we can do it by handle.
+ This keeps our caching token (oplock) and avoids
+ timeouts when the local oplock break takes longer to flush
+ writebehind data than the SMB timeout for the SetPathInfo
+ request would allow */
+ read_lock(&GlobalSMBSeslock);
+ cifsInode = CIFS_I(inode);
+ list_for_each(tmp, &cifsInode->openFileList) {
+ open_file = list_entry(tmp,struct cifsFileInfo, flist);
+ /* We check if file is open for writing first */
+ if((open_file->pfile) && (!open_file->invalidHandle) &&
+ ((open_file->pfile->f_flags & O_RDWR) ||
+ (open_file->pfile->f_flags & O_WRONLY))) {
+ read_unlock(&GlobalSMBSeslock);
+ found = TRUE;
+ rc = CIFSSMBSetFileSize(xid, pTcon, inode->i_size,
+ open_file->netfid,open_file->pid,FALSE);
+ if(rc == 0) {
+ FreeXid(xid);
+ return;
+ }
+ /* Do not need reopen and retry on EAGAIN since we will
+ retry by pathname below */
+ if(rc == -EAGAIN)
+ rc = -EHOSTDOWN;
+
+ break; /* now that we found one valid file handle no
+ sense continuing to loop trying others */
+ }
+ }
+ if(found == FALSE)
+ read_unlock(&GlobalSMBSeslock);
+
+ if (list_empty(&inode->i_dentry)) {
+ cERROR(1,
+ ("Can not get pathname from empty dentry in inode 0x%p ",
+ inode));
+ FreeXid(xid);
+ return;
+ }
+
+ dirent = list_entry(inode->i_dentry.next, struct dentry, d_alias);
+ if (dirent) {
+ full_path = build_path_from_dentry(dirent);
+ rc = CIFSSMBSetEOF(xid, pTcon, full_path, inode->i_size,FALSE,
+ cifs_sb->local_nls);
+ cFYI(1,(" SetEOF (truncate) rc = %d",rc));
+ if (!rc)
+ CIFSSMBSetEOF(xid,pTcon,full_path,inode->i_size,TRUE,cifs_sb->local_nls);
+ /* allocation size setting seems optional so ignore return code */
+ }
+ if (full_path)
+ kfree(full_path);
+ FreeXid(xid);
+ return;
+}
+
+static int cifs_truncate_page(struct address_space *mapping, loff_t from)
+{
+ unsigned long index = from >> PAGE_CACHE_SHIFT;
+ unsigned offset = from & (PAGE_CACHE_SIZE-1);
+ struct page *page;
+ char *kaddr;
+ int rc = 0;
+
+ page = grab_cache_page(mapping, index);
+ if (!page)
+ return -ENOMEM;
+
+ kaddr = kmap_atomic(page, KM_USER0);
+ memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
+ flush_dcache_page(page);
+ kunmap_atomic(kaddr, KM_USER0);
+ unlock_page(page);
+ page_cache_release(page);
+ return rc;
+}
+
+int
+cifs_setattr(struct dentry *direntry, struct iattr *attrs)
+{
+ int xid;
+ struct cifs_sb_info *cifs_sb;
+ struct cifsTconInfo *pTcon;
+ char *full_path = NULL;
+ int rc = -EACCES;
+ int found = FALSE;
+ struct cifsFileInfo *open_file = NULL;
+ FILE_BASIC_INFO time_buf;
+ int set_time = FALSE;
+ __u64 mode = 0xFFFFFFFFFFFFFFFFULL;
+ __u64 uid = 0xFFFFFFFFFFFFFFFFULL;
+ __u64 gid = 0xFFFFFFFFFFFFFFFFULL;
+ struct cifsInodeInfo *cifsInode;
+ struct list_head * tmp;
+
+ xid = GetXid();
+
+ cFYI(1,
+ (" In cifs_setattr, name = %s attrs->iavalid 0x%x ",
+ direntry->d_name.name, attrs->ia_valid));
+ cifs_sb = CIFS_SB(direntry->d_inode->i_sb);
+ pTcon = cifs_sb->tcon;
+
+ down(&direntry->d_sb->s_vfs_rename_sem);
+ full_path = build_path_from_dentry(direntry);
+ up(&direntry->d_sb->s_vfs_rename_sem);
+ if(full_path == NULL) {
+ FreeXid(xid);
+ return -ENOMEM;
+ }
+ cifsInode = CIFS_I(direntry->d_inode);
+
+ /* BB check if we need to refresh inode from server now ? BB */
+
+ /* need to flush data before changing file size on server */
+ filemap_fdatasync(direntry->d_inode->i_mapping);
+
+ if (attrs->ia_valid & ATTR_SIZE) {
+ read_lock(&GlobalSMBSeslock);
+ /* To avoid spurious oplock breaks from server, in the case
+ of inodes that we already have open, avoid doing path
+ based setting of file size if we can do it by handle.
+ This keeps our caching token (oplock) and avoids
+ timeouts when the local oplock break takes longer to flush
+ writebehind data than the SMB timeout for the SetPathInfo
+ request would allow */
+ list_for_each(tmp, &cifsInode->openFileList) {
+ open_file = list_entry(tmp,struct cifsFileInfo, flist);
+ /* We check if file is open for writing first */
+ if((open_file->pfile) &&
+ ((open_file->pfile->f_flags & O_RDWR) ||
+ (open_file->pfile->f_flags & O_WRONLY))) {
+ if(open_file->invalidHandle == FALSE) {
+ /* we found a valid, writeable network file
+ handle to use to try to set the file size */
+ __u16 nfid = open_file->netfid;
+ __u32 npid = open_file->pid;
+ read_unlock(&GlobalSMBSeslock);
+ found = TRUE;
+ rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size,
+ nfid,npid,FALSE);
+ cFYI(1,("SetFileSize by handle (setattrs) rc = %d",rc));
+ /* Do not need reopen and retry on EAGAIN since we will
+ retry by pathname below */
+
+ break; /* now that we found one valid file handle no
+ sense continuing to loop trying others */
+ }
+ }
+ }
+ if(found == FALSE) {
+ read_unlock(&GlobalSMBSeslock);
+ }
+
+
+ if(rc != 0) {
+ /* Set file size by pathname rather than by handle either
+ because no valid, writeable file handle for it was found or
+ because there was an error setting it by handle */
+ rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size,FALSE,
+ cifs_sb->local_nls);
+ cFYI(1,(" SetEOF by path (setattrs) rc = %d",rc));
+ }
+
+ /* Server is ok setting allocation size implicitly - no need to call: */
+ /*CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, TRUE, cifs_sb->local_nls);*/
+
+ if (rc == 0) {
+ rc = vmtruncate(direntry->d_inode, attrs->ia_size);
+ cifs_truncate_page(direntry->d_inode->i_mapping, direntry->d_inode->i_size);
+ }
+ }
+ if (attrs->ia_valid & ATTR_UID) {
+ cFYI(1, (" CIFS - UID changed to %d", attrs->ia_uid));
+ uid = attrs->ia_uid;
+ /* entry->uid = cpu_to_le16(attr->ia_uid); */
+ }
+ if (attrs->ia_valid & ATTR_GID) {
+ cFYI(1, (" CIFS - GID changed to %d", attrs->ia_gid));
+ gid = attrs->ia_gid;
+ /* entry->gid = cpu_to_le16(attr->ia_gid); */
+ }
+
+ time_buf.Attributes = 0;
+ if (attrs->ia_valid & ATTR_MODE) {
+ cFYI(1, (" CIFS - Mode changed to 0x%x", attrs->ia_mode));
+ mode = attrs->ia_mode;
+ /* entry->mode = cpu_to_le16(attr->ia_mode); */
+ }
+
+ if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX)
+ && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID)))
+ rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid,
+ 0 /* dev_t */, cifs_sb->local_nls);
+ else if (attrs->ia_valid & ATTR_MODE) {
+ if((mode & S_IWUGO) == 0) /* not writeable */ {
+ if((cifsInode->cifsAttrs & ATTR_READONLY) == 0)
+ time_buf.Attributes =
+ cpu_to_le32(cifsInode->cifsAttrs | ATTR_READONLY);
+ } else if((mode & S_IWUGO) == S_IWUGO) {
+ if(cifsInode->cifsAttrs & ATTR_READONLY)
+ time_buf.Attributes =
+ cpu_to_le32(cifsInode->cifsAttrs & (~ATTR_READONLY));
+ }
+ /* BB to be implemented - via Windows security descriptors or streams */
+ /* CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,uid,gid,cifs_sb->local_nls);*/
+ }
+
+ if (attrs->ia_valid & ATTR_ATIME) {
+ set_time = TRUE;
+ time_buf.LastAccessTime =
+ cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
+ } else
+ time_buf.LastAccessTime = 0;
+
+ if (attrs->ia_valid & ATTR_MTIME) {
+ set_time = TRUE;
+ time_buf.LastWriteTime =
+ cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
+ } else
+ time_buf.LastWriteTime = 0;
+
+ if (attrs->ia_valid & ATTR_CTIME) {
+ set_time = TRUE;
+ time_buf.ChangeTime =
+ cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
+ } else
+ time_buf.ChangeTime = 0;
+
+ if (set_time | time_buf.Attributes) {
+ /* BB what if setting one attribute fails
+ (such as size) but time setting works */
+ time_buf.CreationTime = 0; /* do not change */
+ /* In the future we should experiment - try setting timestamps
+ via Handle (SetFileInfo) instead of by path */
+ rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf,
+ cifs_sb->local_nls);
+ }
+
+ /* do not need local check to inode_check_ok since the server does that */
+ if (!rc)
+ rc = inode_setattr(direntry->d_inode, attrs);
+ if (full_path)
+ kfree(full_path);
+ FreeXid(xid);
+ return rc;
+}
+
+void
+cifs_delete_inode(struct inode *inode)
+{
+ cFYI(1, ("In cifs_delete_inode, inode = 0x%p ", inode));
+ /* may have to add back in if and when safe distributed caching of
+ directories added e.g. via FindNotify */
+}
diff --git a/release/src/linux/linux/fs/cifs/link.c b/release/src/linux/linux/fs/cifs/link.c
new file mode 100644
index 00000000..d4e93724
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/link.c
@@ -0,0 +1,328 @@
+/*
+ * fs/cifs/link.c
+ *
+ * Copyright (C) International Business Machines Corp., 2002,2003
+ * Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include "cifsfs.h"
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_debug.h"
+#include "cifs_fs_sb.h"
+
+int
+cifs_hardlink(struct dentry *old_file, struct inode *inode,
+ struct dentry *direntry)
+{
+ int rc = -EACCES;
+ int xid;
+ char *fromName = NULL;
+ char *toName = NULL;
+ struct cifs_sb_info *cifs_sb_target;
+ struct cifsTconInfo *pTcon;
+ struct cifsInodeInfo *cifsInode;
+
+ xid = GetXid();
+
+ cifs_sb_target = CIFS_SB(inode->i_sb);
+ pTcon = cifs_sb_target->tcon;
+
+/* No need to check for cross device links since server will do that
+ BB note DFS case in future though (when we may have to check) */
+
+ down(&inode->i_sb->s_vfs_rename_sem);
+ fromName = build_path_from_dentry(old_file);
+ toName = build_path_from_dentry(direntry);
+ up(&inode->i_sb->s_vfs_rename_sem);
+ if((fromName == NULL) || (toName == NULL)) {
+ rc = -ENOMEM;
+ goto cifs_hl_exit;
+ }
+
+ if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX)
+ rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName,
+ cifs_sb_target->local_nls);
+ else {
+ rc = CIFSCreateHardLink(xid, pTcon, fromName, toName,
+ cifs_sb_target->local_nls);
+ if(rc == -EIO)
+ rc = -EOPNOTSUPP;
+ }
+
+/* if (!rc) */
+ {
+ /* renew_parental_timestamps(old_file);
+ inode->i_nlink++;
+ mark_inode_dirty(inode);
+ d_instantiate(direntry, inode); */
+ /* BB add call to either mark inode dirty or refresh its data and timestamp to current time */
+ }
+ d_drop(direntry); /* force new lookup from server */
+ cifsInode = CIFS_I(old_file->d_inode);
+ cifsInode->time = 0; /* will force revalidate to go get info when needed */
+
+cifs_hl_exit:
+ if (fromName)
+ kfree(fromName);
+ if (toName)
+ kfree(toName);
+ FreeXid(xid);
+ return rc;
+}
+
+int
+cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
+{
+ struct inode *inode = direntry->d_inode;
+ int rc = -EACCES;
+ int xid;
+ char *full_path = NULL;
+ char * target_path;
+ struct cifs_sb_info *cifs_sb;
+ struct cifsTconInfo *pTcon;
+
+ xid = GetXid();
+
+ down(&direntry->d_sb->s_vfs_rename_sem);
+ full_path = build_path_from_dentry(direntry);
+ up(&direntry->d_sb->s_vfs_rename_sem);
+
+ if(full_path == NULL) {
+ FreeXid(xid);
+ return -ENOMEM;
+ }
+ cFYI(1, ("Full path: %s inode = 0x%p", full_path, inode));
+ cifs_sb = CIFS_SB(inode->i_sb);
+ pTcon = cifs_sb->tcon;
+ target_path = kmalloc(PATH_MAX, GFP_KERNEL);
+ if(target_path == NULL) {
+ if (full_path)
+ kfree(full_path);
+ FreeXid(xid);
+ return -ENOMEM;
+ }
+ /* can not call the following line due to EFAULT in vfs_readlink which is presumably expecting a user space buffer */
+ /* length = cifs_readlink(direntry,target_path, sizeof(target_path) - 1); */
+
+/* BB add read reparse point symlink code and Unix extensions symlink code here BB */
+ if (pTcon->ses->capabilities & CAP_UNIX)
+ rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path,
+ target_path,
+ PATH_MAX-1,
+ cifs_sb->local_nls);
+ else {
+ /* rc = CIFSSMBQueryReparseLinkInfo */
+ /* BB Add code to Query ReparsePoint info */
+ }
+ /* BB Anything else to do to handle recursive links? */
+ /* BB Should we be using page symlink ops here? */
+
+ if (rc == 0) {
+
+/* BB Add special case check for Samba DFS symlinks */
+
+ target_path[PATH_MAX-1] = 0;
+ rc = vfs_follow_link(nd, target_path);
+ }
+ /* else EACCESS */
+
+ if (target_path)
+ kfree(target_path);
+ if (full_path)
+ kfree(full_path);
+ FreeXid(xid);
+ return rc;
+}
+
+int
+cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
+{
+ int rc = -EOPNOTSUPP;
+ int xid;
+ struct cifs_sb_info *cifs_sb;
+ struct cifsTconInfo *pTcon;
+ char *full_path = NULL;
+ struct inode *newinode = NULL;
+
+ xid = GetXid();
+
+ cifs_sb = CIFS_SB(inode->i_sb);
+ pTcon = cifs_sb->tcon;
+
+ down(&inode->i_sb->s_vfs_rename_sem);
+ full_path = build_path_from_dentry(direntry);
+ up(&inode->i_sb->s_vfs_rename_sem);
+
+ if(full_path == NULL) {
+ FreeXid(xid);
+ return -ENOMEM;
+ }
+
+ cFYI(1, ("Full path: %s ", full_path));
+ cFYI(1, ("symname is %s", symname));
+
+ /* BB what if DFS and this volume is on different share? BB */
+ if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
+ rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
+ cifs_sb->local_nls);
+ /* else
+ rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName,cifs_sb_target->local_nls); */
+
+ if (rc == 0) {
+ if (pTcon->ses->capabilities & CAP_UNIX)
+ rc = cifs_get_inode_info_unix(&newinode, full_path,
+ inode->i_sb,xid);
+ else
+ rc = cifs_get_inode_info(&newinode, full_path, NULL,
+ inode->i_sb,xid);
+
+ if (rc != 0) {
+ cFYI(1,
+ ("Create symlink worked but get_inode_info failed with rc = %d ",
+ rc));
+ } else {
+ direntry->d_op = &cifs_dentry_ops;
+ d_instantiate(direntry, newinode);
+ }
+ }
+
+ if (full_path)
+ kfree(full_path);
+ FreeXid(xid);
+ return rc;
+}
+
+int
+cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen)
+{
+ struct inode *inode = direntry->d_inode;
+ int rc = -EACCES;
+ int xid;
+ int oplock = FALSE;
+ struct cifs_sb_info *cifs_sb;
+ struct cifsTconInfo *pTcon;
+ char *full_path = NULL;
+ char *tmp_path = NULL;
+ char * tmpbuffer;
+ unsigned char * referrals = NULL;
+ int num_referrals = 0;
+ int len;
+ __u16 fid;
+
+ xid = GetXid();
+ cifs_sb = CIFS_SB(inode->i_sb);
+ pTcon = cifs_sb->tcon;
+
+/* BB would it be safe against deadlock to grab this sem
+ even though rename itself grabs the sem and calls lookup? */
+/* down(&inode->i_sb->s_vfs_rename_sem);*/
+ full_path = build_path_from_dentry(direntry);
+/* up(&inode->i_sb->s_vfs_rename_sem);*/
+
+ if(full_path == NULL) {
+ FreeXid(xid);
+ return -ENOMEM;
+ }
+
+ cFYI(1,
+ ("Full path: %s inode = 0x%p pBuffer = 0x%p buflen = %d",
+ full_path, inode, pBuffer, buflen));
+ if(buflen > PATH_MAX)
+ len = PATH_MAX;
+ else
+ len = buflen;
+ tmpbuffer = kmalloc(len,GFP_KERNEL);
+ if(tmpbuffer == NULL) {
+ if (full_path)
+ kfree(full_path);
+ FreeXid(xid);
+ return -ENOMEM;
+ }
+
+/* BB add read reparse point symlink code and Unix extensions symlink code here BB */
+ if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
+ rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path,
+ tmpbuffer,
+ len - 1,
+ cifs_sb->local_nls);
+ else {
+ rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ,
+ OPEN_REPARSE_POINT,&fid, &oplock, NULL, cifs_sb->local_nls);
+ if(!rc) {
+ rc = CIFSSMBQueryReparseLinkInfo(xid, pTcon, full_path,
+ tmpbuffer,
+ len - 1,
+ fid,
+ cifs_sb->local_nls);
+ if(CIFSSMBClose(xid, pTcon, fid)) {
+ cFYI(1,("Error closing junction point (open for ioctl)"));
+ }
+ if(rc == -EIO) {
+ /* Query if DFS Junction */
+ tmp_path =
+ kmalloc(MAX_TREE_SIZE + MAX_PATHCONF + 1,
+ GFP_KERNEL);
+ if (tmp_path) {
+ strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
+ strncat(tmp_path, full_path, MAX_PATHCONF);
+ rc = get_dfs_path(xid, pTcon->ses, tmp_path,
+ cifs_sb->local_nls, &num_referrals, &referrals);
+ cFYI(1,("Get DFS for %s rc = %d ",tmp_path, rc));
+ if((num_referrals == 0) && (rc == 0))
+ rc = -EACCES;
+ else {
+ cFYI(1,("num referral: %d",num_referrals));
+ if(referrals) {
+ cFYI(1,("referral string: %s ",referrals));
+ strncpy(tmpbuffer, referrals, len-1);
+ }
+ }
+ if(referrals)
+ kfree(referrals);
+ kfree(tmp_path);
+ if(referrals) {
+ kfree(referrals);
+ }
+ }
+ /* BB add code like else decode referrals then memcpy to
+ tmpbuffer and free referrals string array BB */
+ }
+ }
+ }
+ /* BB Anything else to do to handle recursive links? */
+ /* BB Should we be using page ops here? */
+
+ /* BB null terminate returned string in pBuffer? BB */
+ if (rc == 0) {
+ rc = vfs_readlink(direntry, pBuffer, len, tmpbuffer);
+ cFYI(1,
+ ("vfs_readlink called from cifs_readlink returned %d",
+ rc));
+ }
+
+ if (tmpbuffer) {
+ kfree(tmpbuffer);
+ }
+ if (full_path) {
+ kfree(full_path);
+ }
+ FreeXid(xid);
+ return rc;
+}
diff --git a/release/src/linux/linux/fs/cifs/md4.c b/release/src/linux/linux/fs/cifs/md4.c
new file mode 100644
index 00000000..1edbe22c
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/md4.c
@@ -0,0 +1,203 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ a implementation of MD4 designed for use in the SMB authentication protocol
+ Copyright (C) Andrew Tridgell 1997-1998.
+ Modified by Steve French (sfrench@us.ibm.com) 2002-2003
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+#include <linux/module.h>
+#include <linux/fs.h>
+/* NOTE: This code makes no attempt to be fast! */
+
+static __u32
+F(__u32 X, __u32 Y, __u32 Z)
+{
+ return (X & Y) | ((~X) & Z);
+}
+
+static __u32
+G(__u32 X, __u32 Y, __u32 Z)
+{
+ return (X & Y) | (X & Z) | (Y & Z);
+}
+
+static __u32
+H(__u32 X, __u32 Y, __u32 Z)
+{
+ return X ^ Y ^ Z;
+}
+
+static __u32
+lshift(__u32 x, int s)
+{
+ x &= 0xFFFFFFFF;
+ return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s));
+}
+
+#define ROUND1(a,b,c,d,k,s) (*a) = lshift((*a) + F(*b,*c,*d) + X[k], s)
+#define ROUND2(a,b,c,d,k,s) (*a) = lshift((*a) + G(*b,*c,*d) + X[k] + (__u32)0x5A827999,s)
+#define ROUND3(a,b,c,d,k,s) (*a) = lshift((*a) + H(*b,*c,*d) + X[k] + (__u32)0x6ED9EBA1,s)
+
+/* this applies md4 to 64 byte chunks */
+static void
+mdfour64(__u32 * M, __u32 * A, __u32 *B, __u32 * C, __u32 *D)
+{
+ int j;
+ __u32 AA, BB, CC, DD;
+ __u32 X[16];
+
+
+ for (j = 0; j < 16; j++)
+ X[j] = M[j];
+
+ AA = *A;
+ BB = *B;
+ CC = *C;
+ DD = *D;
+
+ ROUND1(A, B, C, D, 0, 3);
+ ROUND1(D, A, B, C, 1, 7);
+ ROUND1(C, D, A, B, 2, 11);
+ ROUND1(B, C, D, A, 3, 19);
+ ROUND1(A, B, C, D, 4, 3);
+ ROUND1(D, A, B, C, 5, 7);
+ ROUND1(C, D, A, B, 6, 11);
+ ROUND1(B, C, D, A, 7, 19);
+ ROUND1(A, B, C, D, 8, 3);
+ ROUND1(D, A, B, C, 9, 7);
+ ROUND1(C, D, A, B, 10, 11);
+ ROUND1(B, C, D, A, 11, 19);
+ ROUND1(A, B, C, D, 12, 3);
+ ROUND1(D, A, B, C, 13, 7);
+ ROUND1(C, D, A, B, 14, 11);
+ ROUND1(B, C, D, A, 15, 19);
+
+ ROUND2(A, B, C, D, 0, 3);
+ ROUND2(D, A, B, C, 4, 5);
+ ROUND2(C, D, A, B, 8, 9);
+ ROUND2(B, C, D, A, 12, 13);
+ ROUND2(A, B, C, D, 1, 3);
+ ROUND2(D, A, B, C, 5, 5);
+ ROUND2(C, D, A, B, 9, 9);
+ ROUND2(B, C, D, A, 13, 13);
+ ROUND2(A, B, C, D, 2, 3);
+ ROUND2(D, A, B, C, 6, 5);
+ ROUND2(C, D, A, B, 10, 9);
+ ROUND2(B, C, D, A, 14, 13);
+ ROUND2(A, B, C, D, 3, 3);
+ ROUND2(D, A, B, C, 7, 5);
+ ROUND2(C, D, A, B, 11, 9);
+ ROUND2(B, C, D, A, 15, 13);
+
+ ROUND3(A, B, C, D, 0, 3);
+ ROUND3(D, A, B, C, 8, 9);
+ ROUND3(C, D, A, B, 4, 11);
+ ROUND3(B, C, D, A, 12, 15);
+ ROUND3(A, B, C, D, 2, 3);
+ ROUND3(D, A, B, C, 10, 9);
+ ROUND3(C, D, A, B, 6, 11);
+ ROUND3(B, C, D, A, 14, 15);
+ ROUND3(A, B, C, D, 1, 3);
+ ROUND3(D, A, B, C, 9, 9);
+ ROUND3(C, D, A, B, 5, 11);
+ ROUND3(B, C, D, A, 13, 15);
+ ROUND3(A, B, C, D, 3, 3);
+ ROUND3(D, A, B, C, 11, 9);
+ ROUND3(C, D, A, B, 7, 11);
+ ROUND3(B, C, D, A, 15, 15);
+
+ *A += AA;
+ *B += BB;
+ *C += CC;
+ *D += DD;
+
+ *A &= 0xFFFFFFFF;
+ *B &= 0xFFFFFFFF;
+ *C &= 0xFFFFFFFF;
+ *D &= 0xFFFFFFFF;
+
+ for (j = 0; j < 16; j++)
+ X[j] = 0;
+}
+
+static void
+copy64(__u32 * M, unsigned char *in)
+{
+ int i;
+
+ for (i = 0; i < 16; i++)
+ M[i] = (in[i * 4 + 3] << 24) | (in[i * 4 + 2] << 16) |
+ (in[i * 4 + 1] << 8) | (in[i * 4 + 0] << 0);
+}
+
+static void
+copy4(unsigned char *out, __u32 x)
+{
+ out[0] = x & 0xFF;
+ out[1] = (x >> 8) & 0xFF;
+ out[2] = (x >> 16) & 0xFF;
+ out[3] = (x >> 24) & 0xFF;
+}
+
+/* produce a md4 message digest from data of length n bytes */
+void
+mdfour(unsigned char *out, unsigned char *in, int n)
+{
+ unsigned char buf[128];
+ __u32 M[16];
+ __u32 b = n * 8;
+ int i;
+ __u32 A = 0x67452301;
+ __u32 B = 0xefcdab89;
+ __u32 C = 0x98badcfe;
+ __u32 D = 0x10325476;
+
+ while (n > 64) {
+ copy64(M, in);
+ mdfour64(M,&A,&B, &C, &D);
+ in += 64;
+ n -= 64;
+ }
+
+ for (i = 0; i < 128; i++)
+ buf[i] = 0;
+ memcpy(buf, in, n);
+ buf[n] = 0x80;
+
+ if (n <= 55) {
+ copy4(buf + 56, b);
+ copy64(M, buf);
+ mdfour64(M, &A, &B, &C, &D);
+ } else {
+ copy4(buf + 120, b);
+ copy64(M, buf);
+ mdfour64(M, &A, &B, &C, &D);
+ copy64(M, buf + 64);
+ mdfour64(M, &A, &B, &C, &D);
+ }
+
+ for (i = 0; i < 128; i++)
+ buf[i] = 0;
+ copy64(M, buf);
+
+ copy4(out, A);
+ copy4(out + 4, B);
+ copy4(out + 8, C);
+ copy4(out + 12, D);
+
+ A = B = C = D = 0;
+}
diff --git a/release/src/linux/linux/fs/cifs/md5.c b/release/src/linux/linux/fs/cifs/md5.c
new file mode 100644
index 00000000..7aa23490
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/md5.c
@@ -0,0 +1,363 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+/* This code slightly modified to fit into Samba by
+ abartlet@samba.org Jun 2001
+ and to fit the cifs vfs by
+ Steve French sfrench@us.ibm.com */
+
+#include <linux/string.h>
+#include "md5.h"
+
+static void MD5Transform(__u32 buf[4], __u32 const in[16]);
+
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+static void
+byteReverse(unsigned char *buf, unsigned longs)
+{
+ __u32 t;
+ do {
+ t = (__u32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+ ((unsigned) buf[1] << 8 | buf[0]);
+ *(__u32 *) buf = t;
+ buf += 4;
+ } while (--longs);
+}
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void
+MD5Init(struct MD5Context *ctx)
+{
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bits[0] = 0;
+ ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
+{
+ register __u32 t;
+
+ /* Update bitcount */
+
+ t = ctx->bits[0];
+ if ((ctx->bits[0] = t + ((__u32) len << 3)) < t)
+ ctx->bits[1]++; /* Carry from low to high */
+ ctx->bits[1] += len >> 29;
+
+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+ /* Handle any leading odd-sized chunks */
+
+ if (t) {
+ unsigned char *p = (unsigned char *) ctx->in + t;
+
+ t = 64 - t;
+ if (len < t) {
+ memmove(p, buf, len);
+ return;
+ }
+ memmove(p, buf, t);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (__u32 *) ctx->in);
+ buf += t;
+ len -= t;
+ }
+ /* Process data in 64-byte chunks */
+
+ while (len >= 64) {
+ memmove(ctx->in, buf, 64);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (__u32 *) ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+
+ memmove(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void
+MD5Final(unsigned char digest[16], struct MD5Context *ctx)
+{
+ unsigned int count;
+ unsigned char *p;
+
+ /* Compute number of bytes mod 64 */
+ count = (ctx->bits[0] >> 3) & 0x3F;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ p = ctx->in + count;
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if (count < 8) {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset(p, 0, count);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (__u32 *) ctx->in);
+
+ /* Now fill the next block with 56 bytes */
+ memset(ctx->in, 0, 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(p, 0, count - 8);
+ }
+ byteReverse(ctx->in, 14);
+
+ /* Append length in bits and transform */
+ ((__u32 *) ctx->in)[14] = ctx->bits[0];
+ ((__u32 *) ctx->in)[15] = ctx->bits[1];
+
+ MD5Transform(ctx->buf, (__u32 *) ctx->in);
+ byteReverse((unsigned char *) ctx->buf, 4);
+ memmove(digest, ctx->buf, 16);
+ memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
+}
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void
+MD5Transform(__u32 buf[4], __u32 const in[16])
+{
+ register __u32 a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+/***********************************************************************
+ the rfc 2104 version of hmac_md5 initialisation.
+***********************************************************************/
+void
+hmac_md5_init_rfc2104(unsigned char *key, int key_len,
+ struct HMACMD5Context *ctx)
+{
+ int i;
+
+ /* if key is longer than 64 bytes reset it to key=MD5(key) */
+ if (key_len > 64) {
+ unsigned char tk[16];
+ struct MD5Context tctx;
+
+ MD5Init(&tctx);
+ MD5Update(&tctx, key, key_len);
+ MD5Final(tk, &tctx);
+
+ key = tk;
+ key_len = 16;
+ }
+
+ /* start out by storing key in pads */
+ memset(ctx->k_ipad, 0, sizeof (ctx->k_ipad));
+ memset(ctx->k_opad, 0, sizeof (ctx->k_opad));
+ memcpy(ctx->k_ipad, key, key_len);
+ memcpy(ctx->k_opad, key, key_len);
+
+ /* XOR key with ipad and opad values */
+ for (i = 0; i < 64; i++) {
+ ctx->k_ipad[i] ^= 0x36;
+ ctx->k_opad[i] ^= 0x5c;
+ }
+
+ MD5Init(&ctx->ctx);
+ MD5Update(&ctx->ctx, ctx->k_ipad, 64);
+}
+
+/***********************************************************************
+ the microsoft version of hmac_md5 initialisation.
+***********************************************************************/
+void
+hmac_md5_init_limK_to_64(const unsigned char *key, int key_len,
+ struct HMACMD5Context *ctx)
+{
+ int i;
+
+ /* if key is longer than 64 bytes truncate it */
+ if (key_len > 64) {
+ key_len = 64;
+ }
+
+ /* start out by storing key in pads */
+ memset(ctx->k_ipad, 0, sizeof (ctx->k_ipad));
+ memset(ctx->k_opad, 0, sizeof (ctx->k_opad));
+ memcpy(ctx->k_ipad, key, key_len);
+ memcpy(ctx->k_opad, key, key_len);
+
+ /* XOR key with ipad and opad values */
+ for (i = 0; i < 64; i++) {
+ ctx->k_ipad[i] ^= 0x36;
+ ctx->k_opad[i] ^= 0x5c;
+ }
+
+ MD5Init(&ctx->ctx);
+ MD5Update(&ctx->ctx, ctx->k_ipad, 64);
+}
+
+/***********************************************************************
+ update hmac_md5 "inner" buffer
+***********************************************************************/
+void
+hmac_md5_update(const unsigned char *text, int text_len,
+ struct HMACMD5Context *ctx)
+{
+ MD5Update(&ctx->ctx, text, text_len); /* then text of datagram */
+}
+
+/***********************************************************************
+ finish off hmac_md5 "inner" buffer and generate outer one.
+***********************************************************************/
+void
+hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx)
+{
+ struct MD5Context ctx_o;
+
+ MD5Final(digest, &ctx->ctx);
+
+ MD5Init(&ctx_o);
+ MD5Update(&ctx_o, ctx->k_opad, 64);
+ MD5Update(&ctx_o, digest, 16);
+ MD5Final(digest, &ctx_o);
+}
+
+/***********************************************************
+ single function to calculate an HMAC MD5 digest from data.
+ use the microsoft hmacmd5 init method because the key is 16 bytes.
+************************************************************/
+void
+hmac_md5(unsigned char key[16], unsigned char *data, int data_len,
+ unsigned char *digest)
+{
+ struct HMACMD5Context ctx;
+ hmac_md5_init_limK_to_64(key, 16, &ctx);
+ if (data_len != 0) {
+ hmac_md5_update(data, data_len, &ctx);
+ }
+ hmac_md5_final(digest, &ctx);
+}
diff --git a/release/src/linux/linux/fs/cifs/md5.h b/release/src/linux/linux/fs/cifs/md5.h
new file mode 100644
index 00000000..00e1c539
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/md5.h
@@ -0,0 +1,38 @@
+#ifndef MD5_H
+#define MD5_H
+#ifndef HEADER_MD5_H
+/* Try to avoid clashes with OpenSSL */
+#define HEADER_MD5_H
+#endif
+
+struct MD5Context {
+ __u32 buf[4];
+ __u32 bits[2];
+ unsigned char in[64];
+};
+#endif /* !MD5_H */
+
+#ifndef _HMAC_MD5_H
+struct HMACMD5Context {
+ struct MD5Context ctx;
+ unsigned char k_ipad[65];
+ unsigned char k_opad[65];
+};
+#endif /* _HMAC_MD5_H */
+
+void MD5Init(struct MD5Context *context);
+void MD5Update(struct MD5Context *context, unsigned char const *buf,
+ unsigned len);
+void MD5Final(unsigned char digest[16], struct MD5Context *context);
+
+/* The following definitions come from lib/hmacmd5.c */
+
+void hmac_md5_init_rfc2104(unsigned char *key, int key_len,
+ struct HMACMD5Context *ctx);
+void hmac_md5_init_limK_to_64(const unsigned char *key, int key_len,
+ struct HMACMD5Context *ctx);
+void hmac_md5_update(const unsigned char *text, int text_len,
+ struct HMACMD5Context *ctx);
+void hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx);
+void hmac_md5(unsigned char key[16], unsigned char *data, int data_len,
+ unsigned char *digest);
diff --git a/release/src/linux/linux/fs/cifs/misc.c b/release/src/linux/linux/fs/cifs/misc.c
new file mode 100644
index 00000000..2241c45e
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/misc.c
@@ -0,0 +1,463 @@
+/*
+ * fs/cifs/misc.c
+ *
+ * Copyright (C) International Business Machines Corp., 2002,2003
+ * Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_debug.h"
+#include "smberr.h"
+#include "nterr.h"
+
+extern kmem_cache_t *cifs_req_cachep;
+extern struct task_struct * oplockThread;
+
+__u16 GlobalMid; /* multiplex id - rotating counter */
+
+/* The xid serves as a useful identifier for each incoming vfs request,
+ in a similar way to the mid which is useful to track each sent smb,
+ and CurrentXid can also provide a running counter (although it
+ will eventually wrap past zero) of the total vfs operations handled
+ since the cifs fs was mounted */
+
+unsigned int
+_GetXid(void)
+{
+ unsigned int xid;
+
+ spin_lock(&GlobalMid_Lock);
+ GlobalTotalActiveXid++;
+ if (GlobalTotalActiveXid > GlobalMaxActiveXid)
+ GlobalMaxActiveXid = GlobalTotalActiveXid; /* keep high water mark for number of simultaneous vfs ops in our filesystem */
+ xid = GlobalCurrentXid++;
+ spin_unlock(&GlobalMid_Lock);
+ return xid;
+}
+
+void
+_FreeXid(unsigned int xid)
+{
+ spin_lock(&GlobalMid_Lock);
+ /* if(GlobalTotalActiveXid == 0)
+ BUG(); */
+ GlobalTotalActiveXid--;
+ spin_unlock(&GlobalMid_Lock);
+}
+
+struct cifsSesInfo *
+sesInfoAlloc(void)
+{
+ struct cifsSesInfo *ret_buf;
+
+ ret_buf =
+ (struct cifsSesInfo *) kmalloc(sizeof (struct cifsSesInfo),
+ GFP_KERNEL);
+ if (ret_buf) {
+ memset(ret_buf, 0, sizeof (struct cifsSesInfo));
+ write_lock(&GlobalSMBSeslock);
+ atomic_inc(&sesInfoAllocCount);
+ ret_buf->status = CifsNew;
+ list_add(&ret_buf->cifsSessionList, &GlobalSMBSessionList);
+ init_MUTEX(&ret_buf->sesSem);
+ write_unlock(&GlobalSMBSeslock);
+ }
+ return ret_buf;
+}
+
+void
+sesInfoFree(struct cifsSesInfo *buf_to_free)
+{
+ if (buf_to_free == NULL) {
+ cFYI(1, ("Null buffer passed to sesInfoFree"));
+ return;
+ }
+
+ write_lock(&GlobalSMBSeslock);
+ atomic_dec(&sesInfoAllocCount);
+ list_del(&buf_to_free->cifsSessionList);
+ write_unlock(&GlobalSMBSeslock);
+ if (buf_to_free->serverOS)
+ kfree(buf_to_free->serverOS);
+ if (buf_to_free->serverDomain)
+ kfree(buf_to_free->serverDomain);
+ if (buf_to_free->serverNOS)
+ kfree(buf_to_free->serverNOS);
+ if (buf_to_free->password)
+ kfree(buf_to_free->password);
+ kfree(buf_to_free);
+}
+
+struct cifsTconInfo *
+tconInfoAlloc(void)
+{
+ struct cifsTconInfo *ret_buf;
+ ret_buf =
+ (struct cifsTconInfo *) kmalloc(sizeof (struct cifsTconInfo),
+ GFP_KERNEL);
+ if (ret_buf) {
+ memset(ret_buf, 0, sizeof (struct cifsTconInfo));
+ write_lock(&GlobalSMBSeslock);
+ atomic_inc(&tconInfoAllocCount);
+ list_add(&ret_buf->cifsConnectionList,
+ &GlobalTreeConnectionList);
+ ret_buf->tidStatus = CifsNew;
+ INIT_LIST_HEAD(&ret_buf->openFileList);
+ init_MUTEX(&ret_buf->tconSem);
+#ifdef CONFIG_CIFS_STATS
+ ret_buf->stat_lock = SPIN_LOCK_UNLOCKED;
+#endif
+ write_unlock(&GlobalSMBSeslock);
+ }
+ return ret_buf;
+}
+
+void
+tconInfoFree(struct cifsTconInfo *buf_to_free)
+{
+ if (buf_to_free == NULL) {
+ cFYI(1, ("Null buffer passed to tconInfoFree"));
+ return;
+ }
+ write_lock(&GlobalSMBSeslock);
+ atomic_dec(&tconInfoAllocCount);
+ list_del(&buf_to_free->cifsConnectionList);
+ write_unlock(&GlobalSMBSeslock);
+ if (buf_to_free->nativeFileSystem)
+ kfree(buf_to_free->nativeFileSystem);
+ kfree(buf_to_free);
+}
+
+struct smb_hdr *
+cifs_buf_get(void)
+{
+ struct smb_hdr *ret_buf = NULL;
+
+/* We could use negotiated size instead of max_msgsize -
+ but it may be more efficient to always alloc same size
+ albeit slightly larger than necessary and maxbuffersize
+ defaults to this and can not be bigger */
+ ret_buf =
+ (struct smb_hdr *) kmem_cache_alloc(cifs_req_cachep, SLAB_KERNEL);
+
+ /* clear the first few header bytes */
+ if (ret_buf) {
+ memset(ret_buf, 0, sizeof (struct smb_hdr));
+ atomic_inc(&bufAllocCount);
+ }
+
+ return ret_buf;
+}
+
+void
+cifs_buf_release(void *buf_to_free)
+{
+
+ if (buf_to_free == NULL) {
+ cFYI(1, ("Null buffer passed to cifs_buf_release"));
+ return;
+ }
+ kmem_cache_free(cifs_req_cachep, buf_to_free);
+
+ atomic_dec(&bufAllocCount);
+ return;
+}
+
+void
+header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
+ const struct cifsTconInfo *treeCon, int word_count
+ /* length of fixed section (word count) in two byte units */
+ )
+{
+ int i;
+ __u32 tmp;
+ struct list_head* temp_item;
+ struct cifsSesInfo * ses;
+ char *temp = (char *) buffer;
+
+ for (i = 0; i < MAX_CIFS_HDR_SIZE; i++) {
+ temp[i] = 0; /* BB is this needed ?? */
+ }
+
+ buffer->smb_buf_length =
+ (2 * word_count) + sizeof (struct smb_hdr) -
+ 4 /* RFC 1001 length field does not count */ +
+ 2 /* for bcc field itself */ ;
+ /* Note that this is the only network field that has to be converted to big endian and it is done just before we send it */
+
+ buffer->Protocol[0] = 0xFF;
+ buffer->Protocol[1] = 'S';
+ buffer->Protocol[2] = 'M';
+ buffer->Protocol[3] = 'B';
+ buffer->Command = smb_command;
+ buffer->Flags = 0x00; /* case sensitive */
+ buffer->Flags2 = SMBFLG2_KNOWS_LONG_NAMES;
+ tmp = cpu_to_le32(current->pid);
+ buffer->Pid = tmp & 0xFFFF;
+ tmp >>= 16;
+ buffer->PidHigh = tmp & 0xFFFF;
+ spin_lock(&GlobalMid_Lock);
+ GlobalMid++;
+ buffer->Mid = GlobalMid;
+ spin_unlock(&GlobalMid_Lock);
+ if (treeCon) {
+ buffer->Tid = treeCon->tid;
+ if (treeCon->ses) {
+ if (treeCon->ses->capabilities & CAP_UNICODE)
+ buffer->Flags2 |= SMBFLG2_UNICODE;
+ if (treeCon->ses->capabilities & CAP_STATUS32) {
+ buffer->Flags2 |= SMBFLG2_ERR_STATUS;
+ }
+
+ buffer->Uid = treeCon->ses->Suid; /* always in LE format */
+ if(multiuser_mount != 0) {
+ /* For the multiuser case, there are few obvious technically */
+ /* possible mechanisms to match the local linux user (uid) */
+ /* to a valid remote smb user (smb_uid): */
+ /* 1) Query Winbind (or other local pam/nss daemon */
+ /* for userid/password/logon_domain or credential */
+ /* 2) Query Winbind for uid to sid to username mapping */
+ /* and see if we have a matching password for existing*/
+ /* session for that user perhas getting password by */
+ /* adding a new pam_cifs module that stores passwords */
+ /* so that the cifs vfs can get at that for all logged*/
+ /* on users */
+ /* 3) (Which is the mechanism we have chosen) */
+ /* Search through sessions to the same server for a */
+ /* a match on the uid that was passed in on mount */
+ /* with the current processes uid (or euid?) and use */
+ /* that smb uid. If no existing smb session for */
+ /* that uid found, use the default smb session ie */
+ /* the smb session for the volume mounted which is */
+ /* the same as would be used if the multiuser mount */
+ /* flag were disabled. */
+
+ /* BB Add support for establishing new tCon and SMB Session */
+ /* with userid/password pairs found on the smb session */
+ /* for other target tcp/ip addresses BB */
+ if(current->uid != treeCon->ses->linux_uid) {
+ cFYI(1,("Multiuser mode and UID did not match tcon uid "));
+ read_lock(&GlobalSMBSeslock);
+ list_for_each(temp_item, &GlobalSMBSessionList) {
+ ses = list_entry(temp_item, struct cifsSesInfo, cifsSessionList);
+ if(ses->linux_uid == current->uid) {
+ if(ses->server == treeCon->ses->server) {
+ cFYI(1,("found matching uid substitute right smb_uid"));
+ buffer->Uid = ses->Suid;
+ break;
+ } else {
+ /* BB eventually call cifs_setup_session here */
+ cFYI(1,("local UID found but smb sess with this server does not exist"));
+ }
+ }
+ }
+ read_unlock(&GlobalSMBSeslock);
+ }
+ }
+ }
+ if (treeCon->Flags & SMB_SHARE_IS_IN_DFS)
+ buffer->Flags2 |= SMBFLG2_DFS;
+ if(treeCon->ses->server)
+ if(treeCon->ses->server->secMode &
+ (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+ buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+ }
+
+/* endian conversion of flags is now done just before sending */
+ buffer->WordCount = (char) word_count;
+ return;
+}
+
+int
+checkSMBhdr(struct smb_hdr *smb, __u16 mid)
+{
+ /* Make sure that this really is an SMB, that it is a response,
+ and that the message ids match */
+ if ((*(unsigned int *) smb->Protocol == cpu_to_le32(0x424d53ff)) &&
+ (mid == smb->Mid)) {
+ if(smb->Flags & SMBFLG_RESPONSE)
+ return 0;
+ else {
+ /* only one valid case where server sends us request */
+ if(smb->Command == SMB_COM_LOCKING_ANDX)
+ return 0;
+ else
+ cERROR(1, ("Rcvd Request not response "));
+ }
+ } else { /* bad signature or mid */
+ if (*(unsigned int *) smb->Protocol != cpu_to_le32(0x424d53ff))
+ cERROR(1,
+ ("Bad protocol string signature header %x ",
+ *(unsigned int *) smb->Protocol));
+ if (mid != smb->Mid)
+ cERROR(1, ("Mids do not match"));
+ }
+ cERROR(1, ("bad smb detected. The Mid=%d", smb->Mid));
+ return 1;
+}
+
+int
+checkSMB(struct smb_hdr *smb, __u16 mid, int length)
+{
+ cFYI(0,
+ ("Entering checkSMB with Length: %x, smb_buf_length: %x ",
+ length, ntohl(smb->smb_buf_length)));
+ if (((unsigned int)length < 2 + sizeof (struct smb_hdr))
+ || (ntohl(smb->smb_buf_length) >
+ CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE - 4)) {
+ if ((unsigned int)length < 2 + sizeof (struct smb_hdr)) {
+ cERROR(1, ("Length less than 2 + sizeof smb_hdr "));
+ if (((unsigned int)length >= sizeof (struct smb_hdr) - 1)
+ && (smb->Status.CifsError != 0))
+ return 0; /* some error cases do not return wct and bcc */
+
+ }
+ if (ntohl(smb->smb_buf_length) >
+ CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE - 4)
+ cERROR(1,
+ ("smb_buf_length greater than CIFS_MAX_MSGSIZE ... "));
+ cERROR(1,
+ ("bad smb detected. Illegal length. The mid=%d",
+ smb->Mid));
+ return 1;
+ }
+
+ if (checkSMBhdr(smb, mid))
+ return 1;
+
+ if ((4 + ntohl(smb->smb_buf_length) != smbCalcSize(smb))
+ || (4 + ntohl(smb->smb_buf_length) != (unsigned int)length)) {
+ return 0;
+ } else {
+ cERROR(1, ("smbCalcSize %x ", smbCalcSize(smb)));
+ cERROR(1,
+ ("bad smb size detected. The Mid=%d", smb->Mid));
+ return 1;
+ }
+}
+int
+is_valid_oplock_break(struct smb_hdr *buf)
+{
+ struct smb_com_lock_req * pSMB = (struct smb_com_lock_req *)buf;
+ struct list_head *tmp;
+ struct list_head *tmp1;
+ struct cifsTconInfo *tcon;
+ struct cifsFileInfo *netfile;
+
+ /* could add check for smb response flag 0x80 */
+ cFYI(1,("Checking for oplock break"));
+ if(pSMB->hdr.Command != SMB_COM_LOCKING_ANDX)
+ return FALSE;
+ if(pSMB->hdr.Flags & SMBFLG_RESPONSE) {
+ /* no sense logging error on invalid handle on oplock
+ break - harmless race between close request and oplock
+ break response is expected from time to time writing out
+ large dirty files cached on the client */
+ if ((NT_STATUS_INVALID_HANDLE) ==
+ le32_to_cpu(pSMB->hdr.Status.CifsError)) {
+ cFYI(1,("invalid handle on oplock break"));
+ return TRUE;
+ } else if (ERRbadfid ==
+ le16_to_cpu(pSMB->hdr.Status.DosError.Error)) {
+ return TRUE;
+ } else {
+ return FALSE; /* on valid oplock brk we get "request" */
+ }
+ }
+ if(pSMB->hdr.WordCount != 8)
+ return FALSE;
+
+ cFYI(1,(" oplock type 0x%d level 0x%d",pSMB->LockType,pSMB->OplockLevel));
+ if(!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE))
+ return FALSE;
+
+ /* look up tcon based on tid & uid */
+ read_lock(&GlobalSMBSeslock);
+ list_for_each(tmp, &GlobalTreeConnectionList) {
+ tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
+ if (tcon->tid == buf->Tid) {
+#ifdef CONFIG_CIFS_STATS
+ atomic_inc(&tcon->num_oplock_brks);
+#endif
+ list_for_each(tmp1,&tcon->openFileList){
+ netfile = list_entry(tmp1,struct cifsFileInfo,tlist);
+ if(pSMB->Fid == netfile->netfid) {
+ struct cifsInodeInfo *pCifsInode;
+ read_unlock(&GlobalSMBSeslock);
+ cFYI(1,("Matching file id, processing oplock break"));
+ pCifsInode =
+ CIFS_I(netfile->pInode);
+ pCifsInode->clientCanCacheAll = FALSE;
+ if(pSMB->OplockLevel == 0)
+ pCifsInode->clientCanCacheRead = FALSE;
+ pCifsInode->oplockPending = TRUE;
+ AllocOplockQEntry(netfile->pInode, netfile->netfid, tcon);
+ cFYI(1,("about to wake up oplock thd"));
+ wake_up_process(oplockThread);
+ return TRUE;
+ }
+ }
+ read_unlock(&GlobalSMBSeslock);
+ cFYI(1,("No matching file for oplock break on connection"));
+ return TRUE;
+ }
+ }
+ read_unlock(&GlobalSMBSeslock);
+ cFYI(1,("Can not process oplock break for non-existent connection"));
+ return TRUE;
+}
+
+void
+dump_smb(struct smb_hdr *smb_buf, int smb_buf_length)
+{
+ int i, j;
+ char debug_line[17];
+ unsigned char *buffer;
+
+ if (traceSMB == 0)
+ return;
+
+ buffer = (unsigned char *) smb_buf;
+ for (i = 0, j = 0; i < smb_buf_length; i++, j++) {
+ if (i % 8 == 0) { /* we have reached the beginning of line */
+ printk(KERN_DEBUG "| ");
+ j = 0;
+ }
+ printk("%0#4x ", buffer[i]);
+ debug_line[2 * j] = ' ';
+ if (isprint(buffer[i]))
+ debug_line[1 + (2 * j)] = buffer[i];
+ else
+ debug_line[1 + (2 * j)] = '_';
+
+ if (i % 8 == 7) { /* we have reached end of line, time to print ascii */
+ debug_line[16] = 0;
+ printk(" | %s\n", debug_line);
+ }
+ }
+ for (; j < 8; j++) {
+ printk(" ");
+ debug_line[2 * j] = ' ';
+ debug_line[1 + (2 * j)] = ' ';
+ }
+ printk( " | %s\n", debug_line);
+ return;
+}
diff --git a/release/src/linux/linux/fs/cifs/netmisc.c b/release/src/linux/linux/fs/cifs/netmisc.c
new file mode 100644
index 00000000..0a06be9d
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/netmisc.c
@@ -0,0 +1,905 @@
+/*
+ * fs/cifs/netmisc.c
+ *
+ * Copyright (c) International Business Machines Corp., 2002
+ * Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ * Error mapping routines from Samba libsmb/errormap.c
+ * Copyright (C) Andrew Tridgell 2001
+ *
+ *
+ * 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
+ */
+
+#include <linux/net.h>
+#include <linux/string.h>
+#include <linux/in.h>
+#include <linux/ctype.h>
+#include <linux/fs.h>
+#include <asm/div64.h>
+#include <asm/byteorder.h>
+#include "cifsfs.h"
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "smberr.h"
+#include "cifs_debug.h"
+#include "nterr.h"
+
+struct smb_to_posix_error {
+ __u16 smb_err;
+ int posix_code;
+};
+
+const struct smb_to_posix_error mapping_table_ERRDOS[] = {
+ {ERRbadfunc, -EINVAL},
+ {ERRbadfile, -ENOENT},
+ {ERRbadpath, -ENOTDIR},
+ {ERRnofids, -EMFILE},
+ {ERRnoaccess, -EACCES},
+ {ERRbadfid, -EBADF},
+ {ERRbadmcb, -EIO},
+ {ERRnomem, -ENOMEM},
+ {ERRbadmem, -EFAULT},
+ {ERRbadenv, -EFAULT},
+ {ERRbadformat, -EINVAL},
+ {ERRbadaccess, -EACCES},
+ {ERRbaddata, -EIO},
+ {ERRbaddrive, -ENXIO},
+ {ERRremcd, -EACCES},
+ {ERRdiffdevice, -EXDEV},
+ {ERRnofiles, -ENOENT},
+ {ERRbadshare, -ETXTBSY},
+ {ERRlock, -EACCES},
+ {ERRunsup, -EINVAL},
+ {ERRnosuchshare,-ENXIO},
+ {ERRfilexists, -EEXIST},
+ {ERRinvparm, -EINVAL},
+ {ERRdiskfull, -ENOSPC},
+ {ERRinvname, -ENOENT},
+ {ERRdirnotempty, -ENOTEMPTY},
+ {ERRnotlocked, -ENOLCK},
+ {ERRalreadyexists, -EEXIST},
+ {ERRmoredata, -EOVERFLOW},
+ {ErrQuota, -EDQUOT},
+ {ErrNotALink, -ENOLINK},
+ {ERRnetlogonNotStarted,-ENOPROTOOPT},
+ {0, 0}
+};
+
+const struct smb_to_posix_error mapping_table_ERRSRV[] = {
+ {ERRerror, -EIO},
+ {ERRbadpw, -EPERM},
+ {ERRbadtype, -EREMOTE},
+ {ERRaccess, -EACCES},
+ {ERRinvtid, -ENXIO},
+ {ERRinvnetname, -ENODEV},
+ {ERRinvdevice, -ENXIO},
+ {ERRqfull, -ENOSPC},
+ {ERRqtoobig, -ENOSPC},
+ {ERRqeof, -EIO},
+ {ERRinvpfid, -EBADF},
+ {ERRsmbcmd, -EBADRQC},
+ {ERRsrverror, -EIO},
+ {ERRbadBID, -EIO},
+ {ERRfilespecs, -EINVAL},
+ {ERRbadLink, -EIO},
+ {ERRbadpermits, -EINVAL},
+ {ERRbadPID, -ESRCH},
+ {ERRsetattrmode, -EINVAL},
+ {ERRpaused, -EHOSTDOWN},
+ {ERRmsgoff, -EHOSTDOWN},
+ {ERRnoroom, -ENOSPC},
+ {ERRrmuns, -EUSERS},
+ {ERRtimeout, -ETIME},
+ {ERRnoresource, -ENOBUFS},
+ {ERRtoomanyuids, -EUSERS},
+ {ERRbaduid, -EACCES},
+ {ERRusempx, -EIO},
+ {ERRusestd, -EIO},
+ {ERR_NOTIFY_ENUM_DIR, -ENOBUFS},
+ {ERRaccountexpired, -EACCES},
+ {ERRbadclient, -EACCES},
+ {ERRbadLogonTime, -EACCES},
+ {ERRpasswordExpired, -EACCES},
+ {ERRnosupport, -EINVAL},
+ {0, 0}
+};
+
+const struct smb_to_posix_error mapping_table_ERRHRD[] = {
+ {0, 0}
+};
+
+/* Convert string containing dotted ip address to binary form */
+/* returns 0 if invalid address */
+
+/* BB add address family, change rc to status flag and return union or for ipv6 */
+/* will need parent to call something like inet_pton to convert ipv6 address BB */
+int
+cifs_inet_pton(int address_family, char *cp,void *dst)
+{
+ struct in_addr address;
+ int value;
+ int digit;
+ int i;
+ char temp;
+ char bytes[4];
+ char *end = bytes;
+ static const int addr_class_max[4] =
+ { 0xffffffff, 0xffffff, 0xffff, 0xff };
+
+ if(address_family != AF_INET)
+ return -EAFNOSUPPORT;
+
+ for (i = 0; i < 4; i++) {
+ bytes[i] = 0;
+ }
+
+ temp = *cp;
+
+ while (TRUE) {
+ if (!isdigit(temp))
+ return 0;
+
+ value = 0;
+ digit = 0;
+ for (;;) {
+ if (isascii(temp) && isdigit(temp)) {
+ value = (value * 10) + temp - '0';
+ temp = *++cp;
+ digit = 1;
+ } else
+ break;
+ }
+
+ if (temp == '.') {
+ if ((end > bytes + 2) || (value > 255))
+ return 0;
+ *end++ = value;
+ temp = *++cp;
+ } else if (temp == ':') {
+ cFYI(1,("IPv6 addresses not supported for CIFS mounts yet"));
+ return -1;
+ } else
+ break;
+ }
+
+ /* check for last characters */
+ if (temp != '\0' && (!isascii(temp) || !isspace(temp)))
+ if (temp != '\\') {
+ if (temp != '/')
+ return 0;
+ else
+ (*cp = '\\'); /* switch the slash the expected way */
+ }
+ if (value > addr_class_max[end - bytes])
+ return 0;
+
+ address.s_addr = *((int *) bytes) | htonl(value);
+ *((int *)dst) = address.s_addr;
+ return 1; /* success */
+}
+
+/*****************************************************************************
+convert a NT status code to a dos class/code
+ *****************************************************************************/
+/* NT status -> dos error map */
+static const struct {
+ __u8 dos_class;
+ __u16 dos_code;
+ __u32 ntstatus;
+} ntstatus_to_dos_map[] = {
+ {
+ ERRDOS, ERRgeneral, NT_STATUS_UNSUCCESSFUL}, {
+ ERRDOS, ERRbadfunc, NT_STATUS_NOT_IMPLEMENTED}, {
+ ERRDOS, 87, NT_STATUS_INVALID_INFO_CLASS}, {
+ ERRDOS, 24, NT_STATUS_INFO_LENGTH_MISMATCH}, {
+ ERRHRD, ERRgeneral, NT_STATUS_ACCESS_VIOLATION}, {
+ ERRHRD, ERRgeneral, NT_STATUS_IN_PAGE_ERROR}, {
+ ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_QUOTA}, {
+ ERRDOS, ERRbadfid, NT_STATUS_INVALID_HANDLE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_BAD_INITIAL_STACK}, {
+ ERRDOS, 193, NT_STATUS_BAD_INITIAL_PC}, {
+ ERRDOS, 87, NT_STATUS_INVALID_CID}, {
+ ERRHRD, ERRgeneral, NT_STATUS_TIMER_NOT_CANCELED}, {
+ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER}, {
+ ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_DEVICE}, {
+ ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_FILE}, {
+ ERRDOS, ERRbadfunc, NT_STATUS_INVALID_DEVICE_REQUEST}, {
+ ERRDOS, 38, NT_STATUS_END_OF_FILE}, {
+ ERRDOS, 34, NT_STATUS_WRONG_VOLUME}, {
+ ERRDOS, 21, NT_STATUS_NO_MEDIA_IN_DEVICE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_UNRECOGNIZED_MEDIA}, {
+ ERRDOS, 27, NT_STATUS_NONEXISTENT_SECTOR},
+/* { This NT error code was 'sqashed'
+ from NT_STATUS_MORE_PROCESSING_REQUIRED to NT_STATUS_OK
+ during the session setup } */
+ {
+ ERRDOS, ERRnomem, NT_STATUS_NO_MEMORY}, {
+ ERRDOS, 487, NT_STATUS_CONFLICTING_ADDRESSES}, {
+ ERRDOS, 487, NT_STATUS_NOT_MAPPED_VIEW}, {
+ ERRDOS, 87, NT_STATUS_UNABLE_TO_FREE_VM}, {
+ ERRDOS, 87, NT_STATUS_UNABLE_TO_DELETE_SECTION}, {
+ ERRDOS, 2142, NT_STATUS_INVALID_SYSTEM_SERVICE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_INSTRUCTION}, {
+ ERRDOS, ERRnoaccess, NT_STATUS_INVALID_LOCK_SEQUENCE}, {
+ ERRDOS, ERRnoaccess, NT_STATUS_INVALID_VIEW_SIZE}, {
+ ERRDOS, 193, NT_STATUS_INVALID_FILE_FOR_SECTION}, {
+ ERRDOS, ERRnoaccess, NT_STATUS_ALREADY_COMMITTED},
+/* { This NT error code was 'sqashed'
+ from NT_STATUS_ACCESS_DENIED to NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE
+ during the session setup } */
+ {
+ ERRDOS, ERRnoaccess, NT_STATUS_ACCESS_DENIED}, {
+ ERRDOS, 111, NT_STATUS_BUFFER_TOO_SMALL}, {
+ ERRDOS, ERRbadfid, NT_STATUS_OBJECT_TYPE_MISMATCH}, {
+ ERRHRD, ERRgeneral, NT_STATUS_NONCONTINUABLE_EXCEPTION}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INVALID_DISPOSITION}, {
+ ERRHRD, ERRgeneral, NT_STATUS_UNWIND}, {
+ ERRHRD, ERRgeneral, NT_STATUS_BAD_STACK}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INVALID_UNWIND_TARGET}, {
+ ERRDOS, 158, NT_STATUS_NOT_LOCKED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_PARITY_ERROR}, {
+ ERRDOS, 487, NT_STATUS_UNABLE_TO_DECOMMIT_VM}, {
+ ERRDOS, 487, NT_STATUS_NOT_COMMITTED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INVALID_PORT_ATTRIBUTES}, {
+ ERRHRD, ERRgeneral, NT_STATUS_PORT_MESSAGE_TOO_LONG}, {
+ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_MIX}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INVALID_QUOTA_LOWER}, {
+ ERRHRD, ERRgeneral, NT_STATUS_DISK_CORRUPT_ERROR}, {
+ ERRDOS, ERRbadfile, NT_STATUS_OBJECT_NAME_INVALID}, { /* mapping changed since shell does lookup on * and expects file not found */
+ ERRDOS, ERRbadfile, NT_STATUS_OBJECT_NAME_NOT_FOUND}, {
+ ERRDOS, ERRalreadyexists, NT_STATUS_OBJECT_NAME_COLLISION}, {
+ ERRHRD, ERRgeneral, NT_STATUS_HANDLE_NOT_WAITABLE}, {
+ ERRDOS, ERRbadfid, NT_STATUS_PORT_DISCONNECTED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_DEVICE_ALREADY_ATTACHED}, {
+ ERRDOS, 161, NT_STATUS_OBJECT_PATH_INVALID}, {
+ ERRDOS, ERRbadpath, NT_STATUS_OBJECT_PATH_NOT_FOUND}, {
+ ERRDOS, 161, NT_STATUS_OBJECT_PATH_SYNTAX_BAD}, {
+ ERRHRD, ERRgeneral, NT_STATUS_DATA_OVERRUN}, {
+ ERRHRD, ERRgeneral, NT_STATUS_DATA_LATE_ERROR}, {
+ ERRDOS, 23, NT_STATUS_DATA_ERROR}, {
+ ERRDOS, 23, NT_STATUS_CRC_ERROR}, {
+ ERRDOS, ERRnomem, NT_STATUS_SECTION_TOO_BIG}, {
+ ERRDOS, ERRnoaccess, NT_STATUS_PORT_CONNECTION_REFUSED}, {
+ ERRDOS, ERRbadfid, NT_STATUS_INVALID_PORT_HANDLE}, {
+ ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION}, {
+ ERRHRD, ERRgeneral, NT_STATUS_QUOTA_EXCEEDED}, {
+ ERRDOS, 87, NT_STATUS_INVALID_PAGE_PROTECTION}, {
+ ERRDOS, 288, NT_STATUS_MUTANT_NOT_OWNED}, {
+ ERRDOS, 298, NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED}, {
+ ERRDOS, 87, NT_STATUS_PORT_ALREADY_SET}, {
+ ERRDOS, 87, NT_STATUS_SECTION_NOT_IMAGE}, {
+ ERRDOS, 156, NT_STATUS_SUSPEND_COUNT_EXCEEDED}, {
+ ERRDOS, ERRnoaccess, NT_STATUS_THREAD_IS_TERMINATING}, {
+ ERRDOS, 87, NT_STATUS_BAD_WORKING_SET_LIMIT}, {
+ ERRDOS, 87, NT_STATUS_INCOMPATIBLE_FILE_MAP}, {
+ ERRDOS, 87, NT_STATUS_SECTION_PROTECTION}, {
+ ERRDOS, 282, NT_STATUS_EAS_NOT_SUPPORTED}, {
+ ERRDOS, 255, NT_STATUS_EA_TOO_LARGE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_NONEXISTENT_EA_ENTRY}, {
+ ERRHRD, ERRgeneral, NT_STATUS_NO_EAS_ON_FILE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_EA_CORRUPT_ERROR}, {
+ ERRDOS, ERRlock, NT_STATUS_FILE_LOCK_CONFLICT}, {
+ ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED}, {
+ ERRDOS, ERRbadfile, NT_STATUS_DELETE_PENDING}, {
+ ERRDOS, ERRunsup, NT_STATUS_CTL_FILE_NOT_SUPPORTED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_UNKNOWN_REVISION}, {
+ ERRHRD, ERRgeneral, NT_STATUS_REVISION_MISMATCH}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INVALID_OWNER}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INVALID_PRIMARY_GROUP}, {
+ ERRHRD, ERRgeneral, NT_STATUS_NO_IMPERSONATION_TOKEN}, {
+ ERRHRD, ERRgeneral, NT_STATUS_CANT_DISABLE_MANDATORY}, {
+ ERRDOS, 2215, NT_STATUS_NO_LOGON_SERVERS}, {
+ ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_LOGON_SESSION}, {
+ ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_PRIVILEGE}, {
+ ERRDOS, ERRnoaccess, NT_STATUS_PRIVILEGE_NOT_HELD}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INVALID_ACCOUNT_NAME}, {
+ ERRHRD, ERRgeneral, NT_STATUS_USER_EXISTS},
+/* { This NT error code was 'sqashed'
+ from NT_STATUS_NO_SUCH_USER to NT_STATUS_LOGON_FAILURE
+ during the session setup } */
+ {
+ ERRDOS, ERRnoaccess, NT_STATUS_NO_SUCH_USER}, {
+ ERRHRD, ERRgeneral, NT_STATUS_GROUP_EXISTS}, {
+ ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_GROUP}, {
+ ERRHRD, ERRgeneral, NT_STATUS_MEMBER_IN_GROUP}, {
+ ERRHRD, ERRgeneral, NT_STATUS_MEMBER_NOT_IN_GROUP}, {
+ ERRHRD, ERRgeneral, NT_STATUS_LAST_ADMIN},
+/* { This NT error code was 'sqashed'
+ from NT_STATUS_WRONG_PASSWORD to NT_STATUS_LOGON_FAILURE
+ during the session setup } */
+ {
+ ERRSRV, ERRbadpw, NT_STATUS_WRONG_PASSWORD}, {
+ ERRHRD, ERRgeneral, NT_STATUS_ILL_FORMED_PASSWORD}, {
+ ERRHRD, ERRgeneral, NT_STATUS_PASSWORD_RESTRICTION}, {
+ ERRDOS, ERRnoaccess, NT_STATUS_LOGON_FAILURE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_ACCOUNT_RESTRICTION}, {
+ ERRSRV, 2241, NT_STATUS_INVALID_LOGON_HOURS}, {
+ ERRSRV, 2240, NT_STATUS_INVALID_WORKSTATION}, {
+ ERRSRV, 2242, NT_STATUS_PASSWORD_EXPIRED}, {
+ ERRSRV, 2239, NT_STATUS_ACCOUNT_DISABLED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_NONE_MAPPED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LUIDS_REQUESTED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_LUIDS_EXHAUSTED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INVALID_SUB_AUTHORITY}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INVALID_ACL}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INVALID_SID}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INVALID_SECURITY_DESCR}, {
+ ERRDOS, 127, NT_STATUS_PROCEDURE_NOT_FOUND}, {
+ ERRDOS, 193, NT_STATUS_INVALID_IMAGE_FORMAT}, {
+ ERRHRD, ERRgeneral, NT_STATUS_NO_TOKEN}, {
+ ERRHRD, ERRgeneral, NT_STATUS_BAD_INHERITANCE_ACL}, {
+ ERRDOS, 158, NT_STATUS_RANGE_NOT_LOCKED}, {
+ ERRDOS, 112, NT_STATUS_DISK_FULL}, {
+ ERRHRD, ERRgeneral, NT_STATUS_SERVER_DISABLED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_SERVER_NOT_DISABLED}, {
+ ERRDOS, 68, NT_STATUS_TOO_MANY_GUIDS_REQUESTED}, {
+ ERRDOS, 259, NT_STATUS_GUIDS_EXHAUSTED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INVALID_ID_AUTHORITY}, {
+ ERRDOS, 259, NT_STATUS_AGENTS_EXHAUSTED}, {
+ ERRDOS, 154, NT_STATUS_INVALID_VOLUME_LABEL}, {
+ ERRDOS, 14, NT_STATUS_SECTION_NOT_EXTENDED}, {
+ ERRDOS, 487, NT_STATUS_NOT_MAPPED_DATA}, {
+ ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_DATA_NOT_FOUND}, {
+ ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_TYPE_NOT_FOUND}, {
+ ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_NAME_NOT_FOUND}, {
+ ERRHRD, ERRgeneral, NT_STATUS_ARRAY_BOUNDS_EXCEEDED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_FLOAT_DENORMAL_OPERAND}, {
+ ERRHRD, ERRgeneral, NT_STATUS_FLOAT_DIVIDE_BY_ZERO}, {
+ ERRHRD, ERRgeneral, NT_STATUS_FLOAT_INEXACT_RESULT}, {
+ ERRHRD, ERRgeneral, NT_STATUS_FLOAT_INVALID_OPERATION}, {
+ ERRHRD, ERRgeneral, NT_STATUS_FLOAT_OVERFLOW}, {
+ ERRHRD, ERRgeneral, NT_STATUS_FLOAT_STACK_CHECK}, {
+ ERRHRD, ERRgeneral, NT_STATUS_FLOAT_UNDERFLOW}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INTEGER_DIVIDE_BY_ZERO}, {
+ ERRDOS, 534, NT_STATUS_INTEGER_OVERFLOW}, {
+ ERRHRD, ERRgeneral, NT_STATUS_PRIVILEGED_INSTRUCTION}, {
+ ERRDOS, ERRnomem, NT_STATUS_TOO_MANY_PAGING_FILES}, {
+ ERRHRD, ERRgeneral, NT_STATUS_FILE_INVALID}, {
+ ERRHRD, ERRgeneral, NT_STATUS_ALLOTTED_SPACE_EXCEEDED},
+/* { This NT error code was 'sqashed'
+ from NT_STATUS_INSUFFICIENT_RESOURCES to NT_STATUS_INSUFF_SERVER_RESOURCES
+ during the session setup } */
+ {
+ ERRDOS, ERRnomem, NT_STATUS_INSUFFICIENT_RESOURCES}, {
+ ERRDOS, ERRbadpath, NT_STATUS_DFS_EXIT_PATH_FOUND}, {
+ ERRDOS, 23, NT_STATUS_DEVICE_DATA_ERROR}, {
+ ERRHRD, ERRgeneral, NT_STATUS_DEVICE_NOT_CONNECTED}, {
+ ERRDOS, 21, NT_STATUS_DEVICE_POWER_FAILURE}, {
+ ERRDOS, 487, NT_STATUS_FREE_VM_NOT_AT_BASE}, {
+ ERRDOS, 487, NT_STATUS_MEMORY_NOT_ALLOCATED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_WORKING_SET_QUOTA}, {
+ ERRDOS, 19, NT_STATUS_MEDIA_WRITE_PROTECTED}, {
+ ERRDOS, 21, NT_STATUS_DEVICE_NOT_READY}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INVALID_GROUP_ATTRIBUTES}, {
+ ERRHRD, ERRgeneral, NT_STATUS_BAD_IMPERSONATION_LEVEL}, {
+ ERRHRD, ERRgeneral, NT_STATUS_CANT_OPEN_ANONYMOUS}, {
+ ERRHRD, ERRgeneral, NT_STATUS_BAD_VALIDATION_CLASS}, {
+ ERRHRD, ERRgeneral, NT_STATUS_BAD_TOKEN_TYPE}, {
+ ERRDOS, 87, NT_STATUS_BAD_MASTER_BOOT_RECORD}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INSTRUCTION_MISALIGNMENT}, {
+ ERRDOS, ERRpipebusy, NT_STATUS_INSTANCE_NOT_AVAILABLE}, {
+ ERRDOS, ERRpipebusy, NT_STATUS_PIPE_NOT_AVAILABLE}, {
+ ERRDOS, ERRbadpipe, NT_STATUS_INVALID_PIPE_STATE}, {
+ ERRDOS, ERRpipebusy, NT_STATUS_PIPE_BUSY}, {
+ ERRDOS, ERRbadfunc, NT_STATUS_ILLEGAL_FUNCTION}, {
+ ERRDOS, ERRnotconnected, NT_STATUS_PIPE_DISCONNECTED}, {
+ ERRDOS, ERRpipeclosing, NT_STATUS_PIPE_CLOSING}, {
+ ERRHRD, ERRgeneral, NT_STATUS_PIPE_CONNECTED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_PIPE_LISTENING}, {
+ ERRDOS, ERRbadpipe, NT_STATUS_INVALID_READ_MODE}, {
+ ERRDOS, 121, NT_STATUS_IO_TIMEOUT}, {
+ ERRDOS, 38, NT_STATUS_FILE_FORCED_CLOSED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_PROFILING_NOT_STARTED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_PROFILING_NOT_STOPPED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_COULD_NOT_INTERPRET}, {
+ ERRDOS, ERRnoaccess, NT_STATUS_FILE_IS_A_DIRECTORY}, {
+ ERRDOS, ERRunsup, NT_STATUS_NOT_SUPPORTED}, {
+ ERRDOS, 51, NT_STATUS_REMOTE_NOT_LISTENING}, {
+ ERRDOS, 52, NT_STATUS_DUPLICATE_NAME}, {
+ ERRDOS, 53, NT_STATUS_BAD_NETWORK_PATH}, {
+ ERRDOS, 54, NT_STATUS_NETWORK_BUSY}, {
+ ERRDOS, 55, NT_STATUS_DEVICE_DOES_NOT_EXIST}, {
+ ERRDOS, 56, NT_STATUS_TOO_MANY_COMMANDS}, {
+ ERRDOS, 57, NT_STATUS_ADAPTER_HARDWARE_ERROR}, {
+ ERRDOS, 58, NT_STATUS_INVALID_NETWORK_RESPONSE}, {
+ ERRDOS, 59, NT_STATUS_UNEXPECTED_NETWORK_ERROR}, {
+ ERRDOS, 60, NT_STATUS_BAD_REMOTE_ADAPTER}, {
+ ERRDOS, 61, NT_STATUS_PRINT_QUEUE_FULL}, {
+ ERRDOS, 62, NT_STATUS_NO_SPOOL_SPACE}, {
+ ERRDOS, 63, NT_STATUS_PRINT_CANCELLED}, {
+ ERRDOS, 64, NT_STATUS_NETWORK_NAME_DELETED}, {
+ ERRDOS, 65, NT_STATUS_NETWORK_ACCESS_DENIED}, {
+ ERRDOS, 66, NT_STATUS_BAD_DEVICE_TYPE}, {
+ ERRDOS, ERRnosuchshare, NT_STATUS_BAD_NETWORK_NAME}, {
+ ERRDOS, 68, NT_STATUS_TOO_MANY_NAMES}, {
+ ERRDOS, 69, NT_STATUS_TOO_MANY_SESSIONS}, {
+ ERRDOS, 70, NT_STATUS_SHARING_PAUSED}, {
+ ERRDOS, 71, NT_STATUS_REQUEST_NOT_ACCEPTED}, {
+ ERRDOS, 72, NT_STATUS_REDIRECTOR_PAUSED}, {
+ ERRDOS, 88, NT_STATUS_NET_WRITE_FAULT}, {
+ ERRHRD, ERRgeneral, NT_STATUS_PROFILING_AT_LIMIT}, {
+ ERRDOS, ERRdiffdevice, NT_STATUS_NOT_SAME_DEVICE}, {
+ ERRDOS, ERRnoaccess, NT_STATUS_FILE_RENAMED}, {
+ ERRDOS, 240, NT_STATUS_VIRTUAL_CIRCUIT_CLOSED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_NO_SECURITY_ON_OBJECT}, {
+ ERRHRD, ERRgeneral, NT_STATUS_CANT_WAIT}, {
+ ERRDOS, ERRpipeclosing, NT_STATUS_PIPE_EMPTY}, {
+ ERRHRD, ERRgeneral, NT_STATUS_CANT_ACCESS_DOMAIN_INFO}, {
+ ERRHRD, ERRgeneral, NT_STATUS_CANT_TERMINATE_SELF}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INVALID_SERVER_STATE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INVALID_DOMAIN_STATE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INVALID_DOMAIN_ROLE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_DOMAIN}, {
+ ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_EXISTS}, {
+ ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_LIMIT_EXCEEDED}, {
+ ERRDOS, 300, NT_STATUS_OPLOCK_NOT_GRANTED}, {
+ ERRDOS, 301, NT_STATUS_INVALID_OPLOCK_PROTOCOL}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_DB_CORRUPTION}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_ERROR}, {
+ ERRHRD, ERRgeneral, NT_STATUS_GENERIC_NOT_MAPPED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_BAD_DESCRIPTOR_FORMAT}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INVALID_USER_BUFFER}, {
+ ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_IO_ERROR}, {
+ ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_CREATE_ERR}, {
+ ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_MAP_ERROR}, {
+ ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_EXTEND_ERR}, {
+ ERRHRD, ERRgeneral, NT_STATUS_NOT_LOGON_PROCESS}, {
+ ERRHRD, ERRgeneral, NT_STATUS_LOGON_SESSION_EXISTS}, {
+ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_1}, {
+ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_2}, {
+ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_3}, {
+ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_4}, {
+ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_5}, {
+ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_6}, {
+ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_7}, {
+ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_8}, {
+ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_9}, {
+ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_10}, {
+ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_11}, {
+ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_12}, {
+ ERRDOS, ERRbadpath, NT_STATUS_REDIRECTOR_NOT_STARTED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_REDIRECTOR_STARTED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_STACK_OVERFLOW}, {
+ ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_PACKAGE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_BAD_FUNCTION_TABLE}, {
+ ERRDOS, 203, 0xc0000100}, {
+ ERRDOS, 145, NT_STATUS_DIRECTORY_NOT_EMPTY}, {
+ ERRHRD, ERRgeneral, NT_STATUS_FILE_CORRUPT_ERROR}, {
+ ERRDOS, 267, NT_STATUS_NOT_A_DIRECTORY}, {
+ ERRHRD, ERRgeneral, NT_STATUS_BAD_LOGON_SESSION_STATE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_LOGON_SESSION_COLLISION}, {
+ ERRDOS, 206, NT_STATUS_NAME_TOO_LONG}, {
+ ERRDOS, 2401, NT_STATUS_FILES_OPEN}, {
+ ERRDOS, 2404, NT_STATUS_CONNECTION_IN_USE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_MESSAGE_NOT_FOUND}, {
+ ERRDOS, ERRnoaccess, NT_STATUS_PROCESS_IS_TERMINATING}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INVALID_LOGON_TYPE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_NO_GUID_TRANSLATION}, {
+ ERRHRD, ERRgeneral, NT_STATUS_CANNOT_IMPERSONATE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_IMAGE_ALREADY_LOADED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_ABIOS_NOT_PRESENT}, {
+ ERRHRD, ERRgeneral, NT_STATUS_ABIOS_LID_NOT_EXIST}, {
+ ERRHRD, ERRgeneral, NT_STATUS_ABIOS_LID_ALREADY_OWNED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_ABIOS_NOT_LID_OWNER}, {
+ ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_COMMAND}, {
+ ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_LID}, {
+ ERRHRD, ERRgeneral, NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_SELECTOR}, {
+ ERRHRD, ERRgeneral, NT_STATUS_NO_LDT}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_SIZE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_OFFSET}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_DESCRIPTOR}, {
+ ERRDOS, 193, NT_STATUS_INVALID_IMAGE_NE_FORMAT}, {
+ ERRHRD, ERRgeneral, NT_STATUS_RXACT_INVALID_STATE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_RXACT_COMMIT_FAILURE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_MAPPED_FILE_SIZE_ZERO}, {
+ ERRDOS, ERRnofids, NT_STATUS_TOO_MANY_OPENED_FILES}, {
+ ERRHRD, ERRgeneral, NT_STATUS_CANCELLED}, {
+ ERRDOS, ERRnoaccess, NT_STATUS_CANNOT_DELETE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INVALID_COMPUTER_NAME}, {
+ ERRDOS, ERRnoaccess, NT_STATUS_FILE_DELETED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_ACCOUNT}, {
+ ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_GROUP}, {
+ ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_USER}, {
+ ERRHRD, ERRgeneral, NT_STATUS_MEMBERS_PRIMARY_GROUP}, {
+ ERRDOS, ERRbadfid, NT_STATUS_FILE_CLOSED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_THREADS}, {
+ ERRHRD, ERRgeneral, NT_STATUS_THREAD_NOT_IN_PROCESS}, {
+ ERRHRD, ERRgeneral, NT_STATUS_TOKEN_ALREADY_IN_USE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_QUOTA_EXCEEDED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_COMMITMENT_LIMIT}, {
+ ERRDOS, 193, NT_STATUS_INVALID_IMAGE_LE_FORMAT}, {
+ ERRDOS, 193, NT_STATUS_INVALID_IMAGE_NOT_MZ}, {
+ ERRDOS, 193, NT_STATUS_INVALID_IMAGE_PROTECT}, {
+ ERRDOS, 193, NT_STATUS_INVALID_IMAGE_WIN_16}, {
+ ERRHRD, ERRgeneral, NT_STATUS_LOGON_SERVER_CONFLICT}, {
+ ERRHRD, ERRgeneral, NT_STATUS_TIME_DIFFERENCE_AT_DC}, {
+ ERRHRD, ERRgeneral, NT_STATUS_SYNCHRONIZATION_REQUIRED}, {
+ ERRDOS, 126, NT_STATUS_DLL_NOT_FOUND}, {
+ ERRHRD, ERRgeneral, NT_STATUS_OPEN_FAILED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_IO_PRIVILEGE_FAILED}, {
+ ERRDOS, 182, NT_STATUS_ORDINAL_NOT_FOUND}, {
+ ERRDOS, 127, NT_STATUS_ENTRYPOINT_NOT_FOUND}, {
+ ERRHRD, ERRgeneral, NT_STATUS_CONTROL_C_EXIT}, {
+ ERRDOS, 64, NT_STATUS_LOCAL_DISCONNECT}, {
+ ERRDOS, 64, NT_STATUS_REMOTE_DISCONNECT}, {
+ ERRDOS, 51, NT_STATUS_REMOTE_RESOURCES}, {
+ ERRDOS, 59, NT_STATUS_LINK_FAILED}, {
+ ERRDOS, 59, NT_STATUS_LINK_TIMEOUT}, {
+ ERRDOS, 59, NT_STATUS_INVALID_CONNECTION}, {
+ ERRDOS, 59, NT_STATUS_INVALID_ADDRESS}, {
+ ERRHRD, ERRgeneral, NT_STATUS_DLL_INIT_FAILED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_MISSING_SYSTEMFILE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_UNHANDLED_EXCEPTION}, {
+ ERRHRD, ERRgeneral, NT_STATUS_APP_INIT_FAILURE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_CREATE_FAILED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_NO_PAGEFILE}, {
+ ERRDOS, 124, NT_STATUS_INVALID_LEVEL}, {
+ ERRDOS, 86, NT_STATUS_WRONG_PASSWORD_CORE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_FLOAT_CONTEXT}, {
+ ERRDOS, 109, NT_STATUS_PIPE_BROKEN}, {
+ ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_CORRUPT}, {
+ ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_IO_FAILED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_NO_EVENT_PAIR}, {
+ ERRHRD, ERRgeneral, NT_STATUS_UNRECOGNIZED_VOLUME}, {
+ ERRHRD, ERRgeneral, NT_STATUS_SERIAL_NO_DEVICE_INITED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_ALIAS}, {
+ ERRHRD, ERRgeneral, NT_STATUS_MEMBER_NOT_IN_ALIAS}, {
+ ERRHRD, ERRgeneral, NT_STATUS_MEMBER_IN_ALIAS}, {
+ ERRHRD, ERRgeneral, NT_STATUS_ALIAS_EXISTS}, {
+ ERRHRD, ERRgeneral, NT_STATUS_LOGON_NOT_GRANTED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_SECRETS}, {
+ ERRHRD, ERRgeneral, NT_STATUS_SECRET_TOO_LONG}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_DB_ERROR}, {
+ ERRHRD, ERRgeneral, NT_STATUS_FULLSCREEN_MODE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_CONTEXT_IDS}, {
+ ERRDOS, ERRnoaccess, NT_STATUS_LOGON_TYPE_NOT_GRANTED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_NOT_REGISTRY_FILE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR}, {
+ ERRHRD, ERRgeneral, NT_STATUS_FT_MISSING_MEMBER}, {
+ ERRHRD, ERRgeneral, NT_STATUS_ILL_FORMED_SERVICE_ENTRY}, {
+ ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_CHARACTER}, {
+ ERRHRD, ERRgeneral, NT_STATUS_UNMAPPABLE_CHARACTER}, {
+ ERRHRD, ERRgeneral, NT_STATUS_UNDEFINED_CHARACTER}, {
+ ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_VOLUME}, {
+ ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND}, {
+ ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_WRONG_CYLINDER}, {
+ ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_UNKNOWN_ERROR}, {
+ ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_BAD_REGISTERS}, {
+ ERRHRD, ERRgeneral, NT_STATUS_DISK_RECALIBRATE_FAILED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_DISK_OPERATION_FAILED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_DISK_RESET_FAILED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_SHARED_IRQ_BUSY}, {
+ ERRHRD, ERRgeneral, NT_STATUS_FT_ORPHANING}, {
+ ERRHRD, ERRgeneral, 0xc000016e}, {
+ ERRHRD, ERRgeneral, 0xc000016f}, {
+ ERRHRD, ERRgeneral, 0xc0000170}, {
+ ERRHRD, ERRgeneral, 0xc0000171}, {
+ ERRHRD, ERRgeneral, NT_STATUS_PARTITION_FAILURE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INVALID_BLOCK_LENGTH}, {
+ ERRHRD, ERRgeneral, NT_STATUS_DEVICE_NOT_PARTITIONED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_UNABLE_TO_LOCK_MEDIA}, {
+ ERRHRD, ERRgeneral, NT_STATUS_UNABLE_TO_UNLOAD_MEDIA}, {
+ ERRHRD, ERRgeneral, NT_STATUS_EOM_OVERFLOW}, {
+ ERRHRD, ERRgeneral, NT_STATUS_NO_MEDIA}, {
+ ERRHRD, ERRgeneral, 0xc0000179}, {
+ ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_MEMBER}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INVALID_MEMBER}, {
+ ERRHRD, ERRgeneral, NT_STATUS_KEY_DELETED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_NO_LOG_SPACE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_SIDS}, {
+ ERRHRD, ERRgeneral, NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_KEY_HAS_CHILDREN}, {
+ ERRHRD, ERRgeneral, NT_STATUS_CHILD_MUST_BE_VOLATILE}, {
+ ERRDOS, 87, NT_STATUS_DEVICE_CONFIGURATION_ERROR}, {
+ ERRHRD, ERRgeneral, NT_STATUS_DRIVER_INTERNAL_ERROR}, {
+ ERRDOS, 22, NT_STATUS_INVALID_DEVICE_STATE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_IO_DEVICE_ERROR}, {
+ ERRHRD, ERRgeneral, NT_STATUS_DEVICE_PROTOCOL_ERROR}, {
+ ERRHRD, ERRgeneral, NT_STATUS_BACKUP_CONTROLLER}, {
+ ERRHRD, ERRgeneral, NT_STATUS_LOG_FILE_FULL}, {
+ ERRDOS, 19, NT_STATUS_TOO_LATE}, {
+ ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_LSA_SECRET},
+/* { This NT error code was 'sqashed'
+ from NT_STATUS_NO_TRUST_SAM_ACCOUNT to NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE
+ during the session setup } */
+ {
+ ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_SAM_ACCOUNT}, {
+ ERRDOS, ERRnoaccess, NT_STATUS_TRUSTED_DOMAIN_FAILURE}, {
+ ERRDOS, ERRnoaccess, NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_FILE_CORRUPT}, {
+ ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_CANT_START}, {
+ ERRDOS, ERRnoaccess, NT_STATUS_TRUST_FAILURE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_MUTANT_LIMIT_EXCEEDED}, {
+ ERRDOS, ERRnetlogonNotStarted, NT_STATUS_NETLOGON_NOT_STARTED}, {
+ ERRSRV, 2239, NT_STATUS_ACCOUNT_EXPIRED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_POSSIBLE_DEADLOCK}, {
+ ERRHRD, ERRgeneral, NT_STATUS_NETWORK_CREDENTIAL_CONFLICT}, {
+ ERRHRD, ERRgeneral, NT_STATUS_REMOTE_SESSION_LIMIT}, {
+ ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_FILE_CHANGED}, {
+ ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT}, {
+ ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT}, {
+ ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT},
+/* { This NT error code was 'sqashed'
+ from NT_STATUS_DOMAIN_TRUST_INCONSISTENT to NT_STATUS_LOGON_FAILURE
+ during the session setup } */
+ {
+ ERRDOS, ERRnoaccess, NT_STATUS_DOMAIN_TRUST_INCONSISTENT}, {
+ ERRHRD, ERRgeneral, NT_STATUS_FS_DRIVER_REQUIRED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_NO_USER_SESSION_KEY}, {
+ ERRDOS, 59, NT_STATUS_USER_SESSION_DELETED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_LANG_NOT_FOUND}, {
+ ERRDOS, ERRnomem, NT_STATUS_INSUFF_SERVER_RESOURCES}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INVALID_BUFFER_SIZE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INVALID_ADDRESS_COMPONENT}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INVALID_ADDRESS_WILDCARD}, {
+ ERRDOS, 68, NT_STATUS_TOO_MANY_ADDRESSES}, {
+ ERRDOS, 52, NT_STATUS_ADDRESS_ALREADY_EXISTS}, {
+ ERRDOS, 64, NT_STATUS_ADDRESS_CLOSED}, {
+ ERRDOS, 64, NT_STATUS_CONNECTION_DISCONNECTED}, {
+ ERRDOS, 64, NT_STATUS_CONNECTION_RESET}, {
+ ERRDOS, 68, NT_STATUS_TOO_MANY_NODES}, {
+ ERRDOS, 59, NT_STATUS_TRANSACTION_ABORTED}, {
+ ERRDOS, 59, NT_STATUS_TRANSACTION_TIMED_OUT}, {
+ ERRDOS, 59, NT_STATUS_TRANSACTION_NO_RELEASE}, {
+ ERRDOS, 59, NT_STATUS_TRANSACTION_NO_MATCH}, {
+ ERRDOS, 59, NT_STATUS_TRANSACTION_RESPONDED}, {
+ ERRDOS, 59, NT_STATUS_TRANSACTION_INVALID_ID}, {
+ ERRDOS, 59, NT_STATUS_TRANSACTION_INVALID_TYPE}, {
+ ERRDOS, ERRunsup, NT_STATUS_NOT_SERVER_SESSION}, {
+ ERRDOS, ERRunsup, NT_STATUS_NOT_CLIENT_SESSION}, {
+ ERRHRD, ERRgeneral, NT_STATUS_CANNOT_LOAD_REGISTRY_FILE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_DEBUG_ATTACH_FAILED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_SYSTEM_PROCESS_TERMINATED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_DATA_NOT_ACCEPTED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_NO_BROWSER_SERVERS_FOUND}, {
+ ERRHRD, ERRgeneral, NT_STATUS_VDM_HARD_ERROR}, {
+ ERRHRD, ERRgeneral, NT_STATUS_DRIVER_CANCEL_TIMEOUT}, {
+ ERRHRD, ERRgeneral, NT_STATUS_REPLY_MESSAGE_MISMATCH}, {
+ ERRHRD, ERRgeneral, NT_STATUS_MAPPED_ALIGNMENT}, {
+ ERRDOS, 193, NT_STATUS_IMAGE_CHECKSUM_MISMATCH}, {
+ ERRHRD, ERRgeneral, NT_STATUS_LOST_WRITEBEHIND_DATA}, {
+ ERRHRD, ERRgeneral, NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID}, {
+ ERRSRV, 2242, NT_STATUS_PASSWORD_MUST_CHANGE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_NOT_FOUND}, {
+ ERRHRD, ERRgeneral, NT_STATUS_NOT_TINY_STREAM}, {
+ ERRHRD, ERRgeneral, NT_STATUS_RECOVERY_FAILURE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_STACK_OVERFLOW_READ}, {
+ ERRHRD, ERRgeneral, NT_STATUS_FAIL_CHECK}, {
+ ERRHRD, ERRgeneral, NT_STATUS_DUPLICATE_OBJECTID}, {
+ ERRHRD, ERRgeneral, NT_STATUS_OBJECTID_EXISTS}, {
+ ERRHRD, ERRgeneral, NT_STATUS_CONVERT_TO_LARGE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_RETRY}, {
+ ERRHRD, ERRgeneral, NT_STATUS_FOUND_OUT_OF_SCOPE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_ALLOCATE_BUCKET}, {
+ ERRHRD, ERRgeneral, NT_STATUS_PROPSET_NOT_FOUND}, {
+ ERRHRD, ERRgeneral, NT_STATUS_MARSHALL_OVERFLOW}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INVALID_VARIANT}, {
+ ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND}, {
+ ERRDOS, ERRnoaccess, NT_STATUS_ACCOUNT_LOCKED_OUT}, {
+ ERRDOS, ERRbadfid, NT_STATUS_HANDLE_NOT_CLOSABLE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_REFUSED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_GRACEFUL_DISCONNECT}, {
+ ERRHRD, ERRgeneral, NT_STATUS_ADDRESS_ALREADY_ASSOCIATED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_ADDRESS_NOT_ASSOCIATED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_INVALID}, {
+ ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_ACTIVE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_NETWORK_UNREACHABLE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_HOST_UNREACHABLE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_PROTOCOL_UNREACHABLE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_PORT_UNREACHABLE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_REQUEST_ABORTED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_ABORTED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_BAD_COMPRESSION_BUFFER}, {
+ ERRHRD, ERRgeneral, NT_STATUS_USER_MAPPED_FILE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_AUDIT_FAILED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_TIMER_RESOLUTION_NOT_SET}, {
+ ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_COUNT_LIMIT}, {
+ ERRHRD, ERRgeneral, NT_STATUS_LOGIN_TIME_RESTRICTION}, {
+ ERRHRD, ERRgeneral, NT_STATUS_LOGIN_WKSTA_RESTRICTION}, {
+ ERRDOS, 193, NT_STATUS_IMAGE_MP_UP_MISMATCH}, {
+ ERRHRD, ERRgeneral, 0xc000024a}, {
+ ERRHRD, ERRgeneral, 0xc000024b}, {
+ ERRHRD, ERRgeneral, 0xc000024c}, {
+ ERRHRD, ERRgeneral, 0xc000024d}, {
+ ERRHRD, ERRgeneral, 0xc000024e}, {
+ ERRHRD, ERRgeneral, 0xc000024f}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INSUFFICIENT_LOGON_INFO}, {
+ ERRHRD, ERRgeneral, NT_STATUS_BAD_DLL_ENTRYPOINT}, {
+ ERRHRD, ERRgeneral, NT_STATUS_BAD_SERVICE_ENTRYPOINT}, {
+ ERRHRD, ERRgeneral, NT_STATUS_LPC_REPLY_LOST}, {
+ ERRHRD, ERRgeneral, NT_STATUS_IP_ADDRESS_CONFLICT1}, {
+ ERRHRD, ERRgeneral, NT_STATUS_IP_ADDRESS_CONFLICT2}, {
+ ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_QUOTA_LIMIT}, {
+ ERRSRV, 3, NT_STATUS_PATH_NOT_COVERED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_NO_CALLBACK_ACTIVE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_LICENSE_QUOTA_EXCEEDED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_PWD_TOO_SHORT}, {
+ ERRHRD, ERRgeneral, NT_STATUS_PWD_TOO_RECENT}, {
+ ERRHRD, ERRgeneral, NT_STATUS_PWD_HISTORY_CONFLICT}, {
+ ERRHRD, ERRgeneral, 0xc000025d}, {
+ ERRHRD, ERRgeneral, NT_STATUS_PLUGPLAY_NO_DEVICE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_UNSUPPORTED_COMPRESSION}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INVALID_HW_PROFILE}, {
+ ERRHRD, ERRgeneral, NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH}, {
+ ERRDOS, 182, NT_STATUS_DRIVER_ORDINAL_NOT_FOUND}, {
+ ERRDOS, 127, NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND}, {
+ ERRDOS, 288, NT_STATUS_RESOURCE_NOT_OWNED}, {
+ ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LINKS}, {
+ ERRHRD, ERRgeneral, NT_STATUS_QUOTA_LIST_INCONSISTENT}, {
+ ERRHRD, ERRgeneral, NT_STATUS_FILE_IS_OFFLINE}, {
+ ERRDOS, 21, 0xc000026e}, {
+ ERRDOS, 161, 0xc0000281}, {
+ ERRDOS, ERRnoaccess, 0xc000028a}, {
+ ERRDOS, ERRnoaccess, 0xc000028b}, {
+ ERRHRD, ERRgeneral, 0xc000028c}, {
+ ERRDOS, ERRnoaccess, 0xc000028d}, {
+ ERRDOS, ERRnoaccess, 0xc000028e}, {
+ ERRDOS, ERRnoaccess, 0xc000028f}, {
+ ERRDOS, ERRnoaccess, 0xc0000290}, {
+ERRDOS, ERRbadfunc, 0xc000029c},};
+
+/*****************************************************************************
+ Print an error message from the status code
+ *****************************************************************************/
+static void
+cifs_print_status(__u32 status_code)
+{
+ int idx = 0;
+
+ while (nt_errs[idx].nt_errstr != NULL) {
+ if (((nt_errs[idx].nt_errcode) & 0xFFFFFF) ==
+ (status_code & 0xFFFFFF)) {
+ printk(KERN_NOTICE "Status code returned 0x%08x %s\n",
+ status_code,nt_errs[idx].nt_errstr);
+ }
+ idx++;
+ }
+ return;
+}
+
+
+static void
+ntstatus_to_dos(__u32 ntstatus, __u8 * eclass, __u16 * ecode)
+{
+ int i;
+ if (ntstatus == 0) {
+ *eclass = 0;
+ *ecode = 0;
+ return;
+ }
+ for (i = 0; ntstatus_to_dos_map[i].ntstatus; i++) {
+ if (ntstatus == ntstatus_to_dos_map[i].ntstatus) {
+ *eclass = ntstatus_to_dos_map[i].dos_class;
+ *ecode = ntstatus_to_dos_map[i].dos_code;
+ return;
+ }
+ }
+ *eclass = ERRHRD;
+ *ecode = ERRgeneral;
+}
+
+int
+map_smb_to_linux_error(struct smb_hdr *smb)
+{
+ unsigned int i;
+ int rc = -EIO; /* if transport error smb error may not be set */
+ __u8 smberrclass;
+ __u16 smberrcode;
+
+ /* BB if NT Status codes - map NT BB */
+
+ /* old style smb error codes */
+ if (smb->Status.CifsError == 0)
+ return 0;
+
+ if (smb->Flags2 & SMBFLG2_ERR_STATUS) {
+ /* translate the newer STATUS codes to old style errors and then to POSIX errors */
+ smb->Status.CifsError = le32_to_cpu(smb->Status.CifsError);
+ if(cifsFYI)
+ cifs_print_status(smb->Status.CifsError);
+ ntstatus_to_dos(smb->Status.CifsError, &smberrclass,
+ &smberrcode);
+ } else {
+ smberrclass = smb->Status.DosError.ErrorClass;
+ smb->Status.DosError.Error =
+ le16_to_cpu(smb->Status.DosError.Error);
+ smberrcode = smb->Status.DosError.Error;
+ }
+
+ /* old style errors */
+
+ /* DOS class smb error codes - map DOS */
+ if (smberrclass == ERRDOS) { /* one byte field no need to byte reverse */
+ for (i = 0;
+ i <
+ sizeof (mapping_table_ERRDOS) /
+ sizeof (struct smb_to_posix_error); i++) {
+ if (mapping_table_ERRDOS[i].smb_err == 0)
+ break;
+ else if (mapping_table_ERRDOS[i].smb_err == smberrcode) {
+ rc = mapping_table_ERRDOS[i].posix_code;
+ break;
+ }
+ /* else try the next error mapping one to see if it will match */
+ }
+ } else if (smberrclass == ERRSRV) { /* server class of error codes */
+ for (i = 0;
+ i <
+ sizeof (mapping_table_ERRSRV) /
+ sizeof (struct smb_to_posix_error); i++) {
+ if (mapping_table_ERRSRV[i].smb_err == 0)
+ break;
+ else if (mapping_table_ERRSRV[i].smb_err == smberrcode) {
+ rc = mapping_table_ERRSRV[i].posix_code;
+ break;
+ }
+ /* else try the next error mapping one to see if it will match */
+ }
+ }
+ /* else ERRHRD class errors or junk - return EIO */
+
+ cFYI(1, (" !!Mapping smb error code %d to POSIX err %d !!", smberrcode,rc));
+
+ /* generic corrective action e.g. reconnect SMB session on ERRbaduid could be added */
+
+ return rc;
+}
+
+/*
+ * calculate the size of the SMB message based on the fixed header
+ * portion, the number of word parameters and the data portion of the message
+ */
+unsigned int
+smbCalcSize(struct smb_hdr *ptr)
+{
+ return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) +
+ BCC(ptr));
+}
+
+/* The following are taken from fs/ntfs/util.c */
+
+#define NTFS_TIME_OFFSET ((u64)(369*365 + 89) * 24 * 3600 * 10000000)
+
+ /*
+ * Convert the NT UTC (based 1601-01-01, in hundred nanosecond units)
+ * into Unix UTC (based 1970-01-01, in seconds).
+ */
+time_t
+cifs_NTtimeToUnix(__u64 ntutc)
+{
+ /* BB what about the timezone? BB */
+
+ /* Subtract the NTFS time offset, then convert to 1s intervals. */
+ u64 t;
+
+ t = ntutc - NTFS_TIME_OFFSET;
+ do_div(t, 10000000);
+ return (time_t)t;
+}
+
+/* Convert the Unix UTC into NT UTC. */
+__u64
+cifs_UnixTimeToNT(time_t t)
+{
+ __u64 dce_time;
+ /* Convert to 100ns intervals and then add the NTFS time offset. */
+ dce_time = (__u64) t * 10000000;
+ dce_time += NTFS_TIME_OFFSET;
+ return dce_time;
+}
diff --git a/release/src/linux/linux/fs/cifs/nterr.c b/release/src/linux/linux/fs/cifs/nterr.c
new file mode 100644
index 00000000..4da50cd3
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/nterr.c
@@ -0,0 +1,687 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Luke Kenneth Casson Leighton 1997-2001.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* NT error codes - see nterr.h */
+#include <linux/types.h>
+#include <linux/fs.h>
+#include "nterr.h"
+
+const struct nt_err_code_struct nt_errs[] = {
+ {"NT_STATUS_OK", NT_STATUS_OK},
+ {"NT_STATUS_UNSUCCESSFUL", NT_STATUS_UNSUCCESSFUL},
+ {"NT_STATUS_NOT_IMPLEMENTED", NT_STATUS_NOT_IMPLEMENTED},
+ {"NT_STATUS_INVALID_INFO_CLASS", NT_STATUS_INVALID_INFO_CLASS},
+ {"NT_STATUS_INFO_LENGTH_MISMATCH", NT_STATUS_INFO_LENGTH_MISMATCH},
+ {"NT_STATUS_ACCESS_VIOLATION", NT_STATUS_ACCESS_VIOLATION},
+ {"STATUS_BUFFER_OVERFLOW", STATUS_BUFFER_OVERFLOW},
+ {"NT_STATUS_IN_PAGE_ERROR", NT_STATUS_IN_PAGE_ERROR},
+ {"NT_STATUS_PAGEFILE_QUOTA", NT_STATUS_PAGEFILE_QUOTA},
+ {"NT_STATUS_INVALID_HANDLE", NT_STATUS_INVALID_HANDLE},
+ {"NT_STATUS_BAD_INITIAL_STACK", NT_STATUS_BAD_INITIAL_STACK},
+ {"NT_STATUS_BAD_INITIAL_PC", NT_STATUS_BAD_INITIAL_PC},
+ {"NT_STATUS_INVALID_CID", NT_STATUS_INVALID_CID},
+ {"NT_STATUS_TIMER_NOT_CANCELED", NT_STATUS_TIMER_NOT_CANCELED},
+ {"NT_STATUS_INVALID_PARAMETER", NT_STATUS_INVALID_PARAMETER},
+ {"NT_STATUS_NO_SUCH_DEVICE", NT_STATUS_NO_SUCH_DEVICE},
+ {"NT_STATUS_NO_SUCH_FILE", NT_STATUS_NO_SUCH_FILE},
+ {"NT_STATUS_INVALID_DEVICE_REQUEST",
+ NT_STATUS_INVALID_DEVICE_REQUEST},
+ {"NT_STATUS_END_OF_FILE", NT_STATUS_END_OF_FILE},
+ {"NT_STATUS_WRONG_VOLUME", NT_STATUS_WRONG_VOLUME},
+ {"NT_STATUS_NO_MEDIA_IN_DEVICE", NT_STATUS_NO_MEDIA_IN_DEVICE},
+ {"NT_STATUS_UNRECOGNIZED_MEDIA", NT_STATUS_UNRECOGNIZED_MEDIA},
+ {"NT_STATUS_NONEXISTENT_SECTOR", NT_STATUS_NONEXISTENT_SECTOR},
+ {"NT_STATUS_MORE_PROCESSING_REQUIRED",
+ NT_STATUS_MORE_PROCESSING_REQUIRED},
+ {"NT_STATUS_NO_MEMORY", NT_STATUS_NO_MEMORY},
+ {"NT_STATUS_CONFLICTING_ADDRESSES",
+ NT_STATUS_CONFLICTING_ADDRESSES},
+ {"NT_STATUS_NOT_MAPPED_VIEW", NT_STATUS_NOT_MAPPED_VIEW},
+ {"NT_STATUS_UNABLE_TO_FREE_VM", NT_STATUS_UNABLE_TO_FREE_VM},
+ {"NT_STATUS_UNABLE_TO_DELETE_SECTION",
+ NT_STATUS_UNABLE_TO_DELETE_SECTION},
+ {"NT_STATUS_INVALID_SYSTEM_SERVICE",
+ NT_STATUS_INVALID_SYSTEM_SERVICE},
+ {"NT_STATUS_ILLEGAL_INSTRUCTION", NT_STATUS_ILLEGAL_INSTRUCTION},
+ {"NT_STATUS_INVALID_LOCK_SEQUENCE",
+ NT_STATUS_INVALID_LOCK_SEQUENCE},
+ {"NT_STATUS_INVALID_VIEW_SIZE", NT_STATUS_INVALID_VIEW_SIZE},
+ {"NT_STATUS_INVALID_FILE_FOR_SECTION",
+ NT_STATUS_INVALID_FILE_FOR_SECTION},
+ {"NT_STATUS_ALREADY_COMMITTED", NT_STATUS_ALREADY_COMMITTED},
+ {"NT_STATUS_ACCESS_DENIED", NT_STATUS_ACCESS_DENIED},
+ {"NT_STATUS_BUFFER_TOO_SMALL", NT_STATUS_BUFFER_TOO_SMALL},
+ {"NT_STATUS_OBJECT_TYPE_MISMATCH", NT_STATUS_OBJECT_TYPE_MISMATCH},
+ {"NT_STATUS_NONCONTINUABLE_EXCEPTION",
+ NT_STATUS_NONCONTINUABLE_EXCEPTION},
+ {"NT_STATUS_INVALID_DISPOSITION", NT_STATUS_INVALID_DISPOSITION},
+ {"NT_STATUS_UNWIND", NT_STATUS_UNWIND},
+ {"NT_STATUS_BAD_STACK", NT_STATUS_BAD_STACK},
+ {"NT_STATUS_INVALID_UNWIND_TARGET",
+ NT_STATUS_INVALID_UNWIND_TARGET},
+ {"NT_STATUS_NOT_LOCKED", NT_STATUS_NOT_LOCKED},
+ {"NT_STATUS_PARITY_ERROR", NT_STATUS_PARITY_ERROR},
+ {"NT_STATUS_UNABLE_TO_DECOMMIT_VM",
+ NT_STATUS_UNABLE_TO_DECOMMIT_VM},
+ {"NT_STATUS_NOT_COMMITTED", NT_STATUS_NOT_COMMITTED},
+ {"NT_STATUS_INVALID_PORT_ATTRIBUTES",
+ NT_STATUS_INVALID_PORT_ATTRIBUTES},
+ {"NT_STATUS_PORT_MESSAGE_TOO_LONG",
+ NT_STATUS_PORT_MESSAGE_TOO_LONG},
+ {"NT_STATUS_INVALID_PARAMETER_MIX",
+ NT_STATUS_INVALID_PARAMETER_MIX},
+ {"NT_STATUS_INVALID_QUOTA_LOWER", NT_STATUS_INVALID_QUOTA_LOWER},
+ {"NT_STATUS_DISK_CORRUPT_ERROR", NT_STATUS_DISK_CORRUPT_ERROR},
+ {"NT_STATUS_OBJECT_NAME_INVALID", NT_STATUS_OBJECT_NAME_INVALID},
+ {"NT_STATUS_OBJECT_NAME_NOT_FOUND",
+ NT_STATUS_OBJECT_NAME_NOT_FOUND},
+ {"NT_STATUS_OBJECT_NAME_COLLISION",
+ NT_STATUS_OBJECT_NAME_COLLISION},
+ {"NT_STATUS_HANDLE_NOT_WAITABLE", NT_STATUS_HANDLE_NOT_WAITABLE},
+ {"NT_STATUS_PORT_DISCONNECTED", NT_STATUS_PORT_DISCONNECTED},
+ {"NT_STATUS_DEVICE_ALREADY_ATTACHED",
+ NT_STATUS_DEVICE_ALREADY_ATTACHED},
+ {"NT_STATUS_OBJECT_PATH_INVALID", NT_STATUS_OBJECT_PATH_INVALID},
+ {"NT_STATUS_OBJECT_PATH_NOT_FOUND",
+ NT_STATUS_OBJECT_PATH_NOT_FOUND},
+ {"NT_STATUS_OBJECT_PATH_SYNTAX_BAD",
+ NT_STATUS_OBJECT_PATH_SYNTAX_BAD},
+ {"NT_STATUS_DATA_OVERRUN", NT_STATUS_DATA_OVERRUN},
+ {"NT_STATUS_DATA_LATE_ERROR", NT_STATUS_DATA_LATE_ERROR},
+ {"NT_STATUS_DATA_ERROR", NT_STATUS_DATA_ERROR},
+ {"NT_STATUS_CRC_ERROR", NT_STATUS_CRC_ERROR},
+ {"NT_STATUS_SECTION_TOO_BIG", NT_STATUS_SECTION_TOO_BIG},
+ {"NT_STATUS_PORT_CONNECTION_REFUSED",
+ NT_STATUS_PORT_CONNECTION_REFUSED},
+ {"NT_STATUS_INVALID_PORT_HANDLE", NT_STATUS_INVALID_PORT_HANDLE},
+ {"NT_STATUS_SHARING_VIOLATION", NT_STATUS_SHARING_VIOLATION},
+ {"NT_STATUS_QUOTA_EXCEEDED", NT_STATUS_QUOTA_EXCEEDED},
+ {"NT_STATUS_INVALID_PAGE_PROTECTION",
+ NT_STATUS_INVALID_PAGE_PROTECTION},
+ {"NT_STATUS_MUTANT_NOT_OWNED", NT_STATUS_MUTANT_NOT_OWNED},
+ {"NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED",
+ NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED},
+ {"NT_STATUS_PORT_ALREADY_SET", NT_STATUS_PORT_ALREADY_SET},
+ {"NT_STATUS_SECTION_NOT_IMAGE", NT_STATUS_SECTION_NOT_IMAGE},
+ {"NT_STATUS_SUSPEND_COUNT_EXCEEDED",
+ NT_STATUS_SUSPEND_COUNT_EXCEEDED},
+ {"NT_STATUS_THREAD_IS_TERMINATING",
+ NT_STATUS_THREAD_IS_TERMINATING},
+ {"NT_STATUS_BAD_WORKING_SET_LIMIT",
+ NT_STATUS_BAD_WORKING_SET_LIMIT},
+ {"NT_STATUS_INCOMPATIBLE_FILE_MAP",
+ NT_STATUS_INCOMPATIBLE_FILE_MAP},
+ {"NT_STATUS_SECTION_PROTECTION", NT_STATUS_SECTION_PROTECTION},
+ {"NT_STATUS_EAS_NOT_SUPPORTED", NT_STATUS_EAS_NOT_SUPPORTED},
+ {"NT_STATUS_EA_TOO_LARGE", NT_STATUS_EA_TOO_LARGE},
+ {"NT_STATUS_NONEXISTENT_EA_ENTRY", NT_STATUS_NONEXISTENT_EA_ENTRY},
+ {"NT_STATUS_NO_EAS_ON_FILE", NT_STATUS_NO_EAS_ON_FILE},
+ {"NT_STATUS_EA_CORRUPT_ERROR", NT_STATUS_EA_CORRUPT_ERROR},
+ {"NT_STATUS_FILE_LOCK_CONFLICT", NT_STATUS_FILE_LOCK_CONFLICT},
+ {"NT_STATUS_LOCK_NOT_GRANTED", NT_STATUS_LOCK_NOT_GRANTED},
+ {"NT_STATUS_DELETE_PENDING", NT_STATUS_DELETE_PENDING},
+ {"NT_STATUS_CTL_FILE_NOT_SUPPORTED",
+ NT_STATUS_CTL_FILE_NOT_SUPPORTED},
+ {"NT_STATUS_UNKNOWN_REVISION", NT_STATUS_UNKNOWN_REVISION},
+ {"NT_STATUS_REVISION_MISMATCH", NT_STATUS_REVISION_MISMATCH},
+ {"NT_STATUS_INVALID_OWNER", NT_STATUS_INVALID_OWNER},
+ {"NT_STATUS_INVALID_PRIMARY_GROUP",
+ NT_STATUS_INVALID_PRIMARY_GROUP},
+ {"NT_STATUS_NO_IMPERSONATION_TOKEN",
+ NT_STATUS_NO_IMPERSONATION_TOKEN},
+ {"NT_STATUS_CANT_DISABLE_MANDATORY",
+ NT_STATUS_CANT_DISABLE_MANDATORY},
+ {"NT_STATUS_NO_LOGON_SERVERS", NT_STATUS_NO_LOGON_SERVERS},
+ {"NT_STATUS_NO_SUCH_LOGON_SESSION",
+ NT_STATUS_NO_SUCH_LOGON_SESSION},
+ {"NT_STATUS_NO_SUCH_PRIVILEGE", NT_STATUS_NO_SUCH_PRIVILEGE},
+ {"NT_STATUS_PRIVILEGE_NOT_HELD", NT_STATUS_PRIVILEGE_NOT_HELD},
+ {"NT_STATUS_INVALID_ACCOUNT_NAME", NT_STATUS_INVALID_ACCOUNT_NAME},
+ {"NT_STATUS_USER_EXISTS", NT_STATUS_USER_EXISTS},
+ {"NT_STATUS_NO_SUCH_USER", NT_STATUS_NO_SUCH_USER},
+ {"NT_STATUS_GROUP_EXISTS", NT_STATUS_GROUP_EXISTS},
+ {"NT_STATUS_NO_SUCH_GROUP", NT_STATUS_NO_SUCH_GROUP},
+ {"NT_STATUS_MEMBER_IN_GROUP", NT_STATUS_MEMBER_IN_GROUP},
+ {"NT_STATUS_MEMBER_NOT_IN_GROUP", NT_STATUS_MEMBER_NOT_IN_GROUP},
+ {"NT_STATUS_LAST_ADMIN", NT_STATUS_LAST_ADMIN},
+ {"NT_STATUS_WRONG_PASSWORD", NT_STATUS_WRONG_PASSWORD},
+ {"NT_STATUS_ILL_FORMED_PASSWORD", NT_STATUS_ILL_FORMED_PASSWORD},
+ {"NT_STATUS_PASSWORD_RESTRICTION", NT_STATUS_PASSWORD_RESTRICTION},
+ {"NT_STATUS_LOGON_FAILURE", NT_STATUS_LOGON_FAILURE},
+ {"NT_STATUS_ACCOUNT_RESTRICTION", NT_STATUS_ACCOUNT_RESTRICTION},
+ {"NT_STATUS_INVALID_LOGON_HOURS", NT_STATUS_INVALID_LOGON_HOURS},
+ {"NT_STATUS_INVALID_WORKSTATION", NT_STATUS_INVALID_WORKSTATION},
+ {"NT_STATUS_PASSWORD_EXPIRED", NT_STATUS_PASSWORD_EXPIRED},
+ {"NT_STATUS_ACCOUNT_DISABLED", NT_STATUS_ACCOUNT_DISABLED},
+ {"NT_STATUS_NONE_MAPPED", NT_STATUS_NONE_MAPPED},
+ {"NT_STATUS_TOO_MANY_LUIDS_REQUESTED",
+ NT_STATUS_TOO_MANY_LUIDS_REQUESTED},
+ {"NT_STATUS_LUIDS_EXHAUSTED", NT_STATUS_LUIDS_EXHAUSTED},
+ {"NT_STATUS_INVALID_SUB_AUTHORITY",
+ NT_STATUS_INVALID_SUB_AUTHORITY},
+ {"NT_STATUS_INVALID_ACL", NT_STATUS_INVALID_ACL},
+ {"NT_STATUS_INVALID_SID", NT_STATUS_INVALID_SID},
+ {"NT_STATUS_INVALID_SECURITY_DESCR",
+ NT_STATUS_INVALID_SECURITY_DESCR},
+ {"NT_STATUS_PROCEDURE_NOT_FOUND", NT_STATUS_PROCEDURE_NOT_FOUND},
+ {"NT_STATUS_INVALID_IMAGE_FORMAT", NT_STATUS_INVALID_IMAGE_FORMAT},
+ {"NT_STATUS_NO_TOKEN", NT_STATUS_NO_TOKEN},
+ {"NT_STATUS_BAD_INHERITANCE_ACL", NT_STATUS_BAD_INHERITANCE_ACL},
+ {"NT_STATUS_RANGE_NOT_LOCKED", NT_STATUS_RANGE_NOT_LOCKED},
+ {"NT_STATUS_DISK_FULL", NT_STATUS_DISK_FULL},
+ {"NT_STATUS_SERVER_DISABLED", NT_STATUS_SERVER_DISABLED},
+ {"NT_STATUS_SERVER_NOT_DISABLED", NT_STATUS_SERVER_NOT_DISABLED},
+ {"NT_STATUS_TOO_MANY_GUIDS_REQUESTED",
+ NT_STATUS_TOO_MANY_GUIDS_REQUESTED},
+ {"NT_STATUS_GUIDS_EXHAUSTED", NT_STATUS_GUIDS_EXHAUSTED},
+ {"NT_STATUS_INVALID_ID_AUTHORITY", NT_STATUS_INVALID_ID_AUTHORITY},
+ {"NT_STATUS_AGENTS_EXHAUSTED", NT_STATUS_AGENTS_EXHAUSTED},
+ {"NT_STATUS_INVALID_VOLUME_LABEL", NT_STATUS_INVALID_VOLUME_LABEL},
+ {"NT_STATUS_SECTION_NOT_EXTENDED", NT_STATUS_SECTION_NOT_EXTENDED},
+ {"NT_STATUS_NOT_MAPPED_DATA", NT_STATUS_NOT_MAPPED_DATA},
+ {"NT_STATUS_RESOURCE_DATA_NOT_FOUND",
+ NT_STATUS_RESOURCE_DATA_NOT_FOUND},
+ {"NT_STATUS_RESOURCE_TYPE_NOT_FOUND",
+ NT_STATUS_RESOURCE_TYPE_NOT_FOUND},
+ {"NT_STATUS_RESOURCE_NAME_NOT_FOUND",
+ NT_STATUS_RESOURCE_NAME_NOT_FOUND},
+ {"NT_STATUS_ARRAY_BOUNDS_EXCEEDED",
+ NT_STATUS_ARRAY_BOUNDS_EXCEEDED},
+ {"NT_STATUS_FLOAT_DENORMAL_OPERAND",
+ NT_STATUS_FLOAT_DENORMAL_OPERAND},
+ {"NT_STATUS_FLOAT_DIVIDE_BY_ZERO", NT_STATUS_FLOAT_DIVIDE_BY_ZERO},
+ {"NT_STATUS_FLOAT_INEXACT_RESULT", NT_STATUS_FLOAT_INEXACT_RESULT},
+ {"NT_STATUS_FLOAT_INVALID_OPERATION",
+ NT_STATUS_FLOAT_INVALID_OPERATION},
+ {"NT_STATUS_FLOAT_OVERFLOW", NT_STATUS_FLOAT_OVERFLOW},
+ {"NT_STATUS_FLOAT_STACK_CHECK", NT_STATUS_FLOAT_STACK_CHECK},
+ {"NT_STATUS_FLOAT_UNDERFLOW", NT_STATUS_FLOAT_UNDERFLOW},
+ {"NT_STATUS_INTEGER_DIVIDE_BY_ZERO",
+ NT_STATUS_INTEGER_DIVIDE_BY_ZERO},
+ {"NT_STATUS_INTEGER_OVERFLOW", NT_STATUS_INTEGER_OVERFLOW},
+ {"NT_STATUS_PRIVILEGED_INSTRUCTION",
+ NT_STATUS_PRIVILEGED_INSTRUCTION},
+ {"NT_STATUS_TOO_MANY_PAGING_FILES",
+ NT_STATUS_TOO_MANY_PAGING_FILES},
+ {"NT_STATUS_FILE_INVALID", NT_STATUS_FILE_INVALID},
+ {"NT_STATUS_ALLOTTED_SPACE_EXCEEDED",
+ NT_STATUS_ALLOTTED_SPACE_EXCEEDED},
+ {"NT_STATUS_INSUFFICIENT_RESOURCES",
+ NT_STATUS_INSUFFICIENT_RESOURCES},
+ {"NT_STATUS_DFS_EXIT_PATH_FOUND", NT_STATUS_DFS_EXIT_PATH_FOUND},
+ {"NT_STATUS_DEVICE_DATA_ERROR", NT_STATUS_DEVICE_DATA_ERROR},
+ {"NT_STATUS_DEVICE_NOT_CONNECTED", NT_STATUS_DEVICE_NOT_CONNECTED},
+ {"NT_STATUS_DEVICE_POWER_FAILURE", NT_STATUS_DEVICE_POWER_FAILURE},
+ {"NT_STATUS_FREE_VM_NOT_AT_BASE", NT_STATUS_FREE_VM_NOT_AT_BASE},
+ {"NT_STATUS_MEMORY_NOT_ALLOCATED", NT_STATUS_MEMORY_NOT_ALLOCATED},
+ {"NT_STATUS_WORKING_SET_QUOTA", NT_STATUS_WORKING_SET_QUOTA},
+ {"NT_STATUS_MEDIA_WRITE_PROTECTED",
+ NT_STATUS_MEDIA_WRITE_PROTECTED},
+ {"NT_STATUS_DEVICE_NOT_READY", NT_STATUS_DEVICE_NOT_READY},
+ {"NT_STATUS_INVALID_GROUP_ATTRIBUTES",
+ NT_STATUS_INVALID_GROUP_ATTRIBUTES},
+ {"NT_STATUS_BAD_IMPERSONATION_LEVEL",
+ NT_STATUS_BAD_IMPERSONATION_LEVEL},
+ {"NT_STATUS_CANT_OPEN_ANONYMOUS", NT_STATUS_CANT_OPEN_ANONYMOUS},
+ {"NT_STATUS_BAD_VALIDATION_CLASS", NT_STATUS_BAD_VALIDATION_CLASS},
+ {"NT_STATUS_BAD_TOKEN_TYPE", NT_STATUS_BAD_TOKEN_TYPE},
+ {"NT_STATUS_BAD_MASTER_BOOT_RECORD",
+ NT_STATUS_BAD_MASTER_BOOT_RECORD},
+ {"NT_STATUS_INSTRUCTION_MISALIGNMENT",
+ NT_STATUS_INSTRUCTION_MISALIGNMENT},
+ {"NT_STATUS_INSTANCE_NOT_AVAILABLE",
+ NT_STATUS_INSTANCE_NOT_AVAILABLE},
+ {"NT_STATUS_PIPE_NOT_AVAILABLE", NT_STATUS_PIPE_NOT_AVAILABLE},
+ {"NT_STATUS_INVALID_PIPE_STATE", NT_STATUS_INVALID_PIPE_STATE},
+ {"NT_STATUS_PIPE_BUSY", NT_STATUS_PIPE_BUSY},
+ {"NT_STATUS_ILLEGAL_FUNCTION", NT_STATUS_ILLEGAL_FUNCTION},
+ {"NT_STATUS_PIPE_DISCONNECTED", NT_STATUS_PIPE_DISCONNECTED},
+ {"NT_STATUS_PIPE_CLOSING", NT_STATUS_PIPE_CLOSING},
+ {"NT_STATUS_PIPE_CONNECTED", NT_STATUS_PIPE_CONNECTED},
+ {"NT_STATUS_PIPE_LISTENING", NT_STATUS_PIPE_LISTENING},
+ {"NT_STATUS_INVALID_READ_MODE", NT_STATUS_INVALID_READ_MODE},
+ {"NT_STATUS_IO_TIMEOUT", NT_STATUS_IO_TIMEOUT},
+ {"NT_STATUS_FILE_FORCED_CLOSED", NT_STATUS_FILE_FORCED_CLOSED},
+ {"NT_STATUS_PROFILING_NOT_STARTED",
+ NT_STATUS_PROFILING_NOT_STARTED},
+ {"NT_STATUS_PROFILING_NOT_STOPPED",
+ NT_STATUS_PROFILING_NOT_STOPPED},
+ {"NT_STATUS_COULD_NOT_INTERPRET", NT_STATUS_COULD_NOT_INTERPRET},
+ {"NT_STATUS_FILE_IS_A_DIRECTORY", NT_STATUS_FILE_IS_A_DIRECTORY},
+ {"NT_STATUS_NOT_SUPPORTED", NT_STATUS_NOT_SUPPORTED},
+ {"NT_STATUS_REMOTE_NOT_LISTENING", NT_STATUS_REMOTE_NOT_LISTENING},
+ {"NT_STATUS_DUPLICATE_NAME", NT_STATUS_DUPLICATE_NAME},
+ {"NT_STATUS_BAD_NETWORK_PATH", NT_STATUS_BAD_NETWORK_PATH},
+ {"NT_STATUS_NETWORK_BUSY", NT_STATUS_NETWORK_BUSY},
+ {"NT_STATUS_DEVICE_DOES_NOT_EXIST",
+ NT_STATUS_DEVICE_DOES_NOT_EXIST},
+ {"NT_STATUS_TOO_MANY_COMMANDS", NT_STATUS_TOO_MANY_COMMANDS},
+ {"NT_STATUS_ADAPTER_HARDWARE_ERROR",
+ NT_STATUS_ADAPTER_HARDWARE_ERROR},
+ {"NT_STATUS_INVALID_NETWORK_RESPONSE",
+ NT_STATUS_INVALID_NETWORK_RESPONSE},
+ {"NT_STATUS_UNEXPECTED_NETWORK_ERROR",
+ NT_STATUS_UNEXPECTED_NETWORK_ERROR},
+ {"NT_STATUS_BAD_REMOTE_ADAPTER", NT_STATUS_BAD_REMOTE_ADAPTER},
+ {"NT_STATUS_PRINT_QUEUE_FULL", NT_STATUS_PRINT_QUEUE_FULL},
+ {"NT_STATUS_NO_SPOOL_SPACE", NT_STATUS_NO_SPOOL_SPACE},
+ {"NT_STATUS_PRINT_CANCELLED", NT_STATUS_PRINT_CANCELLED},
+ {"NT_STATUS_NETWORK_NAME_DELETED", NT_STATUS_NETWORK_NAME_DELETED},
+ {"NT_STATUS_NETWORK_ACCESS_DENIED",
+ NT_STATUS_NETWORK_ACCESS_DENIED},
+ {"NT_STATUS_BAD_DEVICE_TYPE", NT_STATUS_BAD_DEVICE_TYPE},
+ {"NT_STATUS_BAD_NETWORK_NAME", NT_STATUS_BAD_NETWORK_NAME},
+ {"NT_STATUS_TOO_MANY_NAMES", NT_STATUS_TOO_MANY_NAMES},
+ {"NT_STATUS_TOO_MANY_SESSIONS", NT_STATUS_TOO_MANY_SESSIONS},
+ {"NT_STATUS_SHARING_PAUSED", NT_STATUS_SHARING_PAUSED},
+ {"NT_STATUS_REQUEST_NOT_ACCEPTED", NT_STATUS_REQUEST_NOT_ACCEPTED},
+ {"NT_STATUS_REDIRECTOR_PAUSED", NT_STATUS_REDIRECTOR_PAUSED},
+ {"NT_STATUS_NET_WRITE_FAULT", NT_STATUS_NET_WRITE_FAULT},
+ {"NT_STATUS_PROFILING_AT_LIMIT", NT_STATUS_PROFILING_AT_LIMIT},
+ {"NT_STATUS_NOT_SAME_DEVICE", NT_STATUS_NOT_SAME_DEVICE},
+ {"NT_STATUS_FILE_RENAMED", NT_STATUS_FILE_RENAMED},
+ {"NT_STATUS_VIRTUAL_CIRCUIT_CLOSED",
+ NT_STATUS_VIRTUAL_CIRCUIT_CLOSED},
+ {"NT_STATUS_NO_SECURITY_ON_OBJECT",
+ NT_STATUS_NO_SECURITY_ON_OBJECT},
+ {"NT_STATUS_CANT_WAIT", NT_STATUS_CANT_WAIT},
+ {"NT_STATUS_PIPE_EMPTY", NT_STATUS_PIPE_EMPTY},
+ {"NT_STATUS_CANT_ACCESS_DOMAIN_INFO",
+ NT_STATUS_CANT_ACCESS_DOMAIN_INFO},
+ {"NT_STATUS_CANT_TERMINATE_SELF", NT_STATUS_CANT_TERMINATE_SELF},
+ {"NT_STATUS_INVALID_SERVER_STATE", NT_STATUS_INVALID_SERVER_STATE},
+ {"NT_STATUS_INVALID_DOMAIN_STATE", NT_STATUS_INVALID_DOMAIN_STATE},
+ {"NT_STATUS_INVALID_DOMAIN_ROLE", NT_STATUS_INVALID_DOMAIN_ROLE},
+ {"NT_STATUS_NO_SUCH_DOMAIN", NT_STATUS_NO_SUCH_DOMAIN},
+ {"NT_STATUS_DOMAIN_EXISTS", NT_STATUS_DOMAIN_EXISTS},
+ {"NT_STATUS_DOMAIN_LIMIT_EXCEEDED",
+ NT_STATUS_DOMAIN_LIMIT_EXCEEDED},
+ {"NT_STATUS_OPLOCK_NOT_GRANTED", NT_STATUS_OPLOCK_NOT_GRANTED},
+ {"NT_STATUS_INVALID_OPLOCK_PROTOCOL",
+ NT_STATUS_INVALID_OPLOCK_PROTOCOL},
+ {"NT_STATUS_INTERNAL_DB_CORRUPTION",
+ NT_STATUS_INTERNAL_DB_CORRUPTION},
+ {"NT_STATUS_INTERNAL_ERROR", NT_STATUS_INTERNAL_ERROR},
+ {"NT_STATUS_GENERIC_NOT_MAPPED", NT_STATUS_GENERIC_NOT_MAPPED},
+ {"NT_STATUS_BAD_DESCRIPTOR_FORMAT",
+ NT_STATUS_BAD_DESCRIPTOR_FORMAT},
+ {"NT_STATUS_INVALID_USER_BUFFER", NT_STATUS_INVALID_USER_BUFFER},
+ {"NT_STATUS_UNEXPECTED_IO_ERROR", NT_STATUS_UNEXPECTED_IO_ERROR},
+ {"NT_STATUS_UNEXPECTED_MM_CREATE_ERR",
+ NT_STATUS_UNEXPECTED_MM_CREATE_ERR},
+ {"NT_STATUS_UNEXPECTED_MM_MAP_ERROR",
+ NT_STATUS_UNEXPECTED_MM_MAP_ERROR},
+ {"NT_STATUS_UNEXPECTED_MM_EXTEND_ERR",
+ NT_STATUS_UNEXPECTED_MM_EXTEND_ERR},
+ {"NT_STATUS_NOT_LOGON_PROCESS", NT_STATUS_NOT_LOGON_PROCESS},
+ {"NT_STATUS_LOGON_SESSION_EXISTS", NT_STATUS_LOGON_SESSION_EXISTS},
+ {"NT_STATUS_INVALID_PARAMETER_1", NT_STATUS_INVALID_PARAMETER_1},
+ {"NT_STATUS_INVALID_PARAMETER_2", NT_STATUS_INVALID_PARAMETER_2},
+ {"NT_STATUS_INVALID_PARAMETER_3", NT_STATUS_INVALID_PARAMETER_3},
+ {"NT_STATUS_INVALID_PARAMETER_4", NT_STATUS_INVALID_PARAMETER_4},
+ {"NT_STATUS_INVALID_PARAMETER_5", NT_STATUS_INVALID_PARAMETER_5},
+ {"NT_STATUS_INVALID_PARAMETER_6", NT_STATUS_INVALID_PARAMETER_6},
+ {"NT_STATUS_INVALID_PARAMETER_7", NT_STATUS_INVALID_PARAMETER_7},
+ {"NT_STATUS_INVALID_PARAMETER_8", NT_STATUS_INVALID_PARAMETER_8},
+ {"NT_STATUS_INVALID_PARAMETER_9", NT_STATUS_INVALID_PARAMETER_9},
+ {"NT_STATUS_INVALID_PARAMETER_10", NT_STATUS_INVALID_PARAMETER_10},
+ {"NT_STATUS_INVALID_PARAMETER_11", NT_STATUS_INVALID_PARAMETER_11},
+ {"NT_STATUS_INVALID_PARAMETER_12", NT_STATUS_INVALID_PARAMETER_12},
+ {"NT_STATUS_REDIRECTOR_NOT_STARTED",
+ NT_STATUS_REDIRECTOR_NOT_STARTED},
+ {"NT_STATUS_REDIRECTOR_STARTED", NT_STATUS_REDIRECTOR_STARTED},
+ {"NT_STATUS_STACK_OVERFLOW", NT_STATUS_STACK_OVERFLOW},
+ {"NT_STATUS_NO_SUCH_PACKAGE", NT_STATUS_NO_SUCH_PACKAGE},
+ {"NT_STATUS_BAD_FUNCTION_TABLE", NT_STATUS_BAD_FUNCTION_TABLE},
+ {"NT_STATUS_DIRECTORY_NOT_EMPTY", NT_STATUS_DIRECTORY_NOT_EMPTY},
+ {"NT_STATUS_FILE_CORRUPT_ERROR", NT_STATUS_FILE_CORRUPT_ERROR},
+ {"NT_STATUS_NOT_A_DIRECTORY", NT_STATUS_NOT_A_DIRECTORY},
+ {"NT_STATUS_BAD_LOGON_SESSION_STATE",
+ NT_STATUS_BAD_LOGON_SESSION_STATE},
+ {"NT_STATUS_LOGON_SESSION_COLLISION",
+ NT_STATUS_LOGON_SESSION_COLLISION},
+ {"NT_STATUS_NAME_TOO_LONG", NT_STATUS_NAME_TOO_LONG},
+ {"NT_STATUS_FILES_OPEN", NT_STATUS_FILES_OPEN},
+ {"NT_STATUS_CONNECTION_IN_USE", NT_STATUS_CONNECTION_IN_USE},
+ {"NT_STATUS_MESSAGE_NOT_FOUND", NT_STATUS_MESSAGE_NOT_FOUND},
+ {"NT_STATUS_PROCESS_IS_TERMINATING",
+ NT_STATUS_PROCESS_IS_TERMINATING},
+ {"NT_STATUS_INVALID_LOGON_TYPE", NT_STATUS_INVALID_LOGON_TYPE},
+ {"NT_STATUS_NO_GUID_TRANSLATION", NT_STATUS_NO_GUID_TRANSLATION},
+ {"NT_STATUS_CANNOT_IMPERSONATE", NT_STATUS_CANNOT_IMPERSONATE},
+ {"NT_STATUS_IMAGE_ALREADY_LOADED", NT_STATUS_IMAGE_ALREADY_LOADED},
+ {"NT_STATUS_ABIOS_NOT_PRESENT", NT_STATUS_ABIOS_NOT_PRESENT},
+ {"NT_STATUS_ABIOS_LID_NOT_EXIST", NT_STATUS_ABIOS_LID_NOT_EXIST},
+ {"NT_STATUS_ABIOS_LID_ALREADY_OWNED",
+ NT_STATUS_ABIOS_LID_ALREADY_OWNED},
+ {"NT_STATUS_ABIOS_NOT_LID_OWNER", NT_STATUS_ABIOS_NOT_LID_OWNER},
+ {"NT_STATUS_ABIOS_INVALID_COMMAND",
+ NT_STATUS_ABIOS_INVALID_COMMAND},
+ {"NT_STATUS_ABIOS_INVALID_LID", NT_STATUS_ABIOS_INVALID_LID},
+ {"NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE",
+ NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE},
+ {"NT_STATUS_ABIOS_INVALID_SELECTOR",
+ NT_STATUS_ABIOS_INVALID_SELECTOR},
+ {"NT_STATUS_NO_LDT", NT_STATUS_NO_LDT},
+ {"NT_STATUS_INVALID_LDT_SIZE", NT_STATUS_INVALID_LDT_SIZE},
+ {"NT_STATUS_INVALID_LDT_OFFSET", NT_STATUS_INVALID_LDT_OFFSET},
+ {"NT_STATUS_INVALID_LDT_DESCRIPTOR",
+ NT_STATUS_INVALID_LDT_DESCRIPTOR},
+ {"NT_STATUS_INVALID_IMAGE_NE_FORMAT",
+ NT_STATUS_INVALID_IMAGE_NE_FORMAT},
+ {"NT_STATUS_RXACT_INVALID_STATE", NT_STATUS_RXACT_INVALID_STATE},
+ {"NT_STATUS_RXACT_COMMIT_FAILURE", NT_STATUS_RXACT_COMMIT_FAILURE},
+ {"NT_STATUS_MAPPED_FILE_SIZE_ZERO",
+ NT_STATUS_MAPPED_FILE_SIZE_ZERO},
+ {"NT_STATUS_TOO_MANY_OPENED_FILES",
+ NT_STATUS_TOO_MANY_OPENED_FILES},
+ {"NT_STATUS_CANCELLED", NT_STATUS_CANCELLED},
+ {"NT_STATUS_CANNOT_DELETE", NT_STATUS_CANNOT_DELETE},
+ {"NT_STATUS_INVALID_COMPUTER_NAME",
+ NT_STATUS_INVALID_COMPUTER_NAME},
+ {"NT_STATUS_FILE_DELETED", NT_STATUS_FILE_DELETED},
+ {"NT_STATUS_SPECIAL_ACCOUNT", NT_STATUS_SPECIAL_ACCOUNT},
+ {"NT_STATUS_SPECIAL_GROUP", NT_STATUS_SPECIAL_GROUP},
+ {"NT_STATUS_SPECIAL_USER", NT_STATUS_SPECIAL_USER},
+ {"NT_STATUS_MEMBERS_PRIMARY_GROUP",
+ NT_STATUS_MEMBERS_PRIMARY_GROUP},
+ {"NT_STATUS_FILE_CLOSED", NT_STATUS_FILE_CLOSED},
+ {"NT_STATUS_TOO_MANY_THREADS", NT_STATUS_TOO_MANY_THREADS},
+ {"NT_STATUS_THREAD_NOT_IN_PROCESS",
+ NT_STATUS_THREAD_NOT_IN_PROCESS},
+ {"NT_STATUS_TOKEN_ALREADY_IN_USE", NT_STATUS_TOKEN_ALREADY_IN_USE},
+ {"NT_STATUS_PAGEFILE_QUOTA_EXCEEDED",
+ NT_STATUS_PAGEFILE_QUOTA_EXCEEDED},
+ {"NT_STATUS_COMMITMENT_LIMIT", NT_STATUS_COMMITMENT_LIMIT},
+ {"NT_STATUS_INVALID_IMAGE_LE_FORMAT",
+ NT_STATUS_INVALID_IMAGE_LE_FORMAT},
+ {"NT_STATUS_INVALID_IMAGE_NOT_MZ", NT_STATUS_INVALID_IMAGE_NOT_MZ},
+ {"NT_STATUS_INVALID_IMAGE_PROTECT",
+ NT_STATUS_INVALID_IMAGE_PROTECT},
+ {"NT_STATUS_INVALID_IMAGE_WIN_16", NT_STATUS_INVALID_IMAGE_WIN_16},
+ {"NT_STATUS_LOGON_SERVER_CONFLICT",
+ NT_STATUS_LOGON_SERVER_CONFLICT},
+ {"NT_STATUS_TIME_DIFFERENCE_AT_DC",
+ NT_STATUS_TIME_DIFFERENCE_AT_DC},
+ {"NT_STATUS_SYNCHRONIZATION_REQUIRED",
+ NT_STATUS_SYNCHRONIZATION_REQUIRED},
+ {"NT_STATUS_DLL_NOT_FOUND", NT_STATUS_DLL_NOT_FOUND},
+ {"NT_STATUS_OPEN_FAILED", NT_STATUS_OPEN_FAILED},
+ {"NT_STATUS_IO_PRIVILEGE_FAILED", NT_STATUS_IO_PRIVILEGE_FAILED},
+ {"NT_STATUS_ORDINAL_NOT_FOUND", NT_STATUS_ORDINAL_NOT_FOUND},
+ {"NT_STATUS_ENTRYPOINT_NOT_FOUND", NT_STATUS_ENTRYPOINT_NOT_FOUND},
+ {"NT_STATUS_CONTROL_C_EXIT", NT_STATUS_CONTROL_C_EXIT},
+ {"NT_STATUS_LOCAL_DISCONNECT", NT_STATUS_LOCAL_DISCONNECT},
+ {"NT_STATUS_REMOTE_DISCONNECT", NT_STATUS_REMOTE_DISCONNECT},
+ {"NT_STATUS_REMOTE_RESOURCES", NT_STATUS_REMOTE_RESOURCES},
+ {"NT_STATUS_LINK_FAILED", NT_STATUS_LINK_FAILED},
+ {"NT_STATUS_LINK_TIMEOUT", NT_STATUS_LINK_TIMEOUT},
+ {"NT_STATUS_INVALID_CONNECTION", NT_STATUS_INVALID_CONNECTION},
+ {"NT_STATUS_INVALID_ADDRESS", NT_STATUS_INVALID_ADDRESS},
+ {"NT_STATUS_DLL_INIT_FAILED", NT_STATUS_DLL_INIT_FAILED},
+ {"NT_STATUS_MISSING_SYSTEMFILE", NT_STATUS_MISSING_SYSTEMFILE},
+ {"NT_STATUS_UNHANDLED_EXCEPTION", NT_STATUS_UNHANDLED_EXCEPTION},
+ {"NT_STATUS_APP_INIT_FAILURE", NT_STATUS_APP_INIT_FAILURE},
+ {"NT_STATUS_PAGEFILE_CREATE_FAILED",
+ NT_STATUS_PAGEFILE_CREATE_FAILED},
+ {"NT_STATUS_NO_PAGEFILE", NT_STATUS_NO_PAGEFILE},
+ {"NT_STATUS_INVALID_LEVEL", NT_STATUS_INVALID_LEVEL},
+ {"NT_STATUS_WRONG_PASSWORD_CORE", NT_STATUS_WRONG_PASSWORD_CORE},
+ {"NT_STATUS_ILLEGAL_FLOAT_CONTEXT",
+ NT_STATUS_ILLEGAL_FLOAT_CONTEXT},
+ {"NT_STATUS_PIPE_BROKEN", NT_STATUS_PIPE_BROKEN},
+ {"NT_STATUS_REGISTRY_CORRUPT", NT_STATUS_REGISTRY_CORRUPT},
+ {"NT_STATUS_REGISTRY_IO_FAILED", NT_STATUS_REGISTRY_IO_FAILED},
+ {"NT_STATUS_NO_EVENT_PAIR", NT_STATUS_NO_EVENT_PAIR},
+ {"NT_STATUS_UNRECOGNIZED_VOLUME", NT_STATUS_UNRECOGNIZED_VOLUME},
+ {"NT_STATUS_SERIAL_NO_DEVICE_INITED",
+ NT_STATUS_SERIAL_NO_DEVICE_INITED},
+ {"NT_STATUS_NO_SUCH_ALIAS", NT_STATUS_NO_SUCH_ALIAS},
+ {"NT_STATUS_MEMBER_NOT_IN_ALIAS", NT_STATUS_MEMBER_NOT_IN_ALIAS},
+ {"NT_STATUS_MEMBER_IN_ALIAS", NT_STATUS_MEMBER_IN_ALIAS},
+ {"NT_STATUS_ALIAS_EXISTS", NT_STATUS_ALIAS_EXISTS},
+ {"NT_STATUS_LOGON_NOT_GRANTED", NT_STATUS_LOGON_NOT_GRANTED},
+ {"NT_STATUS_TOO_MANY_SECRETS", NT_STATUS_TOO_MANY_SECRETS},
+ {"NT_STATUS_SECRET_TOO_LONG", NT_STATUS_SECRET_TOO_LONG},
+ {"NT_STATUS_INTERNAL_DB_ERROR", NT_STATUS_INTERNAL_DB_ERROR},
+ {"NT_STATUS_FULLSCREEN_MODE", NT_STATUS_FULLSCREEN_MODE},
+ {"NT_STATUS_TOO_MANY_CONTEXT_IDS", NT_STATUS_TOO_MANY_CONTEXT_IDS},
+ {"NT_STATUS_LOGON_TYPE_NOT_GRANTED",
+ NT_STATUS_LOGON_TYPE_NOT_GRANTED},
+ {"NT_STATUS_NOT_REGISTRY_FILE", NT_STATUS_NOT_REGISTRY_FILE},
+ {"NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED",
+ NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED},
+ {"NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR",
+ NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR},
+ {"NT_STATUS_FT_MISSING_MEMBER", NT_STATUS_FT_MISSING_MEMBER},
+ {"NT_STATUS_ILL_FORMED_SERVICE_ENTRY",
+ NT_STATUS_ILL_FORMED_SERVICE_ENTRY},
+ {"NT_STATUS_ILLEGAL_CHARACTER", NT_STATUS_ILLEGAL_CHARACTER},
+ {"NT_STATUS_UNMAPPABLE_CHARACTER", NT_STATUS_UNMAPPABLE_CHARACTER},
+ {"NT_STATUS_UNDEFINED_CHARACTER", NT_STATUS_UNDEFINED_CHARACTER},
+ {"NT_STATUS_FLOPPY_VOLUME", NT_STATUS_FLOPPY_VOLUME},
+ {"NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND",
+ NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND},
+ {"NT_STATUS_FLOPPY_WRONG_CYLINDER",
+ NT_STATUS_FLOPPY_WRONG_CYLINDER},
+ {"NT_STATUS_FLOPPY_UNKNOWN_ERROR", NT_STATUS_FLOPPY_UNKNOWN_ERROR},
+ {"NT_STATUS_FLOPPY_BAD_REGISTERS", NT_STATUS_FLOPPY_BAD_REGISTERS},
+ {"NT_STATUS_DISK_RECALIBRATE_FAILED",
+ NT_STATUS_DISK_RECALIBRATE_FAILED},
+ {"NT_STATUS_DISK_OPERATION_FAILED",
+ NT_STATUS_DISK_OPERATION_FAILED},
+ {"NT_STATUS_DISK_RESET_FAILED", NT_STATUS_DISK_RESET_FAILED},
+ {"NT_STATUS_SHARED_IRQ_BUSY", NT_STATUS_SHARED_IRQ_BUSY},
+ {"NT_STATUS_FT_ORPHANING", NT_STATUS_FT_ORPHANING},
+ {"NT_STATUS_PARTITION_FAILURE", NT_STATUS_PARTITION_FAILURE},
+ {"NT_STATUS_INVALID_BLOCK_LENGTH", NT_STATUS_INVALID_BLOCK_LENGTH},
+ {"NT_STATUS_DEVICE_NOT_PARTITIONED",
+ NT_STATUS_DEVICE_NOT_PARTITIONED},
+ {"NT_STATUS_UNABLE_TO_LOCK_MEDIA", NT_STATUS_UNABLE_TO_LOCK_MEDIA},
+ {"NT_STATUS_UNABLE_TO_UNLOAD_MEDIA",
+ NT_STATUS_UNABLE_TO_UNLOAD_MEDIA},
+ {"NT_STATUS_EOM_OVERFLOW", NT_STATUS_EOM_OVERFLOW},
+ {"NT_STATUS_NO_MEDIA", NT_STATUS_NO_MEDIA},
+ {"NT_STATUS_NO_SUCH_MEMBER", NT_STATUS_NO_SUCH_MEMBER},
+ {"NT_STATUS_INVALID_MEMBER", NT_STATUS_INVALID_MEMBER},
+ {"NT_STATUS_KEY_DELETED", NT_STATUS_KEY_DELETED},
+ {"NT_STATUS_NO_LOG_SPACE", NT_STATUS_NO_LOG_SPACE},
+ {"NT_STATUS_TOO_MANY_SIDS", NT_STATUS_TOO_MANY_SIDS},
+ {"NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED",
+ NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED},
+ {"NT_STATUS_KEY_HAS_CHILDREN", NT_STATUS_KEY_HAS_CHILDREN},
+ {"NT_STATUS_CHILD_MUST_BE_VOLATILE",
+ NT_STATUS_CHILD_MUST_BE_VOLATILE},
+ {"NT_STATUS_DEVICE_CONFIGURATION_ERROR",
+ NT_STATUS_DEVICE_CONFIGURATION_ERROR},
+ {"NT_STATUS_DRIVER_INTERNAL_ERROR",
+ NT_STATUS_DRIVER_INTERNAL_ERROR},
+ {"NT_STATUS_INVALID_DEVICE_STATE", NT_STATUS_INVALID_DEVICE_STATE},
+ {"NT_STATUS_IO_DEVICE_ERROR", NT_STATUS_IO_DEVICE_ERROR},
+ {"NT_STATUS_DEVICE_PROTOCOL_ERROR",
+ NT_STATUS_DEVICE_PROTOCOL_ERROR},
+ {"NT_STATUS_BACKUP_CONTROLLER", NT_STATUS_BACKUP_CONTROLLER},
+ {"NT_STATUS_LOG_FILE_FULL", NT_STATUS_LOG_FILE_FULL},
+ {"NT_STATUS_TOO_LATE", NT_STATUS_TOO_LATE},
+ {"NT_STATUS_NO_TRUST_LSA_SECRET", NT_STATUS_NO_TRUST_LSA_SECRET},
+ {"NT_STATUS_NO_TRUST_SAM_ACCOUNT", NT_STATUS_NO_TRUST_SAM_ACCOUNT},
+ {"NT_STATUS_TRUSTED_DOMAIN_FAILURE",
+ NT_STATUS_TRUSTED_DOMAIN_FAILURE},
+ {"NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE",
+ NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE},
+ {"NT_STATUS_EVENTLOG_FILE_CORRUPT",
+ NT_STATUS_EVENTLOG_FILE_CORRUPT},
+ {"NT_STATUS_EVENTLOG_CANT_START", NT_STATUS_EVENTLOG_CANT_START},
+ {"NT_STATUS_TRUST_FAILURE", NT_STATUS_TRUST_FAILURE},
+ {"NT_STATUS_MUTANT_LIMIT_EXCEEDED",
+ NT_STATUS_MUTANT_LIMIT_EXCEEDED},
+ {"NT_STATUS_NETLOGON_NOT_STARTED", NT_STATUS_NETLOGON_NOT_STARTED},
+ {"NT_STATUS_ACCOUNT_EXPIRED", NT_STATUS_ACCOUNT_EXPIRED},
+ {"NT_STATUS_POSSIBLE_DEADLOCK", NT_STATUS_POSSIBLE_DEADLOCK},
+ {"NT_STATUS_NETWORK_CREDENTIAL_CONFLICT",
+ NT_STATUS_NETWORK_CREDENTIAL_CONFLICT},
+ {"NT_STATUS_REMOTE_SESSION_LIMIT", NT_STATUS_REMOTE_SESSION_LIMIT},
+ {"NT_STATUS_EVENTLOG_FILE_CHANGED",
+ NT_STATUS_EVENTLOG_FILE_CHANGED},
+ {"NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT",
+ NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT},
+ {"NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT",
+ NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT},
+ {"NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT",
+ NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT},
+ {"NT_STATUS_DOMAIN_TRUST_INCONSISTENT",
+ NT_STATUS_DOMAIN_TRUST_INCONSISTENT},
+ {"NT_STATUS_FS_DRIVER_REQUIRED", NT_STATUS_FS_DRIVER_REQUIRED},
+ {"NT_STATUS_NO_USER_SESSION_KEY", NT_STATUS_NO_USER_SESSION_KEY},
+ {"NT_STATUS_USER_SESSION_DELETED", NT_STATUS_USER_SESSION_DELETED},
+ {"NT_STATUS_RESOURCE_LANG_NOT_FOUND",
+ NT_STATUS_RESOURCE_LANG_NOT_FOUND},
+ {"NT_STATUS_INSUFF_SERVER_RESOURCES",
+ NT_STATUS_INSUFF_SERVER_RESOURCES},
+ {"NT_STATUS_INVALID_BUFFER_SIZE", NT_STATUS_INVALID_BUFFER_SIZE},
+ {"NT_STATUS_INVALID_ADDRESS_COMPONENT",
+ NT_STATUS_INVALID_ADDRESS_COMPONENT},
+ {"NT_STATUS_INVALID_ADDRESS_WILDCARD",
+ NT_STATUS_INVALID_ADDRESS_WILDCARD},
+ {"NT_STATUS_TOO_MANY_ADDRESSES", NT_STATUS_TOO_MANY_ADDRESSES},
+ {"NT_STATUS_ADDRESS_ALREADY_EXISTS",
+ NT_STATUS_ADDRESS_ALREADY_EXISTS},
+ {"NT_STATUS_ADDRESS_CLOSED", NT_STATUS_ADDRESS_CLOSED},
+ {"NT_STATUS_CONNECTION_DISCONNECTED",
+ NT_STATUS_CONNECTION_DISCONNECTED},
+ {"NT_STATUS_CONNECTION_RESET", NT_STATUS_CONNECTION_RESET},
+ {"NT_STATUS_TOO_MANY_NODES", NT_STATUS_TOO_MANY_NODES},
+ {"NT_STATUS_TRANSACTION_ABORTED", NT_STATUS_TRANSACTION_ABORTED},
+ {"NT_STATUS_TRANSACTION_TIMED_OUT",
+ NT_STATUS_TRANSACTION_TIMED_OUT},
+ {"NT_STATUS_TRANSACTION_NO_RELEASE",
+ NT_STATUS_TRANSACTION_NO_RELEASE},
+ {"NT_STATUS_TRANSACTION_NO_MATCH", NT_STATUS_TRANSACTION_NO_MATCH},
+ {"NT_STATUS_TRANSACTION_RESPONDED",
+ NT_STATUS_TRANSACTION_RESPONDED},
+ {"NT_STATUS_TRANSACTION_INVALID_ID",
+ NT_STATUS_TRANSACTION_INVALID_ID},
+ {"NT_STATUS_TRANSACTION_INVALID_TYPE",
+ NT_STATUS_TRANSACTION_INVALID_TYPE},
+ {"NT_STATUS_NOT_SERVER_SESSION", NT_STATUS_NOT_SERVER_SESSION},
+ {"NT_STATUS_NOT_CLIENT_SESSION", NT_STATUS_NOT_CLIENT_SESSION},
+ {"NT_STATUS_CANNOT_LOAD_REGISTRY_FILE",
+ NT_STATUS_CANNOT_LOAD_REGISTRY_FILE},
+ {"NT_STATUS_DEBUG_ATTACH_FAILED", NT_STATUS_DEBUG_ATTACH_FAILED},
+ {"NT_STATUS_SYSTEM_PROCESS_TERMINATED",
+ NT_STATUS_SYSTEM_PROCESS_TERMINATED},
+ {"NT_STATUS_DATA_NOT_ACCEPTED", NT_STATUS_DATA_NOT_ACCEPTED},
+ {"NT_STATUS_NO_BROWSER_SERVERS_FOUND",
+ NT_STATUS_NO_BROWSER_SERVERS_FOUND},
+ {"NT_STATUS_VDM_HARD_ERROR", NT_STATUS_VDM_HARD_ERROR},
+ {"NT_STATUS_DRIVER_CANCEL_TIMEOUT",
+ NT_STATUS_DRIVER_CANCEL_TIMEOUT},
+ {"NT_STATUS_REPLY_MESSAGE_MISMATCH",
+ NT_STATUS_REPLY_MESSAGE_MISMATCH},
+ {"NT_STATUS_MAPPED_ALIGNMENT", NT_STATUS_MAPPED_ALIGNMENT},
+ {"NT_STATUS_IMAGE_CHECKSUM_MISMATCH",
+ NT_STATUS_IMAGE_CHECKSUM_MISMATCH},
+ {"NT_STATUS_LOST_WRITEBEHIND_DATA",
+ NT_STATUS_LOST_WRITEBEHIND_DATA},
+ {"NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID",
+ NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID},
+ {"NT_STATUS_PASSWORD_MUST_CHANGE", NT_STATUS_PASSWORD_MUST_CHANGE},
+ {"NT_STATUS_NOT_FOUND", NT_STATUS_NOT_FOUND},
+ {"NT_STATUS_NOT_TINY_STREAM", NT_STATUS_NOT_TINY_STREAM},
+ {"NT_STATUS_RECOVERY_FAILURE", NT_STATUS_RECOVERY_FAILURE},
+ {"NT_STATUS_STACK_OVERFLOW_READ", NT_STATUS_STACK_OVERFLOW_READ},
+ {"NT_STATUS_FAIL_CHECK", NT_STATUS_FAIL_CHECK},
+ {"NT_STATUS_DUPLICATE_OBJECTID", NT_STATUS_DUPLICATE_OBJECTID},
+ {"NT_STATUS_OBJECTID_EXISTS", NT_STATUS_OBJECTID_EXISTS},
+ {"NT_STATUS_CONVERT_TO_LARGE", NT_STATUS_CONVERT_TO_LARGE},
+ {"NT_STATUS_RETRY", NT_STATUS_RETRY},
+ {"NT_STATUS_FOUND_OUT_OF_SCOPE", NT_STATUS_FOUND_OUT_OF_SCOPE},
+ {"NT_STATUS_ALLOCATE_BUCKET", NT_STATUS_ALLOCATE_BUCKET},
+ {"NT_STATUS_PROPSET_NOT_FOUND", NT_STATUS_PROPSET_NOT_FOUND},
+ {"NT_STATUS_MARSHALL_OVERFLOW", NT_STATUS_MARSHALL_OVERFLOW},
+ {"NT_STATUS_INVALID_VARIANT", NT_STATUS_INVALID_VARIANT},
+ {"NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND",
+ NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND},
+ {"NT_STATUS_ACCOUNT_LOCKED_OUT", NT_STATUS_ACCOUNT_LOCKED_OUT},
+ {"NT_STATUS_HANDLE_NOT_CLOSABLE", NT_STATUS_HANDLE_NOT_CLOSABLE},
+ {"NT_STATUS_CONNECTION_REFUSED", NT_STATUS_CONNECTION_REFUSED},
+ {"NT_STATUS_GRACEFUL_DISCONNECT", NT_STATUS_GRACEFUL_DISCONNECT},
+ {"NT_STATUS_ADDRESS_ALREADY_ASSOCIATED",
+ NT_STATUS_ADDRESS_ALREADY_ASSOCIATED},
+ {"NT_STATUS_ADDRESS_NOT_ASSOCIATED",
+ NT_STATUS_ADDRESS_NOT_ASSOCIATED},
+ {"NT_STATUS_CONNECTION_INVALID", NT_STATUS_CONNECTION_INVALID},
+ {"NT_STATUS_CONNECTION_ACTIVE", NT_STATUS_CONNECTION_ACTIVE},
+ {"NT_STATUS_NETWORK_UNREACHABLE", NT_STATUS_NETWORK_UNREACHABLE},
+ {"NT_STATUS_HOST_UNREACHABLE", NT_STATUS_HOST_UNREACHABLE},
+ {"NT_STATUS_PROTOCOL_UNREACHABLE", NT_STATUS_PROTOCOL_UNREACHABLE},
+ {"NT_STATUS_PORT_UNREACHABLE", NT_STATUS_PORT_UNREACHABLE},
+ {"NT_STATUS_REQUEST_ABORTED", NT_STATUS_REQUEST_ABORTED},
+ {"NT_STATUS_CONNECTION_ABORTED", NT_STATUS_CONNECTION_ABORTED},
+ {"NT_STATUS_BAD_COMPRESSION_BUFFER",
+ NT_STATUS_BAD_COMPRESSION_BUFFER},
+ {"NT_STATUS_USER_MAPPED_FILE", NT_STATUS_USER_MAPPED_FILE},
+ {"NT_STATUS_AUDIT_FAILED", NT_STATUS_AUDIT_FAILED},
+ {"NT_STATUS_TIMER_RESOLUTION_NOT_SET",
+ NT_STATUS_TIMER_RESOLUTION_NOT_SET},
+ {"NT_STATUS_CONNECTION_COUNT_LIMIT",
+ NT_STATUS_CONNECTION_COUNT_LIMIT},
+ {"NT_STATUS_LOGIN_TIME_RESTRICTION",
+ NT_STATUS_LOGIN_TIME_RESTRICTION},
+ {"NT_STATUS_LOGIN_WKSTA_RESTRICTION",
+ NT_STATUS_LOGIN_WKSTA_RESTRICTION},
+ {"NT_STATUS_IMAGE_MP_UP_MISMATCH", NT_STATUS_IMAGE_MP_UP_MISMATCH},
+ {"NT_STATUS_INSUFFICIENT_LOGON_INFO",
+ NT_STATUS_INSUFFICIENT_LOGON_INFO},
+ {"NT_STATUS_BAD_DLL_ENTRYPOINT", NT_STATUS_BAD_DLL_ENTRYPOINT},
+ {"NT_STATUS_BAD_SERVICE_ENTRYPOINT",
+ NT_STATUS_BAD_SERVICE_ENTRYPOINT},
+ {"NT_STATUS_LPC_REPLY_LOST", NT_STATUS_LPC_REPLY_LOST},
+ {"NT_STATUS_IP_ADDRESS_CONFLICT1", NT_STATUS_IP_ADDRESS_CONFLICT1},
+ {"NT_STATUS_IP_ADDRESS_CONFLICT2", NT_STATUS_IP_ADDRESS_CONFLICT2},
+ {"NT_STATUS_REGISTRY_QUOTA_LIMIT", NT_STATUS_REGISTRY_QUOTA_LIMIT},
+ {"NT_STATUS_PATH_NOT_COVERED", NT_STATUS_PATH_NOT_COVERED},
+ {"NT_STATUS_NO_CALLBACK_ACTIVE", NT_STATUS_NO_CALLBACK_ACTIVE},
+ {"NT_STATUS_LICENSE_QUOTA_EXCEEDED",
+ NT_STATUS_LICENSE_QUOTA_EXCEEDED},
+ {"NT_STATUS_PWD_TOO_SHORT", NT_STATUS_PWD_TOO_SHORT},
+ {"NT_STATUS_PWD_TOO_RECENT", NT_STATUS_PWD_TOO_RECENT},
+ {"NT_STATUS_PWD_HISTORY_CONFLICT", NT_STATUS_PWD_HISTORY_CONFLICT},
+ {"NT_STATUS_PLUGPLAY_NO_DEVICE", NT_STATUS_PLUGPLAY_NO_DEVICE},
+ {"NT_STATUS_UNSUPPORTED_COMPRESSION",
+ NT_STATUS_UNSUPPORTED_COMPRESSION},
+ {"NT_STATUS_INVALID_HW_PROFILE", NT_STATUS_INVALID_HW_PROFILE},
+ {"NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH",
+ NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH},
+ {"NT_STATUS_DRIVER_ORDINAL_NOT_FOUND",
+ NT_STATUS_DRIVER_ORDINAL_NOT_FOUND},
+ {"NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND",
+ NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND},
+ {"NT_STATUS_RESOURCE_NOT_OWNED", NT_STATUS_RESOURCE_NOT_OWNED},
+ {"NT_STATUS_TOO_MANY_LINKS", NT_STATUS_TOO_MANY_LINKS},
+ {"NT_STATUS_QUOTA_LIST_INCONSISTENT",
+ NT_STATUS_QUOTA_LIST_INCONSISTENT},
+ {"NT_STATUS_FILE_IS_OFFLINE", NT_STATUS_FILE_IS_OFFLINE},
+ {"NT_STATUS_NO_MORE_ENTRIES", NT_STATUS_NO_MORE_ENTRIES},
+ {"STATUS_MORE_ENTRIES", STATUS_MORE_ENTRIES},
+ {"STATUS_SOME_UNMAPPED", STATUS_SOME_UNMAPPED},
+ {NULL, 0}
+};
diff --git a/release/src/linux/linux/fs/cifs/nterr.h b/release/src/linux/linux/fs/cifs/nterr.h
new file mode 100644
index 00000000..d2fb06c9
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/nterr.h
@@ -0,0 +1,556 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NT error code constants
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) John H Terpstra 1996-2000
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+ Copyright (C) Paul Ashton 1998-2000
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+
+#ifndef _NTERR_H
+#define _NTERR_H
+
+struct nt_err_code_struct {
+ char *nt_errstr;
+ __u32 nt_errcode;
+};
+
+extern const struct nt_err_code_struct nt_errs[];
+
+/* Win32 Status codes. */
+
+#define STATUS_BUFFER_OVERFLOW 0x80000005
+#define STATUS_MORE_ENTRIES 0x0105
+#define ERROR_INVALID_PARAMETER 0x0057
+#define ERROR_INSUFFICIENT_BUFFER 0x007a
+#define STATUS_1804 0x070c
+#define STATUS_NOTIFY_ENUM_DIR 0x010c
+
+/* Win32 Error codes extracted using a loop in smbclient then printing a
+ netmon sniff to a file. */
+
+#define NT_STATUS_OK 0x0000
+#define STATUS_SOME_UNMAPPED 0x0107
+#define STATUS_BUFFER_OVERFLOW 0x80000005
+#define NT_STATUS_NO_MORE_ENTRIES 0x8000001a
+#define NT_STATUS_UNSUCCESSFUL 0xC0000000 | 0x0001
+#define NT_STATUS_NOT_IMPLEMENTED 0xC0000000 | 0x0002
+#define NT_STATUS_INVALID_INFO_CLASS 0xC0000000 | 0x0003
+#define NT_STATUS_INFO_LENGTH_MISMATCH 0xC0000000 | 0x0004
+#define NT_STATUS_ACCESS_VIOLATION 0xC0000000 | 0x0005
+#define NT_STATUS_IN_PAGE_ERROR 0xC0000000 | 0x0006
+#define NT_STATUS_PAGEFILE_QUOTA 0xC0000000 | 0x0007
+#define NT_STATUS_INVALID_HANDLE 0xC0000000 | 0x0008
+#define NT_STATUS_BAD_INITIAL_STACK 0xC0000000 | 0x0009
+#define NT_STATUS_BAD_INITIAL_PC 0xC0000000 | 0x000a
+#define NT_STATUS_INVALID_CID 0xC0000000 | 0x000b
+#define NT_STATUS_TIMER_NOT_CANCELED 0xC0000000 | 0x000c
+#define NT_STATUS_INVALID_PARAMETER 0xC0000000 | 0x000d
+#define NT_STATUS_NO_SUCH_DEVICE 0xC0000000 | 0x000e
+#define NT_STATUS_NO_SUCH_FILE 0xC0000000 | 0x000f
+#define NT_STATUS_INVALID_DEVICE_REQUEST 0xC0000000 | 0x0010
+#define NT_STATUS_END_OF_FILE 0xC0000000 | 0x0011
+#define NT_STATUS_WRONG_VOLUME 0xC0000000 | 0x0012
+#define NT_STATUS_NO_MEDIA_IN_DEVICE 0xC0000000 | 0x0013
+#define NT_STATUS_UNRECOGNIZED_MEDIA 0xC0000000 | 0x0014
+#define NT_STATUS_NONEXISTENT_SECTOR 0xC0000000 | 0x0015
+#define NT_STATUS_MORE_PROCESSING_REQUIRED 0xC0000000 | 0x0016
+#define NT_STATUS_NO_MEMORY 0xC0000000 | 0x0017
+#define NT_STATUS_CONFLICTING_ADDRESSES 0xC0000000 | 0x0018
+#define NT_STATUS_NOT_MAPPED_VIEW 0xC0000000 | 0x0019
+#define NT_STATUS_UNABLE_TO_FREE_VM 0x80000000 | 0x001a
+#define NT_STATUS_UNABLE_TO_DELETE_SECTION 0xC0000000 | 0x001b
+#define NT_STATUS_INVALID_SYSTEM_SERVICE 0xC0000000 | 0x001c
+#define NT_STATUS_ILLEGAL_INSTRUCTION 0xC0000000 | 0x001d
+#define NT_STATUS_INVALID_LOCK_SEQUENCE 0xC0000000 | 0x001e
+#define NT_STATUS_INVALID_VIEW_SIZE 0xC0000000 | 0x001f
+#define NT_STATUS_INVALID_FILE_FOR_SECTION 0xC0000000 | 0x0020
+#define NT_STATUS_ALREADY_COMMITTED 0xC0000000 | 0x0021
+#define NT_STATUS_ACCESS_DENIED 0xC0000000 | 0x0022
+#define NT_STATUS_BUFFER_TOO_SMALL 0xC0000000 | 0x0023
+#define NT_STATUS_OBJECT_TYPE_MISMATCH 0xC0000000 | 0x0024
+#define NT_STATUS_NONCONTINUABLE_EXCEPTION 0xC0000000 | 0x0025
+#define NT_STATUS_INVALID_DISPOSITION 0xC0000000 | 0x0026
+#define NT_STATUS_UNWIND 0xC0000000 | 0x0027
+#define NT_STATUS_BAD_STACK 0xC0000000 | 0x0028
+#define NT_STATUS_INVALID_UNWIND_TARGET 0xC0000000 | 0x0029
+#define NT_STATUS_NOT_LOCKED 0xC0000000 | 0x002a
+#define NT_STATUS_PARITY_ERROR 0xC0000000 | 0x002b
+#define NT_STATUS_UNABLE_TO_DECOMMIT_VM 0xC0000000 | 0x002c
+#define NT_STATUS_NOT_COMMITTED 0xC0000000 | 0x002d
+#define NT_STATUS_INVALID_PORT_ATTRIBUTES 0xC0000000 | 0x002e
+#define NT_STATUS_PORT_MESSAGE_TOO_LONG 0xC0000000 | 0x002f
+#define NT_STATUS_INVALID_PARAMETER_MIX 0xC0000000 | 0x0030
+#define NT_STATUS_INVALID_QUOTA_LOWER 0xC0000000 | 0x0031
+#define NT_STATUS_DISK_CORRUPT_ERROR 0xC0000000 | 0x0032
+#define NT_STATUS_OBJECT_NAME_INVALID 0xC0000000 | 0x0033
+#define NT_STATUS_OBJECT_NAME_NOT_FOUND 0xC0000000 | 0x0034
+#define NT_STATUS_OBJECT_NAME_COLLISION 0xC0000000 | 0x0035
+#define NT_STATUS_HANDLE_NOT_WAITABLE 0xC0000000 | 0x0036
+#define NT_STATUS_PORT_DISCONNECTED 0xC0000000 | 0x0037
+#define NT_STATUS_DEVICE_ALREADY_ATTACHED 0xC0000000 | 0x0038
+#define NT_STATUS_OBJECT_PATH_INVALID 0xC0000000 | 0x0039
+#define NT_STATUS_OBJECT_PATH_NOT_FOUND 0xC0000000 | 0x003a
+#define NT_STATUS_OBJECT_PATH_SYNTAX_BAD 0xC0000000 | 0x003b
+#define NT_STATUS_DATA_OVERRUN 0xC0000000 | 0x003c
+#define NT_STATUS_DATA_LATE_ERROR 0xC0000000 | 0x003d
+#define NT_STATUS_DATA_ERROR 0xC0000000 | 0x003e
+#define NT_STATUS_CRC_ERROR 0xC0000000 | 0x003f
+#define NT_STATUS_SECTION_TOO_BIG 0xC0000000 | 0x0040
+#define NT_STATUS_PORT_CONNECTION_REFUSED 0xC0000000 | 0x0041
+#define NT_STATUS_INVALID_PORT_HANDLE 0xC0000000 | 0x0042
+#define NT_STATUS_SHARING_VIOLATION 0xC0000000 | 0x0043
+#define NT_STATUS_QUOTA_EXCEEDED 0xC0000000 | 0x0044
+#define NT_STATUS_INVALID_PAGE_PROTECTION 0xC0000000 | 0x0045
+#define NT_STATUS_MUTANT_NOT_OWNED 0xC0000000 | 0x0046
+#define NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED 0xC0000000 | 0x0047
+#define NT_STATUS_PORT_ALREADY_SET 0xC0000000 | 0x0048
+#define NT_STATUS_SECTION_NOT_IMAGE 0xC0000000 | 0x0049
+#define NT_STATUS_SUSPEND_COUNT_EXCEEDED 0xC0000000 | 0x004a
+#define NT_STATUS_THREAD_IS_TERMINATING 0xC0000000 | 0x004b
+#define NT_STATUS_BAD_WORKING_SET_LIMIT 0xC0000000 | 0x004c
+#define NT_STATUS_INCOMPATIBLE_FILE_MAP 0xC0000000 | 0x004d
+#define NT_STATUS_SECTION_PROTECTION 0xC0000000 | 0x004e
+#define NT_STATUS_EAS_NOT_SUPPORTED 0xC0000000 | 0x004f
+#define NT_STATUS_EA_TOO_LARGE 0xC0000000 | 0x0050
+#define NT_STATUS_NONEXISTENT_EA_ENTRY 0xC0000000 | 0x0051
+#define NT_STATUS_NO_EAS_ON_FILE 0xC0000000 | 0x0052
+#define NT_STATUS_EA_CORRUPT_ERROR 0xC0000000 | 0x0053
+#define NT_STATUS_FILE_LOCK_CONFLICT 0xC0000000 | 0x0054
+#define NT_STATUS_LOCK_NOT_GRANTED 0xC0000000 | 0x0055
+#define NT_STATUS_DELETE_PENDING 0xC0000000 | 0x0056
+#define NT_STATUS_CTL_FILE_NOT_SUPPORTED 0xC0000000 | 0x0057
+#define NT_STATUS_UNKNOWN_REVISION 0xC0000000 | 0x0058
+#define NT_STATUS_REVISION_MISMATCH 0xC0000000 | 0x0059
+#define NT_STATUS_INVALID_OWNER 0xC0000000 | 0x005a
+#define NT_STATUS_INVALID_PRIMARY_GROUP 0xC0000000 | 0x005b
+#define NT_STATUS_NO_IMPERSONATION_TOKEN 0xC0000000 | 0x005c
+#define NT_STATUS_CANT_DISABLE_MANDATORY 0xC0000000 | 0x005d
+#define NT_STATUS_NO_LOGON_SERVERS 0xC0000000 | 0x005e
+#define NT_STATUS_NO_SUCH_LOGON_SESSION 0xC0000000 | 0x005f
+#define NT_STATUS_NO_SUCH_PRIVILEGE 0xC0000000 | 0x0060
+#define NT_STATUS_PRIVILEGE_NOT_HELD 0xC0000000 | 0x0061
+#define NT_STATUS_INVALID_ACCOUNT_NAME 0xC0000000 | 0x0062
+#define NT_STATUS_USER_EXISTS 0xC0000000 | 0x0063
+#define NT_STATUS_NO_SUCH_USER 0xC0000000 | 0x0064
+#define NT_STATUS_GROUP_EXISTS 0xC0000000 | 0x0065
+#define NT_STATUS_NO_SUCH_GROUP 0xC0000000 | 0x0066
+#define NT_STATUS_MEMBER_IN_GROUP 0xC0000000 | 0x0067
+#define NT_STATUS_MEMBER_NOT_IN_GROUP 0xC0000000 | 0x0068
+#define NT_STATUS_LAST_ADMIN 0xC0000000 | 0x0069
+#define NT_STATUS_WRONG_PASSWORD 0xC0000000 | 0x006a
+#define NT_STATUS_ILL_FORMED_PASSWORD 0xC0000000 | 0x006b
+#define NT_STATUS_PASSWORD_RESTRICTION 0xC0000000 | 0x006c
+#define NT_STATUS_LOGON_FAILURE 0xC0000000 | 0x006d
+#define NT_STATUS_ACCOUNT_RESTRICTION 0xC0000000 | 0x006e
+#define NT_STATUS_INVALID_LOGON_HOURS 0xC0000000 | 0x006f
+#define NT_STATUS_INVALID_WORKSTATION 0xC0000000 | 0x0070
+#define NT_STATUS_PASSWORD_EXPIRED 0xC0000000 | 0x0071
+#define NT_STATUS_ACCOUNT_DISABLED 0xC0000000 | 0x0072
+#define NT_STATUS_NONE_MAPPED 0xC0000000 | 0x0073
+#define NT_STATUS_TOO_MANY_LUIDS_REQUESTED 0xC0000000 | 0x0074
+#define NT_STATUS_LUIDS_EXHAUSTED 0xC0000000 | 0x0075
+#define NT_STATUS_INVALID_SUB_AUTHORITY 0xC0000000 | 0x0076
+#define NT_STATUS_INVALID_ACL 0xC0000000 | 0x0077
+#define NT_STATUS_INVALID_SID 0xC0000000 | 0x0078
+#define NT_STATUS_INVALID_SECURITY_DESCR 0xC0000000 | 0x0079
+#define NT_STATUS_PROCEDURE_NOT_FOUND 0xC0000000 | 0x007a
+#define NT_STATUS_INVALID_IMAGE_FORMAT 0xC0000000 | 0x007b
+#define NT_STATUS_NO_TOKEN 0xC0000000 | 0x007c
+#define NT_STATUS_BAD_INHERITANCE_ACL 0xC0000000 | 0x007d
+#define NT_STATUS_RANGE_NOT_LOCKED 0xC0000000 | 0x007e
+#define NT_STATUS_DISK_FULL 0xC0000000 | 0x007f
+#define NT_STATUS_SERVER_DISABLED 0xC0000000 | 0x0080
+#define NT_STATUS_SERVER_NOT_DISABLED 0xC0000000 | 0x0081
+#define NT_STATUS_TOO_MANY_GUIDS_REQUESTED 0xC0000000 | 0x0082
+#define NT_STATUS_GUIDS_EXHAUSTED 0xC0000000 | 0x0083
+#define NT_STATUS_INVALID_ID_AUTHORITY 0xC0000000 | 0x0084
+#define NT_STATUS_AGENTS_EXHAUSTED 0xC0000000 | 0x0085
+#define NT_STATUS_INVALID_VOLUME_LABEL 0xC0000000 | 0x0086
+#define NT_STATUS_SECTION_NOT_EXTENDED 0xC0000000 | 0x0087
+#define NT_STATUS_NOT_MAPPED_DATA 0xC0000000 | 0x0088
+#define NT_STATUS_RESOURCE_DATA_NOT_FOUND 0xC0000000 | 0x0089
+#define NT_STATUS_RESOURCE_TYPE_NOT_FOUND 0xC0000000 | 0x008a
+#define NT_STATUS_RESOURCE_NAME_NOT_FOUND 0xC0000000 | 0x008b
+#define NT_STATUS_ARRAY_BOUNDS_EXCEEDED 0xC0000000 | 0x008c
+#define NT_STATUS_FLOAT_DENORMAL_OPERAND 0xC0000000 | 0x008d
+#define NT_STATUS_FLOAT_DIVIDE_BY_ZERO 0xC0000000 | 0x008e
+#define NT_STATUS_FLOAT_INEXACT_RESULT 0xC0000000 | 0x008f
+#define NT_STATUS_FLOAT_INVALID_OPERATION 0xC0000000 | 0x0090
+#define NT_STATUS_FLOAT_OVERFLOW 0xC0000000 | 0x0091
+#define NT_STATUS_FLOAT_STACK_CHECK 0xC0000000 | 0x0092
+#define NT_STATUS_FLOAT_UNDERFLOW 0xC0000000 | 0x0093
+#define NT_STATUS_INTEGER_DIVIDE_BY_ZERO 0xC0000000 | 0x0094
+#define NT_STATUS_INTEGER_OVERFLOW 0xC0000000 | 0x0095
+#define NT_STATUS_PRIVILEGED_INSTRUCTION 0xC0000000 | 0x0096
+#define NT_STATUS_TOO_MANY_PAGING_FILES 0xC0000000 | 0x0097
+#define NT_STATUS_FILE_INVALID 0xC0000000 | 0x0098
+#define NT_STATUS_ALLOTTED_SPACE_EXCEEDED 0xC0000000 | 0x0099
+#define NT_STATUS_INSUFFICIENT_RESOURCES 0xC0000000 | 0x009a
+#define NT_STATUS_DFS_EXIT_PATH_FOUND 0xC0000000 | 0x009b
+#define NT_STATUS_DEVICE_DATA_ERROR 0xC0000000 | 0x009c
+#define NT_STATUS_DEVICE_NOT_CONNECTED 0xC0000000 | 0x009d
+#define NT_STATUS_DEVICE_POWER_FAILURE 0xC0000000 | 0x009e
+#define NT_STATUS_FREE_VM_NOT_AT_BASE 0xC0000000 | 0x009f
+#define NT_STATUS_MEMORY_NOT_ALLOCATED 0xC0000000 | 0x00a0
+#define NT_STATUS_WORKING_SET_QUOTA 0xC0000000 | 0x00a1
+#define NT_STATUS_MEDIA_WRITE_PROTECTED 0xC0000000 | 0x00a2
+#define NT_STATUS_DEVICE_NOT_READY 0xC0000000 | 0x00a3
+#define NT_STATUS_INVALID_GROUP_ATTRIBUTES 0xC0000000 | 0x00a4
+#define NT_STATUS_BAD_IMPERSONATION_LEVEL 0xC0000000 | 0x00a5
+#define NT_STATUS_CANT_OPEN_ANONYMOUS 0xC0000000 | 0x00a6
+#define NT_STATUS_BAD_VALIDATION_CLASS 0xC0000000 | 0x00a7
+#define NT_STATUS_BAD_TOKEN_TYPE 0xC0000000 | 0x00a8
+#define NT_STATUS_BAD_MASTER_BOOT_RECORD 0xC0000000 | 0x00a9
+#define NT_STATUS_INSTRUCTION_MISALIGNMENT 0xC0000000 | 0x00aa
+#define NT_STATUS_INSTANCE_NOT_AVAILABLE 0xC0000000 | 0x00ab
+#define NT_STATUS_PIPE_NOT_AVAILABLE 0xC0000000 | 0x00ac
+#define NT_STATUS_INVALID_PIPE_STATE 0xC0000000 | 0x00ad
+#define NT_STATUS_PIPE_BUSY 0xC0000000 | 0x00ae
+#define NT_STATUS_ILLEGAL_FUNCTION 0xC0000000 | 0x00af
+#define NT_STATUS_PIPE_DISCONNECTED 0xC0000000 | 0x00b0
+#define NT_STATUS_PIPE_CLOSING 0xC0000000 | 0x00b1
+#define NT_STATUS_PIPE_CONNECTED 0xC0000000 | 0x00b2
+#define NT_STATUS_PIPE_LISTENING 0xC0000000 | 0x00b3
+#define NT_STATUS_INVALID_READ_MODE 0xC0000000 | 0x00b4
+#define NT_STATUS_IO_TIMEOUT 0xC0000000 | 0x00b5
+#define NT_STATUS_FILE_FORCED_CLOSED 0xC0000000 | 0x00b6
+#define NT_STATUS_PROFILING_NOT_STARTED 0xC0000000 | 0x00b7
+#define NT_STATUS_PROFILING_NOT_STOPPED 0xC0000000 | 0x00b8
+#define NT_STATUS_COULD_NOT_INTERPRET 0xC0000000 | 0x00b9
+#define NT_STATUS_FILE_IS_A_DIRECTORY 0xC0000000 | 0x00ba
+#define NT_STATUS_NOT_SUPPORTED 0xC0000000 | 0x00bb
+#define NT_STATUS_REMOTE_NOT_LISTENING 0xC0000000 | 0x00bc
+#define NT_STATUS_DUPLICATE_NAME 0xC0000000 | 0x00bd
+#define NT_STATUS_BAD_NETWORK_PATH 0xC0000000 | 0x00be
+#define NT_STATUS_NETWORK_BUSY 0xC0000000 | 0x00bf
+#define NT_STATUS_DEVICE_DOES_NOT_EXIST 0xC0000000 | 0x00c0
+#define NT_STATUS_TOO_MANY_COMMANDS 0xC0000000 | 0x00c1
+#define NT_STATUS_ADAPTER_HARDWARE_ERROR 0xC0000000 | 0x00c2
+#define NT_STATUS_INVALID_NETWORK_RESPONSE 0xC0000000 | 0x00c3
+#define NT_STATUS_UNEXPECTED_NETWORK_ERROR 0xC0000000 | 0x00c4
+#define NT_STATUS_BAD_REMOTE_ADAPTER 0xC0000000 | 0x00c5
+#define NT_STATUS_PRINT_QUEUE_FULL 0xC0000000 | 0x00c6
+#define NT_STATUS_NO_SPOOL_SPACE 0xC0000000 | 0x00c7
+#define NT_STATUS_PRINT_CANCELLED 0xC0000000 | 0x00c8
+#define NT_STATUS_NETWORK_NAME_DELETED 0xC0000000 | 0x00c9
+#define NT_STATUS_NETWORK_ACCESS_DENIED 0xC0000000 | 0x00ca
+#define NT_STATUS_BAD_DEVICE_TYPE 0xC0000000 | 0x00cb
+#define NT_STATUS_BAD_NETWORK_NAME 0xC0000000 | 0x00cc
+#define NT_STATUS_TOO_MANY_NAMES 0xC0000000 | 0x00cd
+#define NT_STATUS_TOO_MANY_SESSIONS 0xC0000000 | 0x00ce
+#define NT_STATUS_SHARING_PAUSED 0xC0000000 | 0x00cf
+#define NT_STATUS_REQUEST_NOT_ACCEPTED 0xC0000000 | 0x00d0
+#define NT_STATUS_REDIRECTOR_PAUSED 0xC0000000 | 0x00d1
+#define NT_STATUS_NET_WRITE_FAULT 0xC0000000 | 0x00d2
+#define NT_STATUS_PROFILING_AT_LIMIT 0xC0000000 | 0x00d3
+#define NT_STATUS_NOT_SAME_DEVICE 0xC0000000 | 0x00d4
+#define NT_STATUS_FILE_RENAMED 0xC0000000 | 0x00d5
+#define NT_STATUS_VIRTUAL_CIRCUIT_CLOSED 0xC0000000 | 0x00d6
+#define NT_STATUS_NO_SECURITY_ON_OBJECT 0xC0000000 | 0x00d7
+#define NT_STATUS_CANT_WAIT 0xC0000000 | 0x00d8
+#define NT_STATUS_PIPE_EMPTY 0xC0000000 | 0x00d9
+#define NT_STATUS_CANT_ACCESS_DOMAIN_INFO 0xC0000000 | 0x00da
+#define NT_STATUS_CANT_TERMINATE_SELF 0xC0000000 | 0x00db
+#define NT_STATUS_INVALID_SERVER_STATE 0xC0000000 | 0x00dc
+#define NT_STATUS_INVALID_DOMAIN_STATE 0xC0000000 | 0x00dd
+#define NT_STATUS_INVALID_DOMAIN_ROLE 0xC0000000 | 0x00de
+#define NT_STATUS_NO_SUCH_DOMAIN 0xC0000000 | 0x00df
+#define NT_STATUS_DOMAIN_EXISTS 0xC0000000 | 0x00e0
+#define NT_STATUS_DOMAIN_LIMIT_EXCEEDED 0xC0000000 | 0x00e1
+#define NT_STATUS_OPLOCK_NOT_GRANTED 0xC0000000 | 0x00e2
+#define NT_STATUS_INVALID_OPLOCK_PROTOCOL 0xC0000000 | 0x00e3
+#define NT_STATUS_INTERNAL_DB_CORRUPTION 0xC0000000 | 0x00e4
+#define NT_STATUS_INTERNAL_ERROR 0xC0000000 | 0x00e5
+#define NT_STATUS_GENERIC_NOT_MAPPED 0xC0000000 | 0x00e6
+#define NT_STATUS_BAD_DESCRIPTOR_FORMAT 0xC0000000 | 0x00e7
+#define NT_STATUS_INVALID_USER_BUFFER 0xC0000000 | 0x00e8
+#define NT_STATUS_UNEXPECTED_IO_ERROR 0xC0000000 | 0x00e9
+#define NT_STATUS_UNEXPECTED_MM_CREATE_ERR 0xC0000000 | 0x00ea
+#define NT_STATUS_UNEXPECTED_MM_MAP_ERROR 0xC0000000 | 0x00eb
+#define NT_STATUS_UNEXPECTED_MM_EXTEND_ERR 0xC0000000 | 0x00ec
+#define NT_STATUS_NOT_LOGON_PROCESS 0xC0000000 | 0x00ed
+#define NT_STATUS_LOGON_SESSION_EXISTS 0xC0000000 | 0x00ee
+#define NT_STATUS_INVALID_PARAMETER_1 0xC0000000 | 0x00ef
+#define NT_STATUS_INVALID_PARAMETER_2 0xC0000000 | 0x00f0
+#define NT_STATUS_INVALID_PARAMETER_3 0xC0000000 | 0x00f1
+#define NT_STATUS_INVALID_PARAMETER_4 0xC0000000 | 0x00f2
+#define NT_STATUS_INVALID_PARAMETER_5 0xC0000000 | 0x00f3
+#define NT_STATUS_INVALID_PARAMETER_6 0xC0000000 | 0x00f4
+#define NT_STATUS_INVALID_PARAMETER_7 0xC0000000 | 0x00f5
+#define NT_STATUS_INVALID_PARAMETER_8 0xC0000000 | 0x00f6
+#define NT_STATUS_INVALID_PARAMETER_9 0xC0000000 | 0x00f7
+#define NT_STATUS_INVALID_PARAMETER_10 0xC0000000 | 0x00f8
+#define NT_STATUS_INVALID_PARAMETER_11 0xC0000000 | 0x00f9
+#define NT_STATUS_INVALID_PARAMETER_12 0xC0000000 | 0x00fa
+#define NT_STATUS_REDIRECTOR_NOT_STARTED 0xC0000000 | 0x00fb
+#define NT_STATUS_REDIRECTOR_STARTED 0xC0000000 | 0x00fc
+#define NT_STATUS_STACK_OVERFLOW 0xC0000000 | 0x00fd
+#define NT_STATUS_NO_SUCH_PACKAGE 0xC0000000 | 0x00fe
+#define NT_STATUS_BAD_FUNCTION_TABLE 0xC0000000 | 0x00ff
+#define NT_STATUS_DIRECTORY_NOT_EMPTY 0xC0000000 | 0x0101
+#define NT_STATUS_FILE_CORRUPT_ERROR 0xC0000000 | 0x0102
+#define NT_STATUS_NOT_A_DIRECTORY 0xC0000000 | 0x0103
+#define NT_STATUS_BAD_LOGON_SESSION_STATE 0xC0000000 | 0x0104
+#define NT_STATUS_LOGON_SESSION_COLLISION 0xC0000000 | 0x0105
+#define NT_STATUS_NAME_TOO_LONG 0xC0000000 | 0x0106
+#define NT_STATUS_FILES_OPEN 0xC0000000 | 0x0107
+#define NT_STATUS_CONNECTION_IN_USE 0xC0000000 | 0x0108
+#define NT_STATUS_MESSAGE_NOT_FOUND 0xC0000000 | 0x0109
+#define NT_STATUS_PROCESS_IS_TERMINATING 0xC0000000 | 0x010a
+#define NT_STATUS_INVALID_LOGON_TYPE 0xC0000000 | 0x010b
+#define NT_STATUS_NO_GUID_TRANSLATION 0xC0000000 | 0x010c
+#define NT_STATUS_CANNOT_IMPERSONATE 0xC0000000 | 0x010d
+#define NT_STATUS_IMAGE_ALREADY_LOADED 0xC0000000 | 0x010e
+#define NT_STATUS_ABIOS_NOT_PRESENT 0xC0000000 | 0x010f
+#define NT_STATUS_ABIOS_LID_NOT_EXIST 0xC0000000 | 0x0110
+#define NT_STATUS_ABIOS_LID_ALREADY_OWNED 0xC0000000 | 0x0111
+#define NT_STATUS_ABIOS_NOT_LID_OWNER 0xC0000000 | 0x0112
+#define NT_STATUS_ABIOS_INVALID_COMMAND 0xC0000000 | 0x0113
+#define NT_STATUS_ABIOS_INVALID_LID 0xC0000000 | 0x0114
+#define NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE 0xC0000000 | 0x0115
+#define NT_STATUS_ABIOS_INVALID_SELECTOR 0xC0000000 | 0x0116
+#define NT_STATUS_NO_LDT 0xC0000000 | 0x0117
+#define NT_STATUS_INVALID_LDT_SIZE 0xC0000000 | 0x0118
+#define NT_STATUS_INVALID_LDT_OFFSET 0xC0000000 | 0x0119
+#define NT_STATUS_INVALID_LDT_DESCRIPTOR 0xC0000000 | 0x011a
+#define NT_STATUS_INVALID_IMAGE_NE_FORMAT 0xC0000000 | 0x011b
+#define NT_STATUS_RXACT_INVALID_STATE 0xC0000000 | 0x011c
+#define NT_STATUS_RXACT_COMMIT_FAILURE 0xC0000000 | 0x011d
+#define NT_STATUS_MAPPED_FILE_SIZE_ZERO 0xC0000000 | 0x011e
+#define NT_STATUS_TOO_MANY_OPENED_FILES 0xC0000000 | 0x011f
+#define NT_STATUS_CANCELLED 0xC0000000 | 0x0120
+#define NT_STATUS_CANNOT_DELETE 0xC0000000 | 0x0121
+#define NT_STATUS_INVALID_COMPUTER_NAME 0xC0000000 | 0x0122
+#define NT_STATUS_FILE_DELETED 0xC0000000 | 0x0123
+#define NT_STATUS_SPECIAL_ACCOUNT 0xC0000000 | 0x0124
+#define NT_STATUS_SPECIAL_GROUP 0xC0000000 | 0x0125
+#define NT_STATUS_SPECIAL_USER 0xC0000000 | 0x0126
+#define NT_STATUS_MEMBERS_PRIMARY_GROUP 0xC0000000 | 0x0127
+#define NT_STATUS_FILE_CLOSED 0xC0000000 | 0x0128
+#define NT_STATUS_TOO_MANY_THREADS 0xC0000000 | 0x0129
+#define NT_STATUS_THREAD_NOT_IN_PROCESS 0xC0000000 | 0x012a
+#define NT_STATUS_TOKEN_ALREADY_IN_USE 0xC0000000 | 0x012b
+#define NT_STATUS_PAGEFILE_QUOTA_EXCEEDED 0xC0000000 | 0x012c
+#define NT_STATUS_COMMITMENT_LIMIT 0xC0000000 | 0x012d
+#define NT_STATUS_INVALID_IMAGE_LE_FORMAT 0xC0000000 | 0x012e
+#define NT_STATUS_INVALID_IMAGE_NOT_MZ 0xC0000000 | 0x012f
+#define NT_STATUS_INVALID_IMAGE_PROTECT 0xC0000000 | 0x0130
+#define NT_STATUS_INVALID_IMAGE_WIN_16 0xC0000000 | 0x0131
+#define NT_STATUS_LOGON_SERVER_CONFLICT 0xC0000000 | 0x0132
+#define NT_STATUS_TIME_DIFFERENCE_AT_DC 0xC0000000 | 0x0133
+#define NT_STATUS_SYNCHRONIZATION_REQUIRED 0xC0000000 | 0x0134
+#define NT_STATUS_DLL_NOT_FOUND 0xC0000000 | 0x0135
+#define NT_STATUS_OPEN_FAILED 0xC0000000 | 0x0136
+#define NT_STATUS_IO_PRIVILEGE_FAILED 0xC0000000 | 0x0137
+#define NT_STATUS_ORDINAL_NOT_FOUND 0xC0000000 | 0x0138
+#define NT_STATUS_ENTRYPOINT_NOT_FOUND 0xC0000000 | 0x0139
+#define NT_STATUS_CONTROL_C_EXIT 0xC0000000 | 0x013a
+#define NT_STATUS_LOCAL_DISCONNECT 0xC0000000 | 0x013b
+#define NT_STATUS_REMOTE_DISCONNECT 0xC0000000 | 0x013c
+#define NT_STATUS_REMOTE_RESOURCES 0xC0000000 | 0x013d
+#define NT_STATUS_LINK_FAILED 0xC0000000 | 0x013e
+#define NT_STATUS_LINK_TIMEOUT 0xC0000000 | 0x013f
+#define NT_STATUS_INVALID_CONNECTION 0xC0000000 | 0x0140
+#define NT_STATUS_INVALID_ADDRESS 0xC0000000 | 0x0141
+#define NT_STATUS_DLL_INIT_FAILED 0xC0000000 | 0x0142
+#define NT_STATUS_MISSING_SYSTEMFILE 0xC0000000 | 0x0143
+#define NT_STATUS_UNHANDLED_EXCEPTION 0xC0000000 | 0x0144
+#define NT_STATUS_APP_INIT_FAILURE 0xC0000000 | 0x0145
+#define NT_STATUS_PAGEFILE_CREATE_FAILED 0xC0000000 | 0x0146
+#define NT_STATUS_NO_PAGEFILE 0xC0000000 | 0x0147
+#define NT_STATUS_INVALID_LEVEL 0xC0000000 | 0x0148
+#define NT_STATUS_WRONG_PASSWORD_CORE 0xC0000000 | 0x0149
+#define NT_STATUS_ILLEGAL_FLOAT_CONTEXT 0xC0000000 | 0x014a
+#define NT_STATUS_PIPE_BROKEN 0xC0000000 | 0x014b
+#define NT_STATUS_REGISTRY_CORRUPT 0xC0000000 | 0x014c
+#define NT_STATUS_REGISTRY_IO_FAILED 0xC0000000 | 0x014d
+#define NT_STATUS_NO_EVENT_PAIR 0xC0000000 | 0x014e
+#define NT_STATUS_UNRECOGNIZED_VOLUME 0xC0000000 | 0x014f
+#define NT_STATUS_SERIAL_NO_DEVICE_INITED 0xC0000000 | 0x0150
+#define NT_STATUS_NO_SUCH_ALIAS 0xC0000000 | 0x0151
+#define NT_STATUS_MEMBER_NOT_IN_ALIAS 0xC0000000 | 0x0152
+#define NT_STATUS_MEMBER_IN_ALIAS 0xC0000000 | 0x0153
+#define NT_STATUS_ALIAS_EXISTS 0xC0000000 | 0x0154
+#define NT_STATUS_LOGON_NOT_GRANTED 0xC0000000 | 0x0155
+#define NT_STATUS_TOO_MANY_SECRETS 0xC0000000 | 0x0156
+#define NT_STATUS_SECRET_TOO_LONG 0xC0000000 | 0x0157
+#define NT_STATUS_INTERNAL_DB_ERROR 0xC0000000 | 0x0158
+#define NT_STATUS_FULLSCREEN_MODE 0xC0000000 | 0x0159
+#define NT_STATUS_TOO_MANY_CONTEXT_IDS 0xC0000000 | 0x015a
+#define NT_STATUS_LOGON_TYPE_NOT_GRANTED 0xC0000000 | 0x015b
+#define NT_STATUS_NOT_REGISTRY_FILE 0xC0000000 | 0x015c
+#define NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED 0xC0000000 | 0x015d
+#define NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR 0xC0000000 | 0x015e
+#define NT_STATUS_FT_MISSING_MEMBER 0xC0000000 | 0x015f
+#define NT_STATUS_ILL_FORMED_SERVICE_ENTRY 0xC0000000 | 0x0160
+#define NT_STATUS_ILLEGAL_CHARACTER 0xC0000000 | 0x0161
+#define NT_STATUS_UNMAPPABLE_CHARACTER 0xC0000000 | 0x0162
+#define NT_STATUS_UNDEFINED_CHARACTER 0xC0000000 | 0x0163
+#define NT_STATUS_FLOPPY_VOLUME 0xC0000000 | 0x0164
+#define NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND 0xC0000000 | 0x0165
+#define NT_STATUS_FLOPPY_WRONG_CYLINDER 0xC0000000 | 0x0166
+#define NT_STATUS_FLOPPY_UNKNOWN_ERROR 0xC0000000 | 0x0167
+#define NT_STATUS_FLOPPY_BAD_REGISTERS 0xC0000000 | 0x0168
+#define NT_STATUS_DISK_RECALIBRATE_FAILED 0xC0000000 | 0x0169
+#define NT_STATUS_DISK_OPERATION_FAILED 0xC0000000 | 0x016a
+#define NT_STATUS_DISK_RESET_FAILED 0xC0000000 | 0x016b
+#define NT_STATUS_SHARED_IRQ_BUSY 0xC0000000 | 0x016c
+#define NT_STATUS_FT_ORPHANING 0xC0000000 | 0x016d
+#define NT_STATUS_PARTITION_FAILURE 0xC0000000 | 0x0172
+#define NT_STATUS_INVALID_BLOCK_LENGTH 0xC0000000 | 0x0173
+#define NT_STATUS_DEVICE_NOT_PARTITIONED 0xC0000000 | 0x0174
+#define NT_STATUS_UNABLE_TO_LOCK_MEDIA 0xC0000000 | 0x0175
+#define NT_STATUS_UNABLE_TO_UNLOAD_MEDIA 0xC0000000 | 0x0176
+#define NT_STATUS_EOM_OVERFLOW 0xC0000000 | 0x0177
+#define NT_STATUS_NO_MEDIA 0xC0000000 | 0x0178
+#define NT_STATUS_NO_SUCH_MEMBER 0xC0000000 | 0x017a
+#define NT_STATUS_INVALID_MEMBER 0xC0000000 | 0x017b
+#define NT_STATUS_KEY_DELETED 0xC0000000 | 0x017c
+#define NT_STATUS_NO_LOG_SPACE 0xC0000000 | 0x017d
+#define NT_STATUS_TOO_MANY_SIDS 0xC0000000 | 0x017e
+#define NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED 0xC0000000 | 0x017f
+#define NT_STATUS_KEY_HAS_CHILDREN 0xC0000000 | 0x0180
+#define NT_STATUS_CHILD_MUST_BE_VOLATILE 0xC0000000 | 0x0181
+#define NT_STATUS_DEVICE_CONFIGURATION_ERROR 0xC0000000 | 0x0182
+#define NT_STATUS_DRIVER_INTERNAL_ERROR 0xC0000000 | 0x0183
+#define NT_STATUS_INVALID_DEVICE_STATE 0xC0000000 | 0x0184
+#define NT_STATUS_IO_DEVICE_ERROR 0xC0000000 | 0x0185
+#define NT_STATUS_DEVICE_PROTOCOL_ERROR 0xC0000000 | 0x0186
+#define NT_STATUS_BACKUP_CONTROLLER 0xC0000000 | 0x0187
+#define NT_STATUS_LOG_FILE_FULL 0xC0000000 | 0x0188
+#define NT_STATUS_TOO_LATE 0xC0000000 | 0x0189
+#define NT_STATUS_NO_TRUST_LSA_SECRET 0xC0000000 | 0x018a
+#define NT_STATUS_NO_TRUST_SAM_ACCOUNT 0xC0000000 | 0x018b
+#define NT_STATUS_TRUSTED_DOMAIN_FAILURE 0xC0000000 | 0x018c
+#define NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE 0xC0000000 | 0x018d
+#define NT_STATUS_EVENTLOG_FILE_CORRUPT 0xC0000000 | 0x018e
+#define NT_STATUS_EVENTLOG_CANT_START 0xC0000000 | 0x018f
+#define NT_STATUS_TRUST_FAILURE 0xC0000000 | 0x0190
+#define NT_STATUS_MUTANT_LIMIT_EXCEEDED 0xC0000000 | 0x0191
+#define NT_STATUS_NETLOGON_NOT_STARTED 0xC0000000 | 0x0192
+#define NT_STATUS_ACCOUNT_EXPIRED 0xC0000000 | 0x0193
+#define NT_STATUS_POSSIBLE_DEADLOCK 0xC0000000 | 0x0194
+#define NT_STATUS_NETWORK_CREDENTIAL_CONFLICT 0xC0000000 | 0x0195
+#define NT_STATUS_REMOTE_SESSION_LIMIT 0xC0000000 | 0x0196
+#define NT_STATUS_EVENTLOG_FILE_CHANGED 0xC0000000 | 0x0197
+#define NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT 0xC0000000 | 0x0198
+#define NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT 0xC0000000 | 0x0199
+#define NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT 0xC0000000 | 0x019a
+#define NT_STATUS_DOMAIN_TRUST_INCONSISTENT 0xC0000000 | 0x019b
+#define NT_STATUS_FS_DRIVER_REQUIRED 0xC0000000 | 0x019c
+#define NT_STATUS_NO_USER_SESSION_KEY 0xC0000000 | 0x0202
+#define NT_STATUS_USER_SESSION_DELETED 0xC0000000 | 0x0203
+#define NT_STATUS_RESOURCE_LANG_NOT_FOUND 0xC0000000 | 0x0204
+#define NT_STATUS_INSUFF_SERVER_RESOURCES 0xC0000000 | 0x0205
+#define NT_STATUS_INVALID_BUFFER_SIZE 0xC0000000 | 0x0206
+#define NT_STATUS_INVALID_ADDRESS_COMPONENT 0xC0000000 | 0x0207
+#define NT_STATUS_INVALID_ADDRESS_WILDCARD 0xC0000000 | 0x0208
+#define NT_STATUS_TOO_MANY_ADDRESSES 0xC0000000 | 0x0209
+#define NT_STATUS_ADDRESS_ALREADY_EXISTS 0xC0000000 | 0x020a
+#define NT_STATUS_ADDRESS_CLOSED 0xC0000000 | 0x020b
+#define NT_STATUS_CONNECTION_DISCONNECTED 0xC0000000 | 0x020c
+#define NT_STATUS_CONNECTION_RESET 0xC0000000 | 0x020d
+#define NT_STATUS_TOO_MANY_NODES 0xC0000000 | 0x020e
+#define NT_STATUS_TRANSACTION_ABORTED 0xC0000000 | 0x020f
+#define NT_STATUS_TRANSACTION_TIMED_OUT 0xC0000000 | 0x0210
+#define NT_STATUS_TRANSACTION_NO_RELEASE 0xC0000000 | 0x0211
+#define NT_STATUS_TRANSACTION_NO_MATCH 0xC0000000 | 0x0212
+#define NT_STATUS_TRANSACTION_RESPONDED 0xC0000000 | 0x0213
+#define NT_STATUS_TRANSACTION_INVALID_ID 0xC0000000 | 0x0214
+#define NT_STATUS_TRANSACTION_INVALID_TYPE 0xC0000000 | 0x0215
+#define NT_STATUS_NOT_SERVER_SESSION 0xC0000000 | 0x0216
+#define NT_STATUS_NOT_CLIENT_SESSION 0xC0000000 | 0x0217
+#define NT_STATUS_CANNOT_LOAD_REGISTRY_FILE 0xC0000000 | 0x0218
+#define NT_STATUS_DEBUG_ATTACH_FAILED 0xC0000000 | 0x0219
+#define NT_STATUS_SYSTEM_PROCESS_TERMINATED 0xC0000000 | 0x021a
+#define NT_STATUS_DATA_NOT_ACCEPTED 0xC0000000 | 0x021b
+#define NT_STATUS_NO_BROWSER_SERVERS_FOUND 0xC0000000 | 0x021c
+#define NT_STATUS_VDM_HARD_ERROR 0xC0000000 | 0x021d
+#define NT_STATUS_DRIVER_CANCEL_TIMEOUT 0xC0000000 | 0x021e
+#define NT_STATUS_REPLY_MESSAGE_MISMATCH 0xC0000000 | 0x021f
+#define NT_STATUS_MAPPED_ALIGNMENT 0xC0000000 | 0x0220
+#define NT_STATUS_IMAGE_CHECKSUM_MISMATCH 0xC0000000 | 0x0221
+#define NT_STATUS_LOST_WRITEBEHIND_DATA 0xC0000000 | 0x0222
+#define NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID 0xC0000000 | 0x0223
+#define NT_STATUS_PASSWORD_MUST_CHANGE 0xC0000000 | 0x0224
+#define NT_STATUS_NOT_FOUND 0xC0000000 | 0x0225
+#define NT_STATUS_NOT_TINY_STREAM 0xC0000000 | 0x0226
+#define NT_STATUS_RECOVERY_FAILURE 0xC0000000 | 0x0227
+#define NT_STATUS_STACK_OVERFLOW_READ 0xC0000000 | 0x0228
+#define NT_STATUS_FAIL_CHECK 0xC0000000 | 0x0229
+#define NT_STATUS_DUPLICATE_OBJECTID 0xC0000000 | 0x022a
+#define NT_STATUS_OBJECTID_EXISTS 0xC0000000 | 0x022b
+#define NT_STATUS_CONVERT_TO_LARGE 0xC0000000 | 0x022c
+#define NT_STATUS_RETRY 0xC0000000 | 0x022d
+#define NT_STATUS_FOUND_OUT_OF_SCOPE 0xC0000000 | 0x022e
+#define NT_STATUS_ALLOCATE_BUCKET 0xC0000000 | 0x022f
+#define NT_STATUS_PROPSET_NOT_FOUND 0xC0000000 | 0x0230
+#define NT_STATUS_MARSHALL_OVERFLOW 0xC0000000 | 0x0231
+#define NT_STATUS_INVALID_VARIANT 0xC0000000 | 0x0232
+#define NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND 0xC0000000 | 0x0233
+#define NT_STATUS_ACCOUNT_LOCKED_OUT 0xC0000000 | 0x0234
+#define NT_STATUS_HANDLE_NOT_CLOSABLE 0xC0000000 | 0x0235
+#define NT_STATUS_CONNECTION_REFUSED 0xC0000000 | 0x0236
+#define NT_STATUS_GRACEFUL_DISCONNECT 0xC0000000 | 0x0237
+#define NT_STATUS_ADDRESS_ALREADY_ASSOCIATED 0xC0000000 | 0x0238
+#define NT_STATUS_ADDRESS_NOT_ASSOCIATED 0xC0000000 | 0x0239
+#define NT_STATUS_CONNECTION_INVALID 0xC0000000 | 0x023a
+#define NT_STATUS_CONNECTION_ACTIVE 0xC0000000 | 0x023b
+#define NT_STATUS_NETWORK_UNREACHABLE 0xC0000000 | 0x023c
+#define NT_STATUS_HOST_UNREACHABLE 0xC0000000 | 0x023d
+#define NT_STATUS_PROTOCOL_UNREACHABLE 0xC0000000 | 0x023e
+#define NT_STATUS_PORT_UNREACHABLE 0xC0000000 | 0x023f
+#define NT_STATUS_REQUEST_ABORTED 0xC0000000 | 0x0240
+#define NT_STATUS_CONNECTION_ABORTED 0xC0000000 | 0x0241
+#define NT_STATUS_BAD_COMPRESSION_BUFFER 0xC0000000 | 0x0242
+#define NT_STATUS_USER_MAPPED_FILE 0xC0000000 | 0x0243
+#define NT_STATUS_AUDIT_FAILED 0xC0000000 | 0x0244
+#define NT_STATUS_TIMER_RESOLUTION_NOT_SET 0xC0000000 | 0x0245
+#define NT_STATUS_CONNECTION_COUNT_LIMIT 0xC0000000 | 0x0246
+#define NT_STATUS_LOGIN_TIME_RESTRICTION 0xC0000000 | 0x0247
+#define NT_STATUS_LOGIN_WKSTA_RESTRICTION 0xC0000000 | 0x0248
+#define NT_STATUS_IMAGE_MP_UP_MISMATCH 0xC0000000 | 0x0249
+#define NT_STATUS_INSUFFICIENT_LOGON_INFO 0xC0000000 | 0x0250
+#define NT_STATUS_BAD_DLL_ENTRYPOINT 0xC0000000 | 0x0251
+#define NT_STATUS_BAD_SERVICE_ENTRYPOINT 0xC0000000 | 0x0252
+#define NT_STATUS_LPC_REPLY_LOST 0xC0000000 | 0x0253
+#define NT_STATUS_IP_ADDRESS_CONFLICT1 0xC0000000 | 0x0254
+#define NT_STATUS_IP_ADDRESS_CONFLICT2 0xC0000000 | 0x0255
+#define NT_STATUS_REGISTRY_QUOTA_LIMIT 0xC0000000 | 0x0256
+#define NT_STATUS_PATH_NOT_COVERED 0xC0000000 | 0x0257
+#define NT_STATUS_NO_CALLBACK_ACTIVE 0xC0000000 | 0x0258
+#define NT_STATUS_LICENSE_QUOTA_EXCEEDED 0xC0000000 | 0x0259
+#define NT_STATUS_PWD_TOO_SHORT 0xC0000000 | 0x025a
+#define NT_STATUS_PWD_TOO_RECENT 0xC0000000 | 0x025b
+#define NT_STATUS_PWD_HISTORY_CONFLICT 0xC0000000 | 0x025c
+#define NT_STATUS_PLUGPLAY_NO_DEVICE 0xC0000000 | 0x025e
+#define NT_STATUS_UNSUPPORTED_COMPRESSION 0xC0000000 | 0x025f
+#define NT_STATUS_INVALID_HW_PROFILE 0xC0000000 | 0x0260
+#define NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH 0xC0000000 | 0x0261
+#define NT_STATUS_DRIVER_ORDINAL_NOT_FOUND 0xC0000000 | 0x0262
+#define NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND 0xC0000000 | 0x0263
+#define NT_STATUS_RESOURCE_NOT_OWNED 0xC0000000 | 0x0264
+#define NT_STATUS_TOO_MANY_LINKS 0xC0000000 | 0x0265
+#define NT_STATUS_QUOTA_LIST_INCONSISTENT 0xC0000000 | 0x0266
+#define NT_STATUS_FILE_IS_OFFLINE 0xC0000000 | 0x0267
+#define NT_STATUS_NO_SUCH_JOB 0xC0000000 | 0xEDE /* scheduler */
+
+#endif /* _NTERR_H */
diff --git a/release/src/linux/linux/fs/cifs/ntlmssp.h b/release/src/linux/linux/fs/cifs/ntlmssp.h
new file mode 100644
index 00000000..f06edcbe
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/ntlmssp.h
@@ -0,0 +1,101 @@
+/*
+ * fs/cifs/ntlmssp.h
+ *
+ * Copyright (c) International Business Machines Corp., 2002
+ * Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#pragma pack(1)
+
+#define NTLMSSP_SIGNATURE "NTLMSSP"
+/* Message Types */
+#define NtLmNegotiate 1
+#define NtLmChallenge 2
+#define NtLmAuthenticate 3
+#define UnknownMessage 8
+
+/* Negotiate Flags */
+#define NTLMSSP_NEGOTIATE_UNICODE 0x01 // Text strings are in unicode
+#define NTLMSSP_NEGOTIATE_OEM 0x02 // Text strings are in OEM
+#define NTLMSSP_REQUEST_TARGET 0x04 // Server return its auth realm
+#define NTLMSSP_NEGOTIATE_SIGN 0x0010 // Request signature capability
+#define NTLMSSP_NEGOTIATE_SEAL 0x0020 // Request confidentiality
+#define NTLMSSP_NEGOTIATE_DGRAM 0x0040
+#define NTLMSSP_NEGOTIATE_LM_KEY 0x0080 // Use LM session key for sign/seal
+#define NTLMSSP_NEGOTIATE_NTLM 0x0200 // NTLM authentication
+#define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x1000
+#define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x2000
+#define NTLMSSP_NEGOTIATE_LOCAL_CALL 0x4000 // client/server on same machine
+#define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x8000 // Sign for all security levels
+#define NTLMSSP_TARGET_TYPE_DOMAIN 0x10000
+#define NTLMSSP_TARGET_TYPE_SERVER 0x20000
+#define NTLMSSP_TARGET_TYPE_SHARE 0x40000
+#define NTLMSSP_NEGOTIATE_NTLMV2 0x80000
+#define NTLMSSP_REQUEST_INIT_RESP 0x100000
+#define NTLMSSP_REQUEST_ACCEPT_RESP 0x200000
+#define NTLMSSP_REQUEST_NOT_NT_KEY 0x400000
+#define NTLMSSP_NEGOTIATE_TARGET_INFO 0x800000
+#define NTLMSSP_NEGOTIATE_128 0x20000000
+#define NTLMSSP_NEGOTIATE_KEY_XCH 0x40000000
+#define NTLMSSP_NEGOTIATE_56 0x80000000
+
+/* Although typedefs are not commonly used for structure definitions */
+/* in the Linux kernel, in this particular case they are useful */
+/* to more closely match the standards document for NTLMSSP from */
+/* OpenGroup and to make the code more closely match the standard in */
+/* appearance */
+
+typedef struct _SECURITY_BUFFER {
+ __u16 Length;
+ __u16 MaximumLength;
+ __u32 Buffer; /* offset to buffer */
+} SECURITY_BUFFER;
+
+typedef struct _NEGOTIATE_MESSAGE {
+ __u8 Signature[sizeof (NTLMSSP_SIGNATURE)];
+ __u32 MessageType; /* 1 */
+ __u32 NegotiateFlags;
+ SECURITY_BUFFER DomainName; /* RFC 1001 style and ASCII */
+ SECURITY_BUFFER WorkstationName; /* RFC 1001 and ASCII */
+ char DomainString[0];
+ /* followed by WorkstationString */
+} NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE;
+
+typedef struct _CHALLENGE_MESSAGE {
+ __u8 Signature[sizeof (NTLMSSP_SIGNATURE)];
+ __u32 MessageType; /* 2 */
+ SECURITY_BUFFER TargetName;
+ __u32 NegotiateFlags;
+ __u8 Challenge[CIFS_CRYPTO_KEY_SIZE];
+ __u8 Reserved[8];
+ SECURITY_BUFFER TargetInfoArray;
+} CHALLENGE_MESSAGE, *PCHALLENGE_MESSAGE;
+
+typedef struct _AUTHENTICATE_MESSAGE {
+ __u8 Signature[sizeof (NTLMSSP_SIGNATURE)];
+ __u32 MessageType; /* 3 */
+ SECURITY_BUFFER LmChallengeResponse;
+ SECURITY_BUFFER NtChallengeResponse;
+ SECURITY_BUFFER DomainName;
+ SECURITY_BUFFER UserName;
+ SECURITY_BUFFER WorkstationName;
+ SECURITY_BUFFER SessionKey;
+ __u32 NegotiateFlags;
+ char UserString[0];
+} AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE;
+
+#pragma pack() /* resume default structure packing */
diff --git a/release/src/linux/linux/fs/cifs/rfc1002pdu.h b/release/src/linux/linux/fs/cifs/rfc1002pdu.h
new file mode 100644
index 00000000..806c0ed0
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/rfc1002pdu.h
@@ -0,0 +1,79 @@
+/*
+ * fs/cifs/rfc1002pdu.h
+ *
+ * Protocol Data Unit definitions for RFC 1001/1002 support
+ *
+ * Copyright (c) International Business Machines Corp., 2004
+ * Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#pragma pack(1)
+
+/* NB: unlike smb/cifs packets, the RFC1002 structures are big endian */
+
+ /* RFC 1002 session packet types */
+#define RFC1002_SESSION_MESASAGE 0x00
+#define RFC1002_SESSION_REQUEST 0x81
+#define RFC1002_POSITIVE_SESSION_RESPONSE 0x82
+#define RFC1002_NEGATIVE_SESSION_RESPONSE 0x83
+#define RFC1002_RETARGET_SESSION_RESPONSE 0x83
+#define RFC1002_SESSION_KEEP_ALIVE 0x85
+
+ /* RFC 1002 flags (only one defined */
+#define RFC1002_LENGTH_EXTEND 0x80 /* high order bit of length (ie +64K) */
+
+struct rfc1002_session_packet {
+ __u8 type;
+ __u8 flags;
+ __u16 length;
+ union {
+ struct {
+ __u8 called_len;
+ __u8 called_name[32];
+ __u8 scope1; /* null */
+ __u8 calling_len;
+ __u8 calling_name[32];
+ __u8 scope2; /* null */
+ } session_req;
+ struct {
+ __u32 retarget_ip_addr;
+ __u16 port;
+ } retarget_resp;
+ __u8 neg_ses_resp_error_code;
+ /* POSITIVE_SESSION_RESPONSE packet does not include trailer.
+ SESSION_KEEP_ALIVE packet also does not include a trailer.
+ Trailer for the SESSION_MESSAGE packet is SMB/CIFS header */
+ } trailer;
+};
+
+/* Negative Session Response error codes */
+#define RFC1002_NOT_LISTENING_CALLED 0x80 /* not listening on called name */
+#define RFC1002_NOT_LISTENING_CALLING 0x81 /* not listening on calling name */
+#define RFC1002_NOT_PRESENT 0x82 /* called name not present */
+#define RFC1002_INSUFFICIENT_RESOURCE 0x83
+#define RFC1002_UNSPECIFIED_ERROR 0x8F
+
+/* RFC 1002 Datagram service packets are not defined here as they
+are not needed for the network filesystem client unless we plan on
+implementing broadcast resolution of the server ip address (from
+server netbios name). Currently server names are resolved only via DNS
+(tcp name) or ip address or an /etc/hosts equivalent mapping to ip address.*/
+
+#define DEFAULT_CIFS_CALLED_NAME "*SMBSERVER "
+
+#pragma pack() /* resume default structure packing */
+
diff --git a/release/src/linux/linux/fs/cifs/smbdes.c b/release/src/linux/linux/fs/cifs/smbdes.c
new file mode 100644
index 00000000..4d765f73
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/smbdes.c
@@ -0,0 +1,408 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+
+ a partial implementation of DES designed for use in the
+ SMB authentication protocol
+
+ Copyright (C) Andrew Tridgell 1998
+ Modified by Steve French (sfrench@us.ibm.com) 2002,2004
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* NOTES:
+
+ This code makes no attempt to be fast! In fact, it is a very
+ slow implementation
+
+ This code is NOT a complete DES implementation. It implements only
+ the minimum necessary for SMB authentication, as used by all SMB
+ products (including every copy of Microsoft Windows95 ever sold)
+
+ In particular, it can only do a unchained forward DES pass. This
+ means it is not possible to use this code for encryption/decryption
+ of data, instead it is only useful as a "hash" algorithm.
+
+ There is no entry point into this code that allows normal DES operation.
+
+ I believe this means that this code does not come under ITAR
+ regulations but this is NOT a legal opinion. If you are concerned
+ about the applicability of ITAR regulations to this code then you
+ should confirm it for yourself (and maybe let me know if you come
+ up with a different answer to the one above)
+*/
+#include <linux/slab.h>
+#define uchar unsigned char
+
+static uchar perm1[56] = { 57, 49, 41, 33, 25, 17, 9,
+ 1, 58, 50, 42, 34, 26, 18,
+ 10, 2, 59, 51, 43, 35, 27,
+ 19, 11, 3, 60, 52, 44, 36,
+ 63, 55, 47, 39, 31, 23, 15,
+ 7, 62, 54, 46, 38, 30, 22,
+ 14, 6, 61, 53, 45, 37, 29,
+ 21, 13, 5, 28, 20, 12, 4
+};
+
+static uchar perm2[48] = { 14, 17, 11, 24, 1, 5,
+ 3, 28, 15, 6, 21, 10,
+ 23, 19, 12, 4, 26, 8,
+ 16, 7, 27, 20, 13, 2,
+ 41, 52, 31, 37, 47, 55,
+ 30, 40, 51, 45, 33, 48,
+ 44, 49, 39, 56, 34, 53,
+ 46, 42, 50, 36, 29, 32
+};
+
+static uchar perm3[64] = { 58, 50, 42, 34, 26, 18, 10, 2,
+ 60, 52, 44, 36, 28, 20, 12, 4,
+ 62, 54, 46, 38, 30, 22, 14, 6,
+ 64, 56, 48, 40, 32, 24, 16, 8,
+ 57, 49, 41, 33, 25, 17, 9, 1,
+ 59, 51, 43, 35, 27, 19, 11, 3,
+ 61, 53, 45, 37, 29, 21, 13, 5,
+ 63, 55, 47, 39, 31, 23, 15, 7
+};
+
+static uchar perm4[48] = { 32, 1, 2, 3, 4, 5,
+ 4, 5, 6, 7, 8, 9,
+ 8, 9, 10, 11, 12, 13,
+ 12, 13, 14, 15, 16, 17,
+ 16, 17, 18, 19, 20, 21,
+ 20, 21, 22, 23, 24, 25,
+ 24, 25, 26, 27, 28, 29,
+ 28, 29, 30, 31, 32, 1
+};
+
+static uchar perm5[32] = { 16, 7, 20, 21,
+ 29, 12, 28, 17,
+ 1, 15, 23, 26,
+ 5, 18, 31, 10,
+ 2, 8, 24, 14,
+ 32, 27, 3, 9,
+ 19, 13, 30, 6,
+ 22, 11, 4, 25
+};
+
+static uchar perm6[64] = { 40, 8, 48, 16, 56, 24, 64, 32,
+ 39, 7, 47, 15, 55, 23, 63, 31,
+ 38, 6, 46, 14, 54, 22, 62, 30,
+ 37, 5, 45, 13, 53, 21, 61, 29,
+ 36, 4, 44, 12, 52, 20, 60, 28,
+ 35, 3, 43, 11, 51, 19, 59, 27,
+ 34, 2, 42, 10, 50, 18, 58, 26,
+ 33, 1, 41, 9, 49, 17, 57, 25
+};
+
+static uchar sc[16] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 };
+
+static uchar sbox[8][4][16] = {
+ {{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7},
+ {0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8},
+ {4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0},
+ {15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}},
+
+ {{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10},
+ {3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5},
+ {0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15},
+ {13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}},
+
+ {{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8},
+ {13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1},
+ {13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7},
+ {1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}},
+
+ {{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15},
+ {13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9},
+ {10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4},
+ {3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}},
+
+ {{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9},
+ {14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6},
+ {4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14},
+ {11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}},
+
+ {{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11},
+ {10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8},
+ {9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6},
+ {4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}},
+
+ {{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1},
+ {13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6},
+ {1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2},
+ {6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}},
+
+ {{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7},
+ {1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2},
+ {7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8},
+ {2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}}
+};
+
+static void
+permute(char *out, char *in, uchar * p, int n)
+{
+ int i;
+ for (i = 0; i < n; i++)
+ out[i] = in[p[i] - 1];
+}
+
+static void
+lshift(char *d, int count, int n)
+{
+ char out[64];
+ int i;
+ for (i = 0; i < n; i++)
+ out[i] = d[(i + count) % n];
+ for (i = 0; i < n; i++)
+ d[i] = out[i];
+}
+
+static void
+concat(char *out, char *in1, char *in2, int l1, int l2)
+{
+ while (l1--)
+ *out++ = *in1++;
+ while (l2--)
+ *out++ = *in2++;
+}
+
+static void
+xor(char *out, char *in1, char *in2, int n)
+{
+ int i;
+ for (i = 0; i < n; i++)
+ out[i] = in1[i] ^ in2[i];
+}
+
+static void
+dohash(char *out, char *in, char *key, int forw)
+{
+ int i, j, k;
+ char *pk1;
+ char c[28];
+ char d[28];
+ char *cd;
+ char ki[16][48];
+ char *pd1;
+ char l[32], r[32];
+ char *rl;
+
+ /* Have to reduce stack usage */
+ pk1 = kmalloc(56+56+64+64,GFP_KERNEL);
+ if(pk1 == NULL)
+ return;
+
+ cd = pk1 + 56;
+ pd1= cd + 56;
+ rl = pd1 + 64;
+
+ permute(pk1, key, perm1, 56);
+
+ for (i = 0; i < 28; i++)
+ c[i] = pk1[i];
+ for (i = 0; i < 28; i++)
+ d[i] = pk1[i + 28];
+
+ for (i = 0; i < 16; i++) {
+ lshift(c, sc[i], 28);
+ lshift(d, sc[i], 28);
+
+ concat(cd, c, d, 28, 28);
+ permute(ki[i], cd, perm2, 48);
+ }
+
+ permute(pd1, in, perm3, 64);
+
+ for (j = 0; j < 32; j++) {
+ l[j] = pd1[j];
+ r[j] = pd1[j + 32];
+ }
+
+ for (i = 0; i < 16; i++) {
+ char *er; /* er[48] */
+ char *erk; /* erk[48] */
+ char b[8][6];
+ char *cb; /* cb[32] */
+ char *pcb; /* pcb[32] */
+ char *r2; /* r2[32] */
+
+ er = kmalloc(48+48+32+32+32, GFP_KERNEL);
+ if(er == NULL) {
+ kfree(pk1);
+ return;
+ }
+ erk = er+48;
+ cb = erk+48;
+ pcb = cb+32;
+ r2 = pcb+32;
+
+ permute(er, r, perm4, 48);
+
+ xor(erk, er, ki[forw ? i : 15 - i], 48);
+
+ for (j = 0; j < 8; j++)
+ for (k = 0; k < 6; k++)
+ b[j][k] = erk[j * 6 + k];
+
+ for (j = 0; j < 8; j++) {
+ int m, n;
+ m = (b[j][0] << 1) | b[j][5];
+
+ n = (b[j][1] << 3) | (b[j][2] << 2) | (b[j][3] <<
+ 1) | b[j][4];
+
+ for (k = 0; k < 4; k++)
+ b[j][k] =
+ (sbox[j][m][n] & (1 << (3 - k))) ? 1 : 0;
+ }
+
+ for (j = 0; j < 8; j++)
+ for (k = 0; k < 4; k++)
+ cb[j * 4 + k] = b[j][k];
+ permute(pcb, cb, perm5, 32);
+
+ xor(r2, l, pcb, 32);
+
+ for (j = 0; j < 32; j++)
+ l[j] = r[j];
+
+ for (j = 0; j < 32; j++)
+ r[j] = r2[j];
+
+ kfree(er);
+ }
+
+ concat(rl, r, l, 32, 32);
+
+ permute(out, rl, perm6, 64);
+ kfree(pk1);
+}
+
+static void
+str_to_key(unsigned char *str, unsigned char *key)
+{
+ int i;
+
+ key[0] = str[0] >> 1;
+ key[1] = ((str[0] & 0x01) << 6) | (str[1] >> 2);
+ key[2] = ((str[1] & 0x03) << 5) | (str[2] >> 3);
+ key[3] = ((str[2] & 0x07) << 4) | (str[3] >> 4);
+ key[4] = ((str[3] & 0x0F) << 3) | (str[4] >> 5);
+ key[5] = ((str[4] & 0x1F) << 2) | (str[5] >> 6);
+ key[6] = ((str[5] & 0x3F) << 1) | (str[6] >> 7);
+ key[7] = str[6] & 0x7F;
+ for (i = 0; i < 8; i++) {
+ key[i] = (key[i] << 1);
+ }
+}
+
+static void
+smbhash(unsigned char *out, unsigned char *in, unsigned char *key, int forw)
+{
+ int i;
+ char *outb; /* outb[64] */
+ char *inb; /* inb[64] */
+ char *keyb; /* keyb[64] */
+ unsigned char key2[8];
+
+ outb = kmalloc(64 * 3,GFP_KERNEL);
+ if(outb == NULL)
+ return;
+
+ inb = outb + 64;
+ keyb = inb + 64;
+
+ str_to_key(key, key2);
+
+ for (i = 0; i < 64; i++) {
+ inb[i] = (in[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0;
+ keyb[i] = (key2[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0;
+ outb[i] = 0;
+ }
+
+ dohash(outb, inb, keyb, forw);
+
+ for (i = 0; i < 8; i++) {
+ out[i] = 0;
+ }
+
+ for (i = 0; i < 64; i++) {
+ if (outb[i])
+ out[i / 8] |= (1 << (7 - (i % 8)));
+ }
+ kfree(outb);
+}
+
+void
+E_P16(unsigned char *p14, unsigned char *p16)
+{
+ unsigned char sp8[8] =
+ { 0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
+ smbhash(p16, sp8, p14, 1);
+ smbhash(p16 + 8, sp8, p14 + 7, 1);
+}
+
+void
+E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24)
+{
+ smbhash(p24, c8, p21, 1);
+ smbhash(p24 + 8, c8, p21 + 7, 1);
+ smbhash(p24 + 16, c8, p21 + 14, 1);
+}
+
+void
+D_P16(unsigned char *p14, unsigned char *in, unsigned char *out)
+{
+ smbhash(out, in, p14, 0);
+ smbhash(out + 8, in + 8, p14 + 7, 0);
+}
+
+void
+E_old_pw_hash(unsigned char *p14, unsigned char *in, unsigned char *out)
+{
+ smbhash(out, in, p14, 1);
+ smbhash(out + 8, in + 8, p14 + 7, 1);
+}
+
+void
+cred_hash1(unsigned char *out, unsigned char *in, unsigned char *key)
+{
+ unsigned char buf[8];
+
+ smbhash(buf, in, key, 1);
+ smbhash(out, buf, key + 9, 1);
+}
+
+void
+cred_hash2(unsigned char *out, unsigned char *in, unsigned char *key)
+{
+ unsigned char buf[8];
+ static unsigned char key2[8];
+
+ smbhash(buf, in, key, 1);
+ key2[0] = key[7];
+ smbhash(out, buf, key2, 1);
+}
+
+void
+cred_hash3(unsigned char *out, unsigned char *in, unsigned char *key, int forw)
+{
+ static unsigned char key2[8];
+
+ smbhash(out, in, key, forw);
+ key2[0] = key[7];
+ smbhash(out + 8, in + 8, key2, forw);
+}
diff --git a/release/src/linux/linux/fs/cifs/smbencrypt.c b/release/src/linux/linux/fs/cifs/smbencrypt.c
new file mode 100644
index 00000000..18329601
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/smbencrypt.c
@@ -0,0 +1,295 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB parameters and setup
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+ Modified by Jeremy Allison 1995.
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2002-2003
+ Modified by Steve French (sfrench@us.ibm.com) 2002-2003
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/random.h>
+#include "cifs_unicode.h"
+#include "cifspdu.h"
+#include "md5.h"
+#include "cifs_debug.h"
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+/* following came from the other byteorder.h to avoid include conflicts */
+#define CVAL(buf,pos) (((unsigned char *)(buf))[pos])
+#define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8)
+#define SSVAL(buf,pos,val) SSVALX((buf),(pos),((__u16)(val)))
+
+/*The following definitions come from lib/md4.c */
+
+void mdfour(unsigned char *out, unsigned char *in, int n);
+
+/*The following definitions come from libsmb/smbdes.c */
+
+void E_P16(unsigned char *p14, unsigned char *p16);
+void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24);
+void D_P16(unsigned char *p14, unsigned char *in, unsigned char *out);
+void E_old_pw_hash(unsigned char *p14, unsigned char *in, unsigned char *out);
+void cred_hash1(unsigned char *out, unsigned char *in, unsigned char *key);
+void cred_hash2(unsigned char *out, unsigned char *in, unsigned char *key);
+void cred_hash3(unsigned char *out, unsigned char *in, unsigned char *key,
+ int forw);
+
+/*The following definitions come from libsmb/smbencrypt.c */
+
+void SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24);
+void E_md4hash(const unsigned char *passwd, unsigned char *p16);
+void nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16]);
+void SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8,
+ unsigned char p24[24]);
+void NTLMSSPOWFencrypt(unsigned char passwd[8],
+ unsigned char *ntlmchalresp, unsigned char p24[24]);
+void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24);
+int decode_pw_buffer(char in_buffer[516], char *new_pwrd,
+ int new_pwrd_size, __u32 * new_pw_len);
+
+/*
+ This implements the X/Open SMB password encryption
+ It takes a password, a 8 byte "crypt key" and puts 24 bytes of
+ encrypted password into p24 */
+/* Note that password must be uppercased and null terminated */
+void
+SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24)
+{
+ unsigned char p14[15], p21[21];
+
+ memset(p21, '\0', 21);
+ memset(p14, '\0', 14);
+ strncpy((char *) p14, (char *) passwd, 14);
+
+/* strupper((char *)p14); *//* BB at least uppercase the easy range */
+ E_P16(p14, p21);
+
+ SMBOWFencrypt(p21, c8, p24);
+
+ memset(p14,0,15);
+ memset(p21,0,21);
+}
+
+/* Routines for Windows NT MD4 Hash functions. */
+static int
+_my_wcslen(__u16 * str)
+{
+ int len = 0;
+ while (*str++ != 0)
+ len++;
+ return len;
+}
+
+/*
+ * Convert a string into an NT UNICODE string.
+ * Note that regardless of processor type
+ * this must be in intel (little-endian)
+ * format.
+ */
+
+static int
+_my_mbstowcs(__u16 * dst, const unsigned char *src, int len)
+{ /* not a very good conversion routine - change/fix */
+ int i;
+ __u16 val;
+
+ for (i = 0; i < len; i++) {
+ val = *src;
+ SSVAL(dst, 0, val);
+ dst++;
+ src++;
+ if (val == 0)
+ break;
+ }
+ return i;
+}
+
+/*
+ * Creates the MD4 Hash of the users password in NT UNICODE.
+ */
+
+void
+E_md4hash(const unsigned char *passwd, unsigned char *p16)
+{
+ int len;
+ __u16 wpwd[129];
+
+ /* Password cannot be longer than 128 characters */
+ if(passwd) {
+ len = strlen((char *) passwd);
+ if (len > 128) {
+ len = 128;
+ }
+ /* Password must be converted to NT unicode */
+ _my_mbstowcs(wpwd, passwd, len);
+ } else
+ len = 0;
+
+ wpwd[len] = 0; /* Ensure string is null terminated */
+ /* Calculate length in bytes */
+ len = _my_wcslen(wpwd) * sizeof (__u16);
+
+ mdfour(p16, (unsigned char *) wpwd, len);
+ memset(wpwd,0,129 * 2);
+}
+
+/* Does both the NT and LM owfs of a user's password */
+void
+nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16])
+{
+ char passwd[514];
+
+ memset(passwd, '\0', 514);
+ if (strlen(pwd) < 513)
+ strcpy(passwd, pwd);
+ else
+ memcpy(passwd, pwd, 512);
+ /* Calculate the MD4 hash (NT compatible) of the password */
+ memset(nt_p16, '\0', 16);
+ E_md4hash(passwd, nt_p16);
+
+ /* Mangle the passwords into Lanman format */
+ passwd[14] = '\0';
+/* strupper(passwd); */
+
+ /* Calculate the SMB (lanman) hash functions of the password */
+
+ memset(p16, '\0', 16);
+ E_P16((unsigned char *) passwd, (unsigned char *) p16);
+
+ /* clear out local copy of user's password (just being paranoid). */
+ memset(passwd, '\0', sizeof (passwd));
+}
+
+/* Does the NTLMv2 owfs of a user's password */
+void
+ntv2_owf_gen(const unsigned char owf[16], const char *user_n,
+ const char *domain_n, unsigned char kr_buf[16],
+ const struct nls_table *nls_codepage)
+{
+ wchar_t * user_u;
+ wchar_t * dom_u;
+ int user_l, domain_l;
+ struct HMACMD5Context ctx;
+
+ /* might as well do one alloc to hold both (user_u and dom_u) */
+ user_u = kmalloc(2048 * sizeof(wchar_t),GFP_KERNEL);
+ if(user_u == NULL)
+ return;
+ dom_u = user_u + 1024;
+
+ /* push_ucs2(NULL, user_u, user_n, (user_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER);
+ push_ucs2(NULL, dom_u, domain_n, (domain_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER); */
+
+ /* BB user and domain may need to be uppercased */
+ user_l = cifs_strtoUCS(user_u, user_n, 511, nls_codepage);
+ domain_l = cifs_strtoUCS(dom_u, domain_n, 511, nls_codepage);
+
+ user_l++; /* trailing null */
+ domain_l++;
+
+ hmac_md5_init_limK_to_64(owf, 16, &ctx);
+ hmac_md5_update((const unsigned char *) user_u, user_l * 2, &ctx);
+ hmac_md5_update((const unsigned char *) dom_u, domain_l * 2, &ctx);
+ hmac_md5_final(kr_buf, &ctx);
+
+ kfree(user_u);
+}
+
+/* Does the des encryption from the NT or LM MD4 hash. */
+void
+SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8,
+ unsigned char p24[24])
+{
+ unsigned char p21[21];
+
+ memset(p21, '\0', 21);
+
+ memcpy(p21, passwd, 16);
+ E_P24(p21, c8, p24);
+}
+
+/* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */
+void
+NTLMSSPOWFencrypt(unsigned char passwd[8],
+ unsigned char *ntlmchalresp, unsigned char p24[24])
+{
+ unsigned char p21[21];
+
+ memset(p21, '\0', 21);
+ memcpy(p21, passwd, 8);
+ memset(p21 + 8, 0xbd, 8);
+
+ E_P24(p21, ntlmchalresp, p24);
+}
+
+/* Does the NT MD4 hash then des encryption. */
+
+void
+SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24)
+{
+ unsigned char p21[21];
+
+ memset(p21, '\0', 21);
+
+ E_md4hash(passwd, p21);
+ SMBOWFencrypt(p21, c8, p24);
+}
+
+/* Does the md5 encryption from the NT hash for NTLMv2. */
+void
+SMBOWFencrypt_ntv2(const unsigned char kr[16],
+ const struct data_blob * srv_chal,
+ const struct data_blob * cli_chal, unsigned char resp_buf[16])
+{
+ struct HMACMD5Context ctx;
+
+ hmac_md5_init_limK_to_64(kr, 16, &ctx);
+ hmac_md5_update(srv_chal->data, srv_chal->length, &ctx);
+ hmac_md5_update(cli_chal->data, cli_chal->length, &ctx);
+ hmac_md5_final(resp_buf, &ctx);
+}
+
+void
+SMBsesskeygen_ntv2(const unsigned char kr[16],
+ const unsigned char *nt_resp, __u8 sess_key[16])
+{
+ struct HMACMD5Context ctx;
+
+ hmac_md5_init_limK_to_64(kr, 16, &ctx);
+ hmac_md5_update(nt_resp, 16, &ctx);
+ hmac_md5_final((unsigned char *) sess_key, &ctx);
+}
+
+void
+SMBsesskeygen_ntv1(const unsigned char kr[16],
+ const unsigned char *nt_resp, __u8 sess_key[16])
+{
+ mdfour((unsigned char *) sess_key, (unsigned char *) kr, 16);
+}
diff --git a/release/src/linux/linux/fs/cifs/smberr.c b/release/src/linux/linux/fs/cifs/smberr.c
new file mode 100644
index 00000000..f408b42b
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/smberr.c
@@ -0,0 +1,240 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Copyright (C) Andrew Tridgell 1998
+ Copyright (C) Steve French (sfrench@us.ibm.com) 2002
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+include "smberr.h"
+#define NO_SYSLOG
+/* error code stuff - put together by Merik Karman
+ merik@blackadder.dsh.oz.au */
+ typedef const struct {
+ char *name;
+ int code;
+ char *message;
+ int posix_code;
+} err_code_struct;
+
+/* Dos Error Messages */
+err_code_struct dos_msgs[] = {
+ {"ERRbadfunc", ERRbadfunc, "Invalid function.", -EINVAL},
+ {"ERRbadfile", ERRbadfile, "File not found.", -ENOENT},
+ {"ERRbadpath", ERRbadpath, "Directory invalid.", -ENOENT},
+ {"ERRnofids", ERRnofids, "No file descriptors available", -EMFILE},
+ {"ERRnoaccess", ERRnoaccess, "Access denied.", -EACCES},
+ {"ERRbadfid", ERRbadfid, "Invalid file handle.", -EBADF},
+ {"ERRbadmcb", 7, "Memory control blocks destroyed.", -EIO},
+ {"ERRnomem", ERRnomem,
+ "Insufficient server memory to perform the requested function.",
+ -ENOMEM},
+ {"ERRbadmem", ERRbadmem, "Invalid memory block address.", -EFAULT},
+ {"ERRbadenv", ERRbadenv, "Invalid environment.", -EFAULT},
+ {"ERRbadformat", 11, "Invalid format.", -EINVAL},
+ {"ERRbadaccess", ERRbadaccess, "Invalid open mode." - EACCES},
+ {"ERRbaddata", ERRbaddata, "Invalid data.", -EIO},
+ {"ERR", ERRres, "reserved.", -EIO},
+ {"ERRbaddrive", ERRbaddrive, "Invalid drive specified.", -ENXIO},
+ {"ERRremcd", ERRremcd,
+ "A Delete Directory request attempted to remove the server's current directory.",
+ -EIO},
+ {"ERRdiffdevice", ERRdiffdevice, "Not same device.", -EXDEV},
+ {"ERRnofiles", ERRnofiles, "A File Search command can find no more files matching the specified criteria.", -ENOENT}, /* Note: must map to zero manually in some places such as readdir */
+ {"ERRbadshare", ERRbadshare,
+ "The sharing mode specified for an Open conflicts with existing FIDs on the file.",
+ -EXTBSY},
+ {"ERRlock", ERRlock,
+ "A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process.",
+ -EACCES},
+ {"ERRunsup", ERRunsup, "The operation is unsupported", -EINVAL},
+ {"ERRnosuchshare", ERRnosuchshare,
+ "You specified an invalid share name", -ENXIO},
+ {"ERRfilexists", ERRfilexists,
+ "The file named in a Create Directory, Make New File or Link request already exists.",
+ -EEXIST},
+ {"ERRinvalidname", ERRinvalidname, "Invalid name", -ENOENT},
+ {"ERRdiskfull", ERRdiskfull, "Disk full", -ENOSPC}
+
+ {"ERRmoredata", ERRmoredata,
+ "There is more data to be returned.",},
+ {"ERRinvgroup", 2455, "Invalid workgroup (try the -W option)"},
+ {NULL, -1, NULL, -EIO}
+};
+
+/* Server Error Messages */
+err_code_struct server_msgs[] = {
+ {"ERRerror", 1, "Non-specific error code."},
+ {"ERRbadpw", 2,
+ "Bad password - name/password pair in a Tree Connect or Session Setup are invalid."},
+ {"ERRbadtype", 3, "reserved."},
+ {"ERRaccess", 4,
+ "The requester does not have the necessary access rights within the specified context for the requested function. The context is defined by the TID or the UID."},
+ {"ERRinvnid", 5,
+ "The tree ID (TID) specified in a command was invalid."},
+ {"ERRinvnetname", 6, "Invalid network name in tree connect."},
+ {"ERRinvdevice", 7,
+ "Invalid device - printer request made to non-printer connection or non-printer request made to printer connection."},
+ {"ERRqfull", 49,
+ "Print queue full (files) -- returned by open print file."},
+ {"ERRqtoobig", 50, "Print queue full -- no space."},
+ {"ERRqeof", 51, "EOF on print queue dump."},
+ {"ERRinvpfid", 52, "Invalid print file FID."},
+ {"ERRsmbcmd", 64,
+ "The server did not recognize the command received."},
+ {"ERRsrverror", 65,
+ "The server encountered an internal error, e.g., system file unavailable."},
+ {"ERRfilespecs", 67,
+ "The file handle (FID) and pathname parameters contained an invalid combination of values."},
+ {"ERRreserved", 68, "reserved."},
+ {"ERRbadpermits", 69,
+ "The access permissions specified for a file or directory are not a valid combination. The server cannot set the requested attribute."},
+ {"ERRreserved", 70, "reserved."},
+ {"ERRsetattrmode", 71,
+ "The attribute mode in the Set File Attribute request is invalid."},
+ {"ERRpaused", 81, "Server is paused."},
+ {"ERRmsgoff", 82, "Not receiving messages."},
+ {"ERRnoroom", 83, "No room to buffer message."},
+ {"ERRrmuns", 87, "Too many remote user names."},
+ {"ERRtimeout", 88, "Operation timed out."},
+ {"ERRnoresource", 89,
+ "No resources currently available for request."},
+ {"ERRtoomanyuids", 90, "Too many UIDs active on this session."},
+ {"ERRbaduid", 91,
+ "The UID is not known as a valid ID on this session."},
+ {"ERRusempx", 250, "Temp unable to support Raw, use MPX mode."},
+ {"ERRusestd", 251,
+ "Temp unable to support Raw, use standard read/write."},
+ {"ERRcontmpx", 252, "Continue in MPX mode."},
+ {"ERRreserved", 253, "reserved."},
+ {"ERRreserved", 254, "reserved."},
+ {"ERRnosupport", 0xFFFF, "Function not supported."},
+ {NULL, -1, NULL}
+};
+
+/* Hard Error Messages */
+err_code_struct hard_msgs[] = {
+ {"ERRnowrite", 19,
+ "Attempt to write on write-protected diskette."},
+ {"ERRbadunit", 20, "Unknown unit."},
+ {"ERRnotready", 21, "Drive not ready."},
+ {"ERRbadcmd", 22, "Unknown command."},
+ {"ERRdata", 23, "Data error (CRC)."},
+ {"ERRbadreq", 24, "Bad request structure length."},
+ {"ERRseek", 25, "Seek error."},
+ {"ERRbadmedia", 26, "Unknown media type."},
+ {"ERRbadsector", 27, "Sector not found."},
+ {"ERRnopaper", 28, "Printer out of paper."},
+ {"ERRwrite", 29, "Write fault."},
+ {"ERRread", 30, "Read fault."},
+ {"ERRgeneral", 31, "General failure."},
+ {"ERRbadshare", 32, "An open conflicts with an existing open."},
+ {"ERRlock", 33,
+ "A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."},
+ {"ERRwrongdisk", 34, "The wrong disk was found in a drive."},
+ {"ERRFCBUnavail", 35, "No FCBs are available to process request."},
+ {"ERRsharebufexc", 36, "A sharing buffer has been exceeded."},
+ {NULL, -1, NULL}
+};
+
+
+const struct {
+ int code;
+ char *class;
+ err_code_struct *err_msgs;
+} err_classes[] = {
+ {
+ 0, "SUCCESS", NULL}, {
+ 0x01, "ERRDOS", dos_msgs}, {
+ 0x02, "ERRSRV", server_msgs}, {
+ 0x03, "ERRHRD", hard_msgs}, {
+ 0x04, "ERRXOS", NULL}, {
+ 0xE1, "ERRRMX1", NULL}, {
+ 0xE2, "ERRRMX2", NULL}, {
+ 0xE3, "ERRRMX3", NULL}, {
+ 0xFF, "ERRCMD", NULL}, {
+-1, NULL, NULL}};
+
+
+/****************************************************************************
+return a SMB error string from a SMB buffer
+****************************************************************************/
+char *smb_dos_errstr(char *inbuf)
+{
+ static pstring ret;
+ int class = CVAL(inbuf, smb_rcls);
+ int num = SVAL(inbuf, smb_err);
+ int i, j;
+
+ for (i = 0; err_classes[i].class; i++)
+ if (err_classes[i].code == class) {
+ if (err_classes[i].err_msgs) {
+ err_code_struct *err =
+ err_classes[i].err_msgs;
+ for (j = 0; err[j].name; j++)
+ if (num == err[j].code) {
+ if (DEBUGLEVEL > 0)
+ slprintf(ret,
+ sizeof
+ (ret) - 1,
+ "%s - %s (%s)",
+ err_classes
+ [i].class,
+ err[j].
+ name,
+ err[j].
+ message);
+ else
+ slprintf(ret,
+ sizeof
+ (ret) - 1,
+ "%s - %s",
+ err_classes
+ [i].class,
+ err[j].
+ name);
+ return ret;
+ }
+ }
+
+ slprintf(ret, sizeof(ret) - 1, "%s - %d",
+ err_classes[i].class, num);
+ return ret;
+ }
+
+ slprintf(ret, sizeof(ret) - 1, "Error: Unknown error (%d,%d)",
+ class, num);
+ return (ret);
+}
+
+
+/*****************************************************************************
+ returns an WERROR error message.
+ *****************************************************************************/
+char *werror_str(WERROR status)
+{
+ static fstring msg;
+ slprintf(msg, sizeof(msg), "WIN32 code 0x%08x", W_ERROR_V(status));
+ return msg;
+}
+
+
+/*****************************************************************************
+map a unix errno to a win32 error
+ *****************************************************************************/
+WERROR map_werror_from_unix(int error)
+{
+ NTSTATUS status = map_nt_error_from_unix(error);
+ return ntstatus_to_werror(status);
+}
diff --git a/release/src/linux/linux/fs/cifs/smberr.h b/release/src/linux/linux/fs/cifs/smberr.h
new file mode 100644
index 00000000..25a39bf3
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/smberr.h
@@ -0,0 +1,113 @@
+/*
+ * fs/cifs/smberr.h
+ *
+ * Copyright (c) International Business Machines Corp., 2002
+ * Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ * See Error Codes section of the SNIA CIFS Specification
+ * for more information
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define SUCCESS 0 /* The request was successful. */
+#define ERRDOS 0x01 /* Error is from the core DOS operating system set */
+#define ERRSRV 0x02 /* Error is generated by the file server daemon */
+#define ERRHRD 0x03 /* Error is a hardware error. */
+#define ERRCMD 0xFF /* Command was not in the "SMB" format. */
+
+/* The following error codes may be generated with the SUCCESS error class.*/
+
+#define SUCCESS 0 /* The request was successful. */
+
+/* The following error codes may be generated with the ERRDOS error class.*/
+
+#define ERRbadfunc 1 /* Invalid function. The server did not recognize or could not perform a system call generated by the server, e.g., set the DIRECTORY attribute on a data file, invalid seek mode. */
+#define ERRbadfile 2 /*File not found. The last component of a file's pathname could not be found. */
+#define ERRbadpath 3 /* Directory invalid. A directory component in a pathname could not be found. */
+#define ERRnofids 4 /* Too many open files. The server has no file handles available. */
+#define ERRnoaccess 5 /* Access denied, the client's context does not permit the requested function. This includes the following conditions: invalid rename command, write to Fid open for read only, read on Fid open for write only, attempt to delete a non-empty directory */
+#define ERRbadfid 6 /* Invalid file handle. The file handle specified was not recognized by the server. */
+#define ERRbadmcb 7 /* Memory control blocks destroyed. */
+#define ERRnomem 8 /* Insufficient server memory to perform the requested function. */
+#define ERRbadmem 9 /* Invalid memory block address. */
+#define ERRbadenv 10 /* Invalid environment. */
+#define ERRbadformat 11 /* Invalid format. */
+#define ERRbadaccess 12 /* Invalid open mode. */
+#define ERRbaddata 13 /* Invalid data (generated only by IOCTL calls within the server). */
+#define ERRbaddrive 15 /* Invalid drive specified. */
+#define ERRremcd 16 /* A Delete Directory request attempted to remove the server's current directory. */
+#define ERRdiffdevice 17 /* Not same device (e.g., a cross volume rename was attempted */
+#define ERRnofiles 18 /* A File Search command can find no more files matching the specified criteria. */
+#define ERRgeneral 31
+#define ERRbadshare 32 /* The sharing mode specified for an Open conflicts with existing FIDs on the file. */
+#define ERRlock 33 /* A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process. */
+#define ERRunsup 50
+#define ERRnosuchshare 67
+#define ERRfilexists 80 /* The file named in the request already exists. */
+#define ERRinvparm 87
+#define ERRdiskfull 112
+#define ERRinvname 123
+#define ERRdirnotempty 145
+#define ERRnotlocked 158
+#define ERRalreadyexists 183
+#define ERRbadpipe 230
+#define ERRpipebusy 231
+#define ERRpipeclosing 232
+#define ERRnotconnected 233
+#define ERRmoredata 234
+#define ErrQuota 0x200 /* The operation would cause a quota limit to be exceeded. */
+#define ErrNotALink 0x201 /* A link operation was performed on a pathname that
+ was not a link. */
+
+/* Following error codes may be generated with the ERRSRV error
+class.*/
+
+#define ERRerror 1 /* Non-specific error code. It is returned under the following conditions: resource other than disk space exhausted (e.g. TIDs), first SMB command was not negotiate, multiple negotiates attempted, and internal server error. */
+#define ERRbadpw 2 /* Bad password - name/password pair in a TreeConnect or Session Setup are invalid. */
+#define ERRbadtype 3 /* used for indicating DFS referral needed */
+#define ERRaccess 4 /* The client does not have the necessary access rights within the specified context for requested function. */
+#define ERRinvtid 5 /* The Tid specified in a command was invalid. */
+#define ERRinvnetname 6 /* Invalid network name in tree connect. */
+#define ERRinvdevice 7 /* Invalid device - printer request made to non-printer connection or non-printer request made to printer connection. */
+#define ERRqfull 49 /* Print queue full (files) -- returned by open print file. */
+#define ERRqtoobig 50 /* Print queue full -- no space. */
+#define ERRqeof 51 /* EOF on print queue dump */
+#define ERRinvpfid 52 /* Invalid print file FID. */
+#define ERRsmbcmd 64 /* The server did not recognize the command received. */
+#define ERRsrverror 65 /* The server encountered an internal error, e.g., system file unavailable. */
+#define ERRbadBID 66 /* (obsolete) */
+#define ERRfilespecs 67 /* The Fid and pathname parameters contained an invalid combination of values. */
+#define ERRbadLink 68 /* (obsolete) */
+#define ERRbadpermits 69 /* The access permissions specified for a file or directory are not a valid combination. */
+#define ERRbadPID 70
+#define ERRsetattrmode 71 /* attribute (mode) is invalid */
+#define ERRpaused 81 /* Server is paused */
+#define ERRmsgoff 82 /* reserved - messaging off */
+#define ERRnoroom 83 /* reserved - no room for message */
+#define ERRrmuns 87 /* reserved - too many remote names */
+#define ERRtimeout 88 /* operation timed out */
+#define ERRnoresource 89 /* No resources available for request */
+#define ERRtoomanyuids 90 /* Too many UIDs active on this session */
+#define ERRbaduid 91 /* The UID is not known as a valid user */
+#define ERRusempx 250 /* temporarily unable to use raw */
+#define ERRusestd 251 /* temporarily unable to use either raw or mpx */
+#define ERR_NOTIFY_ENUM_DIR 1024
+#define ERRaccountexpired 2239
+#define ERRbadclient 2240
+#define ERRbadLogonTime 2241
+#define ERRpasswordExpired 2242
+#define ERRnetlogonNotStarted 2455
+#define ERRnosupport 0xFFFF
diff --git a/release/src/linux/linux/fs/cifs/transport.c b/release/src/linux/linux/fs/cifs/transport.c
new file mode 100644
index 00000000..4092aea7
--- /dev/null
+++ b/release/src/linux/linux/fs/cifs/transport.c
@@ -0,0 +1,434 @@
+/*
+ * fs/cifs/transport.c
+ *
+ * Copyright (C) International Business Machines Corp., 2002,2004
+ * Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/wait.h>
+#include <linux/net.h>
+#include <linux/version.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_debug.h"
+
+extern kmem_cache_t *cifs_mid_cachep;
+extern kmem_cache_t *cifs_oplock_cachep;
+
+struct mid_q_entry *
+AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
+{
+ struct mid_q_entry *temp;
+
+ if (ses == NULL) {
+ cERROR(1, ("Null session passed in to AllocMidQEntry "));
+ return NULL;
+ }
+ if (ses->server == NULL) {
+ cERROR(1, ("Null TCP session in AllocMidQEntry"));
+ return NULL;
+ }
+
+ temp = (struct mid_q_entry *) kmem_cache_alloc(cifs_mid_cachep,
+ SLAB_KERNEL);
+ if (temp == NULL)
+ return temp;
+ else {
+ memset(temp, 0, sizeof (struct mid_q_entry));
+ temp->mid = smb_buffer->Mid; /* always LE */
+ temp->pid = current->pid;
+ temp->command = smb_buffer->Command;
+ cFYI(1, ("For smb_command %d", temp->command));
+ do_gettimeofday(&temp->when_sent);
+ temp->ses = ses;
+ temp->tsk = current;
+ }
+
+ spin_lock(&GlobalMid_Lock);
+ list_add_tail(&temp->qhead, &ses->server->pending_mid_q);
+ atomic_inc(&midCount);
+ temp->midState = MID_REQUEST_ALLOCATED;
+ spin_unlock(&GlobalMid_Lock);
+ return temp;
+}
+
+void
+DeleteMidQEntry(struct mid_q_entry *midEntry)
+{
+ spin_lock(&GlobalMid_Lock);
+ midEntry->midState = MID_FREE;
+ list_del(&midEntry->qhead);
+ atomic_dec(&midCount);
+ spin_unlock(&GlobalMid_Lock);
+ cifs_buf_release(midEntry->resp_buf);
+ kmem_cache_free(cifs_mid_cachep, midEntry);
+}
+
+struct oplock_q_entry *
+AllocOplockQEntry(struct inode * pinode, __u16 fid, struct cifsTconInfo * tcon)
+{
+ struct oplock_q_entry *temp;
+ if ((pinode== NULL) || (tcon == NULL)) {
+ cERROR(1, ("Null parms passed to AllocOplockQEntry"));
+ return NULL;
+ }
+ temp = (struct oplock_q_entry *) kmem_cache_alloc(cifs_oplock_cachep,
+ SLAB_KERNEL);
+ if (temp == NULL)
+ return temp;
+ else {
+ temp->pinode = pinode;
+ temp->tcon = tcon;
+ temp->netfid = fid;
+ spin_lock(&GlobalMid_Lock);
+ list_add_tail(&temp->qhead, &GlobalOplock_Q);
+ spin_unlock(&GlobalMid_Lock);
+ }
+ return temp;
+
+}
+
+void DeleteOplockQEntry(struct oplock_q_entry * oplockEntry)
+{
+ spin_lock(&GlobalMid_Lock);
+ /* should we check if list empty first? */
+ list_del(&oplockEntry->qhead);
+ spin_unlock(&GlobalMid_Lock);
+ kmem_cache_free(cifs_oplock_cachep, oplockEntry);
+}
+
+int
+smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
+ unsigned int smb_buf_length, struct sockaddr *sin)
+{
+ int rc = 0;
+ int i = 0;
+ struct msghdr smb_msg;
+ struct iovec iov;
+ mm_segment_t temp_fs;
+
+ if(ssocket == NULL)
+ return -ENOTSOCK; /* BB eventually add reconnect code here */
+ iov.iov_base = smb_buffer;
+ iov.iov_len = smb_buf_length + 4;
+
+ smb_msg.msg_name = sin;
+ smb_msg.msg_namelen = sizeof (struct sockaddr);
+ smb_msg.msg_iov = &iov;
+ smb_msg.msg_iovlen = 1;
+ smb_msg.msg_control = NULL;
+ smb_msg.msg_controllen = 0;
+ smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
+
+ /* smb header is converted in header_assemble. bcc and rest of SMB word
+ area, and byte area if necessary, is converted to littleendian in
+ cifssmb.c and RFC1001 len is converted to bigendian in smb_send
+ Flags2 is converted in SendReceive */
+
+ smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
+ cFYI(1, ("Sending smb of length %d ", smb_buf_length));
+ dump_smb(smb_buffer, smb_buf_length + 4);
+
+ temp_fs = get_fs(); /* we must turn off socket api parm checking */
+ set_fs(get_ds());
+ while(iov.iov_len > 0) {
+ rc = sock_sendmsg(ssocket, &smb_msg, smb_buf_length + 4);
+ if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
+ i++;
+ if(i > 60) {
+ cERROR(1,
+ ("sends on sock %p stuck for 30 seconds",
+ ssocket));
+ rc = -EAGAIN;
+ break;
+ }
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(HZ/2);
+ continue;
+ }
+ if (rc < 0)
+ break;
+ iov.iov_base += rc;
+ iov.iov_len -= rc;
+ }
+ set_fs(temp_fs);
+
+ if (rc < 0) {
+ cERROR(1,("Error %d sending data on socket to server.", rc));
+ } else {
+ rc = 0;
+ }
+
+ return rc;
+}
+
+int
+SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
+ struct smb_hdr *in_buf, struct smb_hdr *out_buf,
+ int *pbytes_returned, const int long_op)
+{
+ int rc = 0;
+ unsigned int receive_len;
+ long timeout;
+ struct mid_q_entry *midQ;
+
+ if (ses == NULL) {
+ cERROR(1,("Null smb session"));
+ return -EIO;
+ }
+ if(ses->server == NULL) {
+ cERROR(1,("Null tcp session"));
+ return -EIO;
+ }
+
+ /* Ensure that we do not send more than 50 overlapping requests
+ to the same server. We may make this configurable later or
+ use ses->maxReq */
+ if(long_op == -1) {
+ /* oplock breaks must not be held up */
+ atomic_inc(&ses->server->inFlight);
+ } else {
+ spin_lock(&GlobalMid_Lock);
+ while(1) {
+ if(atomic_read(&ses->server->inFlight) >= CIFS_MAX_REQ){
+ spin_unlock(&GlobalMid_Lock);
+ wait_event(ses->server->request_q,
+ atomic_read(&ses->server->inFlight)
+ < CIFS_MAX_REQ);
+ spin_lock(&GlobalMid_Lock);
+ } else {
+ if(ses->server->tcpStatus == CifsExiting) {
+ spin_unlock(&GlobalMid_Lock);
+ return -ENOENT;
+ }
+
+ /* can not count locking commands against total since
+ they are allowed to block on server */
+
+ if(long_op < 3) {
+ /* update # of requests on the wire to server */
+ atomic_inc(&ses->server->inFlight);
+ }
+ spin_unlock(&GlobalMid_Lock);
+ break;
+ }
+ }
+ }
+ /* make sure that we sign in the same order that we send on this socket
+ and avoid races inside tcp sendmsg code that could cause corruption
+ of smb data */
+
+ down(&ses->server->tcpSem);
+
+ if (ses->server->tcpStatus == CifsExiting) {
+ rc = -ENOENT;
+ goto out_unlock;
+ } else if (ses->server->tcpStatus == CifsNeedReconnect) {
+ cFYI(1,("tcp session dead - return to caller to retry"));
+ rc = -EAGAIN;
+ goto out_unlock;
+ } else if (ses->status != CifsGood) {
+ /* check if SMB session is bad because we are setting it up */
+ if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
+ (in_buf->Command != SMB_COM_NEGOTIATE)) {
+ rc = -EAGAIN;
+ goto out_unlock;
+ } /* else ok - we are setting up session */
+ }
+ midQ = AllocMidQEntry(in_buf, ses);
+ if (midQ == NULL) {
+ up(&ses->server->tcpSem);
+ /* If not lock req, update # of requests on wire to server */
+ if(long_op < 3) {
+ atomic_dec(&ses->server->inFlight);
+ wake_up(&ses->server->request_q);
+ }
+ return -ENOMEM;
+ }
+
+ if (in_buf->smb_buf_length > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE - 4) {
+ up(&ses->server->tcpSem);
+ cERROR(1,
+ ("Illegal length, greater than maximum frame, %d ",
+ in_buf->smb_buf_length));
+ DeleteMidQEntry(midQ);
+ /* If not lock req, update # of requests on wire to server */
+ if(long_op < 3) {
+ atomic_dec(&ses->server->inFlight);
+ wake_up(&ses->server->request_q);
+ }
+ return -EIO;
+ }
+
+ if (in_buf->smb_buf_length > 12)
+ in_buf->Flags2 = cpu_to_le16(in_buf->Flags2);
+
+ rc = cifs_sign_smb(in_buf, ses, &midQ->sequence_number);
+
+ midQ->midState = MID_REQUEST_SUBMITTED;
+ rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
+ (struct sockaddr *) &(ses->server->addr.sockAddr));
+ if(rc < 0) {
+ DeleteMidQEntry(midQ);
+ up(&ses->server->tcpSem);
+ /* If not lock req, update # of requests on wire to server */
+ if(long_op < 3) {
+ atomic_dec(&ses->server->inFlight);
+ wake_up(&ses->server->request_q);
+ }
+ return rc;
+ } else
+ up(&ses->server->tcpSem);
+ if (long_op == -1)
+ goto cifs_no_response_exit;
+ else if (long_op == 2) /* writes past end of file can take looooong time */
+ timeout = 300 * HZ;
+ else if (long_op == 1)
+ timeout = 45 * HZ; /* should be greater than
+ servers oplock break timeout (about 43 seconds) */
+ else if (long_op > 2) {
+ timeout = MAX_SCHEDULE_TIMEOUT;
+ } else
+ timeout = 15 * HZ;
+ /* wait for 15 seconds or until woken up due to response arriving or
+ due to last connection to this server being unmounted */
+ if (signal_pending(current)) {
+ /* if signal pending do not hold up user for full smb timeout
+ but we still give response a change to complete */
+ if(midQ->midState & MID_REQUEST_SUBMITTED) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ timeout = sleep_on_timeout(&ses->server->response_q,2 * HZ);
+ }
+ } else { /* using normal timeout */
+ /* timeout = wait_event_interruptible_timeout(ses->server->response_q,
+ (midQ->midState & MID_RESPONSE_RECEIVED) ||
+ ((ses->server->tcpStatus != CifsGood) &&
+ (ses->server->tcpStatus != CifsNew)),
+ timeout); */
+ /* Can not allow user interrupts- wreaks havoc with performance */
+ if(midQ->midState & MID_REQUEST_SUBMITTED) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ timeout = sleep_on_timeout(&ses->server->response_q,timeout);
+ }
+ }
+
+ spin_lock(&GlobalMid_Lock);
+ if (midQ->resp_buf) {
+ spin_unlock(&GlobalMid_Lock);
+ receive_len = be32_to_cpu(midQ->resp_buf->smb_buf_length);
+ } else {
+ cERROR(1,("No response buffer"));
+ if(midQ->midState == MID_REQUEST_SUBMITTED) {
+ if(ses->server->tcpStatus == CifsExiting)
+ rc = -EHOSTDOWN;
+ else {
+ ses->server->tcpStatus = CifsNeedReconnect;
+ midQ->midState = MID_RETRY_NEEDED;
+ }
+ }
+
+ if (rc != -EHOSTDOWN) {
+ if(midQ->midState == MID_RETRY_NEEDED) {
+ rc = -EAGAIN;
+ cFYI(1,("marking request for retry"));
+ } else {
+ rc = -EIO;
+ }
+ }
+ spin_unlock(&GlobalMid_Lock);
+ DeleteMidQEntry(midQ);
+ /* If not lock req, update # of requests on wire to server */
+ if(long_op < 3) {
+ atomic_dec(&ses->server->inFlight);
+ wake_up(&ses->server->request_q);
+ }
+ return rc;
+ }
+
+ if (receive_len > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE) {
+ cERROR(1,
+ ("Frame too large received. Length: %d Xid: %d",
+ receive_len, xid));
+ rc = -EIO;
+ } else { /* rcvd frame is ok */
+
+ if (midQ->resp_buf && out_buf
+ && (midQ->midState == MID_RESPONSE_RECEIVED)) {
+ memcpy(out_buf, midQ->resp_buf,
+ receive_len +
+ 4 /* include 4 byte RFC1001 header */ );
+
+ dump_smb(out_buf, 92);
+ /* convert the length into a more usable form */
+ out_buf->smb_buf_length =
+ be32_to_cpu(out_buf->smb_buf_length);
+ if((out_buf->smb_buf_length > 24) &&
+ (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) {
+ rc = cifs_verify_signature(out_buf, ses->mac_signing_key,midQ->sequence_number); /* BB fix BB */
+ if(rc)
+ cFYI(1,("Unexpected signature received from server"));
+ }
+
+ if (out_buf->smb_buf_length > 12)
+ out_buf->Flags2 = le16_to_cpu(out_buf->Flags2);
+ if (out_buf->smb_buf_length > 28)
+ out_buf->Pid = le16_to_cpu(out_buf->Pid);
+ if (out_buf->smb_buf_length > 28)
+ out_buf->PidHigh =
+ le16_to_cpu(out_buf->PidHigh);
+
+ *pbytes_returned = out_buf->smb_buf_length;
+
+ /* BB special case reconnect tid and reconnect uid here? */
+ rc = map_smb_to_linux_error(out_buf);
+
+ /* convert ByteCount if necessary */
+ if (receive_len >=
+ sizeof (struct smb_hdr) -
+ 4 /* do not count RFC1001 header */ +
+ (2 * out_buf->WordCount) + 2 /* bcc */ )
+ BCC(out_buf) = le16_to_cpu(BCC(out_buf));
+ } else {
+ rc = -EIO;
+ cFYI(1,("Bad MID state? "));
+ }
+ }
+cifs_no_response_exit:
+ DeleteMidQEntry(midQ);
+
+ if(long_op < 3) {
+ atomic_dec(&ses->server->inFlight);
+ wake_up(&ses->server->request_q);
+ }
+
+ return rc;
+
+out_unlock:
+ up(&ses->server->tcpSem);
+ /* If not lock req, update # of requests on wire to server */
+ if(long_op < 3) {
+ atomic_dec(&ses->server->inFlight);
+ wake_up(&ses->server->request_q);
+ }
+
+ return rc;
+}
diff --git a/release/src/linux/linux/fs/nls/Config.in b/release/src/linux/linux/fs/nls/Config.in
index 0ac7ab5d..aff381db 100644
--- a/release/src/linux/linux/fs/nls/Config.in
+++ b/release/src/linux/linux/fs/nls/Config.in
@@ -11,6 +11,7 @@ fi
# msdos and Joliet want NLS
if [ "$CONFIG_JOLIET" = "y" -o "$CONFIG_FAT_FS" != "n" \
+ -o "$CONFIG_CIFS" != "n" \
-o "$CONFIG_NTFS_FS" != "n" -o "$CONFIG_NCPFS_NLS" = "y" \
-o "$CONFIG_SMB_NLS" = "y" -o "$CONFIG_JFS_FS" != "n" \
-o "$CONFIG_BEFS_FS" != "n" ]; then
diff --git a/release/src/linux/linux/fs/squashfs/LzmaDecode.c b/release/src/linux/linux/fs/squashfs/LzmaDecode.c
new file mode 100644
index 00000000..951700bd
--- /dev/null
+++ b/release/src/linux/linux/fs/squashfs/LzmaDecode.c
@@ -0,0 +1,663 @@
+/*
+ LzmaDecode.c
+ LZMA Decoder
+
+ LZMA SDK 4.05 Copyright (c) 1999-2004 Igor Pavlov (2004-08-25)
+ http://www.7-zip.org/
+
+ LZMA SDK is licensed under two licenses:
+ 1) GNU Lesser General Public License (GNU LGPL)
+ 2) Common Public License (CPL)
+ It means that you can select one of these two licenses and
+ follow rules of that license.
+
+ SPECIAL EXCEPTION:
+ Igor Pavlov, as the author of this code, expressly permits you to
+ statically or dynamically link your code (or bind by name) to the
+ interfaces of this file without subjecting your linked code to the
+ terms of the CPL or GNU LGPL. Any modifications or additions
+ to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#include "LzmaDecode.h"
+
+#ifndef Byte
+#define Byte unsigned char
+#endif
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+typedef struct _CRangeDecoder
+{
+ Byte *Buffer;
+ Byte *BufferLim;
+ UInt32 Range;
+ UInt32 Code;
+ #ifdef _LZMA_IN_CB
+ ILzmaInCallback *InCallback;
+ int Result;
+ #endif
+ int ExtraBytes;
+} CRangeDecoder;
+
+Byte RangeDecoderReadByte(CRangeDecoder *rd)
+{
+ if (rd->Buffer == rd->BufferLim)
+ {
+ #ifdef _LZMA_IN_CB
+ UInt32 size;
+ rd->Result = rd->InCallback->Read(rd->InCallback, &rd->Buffer, &size);
+ rd->BufferLim = rd->Buffer + size;
+ if (size == 0)
+ #endif
+ {
+ rd->ExtraBytes = 1;
+ return 0xFF;
+ }
+ }
+ return (*rd->Buffer++);
+}
+
+/* #define ReadByte (*rd->Buffer++) */
+#define ReadByte (RangeDecoderReadByte(rd))
+
+void RangeDecoderInit(CRangeDecoder *rd,
+ #ifdef _LZMA_IN_CB
+ ILzmaInCallback *inCallback
+ #else
+ Byte *stream, UInt32 bufferSize
+ #endif
+ )
+{
+ int i;
+ #ifdef _LZMA_IN_CB
+ rd->InCallback = inCallback;
+ rd->Buffer = rd->BufferLim = 0;
+ #else
+ rd->Buffer = stream;
+ rd->BufferLim = stream + bufferSize;
+ #endif
+ rd->ExtraBytes = 0;
+ rd->Code = 0;
+ rd->Range = (0xFFFFFFFF);
+ for(i = 0; i < 5; i++)
+ rd->Code = (rd->Code << 8) | ReadByte;
+}
+
+#define RC_INIT_VAR UInt32 range = rd->Range; UInt32 code = rd->Code;
+#define RC_FLUSH_VAR rd->Range = range; rd->Code = code;
+#define RC_NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | ReadByte; }
+
+UInt32 RangeDecoderDecodeDirectBits(CRangeDecoder *rd, int numTotalBits)
+{
+ RC_INIT_VAR
+ UInt32 result = 0;
+ int i;
+ for (i = numTotalBits; i > 0; i--)
+ {
+ /* UInt32 t; */
+ range >>= 1;
+
+ result <<= 1;
+ if (code >= range)
+ {
+ code -= range;
+ result |= 1;
+ }
+ /*
+ t = (code - range) >> 31;
+ t &= 1;
+ code -= range & (t - 1);
+ result = (result + result) | (1 - t);
+ */
+ RC_NORMALIZE
+ }
+ RC_FLUSH_VAR
+ return result;
+}
+
+int RangeDecoderBitDecode(CProb *prob, CRangeDecoder *rd)
+{
+ UInt32 bound = (rd->Range >> kNumBitModelTotalBits) * *prob;
+ if (rd->Code < bound)
+ {
+ rd->Range = bound;
+ *prob += (kBitModelTotal - *prob) >> kNumMoveBits;
+ if (rd->Range < kTopValue)
+ {
+ rd->Code = (rd->Code << 8) | ReadByte;
+ rd->Range <<= 8;
+ }
+ return 0;
+ }
+ else
+ {
+ rd->Range -= bound;
+ rd->Code -= bound;
+ *prob -= (*prob) >> kNumMoveBits;
+ if (rd->Range < kTopValue)
+ {
+ rd->Code = (rd->Code << 8) | ReadByte;
+ rd->Range <<= 8;
+ }
+ return 1;
+ }
+}
+
+#define RC_GET_BIT2(prob, mi, A0, A1) \
+ UInt32 bound = (range >> kNumBitModelTotalBits) * *prob; \
+ if (code < bound) \
+ { A0; range = bound; *prob += (kBitModelTotal - *prob) >> kNumMoveBits; mi <<= 1; } \
+ else \
+ { A1; range -= bound; code -= bound; *prob -= (*prob) >> kNumMoveBits; mi = (mi + mi) + 1; } \
+ RC_NORMALIZE
+
+#define RC_GET_BIT(prob, mi) RC_GET_BIT2(prob, mi, ; , ;)
+
+int RangeDecoderBitTreeDecode(CProb *probs, int numLevels, CRangeDecoder *rd)
+{
+ int mi = 1;
+ int i;
+ #ifdef _LZMA_LOC_OPT
+ RC_INIT_VAR
+ #endif
+ for(i = numLevels; i > 0; i--)
+ {
+ #ifdef _LZMA_LOC_OPT
+ CProb *prob = probs + mi;
+ RC_GET_BIT(prob, mi)
+ #else
+ mi = (mi + mi) + RangeDecoderBitDecode(probs + mi, rd);
+ #endif
+ }
+ #ifdef _LZMA_LOC_OPT
+ RC_FLUSH_VAR
+ #endif
+ return mi - (1 << numLevels);
+}
+
+int RangeDecoderReverseBitTreeDecode(CProb *probs, int numLevels, CRangeDecoder *rd)
+{
+ int mi = 1;
+ int i;
+ int symbol = 0;
+ #ifdef _LZMA_LOC_OPT
+ RC_INIT_VAR
+ #endif
+ for(i = 0; i < numLevels; i++)
+ {
+ #ifdef _LZMA_LOC_OPT
+ CProb *prob = probs + mi;
+ RC_GET_BIT2(prob, mi, ; , symbol |= (1 << i))
+ #else
+ int bit = RangeDecoderBitDecode(probs + mi, rd);
+ mi = mi + mi + bit;
+ symbol |= (bit << i);
+ #endif
+ }
+ #ifdef _LZMA_LOC_OPT
+ RC_FLUSH_VAR
+ #endif
+ return symbol;
+}
+
+Byte LzmaLiteralDecode(CProb *probs, CRangeDecoder *rd)
+{
+ int symbol = 1;
+ #ifdef _LZMA_LOC_OPT
+ RC_INIT_VAR
+ #endif
+ do
+ {
+ #ifdef _LZMA_LOC_OPT
+ CProb *prob = probs + symbol;
+ RC_GET_BIT(prob, symbol)
+ #else
+ symbol = (symbol + symbol) | RangeDecoderBitDecode(probs + symbol, rd);
+ #endif
+ }
+ while (symbol < 0x100);
+ #ifdef _LZMA_LOC_OPT
+ RC_FLUSH_VAR
+ #endif
+ return symbol;
+}
+
+Byte LzmaLiteralDecodeMatch(CProb *probs, CRangeDecoder *rd, Byte matchByte)
+{
+ int symbol = 1;
+ #ifdef _LZMA_LOC_OPT
+ RC_INIT_VAR
+ #endif
+ do
+ {
+ int bit;
+ int matchBit = (matchByte >> 7) & 1;
+ matchByte <<= 1;
+ #ifdef _LZMA_LOC_OPT
+ {
+ CProb *prob = probs + ((1 + matchBit) << 8) + symbol;
+ RC_GET_BIT2(prob, symbol, bit = 0, bit = 1)
+ }
+ #else
+ bit = RangeDecoderBitDecode(probs + ((1 + matchBit) << 8) + symbol, rd);
+ symbol = (symbol << 1) | bit;
+ #endif
+ if (matchBit != bit)
+ {
+ while (symbol < 0x100)
+ {
+ #ifdef _LZMA_LOC_OPT
+ CProb *prob = probs + symbol;
+ RC_GET_BIT(prob, symbol)
+ #else
+ symbol = (symbol + symbol) | RangeDecoderBitDecode(probs + symbol, rd);
+ #endif
+ }
+ break;
+ }
+ }
+ while (symbol < 0x100);
+ #ifdef _LZMA_LOC_OPT
+ RC_FLUSH_VAR
+ #endif
+ return symbol;
+}
+
+#define kNumPosBitsMax 4
+#define kNumPosStatesMax (1 << kNumPosBitsMax)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumMidBits 3
+#define kLenNumMidSymbols (1 << kLenNumMidBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define LenChoice 0
+#define LenChoice2 (LenChoice + 1)
+#define LenLow (LenChoice2 + 1)
+#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
+#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
+#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
+
+int LzmaLenDecode(CProb *p, CRangeDecoder *rd, int posState)
+{
+ if(RangeDecoderBitDecode(p + LenChoice, rd) == 0)
+ return RangeDecoderBitTreeDecode(p + LenLow +
+ (posState << kLenNumLowBits), kLenNumLowBits, rd);
+ if(RangeDecoderBitDecode(p + LenChoice2, rd) == 0)
+ return kLenNumLowSymbols + RangeDecoderBitTreeDecode(p + LenMid +
+ (posState << kLenNumMidBits), kLenNumMidBits, rd);
+ return kLenNumLowSymbols + kLenNumMidSymbols +
+ RangeDecoderBitTreeDecode(p + LenHigh, kLenNumHighBits, rd);
+}
+
+#define kNumStates 12
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#define kNumPosSlotBits 6
+#define kNumLenToPosStates 4
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+
+#define kMatchMinLen 2
+
+#define IsMatch 0
+#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
+#define IsRepG0 (IsRep + kNumStates)
+#define IsRepG1 (IsRepG0 + kNumStates)
+#define IsRepG2 (IsRepG1 + kNumStates)
+#define IsRep0Long (IsRepG2 + kNumStates)
+#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
+#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
+#define LenCoder (Align + kAlignTableSize)
+#define RepLenCoder (LenCoder + kNumLenProbs)
+#define Literal (RepLenCoder + kNumLenProbs)
+
+#if Literal != LZMA_BASE_SIZE
+StopCompilingDueBUG
+#endif
+
+#ifdef _LZMA_OUT_READ
+
+typedef struct _LzmaVarState
+{
+ CRangeDecoder RangeDecoder;
+ Byte *Dictionary;
+ UInt32 DictionarySize;
+ UInt32 DictionaryPos;
+ UInt32 GlobalPos;
+ UInt32 Reps[4];
+ int lc;
+ int lp;
+ int pb;
+ int State;
+ int PreviousIsMatch;
+ int RemainLen;
+} LzmaVarState;
+
+int LzmaDecoderInit(
+ unsigned char *buffer, UInt32 bufferSize,
+ int lc, int lp, int pb,
+ unsigned char *dictionary, UInt32 dictionarySize,
+ #ifdef _LZMA_IN_CB
+ ILzmaInCallback *inCallback
+ #else
+ unsigned char *inStream, UInt32 inSize
+ #endif
+ )
+{
+ LzmaVarState *vs = (LzmaVarState *)buffer;
+ CProb *p = (CProb *)(buffer + sizeof(LzmaVarState));
+ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + lp));
+ UInt32 i;
+ if (bufferSize < numProbs * sizeof(CProb) + sizeof(LzmaVarState))
+ return LZMA_RESULT_NOT_ENOUGH_MEM;
+ vs->Dictionary = dictionary;
+ vs->DictionarySize = dictionarySize;
+ vs->DictionaryPos = 0;
+ vs->GlobalPos = 0;
+ vs->Reps[0] = vs->Reps[1] = vs->Reps[2] = vs->Reps[3] = 1;
+ vs->lc = lc;
+ vs->lp = lp;
+ vs->pb = pb;
+ vs->State = 0;
+ vs->PreviousIsMatch = 0;
+ vs->RemainLen = 0;
+ dictionary[dictionarySize - 1] = 0;
+ for (i = 0; i < numProbs; i++)
+ p[i] = kBitModelTotal >> 1;
+ RangeDecoderInit(&vs->RangeDecoder,
+ #ifdef _LZMA_IN_CB
+ inCallback
+ #else
+ inStream, inSize
+ #endif
+ );
+ return LZMA_RESULT_OK;
+}
+
+int LzmaDecode(unsigned char *buffer,
+ unsigned char *outStream, UInt32 outSize,
+ UInt32 *outSizeProcessed)
+{
+ LzmaVarState *vs = (LzmaVarState *)buffer;
+ CProb *p = (CProb *)(buffer + sizeof(LzmaVarState));
+ CRangeDecoder rd = vs->RangeDecoder;
+ int state = vs->State;
+ int previousIsMatch = vs->PreviousIsMatch;
+ Byte previousByte;
+ UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3];
+ UInt32 nowPos = 0;
+ UInt32 posStateMask = (1 << (vs->pb)) - 1;
+ UInt32 literalPosMask = (1 << (vs->lp)) - 1;
+ int lc = vs->lc;
+ int len = vs->RemainLen;
+ UInt32 globalPos = vs->GlobalPos;
+
+ Byte *dictionary = vs->Dictionary;
+ UInt32 dictionarySize = vs->DictionarySize;
+ UInt32 dictionaryPos = vs->DictionaryPos;
+
+ if (len == -1)
+ {
+ *outSizeProcessed = 0;
+ return LZMA_RESULT_OK;
+ }
+
+ while(len > 0 && nowPos < outSize)
+ {
+ UInt32 pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos];
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ len--;
+ }
+ if (dictionaryPos == 0)
+ previousByte = dictionary[dictionarySize - 1];
+ else
+ previousByte = dictionary[dictionaryPos - 1];
+#else
+
+int LzmaDecode(
+ Byte *buffer, UInt32 bufferSize,
+ int lc, int lp, int pb,
+ #ifdef _LZMA_IN_CB
+ ILzmaInCallback *inCallback,
+ #else
+ unsigned char *inStream, UInt32 inSize,
+ #endif
+ unsigned char *outStream, UInt32 outSize,
+ UInt32 *outSizeProcessed)
+{
+ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + lp));
+ CProb *p = (CProb *)buffer;
+ CRangeDecoder rd;
+ UInt32 i;
+ int state = 0;
+ int previousIsMatch = 0;
+ Byte previousByte = 0;
+ UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
+ UInt32 nowPos = 0;
+ UInt32 posStateMask = (1 << pb) - 1;
+ UInt32 literalPosMask = (1 << lp) - 1;
+ int len = 0;
+ if (bufferSize < numProbs * sizeof(CProb))
+ return LZMA_RESULT_NOT_ENOUGH_MEM;
+ for (i = 0; i < numProbs; i++)
+ p[i] = kBitModelTotal >> 1;
+ RangeDecoderInit(&rd,
+ #ifdef _LZMA_IN_CB
+ inCallback
+ #else
+ inStream, inSize
+ #endif
+ );
+#endif
+
+ *outSizeProcessed = 0;
+ while(nowPos < outSize)
+ {
+ int posState = (int)(
+ (nowPos
+ #ifdef _LZMA_OUT_READ
+ + globalPos
+ #endif
+ )
+ & posStateMask);
+ #ifdef _LZMA_IN_CB
+ if (rd.Result != LZMA_RESULT_OK)
+ return rd.Result;
+ #endif
+ if (rd.ExtraBytes != 0)
+ return LZMA_RESULT_DATA_ERROR;
+ if (RangeDecoderBitDecode(p + IsMatch + (state << kNumPosBitsMax) + posState, &rd) == 0)
+ {
+ CProb *probs = p + Literal + (LZMA_LIT_SIZE *
+ (((
+ (nowPos
+ #ifdef _LZMA_OUT_READ
+ + globalPos
+ #endif
+ )
+ & literalPosMask) << lc) + (previousByte >> (8 - lc))));
+
+ if (state < 4) state = 0;
+ else if (state < 10) state -= 3;
+ else state -= 6;
+ if (previousIsMatch)
+ {
+ Byte matchByte;
+ #ifdef _LZMA_OUT_READ
+ UInt32 pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ matchByte = dictionary[pos];
+ #else
+ matchByte = outStream[nowPos - rep0];
+ #endif
+ previousByte = LzmaLiteralDecodeMatch(probs, &rd, matchByte);
+ previousIsMatch = 0;
+ }
+ else
+ previousByte = LzmaLiteralDecode(probs, &rd);
+ outStream[nowPos++] = previousByte;
+ #ifdef _LZMA_OUT_READ
+ dictionary[dictionaryPos] = previousByte;
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ #endif
+ }
+ else
+ {
+ previousIsMatch = 1;
+ if (RangeDecoderBitDecode(p + IsRep + state, &rd) == 1)
+ {
+ if (RangeDecoderBitDecode(p + IsRepG0 + state, &rd) == 0)
+ {
+ if (RangeDecoderBitDecode(p + IsRep0Long + (state << kNumPosBitsMax) + posState, &rd) == 0)
+ {
+ #ifdef _LZMA_OUT_READ
+ UInt32 pos;
+ #endif
+ if (
+ (nowPos
+ #ifdef _LZMA_OUT_READ
+ + globalPos
+ #endif
+ )
+ == 0)
+ return LZMA_RESULT_DATA_ERROR;
+ state = state < 7 ? 9 : 11;
+ #ifdef _LZMA_OUT_READ
+ pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ previousByte = dictionary[pos];
+ dictionary[dictionaryPos] = previousByte;
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ #else
+ previousByte = outStream[nowPos - rep0];
+ #endif
+ outStream[nowPos++] = previousByte;
+ continue;
+ }
+ }
+ else
+ {
+ UInt32 distance;
+ if(RangeDecoderBitDecode(p + IsRepG1 + state, &rd) == 0)
+ distance = rep1;
+ else
+ {
+ if(RangeDecoderBitDecode(p + IsRepG2 + state, &rd) == 0)
+ distance = rep2;
+ else
+ {
+ distance = rep3;
+ rep3 = rep2;
+ }
+ rep2 = rep1;
+ }
+ rep1 = rep0;
+ rep0 = distance;
+ }
+ len = LzmaLenDecode(p + RepLenCoder, &rd, posState);
+ state = state < 7 ? 8 : 11;
+ }
+ else
+ {
+ int posSlot;
+ rep3 = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+ state = state < 7 ? 7 : 10;
+ len = LzmaLenDecode(p + LenCoder, &rd, posState);
+ posSlot = RangeDecoderBitTreeDecode(p + PosSlot +
+ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) <<
+ kNumPosSlotBits), kNumPosSlotBits, &rd);
+ if (posSlot >= kStartPosModelIndex)
+ {
+ int numDirectBits = ((posSlot >> 1) - 1);
+ rep0 = ((2 | ((UInt32)posSlot & 1)) << numDirectBits);
+ if (posSlot < kEndPosModelIndex)
+ {
+ rep0 += RangeDecoderReverseBitTreeDecode(
+ p + SpecPos + rep0 - posSlot - 1, numDirectBits, &rd);
+ }
+ else
+ {
+ rep0 += RangeDecoderDecodeDirectBits(&rd,
+ numDirectBits - kNumAlignBits) << kNumAlignBits;
+ rep0 += RangeDecoderReverseBitTreeDecode(p + Align, kNumAlignBits, &rd);
+ }
+ }
+ else
+ rep0 = posSlot;
+ rep0++;
+ }
+ if (rep0 == (UInt32)(0))
+ {
+ /* it's for stream version */
+ len = -1;
+ break;
+ }
+ if (rep0 > nowPos
+ #ifdef _LZMA_OUT_READ
+ + globalPos
+ #endif
+ )
+ {
+ return LZMA_RESULT_DATA_ERROR;
+ }
+ len += kMatchMinLen;
+ do
+ {
+ #ifdef _LZMA_OUT_READ
+ UInt32 pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ previousByte = dictionary[pos];
+ dictionary[dictionaryPos] = previousByte;
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ #else
+ previousByte = outStream[nowPos - rep0];
+ #endif
+ outStream[nowPos++] = previousByte;
+ len--;
+ }
+ while(len > 0 && nowPos < outSize);
+ }
+ }
+
+ #ifdef _LZMA_OUT_READ
+ vs->RangeDecoder = rd;
+ vs->DictionaryPos = dictionaryPos;
+ vs->GlobalPos = globalPos + nowPos;
+ vs->Reps[0] = rep0;
+ vs->Reps[1] = rep1;
+ vs->Reps[2] = rep2;
+ vs->Reps[3] = rep3;
+ vs->State = state;
+ vs->PreviousIsMatch = previousIsMatch;
+ vs->RemainLen = len;
+ #endif
+
+ *outSizeProcessed = nowPos;
+ return LZMA_RESULT_OK;
+}
diff --git a/release/src/linux/linux/fs/squashfs/LzmaDecode.h b/release/src/linux/linux/fs/squashfs/LzmaDecode.h
new file mode 100644
index 00000000..f58944e3
--- /dev/null
+++ b/release/src/linux/linux/fs/squashfs/LzmaDecode.h
@@ -0,0 +1,100 @@
+/*
+ LzmaDecode.h
+ LZMA Decoder interface
+
+ LZMA SDK 4.05 Copyright (c) 1999-2004 Igor Pavlov (2004-08-25)
+ http://www.7-zip.org/
+
+ LZMA SDK is licensed under two licenses:
+ 1) GNU Lesser General Public License (GNU LGPL)
+ 2) Common Public License (CPL)
+ It means that you can select one of these two licenses and
+ follow rules of that license.
+
+ SPECIAL EXCEPTION:
+ Igor Pavlov, as the author of this code, expressly permits you to
+ statically or dynamically link your code (or bind by name) to the
+ interfaces of this file without subjecting your linked code to the
+ terms of the CPL or GNU LGPL. Any modifications or additions
+ to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#ifndef __LZMADECODE_H
+#define __LZMADECODE_H
+
+/* #define _LZMA_IN_CB */
+/* Use callback for input data */
+
+/* #define _LZMA_OUT_READ */
+/* Use read function for output data */
+
+/* #define _LZMA_PROB32 */
+/* It can increase speed on some 32-bit CPUs,
+ but memory usage will be doubled in that case */
+
+/* #define _LZMA_LOC_OPT */
+/* Enable local speed optimizations inside code */
+
+#ifndef UInt32
+#ifdef _LZMA_UINT32_IS_ULONG
+#define UInt32 unsigned long
+#else
+#define UInt32 unsigned int
+#endif
+#endif
+
+#ifdef _LZMA_PROB32
+#define CProb UInt32
+#else
+#define CProb unsigned short
+#endif
+
+#define LZMA_RESULT_OK 0
+#define LZMA_RESULT_DATA_ERROR 1
+#define LZMA_RESULT_NOT_ENOUGH_MEM 2
+
+#ifdef _LZMA_IN_CB
+typedef struct _ILzmaInCallback
+{
+ int (*Read)(void *object, unsigned char **buffer, UInt32 *bufferSize);
+} ILzmaInCallback;
+#endif
+
+#define LZMA_BASE_SIZE 1846
+#define LZMA_LIT_SIZE 768
+
+/*
+bufferSize = (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp)))* sizeof(CProb)
+bufferSize += 100 in case of _LZMA_OUT_READ
+by default CProb is unsigned short,
+but if specify _LZMA_PROB_32, CProb will be UInt32(unsigned int)
+*/
+
+#ifdef _LZMA_OUT_READ
+int LzmaDecoderInit(
+ unsigned char *buffer, UInt32 bufferSize,
+ int lc, int lp, int pb,
+ unsigned char *dictionary, UInt32 dictionarySize,
+ #ifdef _LZMA_IN_CB
+ ILzmaInCallback *inCallback
+ #else
+ unsigned char *inStream, UInt32 inSize
+ #endif
+);
+#endif
+
+int LzmaDecode(
+ unsigned char *buffer,
+ #ifndef _LZMA_OUT_READ
+ UInt32 bufferSize,
+ int lc, int lp, int pb,
+ #ifdef _LZMA_IN_CB
+ ILzmaInCallback *inCallback,
+ #else
+ unsigned char *inStream, UInt32 inSize,
+ #endif
+ #endif
+ unsigned char *outStream, UInt32 outSize,
+ UInt32 *outSizeProcessed);
+
+#endif
diff --git a/release/src/linux/linux/fs/squashfs/Makefile b/release/src/linux/linux/fs/squashfs/Makefile
index 0dcd8d17..367dbfc2 100644
--- a/release/src/linux/linux/fs/squashfs/Makefile
+++ b/release/src/linux/linux/fs/squashfs/Makefile
@@ -4,7 +4,11 @@
O_TARGET := squashfs.o
-obj-y := inode.o
+obj-y := inode.o squashfs2_0.o
+
+ifdef CONFIG_LZMA_FS_INFLATE
+obj-y += LzmaDecode.o
+endif
obj-m := $(O_TARGET)
diff --git a/release/src/linux/linux/fs/squashfs/inode.c b/release/src/linux/linux/fs/squashfs/inode.c
index 08193482..5c17f070 100644
--- a/release/src/linux/linux/fs/squashfs/inode.c
+++ b/release/src/linux/linux/fs/squashfs/inode.c
@@ -1,7 +1,11 @@
/*
* Squashfs - a compressed read only filesystem for Linux
*
- * Copyright (c) 2002, 2003, 2004 Phillip Lougher <plougher@users.sourceforge.net>
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006
+ * Phillip Lougher <phillip@lougher.org.uk>
+ *
+ * LZMA decompressor support added by Oleg I. Vdovikin
+ * Copyright (c) 2005 Oleg I.Vdovikin <oleg@cs.msu.su>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -16,39 +20,47 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- * Squashfs - a compressed read only filesystem for Linux
*
* inode.c
*/
-#define SQUASHFS_1_0_COMPATIBILITY
-
#include <linux/types.h>
#include <linux/squashfs_fs.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/fs.h>
+#include <linux/smp_lock.h>
#include <linux/locks.h>
#include <linux/init.h>
#include <linux/dcache.h>
-#include <asm/uaccess.h>
#include <linux/wait.h>
-#include <asm/semaphore.h>
#include <linux/zlib.h>
#include <linux/blkdev.h>
#include <linux/vmalloc.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+#include <linux/autoconf.h>
-#ifdef SQUASHFS_TRACE
-#define TRACE(s, args...) printk(KERN_NOTICE "SQUASHFS: "s, ## args)
-#else
-#define TRACE(s, args...) {}
+#include "squashfs.h"
+
+#ifdef CONFIG_LZMA_FS_INFLATE
+ #define SQUASHFS_LZMA
#endif
-#define ERROR(s, args...) printk(KERN_ERR "SQUASHFS error: "s, ## args)
+#ifdef SQUASHFS_LZMA
+#include "LzmaDecode.h"
+
+/* default LZMA settings, should be in sync with mksquashfs */
+#define LZMA_LC 3
+#define LZMA_LP 0
+#define LZMA_PB 2
+
+#define LZMA_WORKSPACE_SIZE ((LZMA_BASE_SIZE + \
+ (LZMA_LIT_SIZE << (LZMA_LC + LZMA_LP))) * sizeof(CProb))
+
+#endif
-#define SERROR(s, args...) if(!silent) printk(KERN_ERR "SQUASHFS error: "s, ## args)
-#define WARNING(s, args...) printk(KERN_WARNING "SQUASHFS: "s, ## args)
static struct super_block *squashfs_read_super(struct super_block *, void *, int);
static void squashfs_put_super(struct super_block *);
@@ -58,26 +70,16 @@ static int squashfs_readpage(struct file *file, struct page *page);
static int squashfs_readpage4K(struct file *file, struct page *page);
static int squashfs_readdir(struct file *, void *, filldir_t);
static struct dentry *squashfs_lookup(struct inode *, struct dentry *);
-static unsigned int read_data(struct super_block *s, char *buffer,
- unsigned int index, unsigned int length, int, unsigned int *next_index);
-static int squashfs_get_cached_block(struct super_block *s, char *buffer,
- unsigned int block, unsigned int offset, int length,
- unsigned int *next_block, unsigned int *next_offset);
-static struct inode *squashfs_iget(struct super_block *s, squashfs_inode inode);
-static unsigned int read_blocklist(struct inode *inode, int index, int readahead_blks,
- char *block_list, char **block_p, unsigned int *bsize);
-static void squashfs_put_super(struct super_block *s);
-
-#ifdef SQUASHFS_1_0_COMPATIBILITY
-static int squashfs_readpage_lessthan4K(struct file *file, struct page *page);
-static struct inode *squashfs_iget_1(struct super_block *s, squashfs_inode inode);
-static unsigned int read_blocklist_1(struct inode *inode, int index, int readahead_blks,
- char *block_list, char **block_p, unsigned int *bsize);
-#endif
-
-DECLARE_MUTEX(read_data_mutex);
+static struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode);
+static long long read_blocklist(struct inode *inode, int index,
+ int readahead_blks, char *block_list,
+ unsigned short **block_p, unsigned int *bsize);
+#ifdef SQUASHFS_LZMA
+static unsigned char lzma_workspace[LZMA_WORKSPACE_SIZE];
+#else
static z_stream stream;
+#endif
static DECLARE_FSTYPE_DEV(squashfs_fs_type, "squashfs", squashfs_read_super);
@@ -86,140 +88,161 @@ static unsigned char squashfs_filetype_table[] = {
};
static struct super_operations squashfs_ops = {
- statfs: squashfs_statfs,
- put_super: squashfs_put_super,
+ .statfs = squashfs_statfs,
+ .put_super = squashfs_put_super,
};
-static struct address_space_operations squashfs_symlink_aops = {
- readpage: squashfs_symlink_readpage
+SQSH_EXTERN struct address_space_operations squashfs_symlink_aops = {
+ .readpage = squashfs_symlink_readpage
};
-static struct address_space_operations squashfs_aops = {
- readpage: squashfs_readpage
+SQSH_EXTERN struct address_space_operations squashfs_aops = {
+ .readpage = squashfs_readpage
};
-static struct address_space_operations squashfs_aops_4K = {
- readpage: squashfs_readpage4K
+SQSH_EXTERN struct address_space_operations squashfs_aops_4K = {
+ .readpage = squashfs_readpage4K
};
-#ifdef SQUASHFS_1_0_COMPATIBILITY
-static struct address_space_operations squashfs_aops_lessthan4K = {
- readpage: squashfs_readpage_lessthan4K
-};
-#endif
-
static struct file_operations squashfs_dir_ops = {
- read: generic_read_dir,
- readdir: squashfs_readdir
+ .read = generic_read_dir,
+ .readdir = squashfs_readdir
};
static struct inode_operations squashfs_dir_inode_ops = {
- lookup: squashfs_lookup
+ .lookup = squashfs_lookup
};
+static struct buffer_head *get_block_length(struct super_block *s,
+ int *cur_index, int *offset, int *c_byte)
+{
+ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
+ unsigned short temp;
+ struct buffer_head *bh;
+
+ if (!(bh = sb_bread(s, *cur_index)))
+ goto out;
+
+ if (msblk->devblksize - *offset == 1) {
+ if (msblk->swap)
+ ((unsigned char *) &temp)[1] = *((unsigned char *)
+ (bh->b_data + *offset));
+ else
+ ((unsigned char *) &temp)[0] = *((unsigned char *)
+ (bh->b_data + *offset));
+ brelse(bh);
+ if (!(bh = sb_bread(s, ++(*cur_index))))
+ goto out;
+ if (msblk->swap)
+ ((unsigned char *) &temp)[0] = *((unsigned char *)
+ bh->b_data);
+ else
+ ((unsigned char *) &temp)[1] = *((unsigned char *)
+ bh->b_data);
+ *c_byte = temp;
+ *offset = 1;
+ } else {
+ if (msblk->swap) {
+ ((unsigned char *) &temp)[1] = *((unsigned char *)
+ (bh->b_data + *offset));
+ ((unsigned char *) &temp)[0] = *((unsigned char *)
+ (bh->b_data + *offset + 1));
+ } else {
+ ((unsigned char *) &temp)[0] = *((unsigned char *)
+ (bh->b_data + *offset));
+ ((unsigned char *) &temp)[1] = *((unsigned char *)
+ (bh->b_data + *offset + 1));
+ }
+ *c_byte = temp;
+ *offset += 2;
+ }
+
+ if (SQUASHFS_CHECK_DATA(msblk->sblk.flags)) {
+ if (*offset == msblk->devblksize) {
+ brelse(bh);
+ if (!(bh = sb_bread(s, ++(*cur_index))))
+ goto out;
+ *offset = 0;
+ }
+ if (*((unsigned char *) (bh->b_data + *offset)) !=
+ SQUASHFS_MARKER_BYTE) {
+ ERROR("Metadata block marker corrupt @ %x\n",
+ *cur_index);
+ brelse(bh);
+ goto out;
+ }
+ (*offset)++;
+ }
+ return bh;
+
+out:
+ return NULL;
+}
+
-static unsigned int read_data(struct super_block *s, char *buffer,
- unsigned int index, unsigned int length, int datablock, unsigned int *next_index)
+SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer,
+ long long index, unsigned int length,
+ long long *next_index)
{
- squashfs_sb_info *msBlk = &s->u.squashfs_sb;
- struct buffer_head *bh[((SQUASHFS_FILE_MAX_SIZE - 1) >> msBlk->devblksize_log2) + 2];
- unsigned int offset = index & ((1 << msBlk->devblksize_log2) - 1);
- unsigned int cur_index = index >> msBlk->devblksize_log2;
- int bytes, avail_bytes, b, k;
+ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
+ struct buffer_head *bh[((SQUASHFS_FILE_MAX_SIZE - 1) >>
+ msblk->devblksize_log2) + 2];
+ unsigned int offset = index & ((1 << msblk->devblksize_log2) - 1);
+ unsigned int cur_index = index >> msblk->devblksize_log2;
+ int bytes, avail_bytes, b = 0, k;
char *c_buffer;
unsigned int compressed;
unsigned int c_byte = length;
- if(c_byte) {
- bytes = msBlk->devblksize - offset;
- if(datablock) {
- c_buffer = (compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte)) ? msBlk->read_data : buffer;
- c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
- } else {
- c_buffer = (compressed = SQUASHFS_COMPRESSED(c_byte)) ? msBlk->read_data : buffer;
- c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
- }
+ if (c_byte) {
+ bytes = msblk->devblksize - offset;
+ compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte);
+ c_buffer = compressed ? msblk->read_data : buffer;
+ c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
- TRACE("Block @ 0x%x, %scompressed size %d\n", index, compressed ? "" : "un", (unsigned int) c_byte);
+ TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed
+ ? "" : "un", (unsigned int) c_byte);
- if(!(bh[0] = sb_getblk(s, cur_index)))
+ if (!(bh[0] = sb_getblk(s, cur_index)))
goto block_release;
- for(b = 1; bytes < c_byte; b++) {
- if(!(bh[b] = sb_getblk(s, ++cur_index)))
+
+ for (b = 1; bytes < c_byte; b++) {
+ if (!(bh[b] = sb_getblk(s, ++cur_index)))
goto block_release;
- bytes += msBlk->devblksize;
+ bytes += msblk->devblksize;
}
ll_rw_block(READ, b, bh);
} else {
- unsigned short temp;
- if(!(bh[0] = sb_bread(s, cur_index)))
+ if (!(bh[0] = get_block_length(s, &cur_index, &offset,
+ &c_byte)))
goto read_failure;
- if(msBlk->devblksize - offset == 1) {
- if(msBlk->swap)
- ((unsigned char *) &temp)[1] = *((unsigned char *) (bh[0]->b_data + offset));
- else
- ((unsigned char *) &temp)[0] = *((unsigned char *) (bh[0]->b_data + offset));
- brelse(bh[0]);
- if(!(bh[0] = sb_bread(s, ++cur_index)))
- goto read_failure;
- if(msBlk->swap)
- ((unsigned char *) &temp)[0] = *((unsigned char *) bh[0]->b_data);
- else
- ((unsigned char *) &temp)[1] = *((unsigned char *) bh[0]->b_data);
- c_byte = temp;
- offset = 1;
- }
- else {
- if(msBlk->swap) {
- unsigned short temp;
- ((unsigned char *) &temp)[1] = *((unsigned char *) (bh[0]->b_data + offset));
- ((unsigned char *) &temp)[0] = *((unsigned char *) (bh[0]->b_data + offset + 1));
- c_byte = temp;
- } else
- c_byte = *((unsigned short *) (bh[0]->b_data + offset));
- offset += 2;
- }
- if(SQUASHFS_CHECK_DATA(msBlk->sBlk.flags)) {
- if(offset == msBlk->devblksize) {
- brelse(bh[0]);
- if(!(bh[0] = sb_bread(s, ++cur_index)))
- goto read_failure;
- offset = 0;
- }
- if(*((unsigned char *) (bh[0]->b_data + offset)) != SQUASHFS_MARKER_BYTE) {
- ERROR("Metadata block marker corrupt @ %x\n", index);
- brelse(bh[0]);
- return 0;
- }
- offset ++;
- }
-
- bytes = msBlk->devblksize - offset;
- if(datablock) {
- c_buffer = (compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte)) ? msBlk->read_data : buffer;
- c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
- } else {
- c_buffer = (compressed = SQUASHFS_COMPRESSED(c_byte)) ? msBlk->read_data : buffer;
- c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
- }
+ bytes = msblk->devblksize - offset;
+ compressed = SQUASHFS_COMPRESSED(c_byte);
+ c_buffer = compressed ? msblk->read_data : buffer;
+ c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
- TRACE("Block @ 0x%x, %scompressed size %d\n", index, compressed ? "" : "un", (unsigned int) c_byte);
+ TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed
+ ? "" : "un", (unsigned int) c_byte);
- for(b = 1; bytes < c_byte; b++) {
- if(!(bh[b] = sb_getblk(s, ++cur_index)))
+ for (b = 1; bytes < c_byte; b++) {
+ if (!(bh[b] = sb_getblk(s, ++cur_index)))
goto block_release;
- bytes += msBlk->devblksize;
+ bytes += msblk->devblksize;
}
ll_rw_block(READ, b - 1, bh + 1);
}
- if(compressed)
- down(&read_data_mutex);
+ if (compressed)
+ down(&msblk->read_data_mutex);
- for(bytes = 0, k = 0; k < b; k++) {
- avail_bytes = (c_byte - bytes) > (msBlk->devblksize - offset) ? msBlk->devblksize - offset : c_byte - bytes;
+ for (bytes = 0, k = 0; k < b; k++) {
+ avail_bytes = (c_byte - bytes) > (msblk->devblksize - offset) ?
+ msblk->devblksize - offset :
+ c_byte - bytes;
wait_on_buffer(bh[k]);
+ if (!buffer_uptodate(bh[k]))
+ goto block_release;
memcpy(c_buffer + bytes, bh[k]->b_data + offset, avail_bytes);
bytes += avail_bytes;
offset = 0;
@@ -229,30 +252,46 @@ static unsigned int read_data(struct super_block *s, char *buffer,
/*
* uncompress block
*/
- if(compressed) {
+ if (compressed) {
int zlib_err;
+#ifdef SQUASHFS_LZMA
+ if ((zlib_err = LzmaDecode(lzma_workspace,
+ LZMA_WORKSPACE_SIZE, LZMA_LC, LZMA_LP, LZMA_PB,
+ c_buffer, c_byte, buffer, msblk->read_size, &bytes)) != LZMA_RESULT_OK)
+ {
+ ERROR("lzma returned unexpected result 0x%x\n", zlib_err);
+ bytes = 0;
+ }
+#else
stream.next_in = c_buffer;
stream.avail_in = c_byte;
stream.next_out = buffer;
- stream.avail_out = msBlk->read_size;
- if(((zlib_err = zlib_inflateInit(&stream)) != Z_OK) ||
- ((zlib_err = zlib_inflate(&stream, Z_FINISH)) != Z_STREAM_END) ||
- ((zlib_err = zlib_inflateEnd(&stream)) != Z_OK)) {
- ERROR("zlib_fs returned unexpected result 0x%x\n", zlib_err);
+ stream.avail_out = msblk->read_size;
+
+ if (((zlib_err = zlib_inflateInit(&stream)) != Z_OK) ||
+ ((zlib_err = zlib_inflate(&stream, Z_FINISH))
+ != Z_STREAM_END) || ((zlib_err =
+ zlib_inflateEnd(&stream)) != Z_OK)) {
+ ERROR("zlib_fs returned unexpected result 0x%x\n",
+ zlib_err);
bytes = 0;
} else
bytes = stream.total_out;
- up(&read_data_mutex);
+#endif
+
+ up(&msblk->read_data_mutex);
}
- if(next_index)
- *next_index = index + c_byte + (length ? 0 : (SQUASHFS_CHECK_DATA(msBlk->sBlk.flags) ? 3 : 2));
-
+ if (next_index)
+ *next_index = index + c_byte + (length ? 0 :
+ (SQUASHFS_CHECK_DATA(msblk->sblk.flags)
+ ? 3 : 2));
return bytes;
block_release:
- while(--b >= 0) brelse(bh[b]);
+ while (--b >= 0)
+ brelse(bh[b]);
read_failure:
ERROR("sb_bread failed reading block 0x%x\n", cur_index);
@@ -260,543 +299,668 @@ read_failure:
}
-static int squashfs_get_cached_block(struct super_block *s, char *buffer,
- unsigned int block, unsigned int offset, int length,
- unsigned int *next_block, unsigned int *next_offset)
+SQSH_EXTERN int squashfs_get_cached_block(struct super_block *s, char *buffer,
+ long long block, unsigned int offset,
+ int length, long long *next_block,
+ unsigned int *next_offset)
{
- squashfs_sb_info *msBlk = &s->u.squashfs_sb;
+ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
int n, i, bytes, return_length = length;
- unsigned int next_index;
+ long long next_index;
- TRACE("Entered squashfs_get_cached_block [%x:%x]\n", block, offset);
+ TRACE("Entered squashfs_get_cached_block [%llx:%x]\n", block, offset);
- for(;;) {
- for(i = 0; i < SQUASHFS_CACHED_BLKS; i++)
- if(msBlk->block_cache[i].block == block)
+ while ( 1 ) {
+ for (i = 0; i < SQUASHFS_CACHED_BLKS; i++)
+ if (msblk->block_cache[i].block == block)
break;
- down(&msBlk->block_cache_mutex);
- if(i == SQUASHFS_CACHED_BLKS) {
+ down(&msblk->block_cache_mutex);
+
+ if (i == SQUASHFS_CACHED_BLKS) {
/* read inode header block */
- for(i = msBlk->next_cache, n = SQUASHFS_CACHED_BLKS; n ; n --, i = (i + 1) % SQUASHFS_CACHED_BLKS)
- if(msBlk->block_cache[i].block != SQUASHFS_USED_BLK)
+ for (i = msblk->next_cache, n = SQUASHFS_CACHED_BLKS;
+ n ; n --, i = (i + 1) %
+ SQUASHFS_CACHED_BLKS)
+ if (msblk->block_cache[i].block !=
+ SQUASHFS_USED_BLK)
break;
- if(n == 0) {
- up(&msBlk->block_cache_mutex);
- sleep_on(&msBlk->waitq);
+
+ if (n == 0) {
+ wait_queue_t wait;
+
+ init_waitqueue_entry(&wait, current);
+ add_wait_queue(&msblk->waitq, &wait);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ up(&msblk->block_cache_mutex);
+ schedule();
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&msblk->waitq, &wait);
continue;
}
- msBlk->next_cache = (i + 1) % SQUASHFS_CACHED_BLKS;
-
- if(msBlk->block_cache[i].block == SQUASHFS_INVALID_BLK) {
- if(!(msBlk->block_cache[i].data = (unsigned char *)
- kmalloc(SQUASHFS_METADATA_SIZE, GFP_KERNEL))) {
- ERROR("Failed to allocate cache block\n");
- up(&msBlk->block_cache_mutex);
- return 0;
+ msblk->next_cache = (i + 1) % SQUASHFS_CACHED_BLKS;
+
+ if (msblk->block_cache[i].block ==
+ SQUASHFS_INVALID_BLK) {
+ if (!(msblk->block_cache[i].data =
+ kmalloc(SQUASHFS_METADATA_SIZE,
+ GFP_KERNEL))) {
+ ERROR("Failed to allocate cache"
+ "block\n");
+ up(&msblk->block_cache_mutex);
+ goto out;
}
}
- msBlk->block_cache[i].block = SQUASHFS_USED_BLK;
- up(&msBlk->block_cache_mutex);
- if(!(msBlk->block_cache[i].length = read_data(s, msBlk->block_cache[i].data, block, 0, 0,
- &next_index))) {
- ERROR("Unable to read cache block [%x:%x]\n", block, offset);
- return 0;
+ msblk->block_cache[i].block = SQUASHFS_USED_BLK;
+ up(&msblk->block_cache_mutex);
+
+ if (!(msblk->block_cache[i].length =
+ squashfs_read_data(s,
+ msblk->block_cache[i].data,
+ block, 0, &next_index))) {
+ ERROR("Unable to read cache block [%llx:%x]\n",
+ block, offset);
+ goto out;
}
- down(&msBlk->block_cache_mutex);
- wake_up(&msBlk->waitq);
- msBlk->block_cache[i].block = block;
- msBlk->block_cache[i].next_index = next_index;
- TRACE("Read cache block [%x:%x]\n", block, offset);
+
+ down(&msblk->block_cache_mutex);
+ wake_up(&msblk->waitq);
+ msblk->block_cache[i].block = block;
+ msblk->block_cache[i].next_index = next_index;
+ TRACE("Read cache block [%llx:%x]\n", block, offset);
}
- if(msBlk->block_cache[i].block != block) {
- up(&msBlk->block_cache_mutex);
+ if (msblk->block_cache[i].block != block) {
+ up(&msblk->block_cache_mutex);
continue;
}
- if((bytes = msBlk->block_cache[i].length - offset) >= length) {
- if(buffer)
- memcpy(buffer, msBlk->block_cache[i].data + offset, length);
- if(msBlk->block_cache[i].length - offset == length) {
- *next_block = msBlk->block_cache[i].next_index;
+ if ((bytes = msblk->block_cache[i].length - offset) >= length) {
+ if (buffer)
+ memcpy(buffer, msblk->block_cache[i].data +
+ offset, length);
+ if (msblk->block_cache[i].length - offset == length) {
+ *next_block = msblk->block_cache[i].next_index;
*next_offset = 0;
} else {
*next_block = block;
*next_offset = offset + length;
}
-
- up(&msBlk->block_cache_mutex);
- return return_length;
+ up(&msblk->block_cache_mutex);
+ goto finish;
} else {
- if(buffer) {
- memcpy(buffer, msBlk->block_cache[i].data + offset, bytes);
+ if (buffer) {
+ memcpy(buffer, msblk->block_cache[i].data +
+ offset, bytes);
buffer += bytes;
}
- block = msBlk->block_cache[i].next_index;
- up(&msBlk->block_cache_mutex);
+ block = msblk->block_cache[i].next_index;
+ up(&msblk->block_cache_mutex);
length -= bytes;
offset = 0;
}
}
+
+finish:
+ return return_length;
+out:
+ return 0;
}
-static int get_fragment_location(struct super_block *s, unsigned int fragment, unsigned int *fragment_start_block, unsigned int *fragment_size)
+static int get_fragment_location(struct super_block *s, unsigned int fragment,
+ long long *fragment_start_block,
+ unsigned int *fragment_size)
{
- squashfs_sb_info *msBlk = &s->u.squashfs_sb;
- unsigned int start_block = msBlk->fragment_index[SQUASHFS_FRAGMENT_INDEX(fragment)];
+ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
+ long long start_block =
+ msblk->fragment_index[SQUASHFS_FRAGMENT_INDEX(fragment)];
int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment);
- squashfs_fragment_entry fragment_entry;
+ struct squashfs_fragment_entry fragment_entry;
- if(msBlk->swap) {
- squashfs_fragment_entry sfragment_entry;
+ if (msblk->swap) {
+ struct squashfs_fragment_entry sfragment_entry;
- if(!squashfs_get_cached_block(s, (char *) &sfragment_entry, start_block, offset,
- sizeof(sfragment_entry), &start_block, &offset))
- return 0;
+ if (!squashfs_get_cached_block(s, (char *) &sfragment_entry,
+ start_block, offset,
+ sizeof(sfragment_entry), &start_block,
+ &offset))
+ goto out;
SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_entry, &sfragment_entry);
} else
- if(!squashfs_get_cached_block(s, (char *) &fragment_entry, start_block, offset,
- sizeof(fragment_entry), &start_block, &offset))
- return 0;
+ if (!squashfs_get_cached_block(s, (char *) &fragment_entry,
+ start_block, offset,
+ sizeof(fragment_entry), &start_block,
+ &offset))
+ goto out;
*fragment_start_block = fragment_entry.start_block;
*fragment_size = fragment_entry.size;
return 1;
+
+out:
+ return 0;
}
-void release_cached_fragment(squashfs_sb_info *msBlk, struct squashfs_fragment_cache *fragment)
+SQSH_EXTERN void release_cached_fragment(struct squashfs_sb_info *msblk, struct
+ squashfs_fragment_cache *fragment)
{
- down(&msBlk->fragment_mutex);
+ down(&msblk->fragment_mutex);
fragment->locked --;
- wake_up(&msBlk->fragment_wait_queue);
- up(&msBlk->fragment_mutex);
+ wake_up(&msblk->fragment_wait_queue);
+ up(&msblk->fragment_mutex);
}
-struct squashfs_fragment_cache *get_cached_fragment(struct super_block *s, unsigned int start_block, int length)
+SQSH_EXTERN struct squashfs_fragment_cache *get_cached_fragment(struct super_block
+ *s, long long start_block,
+ int length)
{
int i, n;
- squashfs_sb_info *msBlk = &s->u.squashfs_sb;
-
- for(;;) {
- down(&msBlk->fragment_mutex);
- for(i = 0; i < SQUASHFS_CACHED_FRAGMENTS && msBlk->fragment[i].block != start_block; i++);
- if(i == SQUASHFS_CACHED_FRAGMENTS) {
- for(i = msBlk->next_fragment, n = SQUASHFS_CACHED_FRAGMENTS;
- n && msBlk->fragment[i].locked; n--, i = (i + 1) % SQUASHFS_CACHED_FRAGMENTS);
-
- if(n == 0) {
- up(&msBlk->fragment_mutex);
- sleep_on(&msBlk->fragment_wait_queue);
+ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
+
+ while ( 1 ) {
+ down(&msblk->fragment_mutex);
+
+ for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS &&
+ msblk->fragment[i].block != start_block; i++);
+
+ if (i == SQUASHFS_CACHED_FRAGMENTS) {
+ for (i = msblk->next_fragment, n =
+ SQUASHFS_CACHED_FRAGMENTS; n &&
+ msblk->fragment[i].locked; n--, i = (i + 1) %
+ SQUASHFS_CACHED_FRAGMENTS);
+
+ if (n == 0) {
+ wait_queue_t wait;
+
+ init_waitqueue_entry(&wait, current);
+ add_wait_queue(&msblk->fragment_wait_queue,
+ &wait);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ up(&msblk->fragment_mutex);
+ schedule();
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&msblk->fragment_wait_queue,
+ &wait);
continue;
}
- msBlk->next_fragment = (msBlk->next_fragment + 1) % SQUASHFS_CACHED_FRAGMENTS;
+ msblk->next_fragment = (msblk->next_fragment + 1) %
+ SQUASHFS_CACHED_FRAGMENTS;
- if(msBlk->fragment[i].data == NULL)
- if(!(msBlk->fragment[i].data = (unsigned char *)
- kmalloc(SQUASHFS_FILE_MAX_SIZE, GFP_KERNEL))) {
- ERROR("Failed to allocate fragment cache block\n");
- up(&msBlk->fragment_mutex);
- return NULL;
+ if (msblk->fragment[i].data == NULL)
+ if (!(msblk->fragment[i].data = SQUASHFS_ALLOC
+ (SQUASHFS_FILE_MAX_SIZE))) {
+ ERROR("Failed to allocate fragment "
+ "cache block\n");
+ up(&msblk->fragment_mutex);
+ goto out;
}
- msBlk->fragment[i].block = SQUASHFS_INVALID_BLK;
- msBlk->fragment[i].locked = 1;
- up(&msBlk->fragment_mutex);
- if(!(msBlk->fragment[i].length = read_data(s, msBlk->fragment[i].data, start_block, length,
- 1, NULL))) {
- ERROR("Unable to read fragment cache block [%x]\n", start_block);
- msBlk->fragment[i].locked = 0;
- return NULL;
+ msblk->fragment[i].block = SQUASHFS_INVALID_BLK;
+ msblk->fragment[i].locked = 1;
+ up(&msblk->fragment_mutex);
+
+ if (!(msblk->fragment[i].length = squashfs_read_data(s,
+ msblk->fragment[i].data,
+ start_block, length, NULL))) {
+ ERROR("Unable to read fragment cache block "
+ "[%llx]\n", start_block);
+ msblk->fragment[i].locked = 0;
+ goto out;
}
- msBlk->fragment[i].block = start_block;
- TRACE("New fragment %d, start block %d, locked %d\n", i, msBlk->fragment[i].block, msBlk->fragment[i].locked);
- return &msBlk->fragment[i];
+
+ msblk->fragment[i].block = start_block;
+ TRACE("New fragment %d, start block %lld, locked %d\n",
+ i, msblk->fragment[i].block,
+ msblk->fragment[i].locked);
+ break;
}
- msBlk->fragment[i].locked ++;
- up(&msBlk->fragment_mutex);
-
- TRACE("Got fragment %d, start block %d, locked %d\n", i, msBlk->fragment[i].block, msBlk->fragment[i].locked);
- return &msBlk->fragment[i];
+ msblk->fragment[i].locked++;
+ up(&msblk->fragment_mutex);
+ TRACE("Got fragment %d, start block %lld, locked %d\n", i,
+ msblk->fragment[i].block,
+ msblk->fragment[i].locked);
+ break;
}
+
+ return &msblk->fragment[i];
+
+out:
+ return NULL;
}
-#ifdef SQUASHFS_1_0_COMPATIBILITY
-static struct inode *squashfs_iget_1(struct super_block *s, squashfs_inode inode)
+static struct inode *squashfs_new_inode(struct super_block *s,
+ struct squashfs_base_inode_header *inodeb)
{
+ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
struct inode *i = new_inode(s);
- squashfs_sb_info *msBlk = &s->u.squashfs_sb;
- squashfs_super_block *sBlk = &msBlk->sBlk;
- unsigned int block = SQUASHFS_INODE_BLK(inode) + sBlk->inode_table_start;
- unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
- unsigned int next_block, next_offset;
- squashfs_base_inode_header_1 inodeb;
-
- TRACE("Entered squashfs_iget_1\n");
- if(msBlk->swap) {
- squashfs_base_inode_header_1 sinodeb;
+ if (i) {
+ i->i_ino = inodeb->inode_number;
+ i->i_mtime = inodeb->mtime;
+ i->i_atime = inodeb->mtime;
+ i->i_ctime = inodeb->mtime;
+ i->i_uid = msblk->uid[inodeb->uid];
+ i->i_mode = inodeb->mode;
+ i->i_size = 0;
+ if (inodeb->guid == SQUASHFS_GUIDS)
+ i->i_gid = i->i_uid;
+ else
+ i->i_gid = msblk->guid[inodeb->guid];
+ }
- if(!squashfs_get_cached_block(s, (char *) &sinodeb, block, offset,
- sizeof(sinodeb), &next_block, &next_offset))
- goto failed_read;
- SQUASHFS_SWAP_BASE_INODE_HEADER_1(&inodeb, &sinodeb, sizeof(sinodeb));
- } else
- if(!squashfs_get_cached_block(s, (char *) &inodeb, block, offset,
- sizeof(inodeb), &next_block, &next_offset))
- goto failed_read;
+ return i;
+}
- i->i_nlink = 1;
- i->i_mtime = sBlk->mkfs_time;
- i->i_atime = sBlk->mkfs_time;
- i->i_ctime = sBlk->mkfs_time;
+static struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode)
+{
+ struct inode *i;
+ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
+ struct squashfs_super_block *sblk = &msblk->sblk;
+ long long block = SQUASHFS_INODE_BLK(inode) +
+ sblk->inode_table_start;
+ unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
+ long long next_block;
+ unsigned int next_offset;
+ union squashfs_inode_header id, sid;
+ struct squashfs_base_inode_header *inodeb = &id.base,
+ *sinodeb = &sid.base;
- if(inodeb.inode_type != SQUASHFS_IPC_TYPE)
- i->i_uid = msBlk->uid[((inodeb.inode_type - 1) / SQUASHFS_TYPES) * 16 + inodeb.uid];
- i->i_ino = SQUASHFS_MK_VFS_INODE(block - sBlk->inode_table_start, offset);
+ TRACE("Entered squashfs_iget\n");
- i->i_mode = inodeb.mode;
+ if (msblk->swap) {
+ if (!squashfs_get_cached_block(s, (char *) sinodeb, block,
+ offset, sizeof(*sinodeb), &next_block,
+ &next_offset))
+ goto failed_read;
+ SQUASHFS_SWAP_BASE_INODE_HEADER(inodeb, sinodeb,
+ sizeof(*sinodeb));
+ } else
+ if (!squashfs_get_cached_block(s, (char *) inodeb, block,
+ offset, sizeof(*inodeb), &next_block,
+ &next_offset))
+ goto failed_read;
- switch(inodeb.inode_type == SQUASHFS_IPC_TYPE ? SQUASHFS_IPC_TYPE : (inodeb.inode_type - 1) % SQUASHFS_TYPES + 1) {
+ switch(inodeb->inode_type) {
case SQUASHFS_FILE_TYPE: {
- squashfs_reg_inode_header_1 inodep;
-
- if(msBlk->swap) {
- squashfs_reg_inode_header_1 sinodep;
-
- if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep),
- &next_block, &next_offset))
+ unsigned int frag_size;
+ long long frag_blk;
+ struct squashfs_reg_inode_header *inodep = &id.reg;
+ struct squashfs_reg_inode_header *sinodep = &sid.reg;
+
+ if (msblk->swap) {
+ if (!squashfs_get_cached_block(s, (char *)
+ sinodep, block, offset,
+ sizeof(*sinodep), &next_block,
+ &next_offset))
goto failed_read;
- SQUASHFS_SWAP_REG_INODE_HEADER_1(&inodep, &sinodep);
+ SQUASHFS_SWAP_REG_INODE_HEADER(inodep, sinodep);
} else
- if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep),
- &next_block, &next_offset))
+ if (!squashfs_get_cached_block(s, (char *)
+ inodep, block, offset,
+ sizeof(*inodep), &next_block,
+ &next_offset))
goto failed_read;
- i->i_size = inodep.file_size;
+ frag_blk = SQUASHFS_INVALID_BLK;
+ if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
+ !get_fragment_location(s,
+ inodep->fragment, &frag_blk, &frag_size))
+ goto failed_read;
+
+ if((i = squashfs_new_inode(s, inodeb)) == NULL)
+ goto failed_read1;
+
+ i->i_nlink = 1;
+ i->i_size = inodep->file_size;
i->i_fop = &generic_ro_fops;
- if(sBlk->block_size > 4096)
+ i->i_mode |= S_IFREG;
+ i->i_blocks = ((i->i_size - 1) >> 9) + 1;
+ i->i_blksize = PAGE_CACHE_SIZE;
+ SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
+ SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
+ SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
+ SQUASHFS_I(i)->start_block = inodep->start_block;
+ SQUASHFS_I(i)->u.s1.block_list_start = next_block;
+ SQUASHFS_I(i)->offset = next_offset;
+ if (sblk->block_size > 4096)
i->i_data.a_ops = &squashfs_aops;
- else if(sBlk->block_size == 4096)
- i->i_data.a_ops = &squashfs_aops_4K;
else
- i->i_data.a_ops = &squashfs_aops_lessthan4K;
+ i->i_data.a_ops = &squashfs_aops_4K;
+
+ TRACE("File inode %x:%x, start_block %llx, "
+ "block_list_start %llx, offset %x\n",
+ SQUASHFS_INODE_BLK(inode), offset,
+ inodep->start_block, next_block,
+ next_offset);
+ break;
+ }
+ case SQUASHFS_LREG_TYPE: {
+ unsigned int frag_size;
+ long long frag_blk;
+ struct squashfs_lreg_inode_header *inodep = &id.lreg;
+ struct squashfs_lreg_inode_header *sinodep = &sid.lreg;
+
+ if (msblk->swap) {
+ if (!squashfs_get_cached_block(s, (char *)
+ sinodep, block, offset,
+ sizeof(*sinodep), &next_block,
+ &next_offset))
+ goto failed_read;
+ SQUASHFS_SWAP_LREG_INODE_HEADER(inodep, sinodep);
+ } else
+ if (!squashfs_get_cached_block(s, (char *)
+ inodep, block, offset,
+ sizeof(*inodep), &next_block,
+ &next_offset))
+ goto failed_read;
+
+ frag_blk = SQUASHFS_INVALID_BLK;
+ if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
+ !get_fragment_location(s,
+ inodep->fragment, &frag_blk, &frag_size))
+ goto failed_read;
+
+ if((i = squashfs_new_inode(s, inodeb)) == NULL)
+ goto failed_read1;
+
+ i->i_nlink = inodep->nlink;
+ i->i_size = inodep->file_size;
+ i->i_fop = &generic_ro_fops;
i->i_mode |= S_IFREG;
- i->i_mtime = inodep.mtime;
- i->i_atime = inodep.mtime;
- i->i_ctime = inodep.mtime;
i->i_blocks = ((i->i_size - 1) >> 9) + 1;
i->i_blksize = PAGE_CACHE_SIZE;
- i->u.squashfs_i.fragment_start_block = SQUASHFS_INVALID_BLK;
- i->u.squashfs_i.fragment_offset = 0;
- i->u.squashfs_i.start_block = inodep.start_block;
- i->u.squashfs_i.block_list_start = next_block;
- i->u.squashfs_i.offset = next_offset;
- TRACE("File inode %x:%x, start_block %x, block_list_start %x, offset %x\n",
- SQUASHFS_INODE_BLK(inode), offset, inodep.start_block, next_block, next_offset);
+ SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
+ SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
+ SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
+ SQUASHFS_I(i)->start_block = inodep->start_block;
+ SQUASHFS_I(i)->u.s1.block_list_start = next_block;
+ SQUASHFS_I(i)->offset = next_offset;
+ if (sblk->block_size > 4096)
+ i->i_data.a_ops = &squashfs_aops;
+ else
+ i->i_data.a_ops = &squashfs_aops_4K;
+
+ TRACE("File inode %x:%x, start_block %llx, "
+ "block_list_start %llx, offset %x\n",
+ SQUASHFS_INODE_BLK(inode), offset,
+ inodep->start_block, next_block,
+ next_offset);
break;
}
case SQUASHFS_DIR_TYPE: {
- squashfs_dir_inode_header_1 inodep;
+ struct squashfs_dir_inode_header *inodep = &id.dir;
+ struct squashfs_dir_inode_header *sinodep = &sid.dir;
+
+ if (msblk->swap) {
+ if (!squashfs_get_cached_block(s, (char *)
+ sinodep, block, offset,
+ sizeof(*sinodep), &next_block,
+ &next_offset))
+ goto failed_read;
+ SQUASHFS_SWAP_DIR_INODE_HEADER(inodep, sinodep);
+ } else
+ if (!squashfs_get_cached_block(s, (char *)
+ inodep, block, offset,
+ sizeof(*inodep), &next_block,
+ &next_offset))
+ goto failed_read;
- if(msBlk->swap) {
- squashfs_dir_inode_header_1 sinodep;
+ if((i = squashfs_new_inode(s, inodeb)) == NULL)
+ goto failed_read1;
- if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep),
- &next_block, &next_offset))
+ i->i_nlink = inodep->nlink;
+ i->i_size = inodep->file_size;
+ i->i_op = &squashfs_dir_inode_ops;
+ i->i_fop = &squashfs_dir_ops;
+ i->i_mode |= S_IFDIR;
+ SQUASHFS_I(i)->start_block = inodep->start_block;
+ SQUASHFS_I(i)->offset = inodep->offset;
+ SQUASHFS_I(i)->u.s2.directory_index_count = 0;
+ SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode;
+
+ TRACE("Directory inode %x:%x, start_block %x, offset "
+ "%x\n", SQUASHFS_INODE_BLK(inode),
+ offset, inodep->start_block,
+ inodep->offset);
+ break;
+ }
+ case SQUASHFS_LDIR_TYPE: {
+ struct squashfs_ldir_inode_header *inodep = &id.ldir;
+ struct squashfs_ldir_inode_header *sinodep = &sid.ldir;
+
+ if (msblk->swap) {
+ if (!squashfs_get_cached_block(s, (char *)
+ sinodep, block, offset,
+ sizeof(*sinodep), &next_block,
+ &next_offset))
goto failed_read;
- SQUASHFS_SWAP_DIR_INODE_HEADER_1(&inodep, &sinodep);
+ SQUASHFS_SWAP_LDIR_INODE_HEADER(inodep,
+ sinodep);
} else
- if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep),
- &next_block, &next_offset))
+ if (!squashfs_get_cached_block(s, (char *)
+ inodep, block, offset,
+ sizeof(*inodep), &next_block,
+ &next_offset))
goto failed_read;
- i->i_size = inodep.file_size;
+ if((i = squashfs_new_inode(s, inodeb)) == NULL)
+ goto failed_read1;
+
+ i->i_nlink = inodep->nlink;
+ i->i_size = inodep->file_size;
i->i_op = &squashfs_dir_inode_ops;
i->i_fop = &squashfs_dir_ops;
i->i_mode |= S_IFDIR;
- i->i_mtime = inodep.mtime;
- i->i_atime = inodep.mtime;
- i->i_ctime = inodep.mtime;
- i->u.squashfs_i.start_block = inodep.start_block;
- i->u.squashfs_i.offset = inodep.offset;
- TRACE("Directory inode %x:%x, start_block %x, offset %x\n", SQUASHFS_INODE_BLK(inode), offset,
- inodep.start_block, inodep.offset);
+ SQUASHFS_I(i)->start_block = inodep->start_block;
+ SQUASHFS_I(i)->offset = inodep->offset;
+ SQUASHFS_I(i)->u.s2.directory_index_start = next_block;
+ SQUASHFS_I(i)->u.s2.directory_index_offset =
+ next_offset;
+ SQUASHFS_I(i)->u.s2.directory_index_count =
+ inodep->i_count;
+ SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode;
+
+ TRACE("Long directory inode %x:%x, start_block %x, "
+ "offset %x\n",
+ SQUASHFS_INODE_BLK(inode), offset,
+ inodep->start_block, inodep->offset);
break;
}
case SQUASHFS_SYMLINK_TYPE: {
- squashfs_symlink_inode_header_1 inodep;
+ struct squashfs_symlink_inode_header *inodep =
+ &id.symlink;
+ struct squashfs_symlink_inode_header *sinodep =
+ &sid.symlink;
- if(msBlk->swap) {
- squashfs_symlink_inode_header_1 sinodep;
-
- if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep),
- &next_block, &next_offset))
+ if (msblk->swap) {
+ if (!squashfs_get_cached_block(s, (char *)
+ sinodep, block, offset,
+ sizeof(*sinodep), &next_block,
+ &next_offset))
goto failed_read;
- SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(&inodep, &sinodep);
+ SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inodep,
+ sinodep);
} else
- if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep),
- &next_block, &next_offset))
+ if (!squashfs_get_cached_block(s, (char *)
+ inodep, block, offset,
+ sizeof(*inodep), &next_block,
+ &next_offset))
goto failed_read;
- i->i_size = inodep.symlink_size;
+ if((i = squashfs_new_inode(s, inodeb)) == NULL)
+ goto failed_read1;
+
+ i->i_nlink = inodep->nlink;
+ i->i_size = inodep->symlink_size;
i->i_op = &page_symlink_inode_operations;
i->i_data.a_ops = &squashfs_symlink_aops;
i->i_mode |= S_IFLNK;
- i->u.squashfs_i.start_block = next_block;
- i->u.squashfs_i.offset = next_offset;
- TRACE("Symbolic link inode %x:%x, start_block %x, offset %x\n",
- SQUASHFS_INODE_BLK(inode), offset, next_block, next_offset);
+ SQUASHFS_I(i)->start_block = next_block;
+ SQUASHFS_I(i)->offset = next_offset;
+
+ TRACE("Symbolic link inode %x:%x, start_block %llx, "
+ "offset %x\n",
+ SQUASHFS_INODE_BLK(inode), offset,
+ next_block, next_offset);
break;
}
case SQUASHFS_BLKDEV_TYPE:
case SQUASHFS_CHRDEV_TYPE: {
- squashfs_dev_inode_header_1 inodep;
-
- if(msBlk->swap) {
- squashfs_dev_inode_header_1 sinodep;
-
- if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep),
- &next_block, &next_offset))
+ struct squashfs_dev_inode_header *inodep = &id.dev;
+ struct squashfs_dev_inode_header *sinodep = &sid.dev;
+
+ if (msblk->swap) {
+ if (!squashfs_get_cached_block(s, (char *)
+ sinodep, block, offset,
+ sizeof(*sinodep), &next_block,
+ &next_offset))
goto failed_read;
- SQUASHFS_SWAP_DEV_INODE_HEADER_1(&inodep, &sinodep);
+ SQUASHFS_SWAP_DEV_INODE_HEADER(inodep, sinodep);
} else
- if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep),
- &next_block, &next_offset))
+ if (!squashfs_get_cached_block(s, (char *)
+ inodep, block, offset,
+ sizeof(*inodep), &next_block,
+ &next_offset))
goto failed_read;
- i->i_size = 0;
- i->i_mode |= (inodeb.inode_type == SQUASHFS_CHRDEV_TYPE) ? S_IFCHR : S_IFBLK;
- init_special_inode(i, i->i_mode, inodep.rdev);
- TRACE("Device inode %x:%x, rdev %x\n", SQUASHFS_INODE_BLK(inode), offset, inodep.rdev);
- break;
- }
- case SQUASHFS_IPC_TYPE: {
- squashfs_ipc_inode_header_1 inodep;
+ if ((i = squashfs_new_inode(s, inodeb)) == NULL)
+ goto failed_read1;
- if(msBlk->swap) {
- squashfs_ipc_inode_header_1 sinodep;
+ i->i_nlink = inodep->nlink;
+ i->i_mode |= (inodeb->inode_type ==
+ SQUASHFS_CHRDEV_TYPE) ? S_IFCHR :
+ S_IFBLK;
+ init_special_inode(i, i->i_mode, inodep->rdev);
- if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep),
- &next_block, &next_offset))
+ TRACE("Device inode %x:%x, rdev %x\n",
+ SQUASHFS_INODE_BLK(inode), offset,
+ inodep->rdev);
+ break;
+ }
+ case SQUASHFS_FIFO_TYPE:
+ case SQUASHFS_SOCKET_TYPE: {
+ struct squashfs_ipc_inode_header *inodep = &id.ipc;
+ struct squashfs_ipc_inode_header *sinodep = &sid.ipc;
+
+ if (msblk->swap) {
+ if (!squashfs_get_cached_block(s, (char *)
+ sinodep, block, offset,
+ sizeof(*sinodep), &next_block,
+ &next_offset))
goto failed_read;
- SQUASHFS_SWAP_IPC_INODE_HEADER_1(&inodep, &sinodep);
+ SQUASHFS_SWAP_IPC_INODE_HEADER(inodep, sinodep);
} else
- if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep),
- &next_block, &next_offset))
+ if (!squashfs_get_cached_block(s, (char *)
+ inodep, block, offset,
+ sizeof(*inodep), &next_block,
+ &next_offset))
goto failed_read;
- i->i_size = 0;
- i->i_mode |= (inodep.type == SQUASHFS_FIFO_TYPE) ? S_IFIFO : S_IFSOCK;
- i->i_uid = msBlk->uid[inodep.offset * 16 + inodeb.uid];
+ if ((i = squashfs_new_inode(s, inodeb)) == NULL)
+ goto failed_read1;
+
+ i->i_nlink = inodep->nlink;
+ i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE)
+ ? S_IFIFO : S_IFSOCK;
init_special_inode(i, i->i_mode, 0);
break;
}
default:
- ERROR("Unknown inode type %d in squashfs_iget!\n", inodeb.inode_type);
- goto failed_read1;
+ ERROR("Unknown inode type %d in squashfs_iget!\n",
+ inodeb->inode_type);
+ goto failed_read1;
}
- if(inodeb.guid == 15)
- i->i_gid = i->i_uid;
- else
- i->i_gid = msBlk->guid[inodeb.guid];
-
+ insert_inode_hash(i);
return i;
failed_read:
- ERROR("Unable to read inode [%x:%x]\n", block, offset);
+ ERROR("Unable to read inode [%llx:%x]\n", block, offset);
failed_read1:
return NULL;
}
-#endif
-static struct inode *squashfs_iget(struct super_block *s, squashfs_inode inode)
+int read_fragment_index_table(struct super_block *s)
{
- struct inode *i = new_inode(s);
- squashfs_sb_info *msBlk = &s->u.squashfs_sb;
- squashfs_super_block *sBlk = &msBlk->sBlk;
- unsigned int block = SQUASHFS_INODE_BLK(inode) + sBlk->inode_table_start;
- unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
- unsigned int next_block, next_offset;
- squashfs_base_inode_header inodeb;
-
- TRACE("Entered squashfs_iget\n");
-
- if(msBlk->swap) {
- squashfs_base_inode_header sinodeb;
+ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
+ struct squashfs_super_block *sblk = &msblk->sblk;
- if(!squashfs_get_cached_block(s, (char *) &sinodeb, block, offset,
- sizeof(sinodeb), &next_block, &next_offset))
- goto failed_read;
- SQUASHFS_SWAP_BASE_INODE_HEADER(&inodeb, &sinodeb, sizeof(sinodeb));
- } else
- if(!squashfs_get_cached_block(s, (char *) &inodeb, block, offset,
- sizeof(inodeb), &next_block, &next_offset))
- goto failed_read;
-
- i->i_nlink = 1;
-
- i->i_mtime = sBlk->mkfs_time;
- i->i_atime = sBlk->mkfs_time;
- i->i_ctime = sBlk->mkfs_time;
-
- if(inodeb.inode_type != SQUASHFS_IPC_TYPE)
- i->i_uid = msBlk->uid[((inodeb.inode_type - 1) / SQUASHFS_TYPES) * 16 + inodeb.uid];
- i->i_ino = SQUASHFS_MK_VFS_INODE(block - sBlk->inode_table_start, offset);
-
- i->i_mode = inodeb.mode;
-
- switch(inodeb.inode_type) {
- case SQUASHFS_FILE_TYPE: {
- squashfs_reg_inode_header inodep;
-
- if(msBlk->swap) {
- squashfs_reg_inode_header sinodep;
-
- if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep),
- &next_block, &next_offset))
- goto failed_read;
- SQUASHFS_SWAP_REG_INODE_HEADER(&inodep, &sinodep);
- } else
- if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep),
- &next_block, &next_offset))
- goto failed_read;
+ if (!(msblk->fragment_index = kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES
+ (sblk->fragments), GFP_KERNEL))) {
+ ERROR("Failed to allocate uid/gid table\n");
+ return 0;
+ }
+
+ if (SQUASHFS_FRAGMENT_INDEX_BYTES(sblk->fragments) &&
+ !squashfs_read_data(s, (char *)
+ msblk->fragment_index,
+ sblk->fragment_table_start,
+ SQUASHFS_FRAGMENT_INDEX_BYTES
+ (sblk->fragments) |
+ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
+ ERROR("unable to read fragment index table\n");
+ return 0;
+ }
- i->u.squashfs_i.fragment_start_block = SQUASHFS_INVALID_BLK;
- if(inodep.fragment != SQUASHFS_INVALID_BLK && !get_fragment_location(s, inodep.fragment,
- &i->u.squashfs_i.fragment_start_block, &i->u.squashfs_i.fragment_size))
- goto failed_read;
+ if (msblk->swap) {
+ int i;
+ long long fragment;
- i->u.squashfs_i.fragment_offset = inodep.offset;
- i->i_size = inodep.file_size;
- i->i_fop = &generic_ro_fops;
- if(sBlk->block_size > 4096)
- i->i_data.a_ops = &squashfs_aops;
- else
- i->i_data.a_ops = &squashfs_aops_4K;
- i->i_mode |= S_IFREG;
- i->i_mtime = inodep.mtime;
- i->i_atime = inodep.mtime;
- i->i_ctime = inodep.mtime;
- i->i_blocks = ((i->i_size - 1) >> 9) + 1;
- i->i_blksize = PAGE_CACHE_SIZE;
- i->u.squashfs_i.start_block = inodep.start_block;
- i->u.squashfs_i.block_list_start = next_block;
- i->u.squashfs_i.offset = next_offset;
- TRACE("File inode %x:%x, start_block %x, block_list_start %x, offset %x fragment_index %x fragment_offset %x\n",
- SQUASHFS_INODE_BLK(inode), offset, inodep.start_block, next_block, next_offset, inodep.fragment, inodep.offset);
- break;
+ for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES(sblk->fragments);
+ i++) {
+ SQUASHFS_SWAP_FRAGMENT_INDEXES((&fragment),
+ &msblk->fragment_index[i], 1);
+ msblk->fragment_index[i] = fragment;
}
- case SQUASHFS_DIR_TYPE: {
- squashfs_dir_inode_header inodep;
+ }
- if(msBlk->swap) {
- squashfs_dir_inode_header sinodep;
+ return 1;
+}
- if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep),
- &next_block, &next_offset))
- goto failed_read;
- SQUASHFS_SWAP_DIR_INODE_HEADER(&inodep, &sinodep);
- } else
- if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep),
- &next_block, &next_offset))
- goto failed_read;
- i->i_size = inodep.file_size;
- i->i_op = &squashfs_dir_inode_ops;
- i->i_fop = &squashfs_dir_ops;
- i->i_mode |= S_IFDIR;
- i->i_mtime = inodep.mtime;
- i->i_atime = inodep.mtime;
- i->i_ctime = inodep.mtime;
- i->u.squashfs_i.start_block = inodep.start_block;
- i->u.squashfs_i.offset = inodep.offset;
- TRACE("Directory inode %x:%x, start_block %x, offset %x\n", SQUASHFS_INODE_BLK(inode), offset,
- inodep.start_block, inodep.offset);
- break;
+static int supported_squashfs_filesystem(struct squashfs_sb_info *msblk, int silent)
+{
+ struct squashfs_super_block *sblk = &msblk->sblk;
+
+ msblk->iget = squashfs_iget;
+ msblk->read_blocklist = read_blocklist;
+ msblk->read_fragment_index_table = read_fragment_index_table;
+
+ if (sblk->s_major == 1) {
+ if (!squashfs_1_0_supported(msblk)) {
+ SERROR("Major/Minor mismatch, Squashfs 1.0 filesystems "
+ "are unsupported\n");
+ SERROR("Please recompile with "
+ "Squashfs 1.0 support enabled\n");
+ return 0;
}
- case SQUASHFS_SYMLINK_TYPE: {
- squashfs_symlink_inode_header inodep;
-
- if(msBlk->swap) {
- squashfs_symlink_inode_header sinodep;
-
- if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep),
- &next_block, &next_offset))
- goto failed_read;
- SQUASHFS_SWAP_SYMLINK_INODE_HEADER(&inodep, &sinodep);
- } else
- if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep),
- &next_block, &next_offset))
- goto failed_read;
-
- i->i_size = inodep.symlink_size;
- i->i_op = &page_symlink_inode_operations;
- i->i_data.a_ops = &squashfs_symlink_aops;
- i->i_mode |= S_IFLNK;
- i->u.squashfs_i.start_block = next_block;
- i->u.squashfs_i.offset = next_offset;
- TRACE("Symbolic link inode %x:%x, start_block %x, offset %x\n",
- SQUASHFS_INODE_BLK(inode), offset, next_block, next_offset);
- break;
- }
- case SQUASHFS_BLKDEV_TYPE:
- case SQUASHFS_CHRDEV_TYPE: {
- squashfs_dev_inode_header inodep;
-
- if(msBlk->swap) {
- squashfs_dev_inode_header sinodep;
-
- if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep),
- &next_block, &next_offset))
- goto failed_read;
- SQUASHFS_SWAP_DEV_INODE_HEADER(&inodep, &sinodep);
- } else
- if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep),
- &next_block, &next_offset))
- goto failed_read;
-
- i->i_size = 0;
- i->i_mode |= (inodeb.inode_type == SQUASHFS_CHRDEV_TYPE) ? S_IFCHR : S_IFBLK;
- init_special_inode(i, i->i_mode, inodep.rdev);
- TRACE("Device inode %x:%x, rdev %x\n", SQUASHFS_INODE_BLK(inode), offset, inodep.rdev);
- break;
- }
- case SQUASHFS_FIFO_TYPE:
- case SQUASHFS_SOCKET_TYPE: {
- i->i_size = 0;
- i->i_mode |= (inodeb.inode_type == SQUASHFS_FIFO_TYPE) ? S_IFIFO : S_IFSOCK;
- init_special_inode(i, i->i_mode, 0);
- break;
- }
- default:
- ERROR("Unknown inode type %d in squashfs_iget!\n", inodeb.inode_type);
- goto failed_read1;
+ } else if (sblk->s_major == 2) {
+ if (!squashfs_2_0_supported(msblk)) {
+ SERROR("Major/Minor mismatch, Squashfs 2.0 filesystems "
+ "are unsupported\n");
+ SERROR("Please recompile with "
+ "Squashfs 2.0 support enabled\n");
+ return 0;
+ }
+ } else if(sblk->s_major != SQUASHFS_MAJOR || sblk->s_minor >
+ SQUASHFS_MINOR) {
+ SERROR("Major/Minor mismatch, trying to mount newer %d.%d "
+ "filesystem\n", sblk->s_major, sblk->s_minor);
+ SERROR("Please update your kernel\n");
+ return 0;
}
-
- if(inodeb.guid == SQUASHFS_GUIDS)
- i->i_gid = i->i_uid;
- else
- i->i_gid = msBlk->guid[inodeb.guid];
-
- return i;
-failed_read:
- ERROR("Unable to read inode [%x:%x]\n", block, offset);
-
-failed_read1:
- return NULL;
+ return 1;
}
@@ -804,221 +968,204 @@ static struct super_block *squashfs_read_super(struct super_block *s,
void *data, int silent)
{
kdev_t dev = s->s_dev;
- squashfs_sb_info *msBlk = &s->u.squashfs_sb;
- squashfs_super_block *sBlk = &msBlk->sBlk;
+ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
+ struct squashfs_super_block *sblk = &msblk->sblk;
int i;
-
- TRACE("Entered squashfs_read_superblock\n");
-
- msBlk->devblksize = get_hardsect_size(dev);
- if(msBlk->devblksize < BLOCK_SIZE)
- msBlk->devblksize = BLOCK_SIZE;
- msBlk->devblksize_log2 = ffz(~msBlk->devblksize);
- set_blocksize(dev, msBlk->devblksize);
- s->s_blocksize = msBlk->devblksize;
- s->s_blocksize_bits = msBlk->devblksize_log2;
-
- init_MUTEX(&msBlk->read_page_mutex);
- init_MUTEX(&msBlk->block_cache_mutex);
- init_MUTEX(&msBlk->fragment_mutex);
+ struct inode *root;
+
+ msblk->devblksize = get_hardsect_size(dev);
+ if(msblk->devblksize < BLOCK_SIZE)
+ msblk->devblksize = BLOCK_SIZE;
+ msblk->devblksize_log2 = ffz(~msblk->devblksize);
+ set_blocksize(dev, msblk->devblksize);
+ s->s_blocksize = msblk->devblksize;
+ s->s_blocksize_bits = msblk->devblksize_log2;
+
+ init_MUTEX(&msblk->read_data_mutex);
+ init_MUTEX(&msblk->read_page_mutex);
+ init_MUTEX(&msblk->block_cache_mutex);
+ init_MUTEX(&msblk->fragment_mutex);
- init_waitqueue_head(&msBlk->waitq);
- init_waitqueue_head(&msBlk->fragment_wait_queue);
+ init_waitqueue_head(&msblk->waitq);
+ init_waitqueue_head(&msblk->fragment_wait_queue);
- if(!read_data(s, (char *) sBlk, SQUASHFS_START, sizeof(squashfs_super_block) | SQUASHFS_COMPRESSED_BIT, 0, NULL)) {
+ if (!squashfs_read_data(s, (char *) sblk, SQUASHFS_START,
+ sizeof(struct squashfs_super_block) |
+ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
SERROR("unable to read superblock\n");
goto failed_mount;
}
/* Check it is a SQUASHFS superblock */
- msBlk->swap = 0;
- if((s->s_magic = sBlk->s_magic) != SQUASHFS_MAGIC) {
- if(sBlk->s_magic == SQUASHFS_MAGIC_SWAP) {
- squashfs_super_block sblk;
- WARNING("Mounting a different endian SQUASHFS filesystem on %s\n", bdevname(dev));
- SQUASHFS_SWAP_SUPER_BLOCK(&sblk, sBlk);
- memcpy(sBlk, &sblk, sizeof(squashfs_super_block));
- msBlk->swap = 1;
+ msblk->swap = 0;
+ if ((s->s_magic = sblk->s_magic) != SQUASHFS_MAGIC) {
+ if (sblk->s_magic == SQUASHFS_MAGIC_SWAP) {
+ struct squashfs_super_block ssblk;
+
+ WARNING("Mounting a different endian SQUASHFS "
+ "filesystem on %s\n", bdevname(dev));
+
+ SQUASHFS_SWAP_SUPER_BLOCK(&ssblk, sblk);
+ memcpy(sblk, &ssblk, sizeof(struct squashfs_super_block));
+ msblk->swap = 1;
} else {
- SERROR("Can't find a SQUASHFS superblock on %s\n", bdevname(dev));
+ SERROR("Can't find a SQUASHFS superblock on %s\n",
+ bdevname(dev));
goto failed_mount;
}
}
/* Check the MAJOR & MINOR versions */
-#ifdef SQUASHFS_1_0_COMPATIBILITY
- if((sBlk->s_major != 1) && (sBlk->s_major != 2 || sBlk->s_minor > SQUASHFS_MINOR)) {
- SERROR("Major/Minor mismatch, filesystem is (%d:%d), I support (1 : x) or (2 : <= %d)\n",
- sBlk->s_major, sBlk->s_minor, SQUASHFS_MINOR);
+ if(!supported_squashfs_filesystem(msblk, silent))
goto failed_mount;
- }
- if(sBlk->s_major == 1)
- sBlk->block_size = sBlk->block_size_1;
-#else
- if(sBlk->s_major != SQUASHFS_MAJOR || sBlk->s_minor > SQUASHFS_MINOR) {
- SERROR("Major/Minor mismatch, filesystem is (%d:%d), I support (%d: <= %d)\n",
- sBlk->s_major, sBlk->s_minor, SQUASHFS_MAJOR, SQUASHFS_MINOR);
- goto failed_mount;
- }
-#endif
TRACE("Found valid superblock on %s\n", bdevname(dev));
- TRACE("Inodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(sBlk->flags) ? "un" : "");
- TRACE("Data is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(sBlk->flags) ? "un" : "");
- TRACE("Check data is %s present in the filesystem\n", SQUASHFS_CHECK_DATA(sBlk->flags) ? "" : "not");
- TRACE("Filesystem size %d bytes\n", sBlk->bytes_used);
- TRACE("Block size %d\n", sBlk->block_size);
- TRACE("Number of inodes %d\n", sBlk->inodes);
- if(sBlk->s_major > 1)
- TRACE("Number of fragments %d\n", sBlk->fragments);
- TRACE("Number of uids %d\n", sBlk->no_uids);
- TRACE("Number of gids %d\n", sBlk->no_guids);
- TRACE("sBlk->inode_table_start %x\n", sBlk->inode_table_start);
- TRACE("sBlk->directory_table_start %x\n", sBlk->directory_table_start);
- if(sBlk->s_major > 1)
- TRACE("sBlk->fragment_table_start %x\n", sBlk->fragment_table_start);
- TRACE("sBlk->uid_start %x\n", sBlk->uid_start);
+ TRACE("Inodes are %scompressed\n",
+ SQUASHFS_UNCOMPRESSED_INODES
+ (sblk->flags) ? "un" : "");
+ TRACE("Data is %scompressed\n",
+ SQUASHFS_UNCOMPRESSED_DATA(sblk->flags)
+ ? "un" : "");
+ TRACE("Check data is %s present in the filesystem\n",
+ SQUASHFS_CHECK_DATA(sblk->flags) ?
+ "" : "not");
+ TRACE("Filesystem size %lld bytes\n", sblk->bytes_used);
+ TRACE("Block size %d\n", sblk->block_size);
+ TRACE("Number of inodes %d\n", sblk->inodes);
+ if (sblk->s_major > 1)
+ TRACE("Number of fragments %d\n", sblk->fragments);
+ TRACE("Number of uids %d\n", sblk->no_uids);
+ TRACE("Number of gids %d\n", sblk->no_guids);
+ TRACE("sblk->inode_table_start %llx\n", sblk->inode_table_start);
+ TRACE("sblk->directory_table_start %llx\n", sblk->directory_table_start);
+ if (sblk->s_major > 1)
+ TRACE("sblk->fragment_table_start %llx\n",
+ sblk->fragment_table_start);
+ TRACE("sblk->uid_start %llx\n", sblk->uid_start);
s->s_flags |= MS_RDONLY;
s->s_op = &squashfs_ops;
/* Init inode_table block pointer array */
- if(!(msBlk->block_cache = (squashfs_cache *) kmalloc(sizeof(squashfs_cache) * SQUASHFS_CACHED_BLKS, GFP_KERNEL))) {
+ if (!(msblk->block_cache = kmalloc(sizeof(struct squashfs_cache) *
+ SQUASHFS_CACHED_BLKS, GFP_KERNEL))) {
ERROR("Failed to allocate block cache\n");
goto failed_mount;
}
- for(i = 0; i < SQUASHFS_CACHED_BLKS; i++)
- msBlk->block_cache[i].block = SQUASHFS_INVALID_BLK;
+ for (i = 0; i < SQUASHFS_CACHED_BLKS; i++)
+ msblk->block_cache[i].block = SQUASHFS_INVALID_BLK;
- msBlk->next_cache = 0;
+ msblk->next_cache = 0;
/* Allocate read_data block */
- msBlk->read_size = (sBlk->block_size < SQUASHFS_METADATA_SIZE) ? SQUASHFS_METADATA_SIZE : sBlk->block_size;
- if(!(msBlk->read_data = (char *) kmalloc(msBlk->read_size, GFP_KERNEL))) {
+ msblk->read_size = (sblk->block_size < SQUASHFS_METADATA_SIZE) ?
+ SQUASHFS_METADATA_SIZE :
+ sblk->block_size;
+
+ if (!(msblk->read_data = kmalloc(msblk->read_size, GFP_KERNEL))) {
ERROR("Failed to allocate read_data block\n");
- goto failed_mount1;
+ goto failed_mount;
}
/* Allocate read_page block */
- if(sBlk->block_size > PAGE_CACHE_SIZE &&
- !(msBlk->read_page = (char *) kmalloc(sBlk->block_size, GFP_KERNEL))) {
+ if (!(msblk->read_page = kmalloc(sblk->block_size, GFP_KERNEL))) {
ERROR("Failed to allocate read_page block\n");
- goto failed_mount2;
+ goto failed_mount;
}
/* Allocate uid and gid tables */
- if(!(msBlk->uid = (squashfs_uid *) kmalloc((sBlk->no_uids +
- sBlk->no_guids) * sizeof(squashfs_uid), GFP_KERNEL))) {
+ if (!(msblk->uid = kmalloc((sblk->no_uids + sblk->no_guids) *
+ sizeof(unsigned int), GFP_KERNEL))) {
ERROR("Failed to allocate uid/gid table\n");
- goto failed_mount3;
+ goto failed_mount;
}
- msBlk->guid = msBlk->uid + sBlk->no_uids;
+ msblk->guid = msblk->uid + sblk->no_uids;
- if(msBlk->swap) {
- squashfs_uid suid[sBlk->no_uids + sBlk->no_guids];
-
- if(!read_data(s, (char *) &suid, sBlk->uid_start, ((sBlk->no_uids + sBlk->no_guids) *
- sizeof(squashfs_uid)) | SQUASHFS_COMPRESSED_BIT, 0, NULL)) {
- SERROR("unable to read uid/gid table\n");
- goto failed_mount4;
+ if (msblk->swap) {
+ unsigned int suid[sblk->no_uids + sblk->no_guids];
+
+ if (!squashfs_read_data(s, (char *) &suid, sblk->uid_start,
+ ((sblk->no_uids + sblk->no_guids) *
+ sizeof(unsigned int)) |
+ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
+ ERROR("unable to read uid/gid table\n");
+ goto failed_mount;
}
- SQUASHFS_SWAP_DATA(msBlk->uid, suid, (sBlk->no_uids + sBlk->no_guids), (sizeof(squashfs_uid) * 8));
+
+ SQUASHFS_SWAP_DATA(msblk->uid, suid, (sblk->no_uids +
+ sblk->no_guids), (sizeof(unsigned int) * 8));
} else
- if(!read_data(s, (char *) msBlk->uid, sBlk->uid_start, ((sBlk->no_uids + sBlk->no_guids) *
- sizeof(squashfs_uid)) | SQUASHFS_COMPRESSED_BIT, 0, NULL)) {
- SERROR("unable to read uid/gid table\n");
- goto failed_mount4;
+ if (!squashfs_read_data(s, (char *) msblk->uid, sblk->uid_start,
+ ((sblk->no_uids + sblk->no_guids) *
+ sizeof(unsigned int)) |
+ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
+ ERROR("unable to read uid/gid table\n");
+ goto failed_mount;
}
-#ifdef SQUASHFS_1_0_COMPATIBILITY
- if(sBlk->s_major == 1) {
- msBlk->iget = squashfs_iget_1;
- msBlk->read_blocklist = read_blocklist_1;
- msBlk->fragment = (struct squashfs_fragment_cache *) msBlk->fragment_index = NULL;
+ if (sblk->s_major == 1 && squashfs_1_0_supported(msblk))
goto allocate_root;
- }
-#endif
- msBlk->iget = squashfs_iget;
- msBlk->read_blocklist = read_blocklist;
- if(!(msBlk->fragment = (struct squashfs_fragment_cache *) kmalloc(sizeof(struct squashfs_fragment_cache) * SQUASHFS_CACHED_FRAGMENTS, GFP_KERNEL))) {
+ if (!(msblk->fragment = kmalloc(sizeof(struct squashfs_fragment_cache) *
+ SQUASHFS_CACHED_FRAGMENTS, GFP_KERNEL))) {
ERROR("Failed to allocate fragment block cache\n");
- goto failed_mount4;
+ goto failed_mount;
}
- for(i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) {
- msBlk->fragment[i].locked = 0;
- msBlk->fragment[i].block = SQUASHFS_INVALID_BLK;
- msBlk->fragment[i].data = NULL;
+ for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) {
+ msblk->fragment[i].locked = 0;
+ msblk->fragment[i].block = SQUASHFS_INVALID_BLK;
+ msblk->fragment[i].data = NULL;
}
- msBlk->next_fragment = 0;
+ msblk->next_fragment = 0;
/* Allocate fragment index table */
- if(!(msBlk->fragment_index = (squashfs_fragment_index *) kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments), GFP_KERNEL))) {
- ERROR("Failed to allocate uid/gid table\n");
- goto failed_mount5;
- }
-
- if(SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments) &&
- !read_data(s, (char *) msBlk->fragment_index, sBlk->fragment_table_start,
- SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments) | SQUASHFS_COMPRESSED_BIT, 0, NULL)) {
- SERROR("unable to read fragment index table\n");
- goto failed_mount6;
- }
-
- if(msBlk->swap) {
- int i;
- squashfs_fragment_index fragment;
-
- for(i = 0; i < SQUASHFS_FRAGMENT_INDEXES(sBlk->fragments); i++) {
- SQUASHFS_SWAP_FRAGMENT_INDEXES((&fragment), &msBlk->fragment_index[i], 1);
- msBlk->fragment_index[i] = fragment;
- }
- }
+ if(msblk->read_fragment_index_table(s) == 0)
+ goto failed_mount;
-#ifdef SQUASHFS_1_0_COMPATIBILITY
allocate_root:
-#endif
- if(!(s->s_root = d_alloc_root((msBlk->iget)(s, sBlk->root_inode)))) {
+ if ((root = (msblk->iget)(s, sblk->root_inode)) == NULL)
+ goto failed_mount;
+
+ if ((s->s_root = d_alloc_root(root)) == NULL) {
ERROR("Root inode create failed\n");
- goto failed_mount5;
+ iput(root);
+ goto failed_mount;
}
TRACE("Leaving squashfs_read_super\n");
return s;
-failed_mount6:
- kfree(msBlk->fragment_index);
-failed_mount5:
- kfree(msBlk->fragment);
-failed_mount4:
- kfree(msBlk->uid);
-failed_mount3:
- kfree(msBlk->read_page);
-failed_mount2:
- kfree(msBlk->read_data);
-failed_mount1:
- kfree(msBlk->block_cache);
failed_mount:
+ kfree(msblk->fragment_index);
+ kfree(msblk->fragment);
+ kfree(msblk->uid);
+ kfree(msblk->read_page);
+ kfree(msblk->read_data);
+ kfree(msblk->block_cache);
+ kfree(msblk->fragment_index_2);
return NULL;
}
static int squashfs_statfs(struct super_block *s, struct statfs *buf)
{
- squashfs_super_block *sBlk = &s->u.squashfs_sb.sBlk;
+ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
+ struct squashfs_super_block *sblk = &msblk->sblk;
TRACE("Entered squashfs_statfs\n");
+
buf->f_type = SQUASHFS_MAGIC;
- buf->f_bsize = sBlk->block_size;
- buf->f_blocks = ((sBlk->bytes_used - 1) >> sBlk->block_log) + 1;
+ buf->f_bsize = sblk->block_size;
+ buf->f_blocks = ((sblk->bytes_used - 1) >> sblk->block_log) + 1;
buf->f_bfree = buf->f_bavail = 0;
- buf->f_files = sBlk->inodes;
+ buf->f_files = sblk->inodes;
buf->f_ffree = 0;
buf->f_namelen = SQUASHFS_NAME_LEN;
+
return 0;
}
@@ -1027,35 +1174,41 @@ static int squashfs_symlink_readpage(struct file *file, struct page *page)
{
struct inode *inode = page->mapping->host;
int index = page->index << PAGE_CACHE_SHIFT, length, bytes;
- int block = inode->u.squashfs_i.start_block;
- int offset = inode->u.squashfs_i.offset;
- void *pageaddr = kmap(page);
-
- TRACE("Entered squashfs_symlink_readpage, page index %x, start block %x, offset %x\n",
- (unsigned int) page->index, inode->u.squashfs_i.start_block, inode->u.squashfs_i.offset);
-
- for(length = 0; length < index; length += bytes) {
- if(!(bytes = squashfs_get_cached_block(inode->i_sb, NULL, block, offset,
- PAGE_CACHE_SIZE, &block, &offset))) {
- ERROR("Unable to read symbolic link [%x:%x]\n", block, offset);
+ long long block = SQUASHFS_I(inode)->start_block;
+ int offset = SQUASHFS_I(inode)->offset;
+ void *pageaddr = kmap(page);
+
+ TRACE("Entered squashfs_symlink_readpage, page index %ld, start block "
+ "%llx, offset %x\n", page->index,
+ SQUASHFS_I(inode)->start_block,
+ SQUASHFS_I(inode)->offset);
+
+ for (length = 0; length < index; length += bytes) {
+ if (!(bytes = squashfs_get_cached_block(inode->i_sb, NULL,
+ block, offset, PAGE_CACHE_SIZE, &block,
+ &offset))) {
+ ERROR("Unable to read symbolic link [%llx:%x]\n", block,
+ offset);
goto skip_read;
}
}
- if(length != index) {
+ if (length != index) {
ERROR("(squashfs_symlink_readpage) length != index\n");
bytes = 0;
goto skip_read;
}
- bytes = (inode->i_size - length) > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE : inode->i_size - length;
- if(!(bytes = squashfs_get_cached_block(inode->i_sb, pageaddr, block, offset, bytes, &block, &offset)))
- ERROR("Unable to read symbolic link [%x:%x]\n", block, offset);
+ bytes = (i_size_read(inode) - length) > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE :
+ i_size_read(inode) - length;
+
+ if (!(bytes = squashfs_get_cached_block(inode->i_sb, pageaddr, block,
+ offset, bytes, &block, &offset)))
+ ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset);
skip_read:
memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
kunmap(page);
- flush_dcache_page(page);
SetPageUptodate(page);
UnlockPage(page);
@@ -1063,155 +1216,358 @@ skip_read:
}
-#define SIZE 256
+struct meta_index *locate_meta_index(struct inode *inode, int index, int offset)
+{
+ struct meta_index *meta = NULL;
+ struct squashfs_sb_info *msblk = &inode->i_sb->u.squashfs_sb;
+ int i;
+
+ down(&msblk->meta_index_mutex);
+
+ TRACE("locate_meta_index: index %d, offset %d\n", index, offset);
+
+ if(msblk->meta_index == NULL)
+ goto not_allocated;
+
+ for (i = 0; i < SQUASHFS_META_NUMBER; i ++)
+ if (msblk->meta_index[i].inode_number == inode->i_ino &&
+ msblk->meta_index[i].offset >= offset &&
+ msblk->meta_index[i].offset <= index &&
+ msblk->meta_index[i].locked == 0) {
+ TRACE("locate_meta_index: entry %d, offset %d\n", i,
+ msblk->meta_index[i].offset);
+ meta = &msblk->meta_index[i];
+ offset = meta->offset;
+ }
-#ifdef SQUASHFS_1_0_COMPATIBILITY
-static unsigned int read_blocklist_1(struct inode *inode, int index, int readahead_blks,
- char *block_list, char **block_p, unsigned int *bsize)
+ if (meta)
+ meta->locked = 1;
+
+not_allocated:
+ up(&msblk->meta_index_mutex);
+
+ return meta;
+}
+
+
+struct meta_index *empty_meta_index(struct inode *inode, int offset, int skip)
{
- squashfs_sb_info *msBlk = &inode->i_sb->u.squashfs_sb;
- unsigned short *block_listp;
- int i = 0;
- int block_ptr = inode->u.squashfs_i.block_list_start;
- int offset = inode->u.squashfs_i.offset;
- int block = inode->u.squashfs_i.start_block;
-
- for(;;) {
- int blocks = (index + readahead_blks - i);
- if(blocks > (SIZE >> 1)) {
- if((index - i) <= (SIZE >> 1))
- blocks = index - i;
- else
- blocks = SIZE >> 1;
+ struct squashfs_sb_info *msblk = &inode->i_sb->u.squashfs_sb;
+ struct meta_index *meta = NULL;
+ int i;
+
+ down(&msblk->meta_index_mutex);
+
+ TRACE("empty_meta_index: offset %d, skip %d\n", offset, skip);
+
+ if(msblk->meta_index == NULL) {
+ if (!(msblk->meta_index = kmalloc(sizeof(struct meta_index) *
+ SQUASHFS_META_NUMBER, GFP_KERNEL))) {
+ ERROR("Failed to allocate meta_index\n");
+ goto failed;
}
+ for(i = 0; i < SQUASHFS_META_NUMBER; i++) {
+ msblk->meta_index[i].inode_number = 0;
+ msblk->meta_index[i].locked = 0;
+ }
+ msblk->next_meta_index = 0;
+ }
- if(msBlk->swap) {
- unsigned char sblock_list[SIZE];
- if(!squashfs_get_cached_block(inode->i_sb, (char *) sblock_list, block_ptr, offset, blocks << 1, &block_ptr, &offset)) {
- ERROR("Unable to read block list [%d:%x]\n", block_ptr, offset);
- return 0;
- }
- SQUASHFS_SWAP_SHORTS(((unsigned short *)block_list), ((unsigned short *)sblock_list), blocks);
- } else
- if(!squashfs_get_cached_block(inode->i_sb, (char *) block_list, block_ptr, offset, blocks << 1, &block_ptr, &offset)) {
- ERROR("Unable to read block list [%d:%x]\n", block_ptr, offset);
- return 0;
- }
- for(block_listp = (unsigned short *) block_list; i < index && blocks; i ++, block_listp ++, blocks --)
- block += SQUASHFS_COMPRESSED_SIZE(*block_listp);
- if(blocks >= readahead_blks)
- break;
+ for(i = SQUASHFS_META_NUMBER; i &&
+ msblk->meta_index[msblk->next_meta_index].locked; i --)
+ msblk->next_meta_index = (msblk->next_meta_index + 1) %
+ SQUASHFS_META_NUMBER;
+
+ if(i == 0) {
+ TRACE("empty_meta_index: failed!\n");
+ goto failed;
}
- if(bsize)
- *bsize = SQUASHFS_COMPRESSED_SIZE(*block_listp) | (!SQUASHFS_COMPRESSED(*block_listp) ? SQUASHFS_COMPRESSED_BIT_BLOCK : 0);
- else
- (unsigned short *) *block_p = block_listp;
- return block;
+ TRACE("empty_meta_index: returned meta entry %d, %p\n",
+ msblk->next_meta_index,
+ &msblk->meta_index[msblk->next_meta_index]);
+
+ meta = &msblk->meta_index[msblk->next_meta_index];
+ msblk->next_meta_index = (msblk->next_meta_index + 1) %
+ SQUASHFS_META_NUMBER;
+
+ meta->inode_number = inode->i_ino;
+ meta->offset = offset;
+ meta->skip = skip;
+ meta->entries = 0;
+ meta->locked = 1;
+
+failed:
+ up(&msblk->meta_index_mutex);
+ return meta;
}
-#endif
+void release_meta_index(struct inode *inode, struct meta_index *meta)
+{
+ meta->locked = 0;
+}
+
-static unsigned int read_blocklist(struct inode *inode, int index, int readahead_blks,
- char *block_list, char **block_p, unsigned int *bsize)
+static int read_block_index(struct super_block *s, int blocks, char *block_list,
+ long long *start_block, int *offset)
{
- squashfs_sb_info *msBlk = &inode->i_sb->u.squashfs_sb;
+ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
unsigned int *block_listp;
- int i = 0;
- int block_ptr = inode->u.squashfs_i.block_list_start;
- int offset = inode->u.squashfs_i.offset;
- int block = inode->u.squashfs_i.start_block;
-
- for(;;) {
- int blocks = (index + readahead_blks - i);
- if(blocks > (SIZE >> 2)) {
- if((index - i) <= (SIZE >> 2))
- blocks = index - i;
- else
- blocks = SIZE >> 2;
+ int block = 0;
+
+ if (msblk->swap) {
+ char sblock_list[blocks << 2];
+
+ if (!squashfs_get_cached_block(s, sblock_list, *start_block,
+ *offset, blocks << 2, start_block, offset)) {
+ ERROR("Unable to read block list [%llx:%x]\n",
+ *start_block, *offset);
+ goto failure;
+ }
+ SQUASHFS_SWAP_INTS(((unsigned int *)block_list),
+ ((unsigned int *)sblock_list), blocks);
+ } else
+ if (!squashfs_get_cached_block(s, block_list, *start_block,
+ *offset, blocks << 2, start_block, offset)) {
+ ERROR("Unable to read block list [%llx:%x]\n",
+ *start_block, *offset);
+ goto failure;
}
- if(msBlk->swap) {
- unsigned char sblock_list[SIZE];
- if(!squashfs_get_cached_block(inode->i_sb, (char *) sblock_list, block_ptr, offset, blocks << 2, &block_ptr, &offset)) {
- ERROR("Unable to read block list [%d:%x]\n", block_ptr, offset);
- return 0;
- }
- SQUASHFS_SWAP_INTS(((unsigned int *)block_list), ((unsigned int *)sblock_list), blocks);
- } else
- if(!squashfs_get_cached_block(inode->i_sb, (char *) block_list, block_ptr, offset, blocks << 2, &block_ptr, &offset)) {
- ERROR("Unable to read block list [%d:%x]\n", block_ptr, offset);
- return 0;
+ for (block_listp = (unsigned int *) block_list; blocks;
+ block_listp++, blocks --)
+ block += SQUASHFS_COMPRESSED_SIZE_BLOCK(*block_listp);
+
+ return block;
+
+failure:
+ return -1;
+}
+
+
+#define SIZE 256
+
+static inline int calculate_skip(int blocks) {
+ int skip = (blocks - 1) / ((SQUASHFS_SLOTS * SQUASHFS_META_ENTRIES + 1) * SQUASHFS_META_INDEXES);
+ return skip >= 7 ? 7 : skip + 1;
+}
+
+
+static int get_meta_index(struct inode *inode, int index,
+ long long *index_block, int *index_offset,
+ long long *data_block, char *block_list)
+{
+ struct squashfs_sb_info *msblk = &inode->i_sb->u.squashfs_sb;
+ struct squashfs_super_block *sblk = &msblk->sblk;
+ int skip = calculate_skip(i_size_read(inode) >> sblk->block_log);
+ int offset = 0;
+ struct meta_index *meta;
+ struct meta_entry *meta_entry;
+ long long cur_index_block = SQUASHFS_I(inode)->u.s1.block_list_start;
+ int cur_offset = SQUASHFS_I(inode)->offset;
+ long long cur_data_block = SQUASHFS_I(inode)->start_block;
+ int i;
+
+ index /= SQUASHFS_META_INDEXES * skip;
+
+ while ( offset < index ) {
+ meta = locate_meta_index(inode, index, offset + 1);
+
+ if (meta == NULL) {
+ if ((meta = empty_meta_index(inode, offset + 1,
+ skip)) == NULL)
+ goto all_done;
+ } else {
+ offset = index < meta->offset + meta->entries ? index :
+ meta->offset + meta->entries - 1;
+ meta_entry = &meta->meta_entry[offset - meta->offset];
+ cur_index_block = meta_entry->index_block + sblk->inode_table_start;
+ cur_offset = meta_entry->offset;
+ cur_data_block = meta_entry->data_block;
+ TRACE("get_meta_index: offset %d, meta->offset %d, "
+ "meta->entries %d\n", offset, meta->offset,
+ meta->entries);
+ TRACE("get_meta_index: index_block 0x%llx, offset 0x%x"
+ " data_block 0x%llx\n", cur_index_block,
+ cur_offset, cur_data_block);
+ }
+
+ for (i = meta->offset + meta->entries; i <= index &&
+ i < meta->offset + SQUASHFS_META_ENTRIES; i++) {
+ int blocks = skip * SQUASHFS_META_INDEXES;
+
+ while (blocks) {
+ int block = blocks > (SIZE >> 2) ? (SIZE >> 2) :
+ blocks;
+ int res = read_block_index(inode->i_sb, block,
+ block_list, &cur_index_block,
+ &cur_offset);
+
+ if (res == -1)
+ goto failed;
+
+ cur_data_block += res;
+ blocks -= block;
}
- for(block_listp = (unsigned int *) block_list; i < index && blocks; i ++, block_listp ++, blocks --)
- block += SQUASHFS_COMPRESSED_SIZE_BLOCK(*block_listp);
- if(blocks >= readahead_blks)
- break;
+
+ meta_entry = &meta->meta_entry[i - meta->offset];
+ meta_entry->index_block = cur_index_block - sblk->inode_table_start;
+ meta_entry->offset = cur_offset;
+ meta_entry->data_block = cur_data_block;
+ meta->entries ++;
+ offset ++;
+ }
+
+ TRACE("get_meta_index: meta->offset %d, meta->entries %d\n",
+ meta->offset, meta->entries);
+
+ release_meta_index(inode, meta);
}
- *bsize = *block_listp;
+all_done:
+ *index_block = cur_index_block;
+ *index_offset = cur_offset;
+ *data_block = cur_data_block;
+
+ return offset * SQUASHFS_META_INDEXES * skip;
+
+failed:
+ release_meta_index(inode, meta);
+ return -1;
+}
+
+
+static long long read_blocklist(struct inode *inode, int index,
+ int readahead_blks, char *block_list,
+ unsigned short **block_p, unsigned int *bsize)
+{
+ long long block_ptr;
+ int offset;
+ long long block;
+ int res = get_meta_index(inode, index, &block_ptr, &offset, &block,
+ block_list);
+
+ TRACE("read_blocklist: res %d, index %d, block_ptr 0x%llx, offset"
+ " 0x%x, block 0x%llx\n", res, index, block_ptr, offset,
+ block);
+
+ if(res == -1)
+ goto failure;
+
+ index -= res;
+
+ while ( index ) {
+ int blocks = index > (SIZE >> 2) ? (SIZE >> 2) : index;
+ int res = read_block_index(inode->i_sb, blocks, block_list,
+ &block_ptr, &offset);
+ if (res == -1)
+ goto failure;
+ block += res;
+ index -= blocks;
+ }
+
+ if (read_block_index(inode->i_sb, 1, block_list,
+ &block_ptr, &offset) == -1)
+ goto failure;
+ *bsize = *((unsigned int *) block_list);
+
return block;
+
+failure:
+ return 0;
}
static int squashfs_readpage(struct file *file, struct page *page)
{
struct inode *inode = page->mapping->host;
- squashfs_sb_info *msBlk = &inode->i_sb->u.squashfs_sb;
- squashfs_super_block *sBlk = &msBlk->sBlk;
+ struct squashfs_sb_info *msblk = &inode->i_sb->u.squashfs_sb;
+ struct squashfs_super_block *sblk = &msblk->sblk;
unsigned char block_list[SIZE];
- unsigned int bsize, block, i = 0, bytes = 0, byte_offset = 0;
- int index = page->index >> (sBlk->block_log - PAGE_CACHE_SHIFT);
- void *pageaddr = kmap(page);
- struct squashfs_fragment_cache *fragment;
- char *data_ptr = msBlk->read_page;
+ long long block;
+ unsigned int bsize, i = 0, bytes = 0, byte_offset = 0;
+ int index = page->index >> (sblk->block_log - PAGE_CACHE_SHIFT);
+ void *pageaddr;
+ struct squashfs_fragment_cache *fragment = NULL;
+ char *data_ptr = msblk->read_page;
- int mask = (1 << (sBlk->block_log - PAGE_CACHE_SHIFT)) - 1;
+ int mask = (1 << (sblk->block_log - PAGE_CACHE_SHIFT)) - 1;
int start_index = page->index & ~mask;
int end_index = start_index | mask;
- TRACE("Entered squashfs_readpage, page index %x, start block %x\n", (unsigned int) page->index,
- inode->u.squashfs_i.start_block);
+ TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n",
+ page->index,
+ SQUASHFS_I(inode)->start_block);
- if(inode->u.squashfs_i.fragment_start_block == SQUASHFS_INVALID_BLK || index < (inode->i_size >> sBlk->block_log)) {
- if((block = (msBlk->read_blocklist)(inode, index, 1, block_list, NULL, &bsize)) == 0)
+ if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
+ PAGE_CACHE_SHIFT))
+ goto skip_read;
+
+ if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
+ || index < (i_size_read(inode) >>
+ sblk->block_log)) {
+ if ((block = (msblk->read_blocklist)(inode, index, 1,
+ block_list, NULL, &bsize)) == 0)
goto skip_read;
- down(&msBlk->read_page_mutex);
- if(!(bytes = read_data(inode->i_sb, msBlk->read_page, block, bsize, 1, NULL))) {
- ERROR("Unable to read page, block %x, size %x\n", block, bsize);
- up(&msBlk->read_page_mutex);
+ down(&msblk->read_page_mutex);
+
+ if (!(bytes = squashfs_read_data(inode->i_sb, msblk->read_page,
+ block, bsize, NULL))) {
+ ERROR("Unable to read page, block %llx, size %x\n", block,
+ bsize);
+ up(&msblk->read_page_mutex);
goto skip_read;
}
} else {
- if((fragment = get_cached_fragment(inode->i_sb, inode->u.squashfs_i.fragment_start_block, inode->u.squashfs_i.fragment_size)) == NULL) {
- ERROR("Unable to read page, block %x, size %x\n", inode->u.squashfs_i.fragment_start_block, (int) inode->u.squashfs_i.fragment_size);
+ if ((fragment = get_cached_fragment(inode->i_sb,
+ SQUASHFS_I(inode)->
+ u.s1.fragment_start_block,
+ SQUASHFS_I(inode)->u.s1.fragment_size))
+ == NULL) {
+ ERROR("Unable to read page, block %llx, size %x\n",
+ SQUASHFS_I(inode)->
+ u.s1.fragment_start_block,
+ (int) SQUASHFS_I(inode)->
+ u.s1.fragment_size);
goto skip_read;
}
- bytes = inode->u.squashfs_i.fragment_offset + (inode->i_size & (sBlk->block_size - 1));
- byte_offset = inode->u.squashfs_i.fragment_offset;
+ bytes = SQUASHFS_I(inode)->u.s1.fragment_offset +
+ (i_size_read(inode) & (sblk->block_size
+ - 1));
+ byte_offset = SQUASHFS_I(inode)->u.s1.fragment_offset;
data_ptr = fragment->data;
}
- for(i = start_index; i <= end_index && byte_offset < bytes; i++, byte_offset += PAGE_CACHE_SIZE) {
+ for (i = start_index; i <= end_index && byte_offset < bytes;
+ i++, byte_offset += PAGE_CACHE_SIZE) {
struct page *push_page;
- int available_bytes = (bytes - byte_offset) > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE : bytes - byte_offset;
-
- TRACE("bytes %d, i %d, byte_offset %d, available_bytes %d\n", bytes, i, byte_offset, available_bytes);
-
- if(i == page->index) {
- memcpy(pageaddr, data_ptr + byte_offset, available_bytes);
- memset(pageaddr + available_bytes, 0, PAGE_CACHE_SIZE - available_bytes);
- kunmap(page);
+ int available_bytes = (bytes - byte_offset) > PAGE_CACHE_SIZE ?
+ PAGE_CACHE_SIZE : bytes - byte_offset;
+
+ TRACE("bytes %d, i %d, byte_offset %d, available_bytes %d\n",
+ bytes, i, byte_offset, available_bytes);
+
+ if (i == page->index) {
+ pageaddr = kmap_atomic(page, KM_USER0);
+ memcpy(pageaddr, data_ptr + byte_offset,
+ available_bytes);
+ memset(pageaddr + available_bytes, 0,
+ PAGE_CACHE_SIZE - available_bytes);
+ kunmap_atomic(pageaddr, KM_USER0);
flush_dcache_page(page);
SetPageUptodate(page);
UnlockPage(page);
- } else if((push_page = grab_cache_page_nowait(page->mapping, i))) {
- void *pageaddr = kmap(push_page);
- memcpy(pageaddr, data_ptr + byte_offset, available_bytes);
- memset(pageaddr + available_bytes, 0, PAGE_CACHE_SIZE - available_bytes);
- kunmap(push_page);
+ } else if ((push_page =
+ grab_cache_page_nowait(page->mapping, i))) {
+ pageaddr = kmap_atomic(push_page, KM_USER0);
+
+ memcpy(pageaddr, data_ptr + byte_offset,
+ available_bytes);
+ memset(pageaddr + available_bytes, 0,
+ PAGE_CACHE_SIZE - available_bytes);
+ kunmap_atomic(pageaddr, KM_USER0);
flush_dcache_page(push_page);
SetPageUptodate(push_page);
UnlockPage(push_page);
@@ -1219,16 +1575,19 @@ static int squashfs_readpage(struct file *file, struct page *page)
}
}
- if(inode->u.squashfs_i.fragment_start_block == SQUASHFS_INVALID_BLK || index < (inode->i_size >> sBlk->block_log))
- up(&msBlk->read_page_mutex);
+ if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
+ || index < (i_size_read(inode) >>
+ sblk->block_log))
+ up(&msblk->read_page_mutex);
else
- release_cached_fragment(msBlk, fragment);
+ release_cached_fragment(msblk, fragment);
return 0;
skip_read:
+ pageaddr = kmap_atomic(page, KM_USER0);
memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
- kunmap(page);
+ kunmap_atomic(pageaddr, KM_USER0);
flush_dcache_page(page);
SetPageUptodate(page);
UnlockPage(page);
@@ -1240,34 +1599,61 @@ skip_read:
static int squashfs_readpage4K(struct file *file, struct page *page)
{
struct inode *inode = page->mapping->host;
- squashfs_sb_info *msBlk = &inode->i_sb->u.squashfs_sb;
- squashfs_super_block *sBlk = &msBlk->sBlk;
+ struct squashfs_sb_info *msblk = &inode->i_sb->u.squashfs_sb;
+ struct squashfs_super_block *sblk = &msblk->sblk;
unsigned char block_list[SIZE];
- unsigned int bsize, block, bytes = 0;
- void *pageaddr = kmap(page);
+ long long block;
+ unsigned int bsize, bytes = 0;
+ void *pageaddr;
- TRACE("Entered squashfs_readpage4K, page index %x, start block %x\n", (unsigned int) page->index,
- inode->u.squashfs_i.start_block);
+ TRACE("Entered squashfs_readpage4K, page index %lx, start block %llx\n",
+ page->index,
+ SQUASHFS_I(inode)->start_block);
- if(page->index < (inode->i_size >> sBlk->block_log)) {
- block = (msBlk->read_blocklist)(inode, page->index, 1, block_list, NULL, &bsize);
+ if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
+ PAGE_CACHE_SHIFT)) {
+ pageaddr = kmap_atomic(page, KM_USER0);
+ goto skip_read;
+ }
- if(!(bytes = read_data(inode->i_sb, pageaddr, block, bsize, 1, NULL)))
- ERROR("Unable to read page, block %x, size %x\n", block, bsize);
+ if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
+ || page->index < (i_size_read(inode) >>
+ sblk->block_log)) {
+ block = (msblk->read_blocklist)(inode, page->index, 1,
+ block_list, NULL, &bsize);
+
+ down(&msblk->read_page_mutex);
+ bytes = squashfs_read_data(inode->i_sb, msblk->read_page, block,
+ bsize, NULL);
+ pageaddr = kmap_atomic(page, KM_USER0);
+ if (bytes)
+ memcpy(pageaddr, msblk->read_page, bytes);
+ else
+ ERROR("Unable to read page, block %llx, size %x\n",
+ block, bsize);
+ up(&msblk->read_page_mutex);
} else {
- struct squashfs_fragment_cache *fragment;
-
- if((fragment = get_cached_fragment(inode->i_sb, inode->u.squashfs_i.fragment_start_block, inode->u.squashfs_i.fragment_size)) == NULL)
- ERROR("Unable to read page, block %x, size %x\n", inode->u.squashfs_i.fragment_start_block, (int) inode->u.squashfs_i.fragment_size);
- else {
- bytes = inode->i_size & (sBlk->block_size - 1);
- memcpy(pageaddr, fragment->data + inode->u.squashfs_i.fragment_offset, bytes);
- release_cached_fragment(msBlk, fragment);
- }
+ struct squashfs_fragment_cache *fragment =
+ get_cached_fragment(inode->i_sb,
+ SQUASHFS_I(inode)->
+ u.s1.fragment_start_block,
+ SQUASHFS_I(inode)-> u.s1.fragment_size);
+ pageaddr = kmap_atomic(page, KM_USER0);
+ if (fragment) {
+ bytes = i_size_read(inode) & (sblk->block_size - 1);
+ memcpy(pageaddr, fragment->data + SQUASHFS_I(inode)->
+ u.s1.fragment_offset, bytes);
+ release_cached_fragment(msblk, fragment);
+ } else
+ ERROR("Unable to read page, block %llx, size %x\n",
+ SQUASHFS_I(inode)->
+ u.s1.fragment_start_block, (int)
+ SQUASHFS_I(inode)-> u.s1.fragment_size);
}
+skip_read:
memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
- kunmap(page);
+ kunmap_atomic(pageaddr, KM_USER0);
flush_dcache_page(page);
SetPageUptodate(page);
UnlockPage(page);
@@ -1276,191 +1662,331 @@ static int squashfs_readpage4K(struct file *file, struct page *page)
}
-#ifdef SQUASHFS_1_0_COMPATIBILITY
-static int squashfs_readpage_lessthan4K(struct file *file, struct page *page)
+static int get_dir_index_using_offset(struct super_block *s, long long
+ *next_block, unsigned int *next_offset,
+ long long index_start,
+ unsigned int index_offset, int i_count,
+ long long f_pos)
{
- struct inode *inode = page->mapping->host;
- squashfs_sb_info *msBlk = &inode->i_sb->u.squashfs_sb;
- squashfs_super_block *sBlk = &msBlk->sBlk;
- unsigned char block_list[SIZE];
- unsigned short *block_listp, block, bytes = 0;
- int index = page->index << (PAGE_CACHE_SHIFT - sBlk->block_log);
- int file_blocks = ((inode->i_size - 1) >> sBlk->block_log) + 1;
- int readahead_blks = 1 << (PAGE_CACHE_SHIFT - sBlk->block_log);
- void *pageaddr = kmap(page);
-
- int i_end = index + (1 << (PAGE_CACHE_SHIFT - sBlk->block_log));
- int byte;
-
- TRACE("Entered squashfs_readpage_lessthan4K, page index %x, start block %x\n", (unsigned int) page->index,
- inode->u.squashfs_i.start_block);
+ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
+ struct squashfs_super_block *sblk = &msblk->sblk;
+ int i, length = 0;
+ struct squashfs_dir_index index;
+
+ TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n",
+ i_count, (unsigned int) f_pos);
+
+ f_pos -= 3;
+ if (f_pos == 0)
+ goto finish;
+
+ for (i = 0; i < i_count; i++) {
+ if (msblk->swap) {
+ struct squashfs_dir_index sindex;
+ squashfs_get_cached_block(s, (char *) &sindex,
+ index_start, index_offset,
+ sizeof(sindex), &index_start,
+ &index_offset);
+ SQUASHFS_SWAP_DIR_INDEX(&index, &sindex);
+ } else
+ squashfs_get_cached_block(s, (char *) &index,
+ index_start, index_offset,
+ sizeof(index), &index_start,
+ &index_offset);
- block = read_blocklist_1(inode, index, readahead_blks, block_list, (char **) &block_listp, NULL);
+ if (index.index > f_pos)
+ break;
- if(i_end > file_blocks)
- i_end = file_blocks;
+ squashfs_get_cached_block(s, NULL, index_start, index_offset,
+ index.size + 1, &index_start,
+ &index_offset);
- while(index < i_end) {
- if(!(byte = read_data(inode->i_sb, pageaddr, block, *block_listp, 0, NULL))) {
- ERROR("Unable to read page, block %x, size %x\n", block, *block_listp);
- goto skip_read;
- }
- block += SQUASHFS_COMPRESSED_SIZE(*block_listp);
- pageaddr += byte;
- bytes += byte;
- index ++;
- block_listp ++;
+ length = index.index;
+ *next_block = index.start_block + sblk->directory_table_start;
}
-skip_read:
- memset(pageaddr, 0, PAGE_CACHE_SIZE - bytes);
- kunmap(page);
- flush_dcache_page(page);
- SetPageUptodate(page);
- UnlockPage(page);
+ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
- return 0;
+finish:
+ return length + 3;
}
-#endif
+static int get_dir_index_using_name(struct super_block *s, long long
+ *next_block, unsigned int *next_offset,
+ long long index_start,
+ unsigned int index_offset, int i_count,
+ const char *name, int size)
+{
+ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
+ struct squashfs_super_block *sblk = &msblk->sblk;
+ int i, length = 0;
+ char buffer[sizeof(struct squashfs_dir_index) + SQUASHFS_NAME_LEN + 1];
+ struct squashfs_dir_index *index = (struct squashfs_dir_index *) buffer;
+ char str[SQUASHFS_NAME_LEN + 1];
+
+ TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count);
+
+ strncpy(str, name, size);
+ str[size] = '\0';
+
+ for (i = 0; i < i_count; i++) {
+ if (msblk->swap) {
+ struct squashfs_dir_index sindex;
+ squashfs_get_cached_block(s, (char *) &sindex,
+ index_start, index_offset,
+ sizeof(sindex), &index_start,
+ &index_offset);
+ SQUASHFS_SWAP_DIR_INDEX(index, &sindex);
+ } else
+ squashfs_get_cached_block(s, (char *) index,
+ index_start, index_offset,
+ sizeof(struct squashfs_dir_index),
+ &index_start, &index_offset);
+
+ squashfs_get_cached_block(s, index->name, index_start,
+ index_offset, index->size + 1,
+ &index_start, &index_offset);
+
+ index->name[index->size + 1] = '\0';
+
+ if (strcmp(index->name, str) > 0)
+ break;
+
+ length = index->index;
+ *next_block = index->start_block + sblk->directory_table_start;
+ }
+
+ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
+ return length + 3;
+}
+
+
static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir)
{
struct inode *i = file->f_dentry->d_inode;
- squashfs_sb_info *msBlk = &i->i_sb->u.squashfs_sb;
- squashfs_super_block *sBlk = &msBlk->sBlk;
- int next_block = i->u.squashfs_i.start_block + sBlk->directory_table_start, next_offset =
- i->u.squashfs_i.offset, length = 0, dirs_read = 0, dir_count;
- squashfs_dir_header dirh;
- char buffer[sizeof(squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1];
- squashfs_dir_entry *dire = (squashfs_dir_entry *) buffer;
+ struct squashfs_sb_info *msblk = &i->i_sb->u.squashfs_sb;
+ struct squashfs_super_block *sblk = &msblk->sblk;
+ long long next_block = SQUASHFS_I(i)->start_block +
+ sblk->directory_table_start;
+ int next_offset = SQUASHFS_I(i)->offset, length = 0, dirs_read = 0,
+ dir_count;
+ struct squashfs_dir_header dirh;
+ char buffer[sizeof(struct squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1];
+ struct squashfs_dir_entry *dire = (struct squashfs_dir_entry *) buffer;
+
+ TRACE("Entered squashfs_readdir [%llx:%x]\n", next_block, next_offset);
+
+ while(file->f_pos < 3) {
+ char *name;
+ int size, i_ino;
+
+ if(file->f_pos == 0) {
+ name = ".";
+ size = 1;
+ i_ino = i->i_ino;
+ } else {
+ name = "..";
+ size = 2;
+ i_ino = SQUASHFS_I(i)->u.s2.parent_inode;
+ }
+ TRACE("Calling filldir(%x, %s, %d, %d, %d, %d)\n",
+ (unsigned int) dirent, name, size, (int)
+ file->f_pos, i_ino,
+ squashfs_filetype_table[1]);
+
+ if (filldir(dirent, name, size,
+ file->f_pos, i_ino,
+ squashfs_filetype_table[1]) < 0) {
+ TRACE("Filldir returned less than 0\n");
+ goto finish;
+ }
+ file->f_pos += size;
+ dirs_read++;
+ }
- TRACE("Entered squashfs_readdir [%x:%x]\n", next_block, next_offset);
+ length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset,
+ SQUASHFS_I(i)->u.s2.directory_index_start,
+ SQUASHFS_I(i)->u.s2.directory_index_offset,
+ SQUASHFS_I(i)->u.s2.directory_index_count,
+ file->f_pos);
- while(length < i->i_size) {
+ while (length < i_size_read(i)) {
/* read directory header */
- if(msBlk->swap) {
- squashfs_dir_header sdirh;
- if(!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, next_block,
- next_offset, sizeof(sdirh), &next_block, &next_offset))
+ if (msblk->swap) {
+ struct squashfs_dir_header sdirh;
+
+ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
+ next_block, next_offset, sizeof(sdirh),
+ &next_block, &next_offset))
goto failed_read;
+
length += sizeof(sdirh);
SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
} else {
- if(!squashfs_get_cached_block(i->i_sb, (char *) &dirh, next_block,
- next_offset, sizeof(dirh), &next_block, &next_offset))
+ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
+ next_block, next_offset, sizeof(dirh),
+ &next_block, &next_offset))
goto failed_read;
+
length += sizeof(dirh);
}
dir_count = dirh.count + 1;
- while(dir_count--) {
- if(msBlk->swap) {
- squashfs_dir_entry sdire;
- if(!squashfs_get_cached_block(i->i_sb, (char *) &sdire, next_block,
- next_offset, sizeof(sdire), &next_block, &next_offset))
+ while (dir_count--) {
+ if (msblk->swap) {
+ struct squashfs_dir_entry sdire;
+ if (!squashfs_get_cached_block(i->i_sb, (char *)
+ &sdire, next_block, next_offset,
+ sizeof(sdire), &next_block,
+ &next_offset))
goto failed_read;
+
length += sizeof(sdire);
SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
} else {
- if(!squashfs_get_cached_block(i->i_sb, (char *) dire, next_block,
- next_offset, sizeof(*dire), &next_block, &next_offset))
+ if (!squashfs_get_cached_block(i->i_sb, (char *)
+ dire, next_block, next_offset,
+ sizeof(*dire), &next_block,
+ &next_offset))
goto failed_read;
+
length += sizeof(*dire);
}
- if(!squashfs_get_cached_block(i->i_sb, dire->name, next_block,
- next_offset, dire->size + 1, &next_block, &next_offset))
+ if (!squashfs_get_cached_block(i->i_sb, dire->name,
+ next_block, next_offset,
+ dire->size + 1, &next_block,
+ &next_offset))
goto failed_read;
+
length += dire->size + 1;
- if(file->f_pos >= length)
+ if (file->f_pos >= length)
continue;
dire->name[dire->size + 1] = '\0';
- TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d)\n", (unsigned int) dirent,
- dire->name, dire->size + 1, (int) file->f_pos,
- dirh.start_block, dire->offset, squashfs_filetype_table[dire->type]);
-
- if(filldir(dirent, dire->name, dire->size + 1, file->f_pos, SQUASHFS_MK_VFS_INODE(dirh.start_block,
- dire->offset), squashfs_filetype_table[dire->type]) < 0) {
+ TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d, %d)\n",
+ (unsigned int) dirent, dire->name,
+ dire->size + 1, (int) file->f_pos,
+ dirh.start_block, dire->offset,
+ dirh.inode_number + dire->inode_number,
+ squashfs_filetype_table[dire->type]);
+
+ if (filldir(dirent, dire->name, dire->size + 1,
+ file->f_pos,
+ dirh.inode_number + dire->inode_number,
+ squashfs_filetype_table[dire->type])
+ < 0) {
TRACE("Filldir returned less than 0\n");
- return dirs_read;
+ goto finish;
}
-
file->f_pos = length;
- dirs_read ++;
+ dirs_read++;
}
}
+finish:
return dirs_read;
failed_read:
- ERROR("Unable to read directory block [%x:%x]\n", next_block, next_offset);
+ ERROR("Unable to read directory block [%llx:%x]\n", next_block,
+ next_offset);
return 0;
}
static struct dentry *squashfs_lookup(struct inode *i, struct dentry *dentry)
{
- const char *name =dentry->d_name.name;
+ const unsigned char *name = dentry->d_name.name;
int len = dentry->d_name.len;
struct inode *inode = NULL;
- squashfs_sb_info *msBlk = &i->i_sb->u.squashfs_sb;
- squashfs_super_block *sBlk = &msBlk->sBlk;
- int next_block = i->u.squashfs_i.start_block + sBlk->directory_table_start, next_offset =
- i->u.squashfs_i.offset, length = 0, dir_count;
- squashfs_dir_header dirh;
- char buffer[sizeof(squashfs_dir_entry) + SQUASHFS_NAME_LEN];
- squashfs_dir_entry *dire = (squashfs_dir_entry *) buffer;
-
- TRACE("Entered squashfs_lookup [%x:%x]\n", next_block, next_offset);
-
- while(length < i->i_size) {
+ struct squashfs_sb_info *msblk = &i->i_sb->u.squashfs_sb;
+ struct squashfs_super_block *sblk = &msblk->sblk;
+ long long next_block = SQUASHFS_I(i)->start_block +
+ sblk->directory_table_start;
+ int next_offset = SQUASHFS_I(i)->offset, length = 0,
+ dir_count;
+ struct squashfs_dir_header dirh;
+ char buffer[sizeof(struct squashfs_dir_entry) + SQUASHFS_NAME_LEN];
+ struct squashfs_dir_entry *dire = (struct squashfs_dir_entry *) buffer;
+
+ TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block, next_offset);
+
+ if (len > SQUASHFS_NAME_LEN)
+ goto exit_loop;
+
+ length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset,
+ SQUASHFS_I(i)->u.s2.directory_index_start,
+ SQUASHFS_I(i)->u.s2.directory_index_offset,
+ SQUASHFS_I(i)->u.s2.directory_index_count, name,
+ len);
+
+ while (length < i_size_read(i)) {
/* read directory header */
- if(msBlk->swap) {
- squashfs_dir_header sdirh;
- if(!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, next_block, next_offset,
- sizeof(sdirh), &next_block, &next_offset))
+ if (msblk->swap) {
+ struct squashfs_dir_header sdirh;
+ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
+ next_block, next_offset, sizeof(sdirh),
+ &next_block, &next_offset))
goto failed_read;
+
length += sizeof(sdirh);
SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
} else {
- if(!squashfs_get_cached_block(i->i_sb, (char *) &dirh, next_block, next_offset,
- sizeof(dirh), &next_block, &next_offset))
+ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
+ next_block, next_offset, sizeof(dirh),
+ &next_block, &next_offset))
goto failed_read;
+
length += sizeof(dirh);
}
dir_count = dirh.count + 1;
- while(dir_count--) {
- if(msBlk->swap) {
- squashfs_dir_entry sdire;
- if(!squashfs_get_cached_block(i->i_sb, (char *) &sdire,
- next_block,next_offset, sizeof(sdire), &next_block, &next_offset))
+ while (dir_count--) {
+ if (msblk->swap) {
+ struct squashfs_dir_entry sdire;
+ if (!squashfs_get_cached_block(i->i_sb, (char *)
+ &sdire, next_block,next_offset,
+ sizeof(sdire), &next_block,
+ &next_offset))
goto failed_read;
+
length += sizeof(sdire);
SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
} else {
- if(!squashfs_get_cached_block(i->i_sb, (char *) dire,
- next_block,next_offset, sizeof(*dire), &next_block, &next_offset))
+ if (!squashfs_get_cached_block(i->i_sb, (char *)
+ dire, next_block,next_offset,
+ sizeof(*dire), &next_block,
+ &next_offset))
goto failed_read;
+
length += sizeof(*dire);
}
- if(!squashfs_get_cached_block(i->i_sb, dire->name,
- next_block, next_offset, dire->size + 1, &next_block, &next_offset))
+ if (!squashfs_get_cached_block(i->i_sb, dire->name,
+ next_block, next_offset, dire->size + 1,
+ &next_block, &next_offset))
goto failed_read;
+
length += dire->size + 1;
- if((len == dire->size + 1) && !strncmp(name, dire->name, len)) {
- squashfs_inode ino = SQUASHFS_MKINODE(dirh.start_block, dire->offset);
+ if (name[0] < dire->name[0])
+ goto exit_loop;
+
+ if ((len == dire->size + 1) && !strncmp(name,
+ dire->name, len)) {
+ squashfs_inode_t ino =
+ SQUASHFS_MKINODE(dirh.start_block,
+ dire->offset);
- TRACE("calling squashfs_iget for directory entry %s, inode %x:%x\n",
- name, dirh.start_block, dire->offset);
+ TRACE("calling squashfs_iget for directory "
+ "entry %s, inode %x:%x, %d\n", name,
+ dirh.start_block, dire->offset,
+ dirh.inode_number + dire->inode_number);
- inode = (msBlk->iget)(i->i_sb, ino);
+ inode = (msblk->iget)(i->i_sb, ino);
goto exit_loop;
}
@@ -1472,36 +1998,63 @@ exit_loop:
return ERR_PTR(0);
failed_read:
- ERROR("Unable to read directory block [%x:%x]\n", next_block, next_offset);
+ ERROR("Unable to read directory block [%llx:%x]\n", next_block,
+ next_offset);
goto exit_loop;
}
static void squashfs_put_super(struct super_block *s)
{
- if(s->u.squashfs_sb.block_cache) kfree(s->u.squashfs_sb.block_cache);
- if(s->u.squashfs_sb.read_data) kfree(s->u.squashfs_sb.read_data);
- if(s->u.squashfs_sb.read_page) kfree(s->u.squashfs_sb.read_page);
- if(s->u.squashfs_sb.uid) kfree(s->u.squashfs_sb.uid);
- s->u.squashfs_sb.block_cache = (void *) s->u.squashfs_sb.uid =
- s->u.squashfs_sb.read_data = s->u.squashfs_sb.read_page = NULL;
+ int i;
+
+ struct squashfs_sb_info *sbi = &s->u.squashfs_sb;
+ if (sbi->block_cache)
+ for (i = 0; i < SQUASHFS_CACHED_BLKS; i++)
+ if (sbi->block_cache[i].block !=
+ SQUASHFS_INVALID_BLK)
+ kfree(sbi->block_cache[i].data);
+ if (sbi->fragment)
+ for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++)
+ SQUASHFS_FREE(sbi->fragment[i].data);
+ kfree(sbi->fragment);
+ kfree(sbi->block_cache);
+ kfree(sbi->read_data);
+ kfree(sbi->read_page);
+ kfree(sbi->uid);
+ kfree(sbi->fragment_index);
+ kfree(sbi->fragment_index_2);
+ sbi->block_cache = NULL;
+ sbi->uid = NULL;
+ sbi->read_data = NULL;
+ sbi->read_page = NULL;
+ sbi->fragment = NULL;
+ sbi->fragment_index = NULL;
+ sbi->fragment_index_2 = NULL;
}
static int __init init_squashfs_fs(void)
{
- if(!(stream.workspace = (char *) vmalloc(zlib_inflate_workspacesize()))) {
+ printk(KERN_INFO "squashfs: version 3.0 (2006/03/15) "
+ "Phillip Lougher\n");
+
+#ifndef SQUASHFS_LZMA
+ if (!(stream.workspace = vmalloc(zlib_inflate_workspacesize()))) {
ERROR("Failed to allocate zlib workspace\n");
return -ENOMEM;
}
+#endif
return register_filesystem(&squashfs_fs_type);
}
static void __exit exit_squashfs_fs(void)
{
+#ifndef SQUASHFS_LZMA
vfree(stream.workspace);
+#endif
unregister_filesystem(&squashfs_fs_type);
}
@@ -1511,5 +2064,5 @@ EXPORT_NO_SYMBOLS;
module_init(init_squashfs_fs);
module_exit(exit_squashfs_fs);
MODULE_DESCRIPTION("squashfs, a compressed read-only filesystem");
-MODULE_AUTHOR("Phillip Lougher <plougher@users.sourceforge.net>");
+MODULE_AUTHOR("Phillip Lougher <phillip@lougher.org.uk>");
MODULE_LICENSE("GPL");
diff --git a/release/src/linux/linux/fs/squashfs/squashfs.h b/release/src/linux/linux/fs/squashfs/squashfs.h
new file mode 100644
index 00000000..e53ceeff
--- /dev/null
+++ b/release/src/linux/linux/fs/squashfs/squashfs.h
@@ -0,0 +1,85 @@
+/*
+ * Squashfs - a compressed read only filesystem for Linux
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006
+ * Phillip Lougher <phillip@lougher.org.uk>
+ *
+ * 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,
+ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * squashfs.h
+ */
+
+#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
+#undef CONFIG_SQUASHFS_1_0_COMPATIBILITY
+#endif
+#ifdef SQUASHFS_TRACE
+#define TRACE(s, args...) printk(KERN_NOTICE "SQUASHFS: "s, ## args)
+#else
+#define TRACE(s, args...) {}
+#endif
+
+#define ERROR(s, args...) printk(KERN_ERR "SQUASHFS error: "s, ## args)
+
+#define SERROR(s, args...) do { \
+ if (!silent) \
+ printk(KERN_ERR "SQUASHFS error: "s, ## args);\
+ } while(0)
+
+#define WARNING(s, args...) printk(KERN_WARNING "SQUASHFS: "s, ## args)
+
+#define SQUASHFS_I(INO) (&INO->u.squashfs_i)
+
+#define i_size_read(INO) (INO->i_size)
+
+#if defined(CONFIG_SQUASHFS_1_0_COMPATIBILITY ) || defined(CONFIG_SQUASHFS_2_0_COMPATIBILITY)
+#define SQSH_EXTERN
+extern unsigned int squashfs_read_data(struct super_block *s, char *buffer,
+ long long index, unsigned int length,
+ long long *next_index);
+extern int squashfs_get_cached_block(struct super_block *s, char *buffer,
+ long long block, unsigned int offset,
+ int length, long long *next_block,
+ unsigned int *next_offset);
+extern void release_cached_fragment(struct squashfs_sb_info *msblk, struct
+ squashfs_fragment_cache *fragment);
+extern struct squashfs_fragment_cache *get_cached_fragment(struct super_block
+ *s, long long start_block,
+ int length);
+extern struct address_space_operations squashfs_symlink_aops;
+extern struct address_space_operations squashfs_aops;
+extern struct address_space_operations squashfs_aops_4K;
+extern struct file_operations squashfs_dir_ops;
+extern struct inode_operations squashfs_dir_inode_ops;
+#else
+#define SQSH_EXTERN static
+#endif
+
+#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
+extern int squashfs_1_0_supported(struct squashfs_sb_info *msblk);
+#else
+static inline int squashfs_1_0_supported(struct squashfs_sb_info *msblk)
+{
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY
+extern int squashfs_2_0_supported(struct squashfs_sb_info *msblk);
+#else
+static inline int squashfs_2_0_supported(struct squashfs_sb_info *msblk)
+{
+ return 0;
+}
+#endif
diff --git a/release/src/linux/linux/fs/squashfs/squashfs2_0.c b/release/src/linux/linux/fs/squashfs/squashfs2_0.c
new file mode 100644
index 00000000..d4efd8a9
--- /dev/null
+++ b/release/src/linux/linux/fs/squashfs/squashfs2_0.c
@@ -0,0 +1,751 @@
+/*
+ * Squashfs - a compressed read only filesystem for Linux
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006
+ * Phillip Lougher <phillip@lougher.org.uk>
+ *
+ * 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,
+ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * squashfs2_0.c
+ */
+
+#include <linux/types.h>
+#include <linux/squashfs_fs.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/smp_lock.h>
+#include <linux/locks.h>
+#include <linux/init.h>
+#include <linux/dcache.h>
+#include <linux/wait.h>
+#include <linux/zlib.h>
+#include <linux/blkdev.h>
+#include <linux/vmalloc.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+#include "squashfs.h"
+
+static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir);
+static struct dentry *squashfs_lookup_2(struct inode *i, struct dentry *dentry);
+
+static struct file_operations squashfs_dir_ops_2 = {
+ .read = generic_read_dir,
+ .readdir = squashfs_readdir_2
+};
+
+static struct inode_operations squashfs_dir_inode_ops_2 = {
+ .lookup = squashfs_lookup_2
+};
+
+static unsigned char squashfs_filetype_table[] = {
+ DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK
+};
+
+static int read_fragment_index_table_2(struct super_block *s)
+{
+ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
+ struct squashfs_super_block *sblk = &msblk->sblk;
+
+ if (!(msblk->fragment_index_2 = kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES_2
+ (sblk->fragments), GFP_KERNEL))) {
+ ERROR("Failed to allocate uid/gid table\n");
+ return 0;
+ }
+
+ if (SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments) &&
+ !squashfs_read_data(s, (char *)
+ msblk->fragment_index_2,
+ sblk->fragment_table_start,
+ SQUASHFS_FRAGMENT_INDEX_BYTES_2
+ (sblk->fragments) |
+ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
+ ERROR("unable to read fragment index table\n");
+ return 0;
+ }
+
+ if (msblk->swap) {
+ int i;
+ unsigned int fragment;
+
+ for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES_2(sblk->fragments);
+ i++) {
+ SQUASHFS_SWAP_FRAGMENT_INDEXES_2((&fragment),
+ &msblk->fragment_index_2[i], 1);
+ msblk->fragment_index_2[i] = fragment;
+ }
+ }
+
+ return 1;
+}
+
+
+static int get_fragment_location_2(struct super_block *s, unsigned int fragment,
+ long long *fragment_start_block,
+ unsigned int *fragment_size)
+{
+ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
+ long long start_block =
+ msblk->fragment_index_2[SQUASHFS_FRAGMENT_INDEX_2(fragment)];
+ int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET_2(fragment);
+ struct squashfs_fragment_entry_2 fragment_entry;
+
+ if (msblk->swap) {
+ struct squashfs_fragment_entry_2 sfragment_entry;
+
+ if (!squashfs_get_cached_block(s, (char *) &sfragment_entry,
+ start_block, offset,
+ sizeof(sfragment_entry), &start_block,
+ &offset))
+ goto out;
+ SQUASHFS_SWAP_FRAGMENT_ENTRY_2(&fragment_entry, &sfragment_entry);
+ } else
+ if (!squashfs_get_cached_block(s, (char *) &fragment_entry,
+ start_block, offset,
+ sizeof(fragment_entry), &start_block,
+ &offset))
+ goto out;
+
+ *fragment_start_block = fragment_entry.start_block;
+ *fragment_size = fragment_entry.size;
+
+ return 1;
+
+out:
+ return 0;
+}
+
+
+static struct inode *squashfs_new_inode(struct super_block *s,
+ struct squashfs_base_inode_header_2 *inodeb, unsigned int ino)
+{
+ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
+ struct squashfs_super_block *sblk = &msblk->sblk;
+ struct inode *i = new_inode(s);
+
+ if (i) {
+ i->i_ino = ino;
+ i->i_mtime = sblk->mkfs_time;
+ i->i_atime = sblk->mkfs_time;
+ i->i_ctime = sblk->mkfs_time;
+ i->i_uid = msblk->uid[inodeb->uid];
+ i->i_mode = inodeb->mode;
+ i->i_nlink = 1;
+ i->i_size = 0;
+ if (inodeb->guid == SQUASHFS_GUIDS)
+ i->i_gid = i->i_uid;
+ else
+ i->i_gid = msblk->guid[inodeb->guid];
+ }
+
+ return i;
+}
+
+
+static struct inode *squashfs_iget_2(struct super_block *s, squashfs_inode_t inode)
+{
+ struct inode *i;
+ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
+ struct squashfs_super_block *sblk = &msblk->sblk;
+ unsigned int block = SQUASHFS_INODE_BLK(inode) +
+ sblk->inode_table_start;
+ unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
+ unsigned int ino = SQUASHFS_MK_VFS_INODE(block
+ - sblk->inode_table_start, offset);
+ long long next_block;
+ unsigned int next_offset;
+ union squashfs_inode_header_2 id, sid;
+ struct squashfs_base_inode_header_2 *inodeb = &id.base,
+ *sinodeb = &sid.base;
+
+ TRACE("Entered squashfs_iget\n");
+
+ if (msblk->swap) {
+ if (!squashfs_get_cached_block(s, (char *) sinodeb, block,
+ offset, sizeof(*sinodeb), &next_block,
+ &next_offset))
+ goto failed_read;
+ SQUASHFS_SWAP_BASE_INODE_HEADER_2(inodeb, sinodeb,
+ sizeof(*sinodeb));
+ } else
+ if (!squashfs_get_cached_block(s, (char *) inodeb, block,
+ offset, sizeof(*inodeb), &next_block,
+ &next_offset))
+ goto failed_read;
+
+ switch(inodeb->inode_type) {
+ case SQUASHFS_FILE_TYPE: {
+ struct squashfs_reg_inode_header_2 *inodep = &id.reg;
+ struct squashfs_reg_inode_header_2 *sinodep = &sid.reg;
+ long long frag_blk;
+ unsigned int frag_size;
+
+ if (msblk->swap) {
+ if (!squashfs_get_cached_block(s, (char *)
+ sinodep, block, offset,
+ sizeof(*sinodep), &next_block,
+ &next_offset))
+ goto failed_read;
+ SQUASHFS_SWAP_REG_INODE_HEADER_2(inodep, sinodep);
+ } else
+ if (!squashfs_get_cached_block(s, (char *)
+ inodep, block, offset,
+ sizeof(*inodep), &next_block,
+ &next_offset))
+ goto failed_read;
+
+ frag_blk = SQUASHFS_INVALID_BLK;
+ if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
+ !get_fragment_location_2(s,
+ inodep->fragment, &frag_blk, &frag_size))
+ goto failed_read;
+
+ if((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
+ goto failed_read1;
+
+ i->i_size = inodep->file_size;
+ i->i_fop = &generic_ro_fops;
+ i->i_mode |= S_IFREG;
+ i->i_mtime = inodep->mtime;
+ i->i_atime = inodep->mtime;
+ i->i_ctime = inodep->mtime;
+ i->i_blocks = ((i->i_size - 1) >> 9) + 1;
+ i->i_blksize = PAGE_CACHE_SIZE;
+ SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
+ SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
+ SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
+ SQUASHFS_I(i)->start_block = inodep->start_block;
+ SQUASHFS_I(i)->u.s1.block_list_start = next_block;
+ SQUASHFS_I(i)->offset = next_offset;
+ if (sblk->block_size > 4096)
+ i->i_data.a_ops = &squashfs_aops;
+ else
+ i->i_data.a_ops = &squashfs_aops_4K;
+
+ TRACE("File inode %x:%x, start_block %x, "
+ "block_list_start %llx, offset %x\n",
+ SQUASHFS_INODE_BLK(inode), offset,
+ inodep->start_block, next_block,
+ next_offset);
+ break;
+ }
+ case SQUASHFS_DIR_TYPE: {
+ struct squashfs_dir_inode_header_2 *inodep = &id.dir;
+ struct squashfs_dir_inode_header_2 *sinodep = &sid.dir;
+
+ if (msblk->swap) {
+ if (!squashfs_get_cached_block(s, (char *)
+ sinodep, block, offset,
+ sizeof(*sinodep), &next_block,
+ &next_offset))
+ goto failed_read;
+ SQUASHFS_SWAP_DIR_INODE_HEADER_2(inodep, sinodep);
+ } else
+ if (!squashfs_get_cached_block(s, (char *)
+ inodep, block, offset,
+ sizeof(*inodep), &next_block,
+ &next_offset))
+ goto failed_read;
+
+ if((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
+ goto failed_read1;
+
+ i->i_size = inodep->file_size;
+ i->i_op = &squashfs_dir_inode_ops_2;
+ i->i_fop = &squashfs_dir_ops_2;
+ i->i_mode |= S_IFDIR;
+ i->i_mtime = inodep->mtime;
+ i->i_atime = inodep->mtime;
+ i->i_ctime = inodep->mtime;
+ SQUASHFS_I(i)->start_block = inodep->start_block;
+ SQUASHFS_I(i)->offset = inodep->offset;
+ SQUASHFS_I(i)->u.s2.directory_index_count = 0;
+ SQUASHFS_I(i)->u.s2.parent_inode = 0;
+
+ TRACE("Directory inode %x:%x, start_block %x, offset "
+ "%x\n", SQUASHFS_INODE_BLK(inode),
+ offset, inodep->start_block,
+ inodep->offset);
+ break;
+ }
+ case SQUASHFS_LDIR_TYPE: {
+ struct squashfs_ldir_inode_header_2 *inodep = &id.ldir;
+ struct squashfs_ldir_inode_header_2 *sinodep = &sid.ldir;
+
+ if (msblk->swap) {
+ if (!squashfs_get_cached_block(s, (char *)
+ sinodep, block, offset,
+ sizeof(*sinodep), &next_block,
+ &next_offset))
+ goto failed_read;
+ SQUASHFS_SWAP_LDIR_INODE_HEADER_2(inodep,
+ sinodep);
+ } else
+ if (!squashfs_get_cached_block(s, (char *)
+ inodep, block, offset,
+ sizeof(*inodep), &next_block,
+ &next_offset))
+ goto failed_read;
+
+ if((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
+ goto failed_read1;
+
+ i->i_size = inodep->file_size;
+ i->i_op = &squashfs_dir_inode_ops_2;
+ i->i_fop = &squashfs_dir_ops_2;
+ i->i_mode |= S_IFDIR;
+ i->i_mtime = inodep->mtime;
+ i->i_atime = inodep->mtime;
+ i->i_ctime = inodep->mtime;
+ SQUASHFS_I(i)->start_block = inodep->start_block;
+ SQUASHFS_I(i)->offset = inodep->offset;
+ SQUASHFS_I(i)->u.s2.directory_index_start = next_block;
+ SQUASHFS_I(i)->u.s2.directory_index_offset =
+ next_offset;
+ SQUASHFS_I(i)->u.s2.directory_index_count =
+ inodep->i_count;
+ SQUASHFS_I(i)->u.s2.parent_inode = 0;
+
+ TRACE("Long directory inode %x:%x, start_block %x, "
+ "offset %x\n",
+ SQUASHFS_INODE_BLK(inode), offset,
+ inodep->start_block, inodep->offset);
+ break;
+ }
+ case SQUASHFS_SYMLINK_TYPE: {
+ struct squashfs_symlink_inode_header_2 *inodep =
+ &id.symlink;
+ struct squashfs_symlink_inode_header_2 *sinodep =
+ &sid.symlink;
+
+ if (msblk->swap) {
+ if (!squashfs_get_cached_block(s, (char *)
+ sinodep, block, offset,
+ sizeof(*sinodep), &next_block,
+ &next_offset))
+ goto failed_read;
+ SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(inodep,
+ sinodep);
+ } else
+ if (!squashfs_get_cached_block(s, (char *)
+ inodep, block, offset,
+ sizeof(*inodep), &next_block,
+ &next_offset))
+ goto failed_read;
+
+ if((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
+ goto failed_read1;
+
+ i->i_size = inodep->symlink_size;
+ i->i_op = &page_symlink_inode_operations;
+ i->i_data.a_ops = &squashfs_symlink_aops;
+ i->i_mode |= S_IFLNK;
+ SQUASHFS_I(i)->start_block = next_block;
+ SQUASHFS_I(i)->offset = next_offset;
+
+ TRACE("Symbolic link inode %x:%x, start_block %llx, "
+ "offset %x\n",
+ SQUASHFS_INODE_BLK(inode), offset,
+ next_block, next_offset);
+ break;
+ }
+ case SQUASHFS_BLKDEV_TYPE:
+ case SQUASHFS_CHRDEV_TYPE: {
+ struct squashfs_dev_inode_header_2 *inodep = &id.dev;
+ struct squashfs_dev_inode_header_2 *sinodep = &sid.dev;
+
+ if (msblk->swap) {
+ if (!squashfs_get_cached_block(s, (char *)
+ sinodep, block, offset,
+ sizeof(*sinodep), &next_block,
+ &next_offset))
+ goto failed_read;
+ SQUASHFS_SWAP_DEV_INODE_HEADER_2(inodep, sinodep);
+ } else
+ if (!squashfs_get_cached_block(s, (char *)
+ inodep, block, offset,
+ sizeof(*inodep), &next_block,
+ &next_offset))
+ goto failed_read;
+
+ if ((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
+ goto failed_read1;
+
+ i->i_mode |= (inodeb->inode_type ==
+ SQUASHFS_CHRDEV_TYPE) ? S_IFCHR :
+ S_IFBLK;
+ init_special_inode(i, i->i_mode, inodep->rdev);
+
+ TRACE("Device inode %x:%x, rdev %x\n",
+ SQUASHFS_INODE_BLK(inode), offset,
+ inodep->rdev);
+ break;
+ }
+ case SQUASHFS_FIFO_TYPE:
+ case SQUASHFS_SOCKET_TYPE: {
+ if ((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
+ goto failed_read1;
+
+ i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE)
+ ? S_IFIFO : S_IFSOCK;
+ init_special_inode(i, i->i_mode, 0);
+ break;
+ }
+ default:
+ ERROR("Unknown inode type %d in squashfs_iget!\n",
+ inodeb->inode_type);
+ goto failed_read1;
+ }
+
+ insert_inode_hash(i);
+ return i;
+
+failed_read:
+ ERROR("Unable to read inode [%x:%x]\n", block, offset);
+
+failed_read1:
+ return NULL;
+}
+
+
+static int get_dir_index_using_offset(struct super_block *s, long long
+ *next_block, unsigned int *next_offset,
+ long long index_start,
+ unsigned int index_offset, int i_count,
+ long long f_pos)
+{
+ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
+ struct squashfs_super_block *sblk = &msblk->sblk;
+ int i, length = 0;
+ struct squashfs_dir_index_2 index;
+
+ TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n",
+ i_count, (unsigned int) f_pos);
+
+ if (f_pos == 0)
+ goto finish;
+
+ for (i = 0; i < i_count; i++) {
+ if (msblk->swap) {
+ struct squashfs_dir_index_2 sindex;
+ squashfs_get_cached_block(s, (char *) &sindex,
+ index_start, index_offset,
+ sizeof(sindex), &index_start,
+ &index_offset);
+ SQUASHFS_SWAP_DIR_INDEX_2(&index, &sindex);
+ } else
+ squashfs_get_cached_block(s, (char *) &index,
+ index_start, index_offset,
+ sizeof(index), &index_start,
+ &index_offset);
+
+ if (index.index > f_pos)
+ break;
+
+ squashfs_get_cached_block(s, NULL, index_start, index_offset,
+ index.size + 1, &index_start,
+ &index_offset);
+
+ length = index.index;
+ *next_block = index.start_block + sblk->directory_table_start;
+ }
+
+ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
+
+finish:
+ return length;
+}
+
+
+static int get_dir_index_using_name(struct super_block *s, long long
+ *next_block, unsigned int *next_offset,
+ long long index_start,
+ unsigned int index_offset, int i_count,
+ const char *name, int size)
+{
+ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
+ struct squashfs_super_block *sblk = &msblk->sblk;
+ int i, length = 0;
+ char buffer[sizeof(struct squashfs_dir_index_2) + SQUASHFS_NAME_LEN + 1];
+ struct squashfs_dir_index_2 *index = (struct squashfs_dir_index_2 *) buffer;
+ char str[SQUASHFS_NAME_LEN + 1];
+
+ TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count);
+
+ strncpy(str, name, size);
+ str[size] = '\0';
+
+ for (i = 0; i < i_count; i++) {
+ if (msblk->swap) {
+ struct squashfs_dir_index_2 sindex;
+ squashfs_get_cached_block(s, (char *) &sindex,
+ index_start, index_offset,
+ sizeof(sindex), &index_start,
+ &index_offset);
+ SQUASHFS_SWAP_DIR_INDEX_2(index, &sindex);
+ } else
+ squashfs_get_cached_block(s, (char *) index,
+ index_start, index_offset,
+ sizeof(struct squashfs_dir_index_2),
+ &index_start, &index_offset);
+
+ squashfs_get_cached_block(s, index->name, index_start,
+ index_offset, index->size + 1,
+ &index_start, &index_offset);
+
+ index->name[index->size + 1] = '\0';
+
+ if (strcmp(index->name, str) > 0)
+ break;
+
+ length = index->index;
+ *next_block = index->start_block + sblk->directory_table_start;
+ }
+
+ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
+ return length;
+}
+
+
+static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir)
+{
+ struct inode *i = file->f_dentry->d_inode;
+ struct squashfs_sb_info *msblk = &i->i_sb->u.squashfs_sb;
+ struct squashfs_super_block *sblk = &msblk->sblk;
+ long long next_block = SQUASHFS_I(i)->start_block +
+ sblk->directory_table_start;
+ int next_offset = SQUASHFS_I(i)->offset, length = 0, dirs_read = 0,
+ dir_count;
+ struct squashfs_dir_header_2 dirh;
+ char buffer[sizeof(struct squashfs_dir_entry_2) + SQUASHFS_NAME_LEN + 1];
+ struct squashfs_dir_entry_2 *dire = (struct squashfs_dir_entry_2 *) buffer;
+
+ TRACE("Entered squashfs_readdir_2 [%llx:%x]\n", next_block, next_offset);
+
+ length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset,
+ SQUASHFS_I(i)->u.s2.directory_index_start,
+ SQUASHFS_I(i)->u.s2.directory_index_offset,
+ SQUASHFS_I(i)->u.s2.directory_index_count,
+ file->f_pos);
+
+ while (length < i_size_read(i)) {
+ /* read directory header */
+ if (msblk->swap) {
+ struct squashfs_dir_header_2 sdirh;
+
+ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
+ next_block, next_offset, sizeof(sdirh),
+ &next_block, &next_offset))
+ goto failed_read;
+
+ length += sizeof(sdirh);
+ SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
+ } else {
+ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
+ next_block, next_offset, sizeof(dirh),
+ &next_block, &next_offset))
+ goto failed_read;
+
+ length += sizeof(dirh);
+ }
+
+ dir_count = dirh.count + 1;
+ while (dir_count--) {
+ if (msblk->swap) {
+ struct squashfs_dir_entry_2 sdire;
+ if (!squashfs_get_cached_block(i->i_sb, (char *)
+ &sdire, next_block, next_offset,
+ sizeof(sdire), &next_block,
+ &next_offset))
+ goto failed_read;
+
+ length += sizeof(sdire);
+ SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
+ } else {
+ if (!squashfs_get_cached_block(i->i_sb, (char *)
+ dire, next_block, next_offset,
+ sizeof(*dire), &next_block,
+ &next_offset))
+ goto failed_read;
+
+ length += sizeof(*dire);
+ }
+
+ if (!squashfs_get_cached_block(i->i_sb, dire->name,
+ next_block, next_offset,
+ dire->size + 1, &next_block,
+ &next_offset))
+ goto failed_read;
+
+ length += dire->size + 1;
+
+ if (file->f_pos >= length)
+ continue;
+
+ dire->name[dire->size + 1] = '\0';
+
+ TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d)\n",
+ (unsigned int) dirent, dire->name,
+ dire->size + 1, (int) file->f_pos,
+ dirh.start_block, dire->offset,
+ squashfs_filetype_table[dire->type]);
+
+ if (filldir(dirent, dire->name, dire->size + 1,
+ file->f_pos, SQUASHFS_MK_VFS_INODE(
+ dirh.start_block, dire->offset),
+ squashfs_filetype_table[dire->type])
+ < 0) {
+ TRACE("Filldir returned less than 0\n");
+ goto finish;
+ }
+ file->f_pos = length;
+ dirs_read++;
+ }
+ }
+
+finish:
+ return dirs_read;
+
+failed_read:
+ ERROR("Unable to read directory block [%llx:%x]\n", next_block,
+ next_offset);
+ return 0;
+}
+
+
+static struct dentry *squashfs_lookup_2(struct inode *i, struct dentry *dentry)
+{
+ const unsigned char *name = dentry->d_name.name;
+ int len = dentry->d_name.len;
+ struct inode *inode = NULL;
+ struct squashfs_sb_info *msblk = &i->i_sb->u.squashfs_sb;
+ struct squashfs_super_block *sblk = &msblk->sblk;
+ long long next_block = SQUASHFS_I(i)->start_block +
+ sblk->directory_table_start;
+ int next_offset = SQUASHFS_I(i)->offset, length = 0,
+ dir_count;
+ struct squashfs_dir_header_2 dirh;
+ char buffer[sizeof(struct squashfs_dir_entry_2) + SQUASHFS_NAME_LEN];
+ struct squashfs_dir_entry_2 *dire = (struct squashfs_dir_entry_2 *) buffer;
+ int sorted = sblk->s_major == 2 && sblk->s_minor >= 1;
+
+ TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block, next_offset);
+
+ if (len > SQUASHFS_NAME_LEN)
+ goto exit_loop;
+
+ length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset,
+ SQUASHFS_I(i)->u.s2.directory_index_start,
+ SQUASHFS_I(i)->u.s2.directory_index_offset,
+ SQUASHFS_I(i)->u.s2.directory_index_count, name,
+ len);
+
+ while (length < i_size_read(i)) {
+ /* read directory header */
+ if (msblk->swap) {
+ struct squashfs_dir_header_2 sdirh;
+ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
+ next_block, next_offset, sizeof(sdirh),
+ &next_block, &next_offset))
+ goto failed_read;
+
+ length += sizeof(sdirh);
+ SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
+ } else {
+ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
+ next_block, next_offset, sizeof(dirh),
+ &next_block, &next_offset))
+ goto failed_read;
+
+ length += sizeof(dirh);
+ }
+
+ dir_count = dirh.count + 1;
+ while (dir_count--) {
+ if (msblk->swap) {
+ struct squashfs_dir_entry_2 sdire;
+ if (!squashfs_get_cached_block(i->i_sb, (char *)
+ &sdire, next_block,next_offset,
+ sizeof(sdire), &next_block,
+ &next_offset))
+ goto failed_read;
+
+ length += sizeof(sdire);
+ SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
+ } else {
+ if (!squashfs_get_cached_block(i->i_sb, (char *)
+ dire, next_block,next_offset,
+ sizeof(*dire), &next_block,
+ &next_offset))
+ goto failed_read;
+
+ length += sizeof(*dire);
+ }
+
+ if (!squashfs_get_cached_block(i->i_sb, dire->name,
+ next_block, next_offset, dire->size + 1,
+ &next_block, &next_offset))
+ goto failed_read;
+
+ length += dire->size + 1;
+
+ if (sorted && name[0] < dire->name[0])
+ goto exit_loop;
+
+ if ((len == dire->size + 1) && !strncmp(name,
+ dire->name, len)) {
+ squashfs_inode_t ino =
+ SQUASHFS_MKINODE(dirh.start_block,
+ dire->offset);
+
+ TRACE("calling squashfs_iget for directory "
+ "entry %s, inode %x:%x, %d\n", name,
+ dirh.start_block, dire->offset, ino);
+
+ inode = (msblk->iget)(i->i_sb, ino);
+
+ goto exit_loop;
+ }
+ }
+ }
+
+exit_loop:
+ d_add(dentry, inode);
+ return ERR_PTR(0);
+
+failed_read:
+ ERROR("Unable to read directory block [%llx:%x]\n", next_block,
+ next_offset);
+ goto exit_loop;
+}
+
+
+int squashfs_2_0_supported(struct squashfs_sb_info *msblk)
+{
+ struct squashfs_super_block *sblk = &msblk->sblk;
+
+ msblk->iget = squashfs_iget_2;
+ msblk->read_fragment_index_table = read_fragment_index_table_2;
+
+ sblk->bytes_used = sblk->bytes_used_2;
+ sblk->uid_start = sblk->uid_start_2;
+ sblk->guid_start = sblk->guid_start_2;
+ sblk->inode_table_start = sblk->inode_table_start_2;
+ sblk->directory_table_start = sblk->directory_table_start_2;
+ sblk->fragment_table_start = sblk->fragment_table_start_2;
+
+ return 1;
+}