diff options
Diffstat (limited to 'fs/cifs/inode.c')
-rw-r--r-- | fs/cifs/inode.c | 186 |
1 files changed, 104 insertions, 82 deletions
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 954b670f1687..82612be9477b 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -806,8 +806,6 @@ cifs_rename_pending_delete(char *full_path, struct inode *inode, int xid) | |||
806 | rc = CIFSSMBRenameOpenFile(xid, tcon, netfid, NULL, cifs_sb->local_nls, | 806 | rc = CIFSSMBRenameOpenFile(xid, tcon, netfid, NULL, cifs_sb->local_nls, |
807 | cifs_sb->mnt_cifs_flags & | 807 | cifs_sb->mnt_cifs_flags & |
808 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 808 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
809 | if (rc != 0) | ||
810 | goto out_close; | ||
811 | 809 | ||
812 | /* set DELETE_ON_CLOSE */ | 810 | /* set DELETE_ON_CLOSE */ |
813 | rc = CIFSSMBSetFileDisposition(xid, tcon, true, netfid, current->tgid); | 811 | rc = CIFSSMBSetFileDisposition(xid, tcon, true, netfid, current->tgid); |
@@ -1180,117 +1178,141 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) | |||
1180 | return rc; | 1178 | return rc; |
1181 | } | 1179 | } |
1182 | 1180 | ||
1181 | static int | ||
1182 | cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath, | ||
1183 | struct dentry *to_dentry, const char *toPath) | ||
1184 | { | ||
1185 | struct cifs_sb_info *cifs_sb = CIFS_SB(from_dentry->d_sb); | ||
1186 | struct cifsTconInfo *pTcon = cifs_sb->tcon; | ||
1187 | __u16 srcfid; | ||
1188 | int oplock, rc; | ||
1189 | |||
1190 | /* try path-based rename first */ | ||
1191 | rc = CIFSSMBRename(xid, pTcon, fromPath, toPath, cifs_sb->local_nls, | ||
1192 | cifs_sb->mnt_cifs_flags & | ||
1193 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1194 | |||
1195 | /* | ||
1196 | * don't bother with rename by filehandle unless file is busy and | ||
1197 | * source Note that cross directory moves do not work with | ||
1198 | * rename by filehandle to various Windows servers. | ||
1199 | */ | ||
1200 | if (rc == 0 || rc != -ETXTBSY) | ||
1201 | return rc; | ||
1202 | |||
1203 | /* open the file to be renamed -- we need DELETE perms */ | ||
1204 | rc = CIFSSMBOpen(xid, pTcon, fromPath, FILE_OPEN, DELETE, | ||
1205 | CREATE_NOT_DIR, &srcfid, &oplock, NULL, | ||
1206 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & | ||
1207 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1208 | |||
1209 | if (rc == 0) { | ||
1210 | rc = CIFSSMBRenameOpenFile(xid, pTcon, srcfid, | ||
1211 | (const char *) to_dentry->d_name.name, | ||
1212 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & | ||
1213 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1214 | |||
1215 | CIFSSMBClose(xid, pTcon, srcfid); | ||
1216 | } | ||
1217 | |||
1218 | return rc; | ||
1219 | } | ||
1220 | |||
1183 | int cifs_rename(struct inode *source_inode, struct dentry *source_direntry, | 1221 | int cifs_rename(struct inode *source_inode, struct dentry *source_direntry, |
1184 | struct inode *target_inode, struct dentry *target_direntry) | 1222 | struct inode *target_inode, struct dentry *target_direntry) |
1185 | { | 1223 | { |
1186 | char *fromName; | 1224 | char *fromName = NULL; |
1187 | char *toName; | 1225 | char *toName = NULL; |
1188 | struct cifs_sb_info *cifs_sb_source; | 1226 | struct cifs_sb_info *cifs_sb_source; |
1189 | struct cifs_sb_info *cifs_sb_target; | 1227 | struct cifs_sb_info *cifs_sb_target; |
1190 | struct cifsTconInfo *pTcon; | 1228 | struct cifsTconInfo *pTcon; |
1229 | FILE_UNIX_BASIC_INFO *info_buf_source = NULL; | ||
1230 | FILE_UNIX_BASIC_INFO *info_buf_target; | ||
1191 | int xid; | 1231 | int xid; |
1192 | int rc = 0; | 1232 | int rc; |
1193 | |||
1194 | xid = GetXid(); | ||
1195 | 1233 | ||
1196 | cifs_sb_target = CIFS_SB(target_inode->i_sb); | 1234 | cifs_sb_target = CIFS_SB(target_inode->i_sb); |
1197 | cifs_sb_source = CIFS_SB(source_inode->i_sb); | 1235 | cifs_sb_source = CIFS_SB(source_inode->i_sb); |
1198 | pTcon = cifs_sb_source->tcon; | 1236 | pTcon = cifs_sb_source->tcon; |
1199 | 1237 | ||
1238 | xid = GetXid(); | ||
1239 | |||
1240 | /* | ||
1241 | * BB: this might be allowed if same server, but different share. | ||
1242 | * Consider adding support for this | ||
1243 | */ | ||
1200 | if (pTcon != cifs_sb_target->tcon) { | 1244 | if (pTcon != cifs_sb_target->tcon) { |
1201 | FreeXid(xid); | 1245 | rc = -EXDEV; |
1202 | return -EXDEV; /* BB actually could be allowed if same server, | 1246 | goto cifs_rename_exit; |
1203 | but different share. | ||
1204 | Might eventually add support for this */ | ||
1205 | } | 1247 | } |
1206 | 1248 | ||
1207 | /* we already have the rename sem so we do not need to grab it again | 1249 | /* |
1208 | here to protect the path integrity */ | 1250 | * we already have the rename sem so we do not need to |
1251 | * grab it again here to protect the path integrity | ||
1252 | */ | ||
1209 | fromName = build_path_from_dentry(source_direntry); | 1253 | fromName = build_path_from_dentry(source_direntry); |
1254 | if (fromName == NULL) { | ||
1255 | rc = -ENOMEM; | ||
1256 | goto cifs_rename_exit; | ||
1257 | } | ||
1258 | |||
1210 | toName = build_path_from_dentry(target_direntry); | 1259 | toName = build_path_from_dentry(target_direntry); |
1211 | if ((fromName == NULL) || (toName == NULL)) { | 1260 | if (toName == NULL) { |
1212 | rc = -ENOMEM; | 1261 | rc = -ENOMEM; |
1213 | goto cifs_rename_exit; | 1262 | goto cifs_rename_exit; |
1214 | } | 1263 | } |
1215 | 1264 | ||
1216 | rc = CIFSSMBRename(xid, pTcon, fromName, toName, | 1265 | rc = cifs_do_rename(xid, source_direntry, fromName, |
1217 | cifs_sb_source->local_nls, | 1266 | target_direntry, toName); |
1218 | cifs_sb_source->mnt_cifs_flags & | 1267 | |
1219 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1220 | if (rc == -EEXIST) { | 1268 | if (rc == -EEXIST) { |
1221 | /* check if they are the same file because rename of hardlinked | 1269 | if (pTcon->unix_ext) { |
1222 | files is a noop */ | 1270 | /* |
1223 | FILE_UNIX_BASIC_INFO *info_buf_source; | 1271 | * Are src and dst hardlinks of same inode? We can |
1224 | FILE_UNIX_BASIC_INFO *info_buf_target; | 1272 | * only tell with unix extensions enabled |
1225 | 1273 | */ | |
1226 | info_buf_source = | 1274 | info_buf_source = |
1227 | kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL); | 1275 | kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO), |
1228 | if (info_buf_source != NULL) { | 1276 | GFP_KERNEL); |
1277 | if (info_buf_source != NULL) | ||
1278 | goto unlink_target; | ||
1279 | |||
1229 | info_buf_target = info_buf_source + 1; | 1280 | info_buf_target = info_buf_source + 1; |
1230 | if (pTcon->unix_ext) | 1281 | rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName, |
1231 | rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName, | 1282 | info_buf_source, |
1232 | info_buf_source, | 1283 | cifs_sb_source->local_nls, |
1233 | cifs_sb_source->local_nls, | 1284 | cifs_sb_source->mnt_cifs_flags & |
1234 | cifs_sb_source->mnt_cifs_flags & | ||
1235 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 1285 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
1236 | /* else rc is still EEXIST so will fall through to | 1286 | if (rc != 0) |
1237 | unlink the target and retry rename */ | 1287 | goto unlink_target; |
1238 | if (rc == 0) { | 1288 | |
1239 | rc = CIFSSMBUnixQPathInfo(xid, pTcon, toName, | 1289 | rc = CIFSSMBUnixQPathInfo(xid, pTcon, |
1240 | info_buf_target, | 1290 | toName, info_buf_target, |
1241 | cifs_sb_target->local_nls, | 1291 | cifs_sb_target->local_nls, |
1242 | /* remap based on source sb */ | 1292 | /* remap based on source sb */ |
1243 | cifs_sb_source->mnt_cifs_flags & | 1293 | cifs_sb_source->mnt_cifs_flags & |
1244 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1245 | } | ||
1246 | if ((rc == 0) && | ||
1247 | (info_buf_source->UniqueId == | ||
1248 | info_buf_target->UniqueId)) { | ||
1249 | /* do not rename since the files are hardlinked which | ||
1250 | is a noop */ | ||
1251 | } else { | ||
1252 | /* we either can not tell the files are hardlinked | ||
1253 | (as with Windows servers) or files are not | ||
1254 | hardlinked so delete the target manually before | ||
1255 | renaming to follow POSIX rather than Windows | ||
1256 | semantics */ | ||
1257 | cifs_unlink(target_inode, target_direntry); | ||
1258 | rc = CIFSSMBRename(xid, pTcon, fromName, | ||
1259 | toName, | ||
1260 | cifs_sb_source->local_nls, | ||
1261 | cifs_sb_source->mnt_cifs_flags | ||
1262 | & CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1263 | } | ||
1264 | kfree(info_buf_source); | ||
1265 | } /* if we can not get memory just leave rc as EEXIST */ | ||
1266 | } | ||
1267 | |||
1268 | if (rc) | ||
1269 | cFYI(1, ("rename rc %d", rc)); | ||
1270 | |||
1271 | if ((rc == -EIO) || (rc == -EEXIST)) { | ||
1272 | int oplock = 0; | ||
1273 | __u16 netfid; | ||
1274 | |||
1275 | /* BB FIXME Is Generic Read correct for rename? */ | ||
1276 | /* if renaming directory - we should not say CREATE_NOT_DIR, | ||
1277 | need to test renaming open directory, also GENERIC_READ | ||
1278 | might not right be right access to request */ | ||
1279 | rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ, | ||
1280 | CREATE_NOT_DIR, &netfid, &oplock, NULL, | ||
1281 | cifs_sb_source->local_nls, | ||
1282 | cifs_sb_source->mnt_cifs_flags & | ||
1283 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1284 | if (rc == 0) { | ||
1285 | rc = CIFSSMBRenameOpenFile(xid, pTcon, netfid, toName, | ||
1286 | cifs_sb_source->local_nls, | ||
1287 | cifs_sb_source->mnt_cifs_flags & | ||
1288 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 1294 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
1289 | CIFSSMBClose(xid, pTcon, netfid); | 1295 | |
1290 | } | 1296 | if (rc == 0 && (info_buf_source->UniqueId == |
1297 | info_buf_target->UniqueId)) | ||
1298 | /* same file, POSIX says that this is a noop */ | ||
1299 | goto cifs_rename_exit; | ||
1300 | } /* else ... BB we could add the same check for Windows by | ||
1301 | checking the UniqueId via FILE_INTERNAL_INFO */ | ||
1302 | unlink_target: | ||
1303 | /* | ||
1304 | * we either can not tell the files are hardlinked (as with | ||
1305 | * Windows servers) or files are not hardlinked. Delete the | ||
1306 | * target manually before renaming to follow POSIX rather than | ||
1307 | * Windows semantics | ||
1308 | */ | ||
1309 | cifs_unlink(target_inode, target_direntry); | ||
1310 | rc = cifs_do_rename(xid, source_direntry, fromName, | ||
1311 | target_direntry, toName); | ||
1291 | } | 1312 | } |
1292 | 1313 | ||
1293 | cifs_rename_exit: | 1314 | cifs_rename_exit: |
1315 | kfree(info_buf_source); | ||
1294 | kfree(fromName); | 1316 | kfree(fromName); |
1295 | kfree(toName); | 1317 | kfree(toName); |
1296 | FreeXid(xid); | 1318 | FreeXid(xid); |