diff options
| -rw-r--r-- | fs/cifs/AUTHORS | 1 | ||||
| -rw-r--r-- | fs/cifs/CHANGES | 5 | ||||
| -rw-r--r-- | fs/cifs/README | 5 | ||||
| -rw-r--r-- | fs/cifs/TODO | 15 | ||||
| -rw-r--r-- | fs/cifs/cifs_dfs_ref.c | 49 | ||||
| -rw-r--r-- | fs/cifs/cifs_fs_sb.h | 1 | ||||
| -rw-r--r-- | fs/cifs/cifsfs.c | 44 | ||||
| -rw-r--r-- | fs/cifs/cifsfs.h | 3 | ||||
| -rw-r--r-- | fs/cifs/cifsglob.h | 1 | ||||
| -rw-r--r-- | fs/cifs/cifspdu.h | 25 | ||||
| -rw-r--r-- | fs/cifs/cifsproto.h | 13 | ||||
| -rw-r--r-- | fs/cifs/cifssmb.c | 315 | ||||
| -rw-r--r-- | fs/cifs/connect.c | 68 | ||||
| -rw-r--r-- | fs/cifs/dir.c | 30 | ||||
| -rw-r--r-- | fs/cifs/dns_resolve.c | 9 | ||||
| -rw-r--r-- | fs/cifs/file.c | 6 | ||||
| -rw-r--r-- | fs/cifs/inode.c | 503 | ||||
| -rw-r--r-- | fs/cifs/ioctl.c | 4 | ||||
| -rw-r--r-- | fs/cifs/link.c | 43 | ||||
| -rw-r--r-- | fs/cifs/netmisc.c | 6 | ||||
| -rw-r--r-- | fs/cifs/ntlmssp.h | 4 | ||||
| -rw-r--r-- | fs/cifs/readdir.c | 7 |
22 files changed, 612 insertions, 545 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 | |||
| 36 | Kazeon team for various fixes especially for 2.4 version. | 36 | Kazeon team for various fixes especially for 2.4 version. |
| 37 | Asser Ferno (Change Notify support) | 37 | Asser Ferno (Change Notify support) |
| 38 | Shaggy (Dave Kleikamp) for inumerable small fs suggestions and some good cleanup | 38 | Shaggy (Dave Kleikamp) for inumerable small fs suggestions and some good cleanup |
| 39 | Igor Mammedov (DFS support) | ||
| 39 | 40 | ||
| 40 | Test case and Bug Report contributors | 41 | Test case and Bug Report contributors |
| 41 | ------------------------------------- | 42 | ------------------------------------- |
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 8355e918fddf..28e3d5c5fcac 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES | |||
| @@ -1,5 +1,7 @@ | |||
| 1 | Version 1.53 | 1 | Version 1.53 |
| 2 | ------------ | 2 | ------------ |
| 3 | DFS support added (Microsoft Distributed File System client support needed | ||
| 4 | for referrals which enable a hierarchical name space among servers). | ||
| 3 | 5 | ||
| 4 | Version 1.52 | 6 | Version 1.52 |
| 5 | ------------ | 7 | ------------ |
| @@ -12,7 +14,8 @@ Add ability to modify cifs acls for handling chmod (when mounted with | |||
| 12 | cifsacl flag). Fix prefixpath path separator so we can handle mounts | 14 | cifsacl flag). Fix prefixpath path separator so we can handle mounts |
| 13 | with prefixpaths longer than one directory (one path component) when | 15 | with prefixpaths longer than one directory (one path component) when |
| 14 | mounted to Windows servers. Fix slow file open when cifsacl | 16 | mounted to Windows servers. Fix slow file open when cifsacl |
| 15 | enabled. | 17 | enabled. Fix memory leak in FindNext when the SMB call returns -EBADF. |
| 18 | |||
| 16 | 19 | ||
| 17 | Version 1.51 | 20 | Version 1.51 |
| 18 | ------------ | 21 | ------------ |
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 @@ | |||
| 1 | Version 1.52 January 3, 2008 | 1 | Version 1.53 May 20, 2008 |
| 2 | 2 | ||
| 3 | A Partial List of Missing Features | 3 | A Partial List of Missing Features |
| 4 | ================================== | 4 | ================================== |
| @@ -20,20 +20,21 @@ d) Cleanup now unneeded SessSetup code in | |||
| 20 | fs/cifs/connect.c and add back in NTLMSSP code if any servers | 20 | fs/cifs/connect.c and add back in NTLMSSP code if any servers |
| 21 | need it | 21 | need it |
| 22 | 22 | ||
| 23 | e) ms-dfs and ms-dfs host name resolution cleanup | 23 | e) fix NTLMv2 signing when two mounts with different users to same |
| 24 | |||
| 25 | f) fix NTLMv2 signing when two mounts with different users to same | ||
| 26 | server. | 24 | server. |
| 27 | 25 | ||
| 28 | g) Directory entry caching relies on a 1 second timer, rather than | 26 | f) Directory entry caching relies on a 1 second timer, rather than |
| 29 | using FindNotify or equivalent. - (started) | 27 | using FindNotify or equivalent. - (started) |
| 30 | 28 | ||
| 31 | h) quota support (needs minor kernel change since quota calls | 29 | g) quota support (needs minor kernel change since quota calls |
| 32 | to make it to network filesystems or deviceless filesystems) | 30 | to make it to network filesystems or deviceless filesystems) |
| 33 | 31 | ||
| 34 | i) investigate sync behavior (including syncpage) and check | 32 | h) investigate sync behavior (including syncpage) and check |
| 35 | for proper behavior of intr/nointr | 33 | for proper behavior of intr/nointr |
| 36 | 34 | ||
| 35 | i) improve support for very old servers (OS/2 and Win9x for example) | ||
| 36 | Including support for changing the time remotely (utimes command). | ||
| 37 | |||
| 37 | j) hook lower into the sockets api (as NFS/SunRPC does) to avoid the | 38 | j) hook lower into the sockets api (as NFS/SunRPC does) to avoid the |
| 38 | extra copy in/out of the socket buffers in some cases. | 39 | extra copy in/out of the socket buffers in some cases. |
| 39 | 40 | ||
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 | ||
| 222 | static 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 | |||
| 269 | static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd, | 222 | static 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 | ||
| 34 | struct cifs_sb_info { | 35 | struct cifs_sb_info { |
| 35 | struct cifsTconInfo *tcon; /* primary mount */ | 36 | struct cifsTconInfo *tcon; /* primary mount */ |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 427a7c695896..5df93fd6303f 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 |
| @@ -353,9 +353,41 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m) | |||
| 353 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) || | 353 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) || |
| 354 | !(cifs_sb->tcon->unix_ext)) | 354 | !(cifs_sb->tcon->unix_ext)) |
| 355 | seq_printf(s, ",gid=%d", cifs_sb->mnt_gid); | 355 | seq_printf(s, ",gid=%d", cifs_sb->mnt_gid); |
| 356 | if (!cifs_sb->tcon->unix_ext) { | ||
| 357 | seq_printf(s, ",file_mode=0%o,dir_mode=0%o", | ||
| 358 | cifs_sb->mnt_file_mode, | ||
| 359 | cifs_sb->mnt_dir_mode); | ||
| 360 | } | ||
| 361 | if (cifs_sb->tcon->seal) | ||
| 362 | seq_printf(s, ",seal"); | ||
| 363 | if (cifs_sb->tcon->nocase) | ||
| 364 | seq_printf(s, ",nocase"); | ||
| 365 | if (cifs_sb->tcon->retry) | ||
| 366 | seq_printf(s, ",hard"); | ||
| 356 | } | 367 | } |
| 357 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) | 368 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) |
| 358 | seq_printf(s, ",posixpaths"); | 369 | seq_printf(s, ",posixpaths"); |
| 370 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) | ||
| 371 | seq_printf(s, ",setuids"); | ||
| 372 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) | ||
| 373 | seq_printf(s, ",serverino"); | ||
| 374 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) | ||
| 375 | seq_printf(s, ",directio"); | ||
| 376 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) | ||
| 377 | seq_printf(s, ",nouser_xattr"); | ||
| 378 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR) | ||
| 379 | seq_printf(s, ",mapchars"); | ||
| 380 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) | ||
| 381 | seq_printf(s, ",sfu"); | ||
| 382 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | ||
| 383 | seq_printf(s, ",nobrl"); | ||
| 384 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) | ||
| 385 | seq_printf(s, ",cifsacl"); | ||
| 386 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) | ||
| 387 | seq_printf(s, ",dynperm"); | ||
| 388 | if (m->mnt_sb->s_flags & MS_POSIXACL) | ||
| 389 | seq_printf(s, ",acl"); | ||
| 390 | |||
| 359 | seq_printf(s, ",rsize=%d", cifs_sb->rsize); | 391 | seq_printf(s, ",rsize=%d", cifs_sb->rsize); |
| 360 | seq_printf(s, ",wsize=%d", cifs_sb->wsize); | 392 | seq_printf(s, ",wsize=%d", cifs_sb->wsize); |
| 361 | } | 393 | } |
| @@ -657,7 +689,7 @@ const struct file_operations cifs_file_ops = { | |||
| 657 | .splice_read = generic_file_splice_read, | 689 | .splice_read = generic_file_splice_read, |
| 658 | .llseek = cifs_llseek, | 690 | .llseek = cifs_llseek, |
| 659 | #ifdef CONFIG_CIFS_POSIX | 691 | #ifdef CONFIG_CIFS_POSIX |
| 660 | .ioctl = cifs_ioctl, | 692 | .unlocked_ioctl = cifs_ioctl, |
| 661 | #endif /* CONFIG_CIFS_POSIX */ | 693 | #endif /* CONFIG_CIFS_POSIX */ |
| 662 | 694 | ||
| 663 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 695 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
| @@ -677,7 +709,7 @@ const struct file_operations cifs_file_direct_ops = { | |||
| 677 | .flush = cifs_flush, | 709 | .flush = cifs_flush, |
| 678 | .splice_read = generic_file_splice_read, | 710 | .splice_read = generic_file_splice_read, |
| 679 | #ifdef CONFIG_CIFS_POSIX | 711 | #ifdef CONFIG_CIFS_POSIX |
| 680 | .ioctl = cifs_ioctl, | 712 | .unlocked_ioctl = cifs_ioctl, |
| 681 | #endif /* CONFIG_CIFS_POSIX */ | 713 | #endif /* CONFIG_CIFS_POSIX */ |
| 682 | .llseek = cifs_llseek, | 714 | .llseek = cifs_llseek, |
| 683 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 715 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
| @@ -697,7 +729,7 @@ const struct file_operations cifs_file_nobrl_ops = { | |||
| 697 | .splice_read = generic_file_splice_read, | 729 | .splice_read = generic_file_splice_read, |
| 698 | .llseek = cifs_llseek, | 730 | .llseek = cifs_llseek, |
| 699 | #ifdef CONFIG_CIFS_POSIX | 731 | #ifdef CONFIG_CIFS_POSIX |
| 700 | .ioctl = cifs_ioctl, | 732 | .unlocked_ioctl = cifs_ioctl, |
| 701 | #endif /* CONFIG_CIFS_POSIX */ | 733 | #endif /* CONFIG_CIFS_POSIX */ |
| 702 | 734 | ||
| 703 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 735 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
| @@ -716,7 +748,7 @@ const struct file_operations cifs_file_direct_nobrl_ops = { | |||
| 716 | .flush = cifs_flush, | 748 | .flush = cifs_flush, |
| 717 | .splice_read = generic_file_splice_read, | 749 | .splice_read = generic_file_splice_read, |
| 718 | #ifdef CONFIG_CIFS_POSIX | 750 | #ifdef CONFIG_CIFS_POSIX |
| 719 | .ioctl = cifs_ioctl, | 751 | .unlocked_ioctl = cifs_ioctl, |
| 720 | #endif /* CONFIG_CIFS_POSIX */ | 752 | #endif /* CONFIG_CIFS_POSIX */ |
| 721 | .llseek = cifs_llseek, | 753 | .llseek = cifs_llseek, |
| 722 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 754 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
| @@ -731,7 +763,7 @@ const struct file_operations cifs_dir_ops = { | |||
| 731 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 763 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
| 732 | .dir_notify = cifs_dir_notify, | 764 | .dir_notify = cifs_dir_notify, |
| 733 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ | 765 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ |
| 734 | .ioctl = cifs_ioctl, | 766 | .unlocked_ioctl = cifs_ioctl, |
| 735 | }; | 767 | }; |
| 736 | 768 | ||
| 737 | static void | 769 | static 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); |
| 96 | extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); | 96 | extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); |
| 97 | extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); | 97 | extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); |
| 98 | extern int cifs_ioctl(struct inode *inode, struct file *filep, | 98 | extern 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 |
| 102 | extern const struct export_operations cifs_export_ops; | 101 | extern const struct export_operations cifs_export_ops; |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index b7d9f698e63e..08914053242b 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)? */ |
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index c43bf4b7a556..65d58b4e6a61 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h | |||
| @@ -1904,19 +1904,26 @@ typedef struct smb_com_transaction2_get_dfs_refer_req { | |||
| 1904 | char RequestFileName[1]; | 1904 | char RequestFileName[1]; |
| 1905 | } __attribute__((packed)) TRANSACTION2_GET_DFS_REFER_REQ; | 1905 | } __attribute__((packed)) TRANSACTION2_GET_DFS_REFER_REQ; |
| 1906 | 1906 | ||
| 1907 | #define DFS_VERSION cpu_to_le16(0x0003) | ||
| 1908 | |||
| 1909 | /* DFS server target type */ | ||
| 1910 | #define DFS_TYPE_LINK 0x0000 /* also for sysvol targets */ | ||
| 1911 | #define DFS_TYPE_ROOT 0x0001 | ||
| 1912 | |||
| 1913 | /* Referral Entry Flags */ | ||
| 1914 | #define DFS_NAME_LIST_REF 0x0200 | ||
| 1915 | |||
| 1907 | typedef struct dfs_referral_level_3 { | 1916 | typedef struct dfs_referral_level_3 { |
| 1908 | __le16 VersionNumber; | 1917 | __le16 VersionNumber; |
| 1909 | __le16 ReferralSize; | 1918 | __le16 Size; |
| 1910 | __le16 ServerType; /* 0x0001 = CIFS server */ | 1919 | __le16 ServerType; /* 0x0001 = root targets; 0x0000 = link targets */ |
| 1911 | __le16 ReferralFlags; /* or proximity - not clear which since it is | 1920 | __le16 ReferralEntryFlags; /* 0x0200 bit set only for domain |
| 1912 | always set to zero - SNIA spec says 0x01 | 1921 | or DC referral responce */ |
| 1913 | means strip off PathConsumed chars before | 1922 | __le32 TimeToLive; |
| 1914 | submitting RequestFileName to remote node */ | ||
| 1915 | __le16 TimeToLive; | ||
| 1916 | __le16 Proximity; | ||
| 1917 | __le16 DfsPathOffset; | 1923 | __le16 DfsPathOffset; |
| 1918 | __le16 DfsAlternatePathOffset; | 1924 | __le16 DfsAlternatePathOffset; |
| 1919 | __le16 NetworkAddressOffset; | 1925 | __le16 NetworkAddressOffset; /* offset of the link target */ |
| 1926 | __le16 ServiceSiteGuid; | ||
| 1920 | } __attribute__((packed)) REFERRAL3; | 1927 | } __attribute__((packed)) REFERRAL3; |
| 1921 | 1928 | ||
| 1922 | typedef struct smb_com_transaction_get_dfs_refer_rsp { | 1929 | typedef 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 | ||
| 94 | extern int cifs_get_inode_info(struct inode **pinode, | 94 | extern 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); |
| 98 | extern int cifs_get_inode_info_unix(struct inode **pinode, | 98 | extern 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 | ||
| 131 | extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, | 131 | extern 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); |
| 136 | extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon, | 136 | extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon, |
| @@ -141,18 +141,15 @@ extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon, | |||
| 141 | extern int CIFSSMBUnixQPathInfo(const int xid, | 141 | extern 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 | ||
| 147 | extern int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, | 147 | extern 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 | ||
| 153 | extern int connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, | ||
| 154 | const char *old_path, | ||
| 155 | const struct nls_table *nls_codepage, int remap); | ||
| 156 | extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, | 153 | extern 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..7b9938445b07 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 | */ | ||
| 90 | static int | ||
| 91 | cifs_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 | |||
| 113 | cifs_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 | ||
| 1203 | static int | ||
| 1204 | access_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 | |||
| 1169 | int | 1217 | int |
| 1170 | SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon, | 1218 | SMBLegacyOpen(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. */ |
| @@ -1767,7 +1809,7 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, | |||
| 1767 | cFYI(1, ("Posix Lock")); | 1809 | cFYI(1, ("Posix Lock")); |
| 1768 | 1810 | ||
| 1769 | if (pLockData == NULL) | 1811 | if (pLockData == NULL) |
| 1770 | return EINVAL; | 1812 | return -EINVAL; |
| 1771 | 1813 | ||
| 1772 | rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB); | 1814 | rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB); |
| 1773 | 1815 | ||
| @@ -1944,7 +1986,7 @@ renameRetry: | |||
| 1944 | /* protocol requires ASCII signature byte on Unicode string */ | 1986 | /* protocol requires ASCII signature byte on Unicode string */ |
| 1945 | pSMB->OldFileName[name_len + 1] = 0x00; | 1987 | pSMB->OldFileName[name_len + 1] = 0x00; |
| 1946 | name_len2 = | 1988 | name_len2 = |
| 1947 | cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2], | 1989 | cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], |
| 1948 | toName, PATH_MAX, nls_codepage, remap); | 1990 | toName, PATH_MAX, nls_codepage, remap); |
| 1949 | name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; | 1991 | name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; |
| 1950 | name_len2 *= 2; /* convert to bytes */ | 1992 | name_len2 *= 2; /* convert to bytes */ |
| @@ -2925,7 +2967,8 @@ setAclRetry: | |||
| 2925 | } | 2967 | } |
| 2926 | params = 6 + name_len; | 2968 | params = 6 + name_len; |
| 2927 | pSMB->MaxParameterCount = cpu_to_le16(2); | 2969 | pSMB->MaxParameterCount = cpu_to_le16(2); |
| 2928 | pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */ | 2970 | /* BB find max SMB size from sess */ |
| 2971 | pSMB->MaxDataCount = cpu_to_le16(1000); | ||
| 2929 | pSMB->MaxSetupCount = 0; | 2972 | pSMB->MaxSetupCount = 0; |
| 2930 | pSMB->Reserved = 0; | 2973 | pSMB->Reserved = 0; |
| 2931 | pSMB->Flags = 0; | 2974 | pSMB->Flags = 0; |
| @@ -3322,7 +3365,8 @@ QPathInfoRetry: | |||
| 3322 | params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */; | 3365 | params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */; |
| 3323 | pSMB->TotalDataCount = 0; | 3366 | pSMB->TotalDataCount = 0; |
| 3324 | pSMB->MaxParameterCount = cpu_to_le16(2); | 3367 | pSMB->MaxParameterCount = cpu_to_le16(2); |
| 3325 | pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ | 3368 | /* BB find exact max SMB PDU from sess structure BB */ |
| 3369 | pSMB->MaxDataCount = cpu_to_le16(4000); | ||
| 3326 | pSMB->MaxSetupCount = 0; | 3370 | pSMB->MaxSetupCount = 0; |
| 3327 | pSMB->Reserved = 0; | 3371 | pSMB->Reserved = 0; |
| 3328 | pSMB->Flags = 0; | 3372 | pSMB->Flags = 0; |
| @@ -3388,7 +3432,7 @@ QPathInfoRetry: | |||
| 3388 | int | 3432 | int |
| 3389 | CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon, | 3433 | CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon, |
| 3390 | const unsigned char *searchName, | 3434 | const unsigned char *searchName, |
| 3391 | FILE_UNIX_BASIC_INFO * pFindData, | 3435 | FILE_UNIX_BASIC_INFO *pFindData, |
| 3392 | const struct nls_table *nls_codepage, int remap) | 3436 | const struct nls_table *nls_codepage, int remap) |
| 3393 | { | 3437 | { |
| 3394 | /* SMB_QUERY_FILE_UNIX_BASIC */ | 3438 | /* SMB_QUERY_FILE_UNIX_BASIC */ |
| @@ -3679,6 +3723,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, | |||
| 3679 | if (rc) { | 3723 | if (rc) { |
| 3680 | if (rc == -EBADF) { | 3724 | if (rc == -EBADF) { |
| 3681 | psrch_inf->endOfSearch = true; | 3725 | psrch_inf->endOfSearch = true; |
| 3726 | cifs_buf_release(pSMB); | ||
| 3682 | rc = 0; /* search probably was closed at end of search*/ | 3727 | rc = 0; /* search probably was closed at end of search*/ |
| 3683 | } else | 3728 | } else |
| 3684 | cFYI(1, ("FindNext returned = %d", rc)); | 3729 | cFYI(1, ("FindNext returned = %d", rc)); |
| @@ -3856,25 +3901,112 @@ GetInodeNumOut: | |||
| 3856 | return rc; | 3901 | return rc; |
| 3857 | } | 3902 | } |
| 3858 | 3903 | ||
| 3904 | /* parses DFS refferal V3 structure | ||
| 3905 | * caller is responsible for freeing target_nodes | ||
| 3906 | * returns: | ||
| 3907 | * on success - 0 | ||
| 3908 | * on failure - errno | ||
| 3909 | */ | ||
| 3910 | static int | ||
| 3911 | parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, | ||
| 3912 | unsigned int *num_of_nodes, | ||
| 3913 | struct dfs_info3_param **target_nodes, | ||
| 3914 | const struct nls_table *nls_codepage) | ||
| 3915 | { | ||
| 3916 | int i, rc = 0; | ||
| 3917 | char *data_end; | ||
| 3918 | bool is_unicode; | ||
| 3919 | struct dfs_referral_level_3 *ref; | ||
| 3920 | |||
| 3921 | is_unicode = pSMBr->hdr.Flags2 & SMBFLG2_UNICODE; | ||
| 3922 | *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals); | ||
| 3923 | |||
| 3924 | if (*num_of_nodes < 1) { | ||
| 3925 | cERROR(1, ("num_referrals: must be at least > 0," | ||
| 3926 | "but we get num_referrals = %d\n", *num_of_nodes)); | ||
| 3927 | rc = -EINVAL; | ||
| 3928 | goto parse_DFS_referrals_exit; | ||
| 3929 | } | ||
| 3930 | |||
| 3931 | ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals); | ||
| 3932 | if (ref->VersionNumber != 3) { | ||
| 3933 | cERROR(1, ("Referrals of V%d version are not supported," | ||
| 3934 | "should be V3", ref->VersionNumber)); | ||
| 3935 | rc = -EINVAL; | ||
| 3936 | goto parse_DFS_referrals_exit; | ||
| 3937 | } | ||
| 3938 | |||
| 3939 | /* get the upper boundary of the resp buffer */ | ||
| 3940 | data_end = (char *)(&(pSMBr->PathConsumed)) + | ||
| 3941 | le16_to_cpu(pSMBr->t2.DataCount); | ||
| 3942 | |||
| 3943 | cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n", | ||
| 3944 | *num_of_nodes, | ||
| 3945 | le16_to_cpu(pSMBr->DFSFlags))); | ||
| 3946 | |||
| 3947 | *target_nodes = kzalloc(sizeof(struct dfs_info3_param) * | ||
| 3948 | *num_of_nodes, GFP_KERNEL); | ||
| 3949 | if (*target_nodes == NULL) { | ||
| 3950 | cERROR(1, ("Failed to allocate buffer for target_nodes\n")); | ||
| 3951 | rc = -ENOMEM; | ||
| 3952 | goto parse_DFS_referrals_exit; | ||
| 3953 | } | ||
| 3954 | |||
| 3955 | /* collect neccessary data from referrals */ | ||
| 3956 | for (i = 0; i < *num_of_nodes; i++) { | ||
| 3957 | char *temp; | ||
| 3958 | int max_len; | ||
| 3959 | struct dfs_info3_param *node = (*target_nodes)+i; | ||
| 3960 | |||
| 3961 | node->flags = le16_to_cpu(pSMBr->DFSFlags); | ||
| 3962 | node->path_consumed = le16_to_cpu(pSMBr->PathConsumed); | ||
| 3963 | node->server_type = le16_to_cpu(ref->ServerType); | ||
| 3964 | node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags); | ||
| 3965 | |||
| 3966 | /* copy DfsPath */ | ||
| 3967 | temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset); | ||
| 3968 | max_len = data_end - temp; | ||
| 3969 | rc = cifs_strncpy_to_host(&(node->path_name), temp, | ||
| 3970 | max_len, is_unicode, nls_codepage); | ||
| 3971 | if (rc) | ||
| 3972 | goto parse_DFS_referrals_exit; | ||
| 3973 | |||
| 3974 | /* copy link target UNC */ | ||
| 3975 | temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset); | ||
| 3976 | max_len = data_end - temp; | ||
| 3977 | rc = cifs_strncpy_to_host(&(node->node_name), temp, | ||
| 3978 | max_len, is_unicode, nls_codepage); | ||
| 3979 | if (rc) | ||
| 3980 | goto parse_DFS_referrals_exit; | ||
| 3981 | |||
| 3982 | ref += ref->Size; | ||
| 3983 | } | ||
| 3984 | |||
| 3985 | parse_DFS_referrals_exit: | ||
| 3986 | if (rc) { | ||
| 3987 | free_dfs_info_array(*target_nodes, *num_of_nodes); | ||
| 3988 | *target_nodes = NULL; | ||
| 3989 | *num_of_nodes = 0; | ||
| 3990 | } | ||
| 3991 | return rc; | ||
| 3992 | } | ||
| 3993 | |||
| 3859 | int | 3994 | int |
| 3860 | CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, | 3995 | CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, |
| 3861 | const unsigned char *searchName, | 3996 | const unsigned char *searchName, |
| 3862 | unsigned char **targetUNCs, | 3997 | struct dfs_info3_param **target_nodes, |
| 3863 | unsigned int *number_of_UNC_in_array, | 3998 | unsigned int *num_of_nodes, |
| 3864 | const struct nls_table *nls_codepage, int remap) | 3999 | const struct nls_table *nls_codepage, int remap) |
| 3865 | { | 4000 | { |
| 3866 | /* TRANS2_GET_DFS_REFERRAL */ | 4001 | /* TRANS2_GET_DFS_REFERRAL */ |
| 3867 | TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL; | 4002 | TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL; |
| 3868 | TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL; | 4003 | TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL; |
| 3869 | struct dfs_referral_level_3 *referrals = NULL; | ||
| 3870 | int rc = 0; | 4004 | int rc = 0; |
| 3871 | int bytes_returned; | 4005 | int bytes_returned; |
| 3872 | int name_len; | 4006 | int name_len; |
| 3873 | unsigned int i; | ||
| 3874 | char *temp; | ||
| 3875 | __u16 params, byte_count; | 4007 | __u16 params, byte_count; |
| 3876 | *number_of_UNC_in_array = 0; | 4008 | *num_of_nodes = 0; |
| 3877 | *targetUNCs = NULL; | 4009 | *target_nodes = NULL; |
| 3878 | 4010 | ||
| 3879 | cFYI(1, ("In GetDFSRefer the path %s", searchName)); | 4011 | cFYI(1, ("In GetDFSRefer the path %s", searchName)); |
| 3880 | if (ses == NULL) | 4012 | if (ses == NULL) |
| @@ -3921,7 +4053,8 @@ getDFSRetry: | |||
| 3921 | pSMB->DataCount = 0; | 4053 | pSMB->DataCount = 0; |
| 3922 | pSMB->DataOffset = 0; | 4054 | pSMB->DataOffset = 0; |
| 3923 | pSMB->MaxParameterCount = 0; | 4055 | pSMB->MaxParameterCount = 0; |
| 3924 | pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ | 4056 | /* BB find exact max SMB PDU from sess structure BB */ |
| 4057 | pSMB->MaxDataCount = cpu_to_le16(4000); | ||
| 3925 | pSMB->MaxSetupCount = 0; | 4058 | pSMB->MaxSetupCount = 0; |
| 3926 | pSMB->Reserved = 0; | 4059 | pSMB->Reserved = 0; |
| 3927 | pSMB->Flags = 0; | 4060 | pSMB->Flags = 0; |
| @@ -3943,100 +4076,24 @@ getDFSRetry: | |||
| 3943 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 4076 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
| 3944 | if (rc) { | 4077 | if (rc) { |
| 3945 | cFYI(1, ("Send error in GetDFSRefer = %d", rc)); | 4078 | cFYI(1, ("Send error in GetDFSRefer = %d", rc)); |
| 3946 | } else { /* decode response */ | 4079 | goto GetDFSRefExit; |
| 3947 | /* BB Add logic to parse referrals here */ | 4080 | } |
| 3948 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 4081 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); |
| 3949 | 4082 | ||
| 3950 | /* BB Also check if enough total bytes returned? */ | 4083 | /* BB Also check if enough total bytes returned? */ |
| 3951 | if (rc || (pSMBr->ByteCount < 17)) | 4084 | if (rc || (pSMBr->ByteCount < 17)) { |
| 3952 | rc = -EIO; /* bad smb */ | 4085 | rc = -EIO; /* bad smb */ |
| 3953 | else { | 4086 | goto GetDFSRefExit; |
| 3954 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | 4087 | } |
| 3955 | __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount); | ||
| 3956 | 4088 | ||
| 3957 | cFYI(1, | 4089 | cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d", |
| 3958 | ("Decoding GetDFSRefer response BCC: %d Offset %d", | 4090 | pSMBr->ByteCount, |
| 3959 | pSMBr->ByteCount, data_offset)); | 4091 | 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 | 4092 | ||
| 3998 | if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { | 4093 | /* parse returned result into more usable form */ |
| 3999 | name_len += UniStrnlen((wchar_t *)temp, | 4094 | rc = parse_DFS_referrals(pSMBr, num_of_nodes, |
| 4000 | data_count); | 4095 | 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 | 4096 | ||
| 4039 | } | ||
| 4040 | GetDFSRefExit: | 4097 | GetDFSRefExit: |
| 4041 | if (pSMB) | 4098 | if (pSMB) |
| 4042 | cifs_buf_release(pSMB); | 4099 | cifs_buf_release(pSMB); |
| @@ -4229,7 +4286,8 @@ QFSAttributeRetry: | |||
| 4229 | params = 2; /* level */ | 4286 | params = 2; /* level */ |
| 4230 | pSMB->TotalDataCount = 0; | 4287 | pSMB->TotalDataCount = 0; |
| 4231 | pSMB->MaxParameterCount = cpu_to_le16(2); | 4288 | pSMB->MaxParameterCount = cpu_to_le16(2); |
| 4232 | pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ | 4289 | /* BB find exact max SMB PDU from sess structure BB */ |
| 4290 | pSMB->MaxDataCount = cpu_to_le16(1000); | ||
| 4233 | pSMB->MaxSetupCount = 0; | 4291 | pSMB->MaxSetupCount = 0; |
| 4234 | pSMB->Reserved = 0; | 4292 | pSMB->Reserved = 0; |
| 4235 | pSMB->Flags = 0; | 4293 | pSMB->Flags = 0; |
| @@ -4298,7 +4356,8 @@ QFSDeviceRetry: | |||
| 4298 | params = 2; /* level */ | 4356 | params = 2; /* level */ |
| 4299 | pSMB->TotalDataCount = 0; | 4357 | pSMB->TotalDataCount = 0; |
| 4300 | pSMB->MaxParameterCount = cpu_to_le16(2); | 4358 | pSMB->MaxParameterCount = cpu_to_le16(2); |
| 4301 | pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ | 4359 | /* BB find exact max SMB PDU from sess structure BB */ |
| 4360 | pSMB->MaxDataCount = cpu_to_le16(1000); | ||
| 4302 | pSMB->MaxSetupCount = 0; | 4361 | pSMB->MaxSetupCount = 0; |
| 4303 | pSMB->Reserved = 0; | 4362 | pSMB->Reserved = 0; |
| 4304 | pSMB->Flags = 0; | 4363 | pSMB->Flags = 0; |
| @@ -4369,7 +4428,8 @@ QFSUnixRetry: | |||
| 4369 | pSMB->DataCount = 0; | 4428 | pSMB->DataCount = 0; |
| 4370 | pSMB->DataOffset = 0; | 4429 | pSMB->DataOffset = 0; |
| 4371 | pSMB->MaxParameterCount = cpu_to_le16(2); | 4430 | pSMB->MaxParameterCount = cpu_to_le16(2); |
| 4372 | pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */ | 4431 | /* BB find exact max SMB PDU from sess structure BB */ |
| 4432 | pSMB->MaxDataCount = cpu_to_le16(100); | ||
| 4373 | pSMB->MaxSetupCount = 0; | 4433 | pSMB->MaxSetupCount = 0; |
| 4374 | pSMB->Reserved = 0; | 4434 | pSMB->Reserved = 0; |
| 4375 | pSMB->Flags = 0; | 4435 | pSMB->Flags = 0; |
| @@ -4444,7 +4504,8 @@ SETFSUnixRetry: | |||
| 4444 | offset = param_offset + params; | 4504 | offset = param_offset + params; |
| 4445 | 4505 | ||
| 4446 | pSMB->MaxParameterCount = cpu_to_le16(4); | 4506 | pSMB->MaxParameterCount = cpu_to_le16(4); |
| 4447 | pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */ | 4507 | /* BB find exact max SMB PDU from sess structure BB */ |
| 4508 | pSMB->MaxDataCount = cpu_to_le16(100); | ||
| 4448 | pSMB->SetupCount = 1; | 4509 | pSMB->SetupCount = 1; |
| 4449 | pSMB->Reserved3 = 0; | 4510 | pSMB->Reserved3 = 0; |
| 4450 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION); | 4511 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION); |
| @@ -4512,7 +4573,8 @@ QFSPosixRetry: | |||
| 4512 | pSMB->DataCount = 0; | 4573 | pSMB->DataCount = 0; |
| 4513 | pSMB->DataOffset = 0; | 4574 | pSMB->DataOffset = 0; |
| 4514 | pSMB->MaxParameterCount = cpu_to_le16(2); | 4575 | pSMB->MaxParameterCount = cpu_to_le16(2); |
| 4515 | pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */ | 4576 | /* BB find exact max SMB PDU from sess structure BB */ |
| 4577 | pSMB->MaxDataCount = cpu_to_le16(100); | ||
| 4516 | pSMB->MaxSetupCount = 0; | 4578 | pSMB->MaxSetupCount = 0; |
| 4517 | pSMB->Reserved = 0; | 4579 | pSMB->Reserved = 0; |
| 4518 | pSMB->Flags = 0; | 4580 | pSMB->Flags = 0; |
| @@ -4702,7 +4764,8 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, | |||
| 4702 | 4764 | ||
| 4703 | count = sizeof(struct file_end_of_file_info); | 4765 | count = sizeof(struct file_end_of_file_info); |
| 4704 | pSMB->MaxParameterCount = cpu_to_le16(2); | 4766 | pSMB->MaxParameterCount = cpu_to_le16(2); |
| 4705 | pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */ | 4767 | /* BB find exact max SMB PDU from sess structure BB */ |
| 4768 | pSMB->MaxDataCount = cpu_to_le16(1000); | ||
| 4706 | pSMB->SetupCount = 1; | 4769 | pSMB->SetupCount = 1; |
| 4707 | pSMB->Reserved3 = 0; | 4770 | pSMB->Reserved3 = 0; |
| 4708 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); | 4771 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); |
| @@ -4789,7 +4852,8 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, | |||
| 4789 | 4852 | ||
| 4790 | count = sizeof(FILE_BASIC_INFO); | 4853 | count = sizeof(FILE_BASIC_INFO); |
| 4791 | pSMB->MaxParameterCount = cpu_to_le16(2); | 4854 | pSMB->MaxParameterCount = cpu_to_le16(2); |
| 4792 | pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */ | 4855 | /* BB find max SMB PDU from sess */ |
| 4856 | pSMB->MaxDataCount = cpu_to_le16(1000); | ||
| 4793 | pSMB->SetupCount = 1; | 4857 | pSMB->SetupCount = 1; |
| 4794 | pSMB->Reserved3 = 0; | 4858 | pSMB->Reserved3 = 0; |
| 4795 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); | 4859 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); |
| @@ -4856,7 +4920,8 @@ SetTimesRetry: | |||
| 4856 | params = 6 + name_len; | 4920 | params = 6 + name_len; |
| 4857 | count = sizeof(FILE_BASIC_INFO); | 4921 | count = sizeof(FILE_BASIC_INFO); |
| 4858 | pSMB->MaxParameterCount = cpu_to_le16(2); | 4922 | pSMB->MaxParameterCount = cpu_to_le16(2); |
| 4859 | pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ | 4923 | /* BB find max SMB PDU from sess structure BB */ |
| 4924 | pSMB->MaxDataCount = cpu_to_le16(1000); | ||
| 4860 | pSMB->MaxSetupCount = 0; | 4925 | pSMB->MaxSetupCount = 0; |
| 4861 | pSMB->Reserved = 0; | 4926 | pSMB->Reserved = 0; |
| 4862 | pSMB->Flags = 0; | 4927 | pSMB->Flags = 0; |
| @@ -4986,7 +5051,8 @@ setPermsRetry: | |||
| 4986 | params = 6 + name_len; | 5051 | params = 6 + name_len; |
| 4987 | count = sizeof(FILE_UNIX_BASIC_INFO); | 5052 | count = sizeof(FILE_UNIX_BASIC_INFO); |
| 4988 | pSMB->MaxParameterCount = cpu_to_le16(2); | 5053 | pSMB->MaxParameterCount = cpu_to_le16(2); |
| 4989 | pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ | 5054 | /* BB find max SMB PDU from sess structure BB */ |
| 5055 | pSMB->MaxDataCount = cpu_to_le16(1000); | ||
| 4990 | pSMB->MaxSetupCount = 0; | 5056 | pSMB->MaxSetupCount = 0; |
| 4991 | pSMB->Reserved = 0; | 5057 | pSMB->Reserved = 0; |
| 4992 | pSMB->Flags = 0; | 5058 | pSMB->Flags = 0; |
| @@ -5169,7 +5235,8 @@ QAllEAsRetry: | |||
| 5169 | params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */; | 5235 | params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */; |
| 5170 | pSMB->TotalDataCount = 0; | 5236 | pSMB->TotalDataCount = 0; |
| 5171 | pSMB->MaxParameterCount = cpu_to_le16(2); | 5237 | pSMB->MaxParameterCount = cpu_to_le16(2); |
| 5172 | pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ | 5238 | /* BB find exact max SMB PDU from sess structure BB */ |
| 5239 | pSMB->MaxDataCount = cpu_to_le16(4000); | ||
| 5173 | pSMB->MaxSetupCount = 0; | 5240 | pSMB->MaxSetupCount = 0; |
| 5174 | pSMB->Reserved = 0; | 5241 | pSMB->Reserved = 0; |
| 5175 | pSMB->Flags = 0; | 5242 | pSMB->Flags = 0; |
| @@ -5317,7 +5384,8 @@ QEARetry: | |||
| 5317 | params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */; | 5384 | params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */; |
| 5318 | pSMB->TotalDataCount = 0; | 5385 | pSMB->TotalDataCount = 0; |
| 5319 | pSMB->MaxParameterCount = cpu_to_le16(2); | 5386 | pSMB->MaxParameterCount = cpu_to_le16(2); |
| 5320 | pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ | 5387 | /* BB find exact max SMB PDU from sess structure BB */ |
| 5388 | pSMB->MaxDataCount = cpu_to_le16(4000); | ||
| 5321 | pSMB->MaxSetupCount = 0; | 5389 | pSMB->MaxSetupCount = 0; |
| 5322 | pSMB->Reserved = 0; | 5390 | pSMB->Reserved = 0; |
| 5323 | pSMB->Flags = 0; | 5391 | pSMB->Flags = 0; |
| @@ -5475,7 +5543,8 @@ SetEARetry: | |||
| 5475 | 5543 | ||
| 5476 | count = sizeof(*parm_data) + ea_value_len + name_len; | 5544 | count = sizeof(*parm_data) + ea_value_len + name_len; |
| 5477 | pSMB->MaxParameterCount = cpu_to_le16(2); | 5545 | pSMB->MaxParameterCount = cpu_to_le16(2); |
| 5478 | pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */ | 5546 | /* BB find max SMB PDU from sess */ |
| 5547 | pSMB->MaxDataCount = cpu_to_le16(1000); | ||
| 5479 | pSMB->MaxSetupCount = 0; | 5548 | pSMB->MaxSetupCount = 0; |
| 5480 | pSMB->Reserved = 0; | 5549 | pSMB->Reserved = 0; |
| 5481 | pSMB->Flags = 0; | 5550 | pSMB->Flags = 0; |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index f428bf3bf1a9..023434f72c15 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; |
| @@ -1246,6 +1248,10 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
| 1246 | vol->setuids = 1; | 1248 | vol->setuids = 1; |
| 1247 | } else if (strnicmp(data, "nosetuids", 9) == 0) { | 1249 | } else if (strnicmp(data, "nosetuids", 9) == 0) { |
| 1248 | vol->setuids = 0; | 1250 | vol->setuids = 0; |
| 1251 | } else if (strnicmp(data, "dynperm", 7) == 0) { | ||
| 1252 | vol->dynperm = true; | ||
| 1253 | } else if (strnicmp(data, "nodynperm", 9) == 0) { | ||
| 1254 | vol->dynperm = false; | ||
| 1249 | } else if (strnicmp(data, "nohard", 6) == 0) { | 1255 | } else if (strnicmp(data, "nohard", 6) == 0) { |
| 1250 | vol->retry = 0; | 1256 | vol->retry = 0; |
| 1251 | } else if (strnicmp(data, "nosoft", 6) == 0) { | 1257 | } else if (strnicmp(data, "nosoft", 6) == 0) { |
| @@ -1268,8 +1274,12 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
| 1268 | vol->no_psx_acl = 1; | 1274 | vol->no_psx_acl = 1; |
| 1269 | } else if (strnicmp(data, "sign", 4) == 0) { | 1275 | } else if (strnicmp(data, "sign", 4) == 0) { |
| 1270 | vol->secFlg |= CIFSSEC_MUST_SIGN; | 1276 | vol->secFlg |= CIFSSEC_MUST_SIGN; |
| 1271 | /* } else if (strnicmp(data, "seal",4) == 0) { | 1277 | } else if (strnicmp(data, "seal", 4) == 0) { |
| 1272 | vol->secFlg |= CIFSSEC_MUST_SEAL; */ | 1278 | /* we do not do the following in secFlags because seal |
| 1279 | is a per tree connection (mount) not a per socket | ||
| 1280 | or per-smb connection option in the protocol */ | ||
| 1281 | /* vol->secFlg |= CIFSSEC_MUST_SEAL; */ | ||
| 1282 | vol->seal = 1; | ||
| 1273 | } else if (strnicmp(data, "direct", 6) == 0) { | 1283 | } else if (strnicmp(data, "direct", 6) == 0) { |
| 1274 | vol->direct_io = 1; | 1284 | vol->direct_io = 1; |
| 1275 | } else if (strnicmp(data, "forcedirectio", 13) == 0) { | 1285 | } else if (strnicmp(data, "forcedirectio", 13) == 0) { |
| @@ -1414,34 +1424,12 @@ find_unc(__be32 new_target_ip_addr, char *uncName, char *userName) | |||
| 1414 | } | 1424 | } |
| 1415 | 1425 | ||
| 1416 | int | 1426 | int |
| 1417 | connect_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 | |||
| 1437 | int | ||
| 1438 | get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, | 1427 | get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, |
| 1439 | const struct nls_table *nls_codepage, unsigned int *pnum_referrals, | 1428 | const struct nls_table *nls_codepage, unsigned int *pnum_referrals, |
| 1440 | struct dfs_info3_param **preferrals, int remap) | 1429 | struct dfs_info3_param **preferrals, int remap) |
| 1441 | { | 1430 | { |
| 1442 | char *temp_unc; | 1431 | char *temp_unc; |
| 1443 | int rc = 0; | 1432 | int rc = 0; |
| 1444 | unsigned char *targetUNCs; | ||
| 1445 | 1433 | ||
| 1446 | *pnum_referrals = 0; | 1434 | *pnum_referrals = 0; |
| 1447 | *preferrals = NULL; | 1435 | *preferrals = NULL; |
| @@ -1464,7 +1452,7 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, | |||
| 1464 | kfree(temp_unc); | 1452 | kfree(temp_unc); |
| 1465 | } | 1453 | } |
| 1466 | if (rc == 0) | 1454 | if (rc == 0) |
| 1467 | rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, &targetUNCs, | 1455 | rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals, |
| 1468 | pnum_referrals, nls_codepage, remap); | 1456 | pnum_referrals, nls_codepage, remap); |
| 1469 | /* BB map targetUNCs to dfs_info3 structures, here or | 1457 | /* BB map targetUNCs to dfs_info3 structures, here or |
| 1470 | in CIFSGetDFSRefer BB */ | 1458 | in CIFSGetDFSRefer BB */ |
| @@ -1815,7 +1803,7 @@ convert_delimiter(char *path, char delim) | |||
| 1815 | if (path == NULL) | 1803 | if (path == NULL) |
| 1816 | return; | 1804 | return; |
| 1817 | 1805 | ||
| 1818 | if (delim == '/') | 1806 | if (delim == '/') |
| 1819 | old_delim = '\\'; | 1807 | old_delim = '\\'; |
| 1820 | else | 1808 | else |
| 1821 | old_delim = '/'; | 1809 | old_delim = '/'; |
| @@ -2125,6 +2113,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 2125 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID; | 2113 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID; |
| 2126 | if (volume_info.override_gid) | 2114 | if (volume_info.override_gid) |
| 2127 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID; | 2115 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID; |
| 2116 | if (volume_info.dynperm) | ||
| 2117 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM; | ||
| 2128 | if (volume_info.direct_io) { | 2118 | if (volume_info.direct_io) { |
| 2129 | cFYI(1, ("mounting share using direct i/o")); | 2119 | cFYI(1, ("mounting share using direct i/o")); |
| 2130 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; | 2120 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; |
| @@ -2141,6 +2131,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 2141 | for the retry flag is used */ | 2131 | for the retry flag is used */ |
| 2142 | tcon->retry = volume_info.retry; | 2132 | tcon->retry = volume_info.retry; |
| 2143 | tcon->nocase = volume_info.nocase; | 2133 | tcon->nocase = volume_info.nocase; |
| 2134 | if (tcon->seal != volume_info.seal) | ||
| 2135 | cERROR(1, ("transport encryption setting " | ||
| 2136 | "conflicts with existing tid")); | ||
| 2144 | } else { | 2137 | } else { |
| 2145 | tcon = tconInfoAlloc(); | 2138 | tcon = tconInfoAlloc(); |
| 2146 | if (tcon == NULL) | 2139 | if (tcon == NULL) |
| @@ -2154,10 +2147,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 2154 | if ((strchr(volume_info.UNC + 3, '\\') == NULL) | 2147 | if ((strchr(volume_info.UNC + 3, '\\') == NULL) |
| 2155 | && (strchr(volume_info.UNC + 3, '/') == | 2148 | && (strchr(volume_info.UNC + 3, '/') == |
| 2156 | NULL)) { | 2149 | NULL)) { |
| 2157 | rc = connect_to_dfs_path(xid, pSesInfo, | 2150 | /* rc = connect_to_dfs_path(xid, pSesInfo, |
| 2158 | "", cifs_sb->local_nls, | 2151 | "", cifs_sb->local_nls, |
| 2159 | cifs_sb->mnt_cifs_flags & | 2152 | cifs_sb->mnt_cifs_flags & |
| 2160 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 2153 | CIFS_MOUNT_MAP_SPECIAL_CHR);*/ |
| 2154 | cFYI(1, ("DFS root not supported")); | ||
| 2161 | rc = -ENODEV; | 2155 | rc = -ENODEV; |
| 2162 | goto out; | 2156 | goto out; |
| 2163 | } else { | 2157 | } else { |
| @@ -2173,6 +2167,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 2173 | atomic_inc(&pSesInfo->inUse); | 2167 | atomic_inc(&pSesInfo->inUse); |
| 2174 | tcon->retry = volume_info.retry; | 2168 | tcon->retry = volume_info.retry; |
| 2175 | tcon->nocase = volume_info.nocase; | 2169 | tcon->nocase = volume_info.nocase; |
| 2170 | tcon->seal = volume_info.seal; | ||
| 2176 | } | 2171 | } |
| 2177 | } | 2172 | } |
| 2178 | } | 2173 | } |
| @@ -2314,9 +2309,10 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 2314 | user = ses->userName; | 2309 | user = ses->userName; |
| 2315 | domain = ses->domainName; | 2310 | domain = ses->domainName; |
| 2316 | smb_buffer = cifs_buf_get(); | 2311 | smb_buffer = cifs_buf_get(); |
| 2317 | if (smb_buffer == NULL) { | 2312 | |
| 2313 | if (smb_buffer == NULL) | ||
| 2318 | return -ENOMEM; | 2314 | return -ENOMEM; |
| 2319 | } | 2315 | |
| 2320 | smb_buffer_response = smb_buffer; | 2316 | smb_buffer_response = smb_buffer; |
| 2321 | pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer; | 2317 | pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer; |
| 2322 | 2318 | ||
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index e4e0078a0526..f0b5b5f3dd2e 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; | ||
| 62 | cifs_bp_rename_retry: | 69 | cifs_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 | ||
| @@ -590,7 +608,7 @@ static int cifs_ci_compare(struct dentry *dentry, struct qstr *a, | |||
| 590 | * case take precedence. If a is not a negative dentry, this | 608 | * case take precedence. If a is not a negative dentry, this |
| 591 | * should have no side effects | 609 | * should have no side effects |
| 592 | */ | 610 | */ |
| 593 | memcpy(a->name, b->name, a->len); | 611 | memcpy((void *)a->name, b->name, a->len); |
| 594 | return 0; | 612 | return 0; |
| 595 | } | 613 | } |
| 596 | return 1; | 614 | 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..8636cec2642c 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 | ||
| 81 | static inline int cifs_get_disposition(unsigned int flags) | 85 | static inline int cifs_get_disposition(unsigned int flags) |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index fcbdbb6ad7bf..00ced97bd53a 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 | ||
| 164 | static 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 | 164 | ||
| 176 | /* use full path name for working with DFS */ | 165 | /* |
| 177 | tree_len = strnlen(pTcon->treeName, MAX_TREE_SIZE + 1); | 166 | * Needed to setup inode data for the directory which is the |
| 178 | path_len = strnlen(search_path, MAX_PATHCONF); | 167 | * junction to the new submount (ie to setup the fake directory |
| 179 | 168 | * which represents a DFS referral) | |
| 180 | tmp_path = kmalloc(tree_len+path_len+1, GFP_KERNEL); | 169 | */ |
| 181 | if (tmp_path == NULL) | 170 | static void fill_fake_finddataunix(FILE_UNIX_BASIC_INFO *pfnd_dat, |
| 182 | return search_path; | 171 | struct super_block *sb) |
| 172 | { | ||
| 173 | struct inode *pinode = NULL; | ||
| 174 | |||
| 175 | memset(pfnd_dat, sizeof(FILE_UNIX_BASIC_INFO), 0); | ||
| 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 | ||
| 195 | int cifs_get_inode_info_unix(struct inode **pinode, | 202 | int 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 | 217 | ||
| 209 | full_path = cifs_get_search_path(cifs_sb, search_path); | ||
| 210 | |||
| 211 | try_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, | ||
| 217 | sizeof(findData)); */ | ||
| 218 | if (rc) { | 222 | if (rc) { |
| 219 | if (rc == -EREMOTE && !is_dfs_referral) { | 223 | if (rc == -EREMOTE && !is_dfs_referral) { |
| 220 | is_dfs_referral = true; | 224 | is_dfs_referral = true; |
| 221 | if (full_path != search_path) { | 225 | cFYI(DBG2, ("DFS ref")); |
| 222 | kfree(full_path); | 226 | /* for DFS, server does not give us real inode data */ |
| 223 | full_path = search_path; | 227 | fill_fake_finddataunix(&find_data, sb); |
| 224 | } | 228 | rc = 0; |
| 225 | goto try_again_CIFSSMBUnixQPathInfo; | ||
| 226 | } | 229 | } |
| 227 | goto cgiiu_exit; | 230 | } |
| 228 | } else { | 231 | num_of_bytes = le64_to_cpu(find_data.NumOfBytes); |
| 229 | struct cifsInodeInfo *cifsInfo; | 232 | end_of_file = le64_to_cpu(find_data.EndOfFile); |
| 230 | __u64 num_of_bytes = le64_to_cpu(findData.NumOfBytes); | ||
| 231 | __u64 end_of_file = le64_to_cpu(findData.EndOfFile); | ||
| 232 | 233 | ||
| 233 | /* get new inode */ | 234 | /* get new inode */ |
| 235 | if (*pinode == NULL) { | ||
| 236 | *pinode = new_inode(sb); | ||
| 234 | if (*pinode == NULL) { | 237 | if (*pinode == NULL) { |
| 235 | *pinode = new_inode(sb); | 238 | rc = -ENOMEM; |
| 236 | if (*pinode == NULL) { | 239 | goto cgiiu_exit; |
| 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 | |||
| 250 | insert_inode_hash(*pinode); | ||
| 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); | ||
| 273 | cgiiu_exit: | 272 | cgiiu_exit: |
| 274 | if (full_path != search_path) | ||
| 275 | kfree(full_path); | ||
| 276 | return rc; | 273 | return rc; |
| 277 | } | 274 | } |
| 278 | 275 | ||
| @@ -379,21 +376,51 @@ 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 | */ | ||
| 384 | static void fill_fake_finddata(FILE_ALL_INFO *pfnd_dat, | ||
| 385 | struct super_block *sb) | ||
| 386 | { | ||
| 387 | memset(pfnd_dat, sizeof(FILE_ALL_INFO), 0); | ||
| 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 | |||
| 382 | int cifs_get_inode_info(struct inode **pinode, | 408 | int 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; |
| 394 | 421 | ||
| 395 | pTcon = cifs_sb->tcon; | 422 | pTcon = cifs_sb->tcon; |
| 396 | cFYI(1, ("Getting info on %s", search_path)); | 423 | cFYI(1, ("Getting info on %s", full_path)); |
| 397 | 424 | ||
| 398 | if ((pfindData == NULL) && (*pinode != NULL)) { | 425 | if ((pfindData == NULL) && (*pinode != NULL)) { |
| 399 | if (CIFS_I(*pinode)->clientCanCacheRead) { | 426 | if (CIFS_I(*pinode)->clientCanCacheRead) { |
| @@ -409,9 +436,6 @@ int cifs_get_inode_info(struct inode **pinode, | |||
| 409 | return -ENOMEM; | 436 | return -ENOMEM; |
| 410 | pfindData = (FILE_ALL_INFO *)buf; | 437 | pfindData = (FILE_ALL_INFO *)buf; |
| 411 | 438 | ||
| 412 | full_path = cifs_get_search_path(cifs_sb, search_path); | ||
| 413 | |||
| 414 | try_again_CIFSSMBQPathInfo: | ||
| 415 | /* could do find first instead but this returns more info */ | 439 | /* could do find first instead but this returns more info */ |
| 416 | rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData, | 440 | rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData, |
| 417 | 0 /* not legacy */, | 441 | 0 /* not legacy */, |
| @@ -429,178 +453,168 @@ try_again_CIFSSMBQPathInfo: | |||
| 429 | } | 453 | } |
| 430 | } | 454 | } |
| 431 | /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */ | 455 | /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */ |
| 432 | if (rc) { | 456 | if (rc == -EREMOTE) { |
| 433 | if (rc == -EREMOTE && !is_dfs_referral) { | 457 | is_dfs_referral = true; |
| 434 | is_dfs_referral = true; | 458 | fill_fake_finddata(pfindData, sb); |
| 435 | if (full_path != search_path) { | 459 | rc = 0; |
| 436 | kfree(full_path); | 460 | } else if (rc) |
| 437 | full_path = search_path; | ||
| 438 | } | ||
| 439 | goto try_again_CIFSSMBQPathInfo; | ||
| 440 | } | ||
| 441 | goto cgii_exit; | 461 | goto cgii_exit; |
| 442 | } else { | ||
| 443 | struct cifsInodeInfo *cifsInfo; | ||
| 444 | __u32 attr = le32_to_cpu(pfindData->Attributes); | ||
| 445 | 462 | ||
| 446 | /* get new inode */ | 463 | attr = le32_to_cpu(pfindData->Attributes); |
| 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 | 464 | ||
| 458 | /* We can not use the IndexNumber field by default from | 465 | /* get new inode */ |
| 459 | Windows or Samba (in ALL_INFO buf) but we can request | 466 | if (*pinode == NULL) { |
| 460 | it explicitly. It may not be unique presumably if | 467 | *pinode = new_inode(sb); |
| 461 | the server has multiple devices mounted under one | 468 | if (*pinode == NULL) { |
| 462 | share */ | 469 | rc = -ENOMEM; |
| 463 | 470 | goto cgii_exit; | |
| 464 | /* There may be higher info levels that work but are | 471 | } |
| 465 | there Windows server or network appliances for which | 472 | /* Is an i_ino of zero legal? Can we use that to check |
| 466 | IndexNumber field is not guaranteed unique? */ | 473 | if the server supports returning inode numbers? Are |
| 467 | 474 | there other sanity checks we can use to ensure that | |
| 468 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { | 475 | the server is really filling in that field? */ |
| 469 | int rc1 = 0; | 476 | |
| 470 | __u64 inode_num; | 477 | /* We can not use the IndexNumber field by default from |
| 471 | 478 | Windows or Samba (in ALL_INFO buf) but we can request | |
| 472 | rc1 = CIFSGetSrvInodeNumber(xid, pTcon, | 479 | it explicitly. It may not be unique presumably if |
| 473 | search_path, &inode_num, | 480 | the server has multiple devices mounted under one share */ |
| 481 | |||
| 482 | /* There may be higher info levels that work but are | ||
| 483 | there Windows server or network appliances for which | ||
| 484 | IndexNumber field is not guaranteed unique? */ | ||
| 485 | |||
| 486 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { | ||
| 487 | int rc1 = 0; | ||
| 488 | __u64 inode_num; | ||
| 489 | |||
| 490 | rc1 = CIFSGetSrvInodeNumber(xid, pTcon, | ||
| 491 | full_path, &inode_num, | ||
| 474 | cifs_sb->local_nls, | 492 | cifs_sb->local_nls, |
| 475 | cifs_sb->mnt_cifs_flags & | 493 | cifs_sb->mnt_cifs_flags & |
| 476 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 494 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 477 | if (rc1) { | 495 | if (rc1) { |
| 478 | cFYI(1, ("GetSrvInodeNum rc %d", rc1)); | 496 | cFYI(1, ("GetSrvInodeNum rc %d", rc1)); |
| 479 | /* BB EOPNOSUPP disable SERVER_INUM? */ | 497 | /* BB EOPNOSUPP disable SERVER_INUM? */ |
| 480 | } else /* do we need cast or hash to ino? */ | 498 | } else /* do we need cast or hash to ino? */ |
| 481 | (*pinode)->i_ino = inode_num; | 499 | (*pinode)->i_ino = inode_num; |
| 482 | } /* else ino incremented to unique num in new_inode*/ | 500 | } /* else ino incremented to unique num in new_inode*/ |
| 483 | if (sb->s_flags & MS_NOATIME) | 501 | if (sb->s_flags & MS_NOATIME) |
| 484 | (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME; | 502 | (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME; |
| 485 | insert_inode_hash(*pinode); | 503 | insert_inode_hash(*pinode); |
| 486 | } | 504 | } |
| 487 | inode = *pinode; | 505 | inode = *pinode; |
| 488 | cifsInfo = CIFS_I(inode); | 506 | cifsInfo = CIFS_I(inode); |
| 489 | cifsInfo->cifsAttrs = attr; | 507 | cifsInfo->cifsAttrs = attr; |
| 490 | cFYI(1, ("Old time %ld", cifsInfo->time)); | 508 | cFYI(1, ("Old time %ld", cifsInfo->time)); |
| 491 | cifsInfo->time = jiffies; | 509 | cifsInfo->time = jiffies; |
| 492 | cFYI(1, ("New time %ld", cifsInfo->time)); | 510 | cFYI(1, ("New time %ld", cifsInfo->time)); |
| 493 | 511 | ||
| 494 | /* blksize needs to be multiple of two. So safer to default to | 512 | /* blksize needs to be multiple of two. So safer to default to |
| 495 | blksize and blkbits set in superblock so 2**blkbits and blksize | 513 | blksize and blkbits set in superblock so 2**blkbits and blksize |
| 496 | will match rather than setting to: | 514 | will match rather than setting to: |
| 497 | (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/ | 515 | (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/ |
| 498 | 516 | ||
| 499 | /* Linux can not store file creation time so ignore it */ | 517 | /* Linux can not store file creation time so ignore it */ |
| 500 | if (pfindData->LastAccessTime) | 518 | if (pfindData->LastAccessTime) |
| 501 | inode->i_atime = cifs_NTtimeToUnix | 519 | inode->i_atime = cifs_NTtimeToUnix |
| 502 | (le64_to_cpu(pfindData->LastAccessTime)); | 520 | (le64_to_cpu(pfindData->LastAccessTime)); |
| 503 | else /* do not need to use current_fs_time - time not stored */ | 521 | else /* do not need to use current_fs_time - time not stored */ |
| 504 | inode->i_atime = CURRENT_TIME; | 522 | inode->i_atime = CURRENT_TIME; |
| 505 | inode->i_mtime = | 523 | inode->i_mtime = |
| 506 | cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); | 524 | cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); |
| 507 | inode->i_ctime = | 525 | inode->i_ctime = |
| 508 | cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); | 526 | cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); |
| 509 | cFYI(0, ("Attributes came in as 0x%x", attr)); | 527 | cFYI(DBG2, ("Attributes came in as 0x%x", attr)); |
| 510 | if (adjustTZ && (pTcon->ses) && (pTcon->ses->server)) { | 528 | if (adjustTZ && (pTcon->ses) && (pTcon->ses->server)) { |
| 511 | inode->i_ctime.tv_sec += pTcon->ses->server->timeAdj; | 529 | inode->i_ctime.tv_sec += pTcon->ses->server->timeAdj; |
| 512 | inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj; | 530 | inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj; |
| 513 | } | 531 | } |
| 514 | 532 | ||
| 515 | /* set default mode. will override for dirs below */ | 533 | /* set default mode. will override for dirs below */ |
| 516 | if (atomic_read(&cifsInfo->inUse) == 0) | 534 | if (atomic_read(&cifsInfo->inUse) == 0) |
| 517 | /* new inode, can safely set these fields */ | 535 | /* new inode, can safely set these fields */ |
| 518 | inode->i_mode = cifs_sb->mnt_file_mode; | 536 | inode->i_mode = cifs_sb->mnt_file_mode; |
| 519 | else /* since we set the inode type below we need to mask off | 537 | else /* since we set the inode type below we need to mask off |
| 520 | to avoid strange results if type changes and both | 538 | to avoid strange results if type changes and both |
| 521 | get orred in */ | 539 | get orred in */ |
| 522 | inode->i_mode &= ~S_IFMT; | 540 | inode->i_mode &= ~S_IFMT; |
| 523 | /* if (attr & ATTR_REPARSE) */ | 541 | /* if (attr & ATTR_REPARSE) */ |
| 524 | /* We no longer handle these as symlinks because we could not | 542 | /* We no longer handle these as symlinks because we could not |
| 525 | follow them due to the absolute path with drive letter */ | 543 | follow them due to the absolute path with drive letter */ |
| 526 | if (attr & ATTR_DIRECTORY) { | 544 | if (attr & ATTR_DIRECTORY) { |
| 527 | /* override default perms since we do not do byte range locking | 545 | /* override default perms since we do not do byte range locking |
| 528 | on dirs */ | 546 | on dirs */ |
| 529 | inode->i_mode = cifs_sb->mnt_dir_mode; | 547 | inode->i_mode = cifs_sb->mnt_dir_mode; |
| 530 | inode->i_mode |= S_IFDIR; | 548 | inode->i_mode |= S_IFDIR; |
| 531 | } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && | 549 | } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && |
| 532 | (cifsInfo->cifsAttrs & ATTR_SYSTEM) && | 550 | (cifsInfo->cifsAttrs & ATTR_SYSTEM) && |
| 533 | /* No need to le64 convert size of zero */ | 551 | /* No need to le64 convert size of zero */ |
| 534 | (pfindData->EndOfFile == 0)) { | 552 | (pfindData->EndOfFile == 0)) { |
| 535 | inode->i_mode = cifs_sb->mnt_file_mode; | 553 | inode->i_mode = cifs_sb->mnt_file_mode; |
| 536 | inode->i_mode |= S_IFIFO; | 554 | inode->i_mode |= S_IFIFO; |
| 537 | /* BB Finish for SFU style symlinks and devices */ | 555 | /* BB Finish for SFU style symlinks and devices */ |
| 538 | } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && | 556 | } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && |
| 539 | (cifsInfo->cifsAttrs & ATTR_SYSTEM)) { | 557 | (cifsInfo->cifsAttrs & ATTR_SYSTEM)) { |
| 540 | if (decode_sfu_inode(inode, | 558 | if (decode_sfu_inode(inode, le64_to_cpu(pfindData->EndOfFile), |
| 541 | le64_to_cpu(pfindData->EndOfFile), | 559 | full_path, cifs_sb, xid)) |
| 542 | search_path, | 560 | cFYI(1, ("Unrecognized sfu inode type")); |
| 543 | cifs_sb, xid)) | ||
| 544 | cFYI(1, ("Unrecognized sfu inode type")); | ||
| 545 | |||
| 546 | cFYI(1, ("sfu mode 0%o", inode->i_mode)); | ||
| 547 | } else { | ||
| 548 | inode->i_mode |= S_IFREG; | ||
| 549 | /* treat the dos attribute of read-only as read-only | ||
| 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 | 561 | ||
| 563 | spin_lock(&inode->i_lock); | 562 | cFYI(1, ("sfu mode 0%o", inode->i_mode)); |
| 564 | if (is_size_safe_to_change(cifsInfo, | 563 | } else { |
| 565 | le64_to_cpu(pfindData->EndOfFile))) { | 564 | inode->i_mode |= S_IFREG; |
| 566 | /* can not safely shrink the file size here if the | 565 | /* treat dos attribute of read-only as read-only mode eg 555 */ |
| 567 | client is writing to it due to potential races */ | 566 | if (cifsInfo->cifsAttrs & ATTR_READONLY) |
| 568 | i_size_write(inode, le64_to_cpu(pfindData->EndOfFile)); | 567 | inode->i_mode &= ~(S_IWUGO); |
| 569 | 568 | else if ((inode->i_mode & S_IWUGO) == 0) | |
| 570 | /* 512 bytes (2**9) is the fake blocksize that must be | 569 | /* the ATTR_READONLY flag may have been */ |
| 571 | used for this calculation */ | 570 | /* changed on server -- set any w bits */ |
| 572 | inode->i_blocks = (512 - 1 + le64_to_cpu( | 571 | /* allowed by mnt_file_mode */ |
| 573 | pfindData->AllocationSize)) >> 9; | 572 | inode->i_mode |= (S_IWUGO & cifs_sb->mnt_file_mode); |
| 574 | } | 573 | /* BB add code to validate if device or weird share or device type? */ |
| 575 | spin_unlock(&inode->i_lock); | 574 | } |
| 575 | |||
| 576 | spin_lock(&inode->i_lock); | ||
| 577 | if (is_size_safe_to_change(cifsInfo, | ||
| 578 | le64_to_cpu(pfindData->EndOfFile))) { | ||
| 579 | /* can not safely shrink the file size here if the | ||
| 580 | client is writing to it due to potential races */ | ||
| 581 | i_size_write(inode, le64_to_cpu(pfindData->EndOfFile)); | ||
| 582 | |||
| 583 | /* 512 bytes (2**9) is the fake blocksize that must be | ||
| 584 | used for this calculation */ | ||
| 585 | inode->i_blocks = (512 - 1 + le64_to_cpu( | ||
| 586 | pfindData->AllocationSize)) >> 9; | ||
| 587 | } | ||
| 588 | spin_unlock(&inode->i_lock); | ||
| 576 | 589 | ||
| 577 | inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks); | 590 | inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks); |
| 578 | 591 | ||
| 579 | /* BB fill in uid and gid here? with help from winbind? | 592 | /* BB fill in uid and gid here? with help from winbind? |
| 580 | or retrieve from NTFS stream extended attribute */ | 593 | or retrieve from NTFS stream extended attribute */ |
| 581 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 594 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
| 582 | /* fill in 0777 bits from ACL */ | 595 | /* fill in 0777 bits from ACL */ |
| 583 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { | 596 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { |
| 584 | cFYI(1, ("Getting mode bits from ACL")); | 597 | cFYI(1, ("Getting mode bits from ACL")); |
| 585 | acl_to_uid_mode(inode, search_path, pfid); | 598 | acl_to_uid_mode(inode, full_path, pfid); |
| 586 | } | 599 | } |
| 587 | #endif | 600 | #endif |
| 588 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { | 601 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { |
| 589 | /* fill in remaining high mode bits e.g. SUID, VTX */ | 602 | /* fill in remaining high mode bits e.g. SUID, VTX */ |
| 590 | get_sfu_mode(inode, search_path, cifs_sb, xid); | 603 | get_sfu_mode(inode, full_path, cifs_sb, xid); |
| 591 | } else if (atomic_read(&cifsInfo->inUse) == 0) { | 604 | } else if (atomic_read(&cifsInfo->inUse) == 0) { |
| 592 | inode->i_uid = cifs_sb->mnt_uid; | 605 | inode->i_uid = cifs_sb->mnt_uid; |
| 593 | inode->i_gid = cifs_sb->mnt_gid; | 606 | inode->i_gid = cifs_sb->mnt_gid; |
| 594 | /* set so we do not keep refreshing these fields with | 607 | /* set so we do not keep refreshing these fields with |
| 595 | bad data after user has changed them in memory */ | 608 | bad data after user has changed them in memory */ |
| 596 | atomic_set(&cifsInfo->inUse, 1); | 609 | atomic_set(&cifsInfo->inUse, 1); |
| 597 | } | ||
| 598 | |||
| 599 | cifs_set_ops(inode, is_dfs_referral); | ||
| 600 | } | 610 | } |
| 611 | |||
| 612 | cifs_set_ops(inode, is_dfs_referral); | ||
| 613 | |||
| 614 | |||
| 615 | |||
| 616 | |||
| 601 | cgii_exit: | 617 | cgii_exit: |
| 602 | if (full_path != search_path) | ||
| 603 | kfree(full_path); | ||
| 604 | kfree(buf); | 618 | kfree(buf); |
| 605 | return rc; | 619 | return rc; |
| 606 | } | 620 | } |
| @@ -1502,8 +1516,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
| 1502 | int oplock = 0; | 1516 | int oplock = 0; |
| 1503 | 1517 | ||
| 1504 | rc = SMBLegacyOpen(xid, pTcon, full_path, | 1518 | rc = SMBLegacyOpen(xid, pTcon, full_path, |
| 1505 | FILE_OPEN, | 1519 | FILE_OPEN, GENERIC_WRITE, |
| 1506 | SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, | ||
| 1507 | CREATE_NOT_DIR, &netfid, &oplock, | 1520 | CREATE_NOT_DIR, &netfid, &oplock, |
| 1508 | NULL, cifs_sb->local_nls, | 1521 | NULL, cifs_sb->local_nls, |
| 1509 | cifs_sb->mnt_cifs_flags & | 1522 | cifs_sb->mnt_cifs_flags & |
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 | ||
| 33 | int cifs_ioctl(struct inode *inode, struct file *filep, | 33 | long 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/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 | ||
| 66 | typedef struct _NEGOTIATE_MESSAGE { | 66 | typedef 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 | ||
| 76 | typedef struct _CHALLENGE_MESSAGE { | 76 | typedef 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..713c25110197 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
| @@ -670,8 +670,11 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
| 670 | (index_to_find < first_entry_in_buffer)) { | 670 | (index_to_find < first_entry_in_buffer)) { |
| 671 | /* close and restart search */ | 671 | /* close and restart search */ |
| 672 | cFYI(1, ("search backing up - close and restart search")); | 672 | cFYI(1, ("search backing up - close and restart search")); |
| 673 | cifsFile->invalidHandle = true; | 673 | if (!cifsFile->srch_inf.endOfSearch && |
| 674 | CIFSFindClose(xid, pTcon, cifsFile->netfid); | 674 | !cifsFile->invalidHandle) { |
| 675 | cifsFile->invalidHandle = true; | ||
| 676 | CIFSFindClose(xid, pTcon, cifsFile->netfid); | ||
| 677 | } | ||
| 675 | kfree(cifsFile->search_resume_name); | 678 | kfree(cifsFile->search_resume_name); |
| 676 | cifsFile->search_resume_name = NULL; | 679 | cifsFile->search_resume_name = NULL; |
| 677 | if (cifsFile->srch_inf.ntwrk_buf_start) { | 680 | if (cifsFile->srch_inf.ntwrk_buf_start) { |
