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

📄 nfs.c

📁 newos is new operation system
💻 C
📖 第 1 页 / 共 2 页
字号:
/*** Copyright 2002, Travis Geiselbrecht. All rights reserved.** Distributed under the terms of the NewOS License.*/#include <kernel/kernel.h>#include <kernel/vfs.h>#include <kernel/heap.h>#include <kernel/debug.h>#include <kernel/lock.h>#include <kernel/sem.h>#include <kernel/vm.h>#include <kernel/net/misc.h>#include <newos/net.h>#include <string.h>#include <ctype.h>#include <stdlib.h>#include "nfs.h"#include "nfs_fs.h"#include "rpc.h"#define NFS_TRACE 0#if NFS_TRACE#define TRACE(x...) dprintf(x)#else#define TRACE(x...)#endifstatic int nfs_getattr(nfs_fs *nfs, nfs_vnode *v, nfs_attrstat *attrstat);#if NFS_TRACEstatic void dump_fhandle(fhandle *handle){	unsigned int i;	for(i=0; i<sizeof(fhandle); i++)		dprintf("%02x", ((uint8 *)handle)[i]);}#endifstatic nfs_vnode *new_vnode_struct(nfs_fs *fs){	nfs_vnode *v;	v = (nfs_vnode *)kmalloc(sizeof(nfs_vnode));	if(!v)		return NULL;	v->sem = sem_create(1, "nfs vnode sem");	if(v->sem < 0) {		kfree(v);		return NULL;	}	v->fs = fs;	return v;}static void destroy_vnode_struct(nfs_vnode *v){	sem_delete(v->sem);	kfree(v);}/* ghetto x.x.x.x:/path parsing code */static int parse_mount(const char *mount, char *address, int address_len, char *server_path, int path_len){	int a, b;	// trim the beginning	for(a = 0; mount[a] != 0 && isspace(mount[a]); a++)		;	if(mount[a] == 0)		return ERR_NOT_FOUND;	// search for the ':'	for(b = a; mount[b] != 0 && mount[b] != ':'; b++)		;	if(mount[b] == 0)		return ERR_NOT_FOUND;	// copy the address out	memcpy(address, &mount[a], b - a);	address[b - a] = 0;	// grab the path	strcpy(server_path, &mount[b+1]);	return NO_ERROR;}static int parse_ipv4_addr_str(ipv4_addr *ip_addr, char *ip_addr_string){	int a, b;	*ip_addr = 0;	// walk through the first number	a = 0;	b = 0;	for(; ip_addr_string[b] != 0 && ip_addr_string[b] != '.'; b++)		;	if(ip_addr_string[b] == 0)		return ERR_NOT_FOUND;	ip_addr_string[b] = 0;	*ip_addr = atoi(&ip_addr_string[a]) << 24;	b++;	// second digit	a = b;	for(; ip_addr_string[b] != 0 && ip_addr_string[b] != '.'; b++)		;	if(ip_addr_string[b] == 0)		return ERR_NOT_FOUND;	ip_addr_string[b] = 0;	*ip_addr |= atoi(&ip_addr_string[a]) << 16;	b++;	// third digit	a = b;	for(; ip_addr_string[b] != 0 && ip_addr_string[b] != '.'; b++)		;	if(ip_addr_string[b] == 0)		return ERR_NOT_FOUND;	ip_addr_string[b] = 0;	*ip_addr |= atoi(&ip_addr_string[a]) << 8;	b++;	// last digit	a = b;	for(; ip_addr_string[b] != 0 && ip_addr_string[b] != '.'; b++)		;	ip_addr_string[b] = 0;	*ip_addr |= atoi(&ip_addr_string[a]);	return NO_ERROR;}static int nfs_mount_fs(nfs_fs *nfs, const char *server_path){	struct mount_args args;	char buf[128];	int err;	memset(&args, sizeof(args), 0);	strlcpy(args.dirpath, server_path, sizeof(args.dirpath));	args.len = htonl(strlen(args.dirpath));	rpc_set_port(&nfs->rpc, MOUNTPORT);	err = rpc_call(&nfs->rpc, MOUNTPROG, MOUNTVERS, MOUNTPROC_MNT, &args, ntohl(args.len) + 4, buf, sizeof(buf));	if(err < 0)		return err;#if NFS_TRACE	TRACE("nfs_mount_fs: have root fhandle: ");	dump_fhandle((fhandle *)&buf[4]);	TRACE("\n");#endif	// we should have the root handle now	memcpy(&nfs->root_vnode->nfs_handle, &buf[4], sizeof(nfs->root_vnode->nfs_handle));	return 0;}static int nfs_unmount_fs(nfs_fs *nfs){	struct mount_args args;	int err;	memset(&args, sizeof(args), 0);	strlcpy(args.dirpath, nfs->server_path, sizeof(args.dirpath));	args.len = htonl(strlen(args.dirpath));	rpc_set_port(&nfs->rpc, MOUNTPORT);	err = rpc_call(&nfs->rpc, MOUNTPROG, MOUNTVERS, MOUNTPROC_UMNT, &args, ntohl(args.len) + 4, NULL, 0);	return err;}int nfs_mount(fs_cookie *fs, fs_id id, const char *device, void *args, vnode_id *root_vnid){	nfs_fs *nfs;	int err;	char ip_addr_str[128];	ipv4_addr ip_addr;	TRACE("nfs_mount: fsid 0x%x, device '%s'\n", id, device);	/* create the fs structure */	nfs = kmalloc(sizeof(nfs_fs));	if(!nfs) {		err = ERR_NO_MEMORY;		goto err;	}	memset(nfs, 0, sizeof(nfs_fs));	mutex_init(&nfs->lock, "nfs lock");	err = parse_mount(device, ip_addr_str, sizeof(ip_addr_str), nfs->server_path, sizeof(nfs->server_path));	if(err < 0) {		err = ERR_NET_BAD_ADDRESS;		goto err1;	}	err = parse_ipv4_addr_str(&ip_addr, ip_addr_str);	if(err < 0) {		err = ERR_NET_BAD_ADDRESS;		goto err1;	}	nfs->id = id;	nfs->server_addr = ip_addr;	// set up the rpc state	rpc_init_state(&nfs->rpc);	// connect	{		netaddr server_addr;		server_addr.type = ADDR_TYPE_IP;		server_addr.len = 4;		NETADDR_TO_IPV4(server_addr) = ip_addr;		rpc_open_socket(&nfs->rpc, &server_addr);	}	nfs->root_vnode = new_vnode_struct(nfs);	nfs->root_vnode->st = STREAM_TYPE_DIR;	// try to mount the filesystem	err = nfs_mount_fs(nfs, nfs->server_path);	if(err < 0)		goto err2;	rpc_set_port(&nfs->rpc, NFSPORT);	*fs = nfs;	*root_vnid = VNODETOVNID(nfs->root_vnode);	return 0;err2:	rpc_destroy_state(&nfs->rpc);err1:	mutex_destroy(&nfs->lock);	kfree(nfs);err:	return err;}int nfs_unmount(fs_cookie fs){	nfs_fs *nfs = (nfs_fs *)fs;	TRACE("nfs_unmount: fsid 0x%x\n", nfs->id);	// put_vnode on the root to release the ref to it	vfs_put_vnode(nfs->id, VNODETOVNID(nfs->root_vnode));	nfs_unmount_fs(nfs);	rpc_destroy_state(&nfs->rpc);	mutex_destroy(&nfs->lock);	kfree(nfs);	return 0;}int nfs_sync(fs_cookie fs){	nfs_fs *nfs = (nfs_fs *)fs;	TOUCH(nfs);	TRACE("nfs_sync: fsid 0x%x\n", nfs->id);	return 0;}int nfs_lookup(fs_cookie fs, fs_vnode _dir, const char *name, vnode_id *id){	nfs_fs *nfs = (nfs_fs *)fs;	nfs_vnode *dir = (nfs_vnode *)_dir;	int err;	TRACE("nfs_lookup: fsid 0x%x, dirvnid 0x%Lx, name '%s'\n", nfs->id, VNODETOVNID(dir), name);	sem_acquire(dir->sem, 1);	{		uint8 buf[sizeof(nfs_diropargs)];		nfs_diropargs *args = (nfs_diropargs *)buf;		nfs_diropres  *res  = (nfs_diropres  *)buf;		int namelen = min(MAXNAMLEN, strlen(name));		/* set up the args structure */		memcpy(&args->dir, &dir->nfs_handle, sizeof(args->dir));		args->name.len = htonl(namelen);		memcpy(args->name.name, name, namelen);		err = rpc_call(&nfs->rpc, NFSPROG, NFSVERS, NFSPROC_LOOKUP, args, sizeof(nfs_diropargs), buf, sizeof(buf));		if(err < 0) {			err = ERR_NOT_FOUND;			goto out;		}		/* see if the lookup was successful */		if(htonl(res->status) == NFS_OK) {			nfs_vnode *new_v;			nfs_vnode *new_v2;			/* successful lookup */#if NFS_TRACE			dprintf("nfs_lookup: result of lookup of '%s'\n", name);			dprintf("\tfhandle: "); dump_fhandle(&res->file); dprintf("\n");			dprintf("\tsize: %d\n", ntohl(res->attributes.size));#endif			new_v = new_vnode_struct(nfs);			if(new_v == NULL) {				err = ERR_NO_MEMORY;				goto out;			}			/* copy the file handle over */			memcpy(&new_v->nfs_handle, &res->file, sizeof(new_v->nfs_handle));			err = vfs_get_vnode(nfs->id, VNODETOVNID(new_v), (fs_vnode *)&new_v2);			if(err < 0) {				destroy_vnode_struct(new_v);				err = ERR_NOT_FOUND;				goto out;			}			ASSERT(new_v == new_v2);			/* figure out the stream type from the return value and cache it */			switch(ntohl(res->attributes.ftype)) {				case NFREG:					new_v->st = STREAM_TYPE_FILE;					break;				case NFDIR:					new_v->st = STREAM_TYPE_DIR;					break;				default:					new_v->st = -1;			}			*id = VNODETOVNID(new_v);		} else {			TRACE("nfs_lookup: '%s' not found\n", name);			err = ERR_NOT_FOUND;			goto out;		}	}	err = NO_ERROR;out:	sem_release(dir->sem, 1);	return err;}int nfs_getvnode(fs_cookie fs, vnode_id id, fs_vnode *v, bool r){	nfs_fs *nfs = (nfs_fs *)fs;	TOUCH(nfs);	TRACE("nfs_getvnode: fsid 0x%x, vnid 0x%Lx\n", nfs->id, id);	*v = VNIDTOVNODE(id);	return NO_ERROR;}int nfs_putvnode(fs_cookie fs, fs_vnode _v, bool r){	nfs_fs *nfs = (nfs_fs *)fs;	nfs_vnode *v = (nfs_vnode *)_v;	TOUCH(nfs);	TRACE("nfs_putvnode: fsid 0x%x, vnid 0x%Lx\n", nfs->id, VNODETOVNID(v));	destroy_vnode_struct(v);	return NO_ERROR;}int nfs_removevnode(fs_cookie fs, fs_vnode _v, bool r){	nfs_fs *nfs = (nfs_fs *)fs;	nfs_vnode *v = (nfs_vnode *)_v;	TOUCH(nfs);TOUCH(v);	TRACE("nfs_removevnode: fsid 0x%x, vnid 0x%Lx\n", nfs->id, VNODETOVNID(v));	return ERR_UNIMPLEMENTED;}static int nfs_opendir(fs_cookie _fs, fs_vnode _v, dir_cookie *_cookie){	struct nfs_vnode *v = (struct nfs_vnode *)_v;	struct nfs_cookie *cookie;	int err = 0;	TRACE(("nfs_opendir: vnode 0x%x\n", v));	if(v->st != STREAM_TYPE_DIR)		return ERR_VFS_NOT_DIR;	cookie = kmalloc(sizeof(struct nfs_cookie));	if(cookie == NULL)		return ERR_NO_MEMORY;	cookie->v = v;	cookie->u.dir.nfscookie = 0;	cookie->u.dir.at_end = false;	*_cookie = cookie;	return err;}static int nfs_closedir(fs_cookie _fs, fs_vnode _v, dir_cookie _cookie){	struct nfs_fs *fs = _fs;	struct nfs_vnode *v = _v;	struct nfs_cookie *cookie = _cookie;	TOUCH(fs);TOUCH(v);TOUCH(cookie);	TRACE(("nfs_closedir: entry vnode 0x%x, cookie 0x%x\n", v, cookie));	if(v->st != STREAM_TYPE_DIR)		return ERR_VFS_NOT_DIR;	if(cookie)		kfree(cookie);	return 0;}static int nfs_rewinddir(fs_cookie _fs, fs_vnode _v, dir_cookie _cookie){	struct nfs_vnode *v = _v;	struct nfs_cookie *cookie = _cookie;	int err = 0;	TOUCH(v);	TRACE(("nfs_rewinddir: vnode 0x%x, cookie 0x%x\n", v, cookie));	if(v->st != STREAM_TYPE_DIR)		return ERR_VFS_NOT_DIR;	sem_acquire(v->sem, 1);	cookie->u.dir.nfscookie = 0;	cookie->u.dir.at_end = false;	sem_acquire(v->sem, 1);	return err;}#define READDIR_BUF_SIZE (MAXNAMLEN + 64)static ssize_t _nfs_readdir(nfs_fs *nfs, nfs_vnode *v, nfs_cookie *cookie, void *buf, ssize_t len){	uint8 abuf[READDIR_BUF_SIZE];	nfs_readdirargs *args = (nfs_readdirargs *)abuf;	nfs_readdirres  *res  = (nfs_readdirres *)abuf;	ssize_t err = 0;	int i;	int namelen;	if(len < MAXNAMLEN)		return ERR_VFS_INSUFFICIENT_BUF; // XXX not quite accurate	/* see if we've already hit the end */	if(cookie->u.dir.at_end)		return 0;	/* put together the message */	memcpy(&args->dir, &v->nfs_handle, sizeof(args->dir));	args->cookie = cookie->u.dir.nfscookie;	args->count = htonl(min(len, READDIR_BUF_SIZE));	err = rpc_call(&nfs->rpc, NFSPROG, NFSVERS, NFSPROC_READDIR, args, sizeof(*args), abuf, sizeof(abuf));	if(err < 0)		return err;	/* get response */	if(ntohl(res->status) != NFS_OK)		return 0;	/* walk into the buffer, looking for the first entry */	if(ntohl(res->data[0]) == 0) {		// end of list		cookie->u.dir.at_end = true;		return 0;	}	i = ntohl(res->data[0]);	/* copy the data out of the first entry */	strlcpy(buf, (char const *)&res->data[i + 2], ntohl(res->data[i + 1]) + 1);	namelen = ROUNDUP(ntohl(res->data[i + 1]), 4);	/* update the cookie */	cookie->u.dir.nfscookie = res->data[i + namelen / 4 + 2];	return ntohl(res->data[i + 1]);}static int nfs_readdir(fs_cookie _fs, fs_vnode _v, dir_cookie _cookie, void *buf, size_t len){	struct nfs_fs *fs = _fs;	struct nfs_vnode *v = _v;	struct nfs_cookie *cookie = _cookie;	int err = 0;	TOUCH(v);	TRACE(("nfs_readdir: vnode 0x%x, cookie 0x%x, len 0x%x\n", v, cookie, len));	if(v->st != STREAM_TYPE_DIR)		return ERR_VFS_NOT_DIR;

⌨️ 快捷键说明

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