⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tfs_subr.c

📁 操作系统SunOS 4.1.3版本的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
#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 + -