aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/inode.c87
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)) {
1376unlink_target: 1370unlink_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
1440undo_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);
1447close_target:
1448 CIFSSMBClose(xid, tcon, dstfid);
1449 } 1378 }
1450 1379
1451cifs_rename_exit: 1380cifs_rename_exit: