Changeset 778d26d in mainline


Ignore:
Timestamp:
2013-07-28T21:06:34Z (11 years ago)
Author:
Jiri Zarevucky <zarevucky.jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
9e9b168
Parents:
bf9dc4e2
Message:

Relativize rename().

Location:
uspace
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/generic/vfs/vfs.c

    rbf9dc4e2 r778d26d  
    730730        async_exch_t *exch = vfs_exchange_begin();
    731731       
    732         req = async_send_0(exch, VFS_IN_RENAME, NULL);
     732        req = async_send_1(exch, VFS_IN_RENAME, -1, NULL);
    733733        rc = async_data_write_start(exch, olda, olda_size);
    734734        if (rc != EOK) {
  • uspace/lib/c/include/ipc/vfs.h

    rbf9dc4e2 r778d26d  
    126126
    127127/**
     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/**
    128134 * Lookup will succeed only if the object is a mount point. The flag is mutually
    129135 * exclusive with L_FILE and L_ROOT.
  • uspace/lib/fs/libfs.c

    rbf9dc4e2 r778d26d  
    632632       
    633633        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               
    634640                async_exch_t *exch = async_exchange_begin(cur->mp_data.sess);
    635641                async_forward_slow(rid, exch, VFS_OUT_LOOKUP, next, last - next,
     
    692698                if ((tmp) && (tmp->mp_data.mp_active) &&
    693699                    (!(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                       
    694707                        async_exch_t *exch = async_exchange_begin(tmp->mp_data.sess);
    695708                        async_forward_slow(rid, exch, VFS_OUT_LOOKUP, next,
  • uspace/srv/vfs/vfs_ops.c

    rbf9dc4e2 r778d26d  
    11381138}
    11391139
     1140static 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
     1159static 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
    11401236void vfs_rename(ipc_callid_t rid, ipc_call_t *request)
    11411237{
     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       
    11421247        /* 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;
    11481251        }
    11491252       
    11501253        /* Retrieve the new path. */
    1151         char *new;
    11521254        rc = async_data_write_accept((void **) &new, true, 0, 0, 0, NULL);
    11531255        if (rc != EOK) {
    1154                 free(old);
    1155                 async_answer_0(rid, rc);
    1156                 return;
     1256                goto out;
    11571257        }
    11581258       
     
    11631263       
    11641264        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
     1286out:
     1287        async_answer_0(rid, rc);
     1288
     1289        if (old) {
    11661290                free(old);
     1291        }
     1292        if (new) {
    11671293                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        }
    13271298}
    13281299
Note: See TracChangeset for help on using the changeset viewer.