struct fs_ctl* lu_fsctl_create(struct list_head *conf){ struct fs_ctl *ctl; const char *fs_name, *user_name; TRACE("creating fs_ctl"); if(!(ctl = (struct fs_ctl*)malloc(sizeof(struct fs_ctl)))) return NULL; memset(ctl, 0, sizeof(struct fs_ctl)); ctl->cache = lu_cache_create(conf); ctl->cfg = conf; if(!(fs_name = lu_opt_getchar(conf, "MOUNT", "fs"))){ ERROR("you need to specify a file system!"); free(ctl); return NULL; } if(!(ctl->fs_ops = get_filesystem(ctl, (char*)fs_name))){ ERROR("unsupported file system: %s", fs_name); free(ctl); return NULL; } if((user_name = lu_opt_getchar(conf, "MOUNT", "username"))) strcpy(ctl->cred.user, user_name); return ctl; }
/** * alloc_fs_context - Create a filesystem context. * @fs_type: The filesystem type. * @reference: The dentry from which this one derives (or NULL) * @sb_flags: Filesystem/superblock flags (SB_*) * @sb_flags_mask: Applicable members of @sb_flags * @purpose: The purpose that this configuration shall be used for. * * Open a filesystem and create a mount context. The mount context is * initialised with the supplied flags and, if a submount/automount from * another superblock (referred to by @reference) is supplied, may have * parameters such as namespaces copied across from that superblock. */ static struct fs_context *alloc_fs_context(struct file_system_type *fs_type, struct dentry *reference, unsigned int sb_flags, unsigned int sb_flags_mask, enum fs_context_purpose purpose) { int (*init_fs_context)(struct fs_context *); struct fs_context *fc; int ret = -ENOMEM; fc = kzalloc(sizeof(struct fs_context), GFP_KERNEL); if (!fc) return ERR_PTR(-ENOMEM); fc->purpose = purpose; fc->sb_flags = sb_flags; fc->sb_flags_mask = sb_flags_mask; fc->fs_type = get_filesystem(fs_type); fc->cred = get_current_cred(); fc->net_ns = get_net(current->nsproxy->net_ns); mutex_init(&fc->uapi_mutex); switch (purpose) { case FS_CONTEXT_FOR_MOUNT: fc->user_ns = get_user_ns(fc->cred->user_ns); break; case FS_CONTEXT_FOR_SUBMOUNT: fc->user_ns = get_user_ns(reference->d_sb->s_user_ns); break; case FS_CONTEXT_FOR_RECONFIGURE: /* We don't pin any namespaces as the superblock's * subscriptions cannot be changed at this point. */ atomic_inc(&reference->d_sb->s_active); fc->root = dget(reference); break; } /* TODO: Make all filesystems support this unconditionally */ init_fs_context = fc->fs_type->init_fs_context; if (!init_fs_context) init_fs_context = legacy_init_fs_context; ret = init_fs_context(fc); if (ret < 0) goto err_fc; fc->need_free = true; return fc; err_fc: put_fs_context(fc); return ERR_PTR(ret); }
nfsstat3 get_fattr(nfs_fh3 object, fattr3 *result) { nfsstat3 status = NFS3_OK; uint64_t identifier = 0; int error = 0; const char *path = NULL; const kfsfilesystem_t *filesystem = get_filesystem(object, &path, &identifier); if (filesystem) { dlog("\t%s (path, getattr)", path); kfsstat_t sbuf = {}; if (filesystem->stat(path, &sbuf, &error, filesystem->context)) { *result = (fattr3){}; if (0) {} else if (sbuf.type == KFS_REG) { result->type = NF3REG; } else if (sbuf.type == KFS_DIR) { result->type = NF3DIR; } else if (sbuf.type == KFS_BLK) { result->type = NF3BLK; } else if (sbuf.type == KFS_CHR) { result->type = NF3CHR; } else if (sbuf.type == KFS_LNK) { result->type = NF3LNK; } else if (sbuf.type == KFS_SOCK) { result->type = NF3SOCK; } else if (sbuf.type == KFS_FIFO) { result->type = NF3FIFO; } if (sbuf.mode & KFS_IRUSR) { result->mode |= NFS_IRUSR; } if (sbuf.mode & KFS_IWUSR) { result->mode |= NFS_IWUSR; } if (sbuf.mode & KFS_IXUSR) { result->mode |= NFS_IXUSR; } if (sbuf.mode & KFS_IRGRP) { result->mode |= NFS_IRGRP; } if (sbuf.mode & KFS_IWGRP) { result->mode |= NFS_IWGRP; } if (sbuf.mode & KFS_IXGRP) { result->mode |= NFS_IXGRP; } if (sbuf.mode & KFS_IROTH) { result->mode |= NFS_IROTH; } if (sbuf.mode & KFS_IWOTH) { result->mode |= NFS_IWOTH; } if (sbuf.mode & KFS_IXOTH) { result->mode |= NFS_IXOTH; } result->nlink = 1; result->uid = getuid(); result->gid = getgid(); result->size = sbuf.size; result->used = sbuf.used; result->rdev = (specdata3){ 0, 0 }; result->fsid = 0; result->fileid = kfs_fileid(identifier, path); result->atime = (nfstime3){ sbuf.atime.sec, sbuf.atime.nsec }; result->mtime = (nfstime3){ sbuf.mtime.sec, sbuf.mtime.nsec }; result->ctime = (nfstime3){ sbuf.ctime.sec, sbuf.ctime.nsec }; } else { // stat failed status = convert_status(error, NFS3ERR_NOENT); } } else { // no filesystem status = NFS3ERR_BADHANDLE; } return status; }
nfsstat3 set_fattr(nfs_fh3 object, const sattr3 *attrs) { nfsstat3 status = NFS3_OK; int error = 0; const char *path = NULL; const kfsfilesystem_t *filesystem = get_filesystem(object, &path, NULL); if (filesystem) { dlog("\t%s (path, setattr)", path); // check for resize if (status == NFS3_OK && attrs->size.set_it) { if (!filesystem->truncate(path, attrs->size.set_size3_u.size, &error, filesystem->context)) { status = convert_status(error, NFS3ERR_NOENT); // truncate failed } } // check for mode change if (status == NFS3_OK && attrs->mode.set_it) { kfsmode_t mode = 0; if (attrs->mode.set_mode3_u.mode & NFS_IRUSR) { mode |= KFS_IRUSR; } if (attrs->mode.set_mode3_u.mode & NFS_IWUSR) { mode |= KFS_IWUSR; } if (attrs->mode.set_mode3_u.mode & NFS_IXUSR) { mode |= KFS_IXUSR; } if (attrs->mode.set_mode3_u.mode & NFS_IRGRP) { mode |= KFS_IRGRP; } if (attrs->mode.set_mode3_u.mode & NFS_IWGRP) { mode |= KFS_IWGRP; } if (attrs->mode.set_mode3_u.mode & NFS_IXGRP) { mode |= KFS_IXGRP; } if (attrs->mode.set_mode3_u.mode & NFS_IROTH) { mode |= KFS_IROTH; } if (attrs->mode.set_mode3_u.mode & NFS_IWOTH) { mode |= KFS_IWOTH; } if (attrs->mode.set_mode3_u.mode & NFS_IXOTH) { mode |= KFS_IXOTH; } if (!filesystem->chmod(path, mode, &error, filesystem->context)) { status = convert_status(error, NFS3ERR_NOENT); // chmod failed } } // set times if (status == NFS3_OK && (attrs->atime.set_it || attrs->mtime.set_it)) { kfstime_t *atime = attrs->atime.set_it ? &(kfstime_t){ .sec = attrs->atime.set_atime_u.atime.seconds, .nsec = attrs->atime.set_atime_u.atime.nseconds } : NULL; kfstime_t *mtime = attrs->mtime.set_it ? &(kfstime_t){ .sec = attrs->mtime.set_mtime_u.mtime.seconds, .nsec = attrs->mtime.set_mtime_u.mtime.nseconds } : NULL;
/** * vfs_dup_fc_config: Duplicate a filesystem context. * @src_fc: The context to copy. */ struct fs_context *vfs_dup_fs_context(struct fs_context *src_fc) { struct fs_context *fc; int ret; if (!src_fc->ops->dup) return ERR_PTR(-EOPNOTSUPP); fc = kmemdup(src_fc, sizeof(struct fs_context), GFP_KERNEL); if (!fc) return ERR_PTR(-ENOMEM); mutex_init(&fc->uapi_mutex); fc->fs_private = NULL; fc->s_fs_info = NULL; fc->source = NULL; fc->security = NULL; get_filesystem(fc->fs_type); get_net(fc->net_ns); get_user_ns(fc->user_ns); get_cred(fc->cred); if (fc->log) refcount_inc(&fc->log->usage); /* Can't call put until we've called ->dup */ ret = fc->ops->dup(fc, src_fc); if (ret < 0) goto err_fc; ret = security_fs_context_dup(fc, src_fc); if (ret < 0) goto err_fc; return fc; err_fc: put_fs_context(fc); return ERR_PTR(ret); }