diff options
| -rw-r--r-- | fs/cifs/inode.c | 87 |
1 files changed, 8 insertions, 79 deletions
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 8ac4eabc1f8b..d54fa8aeaea9 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
| @@ -1293,12 +1293,9 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry, | |||
| 1293 | struct cifs_sb_info *cifs_sb_source; | 1293 | struct cifs_sb_info *cifs_sb_source; |
| 1294 | struct cifs_sb_info *cifs_sb_target; | 1294 | struct cifs_sb_info *cifs_sb_target; |
| 1295 | struct cifsTconInfo *tcon; | 1295 | struct cifsTconInfo *tcon; |
| 1296 | struct cifsInodeInfo *target_cinode; | ||
| 1297 | FILE_UNIX_BASIC_INFO *info_buf_source = NULL; | 1296 | FILE_UNIX_BASIC_INFO *info_buf_source = NULL; |
| 1298 | FILE_UNIX_BASIC_INFO *info_buf_target; | 1297 | FILE_UNIX_BASIC_INFO *info_buf_target; |
| 1299 | __u16 dstfid; | 1298 | int xid, rc, tmprc; |
| 1300 | int xid, rc, tmprc, oplock = 0; | ||
| 1301 | bool delete_already_pending; | ||
| 1302 | 1299 | ||
| 1303 | cifs_sb_target = CIFS_SB(target_dir->i_sb); | 1300 | cifs_sb_target = CIFS_SB(target_dir->i_sb); |
| 1304 | cifs_sb_source = CIFS_SB(source_dir->i_sb); | 1301 | cifs_sb_source = CIFS_SB(source_dir->i_sb); |
| @@ -1348,104 +1345,36 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry, | |||
| 1348 | } | 1345 | } |
| 1349 | 1346 | ||
| 1350 | info_buf_target = info_buf_source + 1; | 1347 | info_buf_target = info_buf_source + 1; |
| 1351 | rc = CIFSSMBUnixQPathInfo(xid, tcon, fromName, | 1348 | tmprc = CIFSSMBUnixQPathInfo(xid, tcon, fromName, |
| 1352 | info_buf_source, | 1349 | info_buf_source, |
| 1353 | cifs_sb_source->local_nls, | 1350 | cifs_sb_source->local_nls, |
| 1354 | cifs_sb_source->mnt_cifs_flags & | 1351 | cifs_sb_source->mnt_cifs_flags & |
| 1355 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 1352 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 1356 | if (rc != 0) | 1353 | if (tmprc != 0) |
| 1357 | goto unlink_target; | 1354 | goto unlink_target; |
| 1358 | 1355 | ||
| 1359 | rc = CIFSSMBUnixQPathInfo(xid, tcon, | 1356 | tmprc = CIFSSMBUnixQPathInfo(xid, tcon, |
| 1360 | toName, info_buf_target, | 1357 | toName, info_buf_target, |
| 1361 | cifs_sb_target->local_nls, | 1358 | cifs_sb_target->local_nls, |
| 1362 | /* remap based on source sb */ | 1359 | /* remap based on source sb */ |
| 1363 | cifs_sb_source->mnt_cifs_flags & | 1360 | cifs_sb_source->mnt_cifs_flags & |
| 1364 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 1361 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 1365 | 1362 | ||
| 1366 | if (rc == 0 && (info_buf_source->UniqueId == | 1363 | if (tmprc == 0 && (info_buf_source->UniqueId == |
| 1367 | info_buf_target->UniqueId)) | 1364 | info_buf_target->UniqueId)) |
| 1368 | /* same file, POSIX says that this is a noop */ | 1365 | /* same file, POSIX says that this is a noop */ |
| 1369 | goto cifs_rename_exit; | 1366 | goto cifs_rename_exit; |
| 1370 | |||
| 1371 | rc = -EEXIST; | ||
| 1372 | } /* else ... BB we could add the same check for Windows by | 1367 | } /* else ... BB we could add the same check for Windows by |
| 1373 | checking the UniqueId via FILE_INTERNAL_INFO */ | 1368 | checking the UniqueId via FILE_INTERNAL_INFO */ |
| 1374 | 1369 | ||
| 1375 | if ((rc == -EACCES) || (rc == -EEXIST)) { | ||
| 1376 | unlink_target: | 1370 | unlink_target: |
| 1377 | /* don't bother if this is a negative dentry */ | 1371 | if ((rc == -EACCES) || (rc == -EEXIST)) { |
| 1378 | if (!target_dentry->d_inode) | 1372 | tmprc = cifs_unlink(target_dir, target_dentry); |
| 1379 | goto cifs_rename_exit; | ||
| 1380 | |||
| 1381 | target_cinode = CIFS_I(target_dentry->d_inode); | ||
| 1382 | |||
| 1383 | /* try to move the target out of the way */ | ||
| 1384 | tmprc = CIFSSMBOpen(xid, tcon, toName, FILE_OPEN, DELETE, | ||
| 1385 | CREATE_NOT_DIR, &dstfid, &oplock, NULL, | ||
| 1386 | cifs_sb_target->local_nls, | ||
| 1387 | cifs_sb_target->mnt_cifs_flags & | ||
| 1388 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 1389 | if (tmprc) | 1373 | if (tmprc) |
| 1390 | goto cifs_rename_exit; | 1374 | goto cifs_rename_exit; |
| 1391 | 1375 | ||
| 1392 | /* rename the file to random name */ | ||
| 1393 | tmprc = CIFSSMBRenameOpenFile(xid, tcon, dstfid, NULL, | ||
| 1394 | cifs_sb_target->local_nls, | ||
| 1395 | cifs_sb_target->mnt_cifs_flags & | ||
| 1396 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 1397 | |||
| 1398 | if (tmprc) | ||
| 1399 | goto close_target; | ||
| 1400 | |||
| 1401 | delete_already_pending = target_cinode->delete_pending; | ||
| 1402 | |||
| 1403 | if (!delete_already_pending) { | ||
| 1404 | /* set delete on close */ | ||
| 1405 | tmprc = CIFSSMBSetFileDisposition(xid, tcon, | ||
| 1406 | true, dstfid, | ||
| 1407 | current->tgid); | ||
| 1408 | /* | ||
| 1409 | * This hack is for broken samba servers, remove this | ||
| 1410 | * once more fixed ones are in the field. | ||
| 1411 | */ | ||
| 1412 | if (tmprc == -ENOENT) | ||
| 1413 | delete_already_pending = false; | ||
| 1414 | else if (tmprc) | ||
| 1415 | goto undo_target_rename; | ||
| 1416 | |||
| 1417 | target_cinode->delete_pending = true; | ||
| 1418 | } | ||
| 1419 | |||
| 1420 | |||
| 1421 | rc = cifs_do_rename(xid, source_dentry, fromName, | 1376 | rc = cifs_do_rename(xid, source_dentry, fromName, |
| 1422 | target_dentry, toName); | 1377 | target_dentry, toName); |
| 1423 | |||
| 1424 | if (rc == 0) | ||
| 1425 | goto close_target; | ||
| 1426 | |||
| 1427 | /* | ||
| 1428 | * after this point, we can't bother with error handling on | ||
| 1429 | * the undo's. This is best effort since we can't do anything | ||
| 1430 | * about failures here. | ||
| 1431 | */ | ||
| 1432 | if (!delete_already_pending) { | ||
| 1433 | tmprc = CIFSSMBSetFileDisposition(xid, tcon, | ||
| 1434 | false, dstfid, | ||
| 1435 | current->tgid); | ||
| 1436 | if (tmprc == 0) | ||
| 1437 | target_cinode->delete_pending = false; | ||
| 1438 | } | ||
| 1439 | |||
| 1440 | undo_target_rename: | ||
| 1441 | /* rename failed: undo target rename */ | ||
| 1442 | CIFSSMBRenameOpenFile(xid, tcon, dstfid, | ||
| 1443 | target_dentry->d_name.name, | ||
| 1444 | cifs_sb_target->local_nls, | ||
| 1445 | cifs_sb_target->mnt_cifs_flags & | ||
| 1446 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 1447 | close_target: | ||
| 1448 | CIFSSMBClose(xid, tcon, dstfid); | ||
| 1449 | } | 1378 | } |
| 1450 | 1379 | ||
| 1451 | cifs_rename_exit: | 1380 | cifs_rename_exit: |
