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

📄 tfs_backlink.c

📁 操作系统SunOS 4.1.3版本的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
#ifndef lintstatic char sccsid[] = "@(#)tfs_backlink.c 1.1 92/07/30 Copyr 1988 Sun Micro";#endif/* * Copyright (c) 1988 Sun Microsystems, Inc. */#include <nse/param.h>#include <nse/util.h>#include "headers.h"#include "vnode.h"#include "tfs.h"#include "subr.h"#include "tfs_lists.h"#include <nse/searchlink.h>/* * Routines to remove and rename directories.  These routines remove/rename * the directory in *all* variants, using the backlinks in .tfs_info to * determine the front layer in each variant.  Renaming a directory can * potentially be a long-running operation, since all the searchlinks and * backlinks of sub-directories have to be renamed.  Therefore, the old and * new name of the directory being renamed are recorded, to allow * completion of the rename later should the tfsd fail to finish the rename * (either because the tfsd is killed or the machine crashes.) * * The following rename records are written, to allow partially completed * directory renames to be recovered: * * !TFS_RENAME1 old_pattern new_pattern *	Written into the source parent directory in the shared sub-layer. *	'old_pattern' and 'new_pattern' can be fed to replace_substring() *	to determine the new directory name from the old name. * * !TFS_RENAME2 shared_path *	Written into the source parent directories in the front sub-layers. *	Also written into the destination parent directory, if the directory *	is being renamed into a different parent directory.  This record *	points to the directory containing the !TFS_RENAME1 record. */int		remove_directory();static int	bl_verify_dir_empty();static int	verify_dir_empty();static int	bl_physical_rmdir();static int	physical_rmdir();static void	remove_tfs_file();int		rename_directory();int		finish_rename_directory();static int	finish_rename_dir();int		whiteout_other_dirs();static int	bl_whiteout();static int	get_backlinks();static int	bl_rename_dir();static int	rename_shared_dir();static int	recursive_directory_op();static int	rename_searchlink();static int	rename_backlinks();static int	create_parent_dir();static int	clear_all_rename_records();static int	bl_clear_rename_record();static int	set_rename_record();static int	clear_rename_record();Nse_whiteout	bl_list_get_rename_elem();static void	bl_list_remove_elem();static void	replace_substring();static char	*common_suffix();static int	update_backlinks();int		exists_in_variant();static int	bl_verify_no_variant();/* * Remove the directory with vnode 'vp'.  This routine returns 0 if the * directory is successfully removed, a positive error code otherwise. */intremove_directory(vp)	struct vnode	*vp;{	struct pnode	*pp;	char		searchlink[MAXPATHLEN];	Nse_list	backlinks;	int		result;	if (result = validate_directory(vp)) {		return result;	}	pp = vp->v_pnode;	while (pp->p_sub_layer < MAX_SUB_LAYER) {		pp = get_next_pnode(vp, pp);	}	if ((result = change_to_dir(PARENT_PNODE(pp))) ||	    (result = get_backlinks(pp->p_name, searchlink, &backlinks, pp))) {		return result;	}	if (nse_list_nelems(backlinks) == 0 && pp != vp->v_pnode) {		vtovn(vp, searchlink);		nse_log_message(	    "warning: can't remove directory %s, need Version 2 .tfs_info\n",			searchlink);		result = EACCES;		goto error;	}	if ((result = (int) nse_list_iterate_or(backlinks,						bl_verify_dir_empty)) ||	    (result = verify_dir_empty(pp, (char *) NULL,				       (struct vnode **) NULL)) ||	    (result = (int) nse_list_iterate_or(backlinks,						bl_physical_rmdir)) ||	    (result = physical_rmdir(pp))) {		goto error;	}	result = update_directory(PARENT_PNODE(pp), pp->p_name,				  DIR_REMOVE_FILE, FALSE, TRUE, NULL);error:	nse_list_destroy(backlinks);	return result;}static intbl_verify_dir_empty(bp)	Backlink	bp;{	return verify_dir_empty(bp->pnode, bp->varname, &bp->dummy_vnode);}static intverify_dir_empty(pp, varname, dummy_vpp)	struct pnode	*pp;	char		*varname;	struct vnode	**dummy_vpp;{	struct vnode	*vnodes[MAX_NAMES];	struct vnode	*vp;	struct vnode	*childvp;	int		result;	bzero((char *) vnodes, sizeof vnodes);	get_vnodes(pp, vnodes);	vp = vnodes[0];	if (vp == NULL) {		if (dummy_vpp == NULL) {			return 0;		}		vp = create_vnode((struct vnode *) NULL, "dummy", 0L);		vp->v_layer = 0;		vp->v_pnode = pp;		*dummy_vpp = vp;		/*		 * Create a tmp view so that validate_directory()		 * can follow searchlinks.		 */		if (create_tmp_view(vp, varname)) {			return ENOTEMPTY;		}	}	if (result = validate_directory(vp)) {		return result;	}	for (childvp = CHILD_VNODE(vp); childvp;	     childvp = next_file(childvp)) {		if (!childvp->v_whited_out &&		    childvp->v_layer != INVALID_LAYER) {			return ENOTEMPTY;		}	}	return 0;}static intbl_physical_rmdir(bp)	Backlink	bp;{	return physical_rmdir(bp->pnode);}static intphysical_rmdir(pp)	struct pnode	*pp;{	char		dir_name[MAXNAMLEN];	/*	 * Remove the .tfs_ files from the directory so that	 * the rmdir call will succeed.	 */	ptoname(pp, dir_name);	remove_tfs_file(dir_name, NSE_TFS_FILE);	remove_tfs_file(dir_name, NSE_TFS_BACK_FILE);	remove_tfs_file(dir_name, NSE_TFS_SWAP_FILE);	if (rmdir(dir_name) < 0) {		return (errno);	}	return (0);}static voidremove_tfs_file(path, name)	char		*path;	char		*name;{	char		tfs_name[MAXPATHLEN];	strcpy(tfs_name, path);	nse_pathcat(tfs_name, name);	(void) unlink(tfs_name);}/* * Rename the directory with vnode 'vp' to be named 'newname' in the * directory 'newpvp'. */intrename_directory(vp, newpvp, newname)	struct vnode	*vp;	struct vnode	*newpvp;	char		*newname;{	struct pnode	*pp;	struct pnode	*new_parentp;	char		str[MAXPATHLEN];	char		var[MAXPATHLEN];	Nse_list	backlinks;	Backlink	bp;	int		result;	if (result = validate_directory(vp)) {		return result;	}	pp = vp->v_pnode;	while (pp->p_sub_layer < MAX_SUB_LAYER) {		pp = get_next_pnode(vp, pp);	}	new_parentp = newpvp->v_pnode;	while (new_parentp->p_sub_layer < MAX_SUB_LAYER) {		new_parentp = get_next_pnode(newpvp, new_parentp);	}	if (result = change_to_dir(new_parentp)) {		return (result);	}	if (result = exists_in_variant(newname, var)) {		vtovn(newpvp, str);		nse_pathcat(str, newname);		nse_log_message(			"rename: %s already exists as a file in variant %s\n",				str, var);		return (ENOTDIR);	}	if ((result = change_to_dir(PARENT_PNODE(pp))) ||	    (result = get_backlinks(pp->p_name, str, &backlinks, pp))) {		return result;	}	if (nse_list_nelems(backlinks) == 0 && pp != vp->v_pnode) {		vtovn(vp, str);		nse_log_message(	"warning: can't rename directory %s, need Version 2 .tfs_info\n",			str);		result = EACCES;		goto error;	}	bp = (Backlink) nse_listelem_data(nse_list_first_elem(backlinks));    	if (result = update_backlinks(bp, backlinks, pp, new_parentp,					  newname)) {		goto error;	}	if ((result = update_directory(PARENT_PNODE(pp), pp->p_name,				DIR_RENAME_FILE, new_parentp, newname,				FALSE, TRUE)) ||	    (result = update_directory(new_parentp, newname, DIR_ADD_FILE))) {		/*		 * Another view may have a vnode for the destination parent		 * directory but not one for the source parent directory.		 * The second call to update_directory() guarantees that		 * the destination directory gets a vnode for the new		 * (renamed) directory.		 */		goto error;	}	if (PARENT_PNODE(pp) != new_parentp ||	    !NSE_STREQ(pp->p_name, newname)) {		rename_pnode(pp, new_parentp, newname);	}error:	nse_list_destroy(backlinks);	return result;}/* * See if 'name' exists in any variant */intexists_in_variant(name, var)	char	*name;	char	*var;{	Nse_list	backlinks;	char		str[MAXPATHLEN];	int		result;		if (result = get_backlinks(".", str, &backlinks, (struct pnode *)0)) {		return result;	}	result = (int) nse_list_iterate_or(backlinks, bl_verify_no_variant,					   name, var);	nse_list_destroy(backlinks);	return result;}/* * Make sure that file 'name' does not exist in variant pointed * to by backlink 'bp'. */static intbl_verify_no_variant(bp, name, var)	Backlink	bp;	char		*name;	char		*var;{	char		path[MAXPATHLEN];	struct stat	statb;	if (bp) {		(void)strcpy(path, bp->path);		nse_pathcat(path, name);		if (lstat(path, &statb) == 0) {			strcpy(var, bp->varname);			return EEXIST;		}	}	return 0;}/* * Update all tfs_info files with search links that point to 'pp' * using backlink information from 'bp' and 'backlinks' and physically * rename 'pp' to 'new_parentp'/'newname'. */static intupdate_backlinks(bp, backlinks, pp, new_parentp, newname)	Backlink	bp;	Nse_list	backlinks;	struct pnode	*pp;	struct pnode	*new_parentp;	char		*newname;{	char		old_path[MAXPATHLEN];	char		new_path[MAXPATHLEN];	char		*old_pattern;	char		*new_pattern;	char		str[MAXPATHLEN];	char		*cp;	bool_t		same_dir;	int		result;	ptopn(pp, old_path);	ptopn(new_parentp, new_path);	nse_pathcat(new_path, newname);	/*	 * If there was no .tfs_info file, and hence no backlink information	 * just do the rename.	 */	if (bp == NULL) {		if (rename(old_path, new_path) == -1) {			return errno;		}		return 0;	}	old_pattern = common_suffix(old_path, bp->path);	new_pattern = &new_path[nse_find_substring(old_path, old_pattern)				- old_path];	sprintf(str, "%s1 %s %s", NSE_TFS_RENAME_STR, old_pattern,		new_pattern);	if (result = set_rename_record(".", str)) {		return result;	}	same_dir = (new_parentp == PARENT_PNODE(pp));	if (!same_dir) {		sprintf(str, "%s2 %s", NSE_TFS_RENAME_STR, old_path);		*rindex(str, '/') = '\0';		cp = rindex(new_path, '/');		*cp = '\0';		result = set_rename_record(new_path, str);		*cp = '/';		if (result) {			return result;		}	}	if ((result = (int) nse_list_iterate_or(backlinks, bl_rename_dir,						old_path, old_pattern, new_pattern,						same_dir)) ||	    (result = rename_shared_dir(pp, new_path, old_pattern,					new_pattern, same_dir)) ||	    (result = clear_all_rename_records(PARENT_PNODE(pp), new_parentp,					       old_pattern, new_pattern, backlinks,					       FALSE))) {		return result;	}	return 0;}/* * Finish a partially-completed directory rename.  (The rename wasn't * completed because the machine went down in the middle of it, for * example.)  'path' is the name of the parent directory of the directory * being renamed. */intfinish_rename_directory(path, rename_entry)	char		*path;	char		*rename_entry;{	char		*cp;	char		type;	Nse_whiteout	bl;	Nse_whiteout	bl_rename;	int		result = 0;	cp = rename_entry + strlen(NSE_TFS_RENAME_STR);	type = *cp++;	switch (type) {	case '1':		result = finish_rename_dir(path, cp);		break;	case '2':		cp++;		if (result = tfsd_get_backlink(cp, &bl)) {			return result;		}		bl_rename = bl_list_get_rename_elem(bl);		if (bl_rename) {			result = finish_rename_directory(cp, bl_rename->name);		} else {			result = clear_rename_record(path);		}		nse_dispose_whiteout(bl);		break;	}	return result;}static intfinish_rename_dir(path, rename_entry)	char		*path;	char		*rename_entry;{	struct pnode	*pp;	struct pnode	*new_parentp;	char		old_path[MAXPATHLEN];	char		new_path[MAXPATHLEN];	char		old_pattern[MAXNAMLEN];	char		new_pattern[MAXNAMLEN];	char		searchlink[MAXPATHLEN];	char		*cp;	bool_t		same_dir;	Nse_list	backlinks = NULL;	int		result;	struct stat	statb;	sscanf(rename_entry, "%s %s", old_pattern, new_pattern);	strcpy(old_path, path);	nse_pathcat(old_path, rindex(old_pattern, '/') + 1);	pp = path_to_pnode(old_path, MAX_SUB_LAYER);	replace_substring(old_path, old_pattern, new_pattern, new_path);	cp = rindex(new_path, '/');	*cp = '\0';	same_dir = NSE_STREQ(path, new_path);	if (!same_dir) {		new_parentp = path_to_pnode(new_path, MAX_SUB_LAYER);	} else {		new_parentp = PARENT_PNODE(pp);	}	*cp = '/';	if (stat(old_path, &statb) == 0) {		/*		 * If the old name still exists, complete the rename		 */		if (result = get_backlinks(old_path, searchlink, &backlinks,					   (struct pnode *) NULL)) {			goto error;		}		if ((result = (int) nse_list_iterate_or(backlinks,					bl_rename_dir, old_path, old_pattern,					new_pattern, same_dir)) ||		    (result = rename_shared_dir(pp, new_path, old_pattern,						new_pattern, same_dir))) {			goto error;		}		nse_list_destroy(backlinks);		backlinks = NULL;	}	/*	 * Necessary to get the backlinks again even if they've already	 * been read, because the backlinks may have pointed to invalid	 * directories if the tfsd crashed after some or all of the front	 * layers were renamed but before the backlinks were renamed.	 */	if (result = get_backlinks(new_path, searchlink, &backlinks,				   (struct pnode *) NULL)) {		goto error;	}	result = clear_all_rename_records(PARENT_PNODE(pp), new_parentp,					  old_pattern, new_pattern,					  backlinks, TRUE);error:	if (backlinks) {		nse_list_destroy(backlinks);	}	if (!same_dir) {		free_pnode(new_parentp);	}	free_pnode(pp);	return result;}/* * Whiteout the file named 'name' in all directories, except directory * 'exclude_pp', which have searchlinks pointing to directory 'shared_pp'. * Needed for tfs_pull(). */intwhiteout_other_dirs(shared_pp, name, exclude_pp)	struct pnode	*shared_pp;	char		*name;	struct pnode	*exclude_pp;{	char		searchlink[MAXPATHLEN];	Nse_list	backlinks;	int		result;	if ((result = change_to_dir(PARENT_PNODE(shared_pp))) ||

⌨️ 快捷键说明

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