@@ -1285,30 +1285,32 @@ cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath,
1285
1285
return rc ;
1286
1286
}
1287
1287
1288
- int cifs_rename (struct inode * source_inode , struct dentry * source_direntry ,
1289
- struct inode * target_inode , struct dentry * target_direntry )
1288
+ int cifs_rename (struct inode * source_dir , struct dentry * source_dentry ,
1289
+ struct inode * target_dir , struct dentry * target_dentry )
1290
1290
{
1291
1291
char * fromName = NULL ;
1292
1292
char * toName = NULL ;
1293
1293
struct cifs_sb_info * cifs_sb_source ;
1294
1294
struct cifs_sb_info * cifs_sb_target ;
1295
- struct cifsTconInfo * pTcon ;
1295
+ struct cifsTconInfo * tcon ;
1296
+ struct cifsInodeInfo * target_cinode ;
1296
1297
FILE_UNIX_BASIC_INFO * info_buf_source = NULL ;
1297
1298
FILE_UNIX_BASIC_INFO * info_buf_target ;
1298
- int xid ;
1299
- int rc ;
1299
+ __u16 dstfid ;
1300
+ int xid , rc , tmprc , oplock = 0 ;
1301
+ bool delete_already_pending ;
1300
1302
1301
- cifs_sb_target = CIFS_SB (target_inode -> i_sb );
1302
- cifs_sb_source = CIFS_SB (source_inode -> i_sb );
1303
- pTcon = cifs_sb_source -> tcon ;
1303
+ cifs_sb_target = CIFS_SB (target_dir -> i_sb );
1304
+ cifs_sb_source = CIFS_SB (source_dir -> i_sb );
1305
+ tcon = cifs_sb_source -> tcon ;
1304
1306
1305
1307
xid = GetXid ();
1306
1308
1307
1309
/*
1308
1310
* BB: this might be allowed if same server, but different share.
1309
1311
* Consider adding support for this
1310
1312
*/
1311
- if (pTcon != cifs_sb_target -> tcon ) {
1313
+ if (tcon != cifs_sb_target -> tcon ) {
1312
1314
rc = - EXDEV ;
1313
1315
goto cifs_rename_exit ;
1314
1316
}
@@ -1317,65 +1319,133 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
1317
1319
* we already have the rename sem so we do not need to
1318
1320
* grab it again here to protect the path integrity
1319
1321
*/
1320
- fromName = build_path_from_dentry (source_direntry );
1322
+ fromName = build_path_from_dentry (source_dentry );
1321
1323
if (fromName == NULL ) {
1322
1324
rc = - ENOMEM ;
1323
1325
goto cifs_rename_exit ;
1324
1326
}
1325
1327
1326
- toName = build_path_from_dentry (target_direntry );
1328
+ toName = build_path_from_dentry (target_dentry );
1327
1329
if (toName == NULL ) {
1328
1330
rc = - ENOMEM ;
1329
1331
goto cifs_rename_exit ;
1330
1332
}
1331
1333
1332
- rc = cifs_do_rename (xid , source_direntry , fromName ,
1333
- target_direntry , toName );
1334
+ rc = cifs_do_rename (xid , source_dentry , fromName ,
1335
+ target_dentry , toName );
1334
1336
1335
- if (rc == - EEXIST ) {
1336
- if (pTcon -> unix_ext ) {
1337
- /*
1338
- * Are src and dst hardlinks of same inode? We can
1339
- * only tell with unix extensions enabled
1340
- */
1341
- info_buf_source =
1342
- kmalloc (2 * sizeof (FILE_UNIX_BASIC_INFO ),
1343
- GFP_KERNEL );
1344
- if (info_buf_source == NULL )
1345
- goto unlink_target ;
1346
-
1347
- info_buf_target = info_buf_source + 1 ;
1348
- rc = CIFSSMBUnixQPathInfo (xid , pTcon , fromName ,
1349
- info_buf_source ,
1350
- cifs_sb_source -> local_nls ,
1351
- cifs_sb_source -> mnt_cifs_flags &
1352
- CIFS_MOUNT_MAP_SPECIAL_CHR );
1353
- if (rc != 0 )
1354
- goto unlink_target ;
1355
-
1356
- rc = CIFSSMBUnixQPathInfo (xid , pTcon ,
1357
- toName , info_buf_target ,
1358
- cifs_sb_target -> local_nls ,
1359
- /* remap based on source sb */
1360
- cifs_sb_source -> mnt_cifs_flags &
1361
- CIFS_MOUNT_MAP_SPECIAL_CHR );
1337
+ if (rc == - EEXIST && tcon -> unix_ext ) {
1338
+ /*
1339
+ * Are src and dst hardlinks of same inode? We can
1340
+ * only tell with unix extensions enabled
1341
+ */
1342
+ info_buf_source =
1343
+ kmalloc (2 * sizeof (FILE_UNIX_BASIC_INFO ),
1344
+ GFP_KERNEL );
1345
+ if (info_buf_source == NULL ) {
1346
+ rc = - ENOMEM ;
1347
+ goto cifs_rename_exit ;
1348
+ }
1349
+
1350
+ info_buf_target = info_buf_source + 1 ;
1351
+ rc = CIFSSMBUnixQPathInfo (xid , tcon , fromName ,
1352
+ info_buf_source ,
1353
+ cifs_sb_source -> local_nls ,
1354
+ cifs_sb_source -> mnt_cifs_flags &
1355
+ CIFS_MOUNT_MAP_SPECIAL_CHR );
1356
+ if (rc != 0 )
1357
+ goto unlink_target ;
1362
1358
1363
- if (rc == 0 && (info_buf_source -> UniqueId ==
1364
- info_buf_target -> UniqueId ))
1365
- /* same file, POSIX says that this is a noop */
1366
- goto cifs_rename_exit ;
1367
- } /* else ... BB we could add the same check for Windows by
1359
+ rc = CIFSSMBUnixQPathInfo (xid , tcon ,
1360
+ toName , info_buf_target ,
1361
+ cifs_sb_target -> local_nls ,
1362
+ /* remap based on source sb */
1363
+ cifs_sb_source -> mnt_cifs_flags &
1364
+ CIFS_MOUNT_MAP_SPECIAL_CHR );
1365
+
1366
+ if (rc == 0 && (info_buf_source -> UniqueId ==
1367
+ info_buf_target -> UniqueId ))
1368
+ /* same file, POSIX says that this is a noop */
1369
+ goto cifs_rename_exit ;
1370
+
1371
+ rc = - EEXIST ;
1372
+ } /* else ... BB we could add the same check for Windows by
1368
1373
checking the UniqueId via FILE_INTERNAL_INFO */
1374
+
1375
+ if ((rc == - EACCES ) || (rc == - EEXIST )) {
1369
1376
unlink_target :
1377
+ /* don't bother if this is a negative dentry */
1378
+ if (!target_dentry -> d_inode )
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 )
1390
+ goto cifs_rename_exit ;
1391
+
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 ,
1422
+ target_dentry , toName );
1423
+
1424
+ if (rc == 0 )
1425
+ goto close_target ;
1426
+
1370
1427
/*
1371
- * we either can not tell the files are hardlinked (as with
1372
- * Windows servers) or files are not hardlinked. Delete the
1373
- * target manually before renaming to follow POSIX rather than
1374
- * Windows semantics
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.
1375
1431
*/
1376
- cifs_unlink (target_inode , target_direntry );
1377
- rc = cifs_do_rename (xid , source_direntry , fromName ,
1378
- target_direntry , toName );
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 );
1379
1449
}
1380
1450
1381
1451
cifs_rename_exit :
0 commit comments