📄 tfs_vnodeops.c
字号:
#ifndef lintstatic char sccsid[] = "@(#)tfs_vnodeops.c 1.1 92/07/30 Copyr 1988 Sun Micro";#endif/* * Copyright (c) 1987 Sun Microsystems, Inc. */#include <nse/types.h>#include "headers.h"#include "vnode.h"#include "tfs.h"#include "subr.h"#include <nse/param.h>#include <nse/util.h>#include <nse/searchlink.h>/* * Routines to implement NFS ops. (Except for readdir, which is in * tfs_dirs.c.) */extern int chmod();extern int fchmod();extern int chown();extern int fchown();int tfs_error();int tfs_null();int tfs_getattr();int tfs_setattr_1();int tfs_setattr_2();static int do_setattr();int tfs_lookup_1();int tfs_lookup_2();static int do_lookup();int tfs_readlink();int tfs_read();int tfs_write();int tfs_create_1();int tfs_create_2();static int do_create();int tfs_remove();int tfs_rename();int tfs_link();int tfs_symlink();int tfs_mkdir_1();int tfs_mkdir_2();static int do_mkdir();int tfs_rmdir();int tfs_statfs();int tfs_translate();/* * Error procedure invoked when an obsolete NFS procedure is called. * (i.e. nfs_root & nfs_writecache) */inttfs_error(){ return (EOPNOTSUPP);}/* * Procedure 0. Null procedure available for ping-ing. */inttfs_null(){#ifdef TFSDEBUG trace_reset(); print_vnode_trees(); pnode_tree_print(); comp_print(); print_fd_cache(); swqueue_print();#endif TFSDEBUG /* do nothing */ return (0);}/* * Procedure 1. Get file attributes. * Returns the current attributes of the file with the given fhandle. *//*ARGSUSED*/inttfs_getattr(vp, fhp, ns) struct vnode *vp; fhandle_t *fhp; struct nfsattrstat *ns;{ if (!attr_cache_on) { init_attr_cache(); } if (getattrs_of(vp, &ns->ns_attr) < 0) { return (errno); } return (0);}/* * Procedure 2. Set file attributes. * Sets the attributes of the file with the given fhandle. Returns * the new attributes. */inttfs_setattr_1(vp, args, ns) struct vnode *vp; struct nfssaargs *args; struct nfsattrstat *ns;{ int result; if (result = do_setattr(vp, args)) { return (result); } if (args->saa_sa.sa_size != (u_long) -1) { /* * Truncate changes the mtime of the file, so make sure that * the updated mtime is correct. */ (void) write_wcache(vp->v_pnode, (char *) NULL, 0, 0L); } if (getattrs_of(vp, &ns->ns_attr) < 0) { return (errno); } return (0);}inttfs_setattr_2(vp, args, dr) struct vnode *vp; struct nfssaargs *args; struct tfsdiropres *dr;{ int result; if (result = do_setattr(vp, args)) { return (result); } fill_diropres(vp, dr); return (0);}static intdo_setattr(vp, args) struct vnode *vp; struct nfssaargs *args;{ struct pnode *pp; char name[MAXNAMLEN]; struct nfssattr *sa = &args->saa_sa; bool_t set_to_now; int result; if (result = has_perm_to_setattr(vp, sa)) { return (result); } pp = vp->v_pnode; if (pp->p_type == PTYPE_REG && pp->p_needs_write) { sync_wcache(pp); } /* * For all operations other than changing the file's access or * modify times, copy-on-write the file before changing its attrs. */ if ((sa->sa_mode != (u_short) -1 && sa->sa_mode != -1) || sa->sa_uid != -1 || sa->sa_gid != -1 || sa->sa_size != (u_long) -1) { if (result = promote_file(vp)) { return (result); } } pp = vp->v_pnode; if (sa->sa_mode != (u_short) -1 && sa->sa_mode != -1) { if (result = modify_file(pp, chmod, fchmod, (int) sa->sa_mode)) { return (result); } } if (sa->sa_uid != -1 || sa->sa_gid != -1) { if (result = modify_file(pp, chown, fchown, (int) sa->sa_uid, (int) sa->sa_gid)) { return (result); } } if (sa->sa_size != (u_long) -1) { /* * ftruncate() needs an fd opened for writing, so just use * truncate(). */ ptoname(pp, name); if (truncate(name, (long) sa->sa_size) < 0) { return (errno); } } /* * Change file access or modified times. */ set_to_now = FALSE; if (sa->sa_atime.tv_sec != -1 || sa->sa_mtime.tv_sec != -1) {#ifdef SUN_OS_4 /* * Allow SysV-compatible option to set access and * modified times. * XXX - va_mtime.tv_usec == -1 flags this. */ if (sa->sa_mtime.tv_sec != -1 && sa->sa_mtime.tv_usec == -1) { set_to_now = TRUE; }#endif if (result = do_utimes(vp, sa->sa_mtime.tv_sec, sa->sa_atime.tv_sec, set_to_now)) { return (result); } } flush_cached_attrs(pp); return (0);}/* * Procedure 4. Directory lookup. * Returns an fhandle and file attributes for file name in a directory. */inttfs_lookup_1(pvp, da, dr) struct vnode *pvp; struct nfsdiropargs *da; struct nfsdiropres *dr;{ struct vnode *vp; int result; if (result = do_lookup(pvp, da, &vp, &dr->dr_attr)) { return (result); } makefh(&dr->dr_fhandle, vp); return (0);}inttfs_lookup_2(pvp, da, dr) struct vnode *pvp; struct nfsdiropargs *da; struct tfsdiropres *dr;{ struct vnode *vp; int result; if (result = do_lookup(pvp, da, &vp, (struct nfsfattr *) NULL)) { return (result); } fill_diropres(vp, dr); return (0);}static intdo_lookup(pvp, da, vpp, attrs) struct vnode *pvp; struct nfsdiropargs *da; struct vnode **vpp; struct nfsfattr *attrs;{ struct vnode *vp; char *name = da->da_name; if (is_tfs_special_file(name)) { return (ENOENT); } else if (NSE_STREQ(name, ".")) { vp = pvp; } else if (NSE_STREQ(name, "..")) { vp = PARENT_VNODE(pvp); if (vp == NULL || pvp->v_is_mount_pt) { vp = pvp; } } else { vp = lookup_vnode(pvp, name, attrs, FALSE); if (vp == NULL) { return (ENOENT); } goto got_attrs; } if (attrs && getattrs_of(vp, attrs) < 0) { return (errno); }got_attrs: *vpp = vp; return (0);}/* * Procedure 5. Read symbolic link. * Returns the string in the symbolic link at the given fhandle. *//* ARGSUSED */inttfs_readlink(vp, fhp, rl) struct vnode *vp; fhandle_t *fhp; struct nfsrdlnres *rl;{ char name[MAXNAMLEN]; int count; rl->rl_data = read_result_buffer; ptoname(vp->v_pnode, name); count = readlink(name, rl->rl_data, MAXPATHLEN); if (count < 0) { rl->rl_data = NULL; rl->rl_count = 0; return (errno); } rl->rl_data[count] = '\0'; rl->rl_count = count; return (0);}/* * Procedure 6. Read data. * Returns some data read from the file at the given fhandle. */inttfs_read(vp, ra, rr) struct vnode *vp; struct nfsreadargs *ra; struct nfsrdresult *rr;{ struct pnode *pp; long offset; int length; int count; /* * Check the transfer size restriction. If we try to send more than * NFS_MAXDATA, we will hang the server. This is only a problem if the * client dosn't listen to our transfer size in statfs. */ if (ra->ra_count > NFS_MAXDATA) { return (EMSGSIZE); } rr->rr_data = read_result_buffer; /* * for now we assume no append mode and ignore totcount (read ahead) */ offset = (long) ra->ra_offset; length = (int) ra->ra_count; count = 0; pp = vp->v_pnode; if (offset >= pp->p_size) { /* * Reading past EOF (happens when the buffer cache * reads-ahead before writing.) */ goto rdwr_finished; } if (get_rw_fd(vp, UIO_READ) < 0) { return (errno); } if (pp->p_needs_write) { /* * Read data from write cache if it's there. */ count = read_wcache(pp, rr->rr_data, length, offset); } if (count <= 0) { count = rdwr_fd(pp, rr->rr_data, length, offset, UIO_READ); }rdwr_finished: if ((count < 0) || getattrs_of(vp, &rr->rr_attr) < 0) { return (errno); } rr->rr_count = count; return (0);}/* * Procedure 8. Write data to file. * Returns attributes of a file after writing some data to it. */inttfs_write(vp, wa, ns) struct vnode *vp; struct nfswriteargs *wa; struct nfsattrstat *ns;{ struct pnode *pp; int result; long offset; int length; /* * for now we assume no append mode */ if (result = promote_file(vp)) { return (result); } pp = vp->v_pnode; if (pp->p_write_error != 0) { /* * Return error code that was returned when an earlier * delayed write failed. */ return (pp->p_write_error); } if (get_rw_fd(vp, UIO_WRITE) < 0) { return (errno); } offset = (long) wa->wa_offset; length = (int) wa->wa_count; if (offset + length >= pp->p_size) { pp->p_size = offset + length; } result = write_wcache(pp, wa->wa_data, length, offset); if ((result < 0) || getattrs_of(vp, &ns->ns_attr) < 0) { return (errno); } return (0);}/* * Procedure 9. Create a file. * Creates a file with given attributes and returns those attributes * and an fhandle for the new file. */inttfs_create_1(pvp, args, dr) struct vnode *pvp; struct nfscreatargs *args; struct nfsdiropres *dr;{ struct vnode *vp; int old_size = -1; int result; if (result = do_create(pvp, args, &vp, &old_size)) { return (result); } if (getattrs_of(vp, &dr->dr_attr) < 0) { return (errno); } if (old_size == -1 || args->ca_sa.sa_size == 0) { /* * If the file was just created or truncated, we have to * update the mtime of the file, even if no writes are * done to the file later. */ (void) write_wcache(vp->v_pnode, (char *) NULL, 0, 0L); if (getattrs_of(vp, &dr->dr_attr) < 0) { return (errno); } } makefh(&dr->dr_fhandle, vp); return (0);}inttfs_create_2(pvp, args, dr) struct vnode *pvp; struct nfscreatargs *args; struct tfsdiropres *dr;{ struct vnode *vp; int result; if (result = do_create(pvp, args, &vp, (int *) NULL)) { return (result); } fill_diropres(vp, dr); return (0);}/* * XXX The sa_uid field of the args is used as a transaction ID to check * for duplicate requests. We really should add a transaction ID field * to the create args. */static intdo_create(pvp, args, vpp, sizep) struct vnode *pvp; struct nfscreatargs *args; struct vnode **vpp; int *sizep;{ struct vnode *vp; struct pnode *parentp; struct pnode *pp; struct nfsfattr attrs; char *name = args->ca_da.da_name; int mode; int flags; int result; /* * XXX Should get exclusive flag and pass it on here. */ if (is_tfs_special_file(name)) { return (EACCES); } vp = lookup_vnode(pvp, name, &attrs, TRUE); if (vp != NULL && !vp->v_whited_out) { if (attrs.na_size == 0 && args->ca_sa.sa_size == 0 && dupreq_is_duplicate(TFS_CREATE, args->ca_sa.sa_uid)) { *vpp = vp; if (sizep) { *sizep = attrs.na_size; } return (0); } /* * If file exists in a back file system, create the file in * the front file system with the mode of the existing file * in the back fs (if we have the proper access to the file.) */ if (!has_access(&attrs, W_OK)) { return (EACCES); } if (sizep) { *sizep = attrs.na_size; } parentp = get_front_parent_pnode(pvp, vp->v_layer); mode = (int) attrs.na_mode; if (!IS_WRITEABLE(vp)) { if ((parentp->p_link && parentp->p_link->l_next) || environ_has_multiple_clients(vp)) { update_ctime(vp, FALSE); } release_pnodes(vp); } else if (args->ca_sa.sa_size == -1) { /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -