00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00035 #include <vfs/vfs.h>
00036 #include <vfs/canonify.h>
00037 #include <macros.h>
00038 #include <stdlib.h>
00039 #include <unistd.h>
00040 #include <dirent.h>
00041 #include <fcntl.h>
00042 #include <stdio.h>
00043 #include <sys/stat.h>
00044 #include <sys/types.h>
00045 #include <ipc/services.h>
00046 #include <ipc/ns.h>
00047 #include <async.h>
00048 #include <fibril_synch.h>
00049 #include <errno.h>
00050 #include <assert.h>
00051 #include <str.h>
00052 #include <devmap.h>
00053 #include <ipc/vfs.h>
00054 #include <ipc/devmap.h>
00055
00056 static async_sess_t vfs_session;
00057
00058 static FIBRIL_MUTEX_INITIALIZE(vfs_phone_mutex);
00059 static int vfs_phone = -1;
00060
00061 static FIBRIL_MUTEX_INITIALIZE(cwd_mutex);
00062
00063 static int cwd_fd = -1;
00064 static char *cwd_path = NULL;
00065 static size_t cwd_size = 0;
00066
00067 char *absolutize(const char *path, size_t *retlen)
00068 {
00069 char *ncwd_path;
00070 char *ncwd_path_nc;
00071 size_t total_size;
00072
00073 fibril_mutex_lock(&cwd_mutex);
00074 size_t size = str_size(path);
00075 if (*path != '/') {
00076 if (!cwd_path) {
00077 fibril_mutex_unlock(&cwd_mutex);
00078 return NULL;
00079 }
00080 total_size = cwd_size + 1 + size + 1;
00081 ncwd_path_nc = malloc(total_size);
00082 if (!ncwd_path_nc) {
00083 fibril_mutex_unlock(&cwd_mutex);
00084 return NULL;
00085 }
00086 str_cpy(ncwd_path_nc, total_size, cwd_path);
00087 ncwd_path_nc[cwd_size] = '/';
00088 ncwd_path_nc[cwd_size + 1] = '\0';
00089 } else {
00090 total_size = size + 1;
00091 ncwd_path_nc = malloc(total_size);
00092 if (!ncwd_path_nc) {
00093 fibril_mutex_unlock(&cwd_mutex);
00094 return NULL;
00095 }
00096 ncwd_path_nc[0] = '\0';
00097 }
00098 str_append(ncwd_path_nc, total_size, path);
00099 ncwd_path = canonify(ncwd_path_nc, retlen);
00100 if (!ncwd_path) {
00101 fibril_mutex_unlock(&cwd_mutex);
00102 free(ncwd_path_nc);
00103 return NULL;
00104 }
00105
00106
00107
00108
00109
00110 ncwd_path = str_dup(ncwd_path);
00111 free(ncwd_path_nc);
00112 if (!ncwd_path) {
00113 fibril_mutex_unlock(&cwd_mutex);
00114 return NULL;
00115 }
00116 fibril_mutex_unlock(&cwd_mutex);
00117 return ncwd_path;
00118 }
00119
00121 static void vfs_connect(void)
00122 {
00123 while (vfs_phone < 0)
00124 vfs_phone = service_connect_blocking(SERVICE_VFS, 0, 0);
00125
00126 async_session_create(&vfs_session, vfs_phone, 0);
00127 }
00128
00133 static int vfs_exchange_begin(void)
00134 {
00135 fibril_mutex_lock(&vfs_phone_mutex);
00136 if (vfs_phone < 0)
00137 vfs_connect();
00138 fibril_mutex_unlock(&vfs_phone_mutex);
00139
00140 return async_exchange_begin(&vfs_session);
00141 }
00142
00147 static void vfs_exchange_end(int phone)
00148 {
00149 async_exchange_end(&vfs_session, phone);
00150 }
00151
00152 int mount(const char *fs_name, const char *mp, const char *fqdn,
00153 const char *opts, unsigned int flags)
00154 {
00155 int null_id = -1;
00156 char null[DEVMAP_NAME_MAXLEN];
00157
00158 if (str_cmp(fqdn, "") == 0) {
00159
00160
00161 null_id = devmap_null_create();
00162
00163 if (null_id == -1)
00164 return ENOMEM;
00165
00166 snprintf(null, DEVMAP_NAME_MAXLEN, "null/%d", null_id);
00167 fqdn = null;
00168 }
00169
00170 devmap_handle_t devmap_handle;
00171 int res = devmap_device_get_handle(fqdn, &devmap_handle, flags);
00172 if (res != EOK) {
00173 if (null_id != -1)
00174 devmap_null_destroy(null_id);
00175
00176 return res;
00177 }
00178
00179 size_t mpa_size;
00180 char *mpa = absolutize(mp, &mpa_size);
00181 if (!mpa) {
00182 if (null_id != -1)
00183 devmap_null_destroy(null_id);
00184
00185 return ENOMEM;
00186 }
00187
00188 int vfs_phone = vfs_exchange_begin();
00189
00190 sysarg_t rc_orig;
00191 aid_t req = async_send_2(vfs_phone, VFS_IN_MOUNT, devmap_handle, flags, NULL);
00192 sysarg_t rc = async_data_write_start(vfs_phone, (void *) mpa, mpa_size);
00193 if (rc != EOK) {
00194 vfs_exchange_end(vfs_phone);
00195 free(mpa);
00196 async_wait_for(req, &rc_orig);
00197
00198 if (null_id != -1)
00199 devmap_null_destroy(null_id);
00200
00201 if (rc_orig == EOK)
00202 return (int) rc;
00203 else
00204 return (int) rc_orig;
00205 }
00206
00207 rc = async_data_write_start(vfs_phone, (void *) opts, str_size(opts));
00208 if (rc != EOK) {
00209 vfs_exchange_end(vfs_phone);
00210 free(mpa);
00211 async_wait_for(req, &rc_orig);
00212
00213 if (null_id != -1)
00214 devmap_null_destroy(null_id);
00215
00216 if (rc_orig == EOK)
00217 return (int) rc;
00218 else
00219 return (int) rc_orig;
00220 }
00221
00222 rc = async_data_write_start(vfs_phone, (void *) fs_name, str_size(fs_name));
00223 if (rc != EOK) {
00224 vfs_exchange_end(vfs_phone);
00225 free(mpa);
00226 async_wait_for(req, &rc_orig);
00227
00228 if (null_id != -1)
00229 devmap_null_destroy(null_id);
00230
00231 if (rc_orig == EOK)
00232 return (int) rc;
00233 else
00234 return (int) rc_orig;
00235 }
00236
00237
00238 rc = async_req_0_0(vfs_phone, IPC_M_PING);
00239 if (rc != EOK) {
00240 vfs_exchange_end(vfs_phone);
00241 free(mpa);
00242 async_wait_for(req, &rc_orig);
00243
00244 if (null_id != -1)
00245 devmap_null_destroy(null_id);
00246
00247 if (rc_orig == EOK)
00248 return (int) rc;
00249 else
00250 return (int) rc_orig;
00251 }
00252
00253 vfs_exchange_end(vfs_phone);
00254 free(mpa);
00255 async_wait_for(req, &rc);
00256
00257 if ((rc != EOK) && (null_id != -1))
00258 devmap_null_destroy(null_id);
00259
00260 return (int) rc;
00261 }
00262
00263 int unmount(const char *mp)
00264 {
00265 sysarg_t rc;
00266 sysarg_t rc_orig;
00267 aid_t req;
00268 size_t mpa_size;
00269 char *mpa;
00270
00271 mpa = absolutize(mp, &mpa_size);
00272 if (!mpa)
00273 return ENOMEM;
00274
00275 int vfs_phone = vfs_exchange_begin();
00276
00277 req = async_send_0(vfs_phone, VFS_IN_UNMOUNT, NULL);
00278 rc = async_data_write_start(vfs_phone, (void *) mpa, mpa_size);
00279 if (rc != EOK) {
00280 vfs_exchange_end(vfs_phone);
00281 free(mpa);
00282 async_wait_for(req, &rc_orig);
00283 if (rc_orig == EOK)
00284 return (int) rc;
00285 else
00286 return (int) rc_orig;
00287 }
00288
00289
00290 vfs_exchange_end(vfs_phone);
00291 free(mpa);
00292 async_wait_for(req, &rc);
00293
00294 return (int) rc;
00295 }
00296
00297 static int open_internal(const char *abs, size_t abs_size, int lflag, int oflag)
00298 {
00299 int vfs_phone = vfs_exchange_begin();
00300
00301 ipc_call_t answer;
00302 aid_t req = async_send_3(vfs_phone, VFS_IN_OPEN, lflag, oflag, 0, &answer);
00303 sysarg_t rc = async_data_write_start(vfs_phone, abs, abs_size);
00304
00305 if (rc != EOK) {
00306 vfs_exchange_end(vfs_phone);
00307
00308 sysarg_t rc_orig;
00309 async_wait_for(req, &rc_orig);
00310
00311 if (rc_orig == EOK)
00312 return (int) rc;
00313 else
00314 return (int) rc_orig;
00315 }
00316
00317 vfs_exchange_end(vfs_phone);
00318 async_wait_for(req, &rc);
00319
00320 if (rc != EOK)
00321 return (int) rc;
00322
00323 return (int) IPC_GET_ARG1(answer);
00324 }
00325
00326 int open(const char *path, int oflag, ...)
00327 {
00328 size_t abs_size;
00329 char *abs = absolutize(path, &abs_size);
00330 if (!abs)
00331 return ENOMEM;
00332
00333 int ret = open_internal(abs, abs_size, L_FILE, oflag);
00334 free(abs);
00335
00336 return ret;
00337 }
00338
00339 int open_node(fdi_node_t *node, int oflag)
00340 {
00341 int vfs_phone = vfs_exchange_begin();
00342
00343 ipc_call_t answer;
00344 aid_t req = async_send_4(vfs_phone, VFS_IN_OPEN_NODE, node->fs_handle,
00345 node->devmap_handle, node->index, oflag, &answer);
00346
00347 vfs_exchange_end(vfs_phone);
00348
00349 sysarg_t rc;
00350 async_wait_for(req, &rc);
00351
00352 if (rc != EOK)
00353 return (int) rc;
00354
00355 return (int) IPC_GET_ARG1(answer);
00356 }
00357
00358 int close(int fildes)
00359 {
00360 sysarg_t rc;
00361
00362 int vfs_phone = vfs_exchange_begin();
00363
00364 rc = async_req_1_0(vfs_phone, VFS_IN_CLOSE, fildes);
00365
00366 vfs_exchange_end(vfs_phone);
00367
00368 return (int)rc;
00369 }
00370
00371 ssize_t read(int fildes, void *buf, size_t nbyte)
00372 {
00373 sysarg_t rc;
00374 ipc_call_t answer;
00375 aid_t req;
00376
00377 int vfs_phone = vfs_exchange_begin();
00378
00379 req = async_send_1(vfs_phone, VFS_IN_READ, fildes, &answer);
00380 rc = async_data_read_start_generic(vfs_phone, (void *) buf, nbyte,
00381 IPC_XF_RESTRICT);
00382 if (rc != EOK) {
00383 vfs_exchange_end(vfs_phone);
00384
00385 sysarg_t rc_orig;
00386 async_wait_for(req, &rc_orig);
00387
00388 if (rc_orig == EOK)
00389 return (ssize_t) rc;
00390 else
00391 return (ssize_t) rc_orig;
00392 }
00393 vfs_exchange_end(vfs_phone);
00394 async_wait_for(req, &rc);
00395 if (rc == EOK)
00396 return (ssize_t) IPC_GET_ARG1(answer);
00397 else
00398 return rc;
00399 }
00400
00401 ssize_t write(int fildes, const void *buf, size_t nbyte)
00402 {
00403 sysarg_t rc;
00404 ipc_call_t answer;
00405 aid_t req;
00406
00407 int vfs_phone = vfs_exchange_begin();
00408
00409 req = async_send_1(vfs_phone, VFS_IN_WRITE, fildes, &answer);
00410 rc = async_data_write_start_generic(vfs_phone, (void *) buf, nbyte,
00411 IPC_XF_RESTRICT);
00412 if (rc != EOK) {
00413 vfs_exchange_end(vfs_phone);
00414
00415 sysarg_t rc_orig;
00416 async_wait_for(req, &rc_orig);
00417
00418 if (rc_orig == EOK)
00419 return (ssize_t) rc;
00420 else
00421 return (ssize_t) rc_orig;
00422 }
00423 vfs_exchange_end(vfs_phone);
00424 async_wait_for(req, &rc);
00425 if (rc == EOK)
00426 return (ssize_t) IPC_GET_ARG1(answer);
00427 else
00428 return -1;
00429 }
00430
00431 int fsync(int fildes)
00432 {
00433 int vfs_phone = vfs_exchange_begin();
00434
00435 sysarg_t rc = async_req_1_0(vfs_phone, VFS_IN_SYNC, fildes);
00436
00437 vfs_exchange_end(vfs_phone);
00438
00439 return (int) rc;
00440 }
00441
00442 off64_t lseek(int fildes, off64_t offset, int whence)
00443 {
00444 int vfs_phone = vfs_exchange_begin();
00445
00446 sysarg_t newoff_lo;
00447 sysarg_t newoff_hi;
00448 sysarg_t rc = async_req_4_2(vfs_phone, VFS_IN_SEEK, fildes,
00449 LOWER32(offset), UPPER32(offset), whence,
00450 &newoff_lo, &newoff_hi);
00451
00452 vfs_exchange_end(vfs_phone);
00453
00454 if (rc != EOK)
00455 return (off64_t) -1;
00456
00457 return (off64_t) MERGE_LOUP32(newoff_lo, newoff_hi);
00458 }
00459
00460 int ftruncate(int fildes, aoff64_t length)
00461 {
00462 sysarg_t rc;
00463
00464 int vfs_phone = vfs_exchange_begin();
00465
00466 rc = async_req_3_0(vfs_phone, VFS_IN_TRUNCATE, fildes,
00467 LOWER32(length), UPPER32(length));
00468 vfs_exchange_end(vfs_phone);
00469
00470 return (int) rc;
00471 }
00472
00473 int fstat(int fildes, struct stat *stat)
00474 {
00475 sysarg_t rc;
00476 aid_t req;
00477
00478 int vfs_phone = vfs_exchange_begin();
00479
00480 req = async_send_1(vfs_phone, VFS_IN_FSTAT, fildes, NULL);
00481 rc = async_data_read_start(vfs_phone, (void *) stat, sizeof(struct stat));
00482 if (rc != EOK) {
00483 vfs_exchange_end(vfs_phone);
00484
00485 sysarg_t rc_orig;
00486 async_wait_for(req, &rc_orig);
00487
00488 if (rc_orig == EOK)
00489 return (ssize_t) rc;
00490 else
00491 return (ssize_t) rc_orig;
00492 }
00493 vfs_exchange_end(vfs_phone);
00494 async_wait_for(req, &rc);
00495
00496 return rc;
00497 }
00498
00499 int stat(const char *path, struct stat *stat)
00500 {
00501 sysarg_t rc;
00502 sysarg_t rc_orig;
00503 aid_t req;
00504
00505 size_t pa_size;
00506 char *pa = absolutize(path, &pa_size);
00507 if (!pa)
00508 return ENOMEM;
00509
00510 int vfs_phone = vfs_exchange_begin();
00511
00512 req = async_send_0(vfs_phone, VFS_IN_STAT, NULL);
00513 rc = async_data_write_start(vfs_phone, pa, pa_size);
00514 if (rc != EOK) {
00515 vfs_exchange_end(vfs_phone);
00516 free(pa);
00517 async_wait_for(req, &rc_orig);
00518 if (rc_orig == EOK)
00519 return (int) rc;
00520 else
00521 return (int) rc_orig;
00522 }
00523 rc = async_data_read_start(vfs_phone, stat, sizeof(struct stat));
00524 if (rc != EOK) {
00525 vfs_exchange_end(vfs_phone);
00526 free(pa);
00527 async_wait_for(req, &rc_orig);
00528 if (rc_orig == EOK)
00529 return (int) rc;
00530 else
00531 return (int) rc_orig;
00532 }
00533 vfs_exchange_end(vfs_phone);
00534 free(pa);
00535 async_wait_for(req, &rc);
00536 return rc;
00537 }
00538
00539 DIR *opendir(const char *dirname)
00540 {
00541 DIR *dirp = malloc(sizeof(DIR));
00542 if (!dirp)
00543 return NULL;
00544
00545 size_t abs_size;
00546 char *abs = absolutize(dirname, &abs_size);
00547 if (!abs) {
00548 free(dirp);
00549 return NULL;
00550 }
00551
00552 int ret = open_internal(abs, abs_size, L_DIRECTORY, 0);
00553 free(abs);
00554
00555 if (ret < 0) {
00556 free(dirp);
00557 return NULL;
00558 }
00559
00560 dirp->fd = ret;
00561 return dirp;
00562 }
00563
00564 struct dirent *readdir(DIR *dirp)
00565 {
00566 ssize_t len = read(dirp->fd, &dirp->res.d_name[0], NAME_MAX + 1);
00567 if (len <= 0)
00568 return NULL;
00569 return &dirp->res;
00570 }
00571
00572 void rewinddir(DIR *dirp)
00573 {
00574 (void) lseek(dirp->fd, 0, SEEK_SET);
00575 }
00576
00577 int closedir(DIR *dirp)
00578 {
00579 (void) close(dirp->fd);
00580 free(dirp);
00581 return 0;
00582 }
00583
00584 int mkdir(const char *path, mode_t mode)
00585 {
00586 sysarg_t rc;
00587 aid_t req;
00588
00589 size_t pa_size;
00590 char *pa = absolutize(path, &pa_size);
00591 if (!pa)
00592 return ENOMEM;
00593
00594 int vfs_phone = vfs_exchange_begin();
00595
00596 req = async_send_1(vfs_phone, VFS_IN_MKDIR, mode, NULL);
00597 rc = async_data_write_start(vfs_phone, pa, pa_size);
00598 if (rc != EOK) {
00599 vfs_exchange_end(vfs_phone);
00600 free(pa);
00601
00602 sysarg_t rc_orig;
00603 async_wait_for(req, &rc_orig);
00604
00605 if (rc_orig == EOK)
00606 return (int) rc;
00607 else
00608 return (int) rc_orig;
00609 }
00610 vfs_exchange_end(vfs_phone);
00611 free(pa);
00612 async_wait_for(req, &rc);
00613 return rc;
00614 }
00615
00616 static int _unlink(const char *path, int lflag)
00617 {
00618 sysarg_t rc;
00619 aid_t req;
00620
00621 size_t pa_size;
00622 char *pa = absolutize(path, &pa_size);
00623 if (!pa)
00624 return ENOMEM;
00625
00626 int vfs_phone = vfs_exchange_begin();
00627
00628 req = async_send_0(vfs_phone, VFS_IN_UNLINK, NULL);
00629 rc = async_data_write_start(vfs_phone, pa, pa_size);
00630 if (rc != EOK) {
00631 vfs_exchange_end(vfs_phone);
00632 free(pa);
00633
00634 sysarg_t rc_orig;
00635 async_wait_for(req, &rc_orig);
00636
00637 if (rc_orig == EOK)
00638 return (int) rc;
00639 else
00640 return (int) rc_orig;
00641 }
00642 vfs_exchange_end(vfs_phone);
00643 free(pa);
00644 async_wait_for(req, &rc);
00645 return rc;
00646 }
00647
00648 int unlink(const char *path)
00649 {
00650 return _unlink(path, L_NONE);
00651 }
00652
00653 int rmdir(const char *path)
00654 {
00655 return _unlink(path, L_DIRECTORY);
00656 }
00657
00658 int rename(const char *old, const char *new)
00659 {
00660 sysarg_t rc;
00661 sysarg_t rc_orig;
00662 aid_t req;
00663
00664 size_t olda_size;
00665 char *olda = absolutize(old, &olda_size);
00666 if (!olda)
00667 return ENOMEM;
00668
00669 size_t newa_size;
00670 char *newa = absolutize(new, &newa_size);
00671 if (!newa) {
00672 free(olda);
00673 return ENOMEM;
00674 }
00675
00676 int vfs_phone = vfs_exchange_begin();
00677
00678 req = async_send_0(vfs_phone, VFS_IN_RENAME, NULL);
00679 rc = async_data_write_start(vfs_phone, olda, olda_size);
00680 if (rc != EOK) {
00681 vfs_exchange_end(vfs_phone);
00682 free(olda);
00683 free(newa);
00684 async_wait_for(req, &rc_orig);
00685 if (rc_orig == EOK)
00686 return (int) rc;
00687 else
00688 return (int) rc_orig;
00689 }
00690 rc = async_data_write_start(vfs_phone, newa, newa_size);
00691 if (rc != EOK) {
00692 vfs_exchange_end(vfs_phone);
00693 free(olda);
00694 free(newa);
00695 async_wait_for(req, &rc_orig);
00696 if (rc_orig == EOK)
00697 return (int) rc;
00698 else
00699 return (int) rc_orig;
00700 }
00701 vfs_exchange_end(vfs_phone);
00702 free(olda);
00703 free(newa);
00704 async_wait_for(req, &rc);
00705 return rc;
00706 }
00707
00708 int chdir(const char *path)
00709 {
00710 size_t abs_size;
00711 char *abs = absolutize(path, &abs_size);
00712 if (!abs)
00713 return ENOMEM;
00714
00715 int fd = open_internal(abs, abs_size, L_DIRECTORY, O_DESC);
00716
00717 if (fd < 0) {
00718 free(abs);
00719 return ENOENT;
00720 }
00721
00722 fibril_mutex_lock(&cwd_mutex);
00723
00724 if (cwd_fd >= 0)
00725 close(cwd_fd);
00726
00727
00728 if (cwd_path)
00729 free(cwd_path);
00730
00731 cwd_fd = fd;
00732 cwd_path = abs;
00733 cwd_size = abs_size;
00734
00735 fibril_mutex_unlock(&cwd_mutex);
00736 return EOK;
00737 }
00738
00739 char *getcwd(char *buf, size_t size)
00740 {
00741 if (size == 0)
00742 return NULL;
00743
00744 fibril_mutex_lock(&cwd_mutex);
00745
00746 if ((cwd_size == 0) || (size < cwd_size + 1)) {
00747 fibril_mutex_unlock(&cwd_mutex);
00748 return NULL;
00749 }
00750
00751 str_cpy(buf, size, cwd_path);
00752 fibril_mutex_unlock(&cwd_mutex);
00753
00754 return buf;
00755 }
00756
00757 int fd_phone(int fildes)
00758 {
00759 struct stat stat;
00760
00761 int rc = fstat(fildes, &stat);
00762 if (rc != 0)
00763 return rc;
00764
00765 if (!stat.device)
00766 return -1;
00767
00768 return devmap_device_connect(stat.device, 0);
00769 }
00770
00771 int fd_node(int fildes, fdi_node_t *node)
00772 {
00773 struct stat stat;
00774 int rc;
00775
00776 rc = fstat(fildes, &stat);
00777
00778 if (rc == EOK) {
00779 node->fs_handle = stat.fs_handle;
00780 node->devmap_handle = stat.devmap_handle;
00781 node->index = stat.index;
00782 }
00783
00784 return rc;
00785 }
00786
00787 int dup2(int oldfd, int newfd)
00788 {
00789 int vfs_phone = vfs_exchange_begin();
00790
00791 sysarg_t ret;
00792 sysarg_t rc = async_req_2_1(vfs_phone, VFS_IN_DUP, oldfd, newfd, &ret);
00793
00794 vfs_exchange_end(vfs_phone);
00795
00796 if (rc == EOK)
00797 return (int) ret;
00798
00799 return (int) rc;
00800 }
00801