aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorJonathan Corbet <corbet@lwn.net>2008-07-14 17:29:34 -0400
committerJonathan Corbet <corbet@lwn.net>2008-07-14 17:29:34 -0400
commit2fceef397f9880b212a74c418290ce69e7ac00eb (patch)
treed9cc09ab992825ef7fede4a688103503e3caf655 /fs/cifs
parentfeae1ef116ed381625d3731c5ae4f4ebcb3fa302 (diff)
parentbce7f793daec3e65ec5c5705d2457b81fe7b5725 (diff)
Merge commit 'v2.6.26' into bkl-removal
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/AUTHORS1
-rw-r--r--fs/cifs/CHANGES10
-rw-r--r--fs/cifs/README5
-rw-r--r--fs/cifs/TODO15
-rw-r--r--fs/cifs/asn1.c14
-rw-r--r--fs/cifs/cifs_dfs_ref.c49
-rw-r--r--fs/cifs/cifs_fs_sb.h1
-rw-r--r--fs/cifs/cifs_spnego.c3
-rw-r--r--fs/cifs/cifsacl.c10
-rw-r--r--fs/cifs/cifsfs.c65
-rw-r--r--fs/cifs/cifsfs.h3
-rw-r--r--fs/cifs/cifsglob.h4
-rw-r--r--fs/cifs/cifspdu.h48
-rw-r--r--fs/cifs/cifsproto.h13
-rw-r--r--fs/cifs/cifssmb.c339
-rw-r--r--fs/cifs/connect.c73
-rw-r--r--fs/cifs/dir.c34
-rw-r--r--fs/cifs/dns_resolve.c9
-rw-r--r--fs/cifs/file.c13
-rw-r--r--fs/cifs/inode.c573
-rw-r--r--fs/cifs/ioctl.c4
-rw-r--r--fs/cifs/link.c43
-rw-r--r--fs/cifs/misc.c3
-rw-r--r--fs/cifs/netmisc.c6
-rw-r--r--fs/cifs/ntlmssp.h4
-rw-r--r--fs/cifs/readdir.c84
26 files changed, 773 insertions, 653 deletions
diff --git a/fs/cifs/AUTHORS b/fs/cifs/AUTHORS
index 8848e4dfa026..9c136d7803d9 100644
--- a/fs/cifs/AUTHORS
+++ b/fs/cifs/AUTHORS
@@ -36,6 +36,7 @@ Miklos Szeredi
36Kazeon team for various fixes especially for 2.4 version. 36Kazeon team for various fixes especially for 2.4 version.
37Asser Ferno (Change Notify support) 37Asser Ferno (Change Notify support)
38Shaggy (Dave Kleikamp) for inumerable small fs suggestions and some good cleanup 38Shaggy (Dave Kleikamp) for inumerable small fs suggestions and some good cleanup
39Igor Mammedov (DFS support)
39 40
40Test case and Bug Report contributors 41Test case and Bug Report contributors
41------------------------------------- 42-------------------------------------
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index 8355e918fddf..1f3465201fdf 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -1,5 +1,12 @@
1Version 1.53 1Version 1.53
2------------ 2------------
3DFS support added (Microsoft Distributed File System client support needed
4for referrals which enable a hierarchical name space among servers).
5Disable temporary caching of mode bits to servers which do not support
6storing of mode (e.g. Windows servers, when client mounts without cifsacl
7mount option) and add new "dynperm" mount option to enable temporary caching
8of mode (enable old behavior). Fix hang on mount caused when server crashes
9tcp session during negotiate protocol.
3 10
4Version 1.52 11Version 1.52
5------------ 12------------
@@ -12,7 +19,8 @@ Add ability to modify cifs acls for handling chmod (when mounted with
12cifsacl flag). Fix prefixpath path separator so we can handle mounts 19cifsacl flag). Fix prefixpath path separator so we can handle mounts
13with prefixpaths longer than one directory (one path component) when 20with prefixpaths longer than one directory (one path component) when
14mounted to Windows servers. Fix slow file open when cifsacl 21mounted to Windows servers. Fix slow file open when cifsacl
15enabled. 22enabled. Fix memory leak in FindNext when the SMB call returns -EBADF.
23
16 24
17Version 1.51 25Version 1.51
18------------ 26------------
diff --git a/fs/cifs/README b/fs/cifs/README
index 621aa1a85971..2bd6fe556f88 100644
--- a/fs/cifs/README
+++ b/fs/cifs/README
@@ -483,6 +483,11 @@ A partial list of the supported mount options follows:
483 sign Must use packet signing (helps avoid unwanted data modification 483 sign Must use packet signing (helps avoid unwanted data modification
484 by intermediate systems in the route). Note that signing 484 by intermediate systems in the route). Note that signing
485 does not work with lanman or plaintext authentication. 485 does not work with lanman or plaintext authentication.
486 seal Must seal (encrypt) all data on this mounted share before
487 sending on the network. Requires support for Unix Extensions.
488 Note that this differs from the sign mount option in that it
489 causes encryption of data sent over this mounted share but other
490 shares mounted to the same server are unaffected.
486 sec Security mode. Allowed values are: 491 sec Security mode. Allowed values are:
487 none attempt to connection as a null user (no name) 492 none attempt to connection as a null user (no name)
488 krb5 Use Kerberos version 5 authentication 493 krb5 Use Kerberos version 5 authentication
diff --git a/fs/cifs/TODO b/fs/cifs/TODO
index 92c9feac440f..5aff46c61e52 100644
--- a/fs/cifs/TODO
+++ b/fs/cifs/TODO
@@ -1,4 +1,4 @@
1Version 1.52 January 3, 2008 1Version 1.53 May 20, 2008
2 2
3A Partial List of Missing Features 3A Partial List of Missing Features
4================================== 4==================================
@@ -20,20 +20,21 @@ d) Cleanup now unneeded SessSetup code in
20fs/cifs/connect.c and add back in NTLMSSP code if any servers 20fs/cifs/connect.c and add back in NTLMSSP code if any servers
21need it 21need it
22 22
23e) ms-dfs and ms-dfs host name resolution cleanup 23e) fix NTLMv2 signing when two mounts with different users to same
24
25f) fix NTLMv2 signing when two mounts with different users to same
26server. 24server.
27 25
28g) Directory entry caching relies on a 1 second timer, rather than 26f) Directory entry caching relies on a 1 second timer, rather than
29using FindNotify or equivalent. - (started) 27using FindNotify or equivalent. - (started)
30 28
31h) quota support (needs minor kernel change since quota calls 29g) quota support (needs minor kernel change since quota calls
32to make it to network filesystems or deviceless filesystems) 30to make it to network filesystems or deviceless filesystems)
33 31
34i) investigate sync behavior (including syncpage) and check 32h) investigate sync behavior (including syncpage) and check
35for proper behavior of intr/nointr 33for proper behavior of intr/nointr
36 34
35i) improve support for very old servers (OS/2 and Win9x for example)
36Including support for changing the time remotely (utimes command).
37
37j) hook lower into the sockets api (as NFS/SunRPC does) to avoid the 38j) hook lower into the sockets api (as NFS/SunRPC does) to avoid the
38extra copy in/out of the socket buffers in some cases. 39extra copy in/out of the socket buffers in some cases.
39 40
diff --git a/fs/cifs/asn1.c b/fs/cifs/asn1.c
index cb52cbbe45ff..f58e41d3ba48 100644
--- a/fs/cifs/asn1.c
+++ b/fs/cifs/asn1.c
@@ -186,6 +186,11 @@ asn1_length_decode(struct asn1_ctx *ctx, unsigned int *def, unsigned int *len)
186 } 186 }
187 } 187 }
188 } 188 }
189
190 /* don't trust len bigger than ctx buffer */
191 if (*len > ctx->end - ctx->pointer)
192 return 0;
193
189 return 1; 194 return 1;
190} 195}
191 196
@@ -203,6 +208,10 @@ asn1_header_decode(struct asn1_ctx *ctx,
203 if (!asn1_length_decode(ctx, &def, &len)) 208 if (!asn1_length_decode(ctx, &def, &len))
204 return 0; 209 return 0;
205 210
211 /* primitive shall be definite, indefinite shall be constructed */
212 if (*con == ASN1_PRI && !def)
213 return 0;
214
206 if (def) 215 if (def)
207 *eoc = ctx->pointer + len; 216 *eoc = ctx->pointer + len;
208 else 217 else
@@ -389,6 +398,11 @@ asn1_oid_decode(struct asn1_ctx *ctx,
389 unsigned long *optr; 398 unsigned long *optr;
390 399
391 size = eoc - ctx->pointer + 1; 400 size = eoc - ctx->pointer + 1;
401
402 /* first subid actually encodes first two subids */
403 if (size < 2 || size > ULONG_MAX/sizeof(unsigned long))
404 return 0;
405
392 *oid = kmalloc(size * sizeof(unsigned long), GFP_ATOMIC); 406 *oid = kmalloc(size * sizeof(unsigned long), GFP_ATOMIC);
393 if (*oid == NULL) 407 if (*oid == NULL)
394 return 0; 408 return 0;
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c
index f6fdecf6598c..d82374c9e329 100644
--- a/fs/cifs/cifs_dfs_ref.c
+++ b/fs/cifs/cifs_dfs_ref.c
@@ -219,53 +219,6 @@ static struct vfsmount *cifs_dfs_do_refmount(const struct vfsmount *mnt_parent,
219 219
220} 220}
221 221
222static char *build_full_dfs_path_from_dentry(struct dentry *dentry)
223{
224 char *full_path = NULL;
225 char *search_path;
226 char *tmp_path;
227 size_t l_max_len;
228 struct cifs_sb_info *cifs_sb;
229
230 if (dentry->d_inode == NULL)
231 return NULL;
232
233 cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
234
235 if (cifs_sb->tcon == NULL)
236 return NULL;
237
238 search_path = build_path_from_dentry(dentry);
239 if (search_path == NULL)
240 return NULL;
241
242 if (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS) {
243 int i;
244 /* we should use full path name for correct working with DFS */
245 l_max_len = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE+1) +
246 strnlen(search_path, MAX_PATHCONF) + 1;
247 tmp_path = kmalloc(l_max_len, GFP_KERNEL);
248 if (tmp_path == NULL) {
249 kfree(search_path);
250 return NULL;
251 }
252 strncpy(tmp_path, cifs_sb->tcon->treeName, l_max_len);
253 tmp_path[l_max_len-1] = 0;
254 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
255 for (i = 0; i < l_max_len; i++) {
256 if (tmp_path[i] == '\\')
257 tmp_path[i] = '/';
258 }
259 strncat(tmp_path, search_path, l_max_len - strlen(tmp_path));
260
261 full_path = tmp_path;
262 kfree(search_path);
263 } else {
264 full_path = search_path;
265 }
266 return full_path;
267}
268
269static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd, 222static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd,
270 struct list_head *mntlist) 223 struct list_head *mntlist)
271{ 224{
@@ -333,7 +286,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
333 goto out_err; 286 goto out_err;
334 } 287 }
335 288
336 full_path = build_full_dfs_path_from_dentry(dentry); 289 full_path = build_path_from_dentry(dentry);
337 if (full_path == NULL) { 290 if (full_path == NULL) {
338 rc = -ENOMEM; 291 rc = -ENOMEM;
339 goto out_err; 292 goto out_err;
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
index 8ad2330ba061..877c85409f1f 100644
--- a/fs/cifs/cifs_fs_sb.h
+++ b/fs/cifs/cifs_fs_sb.h
@@ -30,6 +30,7 @@
30#define CIFS_MOUNT_CIFS_ACL 0x200 /* send ACL requests to non-POSIX srv */ 30#define CIFS_MOUNT_CIFS_ACL 0x200 /* send ACL requests to non-POSIX srv */
31#define CIFS_MOUNT_OVERR_UID 0x400 /* override uid returned from server */ 31#define CIFS_MOUNT_OVERR_UID 0x400 /* override uid returned from server */
32#define CIFS_MOUNT_OVERR_GID 0x800 /* override gid returned from server */ 32#define CIFS_MOUNT_OVERR_GID 0x800 /* override gid returned from server */
33#define CIFS_MOUNT_DYNPERM 0x1000 /* allow in-memory only mode setting */
33 34
34struct cifs_sb_info { 35struct cifs_sb_info {
35 struct cifsTconInfo *tcon; /* primary mount */ 36 struct cifsTconInfo *tcon; /* primary mount */
diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c
index 6653e29637a7..7013aaff6aed 100644
--- a/fs/cifs/cifs_spnego.c
+++ b/fs/cifs/cifs_spnego.c
@@ -119,6 +119,9 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
119 dp = description + strlen(description); 119 dp = description + strlen(description);
120 sprintf(dp, ";uid=0x%x", sesInfo->linux_uid); 120 sprintf(dp, ";uid=0x%x", sesInfo->linux_uid);
121 121
122 dp = description + strlen(description);
123 sprintf(dp, ";user=%s", sesInfo->userName);
124
122 cFYI(1, ("key description = %s", description)); 125 cFYI(1, ("key description = %s", description));
123 spnego_key = request_key(&cifs_spnego_key_type, description, ""); 126 spnego_key = request_key(&cifs_spnego_key_type, description, "");
124 127
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
index 34902cff5400..0e9fc2ba90ee 100644
--- a/fs/cifs/cifsacl.c
+++ b/fs/cifs/cifsacl.c
@@ -34,11 +34,11 @@
34static struct cifs_wksid wksidarr[NUM_WK_SIDS] = { 34static struct cifs_wksid wksidarr[NUM_WK_SIDS] = {
35 {{1, 0, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0} }, "null user"}, 35 {{1, 0, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0} }, "null user"},
36 {{1, 1, {0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 0} }, "nobody"}, 36 {{1, 1, {0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 0} }, "nobody"},
37 {{1, 1, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(11), 0, 0, 0, 0} }, "net-users"}, 37 {{1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(11), 0, 0, 0, 0} }, "net-users"},
38 {{1, 1, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(18), 0, 0, 0, 0} }, "sys"}, 38 {{1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(18), 0, 0, 0, 0} }, "sys"},
39 {{1, 2, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(32), cpu_to_le32(544), 0, 0, 0} }, "root"}, 39 {{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(544), 0, 0, 0} }, "root"},
40 {{1, 2, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(32), cpu_to_le32(545), 0, 0, 0} }, "users"}, 40 {{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(545), 0, 0, 0} }, "users"},
41 {{1, 2, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(32), cpu_to_le32(546), 0, 0, 0} }, "guest"} } 41 {{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(546), 0, 0, 0} }, "guest"} }
42; 42;
43 43
44 44
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index aeff0fe5b6b9..22857c639df5 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * fs/cifs/cifsfs.c 2 * fs/cifs/cifsfs.c
3 * 3 *
4 * Copyright (C) International Business Machines Corp., 2002,2007 4 * Copyright (C) International Business Machines Corp., 2002,2008
5 * Author(s): Steve French (sfrench@us.ibm.com) 5 * Author(s): Steve French (sfrench@us.ibm.com)
6 * 6 *
7 * Common Internet FileSystem (CIFS) client 7 * Common Internet FileSystem (CIFS) client
@@ -97,9 +97,6 @@ cifs_read_super(struct super_block *sb, void *data,
97{ 97{
98 struct inode *inode; 98 struct inode *inode;
99 struct cifs_sb_info *cifs_sb; 99 struct cifs_sb_info *cifs_sb;
100#ifdef CONFIG_CIFS_DFS_UPCALL
101 int len;
102#endif
103 int rc = 0; 100 int rc = 0;
104 101
105 /* BB should we make this contingent on mount parm? */ 102 /* BB should we make this contingent on mount parm? */
@@ -117,15 +114,17 @@ cifs_read_super(struct super_block *sb, void *data,
117 * complex operation (mount), and in case of fail 114 * complex operation (mount), and in case of fail
118 * just exit instead of doing mount and attempting 115 * just exit instead of doing mount and attempting
119 * undo it if this copy fails?*/ 116 * undo it if this copy fails?*/
120 len = strlen(data); 117 if (data) {
121 cifs_sb->mountdata = kzalloc(len + 1, GFP_KERNEL); 118 int len = strlen(data);
122 if (cifs_sb->mountdata == NULL) { 119 cifs_sb->mountdata = kzalloc(len + 1, GFP_KERNEL);
123 kfree(sb->s_fs_info); 120 if (cifs_sb->mountdata == NULL) {
124 sb->s_fs_info = NULL; 121 kfree(sb->s_fs_info);
125 return -ENOMEM; 122 sb->s_fs_info = NULL;
123 return -ENOMEM;
124 }
125 strncpy(cifs_sb->mountdata, data, len + 1);
126 cifs_sb->mountdata[len] = '\0';
126 } 127 }
127 strncpy(cifs_sb->mountdata, data, len + 1);
128 cifs_sb->mountdata[len] = '\0';
129#endif 128#endif
130 129
131 rc = cifs_mount(sb, cifs_sb, data, devname); 130 rc = cifs_mount(sb, cifs_sb, data, devname);
@@ -353,9 +352,41 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m)
353 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) || 352 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) ||
354 !(cifs_sb->tcon->unix_ext)) 353 !(cifs_sb->tcon->unix_ext))
355 seq_printf(s, ",gid=%d", cifs_sb->mnt_gid); 354 seq_printf(s, ",gid=%d", cifs_sb->mnt_gid);
355 if (!cifs_sb->tcon->unix_ext) {
356 seq_printf(s, ",file_mode=0%o,dir_mode=0%o",
357 cifs_sb->mnt_file_mode,
358 cifs_sb->mnt_dir_mode);
359 }
360 if (cifs_sb->tcon->seal)
361 seq_printf(s, ",seal");
362 if (cifs_sb->tcon->nocase)
363 seq_printf(s, ",nocase");
364 if (cifs_sb->tcon->retry)
365 seq_printf(s, ",hard");
356 } 366 }
357 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) 367 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
358 seq_printf(s, ",posixpaths"); 368 seq_printf(s, ",posixpaths");
369 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)
370 seq_printf(s, ",setuids");
371 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
372 seq_printf(s, ",serverino");
373 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
374 seq_printf(s, ",directio");
375 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
376 seq_printf(s, ",nouser_xattr");
377 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR)
378 seq_printf(s, ",mapchars");
379 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
380 seq_printf(s, ",sfu");
381 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
382 seq_printf(s, ",nobrl");
383 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
384 seq_printf(s, ",cifsacl");
385 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
386 seq_printf(s, ",dynperm");
387 if (m->mnt_sb->s_flags & MS_POSIXACL)
388 seq_printf(s, ",acl");
389
359 seq_printf(s, ",rsize=%d", cifs_sb->rsize); 390 seq_printf(s, ",rsize=%d", cifs_sb->rsize);
360 seq_printf(s, ",wsize=%d", cifs_sb->wsize); 391 seq_printf(s, ",wsize=%d", cifs_sb->wsize);
361 } 392 }
@@ -657,7 +688,7 @@ const struct file_operations cifs_file_ops = {
657 .splice_read = generic_file_splice_read, 688 .splice_read = generic_file_splice_read,
658 .llseek = cifs_llseek, 689 .llseek = cifs_llseek,
659#ifdef CONFIG_CIFS_POSIX 690#ifdef CONFIG_CIFS_POSIX
660 .ioctl = cifs_ioctl, 691 .unlocked_ioctl = cifs_ioctl,
661#endif /* CONFIG_CIFS_POSIX */ 692#endif /* CONFIG_CIFS_POSIX */
662 693
663#ifdef CONFIG_CIFS_EXPERIMENTAL 694#ifdef CONFIG_CIFS_EXPERIMENTAL
@@ -677,7 +708,7 @@ const struct file_operations cifs_file_direct_ops = {
677 .flush = cifs_flush, 708 .flush = cifs_flush,
678 .splice_read = generic_file_splice_read, 709 .splice_read = generic_file_splice_read,
679#ifdef CONFIG_CIFS_POSIX 710#ifdef CONFIG_CIFS_POSIX
680 .ioctl = cifs_ioctl, 711 .unlocked_ioctl = cifs_ioctl,
681#endif /* CONFIG_CIFS_POSIX */ 712#endif /* CONFIG_CIFS_POSIX */
682 .llseek = cifs_llseek, 713 .llseek = cifs_llseek,
683#ifdef CONFIG_CIFS_EXPERIMENTAL 714#ifdef CONFIG_CIFS_EXPERIMENTAL
@@ -697,7 +728,7 @@ const struct file_operations cifs_file_nobrl_ops = {
697 .splice_read = generic_file_splice_read, 728 .splice_read = generic_file_splice_read,
698 .llseek = cifs_llseek, 729 .llseek = cifs_llseek,
699#ifdef CONFIG_CIFS_POSIX 730#ifdef CONFIG_CIFS_POSIX
700 .ioctl = cifs_ioctl, 731 .unlocked_ioctl = cifs_ioctl,
701#endif /* CONFIG_CIFS_POSIX */ 732#endif /* CONFIG_CIFS_POSIX */
702 733
703#ifdef CONFIG_CIFS_EXPERIMENTAL 734#ifdef CONFIG_CIFS_EXPERIMENTAL
@@ -716,7 +747,7 @@ const struct file_operations cifs_file_direct_nobrl_ops = {
716 .flush = cifs_flush, 747 .flush = cifs_flush,
717 .splice_read = generic_file_splice_read, 748 .splice_read = generic_file_splice_read,
718#ifdef CONFIG_CIFS_POSIX 749#ifdef CONFIG_CIFS_POSIX
719 .ioctl = cifs_ioctl, 750 .unlocked_ioctl = cifs_ioctl,
720#endif /* CONFIG_CIFS_POSIX */ 751#endif /* CONFIG_CIFS_POSIX */
721 .llseek = cifs_llseek, 752 .llseek = cifs_llseek,
722#ifdef CONFIG_CIFS_EXPERIMENTAL 753#ifdef CONFIG_CIFS_EXPERIMENTAL
@@ -731,7 +762,7 @@ const struct file_operations cifs_dir_ops = {
731#ifdef CONFIG_CIFS_EXPERIMENTAL 762#ifdef CONFIG_CIFS_EXPERIMENTAL
732 .dir_notify = cifs_dir_notify, 763 .dir_notify = cifs_dir_notify,
733#endif /* CONFIG_CIFS_EXPERIMENTAL */ 764#endif /* CONFIG_CIFS_EXPERIMENTAL */
734 .ioctl = cifs_ioctl, 765 .unlocked_ioctl = cifs_ioctl,
735}; 766};
736 767
737static void 768static void
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index cd1301a09b3b..25a6cbd15529 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -95,8 +95,7 @@ extern int cifs_setxattr(struct dentry *, const char *, const void *,
95 size_t, int); 95 size_t, int);
96extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); 96extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t);
97extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); 97extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
98extern int cifs_ioctl(struct inode *inode, struct file *filep, 98extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
99 unsigned int command, unsigned long arg);
100 99
101#ifdef CONFIG_CIFS_EXPERIMENTAL 100#ifdef CONFIG_CIFS_EXPERIMENTAL
102extern const struct export_operations cifs_export_ops; 101extern const struct export_operations cifs_export_ops;
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index b7d9f698e63e..9cfcf326ead3 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -281,6 +281,7 @@ struct cifsTconInfo {
281 bool ipc:1; /* set if connection to IPC$ eg for RPC/PIPES */ 281 bool ipc:1; /* set if connection to IPC$ eg for RPC/PIPES */
282 bool retry:1; 282 bool retry:1;
283 bool nocase:1; 283 bool nocase:1;
284 bool seal:1; /* transport encryption for this mounted share */
284 bool unix_ext:1; /* if false disable Linux extensions to CIFS protocol 285 bool unix_ext:1; /* if false disable Linux extensions to CIFS protocol
285 for this mount even if server would support */ 286 for this mount even if server would support */
286 /* BB add field for back pointer to sb struct(s)? */ 287 /* BB add field for back pointer to sb struct(s)? */
@@ -332,7 +333,6 @@ struct cifsFileInfo {
332 bool messageMode:1; /* for pipes: message vs byte mode */ 333 bool messageMode:1; /* for pipes: message vs byte mode */
333 atomic_t wrtPending; /* handle in use - defer close */ 334 atomic_t wrtPending; /* handle in use - defer close */
334 struct semaphore fh_sem; /* prevents reopen race after dead ses*/ 335 struct semaphore fh_sem; /* prevents reopen race after dead ses*/
335 char *search_resume_name; /* BB removeme BB */
336 struct cifs_search_info srch_inf; 336 struct cifs_search_info srch_inf;
337}; 337};
338 338
@@ -625,7 +625,7 @@ GLOBAL_EXTERN atomic_t tcpSesAllocCount;
625GLOBAL_EXTERN atomic_t tcpSesReconnectCount; 625GLOBAL_EXTERN atomic_t tcpSesReconnectCount;
626GLOBAL_EXTERN atomic_t tconInfoReconnectCount; 626GLOBAL_EXTERN atomic_t tconInfoReconnectCount;
627 627
628/* Various Debug counters to remove someday (BB) */ 628/* Various Debug counters */
629GLOBAL_EXTERN atomic_t bufAllocCount; /* current number allocated */ 629GLOBAL_EXTERN atomic_t bufAllocCount; /* current number allocated */
630#ifdef CONFIG_CIFS_STATS2 630#ifdef CONFIG_CIFS_STATS2
631GLOBAL_EXTERN atomic_t totBufAllocCount; /* total allocated over all time */ 631GLOBAL_EXTERN atomic_t totBufAllocCount; /* total allocated over all time */
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index c43bf4b7a556..0f327c224da3 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -79,6 +79,19 @@
79#define TRANS2_GET_DFS_REFERRAL 0x10 79#define TRANS2_GET_DFS_REFERRAL 0x10
80#define TRANS2_REPORT_DFS_INCOSISTENCY 0x11 80#define TRANS2_REPORT_DFS_INCOSISTENCY 0x11
81 81
82/* SMB Transact (Named Pipe) subcommand codes */
83#define TRANS_SET_NMPIPE_STATE 0x0001
84#define TRANS_RAW_READ_NMPIPE 0x0011
85#define TRANS_QUERY_NMPIPE_STATE 0x0021
86#define TRANS_QUERY_NMPIPE_INFO 0x0022
87#define TRANS_PEEK_NMPIPE 0x0023
88#define TRANS_TRANSACT_NMPIPE 0x0026
89#define TRANS_RAW_WRITE_NMPIPE 0x0031
90#define TRANS_READ_NMPIPE 0x0036
91#define TRANS_WRITE_NMPIPE 0x0037
92#define TRANS_WAIT_NMPIPE 0x0053
93#define TRANS_CALL_NMPIPE 0x0054
94
82/* NT Transact subcommand codes */ 95/* NT Transact subcommand codes */
83#define NT_TRANSACT_CREATE 0x01 96#define NT_TRANSACT_CREATE 0x01
84#define NT_TRANSACT_IOCTL 0x02 97#define NT_TRANSACT_IOCTL 0x02
@@ -328,12 +341,13 @@
328#define CREATE_COMPLETE_IF_OPLK 0x00000100 /* should be zero */ 341#define CREATE_COMPLETE_IF_OPLK 0x00000100 /* should be zero */
329#define CREATE_NO_EA_KNOWLEDGE 0x00000200 342#define CREATE_NO_EA_KNOWLEDGE 0x00000200
330#define CREATE_EIGHT_DOT_THREE 0x00000400 /* doc says this is obsolete 343#define CREATE_EIGHT_DOT_THREE 0x00000400 /* doc says this is obsolete
331 open for recovery flag - should 344 "open for recovery" flag - should
332 be zero */ 345 be zero in any case */
346#define CREATE_OPEN_FOR_RECOVERY 0x00000400
333#define CREATE_RANDOM_ACCESS 0x00000800 347#define CREATE_RANDOM_ACCESS 0x00000800
334#define CREATE_DELETE_ON_CLOSE 0x00001000 348#define CREATE_DELETE_ON_CLOSE 0x00001000
335#define CREATE_OPEN_BY_ID 0x00002000 349#define CREATE_OPEN_BY_ID 0x00002000
336#define CREATE_OPEN_BACKUP_INTN 0x00004000 350#define CREATE_OPEN_BACKUP_INTENT 0x00004000
337#define CREATE_NO_COMPRESSION 0x00008000 351#define CREATE_NO_COMPRESSION 0x00008000
338#define CREATE_RESERVE_OPFILTER 0x00100000 /* should be zero */ 352#define CREATE_RESERVE_OPFILTER 0x00100000 /* should be zero */
339#define OPEN_REPARSE_POINT 0x00200000 353#define OPEN_REPARSE_POINT 0x00200000
@@ -722,7 +736,6 @@ typedef struct smb_com_tconx_rsp_ext {
722#define SMB_CSC_CACHE_AUTO_REINT 0x0004 736#define SMB_CSC_CACHE_AUTO_REINT 0x0004
723#define SMB_CSC_CACHE_VDO 0x0008 737#define SMB_CSC_CACHE_VDO 0x0008
724#define SMB_CSC_NO_CACHING 0x000C 738#define SMB_CSC_NO_CACHING 0x000C
725
726#define SMB_UNIQUE_FILE_NAME 0x0010 739#define SMB_UNIQUE_FILE_NAME 0x0010
727#define SMB_EXTENDED_SIGNATURES 0x0020 740#define SMB_EXTENDED_SIGNATURES 0x0020
728 741
@@ -806,7 +819,7 @@ typedef struct smb_com_findclose_req {
806#define ICOUNT_MASK 0x00FF 819#define ICOUNT_MASK 0x00FF
807#define PIPE_READ_MODE 0x0100 820#define PIPE_READ_MODE 0x0100
808#define NAMED_PIPE_TYPE 0x0400 821#define NAMED_PIPE_TYPE 0x0400
809#define PIPE_END_POINT 0x0800 822#define PIPE_END_POINT 0x4000
810#define BLOCKING_NAMED_PIPE 0x8000 823#define BLOCKING_NAMED_PIPE 0x8000
811 824
812typedef struct smb_com_open_req { /* also handles create */ 825typedef struct smb_com_open_req { /* also handles create */
@@ -1904,19 +1917,26 @@ typedef struct smb_com_transaction2_get_dfs_refer_req {
1904 char RequestFileName[1]; 1917 char RequestFileName[1];
1905} __attribute__((packed)) TRANSACTION2_GET_DFS_REFER_REQ; 1918} __attribute__((packed)) TRANSACTION2_GET_DFS_REFER_REQ;
1906 1919
1920#define DFS_VERSION cpu_to_le16(0x0003)
1921
1922/* DFS server target type */
1923#define DFS_TYPE_LINK 0x0000 /* also for sysvol targets */
1924#define DFS_TYPE_ROOT 0x0001
1925
1926/* Referral Entry Flags */
1927#define DFS_NAME_LIST_REF 0x0200
1928
1907typedef struct dfs_referral_level_3 { 1929typedef struct dfs_referral_level_3 {
1908 __le16 VersionNumber; 1930 __le16 VersionNumber;
1909 __le16 ReferralSize; 1931 __le16 Size;
1910 __le16 ServerType; /* 0x0001 = CIFS server */ 1932 __le16 ServerType; /* 0x0001 = root targets; 0x0000 = link targets */
1911 __le16 ReferralFlags; /* or proximity - not clear which since it is 1933 __le16 ReferralEntryFlags; /* 0x0200 bit set only for domain
1912 always set to zero - SNIA spec says 0x01 1934 or DC referral responce */
1913 means strip off PathConsumed chars before 1935 __le32 TimeToLive;
1914 submitting RequestFileName to remote node */
1915 __le16 TimeToLive;
1916 __le16 Proximity;
1917 __le16 DfsPathOffset; 1936 __le16 DfsPathOffset;
1918 __le16 DfsAlternatePathOffset; 1937 __le16 DfsAlternatePathOffset;
1919 __le16 NetworkAddressOffset; 1938 __le16 NetworkAddressOffset; /* offset of the link target */
1939 __le16 ServiceSiteGuid;
1920} __attribute__((packed)) REFERRAL3; 1940} __attribute__((packed)) REFERRAL3;
1921 1941
1922typedef struct smb_com_transaction_get_dfs_refer_rsp { 1942typedef struct smb_com_transaction_get_dfs_refer_rsp {
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index d481f6c5a2be..b9f5e935f821 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -93,7 +93,7 @@ extern struct timespec cnvrtDosUnixTm(__u16 date, __u16 time);
93 93
94extern int cifs_get_inode_info(struct inode **pinode, 94extern int cifs_get_inode_info(struct inode **pinode,
95 const unsigned char *search_path, 95 const unsigned char *search_path,
96 FILE_ALL_INFO * pfile_info, 96 FILE_ALL_INFO *pfile_info,
97 struct super_block *sb, int xid, const __u16 *pfid); 97 struct super_block *sb, int xid, const __u16 *pfid);
98extern int cifs_get_inode_info_unix(struct inode **pinode, 98extern int cifs_get_inode_info_unix(struct inode **pinode,
99 const unsigned char *search_path, 99 const unsigned char *search_path,
@@ -130,7 +130,7 @@ extern int CIFSFindClose(const int, struct cifsTconInfo *tcon,
130 130
131extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, 131extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
132 const unsigned char *searchName, 132 const unsigned char *searchName,
133 FILE_ALL_INFO * findData, 133 FILE_ALL_INFO *findData,
134 int legacy /* whether to use old info level */, 134 int legacy /* whether to use old info level */,
135 const struct nls_table *nls_codepage, int remap); 135 const struct nls_table *nls_codepage, int remap);
136extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon, 136extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
@@ -141,18 +141,15 @@ extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
141extern int CIFSSMBUnixQPathInfo(const int xid, 141extern int CIFSSMBUnixQPathInfo(const int xid,
142 struct cifsTconInfo *tcon, 142 struct cifsTconInfo *tcon,
143 const unsigned char *searchName, 143 const unsigned char *searchName,
144 FILE_UNIX_BASIC_INFO * pFindData, 144 FILE_UNIX_BASIC_INFO *pFindData,
145 const struct nls_table *nls_codepage, int remap); 145 const struct nls_table *nls_codepage, int remap);
146 146
147extern int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, 147extern int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
148 const unsigned char *searchName, 148 const unsigned char *searchName,
149 unsigned char **targetUNCs, 149 struct dfs_info3_param **target_nodes,
150 unsigned int *number_of_UNC_in_array, 150 unsigned int *number_of_nodes_in_array,
151 const struct nls_table *nls_codepage, int remap); 151 const struct nls_table *nls_codepage, int remap);
152 152
153extern int connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
154 const char *old_path,
155 const struct nls_table *nls_codepage, int remap);
156extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, 153extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
157 const char *old_path, 154 const char *old_path,
158 const struct nls_table *nls_codepage, 155 const struct nls_table *nls_codepage,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 95fbba4ea7d4..4511b708f0f3 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -81,6 +81,40 @@ static struct {
81#endif /* CONFIG_CIFS_WEAK_PW_HASH */ 81#endif /* CONFIG_CIFS_WEAK_PW_HASH */
82#endif /* CIFS_POSIX */ 82#endif /* CIFS_POSIX */
83 83
84/* Allocates buffer into dst and copies smb string from src to it.
85 * caller is responsible for freeing dst if function returned 0.
86 * returns:
87 * on success - 0
88 * on failure - errno
89 */
90static int
91cifs_strncpy_to_host(char **dst, const char *src, const int maxlen,
92 const bool is_unicode, const struct nls_table *nls_codepage)
93{
94 int plen;
95
96 if (is_unicode) {
97 plen = UniStrnlen((wchar_t *)src, maxlen);
98 *dst = kmalloc(plen + 2, GFP_KERNEL);
99 if (!*dst)
100 goto cifs_strncpy_to_host_ErrExit;
101 cifs_strfromUCS_le(*dst, (__le16 *)src, plen, nls_codepage);
102 } else {
103 plen = strnlen(src, maxlen);
104 *dst = kmalloc(plen + 2, GFP_KERNEL);
105 if (!*dst)
106 goto cifs_strncpy_to_host_ErrExit;
107 strncpy(*dst, src, plen);
108 }
109 (*dst)[plen] = 0;
110 (*dst)[plen+1] = 0; /* harmless for ASCII case, needed for Unicode */
111 return 0;
112
113cifs_strncpy_to_host_ErrExit:
114 cERROR(1, ("Failed to allocate buffer for string\n"));
115 return -ENOMEM;
116}
117
84 118
85/* Mark as invalid, all open files on tree connections since they 119/* Mark as invalid, all open files on tree connections since they
86 were closed when session to server was lost */ 120 were closed when session to server was lost */
@@ -1166,6 +1200,20 @@ static __u16 convert_disposition(int disposition)
1166 return ofun; 1200 return ofun;
1167} 1201}
1168 1202
1203static int
1204access_flags_to_smbopen_mode(const int access_flags)
1205{
1206 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1207
1208 if (masked_flags == GENERIC_READ)
1209 return SMBOPEN_READ;
1210 else if (masked_flags == GENERIC_WRITE)
1211 return SMBOPEN_WRITE;
1212
1213 /* just go for read/write */
1214 return SMBOPEN_READWRITE;
1215}
1216
1169int 1217int
1170SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon, 1218SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1171 const char *fileName, const int openDisposition, 1219 const char *fileName, const int openDisposition,
@@ -1207,13 +1255,7 @@ OldOpenRetry:
1207 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK); 1255 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
1208 1256
1209 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO); 1257 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1210 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */ 1258 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
1211 /* 0 = read
1212 1 = write
1213 2 = rw
1214 3 = execute
1215 */
1216 pSMB->Mode = cpu_to_le16(2);
1217 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */ 1259 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1218 /* set file as system file if special file such 1260 /* set file as system file if special file such
1219 as fifo and server expecting SFU style and 1261 as fifo and server expecting SFU style and
@@ -1247,7 +1289,7 @@ OldOpenRetry:
1247 } else { 1289 } else {
1248 /* BB verify if wct == 15 */ 1290 /* BB verify if wct == 15 */
1249 1291
1250/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */ 1292/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
1251 1293
1252 *netfid = pSMBr->Fid; /* cifs fid stays in le */ 1294 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1253 /* Let caller know file was created so we can set the mode. */ 1295 /* Let caller know file was created so we can set the mode. */
@@ -1686,7 +1728,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1686{ 1728{
1687 int rc = 0; 1729 int rc = 0;
1688 LOCK_REQ *pSMB = NULL; 1730 LOCK_REQ *pSMB = NULL;
1689 LOCK_RSP *pSMBr = NULL; 1731/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
1690 int bytes_returned; 1732 int bytes_returned;
1691 int timeout = 0; 1733 int timeout = 0;
1692 __u16 count; 1734 __u16 count;
@@ -1697,8 +1739,6 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1697 if (rc) 1739 if (rc)
1698 return rc; 1740 return rc;
1699 1741
1700 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1701
1702 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) { 1742 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1703 timeout = CIFS_ASYNC_OP; /* no response expected */ 1743 timeout = CIFS_ASYNC_OP; /* no response expected */
1704 pSMB->Timeout = 0; 1744 pSMB->Timeout = 0;
@@ -1732,7 +1772,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1732 1772
1733 if (waitFlag) { 1773 if (waitFlag) {
1734 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB, 1774 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1735 (struct smb_hdr *) pSMBr, &bytes_returned); 1775 (struct smb_hdr *) pSMB, &bytes_returned);
1736 cifs_small_buf_release(pSMB); 1776 cifs_small_buf_release(pSMB);
1737 } else { 1777 } else {
1738 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB, 1778 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
@@ -1767,7 +1807,7 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1767 cFYI(1, ("Posix Lock")); 1807 cFYI(1, ("Posix Lock"));
1768 1808
1769 if (pLockData == NULL) 1809 if (pLockData == NULL)
1770 return EINVAL; 1810 return -EINVAL;
1771 1811
1772 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB); 1812 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1773 1813
@@ -1944,7 +1984,7 @@ renameRetry:
1944 /* protocol requires ASCII signature byte on Unicode string */ 1984 /* protocol requires ASCII signature byte on Unicode string */
1945 pSMB->OldFileName[name_len + 1] = 0x00; 1985 pSMB->OldFileName[name_len + 1] = 0x00;
1946 name_len2 = 1986 name_len2 =
1947 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2], 1987 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
1948 toName, PATH_MAX, nls_codepage, remap); 1988 toName, PATH_MAX, nls_codepage, remap);
1949 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; 1989 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1950 name_len2 *= 2; /* convert to bytes */ 1990 name_len2 *= 2; /* convert to bytes */
@@ -2117,8 +2157,7 @@ copyRetry:
2117 cFYI(1, ("Send error in copy = %d with %d files copied", 2157 cFYI(1, ("Send error in copy = %d with %d files copied",
2118 rc, le16_to_cpu(pSMBr->CopyCount))); 2158 rc, le16_to_cpu(pSMBr->CopyCount)));
2119 } 2159 }
2120 if (pSMB) 2160 cifs_buf_release(pSMB);
2121 cifs_buf_release(pSMB);
2122 2161
2123 if (rc == -EAGAIN) 2162 if (rc == -EAGAIN)
2124 goto copyRetry; 2163 goto copyRetry;
@@ -2207,8 +2246,7 @@ createSymLinkRetry:
2207 if (rc) 2246 if (rc)
2208 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc)); 2247 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
2209 2248
2210 if (pSMB) 2249 cifs_buf_release(pSMB);
2211 cifs_buf_release(pSMB);
2212 2250
2213 if (rc == -EAGAIN) 2251 if (rc == -EAGAIN)
2214 goto createSymLinkRetry; 2252 goto createSymLinkRetry;
@@ -2925,7 +2963,8 @@ setAclRetry:
2925 } 2963 }
2926 params = 6 + name_len; 2964 params = 6 + name_len;
2927 pSMB->MaxParameterCount = cpu_to_le16(2); 2965 pSMB->MaxParameterCount = cpu_to_le16(2);
2928 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */ 2966 /* BB find max SMB size from sess */
2967 pSMB->MaxDataCount = cpu_to_le16(1000);
2929 pSMB->MaxSetupCount = 0; 2968 pSMB->MaxSetupCount = 0;
2930 pSMB->Reserved = 0; 2969 pSMB->Reserved = 0;
2931 pSMB->Flags = 0; 2970 pSMB->Flags = 0;
@@ -3322,7 +3361,8 @@ QPathInfoRetry:
3322 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */; 3361 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3323 pSMB->TotalDataCount = 0; 3362 pSMB->TotalDataCount = 0;
3324 pSMB->MaxParameterCount = cpu_to_le16(2); 3363 pSMB->MaxParameterCount = cpu_to_le16(2);
3325 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ 3364 /* BB find exact max SMB PDU from sess structure BB */
3365 pSMB->MaxDataCount = cpu_to_le16(4000);
3326 pSMB->MaxSetupCount = 0; 3366 pSMB->MaxSetupCount = 0;
3327 pSMB->Reserved = 0; 3367 pSMB->Reserved = 0;
3328 pSMB->Flags = 0; 3368 pSMB->Flags = 0;
@@ -3388,7 +3428,7 @@ QPathInfoRetry:
3388int 3428int
3389CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon, 3429CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3390 const unsigned char *searchName, 3430 const unsigned char *searchName,
3391 FILE_UNIX_BASIC_INFO * pFindData, 3431 FILE_UNIX_BASIC_INFO *pFindData,
3392 const struct nls_table *nls_codepage, int remap) 3432 const struct nls_table *nls_codepage, int remap)
3393{ 3433{
3394/* SMB_QUERY_FILE_UNIX_BASIC */ 3434/* SMB_QUERY_FILE_UNIX_BASIC */
@@ -3679,6 +3719,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3679 if (rc) { 3719 if (rc) {
3680 if (rc == -EBADF) { 3720 if (rc == -EBADF) {
3681 psrch_inf->endOfSearch = true; 3721 psrch_inf->endOfSearch = true;
3722 cifs_buf_release(pSMB);
3682 rc = 0; /* search probably was closed at end of search*/ 3723 rc = 0; /* search probably was closed at end of search*/
3683 } else 3724 } else
3684 cFYI(1, ("FindNext returned = %d", rc)); 3725 cFYI(1, ("FindNext returned = %d", rc));
@@ -3856,25 +3897,112 @@ GetInodeNumOut:
3856 return rc; 3897 return rc;
3857} 3898}
3858 3899
3900/* parses DFS refferal V3 structure
3901 * caller is responsible for freeing target_nodes
3902 * returns:
3903 * on success - 0
3904 * on failure - errno
3905 */
3906static int
3907parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
3908 unsigned int *num_of_nodes,
3909 struct dfs_info3_param **target_nodes,
3910 const struct nls_table *nls_codepage)
3911{
3912 int i, rc = 0;
3913 char *data_end;
3914 bool is_unicode;
3915 struct dfs_referral_level_3 *ref;
3916
3917 is_unicode = pSMBr->hdr.Flags2 & SMBFLG2_UNICODE;
3918 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
3919
3920 if (*num_of_nodes < 1) {
3921 cERROR(1, ("num_referrals: must be at least > 0,"
3922 "but we get num_referrals = %d\n", *num_of_nodes));
3923 rc = -EINVAL;
3924 goto parse_DFS_referrals_exit;
3925 }
3926
3927 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
3928 if (ref->VersionNumber != cpu_to_le16(3)) {
3929 cERROR(1, ("Referrals of V%d version are not supported,"
3930 "should be V3", le16_to_cpu(ref->VersionNumber)));
3931 rc = -EINVAL;
3932 goto parse_DFS_referrals_exit;
3933 }
3934
3935 /* get the upper boundary of the resp buffer */
3936 data_end = (char *)(&(pSMBr->PathConsumed)) +
3937 le16_to_cpu(pSMBr->t2.DataCount);
3938
3939 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n",
3940 *num_of_nodes,
3941 le16_to_cpu(pSMBr->DFSFlags)));
3942
3943 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
3944 *num_of_nodes, GFP_KERNEL);
3945 if (*target_nodes == NULL) {
3946 cERROR(1, ("Failed to allocate buffer for target_nodes\n"));
3947 rc = -ENOMEM;
3948 goto parse_DFS_referrals_exit;
3949 }
3950
3951 /* collect neccessary data from referrals */
3952 for (i = 0; i < *num_of_nodes; i++) {
3953 char *temp;
3954 int max_len;
3955 struct dfs_info3_param *node = (*target_nodes)+i;
3956
3957 node->flags = le16_to_cpu(pSMBr->DFSFlags);
3958 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
3959 node->server_type = le16_to_cpu(ref->ServerType);
3960 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
3961
3962 /* copy DfsPath */
3963 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
3964 max_len = data_end - temp;
3965 rc = cifs_strncpy_to_host(&(node->path_name), temp,
3966 max_len, is_unicode, nls_codepage);
3967 if (rc)
3968 goto parse_DFS_referrals_exit;
3969
3970 /* copy link target UNC */
3971 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
3972 max_len = data_end - temp;
3973 rc = cifs_strncpy_to_host(&(node->node_name), temp,
3974 max_len, is_unicode, nls_codepage);
3975 if (rc)
3976 goto parse_DFS_referrals_exit;
3977
3978 ref += le16_to_cpu(ref->Size);
3979 }
3980
3981parse_DFS_referrals_exit:
3982 if (rc) {
3983 free_dfs_info_array(*target_nodes, *num_of_nodes);
3984 *target_nodes = NULL;
3985 *num_of_nodes = 0;
3986 }
3987 return rc;
3988}
3989
3859int 3990int
3860CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, 3991CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3861 const unsigned char *searchName, 3992 const unsigned char *searchName,
3862 unsigned char **targetUNCs, 3993 struct dfs_info3_param **target_nodes,
3863 unsigned int *number_of_UNC_in_array, 3994 unsigned int *num_of_nodes,
3864 const struct nls_table *nls_codepage, int remap) 3995 const struct nls_table *nls_codepage, int remap)
3865{ 3996{
3866/* TRANS2_GET_DFS_REFERRAL */ 3997/* TRANS2_GET_DFS_REFERRAL */
3867 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL; 3998 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3868 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL; 3999 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3869 struct dfs_referral_level_3 *referrals = NULL;
3870 int rc = 0; 4000 int rc = 0;
3871 int bytes_returned; 4001 int bytes_returned;
3872 int name_len; 4002 int name_len;
3873 unsigned int i;
3874 char *temp;
3875 __u16 params, byte_count; 4003 __u16 params, byte_count;
3876 *number_of_UNC_in_array = 0; 4004 *num_of_nodes = 0;
3877 *targetUNCs = NULL; 4005 *target_nodes = NULL;
3878 4006
3879 cFYI(1, ("In GetDFSRefer the path %s", searchName)); 4007 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3880 if (ses == NULL) 4008 if (ses == NULL)
@@ -3921,7 +4049,8 @@ getDFSRetry:
3921 pSMB->DataCount = 0; 4049 pSMB->DataCount = 0;
3922 pSMB->DataOffset = 0; 4050 pSMB->DataOffset = 0;
3923 pSMB->MaxParameterCount = 0; 4051 pSMB->MaxParameterCount = 0;
3924 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ 4052 /* BB find exact max SMB PDU from sess structure BB */
4053 pSMB->MaxDataCount = cpu_to_le16(4000);
3925 pSMB->MaxSetupCount = 0; 4054 pSMB->MaxSetupCount = 0;
3926 pSMB->Reserved = 0; 4055 pSMB->Reserved = 0;
3927 pSMB->Flags = 0; 4056 pSMB->Flags = 0;
@@ -3943,103 +4072,26 @@ getDFSRetry:
3943 (struct smb_hdr *) pSMBr, &bytes_returned, 0); 4072 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3944 if (rc) { 4073 if (rc) {
3945 cFYI(1, ("Send error in GetDFSRefer = %d", rc)); 4074 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3946 } else { /* decode response */ 4075 goto GetDFSRefExit;
3947/* BB Add logic to parse referrals here */ 4076 }
3948 rc = validate_t2((struct smb_t2_rsp *)pSMBr); 4077 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3949 4078
3950 /* BB Also check if enough total bytes returned? */ 4079 /* BB Also check if enough total bytes returned? */
3951 if (rc || (pSMBr->ByteCount < 17)) 4080 if (rc || (pSMBr->ByteCount < 17)) {
3952 rc = -EIO; /* bad smb */ 4081 rc = -EIO; /* bad smb */
3953 else { 4082 goto GetDFSRefExit;
3954 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 4083 }
3955 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3956 4084
3957 cFYI(1, 4085 cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d",
3958 ("Decoding GetDFSRefer response BCC: %d Offset %d", 4086 pSMBr->ByteCount,
3959 pSMBr->ByteCount, data_offset)); 4087 le16_to_cpu(pSMBr->t2.DataOffset)));
3960 referrals =
3961 (struct dfs_referral_level_3 *)
3962 (8 /* sizeof start of data block */ +
3963 data_offset +
3964 (char *) &pSMBr->hdr.Protocol);
3965 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n"
3966 "for referral one refer size: 0x%x srv "
3967 "type: 0x%x refer flags: 0x%x ttl: 0x%x",
3968 le16_to_cpu(pSMBr->NumberOfReferrals),
3969 le16_to_cpu(pSMBr->DFSFlags),
3970 le16_to_cpu(referrals->ReferralSize),
3971 le16_to_cpu(referrals->ServerType),
3972 le16_to_cpu(referrals->ReferralFlags),
3973 le16_to_cpu(referrals->TimeToLive)));
3974 /* BB This field is actually two bytes in from start of
3975 data block so we could do safety check that DataBlock
3976 begins at address of pSMBr->NumberOfReferrals */
3977 *number_of_UNC_in_array =
3978 le16_to_cpu(pSMBr->NumberOfReferrals);
3979
3980 /* BB Fix below so can return more than one referral */
3981 if (*number_of_UNC_in_array > 1)
3982 *number_of_UNC_in_array = 1;
3983
3984 /* get the length of the strings describing refs */
3985 name_len = 0;
3986 for (i = 0; i < *number_of_UNC_in_array; i++) {
3987 /* make sure that DfsPathOffset not past end */
3988 __u16 offset =
3989 le16_to_cpu(referrals->DfsPathOffset);
3990 if (offset > data_count) {
3991 /* if invalid referral, stop here and do
3992 not try to copy any more */
3993 *number_of_UNC_in_array = i;
3994 break;
3995 }
3996 temp = ((char *)referrals) + offset;
3997 4088
3998 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { 4089 /* parse returned result into more usable form */
3999 name_len += UniStrnlen((wchar_t *)temp, 4090 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
4000 data_count); 4091 target_nodes, nls_codepage);
4001 } else {
4002 name_len += strnlen(temp, data_count);
4003 }
4004 referrals++;
4005 /* BB add check that referral pointer does
4006 not fall off end PDU */
4007 }
4008 /* BB add check for name_len bigger than bcc */
4009 *targetUNCs =
4010 kmalloc(name_len+1+(*number_of_UNC_in_array),
4011 GFP_KERNEL);
4012 if (*targetUNCs == NULL) {
4013 rc = -ENOMEM;
4014 goto GetDFSRefExit;
4015 }
4016 /* copy the ref strings */
4017 referrals = (struct dfs_referral_level_3 *)
4018 (8 /* sizeof data hdr */ + data_offset +
4019 (char *) &pSMBr->hdr.Protocol);
4020
4021 for (i = 0; i < *number_of_UNC_in_array; i++) {
4022 temp = ((char *)referrals) +
4023 le16_to_cpu(referrals->DfsPathOffset);
4024 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
4025 cifs_strfromUCS_le(*targetUNCs,
4026 (__le16 *) temp,
4027 name_len,
4028 nls_codepage);
4029 } else {
4030 strncpy(*targetUNCs, temp, name_len);
4031 }
4032 /* BB update target_uncs pointers */
4033 referrals++;
4034 }
4035 temp = *targetUNCs;
4036 temp[name_len] = 0;
4037 }
4038 4092
4039 }
4040GetDFSRefExit: 4093GetDFSRefExit:
4041 if (pSMB) 4094 cifs_buf_release(pSMB);
4042 cifs_buf_release(pSMB);
4043 4095
4044 if (rc == -EAGAIN) 4096 if (rc == -EAGAIN)
4045 goto getDFSRetry; 4097 goto getDFSRetry;
@@ -4229,7 +4281,8 @@ QFSAttributeRetry:
4229 params = 2; /* level */ 4281 params = 2; /* level */
4230 pSMB->TotalDataCount = 0; 4282 pSMB->TotalDataCount = 0;
4231 pSMB->MaxParameterCount = cpu_to_le16(2); 4283 pSMB->MaxParameterCount = cpu_to_le16(2);
4232 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ 4284 /* BB find exact max SMB PDU from sess structure BB */
4285 pSMB->MaxDataCount = cpu_to_le16(1000);
4233 pSMB->MaxSetupCount = 0; 4286 pSMB->MaxSetupCount = 0;
4234 pSMB->Reserved = 0; 4287 pSMB->Reserved = 0;
4235 pSMB->Flags = 0; 4288 pSMB->Flags = 0;
@@ -4298,7 +4351,8 @@ QFSDeviceRetry:
4298 params = 2; /* level */ 4351 params = 2; /* level */
4299 pSMB->TotalDataCount = 0; 4352 pSMB->TotalDataCount = 0;
4300 pSMB->MaxParameterCount = cpu_to_le16(2); 4353 pSMB->MaxParameterCount = cpu_to_le16(2);
4301 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ 4354 /* BB find exact max SMB PDU from sess structure BB */
4355 pSMB->MaxDataCount = cpu_to_le16(1000);
4302 pSMB->MaxSetupCount = 0; 4356 pSMB->MaxSetupCount = 0;
4303 pSMB->Reserved = 0; 4357 pSMB->Reserved = 0;
4304 pSMB->Flags = 0; 4358 pSMB->Flags = 0;
@@ -4369,7 +4423,8 @@ QFSUnixRetry:
4369 pSMB->DataCount = 0; 4423 pSMB->DataCount = 0;
4370 pSMB->DataOffset = 0; 4424 pSMB->DataOffset = 0;
4371 pSMB->MaxParameterCount = cpu_to_le16(2); 4425 pSMB->MaxParameterCount = cpu_to_le16(2);
4372 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */ 4426 /* BB find exact max SMB PDU from sess structure BB */
4427 pSMB->MaxDataCount = cpu_to_le16(100);
4373 pSMB->MaxSetupCount = 0; 4428 pSMB->MaxSetupCount = 0;
4374 pSMB->Reserved = 0; 4429 pSMB->Reserved = 0;
4375 pSMB->Flags = 0; 4430 pSMB->Flags = 0;
@@ -4444,7 +4499,8 @@ SETFSUnixRetry:
4444 offset = param_offset + params; 4499 offset = param_offset + params;
4445 4500
4446 pSMB->MaxParameterCount = cpu_to_le16(4); 4501 pSMB->MaxParameterCount = cpu_to_le16(4);
4447 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */ 4502 /* BB find exact max SMB PDU from sess structure BB */
4503 pSMB->MaxDataCount = cpu_to_le16(100);
4448 pSMB->SetupCount = 1; 4504 pSMB->SetupCount = 1;
4449 pSMB->Reserved3 = 0; 4505 pSMB->Reserved3 = 0;
4450 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION); 4506 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
@@ -4512,7 +4568,8 @@ QFSPosixRetry:
4512 pSMB->DataCount = 0; 4568 pSMB->DataCount = 0;
4513 pSMB->DataOffset = 0; 4569 pSMB->DataOffset = 0;
4514 pSMB->MaxParameterCount = cpu_to_le16(2); 4570 pSMB->MaxParameterCount = cpu_to_le16(2);
4515 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */ 4571 /* BB find exact max SMB PDU from sess structure BB */
4572 pSMB->MaxDataCount = cpu_to_le16(100);
4516 pSMB->MaxSetupCount = 0; 4573 pSMB->MaxSetupCount = 0;
4517 pSMB->Reserved = 0; 4574 pSMB->Reserved = 0;
4518 pSMB->Flags = 0; 4575 pSMB->Flags = 0;
@@ -4702,7 +4759,8 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4702 4759
4703 count = sizeof(struct file_end_of_file_info); 4760 count = sizeof(struct file_end_of_file_info);
4704 pSMB->MaxParameterCount = cpu_to_le16(2); 4761 pSMB->MaxParameterCount = cpu_to_le16(2);
4705 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */ 4762 /* BB find exact max SMB PDU from sess structure BB */
4763 pSMB->MaxDataCount = cpu_to_le16(1000);
4706 pSMB->SetupCount = 1; 4764 pSMB->SetupCount = 1;
4707 pSMB->Reserved3 = 0; 4765 pSMB->Reserved3 = 0;
4708 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); 4766 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
@@ -4789,7 +4847,8 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
4789 4847
4790 count = sizeof(FILE_BASIC_INFO); 4848 count = sizeof(FILE_BASIC_INFO);
4791 pSMB->MaxParameterCount = cpu_to_le16(2); 4849 pSMB->MaxParameterCount = cpu_to_le16(2);
4792 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */ 4850 /* BB find max SMB PDU from sess */
4851 pSMB->MaxDataCount = cpu_to_le16(1000);
4793 pSMB->SetupCount = 1; 4852 pSMB->SetupCount = 1;
4794 pSMB->Reserved3 = 0; 4853 pSMB->Reserved3 = 0;
4795 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); 4854 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
@@ -4856,7 +4915,8 @@ SetTimesRetry:
4856 params = 6 + name_len; 4915 params = 6 + name_len;
4857 count = sizeof(FILE_BASIC_INFO); 4916 count = sizeof(FILE_BASIC_INFO);
4858 pSMB->MaxParameterCount = cpu_to_le16(2); 4917 pSMB->MaxParameterCount = cpu_to_le16(2);
4859 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ 4918 /* BB find max SMB PDU from sess structure BB */
4919 pSMB->MaxDataCount = cpu_to_le16(1000);
4860 pSMB->MaxSetupCount = 0; 4920 pSMB->MaxSetupCount = 0;
4861 pSMB->Reserved = 0; 4921 pSMB->Reserved = 0;
4862 pSMB->Flags = 0; 4922 pSMB->Flags = 0;
@@ -4986,7 +5046,8 @@ setPermsRetry:
4986 params = 6 + name_len; 5046 params = 6 + name_len;
4987 count = sizeof(FILE_UNIX_BASIC_INFO); 5047 count = sizeof(FILE_UNIX_BASIC_INFO);
4988 pSMB->MaxParameterCount = cpu_to_le16(2); 5048 pSMB->MaxParameterCount = cpu_to_le16(2);
4989 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ 5049 /* BB find max SMB PDU from sess structure BB */
5050 pSMB->MaxDataCount = cpu_to_le16(1000);
4990 pSMB->MaxSetupCount = 0; 5051 pSMB->MaxSetupCount = 0;
4991 pSMB->Reserved = 0; 5052 pSMB->Reserved = 0;
4992 pSMB->Flags = 0; 5053 pSMB->Flags = 0;
@@ -5051,8 +5112,7 @@ setPermsRetry:
5051 if (rc) 5112 if (rc)
5052 cFYI(1, ("SetPathInfo (perms) returned %d", rc)); 5113 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
5053 5114
5054 if (pSMB) 5115 cifs_buf_release(pSMB);
5055 cifs_buf_release(pSMB);
5056 if (rc == -EAGAIN) 5116 if (rc == -EAGAIN)
5057 goto setPermsRetry; 5117 goto setPermsRetry;
5058 return rc; 5118 return rc;
@@ -5169,7 +5229,8 @@ QAllEAsRetry:
5169 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */; 5229 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
5170 pSMB->TotalDataCount = 0; 5230 pSMB->TotalDataCount = 0;
5171 pSMB->MaxParameterCount = cpu_to_le16(2); 5231 pSMB->MaxParameterCount = cpu_to_le16(2);
5172 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ 5232 /* BB find exact max SMB PDU from sess structure BB */
5233 pSMB->MaxDataCount = cpu_to_le16(4000);
5173 pSMB->MaxSetupCount = 0; 5234 pSMB->MaxSetupCount = 0;
5174 pSMB->Reserved = 0; 5235 pSMB->Reserved = 0;
5175 pSMB->Flags = 0; 5236 pSMB->Flags = 0;
@@ -5273,8 +5334,7 @@ QAllEAsRetry:
5273 } 5334 }
5274 } 5335 }
5275 } 5336 }
5276 if (pSMB) 5337 cifs_buf_release(pSMB);
5277 cifs_buf_release(pSMB);
5278 if (rc == -EAGAIN) 5338 if (rc == -EAGAIN)
5279 goto QAllEAsRetry; 5339 goto QAllEAsRetry;
5280 5340
@@ -5317,7 +5377,8 @@ QEARetry:
5317 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */; 5377 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
5318 pSMB->TotalDataCount = 0; 5378 pSMB->TotalDataCount = 0;
5319 pSMB->MaxParameterCount = cpu_to_le16(2); 5379 pSMB->MaxParameterCount = cpu_to_le16(2);
5320 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ 5380 /* BB find exact max SMB PDU from sess structure BB */
5381 pSMB->MaxDataCount = cpu_to_le16(4000);
5321 pSMB->MaxSetupCount = 0; 5382 pSMB->MaxSetupCount = 0;
5322 pSMB->Reserved = 0; 5383 pSMB->Reserved = 0;
5323 pSMB->Flags = 0; 5384 pSMB->Flags = 0;
@@ -5422,8 +5483,7 @@ QEARetry:
5422 } 5483 }
5423 } 5484 }
5424 } 5485 }
5425 if (pSMB) 5486 cifs_buf_release(pSMB);
5426 cifs_buf_release(pSMB);
5427 if (rc == -EAGAIN) 5487 if (rc == -EAGAIN)
5428 goto QEARetry; 5488 goto QEARetry;
5429 5489
@@ -5475,7 +5535,8 @@ SetEARetry:
5475 5535
5476 count = sizeof(*parm_data) + ea_value_len + name_len; 5536 count = sizeof(*parm_data) + ea_value_len + name_len;
5477 pSMB->MaxParameterCount = cpu_to_le16(2); 5537 pSMB->MaxParameterCount = cpu_to_le16(2);
5478 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */ 5538 /* BB find max SMB PDU from sess */
5539 pSMB->MaxDataCount = cpu_to_le16(1000);
5479 pSMB->MaxSetupCount = 0; 5540 pSMB->MaxSetupCount = 0;
5480 pSMB->Reserved = 0; 5541 pSMB->Reserved = 0;
5481 pSMB->Flags = 0; 5542 pSMB->Flags = 0;
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index f428bf3bf1a9..e8fa46c7cff2 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -60,7 +60,7 @@ struct smb_vol {
60 char *domainname; 60 char *domainname;
61 char *UNC; 61 char *UNC;
62 char *UNCip; 62 char *UNCip;
63 char *in6_addr; /* ipv6 address as human readable form of in6_addr */ 63 char *in6_addr; /* ipv6 address as human readable form of in6_addr */
64 char *iocharset; /* local code page for mapping to and from Unicode */ 64 char *iocharset; /* local code page for mapping to and from Unicode */
65 char source_rfc1001_name[16]; /* netbios name of client */ 65 char source_rfc1001_name[16]; /* netbios name of client */
66 char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */ 66 char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */
@@ -75,19 +75,21 @@ struct smb_vol {
75 bool setuids:1; 75 bool setuids:1;
76 bool override_uid:1; 76 bool override_uid:1;
77 bool override_gid:1; 77 bool override_gid:1;
78 bool dynperm:1;
78 bool noperm:1; 79 bool noperm:1;
79 bool no_psx_acl:1; /* set if posix acl support should be disabled */ 80 bool no_psx_acl:1; /* set if posix acl support should be disabled */
80 bool cifs_acl:1; 81 bool cifs_acl:1;
81 bool no_xattr:1; /* set if xattr (EA) support should be disabled*/ 82 bool no_xattr:1; /* set if xattr (EA) support should be disabled*/
82 bool server_ino:1; /* use inode numbers from server ie UniqueId */ 83 bool server_ino:1; /* use inode numbers from server ie UniqueId */
83 bool direct_io:1; 84 bool direct_io:1;
84 bool remap:1; /* set to remap seven reserved chars in filenames */ 85 bool remap:1; /* set to remap seven reserved chars in filenames */
85 bool posix_paths:1; /* unset to not ask for posix pathnames. */ 86 bool posix_paths:1; /* unset to not ask for posix pathnames. */
86 bool no_linux_ext:1; 87 bool no_linux_ext:1;
87 bool sfu_emul:1; 88 bool sfu_emul:1;
88 bool nullauth:1; /* attempt to authenticate with null user */ 89 bool nullauth:1; /* attempt to authenticate with null user */
89 unsigned nocase; /* request case insensitive filenames */ 90 bool nocase:1; /* request case insensitive filenames */
90 unsigned nobrl; /* disable sending byte range locks to srv */ 91 bool nobrl:1; /* disable sending byte range locks to srv */
92 bool seal:1; /* request transport encryption on share */
91 unsigned int rsize; 93 unsigned int rsize;
92 unsigned int wsize; 94 unsigned int wsize;
93 unsigned int sockopt; 95 unsigned int sockopt;
@@ -651,6 +653,7 @@ multi_t2_fnd:
651 spin_lock(&GlobalMid_Lock); 653 spin_lock(&GlobalMid_Lock);
652 server->tcpStatus = CifsExiting; 654 server->tcpStatus = CifsExiting;
653 spin_unlock(&GlobalMid_Lock); 655 spin_unlock(&GlobalMid_Lock);
656 wake_up_all(&server->response_q);
654 657
655 /* don't exit until kthread_stop is called */ 658 /* don't exit until kthread_stop is called */
656 set_current_state(TASK_UNINTERRUPTIBLE); 659 set_current_state(TASK_UNINTERRUPTIBLE);
@@ -1246,6 +1249,10 @@ cifs_parse_mount_options(char *options, const char *devname,
1246 vol->setuids = 1; 1249 vol->setuids = 1;
1247 } else if (strnicmp(data, "nosetuids", 9) == 0) { 1250 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1248 vol->setuids = 0; 1251 vol->setuids = 0;
1252 } else if (strnicmp(data, "dynperm", 7) == 0) {
1253 vol->dynperm = true;
1254 } else if (strnicmp(data, "nodynperm", 9) == 0) {
1255 vol->dynperm = false;
1249 } else if (strnicmp(data, "nohard", 6) == 0) { 1256 } else if (strnicmp(data, "nohard", 6) == 0) {
1250 vol->retry = 0; 1257 vol->retry = 0;
1251 } else if (strnicmp(data, "nosoft", 6) == 0) { 1258 } else if (strnicmp(data, "nosoft", 6) == 0) {
@@ -1268,8 +1275,12 @@ cifs_parse_mount_options(char *options, const char *devname,
1268 vol->no_psx_acl = 1; 1275 vol->no_psx_acl = 1;
1269 } else if (strnicmp(data, "sign", 4) == 0) { 1276 } else if (strnicmp(data, "sign", 4) == 0) {
1270 vol->secFlg |= CIFSSEC_MUST_SIGN; 1277 vol->secFlg |= CIFSSEC_MUST_SIGN;
1271/* } else if (strnicmp(data, "seal",4) == 0) { 1278 } else if (strnicmp(data, "seal", 4) == 0) {
1272 vol->secFlg |= CIFSSEC_MUST_SEAL; */ 1279 /* we do not do the following in secFlags because seal
1280 is a per tree connection (mount) not a per socket
1281 or per-smb connection option in the protocol */
1282 /* vol->secFlg |= CIFSSEC_MUST_SEAL; */
1283 vol->seal = 1;
1273 } else if (strnicmp(data, "direct", 6) == 0) { 1284 } else if (strnicmp(data, "direct", 6) == 0) {
1274 vol->direct_io = 1; 1285 vol->direct_io = 1;
1275 } else if (strnicmp(data, "forcedirectio", 13) == 0) { 1286 } else if (strnicmp(data, "forcedirectio", 13) == 0) {
@@ -1414,34 +1425,12 @@ find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
1414} 1425}
1415 1426
1416int 1427int
1417connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
1418 const char *old_path, const struct nls_table *nls_codepage,
1419 int remap)
1420{
1421 struct dfs_info3_param *referrals = NULL;
1422 unsigned int num_referrals;
1423 int rc = 0;
1424
1425 rc = get_dfs_path(xid, pSesInfo, old_path, nls_codepage,
1426 &num_referrals, &referrals, remap);
1427
1428 /* BB Add in code to: if valid refrl, if not ip address contact
1429 the helper that resolves tcp names, mount to it, try to
1430 tcon to it unmount it if fail */
1431
1432 kfree(referrals);
1433
1434 return rc;
1435}
1436
1437int
1438get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, 1428get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
1439 const struct nls_table *nls_codepage, unsigned int *pnum_referrals, 1429 const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
1440 struct dfs_info3_param **preferrals, int remap) 1430 struct dfs_info3_param **preferrals, int remap)
1441{ 1431{
1442 char *temp_unc; 1432 char *temp_unc;
1443 int rc = 0; 1433 int rc = 0;
1444 unsigned char *targetUNCs;
1445 1434
1446 *pnum_referrals = 0; 1435 *pnum_referrals = 0;
1447 *preferrals = NULL; 1436 *preferrals = NULL;
@@ -1464,7 +1453,7 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
1464 kfree(temp_unc); 1453 kfree(temp_unc);
1465 } 1454 }
1466 if (rc == 0) 1455 if (rc == 0)
1467 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, &targetUNCs, 1456 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
1468 pnum_referrals, nls_codepage, remap); 1457 pnum_referrals, nls_codepage, remap);
1469 /* BB map targetUNCs to dfs_info3 structures, here or 1458 /* BB map targetUNCs to dfs_info3 structures, here or
1470 in CIFSGetDFSRefer BB */ 1459 in CIFSGetDFSRefer BB */
@@ -1815,7 +1804,7 @@ convert_delimiter(char *path, char delim)
1815 if (path == NULL) 1804 if (path == NULL)
1816 return; 1805 return;
1817 1806
1818 if (delim == '/') 1807 if (delim == '/')
1819 old_delim = '\\'; 1808 old_delim = '\\';
1820 else 1809 else
1821 old_delim = '/'; 1810 old_delim = '/';
@@ -2125,11 +2114,17 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2125 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID; 2114 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
2126 if (volume_info.override_gid) 2115 if (volume_info.override_gid)
2127 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID; 2116 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
2117 if (volume_info.dynperm)
2118 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
2128 if (volume_info.direct_io) { 2119 if (volume_info.direct_io) {
2129 cFYI(1, ("mounting share using direct i/o")); 2120 cFYI(1, ("mounting share using direct i/o"));
2130 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; 2121 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
2131 } 2122 }
2132 2123
2124 if ((volume_info.cifs_acl) && (volume_info.dynperm))
2125 cERROR(1, ("mount option dynperm ignored if cifsacl "
2126 "mount option supported"));
2127
2133 tcon = 2128 tcon =
2134 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC, 2129 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
2135 volume_info.username); 2130 volume_info.username);
@@ -2141,6 +2136,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2141 for the retry flag is used */ 2136 for the retry flag is used */
2142 tcon->retry = volume_info.retry; 2137 tcon->retry = volume_info.retry;
2143 tcon->nocase = volume_info.nocase; 2138 tcon->nocase = volume_info.nocase;
2139 if (tcon->seal != volume_info.seal)
2140 cERROR(1, ("transport encryption setting "
2141 "conflicts with existing tid"));
2144 } else { 2142 } else {
2145 tcon = tconInfoAlloc(); 2143 tcon = tconInfoAlloc();
2146 if (tcon == NULL) 2144 if (tcon == NULL)
@@ -2154,10 +2152,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2154 if ((strchr(volume_info.UNC + 3, '\\') == NULL) 2152 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
2155 && (strchr(volume_info.UNC + 3, '/') == 2153 && (strchr(volume_info.UNC + 3, '/') ==
2156 NULL)) { 2154 NULL)) {
2157 rc = connect_to_dfs_path(xid, pSesInfo, 2155/* rc = connect_to_dfs_path(xid, pSesInfo,
2158 "", cifs_sb->local_nls, 2156 "", cifs_sb->local_nls,
2159 cifs_sb->mnt_cifs_flags & 2157 cifs_sb->mnt_cifs_flags &
2160 CIFS_MOUNT_MAP_SPECIAL_CHR); 2158 CIFS_MOUNT_MAP_SPECIAL_CHR);*/
2159 cFYI(1, ("DFS root not supported"));
2161 rc = -ENODEV; 2160 rc = -ENODEV;
2162 goto out; 2161 goto out;
2163 } else { 2162 } else {
@@ -2173,6 +2172,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2173 atomic_inc(&pSesInfo->inUse); 2172 atomic_inc(&pSesInfo->inUse);
2174 tcon->retry = volume_info.retry; 2173 tcon->retry = volume_info.retry;
2175 tcon->nocase = volume_info.nocase; 2174 tcon->nocase = volume_info.nocase;
2175 tcon->seal = volume_info.seal;
2176 } 2176 }
2177 } 2177 }
2178 } 2178 }
@@ -2314,9 +2314,10 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2314 user = ses->userName; 2314 user = ses->userName;
2315 domain = ses->domainName; 2315 domain = ses->domainName;
2316 smb_buffer = cifs_buf_get(); 2316 smb_buffer = cifs_buf_get();
2317 if (smb_buffer == NULL) { 2317
2318 if (smb_buffer == NULL)
2318 return -ENOMEM; 2319 return -ENOMEM;
2319 } 2320
2320 smb_buffer_response = smb_buffer; 2321 smb_buffer_response = smb_buffer;
2321 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer; 2322 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2322 2323
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index e4e0078a0526..fb69c1fa85c9 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -49,18 +49,25 @@ build_path_from_dentry(struct dentry *direntry)
49 struct dentry *temp; 49 struct dentry *temp;
50 int namelen; 50 int namelen;
51 int pplen; 51 int pplen;
52 int dfsplen;
52 char *full_path; 53 char *full_path;
53 char dirsep; 54 char dirsep;
55 struct cifs_sb_info *cifs_sb;
54 56
55 if (direntry == NULL) 57 if (direntry == NULL)
56 return NULL; /* not much we can do if dentry is freed and 58 return NULL; /* not much we can do if dentry is freed and
57 we need to reopen the file after it was closed implicitly 59 we need to reopen the file after it was closed implicitly
58 when the server crashed */ 60 when the server crashed */
59 61
60 dirsep = CIFS_DIR_SEP(CIFS_SB(direntry->d_sb)); 62 cifs_sb = CIFS_SB(direntry->d_sb);
61 pplen = CIFS_SB(direntry->d_sb)->prepathlen; 63 dirsep = CIFS_DIR_SEP(cifs_sb);
64 pplen = cifs_sb->prepathlen;
65 if (cifs_sb->tcon && (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS))
66 dfsplen = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE + 1);
67 else
68 dfsplen = 0;
62cifs_bp_rename_retry: 69cifs_bp_rename_retry:
63 namelen = pplen; 70 namelen = pplen + dfsplen;
64 for (temp = direntry; !IS_ROOT(temp);) { 71 for (temp = direntry; !IS_ROOT(temp);) {
65 namelen += (1 + temp->d_name.len); 72 namelen += (1 + temp->d_name.len);
66 temp = temp->d_parent; 73 temp = temp->d_parent;
@@ -91,7 +98,7 @@ cifs_bp_rename_retry:
91 return NULL; 98 return NULL;
92 } 99 }
93 } 100 }
94 if (namelen != pplen) { 101 if (namelen != pplen + dfsplen) {
95 cERROR(1, 102 cERROR(1,
96 ("did not end path lookup where expected namelen is %d", 103 ("did not end path lookup where expected namelen is %d",
97 namelen)); 104 namelen));
@@ -107,7 +114,18 @@ cifs_bp_rename_retry:
107 since the '\' is a valid posix character so we can not switch 114 since the '\' is a valid posix character so we can not switch
108 those safely to '/' if any are found in the middle of the prepath */ 115 those safely to '/' if any are found in the middle of the prepath */
109 /* BB test paths to Windows with '/' in the midst of prepath */ 116 /* BB test paths to Windows with '/' in the midst of prepath */
110 strncpy(full_path, CIFS_SB(direntry->d_sb)->prepath, pplen); 117
118 if (dfsplen) {
119 strncpy(full_path, cifs_sb->tcon->treeName, dfsplen);
120 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
121 int i;
122 for (i = 0; i < dfsplen; i++) {
123 if (full_path[i] == '\\')
124 full_path[i] = '/';
125 }
126 }
127 }
128 strncpy(full_path + dfsplen, CIFS_SB(direntry->d_sb)->prepath, pplen);
111 return full_path; 129 return full_path;
112} 130}
113 131
@@ -242,7 +260,9 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
242 buf, inode->i_sb, xid, 260 buf, inode->i_sb, xid,
243 &fileHandle); 261 &fileHandle);
244 if (newinode) { 262 if (newinode) {
245 newinode->i_mode = mode; 263 if (cifs_sb->mnt_cifs_flags &
264 CIFS_MOUNT_DYNPERM)
265 newinode->i_mode = mode;
246 if ((oplock & CIFS_CREATE_ACTION) && 266 if ((oplock & CIFS_CREATE_ACTION) &&
247 (cifs_sb->mnt_cifs_flags & 267 (cifs_sb->mnt_cifs_flags &
248 CIFS_MOUNT_SET_UID)) { 268 CIFS_MOUNT_SET_UID)) {
@@ -590,7 +610,7 @@ static int cifs_ci_compare(struct dentry *dentry, struct qstr *a,
590 * case take precedence. If a is not a negative dentry, this 610 * case take precedence. If a is not a negative dentry, this
591 * should have no side effects 611 * should have no side effects
592 */ 612 */
593 memcpy(a->name, b->name, a->len); 613 memcpy((void *)a->name, b->name, a->len);
594 return 0; 614 return 0;
595 } 615 }
596 return 1; 616 return 1;
diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c
index 939e256f8497..f730ef35499e 100644
--- a/fs/cifs/dns_resolve.c
+++ b/fs/cifs/dns_resolve.c
@@ -134,10 +134,6 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
134 rkey = request_key(&key_type_dns_resolver, name, ""); 134 rkey = request_key(&key_type_dns_resolver, name, "");
135 if (!IS_ERR(rkey)) { 135 if (!IS_ERR(rkey)) {
136 data = rkey->payload.data; 136 data = rkey->payload.data;
137 cFYI(1, ("%s: resolved: %s to %s", __func__,
138 rkey->description,
139 *ip_addr
140 ));
141 } else { 137 } else {
142 cERROR(1, ("%s: unable to resolve: %s", __func__, name)); 138 cERROR(1, ("%s: unable to resolve: %s", __func__, name));
143 goto out; 139 goto out;
@@ -150,6 +146,11 @@ skip_upcall:
150 if (*ip_addr) { 146 if (*ip_addr) {
151 memcpy(*ip_addr, data, len); 147 memcpy(*ip_addr, data, len);
152 (*ip_addr)[len] = '\0'; 148 (*ip_addr)[len] = '\0';
149 if (!IS_ERR(rkey))
150 cFYI(1, ("%s: resolved: %s to %s", __func__,
151 name,
152 *ip_addr
153 ));
153 rc = 0; 154 rc = 0;
154 } else { 155 } else {
155 rc = -ENOMEM; 156 rc = -ENOMEM;
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 31a0a33b9d95..0aac824371a5 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -75,7 +75,11 @@ static inline int cifs_convert_flags(unsigned int flags)
75 return (GENERIC_READ | GENERIC_WRITE); 75 return (GENERIC_READ | GENERIC_WRITE);
76 } 76 }
77 77
78 return 0x20197; 78 return (READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES |
79 FILE_WRITE_EA | FILE_APPEND_DATA | FILE_WRITE_DATA |
80 FILE_READ_DATA);
81
82
79} 83}
80 84
81static inline int cifs_get_disposition(unsigned int flags) 85static inline int cifs_get_disposition(unsigned int flags)
@@ -542,7 +546,6 @@ int cifs_close(struct inode *inode, struct file *file)
542 msleep(timeout); 546 msleep(timeout);
543 timeout *= 8; 547 timeout *= 8;
544 } 548 }
545 kfree(pSMBFile->search_resume_name);
546 kfree(file->private_data); 549 kfree(file->private_data);
547 file->private_data = NULL; 550 file->private_data = NULL;
548 } else 551 } else
@@ -601,12 +604,6 @@ int cifs_closedir(struct inode *inode, struct file *file)
601 else 604 else
602 cifs_buf_release(ptmp); 605 cifs_buf_release(ptmp);
603 } 606 }
604 ptmp = pCFileStruct->search_resume_name;
605 if (ptmp) {
606 cFYI(1, ("closedir free resume name"));
607 pCFileStruct->search_resume_name = NULL;
608 kfree(ptmp);
609 }
610 kfree(file->private_data); 607 kfree(file->private_data);
611 file->private_data = NULL; 608 file->private_data = NULL;
612 } 609 }
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index fcbdbb6ad7bf..2e904bd111c8 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -161,118 +161,115 @@ static void cifs_unix_info_to_inode(struct inode *inode,
161 spin_unlock(&inode->i_lock); 161 spin_unlock(&inode->i_lock);
162} 162}
163 163
164static const unsigned char *cifs_get_search_path(struct cifs_sb_info *cifs_sb,
165 const char *search_path)
166{
167 int tree_len;
168 int path_len;
169 int i;
170 char *tmp_path;
171 struct cifsTconInfo *pTcon = cifs_sb->tcon;
172
173 if (!(pTcon->Flags & SMB_SHARE_IS_IN_DFS))
174 return search_path;
175
176 /* use full path name for working with DFS */
177 tree_len = strnlen(pTcon->treeName, MAX_TREE_SIZE + 1);
178 path_len = strnlen(search_path, MAX_PATHCONF);
179 164
180 tmp_path = kmalloc(tree_len+path_len+1, GFP_KERNEL); 165/*
181 if (tmp_path == NULL) 166 * Needed to setup inode data for the directory which is the
182 return search_path; 167 * junction to the new submount (ie to setup the fake directory
168 * which represents a DFS referral)
169 */
170static void fill_fake_finddataunix(FILE_UNIX_BASIC_INFO *pfnd_dat,
171 struct super_block *sb)
172{
173 struct inode *pinode = NULL;
174
175 memset(pfnd_dat, 0, sizeof(FILE_UNIX_BASIC_INFO));
176
177/* __le64 pfnd_dat->EndOfFile = cpu_to_le64(0);
178 __le64 pfnd_dat->NumOfBytes = cpu_to_le64(0);
179 __u64 UniqueId = 0; */
180 pfnd_dat->LastStatusChange =
181 cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
182 pfnd_dat->LastAccessTime =
183 cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
184 pfnd_dat->LastModificationTime =
185 cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
186 pfnd_dat->Type = cpu_to_le32(UNIX_DIR);
187 pfnd_dat->Permissions = cpu_to_le64(S_IXUGO | S_IRWXU);
188 pfnd_dat->Nlinks = cpu_to_le64(2);
189 if (sb->s_root)
190 pinode = sb->s_root->d_inode;
191 if (pinode == NULL)
192 return;
183 193
184 strncpy(tmp_path, pTcon->treeName, tree_len); 194 /* fill in default values for the remaining based on root
185 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) 195 inode since we can not query the server for this inode info */
186 for (i = 0; i < tree_len; i++) { 196 pfnd_dat->DevMajor = cpu_to_le64(MAJOR(pinode->i_rdev));
187 if (tmp_path[i] == '\\') 197 pfnd_dat->DevMinor = cpu_to_le64(MINOR(pinode->i_rdev));
188 tmp_path[i] = '/'; 198 pfnd_dat->Uid = cpu_to_le64(pinode->i_uid);
189 } 199 pfnd_dat->Gid = cpu_to_le64(pinode->i_gid);
190 strncpy(tmp_path+tree_len, search_path, path_len);
191 tmp_path[tree_len+path_len] = 0;
192 return tmp_path;
193} 200}
194 201
195int cifs_get_inode_info_unix(struct inode **pinode, 202int cifs_get_inode_info_unix(struct inode **pinode,
196 const unsigned char *search_path, struct super_block *sb, int xid) 203 const unsigned char *full_path, struct super_block *sb, int xid)
197{ 204{
198 int rc = 0; 205 int rc = 0;
199 FILE_UNIX_BASIC_INFO findData; 206 FILE_UNIX_BASIC_INFO find_data;
200 struct cifsTconInfo *pTcon; 207 struct cifsTconInfo *pTcon;
201 struct inode *inode; 208 struct inode *inode;
202 struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 209 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
203 const unsigned char *full_path;
204 bool is_dfs_referral = false; 210 bool is_dfs_referral = false;
211 struct cifsInodeInfo *cifsInfo;
212 __u64 num_of_bytes;
213 __u64 end_of_file;
205 214
206 pTcon = cifs_sb->tcon; 215 pTcon = cifs_sb->tcon;
207 cFYI(1, ("Getting info on %s", search_path)); 216 cFYI(1, ("Getting info on %s", full_path));
208
209 full_path = cifs_get_search_path(cifs_sb, search_path);
210 217
211try_again_CIFSSMBUnixQPathInfo:
212 /* could have done a find first instead but this returns more info */ 218 /* could have done a find first instead but this returns more info */
213 rc = CIFSSMBUnixQPathInfo(xid, pTcon, full_path, &findData, 219 rc = CIFSSMBUnixQPathInfo(xid, pTcon, full_path, &find_data,
214 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 220 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
215 CIFS_MOUNT_MAP_SPECIAL_CHR); 221 CIFS_MOUNT_MAP_SPECIAL_CHR);
216/* dump_mem("\nUnixQPathInfo return data", &findData, 222 if (rc == -EREMOTE && !is_dfs_referral) {
217 sizeof(findData)); */ 223 is_dfs_referral = true;
218 if (rc) { 224 cFYI(DBG2, ("DFS ref"));
219 if (rc == -EREMOTE && !is_dfs_referral) { 225 /* for DFS, server does not give us real inode data */
220 is_dfs_referral = true; 226 fill_fake_finddataunix(&find_data, sb);
221 if (full_path != search_path) { 227 rc = 0;
222 kfree(full_path); 228 } else if (rc)
223 full_path = search_path;
224 }
225 goto try_again_CIFSSMBUnixQPathInfo;
226 }
227 goto cgiiu_exit; 229 goto cgiiu_exit;
228 } else {
229 struct cifsInodeInfo *cifsInfo;
230 __u64 num_of_bytes = le64_to_cpu(findData.NumOfBytes);
231 __u64 end_of_file = le64_to_cpu(findData.EndOfFile);
232 230
233 /* get new inode */ 231 num_of_bytes = le64_to_cpu(find_data.NumOfBytes);
234 if (*pinode == NULL) { 232 end_of_file = le64_to_cpu(find_data.EndOfFile);
235 *pinode = new_inode(sb);
236 if (*pinode == NULL) {
237 rc = -ENOMEM;
238 goto cgiiu_exit;
239 }
240 /* Is an i_ino of zero legal? */
241 /* Are there sanity checks we can use to ensure that
242 the server is really filling in that field? */
243 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
244 (*pinode)->i_ino =
245 (unsigned long)findData.UniqueId;
246 } /* note ino incremented to unique num in new_inode */
247 if (sb->s_flags & MS_NOATIME)
248 (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
249 233
250 insert_inode_hash(*pinode); 234 /* get new inode */
235 if (*pinode == NULL) {
236 *pinode = new_inode(sb);
237 if (*pinode == NULL) {
238 rc = -ENOMEM;
239 goto cgiiu_exit;
251 } 240 }
241 /* Is an i_ino of zero legal? */
242 /* note ino incremented to unique num in new_inode */
243 /* Are there sanity checks we can use to ensure that
244 the server is really filling in that field? */
245 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
246 (*pinode)->i_ino = (unsigned long)find_data.UniqueId;
252 247
253 inode = *pinode; 248 if (sb->s_flags & MS_NOATIME)
254 cifsInfo = CIFS_I(inode); 249 (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
255 250
256 cFYI(1, ("Old time %ld", cifsInfo->time)); 251 insert_inode_hash(*pinode);
257 cifsInfo->time = jiffies; 252 }
258 cFYI(1, ("New time %ld", cifsInfo->time));
259 /* this is ok to set on every inode revalidate */
260 atomic_set(&cifsInfo->inUse, 1);
261 253
262 cifs_unix_info_to_inode(inode, &findData, 0); 254 inode = *pinode;
255 cifsInfo = CIFS_I(inode);
263 256
257 cFYI(1, ("Old time %ld", cifsInfo->time));
258 cifsInfo->time = jiffies;
259 cFYI(1, ("New time %ld", cifsInfo->time));
260 /* this is ok to set on every inode revalidate */
261 atomic_set(&cifsInfo->inUse, 1);
264 262
265 if (num_of_bytes < end_of_file) 263 cifs_unix_info_to_inode(inode, &find_data, 0);
266 cFYI(1, ("allocation size less than end of file"));
267 cFYI(1, ("Size %ld and blocks %llu",
268 (unsigned long) inode->i_size,
269 (unsigned long long)inode->i_blocks));
270 264
271 cifs_set_ops(inode, is_dfs_referral); 265 if (num_of_bytes < end_of_file)
272 } 266 cFYI(1, ("allocation size less than end of file"));
267 cFYI(1, ("Size %ld and blocks %llu",
268 (unsigned long) inode->i_size,
269 (unsigned long long)inode->i_blocks));
270
271 cifs_set_ops(inode, is_dfs_referral);
273cgiiu_exit: 272cgiiu_exit:
274 if (full_path != search_path)
275 kfree(full_path);
276 return rc; 273 return rc;
277} 274}
278 275
@@ -379,21 +376,52 @@ static int get_sfu_mode(struct inode *inode,
379#endif 376#endif
380} 377}
381 378
379/*
380 * Needed to setup inode data for the directory which is the
381 * junction to the new submount (ie to setup the fake directory
382 * which represents a DFS referral)
383 */
384static void fill_fake_finddata(FILE_ALL_INFO *pfnd_dat,
385 struct super_block *sb)
386{
387 memset(pfnd_dat, 0, sizeof(FILE_ALL_INFO));
388
389/* __le64 pfnd_dat->AllocationSize = cpu_to_le64(0);
390 __le64 pfnd_dat->EndOfFile = cpu_to_le64(0);
391 __u8 pfnd_dat->DeletePending = 0;
392 __u8 pfnd_data->Directory = 0;
393 __le32 pfnd_dat->EASize = 0;
394 __u64 pfnd_dat->IndexNumber = 0;
395 __u64 pfnd_dat->IndexNumber1 = 0; */
396 pfnd_dat->CreationTime =
397 cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
398 pfnd_dat->LastAccessTime =
399 cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
400 pfnd_dat->LastWriteTime =
401 cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
402 pfnd_dat->ChangeTime =
403 cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
404 pfnd_dat->Attributes = cpu_to_le32(ATTR_DIRECTORY);
405 pfnd_dat->NumberOfLinks = cpu_to_le32(2);
406}
407
382int cifs_get_inode_info(struct inode **pinode, 408int cifs_get_inode_info(struct inode **pinode,
383 const unsigned char *search_path, FILE_ALL_INFO *pfindData, 409 const unsigned char *full_path, FILE_ALL_INFO *pfindData,
384 struct super_block *sb, int xid, const __u16 *pfid) 410 struct super_block *sb, int xid, const __u16 *pfid)
385{ 411{
386 int rc = 0; 412 int rc = 0;
413 __u32 attr;
414 struct cifsInodeInfo *cifsInfo;
387 struct cifsTconInfo *pTcon; 415 struct cifsTconInfo *pTcon;
388 struct inode *inode; 416 struct inode *inode;
389 struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 417 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
390 const unsigned char *full_path = NULL;
391 char *buf = NULL; 418 char *buf = NULL;
392 bool adjustTZ = false; 419 bool adjustTZ = false;
393 bool is_dfs_referral = false; 420 bool is_dfs_referral = false;
421 umode_t default_mode;
394 422
395 pTcon = cifs_sb->tcon; 423 pTcon = cifs_sb->tcon;
396 cFYI(1, ("Getting info on %s", search_path)); 424 cFYI(1, ("Getting info on %s", full_path));
397 425
398 if ((pfindData == NULL) && (*pinode != NULL)) { 426 if ((pfindData == NULL) && (*pinode != NULL)) {
399 if (CIFS_I(*pinode)->clientCanCacheRead) { 427 if (CIFS_I(*pinode)->clientCanCacheRead) {
@@ -409,9 +437,6 @@ int cifs_get_inode_info(struct inode **pinode,
409 return -ENOMEM; 437 return -ENOMEM;
410 pfindData = (FILE_ALL_INFO *)buf; 438 pfindData = (FILE_ALL_INFO *)buf;
411 439
412 full_path = cifs_get_search_path(cifs_sb, search_path);
413
414try_again_CIFSSMBQPathInfo:
415 /* could do find first instead but this returns more info */ 440 /* could do find first instead but this returns more info */
416 rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData, 441 rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData,
417 0 /* not legacy */, 442 0 /* not legacy */,
@@ -429,178 +454,163 @@ try_again_CIFSSMBQPathInfo:
429 } 454 }
430 } 455 }
431 /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */ 456 /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
432 if (rc) { 457 if (rc == -EREMOTE) {
433 if (rc == -EREMOTE && !is_dfs_referral) { 458 is_dfs_referral = true;
434 is_dfs_referral = true; 459 fill_fake_finddata(pfindData, sb);
435 if (full_path != search_path) { 460 rc = 0;
436 kfree(full_path); 461 } else if (rc)
437 full_path = search_path;
438 }
439 goto try_again_CIFSSMBQPathInfo;
440 }
441 goto cgii_exit; 462 goto cgii_exit;
442 } else {
443 struct cifsInodeInfo *cifsInfo;
444 __u32 attr = le32_to_cpu(pfindData->Attributes);
445
446 /* get new inode */
447 if (*pinode == NULL) {
448 *pinode = new_inode(sb);
449 if (*pinode == NULL) {
450 rc = -ENOMEM;
451 goto cgii_exit;
452 }
453 /* Is an i_ino of zero legal? Can we use that to check
454 if the server supports returning inode numbers? Are
455 there other sanity checks we can use to ensure that
456 the server is really filling in that field? */
457
458 /* We can not use the IndexNumber field by default from
459 Windows or Samba (in ALL_INFO buf) but we can request
460 it explicitly. It may not be unique presumably if
461 the server has multiple devices mounted under one
462 share */
463
464 /* There may be higher info levels that work but are
465 there Windows server or network appliances for which
466 IndexNumber field is not guaranteed unique? */
467 463
468 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { 464 attr = le32_to_cpu(pfindData->Attributes);
469 int rc1 = 0;
470 __u64 inode_num;
471 465
472 rc1 = CIFSGetSrvInodeNumber(xid, pTcon, 466 /* get new inode */
473 search_path, &inode_num, 467 if (*pinode == NULL) {
468 *pinode = new_inode(sb);
469 if (*pinode == NULL) {
470 rc = -ENOMEM;
471 goto cgii_exit;
472 }
473 /* Is an i_ino of zero legal? Can we use that to check
474 if the server supports returning inode numbers? Are
475 there other sanity checks we can use to ensure that
476 the server is really filling in that field? */
477
478 /* We can not use the IndexNumber field by default from
479 Windows or Samba (in ALL_INFO buf) but we can request
480 it explicitly. It may not be unique presumably if
481 the server has multiple devices mounted under one share */
482
483 /* There may be higher info levels that work but are
484 there Windows server or network appliances for which
485 IndexNumber field is not guaranteed unique? */
486
487 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
488 int rc1 = 0;
489 __u64 inode_num;
490
491 rc1 = CIFSGetSrvInodeNumber(xid, pTcon,
492 full_path, &inode_num,
474 cifs_sb->local_nls, 493 cifs_sb->local_nls,
475 cifs_sb->mnt_cifs_flags & 494 cifs_sb->mnt_cifs_flags &
476 CIFS_MOUNT_MAP_SPECIAL_CHR); 495 CIFS_MOUNT_MAP_SPECIAL_CHR);
477 if (rc1) { 496 if (rc1) {
478 cFYI(1, ("GetSrvInodeNum rc %d", rc1)); 497 cFYI(1, ("GetSrvInodeNum rc %d", rc1));
479 /* BB EOPNOSUPP disable SERVER_INUM? */ 498 /* BB EOPNOSUPP disable SERVER_INUM? */
480 } else /* do we need cast or hash to ino? */ 499 } else /* do we need cast or hash to ino? */
481 (*pinode)->i_ino = inode_num; 500 (*pinode)->i_ino = inode_num;
482 } /* else ino incremented to unique num in new_inode*/ 501 } /* else ino incremented to unique num in new_inode*/
483 if (sb->s_flags & MS_NOATIME) 502 if (sb->s_flags & MS_NOATIME)
484 (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME; 503 (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
485 insert_inode_hash(*pinode); 504 insert_inode_hash(*pinode);
486 } 505 }
487 inode = *pinode; 506 inode = *pinode;
488 cifsInfo = CIFS_I(inode); 507 cifsInfo = CIFS_I(inode);
489 cifsInfo->cifsAttrs = attr; 508 cifsInfo->cifsAttrs = attr;
490 cFYI(1, ("Old time %ld", cifsInfo->time)); 509 cFYI(1, ("Old time %ld", cifsInfo->time));
491 cifsInfo->time = jiffies; 510 cifsInfo->time = jiffies;
492 cFYI(1, ("New time %ld", cifsInfo->time)); 511 cFYI(1, ("New time %ld", cifsInfo->time));
493 512
494 /* blksize needs to be multiple of two. So safer to default to 513 /* blksize needs to be multiple of two. So safer to default to
495 blksize and blkbits set in superblock so 2**blkbits and blksize 514 blksize and blkbits set in superblock so 2**blkbits and blksize
496 will match rather than setting to: 515 will match rather than setting to:
497 (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/ 516 (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
498 517
499 /* Linux can not store file creation time so ignore it */ 518 /* Linux can not store file creation time so ignore it */
500 if (pfindData->LastAccessTime) 519 if (pfindData->LastAccessTime)
501 inode->i_atime = cifs_NTtimeToUnix 520 inode->i_atime = cifs_NTtimeToUnix
502 (le64_to_cpu(pfindData->LastAccessTime)); 521 (le64_to_cpu(pfindData->LastAccessTime));
503 else /* do not need to use current_fs_time - time not stored */ 522 else /* do not need to use current_fs_time - time not stored */
504 inode->i_atime = CURRENT_TIME; 523 inode->i_atime = CURRENT_TIME;
505 inode->i_mtime = 524 inode->i_mtime =
506 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); 525 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
507 inode->i_ctime = 526 inode->i_ctime =
508 cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); 527 cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
509 cFYI(0, ("Attributes came in as 0x%x", attr)); 528 cFYI(DBG2, ("Attributes came in as 0x%x", attr));
510 if (adjustTZ && (pTcon->ses) && (pTcon->ses->server)) { 529 if (adjustTZ && (pTcon->ses) && (pTcon->ses->server)) {
511 inode->i_ctime.tv_sec += pTcon->ses->server->timeAdj; 530 inode->i_ctime.tv_sec += pTcon->ses->server->timeAdj;
512 inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj; 531 inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj;
513 } 532 }
514 533
515 /* set default mode. will override for dirs below */ 534 /* get default inode mode */
516 if (atomic_read(&cifsInfo->inUse) == 0) 535 if (attr & ATTR_DIRECTORY)
517 /* new inode, can safely set these fields */ 536 default_mode = cifs_sb->mnt_dir_mode;
518 inode->i_mode = cifs_sb->mnt_file_mode; 537 else
519 else /* since we set the inode type below we need to mask off 538 default_mode = cifs_sb->mnt_file_mode;
520 to avoid strange results if type changes and both 539
521 get orred in */ 540 /* set permission bits */
541 if (atomic_read(&cifsInfo->inUse) == 0 ||
542 (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
543 inode->i_mode = default_mode;
544 else {
545 /* just reenable write bits if !ATTR_READONLY */
546 if ((inode->i_mode & S_IWUGO) == 0 &&
547 (attr & ATTR_READONLY) == 0)
548 inode->i_mode |= (S_IWUGO & default_mode);
522 inode->i_mode &= ~S_IFMT; 549 inode->i_mode &= ~S_IFMT;
523/* if (attr & ATTR_REPARSE) */ 550 }
524 /* We no longer handle these as symlinks because we could not 551 /* clear write bits if ATTR_READONLY is set */
525 follow them due to the absolute path with drive letter */ 552 if (attr & ATTR_READONLY)
526 if (attr & ATTR_DIRECTORY) { 553 inode->i_mode &= ~S_IWUGO;
527 /* override default perms since we do not do byte range locking 554
528 on dirs */ 555 /* set inode type */
529 inode->i_mode = cifs_sb->mnt_dir_mode; 556 if ((attr & ATTR_SYSTEM) &&
530 inode->i_mode |= S_IFDIR; 557 (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) {
531 } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && 558 /* no need to fix endianness on 0 */
532 (cifsInfo->cifsAttrs & ATTR_SYSTEM) && 559 if (pfindData->EndOfFile == 0)
533 /* No need to le64 convert size of zero */
534 (pfindData->EndOfFile == 0)) {
535 inode->i_mode = cifs_sb->mnt_file_mode;
536 inode->i_mode |= S_IFIFO; 560 inode->i_mode |= S_IFIFO;
537/* BB Finish for SFU style symlinks and devices */ 561 else if (decode_sfu_inode(inode,
538 } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && 562 le64_to_cpu(pfindData->EndOfFile),
539 (cifsInfo->cifsAttrs & ATTR_SYSTEM)) { 563 full_path, cifs_sb, xid))
540 if (decode_sfu_inode(inode, 564 cFYI(1, ("unknown SFU file type\n"));
541 le64_to_cpu(pfindData->EndOfFile), 565 } else {
542 search_path, 566 if (attr & ATTR_DIRECTORY)
543 cifs_sb, xid)) 567 inode->i_mode |= S_IFDIR;
544 cFYI(1, ("Unrecognized sfu inode type")); 568 else
545
546 cFYI(1, ("sfu mode 0%o", inode->i_mode));
547 } else {
548 inode->i_mode |= S_IFREG; 569 inode->i_mode |= S_IFREG;
549 /* treat the dos attribute of read-only as read-only 570 }
550 mode e.g. 555 */
551 if (cifsInfo->cifsAttrs & ATTR_READONLY)
552 inode->i_mode &= ~(S_IWUGO);
553 else if ((inode->i_mode & S_IWUGO) == 0)
554 /* the ATTR_READONLY flag may have been */
555 /* changed on server -- set any w bits */
556 /* allowed by mnt_file_mode */
557 inode->i_mode |= (S_IWUGO &
558 cifs_sb->mnt_file_mode);
559 /* BB add code here -
560 validate if device or weird share or device type? */
561 }
562 571
563 spin_lock(&inode->i_lock); 572 spin_lock(&inode->i_lock);
564 if (is_size_safe_to_change(cifsInfo, 573 if (is_size_safe_to_change(cifsInfo,
565 le64_to_cpu(pfindData->EndOfFile))) { 574 le64_to_cpu(pfindData->EndOfFile))) {
566 /* can not safely shrink the file size here if the 575 /* can not safely shrink the file size here if the
567 client is writing to it due to potential races */ 576 client is writing to it due to potential races */
568 i_size_write(inode, le64_to_cpu(pfindData->EndOfFile)); 577 i_size_write(inode, le64_to_cpu(pfindData->EndOfFile));
569 578
570 /* 512 bytes (2**9) is the fake blocksize that must be 579 /* 512 bytes (2**9) is the fake blocksize that must be
571 used for this calculation */ 580 used for this calculation */
572 inode->i_blocks = (512 - 1 + le64_to_cpu( 581 inode->i_blocks = (512 - 1 + le64_to_cpu(
573 pfindData->AllocationSize)) >> 9; 582 pfindData->AllocationSize)) >> 9;
574 } 583 }
575 spin_unlock(&inode->i_lock); 584 spin_unlock(&inode->i_lock);
576 585
577 inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks); 586 inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks);
578 587
579 /* BB fill in uid and gid here? with help from winbind? 588 /* BB fill in uid and gid here? with help from winbind?
580 or retrieve from NTFS stream extended attribute */ 589 or retrieve from NTFS stream extended attribute */
581#ifdef CONFIG_CIFS_EXPERIMENTAL 590#ifdef CONFIG_CIFS_EXPERIMENTAL
582 /* fill in 0777 bits from ACL */ 591 /* fill in 0777 bits from ACL */
583 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { 592 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
584 cFYI(1, ("Getting mode bits from ACL")); 593 cFYI(1, ("Getting mode bits from ACL"));
585 acl_to_uid_mode(inode, search_path, pfid); 594 acl_to_uid_mode(inode, full_path, pfid);
586 } 595 }
587#endif 596#endif
588 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { 597 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
589 /* fill in remaining high mode bits e.g. SUID, VTX */ 598 /* fill in remaining high mode bits e.g. SUID, VTX */
590 get_sfu_mode(inode, search_path, cifs_sb, xid); 599 get_sfu_mode(inode, full_path, cifs_sb, xid);
591 } else if (atomic_read(&cifsInfo->inUse) == 0) { 600 } else if (atomic_read(&cifsInfo->inUse) == 0) {
592 inode->i_uid = cifs_sb->mnt_uid; 601 inode->i_uid = cifs_sb->mnt_uid;
593 inode->i_gid = cifs_sb->mnt_gid; 602 inode->i_gid = cifs_sb->mnt_gid;
594 /* set so we do not keep refreshing these fields with 603 /* set so we do not keep refreshing these fields with
595 bad data after user has changed them in memory */ 604 bad data after user has changed them in memory */
596 atomic_set(&cifsInfo->inUse, 1); 605 atomic_set(&cifsInfo->inUse, 1);
597 }
598
599 cifs_set_ops(inode, is_dfs_referral);
600 } 606 }
607
608 cifs_set_ops(inode, is_dfs_referral);
609
610
611
612
601cgii_exit: 613cgii_exit:
602 if (full_path != search_path)
603 kfree(full_path);
604 kfree(buf); 614 kfree(buf);
605 return rc; 615 return rc;
606} 616}
@@ -1005,8 +1015,11 @@ mkdir_get_info:
1005 CIFS_MOUNT_MAP_SPECIAL_CHR); 1015 CIFS_MOUNT_MAP_SPECIAL_CHR);
1006 } 1016 }
1007 if (direntry->d_inode) { 1017 if (direntry->d_inode) {
1008 direntry->d_inode->i_mode = mode; 1018 if (cifs_sb->mnt_cifs_flags &
1009 direntry->d_inode->i_mode |= S_IFDIR; 1019 CIFS_MOUNT_DYNPERM)
1020 direntry->d_inode->i_mode =
1021 (mode | S_IFDIR);
1022
1010 if (cifs_sb->mnt_cifs_flags & 1023 if (cifs_sb->mnt_cifs_flags &
1011 CIFS_MOUNT_SET_UID) { 1024 CIFS_MOUNT_SET_UID) {
1012 direntry->d_inode->i_uid = 1025 direntry->d_inode->i_uid =
@@ -1502,8 +1515,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1502 int oplock = 0; 1515 int oplock = 0;
1503 1516
1504 rc = SMBLegacyOpen(xid, pTcon, full_path, 1517 rc = SMBLegacyOpen(xid, pTcon, full_path,
1505 FILE_OPEN, 1518 FILE_OPEN, GENERIC_WRITE,
1506 SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
1507 CREATE_NOT_DIR, &netfid, &oplock, 1519 CREATE_NOT_DIR, &netfid, &oplock,
1508 NULL, cifs_sb->local_nls, 1520 NULL, cifs_sb->local_nls,
1509 cifs_sb->mnt_cifs_flags & 1521 cifs_sb->mnt_cifs_flags &
@@ -1534,13 +1546,26 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1534 } else 1546 } else
1535 goto cifs_setattr_exit; 1547 goto cifs_setattr_exit;
1536 } 1548 }
1537 if (attrs->ia_valid & ATTR_UID) { 1549
1538 cFYI(1, ("UID changed to %d", attrs->ia_uid)); 1550 /*
1539 uid = attrs->ia_uid; 1551 * Without unix extensions we can't send ownership changes to the
1540 } 1552 * server, so silently ignore them. This is consistent with how
1541 if (attrs->ia_valid & ATTR_GID) { 1553 * local DOS/Windows filesystems behave (VFAT, NTFS, etc). With
1542 cFYI(1, ("GID changed to %d", attrs->ia_gid)); 1554 * CIFSACL support + proper Windows to Unix idmapping, we may be
1543 gid = attrs->ia_gid; 1555 * able to support this in the future.
1556 */
1557 if (!pTcon->unix_ext &&
1558 !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) {
1559 attrs->ia_valid &= ~(ATTR_UID | ATTR_GID);
1560 } else {
1561 if (attrs->ia_valid & ATTR_UID) {
1562 cFYI(1, ("UID changed to %d", attrs->ia_uid));
1563 uid = attrs->ia_uid;
1564 }
1565 if (attrs->ia_valid & ATTR_GID) {
1566 cFYI(1, ("GID changed to %d", attrs->ia_gid));
1567 gid = attrs->ia_gid;
1568 }
1544 } 1569 }
1545 1570
1546 time_buf.Attributes = 0; 1571 time_buf.Attributes = 0;
@@ -1550,7 +1575,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1550 attrs->ia_valid &= ~ATTR_MODE; 1575 attrs->ia_valid &= ~ATTR_MODE;
1551 1576
1552 if (attrs->ia_valid & ATTR_MODE) { 1577 if (attrs->ia_valid & ATTR_MODE) {
1553 cFYI(1, ("Mode changed to 0x%x", attrs->ia_mode)); 1578 cFYI(1, ("Mode changed to 0%o", attrs->ia_mode));
1554 mode = attrs->ia_mode; 1579 mode = attrs->ia_mode;
1555 } 1580 }
1556 1581
@@ -1565,18 +1590,18 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1565#ifdef CONFIG_CIFS_EXPERIMENTAL 1590#ifdef CONFIG_CIFS_EXPERIMENTAL
1566 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) 1591 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
1567 rc = mode_to_acl(inode, full_path, mode); 1592 rc = mode_to_acl(inode, full_path, mode);
1568 else if ((mode & S_IWUGO) == 0) { 1593 else
1569#else
1570 if ((mode & S_IWUGO) == 0) {
1571#endif 1594#endif
1572 /* not writeable */ 1595 if (((mode & S_IWUGO) == 0) &&
1573 if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0) { 1596 (cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
1574 set_dosattr = true; 1597 set_dosattr = true;
1575 time_buf.Attributes = 1598 time_buf.Attributes = cpu_to_le32(cifsInode->cifsAttrs |
1576 cpu_to_le32(cifsInode->cifsAttrs | 1599 ATTR_READONLY);
1577 ATTR_READONLY); 1600 /* fix up mode if we're not using dynperm */
1578 } 1601 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
1579 } else if (cifsInode->cifsAttrs & ATTR_READONLY) { 1602 attrs->ia_mode = inode->i_mode & ~S_IWUGO;
1603 } else if ((mode & S_IWUGO) &&
1604 (cifsInode->cifsAttrs & ATTR_READONLY)) {
1580 /* If file is readonly on server, we would 1605 /* If file is readonly on server, we would
1581 not be able to write to it - so if any write 1606 not be able to write to it - so if any write
1582 bit is enabled for user or group or other we 1607 bit is enabled for user or group or other we
@@ -1587,6 +1612,20 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1587 /* Windows ignores set to zero */ 1612 /* Windows ignores set to zero */
1588 if (time_buf.Attributes == 0) 1613 if (time_buf.Attributes == 0)
1589 time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL); 1614 time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL);
1615
1616 /* reset local inode permissions to normal */
1617 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
1618 attrs->ia_mode &= ~(S_IALLUGO);
1619 if (S_ISDIR(inode->i_mode))
1620 attrs->ia_mode |=
1621 cifs_sb->mnt_dir_mode;
1622 else
1623 attrs->ia_mode |=
1624 cifs_sb->mnt_file_mode;
1625 }
1626 } else if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
1627 /* ignore mode change - ATTR_READONLY hasn't changed */
1628 attrs->ia_valid &= ~ATTR_MODE;
1590 } 1629 }
1591 } 1630 }
1592 1631
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c
index 5c792df13d62..0088a5b52564 100644
--- a/fs/cifs/ioctl.c
+++ b/fs/cifs/ioctl.c
@@ -30,9 +30,9 @@
30 30
31#define CIFS_IOC_CHECKUMOUNT _IO(0xCF, 2) 31#define CIFS_IOC_CHECKUMOUNT _IO(0xCF, 2)
32 32
33int cifs_ioctl(struct inode *inode, struct file *filep, 33long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
34 unsigned int command, unsigned long arg)
35{ 34{
35 struct inode *inode = filep->f_dentry->d_inode;
36 int rc = -ENOTTY; /* strange error - but the precedent */ 36 int rc = -ENOTTY; /* strange error - but the precedent */
37 int xid; 37 int xid;
38 struct cifs_sb_info *cifs_sb; 38 struct cifs_sb_info *cifs_sb;
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index 1c2c3ce5020b..63f644000ce5 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -234,7 +234,6 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
234 struct cifs_sb_info *cifs_sb; 234 struct cifs_sb_info *cifs_sb;
235 struct cifsTconInfo *pTcon; 235 struct cifsTconInfo *pTcon;
236 char *full_path = NULL; 236 char *full_path = NULL;
237 char *tmp_path = NULL;
238 char *tmpbuffer; 237 char *tmpbuffer;
239 int len; 238 int len;
240 __u16 fid; 239 __u16 fid;
@@ -295,45 +294,9 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
295 cFYI(1, ("Error closing junction point " 294 cFYI(1, ("Error closing junction point "
296 "(open for ioctl)")); 295 "(open for ioctl)"));
297 } 296 }
298 /* BB unwind this long, nested function, or remove BB */ 297 /* If it is a DFS junction earlier we would have gotten
299 if (rc == -EIO) { 298 PATH_NOT_COVERED returned from server so we do
300 /* Query if DFS Junction */ 299 not need to request the DFS info here */
301 unsigned int num_referrals = 0;
302 struct dfs_info3_param *refs = NULL;
303 tmp_path =
304 kmalloc(MAX_TREE_SIZE + MAX_PATHCONF + 1,
305 GFP_KERNEL);
306 if (tmp_path) {
307 strncpy(tmp_path, pTcon->treeName,
308 MAX_TREE_SIZE);
309 strncat(tmp_path, full_path,
310 MAX_PATHCONF);
311 rc = get_dfs_path(xid, pTcon->ses,
312 tmp_path,
313 cifs_sb->local_nls,
314 &num_referrals, &refs,
315 cifs_sb->mnt_cifs_flags &
316 CIFS_MOUNT_MAP_SPECIAL_CHR);
317 cFYI(1, ("Get DFS for %s rc = %d ",
318 tmp_path, rc));
319 if ((num_referrals == 0) && (rc == 0))
320 rc = -EACCES;
321 else {
322 cFYI(1, ("num referral: %d",
323 num_referrals));
324 if (refs && refs->path_name) {
325 strncpy(tmpbuffer,
326 refs->path_name,
327 len-1);
328 }
329 }
330 kfree(refs);
331 kfree(tmp_path);
332}
333 /* BB add code like else decode referrals
334 then memcpy to tmpbuffer and free referrals
335 string array BB */
336 }
337 } 300 }
338 } 301 }
339 /* BB Anything else to do to handle recursive links? */ 302 /* BB Anything else to do to handle recursive links? */
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 1d69b8014e0b..4b17f8fe3157 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -519,8 +519,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
519 pnotify = (struct file_notify_information *) 519 pnotify = (struct file_notify_information *)
520 ((char *)&pSMBr->hdr.Protocol + data_offset); 520 ((char *)&pSMBr->hdr.Protocol + data_offset);
521 cFYI(1, ("dnotify on %s Action: 0x%x", 521 cFYI(1, ("dnotify on %s Action: 0x%x",
522 pnotify->FileName, 522 pnotify->FileName, pnotify->Action));
523 pnotify->Action)); /* BB removeme BB */
524 /* cifs_dump_mem("Rcvd notify Data: ",buf, 523 /* cifs_dump_mem("Rcvd notify Data: ",buf,
525 sizeof(struct smb_hdr)+60); */ 524 sizeof(struct smb_hdr)+60); */
526 return true; 525 return true;
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
index 00f4cff400b3..8703d68f5b20 100644
--- a/fs/cifs/netmisc.c
+++ b/fs/cifs/netmisc.c
@@ -141,11 +141,11 @@ cifs_inet_pton(const int address_family, const char *cp, void *dst)
141 int ret = 0; 141 int ret = 0;
142 142
143 /* calculate length by finding first slash or NULL */ 143 /* calculate length by finding first slash or NULL */
144 if (address_family == AF_INET) { 144 if (address_family == AF_INET)
145 ret = in4_pton(cp, -1 /* len */, dst, '\\', NULL); 145 ret = in4_pton(cp, -1 /* len */, dst, '\\', NULL);
146 } else if (address_family == AF_INET6) { 146 else if (address_family == AF_INET6)
147 ret = in6_pton(cp, -1 /* len */, dst , '\\', NULL); 147 ret = in6_pton(cp, -1 /* len */, dst , '\\', NULL);
148 } 148
149 cFYI(DBG2, ("address conversion returned %d for %s", ret, cp)); 149 cFYI(DBG2, ("address conversion returned %d for %s", ret, cp));
150 if (ret > 0) 150 if (ret > 0)
151 ret = 1; 151 ret = 1;
diff --git a/fs/cifs/ntlmssp.h b/fs/cifs/ntlmssp.h
index 7170a9b70f1e..c377d8065d99 100644
--- a/fs/cifs/ntlmssp.h
+++ b/fs/cifs/ntlmssp.h
@@ -64,7 +64,7 @@ typedef struct _SECURITY_BUFFER {
64} __attribute__((packed)) SECURITY_BUFFER; 64} __attribute__((packed)) SECURITY_BUFFER;
65 65
66typedef struct _NEGOTIATE_MESSAGE { 66typedef struct _NEGOTIATE_MESSAGE {
67 __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; 67 __u8 Signature[sizeof(NTLMSSP_SIGNATURE)];
68 __le32 MessageType; /* 1 */ 68 __le32 MessageType; /* 1 */
69 __le32 NegotiateFlags; 69 __le32 NegotiateFlags;
70 SECURITY_BUFFER DomainName; /* RFC 1001 style and ASCII */ 70 SECURITY_BUFFER DomainName; /* RFC 1001 style and ASCII */
@@ -74,7 +74,7 @@ typedef struct _NEGOTIATE_MESSAGE {
74} __attribute__((packed)) NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE; 74} __attribute__((packed)) NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE;
75 75
76typedef struct _CHALLENGE_MESSAGE { 76typedef struct _CHALLENGE_MESSAGE {
77 __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; 77 __u8 Signature[sizeof(NTLMSSP_SIGNATURE)];
78 __le32 MessageType; /* 2 */ 78 __le32 MessageType; /* 2 */
79 SECURITY_BUFFER TargetName; 79 SECURITY_BUFFER TargetName;
80 __le32 NegotiateFlags; 80 __le32 NegotiateFlags;
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 34ec32100c72..83f306954883 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -132,6 +132,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
132 __u32 attr; 132 __u32 attr;
133 __u64 allocation_size; 133 __u64 allocation_size;
134 __u64 end_of_file; 134 __u64 end_of_file;
135 umode_t default_mode;
135 136
136 /* save mtime and size */ 137 /* save mtime and size */
137 local_mtime = tmp_inode->i_mtime; 138 local_mtime = tmp_inode->i_mtime;
@@ -187,48 +188,54 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
187 if (atomic_read(&cifsInfo->inUse) == 0) { 188 if (atomic_read(&cifsInfo->inUse) == 0) {
188 tmp_inode->i_uid = cifs_sb->mnt_uid; 189 tmp_inode->i_uid = cifs_sb->mnt_uid;
189 tmp_inode->i_gid = cifs_sb->mnt_gid; 190 tmp_inode->i_gid = cifs_sb->mnt_gid;
190 /* set default mode. will override for dirs below */ 191 }
191 tmp_inode->i_mode = cifs_sb->mnt_file_mode; 192
192 } else { 193 if (attr & ATTR_DIRECTORY)
193 /* mask off the type bits since it gets set 194 default_mode = cifs_sb->mnt_dir_mode;
194 below and we do not want to get two type 195 else
195 bits set */ 196 default_mode = cifs_sb->mnt_file_mode;
197
198 /* set initial permissions */
199 if ((atomic_read(&cifsInfo->inUse) == 0) ||
200 (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
201 tmp_inode->i_mode = default_mode;
202 else {
203 /* just reenable write bits if !ATTR_READONLY */
204 if ((tmp_inode->i_mode & S_IWUGO) == 0 &&
205 (attr & ATTR_READONLY) == 0)
206 tmp_inode->i_mode |= (S_IWUGO & default_mode);
207
196 tmp_inode->i_mode &= ~S_IFMT; 208 tmp_inode->i_mode &= ~S_IFMT;
197 } 209 }
198 210
199 if (attr & ATTR_DIRECTORY) { 211 /* clear write bits if ATTR_READONLY is set */
200 *pobject_type = DT_DIR; 212 if (attr & ATTR_READONLY)
201 /* override default perms since we do not lock dirs */ 213 tmp_inode->i_mode &= ~S_IWUGO;
202 if (atomic_read(&cifsInfo->inUse) == 0) 214
203 tmp_inode->i_mode = cifs_sb->mnt_dir_mode; 215 /* set inode type */
204 tmp_inode->i_mode |= S_IFDIR; 216 if ((attr & ATTR_SYSTEM) &&
205 } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && 217 (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) {
206 (attr & ATTR_SYSTEM)) {
207 if (end_of_file == 0) { 218 if (end_of_file == 0) {
208 *pobject_type = DT_FIFO;
209 tmp_inode->i_mode |= S_IFIFO; 219 tmp_inode->i_mode |= S_IFIFO;
220 *pobject_type = DT_FIFO;
210 } else { 221 } else {
211 /* rather than get the type here, we mark the 222 /*
212 inode as needing revalidate and get the real type 223 * trying to get the type can be slow, so just call
213 (blk vs chr vs. symlink) later ie in lookup */ 224 * this a regular file for now, and mark for reval
214 *pobject_type = DT_REG; 225 */
215 tmp_inode->i_mode |= S_IFREG; 226 tmp_inode->i_mode |= S_IFREG;
227 *pobject_type = DT_REG;
216 cifsInfo->time = 0; 228 cifsInfo->time = 0;
217 } 229 }
218/* we no longer mark these because we could not follow them */
219/* } else if (attr & ATTR_REPARSE) {
220 *pobject_type = DT_LNK;
221 tmp_inode->i_mode |= S_IFLNK; */
222 } else { 230 } else {
223 *pobject_type = DT_REG; 231 if (attr & ATTR_DIRECTORY) {
224 tmp_inode->i_mode |= S_IFREG; 232 tmp_inode->i_mode |= S_IFDIR;
225 if (attr & ATTR_READONLY) 233 *pobject_type = DT_DIR;
226 tmp_inode->i_mode &= ~(S_IWUGO); 234 } else {
227 else if ((tmp_inode->i_mode & S_IWUGO) == 0) 235 tmp_inode->i_mode |= S_IFREG;
228 /* the ATTR_READONLY flag may have been changed on */ 236 *pobject_type = DT_REG;
229 /* server -- set any w bits allowed by mnt_file_mode */ 237 }
230 tmp_inode->i_mode |= (S_IWUGO & cifs_sb->mnt_file_mode); 238 }
231 } /* could add code here - to validate if device or weird share type? */
232 239
233 /* can not fill in nlink here as in qpathinfo version and Unx search */ 240 /* can not fill in nlink here as in qpathinfo version and Unx search */
234 if (atomic_read(&cifsInfo->inUse) == 0) 241 if (atomic_read(&cifsInfo->inUse) == 0)
@@ -670,10 +677,11 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
670 (index_to_find < first_entry_in_buffer)) { 677 (index_to_find < first_entry_in_buffer)) {
671 /* close and restart search */ 678 /* close and restart search */
672 cFYI(1, ("search backing up - close and restart search")); 679 cFYI(1, ("search backing up - close and restart search"));
673 cifsFile->invalidHandle = true; 680 if (!cifsFile->srch_inf.endOfSearch &&
674 CIFSFindClose(xid, pTcon, cifsFile->netfid); 681 !cifsFile->invalidHandle) {
675 kfree(cifsFile->search_resume_name); 682 cifsFile->invalidHandle = true;
676 cifsFile->search_resume_name = NULL; 683 CIFSFindClose(xid, pTcon, cifsFile->netfid);
684 }
677 if (cifsFile->srch_inf.ntwrk_buf_start) { 685 if (cifsFile->srch_inf.ntwrk_buf_start) {
678 cFYI(1, ("freeing SMB ff cache buf on search rewind")); 686 cFYI(1, ("freeing SMB ff cache buf on search rewind"));
679 if (cifsFile->srch_inf.smallBuf) 687 if (cifsFile->srch_inf.smallBuf)
@@ -1040,9 +1048,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
1040 } /* else { 1048 } /* else {
1041 cifsFile->invalidHandle = true; 1049 cifsFile->invalidHandle = true;
1042 CIFSFindClose(xid, pTcon, cifsFile->netfid); 1050 CIFSFindClose(xid, pTcon, cifsFile->netfid);
1043 } 1051 } */
1044 kfree(cifsFile->search_resume_name);
1045 cifsFile->search_resume_name = NULL; */
1046 1052
1047 rc = find_cifs_entry(xid, pTcon, file, 1053 rc = find_cifs_entry(xid, pTcon, file,
1048 &current_entry, &num_to_fill); 1054 &current_entry, &num_to_fill);