diff options
-rw-r--r-- | fs/cifs/cifs_fs_sb.h | 4 | ||||
-rw-r--r-- | fs/cifs/cifsacl.c | 18 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 7 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 1 | ||||
-rw-r--r-- | fs/cifs/connect.c | 27 | ||||
-rw-r--r-- | fs/cifs/dir.c | 10 | ||||
-rw-r--r-- | fs/cifs/file.c | 12 | ||||
-rw-r--r-- | fs/cifs/link.c | 17 | ||||
-rw-r--r-- | fs/cifs/misc.c | 15 |
9 files changed, 95 insertions, 16 deletions
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index 7260e11e21f8..500d65859279 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h | |||
@@ -43,6 +43,8 @@ | |||
43 | #define CIFS_MOUNT_STRICT_IO 0x40000 /* strict cache mode */ | 43 | #define CIFS_MOUNT_STRICT_IO 0x40000 /* strict cache mode */ |
44 | #define CIFS_MOUNT_RWPIDFORWARD 0x80000 /* use pid forwarding for rw */ | 44 | #define CIFS_MOUNT_RWPIDFORWARD 0x80000 /* use pid forwarding for rw */ |
45 | #define CIFS_MOUNT_POSIXACL 0x100000 /* mirror of MS_POSIXACL in mnt_cifs_flags */ | 45 | #define CIFS_MOUNT_POSIXACL 0x100000 /* mirror of MS_POSIXACL in mnt_cifs_flags */ |
46 | #define CIFS_MOUNT_CIFS_BACKUPUID 0x200000 /* backup intent bit for a user */ | ||
47 | #define CIFS_MOUNT_CIFS_BACKUPGID 0x400000 /* backup intent bit for a group */ | ||
46 | 48 | ||
47 | struct cifs_sb_info { | 49 | struct cifs_sb_info { |
48 | struct rb_root tlink_tree; | 50 | struct rb_root tlink_tree; |
@@ -55,6 +57,8 @@ struct cifs_sb_info { | |||
55 | atomic_t active; | 57 | atomic_t active; |
56 | uid_t mnt_uid; | 58 | uid_t mnt_uid; |
57 | gid_t mnt_gid; | 59 | gid_t mnt_gid; |
60 | uid_t mnt_backupuid; | ||
61 | gid_t mnt_backupgid; | ||
58 | mode_t mnt_file_mode; | 62 | mode_t mnt_file_mode; |
59 | mode_t mnt_dir_mode; | 63 | mode_t mnt_dir_mode; |
60 | unsigned int mnt_cifs_flags; | 64 | unsigned int mnt_cifs_flags; |
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index d0f59faefb78..b244e07c3048 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c | |||
@@ -945,7 +945,7 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, | |||
945 | { | 945 | { |
946 | struct cifs_ntsd *pntsd = NULL; | 946 | struct cifs_ntsd *pntsd = NULL; |
947 | int oplock = 0; | 947 | int oplock = 0; |
948 | int xid, rc; | 948 | int xid, rc, create_options = 0; |
949 | __u16 fid; | 949 | __u16 fid; |
950 | struct cifs_tcon *tcon; | 950 | struct cifs_tcon *tcon; |
951 | struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); | 951 | struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); |
@@ -956,9 +956,12 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, | |||
956 | tcon = tlink_tcon(tlink); | 956 | tcon = tlink_tcon(tlink); |
957 | xid = GetXid(); | 957 | xid = GetXid(); |
958 | 958 | ||
959 | rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL, 0, | 959 | if (backup_cred(cifs_sb)) |
960 | &fid, &oplock, NULL, cifs_sb->local_nls, | 960 | create_options |= CREATE_OPEN_BACKUP_INTENT; |
961 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 961 | |
962 | rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL, | ||
963 | create_options, &fid, &oplock, NULL, cifs_sb->local_nls, | ||
964 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
962 | if (!rc) { | 965 | if (!rc) { |
963 | rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen); | 966 | rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen); |
964 | CIFSSMBClose(xid, tcon, fid); | 967 | CIFSSMBClose(xid, tcon, fid); |
@@ -995,7 +998,7 @@ static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path, | |||
995 | struct cifs_ntsd *pnntsd, u32 acllen) | 998 | struct cifs_ntsd *pnntsd, u32 acllen) |
996 | { | 999 | { |
997 | int oplock = 0; | 1000 | int oplock = 0; |
998 | int xid, rc; | 1001 | int xid, rc, create_options = 0; |
999 | __u16 fid; | 1002 | __u16 fid; |
1000 | struct cifs_tcon *tcon; | 1003 | struct cifs_tcon *tcon; |
1001 | struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); | 1004 | struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); |
@@ -1006,7 +1009,10 @@ static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path, | |||
1006 | tcon = tlink_tcon(tlink); | 1009 | tcon = tlink_tcon(tlink); |
1007 | xid = GetXid(); | 1010 | xid = GetXid(); |
1008 | 1011 | ||
1009 | rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, WRITE_DAC, 0, | 1012 | if (backup_cred(cifs_sb)) |
1013 | create_options |= CREATE_OPEN_BACKUP_INTENT; | ||
1014 | |||
1015 | rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, WRITE_DAC, create_options, | ||
1010 | &fid, &oplock, NULL, cifs_sb->local_nls, | 1016 | &fid, &oplock, NULL, cifs_sb->local_nls, |
1011 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 1017 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
1012 | if (rc) { | 1018 | if (rc) { |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index d734dee9d495..9551437a2498 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -167,6 +167,8 @@ struct smb_vol { | |||
167 | uid_t cred_uid; | 167 | uid_t cred_uid; |
168 | uid_t linux_uid; | 168 | uid_t linux_uid; |
169 | gid_t linux_gid; | 169 | gid_t linux_gid; |
170 | uid_t backupuid; | ||
171 | gid_t backupgid; | ||
170 | mode_t file_mode; | 172 | mode_t file_mode; |
171 | mode_t dir_mode; | 173 | mode_t dir_mode; |
172 | unsigned secFlg; | 174 | unsigned secFlg; |
@@ -179,6 +181,8 @@ struct smb_vol { | |||
179 | bool noperm:1; | 181 | bool noperm:1; |
180 | bool no_psx_acl:1; /* set if posix acl support should be disabled */ | 182 | bool no_psx_acl:1; /* set if posix acl support should be disabled */ |
181 | bool cifs_acl:1; | 183 | bool cifs_acl:1; |
184 | bool backupuid_specified; /* mount option backupuid is specified */ | ||
185 | bool backupgid_specified; /* mount option backupgid is specified */ | ||
182 | bool no_xattr:1; /* set if xattr (EA) support should be disabled*/ | 186 | bool no_xattr:1; /* set if xattr (EA) support should be disabled*/ |
183 | bool server_ino:1; /* use inode numbers from server ie UniqueId */ | 187 | bool server_ino:1; /* use inode numbers from server ie UniqueId */ |
184 | bool direct_io:1; | 188 | bool direct_io:1; |
@@ -219,7 +223,8 @@ struct smb_vol { | |||
219 | CIFS_MOUNT_OVERR_GID | CIFS_MOUNT_DYNPERM | \ | 223 | CIFS_MOUNT_OVERR_GID | CIFS_MOUNT_DYNPERM | \ |
220 | CIFS_MOUNT_NOPOSIXBRL | CIFS_MOUNT_NOSSYNC | \ | 224 | CIFS_MOUNT_NOPOSIXBRL | CIFS_MOUNT_NOSSYNC | \ |
221 | CIFS_MOUNT_FSCACHE | CIFS_MOUNT_MF_SYMLINKS | \ | 225 | CIFS_MOUNT_FSCACHE | CIFS_MOUNT_MF_SYMLINKS | \ |
222 | CIFS_MOUNT_MULTIUSER | CIFS_MOUNT_STRICT_IO) | 226 | CIFS_MOUNT_MULTIUSER | CIFS_MOUNT_STRICT_IO | \ |
227 | CIFS_MOUNT_CIFS_BACKUPUID | CIFS_MOUNT_CIFS_BACKUPGID) | ||
223 | 228 | ||
224 | #define CIFS_MS_MASK (MS_RDONLY | MS_MANDLOCK | MS_NOEXEC | MS_NOSUID | \ | 229 | #define CIFS_MS_MASK (MS_RDONLY | MS_MANDLOCK | MS_NOEXEC | MS_NOSUID | \ |
225 | MS_NODEV | MS_SYNCHRONOUS) | 230 | MS_NODEV | MS_SYNCHRONOUS) |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 03dc945d94a3..9ddb1eccde69 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -90,6 +90,7 @@ extern int SendReceiveBlockingLock(const unsigned int xid, | |||
90 | extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length); | 90 | extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length); |
91 | extern bool is_valid_oplock_break(struct smb_hdr *smb, | 91 | extern bool is_valid_oplock_break(struct smb_hdr *smb, |
92 | struct TCP_Server_Info *); | 92 | struct TCP_Server_Info *); |
93 | extern bool backup_cred(struct cifs_sb_info *); | ||
93 | extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof); | 94 | extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof); |
94 | extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, | 95 | extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, |
95 | unsigned int bytes_written); | 96 | unsigned int bytes_written); |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index abbc6c3fe3f1..70dd2c418276 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -831,6 +831,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
831 | { | 831 | { |
832 | char *value, *data, *end; | 832 | char *value, *data, *end; |
833 | char *mountdata_copy = NULL, *options; | 833 | char *mountdata_copy = NULL, *options; |
834 | int err; | ||
834 | unsigned int temp_len, i, j; | 835 | unsigned int temp_len, i, j; |
835 | char separator[2]; | 836 | char separator[2]; |
836 | short int override_uid = -1; | 837 | short int override_uid = -1; |
@@ -887,6 +888,8 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
887 | cFYI(1, "Null separator not allowed"); | 888 | cFYI(1, "Null separator not allowed"); |
888 | } | 889 | } |
889 | } | 890 | } |
891 | vol->backupuid_specified = false; /* no backup intent for a user */ | ||
892 | vol->backupgid_specified = false; /* no backup intent for a group */ | ||
890 | 893 | ||
891 | while ((data = strsep(&options, separator)) != NULL) { | 894 | while ((data = strsep(&options, separator)) != NULL) { |
892 | if (!*data) | 895 | if (!*data) |
@@ -1446,6 +1449,22 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
1446 | vol->mfsymlinks = true; | 1449 | vol->mfsymlinks = true; |
1447 | } else if (strnicmp(data, "multiuser", 8) == 0) { | 1450 | } else if (strnicmp(data, "multiuser", 8) == 0) { |
1448 | vol->multiuser = true; | 1451 | vol->multiuser = true; |
1452 | } else if (!strnicmp(data, "backupuid", 9) && value && *value) { | ||
1453 | err = kstrtouint(value, 0, &vol->backupuid); | ||
1454 | if (err < 0) { | ||
1455 | cERROR(1, "%s: Invalid backupuid value", | ||
1456 | __func__); | ||
1457 | goto cifs_parse_mount_err; | ||
1458 | } | ||
1459 | vol->backupuid_specified = true; | ||
1460 | } else if (!strnicmp(data, "backupgid", 9) && value && *value) { | ||
1461 | err = kstrtouint(value, 0, &vol->backupgid); | ||
1462 | if (err < 0) { | ||
1463 | cERROR(1, "%s: Invalid backupgid value", | ||
1464 | __func__); | ||
1465 | goto cifs_parse_mount_err; | ||
1466 | } | ||
1467 | vol->backupgid_specified = true; | ||
1449 | } else | 1468 | } else |
1450 | printk(KERN_WARNING "CIFS: Unknown mount option %s\n", | 1469 | printk(KERN_WARNING "CIFS: Unknown mount option %s\n", |
1451 | data); | 1470 | data); |
@@ -2737,6 +2756,10 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info, | |||
2737 | 2756 | ||
2738 | cifs_sb->mnt_uid = pvolume_info->linux_uid; | 2757 | cifs_sb->mnt_uid = pvolume_info->linux_uid; |
2739 | cifs_sb->mnt_gid = pvolume_info->linux_gid; | 2758 | cifs_sb->mnt_gid = pvolume_info->linux_gid; |
2759 | if (pvolume_info->backupuid_specified) | ||
2760 | cifs_sb->mnt_backupuid = pvolume_info->backupuid; | ||
2761 | if (pvolume_info->backupgid_specified) | ||
2762 | cifs_sb->mnt_backupgid = pvolume_info->backupgid; | ||
2740 | cifs_sb->mnt_file_mode = pvolume_info->file_mode; | 2763 | cifs_sb->mnt_file_mode = pvolume_info->file_mode; |
2741 | cifs_sb->mnt_dir_mode = pvolume_info->dir_mode; | 2764 | cifs_sb->mnt_dir_mode = pvolume_info->dir_mode; |
2742 | cFYI(1, "file mode: 0x%x dir mode: 0x%x", | 2765 | cFYI(1, "file mode: 0x%x dir mode: 0x%x", |
@@ -2767,6 +2790,10 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info, | |||
2767 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_RWPIDFORWARD; | 2790 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_RWPIDFORWARD; |
2768 | if (pvolume_info->cifs_acl) | 2791 | if (pvolume_info->cifs_acl) |
2769 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL; | 2792 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL; |
2793 | if (pvolume_info->backupuid_specified) | ||
2794 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_BACKUPUID; | ||
2795 | if (pvolume_info->backupgid_specified) | ||
2796 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_BACKUPGID; | ||
2770 | if (pvolume_info->override_uid) | 2797 | if (pvolume_info->override_uid) |
2771 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID; | 2798 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID; |
2772 | if (pvolume_info->override_gid) | 2799 | if (pvolume_info->override_gid) |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 4dd5333753fa..0c8098d54d2b 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -244,6 +244,9 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
244 | if (!tcon->unix_ext && (mode & S_IWUGO) == 0) | 244 | if (!tcon->unix_ext && (mode & S_IWUGO) == 0) |
245 | create_options |= CREATE_OPTION_READONLY; | 245 | create_options |= CREATE_OPTION_READONLY; |
246 | 246 | ||
247 | if (backup_cred(cifs_sb)) | ||
248 | create_options |= CREATE_OPEN_BACKUP_INTENT; | ||
249 | |||
247 | if (tcon->ses->capabilities & CAP_NT_SMBS) | 250 | if (tcon->ses->capabilities & CAP_NT_SMBS) |
248 | rc = CIFSSMBOpen(xid, tcon, full_path, disposition, | 251 | rc = CIFSSMBOpen(xid, tcon, full_path, disposition, |
249 | desiredAccess, create_options, | 252 | desiredAccess, create_options, |
@@ -357,6 +360,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, | |||
357 | { | 360 | { |
358 | int rc = -EPERM; | 361 | int rc = -EPERM; |
359 | int xid; | 362 | int xid; |
363 | int create_options = CREATE_NOT_DIR | CREATE_OPTION_SPECIAL; | ||
360 | struct cifs_sb_info *cifs_sb; | 364 | struct cifs_sb_info *cifs_sb; |
361 | struct tcon_link *tlink; | 365 | struct tcon_link *tlink; |
362 | struct cifs_tcon *pTcon; | 366 | struct cifs_tcon *pTcon; |
@@ -431,9 +435,11 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, | |||
431 | return rc; | 435 | return rc; |
432 | } | 436 | } |
433 | 437 | ||
434 | /* FIXME: would WRITE_OWNER | WRITE_DAC be better? */ | 438 | if (backup_cred(cifs_sb)) |
439 | create_options |= CREATE_OPEN_BACKUP_INTENT; | ||
440 | |||
435 | rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_CREATE, | 441 | rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_CREATE, |
436 | GENERIC_WRITE, CREATE_NOT_DIR | CREATE_OPTION_SPECIAL, | 442 | GENERIC_WRITE, create_options, |
437 | &fileHandle, &oplock, buf, cifs_sb->local_nls, | 443 | &fileHandle, &oplock, buf, cifs_sb->local_nls, |
438 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 444 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
439 | if (rc) | 445 | if (rc) |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 8e184150cfb5..237192ae7587 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -174,6 +174,7 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb, | |||
174 | int rc; | 174 | int rc; |
175 | int desiredAccess; | 175 | int desiredAccess; |
176 | int disposition; | 176 | int disposition; |
177 | int create_options = CREATE_NOT_DIR; | ||
177 | FILE_ALL_INFO *buf; | 178 | FILE_ALL_INFO *buf; |
178 | 179 | ||
179 | desiredAccess = cifs_convert_flags(f_flags); | 180 | desiredAccess = cifs_convert_flags(f_flags); |
@@ -210,9 +211,12 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb, | |||
210 | if (!buf) | 211 | if (!buf) |
211 | return -ENOMEM; | 212 | return -ENOMEM; |
212 | 213 | ||
214 | if (backup_cred(cifs_sb)) | ||
215 | create_options |= CREATE_OPEN_BACKUP_INTENT; | ||
216 | |||
213 | if (tcon->ses->capabilities & CAP_NT_SMBS) | 217 | if (tcon->ses->capabilities & CAP_NT_SMBS) |
214 | rc = CIFSSMBOpen(xid, tcon, full_path, disposition, | 218 | rc = CIFSSMBOpen(xid, tcon, full_path, disposition, |
215 | desiredAccess, CREATE_NOT_DIR, pnetfid, poplock, buf, | 219 | desiredAccess, create_options, pnetfid, poplock, buf, |
216 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags | 220 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags |
217 | & CIFS_MOUNT_MAP_SPECIAL_CHR); | 221 | & CIFS_MOUNT_MAP_SPECIAL_CHR); |
218 | else | 222 | else |
@@ -465,6 +469,7 @@ static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush) | |||
465 | char *full_path = NULL; | 469 | char *full_path = NULL; |
466 | int desiredAccess; | 470 | int desiredAccess; |
467 | int disposition = FILE_OPEN; | 471 | int disposition = FILE_OPEN; |
472 | int create_options = CREATE_NOT_DIR; | ||
468 | __u16 netfid; | 473 | __u16 netfid; |
469 | 474 | ||
470 | xid = GetXid(); | 475 | xid = GetXid(); |
@@ -524,6 +529,9 @@ static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush) | |||
524 | 529 | ||
525 | desiredAccess = cifs_convert_flags(pCifsFile->f_flags); | 530 | desiredAccess = cifs_convert_flags(pCifsFile->f_flags); |
526 | 531 | ||
532 | if (backup_cred(cifs_sb)) | ||
533 | create_options |= CREATE_OPEN_BACKUP_INTENT; | ||
534 | |||
527 | /* Can not refresh inode by passing in file_info buf to be returned | 535 | /* Can not refresh inode by passing in file_info buf to be returned |
528 | by SMBOpen and then calling get_inode_info with returned buf | 536 | by SMBOpen and then calling get_inode_info with returned buf |
529 | since file might have write behind data that needs to be flushed | 537 | since file might have write behind data that needs to be flushed |
@@ -531,7 +539,7 @@ static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush) | |||
531 | that inode was not dirty locally we could do this */ | 539 | that inode was not dirty locally we could do this */ |
532 | 540 | ||
533 | rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess, | 541 | rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess, |
534 | CREATE_NOT_DIR, &netfid, &oplock, NULL, | 542 | create_options, &netfid, &oplock, NULL, |
535 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & | 543 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & |
536 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 544 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
537 | if (rc) { | 545 | if (rc) { |
diff --git a/fs/cifs/link.c b/fs/cifs/link.c index db3f18cdf024..8693b5d0e180 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c | |||
@@ -183,14 +183,20 @@ CIFSFormatMFSymlink(u8 *buf, unsigned int buf_len, const char *link_str) | |||
183 | static int | 183 | static int |
184 | CIFSCreateMFSymLink(const int xid, struct cifs_tcon *tcon, | 184 | CIFSCreateMFSymLink(const int xid, struct cifs_tcon *tcon, |
185 | const char *fromName, const char *toName, | 185 | const char *fromName, const char *toName, |
186 | const struct nls_table *nls_codepage, int remap) | 186 | struct cifs_sb_info *cifs_sb) |
187 | { | 187 | { |
188 | int rc; | 188 | int rc; |
189 | int oplock = 0; | 189 | int oplock = 0; |
190 | int remap; | ||
191 | int create_options = CREATE_NOT_DIR; | ||
190 | __u16 netfid = 0; | 192 | __u16 netfid = 0; |
191 | u8 *buf; | 193 | u8 *buf; |
192 | unsigned int bytes_written = 0; | 194 | unsigned int bytes_written = 0; |
193 | struct cifs_io_parms io_parms; | 195 | struct cifs_io_parms io_parms; |
196 | struct nls_table *nls_codepage; | ||
197 | |||
198 | nls_codepage = cifs_sb->local_nls; | ||
199 | remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR; | ||
194 | 200 | ||
195 | buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL); | 201 | buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL); |
196 | if (!buf) | 202 | if (!buf) |
@@ -202,8 +208,11 @@ CIFSCreateMFSymLink(const int xid, struct cifs_tcon *tcon, | |||
202 | return rc; | 208 | return rc; |
203 | } | 209 | } |
204 | 210 | ||
211 | if (backup_cred(cifs_sb)) | ||
212 | create_options |= CREATE_OPEN_BACKUP_INTENT; | ||
213 | |||
205 | rc = CIFSSMBOpen(xid, tcon, fromName, FILE_CREATE, GENERIC_WRITE, | 214 | rc = CIFSSMBOpen(xid, tcon, fromName, FILE_CREATE, GENERIC_WRITE, |
206 | CREATE_NOT_DIR, &netfid, &oplock, NULL, | 215 | create_options, &netfid, &oplock, NULL, |
207 | nls_codepage, remap); | 216 | nls_codepage, remap); |
208 | if (rc != 0) { | 217 | if (rc != 0) { |
209 | kfree(buf); | 218 | kfree(buf); |
@@ -559,9 +568,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) | |||
559 | /* BB what if DFS and this volume is on different share? BB */ | 568 | /* BB what if DFS and this volume is on different share? BB */ |
560 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) | 569 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) |
561 | rc = CIFSCreateMFSymLink(xid, pTcon, full_path, symname, | 570 | rc = CIFSCreateMFSymLink(xid, pTcon, full_path, symname, |
562 | cifs_sb->local_nls, | 571 | cifs_sb); |
563 | cifs_sb->mnt_cifs_flags & | ||
564 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
565 | else if (pTcon->unix_ext) | 572 | else if (pTcon->unix_ext) |
566 | rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname, | 573 | rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname, |
567 | cifs_sb->local_nls); | 574 | cifs_sb->local_nls); |
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 4a1801b3195f..703ef5c6fdb1 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
@@ -675,3 +675,18 @@ void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock) | |||
675 | cinode->clientCanCacheRead = false; | 675 | cinode->clientCanCacheRead = false; |
676 | } | 676 | } |
677 | } | 677 | } |
678 | |||
679 | bool | ||
680 | backup_cred(struct cifs_sb_info *cifs_sb) | ||
681 | { | ||
682 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPUID) { | ||
683 | if (cifs_sb->mnt_backupuid == current_fsuid()) | ||
684 | return true; | ||
685 | } | ||
686 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPGID) { | ||
687 | if (in_group_p(cifs_sb->mnt_backupgid)) | ||
688 | return true; | ||
689 | } | ||
690 | |||
691 | return false; | ||
692 | } | ||