📄 tfs_subr.c
字号:
#ifndef lintstatic char sccsid[] = "@(#)tfs_subr.c 1.1 92/07/30 Copyr 1988 Sun Micro";#endif/* * Copyright (c) 1987 Sun Microsystems, Inc. */#include <nse/param.h>#include <nse/util.h>#include "headers.h"#include "vnode.h"#include "tfs.h"#include "subr.h"#include <signal.h>#include <nse/searchlink.h>#include <nse/hash.h>#include <nse/tfs_calls.h>#include <nse/stdio.h>#ifdef TFSDEBUGchar debug_pn[100]; /* for use in dbxtool */#endif TFSDEBUGint num_linknodes;/* * Copy-on-write routines */int promote_file();static int copy_to_front();static int copy_file_with_retry();static int copy_to_front_directory();static int promote_directory();/* * Routines which operate on linknodes. */struct pnode *get_front_parent_pnode();struct pnode *get_pnode_at_layer();struct pnode *get_next_pnode();void set_next_pnode();struct pnode *release_linknode();bool_t has_linknode();void set_linknode_layers();void get_vnodes();/* * Pathname reconstruction routines. */void ptoname();void ptoname_or_pn();void ptopn();void vtovn();char *prepend();/* * Alarm routines */long get_current_time();void alarm_handler();/* * Routines which keep track of the process's user credentials. */void change_user_id();int current_user_id();int set_user_id();int has_perm_to_setattr();bool_t has_access();static bool_t in_group_list();/* * Wrapper routines for NSE library routines which manipulate .tfs_info */int tfsd_set_searchlink();int tfsd_set_whiteout();int tfsd_clear_whiteout();int tfsd_get_backlink();int tfsd_set_backlink();int tfsd_get_tfs_info();int tfsd_set_tfs_info();/* * Miscellaneous */int modify_file();int do_utimes();static int get_server_time();void update_ctime();int utimes_as_owner();void set_expire_time();int handle_rename_sub_layers();bool_t expand_searchlink();static bool_t create_variant_searchlink();void fill_diropres();static void sattr_null();void panic();void kill_me();bool_t is_tfs_special_file();void print_warning_msg();void print_pnode_path();void tfsd_perror();void tfsd_err_print();int hash_string();void makefh();FILE *open_tfs_file();struct vnode *next_file();struct vnode *next_whiteout();/* * Copy-on-write routines *//* * Postcondition of this function: the file with vnode 'vp' exists in a * writeable layer. Directories must exist in the frontmost layer. */intpromote_file(vp) struct vnode *vp;{ switch (vp->v_pnode->p_type) { case PTYPE_REG: if (IS_WRITEABLE(vp)) { return (0); } else { return (copy_to_front(vp)); } case PTYPE_DIR: if (vp->v_layer == 0) { return (0); } else if (vp->v_is_mount_pt) { /* * This case can occur if mount_tfs has TFS-mounted * a directory on a subdir of another TFS mount. */ vp->v_layer = 0; } else { return (copy_to_front_directory(vp)); } } return (0);}/* * Copy the file with vnode 'vp' to a writeable file system. Assumes that * the parent directory exists in the frontmost layer. If this weren't * true, it would be necessary to recursively promote all the parent * directories. */static intcopy_to_front(vp) struct vnode *vp;{ struct pnode *parentp; struct pnode *newp; int result; parentp = get_front_parent_pnode(PARENT_VNODE(vp), vp->v_layer); newp = alloc_pnode(parentp, vp->v_name); newp->p_type = PTYPE_REG; newp->p_refcnt = 1; if (copy_file_with_retry(vp, newp) == -1) { free_pnode(newp); return (errno); } if ((parentp->p_link && parentp->p_link->l_next) || environ_has_multiple_clients(vp)) { update_ctime(vp, FALSE); } release_pnodes(vp); vp->v_pnode = newp; vp->v_dont_flush = TRUE; result = update_directory(parentp, vp->v_name, DIR_ADD_FILE); vp->v_dont_flush = FALSE; newp->p_refcnt = 1; if (result == 0 && vp->v_mtime != 0) { result = do_utimes(vp, vp->v_mtime, (long) -1, FALSE); } return (result);}/* * Copy the the file with vnode 'vp' to a writeable filesystem, if the * user has permission to do so. (The user can copy the file if he owns * the file, or if he doesn't own the file but has write access to it.) * The new pnode of the file is 'newp'. If the file copy fails because we * don't have read access to the file, temporarily chmod the file in back * so that we can copy it. */static intcopy_file_with_retry(vp, newp) struct vnode *vp; struct pnode *newp;{ char src_path[MAXPATHLEN]; char dest_path[MAXNAMLEN]; struct nfsfattr attrs; struct stat statb; int result = 0; if (!vp->v_back_owner) { if (getattrs_of(vp, &attrs) < 0) { return (-1); } if (attrs.na_uid != current_user_id() && !has_access(&attrs, W_OK)) { errno = EACCES; return (-1); } } ptoname(newp, dest_path); ptopn(vp->v_pnode, src_path);#ifdef TFSDEBUG dprint(tfsdebug, 3, "copy_to_front_file(%s -> %s)\n", src_path, dest_path);#endif TFSDEBUG if (_nse_copy_file(dest_path, src_path, 1) == NULL) { return (0); } if (errno != EACCES) { return (-1); } /* * File copy failed because we don't have read access to the * source file -- chmod the source file to allow read access by * all and retry. */ if (LSTAT(src_path, &statb) < 0) { return (-1); } change_user_id((int) statb.st_uid); if (chmod(src_path, (int) statb.st_mode | 0444) < 0) { result = -1; goto error; } change_user_id(current_user_id()); if (_nse_copy_file(dest_path, src_path, 1)) { result = -1; } else { (void) chmod(dest_path, (int) statb.st_mode); } change_user_id((int) statb.st_uid); (void) chmod(src_path, (int) statb.st_mode);error: change_user_id(current_user_id()); return (result);}/* * Copy the directory with vnode 'vp' to all the writeable file systems * in front of the frontmost instance of the directory. We create a new * pnode for each new instance of the directory and set searchlinks in * each new instance of the directory. */static intcopy_to_front_directory(vp) struct vnode *vp;{ struct vnode *pvp; struct pnode *newp; struct nfsfattr attrs; int result; if (getattrs_of(vp, &attrs) < 0) { return (errno); } pvp = PARENT_VNODE(vp); vp->v_dont_flush = TRUE; result = promote_directory(pvp->v_pnode, pvp, vp, 0, (int) attrs.na_mode, &newp); vp->v_dont_flush = FALSE; if (result) { return (result); } vp->v_pnode = newp; set_linknode_layers(vp);/* This is necessary if we don't assume that the parent directory is always in the front fs for (childvp = CHILD_VNODE(vp); childvp != NULL; childvp = NEXT_VNODE(childvp)) { if (childvp->v_layer != INVALID_LAYER) { childvp->v_layer += old_layer; if (childvp->v_back_layer != INVALID_LAYER) { childvp->v_back_layer += old_layer; } } } */ return (0);}/* * Recursively promote the directory with vnode 'vp'. 'pvp' is the vnode * of the parent directory. 'parentp' is the pnode for 'pvp' at layer * 'layer'. We mkdir the directory at the current layer, and create a * pnode 'new_pp' for the new directory. */static intpromote_directory(parentp, pvp, vp, layer, mode, new_pp) struct pnode *parentp; struct vnode *pvp; struct vnode *vp; int layer; int mode; struct pnode **new_pp;{ struct pnode *next_parentp; struct pnode *next_pp; struct pnode *newp; char path[MAXPATHLEN]; char searchlink[MAXPATHLEN]; char backlink[MAXPATHLEN]; char *name; char *nam; int result; if (layer == vp->v_layer || layer > pvp->v_writeable) { *new_pp = vp->v_pnode; return (0); } next_parentp = get_next_pnode(pvp, parentp); if ((result = promote_directory(next_parentp, pvp, vp, layer + 1, mode, &next_pp)) || (result = change_to_dir(parentp))) { return (result); } name = vp->v_name; if (mkdir(name, mode) < 0 && errno != EEXIST) { return (errno); } ptopn(parentp, path); if ((nam = environ_default_name(vp->v_environ_id)) && nse_find_substring(path, nam)) { ptopn(next_pp, path); if (!create_variant_searchlink(path, vp->v_environ_id, searchlink)) { strcpy(searchlink, path); } } else { ptopn(next_pp, searchlink); if (nam = environ_var_name(vp->v_environ_id)) { strcpy(backlink, nam); strcat(backlink, path); nse_pathcat(backlink, name); if (result = tfsd_set_backlink(searchlink, backlink)) { return (result); } } } if ((result = tfsd_set_searchlink(name, searchlink, parentp)) || (result = update_directory(parentp, name, DIR_ADD_FILE))) { return (result); } newp = alloc_pnode(parentp, name); newp->p_refcnt = 1; set_next_pnode(vp, newp, next_pp, 0); *new_pp = newp; return (0);}/* * Routines which operate on linknodes. *//* * Gets the parent pnode at the correct sub-layer in the front file * system for a file at layer 'layer'. */struct pnode *get_front_parent_pnode(pvp, layer) struct vnode *pvp; unsigned layer;{ struct pnode *pp; pp = get_pnode_at_layer(pvp, layer); if (layer <= pvp->v_writeable) { return (pp); } else { return (get_pnode_at_layer(pvp, SUBL_TO_LAYER(pvp, pp))); }}struct pnode *get_pnode_at_layer(vp, layer) struct vnode *vp; unsigned layer;{ struct pnode *pp = vp->v_pnode; int i = 0; while (i < layer) { pp = get_next_pnode(vp, pp); if (pp == NULL) { nse_log_message("panic: get_pnode_at_layer(%d)", layer); panic(vp->v_pnode); } i++; } return (pp);}struct pnode *get_next_pnode(vp, pp) struct vnode *vp; struct pnode *pp;{ struct linknode *lp; for (lp = pp->p_link; lp != NULL; lp = lp->l_next) { if (lp->l_vnode == vp) { return (lp->l_next_pnode); } } return (NULL);}voidset_next_pnode(vp, pp, nextp, layer) struct vnode *vp; struct pnode *pp; struct pnode *nextp; int layer;{ struct linknode *lp; lp = (struct linknode *) nse_malloc(sizeof(struct linknode)); num_linknodes++; lp->l_next_pnode = nextp; lp->l_vnode = vp; lp->l_layer = layer; lp->l_next = pp->p_link; pp->p_link = lp;}struct pnode *release_linknode(vp, pp) struct vnode *vp; struct pnode *pp;{ struct linknode *lp; struct linknode *lp_prev = NULL; struct pnode *next_pp; for (lp = pp->p_link; lp != NULL; lp = lp->l_next) { if (lp->l_vnode == vp) { break; } lp_prev = lp; } if (lp == NULL) { return (NULL); } if (lp_prev == NULL) { pp->p_link = lp->l_next; } else { lp_prev->l_next = lp->l_next; } next_pp = lp->l_next_pnode; free((char *) lp); num_linknodes--; return (next_pp);}bool_thas_linknode(vp, pp) struct vnode *vp; struct pnode *pp;{ struct linknode *lp; for (lp = pp->p_link; lp != NULL; lp = lp->l_next) { if (lp->l_vnode == vp) { return (TRUE); } } return (FALSE);}voidset_linknode_layers(vp) struct vnode *vp;{ struct pnode *pp = vp->v_pnode; struct linknode *lp; int layer = 0; while (pp != NULL) { for (lp = pp->p_link; lp != NULL; lp = lp->l_next) { if (lp->l_vnode == vp) { break; } } if (lp == NULL) { break; } lp->l_layer = layer++; pp = lp->l_next_pnode; }}/* * Returns all vnodes with 'pp' as their frontmost pnode. 'vnodes' should * be a bzero'd array with MAX_NAMES entries. */voidget_vnodes(pp, vnodes) struct pnode *pp; struct vnode **vnodes;{ struct linknode *lp; int i = 0; for (lp = pp->p_link; lp != NULL; lp = lp->l_next) { if (lp->l_layer == 0) { if (i == MAX_NAMES) { /* * This is bad. Panic now before the stack * is corrupted. */ nse_log_message("panic: get_vnodes"); panic(pp); } vnodes[i] = lp->l_vnode; i++; } }}/* * Pathname reconstruction routines. *//* * Return the name of pnode 'pp', and fchdir to the parent directory, so * that the relative name can be used in system calls. */voidptoname(pp, name) struct pnode *pp; char *name;{ if (change_to_dir(PARENT_PNODE(pp)) == 0) { strcpy(name, pp->p_name); } else { ptopn(pp, name); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -