|
|
1.1 ! root 1: /* ! 2: * Virtio 9p synthetic file system support ! 3: * ! 4: * Copyright IBM, Corp. 2011 ! 5: * ! 6: * Authors: ! 7: * Malahal Naineni <[email protected]> ! 8: * Aneesh Kumar K.V <[email protected]> ! 9: * ! 10: * This work is licensed under the terms of the GNU GPL, version 2. See ! 11: * the COPYING file in the top-level directory. ! 12: * ! 13: */ ! 14: ! 15: #include "hw/virtio.h" ! 16: #include "virtio-9p.h" ! 17: #include "virtio-9p-xattr.h" ! 18: #include "fsdev/qemu-fsdev.h" ! 19: #include "virtio-9p-synth.h" ! 20: ! 21: #include <sys/stat.h> ! 22: ! 23: /* Root node for synth file system */ ! 24: V9fsSynthNode v9fs_synth_root = { ! 25: .name = "/", ! 26: .actual_attr = { ! 27: .mode = 0555 | S_IFDIR, ! 28: .nlink = 1, ! 29: }, ! 30: .attr = &v9fs_synth_root.actual_attr, ! 31: }; ! 32: ! 33: static QemuMutex v9fs_synth_mutex; ! 34: static int v9fs_synth_node_count; ! 35: /* set to 1 when the synth fs is ready */ ! 36: static int v9fs_synth_fs; ! 37: ! 38: static V9fsSynthNode *v9fs_add_dir_node(V9fsSynthNode *parent, int mode, ! 39: const char *name, ! 40: V9fsSynthNodeAttr *attr, int inode) ! 41: { ! 42: V9fsSynthNode *node; ! 43: ! 44: /* Add directory type and remove write bits */ ! 45: mode = ((mode & 0777) | S_IFDIR) & ~(S_IWUSR | S_IWGRP | S_IWOTH); ! 46: node = g_malloc0(sizeof(V9fsSynthNode)); ! 47: if (attr) { ! 48: /* We are adding .. or . entries */ ! 49: node->attr = attr; ! 50: node->attr->nlink++; ! 51: } else { ! 52: node->attr = &node->actual_attr; ! 53: node->attr->inode = inode; ! 54: node->attr->nlink = 1; ! 55: /* We don't allow write to directories */ ! 56: node->attr->mode = mode; ! 57: node->attr->write = NULL; ! 58: node->attr->read = NULL; ! 59: } ! 60: node->private = node; ! 61: strncpy(node->name, name, sizeof(node->name)); ! 62: QLIST_INSERT_HEAD_RCU(&parent->child, node, sibling); ! 63: return node; ! 64: } ! 65: ! 66: int qemu_v9fs_synth_mkdir(V9fsSynthNode *parent, int mode, ! 67: const char *name, V9fsSynthNode **result) ! 68: { ! 69: int ret; ! 70: V9fsSynthNode *node, *tmp; ! 71: ! 72: if (!v9fs_synth_fs) { ! 73: return EAGAIN; ! 74: } ! 75: if (!name || (strlen(name) >= NAME_MAX)) { ! 76: return EINVAL; ! 77: } ! 78: if (!parent) { ! 79: parent = &v9fs_synth_root; ! 80: } ! 81: qemu_mutex_lock(&v9fs_synth_mutex); ! 82: QLIST_FOREACH(tmp, &parent->child, sibling) { ! 83: if (!strcmp(tmp->name, name)) { ! 84: ret = EEXIST; ! 85: goto err_out; ! 86: } ! 87: } ! 88: /* Add the name */ ! 89: node = v9fs_add_dir_node(parent, mode, name, NULL, v9fs_synth_node_count++); ! 90: v9fs_add_dir_node(node, parent->attr->mode, "..", ! 91: parent->attr, parent->attr->inode); ! 92: v9fs_add_dir_node(node, node->attr->mode, ".", ! 93: node->attr, node->attr->inode); ! 94: *result = node; ! 95: ret = 0; ! 96: err_out: ! 97: qemu_mutex_unlock(&v9fs_synth_mutex); ! 98: return ret; ! 99: } ! 100: ! 101: int qemu_v9fs_synth_add_file(V9fsSynthNode *parent, int mode, ! 102: const char *name, v9fs_synth_read read, ! 103: v9fs_synth_write write, void *arg) ! 104: { ! 105: int ret; ! 106: V9fsSynthNode *node, *tmp; ! 107: ! 108: if (!v9fs_synth_fs) { ! 109: return EAGAIN; ! 110: } ! 111: if (!name || (strlen(name) >= NAME_MAX)) { ! 112: return EINVAL; ! 113: } ! 114: if (!parent) { ! 115: parent = &v9fs_synth_root; ! 116: } ! 117: ! 118: qemu_mutex_lock(&v9fs_synth_mutex); ! 119: QLIST_FOREACH(tmp, &parent->child, sibling) { ! 120: if (!strcmp(tmp->name, name)) { ! 121: ret = EEXIST; ! 122: goto err_out; ! 123: } ! 124: } ! 125: /* Add file type and remove write bits */ ! 126: mode = ((mode & 0777) | S_IFREG); ! 127: node = g_malloc0(sizeof(V9fsSynthNode)); ! 128: node->attr = &node->actual_attr; ! 129: node->attr->inode = v9fs_synth_node_count++; ! 130: node->attr->nlink = 1; ! 131: node->attr->read = read; ! 132: node->attr->write = write; ! 133: node->attr->mode = mode; ! 134: node->private = arg; ! 135: strncpy(node->name, name, sizeof(node->name)); ! 136: QLIST_INSERT_HEAD_RCU(&parent->child, node, sibling); ! 137: ret = 0; ! 138: err_out: ! 139: qemu_mutex_unlock(&v9fs_synth_mutex); ! 140: return ret; ! 141: } ! 142: ! 143: static void v9fs_synth_fill_statbuf(V9fsSynthNode *node, struct stat *stbuf) ! 144: { ! 145: stbuf->st_dev = 0; ! 146: stbuf->st_ino = node->attr->inode; ! 147: stbuf->st_mode = node->attr->mode; ! 148: stbuf->st_nlink = node->attr->nlink; ! 149: stbuf->st_uid = 0; ! 150: stbuf->st_gid = 0; ! 151: stbuf->st_rdev = 0; ! 152: stbuf->st_size = 0; ! 153: stbuf->st_blksize = 0; ! 154: stbuf->st_blocks = 0; ! 155: stbuf->st_atime = 0; ! 156: stbuf->st_mtime = 0; ! 157: stbuf->st_ctime = 0; ! 158: } ! 159: ! 160: static int v9fs_synth_lstat(FsContext *fs_ctx, ! 161: V9fsPath *fs_path, struct stat *stbuf) ! 162: { ! 163: V9fsSynthNode *node = *(V9fsSynthNode **)fs_path->data; ! 164: ! 165: v9fs_synth_fill_statbuf(node, stbuf); ! 166: return 0; ! 167: } ! 168: ! 169: static int v9fs_synth_fstat(FsContext *fs_ctx, int fid_type, ! 170: V9fsFidOpenState *fs, struct stat *stbuf) ! 171: { ! 172: V9fsSynthOpenState *synth_open = fs->private; ! 173: v9fs_synth_fill_statbuf(synth_open->node, stbuf); ! 174: return 0; ! 175: } ! 176: ! 177: static int v9fs_synth_opendir(FsContext *ctx, ! 178: V9fsPath *fs_path, V9fsFidOpenState *fs) ! 179: { ! 180: V9fsSynthOpenState *synth_open; ! 181: V9fsSynthNode *node = *(V9fsSynthNode **)fs_path->data; ! 182: ! 183: synth_open = g_malloc(sizeof(*synth_open)); ! 184: synth_open->node = node; ! 185: node->open_count++; ! 186: fs->private = synth_open; ! 187: return 0; ! 188: } ! 189: ! 190: static int v9fs_synth_closedir(FsContext *ctx, V9fsFidOpenState *fs) ! 191: { ! 192: V9fsSynthOpenState *synth_open = fs->private; ! 193: V9fsSynthNode *node = synth_open->node; ! 194: ! 195: node->open_count--; ! 196: g_free(synth_open); ! 197: fs->private = NULL; ! 198: return 0; ! 199: } ! 200: ! 201: static off_t v9fs_synth_telldir(FsContext *ctx, V9fsFidOpenState *fs) ! 202: { ! 203: V9fsSynthOpenState *synth_open = fs->private; ! 204: return synth_open->offset; ! 205: } ! 206: ! 207: static void v9fs_synth_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off) ! 208: { ! 209: V9fsSynthOpenState *synth_open = fs->private; ! 210: synth_open->offset = off; ! 211: } ! 212: ! 213: static void v9fs_synth_rewinddir(FsContext *ctx, V9fsFidOpenState *fs) ! 214: { ! 215: v9fs_synth_seekdir(ctx, fs, 0); ! 216: } ! 217: ! 218: static void v9fs_synth_direntry(V9fsSynthNode *node, ! 219: struct dirent *entry, off_t off) ! 220: { ! 221: strcpy(entry->d_name, node->name); ! 222: entry->d_ino = node->attr->inode; ! 223: entry->d_off = off + 1; ! 224: } ! 225: ! 226: static int v9fs_synth_get_dentry(V9fsSynthNode *dir, struct dirent *entry, ! 227: struct dirent **result, off_t off) ! 228: { ! 229: int i = 0; ! 230: V9fsSynthNode *node; ! 231: ! 232: rcu_read_lock(); ! 233: QLIST_FOREACH(node, &dir->child, sibling) { ! 234: /* This is the off child of the directory */ ! 235: if (i == off) { ! 236: break; ! 237: } ! 238: i++; ! 239: } ! 240: rcu_read_unlock(); ! 241: if (!node) { ! 242: /* end of directory */ ! 243: *result = NULL; ! 244: return 0; ! 245: } ! 246: v9fs_synth_direntry(node, entry, off); ! 247: *result = entry; ! 248: return 0; ! 249: } ! 250: ! 251: static int v9fs_synth_readdir_r(FsContext *ctx, V9fsFidOpenState *fs, ! 252: struct dirent *entry, struct dirent **result) ! 253: { ! 254: int ret; ! 255: V9fsSynthOpenState *synth_open = fs->private; ! 256: V9fsSynthNode *node = synth_open->node; ! 257: ret = v9fs_synth_get_dentry(node, entry, result, synth_open->offset); ! 258: if (!ret && *result != NULL) { ! 259: synth_open->offset++; ! 260: } ! 261: return ret; ! 262: } ! 263: ! 264: static int v9fs_synth_open(FsContext *ctx, V9fsPath *fs_path, ! 265: int flags, V9fsFidOpenState *fs) ! 266: { ! 267: V9fsSynthOpenState *synth_open; ! 268: V9fsSynthNode *node = *(V9fsSynthNode **)fs_path->data; ! 269: ! 270: synth_open = g_malloc(sizeof(*synth_open)); ! 271: synth_open->node = node; ! 272: node->open_count++; ! 273: fs->private = synth_open; ! 274: return 0; ! 275: } ! 276: ! 277: static int v9fs_synth_open2(FsContext *fs_ctx, V9fsPath *dir_path, ! 278: const char *name, int flags, ! 279: FsCred *credp, V9fsFidOpenState *fs) ! 280: { ! 281: errno = ENOSYS; ! 282: return -1; ! 283: } ! 284: ! 285: static int v9fs_synth_close(FsContext *ctx, V9fsFidOpenState *fs) ! 286: { ! 287: V9fsSynthOpenState *synth_open = fs->private; ! 288: V9fsSynthNode *node = synth_open->node; ! 289: ! 290: node->open_count--; ! 291: g_free(synth_open); ! 292: fs->private = NULL; ! 293: return 0; ! 294: } ! 295: ! 296: static ssize_t v9fs_synth_pwritev(FsContext *ctx, V9fsFidOpenState *fs, ! 297: const struct iovec *iov, ! 298: int iovcnt, off_t offset) ! 299: { ! 300: int i, count = 0, wcount; ! 301: V9fsSynthOpenState *synth_open = fs->private; ! 302: V9fsSynthNode *node = synth_open->node; ! 303: if (!node->attr->write) { ! 304: errno = EPERM; ! 305: return -1; ! 306: } ! 307: for (i = 0; i < iovcnt; i++) { ! 308: wcount = node->attr->write(iov[i].iov_base, iov[i].iov_len, ! 309: offset, node->private); ! 310: offset += wcount; ! 311: count += wcount; ! 312: /* If we wrote less than requested. we are done */ ! 313: if (wcount < iov[i].iov_len) { ! 314: break; ! 315: } ! 316: } ! 317: return count; ! 318: } ! 319: ! 320: static ssize_t v9fs_synth_preadv(FsContext *ctx, V9fsFidOpenState *fs, ! 321: const struct iovec *iov, ! 322: int iovcnt, off_t offset) ! 323: { ! 324: int i, count = 0, rcount; ! 325: V9fsSynthOpenState *synth_open = fs->private; ! 326: V9fsSynthNode *node = synth_open->node; ! 327: if (!node->attr->read) { ! 328: errno = EPERM; ! 329: return -1; ! 330: } ! 331: for (i = 0; i < iovcnt; i++) { ! 332: rcount = node->attr->read(iov[i].iov_base, iov[i].iov_len, ! 333: offset, node->private); ! 334: offset += rcount; ! 335: count += rcount; ! 336: /* If we read less than requested. we are done */ ! 337: if (rcount < iov[i].iov_len) { ! 338: break; ! 339: } ! 340: } ! 341: return count; ! 342: } ! 343: ! 344: static int v9fs_synth_truncate(FsContext *ctx, V9fsPath *path, off_t offset) ! 345: { ! 346: errno = ENOSYS; ! 347: return -1; ! 348: } ! 349: ! 350: static int v9fs_synth_chmod(FsContext *fs_ctx, V9fsPath *path, FsCred *credp) ! 351: { ! 352: errno = EPERM; ! 353: return -1; ! 354: } ! 355: ! 356: static int v9fs_synth_mknod(FsContext *fs_ctx, V9fsPath *path, ! 357: const char *buf, FsCred *credp) ! 358: { ! 359: errno = EPERM; ! 360: return -1; ! 361: } ! 362: ! 363: static int v9fs_synth_mkdir(FsContext *fs_ctx, V9fsPath *path, ! 364: const char *buf, FsCred *credp) ! 365: { ! 366: errno = EPERM; ! 367: return -1; ! 368: } ! 369: ! 370: static ssize_t v9fs_synth_readlink(FsContext *fs_ctx, V9fsPath *path, ! 371: char *buf, size_t bufsz) ! 372: { ! 373: errno = ENOSYS; ! 374: return -1; ! 375: } ! 376: ! 377: static int v9fs_synth_symlink(FsContext *fs_ctx, const char *oldpath, ! 378: V9fsPath *newpath, const char *buf, FsCred *credp) ! 379: { ! 380: errno = EPERM; ! 381: return -1; ! 382: } ! 383: ! 384: static int v9fs_synth_link(FsContext *fs_ctx, V9fsPath *oldpath, ! 385: V9fsPath *newpath, const char *buf) ! 386: { ! 387: errno = EPERM; ! 388: return -1; ! 389: } ! 390: ! 391: static int v9fs_synth_rename(FsContext *ctx, const char *oldpath, ! 392: const char *newpath) ! 393: { ! 394: errno = EPERM; ! 395: return -1; ! 396: } ! 397: ! 398: static int v9fs_synth_chown(FsContext *fs_ctx, V9fsPath *path, FsCred *credp) ! 399: { ! 400: errno = EPERM; ! 401: return -1; ! 402: } ! 403: ! 404: static int v9fs_synth_utimensat(FsContext *fs_ctx, V9fsPath *path, ! 405: const struct timespec *buf) ! 406: { ! 407: errno = EPERM; ! 408: return 0; ! 409: } ! 410: ! 411: static int v9fs_synth_remove(FsContext *ctx, const char *path) ! 412: { ! 413: errno = EPERM; ! 414: return -1; ! 415: } ! 416: ! 417: static int v9fs_synth_fsync(FsContext *ctx, int fid_type, ! 418: V9fsFidOpenState *fs, int datasync) ! 419: { ! 420: errno = ENOSYS; ! 421: return 0; ! 422: } ! 423: ! 424: static int v9fs_synth_statfs(FsContext *s, V9fsPath *fs_path, ! 425: struct statfs *stbuf) ! 426: { ! 427: stbuf->f_type = 0xABCD; ! 428: stbuf->f_bsize = 512; ! 429: stbuf->f_blocks = 0; ! 430: stbuf->f_files = v9fs_synth_node_count; ! 431: stbuf->f_namelen = NAME_MAX; ! 432: return 0; ! 433: } ! 434: ! 435: static ssize_t v9fs_synth_lgetxattr(FsContext *ctx, V9fsPath *path, ! 436: const char *name, void *value, size_t size) ! 437: { ! 438: errno = ENOTSUP; ! 439: return -1; ! 440: } ! 441: ! 442: static ssize_t v9fs_synth_llistxattr(FsContext *ctx, V9fsPath *path, ! 443: void *value, size_t size) ! 444: { ! 445: errno = ENOTSUP; ! 446: return -1; ! 447: } ! 448: ! 449: static int v9fs_synth_lsetxattr(FsContext *ctx, V9fsPath *path, ! 450: const char *name, void *value, ! 451: size_t size, int flags) ! 452: { ! 453: errno = ENOTSUP; ! 454: return -1; ! 455: } ! 456: ! 457: static int v9fs_synth_lremovexattr(FsContext *ctx, ! 458: V9fsPath *path, const char *name) ! 459: { ! 460: errno = ENOTSUP; ! 461: return -1; ! 462: } ! 463: ! 464: static int v9fs_synth_name_to_path(FsContext *ctx, V9fsPath *dir_path, ! 465: const char *name, V9fsPath *target) ! 466: { ! 467: V9fsSynthNode *node; ! 468: V9fsSynthNode *dir_node; ! 469: ! 470: /* "." and ".." are not allowed */ ! 471: if (!strcmp(name, ".") || !strcmp(name, "..")) { ! 472: errno = EINVAL; ! 473: return -1; ! 474: ! 475: } ! 476: if (!dir_path) { ! 477: dir_node = &v9fs_synth_root; ! 478: } else { ! 479: dir_node = *(V9fsSynthNode **)dir_path->data; ! 480: } ! 481: if (!strcmp(name, "/")) { ! 482: node = dir_node; ! 483: goto out; ! 484: } ! 485: /* search for the name in the childern */ ! 486: rcu_read_lock(); ! 487: QLIST_FOREACH(node, &dir_node->child, sibling) { ! 488: if (!strcmp(node->name, name)) { ! 489: break; ! 490: } ! 491: } ! 492: rcu_read_unlock(); ! 493: ! 494: if (!node) { ! 495: errno = ENOENT; ! 496: return -1; ! 497: } ! 498: out: ! 499: /* Copy the node pointer to fid */ ! 500: target->data = g_malloc(sizeof(void *)); ! 501: memcpy(target->data, &node, sizeof(void *)); ! 502: target->size = sizeof(void *); ! 503: return 0; ! 504: } ! 505: ! 506: static int v9fs_synth_renameat(FsContext *ctx, V9fsPath *olddir, ! 507: const char *old_name, V9fsPath *newdir, ! 508: const char *new_name) ! 509: { ! 510: errno = EPERM; ! 511: return -1; ! 512: } ! 513: ! 514: static int v9fs_synth_unlinkat(FsContext *ctx, V9fsPath *dir, ! 515: const char *name, int flags) ! 516: { ! 517: errno = EPERM; ! 518: return -1; ! 519: } ! 520: ! 521: static int v9fs_synth_init(FsContext *ctx) ! 522: { ! 523: QLIST_INIT(&v9fs_synth_root.child); ! 524: qemu_mutex_init(&v9fs_synth_mutex); ! 525: ! 526: /* Add "." and ".." entries for root */ ! 527: v9fs_add_dir_node(&v9fs_synth_root, v9fs_synth_root.attr->mode, ! 528: "..", v9fs_synth_root.attr, v9fs_synth_root.attr->inode); ! 529: v9fs_add_dir_node(&v9fs_synth_root, v9fs_synth_root.attr->mode, ! 530: ".", v9fs_synth_root.attr, v9fs_synth_root.attr->inode); ! 531: ! 532: /* Mark the subsystem is ready for use */ ! 533: v9fs_synth_fs = 1; ! 534: return 0; ! 535: } ! 536: ! 537: FileOperations synth_ops = { ! 538: .init = v9fs_synth_init, ! 539: .lstat = v9fs_synth_lstat, ! 540: .readlink = v9fs_synth_readlink, ! 541: .close = v9fs_synth_close, ! 542: .closedir = v9fs_synth_closedir, ! 543: .open = v9fs_synth_open, ! 544: .opendir = v9fs_synth_opendir, ! 545: .rewinddir = v9fs_synth_rewinddir, ! 546: .telldir = v9fs_synth_telldir, ! 547: .readdir_r = v9fs_synth_readdir_r, ! 548: .seekdir = v9fs_synth_seekdir, ! 549: .preadv = v9fs_synth_preadv, ! 550: .pwritev = v9fs_synth_pwritev, ! 551: .chmod = v9fs_synth_chmod, ! 552: .mknod = v9fs_synth_mknod, ! 553: .mkdir = v9fs_synth_mkdir, ! 554: .fstat = v9fs_synth_fstat, ! 555: .open2 = v9fs_synth_open2, ! 556: .symlink = v9fs_synth_symlink, ! 557: .link = v9fs_synth_link, ! 558: .truncate = v9fs_synth_truncate, ! 559: .rename = v9fs_synth_rename, ! 560: .chown = v9fs_synth_chown, ! 561: .utimensat = v9fs_synth_utimensat, ! 562: .remove = v9fs_synth_remove, ! 563: .fsync = v9fs_synth_fsync, ! 564: .statfs = v9fs_synth_statfs, ! 565: .lgetxattr = v9fs_synth_lgetxattr, ! 566: .llistxattr = v9fs_synth_llistxattr, ! 567: .lsetxattr = v9fs_synth_lsetxattr, ! 568: .lremovexattr = v9fs_synth_lremovexattr, ! 569: .name_to_path = v9fs_synth_name_to_path, ! 570: .renameat = v9fs_synth_renameat, ! 571: .unlinkat = v9fs_synth_unlinkat, ! 572: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.