diff options
| -rw-r--r-- | fs/cifs/cifsglob.h | 10 | ||||
| -rw-r--r-- | fs/cifs/cifsproto.h | 11 | ||||
| -rw-r--r-- | fs/cifs/cifssmb.c | 31 | ||||
| -rw-r--r-- | fs/cifs/inode.c | 302 | ||||
| -rw-r--r-- | fs/cifs/smb1ops.c | 24 | ||||
| -rw-r--r-- | fs/cifs/smb2inode.c | 39 | ||||
| -rw-r--r-- | fs/cifs/smb2ops.c | 3 | ||||
| -rw-r--r-- | fs/cifs/smb2proto.h | 8 |
8 files changed, 270 insertions, 158 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 497da5ce704c..977dc0e85ccb 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
| @@ -246,6 +246,16 @@ struct smb_version_operations { | |||
| 246 | bool (*can_echo)(struct TCP_Server_Info *); | 246 | bool (*can_echo)(struct TCP_Server_Info *); |
| 247 | /* send echo request */ | 247 | /* send echo request */ |
| 248 | int (*echo)(struct TCP_Server_Info *); | 248 | int (*echo)(struct TCP_Server_Info *); |
| 249 | /* create directory */ | ||
| 250 | int (*mkdir)(const unsigned int, struct cifs_tcon *, const char *, | ||
| 251 | struct cifs_sb_info *); | ||
| 252 | /* set info on created directory */ | ||
| 253 | void (*mkdir_setinfo)(struct inode *, const char *, | ||
| 254 | struct cifs_sb_info *, struct cifs_tcon *, | ||
| 255 | const unsigned int); | ||
| 256 | /* remove directory */ | ||
| 257 | int (*rmdir)(const unsigned int, struct cifs_tcon *, const char *, | ||
| 258 | struct cifs_sb_info *); | ||
| 249 | }; | 259 | }; |
| 250 | 260 | ||
| 251 | struct smb_version_values { | 261 | struct smb_version_values { |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index cf7fb185103c..f1bbf8305d3a 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
| @@ -289,18 +289,15 @@ extern int CIFSSMBUnixSetFileInfo(const unsigned int xid, | |||
| 289 | u16 fid, u32 pid_of_opener); | 289 | u16 fid, u32 pid_of_opener); |
| 290 | 290 | ||
| 291 | extern int CIFSSMBUnixSetPathInfo(const unsigned int xid, | 291 | extern int CIFSSMBUnixSetPathInfo(const unsigned int xid, |
| 292 | struct cifs_tcon *tcon, char *file_name, | 292 | struct cifs_tcon *tcon, const char *file_name, |
| 293 | const struct cifs_unix_set_info_args *args, | 293 | const struct cifs_unix_set_info_args *args, |
| 294 | const struct nls_table *nls_codepage, | 294 | const struct nls_table *nls_codepage, |
| 295 | int remap_special_chars); | 295 | int remap); |
| 296 | 296 | ||
| 297 | extern int CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, | 297 | extern int CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, |
| 298 | const char *newName, | 298 | const char *name, struct cifs_sb_info *cifs_sb); |
| 299 | const struct nls_table *nls_codepage, | ||
| 300 | int remap_special_chars); | ||
| 301 | extern int CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, | 299 | extern int CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, |
| 302 | const char *name, const struct nls_table *nls_codepage, | 300 | const char *name, struct cifs_sb_info *cifs_sb); |
| 303 | int remap_special_chars); | ||
| 304 | extern int CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon, | 301 | extern int CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon, |
| 305 | const char *name, __u16 type, | 302 | const char *name, __u16 type, |
| 306 | const struct nls_table *nls_codepage, | 303 | const struct nls_table *nls_codepage, |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index cabc7a01f5df..074923ce593d 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
| @@ -948,15 +948,15 @@ DelFileRetry: | |||
| 948 | } | 948 | } |
| 949 | 949 | ||
| 950 | int | 950 | int |
| 951 | CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, | 951 | CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, |
| 952 | const char *dirName, const struct nls_table *nls_codepage, | 952 | struct cifs_sb_info *cifs_sb) |
| 953 | int remap) | ||
| 954 | { | 953 | { |
| 955 | DELETE_DIRECTORY_REQ *pSMB = NULL; | 954 | DELETE_DIRECTORY_REQ *pSMB = NULL; |
| 956 | DELETE_DIRECTORY_RSP *pSMBr = NULL; | 955 | DELETE_DIRECTORY_RSP *pSMBr = NULL; |
| 957 | int rc = 0; | 956 | int rc = 0; |
| 958 | int bytes_returned; | 957 | int bytes_returned; |
| 959 | int name_len; | 958 | int name_len; |
| 959 | int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR; | ||
| 960 | 960 | ||
| 961 | cFYI(1, "In CIFSSMBRmDir"); | 961 | cFYI(1, "In CIFSSMBRmDir"); |
| 962 | RmDirRetry: | 962 | RmDirRetry: |
| @@ -966,14 +966,15 @@ RmDirRetry: | |||
| 966 | return rc; | 966 | return rc; |
| 967 | 967 | ||
| 968 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 968 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { |
| 969 | name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, dirName, | 969 | name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name, |
| 970 | PATH_MAX, nls_codepage, remap); | 970 | PATH_MAX, cifs_sb->local_nls, |
| 971 | remap); | ||
| 971 | name_len++; /* trailing null */ | 972 | name_len++; /* trailing null */ |
| 972 | name_len *= 2; | 973 | name_len *= 2; |
| 973 | } else { /* BB improve check for buffer overruns BB */ | 974 | } else { /* BB improve check for buffer overruns BB */ |
| 974 | name_len = strnlen(dirName, PATH_MAX); | 975 | name_len = strnlen(name, PATH_MAX); |
| 975 | name_len++; /* trailing null */ | 976 | name_len++; /* trailing null */ |
| 976 | strncpy(pSMB->DirName, dirName, name_len); | 977 | strncpy(pSMB->DirName, name, name_len); |
| 977 | } | 978 | } |
| 978 | 979 | ||
| 979 | pSMB->BufferFormat = 0x04; | 980 | pSMB->BufferFormat = 0x04; |
| @@ -992,14 +993,15 @@ RmDirRetry: | |||
| 992 | } | 993 | } |
| 993 | 994 | ||
| 994 | int | 995 | int |
| 995 | CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, | 996 | CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, |
| 996 | const char *name, const struct nls_table *nls_codepage, int remap) | 997 | struct cifs_sb_info *cifs_sb) |
| 997 | { | 998 | { |
| 998 | int rc = 0; | 999 | int rc = 0; |
| 999 | CREATE_DIRECTORY_REQ *pSMB = NULL; | 1000 | CREATE_DIRECTORY_REQ *pSMB = NULL; |
| 1000 | CREATE_DIRECTORY_RSP *pSMBr = NULL; | 1001 | CREATE_DIRECTORY_RSP *pSMBr = NULL; |
| 1001 | int bytes_returned; | 1002 | int bytes_returned; |
| 1002 | int name_len; | 1003 | int name_len; |
| 1004 | int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR; | ||
| 1003 | 1005 | ||
| 1004 | cFYI(1, "In CIFSSMBMkDir"); | 1006 | cFYI(1, "In CIFSSMBMkDir"); |
| 1005 | MkDirRetry: | 1007 | MkDirRetry: |
| @@ -1010,7 +1012,8 @@ MkDirRetry: | |||
| 1010 | 1012 | ||
| 1011 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 1013 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { |
| 1012 | name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name, | 1014 | name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name, |
| 1013 | PATH_MAX, nls_codepage, remap); | 1015 | PATH_MAX, cifs_sb->local_nls, |
| 1016 | remap); | ||
| 1014 | name_len++; /* trailing null */ | 1017 | name_len++; /* trailing null */ |
| 1015 | name_len *= 2; | 1018 | name_len *= 2; |
| 1016 | } else { /* BB improve check for buffer overruns BB */ | 1019 | } else { /* BB improve check for buffer overruns BB */ |
| @@ -5943,7 +5946,7 @@ CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon, | |||
| 5943 | 5946 | ||
| 5944 | int | 5947 | int |
| 5945 | CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon, | 5948 | CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon, |
| 5946 | char *fileName, | 5949 | const char *file_name, |
| 5947 | const struct cifs_unix_set_info_args *args, | 5950 | const struct cifs_unix_set_info_args *args, |
| 5948 | const struct nls_table *nls_codepage, int remap) | 5951 | const struct nls_table *nls_codepage, int remap) |
| 5949 | { | 5952 | { |
| @@ -5964,14 +5967,14 @@ setPermsRetry: | |||
| 5964 | 5967 | ||
| 5965 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 5968 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { |
| 5966 | name_len = | 5969 | name_len = |
| 5967 | cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName, | 5970 | cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name, |
| 5968 | PATH_MAX, nls_codepage, remap); | 5971 | PATH_MAX, nls_codepage, remap); |
| 5969 | name_len++; /* trailing null */ | 5972 | name_len++; /* trailing null */ |
| 5970 | name_len *= 2; | 5973 | name_len *= 2; |
| 5971 | } else { /* BB improve the check for buffer overruns BB */ | 5974 | } else { /* BB improve the check for buffer overruns BB */ |
| 5972 | name_len = strnlen(fileName, PATH_MAX); | 5975 | name_len = strnlen(file_name, PATH_MAX); |
| 5973 | name_len++; /* trailing null */ | 5976 | name_len++; /* trailing null */ |
| 5974 | strncpy(pSMB->FileName, fileName, name_len); | 5977 | strncpy(pSMB->FileName, file_name, name_len); |
| 5975 | } | 5978 | } |
| 5976 | 5979 | ||
| 5977 | params = 6 + name_len; | 5980 | params = 6 + name_len; |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 35cb6a374a45..7354877fa3bd 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
| @@ -1219,16 +1219,153 @@ unlink_out: | |||
| 1219 | return rc; | 1219 | return rc; |
| 1220 | } | 1220 | } |
| 1221 | 1221 | ||
| 1222 | static int | ||
| 1223 | cifs_mkdir_qinfo(struct inode *inode, struct dentry *dentry, umode_t mode, | ||
| 1224 | const char *full_path, struct cifs_sb_info *cifs_sb, | ||
| 1225 | struct cifs_tcon *tcon, const unsigned int xid) | ||
| 1226 | { | ||
| 1227 | int rc = 0; | ||
| 1228 | struct inode *newinode = NULL; | ||
| 1229 | |||
| 1230 | if (tcon->unix_ext) | ||
| 1231 | rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb, | ||
| 1232 | xid); | ||
| 1233 | else | ||
| 1234 | rc = cifs_get_inode_info(&newinode, full_path, NULL, | ||
| 1235 | inode->i_sb, xid, NULL); | ||
| 1236 | if (rc) | ||
| 1237 | return rc; | ||
| 1238 | |||
| 1239 | d_instantiate(dentry, newinode); | ||
| 1240 | /* | ||
| 1241 | * setting nlink not necessary except in cases where we failed to get it | ||
| 1242 | * from the server or was set bogus | ||
| 1243 | */ | ||
| 1244 | if ((dentry->d_inode) && (dentry->d_inode->i_nlink < 2)) | ||
| 1245 | set_nlink(dentry->d_inode, 2); | ||
| 1246 | |||
| 1247 | mode &= ~current_umask(); | ||
| 1248 | /* must turn on setgid bit if parent dir has it */ | ||
| 1249 | if (inode->i_mode & S_ISGID) | ||
| 1250 | mode |= S_ISGID; | ||
| 1251 | |||
| 1252 | if (tcon->unix_ext) { | ||
| 1253 | struct cifs_unix_set_info_args args = { | ||
| 1254 | .mode = mode, | ||
| 1255 | .ctime = NO_CHANGE_64, | ||
| 1256 | .atime = NO_CHANGE_64, | ||
| 1257 | .mtime = NO_CHANGE_64, | ||
| 1258 | .device = 0, | ||
| 1259 | }; | ||
| 1260 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { | ||
| 1261 | args.uid = (__u64)current_fsuid(); | ||
| 1262 | if (inode->i_mode & S_ISGID) | ||
| 1263 | args.gid = (__u64)inode->i_gid; | ||
| 1264 | else | ||
| 1265 | args.gid = (__u64)current_fsgid(); | ||
| 1266 | } else { | ||
| 1267 | args.uid = NO_CHANGE_64; | ||
| 1268 | args.gid = NO_CHANGE_64; | ||
| 1269 | } | ||
| 1270 | CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args, | ||
| 1271 | cifs_sb->local_nls, | ||
| 1272 | cifs_sb->mnt_cifs_flags & | ||
| 1273 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 1274 | } else { | ||
| 1275 | struct TCP_Server_Info *server = tcon->ses->server; | ||
| 1276 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) && | ||
| 1277 | (mode & S_IWUGO) == 0 && server->ops->mkdir_setinfo) | ||
| 1278 | server->ops->mkdir_setinfo(newinode, full_path, cifs_sb, | ||
| 1279 | tcon, xid); | ||
| 1280 | if (dentry->d_inode) { | ||
| 1281 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) | ||
| 1282 | dentry->d_inode->i_mode = (mode | S_IFDIR); | ||
| 1283 | |||
| 1284 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { | ||
| 1285 | dentry->d_inode->i_uid = current_fsuid(); | ||
| 1286 | if (inode->i_mode & S_ISGID) | ||
| 1287 | dentry->d_inode->i_gid = inode->i_gid; | ||
| 1288 | else | ||
| 1289 | dentry->d_inode->i_gid = | ||
| 1290 | current_fsgid(); | ||
| 1291 | } | ||
| 1292 | } | ||
| 1293 | } | ||
| 1294 | return rc; | ||
| 1295 | } | ||
| 1296 | |||
| 1297 | static int | ||
| 1298 | cifs_posix_mkdir(struct inode *inode, struct dentry *dentry, umode_t mode, | ||
| 1299 | const char *full_path, struct cifs_sb_info *cifs_sb, | ||
| 1300 | struct cifs_tcon *tcon, const unsigned int xid) | ||
| 1301 | { | ||
| 1302 | int rc = 0; | ||
| 1303 | u32 oplock = 0; | ||
| 1304 | FILE_UNIX_BASIC_INFO *info = NULL; | ||
| 1305 | struct inode *newinode = NULL; | ||
| 1306 | struct cifs_fattr fattr; | ||
| 1307 | |||
| 1308 | info = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL); | ||
| 1309 | if (info == NULL) { | ||
| 1310 | rc = -ENOMEM; | ||
| 1311 | goto posix_mkdir_out; | ||
| 1312 | } | ||
| 1313 | |||
| 1314 | mode &= ~current_umask(); | ||
| 1315 | rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT, mode, | ||
| 1316 | NULL /* netfid */, info, &oplock, full_path, | ||
| 1317 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & | ||
| 1318 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 1319 | if (rc == -EOPNOTSUPP) | ||
| 1320 | goto posix_mkdir_out; | ||
| 1321 | else if (rc) { | ||
| 1322 | cFYI(1, "posix mkdir returned 0x%x", rc); | ||
| 1323 | d_drop(dentry); | ||
| 1324 | goto posix_mkdir_out; | ||
| 1325 | } | ||
| 1326 | |||
| 1327 | if (info->Type == cpu_to_le32(-1)) | ||
| 1328 | /* no return info, go query for it */ | ||
| 1329 | goto posix_mkdir_get_info; | ||
| 1330 | /* | ||
| 1331 | * BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if | ||
| 1332 | * need to set uid/gid. | ||
| 1333 | */ | ||
| 1334 | |||
| 1335 | cifs_unix_basic_to_fattr(&fattr, info, cifs_sb); | ||
| 1336 | cifs_fill_uniqueid(inode->i_sb, &fattr); | ||
| 1337 | newinode = cifs_iget(inode->i_sb, &fattr); | ||
| 1338 | if (!newinode) | ||
| 1339 | goto posix_mkdir_get_info; | ||
| 1340 | |||
| 1341 | d_instantiate(dentry, newinode); | ||
| 1342 | |||
| 1343 | #ifdef CONFIG_CIFS_DEBUG2 | ||
| 1344 | cFYI(1, "instantiated dentry %p %s to inode %p", dentry, | ||
| 1345 | dentry->d_name.name, newinode); | ||
| 1346 | |||
| 1347 | if (newinode->i_nlink != 2) | ||
| 1348 | cFYI(1, "unexpected number of links %d", newinode->i_nlink); | ||
| 1349 | #endif | ||
| 1350 | |||
| 1351 | posix_mkdir_out: | ||
| 1352 | kfree(info); | ||
| 1353 | return rc; | ||
| 1354 | posix_mkdir_get_info: | ||
| 1355 | rc = cifs_mkdir_qinfo(inode, dentry, mode, full_path, cifs_sb, tcon, | ||
| 1356 | xid); | ||
| 1357 | goto posix_mkdir_out; | ||
| 1358 | } | ||
| 1359 | |||
| 1222 | int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode) | 1360 | int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode) |
| 1223 | { | 1361 | { |
| 1224 | int rc = 0, tmprc; | 1362 | int rc = 0; |
| 1225 | unsigned int xid; | 1363 | unsigned int xid; |
| 1226 | struct cifs_sb_info *cifs_sb; | 1364 | struct cifs_sb_info *cifs_sb; |
| 1227 | struct tcon_link *tlink; | 1365 | struct tcon_link *tlink; |
| 1228 | struct cifs_tcon *tcon; | 1366 | struct cifs_tcon *tcon; |
| 1229 | char *full_path = NULL; | 1367 | struct TCP_Server_Info *server; |
| 1230 | struct inode *newinode = NULL; | 1368 | char *full_path; |
| 1231 | struct cifs_fattr fattr; | ||
| 1232 | 1369 | ||
| 1233 | cFYI(1, "In cifs_mkdir, mode = 0x%hx inode = 0x%p", mode, inode); | 1370 | cFYI(1, "In cifs_mkdir, mode = 0x%hx inode = 0x%p", mode, inode); |
| 1234 | 1371 | ||
| @@ -1248,145 +1385,29 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode) | |||
| 1248 | 1385 | ||
| 1249 | if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP & | 1386 | if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP & |
| 1250 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { | 1387 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { |
| 1251 | u32 oplock = 0; | 1388 | rc = cifs_posix_mkdir(inode, direntry, mode, full_path, cifs_sb, |
| 1252 | FILE_UNIX_BASIC_INFO *pInfo = | 1389 | tcon, xid); |
| 1253 | kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL); | 1390 | if (rc != -EOPNOTSUPP) |
| 1254 | if (pInfo == NULL) { | ||
| 1255 | rc = -ENOMEM; | ||
| 1256 | goto mkdir_out; | 1391 | goto mkdir_out; |
| 1257 | } | 1392 | } |
| 1258 | |||
| 1259 | mode &= ~current_umask(); | ||
| 1260 | rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT, | ||
| 1261 | mode, NULL /* netfid */, pInfo, &oplock, | ||
| 1262 | full_path, cifs_sb->local_nls, | ||
| 1263 | cifs_sb->mnt_cifs_flags & | ||
| 1264 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 1265 | if (rc == -EOPNOTSUPP) { | ||
| 1266 | kfree(pInfo); | ||
| 1267 | goto mkdir_retry_old; | ||
| 1268 | } else if (rc) { | ||
| 1269 | cFYI(1, "posix mkdir returned 0x%x", rc); | ||
| 1270 | d_drop(direntry); | ||
| 1271 | } else { | ||
| 1272 | if (pInfo->Type == cpu_to_le32(-1)) { | ||
| 1273 | /* no return info, go query for it */ | ||
| 1274 | kfree(pInfo); | ||
| 1275 | goto mkdir_get_info; | ||
| 1276 | } | ||
| 1277 | /*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need | ||
| 1278 | to set uid/gid */ | ||
| 1279 | |||
| 1280 | cifs_unix_basic_to_fattr(&fattr, pInfo, cifs_sb); | ||
| 1281 | cifs_fill_uniqueid(inode->i_sb, &fattr); | ||
| 1282 | newinode = cifs_iget(inode->i_sb, &fattr); | ||
| 1283 | if (!newinode) { | ||
| 1284 | kfree(pInfo); | ||
| 1285 | goto mkdir_get_info; | ||
| 1286 | } | ||
| 1287 | |||
| 1288 | d_instantiate(direntry, newinode); | ||
| 1289 | 1393 | ||
| 1290 | #ifdef CONFIG_CIFS_DEBUG2 | 1394 | server = tcon->ses->server; |
| 1291 | cFYI(1, "instantiated dentry %p %s to inode %p", | ||
| 1292 | direntry, direntry->d_name.name, newinode); | ||
| 1293 | 1395 | ||
| 1294 | if (newinode->i_nlink != 2) | 1396 | if (!server->ops->mkdir) { |
| 1295 | cFYI(1, "unexpected number of links %d", | 1397 | rc = -ENOSYS; |
| 1296 | newinode->i_nlink); | ||
| 1297 | #endif | ||
| 1298 | } | ||
| 1299 | kfree(pInfo); | ||
| 1300 | goto mkdir_out; | 1398 | goto mkdir_out; |
| 1301 | } | 1399 | } |
| 1302 | mkdir_retry_old: | 1400 | |
| 1303 | /* BB add setting the equivalent of mode via CreateX w/ACLs */ | 1401 | /* BB add setting the equivalent of mode via CreateX w/ACLs */ |
| 1304 | rc = CIFSSMBMkDir(xid, tcon, full_path, cifs_sb->local_nls, | 1402 | rc = server->ops->mkdir(xid, tcon, full_path, cifs_sb); |
| 1305 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 1306 | if (rc) { | 1403 | if (rc) { |
| 1307 | cFYI(1, "cifs_mkdir returned 0x%x", rc); | 1404 | cFYI(1, "cifs_mkdir returned 0x%x", rc); |
| 1308 | d_drop(direntry); | 1405 | d_drop(direntry); |
| 1309 | } else { | 1406 | goto mkdir_out; |
| 1310 | mkdir_get_info: | ||
| 1311 | if (tcon->unix_ext) | ||
| 1312 | rc = cifs_get_inode_info_unix(&newinode, full_path, | ||
| 1313 | inode->i_sb, xid); | ||
| 1314 | else | ||
| 1315 | rc = cifs_get_inode_info(&newinode, full_path, NULL, | ||
| 1316 | inode->i_sb, xid, NULL); | ||
| 1317 | |||
| 1318 | d_instantiate(direntry, newinode); | ||
| 1319 | /* setting nlink not necessary except in cases where we | ||
| 1320 | * failed to get it from the server or was set bogus */ | ||
| 1321 | if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2)) | ||
| 1322 | set_nlink(direntry->d_inode, 2); | ||
| 1323 | |||
| 1324 | mode &= ~current_umask(); | ||
| 1325 | /* must turn on setgid bit if parent dir has it */ | ||
| 1326 | if (inode->i_mode & S_ISGID) | ||
| 1327 | mode |= S_ISGID; | ||
| 1328 | |||
| 1329 | if (tcon->unix_ext) { | ||
| 1330 | struct cifs_unix_set_info_args args = { | ||
| 1331 | .mode = mode, | ||
| 1332 | .ctime = NO_CHANGE_64, | ||
| 1333 | .atime = NO_CHANGE_64, | ||
| 1334 | .mtime = NO_CHANGE_64, | ||
| 1335 | .device = 0, | ||
| 1336 | }; | ||
| 1337 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { | ||
| 1338 | args.uid = (__u64)current_fsuid(); | ||
| 1339 | if (inode->i_mode & S_ISGID) | ||
| 1340 | args.gid = (__u64)inode->i_gid; | ||
| 1341 | else | ||
| 1342 | args.gid = (__u64)current_fsgid(); | ||
| 1343 | } else { | ||
| 1344 | args.uid = NO_CHANGE_64; | ||
| 1345 | args.gid = NO_CHANGE_64; | ||
| 1346 | } | ||
| 1347 | CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args, | ||
| 1348 | cifs_sb->local_nls, | ||
| 1349 | cifs_sb->mnt_cifs_flags & | ||
| 1350 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 1351 | } else { | ||
| 1352 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) && | ||
| 1353 | (mode & S_IWUGO) == 0) { | ||
| 1354 | FILE_BASIC_INFO pInfo; | ||
| 1355 | struct cifsInodeInfo *cifsInode; | ||
| 1356 | u32 dosattrs; | ||
| 1357 | |||
| 1358 | memset(&pInfo, 0, sizeof(pInfo)); | ||
| 1359 | cifsInode = CIFS_I(newinode); | ||
| 1360 | dosattrs = cifsInode->cifsAttrs|ATTR_READONLY; | ||
| 1361 | pInfo.Attributes = cpu_to_le32(dosattrs); | ||
| 1362 | tmprc = CIFSSMBSetPathInfo(xid, tcon, | ||
| 1363 | full_path, &pInfo, | ||
| 1364 | cifs_sb->local_nls, | ||
| 1365 | cifs_sb->mnt_cifs_flags & | ||
| 1366 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 1367 | if (tmprc == 0) | ||
| 1368 | cifsInode->cifsAttrs = dosattrs; | ||
| 1369 | } | ||
| 1370 | if (direntry->d_inode) { | ||
| 1371 | if (cifs_sb->mnt_cifs_flags & | ||
| 1372 | CIFS_MOUNT_DYNPERM) | ||
| 1373 | direntry->d_inode->i_mode = | ||
| 1374 | (mode | S_IFDIR); | ||
| 1375 | |||
| 1376 | if (cifs_sb->mnt_cifs_flags & | ||
| 1377 | CIFS_MOUNT_SET_UID) { | ||
| 1378 | direntry->d_inode->i_uid = | ||
| 1379 | current_fsuid(); | ||
| 1380 | if (inode->i_mode & S_ISGID) | ||
| 1381 | direntry->d_inode->i_gid = | ||
| 1382 | inode->i_gid; | ||
| 1383 | else | ||
| 1384 | direntry->d_inode->i_gid = | ||
| 1385 | current_fsgid(); | ||
| 1386 | } | ||
| 1387 | } | ||
| 1388 | } | ||
| 1389 | } | 1407 | } |
| 1408 | |||
| 1409 | rc = cifs_mkdir_qinfo(inode, direntry, mode, full_path, cifs_sb, tcon, | ||
| 1410 | xid); | ||
| 1390 | mkdir_out: | 1411 | mkdir_out: |
| 1391 | /* | 1412 | /* |
| 1392 | * Force revalidate to get parent dir info when needed since cached | 1413 | * Force revalidate to get parent dir info when needed since cached |
| @@ -1405,7 +1426,8 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) | |||
| 1405 | unsigned int xid; | 1426 | unsigned int xid; |
| 1406 | struct cifs_sb_info *cifs_sb; | 1427 | struct cifs_sb_info *cifs_sb; |
| 1407 | struct tcon_link *tlink; | 1428 | struct tcon_link *tlink; |
| 1408 | struct cifs_tcon *pTcon; | 1429 | struct cifs_tcon *tcon; |
| 1430 | struct TCP_Server_Info *server; | ||
| 1409 | char *full_path = NULL; | 1431 | char *full_path = NULL; |
| 1410 | struct cifsInodeInfo *cifsInode; | 1432 | struct cifsInodeInfo *cifsInode; |
| 1411 | 1433 | ||
| @@ -1425,10 +1447,16 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) | |||
| 1425 | rc = PTR_ERR(tlink); | 1447 | rc = PTR_ERR(tlink); |
| 1426 | goto rmdir_exit; | 1448 | goto rmdir_exit; |
| 1427 | } | 1449 | } |
| 1428 | pTcon = tlink_tcon(tlink); | 1450 | tcon = tlink_tcon(tlink); |
| 1451 | server = tcon->ses->server; | ||
| 1452 | |||
| 1453 | if (!server->ops->rmdir) { | ||
| 1454 | rc = -ENOSYS; | ||
| 1455 | cifs_put_tlink(tlink); | ||
| 1456 | goto rmdir_exit; | ||
| 1457 | } | ||
| 1429 | 1458 | ||
| 1430 | rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls, | 1459 | rc = server->ops->rmdir(xid, tcon, full_path, cifs_sb); |
| 1431 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 1432 | cifs_put_tlink(tlink); | 1460 | cifs_put_tlink(tlink); |
| 1433 | 1461 | ||
| 1434 | if (!rc) { | 1462 | if (!rc) { |
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index c40356d24c5c..3129ac74b819 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c | |||
| @@ -586,6 +586,27 @@ cifs_print_stats(struct seq_file *m, struct cifs_tcon *tcon) | |||
| 586 | #endif | 586 | #endif |
| 587 | } | 587 | } |
| 588 | 588 | ||
| 589 | static void | ||
| 590 | cifs_mkdir_setinfo(struct inode *inode, const char *full_path, | ||
| 591 | struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon, | ||
| 592 | const unsigned int xid) | ||
| 593 | { | ||
| 594 | FILE_BASIC_INFO info; | ||
| 595 | struct cifsInodeInfo *cifsInode; | ||
| 596 | u32 dosattrs; | ||
| 597 | int rc; | ||
| 598 | |||
| 599 | memset(&info, 0, sizeof(info)); | ||
| 600 | cifsInode = CIFS_I(inode); | ||
| 601 | dosattrs = cifsInode->cifsAttrs|ATTR_READONLY; | ||
| 602 | info.Attributes = cpu_to_le32(dosattrs); | ||
| 603 | rc = CIFSSMBSetPathInfo(xid, tcon, full_path, &info, cifs_sb->local_nls, | ||
| 604 | cifs_sb->mnt_cifs_flags & | ||
| 605 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 606 | if (rc == 0) | ||
| 607 | cifsInode->cifsAttrs = dosattrs; | ||
| 608 | } | ||
| 609 | |||
| 589 | struct smb_version_operations smb1_operations = { | 610 | struct smb_version_operations smb1_operations = { |
| 590 | .send_cancel = send_nt_cancel, | 611 | .send_cancel = send_nt_cancel, |
| 591 | .compare_fids = cifs_compare_fids, | 612 | .compare_fids = cifs_compare_fids, |
| @@ -620,6 +641,9 @@ struct smb_version_operations smb1_operations = { | |||
| 620 | .get_srv_inum = cifs_get_srv_inum, | 641 | .get_srv_inum = cifs_get_srv_inum, |
| 621 | .build_path_to_root = cifs_build_path_to_root, | 642 | .build_path_to_root = cifs_build_path_to_root, |
| 622 | .echo = CIFSSMBEcho, | 643 | .echo = CIFSSMBEcho, |
| 644 | .mkdir = CIFSSMBMkDir, | ||
| 645 | .mkdir_setinfo = cifs_mkdir_setinfo, | ||
| 646 | .rmdir = CIFSSMBRmDir, | ||
| 623 | }; | 647 | }; |
| 624 | 648 | ||
| 625 | struct smb_version_values smb1_values = { | 649 | struct smb_version_values smb1_values = { |
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c index 1ba5c405315c..2aa5cb08c526 100644 --- a/fs/cifs/smb2inode.c +++ b/fs/cifs/smb2inode.c | |||
| @@ -122,3 +122,42 @@ out: | |||
| 122 | kfree(smb2_data); | 122 | kfree(smb2_data); |
| 123 | return rc; | 123 | return rc; |
| 124 | } | 124 | } |
| 125 | |||
| 126 | int | ||
| 127 | smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, | ||
| 128 | struct cifs_sb_info *cifs_sb) | ||
| 129 | { | ||
| 130 | return smb2_open_op_close(xid, tcon, cifs_sb, name, | ||
| 131 | FILE_WRITE_ATTRIBUTES, FILE_CREATE, 0, | ||
| 132 | CREATE_NOT_FILE, NULL, SMB2_OP_MKDIR); | ||
| 133 | } | ||
| 134 | |||
| 135 | void | ||
| 136 | smb2_mkdir_setinfo(struct inode *inode, const char *name, | ||
| 137 | struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon, | ||
| 138 | const unsigned int xid) | ||
| 139 | { | ||
| 140 | FILE_BASIC_INFO data; | ||
| 141 | struct cifsInodeInfo *cifs_i; | ||
| 142 | u32 dosattrs; | ||
| 143 | int tmprc; | ||
| 144 | |||
| 145 | memset(&data, 0, sizeof(data)); | ||
| 146 | cifs_i = CIFS_I(inode); | ||
| 147 | dosattrs = cifs_i->cifsAttrs | ATTR_READONLY; | ||
| 148 | data.Attributes = cpu_to_le32(dosattrs); | ||
| 149 | tmprc = smb2_open_op_close(xid, tcon, cifs_sb, name, | ||
| 150 | FILE_WRITE_ATTRIBUTES, FILE_CREATE, 0, | ||
| 151 | CREATE_NOT_FILE, &data, SMB2_OP_SET_INFO); | ||
| 152 | if (tmprc == 0) | ||
| 153 | cifs_i->cifsAttrs = dosattrs; | ||
| 154 | } | ||
| 155 | |||
| 156 | int | ||
| 157 | smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, | ||
| 158 | struct cifs_sb_info *cifs_sb) | ||
| 159 | { | ||
| 160 | return smb2_open_op_close(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN, | ||
| 161 | 0, CREATE_NOT_FILE | CREATE_DELETE_ON_CLOSE, | ||
| 162 | NULL, SMB2_OP_DELETE); | ||
| 163 | } | ||
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 410cf925ea26..826209bf3684 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c | |||
| @@ -318,6 +318,9 @@ struct smb_version_operations smb21_operations = { | |||
| 318 | .query_path_info = smb2_query_path_info, | 318 | .query_path_info = smb2_query_path_info, |
| 319 | .get_srv_inum = smb2_get_srv_inum, | 319 | .get_srv_inum = smb2_get_srv_inum, |
| 320 | .build_path_to_root = smb2_build_path_to_root, | 320 | .build_path_to_root = smb2_build_path_to_root, |
| 321 | .mkdir = smb2_mkdir, | ||
| 322 | .mkdir_setinfo = smb2_mkdir_setinfo, | ||
| 323 | .rmdir = smb2_rmdir, | ||
| 321 | }; | 324 | }; |
| 322 | 325 | ||
| 323 | struct smb_version_values smb21_values = { | 326 | struct smb_version_values smb21_values = { |
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index 902bbe2b5ad3..bfaa7b148afd 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h | |||
| @@ -52,6 +52,14 @@ extern int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, | |||
| 52 | struct cifs_sb_info *cifs_sb, | 52 | struct cifs_sb_info *cifs_sb, |
| 53 | const char *full_path, FILE_ALL_INFO *data, | 53 | const char *full_path, FILE_ALL_INFO *data, |
| 54 | bool *adjust_tz); | 54 | bool *adjust_tz); |
| 55 | extern int smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon, | ||
| 56 | const char *name, struct cifs_sb_info *cifs_sb); | ||
| 57 | extern void smb2_mkdir_setinfo(struct inode *inode, const char *full_path, | ||
| 58 | struct cifs_sb_info *cifs_sb, | ||
| 59 | struct cifs_tcon *tcon, const unsigned int xid); | ||
| 60 | extern int smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, | ||
| 61 | const char *name, struct cifs_sb_info *cifs_sb); | ||
| 62 | |||
| 55 | /* | 63 | /* |
| 56 | * SMB2 Worker functions - most of protocol specific implementation details | 64 | * SMB2 Worker functions - most of protocol specific implementation details |
| 57 | * are contained within these calls. | 65 | * are contained within these calls. |
