This is file_ops.c in view mode; [Download] [Up]
/* * Name: file_ops.c * Description: Functions that can be called from the NFS interface. * Author: Christian Starkjohann <cs@hal.kph.tuwien.ac.at> * Date: 1996-11-14 * Copyright: GNU-GPL * Tabsize: 4 */ #include <linux/autoconf.h> #include <linux/fs.h> #include <linux/affs_fs.h> #include <linux/ext2_fs.h> #include <linux/ext_fs.h> #include <linux/hpfs_fs.h> #include <linux/iso_fs.h> #include <linux/minix_fs.h> #include <linux/msdos_fs.h> #include <linux/ncp_fs.h> #include <linux/nfs_fs.h> #include <linux/proc_fs.h> #include <linux/smb_fs.h> #include <linux/sysv_fs.h> #include <linux/ufs_fs.h> #include <linux/umsdos_fs.h> #include <linux/xia_fs.h> #include "my_defines.h" #define DPRINTF(arg) if(debug_mode & DEBUG_FOPS) dprintf arg extern void init_ntfs_fs(void); #define MY_DEVICE 256 #define TRANSFER_BUFFER_SIZE 50000 /* ------------------------------------------------------------------------- */ extern void bzero(void *block, int size); extern void *malloc(int size); extern int my_blocksize; /* ------------------------------------------------------------------------- */ struct super_block my_superblock; static struct file_system_type *fs_types = NULL; /* ------------------------------------------------------------------------- */ int register_filesystem(struct file_system_type *fstype) { DPRINTF(("registering filesystem %s\n", fstype->name)); fstype->next = fs_types; fs_types = fstype; return 0; } /* ------------------------------------------------------------------------- */ static void my_sync_super(void) { struct super_block *s = &my_superblock; if(s->s_dirt && s->s_op->write_super != NULL){ s->s_op->write_super(s); s->s_dirt = 0; } } /* ------------------------------------------------------------------------- */ void my_sync(void) { my_sync_super(); my_sync_inodes(); my_sync_blocks(); } /* ------------------------------------------------------------------------- */ static int is_valid_fs(struct file_system_type *fs) { struct super_block s; bzero(&s, sizeof(s)); s.s_dev = MY_DEVICE; s.s_flags = MS_RDONLY; return fs->read_super(&s, "", 0) != 0; } /* ------------------------------------------------------------------------- */ char *valid_filesystems(void) { struct file_system_type *fs; static char fslist[1024]; /* don't like static limits.... */ fslist[0] = 0; for(fs=fs_types;fs!=NULL;fs=fs->next){ if(is_valid_fs(fs)){ if(fslist[0] != 0) strcat(fslist, " "); strcat(fslist, fs->name); } } return fslist; } /* ------------------------------------------------------------------------- */ static int do_my_mount(struct file_system_type *fs, int flags, void *data, int *root_i) { struct super_block *s = &my_superblock; DPRINTF(("do_my_mount(fs=%s, flags=0x%x)\n", fs->name, flags)); s->s_dev = MY_DEVICE; s->s_flags = flags; if (!fs->read_super(s, data, 0)){ return -1; } s->s_dev = MY_DEVICE; s->s_covered = s->s_mounted; /* used for error output! should be NULL */ s->s_type = fs; *root_i = s->s_mounted->i_ino; if(s->s_op->write_super != NULL){ s->s_op->write_super(s); s->s_dirt = 0; } my_sync(); return 0; } /* ------------------------------------------------------------------------- */ int my_mount(char *fsname, int options, void *data, int *root_inode) { struct file_system_type *fs; bzero(&my_superblock, sizeof(my_superblock)); for(fs=fs_types;fs!=NULL;fs=fs->next){ if(strcmp(fsname, fs->name) == 0){ break; } } if(fs != NULL){ return do_my_mount(fs, options & MNT_RONLY ? MS_RDONLY : 0, data, root_inode); }else{ printk("filesystem ->%s<- not found\n", fsname); return -1; } } /* ------------------------------------------------------------------------- */ int my_unmount(void) { struct super_block *sb = &my_superblock; DPRINTF(("my_unmount()\n")); iput(sb->s_mounted); /* free mounted inode */ my_sync(); if(sb->s_op && sb->s_op->put_super) sb->s_op->put_super(sb); my_sync_inodes(); my_sync_blocks(); return 0; } /* ------------------------------------------------------------------------- */ static int check_access(struct inode *inode, int mode) { int i, igid = inode->i_gid, iuid = inode->i_uid; if(nfs_uid == 0){ /* root may do everything */ return 1; } if(id_is_fixed(IDBUF_USR)) iuid = fixed_id(IDBUF_USR); if(id_is_fixed(IDBUF_GRP)) igid = fixed_id(IDBUF_GRP); if(nfs_uid == iuid){ /* you may always access your own files */ return 1; } if(iuid == nfs_uid){ return (inode->i_mode & (mode << 6)) != 0; } for(i=0;i<nfs_gidslen;i++){ if(igid == nfs_gids[i]){ return (inode->i_mode & (mode << 3)) != 0; } } return (inode->i_mode & mode) != 0; } /* ------------------------------------------------------------------------- */ #define CHECK_WRITE(inode, iputs) \ if(!check_access(inode, 2)){ \ error = -MY_NFSERR_ACCES; \ DPRINTF(("write access for %ld denied\n", inode->i_ino)); \ iputs; \ goto do_return; \ } #define CHECK_READ(inode, iputs) \ if(!check_access(inode, 4)){ \ error = -MY_NFSERR_ACCES; \ DPRINTF(("read access for %ld denied\n", inode->i_ino)); \ iputs; \ goto do_return; \ } #define CHECK_EXEC(inode, iputs) \ if(!check_access(inode, 1)){ \ error = -MY_NFSERR_ACCES; \ DPRINTF(("search access for %ld denied\n", inode->i_ino)); \ iputs; \ goto do_return; \ } #define CHECK_ATTR(inode, iputs) \ { int iuid = inode->i_uid; \ if(id_is_fixed(IDBUF_USR)) \ iuid = fixed_id(IDBUF_USR); \ if(nfs_uid != 0 && iuid != nfs_uid){ \ error = -MY_NFSERR_ACCES; \ DPRINTF(("chmod access for %ld denied\n", inode->i_ino)); \ iputs; \ goto do_return; \ } \ } /* ------------------------------------------------------------------------- */ static void set_attr(struct inode *inode, my_attr_t *attr) { int i; if(attr->mode != -1 && inode->i_mode != attr->mode){ inode->i_mode = (inode->i_mode & ~07777) | (attr->mode & 07777); inode->i_dirt = 1; } if(nfs_uid == 0 && attr->uid != -1 && inode->i_uid != attr->uid){ inode->i_uid = attr->uid; inode->i_dirt = 1; } if(attr->gid != -1 && inode->i_gid != attr->gid){ for(i=0;i<nfs_gidslen;i++){ if(nfs_gids[i] == attr->gid){ inode->i_gid = attr->gid; inode->i_dirt = 1; break; } } } if(attr->mtime != -1 && inode->i_mtime != attr->mtime){ inode->i_mtime = attr->mtime; inode->i_dirt = 1; } } /* ------------------------------------------------------------------------- */ static void get_attr(struct inode *inode, my_attr_t *attr) { attr->mode = inode->i_mode; attr->nlink = inode->i_nlink; attr->uid = inode->i_uid; attr->gid = inode->i_gid; attr->size = S_ISDIR(attr->mode) && inode->i_size == 0 ? 100000 : inode->i_size; /* fake a directory size */ attr->blocksize = inode->i_blksize > 0 ? inode->i_blksize : PAGE_SIZE; attr->blocks = inode->i_blocks > 0 ? inode->i_blocks : (attr->size + my_blocksize - 1) / my_blocksize; attr->fileid = inode->i_ino; attr->atime = inode->i_atime; attr->mtime = inode->i_mtime; attr->ctime = inode->i_ctime; attr->rdev = inode->i_rdev; } /* ------------------------------------------------------------------------- */ #define FIND_INODE(inode, fh, ops, iputs) \ if((inode = iget(&my_superblock, fh)) == NULL){ \ DPRINTF(("invalid inode %d: not found in %s/%d\n",\ fh, __FILE__, __LINE__)); \ iputs; \ error = -MY_NFSERR_STALE; \ goto do_return; \ } \ if((ops = inode->i_op) == NULL){ \ printk("invalid inode %d: no inode operations in %s/%d\n",\ fh, __FILE__, __LINE__);\ iput(inode); \ iputs; \ error = -MY_NFSERR_STALE; \ goto do_return; \ } #define VALIDATE(operation, iputs) \ if(!(operation)){ \ DPRINTF(("invalid operation in %s/%d\n", __FILE__, __LINE__));\ iputs; \ error = -EINVAL; \ goto do_return; \ } #define RETAIN(inode) (inode)->i_count++ /* ------------------------------------------------------------------------- */ static int fo_new(int is_dir, int *fh, my_attr_t *fa, int dir, char *name, my_attr_t *sa) { struct inode *inode, *new_inode = NULL; struct inode_operations *ops; int error = 0; FIND_INODE(inode, dir, ops, ;); VALIDATE(ops->lookup, ;); CHECK_WRITE(inode, ;); if(is_dir){ VALIDATE(ops->mkdir, ;); RETAIN(inode); /* retain for mkdir */ error = ops->mkdir(inode, name, strlen(name), sa->mode); if(error) goto do_return; RETAIN(inode); /* retain for second operation */ error = ops->lookup(inode, name, strlen(name), &new_inode); }else{ RETAIN(inode); /* retain for additional lookup or unlink */ if(sa->size == 0){ VALIDATE(ops->unlink, iput(inode)); ops->unlink(inode, name, strlen(name)); /* ignore errors */ }else{ if(ops->lookup(inode, name, strlen(name), &new_inode) == 0){ *fh = new_inode->i_ino; get_attr(new_inode, fa); iput(new_inode); iput(inode); return 0; } } VALIDATE(ops->create, ;); RETAIN(inode); /* retain for create */ error = ops->create(inode, name, strlen(name), sa->mode, &new_inode); } if(error) goto do_return; *fh = new_inode->i_ino; new_inode->i_uid = nfs_uid; new_inode->i_gid = nfs_gid; new_inode->i_dirt = 1; set_attr(new_inode, sa); new_inode->i_mode &= ~S_IFMT; new_inode->i_mode |= is_dir ? S_IFDIR : S_IFREG; get_attr(new_inode, fa); iput(new_inode); do_return: iput(inode); return error; } /* ------------------------------------------------------------------------- */ int fo_create(int *fh, my_attr_t *fa, int dir, char *name, my_attr_t *sa) { DPRINTF(("fo_create(ino=%d, name=%s)\n", dir, name)); return fo_new(0, fh, fa, dir, name, sa); } /* ------------------------------------------------------------------------- */ int fo_mkdir(int *fh, my_attr_t *fa, int dir, char *name, my_attr_t *sa) { DPRINTF(("fo_mkdir(ino=%d, name=%s)\n", dir, name)); return fo_new(1, fh, fa, dir, name, sa); } /* ------------------------------------------------------------------------- */ int fo_getattr(my_attr_t *fa, int fh) { struct inode *inode; struct inode_operations *ops; int error = 0; DPRINTF(("fo_getattr(ino=%d)\n", fh)); FIND_INODE(inode, fh, ops, ;); get_attr(inode, fa); iput(inode); do_return: return error; } /* ------------------------------------------------------------------------- */ int fo_lookup(int *fh, my_attr_t *fa, int dir, char *name) { struct inode *inode, *found_inode = NULL; struct inode_operations *ops; int error = 0; DPRINTF(("fo_lookup(ino=%d, name=%s)\n", dir, name)); FIND_INODE(inode, dir, ops, ;); CHECK_READ(inode, iput(inode)); VALIDATE(ops->lookup, iput(inode)); if((error = ops->lookup(inode, name, strlen(name), &found_inode)) != 0) goto do_return; get_attr(found_inode, fa); *fh = found_inode->i_ino; iput(found_inode); do_return: return error; } /* ------------------------------------------------------------------------- */ struct my_dirinfo{ my_direntry_t **entries; int max_bytes; int *put_cookie; int called; }; /* ------------------------------------------------------------------------- */ static int callback(void *arg, const char *name, int namelen, off_t offs, ino_t inum) { struct my_dirinfo *di = arg; my_direntry_t *p; di->called = 1; if(di->put_cookie != NULL) *(di->put_cookie) = offs; di->max_bytes -= namelen + 1 + sizeof(my_direntry_t); if(di->max_bytes < 0){ DPRINTF(("callback(): stopping\n")); return -1; } p = malloc(sizeof(my_direntry_t)); p->fh = inum; p->name = malloc(namelen + 1); memcpy(p->name, name, namelen); p->name[namelen] = 0; p->cookie = -1; di->put_cookie = &p->cookie; p->next = NULL; *(di->entries) = p; di->entries = &p->next; DPRINTF(("callback(): added ->%s<- offset=%d, inode=%d\n", p->name, (int)offs, (int)inum)); return 0; } /* ------------------------------------------------------------------------- */ int fo_readdir(my_direntry_t **result, int *eof, int max_bytes, int dir, int cookie) { struct inode *inode; struct inode_operations *ops; struct file_operations *fops; struct file filp; int error = 0; struct my_dirinfo dirinfo; *result = NULL; dirinfo.entries = result; dirinfo.max_bytes = max_bytes; dirinfo.put_cookie = NULL; dirinfo.called = 0; DPRINTF(("fo_readdir(ino=%d, cookie=%d, max=%d)\n",dir,cookie,max_bytes)); FIND_INODE(inode, dir, ops, ;); CHECK_EXEC(inode, ;); CHECK_READ(inode, ;); VALIDATE(ops->default_file_ops, ;); fops = ops->default_file_ops; VALIDATE(fops->readdir, ;); bzero(&filp, sizeof(filp)); filp.f_mode = inode->i_mode; filp.f_pos = cookie; do{ dirinfo.called = 0; error = fops->readdir(inode, &filp, &dirinfo, callback); if(error < 0) break; }while(dirinfo.max_bytes > 0 && dirinfo.called); if(dirinfo.put_cookie != NULL) *(dirinfo.put_cookie) = filp.f_pos; do_return: *eof = !dirinfo.called; iput(inode); return error; } /* ------------------------------------------------------------------------- */ int fo_setattr(my_attr_t *fa, int fh, my_attr_t *sa) { struct inode *inode; struct inode_operations *ops; int error = 0; DPRINTF(("fo_setattr(ino=%d)\n", fh)); FIND_INODE(inode, fh, ops, ;); CHECK_ATTR(inode, iput(inode)); set_attr(inode, sa); get_attr(inode, fa); iput(inode); do_return: return error; } /* ------------------------------------------------------------------------- */ static int fo_rm(int is_dir, int dir, char *name) { struct inode *inode; struct inode_operations *ops; int error = 0; int (*rmop)(struct inode *,const char *,int); DPRINTF(("fo_rm(ino=%d, name=%s)\n", dir, name)); FIND_INODE(inode, dir, ops, ;); CHECK_WRITE(inode, iput(inode)); rmop = is_dir ? ops->rmdir : ops->unlink; VALIDATE(rmop, iput(inode)); if((error = rmop(inode, name, strlen(name))) != 0) goto do_return; do_return: return error; } /* ------------------------------------------------------------------------- */ int fo_remove(int dir, char *name) { return fo_rm(0, dir, name); } /* ------------------------------------------------------------------------- */ int fo_rmdir(int dir, char *name) { return fo_rm(1, dir, name); } /* ------------------------------------------------------------------------- */ int fo_rename(int fromdir, char *fromname, int todir, char *toname) { struct inode *from_i, *to_i; struct inode_operations *from_o, *to_o; int error = 0; DPRINTF(("fo_rename(ino=%d, name=%s, ino=%d, name=%s)\n", fromdir, fromname, todir, toname)); FIND_INODE(from_i, fromdir, from_o, ;); CHECK_WRITE(from_i, iput(from_i)); FIND_INODE(to_i, todir, to_o, iput(from_i)); CHECK_WRITE(to_i, iput(from_i); iput(to_i)); VALIDATE(from_o->rename, iput(from_i); iput(to_i)); error = from_o->rename(from_i, fromname, strlen(fromname), to_i, toname, strlen(toname), 0); do_return: return error; } /* ------------------------------------------------------------------------- */ int fo_statfs(my_statfs_t *fsstat) { struct statfs stat; DPRINTF(("fo_statfs()\n")); if(!my_superblock.s_op->statfs) return -EINVAL; my_superblock.s_op->statfs(&my_superblock, &stat, sizeof(stat)); fsstat->type = stat.f_type; fsstat->bsize = stat.f_bsize; fsstat->blocks = stat.f_blocks; fsstat->bfree = stat.f_bfree; fsstat->bavail = stat.f_bavail; fsstat->files = stat.f_files; fsstat->ffree = stat.f_ffree; return 0; } /* ------------------------------------------------------------------------- */ int fo_read(my_attr_t *fa, int *len, char **data, int fh, int offs, int count) { static char transfer_buf[TRANSFER_BUFFER_SIZE]; struct inode *inode; struct inode_operations *ops; struct file_operations *fops; struct file filp; int error = 0; DPRINTF(("fo_read(ino=%d, offs=%d, len=%d)\n", fh, offs, count)); *data = transfer_buf; FIND_INODE(inode, fh, ops, ;); CHECK_READ(inode, ;); if(offs + count > inode->i_size) count = inode->i_size - offs; if(count <= 0){ /* nothing to be done */ get_attr(inode, fa); *len = 0; goto do_return; } VALIDATE(ops->default_file_ops, ;); fops = ops->default_file_ops; VALIDATE(fops->read, ;); bzero(&filp, sizeof(filp)); filp.f_mode = inode->i_mode; filp.f_pos = offs; if(count > sizeof(transfer_buf)) count = sizeof(transfer_buf); error = fops->read(inode, &filp, transfer_buf, count); *len = error; error = error < 0 ? error : 0; get_attr(inode, fa); do_return: iput(inode); DPRINTF(("fo_read() returns %d\n", error)); return error; } /* ------------------------------------------------------------------------- */ int fo_write(my_attr_t *fa, int fh, int offset, int count, char *data) { struct inode *inode; struct inode_operations *ops; struct file_operations *fops; struct file filp; int error = 0; DPRINTF(("fo_write(ino=%d, offs=%d, len=%d)\n", fh, offset, count)); FIND_INODE(inode, fh, ops, ;); CHECK_WRITE(inode, ;); if(count <= 0){ /* nothing to be done */ get_attr(inode, fa); goto do_return; } VALIDATE(ops->default_file_ops, ;); fops = ops->default_file_ops; VALIDATE(fops->write, ;); bzero(&filp, sizeof(filp)); filp.f_mode = inode->i_mode; filp.f_pos = offset; error = fops->write(inode, &filp, data, count); error = error < 0 ? error : 0; get_attr(inode, fa); do_return: iput(inode); DPRINTF(("fo_write() returns %d\n", error)); return error; } /* ------------------------------------------------------------------------- */ int fo_link(int from, int dir, char *name) { struct inode *from_i, *dir_i; struct inode_operations *from_o, *dir_o; int error = 0; DPRINTF(("fo_link(ino=%d, dir=%d, name=%s)\n", from, dir, name)); FIND_INODE(from_i, from, from_o, ;); FIND_INODE(dir_i, dir, dir_o, iput(from_i)); CHECK_WRITE(dir_i, iput(from_i); iput(dir_i)); VALIDATE(dir_o->link, iput(from_i); iput(dir_i)); error = dir_o->link(from_i, dir_i, name, strlen(name)); do_return: return error; } /* ------------------------------------------------------------------------- */ int fo_readlink(char **path, int fh) { struct inode *inode; struct inode_operations *ops; int error = 0; static char namebuf[2048]; DPRINTF(("fo_readlink(ino=%d)\n", fh)); FIND_INODE(inode, fh, ops, ;); VALIDATE(ops->readlink, iput(inode)); *path = namebuf; error = ops->readlink(inode, *path, sizeof(namebuf)); if(error >= 0){ if(error < sizeof(namebuf)) namebuf[error] = 0; else namebuf[sizeof(namebuf)-1] = 0; } do_return: return error; } /* ------------------------------------------------------------------------- */ int fo_symlink(int fromdir, char *fromname, char *topath, my_attr_t *sa) { struct inode *dir_i; struct inode_operations *dir_o; int error = 0; DPRINTF(("fo_symlink(dir=%d, name=%s, path=%s)\n", fromdir, fromname, topath)); FIND_INODE(dir_i, fromdir, dir_o, ;); CHECK_WRITE(dir_i, iput(dir_i)); VALIDATE(dir_o->symlink, iput(dir_i)); error = dir_o->symlink(dir_i, fromname, strlen(fromname), topath); /* ignore attributes! links should have all flags set, anyway */ do_return: return error; } /* ------------------------------------------------------------------------- */ void fops_regular(void) { static int i = 0; if(++i > 10){ /* do a sync every 10s */ i = 0; my_sync(); } } /* ------------------------------------------------------------------------- */ void fops_init(void) { #ifdef CONFIG_EXT_FS init_ext_fs(); #endif #ifdef CONFIG_EXT2_FS init_ext2_fs(); #endif #ifdef CONFIG_XIA_FS init_xiafs_fs(); #endif #ifdef CONFIG_MINIX_FS init_minix_fs(); #endif #ifdef CONFIG_UMSDOS_FS init_umsdos_fs(); #endif #ifdef CONFIG_FAT_FS init_fat_fs(); #endif #ifdef CONFIG_MSDOS_FS init_msdos_fs(); #endif #ifdef CONFIG_VFAT_FS init_vfat_fs(); #endif #ifdef CONFIG_PROC_FS init_proc_fs(); #endif #ifdef CONFIG_NFS_FS init_nfs_fs(); #endif #ifdef CONFIG_SMB_FS init_smb_fs(); #endif #ifdef CONFIG_NCP_FS init_ncp_fs(); #endif #ifdef CONFIG_ISO9660_FS init_iso9660_fs(); #endif #ifdef CONFIG_SYSV_FS init_sysv_fs(); #endif #ifdef CONFIG_HPFS_FS init_hpfs_fs(); #endif #ifdef CONFIG_AFFS_FS init_affs_fs(); #endif #ifdef CONFIG_UFS_FS init_ufs_fs(); #endif #ifdef CONFIG_NTFS_FS init_ntfs_fs(); #endif } /* ------------------------------------------------------------------------- */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.