Changeset 778d26d in mainline
- Timestamp:
- 2013-07-28T21:06:34Z (12 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 9e9b168
- Parents:
- bf9dc4e2
- Location:
- uspace
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/vfs/vfs.c
rbf9dc4e2 r778d26d 730 730 async_exch_t *exch = vfs_exchange_begin(); 731 731 732 req = async_send_ 0(exch, VFS_IN_RENAME, NULL);732 req = async_send_1(exch, VFS_IN_RENAME, -1, NULL); 733 733 rc = async_data_write_start(exch, olda, olda_size); 734 734 if (rc != EOK) { -
uspace/lib/c/include/ipc/vfs.h
rbf9dc4e2 r778d26d 126 126 127 127 /** 128 * Lookup will not cross any mount points. 129 * If the lookup would have to cross a mount point, it returns EXDEV instead. 130 */ 131 #define L_DISABLE_MOUNTS 4 132 133 /** 128 134 * Lookup will succeed only if the object is a mount point. The flag is mutually 129 135 * exclusive with L_FILE and L_ROOT. -
uspace/lib/fs/libfs.c
rbf9dc4e2 r778d26d 632 632 633 633 if (cur->mp_data.mp_active) { 634 if (lflag & L_DISABLE_MOUNTS) { 635 async_answer_0(rid, EXDEV); 636 LOG_EXIT(EXDEV); 637 goto out; 638 } 639 634 640 async_exch_t *exch = async_exchange_begin(cur->mp_data.sess); 635 641 async_forward_slow(rid, exch, VFS_OUT_LOOKUP, next, last - next, … … 692 698 if ((tmp) && (tmp->mp_data.mp_active) && 693 699 (!(lflag & L_MP) || (next < last))) { 700 701 if (lflag & L_DISABLE_MOUNTS) { 702 async_answer_0(rid, EXDEV); 703 LOG_EXIT(EXDEV); 704 goto out; 705 } 706 694 707 async_exch_t *exch = async_exchange_begin(tmp->mp_data.sess); 695 708 async_forward_slow(rid, exch, VFS_OUT_LOOKUP, next, -
uspace/srv/vfs/vfs_ops.c
rbf9dc4e2 r778d26d 1138 1138 } 1139 1139 1140 static size_t shared_path(char *a, char *b) 1141 { 1142 size_t res = 0; 1143 1144 while (a[res] == b[res] && a[res] != 0) { 1145 res++; 1146 } 1147 1148 if (a[res] == b[res]) { 1149 return res; 1150 } 1151 1152 res--; 1153 while (a[res] != '/') { 1154 res--; 1155 } 1156 return res; 1157 } 1158 1159 static int vfs_rename_internal(vfs_triplet_t *base, char *old, char *new) 1160 { 1161 assert(base != NULL); 1162 assert(old != NULL); 1163 assert(new != NULL); 1164 1165 vfs_lookup_res_t base_lr; 1166 vfs_lookup_res_t old_lr; 1167 vfs_lookup_res_t new_lr_orig; 1168 bool orig_unlinked = false; 1169 1170 int rc; 1171 1172 size_t shared = shared_path(old, new); 1173 1174 /* Do not allow one path to be a prefix of the other. */ 1175 if (old[shared] == 0 || new[shared] == 0) { 1176 return EINVAL; 1177 } 1178 assert(old[shared] == '/'); 1179 assert(new[shared] == '/'); 1180 1181 fibril_rwlock_write_lock(&namespace_rwlock); 1182 1183 /* Resolve the shared portion of the path first. */ 1184 if (shared != 0) { 1185 old[shared] = 0; 1186 rc = vfs_lookup_internal(base, old, L_DIRECTORY, &base_lr); 1187 if (rc != EOK) { 1188 fibril_rwlock_write_unlock(&namespace_rwlock); 1189 return rc; 1190 } 1191 1192 base = &base_lr.triplet; 1193 old[shared] = '/'; 1194 old += shared; 1195 new += shared; 1196 } 1197 1198 1199 rc = vfs_lookup_internal(base, new, L_UNLINK | L_DISABLE_MOUNTS, &new_lr_orig); 1200 if (rc == EOK) { 1201 orig_unlinked = true; 1202 } else if (rc != ENOENT) { 1203 fibril_rwlock_write_unlock(&namespace_rwlock); 1204 return rc; 1205 } 1206 1207 rc = vfs_lookup_internal(base, old, L_UNLINK | L_DISABLE_MOUNTS, &old_lr); 1208 if (rc != EOK) { 1209 if (orig_unlinked) { 1210 vfs_link_internal(base, new, &new_lr_orig.triplet); 1211 } 1212 fibril_rwlock_write_unlock(&namespace_rwlock); 1213 return rc; 1214 } 1215 1216 rc = vfs_link_internal(base, new, &old_lr.triplet); 1217 if (rc != EOK) { 1218 vfs_link_internal(base, old, &old_lr.triplet); 1219 if (orig_unlinked) { 1220 vfs_link_internal(base, new, &new_lr_orig.triplet); 1221 } 1222 fibril_rwlock_write_unlock(&namespace_rwlock); 1223 return rc; 1224 } 1225 1226 if (orig_unlinked) { 1227 vfs_node_t *node = vfs_node_get(&new_lr_orig); 1228 vfs_node_delref(node); 1229 vfs_node_put(node); 1230 } 1231 1232 fibril_rwlock_write_unlock(&namespace_rwlock); 1233 return EOK; 1234 } 1235 1140 1236 void vfs_rename(ipc_callid_t rid, ipc_call_t *request) 1141 1237 { 1238 /* The common base directory. */ 1239 int basefd; 1240 char *old = NULL; 1241 char *new = NULL; 1242 vfs_file_t *base = NULL; 1243 int rc; 1244 1245 basefd = IPC_GET_ARG1(*request); 1246 1142 1247 /* Retrieve the old path. */ 1143 char *old; 1144 int rc = async_data_write_accept((void **) &old, true, 0, 0, 0, NULL); 1145 if (rc != EOK) { 1146 async_answer_0(rid, rc); 1147 return; 1248 rc = async_data_write_accept((void **) &old, true, 0, 0, 0, NULL); 1249 if (rc != EOK) { 1250 goto out; 1148 1251 } 1149 1252 1150 1253 /* Retrieve the new path. */ 1151 char *new;1152 1254 rc = async_data_write_accept((void **) &new, true, 0, 0, 0, NULL); 1153 1255 if (rc != EOK) { 1154 free(old); 1155 async_answer_0(rid, rc); 1156 return; 1256 goto out; 1157 1257 } 1158 1258 … … 1163 1263 1164 1264 if ((!oldc) || (!newc)) { 1165 async_answer_0(rid, EINVAL); 1265 rc = EINVAL; 1266 goto out; 1267 } 1268 1269 assert(oldc[olen] == '\0'); 1270 assert(newc[nlen] == '\0'); 1271 1272 /* Lookup the file structure corresponding to the file descriptor. */ 1273 vfs_node_t *base_node = root; 1274 // TODO: Client-side root. 1275 if (basefd != -1) { 1276 base = vfs_file_get(basefd); 1277 if (!base) { 1278 rc = EBADF; 1279 goto out; 1280 } 1281 base_node = base->node; 1282 } 1283 1284 rc = vfs_rename_internal((vfs_triplet_t *) base_node, oldc, newc); 1285 1286 out: 1287 async_answer_0(rid, rc); 1288 1289 if (old) { 1166 1290 free(old); 1291 } 1292 if (new) { 1167 1293 free(new); 1168 return; 1169 } 1170 1171 oldc[olen] = '\0'; 1172 newc[nlen] = '\0'; 1173 1174 if ((!str_lcmp(newc, oldc, str_length(oldc))) && 1175 ((newc[str_length(oldc)] == '/') || 1176 (str_length(oldc) == 1) || 1177 (str_length(oldc) == str_length(newc)))) { 1178 /* 1179 * oldc is a prefix of newc and either 1180 * - newc continues with a / where oldc ends, or 1181 * - oldc was / itself, or 1182 * - oldc and newc are equal. 1183 */ 1184 async_answer_0(rid, EINVAL); 1185 free(old); 1186 free(new); 1187 return; 1188 } 1189 1190 vfs_lookup_res_t old_lr; 1191 vfs_lookup_res_t new_lr; 1192 vfs_lookup_res_t new_par_lr; 1193 fibril_rwlock_write_lock(&namespace_rwlock); 1194 1195 /* Lookup the node belonging to the old file name. */ 1196 rc = vfs_lookup_internal((vfs_triplet_t *) root, oldc, L_NONE, &old_lr); 1197 if (rc != EOK) { 1198 fibril_rwlock_write_unlock(&namespace_rwlock); 1199 async_answer_0(rid, rc); 1200 free(old); 1201 free(new); 1202 return; 1203 } 1204 1205 vfs_node_t *old_node = vfs_node_get(&old_lr); 1206 if (!old_node) { 1207 fibril_rwlock_write_unlock(&namespace_rwlock); 1208 async_answer_0(rid, ENOMEM); 1209 free(old); 1210 free(new); 1211 return; 1212 } 1213 1214 /* Determine the path to the parent of the node with the new name. */ 1215 char *parentc = str_dup(newc); 1216 if (!parentc) { 1217 fibril_rwlock_write_unlock(&namespace_rwlock); 1218 vfs_node_put(old_node); 1219 async_answer_0(rid, rc); 1220 free(old); 1221 free(new); 1222 return; 1223 } 1224 1225 char *lastsl = str_rchr(parentc + 1, '/'); 1226 if (lastsl) 1227 *lastsl = '\0'; 1228 else 1229 parentc[1] = '\0'; 1230 1231 /* Lookup parent of the new file name. */ 1232 rc = vfs_lookup_internal((vfs_triplet_t *) root, parentc, L_NONE, &new_par_lr); 1233 free(parentc); /* not needed anymore */ 1234 if (rc != EOK) { 1235 fibril_rwlock_write_unlock(&namespace_rwlock); 1236 vfs_node_put(old_node); 1237 async_answer_0(rid, rc); 1238 free(old); 1239 free(new); 1240 return; 1241 } 1242 1243 /* Check whether linking to the same file system instance. */ 1244 if ((old_node->fs_handle != new_par_lr.triplet.fs_handle) || 1245 (old_node->service_id != new_par_lr.triplet.service_id)) { 1246 fibril_rwlock_write_unlock(&namespace_rwlock); 1247 vfs_node_put(old_node); 1248 async_answer_0(rid, EXDEV); /* different file systems */ 1249 free(old); 1250 free(new); 1251 return; 1252 } 1253 1254 /* Destroy the old link for the new name. */ 1255 vfs_node_t *new_node = NULL; 1256 rc = vfs_lookup_internal((vfs_triplet_t *) root, newc, L_UNLINK, &new_lr); 1257 1258 switch (rc) { 1259 case ENOENT: 1260 /* simply not in our way */ 1261 break; 1262 case EOK: 1263 new_node = vfs_node_get(&new_lr); 1264 if (!new_node) { 1265 fibril_rwlock_write_unlock(&namespace_rwlock); 1266 vfs_node_put(old_node); 1267 async_answer_0(rid, ENOMEM); 1268 free(old); 1269 free(new); 1270 return; 1271 } 1272 fibril_mutex_lock(&nodes_mutex); 1273 new_node->lnkcnt--; 1274 fibril_mutex_unlock(&nodes_mutex); 1275 break; 1276 default: 1277 fibril_rwlock_write_unlock(&namespace_rwlock); 1278 vfs_node_put(old_node); 1279 async_answer_0(rid, ENOTEMPTY); 1280 free(old); 1281 free(new); 1282 return; 1283 } 1284 1285 /* Create the new link for the new name. */ 1286 rc = vfs_link_internal((vfs_triplet_t *) root, newc, (vfs_triplet_t *) old_node); 1287 if (rc != EOK) { 1288 fibril_rwlock_write_unlock(&namespace_rwlock); 1289 vfs_node_put(old_node); 1290 if (new_node) 1291 vfs_node_put(new_node); 1292 async_answer_0(rid, rc); 1293 free(old); 1294 free(new); 1295 return; 1296 } 1297 1298 fibril_mutex_lock(&nodes_mutex); 1299 old_node->lnkcnt++; 1300 fibril_mutex_unlock(&nodes_mutex); 1301 1302 /* Destroy the link for the old name. */ 1303 rc = vfs_lookup_internal((vfs_triplet_t *) root, oldc, L_UNLINK, NULL); 1304 if (rc != EOK) { 1305 fibril_rwlock_write_unlock(&namespace_rwlock); 1306 vfs_node_put(old_node); 1307 if (new_node) 1308 vfs_node_put(new_node); 1309 async_answer_0(rid, rc); 1310 free(old); 1311 free(new); 1312 return; 1313 } 1314 1315 fibril_mutex_lock(&nodes_mutex); 1316 old_node->lnkcnt--; 1317 fibril_mutex_unlock(&nodes_mutex); 1318 fibril_rwlock_write_unlock(&namespace_rwlock); 1319 vfs_node_put(old_node); 1320 1321 if (new_node) 1322 vfs_node_put(new_node); 1323 1324 free(old); 1325 free(new); 1326 async_answer_0(rid, EOK); 1294 } 1295 if (base) { 1296 vfs_file_put(base); 1297 } 1327 1298 } 1328 1299
Note:
See TracChangeset
for help on using the changeset viewer.