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

📄 tfs_fd.c

📁 操作系统SunOS 4.1.3版本的源码
💻 C
字号:
#ifndef lintstatic char sccsid[] = "@(#)tfs_fd.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 "subr.h"#include "tfs.h"#include <nse/util.h>/*  * File caching routines *//* * File descriptor cache entry. */struct tfd {	struct pnode	*pnode;	int		flags;	short		prev;	short		next;};static struct tfd *tfd_table;static short	tfd_first = -1;static short	tfd_last = -1;static short	tfd_max;static short	tfd_count = 0;static int	current_fd;extern int	chmod();extern int	fchmod();DIR            *tfs_opendir();void            tfs_closedir();int		get_rw_fd();int             open_fd();void		close_fd();int		rdwr_fd();void            use_fd();int             get_open_fd_flags();static void     enqueue_fd();static void     dequeue_fd();int		init_fd_cache();int		change_to_dir();static int	tfs_fchdir();#ifdef TFSDEBUGvoid		tfs_getwd();#endif TFSDEBUG/* * Special versions of the opendir() and closedir() library routines which * make use of the TFS file descriptor cache to save the fd of the directory. *//* * open a directory. */DIR            *tfs_opendir(pp)	struct pnode   *pp;{	static DIR	dir_desc;	/* Only tfs_readdir calls this, so					 * this is safe for now. */	int             fd;	if (pp->p_type != PTYPE_DIR) {		errno = ENOTDIR;		return (NULL);	}	fd = pp->p_fd;	if (fd != 0) {		use_fd(fd);		(void) lseek(fd, (long) 0, L_SET);	} else {		fd = open_fd(pp, 0, 0);		if (fd == -1) {			return (NULL);		}	}	BZERO((char *) &dir_desc, sizeof(DIR));	dir_desc.dd_buf = readdir_buffer;	dir_desc.dd_bsize = NFS_MAXDATA;	dir_desc.dd_fd = fd;	return (&dir_desc);}/* * close a directory. */voidtfs_closedir(dirp)	DIR            *dirp;{	dirp->dd_fd = -1;	dirp->dd_loc = 0;}/* * Get file descriptor to read/write.  Returns fd, or -1 if an error occurs. */intget_rw_fd(vp, rw)	struct vnode	*vp;	enum uio_rw	rw;{	struct pnode	*pp;	int             fd;	int             openflags;	int		prevflags;	struct nfsfattr attrs;	pp = vp->v_pnode;	openflags = (rw == UIO_READ) ? O_RDONLY : O_RDWR;	fd = pp->p_fd;	if (fd != 0) {		prevflags = get_open_fd_flags(fd);		if ((prevflags != openflags) && (prevflags != O_RDWR)) {			close_fd(pp);			/*			 * We have now seen both reads & writes on this file,			 * so open it read/write for the duration.			 */			openflags = O_RDWR;		} else {			return (fd);		}	}	fd = open_fd(pp, openflags, 0);	if (fd >= 0 || errno != EACCES) {		return (fd);	}	if (getattrs_of(vp, &attrs) < 0) {		errno == EACCES;		return (-1);	}	if (vp->v_created && attrs.na_uid == current_user_id()) {		/*		 * If the open fails, and this file was created by the TFS,		 * then assume that the user created the file with		 * insufficient perms for read or write, and then the fd		 * was later closed (by a tfs_flush, say).  Chmod the file		 * temporarily so that the user can open it.		 */		if (modify_file(pp, chmod, fchmod, 0744) != 0) {			tfsd_perror("tfsd: warning: get_rw_fd: chmod");			return (-1);		}		fd = open_fd(pp, openflags, 0);		(void) modify_file(pp, chmod, fchmod, (int) attrs.na_mode);		return (fd);	} else if (rw == UIO_READ && has_access(&attrs, X_OK)) {		/*		 * If the open fails and the user is trying to read a		 * file that is executable, assume that the user is		 * trying to execute the file and open an fd.		 */		change_user_id(0);		fd = open_fd(pp, openflags, 0);		change_user_id(current_user_id());		return (fd);	}	errno = EACCES;	return (-1);}/* * Make a tfd entry in the file descriptor cache.  Returns fd or -1 if error */intopen_fd(pp, flags, mode)	struct pnode   *pp;	int             flags, mode;{	char		pn[MAXPATHLEN];	int		fd;	/* if there are no available tfds, close the lru */	if (tfd_count >= tfd_max) {		close_fd(tfd_table[tfd_first].pnode);	}	ptoname_or_pn(pp, pn);	if ((fd = open(pn, flags, mode)) < 0) {		return (-1);	}	/* add tfd to end of list */	tfd_table[fd].pnode = pp;	tfd_table[fd].flags = flags & 03;	enqueue_fd(fd);	pp->p_fd = fd;	if (pp->p_type == PTYPE_REG) {		pp->p_offset = 0;	}	return (fd);}/* * Close the file descriptor refered to by physical node 'pp'. * The close may fail with ENOSPC if the file is on a full network * file system and delayed writes are pending. Anything else indicates * a serious error. */voidclose_fd(pp)	struct pnode	*pp;{	int		fd = pp->p_fd;	if (pp->p_needs_write) {		sync_wcache(pp);	}	if (close(fd) < 0) {		if (errno != ENOSPC) {			nse_log_message("panic: can't close cached fd #%d",fd);			tfsd_perror("");			panic(pp);			/* NOTREACHED */		}		pp->p_write_error = ENOSPC;	}	pp->p_fd = 0;	dequeue_fd(fd);	if (fd == current_fd) {		current_fd = 0;		(void) chdir("/");	}}/* * Read/write file with pnode 'pp' at 'offset'.  Don't lseek unless it's * necessary. */intrdwr_fd(pp, buf, length, offset, rw)	struct pnode	*pp;	char		*buf;	int		length;	long		offset;	enum uio_rw	rw;{	int		count;	if (offset != pp->p_offset) {		pp->p_offset = offset;		if (lseek((int) pp->p_fd, offset, L_SET) < 0) {			close_fd(pp);			return (-1);		}	}	if (rw == UIO_READ) {		count = read((int) pp->p_fd, buf, length);	} else {		count = write((int) pp->p_fd, buf, length);	}	if (count >= 0) {		pp->p_offset += count;	} else {		pp->p_offset = -1;	}	return (count);}voiduse_fd(fd)	int             fd;{	if (tfd_last != fd) {		dequeue_fd(fd);		enqueue_fd(fd);	}}intget_open_fd_flags(fd){#ifdef TFSDEBUG	if (fd == 0) {		printf("get_fd_flags: fd == 0?\n");	}#endif TFSDEBUG	return (tfd_table[fd].flags);}static voidenqueue_fd(fd)	int             fd;{	tfd_table[fd].prev = tfd_last;	tfd_table[fd].next = -1;	if (tfd_last >= 0) {		tfd_table[tfd_last].next = fd;	}	if (tfd_first < 0) {		tfd_first = fd;	}	tfd_last = fd;	tfd_count++;}static voiddequeue_fd(fd)	int             fd;{	if (fd == tfd_first) {		tfd_first = tfd_table[fd].next;		if (tfd_first == -1) {			/* Have dequeued the only entry in the queue */			tfd_last = -1;		} else {			tfd_table[tfd_first].prev = -1;		}	} else if (fd == tfd_last) {		tfd_last = tfd_table[fd].prev;		tfd_table[tfd_last].next = -1;	} else {		tfd_table[tfd_table[fd].prev].next = tfd_table[fd].next;		tfd_table[tfd_table[fd].next].prev = tfd_table[fd].prev;	}	tfd_count--;}intinit_fd_cache(){	int		nfds;	nfds = getdtablesize();	tfd_table = (struct tfd *) nse_calloc((unsigned) nfds,					      sizeof(struct tfd));	tfd_max = nfds - 10;}#ifdef TFSDEBUGprint_fd_cache(){	char		pn[MAXPATHLEN];	int		fd;	dprint(0, 0, "fd cache:\n");	fd = tfd_last;	while (fd != -1) {		ptopn(tfd_table[fd].pnode, pn);		dprint(0, 0, "  %3d  (%s)\n", fd, pn);		fd = tfd_table[fd].prev;	}}#endif TFSDEBUG/* * chdir to the directory with pnode 'pp'. */intchange_to_dir(pp)	struct pnode	*pp;{	int		numtries = 0;again:	if (pp->p_fd == 0) {		if (open_fd(pp, O_RDONLY, 0) < 0) {			return (errno);		}	}	if (tfs_fchdir((int) pp->p_fd) < 0) {		numtries++;		if (numtries == 2) {			return (errno);		}		close_fd(pp);		goto again;	}	return (0);}static inttfs_fchdir(fd)	int		fd;{	use_fd(fd);	if (fd != current_fd) {		current_fd = fd;		if (nse_fchdir(fd) != 0) {			return (-1);		}	}	return (0);}#ifdef TFSDEBUGvoidtfs_getwd(path)	char		*path;{	if (current_fd != 0) {		ptopn(tfd_table[current_fd].pnode, path);	} else {		path[0] = '\0';	}}#endif TFSDEBUG/* Avoid SunOs 4.0 close bug by redefining 'close' and checking for * spurious value of errno. This can be removed as soon as nobody in * the world is running SunOs 4.0. */#include <syscall.h>intclose(fd)	int fd;{	extern int	errno;	int		saved_errno = errno;	int		ret;		if ((ret = syscall(SYS_close, fd)) < 0) {		if (errno < 0) {			errno = saved_errno;			return 0;		}	}	return ret;}

⌨️ 快捷键说明

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