📄 tfs_subr.c
字号:
tvp[1].tv_usec = 0; if (utimes(fname, tvp) < 0) { return (errno); } } return (0); } if (set_to_now) { if (result = get_server_time(parentp, &mtime)) { return (result); } atime = mtime; } if (mtime != -1) { if ((result = update_directory(parentp, fname, DIR_UTIME_FILE, mtime)) || (result = change_backlist_mtime(parentp, fname, mtime))) { return (result); } } if (atime != -1) { /* * Set the access time of the file in the read-only layer */ if (get_realattrs_of(vp, &attrs) < 0) { return (errno); } if (attrs.na_atime.tv_sec == atime) { return (0); } tvp[0].tv_sec = atime; tvp[0].tv_usec = 0; tvp[1].tv_sec = -1; tvp[1].tv_usec = 0; ptoname(vp->v_pnode, name); result = utimes_as_owner(name, tvp, (int) attrs.na_uid); } return (result);}/* * Create a dummy file in 'dir' whose sole purpose is to get the * current 'mtime' on the NFS server on which it resides. This is * used by utimes(x, NULL) to get the right value of 'mtime' for a * file 'x' which is in the read-only layers of 'dir'. */static intget_server_time(dir, mtime) struct pnode *dir; long *mtime;{ int fd; struct stat stbuf; int result = 0; *mtime = -1; if (result = change_to_dir(dir)) { return result; } if (utimes(NSE_TFS_FILE, (struct timeval *) NULL) == -1 || stat(NSE_TFS_FILE, &stbuf) == -1) { if (errno != ENOENT) { return (errno); } fd = open(NSE_TFS_UTIMES_FILE, O_RDWR|O_CREAT, 0666); if (fd == -1) { return (errno); } if (fstat(fd, &stbuf) == -1) { result = errno; } if (close(fd) == -1 && result == 0) { result = errno; } if (unlink(NSE_TFS_UTIMES_FILE) == -1 && result == 0) { result = errno; } } *mtime = stbuf.st_mtime; return (result);}/* * Update the ctime of the file with vnode 'vp' by setting its atime and * mtime to their current values. This is necessary so that the kernel VFS * will know when a directory has had an entry removed. (The kernel VFS * needs to flush a directory from the directory name lookup cache (DNLC) * when the directory's ctime changes, because it is possible for someone * on another machine to remove or rename a file/dir that was in the local * machine's DNLC; we don't want the file to be reachable through the DNLC * any longer.) The tfsd needs to explicitly update the ctime of the * directory in the front layer when a file is removed from a back layer, * or a file is removed by creating a whiteout entry. * * This routine is also called when a file in a back layer is * copy-on-writed, in two cases: 1) there is more than one view on the file * (e.g. the file can be seen in both a var-sun3 and a var-sun4 activation * at the same time), or 2) the environ containing the file is being * accessed by more than one client machine. In such a case, it is * possible for a client on one machine to copy-on-write a file for which * there is another kernel TFS vnode. Updating the ctime of the file * in the back layer is the only way to alert the client kernel that the * other TFS vnode's real vnode has changed. NOTE: this unfortunately updates * the ctime of a file in a read-only layer. * * It is not necessary to call this routine when a directory is * copy-on-writed, because the kernel VFS knows that a directory is * copy-on-writed the first time it is read, and so will flush the real * vnode of a non-writeable directory the first time it is read. */voidupdate_ctime(vp, avoid_dup_updates) struct vnode *vp; bool_t avoid_dup_updates;{ struct nfsfattr attrs; struct timeval tvp[2]; char name[MAXNAMLEN]; int result; if (avoid_dup_updates) { if (vp->v_pnode->p_updated) { return; } vp->v_pnode->p_updated = TRUE; } if (get_realattrs_of(vp, &attrs) < 0) { print_warning_msg(vp->v_pnode, "update_ctime: getattrs"); return; } tvp[0].tv_sec = attrs.na_atime.tv_sec; tvp[0].tv_usec = 0; tvp[1].tv_sec = attrs.na_mtime.tv_sec; tvp[1].tv_usec = 0; if (vp->v_pnode->p_type == PTYPE_DIR && change_to_dir(vp->v_pnode) == 0) { strcpy(name, "."); } else { ptoname(vp->v_pnode, name); } result = utimes_as_owner(name, tvp, (int) attrs.na_uid); if (result) { errno = result; print_warning_msg(vp->v_pnode, "update_ctime: utimes"); }}intutimes_as_owner(name, tvp, owner) char *name; struct timeval tvp[2]; int owner;{ int result = 0; if (owner != current_user_id()) { change_user_id(owner); } if (utimes(name, tvp) < 0) { result = errno; } if (owner != current_user_id()) { change_user_id(current_user_id()); } return (result);}/* * Determine when the cached mtime for pnode 'pp' will expire and need to * be checked. Use the algorithm used by the NFS -- base the expire time * on the time since the directory last changed, but set limits on the * maximum and minimum expire times. */voidset_expire_time(pp) struct pnode *pp;{ long delta; pp->p_expire = get_current_time(FALSE); delta = (pp->p_expire - pp->p_mtime) >> 4; if (delta < MIN_DIR_EXPIRE) { delta = MIN_DIR_EXPIRE; } else if (delta > MAX_DIR_EXPIRE) { delta = MAX_DIR_EXPIRE; } pp->p_expire += delta;}/* * This routine is called by tfs_rename() and tfs_link(), which create * new names for objects at specified sub-layers. This routine handles * two complications that arise: * 1) If the source file occurred at a layer further back than the dest * file, then the original dest file has to be removed. (This ensures * that we don't create a file underneath an existing file/whiteout entry.) * 2) If the source file at a layer further forward than the dest file, * but dest is at a greater sub-layer, then the source file will have * to be pushed to the sub-layer of dest. In this case, 'dest_sub_layer' * is set to the sub-layer that the file has to be pushed to. */inthandle_rename_sub_layers(dest_vp, src_layer, dest_sub_layer) struct vnode *dest_vp; unsigned src_layer; int *dest_sub_layer;{ struct pnode *src_pp; struct pnode *dest_pp; int result; dest_pp = get_front_parent_pnode(PARENT_VNODE(dest_vp), dest_vp->v_layer); if (dest_vp->v_layer < src_layer) { if (result = clear_file(dest_pp, dest_vp)) { return (result); } } else if (dest_vp->v_layer > src_layer) { src_pp = get_front_parent_pnode(PARENT_VNODE(dest_vp), src_layer); if (src_pp->p_sub_layer < dest_pp->p_sub_layer) { *dest_sub_layer = dest_pp->p_sub_layer; } } return (0);}/* * Expand the variant searchlink 'path' into 'expanded_path'. 'cp' is a * pointer to the position of the wildcard string in 'path', and 'environ_id' * is the environment ID which should be used to expand the searchlink. * 'use_var_name' indicates whether to use the variant name or the default * name of the environment. */bool_texpand_searchlink(path, environ_id, cp, expanded_path, use_var_name) char *path; unsigned environ_id; char *cp; char *expanded_path; bool_t use_var_name;{ char *tailp; char oldc; tailp = cp + strlen(NSE_TFS_WILDCARD); if (*tailp != '/') { return (FALSE); } oldc = *cp; *cp = '\0'; strcpy(expanded_path, path); *cp = oldc; if (use_var_name && (cp = environ_var_name(environ_id))) { strcat(expanded_path, cp); } else if (cp = environ_default_name(environ_id)) { strcat(expanded_path, cp); } else { return (FALSE); } strcat(expanded_path, tailp); return (TRUE);}/* * Convert the path 'path' into a variant searchlink. */static bool_tcreate_variant_searchlink(path, environ_id, unexpanded_path) char *path; unsigned environ_id; char *unexpanded_path;{ char *cp = NULL; char *tailp; char oldc; char *varname; char *default_name; varname = environ_var_name(environ_id); if (varname) { cp = nse_find_substring(path, varname); } if (cp) { tailp = cp + strlen(varname); } else { default_name = environ_default_name(environ_id); cp = nse_find_substring(path, default_name); if (cp == NULL) { return (FALSE); } tailp = cp + strlen(default_name); } if (*tailp != '/') { return (FALSE); } oldc = *cp; *cp = '\0'; strcpy(unexpanded_path, path); *cp = oldc; strcat(unexpanded_path, NSE_TFS_WILDCARD); strcat(unexpanded_path, tailp); return (TRUE);}/* * Fill tfsdiropres struct to send back to kernel. Used by TFS version 2 * requests. (The client kernel contains the kernel VFS.) */voidfill_diropres(vp, dr) struct vnode *vp; struct tfsdiropres *dr;{ static char pn[MAXPATHLEN]; makefh(&dr->dr_fh, vp); dr->dr_nodeid = vp->v_fhid; ptopn(vp->v_pnode, pn); if (vp->v_pnode->p_type == PTYPE_DIR) { /* * A mountpoint vnode may have a pnode which is actually * a symlink, if a branch mount has been made of a relocated * variant. In this case, we want to return the pathname * of the real directory, not the symlink, to the kernel. * Note that the pnodes at mountpoints are the only ones * which can be assigned a p_type which does not match * the type of the real file. */ if (vp->v_is_mount_pt) { struct stat statb; while (LSTAT(pn, &statb) == 0 && (statb.st_mode & S_IFMT) == S_IFLNK) { int count; count = readlink(pn, pn, MAXPATHLEN); if (count < 0) { break; } pn[count] = '\0'; } } dr->dr_writeable = (vp->v_layer == 0); } else { dr->dr_writeable = IS_WRITEABLE(vp); } dr->dr_path = pn; dr->dr_pathlen = strlen(pn); sattr_null(&dr->dr_sattrs); if (!IS_WRITEABLE(vp)) { if (vp->v_back_owner) { dr->dr_sattrs.sa_uid = current_user_id(); } if (vp->v_mtime != 0) { dr->dr_sattrs.sa_mtime.tv_sec = vp->v_mtime; dr->dr_sattrs.sa_mtime.tv_usec = 0; } }}/* * Set sattr structure to a null value. * XXX machine dependent? */static voidsattr_null(sap) struct nfssattr *sap;{ int n; char *cp; n = sizeof(struct nfssattr); cp = (char *) sap; while (n--) { *cp++ = -1; }}/* * Chdir to /tmp and dump core there. Called from various places when * something strange happens. */voidpanic(pp) struct pnode *pp;{ if (pp != NULL) { print_pnode_path(pp); } kill_me();}voidkill_me(){ /* * Core dump will be successful only if (uid == euid && gid == egid) */ (void) setreuid(-1, 0); (void) setregid(-1, getgid()); (void) chdir("/tmp"); abort();}bool_tis_tfs_special_file(name) char *name;{ return (strncmp(name, NSE_TFS_FILE_PREFIX, NSE_TFS_FILE_PREFIX_LEN) == 0);}voidprint_warning_msg(pp, str) struct pnode *pp; char *str;{ nse_log_message("warning: "); tfsd_perror(str); print_pnode_path(pp);}voidprint_pnode_path(pp) struct pnode *pp;{ char pn[MAXPATHLEN]; ptopn(pp, pn); fprintf(stderr, " (dir %s)\n", pn); fprintf(stdout, " (dir %s)\n", pn);}extern int sys_nerr;extern char *sys_errlist[];voidtfsd_perror(str) char *str;{ char string[MAXPATHLEN]; strcpy(string, str); strcat(string, ": "); if (errno < sys_nerr && errno > 0) { strcat(string, sys_errlist[errno]); } else { str = string + strlen(string); sprintf(str, "Unknown error #%d", errno); } fprintf(stderr, string); fprintf(stdout, string);}/* * Print the error string to stdout and stderr without the leading * 'tfsd: '. */voidtfsd_err_print(err) Nse_err err;{ char *str; if (err) { str = index(err->str, ' '); str++; fprintf(stderr, "%s\n", str); fprintf(stdout, "%s\n", str); }}inthash_string(compname) char *compname;{ int sum; for (sum = 0; *compname; sum += *compname++) ; return (sum & (HASH_TABLE_SIZE - 1));}/* * get the fhandle from a given vnode. */voidmakefh(fh, vp) fhandle_t *fh; struct vnode *vp;{ extern time_t tfsd_timestamp; BZERO((caddr_t) fh, NFS_FHSIZE); TFS_FH(fh)->fh_id = vp->v_fhid; TFS_FH(fh)->fh_parent_id = PARENT_VNODE(vp)->v_fhid; TFS_FH(fh)->fh_timestamp = tfsd_timestamp;}FILE *open_tfs_file(path, mode, errp) char *path; char *mode; Nse_err *errp;{ FILE *file; Nse_err err; if (err = nse_fopen(path, mode, &file)) { if (errp) { *errp = err; } else { nse_log_err_print(err); } return (NULL); } if (file != NULL) { setbuffer(file, read_result_buffer, NFS_MAXDATA); } return (file);}/* * Returns the next vnode in the directory (which is not a whiteout vnode.) */struct vnode *next_file(vp) struct vnode *vp;{ do { vp = NEXT_VNODE(vp); } while (vp != NULL && vp->v_whited_out); return (vp);}/* * Returns the next whiteout vnode in the directory. */struct vnode *next_whiteout(vp) struct vnode *vp;{ do { vp = NEXT_VNODE(vp); } while (vp != NULL && (!vp->v_whited_out || !IS_WRITEABLE(vp))); return (vp);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -