diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-08-02 13:54:11 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-08-02 13:54:11 -0400 |
commit | 630103ea2c286de3e7ea9ae6b1035d91ef051413 (patch) | |
tree | 864fe60cc603434ddc16e7c0344a1a7f982d7b54 /fs | |
parent | 8783b6e2b2cb726f2734cf208d101f73ac1ba616 (diff) | |
parent | 1a500f010fb2d121c58f77ddfde2eca1bde3bfcd (diff) |
Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6
Pull CIFS update from Steve French:
"Adds SMB2 rmdir/mkdir capability to the SMB2/SMB2.1 support in cifs.
I am holding up a few more days on merging the remainder of the
SMB2/SMB2.1 enablement although it is nearing review completion, in
order to address some review comments from Jeff Layton on a few of the
subsequent SMB2 patches, and also to debug an unrelated cifs problem
that Pavel discovered."
* 'for-next' of git://git.samba.org/sfrench/cifs-2.6:
CIFS: Add SMB2 support for rmdir
CIFS: Move rmdir code to ops struct
CIFS: Add SMB2 support for mkdir operation
CIFS: Separate protocol specific part from mkdir
CIFS: Simplify cifs_mkdir call
Diffstat (limited to 'fs')
-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. |