📄 fs_incore.c
字号:
/* * This Cplant(TM) source code is the property of Sandia National * Laboratories. * * This Cplant(TM) source code is copyrighted by Sandia National * Laboratories. * * The redistribution of this Cplant(TM) source code is subject to the * terms of the GNU Lesser General Public License * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) * * Cplant(TM) Copyright 1998-2003 Sandia Corporation. * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive * license for use of this work by or on behalf of the US Government. * Export of this program may require a license from the United States * Government. *//* * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Questions or comments about this library should be sent to: * * Lee Ward * Sandia National Laboratories, New Mexico * P.O. Box 5800 * Albuquerque, NM 87185-1110 * * lee@sandia.gov */#ifdef __linux__#define _BSD_SOURCE#endif#include <stdlib.h>#include <string.h>#include <unistd.h>#include <time.h>#include <limits.h>#include <errno.h>#include <assert.h>#include <sys/uio.h>#include <sys/types.h>#include <dirent.h>#include <sys/stat.h>#ifdef _HAVE_STATVFS#include <sys/statvfs.h>#endif#include <sys/queue.h>#include "sysio.h"#include "xtio.h"#include "fs.h"#include "mount.h"#include "inode.h"#include "dev.h"#include "fs_incore.h"/* * In-core file system pseudo-driver. *//* * Pseudo-blocksize. */#define INCORE_BLKSIZE (8192)/* * Format of an incore inode. */struct incore_inode { LIST_ENTRY(incore_inode) ici_link; /* i-nodes list link */ struct intnl_stat ici_st; /* attrs */ struct file_identifier ici_fileid; /* file ID */ void *ici_data; /* file data */};/* * Given pointer to inode, return pointer to incore-inode. */#define I2IC(ino) ((struct incore_inode *)(ino)->i_private)struct incore_filesys { LIST_HEAD(, incore_inode) icfs_icinodes; /* all i-nodes list */};/* * Given pointer to filesys, return pointer to incore-filesys. */#define FS2ICFS(fs) ((struct incore_filesys *)(fs)->fs_private)static int _sysio_incore_fsswop_mount(const char *source, unsigned flags, const void *data, struct pnode *tocover, struct mount **mntp);static struct fssw_ops incore_fssw_ops = { _sysio_incore_fsswop_mount};static void _sysio_incore_fsop_gone(struct filesys *fs);static struct filesys_ops incore_fs_ops = { _sysio_incore_fsop_gone,};static int _sysio_incore_dirop_lookup(struct pnode *pno, struct inode **inop, struct intent *intnt, const char *path);static int _sysio_incore_inop_getattr(struct pnode *pno, struct inode *ino, struct intnl_stat *stbuf);static int _sysio_incore_inop_setattr(struct pnode *pno, struct inode *ino, unsigned mask, struct intnl_stat *stbuf);static ssize_t _sysio_incore_dirop_filldirentries(struct inode *ino, _SYSIO_OFF_T *posp, char *buf, size_t nbytes);static int _sysio_incore_dirop_mkdir(struct pnode *pno, mode_t mode);static int _sysio_incore_dirop_rmdir(struct pnode *pno);static int _sysio_incore_inop_open(struct pnode *pno, int flags, mode_t mode);static int _sysio_incore_inop_close(struct inode *ino);static int _sysio_incore_dirop_link(struct pnode *old, struct pnode *new);static int _sysio_incore_dirop_unlink(struct pnode *pno);static int _sysio_incore_dirop_rename(struct pnode *old, struct pnode *new);static int _sysio_incore_filop_read(struct inode *ino, struct ioctx *ioctx);static int _sysio_incore_filop_write(struct inode *ino, struct ioctx *ioctx);static _SYSIO_OFF_T _sysio_incore_filop_pos(struct inode *ino, _SYSIO_OFF_T off);static int _sysio_incore_filop_iodone(struct ioctx *ioctx);static int _sysio_incore_filop_fcntl(struct inode *ino, int cmd, va_list ap, int *rtn);static int _sysio_incore_inop_sync(struct inode *ino);static int _sysio_incore_filop_ioctl(struct inode *ino, unsigned long int request, va_list ap);static int _sysio_incore_dirop_mknod(struct pnode *pno, mode_t mode, dev_t dev);#ifdef _HAVE_STATVFSstatic int _sysio_incore_inop_statvfs(struct pnode *pno, struct inode *ino, struct intnl_statvfs *buf);#endifstatic void _sysio_incore_inop_gone(struct inode *ino);#define _sysio_incore_dirop_symlink \ (int (*)(struct pnode *, const char *))_sysio_do_enosys#define _sysio_incore_dirop_readlink \ (int (*)(struct pnode *, char *, size_t))_sysio_do_enosys#define _sysio_incore_dirop_read \ (int (*)(struct inode *, \ struct ioctx *))_sysio_do_eisdir#define _sysio_incore_dirop_write \ (int (*)(struct inode *, \ struct ioctx *))_sysio_do_eisdir#define _sysio_incore_dirop_pos \ (_SYSIO_OFF_T (*)(struct inode *, \ _SYSIO_OFF_T))_sysio_do_eisdir#define _sysio_incore_dirop_iodone \ (int (*)(struct ioctx *))_sysio_do_illop#define _sysio_incore_dirop_fcntl \ (int (*)(struct inode *, int, va_list, int *))_sysio_do_eisdir#define _sysio_incore_dirop_ioctl \ (int (*)(struct inode *, \ unsigned long int, \ va_list))_sysio_do_eisdirstatic struct inode_ops _sysio_incore_dir_ops = { _sysio_incore_dirop_lookup, _sysio_incore_inop_getattr, _sysio_incore_inop_setattr, _sysio_incore_dirop_filldirentries, _sysio_incore_dirop_mkdir, _sysio_incore_dirop_rmdir, _sysio_incore_dirop_symlink, _sysio_incore_dirop_readlink, _sysio_incore_inop_open, _sysio_incore_inop_close, _sysio_incore_dirop_link, _sysio_incore_dirop_unlink, _sysio_incore_dirop_rename, _sysio_incore_dirop_read, _sysio_incore_dirop_write, _sysio_incore_dirop_pos, _sysio_incore_dirop_iodone, _sysio_incore_dirop_fcntl, _sysio_incore_inop_sync, _sysio_incore_inop_sync, _sysio_incore_dirop_ioctl, _sysio_incore_dirop_mknod,#ifdef _HAVE_STATVFS _sysio_incore_inop_statvfs,#endif _sysio_incore_inop_gone};#define _sysio_incore_filop_lookup \ (int (*)(struct pnode *, \ struct inode **, \ struct intent *, \ const char *))_sysio_do_illop#define _sysio_incore_filop_filldirentries \ (ssize_t (*)(struct inode *, \ _SYSIO_OFF_T *, \ char *, \ size_t))_sysio_do_illop#define _sysio_incore_filop_mkdir \ (int (*)(struct pnode *, mode_t))_sysio_do_illop#define _sysio_incore_filop_rmdir \ (int (*)(struct pnode *))_sysio_do_illop#define _sysio_incore_filop_symlink \ (int (*)(struct pnode *, const char *))_sysio_do_illop#define _sysio_incore_symlinkop_readlink \ (int (*)(struct pnode *, char *, size_t))_sysio_do_illop#define _sysio_incore_filop_link \ (int (*)(struct pnode *old, struct pnode *new))_sysio_do_illop#define _sysio_incore_filop_unlink \ (int (*)(struct pnode *pno))_sysio_do_illop#define _sysio_incore_filop_rename \ (int (*)(struct pnode *old, struct pnode *new))_sysio_do_illop#define _sysio_incore_filop_mknod \ (int (*)(struct pnode *pno, mode_t, dev_t))_sysio_do_illopstatic struct inode_ops _sysio_incore_file_ops = { _sysio_incore_filop_lookup, _sysio_incore_inop_getattr, _sysio_incore_inop_setattr, _sysio_incore_filop_filldirentries, _sysio_incore_filop_mkdir, _sysio_incore_filop_rmdir, _sysio_incore_filop_symlink, _sysio_incore_symlinkop_readlink, _sysio_incore_inop_open, _sysio_incore_inop_close, _sysio_incore_filop_link, _sysio_incore_filop_unlink, _sysio_incore_filop_rename, _sysio_incore_filop_read, _sysio_incore_filop_write, _sysio_incore_filop_pos, _sysio_incore_filop_iodone, _sysio_incore_filop_fcntl, _sysio_incore_inop_sync, _sysio_incore_inop_sync, _sysio_incore_filop_ioctl, _sysio_incore_filop_mknod,#ifdef _HAVE_STATVFS _sysio_incore_inop_statvfs,#endif _sysio_incore_inop_gone};static struct inode_ops _sysio_incore_dev_ops = { _sysio_incore_filop_lookup, _sysio_incore_inop_getattr, _sysio_incore_inop_setattr, _sysio_incore_filop_filldirentries, _sysio_incore_filop_mkdir, _sysio_incore_filop_rmdir, _sysio_incore_filop_symlink, _sysio_incore_symlinkop_readlink, _sysio_nodev_inop_open, _sysio_nodev_inop_close, _sysio_incore_filop_link, _sysio_incore_filop_unlink, _sysio_incore_filop_rename, _sysio_nodev_inop_read, _sysio_nodev_inop_write, _sysio_nodev_inop_pos, _sysio_nodev_inop_iodone, _sysio_incore_filop_fcntl, _sysio_incore_inop_sync, _sysio_nodev_inop_sync, _sysio_nodev_inop_ioctl, _sysio_incore_filop_mknod,#ifdef _HAVE_STATVFS _sysio_incore_inop_statvfs,#endif _sysio_incore_inop_gone};typedef void *(*probe_ty)(void *data, size_t len, void *arg);/* * Lookup data argument bundle record. */struct lookup_data { struct qstr *name; /* desired entry name */ struct intnl_dirent *de; /* last dirent */ size_t minsiz; /* min hole needed */ struct { void *p; /* best hole */ size_t len; /* best hole len */ } hole;};/* * Initialize lookup data argument bundle. */#define INCORE_LD_INIT(ld, minsz, qs) \ do { \ (ld)->name = (qs); \ (ld)->de = NULL; \ (ld)->minsiz = (minsz); \ (ld)->hole.p = NULL; \ (ld)->hole.len = 0; \ } while (0)/* * Calculate size of a directory entry given length of the entry name. */#define INCORE_D_RECLEN(namlen) \ (((size_t )&((struct intnl_dirent *)0)->d_name + \ (namlen) + 1 + sizeof(void *)) & \ ~(sizeof(void *) - 1))/* * Given mode bits, return directory entry type code. */#define INCORE_D_TYPEOF(m) (((m) & S_IFMT) >> 12)static char incore_dir_template[INCORE_D_RECLEN(1) + INCORE_D_RECLEN(2)];#if 0static struct intnl_dirent incore_dir_template[] = { { 0, INCORE_D_RECLEN(1), INCORE_D_RECLEN(1), INCORE_D_TYPEOF(S_IFDIR), { '.', '\0' } }, { 0, INCORE_D_RECLEN(1) + INCORE_D_RECLEN(2), INCORE_D_RECLEN(2), INCORE_D_TYPEOF(S_IFDIR), { '.', '.', '\0' } }};#endif/* * Initialize this driver. */int_sysio_incore_init(){ struct intnl_dirent *de; off_t off; /* * Fill in the directory template. */ de = (struct intnl_dirent *)incore_dir_template;#ifdef _DIRENT_HAVE_D_OFF de->d_off =#endif off = de->d_reclen = INCORE_D_RECLEN(1); de->d_type = INCORE_D_TYPEOF(S_IFDIR); de->d_name[0] = '.';#ifdef _DIRENT_HAVE_D_NAMLEN de->d_namlen = 1;#endif /* * Move to entry for `..' */ de = (struct intnl_dirent *)((char *)de + off); de->d_reclen = INCORE_D_RECLEN(2);#ifdef _DIRENT_HAVE_D_NAMLEN de->d_namlen = 2;#endif#ifdef _DIRENT_HAVE_D_OFF de->d_off =#endif off += de->d_reclen; de->d_type = INCORE_D_TYPEOF(S_IFDIR); de->d_name[0] = de->d_name[1] = '.'; de->d_name[2] = ' '; return _sysio_fssw_register("incore", &incore_fssw_ops);}static ino_tincore_inum_alloc(){ static ino_t nxtnum = 1; assert(nxtnum); return nxtnum++;}static struct incore_inode *incore_i_alloc(struct incore_filesys *icfs, struct intnl_stat *st){ struct incore_inode *icino; assert(st->st_ino); assert(!st->st_size); icino = malloc(sizeof(struct incore_inode)); if (!icino) return NULL; icino->ici_st = *st; icino->ici_fileid.fid_data = &icino->ici_st.st_ino; icino->ici_fileid.fid_len = sizeof(icino->ici_st.st_ino); icino->ici_data = NULL; LIST_INSERT_HEAD(&icfs->icfs_icinodes, icino, ici_link); return icino;}static intincore_trunc(struct incore_inode *icino, _SYSIO_OFF_T size, int clear){ _SYSIO_OFF_T n; void *p; if (size < 0) return -EINVAL; n = size; if (!size) { if (icino->ici_data) { free(icino->ici_data); icino->ici_data = NULL; } n = 0; goto out; } p = realloc(icino->ici_data, (size_t )n); if (!p) return -ENOSPC; icino->ici_data = p; if (clear && n > icino->ici_st.st_size) (void )memset((char *)icino->ici_data + icino->ici_st.st_size, 0, (size_t )(n - icino->ici_st.st_size));out: icino->ici_st.st_size = n; icino->ici_st.st_blocks = (n + icino->ici_st.st_blksize - 1) / icino->ici_st.st_blksize; icino->ici_st.st_mtime = time(NULL); return 0;}static voidincore_i_destroy(struct incore_inode *icino){ LIST_REMOVE(icino, ici_link); (void )incore_trunc(icino, 0, 0); free(icino);}static struct incore_inode *incore_directory_new(struct incore_filesys *icfs, struct incore_inode *parent, struct intnl_stat *st){ struct incore_inode *icino; int err; struct intnl_dirent *de; icino = incore_i_alloc(icfs, st); if (!icino) return NULL; if (!parent) parent = icino; /* root */ /* * Allocate and init directory data. */ err = incore_trunc(icino, sizeof(incore_dir_template), 1); if (err) { incore_i_destroy(icino); return NULL; } (void )memcpy(icino->ici_data, &incore_dir_template, sizeof(incore_dir_template)); de = icino->ici_data; de->d_ino = st->st_ino; de = (struct intnl_dirent *)((char *)de +#ifdef _DIRENT_HAVE_D_OFF de->d_off#else de->d_reclen#endif ); de->d_ino = parent->ici_st.st_ino; /* * Set creation time to modify time set by truncate. */ st->st_ctime = st->st_mtime; return icino;}static int_sysio_incore_fsswop_mount(const char *source, unsigned flags, const void *data __IS_UNUSED, struct pnode *tocover, struct mount **mntp){ char *cp; unsigned long ul; long l; mode_t mode; uid_t uid; gid_t gid; int err; dev_t dev; struct intnl_stat stat; struct incore_filesys *icfs; ino_t inum; struct incore_inode *icino; struct filesys *fs; struct inode *rooti; struct pnode_base *rootpb; struct mount *mnt; static struct qstr noname = { NULL, 0, 0 }; /* * Source is a specification for the root attributes of this * new file system in the format: * * <permissions>[+<owner>][-<group>] */ ul = strtoul(source, &cp, 0); mode = (mode_t )ul & 07777; uid = getuid(); /* default */ gid = getgid(); /* default */ if (*cp != '\0') { /* * Get user and/or group. */ if (*cp != '+' || (ul == ULONG_MAX && errno == ERANGE) || (unsigned long)mode != ul || mode > 07777) return -EINVAL; source = cp; l = strtol(source, &cp, 0); uid = (uid_t )l; if (((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE) || (long )uid != l) return -EINVAL; if (*cp != '+') return -EINVAL; source = cp; l = strtol(source, &cp, 0); gid = (gid_t )l;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -