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

📄 tfs_dirs.c

📁 操作系统SunOS 4.1.3版本的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
#ifndef lintstatic char sccsid[] = "@(#)tfs_dirs.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>#include <nse/hash.h>#include "tfs_lists.h"#include <nse/stdio.h>/* * Routines to read in directories. * * TFS_BACKFILES * * Also included here are routines which operate on .tfs_backfiles files. * These files contain the names of all directories and files visible * in back (read-only) file systems.  There is a .tfs_backfiles for * each sub-layer, and the .tfs_backfiles for each sub-layer contains * the read-only files showing through from back instances of that * sub-layer. * * The format of the file is: *	<filename>  <layer #>  [<mtime>] * * <filename> is either the name of a file or is an absolute pathname * to a directory (the directory which contains all the files at the * given layer.)  There is an entry for each read-only directory that * has visible files. * * <layer #> is the absolute layer # of the directory.  (So the layer * #s aren't necessarily consecutive.)  Layers are numbered starting * at 1. * * <mtime> is the modify time of the file, if the file's mtime in * this layer is different from the file's mtime in the read-only * layer.  (This is done so that we don't have to copy-on-write a * file just to change its mtime.) * * The first read-only layer is always written into .tfs_backfiles * so that the file can be checked for validity -- when the searchlink * into the first read-only directory changes we'll be able to detect it. */#define NSE_TFS_BACKF_VERSION 3#define HASH_SIZE	100#define HASH_VALUE	1#define INFINITY	1000000000#define IS_DIRNAME(entry)		(entry->fname[0] == '/')/* * Structure to help in iterating through lists of Filelist entries. */typedef struct Flist_iter {	Nse_listelem	elem;		/* Current element */	Nse_listelem	end;		/* End of list */	Filelist	entry;		/* Data of current element */} *Flist_iter, Flist_iter_rec;#define END_OF_LIST(flist)	(flist.elem == flist.end)extern int	free();int		tfs_readdir();static bool_t	add_entry();int		validate_directory();static int	readdir_vnodes();static struct vnode *matching_vnode();static void	copy_vnodes_and_pnodes();static bool_t	readdir_vnodes_one_layer();static bool_t	read_and_verify_backlists();static int	build_backlists();static bool_t	build_backlist_one_layer();static void	add_dir_to_backlist();static bool_t	have_all_ro_backlists();static void	copy_backlists();static void	copy_backlist_entry();static bool_t	add_to_backlist_unique();static void	readdir_backlists();static void	get_next_entry();static void	destroy_backlists();static struct vnode *create_child_vnode();static void	create_whiteout_vnodes();static void	insert_whiteout_into_hash();int		change_backlist_mtime();static void	change_mtime();int		change_backlist_name();static void	change_name();static int	modify_backlist();static Nse_list	read_backlist();static int	write_backlist();static Nse_err	read_backlist_entry();static Nse_err	write_backlist_entry();static void	add_to_backlist();static Hash	init_dir_hash();static bool_t	good_name();static bool_t	backlist_name_eq();static bool_t	backlist_is_dir();/* * Variables shared between tfs_readdir() and add_entry() */static char	*buf_base;static int	buf_size;static int	buf_maxcount;static long	last_offset;/* * Procedure 16.  Read directory entries. * * There are some weird things to look out for here.  rda->rda_offset is * either 0 or it is the offset returned from a previous readdir.  It is an * opaque value used by the server to find the correct directory block to * read.  In this implementation, the offset of a directory entry is the * index into the list of child vnodes for the directory. */inttfs_readdir(pvp, rda, rd)	struct vnode   *pvp;	struct nfsrddirargs *rda;	struct nfsreaddirres *rd;{	static struct vnode *last_pvp;	static struct vnode *last_vp;	struct vnode	*vp;	struct vnode	*next_vp;	int		result;	long		offset;	/*	 * No longer test for cd access to directory here.  If the	 * directory is readable, then we should be able to read it,	 * regardless of the search perms of the directory.  (This is the	 * way the UFS behaves.)	 */	if (!pvp->v_dir_valid) {		last_pvp = NULL;	}	if (result = validate_directory(pvp)) {		return (result);	}	if ((pvp == last_pvp) && (rda->rda_offset == last_offset)) {		vp = last_vp;	} else {		last_pvp = pvp;		last_offset = rda->rda_offset;		vp = CHILD_VNODE(pvp);		if (vp != NULL && vp->v_whited_out) {			vp = next_file(vp);		}		/*		 * '.' and '..' are at offsets 1 and 2.		 */		offset = 3;		while ((vp != NULL) && (offset <= last_offset)) {			vp = next_file(vp);			offset++;		}	}	rd->rd_bufsize = rda->rda_count;#ifdef SUN_OS_4	rd->rd_entries = (struct dirent *) read_result_buffer;#else	rd->rd_entries = (struct direct *) read_result_buffer;#endif	buf_base = read_result_buffer;	buf_size = 0;	/*	 * Leave 1000 bytes free in result buffer so that UDP buffer won't	 * overflow when XDR adds stuff later.	 */	buf_maxcount = rd->rd_bufsize - 1000;	if (last_offset == 0) {		(void) add_entry(pvp->v_fhid, ".");		(void) add_entry((PARENT_VNODE(pvp))->v_fhid, "..");	}	while (vp != NULL) {		if (vp->v_layer != INVALID_LAYER) {			if (!add_entry(vp->v_fhid, vp->v_name)) {				break;			}			vp = next_file(vp);		} else {			next_vp = next_file(vp);			vnode_tree_release(vp);			vp = next_vp;		}	}	rd->rd_size = buf_size;	rd->rd_offset = last_offset;	rd->rd_eof = (vp == NULL);	last_vp = vp;	return (0);}/* * Add one entry to the readdir result buffer with the specified file # and * name.  Returns TRUE if the entry fits in the result buffer. */static bool_tadd_entry(nodeid, name)	long		nodeid;	char		*name;{	struct udirect	*udp;	int		len;	int		reclen;	len = strlen(name);	reclen = UENTRYSIZ(len);	if (buf_size + reclen >= buf_maxcount) {		return (FALSE);	}	udp = (struct udirect *) buf_base;	udp->d_fileno = nodeid;	strcpy(udp->d_name, name);	udp->d_namlen = len;	udp->d_reclen = reclen;	udp->d_offset = ++last_offset;	buf_size += reclen;	buf_base += reclen;	return (TRUE);}/* * Validate the directory with vnode 'vp'.  Returns 0 on success, a positive * error code if an error occurred. */intvalidate_directory(vp)	struct vnode	*vp;{	int	result = 0;		if (vp->v_pnode->p_swapped) {		swap_in_directory(vp->v_pnode);	} else if (vp->v_pnode->p_in_queue) {		swqueue_use_pnode(vp->v_pnode);	}	if (!vp->v_back_owner && vp->v_dir_valid) {		struct pnode	*pp;		long		time;		time = get_current_time(FALSE);		for (pp = vp->v_pnode; pp != NULL;		     pp = get_next_pnode(vp, pp)) {			if (pp->p_expire <= time) {				char		name[MAXNAMLEN];				struct stat	statb;				ptoname_or_pn(pp, name);				if (stat(name, &statb) < 0) {					return (errno);				}				if (pp->p_mtime != statb.st_mtime) {					if (pp != vp->v_pnode) {						update_ctime(vp, FALSE);					}					vp->v_dir_valid = FALSE;					break;				} else {					set_expire_time(pp);				}			}		}	}	if (!vp->v_dir_valid) {		result = readdir_vnodes(vp);		clear_visited_pnodes();		return result;	} else {		return (0);	}}/* * Build child vnodes and directory pnodes for directory 'pvp'. */static intreaddir_vnodes(pvp)	struct vnode	*pvp;{	struct vnode	*vp;	struct pnode	*pp;	struct pnode	*prev_pp = NULL;	struct pnode	*front_pnodes[MAX_SUB_LAYER + 1];	Nse_list	backlists[MAX_SUB_LAYER + 1];	Nse_whiteout	wp;	int		layer = 0;	bool_t		rename_recovered = FALSE;	int		result = 0;	for (vp = CHILD_VNODE(pvp); vp != NULL; vp = NEXT_VNODE(vp)) {		vp->v_layer = INVALID_LAYER;		vp->v_back_layer = INVALID_LAYER;		vp->v_whited_out = FALSE;		vp->v_back_whited_out = FALSE;		vp->v_mtime = 0;		if (vp->v_pnode != NULL && vp->v_pnode->p_type != PTYPE_DIR) {			release_pnodes(vp);		}	}	if (pvp->v_layer == 0) {		if (vp = matching_vnode(pvp)) {			copy_vnodes_and_pnodes(vp, pvp);			pvp->v_dir_valid = TRUE;			return (0);		}	} else if (result = promote_file(pvp)) {		/*		 * Always promote the directory to the front-most writeable		 * layer.  If there is at least one read-only layer, we		 * need to promote the directory to hold a .tfs_backfiles		 * file.  If there is no read-only layer, we still want the		 * directory to exist in all the writeable layers.		 */		return (result);	}	/*	 * If there is more than one pnode for this directory (because the	 * directory was just promoted or swapped in,) release all but the	 * front one, as the rest will be built below.	 */	release_back_pnodes(pvp);	pp = pvp->v_pnode;	if (!pvp->v_back_owner) {		char		name[MAXNAMLEN];		struct stat	statb;		ptoname_or_pn(pp, name);		if (stat(name, &statb) < 0) {			return (errno);		}		pp->p_mtime = statb.st_mtime;		set_expire_time(pp);	}	bzero((char *) front_pnodes, sizeof front_pnodes);	do {		/*		 * If the user doesn't own files showing through from		 * read-only filesystems, don't use .tfs_backfiles.		 * Otherwise, read the backfiles after reading all the		 * writeable sub-layers.		 */		if (front_pnodes[pp->p_sub_layer] == NULL) {			front_pnodes[pp->p_sub_layer] = pp;		} else if (pvp->v_back_owner) {			break;		}		if (!readdir_vnodes_one_layer(pvp, pp, layer)) {			return (errno);		}		if (prev_pp != NULL) {			set_next_pnode(pvp, prev_pp, pp, layer - 1);		}		prev_pp = pp;		pp = follow_searchlink(pp, pvp->v_environ_id, FIRST_SUBL(pvp),				       &wp, &rename_recovered);		create_whiteout_vnodes(pvp, layer, wp);		nse_dispose_whiteout(wp);		if (rename_recovered) {			return (readdir_vnodes(pvp));		}		layer++;	} while (pp != NULL);	if (pp != NULL) {		bzero((char *) backlists, sizeof backlists);		if (read_and_verify_backlists(front_pnodes, pp, backlists)) {			free_pnode(pp);		} else if (result = build_backlists(front_pnodes, pp,					FIRST_SUBL(pvp), pvp->v_environ_id,					backlists)) {			destroy_backlists(backlists);			return (result);		}		readdir_backlists(pvp, prev_pp, backlists, layer - 1);		destroy_backlists(backlists);	} else {		set_next_pnode(pvp, prev_pp, (struct pnode *) NULL, layer - 1);	}	pvp->v_dir_valid = TRUE;	/*	 * Put the new directory in the swap queue only if it has more	 * than one child.	 */	if (pvp->v_back_owner && !pvp->v_pnode->p_in_queue) {		if ((vp = CHILD_VNODE(pvp)) && NEXT_VNODE(vp)) {			swqueue_add_pnode(pvp->v_pnode);		}	}	return (0);}/* * 'vp' is a directory vnode with only one pnode.  Determine if there * is another vnode for the same environment which has the same front * pnode as vp.  If there is, return that vnode. */static struct vnode *matching_vnode(vp)	struct vnode	*vp;{	struct vnode	*vnodes[MAX_NAMES];	bzero((char *) vnodes, sizeof vnodes);	get_vnodes(vp->v_pnode, vnodes);	if (vnodes[0] && vnodes[0]->v_dir_valid &&	    vnodes[0]->v_environ_id == vp->v_environ_id) {		/*		 * Note that vnodes[0] will not have the correct environ_id		 * if this directory does not exist yet in the front		 * sub-layer.		 */		return (vnodes[0]);	}	return (NULL);}/* * Setup vnode 'new_vp' to have the same pnodes and child vnodes as the * vnode 'old_vp'.  The child vnodes are all created with different * nodeid's from those of the original child vnodes. */static voidcopy_vnodes_and_pnodes(old_vp, new_vp)	struct vnode	*old_vp;	struct vnode	*new_vp;{	struct pnode	*pp;	struct pnode	*next_pp;	int		layer = 0;	struct vnode	*vp;	struct vnode	*nvp;	/*	 * Copy directory pnodes	 */	release_back_pnodes(new_vp);	pp = new_vp->v_pnode;	next_pp = get_next_pnode(old_vp, old_vp->v_pnode);	while (next_pp != NULL) {		next_pp->p_refcnt++;		set_next_pnode(new_vp, pp, next_pp, layer);		layer++;		pp = next_pp;		next_pp = get_next_pnode(old_vp, next_pp);	}	set_next_pnode(new_vp, pp, (struct pnode *) NULL, layer);	/*	 * Copy child vnodes	 */	for (vp = CHILD_VNODE(old_vp); vp != NULL; vp = NEXT_VNODE(vp)) {		nvp = create_child_vnode(new_vp, vp->v_name,					 (int) vp->v_layer, vp->v_mtime);		nvp->v_whited_out = vp->v_whited_out;		nvp->v_back_layer = vp->v_back_layer;		nvp->v_back_whited_out = vp->v_back_whited_out;	}}/* * Read directory entries from one layer.  Creates vnodes for all files * seen in this layer. */static bool_treaddir_vnodes_one_layer(pvp, pp, layer)	struct vnode	*pvp;	struct pnode	*pp;	int		layer;{	DIR		*dirp;	struct direct	*dp;	dirp = tfs_opendir(pp);	if (dirp == NULL) {		return (FALSE);	}	dp = readdir(dirp);	while (dp != NULL) {		if (good_name(dp->d_name)) {			(void) create_child_vnode(pvp, dp->d_name, layer,						  (long) 0);		}		dp = readdir(dirp);	}	tfs_closedir(dirp);	return (TRUE);}/* * 'front_pnodes', an array indexed by sub-layer #, contains the pnodes * of all the writeable sub-layers.  Read in the backlist for each * of the writeable sub-layers into 'backlists', which is an array of * backlists indexed by sub-layer #.  Returns TRUE if the backlists are * valid. * 'ro_pp' is the first read-only pnode. */static bool_tread_and_verify_backlists(front_pnodes, ro_pp, backlists)	struct pnode	**front_pnodes;	struct pnode	*ro_pp;	Nse_list	*backlists;{	char		pn[MAXPATHLEN];	int		i;	Filelist	fl;	for (i = 0; i <= MAX_SUB_LAYER; i++) {		if (front_pnodes[i]) {			backlists[i] = read_backlist(front_pnodes[i]);			if (backlists[i] == NULL) {				goto error;			}		}	}	fl = (Filelist) nse_list_search(backlists[ro_pp->p_sub_layer],					backlist_is_dir);	ptopn(ro_pp, pn);	if (fl != NULL && fl->layer == 1 && NSE_STREQ(pn, fl->fname)) {		return TRUE;	}error:	destroy_backlists(backlists);	return FALSE;}/* * Build .tfs_backfiles files for all sub-layers of the directory whose * first read-only layer is 'pp'.  Read in the directory entries for all * sub-layers of the first read-only layer, and then use the backfiles * of these sub-layers to finish building the backfiles.  If there aren't * backfiles in the first read-only layer, then recursively build them. */static intbuild_backlists(front_pnodes, pp, first_sub_layer, environ_id, backlists)	struct pnode	**front_pnodes;	struct pnode	*pp;	unsigned	first_sub_layer;	unsigned	environ_id;	Nse_list	*backlists;{	struct pnode	*ro_pnodes[MAX_SUB_LAYER + 1];	Hash		backhashs[MAX_SUB_LAYER + 1];	Nse_list	ro_backlists[MAX_SUB_LAYER + 1];	Nse_whiteout	wp;	int		sub_layer;	int		last_sub_layer = -1;	int		i;	int		result = 0;#ifdef TFSDEBUG	dprint(tfsdebug, 3, "build_backlists()\n");#endif TFSDEBUG	bzero((char *) ro_pnodes, sizeof ro_pnodes);	bzero((char *) ro_backlists, sizeof ro_backlists);	for (i = 0; i <= MAX_SUB_LAYER; i++) {		backhashs[i] = init_dir_hash();		backlists[i] = filelist_create();	}	do {		sub_layer = pp->p_sub_layer;		if (ro_pnodes[sub_layer] == NULL &&		    sub_layer > last_sub_layer) {			ro_pnodes[sub_layer] = pp;		} else {			break;		}		last_sub_layer = sub_layer;		ro_backlists[sub_layer] = read_backlist(pp);		if (!build_backlist_one_layer(pp, sub_layer, backhashs,					      backlists[sub_layer])) {			result = errno;			goto error;		}		add_dir_to_backlist(pp, backlists[sub_layer]);		pp = follow_searchlink(pp, environ_id, first_sub_layer, &wp,				       (bool_t *) NULL);		insert_whiteout_into_hash(backhashs[sub_layer], wp);		nse_dispose_whiteout(wp);	} while (pp != NULL);	if (pp != NULL) {		if (!have_all_ro_backlists(ro_pnodes, ro_backlists,					   first_sub_layer)) {			destroy_backlists(ro_backlists);			bzero((char *) ro_backlists, sizeof ro_backlists);			if (result = build_backlists(ro_pnodes, pp,						first_sub_layer, environ_id,						ro_backlists)) {				goto error;			}		} else {			free_pnode(pp);		}		copy_backlists(backlists, backhashs, ro_backlists,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -