1#include <string.h>2#include <unistd.h>3#include <fcntl.h>4#include <errno.h>56#include "9p.h"7#include "vfs.h"8#include "9pfs.h"9#include "9util.h"1011#define ENABLE_DEBUG (0)12#include "debug.h"1314/**15 * Split a given path into the directory and file portition.16 *17 * @param buf Pointer to a temporary buffer used to create a copy of the18 * path argument in order to prevent modification of the latter.19 * @param bufsiz Size of the temporary buffer.20 * @param path Pointer to the path which should be split.21 * @param dname Pointer to a memory location which should be set to the22 * address of the directory portion.23 * @return Pointer to the file portion of the name.24 */25static char*26breakpath(char *buf, size_t bufsiz, const char *path, char **dname)27{28 char *bname;2930 strncpy(buf, path, bufsiz);31 *dname = buf;3233 bname = strrchr(buf, '/');34 *bname++ = '\0';35 return bname;36}3738/**39 * @defgroup _9pfs_fs_ops File system operations.40 *41 * @{42 */4344static int45_9pfs_mount(vfs_mount_t *mountp)46{47 int r;48 _9pfid *f;49 _9pfs *fs;5051 fs = mountp->private_data;5253 mutex_init(&fs->mtx);54 if ((r = _9pversion(&fs->ctx)))55 return r;56 if ((r = _9pattach(&fs->ctx, &f, fs->uname, fs->aname)))57 return r;5859 (void)f;60 return 0;61}6263static int64_9pfs_umount(vfs_mount_t *mountp)65{66 (void)mountp;6768 return 0;69}7071static int72_9pfs_unlink(vfs_mount_t *mountp, const char *name)73{74 _9pfid *f;75 _9pfs *fs;76 int r;7778 r = 0;79 fs = mountp->private_data;8081 mutex_lock(&fs->mtx);82 if (_9pwalk(&fs->ctx, &f, (char*)name)) {83 r = -ENOENT;84 goto ret;85 }86 if (_9premove(&fs->ctx, f)) {87 r = -EACCES;88 goto ret;89 }9091ret:92 mutex_unlock(&fs->mtx);93 return r;94}9596static int97_9pfs_mkdir(vfs_mount_t *mountp, const char *name, mode_t mode)98{99 _9pfid *f;100 char buf[VFS_NAME_MAX + 1];101 char *dname, *bname;102 _9pfs *fs;103 int r;104105 r = 0;106 fs = mountp->private_data;107108 mutex_lock(&fs->mtx);109 if (!_9pwalk(&fs->ctx, &f, (char*)name)) {110 _9pclunk(&fs->ctx, f);111 r = -EEXIST;112 goto ret;113 }114115 bname = breakpath(buf, sizeof(buf), name, &dname);116 DEBUG("Creating directory '%s' in directory '%s'\n", bname, dname);117118 if (_9pwalk(&fs->ctx, &f, dname)) {119 r = -EACCES;120 goto ret;121 }122123 mode &= 0777;124 mode |= DMDIR;125126 if (_9pcreate(&fs->ctx, f, bname, mode, OREAD)) {127 _9pclunk(&fs->ctx, f);128 r = -EACCES;129 goto ret;130 }131132 _9pclunk(&fs->ctx, f);133134ret:135 mutex_unlock(&fs->mtx);136 return r;137}138139static int140_9pfs_rmdir(vfs_mount_t *mountp, const char *name)141{142 return _9pfs_unlink(mountp, name);143}144145static int146_9pfs_stat(vfs_mount_t *mountp, const char *restrict name, struct stat *restrict buf)147{148 _9pfid *f;149 _9pfs *fs;150 int r;151152 fs = mountp->private_data;153 r = 0;154155 mutex_lock(&fs->mtx);156 if (_9pwalk(&fs->ctx, &f, (char*)name)) {157 r = -ENOENT;158 goto ret;159 }160161 if (_9pstat(&fs->ctx, f, buf)) {162 _9pclunk(&fs->ctx, f);163 r = -EACCES;164 goto ret;165 }166167 _9pclunk(&fs->ctx, f);168169ret:170 mutex_unlock(&fs->mtx);171 return r;172}173174/**@}*/175176/**177 * @defgroup _9pfs_file_ops File operations.178 *179 * @{180 */181182static int183_9pfs_close(vfs_file_t *filp)184{185 _9pfid *f;186 _9pfs *fs;187188 f = filp->private_data.ptr;189 fs = filp->mp->private_data;190191 mutex_lock(&fs->mtx);192 if (_9pclunk(&fs->ctx, f) == -EBADF) {193 mutex_unlock(&fs->mtx);194 return -EBADF;195 }196 mutex_unlock(&fs->mtx);197198 return 0;199}200201static int202_9pfs_fstat(vfs_file_t *filp, struct stat *buf)203{204 _9pfid *f;205 _9pfs *fs;206207 f = filp->private_data.ptr;208 fs = filp->mp->private_data;209210 mutex_lock(&fs->mtx);211 if (_9pstat(&fs->ctx, f, buf)) {212 mutex_unlock(&fs->mtx);213 return -EACCES;214 }215 mutex_unlock(&fs->mtx);216217 return 0;218}219220static off_t _9pfs_lseek(vfs_file_t *filp, off_t off, int whence)221{222 _9pfid *f;223 _9pfs *fs;224 struct stat st;225226 f = filp->private_data.ptr;227 fs = filp->mp->private_data;228229 switch (whence) {230 case SEEK_SET:231 break;232 case SEEK_CUR:233 off += f->off;234 break;235 case SEEK_END:236 mutex_lock(&fs->mtx);237 if (_9pstat(&fs->ctx, f, &st)) {238 mutex_unlock(&fs->mtx);239 return -EINVAL;240 }241 mutex_unlock(&fs->mtx);242243 off += st.st_size;244 break;245 default:246 return -EINVAL;247 }248249 if (off < 0)250 return -EINVAL;251252 mutex_lock(&fs->mtx);253 f->off = off;254 mutex_unlock(&fs->mtx);255256 return off;257}258259static int260_9pfs_open(vfs_file_t *filp, const char *name, int flags, mode_t mode, const char *abs_path)261{262 int r, fl;263 _9pfid *f;264 _9pfs *fs;265 char buf[VFS_NAME_MAX + 1];266 char *bname, *dname;267268 (void)abs_path;269270 r = 0;271 fs = filp->mp->private_data;272273 /* Convert the mode. This assumes that OREAD == O_RDONLY,274 * O_WRONLY == OWRITE and O_RDWR == ORDWR which should always be275 * the case on RIOT. */276 fl = flags & O_ACCMODE;277 if (flags & O_TRUNC)278 fl |= OTRUNC;279280 mutex_lock(&fs->mtx);281 if (!_9pwalk(&fs->ctx, &f, (char*)name)) {282 if (_9popen(&fs->ctx, f, fl)) {283 _9pclunk(&fs->ctx, f);284 r = -EACCES;285 goto ret;286 }287288 filp->private_data.ptr = f;289 goto ret;290 } else if (flags & O_CREAT) {291 bname = breakpath(buf, sizeof(buf), name, &dname);292 if (_9pwalk(&fs->ctx, &f, dname)) {293 r = -ENOENT;294 goto ret;295 }296297 if (_9pcreate(&fs->ctx, f, bname, mode, fl)) {298 _9pclunk(&fs->ctx, f);299 r = -EACCES;300 goto ret;301 }302303 filp->private_data.ptr = f;304 goto ret;305 } else {306 r = -ENOENT;307 goto ret;308 }309310ret:311 mutex_unlock(&fs->mtx);312 return r;313}314315static ssize_t316_9pfs_read(vfs_file_t *filp, void *dest, size_t nbytes)317{318 ssize_t ret;319 _9pfid *f;320 _9pfs *fs;321322 f = filp->private_data.ptr;323 fs = filp->mp->private_data;324325 mutex_lock(&fs->mtx);326 if ((ret = _9pread(&fs->ctx, f, dest, nbytes)) < 0) {327 mutex_unlock(&fs->mtx);328 return -EIO;329 }330 mutex_unlock(&fs->mtx);331332 return ret;333}334335static ssize_t336_9pfs_write(vfs_file_t *filp, const void *src, size_t nbytes)337{338 ssize_t ret;339 _9pfid *f;340 _9pfs *fs;341342 f = filp->private_data.ptr;343 fs = filp->mp->private_data;344345 mutex_lock(&fs->mtx);346 if ((ret = _9pwrite(&fs->ctx, f, (void*)src, nbytes)) < 0) {347 mutex_unlock(&fs->mtx);348 return -EIO;349 }350 mutex_unlock(&fs->mtx);351352 return ret;353}354355/**@}*/356357/**358 * @defgroup _9pfs_dir_ops Directory operations.359 *360 * @{361 */362363static int364_9pfs_opendir(vfs_DIR *dirp, const char *dirname, const char *abs_path)365{366 _9pfid *f;367 _9pfs *fs;368 int r;369370 (void)abs_path;371372 r = 0;373 fs = dirp->mp->private_data;374375 mutex_lock(&fs->mtx);376 if (_9pwalk(&fs->ctx, &f, (char*)dirname)) {377 r = -ENOENT;378 goto ret;379 }380381 if (_9popen(&fs->ctx, f, OREAD)) {382 _9pclunk(&fs->ctx, f);383 r = -EACCES;384 goto ret;385 }386387 if (!(f->qid.type & QTDIR)) {388 _9pclunk(&fs->ctx, f);389 r = -ENOTDIR;390 goto ret;391 }392393 dirp->private_data.ptr = f;394395ret:396 mutex_unlock(&fs->mtx);397 return r;398}399400static int401_9pfs_readdir(vfs_DIR *dirp, vfs_dirent_t *entry)402{403 ssize_t n;404 _9pfid *f;405 _9ppkt pkt;406 _9pfs *fs;407 char dest[_9P_MINSTSIZ + VFS_NAME_MAX + 1];408 int r;409410 r = 0;411 f = dirp->private_data.ptr;412 fs = dirp->mp->private_data;413414 mutex_lock(&fs->mtx);415 if ((n = _9pread(&fs->ctx, f, dest, sizeof(dest))) < 0) {416 r = -EIO;417 goto ret;418 } else if (n == 0) {419 goto ret;420 }421422 pkt.len = n;423 pkt.buf = (unsigned char*)dest;424425 /* Skip all the information we don't need. */426 advbuf(&pkt, 2 * BIT16SZ + BIT32SZ + _9P_QIDSIZ + 3 * BIT32SZ + BIT64SZ);427 if (hstring(entry->d_name, sizeof(entry->d_name), &pkt)) {428 r = -EIO;429 goto ret;430 }431432 entry->d_ino = 0; /* XXX */433 r = 1;434435ret:436 mutex_unlock(&fs->mtx);437 return r;438}439440static int441_9pfs_closedir(vfs_DIR *dirp)442{443 _9pfid *f;444 _9pfs *fs;445446 f = dirp->private_data.ptr;447 fs = dirp->mp->private_data;448449 mutex_lock(&fs->mtx);450 if (_9pclunk(&fs->ctx, f) == -EBADF) {451 mutex_unlock(&fs->mtx);452 return -EBADF;453 }454 mutex_unlock(&fs->mtx);455456 return 0;457}458459/**@}*/460461/**462 * @defgroup fs Struct definitions.463 *464 * @{465 */466467static const vfs_file_system_ops_t _9pfs_fs_ops = {468 .mount = _9pfs_mount,469 .umount = _9pfs_umount,470 .rename = NULL, /* TODO */471 .unlink = _9pfs_unlink,472 .mkdir = _9pfs_mkdir,473 .rmdir = _9pfs_rmdir,474 .stat = _9pfs_stat,475 .statvfs = NULL,476 .fstatvfs = NULL, /* TODO */477};478479static const vfs_file_ops_t _9pfs_file_ops = {480 .close = _9pfs_close,481 .fcntl = NULL,482 .fstat = _9pfs_fstat,483 .lseek = _9pfs_lseek,484 .open = _9pfs_open,485 .read = _9pfs_read,486 .write = _9pfs_write,487};488489static const vfs_dir_ops_t _9pfs_dir_ops = {490 .opendir = _9pfs_opendir,491 .readdir = _9pfs_readdir,492 .closedir = _9pfs_closedir,493};494495const vfs_file_system_t _9p_file_system = {496 .f_op = &_9pfs_file_ops,497 .fs_op = &_9pfs_fs_ops,498 .d_op = &_9pfs_dir_ops,499};500501/**@}*/