Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
f27e5a2c
Commit
f27e5a2c
authored
Dec 02, 2004
by
Steve French
Browse files
Options
Browse Files
Download
Plain Diff
Merge
bk://linux.bkbits.net/linux-2.5
into bkbits.net:/repos/c/cifs/linux-2.5cifs
parents
01eb4811
4096004b
Changes
23
Hide whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
2377 additions
and
330 deletions
+2377
-330
fs/Kconfig
fs/Kconfig
+12
-2
fs/cifs/CHANGES
fs/cifs/CHANGES
+29
-0
fs/cifs/Makefile
fs/cifs/Makefile
+1
-1
fs/cifs/README
fs/cifs/README
+50
-4
fs/cifs/cifs_debug.c
fs/cifs/cifs_debug.c
+13
-6
fs/cifs/cifs_fs_sb.h
fs/cifs/cifs_fs_sb.h
+4
-2
fs/cifs/cifsfs.c
fs/cifs/cifsfs.c
+71
-1
fs/cifs/cifsfs.h
fs/cifs/cifsfs.h
+1
-1
fs/cifs/cifsglob.h
fs/cifs/cifsglob.h
+23
-6
fs/cifs/cifspdu.h
fs/cifs/cifspdu.h
+236
-157
fs/cifs/cifsproto.h
fs/cifs/cifsproto.h
+13
-1
fs/cifs/cifssmb.c
fs/cifs/cifssmb.c
+823
-74
fs/cifs/connect.c
fs/cifs/connect.c
+47
-10
fs/cifs/dir.c
fs/cifs/dir.c
+0
-3
fs/cifs/fcntl.c
fs/cifs/fcntl.c
+1
-1
fs/cifs/file.c
fs/cifs/file.c
+102
-35
fs/cifs/inode.c
fs/cifs/inode.c
+26
-4
fs/cifs/misc.c
fs/cifs/misc.c
+45
-2
fs/cifs/netmisc.c
fs/cifs/netmisc.c
+3
-1
fs/cifs/readdir.c
fs/cifs/readdir.c
+659
-0
fs/cifs/smberr.h
fs/cifs/smberr.h
+1
-0
fs/cifs/transport.c
fs/cifs/transport.c
+137
-1
fs/cifs/xattr.c
fs/cifs/xattr.c
+80
-18
No files found.
fs/Kconfig
View file @
f27e5a2c
...
...
@@ -1718,12 +1718,22 @@ config CIFS_XATTR
config CIFS_POSIX
bool "CIFS POSIX Extensions (EXPERIMENTAL)"
depends on CIFS
depends on CIFS
_XATTR
help
Enabling this option will cause the cifs client to attempt to
negotiate a newer dialect with servers, such as Samba 3.0.5
or later, that optionally can handle more POSIX like (rather
than Windows like) file behavior. If unsure, say N.
than Windows like) file behavior. It also enables
support for POSIX ACLs (getfacl and setfacl) to servers
(such as Samba 3.10 and later) which can negotiate
CIFS POSIX ACL support. If unsure, say N.
config CIFS_EXPERIMENTAL
bool "CIFS Experimental Features (EXPERIMENTAL)"
depends on CIFS
help
Enables cifs features under testing. These features
are highly experimental. If unsure, say N.
config NCP_FS
tristate "NCP file system support (to mount NetWare volumes)"
...
...
fs/cifs/CHANGES
View file @
f27e5a2c
Version 1.26
------------
Add setfacl support to allow setting of ACLs remotely to Samba 3.10 and later
and other POSIX CIFS compliant servers. Fix error mapping for getfacl
to EOPNOTSUPP when server does not support posix acls on the wire. Fix
improperly zeroed buffer in CIFS Unix extensions set times call.
Version 1.25
------------
Fix internationlization problem in cifs readdir with filenames that map to
longer UTF8 strings than the string on the wire was in Unicode. Add workaround
for readdir to netapp servers. Fix search rewind (seek into readdir to return
non-consecutive entries). Do not do readdir when server negotiates
buffer size to small to fit filename. Add support for reading POSIX ACLs from
the server (add also acl and noacl mount options).
Version 1.24
------------
Optionally allow using server side inode numbers, rather than client generated
ones by specifying mount option "serverino" - this is required for some apps
to work which double check hardlinked files and have persistent inode numbers.
Version 1.23
------------
Multiple bigendian fixes. On little endian systems (for reconnect after
network failure) fix tcp session reconnect code so we do not try first
to reconnect on reverse of port 445. Treat reparse points (NTFS junctions)
as directories rather than symlinks because we can do follow link on them.
Version 1.22
------------
Add config option to enable XATTR (extended attribute) support, mapping
...
...
fs/cifs/Makefile
View file @
f27e5a2c
...
...
@@ -3,4 +3,4 @@
#
obj-$(CONFIG_CIFS)
+=
cifs.o
cifs-objs
:=
cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o
cifs-objs
:=
cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o
readdir.o
fs/cifs/README
View file @
f27e5a2c
...
...
@@ -115,11 +115,20 @@ cifs client, and that EA support is present in later versions of Samba (e.g.
3.0.6 and later (also EA support works in all versions of Windows, at least to
shares on NTFS filesystems). Extended Attribute (xattr) support is an optional
feature of most Linux filesystems which may require enabling via
make menuconfig
make menuconfig.
The CIFS client can get and set POSIX ACLs (getfacl, setfacl) to Samba servers
version 3.10 and later. Setting POSIX ACLs requires enabling both XATTR and
then POSIX support in the CIFS configuration options when building the cifs
module.
Some administrators may want to change Samba's smb.conf "map archive" and
"create mask" parameters from the default. Creating special devices (mknod)
remotely may require specifying a mkdev function to Samba if you are not using
"create mask" parameters from the default. Unless the create mask is changed
newly created files can end up with an unnecessarily restrictive default mode,
which may not be what you want, although if the CIFS Unix extensions are
enabled on the server and client, subsequent setattr calls (e.g. chmod) can
fix the mode. Note that creating special devices (mknod) remotely
may require specifying a mkdev function to Samba if you are not using
Samba 3.0.6 or later. For more information on these see the manual pages
("man smb.conf") on the Samba server system. Note that the cifs vfs,
unlike the smbfs vfs, does not read the smb.conf on the client system
...
...
@@ -266,6 +275,10 @@ A partial list of the supported mount options follows:
If you do not trust the servers in your network (your mount
targets) it is recommended that you specify this option for
greater security.
exec Permit execution of binaries on the mount.
noexec Do not permit execution of binaries on the mount.
dev Recognize block devices on the remote mount.
nodev Do not recognize devices on the remote mount.
suid Allow remote files on this mountpoint with suid enabled to
be executed (default for mounts when executed as root,
nosuid is default for user mounts).
...
...
@@ -292,6 +305,22 @@ A partial list of the supported mount options follows:
Note that this does not affect the normal ACL check on the
target machine done by the server software (of the server
ACL against the user name provided at mount time).
serverino Use servers inode numbers instead of generating automatically
incrementing inode numbers on the client. Although this will
make it easier to spot hardlinked files (as they will have
the same inode numbers) and inode numbers may be persistent,
note that the server does not guarantee that the inode numbers
are unique if multiple server side mounts are exported under a
single share (since inode numbers on the servers might not
be unique if multiple filesystems are mounted under the same
shared higher level directory). Note that this requires that
the server support the CIFS Unix Extensions as other servers
do not return a unique IndexNumber on SMB FindFirst (most
servers return zero as the IndexNumber). Parameter has no
effect to Windows servers and others which do not support the
CIFS Unix Extensions.
noserverino Client generates inode numbers (rather than using the actual one
from the server) by default.
setuids If the CIFS Unix extensions are negotiated with the server
the client will attempt to set the effective uid and gid of
the local process on newly created files, directories, and
...
...
@@ -304,6 +333,23 @@ A partial list of the supported mount options follows:
the client) set the uid and gid is the default. This
parameter has no effect if the CIFS Unix Extensions are not
negotiated.
netbiosname When mounting to servers via port 139, specifies the RFC1001
source name to use to represent the client netbios machine
name when doing the RFC1001 netbios session initialize.
direct Do not do inode data caching on files opened on this mount.
This precludes mmaping files on this mount. In some cases
with fast networks and little or no caching benefits on the
client (e.g. when the application is doing large sequential
reads bigger than page size without rereading the same data)
this can provide better performance than the default
behavior which caches reads (reaadahead) and writes
(writebehind) through the local Linux client pagecache
if oplock (caching token) is granted and held. Note that
direct allows write operations larger than page size
to be sent to the server.
acl Allow setfacl and getfacl to manage posix ACLs if server
supports them. (default)
noacl Do not allow setfacl and getfacl calls on this mount
The mount.cifs mount helper also accepts a few mount options before -o
including:
...
...
@@ -382,7 +428,7 @@ require enabling an ifdef (e.g. by adding "#define CIFS_FCNTL" in cifsglob.h)
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
Per share (per client mount) statistics are available in /proc/fs/cifs/
Stats
if the kernel was configured with cifs statistics enabled. The statistics
represent the number of successful (ie non-zero return code from the server)
SMB responses to some of the more common commands (open, delete, mkdir etc.).
...
...
fs/cifs/cifs_debug.c
View file @
f27e5a2c
...
...
@@ -201,7 +201,14 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
sprintf
(
buf
,
"SMB Request/Response Buffer: %d
\n
"
,
bufAllocCount
.
counter
);
length
+=
item_length
;
buf
+=
item_length
;
buf
+=
item_length
;
#ifdef CONFIG_CIFS_EXPERIMENTAL
item_length
=
sprintf
(
buf
,
"SMB Small Req/Resp Buffer: %d
\n
"
,
smBufAllocCount
.
counter
);
length
+=
item_length
;
buf
+=
item_length
;
#endif
/* CIFS_EXPERIMENTAL */
item_length
=
sprintf
(
buf
,
"Operations (MIDs): %d
\n
"
,
midCount
.
counter
);
...
...
@@ -337,7 +344,7 @@ cifs_proc_init(void)
if
(
pde
)
pde
->
write_proc
=
oplockEnabled_write
;
pde
=
create_proc_read_entry
(
"
QuotaEnabled
"
,
0
,
proc_fs_cifs
,
pde
=
create_proc_read_entry
(
"
ReenableOldCifsReaddirCode
"
,
0
,
proc_fs_cifs
,
quotaEnabled_read
,
NULL
);
if
(
pde
)
pde
->
write_proc
=
quotaEnabled_write
;
...
...
@@ -396,7 +403,7 @@ cifs_proc_clean(void)
remove_proc_entry
(
"ExtendedSecurity"
,
proc_fs_cifs
);
remove_proc_entry
(
"PacketSigningEnabled"
,
proc_fs_cifs
);
remove_proc_entry
(
"LinuxExtensionsEnabled"
,
proc_fs_cifs
);
remove_proc_entry
(
"
QuotaEnabled
"
,
proc_fs_cifs
);
remove_proc_entry
(
"
ReenableOldCifsReaddirCode
"
,
proc_fs_cifs
);
remove_proc_entry
(
"LookupCacheEnabled"
,
proc_fs_cifs
);
remove_proc_entry
(
"cifs"
,
proc_root_fs
);
}
...
...
@@ -485,7 +492,7 @@ quotaEnabled_read(char *page, char **start, off_t off,
{
int
len
;
len
=
sprintf
(
page
,
"%d
\n
"
,
quota
Enabled
);
len
=
sprintf
(
page
,
"%d
\n
"
,
experim
Enabled
);
/* could also check if quotas are enabled in kernel
as a whole first */
len
-=
off
;
...
...
@@ -512,9 +519,9 @@ quotaEnabled_write(struct file *file, const char __user *buffer,
if
(
rc
)
return
rc
;
if
(
c
==
'0'
||
c
==
'n'
||
c
==
'N'
)
quota
Enabled
=
0
;
experim
Enabled
=
0
;
else
if
(
c
==
'1'
||
c
==
'y'
||
c
==
'Y'
)
quota
Enabled
=
1
;
experim
Enabled
=
1
;
return
count
;
}
...
...
fs/cifs/cifs_fs_sb.h
View file @
f27e5a2c
/*
* fs/cifs/cifs_fs_sb.h
*
* Copyright (c) International Business Machines Corp., 2002
* Copyright (c) International Business Machines Corp., 2002
,2004
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
...
...
@@ -18,8 +18,10 @@
#ifndef _CIFS_FS_SB_H
#define _CIFS_FS_SB_H
#define CIFS_MOUNT_NO_PERM
1
/* do not do client vfs_perm check */
#define CIFS_MOUNT_NO_PERM
1
/* do not do client vfs_perm check */
#define CIFS_MOUNT_SET_UID 2
/* set current->euid in create etc. */
#define CIFS_MOUNT_SERVER_INUM 4
/* inode numbers from uniqueid from server */
#define CIFS_MOUNT_DIRECT_IO 8
/* do not write nor read through page cache */
struct
cifs_sb_info
{
struct
cifsTconInfo
*
tcon
;
/* primary mount */
...
...
fs/cifs/cifsfs.c
View file @
f27e5a2c
...
...
@@ -50,7 +50,7 @@ int cifsFYI = 0;
int
cifsERROR
=
1
;
int
traceSMB
=
0
;
unsigned
int
oplockEnabled
=
1
;
unsigned
int
quota
Enabled
=
0
;
unsigned
int
experim
Enabled
=
0
;
unsigned
int
linuxExtEnabled
=
1
;
unsigned
int
lookupCacheEnabled
=
1
;
unsigned
int
multiuser_mount
=
0
;
...
...
@@ -207,6 +207,10 @@ static kmem_cache_t *cifs_inode_cachep;
static
kmem_cache_t
*
cifs_req_cachep
;
static
kmem_cache_t
*
cifs_mid_cachep
;
kmem_cache_t
*
cifs_oplock_cachep
;
#ifdef CONFIG_CIFS_EXPERIMENTAL
static
kmem_cache_t
*
cifs_sm_req_cachep
;
mempool_t
*
cifs_sm_req_poolp
;
#endif
/* CIFS_EXPERIMENTAL */
mempool_t
*
cifs_req_poolp
;
mempool_t
*
cifs_mid_poolp
;
...
...
@@ -431,6 +435,20 @@ cifs_read_wrapper(struct file * file, char __user *read_data, size_t read_size,
return
-
EIO
;
cFYI
(
1
,(
"In read_wrapper size %zd at %lld"
,
read_size
,
*
poffset
));
#ifdef CONFIG_CIFS_EXPERIMENTAL
/* BB fixme - fix user char * to kernel char * mapping here BB */
/* check whether we can cache writes locally */
if
(
file
->
f_dentry
->
d_sb
)
{
struct
cifs_sb_info
*
cifs_sb
;
cifs_sb
=
CIFS_SB
(
file
->
f_dentry
->
d_sb
);
if
(
cifs_sb
!=
NULL
)
{
if
(
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_DIRECT_IO
)
return
cifs_read
(
file
,
read_data
,
read_size
,
poffset
);
}
}
#endif
/* CIFS_EXPERIMENTAL */
if
(
CIFS_I
(
file
->
f_dentry
->
d_inode
)
->
clientCanCacheRead
)
{
return
generic_file_read
(
file
,
read_data
,
read_size
,
poffset
);
}
else
{
...
...
@@ -463,7 +481,19 @@ cifs_write_wrapper(struct file * file, const char __user *write_data,
cFYI
(
1
,(
"In write_wrapper size %zd at %lld"
,
write_size
,
*
poffset
));
#ifdef CONFIG_CIFS_EXPERIMENTAL
/* BB fixme - fix user char * to kernel char * mapping here BB */
/* check whether we can cache writes locally */
if
(
file
->
f_dentry
->
d_sb
)
{
struct
cifs_sb_info
*
cifs_sb
;
cifs_sb
=
CIFS_SB
(
file
->
f_dentry
->
d_sb
);
if
(
cifs_sb
!=
NULL
)
{
if
(
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_DIRECT_IO
)
{
return
cifs_write
(
file
,
write_data
,
write_size
,
poffset
);
}
}
}
#endif
/* CIFS_EXPERIMENTAL */
written
=
generic_file_write
(
file
,
write_data
,
write_size
,
poffset
);
if
(
!
CIFS_I
(
file
->
f_dentry
->
d_inode
)
->
clientCanCacheAll
)
{
if
(
file
->
f_dentry
->
d_inode
->
i_mapping
)
{
...
...
@@ -495,6 +525,12 @@ struct inode_operations cifs_dir_inode_ops = {
.
setattr
=
cifs_setattr
,
.
symlink
=
cifs_symlink
,
.
mknod
=
cifs_mknod
,
#ifdef CONFIG_CIFS_XATTR
.
setxattr
=
cifs_setxattr
,
.
getxattr
=
cifs_getxattr
,
.
listxattr
=
cifs_listxattr
,
.
removexattr
=
cifs_removexattr
,
#endif
};
struct
inode_operations
cifs_file_inode_ops
=
{
...
...
@@ -598,6 +634,34 @@ cifs_init_request_bufs(void)
kmem_cache_destroy
(
cifs_req_cachep
);
return
-
ENOMEM
;
}
#ifdef CONFIG_CIFS_EXPERIMENTAL
/* 120 bytes is enough for most SMB responses and handle
based requests (but not write response, nor is it
sufficient for path based requests). 112 bytes is 75 more than
sizeof(struct smb_hdr) but still (with slab hdr) just smaller than
128 byte cutoff which should make it easy to alloc off the slab
compared to 17K (5page) alloc of large cifs buffers and not
so large as to force a single page alloc for each slab entry */
cifs_sm_req_cachep
=
kmem_cache_create
(
"cifs_small_rq"
,
112
,
0
,
SLAB_HWCACHE_ALIGN
,
NULL
,
NULL
);
if
(
cifs_sm_req_cachep
==
NULL
)
{
mempool_destroy
(
cifs_req_poolp
);
kmem_cache_destroy
(
cifs_req_cachep
);
return
-
ENOMEM
;
}
cifs_sm_req_poolp
=
mempool_create
(
64
,
mempool_alloc_slab
,
mempool_free_slab
,
cifs_sm_req_cachep
);
if
(
cifs_sm_req_poolp
==
NULL
)
{
mempool_destroy
(
cifs_req_poolp
);
kmem_cache_destroy
(
cifs_req_cachep
);
kmem_cache_destroy
(
cifs_sm_req_cachep
);
return
-
ENOMEM
;
}
#endif
/* CIFS_EXPERIMENTAL */
return
0
;
}
...
...
@@ -609,6 +673,12 @@ 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
"
);
#ifdef CONFIG_CIFS_EXPERIMENTAL
mempool_destroy
(
cifs_sm_req_poolp
);
if
(
kmem_cache_destroy
(
cifs_sm_req_cachep
))
printk
(
KERN_WARNING
"cifs_destroy_request_cache: cifs_small_rq free error
\n
"
);
#endif
/* CIFS_EXPERIMENTAL */
}
static
int
...
...
fs/cifs/cifsfs.h
View file @
f27e5a2c
...
...
@@ -90,5 +90,5 @@ 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.2
0
"
#define CIFS_VERSION "1.2
6
"
#endif
/* _CIFSFS_H */
fs/cifs/cifsglob.h
View file @
f27e5a2c
...
...
@@ -240,6 +240,20 @@ struct cifsLockInfo {
/*
* One of these for each open instance of a file
*/
struct
cifs_search_info
{
loff_t
index_of_last_entry
;
__u16
entries_in_buffer
;
__u16
info_level
;
__u32
resume_key
;
char
*
ntwrk_buf_start
;
char
*
srch_entries_start
;
char
*
presume_name
;
unsigned
int
resume_name_len
;
unsigned
endOfSearch
:
1
;
unsigned
emptyDir
:
1
;
unsigned
unicode
:
1
;
};
struct
cifsFileInfo
{
struct
list_head
tlist
;
/* pointer to next fid owned by tcon */
struct
list_head
flist
;
/* next fid (file instance) for this inode */
...
...
@@ -250,14 +264,12 @@ struct cifsFileInfo {
/* lock scope id (0 if none) */
struct
file
*
pfile
;
/* needed for writepage */
struct
inode
*
pInode
;
/* needed for oplock break */
unsigned
endOfSearch
:
1
;
/* we have reached end of search */
unsigned
closePend
:
1
;
/* file is marked to close */
unsigned
emptyDir
:
1
;
unsigned
invalidHandle
:
1
;
/* file closed via session abend */
struct
semaphore
fh_sem
;
/* prevents reopen race after dead ses*/
char
*
search_resume_name
;
unsigned
int
resume_name_length
;
__u32
resume_key
;
char
*
search_resume_name
;
/* BB removeme BB */
unsigned
int
resume_name_length
;
/* BB removeme - field renamed and moved BB */
struct
cifs_search_info
srch_inf
;
};
/*
...
...
@@ -317,6 +329,8 @@ struct oplock_q_entry {
#define MID_REQUEST_SUBMITTED 2
#define MID_RESPONSE_RECEIVED 4
#define MID_RETRY_NEEDED 8
/* session closed while this request out */
#define MID_NO_RESP_NEEDED 0x10
#define MID_SMALL_BUFFER 0x20
/* 112 byte response buffer instead of 4K */
/*
*****************************************************************
...
...
@@ -399,6 +413,9 @@ GLOBAL_EXTERN atomic_t tconInfoReconnectCount;
/* Various Debug counters to remove someday (BB) */
GLOBAL_EXTERN
atomic_t
bufAllocCount
;
#ifdef CONFIG_CIFS_EXPERIMENTAL
GLOBAL_EXTERN
atomic_t
smBufAllocCount
;
#endif
/* CIFS_EXPERIMENTAL */
GLOBAL_EXTERN
atomic_t
midCount
;
/* Misc globals */
...
...
@@ -407,7 +424,7 @@ GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions
have the uid/password or Kerberos credential
or equivalent for current user */
GLOBAL_EXTERN
unsigned
int
oplockEnabled
;
GLOBAL_EXTERN
unsigned
int
quota
Enabled
;
GLOBAL_EXTERN
unsigned
int
experim
Enabled
;
GLOBAL_EXTERN
unsigned
int
lookupCacheEnabled
;
GLOBAL_EXTERN
unsigned
int
extended_security
;
/* if on, session setup sent
with more secure ntlmssp2 challenge/resp */
...
...
fs/cifs/cifspdu.h
View file @
f27e5a2c
...
...
@@ -28,27 +28,30 @@
#define BAD_PROT CIFS_PROT+1
/* SMB command codes */
#define SMB_COM_CREATE_DIRECTORY 0x00
#define SMB_COM_DELETE_DIRECTORY 0x01
#define SMB_COM_CLOSE 0x04
#define SMB_COM_DELETE 0x06
#define SMB_COM_RENAME 0x07
#define SMB_COM_LOCKING_ANDX 0x24
#define SMB_COM_COPY 0x29
/* Some commands have minimal (wct=0,bcc=0), or uninteresting, responses
(ie which include no useful data other than the SMB error code itself).
Knowing this helps avoid response buffer allocations and copy in some cases */
#define SMB_COM_CREATE_DIRECTORY 0x00
/* trivial response */
#define SMB_COM_DELETE_DIRECTORY 0x01
/* trivial response */
#define SMB_COM_CLOSE 0x04
/* triv req/rsp, timestamp ignored */
#define SMB_COM_DELETE 0x06
/* trivial response */
#define SMB_COM_RENAME 0x07
/* trivial response */
#define SMB_COM_LOCKING_ANDX 0x24
/* trivial response */
#define SMB_COM_COPY 0x29
/* trivial rsp, fail filename ignrd*/
#define SMB_COM_READ_ANDX 0x2E
#define SMB_COM_WRITE_ANDX 0x2F
#define SMB_COM_TRANSACTION2 0x32
#define SMB_COM_TRANSACTION2_SECONDARY 0x33
#define SMB_COM_FIND_CLOSE2 0x34
#define SMB_COM_TREE_DISCONNECT 0x71
#define SMB_COM_FIND_CLOSE2 0x34
/* trivial response */
#define SMB_COM_TREE_DISCONNECT 0x71
/* trivial response */
#define SMB_COM_NEGOTIATE 0x72
#define SMB_COM_SESSION_SETUP_ANDX 0x73
#define SMB_COM_LOGOFF_ANDX 0x74
#define SMB_COM_LOGOFF_ANDX 0x74
/* trivial response */
#define SMB_COM_TREE_CONNECT_ANDX 0x75
#define SMB_COM_NT_TRANSACT 0xA0
#define SMB_COM_NT_TRANSACT_SECONDARY 0xA1
#define SMB_COM_NT_CREATE_ANDX 0xA2
#define SMB_COM_NT_RENAME 0xA5
#define SMB_COM_NT_RENAME 0xA5
/* trivial response */
/* Transact2 subcommand codes */
#define TRANS2_OPEN 0x00
...
...
@@ -141,7 +144,7 @@
#define SMBFLG2_KNOWS_EAS cpu_to_le16(2)
#define SMBFLG2_SECURITY_SIGNATURE cpu_to_le16(4)
#define SMBFLG2_IS_LONG_NAME cpu_to_le16(0x40)
#define SMBFLG2_EXT_SEC cpu_to_le16(0x80)
#define SMBFLG2_EXT_SEC cpu_to_le16(0x80
0
)
#define SMBFLG2_DFS cpu_to_le16(0x1000)
#define SMBFLG2_PAGING_IO cpu_to_le16(0x2000)
#define SMBFLG2_ERR_STATUS cpu_to_le16(0x4000)
...
...
@@ -1004,45 +1007,55 @@ struct cifs_quota_data {
#define QUOTA_LIST_START 0x100
#define QUOTA_FOR_SID 0x101
typedef
union
smb_com_transaction2
{
struct
{
struct
smb_hdr
hdr
;
/* wct = 14+ */
__u16
TotalParameterCount
;
__u16
TotalDataCount
;
__u16
MaxParameterCount
;
__u16
MaxDataCount
;
__u8
MaxSetupCount
;
__u8
Reserved
;
__u16
Flags
;
__u32
Timeout
;
__u16
Reserved2
;
__u16
ParameterCount
;
__u16
ParameterOffset
;
__u16
DataCount
;
__u16
DataOffset
;
__u8
SetupCount
;
__u8
Reserved3
;
__u16
SubCommand
;
/* 1st setup word - can be followed by SetupCount words */
__u16
ByteCount
;
/* careful - setupcount is not always one */
}
req
;
struct
{
struct
smb_hdr
hdr
;
/* wct = 0 */
__u16
TotalParameterCount
;
__u16
TotalDataCount
;
__u16
Reserved
;
__u16
ParameterCount
;
__u16
ParamterOffset
;
__u16
ParameterDisplacement
;
__u16
DataCount
;
__u16
DataOffset
;
__u16
DataDisplacement
;
__u8
SetupCount
;
__u8
Reserved1
;
/* should be zero setup words following */
__u16
ByteCount
;
__u16
Reserved2
;
/* parameter word reserved - present for infolevels > 100 */
/* data area follows */
}
resp
;
}
TRANSACTION2
;
struct
trans2_req
{
/* struct smb_hdr hdr precedes. Set wct = 14+ */
__le16
TotalParameterCount
;
__le16
TotalDataCount
;
__le16
MaxParameterCount
;
__le16
MaxDataCount
;
__u8
MaxSetupCount
;
__u8
Reserved
;
__le16
Flags
;
__le32
Timeout
;
__u16
Reserved2
;
__le16
ParameterCount
;
__le16
ParameterOffset
;
__le16
DataCount
;
__le16
DataOffset
;
__u8
SetupCount
;
__u8
Reserved3
;
__le16
SubCommand
;
/* 1st setup word - SetupCount words follow */
__le16
ByteCount
;
};
struct
smb_t2_req
{
struct
smb_hdr
hdr
;
struct
trans2_req
t2_req
;
};
struct
trans2_resp
{
/* struct smb_hdr hdr precedes. Note wct = 10 + setup count */
__le16
TotalParameterCount
;
__le16
TotalDataCount
;
__u16
Reserved
;
__le16
ParameterCount
;
__le16
ParameterOffset
;
__le16
ParameterDisplacement
;
__le16
DataCount
;
__le16
DataOffset
;
__le16
DataDisplacement
;
__u8
SetupCount
;
__u8
Reserved1
;
/* SetupWords[SetupCount];
__u16 ByteCount;
__u16 Reserved2;*/
/* data area follows */
};
struct
smb_t2_rsp
{
struct
smb_hdr
hdr
;
struct
trans2_resp
t2_rsp
;
};
/* PathInfo/FileInfo infolevels */
#define SMB_INFO_STANDARD 1
...
...
@@ -1063,6 +1076,14 @@ typedef union smb_com_transaction2 {
#define SMB_QUERY_FILE_COMPRESSION_INFO 0x10B
#define SMB_QUERY_FILE_UNIX_BASIC 0x200
#define SMB_QUERY_FILE_UNIX_LINK 0x201
#define SMB_QUERY_POSIX_ACL 0x204
#define SMB_QUERY_FILE_INTERNAL_INFO 0x3ee
#define SMB_QUERY_FILE_ACCESS_INFO 0x3f0
#define SMB_QUERY_FILE_NAME_INFO2 0x3f1
/* 0x30 bytes */
#define SMB_QUERY_FILE_POSITION_INFO 0x3f6
#define SMB_QUERY_FILE_MODE_INFO 0x3f8
#define SMB_QUERY_FILE_ALGN_INFO 0x3f9
#define SMB_SET_FILE_BASIC_INFO 0x101
#define SMB_SET_FILE_DISPOSITION_INFO 0x102
...
...
@@ -1070,9 +1091,10 @@ typedef union smb_com_transaction2 {
#define SMB_SET_FILE_END_OF_FILE_INFO 0x104
#define SMB_SET_FILE_UNIX_BASIC 0x200
#define SMB_SET_FILE_UNIX_LINK 0x201
#define SMB_SET_POSIX_ACL 0x204
#define SMB_SET_FILE_UNIX_HLINK 0x203
#define SMB_SET_FILE_BASIC_INFO2 0x3ec
#define SMB_SET_FILE_RENAME_INFORMATION 0x3f2
#define SMB_SET_FILE_RENAME_INFORMATION 0x3f2
/* BB check if qpathinfo level too */
#define SMB_FILE_ALL_INFO2 0x3fa
#define SMB_SET_FILE_ALLOCATION_INFO2 0x3fb
#define SMB_SET_FILE_END_OF_FILE_INFO2 0x3fc
...
...
@@ -1086,6 +1108,8 @@ typedef union smb_com_transaction2 {
#define SMB_FIND_FILE_FULL_DIRECTORY_INFO 0x102
#define SMB_FIND_FILE_NAMES_INFO 0x103
#define SMB_FIND_FILE_BOTH_DIRECTORY_INFO 0x104
#define SMB_FIND_FILE_ID_FULL_DIR_INFO 0x105
#define SMB_FIND_FILE_ID_BOTH_DIR_INFO 0x106
#define SMB_FIND_FILE_UNIX 0x202
typedef
struct
smb_com_transaction2_qpi_req
{
...
...
@@ -1115,17 +1139,7 @@ typedef struct smb_com_transaction2_qpi_req {
typedef
struct
smb_com_transaction2_qpi_rsp
{
struct
smb_hdr
hdr
;
/* wct = 10 + SetupCount */
__le16
TotalParameterCount
;
__le16
TotalDataCount
;
__le16
Reserved
;
__le16
ParameterCount
;
__le16
ParameterOffset
;
__le16
ParameterDisplacement
;
__le16
DataCount
;
__le16
DataOffset
;
__le16
DataDisplacement
;
__u8
SetupCount
;
__u8
Reserved1
;
/* should be zero setup words following */
struct
trans2_resp
t2
;
__u16
ByteCount
;
__u16
Reserved2
;
/* parameter word reserved - present for infolevels > 100 */
}
TRANSACTION2_QPI_RSP
;
...
...
@@ -1158,17 +1172,7 @@ typedef struct smb_com_transaction2_spi_req {
typedef
struct
smb_com_transaction2_spi_rsp
{
struct
smb_hdr
hdr
;
/* wct = 10 + SetupCount */
__le16
TotalParameterCount
;
__le16
TotalDataCount
;
__u16
Reserved
;
__le16
ParameterCount
;
__le16
ParameterOffset
;
__le16
ParameterDisplacement
;
__le16
DataCount
;
__le16
DataOffset
;
__le16
DataDisplacement
;
__u8
SetupCount
;
__u8
Reserved1
;
/* should be zero setup words following */
struct
trans2_resp
t2
;
__u16
ByteCount
;
__u16
Reserved2
;
/* parameter word reserved - present for infolevels > 100 */
}
TRANSACTION2_SPI_RSP
;
...
...
@@ -1208,17 +1212,7 @@ struct smb_com_transaction2_sfi_req {
struct
smb_com_transaction2_sfi_rsp
{
struct
smb_hdr
hdr
;
/* wct = 10 + SetupCount */
__le16
TotalParameterCount
;
__le16
TotalDataCount
;
__u16
Reserved
;
__le16
ParameterCount
;
__le16
ParameterOffset
;
__le16
ParameterDisplacement
;
__le16
DataCount
;
__le16
DataOffset
;
__le16
DataDisplacement
;
__u8
SetupCount
;
__u8
Reserved1
;
/* should be zero setup words following */
struct
trans2_resp
t2
;
__u16
ByteCount
;
__u16
Reserved2
;
/* parameter word reserved - present for infolevels > 100 */
};
...
...
@@ -1268,17 +1262,7 @@ typedef struct smb_com_transaction2_ffirst_req {
typedef
struct
smb_com_transaction2_ffirst_rsp
{
struct
smb_hdr
hdr
;
/* wct = 10 */
__le16
TotalParameterCount
;
__le16
TotalDataCount
;
__u16
Reserved
;
__le16
ParameterCount
;
__le16
ParameterOffset
;
__le16
ParameterDisplacement
;
__le16
DataCount
;
__le16
DataOffset
;
__le16
DataDisplacement
;
__u8
SetupCount
;
__u8
Reserved1
;
/* should be zero setup words following */
struct
trans2_resp
t2
;
__u16
ByteCount
;
}
TRANSACTION2_FFIRST_RSP
;
...
...
@@ -1320,17 +1304,7 @@ typedef struct smb_com_transaction2_fnext_req {
typedef
struct
smb_com_transaction2_fnext_rsp
{
struct
smb_hdr
hdr
;
/* wct = 10 */
__le16
TotalParameterCount
;
__le16
TotalDataCount
;
__u16
Reserved
;
__le16
ParameterCount
;
__le16
ParameterOffset
;
__le16
ParameterDisplacement
;
__le16
DataCount
;
__le16
DataOffset
;
__le16
DataDisplacement
;
__u8
SetupCount
;
__u8
Reserved1
;
/* should be zero setup words following */
struct
trans2_resp
t2
;
__u16
ByteCount
;
}
TRANSACTION2_FNEXT_RSP
;
...
...
@@ -1351,6 +1325,8 @@ typedef struct smb_com_transaction2_fnext_rsp_parms {
#define SMB_QUERY_CIFS_UNIX_INFO 0x200
#define SMB_QUERY_LABEL_INFO 0x3ea
#define SMB_QUERY_FS_QUOTA_INFO 0x3ee
#define SMB_QUERY_FS_FULL_SIZE_INFO 0x3ef
#define SMB_QUERY_OBJECTID_INFO 0x3f0
typedef
struct
smb_com_transaction2_qfsi_req
{
struct
smb_hdr
hdr
;
/* wct = 14+ */
...
...
@@ -1377,17 +1353,7 @@ typedef struct smb_com_transaction2_qfsi_req {
typedef
struct
smb_com_transaction_qfsi_rsp
{
struct
smb_hdr
hdr
;
/* wct = 10 + SetupCount */
__le16
TotalParameterCount
;
__le16
TotalDataCount
;
__u16
Reserved
;
__le16
ParameterCount
;
__le16
ParameterOffset
;
__le16
ParameterDisplacement
;
__le16
DataCount
;
__le16
DataOffset
;
__le16
DataDisplacement
;
__u8
SetupCount
;
__u8
Reserved1
;
/* should be zero setup words following */
struct
trans2_resp
t2
;
__u16
ByteCount
;
__u8
Pad
;
/* may be three bytes *//* followed by data area */
}
TRANSACTION2_QFSI_RSP
;
...
...
@@ -1430,17 +1396,7 @@ typedef struct dfs_referral_level_3 {
typedef
struct
smb_com_transaction_get_dfs_refer_rsp
{
struct
smb_hdr
hdr
;
/* wct = 10 */
__le16
TotalParameterCount
;
__le16
TotalDataCount
;
__u16
Reserved
;
__le16
ParameterCount
;
__le16
ParameterOffset
;
__le16
ParameterDisplacement
;
__le16
DataCount
;
__le16
DataOffset
;
__le16
DataDisplacement
;
__u8
SetupCount
;
__u8
Reserved1
;
/* zero setup words following */
struct
trans2_resp
t2
;
__u16
ByteCount
;
__u8
Pad
;
__le16
PathConsumed
;
...
...
@@ -1575,10 +1531,13 @@ typedef struct {
__le32
Attributes
;
__le32
MaxPathNameComponentLength
;
__le32
FileSystemNameLen
;
char
FileSystemName
[
52
];
/* do not really need to save this - so potentially get only subset of name */
char
FileSystemName
[
52
];
/* do not really need to save this - so potentially get only subset of name */
}
FILE_SYSTEM_ATTRIBUTE_INFO
;
typedef
struct
{
/* data block encoding of response to level 263 QPathInfo */
/******************************************************************************/
/* QueryFileInfo/QueryPathinfo (also for SetPath/SetFile) data buffer formats */
/******************************************************************************/
typedef
struct
{
/* data block encoding of response to level 263 QPathInfo */
__le64
CreationTime
;
__le64
LastAccessTime
;
__le64
LastWriteTime
;
...
...
@@ -1600,12 +1559,20 @@ typedef struct { /* data block encoding of response to level 263 QPathInfo */
__le32
AlignmentRequirement
;
__le32
FileNameLength
;
char
FileName
[
1
];
}
FILE_ALL_INFO
;
/* level
263
QPathInfo */
}
FILE_ALL_INFO
;
/* level
0x107
QPathInfo */
/* defines for enumerating possible values of the Unix type field below */
#define UNIX_FILE 0
#define UNIX_DIR 1
#define UNIX_SYMLINK 2
#define UNIX_CHARDEV 3
#define UNIX_BLOCKDEV 4
#define UNIX_FIFO 5
#define UNIX_SOCKET 6
typedef
struct
{
__le64
EndOfFile
;
__le64
NumOfBytes
;
__le64
LastStatusChange
;
/*SNIA spec says DCE time for the three
time fields */
__le64
LastStatusChange
;
/*SNIA specs DCE time for the 3
time fields */
__le64
LastAccessTime
;
__le64
LastModificationTime
;
__le64
Uid
;
...
...
@@ -1616,11 +1583,11 @@ typedef struct {
__u64
UniqueId
;
__le64
Permissions
;
__le64
Nlinks
;
}
FILE_UNIX_BASIC_INFO
;
/* level
512
QPathInfo */
}
FILE_UNIX_BASIC_INFO
;
/* level
0x200
QPathInfo */
typedef
struct
{
char
LinkDest
[
1
];
}
FILE_UNIX_LINK_INFO
;
/* level
513
QPathInfo */
}
FILE_UNIX_LINK_INFO
;
/* level
0x201
QPathInfo */
typedef
struct
{
__u16
CreationDate
;
...
...
@@ -1635,21 +1602,99 @@ typedef struct {
__u32
EASize
;
}
FILE_INFO_STANDARD
;
/* level 1 SetPath/FileInfo */
/* defines for enumerating possible values of the Unix type field below */
#define UNIX_FILE 0
#define UNIX_DIR 1
#define UNIX_SYMLINK 2
#define UNIX_CHARDEV 3
#define UNIX_BLOCKDEV 4
#define UNIX_FIFO 5
#define UNIX_SOCKET 6
typedef
struct
{
__le64
CreationTime
;
__le64
LastAccessTime
;
__le64
LastWriteTime
;
__le64
ChangeTime
;
__le32
Attributes
;
__u32
Pad
;
}
FILE_BASIC_INFO
;
/* size info, level 0x101 */
struct
file_allocation_info
{
__le64
AllocationSize
;
/* Note old Samba srvr rounds this up too much */
};
/* size used on disk, level 0x103 for set, 0x105 for query */
struct
file_end_of_file_info
{
__le64
FileSize
;
/* offset to end of file */
};
/* size info, level 0x104 for set, 0x106 for query */
struct
file_alt_name_info
{
__u8
alt_name
[
1
];
};
/* level 0x0108 */
struct
file_stream_info
{
__le32
number_of_streams
;
/* BB check sizes and verify location */
/* followed by info on streams themselves
u64 size;
u64 allocation_size
stream info */
};
/* level 0x109 */
struct
file_compression_info
{
__le64
compressed_size
;
__le16
format
;
__u8
unit_shift
;
__u8
ch_shift
;
__u8
cl_shift
;
__u8
pad
[
3
];
};
/* level 0x10b */
/* POSIX ACL set/query path info structures */
#define CIFS_ACL_VERSION 1
struct
cifs_posix_ace
{
/* access control entry (ACE) */
__u8
cifs_e_tag
;
__u8
cifs_e_perm
;
__le64
cifs_uid
;
/* or gid */
};
struct
cifs_posix_acl
{
/* access conrol list (ACL) */
__le16
version
;
__le16
access_entry_count
;
/* access ACL - count of entries */
__le16
default_entry_count
;
/* default ACL - count of entries */
struct
cifs_posix_ace
ace_array
[
0
];
/* followed by
struct cifs_posix_ace default_ace_arraay[] */
};
/* level 0x204 */
/* types of access control entries already defined in posix_acl.h */
/* #define CIFS_POSIX_ACL_USER_OBJ 0x01
#define CIFS_POSIX_ACL_USER 0x02
#define CIFS_POSIX_ACL_GROUP_OBJ 0x04
#define CIFS_POSIX_ACL_GROUP 0x08
#define CIFS_POSIX_ACL_MASK 0x10
#define CIFS_POSIX_ACL_OTHER 0x20 */
/* types of perms */
/* #define CIFS_POSIX_ACL_EXECUTE 0x01
#define CIFS_POSIX_ACL_WRITE 0x02
#define CIFS_POSIX_ACL_READ 0x04 */
/* end of POSIX ACL definitions */
struct
file_internal_info
{
__u64
UniqueId
;
/* inode number */
};
/* level 0x3ee */
struct
file_mode_info
{
__le32
Mode
;
};
/* level 0x3f8 */
struct
file_attrib_tag
{
__le32
Attribute
;
__le32
ReparseTag
;
};
/* level 0x40b */
/********************************************************/
/* FindFirst/FindNext transact2 data buffer formats */
/********************************************************/
typedef
struct
{
__le32
NextEntryOffset
;
__
le32
ResumeKey
;
__
u32
ResumeKey
;
/* as with FileIndex - no need to convert */
__le64
EndOfFile
;
__le64
NumOfBytes
;
__le64
LastStatusChange
;
/*SNIA spec says DCE time for the three
time fields */
__le64
LastStatusChange
;
/*SNIA specs DCE time for the 3
time fields */
__le64
LastAccessTime
;
__le64
LastModificationTime
;
__le64
Uid
;
...
...
@@ -1657,28 +1702,40 @@ typedef struct {
__le32
Type
;
__le64
DevMajor
;
__le64
DevMinor
;
__
le
64
UniqueId
;
__
u
64
UniqueId
;
__le64
Permissions
;
__le64
Nlinks
;
char
FileName
[
1
];
}
FILE_UNIX_INFO
;
}
FILE_UNIX_INFO
;
/* level 0x202 */
typedef
struct
{
__le32
NextEntryOffset
;
__u32
FileIndex
;
__le64
CreationTime
;
__le64
LastAccessTime
;
__le64
LastWriteTime
;
__le64
ChangeTime
;
__le32
Attributes
;
__u32
Pad
;
}
FILE_BASIC_INFO
;
/* size info, level 0x101 */
struct
file_allocation_info
{
__le64
EndOfFile
;
__le64
AllocationSize
;
};
/* size info, level 0x103 */
__le32
ExtFileAttributes
;
__le32
FileNameLength
;
char
FileName
[
1
];
}
FILE_DIRECTORY_INFO
;
/* level 0x101 FF response data area */
struct
file_end_of_file_info
{
__le64
FileSize
;
/* offset to end of file */
};
/* size info, level 0x104 */
typedef
struct
{
__le32
NextEntryOffset
;
__u32
FileIndex
;
__le64
CreationTime
;
__le64
LastAccessTime
;
__le64
LastWriteTime
;
__le64
ChangeTime
;
__le64
EndOfFile
;
__le64
AllocationSize
;
__le32
ExtFileAttributes
;
__le32
FileNameLength
;
__le32
EaSize
;
/* length of the xattrs */
char
FileName
[
1
];
}
FILE_FULL_DIRECTORY_INFO
;
/* level 0x102 FF response data area */
typedef
struct
{
__le32
NextEntryOffset
;
...
...
@@ -1691,8 +1748,30 @@ typedef struct {
__le64
AllocationSize
;
__le32
ExtFileAttributes
;
__le32
FileNameLength
;
__le32
EaSize
;
/* EA size */
__le32
Reserved
;
__u64
UniqueId
;
/* inode num - le since Samba puts ino in low 32 bit*/
char
FileName
[
1
];
}
SEARCH_ID_FULL_DIR_INFO
;
/* level 0x105 FF response data area */
typedef
struct
{
__le32
NextEntryOffset
;
__u32
FileIndex
;
__le64
CreationTime
;
__le64
LastAccessTime
;
__le64
LastWriteTime
;
__le64
ChangeTime
;
__le64
EndOfFile
;
__le64
AllocationSize
;
__le32
ExtFileAttributes
;
__le32
FileNameLength
;
__le32
EaSize
;
/* length of the xattrs */
__u8
ShortNameLength
;
__u8
Reserved
;
__u8
ShortName
[
12
];
char
FileName
[
1
];
}
FILE_DIRECTORY_INFO
;
/* level 257 FF response data area */
}
FILE_BOTH_DIRECTORY_INFO
;
/* level 0x104 FF response data area */
struct
gea
{
unsigned
char
name_len
;
...
...
fs/cifs/cifsproto.h
View file @
f27e5a2c
/*
* fs/cifs/cifsproto.h
*
* Copyright (c) International Business Machines Corp., 2002
* Copyright (c) International Business Machines Corp., 2002
,2004
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
...
...
@@ -32,6 +32,10 @@ struct statfs;
extern
struct
smb_hdr
*
cifs_buf_get
(
void
);
extern
void
cifs_buf_release
(
void
*
);
#ifdef CONFIG_CIFS_EXPERIMENTAL
extern
struct
smb_hdr
*
cifs_small_buf_get
(
void
);
extern
void
cifs_small_buf_release
(
void
*
);
#endif
/* CIFS_EXPERIMENTAL */
extern
int
smb_send
(
struct
socket
*
,
struct
smb_hdr
*
,
unsigned
int
/* length */
,
struct
sockaddr
*
);
extern
unsigned
int
_GetXid
(
void
);
...
...
@@ -233,4 +237,12 @@ extern int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon,
const
char
*
fileName
,
const
char
*
ea_name
,
const
void
*
ea_value
,
const
__u16
ea_value_len
,
const
struct
nls_table
*
nls_codepage
);
extern
int
CIFSSMBGetPosixACL
(
const
int
xid
,
struct
cifsTconInfo
*
tcon
,
const
unsigned
char
*
searchName
,
char
*
acl_inf
,
const
int
buflen
,
const
int
acl_type
,
const
struct
nls_table
*
nls_codepage
);
extern
int
CIFSSMBSetPosixACL
(
const
int
xid
,
struct
cifsTconInfo
*
tcon
,
const
unsigned
char
*
fileName
,
const
char
*
local_acl
,
const
int
buflen
,
const
int
acl_type
,
const
struct
nls_table
*
nls_codepage
);
#endif
/* _CIFSPROTO_H */
fs/cifs/cifssmb.c
View file @
f27e5a2c
...
...
@@ -30,6 +30,7 @@
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/vfs.h>
#include <linux/posix_acl_xattr.h>
#include <asm/uaccess.h>
#include "cifspdu.h"
#include "cifsglob.h"
...
...
@@ -77,6 +78,99 @@ static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
/* BB Add call to invalidate_inodes(sb) for all superblocks mounted to this tcon */
}
#ifdef CONFIG_CIFS_EXPERIMENTAL
static
int
small_smb_init
(
int
smb_command
,
int
wct
,
struct
cifsTconInfo
*
tcon
,
void
**
request_buf
/* returned */
)
{
int
rc
=
0
;
/* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
check for tcp and smb session status done differently
for those three - in the calling routine */
if
(
tcon
)
{
if
((
tcon
->
ses
)
&&
(
tcon
->
ses
->
server
)){
struct
nls_table
*
nls_codepage
;
/* Give Demultiplex thread up to 10 seconds to
reconnect, should be greater than cifs socket
timeout which is 7 seconds */
while
(
tcon
->
ses
->
server
->
tcpStatus
==
CifsNeedReconnect
)
{
wait_event_interruptible_timeout
(
tcon
->
ses
->
server
->
response_q
,
(
tcon
->
ses
->
server
->
tcpStatus
==
CifsGood
),
10
*
HZ
);
if
(
tcon
->
ses
->
server
->
tcpStatus
==
CifsNeedReconnect
)
{
/* on "soft" mounts we wait once */
if
((
tcon
->
retry
==
FALSE
)
||
(
tcon
->
ses
->
status
==
CifsExiting
))
{
cFYI
(
1
,(
"gave up waiting on reconnect in smb_init"
));
return
-
EHOSTDOWN
;
}
/* else "hard" mount - keep retrying until
process is killed or server comes back up */
}
else
/* TCP session is reestablished now */
break
;
}
nls_codepage
=
load_nls_default
();
/* need to prevent multiple threads trying to
simultaneously reconnect the same SMB session */
down
(
&
tcon
->
ses
->
sesSem
);
if
(
tcon
->
ses
->
status
==
CifsNeedReconnect
)
rc
=
cifs_setup_session
(
0
,
tcon
->
ses
,
nls_codepage
);
if
(
!
rc
&&
(
tcon
->
tidStatus
==
CifsNeedReconnect
))
{
mark_open_files_invalid
(
tcon
);
rc
=
CIFSTCon
(
0
,
tcon
->
ses
,
tcon
->
treeName
,
tcon
,
nls_codepage
);
up
(
&
tcon
->
ses
->
sesSem
);
if
(
rc
==
0
)
atomic_inc
(
&
tconInfoReconnectCount
);
cFYI
(
1
,
(
"reconnect tcon rc = %d"
,
rc
));
/* Removed call to reopen open files here -
it is safer (and faster) to reopen files
one at a time as needed in read and write */
/* Check if handle based operation so we
know whether we can continue or not without
returning to caller to reset file handle */
switch
(
smb_command
)
{
case
SMB_COM_READ_ANDX
:
case
SMB_COM_WRITE_ANDX
:
case
SMB_COM_CLOSE
:
case
SMB_COM_FIND_CLOSE2
:
case
SMB_COM_LOCKING_ANDX
:
{
unload_nls
(
nls_codepage
);
return
-
EAGAIN
;
}
}
}
else
{
up
(
&
tcon
->
ses
->
sesSem
);
}
unload_nls
(
nls_codepage
);
}
else
{
return
-
EIO
;
}
}
if
(
rc
)
return
rc
;
*
request_buf
=
cifs_small_buf_get
();
if
(
*
request_buf
==
0
)
{
/* BB should we add a retry in here if not a writepage? */
return
-
ENOMEM
;
}
header_assemble
((
struct
smb_hdr
*
)
*
request_buf
,
smb_command
,
tcon
,
wct
);
#ifdef CONFIG_CIFS_STATS
if
(
tcon
!=
NULL
)
{
atomic_inc
(
&
tcon
->
num_smbs_sent
);
}
#endif
/* CONFIG_CIFS_STATS */
return
rc
;
}
#endif
/* CIFS_EXPERIMENTAL */
static
int
smb_init
(
int
smb_command
,
int
wct
,
struct
cifsTconInfo
*
tcon
,
void
**
request_buf
/* returned */
,
...
...
@@ -171,10 +265,42 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
if
(
tcon
!=
NULL
)
{
atomic_inc
(
&
tcon
->
num_smbs_sent
);
}
#endif
#endif
/* CONFIG_CIFS_STATS */
return
rc
;
}
static
int
validate_t2
(
struct
smb_t2_rsp
*
pSMB
)
{
int
rc
=
-
EINVAL
;
int
total_size
;
char
*
pBCC
;
/* check for plausible wct, bcc and t2 data and parm sizes */
/* check for parm and data offset going beyond end of smb */
if
(
pSMB
->
hdr
.
WordCount
>=
10
)
{
if
((
le16_to_cpu
(
pSMB
->
t2_rsp
.
ParameterOffset
)
<=
1024
)
&&
(
le16_to_cpu
(
pSMB
->
t2_rsp
.
DataOffset
)
<=
1024
))
{
/* check that bcc is at least as big as parms + data */
/* check that bcc is less than negotiated smb buffer */
total_size
=
le16_to_cpu
(
pSMB
->
t2_rsp
.
ParameterCount
);
if
(
total_size
<
512
)
{
total_size
+=
le16_to_cpu
(
pSMB
->
t2_rsp
.
DataCount
);
/* BCC le converted in SendReceive */
pBCC
=
(
pSMB
->
hdr
.
WordCount
*
2
)
+
sizeof
(
struct
smb_hdr
)
+
(
char
*
)
pSMB
;
if
((
total_size
<=
(
*
(
u16
*
)
pBCC
))
&&
(
total_size
<
CIFS_MAX_MSGSIZE
+
MAX_CIFS_HDR_SIZE
))
{
return
0
;
}
}
}
}
cifs_dump_mem
(
"Invalid transact2 SMB: "
,(
char
*
)
pSMB
,
sizeof
(
struct
smb_t2_rsp
)
+
16
);
return
rc
;
}
int
CIFSSMBNegotiate
(
unsigned
int
xid
,
struct
cifsSesInfo
*
ses
)
{
...
...
@@ -754,6 +880,8 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
pSMB
->
Fid
=
netfid
;
pSMB
->
OffsetLow
=
cpu_to_le32
(
offset
&
0xFFFFFFFF
);
pSMB
->
OffsetHigh
=
cpu_to_le32
(
offset
>>
32
);
pSMB
->
Reserved
=
0xFFFFFFFF
;
pSMB
->
WriteMode
=
0
;
pSMB
->
Remaining
=
0
;
bytes_sent
=
(
tcon
->
ses
->
server
->
maxBuf
-
MAX_CIFS_HDR_SIZE
)
&
~
0xFF
;
if
(
bytes_sent
>
count
)
...
...
@@ -861,8 +989,13 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
cFYI
(
1
,
(
"In CIFSSMBClose"
));
/* do not retry on dead session on close */
#ifdef CONFIG_CIFS_EXPERIMENTAL
rc
=
small_smb_init
(
SMB_COM_CLOSE
,
3
,
tcon
,
(
void
**
)
&
pSMB
);
pSMBr
=
(
CLOSE_RSP
*
)
pSMB
;
/* BB removeme BB */
#else
rc
=
smb_init
(
SMB_COM_CLOSE
,
3
,
tcon
,
(
void
**
)
&
pSMB
,
(
void
**
)
&
pSMBr
);
#endif
/* CIFS_EXPERIMENTAL */
if
(
rc
==
-
EAGAIN
)
return
0
;
if
(
rc
)
...
...
@@ -879,8 +1012,14 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
cERROR
(
1
,
(
"Send error in Close = %d"
,
rc
));
}
}
#ifdef CONFIG_CIFS_EXPERIMENTAL
if
(
pSMB
)
cifs_small_buf_release
(
pSMB
);
#else
if
(
pSMB
)
cifs_buf_release
(
pSMB
);
#endif
/* CIFS_EXPERIMENTAL */
/* Since session is dead, file will be closed on server already */
if
(
rc
==
-
EAGAIN
)
...
...
@@ -1432,13 +1571,17 @@ CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
(
struct
smb_hdr
*
)
pSMBr
,
&
bytes_returned
,
0
);
if
(
rc
)
{
cFYI
(
1
,
(
"Send error in QuerySymLinkInfo = %d"
,
rc
));
}
else
{
/* decode response */
__u16
data_offset
=
le16_to_cpu
(
pSMBr
->
DataOffset
);
__u16
count
=
le16_to_cpu
(
pSMBr
->
DataCount
);
if
((
pSMBr
->
ByteCount
<
2
)
||
(
data_offset
>
512
))
}
else
{
/* decode response */
rc
=
validate_t2
((
struct
smb_t2_rsp
*
)
pSMBr
);
if
(
rc
||
(
pSMBr
->
ByteCount
<
2
))
/* BB also check enough total bytes returned */
rc
=
-
EIO
;
/* bad smb */
else
{
__u16
data_offset
=
le16_to_cpu
(
pSMBr
->
t2
.
DataOffset
);
__u16
count
=
le16_to_cpu
(
pSMBr
->
t2
.
DataCount
);
if
(
pSMBr
->
hdr
.
Flags2
&
SMBFLG2_UNICODE
)
{
name_len
=
UniStrnlen
((
wchar_t
*
)
((
char
*
)
&
pSMBr
->
hdr
.
Protocol
+
data_offset
),
...
...
@@ -1550,6 +1693,306 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
return
rc
;
}
#ifdef CONFIG_CIFS_POSIX
/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
static
void
cifs_convert_ace
(
posix_acl_xattr_entry
*
ace
,
struct
cifs_posix_ace
*
cifs_ace
)
{
/* u8 cifs fields do not need le conversion */
ace
->
e_perm
=
(
__u16
)
cifs_ace
->
cifs_e_perm
;
ace
->
e_tag
=
(
__u16
)
cifs_ace
->
cifs_e_tag
;
ace
->
e_id
=
(
__u32
)
le64_to_cpu
(
cifs_ace
->
cifs_uid
);
/* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
return
;
}
/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
static
int
cifs_copy_posix_acl
(
char
*
trgt
,
char
*
src
,
const
int
buflen
,
const
int
acl_type
,
const
int
size_of_data_area
)
{
int
size
=
0
;
int
i
;
__u16
count
;
struct
cifs_posix_ace
*
pACE
;
struct
cifs_posix_acl
*
cifs_acl
=
(
struct
cifs_posix_acl
*
)
src
;
posix_acl_xattr_header
*
local_acl
=
(
posix_acl_xattr_header
*
)
trgt
;
if
(
le16_to_cpu
(
cifs_acl
->
version
)
!=
CIFS_ACL_VERSION
)
return
-
EOPNOTSUPP
;
if
(
acl_type
&
ACL_TYPE_ACCESS
)
{
count
=
le16_to_cpu
(
cifs_acl
->
access_entry_count
);
pACE
=
&
cifs_acl
->
ace_array
[
0
];
size
=
sizeof
(
struct
cifs_posix_acl
);
size
+=
sizeof
(
struct
cifs_posix_ace
)
*
count
;
/* check if we would go beyond end of SMB */
if
(
size_of_data_area
<
size
)
{
cFYI
(
1
,(
"bad CIFS POSIX ACL size %d vs. %d"
,
size_of_data_area
,
size
));
return
-
EINVAL
;
}
}
else
if
(
acl_type
&
ACL_TYPE_DEFAULT
)
{
count
=
le16_to_cpu
(
cifs_acl
->
access_entry_count
);
size
=
sizeof
(
struct
cifs_posix_acl
);
size
+=
sizeof
(
struct
cifs_posix_ace
)
*
count
;
/* skip past access ACEs to get to default ACEs */
pACE
=
&
cifs_acl
->
ace_array
[
count
];
count
=
le16_to_cpu
(
cifs_acl
->
default_entry_count
);
size
+=
sizeof
(
struct
cifs_posix_ace
)
*
count
;
/* check if we would go beyond end of SMB */
if
(
size_of_data_area
<
size
)
return
-
EINVAL
;
}
else
{
/* illegal type */
return
-
EINVAL
;
}
size
=
posix_acl_xattr_size
(
count
);
if
((
buflen
==
0
)
||
(
local_acl
==
NULL
))
{
/* used to query ACL EA size */
}
else
if
(
size
>
buflen
)
{
return
-
ERANGE
;
}
else
/* buffer big enough */
{
local_acl
->
a_version
=
POSIX_ACL_XATTR_VERSION
;
for
(
i
=
0
;
i
<
count
;
i
++
)
{
cifs_convert_ace
(
&
local_acl
->
a_entries
[
i
],
pACE
);
pACE
++
;
}
}
return
size
;
}
__u16
convert_ace_to_cifs_ace
(
struct
cifs_posix_ace
*
cifs_ace
,
const
posix_acl_xattr_entry
*
local_ace
)
{
__u16
rc
=
0
;
/* 0 = ACL converted ok */
cifs_ace
->
cifs_e_perm
=
(
__u8
)
cpu_to_le16
(
local_ace
->
e_perm
);
cifs_ace
->
cifs_e_tag
=
(
__u8
)
cpu_to_le16
(
local_ace
->
e_tag
);
/* BB is there a better way to handle the large uid? */
if
(
local_ace
->
e_id
==
-
1
)
{
/* Probably no need to le convert -1 on any arch but can not hurt */
cifs_ace
->
cifs_uid
=
cpu_to_le64
(
-
1
);
}
else
cifs_ace
->
cifs_uid
=
(
__u64
)
cpu_to_le32
(
local_ace
->
e_id
);
/*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
return
rc
;
}
/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
__u16
ACL_to_cifs_posix
(
char
*
parm_data
,
const
char
*
pACL
,
const
int
buflen
,
const
int
acl_type
)
{
__u16
rc
=
0
;
struct
cifs_posix_acl
*
cifs_acl
=
(
struct
cifs_posix_acl
*
)
parm_data
;
posix_acl_xattr_header
*
local_acl
=
(
posix_acl_xattr_header
*
)
pACL
;
int
count
;
int
i
;
if
((
buflen
==
0
)
||
(
pACL
==
NULL
)
||
(
cifs_acl
==
NULL
))
return
0
;
count
=
posix_acl_xattr_count
((
size_t
)
buflen
);
cFYI
(
1
,(
"setting acl with %d entries from buf of length %d and version of %d"
,
count
,
buflen
,
local_acl
->
a_version
));
if
(
local_acl
->
a_version
!=
2
)
{
cFYI
(
1
,(
"unknown POSIX ACL version %d"
,
local_acl
->
a_version
));
return
0
;
}
cifs_acl
->
version
=
cpu_to_le16
(
1
);
if
(
acl_type
==
ACL_TYPE_ACCESS
)
cifs_acl
->
access_entry_count
=
count
;
else
if
(
acl_type
==
ACL_TYPE_DEFAULT
)
cifs_acl
->
default_entry_count
=
count
;
else
{
cFYI
(
1
,(
"unknown ACL type %d"
,
acl_type
));
return
0
;
}
for
(
i
=
0
;
i
<
count
;
i
++
)
{
rc
=
convert_ace_to_cifs_ace
(
&
cifs_acl
->
ace_array
[
i
],
&
local_acl
->
a_entries
[
i
]);
if
(
rc
!=
0
)
{
/* ACE not converted */
break
;
}
}
if
(
rc
==
0
)
{
rc
=
(
__u16
)(
count
*
sizeof
(
struct
cifs_posix_ace
));
rc
+=
sizeof
(
struct
cifs_posix_acl
);
/* BB add check to make sure ACL does not overflow SMB */
}
return
rc
;
}
int
CIFSSMBGetPosixACL
(
const
int
xid
,
struct
cifsTconInfo
*
tcon
,
const
unsigned
char
*
searchName
,
char
*
acl_inf
,
const
int
buflen
,
const
int
acl_type
,
const
struct
nls_table
*
nls_codepage
)
{
/* SMB_QUERY_POSIX_ACL */
TRANSACTION2_QPI_REQ
*
pSMB
=
NULL
;
TRANSACTION2_QPI_RSP
*
pSMBr
=
NULL
;
int
rc
=
0
;
int
bytes_returned
;
int
name_len
;
__u16
params
,
byte_count
;
cFYI
(
1
,
(
"In GetPosixACL (Unix) for path %s"
,
searchName
));
queryAclRetry:
rc
=
smb_init
(
SMB_COM_TRANSACTION2
,
15
,
tcon
,
(
void
**
)
&
pSMB
,
(
void
**
)
&
pSMBr
);
if
(
rc
)
return
rc
;
if
(
pSMB
->
hdr
.
Flags2
&
SMBFLG2_UNICODE
)
{
name_len
=
cifs_strtoUCS
((
wchar_t
*
)
pSMB
->
FileName
,
searchName
,
530
/* BB fixme find define for this maxpathcomponent */
,
nls_codepage
);
name_len
++
;
/* trailing null */
name_len
*=
2
;
pSMB
->
FileName
[
name_len
]
=
0
;
pSMB
->
FileName
[
name_len
+
1
]
=
0
;
}
else
{
/* BB improve the check for buffer overruns BB */
name_len
=
strnlen
(
searchName
,
530
/* BB fixme */
);
name_len
++
;
/* trailing null */
strncpy
(
pSMB
->
FileName
,
searchName
,
name_len
);
}
params
=
2
/* level */
+
4
/* rsrvd */
+
name_len
/* incl null */
;
pSMB
->
TotalDataCount
=
0
;
pSMB
->
MaxParameterCount
=
cpu_to_le16
(
2
);
/* BB find exact max data count below from sess structure BB */
pSMB
->
MaxDataCount
=
cpu_to_le16
(
4000
);
pSMB
->
MaxSetupCount
=
0
;
pSMB
->
Reserved
=
0
;
pSMB
->
Flags
=
0
;
pSMB
->
Timeout
=
0
;
pSMB
->
Reserved2
=
0
;
pSMB
->
ParameterOffset
=
cpu_to_le16
(
offsetof
(
struct
smb_com_transaction2_qpi_req
,
InformationLevel
)
-
4
);
pSMB
->
DataCount
=
0
;
pSMB
->
DataOffset
=
0
;
pSMB
->
SetupCount
=
1
;
pSMB
->
Reserved3
=
0
;
pSMB
->
SubCommand
=
cpu_to_le16
(
TRANS2_QUERY_PATH_INFORMATION
);
byte_count
=
params
+
1
/* pad */
;
pSMB
->
TotalParameterCount
=
cpu_to_le16
(
params
);
pSMB
->
ParameterCount
=
pSMB
->
TotalParameterCount
;
pSMB
->
InformationLevel
=
cpu_to_le16
(
SMB_QUERY_POSIX_ACL
);
pSMB
->
Reserved4
=
0
;
pSMB
->
hdr
.
smb_buf_length
+=
byte_count
;
pSMB
->
ByteCount
=
cpu_to_le16
(
byte_count
);
rc
=
SendReceive
(
xid
,
tcon
->
ses
,
(
struct
smb_hdr
*
)
pSMB
,
(
struct
smb_hdr
*
)
pSMBr
,
&
bytes_returned
,
0
);
if
(
rc
)
{
cFYI
(
1
,
(
"Send error in Query POSIX ACL = %d"
,
rc
));
}
else
{
/* decode response */
rc
=
validate_t2
((
struct
smb_t2_rsp
*
)
pSMBr
);
if
(
rc
||
(
pSMBr
->
ByteCount
<
2
))
/* BB also check enough total bytes returned */
rc
=
-
EIO
;
/* bad smb */
else
{
__u16
data_offset
=
le16_to_cpu
(
pSMBr
->
t2
.
DataOffset
);
__u16
count
=
le16_to_cpu
(
pSMBr
->
t2
.
DataCount
);
rc
=
cifs_copy_posix_acl
(
acl_inf
,
(
char
*
)
&
pSMBr
->
hdr
.
Protocol
+
data_offset
,
buflen
,
acl_type
,
count
);
}
}
if
(
pSMB
)
cifs_buf_release
(
pSMB
);
if
(
rc
==
-
EAGAIN
)
goto
queryAclRetry
;
return
rc
;
}
int
CIFSSMBSetPosixACL
(
const
int
xid
,
struct
cifsTconInfo
*
tcon
,
const
unsigned
char
*
fileName
,
const
char
*
local_acl
,
const
int
buflen
,
const
int
acl_type
,
const
struct
nls_table
*
nls_codepage
)
{
struct
smb_com_transaction2_spi_req
*
pSMB
=
NULL
;
struct
smb_com_transaction2_spi_rsp
*
pSMBr
=
NULL
;
char
*
parm_data
;
int
name_len
;
int
rc
=
0
;
int
bytes_returned
=
0
;
__u16
params
,
byte_count
,
data_count
,
param_offset
,
offset
;
cFYI
(
1
,
(
"In SetPosixACL (Unix) for path %s"
,
fileName
));
setAclRetry:
rc
=
smb_init
(
SMB_COM_TRANSACTION2
,
15
,
tcon
,
(
void
**
)
&
pSMB
,
(
void
**
)
&
pSMBr
);
if
(
rc
)
return
rc
;
if
(
pSMB
->
hdr
.
Flags2
&
SMBFLG2_UNICODE
)
{
name_len
=
cifs_strtoUCS
((
wchar_t
*
)
pSMB
->
FileName
,
fileName
,
530
/* BB fixme find define for this maxpathcomponent */
,
nls_codepage
);
name_len
++
;
/* trailing null */
name_len
*=
2
;
}
else
{
/* BB improve the check for buffer overruns BB */
name_len
=
strnlen
(
fileName
,
530
);
name_len
++
;
/* trailing null */
strncpy
(
pSMB
->
FileName
,
fileName
,
name_len
);
}
params
=
6
+
name_len
;
pSMB
->
MaxParameterCount
=
cpu_to_le16
(
2
);
pSMB
->
MaxDataCount
=
cpu_to_le16
(
1000
);
/* BB find max SMB size from sess */
pSMB
->
MaxSetupCount
=
0
;
pSMB
->
Reserved
=
0
;
pSMB
->
Flags
=
0
;
pSMB
->
Timeout
=
0
;
pSMB
->
Reserved2
=
0
;
param_offset
=
offsetof
(
struct
smb_com_transaction2_spi_req
,
InformationLevel
)
-
4
;
offset
=
param_offset
+
params
;
parm_data
=
((
char
*
)
&
pSMB
->
hdr
.
Protocol
)
+
offset
;
pSMB
->
ParameterOffset
=
cpu_to_le16
(
param_offset
);
/* convert to on the wire format for POSIX ACL */
data_count
=
ACL_to_cifs_posix
(
parm_data
,
local_acl
,
buflen
,
acl_type
);
if
(
data_count
==
0
)
{
rc
=
-
EOPNOTSUPP
;
goto
setACLerrorExit
;
}
pSMB
->
DataOffset
=
cpu_to_le16
(
offset
);
pSMB
->
SetupCount
=
1
;
pSMB
->
Reserved3
=
0
;
pSMB
->
SubCommand
=
cpu_to_le16
(
TRANS2_SET_PATH_INFORMATION
);
pSMB
->
InformationLevel
=
cpu_to_le16
(
SMB_SET_POSIX_ACL
);
byte_count
=
3
/* pad */
+
params
+
data_count
;
pSMB
->
DataCount
=
cpu_to_le16
(
data_count
);
pSMB
->
TotalDataCount
=
pSMB
->
DataCount
;
pSMB
->
ParameterCount
=
cpu_to_le16
(
params
);
pSMB
->
TotalParameterCount
=
pSMB
->
ParameterCount
;
pSMB
->
Reserved4
=
0
;
pSMB
->
hdr
.
smb_buf_length
+=
byte_count
;
pSMB
->
ByteCount
=
cpu_to_le16
(
byte_count
);
rc
=
SendReceive
(
xid
,
tcon
->
ses
,
(
struct
smb_hdr
*
)
pSMB
,
(
struct
smb_hdr
*
)
pSMBr
,
&
bytes_returned
,
0
);
if
(
rc
)
{
cFYI
(
1
,
(
"Set POSIX ACL returned %d"
,
rc
));
}
setACLerrorExit:
if
(
pSMB
)
cifs_buf_release
(
pSMB
);
if
(
rc
==
-
EAGAIN
)
goto
setAclRetry
;
return
rc
;
}
#endif
int
CIFSSMBQPathInfo
(
const
int
xid
,
struct
cifsTconInfo
*
tcon
,
const
unsigned
char
*
searchName
,
...
...
@@ -1564,7 +2007,7 @@ CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
int
name_len
;
__u16
params
,
byte_count
;
cFYI
(
1
,
(
"In QPathInfo path %s"
,
searchName
));
/* cFYI(1, ("In QPathInfo path %s", searchName)); */
/* BB fixme BB */
QPathInfoRetry:
rc
=
smb_init
(
SMB_COM_TRANSACTION2
,
15
,
tcon
,
(
void
**
)
&
pSMB
,
(
void
**
)
&
pSMBr
);
...
...
@@ -1613,13 +2056,12 @@ CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
if
(
rc
)
{
cFYI
(
1
,
(
"Send error in QPathInfo = %d"
,
rc
));
}
else
{
/* decode response */
__u16
data_offset
=
le16_to_cpu
(
pSMBr
->
DataOffset
);
/* BB also check enough total bytes returned */
/* BB we need to improve the validity checking
of these trans2 responses */
if
((
pSMBr
->
ByteCount
<
40
)
||
(
data_offset
>
512
))
rc
=
validate_t2
((
struct
smb_t2_rsp
*
)
pSMBr
);
if
(
rc
||
(
pSMBr
->
ByteCount
<
40
))
rc
=
-
EIO
;
/* bad smb */
else
if
(
pFindData
){
__u16
data_offset
=
le16_to_cpu
(
pSMBr
->
t2
.
DataOffset
);
memcpy
((
char
*
)
pFindData
,
(
char
*
)
&
pSMBr
->
hdr
.
Protocol
+
data_offset
,
sizeof
(
FILE_ALL_INFO
));
...
...
@@ -1698,15 +2140,12 @@ CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
if
(
rc
)
{
cFYI
(
1
,
(
"Send error in QPathInfo = %d"
,
rc
));
}
else
{
/* decode response */
__u16
data_offset
=
le16_to_cpu
(
pSMBr
->
DataOffset
);
/* BB also check if enough total bytes returned */
if
((
pSMBr
->
ByteCount
<
sizeof
(
FILE_UNIX_BASIC_INFO
))
||
(
data_offset
>
512
)
||
(
data_offset
<
sizeof
(
struct
smb_hdr
)))
{
cFYI
(
1
,(
"UnixQPathinfo invalid data offset %d bytes returned %d"
,
(
int
)
data_offset
,
bytes_returned
));
rc
=
validate_t2
((
struct
smb_t2_rsp
*
)
pSMBr
);
if
(
rc
||
(
pSMBr
->
ByteCount
<
sizeof
(
FILE_UNIX_BASIC_INFO
)))
{
rc
=
-
EIO
;
/* bad smb */
}
else
{
__u16
data_offset
=
le16_to_cpu
(
pSMBr
->
t2
.
DataOffset
);
memcpy
((
char
*
)
pFindData
,
(
char
*
)
&
pSMBr
->
hdr
.
Protocol
+
data_offset
,
...
...
@@ -1721,6 +2160,7 @@ CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
return
rc
;
}
#ifdef CONFIG_CIFS_EXPERIMENTAL
/* function unused at present */
int
CIFSFindSingle
(
const
int
xid
,
struct
cifsTconInfo
*
tcon
,
const
char
*
searchName
,
FILE_ALL_INFO
*
findData
,
...
...
@@ -1764,7 +2204,7 @@ CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
pSMB
->
Timeout
=
0
;
pSMB
->
Reserved2
=
0
;
pSMB
->
ParameterOffset
=
cpu_to_le16
(
offsetof
(
struct
smb_com_transaction2_ffirst_req
,
InformationLevel
)
-
4
);
offsetof
(
struct
smb_com_transaction2_ffirst_req
,
InformationLevel
)
-
4
);
pSMB
->
DataCount
=
0
;
pSMB
->
DataOffset
=
0
;
pSMB
->
SetupCount
=
1
;
/* one byte, no need to le convert */
...
...
@@ -1799,6 +2239,7 @@ CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
return
rc
;
}
#endif
/* CIFS_EXPERIMENTAL */
int
CIFSFindFirst
(
const
int
xid
,
struct
cifsTconInfo
*
tcon
,
...
...
@@ -1849,8 +2290,8 @@ CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
byte_count
=
params
+
1
/* pad */
;
pSMB
->
TotalParameterCount
=
cpu_to_le16
(
params
);
pSMB
->
ParameterCount
=
pSMB
->
TotalParameterCount
;
pSMB
->
ParameterOffset
=
cpu_to_le16
(
offsetof
(
struct
smb_com_transaction2_ffirst_req
,
SearchAttributes
)
-
4
);
pSMB
->
ParameterOffset
=
cpu_to_le16
(
offsetof
(
struct
smb_com_transaction2_ffirst_req
,
SearchAttributes
)
-
4
);
pSMB
->
DataCount
=
0
;
pSMB
->
DataOffset
=
0
;
pSMB
->
SetupCount
=
1
;
/* one byte no need to make endian neutral */
...
...
@@ -1880,20 +2321,25 @@ CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
if
(
rc
)
{
/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
cFYI
(
1
,
(
"Error in FindFirst = %d"
,
rc
));
}
else
{
/* decode response */
}
else
{
rc
=
validate_t2
((
struct
smb_t2_rsp
*
)
pSMBr
);
if
(
!
rc
)
{
/* decode response */
/* BB add safety checks for these memcpys */
if
(
pSMBr
->
hdr
.
Flags2
&
SMBFLG2_UNICODE
)
*
pUnicodeFlag
=
TRUE
;
else
*
pUnicodeFlag
=
FALSE
;
memcpy
(
findParms
,
(
char
*
)
&
pSMBr
->
hdr
.
Protocol
+
le16_to_cpu
(
pSMBr
->
ParameterOffset
),
sizeof
(
T2_FFIRST_RSP_PARMS
));
response_data
=
(
char
*
)
&
pSMBr
->
hdr
.
Protocol
+
le16_to_cpu
(
pSMBr
->
DataOffset
);
memcpy
(
findData
,
response_data
,
le16_to_cpu
(
pSMBr
->
DataCount
));
if
(
pSMBr
->
hdr
.
Flags2
&
SMBFLG2_UNICODE
)
*
pUnicodeFlag
=
TRUE
;
else
*
pUnicodeFlag
=
FALSE
;
memcpy
(
findParms
,
(
char
*
)
&
pSMBr
->
hdr
.
Protocol
+
le16_to_cpu
(
pSMBr
->
t2
.
ParameterOffset
),
sizeof
(
T2_FFIRST_RSP_PARMS
));
response_data
=
(
char
*
)
&
pSMBr
->
hdr
.
Protocol
+
le16_to_cpu
(
pSMBr
->
t2
.
DataOffset
);
memcpy
(
findData
,
response_data
,
le16_to_cpu
(
pSMBr
->
t2
.
DataCount
));
}
}
if
(
pSMB
)
cifs_buf_release
(
pSMB
);
...
...
@@ -1904,6 +2350,256 @@ CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
return
rc
;
}
/* xid, tcon, searchName and codepage are input parms, rest are returned */
int
CIFSFindFirst2
(
const
int
xid
,
struct
cifsTconInfo
*
tcon
,
const
char
*
searchName
,
const
struct
nls_table
*
nls_codepage
,
__u16
*
pnetfid
,
struct
cifs_search_info
*
psrch_inf
)
{
/* level 257 SMB_ */
TRANSACTION2_FFIRST_REQ
*
pSMB
=
NULL
;
TRANSACTION2_FFIRST_RSP
*
pSMBr
=
NULL
;
T2_FFIRST_RSP_PARMS
*
parms
;
int
rc
=
0
;
int
bytes_returned
=
0
;
int
name_len
;
__u16
params
,
byte_count
;
cFYI
(
1
,
(
"In FindFirst2"
));
findFirst2Retry:
rc
=
smb_init
(
SMB_COM_TRANSACTION2
,
15
,
tcon
,
(
void
**
)
&
pSMB
,
(
void
**
)
&
pSMBr
);
if
(
rc
)
return
rc
;
if
(
pSMB
->
hdr
.
Flags2
&
SMBFLG2_UNICODE
)
{
name_len
=
cifs_strtoUCS
((
wchar_t
*
)
pSMB
->
FileName
,
searchName
,
PATH_MAX
,
nls_codepage
);
name_len
++
;
/* trailing null */
name_len
*=
2
;
pSMB
->
FileName
[
name_len
]
=
0
;
/* null terminate just in case */
pSMB
->
FileName
[
name_len
+
1
]
=
0
;
}
else
{
/* BB add check for overrun of SMB buf BB */
name_len
=
strnlen
(
searchName
,
PATH_MAX
);
name_len
++
;
/* trailing null */
/* BB fix here and in unicode clause above ie
if(name_len > buffersize-header)
free buffer exit; BB */
strncpy
(
pSMB
->
FileName
,
searchName
,
name_len
);
pSMB
->
FileName
[
name_len
]
=
0
;
/* just in case */
}
params
=
12
+
name_len
/* includes null */
;
pSMB
->
TotalDataCount
=
0
;
/* no EAs */
pSMB
->
MaxParameterCount
=
cpu_to_le16
(
10
);
pSMB
->
MaxDataCount
=
cpu_to_le16
((
tcon
->
ses
->
server
->
maxBuf
-
MAX_CIFS_HDR_SIZE
)
&
0xFFFFFF00
);
pSMB
->
MaxSetupCount
=
0
;
pSMB
->
Reserved
=
0
;
pSMB
->
Flags
=
0
;
pSMB
->
Timeout
=
0
;
pSMB
->
Reserved2
=
0
;
byte_count
=
params
+
1
/* pad */
;
pSMB
->
TotalParameterCount
=
cpu_to_le16
(
params
);
pSMB
->
ParameterCount
=
pSMB
->
TotalParameterCount
;
pSMB
->
ParameterOffset
=
cpu_to_le16
(
offsetof
(
struct
smb_com_transaction2_ffirst_req
,
SearchAttributes
)
-
4
);
pSMB
->
DataCount
=
0
;
pSMB
->
DataOffset
=
0
;
pSMB
->
SetupCount
=
1
;
/* one byte, no need to make endian neutral */
pSMB
->
Reserved3
=
0
;
pSMB
->
SubCommand
=
cpu_to_le16
(
TRANS2_FIND_FIRST
);
pSMB
->
SearchAttributes
=
cpu_to_le16
(
ATTR_READONLY
|
ATTR_HIDDEN
|
ATTR_SYSTEM
|
ATTR_DIRECTORY
);
pSMB
->
SearchCount
=
cpu_to_le16
(
CIFS_MAX_MSGSIZE
/
sizeof
(
FILE_UNIX_INFO
));
pSMB
->
SearchFlags
=
cpu_to_le16
(
CIFS_SEARCH_CLOSE_AT_END
|
CIFS_SEARCH_RETURN_RESUME
);
pSMB
->
InformationLevel
=
cpu_to_le16
(
psrch_inf
->
info_level
);
/* BB what should we set StorageType to? Does it matter? BB */
pSMB
->
SearchStorageType
=
0
;
pSMB
->
hdr
.
smb_buf_length
+=
byte_count
;
pSMB
->
ByteCount
=
cpu_to_le16
(
byte_count
);
rc
=
SendReceive
(
xid
,
tcon
->
ses
,
(
struct
smb_hdr
*
)
pSMB
,
(
struct
smb_hdr
*
)
pSMBr
,
&
bytes_returned
,
0
);
if
(
rc
)
{
/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
/* BB Add code to handle unsupported level rc */
cFYI
(
1
,
(
"Error in FindFirst = %d"
,
rc
));
if
(
pSMB
)
cifs_buf_release
(
pSMB
);
/* BB eventually could optimize out free and realloc of buf */
/* for this case */
if
(
rc
==
-
EAGAIN
)
goto
findFirst2Retry
;
}
else
{
/* decode response */
/* BB remember to free buffer if error BB */
rc
=
validate_t2
((
struct
smb_t2_rsp
*
)
pSMBr
);
if
(
rc
==
0
)
{
if
(
pSMBr
->
hdr
.
Flags2
&
SMBFLG2_UNICODE
)
psrch_inf
->
unicode
=
TRUE
;
else
psrch_inf
->
unicode
=
FALSE
;
psrch_inf
->
ntwrk_buf_start
=
(
char
*
)
pSMBr
;
psrch_inf
->
srch_entries_start
=
(
char
*
)
&
pSMBr
->
hdr
.
Protocol
+
le16_to_cpu
(
pSMBr
->
t2
.
DataOffset
);
parms
=
(
T2_FFIRST_RSP_PARMS
*
)((
char
*
)
&
pSMBr
->
hdr
.
Protocol
+
le16_to_cpu
(
pSMBr
->
t2
.
ParameterOffset
));
if
(
parms
->
EndofSearch
)
psrch_inf
->
endOfSearch
=
TRUE
;
else
psrch_inf
->
endOfSearch
=
FALSE
;
psrch_inf
->
entries_in_buffer
=
le16_to_cpu
(
parms
->
SearchCount
);
psrch_inf
->
index_of_last_entry
=
psrch_inf
->
entries_in_buffer
;
/*cFYI(1,("entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
*
pnetfid
=
parms
->
SearchHandle
;
}
else
{
if
(
pSMB
)
cifs_buf_release
(
pSMB
);
}
}
return
rc
;
}
int
CIFSFindNext2
(
const
int
xid
,
struct
cifsTconInfo
*
tcon
,
__u16
searchHandle
,
struct
cifs_search_info
*
psrch_inf
)
{
TRANSACTION2_FNEXT_REQ
*
pSMB
=
NULL
;
TRANSACTION2_FNEXT_RSP
*
pSMBr
=
NULL
;
T2_FNEXT_RSP_PARMS
*
parms
;
char
*
response_data
;
int
rc
=
0
;
int
bytes_returned
,
name_len
;
__u16
params
,
byte_count
;
cFYI
(
1
,
(
"In FindNext2"
));
if
(
psrch_inf
->
endOfSearch
==
TRUE
)
return
-
ENOENT
;
rc
=
smb_init
(
SMB_COM_TRANSACTION2
,
15
,
tcon
,
(
void
**
)
&
pSMB
,
(
void
**
)
&
pSMBr
);
if
(
rc
)
return
rc
;
params
=
14
;
/* includes 2 bytes of null string, converted to LE below */
byte_count
=
0
;
pSMB
->
TotalDataCount
=
0
;
/* no EAs */
pSMB
->
MaxParameterCount
=
cpu_to_le16
(
8
);
pSMB
->
MaxDataCount
=
cpu_to_le16
((
tcon
->
ses
->
server
->
maxBuf
-
MAX_CIFS_HDR_SIZE
)
&
0xFFFFFF00
);
pSMB
->
MaxSetupCount
=
0
;
pSMB
->
Reserved
=
0
;
pSMB
->
Flags
=
0
;
pSMB
->
Timeout
=
0
;
pSMB
->
Reserved2
=
0
;
pSMB
->
ParameterOffset
=
cpu_to_le16
(
offsetof
(
struct
smb_com_transaction2_fnext_req
,
SearchHandle
)
-
4
);
pSMB
->
DataCount
=
0
;
pSMB
->
DataOffset
=
0
;
pSMB
->
SetupCount
=
1
;
pSMB
->
Reserved3
=
0
;
pSMB
->
SubCommand
=
cpu_to_le16
(
TRANS2_FIND_NEXT
);
pSMB
->
SearchHandle
=
searchHandle
;
/* always kept as le */
pSMB
->
SearchCount
=
cpu_to_le16
(
CIFS_MAX_MSGSIZE
/
sizeof
(
FILE_UNIX_INFO
));
/* test for Unix extensions */
/* if (tcon->ses->capabilities & CAP_UNIX) {
pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
psrch_inf->info_level = SMB_FIND_FILE_UNIX;
} else {
pSMB->InformationLevel =
cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
} */
pSMB
->
InformationLevel
=
cpu_to_le16
(
psrch_inf
->
info_level
);
pSMB
->
ResumeKey
=
psrch_inf
->
resume_key
;
pSMB
->
SearchFlags
=
cpu_to_le16
(
CIFS_SEARCH_CLOSE_AT_END
|
CIFS_SEARCH_RETURN_RESUME
);
name_len
=
psrch_inf
->
resume_name_len
;
params
+=
name_len
;
if
(
name_len
<
PATH_MAX
)
{
memcpy
(
pSMB
->
ResumeFileName
,
psrch_inf
->
presume_name
,
name_len
);
byte_count
+=
name_len
;
}
else
{
rc
=
-
EINVAL
;
goto
FNext2_err_exit
;
}
byte_count
=
params
+
1
/* pad */
;
pSMB
->
TotalParameterCount
=
cpu_to_le16
(
params
);
pSMB
->
ParameterCount
=
pSMB
->
TotalParameterCount
;
pSMB
->
hdr
.
smb_buf_length
+=
byte_count
;
pSMB
->
ByteCount
=
cpu_to_le16
(
byte_count
);
rc
=
SendReceive
(
xid
,
tcon
->
ses
,
(
struct
smb_hdr
*
)
pSMB
,
(
struct
smb_hdr
*
)
pSMBr
,
&
bytes_returned
,
0
);
if
(
rc
)
{
if
(
rc
==
-
EBADF
)
{
psrch_inf
->
endOfSearch
=
TRUE
;
rc
=
0
;
/* search probably was closed at end of search above */
}
else
cFYI
(
1
,
(
"FindNext returned = %d"
,
rc
));
}
else
{
/* decode response */
rc
=
validate_t2
((
struct
smb_t2_rsp
*
)
pSMBr
);
if
(
rc
==
0
)
{
/* BB fixme add lock for file (srch_info) struct here */
if
(
pSMBr
->
hdr
.
Flags2
&
SMBFLG2_UNICODE
)
psrch_inf
->
unicode
=
TRUE
;
else
psrch_inf
->
unicode
=
FALSE
;
response_data
=
(
char
*
)
&
pSMBr
->
hdr
.
Protocol
+
le16_to_cpu
(
pSMBr
->
t2
.
ParameterOffset
);
parms
=
(
T2_FNEXT_RSP_PARMS
*
)
response_data
;
response_data
=
(
char
*
)
&
pSMBr
->
hdr
.
Protocol
+
le16_to_cpu
(
pSMBr
->
t2
.
DataOffset
);
cifs_buf_release
(
psrch_inf
->
ntwrk_buf_start
);
psrch_inf
->
srch_entries_start
=
response_data
;
psrch_inf
->
ntwrk_buf_start
=
(
char
*
)
pSMB
;
if
(
parms
->
EndofSearch
)
psrch_inf
->
endOfSearch
=
TRUE
;
else
psrch_inf
->
endOfSearch
=
FALSE
;
psrch_inf
->
entries_in_buffer
=
le16_to_cpu
(
parms
->
SearchCount
);
psrch_inf
->
index_of_last_entry
+=
psrch_inf
->
entries_in_buffer
;
/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
/* BB fixme add unlock here */
}
}
/* BB On error, should we leave previous search buf (and count and
last entry fields) intact or free the previous one? */
/* Note: On -EAGAIN error only caller can retry on handle based calls
since file handle passed in no longer valid */
FNext2_err_exit:
if
((
rc
!=
0
)
&&
pSMB
)
cifs_buf_release
(
pSMB
);
return
rc
;
}
int
CIFSFindNext
(
const
int
xid
,
struct
cifsTconInfo
*
tcon
,
FILE_DIRECTORY_INFO
*
findData
,
T2_FNEXT_RSP_PARMS
*
findParms
,
...
...
@@ -1939,8 +2635,8 @@ CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
pSMB
->
Flags
=
0
;
pSMB
->
Timeout
=
0
;
pSMB
->
Reserved2
=
0
;
pSMB
->
ParameterOffset
=
cpu_to_le16
(
offsetof
(
struct
smb_com_transaction2_fnext_req
,
SearchHandle
)
-
4
);
pSMB
->
ParameterOffset
=
cpu_to_le16
(
offsetof
(
struct
smb_com_transaction2_fnext_req
,
SearchHandle
)
-
4
);
pSMB
->
DataCount
=
0
;
pSMB
->
DataOffset
=
0
;
pSMB
->
SetupCount
=
1
;
...
...
@@ -1949,7 +2645,7 @@ CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
pSMB
->
SearchHandle
=
searchHandle
;
/* always kept as le */
findParms
->
SearchCount
=
0
;
/* set to zero in case of error */
pSMB
->
SearchCount
=
cpu_to_le16
(
CIFS_MAX_MSGSIZE
/
sizeof
(
FILE_
DIRECTORY
_INFO
));
cpu_to_le16
(
CIFS_MAX_MSGSIZE
/
sizeof
(
FILE_
UNIX
_INFO
));
/* test for Unix extensions */
if
(
tcon
->
ses
->
capabilities
&
CAP_UNIX
)
{
pSMB
->
InformationLevel
=
cpu_to_le16
(
SMB_FIND_FILE_UNIX
);
...
...
@@ -1963,7 +2659,7 @@ CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
pSMB
->
SearchFlags
=
cpu_to_le16
(
CIFS_SEARCH_CLOSE_AT_END
|
CIFS_SEARCH_RETURN_RESUME
);
/* BB add check to make sure we do not cross end of smb */
if
(
name_len
<
CIFS_MAX_MSGSIZE
)
{
if
(
name_len
<
PATH_MAX
)
{
memcpy
(
pSMB
->
ResumeFileName
,
resume_file_name
,
name_len
);
byte_count
+=
name_len
;
}
...
...
@@ -1984,19 +2680,23 @@ CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
else
cFYI
(
1
,
(
"FindNext returned = %d"
,
rc
));
}
else
{
/* decode response */
rc
=
validate_t2
((
struct
smb_t2_rsp
*
)
pSMBr
);
/* BB add safety checks for these memcpys */
if
(
pSMBr
->
hdr
.
Flags2
&
SMBFLG2_UNICODE
)
*
pUnicodeFlag
=
TRUE
;
else
*
pUnicodeFlag
=
FALSE
;
memcpy
(
findParms
,
(
char
*
)
&
pSMBr
->
hdr
.
Protocol
+
le16_to_cpu
(
pSMBr
->
ParameterOffset
),
sizeof
(
T2_FNEXT_RSP_PARMS
));
response_data
=
(
char
*
)
&
pSMBr
->
hdr
.
Protocol
+
le16_to_cpu
(
pSMBr
->
DataOffset
);
memcpy
(
findData
,
response_data
,
le16_to_cpu
(
pSMBr
->
DataCount
));
if
(
rc
==
0
)
{
if
(
pSMBr
->
hdr
.
Flags2
&
SMBFLG2_UNICODE
)
*
pUnicodeFlag
=
TRUE
;
else
*
pUnicodeFlag
=
FALSE
;
memcpy
(
findParms
,
(
char
*
)
&
pSMBr
->
hdr
.
Protocol
+
le16_to_cpu
(
pSMBr
->
t2
.
ParameterOffset
),
sizeof
(
T2_FNEXT_RSP_PARMS
));
response_data
=
(
char
*
)
&
pSMBr
->
hdr
.
Protocol
+
le16_to_cpu
(
pSMBr
->
t2
.
DataOffset
);
memcpy
(
findData
,
response_data
,
le16_to_cpu
(
pSMBr
->
t2
.
DataCount
));
}
}
if
(
pSMB
)
cifs_buf_release
(
pSMB
);
...
...
@@ -2042,6 +2742,39 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle
return
rc
;
}
#ifdef CONFIG_CIFS_EXPERIMENTAL
int
CIFSGetSrvInodeNumber
(
const
int
xid
,
struct
cifsTconInfo
*
tcon
,
const
unsigned
char
*
searchName
,
__u64
*
inode_number
,
const
struct
nls_table
*
nls_codepage
)
{
int
rc
=
0
;
TRANSACTION2_QPI_REQ
*
pSMB
=
NULL
;
TRANSACTION2_QPI_RSP
*
pSMBr
=
NULL
;
cFYI
(
1
,(
"In GetSrvInodeNumber for %s"
,
searchName
));
if
(
tcon
==
NULL
)
return
-
ENODEV
;
cFYI
(
1
,
(
"In QPathInfo path %s"
,
searchName
));
GetInodeNumberRetry:
rc
=
smb_init
(
SMB_COM_TRANSACTION2
,
15
,
tcon
,
(
void
**
)
&
pSMB
,
(
void
**
)
&
pSMBr
);
if
(
rc
)
return
rc
;
/* BB add missing code here */
if
(
pSMB
)
cifs_buf_release
(
pSMB
);
if
(
rc
==
-
EAGAIN
)
goto
GetInodeNumberRetry
;
return
rc
;
}
#endif
/* CIFS_EXPERIMENTAL */
int
CIFSGetDFSRefer
(
const
int
xid
,
struct
cifsSesInfo
*
ses
,
const
unsigned
char
*
searchName
,
...
...
@@ -2124,14 +2857,17 @@ CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
cFYI
(
1
,
(
"Send error in GetDFSRefer = %d"
,
rc
));
}
else
{
/* decode response */
/* BB Add logic to parse referrals here */
__u16
data_offset
=
le16_to_cpu
(
pSMBr
->
DataOffset
);
__u16
data_count
=
le16_to_cpu
(
pSMBr
->
DataCount
);
cFYI
(
1
,
(
"Decoding GetDFSRefer response. BCC: %d Offset %d"
,
pSMBr
->
ByteCount
,
data_offset
));
if
((
pSMBr
->
ByteCount
<
17
)
||
(
data_offset
>
512
))
/* BB also check enough total bytes returned */
rc
=
-
EIO
;
/* bad smb */
rc
=
validate_t2
((
struct
smb_t2_rsp
*
)
pSMBr
);
if
(
rc
||
(
pSMBr
->
ByteCount
<
17
))
/* BB also check enough total bytes returned */
rc
=
-
EIO
;
/* bad smb */
else
{
__u16
data_offset
=
le16_to_cpu
(
pSMBr
->
t2
.
DataOffset
);
__u16
data_count
=
le16_to_cpu
(
pSMBr
->
t2
.
DataCount
);
cFYI
(
1
,
(
"Decoding GetDFSRefer response. BCC: %d Offset %d"
,
pSMBr
->
ByteCount
,
data_offset
));
referrals
=
(
struct
dfs_referral_level_3
*
)
(
8
/* sizeof start of data block */
+
...
...
@@ -2257,13 +2993,16 @@ CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
if
(
rc
)
{
cERROR
(
1
,
(
"Send error in QFSInfo = %d"
,
rc
));
}
else
{
/* decode response */
__u16
data_offset
=
le16_to_cpu
(
pSMBr
->
DataOffset
);
cFYI
(
1
,
(
"Decoding qfsinfo response. BCC: %d Offset %d"
,
pSMBr
->
ByteCount
,
data_offset
));
if
((
pSMBr
->
ByteCount
<
24
)
||
(
data_offset
>
512
))
/* BB also check enough total bytes returned */
rc
=
validate_t2
((
struct
smb_t2_rsp
*
)
pSMBr
);
if
(
rc
||
(
pSMBr
->
ByteCount
<
24
))
/* BB alsO CHEck enough total bytes returned */
rc
=
-
EIO
;
/* bad smb */
else
{
__u16
data_offset
=
le16_to_cpu
(
pSMBr
->
t2
.
DataOffset
);
cFYI
(
1
,
(
"Decoding qfsinfo response. BCC: %d Offset %d"
,
pSMBr
->
ByteCount
,
data_offset
));
response_data
=
(
FILE_SYSTEM_INFO
*
)
(((
char
*
)
&
pSMBr
->
hdr
.
Protocol
)
+
...
...
@@ -2339,10 +3078,12 @@ CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon,
if
(
rc
)
{
cERROR
(
1
,
(
"Send error in QFSAttributeInfo = %d"
,
rc
));
}
else
{
/* decode response */
__u16
data_offset
=
le16_to_cpu
(
pSMBr
->
DataOffset
);
if
((
pSMBr
->
ByteCount
<
13
)
||
(
data_offset
>
512
))
{
/* BB also check enough bytes returned */
rc
=
validate_t2
((
struct
smb_t2_rsp
*
)
pSMBr
);
if
(
rc
||
(
pSMBr
->
ByteCount
<
13
))
{
/* BB also check enough bytes returned */
rc
=
-
EIO
;
/* bad smb */
}
else
{
__u16
data_offset
=
le16_to_cpu
(
pSMBr
->
t2
.
DataOffset
);
response_data
=
(
FILE_SYSTEM_ATTRIBUTE_INFO
*
)
(((
char
*
)
&
pSMBr
->
hdr
.
Protocol
)
+
...
...
@@ -2408,11 +3149,12 @@ CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon,
if
(
rc
)
{
cFYI
(
1
,
(
"Send error in QFSDeviceInfo = %d"
,
rc
));
}
else
{
/* decode response */
__u16
data_offset
=
le16_to_cpu
(
pSMBr
->
DataOffset
);
if
((
pSMBr
->
ByteCount
<
sizeof
(
FILE_SYSTEM_DEVICE_INFO
))
||
(
data_offset
>
512
))
rc
=
validate_t2
((
struct
smb_t2_rsp
*
)
pSMBr
);
if
(
rc
||
(
pSMBr
->
ByteCount
<
sizeof
(
FILE_SYSTEM_DEVICE_INFO
)
))
rc
=
-
EIO
;
/* bad smb */
else
{
__u16
data_offset
=
le16_to_cpu
(
pSMBr
->
t2
.
DataOffset
);
response_data
=
(
FILE_SYSTEM_DEVICE_INFO
*
)
(((
char
*
)
&
pSMBr
->
hdr
.
Protocol
)
+
...
...
@@ -2477,10 +3219,12 @@ CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon,
if
(
rc
)
{
cERROR
(
1
,
(
"Send error in QFSUnixInfo = %d"
,
rc
));
}
else
{
/* decode response */
__u16
data_offset
=
le16_to_cpu
(
pSMBr
->
DataOffset
);
if
((
pSMBr
->
ByteCount
<
13
)
||
(
data_offset
>
512
))
{
rc
=
validate_t2
((
struct
smb_t2_rsp
*
)
pSMBr
);
if
(
rc
||
(
pSMBr
->
ByteCount
<
13
))
{
rc
=
-
EIO
;
/* bad smb */
}
else
{
__u16
data_offset
=
le16_to_cpu
(
pSMBr
->
t2
.
DataOffset
);
response_data
=
(
FILE_SYSTEM_UNIX_INFO
*
)
(((
char
*
)
&
pSMBr
->
hdr
.
Protocol
)
+
...
...
@@ -2894,6 +3638,7 @@ CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
data_offset
=
(
FILE_UNIX_BASIC_INFO
*
)
((
char
*
)
&
pSMB
->
hdr
.
Protocol
+
offset
);
memset
(
data_offset
,
0
,
count
);
pSMB
->
DataOffset
=
cpu_to_le16
(
offset
);
pSMB
->
ParameterOffset
=
cpu_to_le16
(
param_offset
);
pSMB
->
SetupCount
=
1
;
...
...
@@ -3056,11 +3801,12 @@ CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
if
(
rc
)
{
cFYI
(
1
,
(
"Send error in QueryAllEAs = %d"
,
rc
));
}
else
{
/* decode response */
__u16
data_offset
=
le16_to_cpu
(
pSMBr
->
DataOffset
);
rc
=
validate_t2
((
struct
smb_t2_rsp
*
)
pSMBr
);
/* BB also check enough total bytes returned */
/* BB we need to improve the validity checking
of these trans2 responses */
if
(
(
pSMBr
->
ByteCount
<
4
)
||
(
data_offset
>
512
))
if
(
rc
||
(
pSMBr
->
ByteCount
<
4
))
rc
=
-
EIO
;
/* bad smb */
/* else if (pFindData){
memcpy((char *) pFindData,
...
...
@@ -3072,6 +3818,7 @@ CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
of list */
/* check that each element of each entry does not
go beyond end of list */
__u16
data_offset
=
le16_to_cpu
(
pSMBr
->
t2
.
DataOffset
);
struct
fealist
*
ea_response_data
;
rc
=
0
;
/* validate_trans2_offsets() */
...
...
@@ -3198,11 +3945,12 @@ ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
if
(
rc
)
{
cFYI
(
1
,
(
"Send error in Query EA = %d"
,
rc
));
}
else
{
/* decode response */
__u16
data_offset
=
le16_to_cpu
(
pSMBr
->
DataOffset
);
rc
=
validate_t2
((
struct
smb_t2_rsp
*
)
pSMBr
);
/* BB also check enough total bytes returned */
/* BB we need to improve the validity checking
of these trans2 responses */
if
(
(
pSMBr
->
ByteCount
<
4
)
||
(
data_offset
>
512
))
if
(
rc
||
(
pSMBr
->
ByteCount
<
4
))
rc
=
-
EIO
;
/* bad smb */
/* else if (pFindData){
memcpy((char *) pFindData,
...
...
@@ -3214,8 +3962,9 @@ ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
of list */
/* check that each element of each entry does not
go beyond end of list */
__u16
data_offset
=
le16_to_cpu
(
pSMBr
->
t2
.
DataOffset
);
struct
fealist
*
ea_response_data
;
rc
=
-
ENO
ENT
;
rc
=
-
ENO
DATA
;
/* validate_trans2_offsets() */
/* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
ea_response_data
=
(
struct
fealist
*
)
...
...
fs/cifs/connect.c
View file @
f27e5a2c
...
...
@@ -69,6 +69,9 @@ struct smb_vol {
unsigned
intr
:
1
;
unsigned
setuids
:
1
;
unsigned
noperm
:
1
;
unsigned
no_psx_acl
:
1
;
/* set if posix acl support should be disabled */
unsigned
server_ino
:
1
;
/* use inode numbers from server ie UniqueId */
unsigned
direct_io
:
1
;
unsigned
int
rsize
;
unsigned
int
wsize
;
unsigned
int
sockopt
;
...
...
@@ -335,7 +338,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
(
checkSMBhdr
(
smb_buffer
,
smb_buffer
->
Mid
)))
{
cERROR
(
1
,
(
"Invalid size or format for SMB found with length %d and pdu_leng
ht
%d"
,
(
"Invalid size or format for SMB found with length %d and pdu_leng
th
%d"
,
length
,
pdu_length
));
cifs_dump_mem
(
"Received Data is: "
,
temp
,
sizeof
(
struct
smb_hdr
));
/* could we fix this network corruption by finding next
...
...
@@ -505,7 +508,7 @@ cifs_kcalloc(size_t size, int type)
}
static
int
cifs_parse_mount_options
(
char
*
options
,
const
char
*
devname
,
struct
smb_vol
*
vol
)
cifs_parse_mount_options
(
char
*
options
,
const
char
*
devname
,
struct
smb_vol
*
vol
)
{
char
*
value
;
char
*
data
;
...
...
@@ -692,7 +695,12 @@ cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol
vol
->
file_mode
=
simple_strtoul
(
value
,
&
value
,
0
);
}
}
else
if
(
strnicmp
(
data
,
"dir_mode"
,
3
)
==
0
)
{
}
else
if
(
strnicmp
(
data
,
"dir_mode"
,
4
)
==
0
)
{
if
(
value
&&
*
value
)
{
vol
->
dir_mode
=
simple_strtoul
(
value
,
&
value
,
0
);
}
}
else
if
(
strnicmp
(
data
,
"dirmode"
,
4
)
==
0
)
{
if
(
value
&&
*
value
)
{
vol
->
dir_mode
=
simple_strtoul
(
value
,
&
value
,
0
);
...
...
@@ -742,6 +750,8 @@ cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol
/* ignore */
}
else
if
(
strnicmp
(
data
,
"version"
,
3
)
==
0
)
{
/* ignore */
}
else
if
(
strnicmp
(
data
,
"guest"
,
5
)
==
0
)
{
/* ignore */
}
else
if
(
strnicmp
(
data
,
"rw"
,
2
)
==
0
)
{
vol
->
rw
=
TRUE
;
}
else
if
((
strnicmp
(
data
,
"suid"
,
4
)
==
0
)
||
...
...
@@ -780,6 +790,18 @@ cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol
vol
->
intr
=
0
;
}
else
if
(
strnicmp
(
data
,
"intr"
,
4
)
==
0
)
{
vol
->
intr
=
1
;
}
else
if
(
strnicmp
(
data
,
"serverino"
,
7
)
==
0
)
{
vol
->
server_ino
=
1
;
}
else
if
(
strnicmp
(
data
,
"noserverino"
,
9
)
==
0
)
{
vol
->
server_ino
=
0
;
}
else
if
(
strnicmp
(
data
,
"acl"
,
3
)
==
0
)
{
vol
->
no_psx_acl
=
0
;
}
else
if
(
strnicmp
(
data
,
"noacl"
,
5
)
==
0
)
{
vol
->
no_psx_acl
=
1
;
}
else
if
(
strnicmp
(
data
,
"direct"
,
6
)
==
0
)
{
vol
->
direct_io
=
1
;
}
else
if
(
strnicmp
(
data
,
"forcedirectio"
,
13
)
==
0
)
{
vol
->
direct_io
=
1
;
}
else
if
(
strnicmp
(
data
,
"noac"
,
4
)
==
0
)
{
printk
(
KERN_WARNING
"CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0
\n
"
);
}
else
...
...
@@ -1393,6 +1415,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_NO_PERM
;
if
(
volume_info
.
setuids
)
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_SET_UID
;
if
(
volume_info
.
server_ino
)
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_SERVER_INUM
;
if
(
volume_info
.
direct_io
)
{
cERROR
(
1
,(
"mounting share using direct i/o"
));
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_DIRECT_IO
;
}
tcon
=
find_unc
(
sin_server
.
sin_addr
.
s_addr
,
volume_info
.
UNC
,
...
...
@@ -1482,8 +1510,16 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
/* do not care if following two calls succeed - informational only */
CIFSSMBQFSDeviceInfo
(
xid
,
tcon
,
cifs_sb
->
local_nls
);
CIFSSMBQFSAttributeInfo
(
xid
,
tcon
,
cifs_sb
->
local_nls
);
if
(
tcon
->
ses
->
capabilities
&
CAP_UNIX
)
CIFSSMBQFSUnixInfo
(
xid
,
tcon
,
cifs_sb
->
local_nls
);
if
(
tcon
->
ses
->
capabilities
&
CAP_UNIX
)
{
if
(
!
CIFSSMBQFSUnixInfo
(
xid
,
tcon
,
cifs_sb
->
local_nls
))
{
if
(
!
volume_info
.
no_psx_acl
)
{
if
(
CIFS_UNIX_POSIX_ACL_CAP
&
le64_to_cpu
(
tcon
->
fsUnixInfo
.
Capability
))
cFYI
(
1
,(
"server negotiated posix acl support"
));
sb
->
s_flags
|=
MS_POSIXACL
;
}
}
}
}
/* volume_info.password is freed above when existing session found
...
...
@@ -1552,14 +1588,15 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
capabilities
|=
CAP_DFS
;
}
pSMB
->
req_no_secext
.
Capabilities
=
cpu_to_le32
(
capabilities
);
/* pSMB->req_no_secext.CaseInsensitivePasswordLength =
CIFS_SESSION_KEY_SIZE; */
pSMB
->
req_no_secext
.
CaseInsensitivePasswordLength
=
0
;
pSMB
->
req_no_secext
.
CaseInsensitivePasswordLength
=
cpu_to_le16
(
CIFS_SESSION_KEY_SIZE
);
pSMB
->
req_no_secext
.
CaseSensitivePasswordLength
=
cpu_to_le16
(
CIFS_SESSION_KEY_SIZE
);
bcc_ptr
=
pByteArea
(
smb_buffer
);
/* memcpy(bcc_ptr, (char *) lm_
session_key, CIFS_SESSION_KEY_SIZE);
bcc_ptr += CIFS_SESSION_KEY_SIZE; */
memcpy
(
bcc_ptr
,
(
char
*
)
session_key
,
CIFS_SESSION_KEY_SIZE
);
bcc_ptr
+=
CIFS_SESSION_KEY_SIZE
;
memcpy
(
bcc_ptr
,
(
char
*
)
session_key
,
CIFS_SESSION_KEY_SIZE
);
bcc_ptr
+=
CIFS_SESSION_KEY_SIZE
;
...
...
fs/cifs/dir.c
View file @
f27e5a2c
...
...
@@ -399,9 +399,6 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name
(
" parent inode = 0x%p name is: %s and dentry = 0x%p"
,
parent_dir_inode
,
direntry
->
d_name
.
name
,
direntry
));
if
(
nd
)
{
/* BB removeme */
cFYI
(
1
,(
"In lookup nd flags 0x%x open intent flags 0x%x"
,
nd
->
flags
,
nd
->
intent
.
open
.
flags
));
}
/* BB removeme BB */
/* BB Add check of incoming data - e.g. frame not longer than maximum SMB - let server check the namelen BB */
/* check whether path exists */
...
...
fs/cifs/fcntl.c
View file @
f27e5a2c
...
...
@@ -37,7 +37,7 @@ int cifs_dir_notify(struct file * file, unsigned long arg)
struct
cifsTconInfo
*
pTcon
;
char
*
full_path
=
NULL
;
__u32
filter
=
FILE_NOTIFY_CHANGE_NAME
|
FILE_NOTIFY_CHANGE_ATTRIBUTES
;
__u16
netfid
;
__u16
netfid
;
xid
=
GetXid
();
cifs_sb
=
CIFS_SB
(
file
->
f_dentry
->
d_sb
);
...
...
fs/cifs/file.c
View file @
f27e5a2c
...
...
@@ -35,6 +35,8 @@
#include "cifs_debug.h"
#include "cifs_fs_sb.h"
extern
int
cifs_readdir2
(
struct
file
*
file
,
void
*
direntry
,
filldir_t
filldir
);
/* BB removeme BB */
int
cifs_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
...
...
@@ -452,18 +454,44 @@ cifs_closedir(struct inode *inode, struct file *file)
{
int
rc
=
0
;
int
xid
;
struct
cifsFileInfo
*
p
SMB
FileStruct
=
struct
cifsFileInfo
*
p
C
FileStruct
=
(
struct
cifsFileInfo
*
)
file
->
private_data
;
char
*
ptmp
;
cFYI
(
1
,
(
"Closedir inode = 0x%p with "
,
inode
));
xid
=
GetXid
();
if
(
pSMBFileStruct
)
{
if
(
pCFileStruct
)
{
struct
cifsTconInfo
*
pTcon
;
struct
cifs_sb_info
*
cifs_sb
=
CIFS_SB
(
file
->
f_dentry
->
d_sb
);
pTcon
=
cifs_sb
->
tcon
;
cFYI
(
1
,
(
"Freeing private data in close dir"
));
if
(
pCFileStruct
->
srch_inf
.
endOfSearch
==
FALSE
)
{
pCFileStruct
->
invalidHandle
=
TRUE
;
rc
=
CIFSFindClose
(
xid
,
pTcon
,
pCFileStruct
->
netfid
);
cFYI
(
1
,(
"Closing uncompleted readdir with rc %d"
,
rc
));
/* not much we can do if it fails anywway, ignore rc */
rc
=
0
;
}
ptmp
=
pCFileStruct
->
srch_inf
.
ntwrk_buf_start
;
if
(
ptmp
)
{
cFYI
(
1
,(
"freeing smb buf in srch struct in closedir"
));
/* BB removeme BB */
pCFileStruct
->
srch_inf
.
ntwrk_buf_start
=
NULL
;
cifs_buf_release
(
ptmp
);
}
ptmp
=
pCFileStruct
->
search_resume_name
;
if
(
ptmp
)
{
cFYI
(
1
,(
"freeing resume name in closedir"
));
/* BB removeme BB */
pCFileStruct
->
search_resume_name
=
NULL
;
kfree
(
ptmp
);
}
kfree
(
file
->
private_data
);
file
->
private_data
=
NULL
;
}
/* BB can we lock the filestruct while this is going on? */
FreeXid
(
xid
);
return
rc
;
}
...
...
@@ -1039,6 +1067,17 @@ int cifs_file_mmap(struct file * file, struct vm_area_struct * vma)
struct
dentry
*
dentry
=
file
->
f_dentry
;
int
rc
,
xid
;
#ifdef CIFS_EXPERIMENTAL
/* BB fixme reenable when cifs_read_wrapper fixed */
if
(
dentry
->
d_sb
)
{
struct
cifs_sb_info
*
cifs_sb
;
cifs_sb
=
CIFS_SB
(
sb
);
if
(
cifs_sb
!=
NULL
)
{
if
(
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_DIRECT_IO
)
return
-
ENODEV
}
}
#endif
/* CIFS_EXPERIMENTAL */
xid
=
GetXid
();
rc
=
cifs_revalidate
(
dentry
);
if
(
rc
)
{
...
...
@@ -1376,23 +1415,22 @@ fill_in_inode(struct inode *tmp_inode,
cFYI
(
0
,
(
"CIFS FFIRST: Attributes came in as 0x%x"
,
attr
));
if
(
attr
&
ATTR_REPARSE
)
{
*
pobject_type
=
DT_LNK
;
/* BB can this and S_IFREG or S_IFDIR be set as in Windows? */
tmp_inode
->
i_mode
|=
S_IFLNK
;
}
else
if
(
attr
&
ATTR_DIRECTORY
)
{
if
(
attr
&
ATTR_DIRECTORY
)
{
*
pobject_type
=
DT_DIR
;
/* override default perms since we do not lock dirs */
if
(
atomic_read
(
&
cifsInfo
->
inUse
)
==
0
)
{
tmp_inode
->
i_mode
=
cifs_sb
->
mnt_dir_mode
;
}
tmp_inode
->
i_mode
|=
S_IFDIR
;
/* we no longer mark these because we could not follow them */
/* } else if (attr & ATTR_REPARSE) {
*pobject_type = DT_LNK;
tmp_inode->i_mode |= S_IFLNK;*/
}
else
{
*
pobject_type
=
DT_REG
;
tmp_inode
->
i_mode
|=
S_IFREG
;
if
(
attr
&
ATTR_READONLY
)
tmp_inode
->
i_mode
&=
~
(
S_IWUGO
);
}
/* could add code here - to validate if device or weird share type? */
/* can not fill in nlink here as in qpathinfo version and Unx search */
...
...
@@ -1516,13 +1554,16 @@ unix_fill_in_inode(struct inode *tmp_inode,
}
}
static
void
/* Returns one if new inode created (which therefore needs to be hashed) */
/* Might check in the future if inode number changed so we can rehash inode */
int
construct_dentry
(
struct
qstr
*
qstring
,
struct
file
*
file
,
struct
inode
**
ptmp_inode
,
struct
dentry
**
pnew_dentry
)
{
struct
dentry
*
tmp_dentry
;
struct
cifs_sb_info
*
cifs_sb
;
struct
cifsTconInfo
*
pTcon
;
int
rc
=
0
;
cFYI
(
1
,
(
"For %s "
,
qstring
->
name
));
cifs_sb
=
CIFS_SB
(
file
->
f_dentry
->
d_sb
);
...
...
@@ -1537,29 +1578,30 @@ construct_dentry(struct qstr *qstring, struct file *file,
if
(
*
ptmp_inode
==
NULL
)
{
*
ptmp_inode
=
new_inode
(
file
->
f_dentry
->
d_sb
);
if
(
*
ptmp_inode
==
NULL
)
return
;
return
rc
;
rc
=
1
;
d_instantiate
(
tmp_dentry
,
*
ptmp_inode
);
insert_inode_hash
(
*
ptmp_inode
);
}
}
else
{
tmp_dentry
=
d_alloc
(
file
->
f_dentry
,
qstring
);
if
(
tmp_dentry
==
NULL
)
{
cERROR
(
1
,(
"Failed allocating dentry"
));
*
ptmp_inode
=
NULL
;
return
;
return
rc
;
}
*
ptmp_inode
=
new_inode
(
file
->
f_dentry
->
d_sb
);
tmp_dentry
->
d_op
=
&
cifs_dentry_ops
;
if
(
*
ptmp_inode
==
NULL
)
return
;
return
rc
;
rc
=
1
;
d_instantiate
(
tmp_dentry
,
*
ptmp_inode
);
d_rehash
(
tmp_dentry
);
insert_inode_hash
(
*
ptmp_inode
);
}
tmp_dentry
->
d_time
=
jiffies
;
*
pnew_dentry
=
tmp_dentry
;
return
rc
;
}
static
void
reset_resume_key
(
struct
file
*
dir_file
,
...
...
@@ -1609,11 +1651,19 @@ cifs_filldir(struct qstr *pqstring, FILE_DIRECTORY_INFO * pfindData,
pqstring
->
name
=
pfindData
->
FileName
;
/* pqstring->len is already set by caller */
construct_dentry
(
pqstring
,
file
,
&
tmp_inode
,
&
tmp_dentry
);
rc
=
construct_dentry
(
pqstring
,
file
,
&
tmp_inode
,
&
tmp_dentry
);
if
((
tmp_inode
==
NULL
)
||
(
tmp_dentry
==
NULL
))
{
return
-
ENOMEM
;
}
fill_in_inode
(
tmp_inode
,
pfindData
,
&
object_type
);
if
(
rc
)
{
/* We have no reliable way to get inode numbers
from servers w/o Unix extensions yet so we can not set
i_ino from pfindData yet */
/* new inode created, let us hash it */
insert_inode_hash
(
tmp_inode
);
}
/* else if inode number changed do we rehash it? */
rc
=
filldir
(
direntry
,
pfindData
->
FileName
,
pqstring
->
len
,
file
->
f_pos
,
tmp_inode
->
i_ino
,
object_type
);
if
(
rc
)
{
...
...
@@ -1637,11 +1687,19 @@ cifs_filldir_unix(struct qstr *pqstring,
pqstring
->
name
=
pUnixFindData
->
FileName
;
pqstring
->
len
=
strnlen
(
pUnixFindData
->
FileName
,
MAX_PATHCONF
);
construct_dentry
(
pqstring
,
file
,
&
tmp_inode
,
&
tmp_dentry
);
rc
=
construct_dentry
(
pqstring
,
file
,
&
tmp_inode
,
&
tmp_dentry
);
if
((
tmp_inode
==
NULL
)
||
(
tmp_dentry
==
NULL
))
{
return
-
ENOMEM
;
}
}
if
(
rc
)
{
struct
cifs_sb_info
*
cifs_sb
=
CIFS_SB
(
tmp_inode
->
i_sb
);
if
(
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_SERVER_INUM
)
{
tmp_inode
->
i_ino
=
(
unsigned
long
)
pUnixFindData
->
UniqueId
;
}
insert_inode_hash
(
tmp_inode
);
}
/* else if i_ino has changed should we rehash it? */
unix_fill_in_inode
(
tmp_inode
,
pUnixFindData
,
&
object_type
);
rc
=
filldir
(
direntry
,
pUnixFindData
->
FileName
,
pqstring
->
len
,
file
->
f_pos
,
tmp_inode
->
i_ino
,
object_type
);
...
...
@@ -1675,25 +1733,34 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
FILE_DIRECTORY_INFO
*
lastFindData
;
FILE_UNIX_INFO
*
pfindDataUnix
;
/* BB removeme begin */
if
(
!
experimEnabled
)
return
cifs_readdir2
(
file
,
direntry
,
filldir
);
/* BB removeme end */
xid
=
GetXid
();
if
(
file
->
f_dentry
==
NULL
)
{
rc
=
-
EIO
;
FreeXid
(
xid
);
return
rc
;
}
cifs_sb
=
CIFS_SB
(
file
->
f_dentry
->
d_sb
);
pTcon
=
cifs_sb
->
tcon
;
bufsize
=
pTcon
->
ses
->
server
->
maxBuf
-
MAX_CIFS_HDR_SIZE
;
if
(
bufsize
>
CIFS_MAX_MSGSIZE
)
{
rc
=
-
EIO
;
FreeXid
(
xid
);
return
-
EIO
;
return
rc
;
}
data
=
kmalloc
(
bufsize
,
GFP_KERNEL
);
pfindData
=
(
FILE_DIRECTORY_INFO
*
)
data
;
if
(
data
==
NULL
)
{
rc
=
-
ENOMEM
;
FreeXid
(
xid
);
return
-
ENOMEM
;
}
if
(
file
->
f_dentry
==
NULL
)
{
kfree
(
data
);
FreeXid
(
xid
);
return
-
EIO
;
return
rc
;
}
down
(
&
file
->
f_dentry
->
d_sb
->
s_vfs_rename_sem
);
full_path
=
build_wildcard_path_from_dentry
(
file
->
f_dentry
);
...
...
@@ -1727,8 +1794,8 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
if
(
file
->
private_data
!=
NULL
)
{
cifsFile
=
(
struct
cifsFileInfo
*
)
file
->
private_data
;
if
(
cifsFile
->
endOfSearch
)
{
if
(
cifsFile
->
emptyDir
)
{
if
(
cifsFile
->
srch_inf
.
endOfSearch
)
{
if
(
cifsFile
->
srch_inf
.
emptyDir
)
{
cFYI
(
1
,
(
"End of search, empty dir"
));
rc
=
0
;
break
;
...
...
@@ -1778,7 +1845,7 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
break
;
}
/* Offset of resume key same for levels 257 and 514 */
cifsFile
->
resume_key
=
lastFindData
->
FileIndex
;
cifsFile
->
srch_inf
.
resume_key
=
lastFindData
->
FileIndex
;
if
(
UnixSearch
==
FALSE
)
{
cifsFile
->
resume_name_length
=
le32_to_cpu
(
lastFindData
->
FileNameLength
);
...
...
@@ -1915,13 +1982,13 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
/* if(pfindData > lastFindData) rc = -EIO; break; */
}
/* end for loop */
if
((
findParms
.
EndofSearch
!=
0
)
&&
cifsFile
)
{
cifsFile
->
endOfSearch
=
TRUE
;
cifsFile
->
srch_inf
.
endOfSearch
=
TRUE
;
if
(
findParms
.
SearchCount
==
cpu_to_le16
(
2
))
cifsFile
->
emptyDir
=
TRUE
;
cifsFile
->
srch_inf
.
emptyDir
=
TRUE
;
}
}
else
{
if
(
cifsFile
)
cifsFile
->
endOfSearch
=
TRUE
;
cifsFile
->
srch_inf
.
endOfSearch
=
TRUE
;
/* unless parent directory gone do not return error */
rc
=
0
;
}
...
...
@@ -1934,7 +2001,7 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
file
->
f_pos
));
}
else
{
cifsFile
=
(
struct
cifsFileInfo
*
)
file
->
private_data
;
if
(
cifsFile
->
endOfSearch
)
{
if
(
cifsFile
->
srch_inf
.
endOfSearch
)
{
rc
=
0
;
cFYI
(
1
,
(
"End of search "
));
break
;
...
...
@@ -1944,7 +2011,7 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
&
findNextParms
,
searchHandle
,
cifsFile
->
search_resume_name
,
cifsFile
->
resume_name_length
,
cifsFile
->
resume_key
,
cifsFile
->
srch_inf
.
resume_key
,
&
Unicode
,
&
UnixSearch
);
cFYI
(
1
,(
"Count: %d End: %d "
,
le16_to_cpu
(
findNextParms
.
SearchCount
),
...
...
@@ -1961,7 +2028,7 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
break
;
}
/* Offset of resume key same for levels 257 and 514 */
cifsFile
->
resume_key
=
lastFindData
->
FileIndex
;
cifsFile
->
srch_inf
.
resume_key
=
lastFindData
->
FileIndex
;
if
(
UnixSearch
==
FALSE
)
{
cifsFile
->
resume_name_length
=
...
...
@@ -2114,10 +2181,10 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
/* BB also should check to ensure pointer not beyond end of SMB */
}
/* end for loop */
if
(
findNextParms
.
EndofSearch
!=
0
)
{
cifsFile
->
endOfSearch
=
TRUE
;
cifsFile
->
srch_inf
.
endOfSearch
=
TRUE
;
}
}
else
{
cifsFile
->
endOfSearch
=
TRUE
;
cifsFile
->
srch_inf
.
endOfSearch
=
TRUE
;
rc
=
0
;
/* unless parent directory disappeared - do not
return error here (eg Access Denied or no more files) */
}
...
...
fs/cifs/inode.c
View file @
f27e5a2c
...
...
@@ -85,6 +85,13 @@ cifs_get_inode_info_unix(struct inode **pinode,
*
pinode
=
new_inode
(
sb
);
if
(
*
pinode
==
NULL
)
return
-
ENOMEM
;
/* Is an i_ino of zero legal? */
/* Are there sanity checks we can use to ensure that
the server is really filling in that field? */
if
(
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_SERVER_INUM
)
{
(
*
pinode
)
->
i_ino
=
(
unsigned
long
)
findData
.
UniqueId
;
}
/* note ino incremented to unique num in new_inode */
insert_inode_hash
(
*
pinode
);
}
...
...
@@ -244,6 +251,21 @@ cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path,
*
pinode
=
new_inode
(
sb
);
if
(
*
pinode
==
NULL
)
return
-
ENOMEM
;
/* Is an i_ino of zero legal? */
/* Are there sanity checks we can use to ensure that
the server is really filling in that field? */
/* We can not use the IndexNumber from either
Windows or Samba as it is frequently set to zero */
/* There may be higher info levels that work but
Are there Windows server or network appliances
for which IndexNumber field is not guaranteed unique? */
/* if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
(*pinode)->i_ino =
(unsigned long)pfindData->IndexNumber;
} */
/*NB: ino incremented to unique num in new_inode*/
insert_inode_hash
(
*
pinode
);
}
inode
=
*
pinode
;
...
...
@@ -273,10 +295,10 @@ cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path,
/* new inode, can safely set these fields */
inode
->
i_mode
=
cifs_sb
->
mnt_file_mode
;
if
(
attr
&
ATTR_REPARSE
)
{
/* Can IFLNK be set as it basically is on windows with IFREG or IFDIR?
*/
inode
->
i_mode
|=
S_IFLNK
;
}
else
if
(
attr
&
ATTR_DIRECTORY
)
{
/* if (attr & ATTR_REPARSE) */
/* We no longer handle these as symlinks because we could not
*/
/* follow them due to the absolute path with drive letter */
if
(
attr
&
ATTR_DIRECTORY
)
{
/* override default perms since we do not do byte range locking on dirs */
inode
->
i_mode
=
cifs_sb
->
mnt_dir_mode
;
inode
->
i_mode
|=
S_IFDIR
;
...
...
fs/cifs/misc.c
View file @
f27e5a2c
/*
* fs/cifs/misc.c
*
* Copyright (C) International Business Machines Corp., 2002,200
3
* Copyright (C) International Business Machines Corp., 2002,200
4
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
...
...
@@ -29,6 +29,9 @@
#include "smberr.h"
#include "nterr.h"
#ifdef CONFIG_CIFS_EXPERIMENTAL
extern
mempool_t
*
cifs_sm_req_poolp
;
#endif
/* CIFS_EXPERIMENTAL */
extern
mempool_t
*
cifs_req_poolp
;
extern
struct
task_struct
*
oplockThread
;
...
...
@@ -160,8 +163,10 @@ cifs_buf_get(void)
(
struct
smb_hdr
*
)
mempool_alloc
(
cifs_req_poolp
,
SLAB_KERNEL
|
SLAB_NOFS
);
/* clear the first few header bytes */
/* clear through bcc + 1, making an even 0x40 bytes */
if
(
ret_buf
)
{
memset
(
ret_buf
,
0
,
sizeof
(
struct
smb_hdr
)
);
memset
(
ret_buf
,
0
,
sizeof
(
struct
smb_hdr
)
+
27
);
atomic_inc
(
&
bufAllocCount
);
}
...
...
@@ -182,6 +187,44 @@ cifs_buf_release(void *buf_to_free)
return
;
}
#ifdef CONFIG_CIFS_EXPERIMENTAL
struct
smb_hdr
*
cifs_small_buf_get
(
void
)
{
struct
smb_hdr
*
ret_buf
=
NULL
;
/* We could use negotiated size instead of max_msgsize -
but it may be more efficient to always alloc same size
albeit slightly larger than necessary and maxbuffersize
defaults to this and can not be bigger */
ret_buf
=
(
struct
smb_hdr
*
)
mempool_alloc
(
cifs_sm_req_poolp
,
SLAB_KERNEL
|
SLAB_NOFS
);
/* clear the first few header bytes */
/* clear through bcc + 1, making an even 0x40 bytes */
if
(
ret_buf
)
{
memset
(
ret_buf
,
0
,
sizeof
(
struct
smb_hdr
)
+
27
);
atomic_inc
(
&
smBufAllocCount
);
}
return
ret_buf
;
}
void
cifs_small_buf_release
(
void
*
buf_to_free
)
{
if
(
buf_to_free
==
NULL
)
{
cFYI
(
1
,
(
"Null buffer passed to cifs_small_buf_release"
));
return
;
}
mempool_free
(
buf_to_free
,
cifs_sm_req_poolp
);
atomic_dec
(
&
smBufAllocCount
);
return
;
}
#endif
/* CIFS_EXPERIMENTAL */
void
header_assemble
(
struct
smb_hdr
*
buffer
,
char
smb_command
/* command */
,
const
struct
cifsTconInfo
*
treeCon
,
int
word_count
...
...
fs/cifs/netmisc.c
View file @
f27e5a2c
...
...
@@ -69,10 +69,12 @@ const struct smb_to_posix_error mapping_table_ERRDOS[] = {
{
ERRinvparm
,
-
EINVAL
},
{
ERRdiskfull
,
-
ENOSPC
},
{
ERRinvname
,
-
ENOENT
},
{
ERRinvlevel
,
-
EOPNOTSUPP
},
{
ERRdirnotempty
,
-
ENOTEMPTY
},
{
ERRnotlocked
,
-
ENOLCK
},
{
ERRalreadyexists
,
-
EEXIST
},
{
ERRmoredata
,
-
EOVERFLOW
},
{
ERReasnotsupported
,
-
EOPNOTSUPP
},
{
ErrQuota
,
-
EDQUOT
},
{
ErrNotALink
,
-
ENOLINK
},
{
ERRnetlogonNotStarted
,
-
ENOPROTOOPT
},
...
...
@@ -287,7 +289,7 @@ static const struct {
ERRDOS
,
87
,
NT_STATUS_BAD_WORKING_SET_LIMIT
},
{
ERRDOS
,
87
,
NT_STATUS_INCOMPATIBLE_FILE_MAP
},
{
ERRDOS
,
87
,
NT_STATUS_SECTION_PROTECTION
},
{
ERRDOS
,
282
,
NT_STATUS_EAS_NOT_SUPPORTED
},
{
ERRDOS
,
ERReasnotsupported
,
NT_STATUS_EAS_NOT_SUPPORTED
},
{
ERRDOS
,
255
,
NT_STATUS_EA_TOO_LARGE
},
{
ERRHRD
,
ERRgeneral
,
NT_STATUS_NONEXISTENT_EA_ENTRY
},
{
ERRHRD
,
ERRgeneral
,
NT_STATUS_NO_EAS_ON_FILE
},
{
...
...
fs/cifs/readdir.c
0 → 100644
View file @
f27e5a2c
/*
* fs/cifs/readdir.c
*
* Directory search handling
*
* Copyright (C) International Business Machines Corp., 2004
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/fs.h>
#include <linux/stat.h>
#include <linux/smp_lock.h>
#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_unicode.h"
#include "cifs_debug.h"
#include "cifs_fs_sb.h"
extern
int
CIFSFindFirst2
(
const
int
xid
,
struct
cifsTconInfo
*
tcon
,
const
char
*
searchName
,
const
struct
nls_table
*
nls_codepage
,
__u16
*
searchHandle
,
struct
cifs_search_info
*
psrch_inf
);
extern
int
CIFSFindNext2
(
const
int
xid
,
struct
cifsTconInfo
*
tcon
,
__u16
searchHandle
,
struct
cifs_search_info
*
psrch_inf
);
extern
int
construct_dentry
(
struct
qstr
*
qstring
,
struct
file
*
file
,
struct
inode
**
ptmp_inode
,
struct
dentry
**
pnew_dentry
);
extern
void
fill_in_inode
(
struct
inode
*
tmp_inode
,
FILE_DIRECTORY_INFO
*
pfindData
,
int
*
pobject_type
);
extern
void
unix_fill_in_inode
(
struct
inode
*
tmp_inode
,
FILE_UNIX_INFO
*
pfindData
,
int
*
pobject_type
);
/* BB fixme - add debug wrappers around this function to disable it fixme BB */
/* static void dump_cifs_file_struct(struct file * file, char * label)
{
struct cifsFileInfo * cf;
if(file) {
cf = (struct cifsFileInfo *)file->private_data;
if(cf == NULL) {
cFYI(1,("empty cifs private file data"));
return;
}
if(cf->invalidHandle) {
cFYI(1,("invalid handle"));
}
if(cf->srch_inf.endOfSearch) {
cFYI(1,("end of search"));
}
if(cf->srch_inf.emptyDir) {
cFYI(1,("empty dir"));
}
}
} */
static
int
initiate_cifs_search
(
const
int
xid
,
struct
file
*
file
)
{
int
rc
=
0
;
char
*
full_path
;
struct
cifsFileInfo
*
cifsFile
;
struct
cifs_sb_info
*
cifs_sb
;
struct
cifsTconInfo
*
pTcon
;
if
(
file
->
private_data
==
NULL
)
{
file
->
private_data
=
kmalloc
(
sizeof
(
struct
cifsFileInfo
),
GFP_KERNEL
);
}
if
(
file
->
private_data
==
NULL
)
{
return
-
ENOMEM
;
}
else
{
memset
(
file
->
private_data
,
0
,
sizeof
(
struct
cifsFileInfo
));
}
cifsFile
=
(
struct
cifsFileInfo
*
)
file
->
private_data
;
cifsFile
->
invalidHandle
=
TRUE
;
cifsFile
->
srch_inf
.
endOfSearch
=
FALSE
;
cifs_sb
=
CIFS_SB
(
file
->
f_dentry
->
d_sb
);
if
(
cifs_sb
==
NULL
)
return
-
EINVAL
;
pTcon
=
cifs_sb
->
tcon
;
if
(
pTcon
==
NULL
)
return
-
EINVAL
;
if
(
file
->
f_dentry
==
NULL
)
return
-
ENOENT
;
down
(
&
file
->
f_dentry
->
d_sb
->
s_vfs_rename_sem
);
full_path
=
build_wildcard_path_from_dentry
(
file
->
f_dentry
);
up
(
&
file
->
f_dentry
->
d_sb
->
s_vfs_rename_sem
);
if
(
full_path
==
NULL
)
{
return
-
ENOMEM
;
}
cFYI
(
1
,
(
"Full path: %s start at: %lld "
,
full_path
,
file
->
f_pos
));
/* test for Unix extensions */
if
(
pTcon
->
ses
->
capabilities
&
CAP_UNIX
)
{
cifsFile
->
srch_inf
.
info_level
=
SMB_FIND_FILE_UNIX
;
}
else
if
(
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_SERVER_INUM
)
{
cifsFile
->
srch_inf
.
info_level
=
SMB_FIND_FILE_ID_FULL_DIR_INFO
;
}
else
/* not srvinos - BB fixme add check for backlevel? */
{
cifsFile
->
srch_inf
.
info_level
=
SMB_FIND_FILE_DIRECTORY_INFO
;
}
rc
=
CIFSFindFirst2
(
xid
,
pTcon
,
full_path
,
cifs_sb
->
local_nls
,
&
cifsFile
->
netfid
,
&
cifsFile
->
srch_inf
);
if
(
rc
==
0
)
cifsFile
->
invalidHandle
=
FALSE
;
if
(
full_path
)
kfree
(
full_path
);
return
rc
;
}
/* return length of unicode string in bytes */
static
int
cifs_unicode_bytelen
(
char
*
str
)
{
int
len
;
__le16
*
ustr
=
(
__le16
*
)
str
;
for
(
len
=
0
;
len
<=
PATH_MAX
;
len
++
)
{
if
(
ustr
[
len
]
==
0
)
return
len
<<
1
;
}
cFYI
(
1
,(
"Unicode string longer than PATH_MAX found"
));
return
len
<<
1
;
}
static
char
*
nxt_dir_entry
(
char
*
old_entry
,
char
*
end_of_smb
)
{
char
*
new_entry
;
FILE_DIRECTORY_INFO
*
pDirInfo
=
(
FILE_DIRECTORY_INFO
*
)
old_entry
;
new_entry
=
old_entry
+
le32_to_cpu
(
pDirInfo
->
NextEntryOffset
);
cFYI
(
1
,(
"new entry %p old entry %p"
,
new_entry
,
old_entry
));
/* validate that new_entry is not past end of SMB */
if
(
new_entry
>=
end_of_smb
)
{
cFYI
(
1
,(
"search entry %p began after end of SMB %p old entry is %p"
,
new_entry
,
end_of_smb
,
old_entry
));
/* BB removeme BB */
return
NULL
;
}
else
return
new_entry
;
}
#define UNICODE_DOT cpu_to_le16(0x2e)
/* return 0 if no match and 1 for . (current directory) and 2 for .. (parent) */
static
int
cifs_entry_is_dot
(
char
*
current_entry
,
struct
cifsFileInfo
*
cfile
)
{
int
rc
=
0
;
char
*
filename
=
NULL
;
int
len
=
0
;
if
(
cfile
->
srch_inf
.
info_level
==
0x202
)
{
FILE_UNIX_INFO
*
pFindData
=
(
FILE_UNIX_INFO
*
)
current_entry
;
filename
=
&
pFindData
->
FileName
[
0
];
if
(
cfile
->
srch_inf
.
unicode
)
{
len
=
cifs_unicode_bytelen
(
filename
);
}
else
{
/* BB should we make this strnlen of PATH_MAX? */
len
=
strnlen
(
filename
,
5
);
}
}
else
if
(
cfile
->
srch_inf
.
info_level
==
0x101
)
{
FILE_DIRECTORY_INFO
*
pFindData
=
(
FILE_DIRECTORY_INFO
*
)
current_entry
;
filename
=
&
pFindData
->
FileName
[
0
];
len
=
le32_to_cpu
(
pFindData
->
FileNameLength
);
}
else
if
(
cfile
->
srch_inf
.
info_level
==
0x102
)
{
FILE_FULL_DIRECTORY_INFO
*
pFindData
=
(
FILE_FULL_DIRECTORY_INFO
*
)
current_entry
;
filename
=
&
pFindData
->
FileName
[
0
];
len
=
le32_to_cpu
(
pFindData
->
FileNameLength
);
}
else
if
(
cfile
->
srch_inf
.
info_level
==
0x105
)
{
SEARCH_ID_FULL_DIR_INFO
*
pFindData
=
(
SEARCH_ID_FULL_DIR_INFO
*
)
current_entry
;
filename
=
&
pFindData
->
FileName
[
0
];
len
=
le32_to_cpu
(
pFindData
->
FileNameLength
);
}
else
if
(
cfile
->
srch_inf
.
info_level
==
0x104
)
{
FILE_BOTH_DIRECTORY_INFO
*
pFindData
=
(
FILE_BOTH_DIRECTORY_INFO
*
)
current_entry
;
filename
=
&
pFindData
->
FileName
[
0
];
len
=
le32_to_cpu
(
pFindData
->
FileNameLength
);
}
else
{
cFYI
(
1
,(
"Unknown findfirst level %d"
,
cfile
->
srch_inf
.
info_level
));
}
if
(
filename
)
{
if
(
cfile
->
srch_inf
.
unicode
)
{
__le16
*
ufilename
=
(
__le16
*
)
filename
;
if
(
len
==
2
)
{
/* check for . */
if
(
ufilename
[
0
]
==
UNICODE_DOT
)
rc
=
1
;
}
else
if
(
len
==
4
)
{
/* check for .. */
if
((
ufilename
[
0
]
==
UNICODE_DOT
)
&&
(
ufilename
[
1
]
==
UNICODE_DOT
))
rc
=
2
;
}
}
else
/* ASCII */
{
if
(
len
==
1
)
{
if
(
filename
[
0
]
==
'.'
)
rc
=
1
;
}
else
if
(
len
==
2
)
{
if
((
filename
[
0
]
==
'.'
)
&&
(
filename
[
1
]
==
'.'
))
rc
=
2
;
}
}
}
return
rc
;
}
/* find the corresponding entry in the search */
/* Note that the SMB server returns search entries for . and .. which
complicates logic here if we choose to parse for them and we do not
assume that they are located in the findfirst return buffer.*/
/* We start counting in the buffer with entry 2 and increment for every
entry (do not increment for . or .. entry) */
static
int
find_cifs_entry
(
const
int
xid
,
struct
cifsTconInfo
*
pTcon
,
struct
file
*
file
,
char
**
ppCurrentEntry
,
int
*
num_to_ret
)
{
int
rc
=
0
;
int
pos_in_buf
=
0
;
loff_t
first_entry_in_buffer
;
loff_t
index_to_find
=
file
->
f_pos
;
struct
cifsFileInfo
*
cifsFile
=
(
struct
cifsFileInfo
*
)
file
->
private_data
;
/* check if index in the buffer */
if
((
cifsFile
==
NULL
)
||
(
ppCurrentEntry
==
NULL
)
||
(
num_to_ret
==
NULL
))
return
-
ENOENT
;
*
ppCurrentEntry
=
NULL
;
first_entry_in_buffer
=
cifsFile
->
srch_inf
.
index_of_last_entry
-
cifsFile
->
srch_inf
.
entries_in_buffer
;
/* dump_cifs_file_struct(file, "In fce ");*/
if
(
index_to_find
<
first_entry_in_buffer
)
{
/* close and restart search */
cFYI
(
1
,(
"search backing up - close and restart search"
));
cifsFile
->
invalidHandle
=
TRUE
;
CIFSFindClose
(
xid
,
pTcon
,
cifsFile
->
netfid
);
if
(
cifsFile
->
search_resume_name
)
{
kfree
(
cifsFile
->
search_resume_name
);
cifsFile
->
search_resume_name
=
NULL
;
}
if
(
cifsFile
->
srch_inf
.
ntwrk_buf_start
)
{
cFYI
(
1
,(
"freeing SMB ff cache buf on search rewind"
));
/* BB removeme BB */
cifs_buf_release
(
cifsFile
->
srch_inf
.
ntwrk_buf_start
);
}
rc
=
initiate_cifs_search
(
xid
,
file
);
if
(
rc
)
{
cFYI
(
1
,(
"error %d reinitiating a search on rewind"
,
rc
));
return
rc
;
}
}
if
(
cifsFile
->
srch_inf
.
endOfSearch
)
{
cFYI
(
1
,(
"end of search"
));
/* BB removeme BB */
}
while
((
index_to_find
>=
cifsFile
->
srch_inf
.
index_of_last_entry
)
&&
(
rc
==
0
)
&&
(
cifsFile
->
srch_inf
.
endOfSearch
==
FALSE
)){
cFYI
(
1
,(
"calling findnext2"
));
rc
=
CIFSFindNext2
(
xid
,
pTcon
,
cifsFile
->
netfid
,
&
cifsFile
->
srch_inf
);
if
(
rc
)
return
-
ENOENT
;
}
if
(
index_to_find
<
cifsFile
->
srch_inf
.
index_of_last_entry
)
{
/* we found the buffer that contains the entry */
/* scan and find it */
int
i
;
char
*
current_entry
;
char
*
end_of_smb
=
cifsFile
->
srch_inf
.
ntwrk_buf_start
+
smbCalcSize
((
struct
smb_hdr
*
)
cifsFile
->
srch_inf
.
ntwrk_buf_start
);
/* dump_cifs_file_struct(file,"found entry in fce "); */
first_entry_in_buffer
=
cifsFile
->
srch_inf
.
index_of_last_entry
-
cifsFile
->
srch_inf
.
entries_in_buffer
;
pos_in_buf
=
index_to_find
-
first_entry_in_buffer
;
cFYI
(
1
,(
"found entry - pos_in_buf %d"
,
pos_in_buf
));
/* BB removeme BB */
current_entry
=
cifsFile
->
srch_inf
.
srch_entries_start
;
for
(
i
=
0
;(
i
<
(
pos_in_buf
))
&&
(
current_entry
!=
NULL
);
i
++
)
{
/* go entry to next entry figuring out which we need to start with */
/* if( . or ..)
skip */
rc
=
cifs_entry_is_dot
(
current_entry
,
cifsFile
);
if
(
rc
==
1
)
/* is . or .. so skip */
{
cFYI
(
1
,(
"Entry is ."
));
/* BB removeme BB */
/* continue; */
}
else
if
(
rc
==
2
)
{
cFYI
(
1
,(
"Entry is .."
));
/* BB removeme BB */
/* continue; */
}
current_entry
=
nxt_dir_entry
(
current_entry
,
end_of_smb
);
}
if
((
current_entry
==
NULL
)
&&
(
i
<
pos_in_buf
))
{
cERROR
(
1
,(
"reached end of buf searching for pos in buf %d index to find %lld rc %d"
,
pos_in_buf
,
index_to_find
,
rc
));
/* BB removeme BB */
}
rc
=
0
;
*
ppCurrentEntry
=
current_entry
;
}
else
{
cFYI
(
1
,(
"index not in buffer - could not findnext into it"
));
return
0
;
}
if
(
pos_in_buf
>=
cifsFile
->
srch_inf
.
entries_in_buffer
)
{
cFYI
(
1
,(
"can not return entries when pos_in_buf beyond last entry"
));
*
num_to_ret
=
0
;
}
else
*
num_to_ret
=
cifsFile
->
srch_inf
.
entries_in_buffer
-
pos_in_buf
;
/* dump_cifs_file_struct(file, "end fce ");*/
return
rc
;
}
/* inode num, inode type and filename returned */
static
int
cifs_get_name_from_search_buf
(
struct
qstr
*
pqst
,
char
*
current_entry
,
__u16
level
,
unsigned
int
unicode
,
struct
nls_table
*
nlt
,
ino_t
*
pinum
)
{
int
rc
=
0
;
unsigned
int
len
=
0
;
char
*
filename
;
*
pinum
=
0
;
if
(
level
==
SMB_FIND_FILE_UNIX
)
{
FILE_UNIX_INFO
*
pFindData
=
(
FILE_UNIX_INFO
*
)
current_entry
;
filename
=
&
pFindData
->
FileName
[
0
];
if
(
unicode
)
{
len
=
cifs_unicode_bytelen
(
filename
);
}
else
{
/* BB should we make this strnlen of PATH_MAX? */
len
=
strnlen
(
filename
,
PATH_MAX
);
}
/* BB fixme - hash low and high 32 bits if not 64 bit arch BB fixme */
*
pinum
=
pFindData
->
UniqueId
;
}
else
if
(
level
==
SMB_FIND_FILE_DIRECTORY_INFO
)
{
FILE_DIRECTORY_INFO
*
pFindData
=
(
FILE_DIRECTORY_INFO
*
)
current_entry
;
filename
=
&
pFindData
->
FileName
[
0
];
len
=
le32_to_cpu
(
pFindData
->
FileNameLength
);
}
else
if
(
level
==
SMB_FIND_FILE_FULL_DIRECTORY_INFO
)
{
FILE_FULL_DIRECTORY_INFO
*
pFindData
=
(
FILE_FULL_DIRECTORY_INFO
*
)
current_entry
;
filename
=
&
pFindData
->
FileName
[
0
];
len
=
le32_to_cpu
(
pFindData
->
FileNameLength
);
}
else
if
(
level
==
SMB_FIND_FILE_ID_FULL_DIR_INFO
)
{
SEARCH_ID_FULL_DIR_INFO
*
pFindData
=
(
SEARCH_ID_FULL_DIR_INFO
*
)
current_entry
;
filename
=
&
pFindData
->
FileName
[
0
];
len
=
le32_to_cpu
(
pFindData
->
FileNameLength
);
*
pinum
=
pFindData
->
UniqueId
;
}
else
if
(
level
==
SMB_FIND_FILE_BOTH_DIRECTORY_INFO
)
{
FILE_BOTH_DIRECTORY_INFO
*
pFindData
=
(
FILE_BOTH_DIRECTORY_INFO
*
)
current_entry
;
filename
=
&
pFindData
->
FileName
[
0
];
len
=
le32_to_cpu
(
pFindData
->
FileNameLength
);
}
else
{
cFYI
(
1
,(
"Unknown findfirst level %d"
,
level
));
return
-
EINVAL
;
}
if
(
unicode
)
{
/* BB fixme - test with long names */
/* Note converted filename can be longer than in unicode */
pqst
->
len
=
cifs_strfromUCS_le
((
char
*
)
pqst
->
name
,(
wchar_t
*
)
filename
,
len
/
2
,
nlt
);
}
else
{
pqst
->
name
=
filename
;
pqst
->
len
=
len
;
}
pqst
->
hash
=
full_name_hash
(
pqst
->
name
,
pqst
->
len
);
cFYI
(
1
,(
"filldir on %s"
,
pqst
->
name
));
/* BB removeme BB */
return
rc
;
}
static
int
cifs_filldir2
(
char
*
pfindEntry
,
struct
file
*
file
,
filldir_t
filldir
,
void
*
direntry
,
char
*
scratch_buf
)
{
int
rc
=
0
;
struct
qstr
qstring
;
struct
cifsFileInfo
*
pCifsF
;
unsigned
obj_type
;
ino_t
inum
;
struct
cifs_sb_info
*
cifs_sb
;
struct
inode
*
tmp_inode
;
struct
dentry
*
tmp_dentry
;
/* get filename and len into qstring */
/* get dentry */
/* decide whether to create and populate ionde */
if
((
direntry
==
NULL
)
||
(
file
==
NULL
))
return
-
EINVAL
;
pCifsF
=
file
->
private_data
;
if
((
scratch_buf
==
NULL
)
||
(
pfindEntry
==
NULL
)
||
(
pCifsF
==
NULL
))
return
-
ENOENT
;
if
(
file
->
f_dentry
==
NULL
)
return
-
ENOENT
;
cifs_sb
=
CIFS_SB
(
file
->
f_dentry
->
d_sb
);
qstring
.
name
=
scratch_buf
;
rc
=
cifs_get_name_from_search_buf
(
&
qstring
,
pfindEntry
,
pCifsF
->
srch_inf
.
info_level
,
pCifsF
->
srch_inf
.
unicode
,
cifs_sb
->
local_nls
,
&
inum
/* returned */
);
if
(
rc
)
return
rc
;
rc
=
construct_dentry
(
&
qstring
,
file
,
&
tmp_inode
,
&
tmp_dentry
);
if
((
tmp_inode
==
NULL
)
||
(
tmp_dentry
==
NULL
))
return
-
ENOMEM
;
if
(
rc
)
{
/* inode created, we need to hash it with right inode number */
if
(
inum
!=
0
)
{
/* BB fixme - hash the 2 32 quantities bits together if necessary BB */
tmp_inode
->
i_ino
=
inum
;
}
insert_inode_hash
(
tmp_inode
);
}
if
(
pCifsF
->
srch_inf
.
info_level
==
SMB_FIND_FILE_UNIX
)
{
unix_fill_in_inode
(
tmp_inode
,(
FILE_UNIX_INFO
*
)
pfindEntry
,
&
obj_type
);
}
else
{
fill_in_inode
(
tmp_inode
,(
FILE_DIRECTORY_INFO
*
)
pfindEntry
,
&
obj_type
);
}
rc
=
filldir
(
direntry
,
qstring
.
name
,
qstring
.
len
,
file
->
f_pos
,
tmp_inode
->
i_ino
,
obj_type
);
if
(
rc
)
{
cFYI
(
1
,(
"filldir rc = %d"
,
rc
));
}
dput
(
tmp_dentry
);
return
rc
;
}
int
cifs_save_resume_key
(
const
char
*
current_entry
,
struct
cifsFileInfo
*
cifsFile
)
{
int
rc
=
0
;
unsigned
int
len
=
0
;
__u16
level
;
char
*
filename
;
if
((
cifsFile
==
NULL
)
||
(
current_entry
==
NULL
))
return
-
EINVAL
;
level
=
cifsFile
->
srch_inf
.
info_level
;
if
(
level
==
SMB_FIND_FILE_UNIX
)
{
FILE_UNIX_INFO
*
pFindData
=
(
FILE_UNIX_INFO
*
)
current_entry
;
filename
=
&
pFindData
->
FileName
[
0
];
if
(
cifsFile
->
srch_inf
.
unicode
)
{
len
=
cifs_unicode_bytelen
(
filename
);
}
else
{
/* BB should we make this strnlen of PATH_MAX? */
len
=
strnlen
(
filename
,
PATH_MAX
);
}
cifsFile
->
srch_inf
.
resume_key
=
pFindData
->
ResumeKey
;
}
else
if
(
level
==
SMB_FIND_FILE_DIRECTORY_INFO
)
{
FILE_DIRECTORY_INFO
*
pFindData
=
(
FILE_DIRECTORY_INFO
*
)
current_entry
;
filename
=
&
pFindData
->
FileName
[
0
];
len
=
le32_to_cpu
(
pFindData
->
FileNameLength
);
cifsFile
->
srch_inf
.
resume_key
=
pFindData
->
FileIndex
;
}
else
if
(
level
==
SMB_FIND_FILE_FULL_DIRECTORY_INFO
)
{
FILE_FULL_DIRECTORY_INFO
*
pFindData
=
(
FILE_FULL_DIRECTORY_INFO
*
)
current_entry
;
filename
=
&
pFindData
->
FileName
[
0
];
len
=
le32_to_cpu
(
pFindData
->
FileNameLength
);
cifsFile
->
srch_inf
.
resume_key
=
pFindData
->
FileIndex
;
}
else
if
(
level
==
SMB_FIND_FILE_ID_FULL_DIR_INFO
)
{
SEARCH_ID_FULL_DIR_INFO
*
pFindData
=
(
SEARCH_ID_FULL_DIR_INFO
*
)
current_entry
;
filename
=
&
pFindData
->
FileName
[
0
];
len
=
le32_to_cpu
(
pFindData
->
FileNameLength
);
cifsFile
->
srch_inf
.
resume_key
=
pFindData
->
FileIndex
;
}
else
if
(
level
==
SMB_FIND_FILE_BOTH_DIRECTORY_INFO
)
{
FILE_BOTH_DIRECTORY_INFO
*
pFindData
=
(
FILE_BOTH_DIRECTORY_INFO
*
)
current_entry
;
filename
=
&
pFindData
->
FileName
[
0
];
len
=
le32_to_cpu
(
pFindData
->
FileNameLength
);
cifsFile
->
srch_inf
.
resume_key
=
pFindData
->
FileIndex
;
}
else
{
cFYI
(
1
,(
"Unknown findfirst level %d"
,
level
));
return
-
EINVAL
;
}
cifsFile
->
srch_inf
.
resume_name_len
=
len
;
cifsFile
->
srch_inf
.
presume_name
=
filename
;
return
rc
;
}
int
cifs_readdir2
(
struct
file
*
file
,
void
*
direntry
,
filldir_t
filldir
)
{
int
rc
=
0
;
int
xid
,
i
;
struct
cifs_sb_info
*
cifs_sb
;
struct
cifsTconInfo
*
pTcon
;
struct
cifsFileInfo
*
cifsFile
=
NULL
;
char
*
current_entry
;
int
num_to_fill
=
0
;
char
*
tmp_buf
=
NULL
;
char
*
end_of_smb
;
xid
=
GetXid
();
if
(
file
->
f_dentry
==
NULL
)
{
FreeXid
(
xid
);
return
-
EIO
;
}
/* dump_cifs_file_struct(file, "Begin rdir "); */
cifs_sb
=
CIFS_SB
(
file
->
f_dentry
->
d_sb
);
pTcon
=
cifs_sb
->
tcon
;
if
(
pTcon
==
NULL
)
return
-
EINVAL
;
cFYI
(
1
,(
"readdir2 pos: %lld"
,
file
->
f_pos
));
/* BB removeme BB */
switch
((
int
)
file
->
f_pos
)
{
case
0
:
/*if (filldir(direntry, ".", 1, file->f_pos,
file->f_dentry->d_inode->i_ino, DT_DIR) < 0) {
cERROR(1, ("Filldir for current dir failed "));
rc = -ENOMEM;
break;
}
file->f_pos++; */
case
1
:
/* if (filldir(direntry, "..", 2, file->f_pos,
file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) {
cERROR(1, ("Filldir for parent dir failed "));
rc = -ENOMEM;
break;
}
file->f_pos++; */
case
2
:
/* 1) If search is active,
is in current search buffer?
if it before then restart search
if after then keep searching till find it */
if
(
file
->
private_data
==
NULL
)
{
rc
=
initiate_cifs_search
(
xid
,
file
);
cFYI
(
1
,(
"initiate cifs search rc %d"
,
rc
));
if
(
rc
)
{
FreeXid
(
xid
);
return
rc
;
}
}
default:
if
(
file
->
private_data
==
NULL
)
{
rc
=
-
EINVAL
;
FreeXid
(
xid
);
return
rc
;
}
cifsFile
=
(
struct
cifsFileInfo
*
)
file
->
private_data
;
if
(
cifsFile
->
srch_inf
.
endOfSearch
)
{
if
(
cifsFile
->
srch_inf
.
emptyDir
)
{
cFYI
(
1
,
(
"End of search, empty dir"
));
rc
=
0
;
break
;
}
}
/* else {
cifsFile->invalidHandle = TRUE;
CIFSFindClose(xid, pTcon, cifsFile->netfid);
}
if(cifsFile->search_resume_name) {
kfree(cifsFile->search_resume_name);
cifsFile->search_resume_name = NULL;
} */
/* BB account for . and .. in f_pos */
/* dump_cifs_file_struct(file, "rdir after default ");*/
rc
=
find_cifs_entry
(
xid
,
pTcon
,
file
,
&
current_entry
,
&
num_to_fill
);
if
(
rc
)
{
cFYI
(
1
,(
"fce error %d"
,
rc
));
/* BB removeme BB */
goto
rddir2_exit
;
}
else
{
cFYI
(
1
,(
"entry %lld found"
,
file
->
f_pos
));
}
if
(
current_entry
==
NULL
)
{
cERROR
(
1
,(
"current search entry null,exiting"
));
goto
rddir2_exit
;
}
/* 2) initiate search, */
/* 3) seek into search buffer */
/* 4) if not found && later - FindNext */
/* else if earlier in search, close search and
restart, continuing search till found or EndOfSearch */
cFYI
(
1
,(
"loop through %d times filling dir for net buf start %p"
,
num_to_fill
,
cifsFile
->
srch_inf
.
ntwrk_buf_start
));
/* BB removeme BB */
end_of_smb
=
cifsFile
->
srch_inf
.
ntwrk_buf_start
+
smbCalcSize
((
struct
smb_hdr
*
)
cifsFile
->
srch_inf
.
ntwrk_buf_start
);
tmp_buf
=
kmalloc
(
NAME_MAX
+
1
,
GFP_KERNEL
);
cFYI
(
1
,(
"end of smb %p and tmp_buf %p current_entry %p"
,
end_of_smb
,
tmp_buf
,
current_entry
));
/* BB removeme BB */
for
(
i
=
0
;(
i
<
num_to_fill
)
&&
(
rc
==
0
);
i
++
)
{
if
(
current_entry
==
NULL
)
{
cERROR
(
1
,(
"beyond end of smb with num to fill %d i %d"
,
num_to_fill
,
i
));
/* BB removeme BB */
break
;
}
/* if((!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) ||
(cifsFile->srch_inf.info_level != something that supports server inodes)) {
create dentry
create inode
fill in inode new_inode (which makes number locally)
}
also create local inode for per reasons unless new mount parm says otherwise */
rc
=
cifs_filldir2
(
current_entry
,
file
,
filldir
,
direntry
,
tmp_buf
);
file
->
f_pos
++
;
if
(
file
->
f_pos
==
cifsFile
->
srch_inf
.
index_of_last_entry
)
{
cFYI
(
1
,(
"last entry in buf at pos %lld %s"
,
file
->
f_pos
,
tmp_buf
));
/* BB removeme BB */
/* BB fixme save resume key BB */
cifs_save_resume_key
(
current_entry
,
cifsFile
);
break
;
}
else
current_entry
=
nxt_dir_entry
(
current_entry
,
end_of_smb
);
}
if
(
tmp_buf
!=
NULL
)
kfree
(
tmp_buf
);
break
;
}
/* end switch */
rddir2_exit:
/* dump_cifs_file_struct(file, "end rdir "); */
FreeXid
(
xid
);
return
rc
;
}
fs/cifs/smberr.h
View file @
f27e5a2c
...
...
@@ -69,6 +69,7 @@
#define ERRpipeclosing 232
#define ERRnotconnected 233
#define ERRmoredata 234
#define ERReasnotsupported 282
#define ErrQuota 0x200
/* The operation would cause a quota limit to be exceeded. */
#define ErrNotALink 0x201
/* A link operation was performed on a pathname that
was not a link. */
...
...
fs/cifs/transport.c
View file @
f27e5a2c
...
...
@@ -176,6 +176,143 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
return
rc
;
}
#ifdef CIFS_EXPERIMENTAL
/* BB finish off this function, adding support for writing set of pages as iovec */
/* and also adding support for operations that need to parse the response smb */
int
CIFSSendRcv
(
const
unsigned
int
xid
,
struct
cifsSesInfo
*
ses
,
struct
smb_hdr
*
in_buf
,
struct
kvec
*
write_vector
/* page list */
,
int
*
pbytes_returned
,
const
int
long_op
)
{
int
rc
=
0
;
unsigned
long
timeout
=
15
*
HZ
;
struct
mid_q_entry
*
midQ
=
NULL
;
if
(
ses
==
NULL
)
{
cERROR
(
1
,(
"Null smb session"
));
return
-
EIO
;
}
if
(
ses
->
server
==
NULL
)
{
cERROR
(
1
,(
"Null tcp session"
));
return
-
EIO
;
}
if
(
pbytes_returned
==
NULL
)
return
-
EIO
;
else
*
pbytes_returned
=
0
;
/* Ensure that we do not send more than 50 overlapping requests
to the same server. We may make this configurable later or
use ses->maxReq */
if
(
long_op
==
-
1
)
{
/* oplock breaks must not be held up */
atomic_inc
(
&
ses
->
server
->
inFlight
);
}
else
{
spin_lock
(
&
GlobalMid_Lock
);
while
(
1
)
{
if
(
atomic_read
(
&
ses
->
server
->
inFlight
)
>=
CIFS_MAX_REQ
){
spin_unlock
(
&
GlobalMid_Lock
);
wait_event
(
ses
->
server
->
request_q
,
atomic_read
(
&
ses
->
server
->
inFlight
)
<
CIFS_MAX_REQ
);
spin_lock
(
&
GlobalMid_Lock
);
}
else
{
if
(
ses
->
server
->
tcpStatus
==
CifsExiting
)
{
spin_unlock
(
&
GlobalMid_Lock
);
return
-
ENOENT
;
}
/* can not count locking commands against total since
they are allowed to block on server */
if
(
long_op
<
3
)
{
/* update # of requests on the wire to server */
atomic_inc
(
&
ses
->
server
->
inFlight
);
}
spin_unlock
(
&
GlobalMid_Lock
);
break
;
}
}
}
/* make sure that we sign in the same order that we send on this socket
and avoid races inside tcp sendmsg code that could cause corruption
of smb data */
down
(
&
ses
->
server
->
tcpSem
);
if
(
ses
->
server
->
tcpStatus
==
CifsExiting
)
{
rc
=
-
ENOENT
;
goto
cifs_out_label
;
}
else
if
(
ses
->
server
->
tcpStatus
==
CifsNeedReconnect
)
{
cFYI
(
1
,(
"tcp session dead - return to caller to retry"
));
rc
=
-
EAGAIN
;
goto
cifs_out_label
;
}
else
if
(
ses
->
status
!=
CifsGood
)
{
/* check if SMB session is bad because we are setting it up */
if
((
in_buf
->
Command
!=
SMB_COM_SESSION_SETUP_ANDX
)
&&
(
in_buf
->
Command
!=
SMB_COM_NEGOTIATE
))
{
rc
=
-
EAGAIN
;
goto
cifs_out_label
;
}
/* else ok - we are setting up session */
}
midQ
=
AllocMidQEntry
(
in_buf
,
ses
);
if
(
midQ
==
NULL
)
{
up
(
&
ses
->
server
->
tcpSem
);
/* If not lock req, update # of requests on wire to server */
if
(
long_op
<
3
)
{
atomic_dec
(
&
ses
->
server
->
inFlight
);
wake_up
(
&
ses
->
server
->
request_q
);
}
return
-
ENOMEM
;
}
if
(
in_buf
->
smb_buf_length
>
CIFS_MAX_MSGSIZE
+
MAX_CIFS_HDR_SIZE
-
4
)
{
up
(
&
ses
->
server
->
tcpSem
);
cERROR
(
1
,
(
"Illegal length, greater than maximum frame, %d "
,
in_buf
->
smb_buf_length
));
DeleteMidQEntry
(
midQ
);
/* If not lock req, update # of requests on wire to server */
if
(
long_op
<
3
)
{
atomic_dec
(
&
ses
->
server
->
inFlight
);
wake_up
(
&
ses
->
server
->
request_q
);
}
return
-
EIO
;
}
/* BB can we sign efficiently in this path? */
rc
=
cifs_sign_smb
(
in_buf
,
ses
,
&
midQ
->
sequence_number
);
midQ
->
midState
=
MID_REQUEST_SUBMITTED
;
/* rc = smb_send2(ses->server->ssocket, in_buf, in_buf->smb_buf_length, piovec,
(struct sockaddr *) &(ses->server->addr.sockAddr));*/
if
(
rc
<
0
)
{
DeleteMidQEntry
(
midQ
);
up
(
&
ses
->
server
->
tcpSem
);
/* If not lock req, update # of requests on wire to server */
if
(
long_op
<
3
)
{
atomic_dec
(
&
ses
->
server
->
inFlight
);
wake_up
(
&
ses
->
server
->
request_q
);
}
return
rc
;
}
else
up
(
&
ses
->
server
->
tcpSem
);
cifs_out_label:
if
(
midQ
)
DeleteMidQEntry
(
midQ
);
if
(
long_op
<
3
)
{
atomic_dec
(
&
ses
->
server
->
inFlight
);
wake_up
(
&
ses
->
server
->
request_q
);
}
return
rc
;
}
#endif
/* CIFS_EXPERIMENTAL */
int
SendReceive
(
const
unsigned
int
xid
,
struct
cifsSesInfo
*
ses
,
struct
smb_hdr
*
in_buf
,
struct
smb_hdr
*
out_buf
,
...
...
@@ -307,7 +444,6 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
/* if signal pending do not hold up user for full smb timeout
but we still give response a change to complete */
timeout
=
2
*
HZ
;
}
/* No user interrupts in wait - wreaks havoc with performance */
...
...
fs/cifs/xattr.c
View file @
f27e5a2c
...
...
@@ -20,6 +20,7 @@
*/
#include <linux/fs.h>
#include <linux/posix_acl_xattr.h>
#include "cifsfs.h"
#include "cifspdu.h"
#include "cifsglob.h"
...
...
@@ -27,10 +28,10 @@
#include "cifs_debug.h"
#define MAX_EA_VALUE_SIZE 65535
#define CIFS_XATTR_DOS_ATTRIB "user.D
OSATTRIB
"
#define CIFS_XATTR_DOS_ATTRIB "user.D
osAttrib
"
#define CIFS_XATTR_USER_PREFIX "user."
#define CIFS_XATTR_SYSTEM_PREFIX "system."
#define CIFS_XATTR_OS2_PREFIX "
OS
2."
/* BB should check for this someday */
#define CIFS_XATTR_OS2_PREFIX "
os
2."
/* BB should check for this someday */
/* also note could add check for security prefix XATTR_SECURITY_PREFIX */
...
...
@@ -128,16 +129,47 @@ int cifs_setxattr(struct dentry * direntry, const char * ea_name,
if
(
ea_name
==
NULL
)
{
cFYI
(
1
,(
"Null xattr names not supported"
));
}
else
if
(
strncmp
(
ea_name
,
CIFS_XATTR_USER_PREFIX
,
5
))
{
cFYI
(
1
,(
"illegal xattr namespace %s (only user namespace supported)"
,
ea_name
));
}
else
if
(
strncmp
(
ea_name
,
CIFS_XATTR_USER_PREFIX
,
5
)
==
0
)
{
if
(
strncmp
(
ea_name
,
CIFS_XATTR_DOS_ATTRIB
,
14
)
==
0
)
{
cFYI
(
1
,(
"attempt to set cifs inode metadata"
));
}
ea_name
+=
5
;
/* skip past user. prefix */
rc
=
CIFSSMBSetEA
(
xid
,
pTcon
,
full_path
,
ea_name
,
ea_value
,
(
__u16
)
value_size
,
cifs_sb
->
local_nls
);
}
else
if
(
strncmp
(
ea_name
,
CIFS_XATTR_OS2_PREFIX
,
4
)
==
0
)
{
ea_name
+=
4
;
/* skip past os2. prefix */
rc
=
CIFSSMBSetEA
(
xid
,
pTcon
,
full_path
,
ea_name
,
ea_value
,
(
__u16
)
value_size
,
cifs_sb
->
local_nls
);
}
else
{
int
temp
;
temp
=
strncmp
(
ea_name
,
POSIX_ACL_XATTR_ACCESS
,
strlen
(
POSIX_ACL_XATTR_ACCESS
));
if
(
temp
==
0
)
{
#ifdef CONFIG_CIFS_POSIX
rc
=
CIFSSMBSetPosixACL
(
xid
,
pTcon
,
full_path
,
ea_value
,
(
const
int
)
value_size
,
ACL_TYPE_ACCESS
,
cifs_sb
->
local_nls
);
cFYI
(
1
,(
"set POSIX ACL rc %d"
,
rc
));
#else
cFYI
(
1
,(
"set POSIX ACL not supported"
));
#endif
}
else
if
(
strncmp
(
ea_name
,
POSIX_ACL_XATTR_DEFAULT
,
strlen
(
POSIX_ACL_XATTR_DEFAULT
))
==
0
)
{
#ifdef CONFIG_CIFS_POSIX
rc
=
CIFSSMBSetPosixACL
(
xid
,
pTcon
,
full_path
,
ea_value
,
(
const
int
)
value_size
,
ACL_TYPE_DEFAULT
,
cifs_sb
->
local_nls
);
cFYI
(
1
,(
"set POSIX default ACL rc %d"
,
rc
));
#else
cFYI
(
1
,(
"set default POSIX ACL not supported"
));
#endif
}
else
{
cFYI
(
1
,(
"illegal xattr request %s (only user namespace supported)"
,
ea_name
));
/* BB what if no namespace prefix? */
/* Should we just pass them to server, except for
system and perhaps security prefixes? */
}
else
{
ea_name
+=
5
;
/* skip past user. prefix */
rc
=
CIFSSMBSetEA
(
xid
,
pTcon
,
full_path
,
ea_name
,
ea_value
,
(
__u16
)
value_size
,
cifs_sb
->
local_nls
);
}
}
if
(
full_path
)
kfree
(
full_path
);
FreeXid
(
xid
);
...
...
@@ -163,6 +195,7 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name,
sb
=
direntry
->
d_inode
->
i_sb
;
if
(
sb
==
NULL
)
return
-
EIO
;
xid
=
GetXid
();
cifs_sb
=
CIFS_SB
(
sb
);
...
...
@@ -177,19 +210,48 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name,
}
/* return dos attributes as pseudo xattr */
/* return alt name if available as pseudo attr */
if
(
strncmp
(
ea_name
,
CIFS_XATTR_USER_PREFIX
,
5
))
{
cFYI
(
1
,(
"illegal xattr namespace %s (only user namespace supported)"
,
ea_name
));
/* BB what if no namespace prefix? */
/* Should we just pass them to server, except for system? */
}
else
{
/* We could add a check here
if
(
ea_name
==
NULL
)
{
cFYI
(
1
,(
"Null xattr names not supported"
));
}
else
if
(
strncmp
(
ea_name
,
CIFS_XATTR_USER_PREFIX
,
5
)
==
0
)
{
if
(
strncmp
(
ea_name
,
CIFS_XATTR_DOS_ATTRIB
,
14
)
==
0
)
{
cFYI
(
1
,(
"attempt to query cifs inode metadata"
));
/* revalidate/getattr then populate from inode */
}
/* BB add else when above is implemented */
ea_name
+=
5
;
/* skip past user. prefix */
rc
=
CIFSSMBQueryEA
(
xid
,
pTcon
,
full_path
,
ea_name
,
ea_value
,
buf_size
,
cifs_sb
->
local_nls
);
}
else
if
(
strncmp
(
ea_name
,
CIFS_XATTR_OS2_PREFIX
,
4
)
==
0
)
{
ea_name
+=
4
;
/* skip past os2. prefix */
rc
=
CIFSSMBQueryEA
(
xid
,
pTcon
,
full_path
,
ea_name
,
ea_value
,
buf_size
,
cifs_sb
->
local_nls
);
}
else
if
(
strncmp
(
ea_name
,
POSIX_ACL_XATTR_ACCESS
,
strlen
(
POSIX_ACL_XATTR_ACCESS
))
==
0
)
{
#ifdef CONFIG_CIFS_POSIX
rc
=
CIFSSMBGetPosixACL
(
xid
,
pTcon
,
full_path
,
ea_value
,
buf_size
,
ACL_TYPE_ACCESS
,
cifs_sb
->
local_nls
);
#else
cFYI
(
1
,(
"query POSIX ACL not supported yet"
));
#endif
/* CONFIG_CIFS_POSIX */
}
else
if
(
strncmp
(
ea_name
,
POSIX_ACL_XATTR_DEFAULT
,
strlen
(
POSIX_ACL_XATTR_DEFAULT
))
==
0
)
{
#ifdef CONFIG_CIFS_POSIX
rc
=
CIFSSMBGetPosixACL
(
xid
,
pTcon
,
full_path
,
ea_value
,
buf_size
,
ACL_TYPE_DEFAULT
,
cifs_sb
->
local_nls
);
#else
cFYI
(
1
,(
"query POSIX default ACL not supported yet"
));
#endif
}
else
{
cFYI
(
1
,(
"illegal xattr name request %s (only user namespace supported)"
,
ea_name
));
}
/* We could add an additional check for streams ie
if proc/fs/cifs/streamstoxattr is set then
search server for EAs or streams to
returns as xattrs */
ea_name
+=
5
;
/* skip past user. */
rc
=
CIFSSMBQueryEA
(
xid
,
pTcon
,
full_path
,
ea_name
,
ea_value
,
buf_size
,
cifs_sb
->
local_nls
);
}
if
(
rc
==
-
EINVAL
)
rc
=
-
EOPNOTSUPP
;
if
(
full_path
)
kfree
(
full_path
);
FreeXid
(
xid
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment