From f4783a9fb9129819d76ecd61907238780345ea9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Revol?= Date: Fri, 29 Sep 2006 23:49:30 +0000 Subject: [PATCH] The fixed version of the NFS client git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18983 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../kernel/file_systems/nfs/RPCPendingCalls.c | 182 ++ .../kernel/file_systems/nfs/RPCPendingCalls.h | 52 + .../kernel/file_systems/nfs/XDRInPacket.c | 62 + .../kernel/file_systems/nfs/XDRInPacket.h | 21 + .../kernel/file_systems/nfs/XDROutPacket.c | 88 + .../kernel/file_systems/nfs/XDROutPacket.h | 30 + src/add-ons/kernel/file_systems/nfs/fsproto.h | 246 ++ src/add-ons/kernel/file_systems/nfs/ksocket.h | 73 + src/add-ons/kernel/file_systems/nfs/makefile | 219 ++ src/add-ons/kernel/file_systems/nfs/mount.h | 20 + src/add-ons/kernel/file_systems/nfs/nfs.h | 90 + .../kernel/file_systems/nfs/nfs_add_on.c | 2347 +++++++++++++++++ .../kernel/file_systems/nfs/nfs_add_on.h | 149 ++ src/add-ons/kernel/file_systems/nfs/pmap.h | 22 + src/add-ons/kernel/file_systems/nfs/rpc.h | 60 + 15 files changed, 3661 insertions(+) create mode 100644 src/add-ons/kernel/file_systems/nfs/RPCPendingCalls.c create mode 100644 src/add-ons/kernel/file_systems/nfs/RPCPendingCalls.h create mode 100644 src/add-ons/kernel/file_systems/nfs/XDRInPacket.c create mode 100644 src/add-ons/kernel/file_systems/nfs/XDRInPacket.h create mode 100644 src/add-ons/kernel/file_systems/nfs/XDROutPacket.c create mode 100644 src/add-ons/kernel/file_systems/nfs/XDROutPacket.h create mode 100644 src/add-ons/kernel/file_systems/nfs/fsproto.h create mode 100644 src/add-ons/kernel/file_systems/nfs/ksocket.h create mode 100644 src/add-ons/kernel/file_systems/nfs/makefile create mode 100644 src/add-ons/kernel/file_systems/nfs/mount.h create mode 100644 src/add-ons/kernel/file_systems/nfs/nfs.h create mode 100644 src/add-ons/kernel/file_systems/nfs/nfs_add_on.c create mode 100644 src/add-ons/kernel/file_systems/nfs/nfs_add_on.h create mode 100644 src/add-ons/kernel/file_systems/nfs/pmap.h create mode 100644 src/add-ons/kernel/file_systems/nfs/rpc.h diff --git a/src/add-ons/kernel/file_systems/nfs/RPCPendingCalls.c b/src/add-ons/kernel/file_systems/nfs/RPCPendingCalls.c new file mode 100644 index 0000000000..07b1bb637e --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs/RPCPendingCalls.c @@ -0,0 +1,182 @@ +#include "RPCPendingCalls.h" +#include + +extern bool conf_no_check_ip_xid; + +extern void +PendingCallInit(struct PendingCall *call) +{ + call->buffer=NULL; +} + +extern void +PendingCallDestroy(struct PendingCall *call) +{ + free (call->buffer); +} + +extern void +RPCPendingCallsInit(struct RPCPendingCalls *calls) +{ + SemaphorePoolInit(&calls->fPool); + + calls->fFirst=NULL; + calls->fSem=create_sem(1,"RPCPendingCalls"); + set_sem_owner (calls->fSem,B_SYSTEM_TEAM); +} + +extern void +RPCPendingCallsDestroy(struct RPCPendingCalls *calls) +{ + delete_sem(calls->fSem); + + while (calls->fFirst) + { + struct PendingCall *next=calls->fFirst->next; + + SemaphorePoolPut (&calls->fPool,calls->fFirst->sem); + PendingCallDestroy (calls->fFirst); + free (calls->fFirst); + + calls->fFirst=next; + } + + SemaphorePoolDestroy (&calls->fPool); +} + +extern struct PendingCall * +RPCPendingCallsAddPendingCall (struct RPCPendingCalls *calls, + int32 xid, const struct sockaddr_in *addr) +{ + struct PendingCall *call=(struct PendingCall *)malloc(sizeof(struct PendingCall)); + PendingCallInit (call); + + call->sem=SemaphorePoolGet(&calls->fPool); + + memcpy(&call->addr,addr,sizeof(struct sockaddr_in)); + call->xid=xid; + + while (acquire_sem (calls->fSem)==B_INTERRUPTED); + + call->next=calls->fFirst; + calls->fFirst=call; + + while (release_sem (calls->fSem)==B_INTERRUPTED); + + return call; +} + +extern struct PendingCall * +RPCPendingCallsFindAndRemovePendingCall (struct RPCPendingCalls *calls, + int32 xid, const struct sockaddr_in *addr) +{ + struct PendingCall *last=NULL; + struct PendingCall *current; + + while (acquire_sem (calls->fSem)==B_INTERRUPTED); + + current=calls->fFirst; // mmu_man + + while (current) + { + if (current->xid==xid) + { + if ((current->addr.sin_addr.s_addr==addr->sin_addr.s_addr)&& + (current->addr.sin_port==addr->sin_port) || conf_no_check_ip_xid) + { + if (last) + last->next=current->next; + else + calls->fFirst=current->next; + + current->next=NULL; + + while (release_sem (calls->fSem)==B_INTERRUPTED); + return current; + } + } + + last=current; + current=current->next; + } + + while (release_sem (calls->fSem)==B_INTERRUPTED); + + return NULL; +} + +extern void +SemaphorePoolInit(struct SemaphorePool *pool) +{ + pool->fPool=NULL; + pool->fPoolCount=0; + pool->fPoolSize=0; + + pool->fPoolSem=create_sem(1,"semaphore_pool_sem"); + set_sem_owner (pool->fPoolSem,B_SYSTEM_TEAM); +} + +extern void +SemaphorePoolDestroy(struct SemaphorePool *pool) +{ + int32 i; + + for (i=0;ifPoolCount;i++) + delete_sem (pool->fPool[i]); + + free (pool->fPool); + + delete_sem (pool->fPoolSem); +} + +extern sem_id +SemaphorePoolGet(struct SemaphorePool *pool) +{ + sem_id sem; + + while (acquire_sem(pool->fPoolSem)==B_INTERRUPTED) + { + } + + if (pool->fPoolCount==0) + { + sem_id sem=create_sem (0,"pending_call"); + + while (release_sem(pool->fPoolSem)==B_INTERRUPTED) + { + } + + return sem; + } + + sem=pool->fPool[pool->fPoolCount-1]; + pool->fPoolCount--; + + while (release_sem(pool->fPoolSem)==B_INTERRUPTED) + { + } + + return sem; +} + +extern void +SemaphorePoolPut(struct SemaphorePool *pool, sem_id sem) +{ + while (acquire_sem(pool->fPoolSem)==B_INTERRUPTED) + { + } + + if (pool->fPoolCount+1>pool->fPoolSize) + { + pool->fPoolSize+=8; + pool->fPool=(sem_id *)realloc(pool->fPool,pool->fPoolSize*sizeof(sem_id)); + } + + pool->fPool[pool->fPoolCount]=sem; + pool->fPoolCount++; + + while (release_sem(pool->fPoolSem)==B_INTERRUPTED) + { + } +} + diff --git a/src/add-ons/kernel/file_systems/nfs/RPCPendingCalls.h b/src/add-ons/kernel/file_systems/nfs/RPCPendingCalls.h new file mode 100644 index 0000000000..a86e98b3d2 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs/RPCPendingCalls.h @@ -0,0 +1,52 @@ +#ifndef _RPCPENDINGCALLS_H + +#define _RPCPENDINGCALLS_H + +#include +#include +#include +#include + +struct SemaphorePool +{ + sem_id *fPool; + int32 fPoolCount; + int32 fPoolSize; + sem_id fPoolSem; +}; + +void SemaphorePoolInit (struct SemaphorePool *pool); +void SemaphorePoolDestroy (struct SemaphorePool *pool); +sem_id SemaphorePoolGet(struct SemaphorePool *pool); +void SemaphorePoolPut (struct SemaphorePool *pool, sem_id sem); + +struct PendingCall +{ + struct PendingCall *next; + + sem_id sem; + struct sockaddr_in addr; + int32 xid; + uint8 *buffer; +}; + +void PendingCallInit (struct PendingCall *call); +void PendingCallDestroy (struct PendingCall *call); + +struct RPCPendingCalls +{ + struct PendingCall *fFirst; + sem_id fSem; + struct SemaphorePool fPool; +}; + +void RPCPendingCallsInit (struct RPCPendingCalls *calls); +void RPCPendingCallsDestroy (struct RPCPendingCalls *calls); + +struct PendingCall *RPCPendingCallsAddPendingCall (struct RPCPendingCalls *calls, + int32 xid, const struct sockaddr_in *addr); + +struct PendingCall *RPCPendingCallsFindAndRemovePendingCall (struct RPCPendingCalls *calls, + int32 xid, const struct sockaddr_in *addr); + +#endif diff --git a/src/add-ons/kernel/file_systems/nfs/XDRInPacket.c b/src/add-ons/kernel/file_systems/nfs/XDRInPacket.c new file mode 100644 index 0000000000..750327da5b --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs/XDRInPacket.c @@ -0,0 +1,62 @@ +#include "XDRInPacket.h" +#include +#include +#include + +extern void +XDRInPacketInit(struct XDRInPacket *packet) +{ + packet->fBuffer=NULL; + packet->fOffset=0; +} + +extern void +XDRInPacketDestroy(struct XDRInPacket *packet) +{ + free (packet->fBuffer); +} + +extern int32 +XDRInPacketGetInt32(struct XDRInPacket *packet) +{ + int32 val=B_BENDIAN_TO_HOST_INT32(*((int32 *)&packet->fBuffer[packet->fOffset])); + + packet->fOffset+=4; + + return val; +} + +extern void +XDRInPacketGetFixed(struct XDRInPacket *packet, void *buffer, size_t len) +{ + memcpy (buffer,&packet->fBuffer[packet->fOffset],len); + packet->fOffset+=(len+3)&~3; +} + +extern size_t +XDRInPacketGetDynamic(struct XDRInPacket *packet, void *buffer) +{ + size_t size=XDRInPacketGetInt32(packet); + XDRInPacketGetFixed (packet,buffer,size); + + return size; +} + +extern char * +XDRInPacketGetString(struct XDRInPacket *packet) +{ + int32 size=XDRInPacketGetInt32(packet); + char *string=(char *)malloc(size+1); + string[size]=0; + XDRInPacketGetFixed (packet,string,size); + + return string; +} + +extern void +XDRInPacketSetTo(struct XDRInPacket *packet, uint8 *buffer, size_t offset) +{ + free (packet->fBuffer); + packet->fBuffer=buffer; + packet->fOffset=offset; +} diff --git a/src/add-ons/kernel/file_systems/nfs/XDRInPacket.h b/src/add-ons/kernel/file_systems/nfs/XDRInPacket.h new file mode 100644 index 0000000000..43b7e48329 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs/XDRInPacket.h @@ -0,0 +1,21 @@ +#ifndef _XDRINPACKET_H + +#define _XDRINPACKET_H + +#include + +struct XDRInPacket +{ + uint8 *fBuffer; + size_t fOffset; +}; + +void XDRInPacketInit (struct XDRInPacket *packet); +void XDRInPacketDestroy (struct XDRInPacket *packet); +int32 XDRInPacketGetInt32 (struct XDRInPacket *packet); +void XDRInPacketGetFixed (struct XDRInPacket *packet, void *buffer, size_t len); +size_t XDRInPacketGetDynamic (struct XDRInPacket *packet, void *buffer); +char *XDRInPacketGetString (struct XDRInPacket *packet); +void XDRInPacketSetTo (struct XDRInPacket *packet, uint8 *buffer, size_t offset); + +#endif diff --git a/src/add-ons/kernel/file_systems/nfs/XDROutPacket.c b/src/add-ons/kernel/file_systems/nfs/XDROutPacket.c new file mode 100644 index 0000000000..9731db47b2 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs/XDROutPacket.c @@ -0,0 +1,88 @@ +#include "XDROutPacket.h" + +#include +#include +#include + +extern const uint8 * +XDROutPacketBuffer(struct XDROutPacket *packet) +{ + return packet->fBuffer; +} + +extern size_t +XDROutPacketLength(struct XDROutPacket *packet) +{ + return packet->fLength; +} + +extern void +XDROutPacketInit(struct XDROutPacket *packet) +{ + packet->fBuffer=NULL; + packet->fSize=packet->fLength=0; +} + +extern void +XDROutPacketDestroy(struct XDROutPacket *packet) +{ + free (packet->fBuffer); +} + +extern void +XDROutPacketGrow(struct XDROutPacket *packet, size_t size) +{ + if (packet->fLength+size>packet->fSize) + { + while (packet->fLength+size>packet->fSize) + packet->fSize+=XDROUTPACKET_BUFFER_INCREMENT; + + packet->fBuffer=(uint8 *)realloc(packet->fBuffer,packet->fSize); + } +} + +extern void +XDROutPacketAddInt32(struct XDROutPacket *packet, int32 val) +{ + XDROutPacketGrow (packet,4); + *(int32 *)(&packet->fBuffer[packet->fLength])=B_HOST_TO_BENDIAN_INT32(val); + packet->fLength+=4; +} + +extern void +XDROutPacketAddDynamic(struct XDROutPacket *packet, const void *data, size_t size) +{ + XDROutPacketAddInt32 (packet,size); + XDROutPacketAddFixed (packet,data,size); +} + +extern void +XDROutPacketAddFixed(struct XDROutPacket *packet, const void *data, size_t size) +{ + size_t roundedSize=(size+3)&~3; + XDROutPacketGrow (packet,roundedSize); + memcpy (&packet->fBuffer[packet->fLength],data,size); + memset (&packet->fBuffer[packet->fLength+size],0,roundedSize-size); + packet->fLength+=roundedSize; +} + +extern void +XDROutPacketAddString(struct XDROutPacket *packet, const char *string) +{ + XDROutPacketAddDynamic(packet,string,strlen(string)); +} + +extern void +XDROutPacketAppend(struct XDROutPacket *me, const struct XDROutPacket *packet) +{ + XDROutPacketGrow (me,packet->fLength); + memcpy (&me->fBuffer[me->fLength],packet->fBuffer,packet->fLength); + me->fLength+=packet->fLength; +} + +extern void +XDROutPacketClear(struct XDROutPacket *packet) +{ + packet->fLength=0; +} + diff --git a/src/add-ons/kernel/file_systems/nfs/XDROutPacket.h b/src/add-ons/kernel/file_systems/nfs/XDROutPacket.h new file mode 100644 index 0000000000..5ef1053fd4 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs/XDROutPacket.h @@ -0,0 +1,30 @@ +#ifndef _XDROUTPACKET_H + +#define _XDROUTPACKET_H + +#include + +#define XDROUTPACKET_BUFFER_INCREMENT 512 + +struct XDROutPacket +{ + uint8 *fBuffer; + size_t fSize; + size_t fLength; +}; + +void XDROutPacketInit (struct XDROutPacket *packet); +void XDROutPacketDestroy (struct XDROutPacket *packet); + +void XDROutPacketGrow (struct XDROutPacket *packet, size_t size); +void XDROutPacketAddInt32 (struct XDROutPacket *packet, int32 val); +void XDROutPacketAddDynamic (struct XDROutPacket *packet, const void *data, size_t size); +void XDROutPacketAddFixed (struct XDROutPacket *packet, const void *data, size_t size); +void XDROutPacketAddString (struct XDROutPacket *packet, const char *string); +void XDROutPacketAppend (struct XDROutPacket *me, const struct XDROutPacket *packet); + +const uint8 *XDROutPacketBuffer (struct XDROutPacket *packet); +size_t XDROutPacketLength (struct XDROutPacket *packet); +void XDROutPacketClear (struct XDROutPacket *packet); + +#endif diff --git a/src/add-ons/kernel/file_systems/nfs/fsproto.h b/src/add-ons/kernel/file_systems/nfs/fsproto.h new file mode 100644 index 0000000000..01a2daa32d --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs/fsproto.h @@ -0,0 +1,246 @@ +#ifndef _FSPROTO_H +#define _FSPROTO_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef dev_t nspace_id; +typedef ino_t vnode_id; + +/* UGLY UGLY UGLY */ +#ifndef _DRIVERS_H +struct selectsync; +typedef struct selectsync selectsync; +#endif + + +/* + * PUBLIC PART OF THE FILE SYSTEM PROTOCOL + */ + +#define WSTAT_MODE 0x0001 +#define WSTAT_UID 0x0002 +#define WSTAT_GID 0x0004 +#define WSTAT_SIZE 0x0008 +#define WSTAT_ATIME 0x0010 +#define WSTAT_MTIME 0x0020 +#define WSTAT_CRTIME 0x0040 + +#define WFSSTAT_NAME 0x0001 + +#define B_ENTRY_CREATED 1 +#define B_ENTRY_REMOVED 2 +#define B_ENTRY_MOVED 3 +#define B_STAT_CHANGED 4 +#define B_ATTR_CHANGED 5 +#define B_DEVICE_MOUNTED 6 +#define B_DEVICE_UNMOUNTED 7 + +#define B_STOP_WATCHING 0x0000 +#define B_WATCH_NAME 0x0001 +#define B_WATCH_STAT 0x0002 +#define B_WATCH_ATTR 0x0004 +#define B_WATCH_DIRECTORY 0x0008 + +#define SELECT_READ 1 +#define SELECT_WRITE 2 +#define SELECT_EXCEPTION 3 + +#define B_CUR_FS_API_VERSION 2 + +struct attr_info; +struct index_info; + +typedef int op_read_vnode(void *ns, vnode_id vnid, char r, void **node); +typedef int op_write_vnode(void *ns, void *node, char r); +typedef int op_remove_vnode(void *ns, void *node, char r); +typedef int op_secure_vnode(void *ns, void *node); + +typedef int op_walk(void *ns, void *base, const char *file, char **newpath, + vnode_id *vnid); + +typedef int op_access(void *ns, void *node, int mode); + +typedef int op_create(void *ns, void *dir, const char *name, + int omode, int perms, vnode_id *vnid, void **cookie); +typedef int op_mkdir(void *ns, void *dir, const char *name, int perms); +typedef int op_symlink(void *ns, void *dir, const char *name, + const char *path); +typedef int op_link(void *ns, void *dir, const char *name, void *node); + +typedef int op_rename(void *ns, void *olddir, const char *oldname, + void *newdir, const char *newname); +typedef int op_unlink(void *ns, void *dir, const char *name); +typedef int op_rmdir(void *ns, void *dir, const char *name); + +typedef int op_readlink(void *ns, void *node, char *buf, size_t *bufsize); + +typedef int op_opendir(void *ns, void *node, void **cookie); +typedef int op_closedir(void *ns, void *node, void *cookie); +typedef int op_rewinddir(void *ns, void *node, void *cookie); +typedef int op_readdir(void *ns, void *node, void *cookie, long *num, + struct dirent *buf, size_t bufsize); + +typedef int op_open(void *ns, void *node, int omode, void **cookie); +typedef int op_close(void *ns, void *node, void *cookie); +typedef int op_free_cookie(void *ns, void *node, void *cookie); +typedef int op_read(void *ns, void *node, void *cookie, off_t pos, void *buf, + size_t *len); +typedef int op_write(void *ns, void *node, void *cookie, off_t pos, + const void *buf, size_t *len); +typedef int op_readv(void *ns, void *node, void *cookie, off_t pos, const iovec *vec, + size_t count, size_t *len); +typedef int op_writev(void *ns, void *node, void *cookie, off_t pos, const iovec *vec, + size_t count, size_t *len); +typedef int op_ioctl(void *ns, void *node, void *cookie, int cmd, void *buf, + size_t len); +typedef int op_setflags(void *ns, void *node, void *cookie, int flags); + +typedef int op_rstat(void *ns, void *node, struct stat *); +typedef int op_wstat(void *ns, void *node, struct stat *, long mask); +typedef int op_fsync(void *ns, void *node); + +typedef int op_select(void *ns, void *node, void *cookie, uint8 event, + uint32 ref, selectsync *sync); +typedef int op_deselect(void *ns, void *node, void *cookie, uint8 event, + selectsync *sync); + +typedef int op_initialize(const char *devname, void *parms, size_t len); +typedef int op_mount(nspace_id nsid, const char *devname, ulong flags, + void *parms, size_t len, void **data, vnode_id *vnid); +typedef int op_unmount(void *ns); +typedef int op_sync(void *ns); +typedef int op_rfsstat(void *ns, struct fs_info *); +typedef int op_wfsstat(void *ns, struct fs_info *, long mask); + + +typedef int op_open_attrdir(void *ns, void *node, void **cookie); +typedef int op_close_attrdir(void *ns, void *node, void *cookie); +typedef int op_rewind_attrdir(void *ns, void *node, void *cookie); +typedef int op_read_attrdir(void *ns, void *node, void *cookie, long *num, + struct dirent *buf, size_t bufsize); +typedef int op_remove_attr(void *ns, void *node, const char *name); +typedef int op_rename_attr(void *ns, void *node, const char *oldname, + const char *newname); +typedef int op_stat_attr(void *ns, void *node, const char *name, + struct attr_info *buf); + +typedef int op_write_attr(void *ns, void *node, const char *name, int type, + const void *buf, size_t *len, off_t pos); +typedef int op_read_attr(void *ns, void *node, const char *name, int type, + void *buf, size_t *len, off_t pos); + +typedef int op_open_indexdir(void *ns, void **cookie); +typedef int op_close_indexdir(void *ns, void *cookie); +typedef int op_rewind_indexdir(void *ns, void *cookie); +typedef int op_read_indexdir(void *ns, void *cookie, long *num, + struct dirent *buf, size_t bufsize); +typedef int op_create_index(void *ns, const char *name, int type, int flags); +typedef int op_remove_index(void *ns, const char *name); +typedef int op_rename_index(void *ns, const char *oldname, + const char *newname); +typedef int op_stat_index(void *ns, const char *name, struct index_info *buf); + +typedef int op_open_query(void *ns, const char *query, ulong flags, + port_id port, long token, void **cookie); +typedef int op_close_query(void *ns, void *cookie); +typedef int op_read_query(void *ns, void *cookie, long *num, + struct dirent *buf, size_t bufsize); + +typedef struct vnode_ops { + op_read_vnode (*read_vnode); + op_write_vnode (*write_vnode); + op_remove_vnode (*remove_vnode); + op_secure_vnode (*secure_vnode); + op_walk (*walk); + op_access (*access); + op_create (*create); + op_mkdir (*mkdir); + op_symlink (*symlink); + op_link (*link); + op_rename (*rename); + op_unlink (*unlink); + op_rmdir (*rmdir); + op_readlink (*readlink); + op_opendir (*opendir); + op_closedir (*closedir); + op_free_cookie (*free_dircookie); + op_rewinddir (*rewinddir); + op_readdir (*readdir); + op_open (*open); + op_close (*close); + op_free_cookie (*free_cookie); + op_read (*read); + op_write (*write); + op_readv (*readv); + op_writev (*writev); + op_ioctl (*ioctl); + op_setflags (*setflags); + op_rstat (*rstat); + op_wstat (*wstat); + op_fsync (*fsync); + op_initialize (*initialize); + op_mount (*mount); + op_unmount (*unmount); + op_sync (*sync); + op_rfsstat (*rfsstat); + op_wfsstat (*wfsstat); + op_select (*select); + op_deselect (*deselect); + op_open_indexdir (*open_indexdir); + op_close_indexdir (*close_indexdir); + op_free_cookie (*free_indexdircookie); + op_rewind_indexdir (*rewind_indexdir); + op_read_indexdir (*read_indexdir); + op_create_index (*create_index); + op_remove_index (*remove_index); + op_rename_index (*rename_index); + op_stat_index (*stat_index); + op_open_attrdir (*open_attrdir); + op_close_attrdir (*close_attrdir); + op_free_cookie (*free_attrdircookie); + op_rewind_attrdir (*rewind_attrdir); + op_read_attrdir (*read_attrdir); + op_write_attr (*write_attr); + op_read_attr (*read_attr); + op_remove_attr (*remove_attr); + op_rename_attr (*rename_attr); + op_stat_attr (*stat_attr); + op_open_query (*open_query); + op_close_query (*close_query); + op_free_cookie (*free_querycookie); + op_read_query (*read_query); +} vnode_ops; + +extern int new_path(const char *path, char **copy); +extern void free_path(char *p); + +extern int notify_listener(int op, nspace_id nsid, + vnode_id vnida, vnode_id vnidb, + vnode_id vnidc, const char *name); +extern void notify_select_event(selectsync *sync, uint32 ref); +extern int send_notification(port_id port, long token, + ulong what, long op, nspace_id nsida, + nspace_id nsidb, vnode_id vnida, + vnode_id vnidb, vnode_id vnidc, + const char *name); +extern int get_vnode(nspace_id nsid, vnode_id vnid, void **data); +extern int put_vnode(nspace_id nsid, vnode_id vnid); +extern int new_vnode(nspace_id nsid, vnode_id vnid, void *data); +extern int remove_vnode(nspace_id nsid, vnode_id vnid); +extern int unremove_vnode(nspace_id nsid, vnode_id vnid); +extern int is_vnode_removed(nspace_id nsid, vnode_id vnid); + + +extern _EXPORT vnode_ops fs_entry; +extern _EXPORT int32 api_version; + +#endif diff --git a/src/add-ons/kernel/file_systems/nfs/ksocket.h b/src/add-ons/kernel/file_systems/nfs/ksocket.h new file mode 100644 index 0000000000..fb100bbff6 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs/ksocket.h @@ -0,0 +1,73 @@ +/* + * kernel-level support for sockets, includes userland support as well for testing. + * François Revol. + */ + +#ifndef _KSOCKET_H +#define _KSOCKET_H + +#include + +#ifndef _KERNEL_MODE + +#define ksocket socket +#define kbind bind +#define kconnect connect +#define kgetsockname getsockname +#define kgetpeername getpeername +#define kaccept accept +#define krecvfrom recvfrom +#define ksendto sendto +#define krecv recv +#define ksend send +#define klisten listen +#define kshutdown shutdown +#define kclosesocket close +#define ksocket_init() ({B_OK;}) +#define ksocket_cleanup() ({B_OK;}) +#define kmessage(fmt, ...) printf(fmt "\n", ##__VA_ARGS__) +#define KSOCKET_MODULE_DECL /* nothing */ + +#elif defined(BONE_VERSION) + +/* BONE socket module */ +#include + +extern bone_socket_info_t *gSocket; +#define ksocket (gSocket->socket) +//#define ksocket(_fam, _typ, _pro) ({int thesock; thesock = (gSocket->socket)(_fam, _typ, _pro); dprintf("ksocket(%d, %d, %d) = %d\n", _fam, _typ, _pro, thesock); thesock;}) +#define kbind (gSocket->bind) +#define kconnect (gSocket->connect) +#define kgetsockname (gSocket->getsockname) +#define kgetpeername (gSocket->getpeername) +#define kaccept (gSocket->accept) +//#define kaccept(_fd, _addr, _sz) ({int thesock; thesock = (gSocket->accept)(_fd, _addr, _sz); dprintf("kaccept(%d, , ) = %d\n", _fd, thesock); thesock; }) +#define krecvfrom (gSocket->recvfrom) +#define ksendto (gSocket->sendto) +#define krecv (gSocket->recv) +#define ksend (gSocket->send) +#define klisten (gSocket->listen) +#define kshutdown (gSocket->shutdown) +#define kclosesocket close +#define kmessage(fmt, ...) dprintf("ksocket: " fmt "\n", ##__VA_ARGS__) + +extern status_t ksocket_init (); +extern status_t ksocket_cleanup (); + +#define KSOCKET_MODULE_DECL \ +bone_socket_info_t *gSocket; \ +status_t ksocket_init () { \ + return get_module(BONE_SOCKET_MODULE, (module_info **)&gSocket); \ +} \ + \ +status_t ksocket_cleanup () { \ + return put_module(BONE_SOCKET_MODULE); \ +} + +#else /* _KERNEL_MODE, !BONE_VERSION */ + +#error feel free to put back ksocketd support if you dare + +#endif /* _KERNEL_MODE, BONE_VERSION */ + +#endif /* _KSOCKET_H */ diff --git a/src/add-ons/kernel/file_systems/nfs/makefile b/src/add-ons/kernel/file_systems/nfs/makefile new file mode 100644 index 0000000000..673d5d2ebe --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs/makefile @@ -0,0 +1,219 @@ +## ****************************************** ## +## BeOS Generic Makefile v2.9.0.Zeta-internal ## + +## Fill in this file to specify the project being created, and the referenced +## makefile-engine will do all of the hard work for you. This handles both +## Intel and PowerPC builds of the BeOS. + +## Application Specific Settings --------------------------------------------- + +# specify the name of the binary +NAME :=nfs + +# specify the type of binary +# APP: Application +# SHARED: Shared library +# ADDON: An add-on +# STATIC: Static library archive +# DRIVER: Kernel Driver +# MODULE: Kernel Module +# DECOR: A window decorator project +TYPE :=MODULE + +# add support for new Pe and Eddie features +# to fill in generic makefile + +#%{ +# @src->@ + +# specify the source files to use +# full paths or paths relative to the makefile can be included +# all files, regardless of directory, will have their object +# files created in the common object directory. +# Note that this means this makefile will not work correctly +# if two source files with the same name (source.c or source.cpp) +# are included from different directories. Also note that spaces +# in folder names do not work well with this makefile. +SRCS := $(wildcard *.c) + +# specify the resource files to use +# full path or a relative path to the resource file can be used. +RSRCS := + +# Specify your RDEF files, if any. +RDEFS := + +# @<-src@ +#%} + +# end support for Pe and Eddie + +# specify additional libraries to link against +# there are two acceptable forms of library specifications +# - if your library follows the naming pattern of: +# libXXX.so or libXXX.a you can simply specify XXX +# library: libbe.so entry: be +# +# - if your library does not follow the standard library +# naming scheme you need to specify the path to the library +# and it's name +# library: my_lib.a entry: my_lib.a or path/my_lib.a +LIBS := + +# specify additional paths to directories following the standard +# libXXX.so or libXXX.a naming scheme. You can specify full paths +# or paths relative to the makefile. The paths included may not +# be recursive, so include $(BUILD_SCRIPT_DIR)/all of the paths where libraries can +# be found. Directories where source files are found are +# automatically included. +LIBPATHS := + +# additional paths to look for system headers +# thes use the form: #include $(BUILD_SCRIPT_DIR)/
+# source file directories are NOT auto-included here +SYSTEM_INCLUDE_PATHS := + +# additional paths to look for local headers +# thes use the form: #include $(BUILD_SCRIPT_DIR)/"header" +# source file directories are automatically included +LOCAL_INCLUDE_PATHS := + +# specify the level of optimization that you desire +# NONE, SOME, FULL +OPTIMIZE :=FULL + +# specify any preprocessor symbols to be defined. The symbols will not +# have their values set automatically; you must supply the value (if any) +# to use. For example, setting DEFINES to "DEBUG=1" will cause the +# compiler option "-DDEBUG=1" to be used. Setting DEFINES to "DEBUG" +# would pass "-DDEBUG" on the compiler's command line. +DEFINES := _BUILDING_fs=1 + +# specify special warning levels +# if unspecified default warnings will be used +# NONE = supress all warnings +# ALL = enable all warnings +WARNINGS :=ALL + +# specify whether image symbols will be created +# so that stack crawls in the debugger are meaningful +# if TRUE symbols will be created +SYMBOLS := + +# specify debug settings +# if TRUE will allow application to be run from a source-level +# debugger. Note that this will disable all optimzation. +DEBUGGER := + +# specify additional compiler flags for all files +COMPILER_FLAGS := + +# specify additional linker flags +LINKER_FLAGS := + +# specify additional flex flags +FLEX_FLAGS = + +# specify additional bison flags +BISON_FLAGS = + +# specify the version of this particular item +# (for example, -app 3 4 0 d 0 -short 340 -long "340 "`echo -n -e '\302\251'`"1999 GNU GPL") +# This may also be specified in a resource. +APP_VERSION := + +# (for TYPE == DRIVER only) Specify desired location of driver in the /dev +# hierarchy. Used by the driverinstall rule. E.g., DRIVER_PATH = video/usb will +# instruct the driverinstall rule to place a symlink to your driver's binary in +# ~/add-ons/kernel/drivers/dev/video/usb, so that your driver will appear at +# /dev/video/usb when loaded. Default is "misc". +DRIVER_PATH := + +# Specify if you want the object files to be somewhere besides the default location. +OBJ_DIR := + +# Specify a non default placement for the target +TARGET_DIR := + +# If you want to see the complete build line for every file, then set this to 'true', +# otherwise it will tell you at the end what the build flags were. +#CHATTY := + +# Special Zeta build system var +BOOTREL_INSTALL_DIR := beos/system/add-ons/kernel/file_systems + +# Specify a directory for the 'install' target. +INSTALL_DIR := /boot/$(BOOTREL_INSTALL_DIR) + +# Specify the name of this makefile. +# If you leave this blank, the makefile will not be considered as part of the +# dependenies for the project, and the project will not be rebuilt when the makefile +# is changed +MAKEFILE := + +# Specify TRUE if you want the install target to create links in the BeMenu +MENU_LINKS := + +# Related to MENU_LINKS, specify the name of the direcotry in the BeMenu +# you wish the link to go in. If the directory does not exist, it will be +# created. +APP_MENU := + +# If, for some reason, you don't want to use the dependencies (flex and yacc seem to choke +# on them), set this to false +DODEPS := + +# Set this variable if you have an svg text file you wish to use as +# your target's icon. +SVG_ICON := + +# If you have some fancy custom build steps to do, specify them here +EXTRA_BUILD_STEPS = + + +# If you have some other files that should trigger a re-link, such as libs in the same +# project that may get rebuilt, specify the full path to them here. +EXTRA_DEPS := + + +################################################################################################## +# +## Z E T A S p e c i f i c +# +################################################################################################## + +# Specify the path to the Screenshot file. If this is not specified, then the SCREENSHOT default +# will be $(PWD)/$(NAME).png +# If this application is not to have a screenshot, use NONE +SCREENSHOT := + +# Specify the category that this zeta component belongs in +ZETA_CATEGORY := BaseInstallation + +# The .zip package that this file will be included in. If this is left blank, then +# $(NAME).zip will be used. +# This feature is meant for having multiple items included in the a single .zip package +PACKAGE := + +# If this target is a component of another target. That is, if this is part of a package +# but not the 'main' part. Typically the main app will have the screenshot, and set +# the relevant attributes. If this is set to 'true' then this makefile will not attempt to set +# attributes or a screenshot or a description. +IS_COMPONENT := + +# If this is a mandatory component, set this to 'false'. The default is true. +# Optional components will be zipped up with thier attribs and everything. +# Non-Optional (mandatory) components will just be copied to the directory structure and +# added to the manifest for copying during install +OPTIONAL :=false + +# Specify the names of the Language files here. (ie: AboutWindow.de AboutWindow.en) +LANG_FILES := + +# If your language files are in a different directory, specify the relative directory here. +# ie: Language/Dictionaries +LANG_FILES_DIR := + + +## include $(BUILD_SCRIPT_DIR)/the makefile-engine +include $(BUILD_SCRIPT_DIR)/makefile-engine.zeta diff --git a/src/add-ons/kernel/file_systems/nfs/mount.h b/src/add-ons/kernel/file_systems/nfs/mount.h new file mode 100644 index 0000000000..3d94158082 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs/mount.h @@ -0,0 +1,20 @@ +#ifndef _MOUNT_H + +#define _MOUNT_H + +#include + +const int32 MOUNT_VERSION=1; +const int32 MOUNT_PROGRAM=100005; + +enum +{ + MOUNTPROC_NULL = 0, + MOUNTPROC_MNT = 1, + MOUNTPROC_DUMP = 2, + MOUNTPROC_UMNT = 3, + MOUNTPROC_UMNTALL = 4, + MOUNTPROC_EXPORT = 5 +}; + +#endif diff --git a/src/add-ons/kernel/file_systems/nfs/nfs.h b/src/add-ons/kernel/file_systems/nfs/nfs.h new file mode 100644 index 0000000000..a8869d9ba2 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs/nfs.h @@ -0,0 +1,90 @@ +#ifndef _NFS_H + +#define _NFS_H + +#include + +const int32 NFS_VERSION=2; +const int32 NFS_PROGRAM=100003; + +typedef enum nfs_stat +{ + NFS_OK = 0, + NFSERR_PERM=1, + NFSERR_NOENT=2, + NFSERR_IO=5, + NFSERR_NXIO=6, + NFSERR_ACCES=13, + NFSERR_EXIST=17, + NFSERR_NODEV=19, + NFSERR_NOTDIR=20, + NFSERR_ISDIR=21, + NFSERR_FBIG=27, + NFSERR_NOSPC=28, + NFSERR_ROFS=30, + NFSERR_NAMETOOLONG=63, + NFSERR_NOTEMPTY=66, + NFSERR_DQUOT=69, + NFSERR_STALE=70, + NFSERR_WFLUSH=99 +} nfs_stat; + + +typedef enum nfs_ftype +{ + NFS_NFNON = 0, + NFS_NFREG = 1, + NFS_NFDIR = 2, + NFS_NFBLK = 3, + NFS_NFCHR = 4, + NFS_NFLNK = 5 +} nfs_ftype; + +//#define NFS_MAXDATA 8192 +#define NFS_MAXDATA 1024 + +/* The maximum number of bytes in a pathname argument. */ +#define NFS_MAXPATHLEN 1024 + +/* The maximum number of bytes in a file name argument. */ +#define NFS_MAXNAMLEN 255 + +/* The size in bytes of the opaque "cookie" passed by READDIR. */ +#define NFS_COOKIESIZE 4 + +/* The size in bytes of the opaque file handle. */ +#define NFS_FHSIZE 32 + +enum +{ + NFSPROC_NULL = 0, + NFSPROC_GETATTR = 1, + NFSPROC_SETATTR = 2, + NFSPROC_ROOT = 3, + NFSPROC_LOOKUP = 4, + NFSPROC_READLINK = 5, + NFSPROC_READ = 6, + NFSPROC_WRITECACHE = 7, + NFSPROC_WRITE = 8, + NFSPROC_CREATE = 9, + NFSPROC_REMOVE = 10, + NFSPROC_RENAME = 11, + NFSPROC_LINK = 12, + NFSPROC_SYMLINK = 13, + NFSPROC_MKDIR = 14, + NFSPROC_RMDIR = 15, + NFSPROC_READDIR = 16, + NFSPROC_STATFS = 17 +}; + +struct nfs_fhandle +{ + char opaque[NFS_FHSIZE]; +}; + +struct nfs_cookie +{ + char opaque[NFS_COOKIESIZE]; +}; + +#endif diff --git a/src/add-ons/kernel/file_systems/nfs/nfs_add_on.c b/src/add-ons/kernel/file_systems/nfs/nfs_add_on.c new file mode 100644 index 0000000000..47129787bf --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs/nfs_add_on.c @@ -0,0 +1,2347 @@ +#include + +#include "nfs_add_on.h" +#include "ksocket.h" + +#include "rpc.h" +#include "pmap.h" +#include "nfs.h" +#include "mount.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#define B_UDP_MAX_SIZE UDP_SIZE_MAX + +/* declare gSocket and others */ +KSOCKET_MODULE_DECL; + +/* *** configuration *** */ + +//#define NFS_FS_FLAGS B_FS_IS_SHARED +#define NFS_FS_FLAGS B_FS_IS_SHARED|B_FS_IS_PERSISTENT + +/* port numbers: most NFS servers insist on the client port to be < 1024 (secure option) */ +/* ports to bind() to; we start at conf_high_port, then go down */ +static int16 conf_high_port = 1023; +static int16 conf_low_port = 900; + +/* Allow open() to open directories too */ +static bool conf_allow_dir_open = true; + +/* Do we list ".." in readdir(rootid) ? (the VFS corrects the dirents anyway) */ +/* this seems to be mandatory for Dano... BEntry::GetPath() needs that */ +static bool conf_ls_root_parent = true; + +/* timeout when waiting for an answer to a call */ +static bigtime_t conf_call_timeout = 2000000; + +/* number of retries when waiting for an anwser to a call */ +static unsigned long conf_call_tries = 3; + +/* don't check who the answers come from for requests */ +bool conf_no_check_ip_xid = false; + +/* *** DEBUG stuff *** */ +//#define my_notify_listener(p_a, p_b, p_c, p_d, p_e, p_f) ({dprintf("nfs: notify_listener(%08lx)\n", p_a); notify_listener(p_a, p_b, p_c, p_d, p_e, p_f); }) +#define my_notify_listener notify_listener + +_EXPORT vnode_ops fs_entry = +{ + (op_read_vnode *)&fs_read_vnode, + (op_write_vnode *)&fs_write_vnode, + (op_remove_vnode *)&fs_remove_vnode, + (op_secure_vnode *)&fs_secure_vnode, + (op_walk *)&fs_walk, + (op_access *)&fs_access, + (op_create *)&fs_create, + (op_mkdir *)&fs_mkdir, + (op_symlink *)&fs_symlink, + NULL, // &fs_link, + (op_rename *)&fs_rename, + (op_unlink *)&fs_unlink, + (op_rmdir *)&fs_rmdir, + (op_readlink *)&fs_readlink, + (op_opendir *)&fs_opendir, + (op_closedir *)&fs_closedir, + (op_free_cookie *)&fs_free_dircookie, + (op_rewinddir *)&fs_rewinddir, + (op_readdir *)&fs_readdir, + (op_open *)&fs_open, + (op_close *)&fs_close, + (op_free_cookie *)&fs_free_cookie, + (op_read *)&fs_read, + (op_write *)&fs_write, + NULL, // &fs_readv, + NULL, // &fs_writev, + NULL, // &fs_ioctl, + NULL, // &fs_setflags, + (op_rstat *)&fs_rstat, + (op_wstat *)&fs_wstat, + NULL, // &fs_fsync, + NULL, // &fs_initialize, + (op_mount *)&fs_mount, + (op_unmount *)&fs_unmount, + NULL, // &fs_sync, + (op_rfsstat *)&fs_rfsstat, + (op_wfsstat *)&fs_wfsstat, + NULL, // &fs_select, + NULL, // &fs_deselect, + NULL, // &fs_open_indexdir, + NULL, // &fs_close_indexdir, + NULL, // &fs_free_indexdircookie, + NULL, // &fs_rewind_indexdir, + NULL, // &fs_read_indexdir, + NULL, // &fs_create_index, + NULL, // &fs_remove_index, + NULL, // &fs_rename_index, + NULL, // &fs_stat_index, + NULL, // &fs_open_attrdir, + NULL, // &fs_close_attrdir, + NULL, // &fs_free_attrdircookie, + NULL, // &fs_rewind_attrdir, + NULL, // &fs_read_attrdir, + NULL, // &fs_write_attr, + NULL, // &fs_read_attr, + NULL, // &fs_remove_attr, + NULL, // &fs_rename_attr, + NULL, // &fs_stat_attr, + NULL, // &fs_open_query, + NULL, // &fs_close_query, + NULL, // &fs_free_querycookie, + NULL, // &fs_read_query +}; + +_EXPORT int32 api_version=B_CUR_FS_API_VERSION; + +static vint32 refcount = 0; /* we only want to read the config once ? */ + +static status_t read_config(void) +{ + void *handle; + const char *str, *endptr; + int32 value = 0; + + handle = load_driver_settings("nfs"); + if (handle == NULL) + return ENOENT; + + str = get_driver_parameter(handle, "high_port", NULL, NULL); + if (str) { + endptr = str + strlen(str); + conf_high_port = (int16)strtoul(str, &endptr, 10); + } + str = get_driver_parameter(handle, "low_port", NULL, NULL); + if (str) { + endptr = str + strlen(str); + conf_low_port = (int16)strtoul(str, &endptr, 10); + } + + conf_allow_dir_open = get_driver_boolean_parameter(handle, "allow_dir_open", conf_allow_dir_open, true); + conf_ls_root_parent = get_driver_boolean_parameter(handle, "ls_root_parent", conf_ls_root_parent, false); + conf_no_check_ip_xid = get_driver_boolean_parameter(handle, "no_check_ip_xid", conf_no_check_ip_xid, false); + + str = get_driver_parameter(handle, "call_timeout", NULL, NULL); + if (str) { + endptr = str + strlen(str); + conf_call_timeout = (bigtime_t)1000 * strtoul(str, &endptr, 10); + if (conf_call_timeout < 1000) + conf_call_timeout = 1000; + } + + str = get_driver_parameter(handle, "call_tries", NULL, NULL); + if (str) { + endptr = str + strlen(str); + conf_call_tries = strtoul(str, &endptr, 10); + } + + unload_driver_settings(handle); + return B_OK; +} + +extern status_t +create_socket(fs_nspace *ns) +{ + struct sockaddr_in addr; + uint16 port=conf_high_port; + + ns->s=ksocket(AF_INET,SOCK_DGRAM,0); + + if (ns->s<0) + return errno; + + do + { + addr.sin_family=AF_INET; + addr.sin_addr.s_addr=htonl(INADDR_ANY); + //addr.sin_addr.s_addr=htonl(INADDR_LOOPBACK); + addr.sin_port=htons(port); + memset (addr.sin_zero,0,sizeof(addr.sin_zero)); + + if (kbind(ns->s,(const struct sockaddr *)&addr,sizeof(addr))<0) + { + if (errno!=EADDRINUSE) + { + int result=errno; + kclosesocket(ns->s); + return result; + } + + port--; + if (port==conf_low_port) + { + kclosesocket(ns->s); + return B_ERROR; + } + } + else + break;//return B_OK; + } + while (true); + + // doesn't seem to help with autoincrementing port on source address... + addr.sin_addr = ns->mountAddr.sin_addr; + addr.sin_port = htons(111); + //kconnect(ns->s,(const struct sockaddr *)&addr,sizeof(addr)); + + return B_OK; +} + +extern status_t +connect_socket(fs_nspace *ns) +{ + uint16 port=conf_high_port; + + struct sockaddr_in addr; + addr.sin_family=AF_INET; + addr.sin_addr.s_addr=htonl(INADDR_ANY); + //addr.sin_addr.s_addr=htonl(INADDR_LOOPBACK); + addr.sin_port=htons(port); + memset (addr.sin_zero,0,sizeof(addr.sin_zero)); + + if (kconnect(ns->s,(const struct sockaddr *)&ns->nfsAddr,sizeof(ns->nfsAddr))<0) + { + return -1; + } + return B_OK; +} + +extern status_t +init_postoffice(fs_nspace *ns) +{ + status_t result; + + ns->tid=spawn_kernel_thread ((thread_func)postoffice_func,"Postoffice",B_NORMAL_PRIORITY,ns); + + if (ns->tidtid; + + ns->quit=false; + + result=resume_thread (ns->tid); + + if (resulttid); + + return result; + } + + return B_OK; +} + +extern void +shutdown_postoffice(fs_nspace *ns) +{ + struct sockaddr addr; + int addrSize; + status_t result; + + ns->quit=true; + kclosesocket(ns->s); + + wait_for_thread (ns->tid,&result); +} + +extern status_t +postoffice_func(fs_nspace *ns) +{ + uint8 *buffer=(uint8 *)malloc(B_UDP_MAX_SIZE); + + while (!ns->quit) + { + struct sockaddr_in from; + int fromLen=sizeof(from); + + ssize_t bytes=krecvfrom (ns->s,buffer,B_UDP_MAX_SIZE,0,(struct sockaddr *)&from,&fromLen); + + if (bytes>=4) + { + struct PendingCall *call; + int32 xid=B_BENDIAN_TO_HOST_INT32(*((int32 *)buffer)); + + call=RPCPendingCallsFindAndRemovePendingCall(&ns->pendingCalls,xid,&from); + + if (call) + { + call->buffer=(uint8 *)malloc(bytes); + memcpy (call->buffer,buffer,bytes); + + while (release_sem (call->sem)==B_INTERRUPTED); + } else { + dprintf("nfs: postoffice: can't find pending call to remove for xid %d\n", xid); + } + } + } + + free (buffer); + + return B_OK; +} + +uint8 *send_rpc_call (fs_nspace *ns, const struct sockaddr_in *addr, + int32 prog, int32 vers, int32 proc, + const struct XDROutPacket *packet) +{ + int32 xid; + size_t authSize; + struct PendingCall *pending; + int32 retries=conf_call_tries; + status_t result; + struct PendingCall *call; + + struct XDROutPacket rpc_call; + XDROutPacketInit (&rpc_call); + + xid=atomic_add(&ns->xid,1); +#ifdef DEBUG_XID + //dbgprintxid(logfd1, xid); +#endif + + XDROutPacketAddInt32(&rpc_call,xid); + XDROutPacketAddInt32(&rpc_call,RPC_CALL); + XDROutPacketAddInt32(&rpc_call,RPC_VERSION); + XDROutPacketAddInt32(&rpc_call,prog); + XDROutPacketAddInt32(&rpc_call,vers); + XDROutPacketAddInt32(&rpc_call,proc); + +#if !defined(USE_SYSTEM_AUTHENTICATION) + XDROutPacketAddInt32(&rpc_call,RPC_AUTH_NONE); + XDROutPacketAddDynamic (&rpc_call,NULL,0); +#else + XDROutPacketAddInt32(&rpc_call,RPC_AUTH_SYS); + authSize=4+4+((strlen(ns->params.server)+3)&~3)+4+4+4; + XDROutPacketAddInt32(&rpc_call,authSize); + XDROutPacketAddInt32(&rpc_call,0); + XDROutPacketAddString(&rpc_call,ns->params.server); + XDROutPacketAddInt32(&rpc_call,ns->params.uid); + XDROutPacketAddInt32(&rpc_call,ns->params.gid); + XDROutPacketAddInt32(&rpc_call,0); +#endif + + XDROutPacketAddInt32(&rpc_call,RPC_AUTH_NONE); + XDROutPacketAddDynamic (&rpc_call,NULL,0); + + XDROutPacketAppend (&rpc_call,packet); + + pending=RPCPendingCallsAddPendingCall(&ns->pendingCalls,xid,addr); +#ifdef DEBUG_XID + checksemstate(xid, pending->sem, 0); +#endif + + do + { + ssize_t bytes; + do + { + bytes=ksendto (ns->s,(const void *)XDROutPacketBuffer(&rpc_call), + XDROutPacketLength(&rpc_call),0, + (const struct sockaddr *)addr,sizeof(*addr)); + } + while ((bytes<0)&&(errno==EINTR)); + + do + { + result=acquire_sem_etc (pending->sem,1,B_TIMEOUT,(retries)?(conf_call_timeout):(2*conf_call_timeout)); + } + while (result==B_INTERRUPTED); + + retries--; + } + while ((result==B_TIMED_OUT)&&(retries>=0)); + + if (result>=B_OK) + { + uint8 *buffer=pending->buffer; + pending->buffer=NULL; + SemaphorePoolPut(&ns->pendingCalls.fPool,pending->sem); + + PendingCallDestroy(pending); + free(pending); + + XDROutPacketDestroy (&rpc_call); + return buffer; + } + + // we timed out + + call=RPCPendingCallsFindAndRemovePendingCall(&ns->pendingCalls,xid,addr); + + kmessage ("nfs: xid %d timed out, removing from queue",xid); + +#if 0 + if (call==NULL) + { +#if 1 + //XXX:mmu_man:??? + while (acquire_sem(pending->sem)==B_INTERRUPTED); +#else + status_t err; + /* NOTE(mmu_man): there can be a race condition here where the sem is returned + * to the pool without the correct value, compromising the next call using it. + * however it seems waiting forever can lead to lockups... + */ + while ((err = acquire_sem_etc(pending->sem,1,B_TIMEOUT,5000000))==B_INTERRUPTED); + dprintf("nfs: acquire(pending->sem) = 0x%08lx\n", err); + if (err == B_TIMED_OUT) + dprintf("nfs: timed out waiting on sem\n"); +#endif + } +#endif + + free(pending->buffer); + + /* mmu_man */ + if (call) /* if the call has been found and removed (atomic op), the sem hasn't been released */ + SemaphorePoolPut(&ns->pendingCalls.fPool,pending->sem); + else + delete_sem(pending->sem); /* else it's in an unknown state, forget it */ + + PendingCallDestroy (pending); + free(pending); + + XDROutPacketDestroy (&rpc_call); + return NULL; +} + +bool is_successful_reply (struct XDRInPacket *reply) +{ + bool success=false; + + int32 xid=XDRInPacketGetInt32(reply); + rpc_msg_type mtype=(rpc_msg_type)XDRInPacketGetInt32(reply); + rpc_reply_stat replyStat=(rpc_reply_stat)XDRInPacketGetInt32(reply); + + if (replyStat==RPC_MSG_DENIED) + { + rpc_reject_stat rejectStat=(rpc_reject_stat)XDRInPacketGetInt32(reply); + + if (rejectStat==RPC_RPC_MISMATCH) + { + int32 low=XDRInPacketGetInt32(reply); + int32 high=XDRInPacketGetInt32(reply); + + kmessage ("RPC_MISMATCH (%d,%d)",low,high); + } + else + { + rpc_auth_stat authStat=(rpc_auth_stat)XDRInPacketGetInt32(reply); + + kmessage ("RPC_AUTH_ERROR (%d)",authStat); + } + } + else + { + rpc_auth_flavor flavor=(rpc_auth_flavor)XDRInPacketGetInt32(reply); + char body[400]; + size_t bodyLength=XDRInPacketGetDynamic(reply,body); + + rpc_accept_stat acceptStat=(rpc_accept_stat)XDRInPacketGetInt32(reply); + + if (acceptStat==RPC_PROG_MISMATCH) + { + int32 low=XDRInPacketGetInt32(reply); + int32 high=XDRInPacketGetInt32(reply); + + kmessage ("RPC_PROG_MISMATCH (%d,%d)",low,high); + } + else if (acceptStat!=RPC_SUCCESS) + kmessage ("Accepted but failed (%d)",acceptStat); + else + success=true; + } + + return success; +} + +status_t get_remote_address (fs_nspace *ns, int32 prog, int32 vers, int32 prot, struct sockaddr_in *addr) +{ + struct XDROutPacket call; + uint8 *replyBuf; + + XDROutPacketInit (&call); + + addr->sin_port=htons(PMAP_PORT); + + XDROutPacketAddInt32 (&call,prog); + XDROutPacketAddInt32 (&call,vers); + XDROutPacketAddInt32 (&call,prot); + XDROutPacketAddInt32 (&call,0); + + replyBuf=send_rpc_call (ns,addr,PMAP_PROGRAM,PMAP_VERSION,PMAPPROC_GETPORT,&call); + + if (replyBuf) + { + struct XDRInPacket reply; + XDRInPacketInit (&reply); + + XDRInPacketSetTo (&reply,replyBuf,0); + + if (is_successful_reply(&reply)) + { + addr->sin_port=htons(XDRInPacketGetInt32(&reply)); + memset (addr->sin_zero,0,sizeof(addr->sin_zero)); + + XDRInPacketDestroy(&reply); + XDROutPacketDestroy (&call); + return B_OK; + } + + XDRInPacketDestroy(&reply); + } + + XDROutPacketDestroy (&call); + return EHOSTUNREACH; +} + +status_t nfs_mount (fs_nspace *ns, const char *path, nfs_fhandle *fhandle) +{ + struct XDROutPacket call; + struct XDRInPacket reply; + uint8 *replyBuf; + int32 fhstatus; + + XDROutPacketInit (&call); + XDRInPacketInit (&reply); + + XDROutPacketAddString (&call,path); + + replyBuf=send_rpc_call (ns,&ns->mountAddr,MOUNT_PROGRAM,MOUNT_VERSION,MOUNTPROC_MNT,&call); + + if (!replyBuf) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return EHOSTUNREACH; + } + + XDRInPacketSetTo (&reply,replyBuf,0); + + if (!is_successful_reply(&reply)) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return B_ERROR; + } + + fhstatus=XDRInPacketGetInt32(&reply); + + if (fhstatus!=0) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return map_nfs_to_system_error(fhstatus); + } + + XDRInPacketGetFixed (&reply,fhandle->opaque,NFS_FHSIZE); + + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return B_OK; +} + +status_t nfs_lookup (fs_nspace *ns, const nfs_fhandle *dir, const char *filename, nfs_fhandle *fhandle, + struct stat *st) +{ + struct XDROutPacket call; + struct XDRInPacket reply; + int32 status; + uint8 *replyBuf; + + XDROutPacketInit (&call); + XDRInPacketInit (&reply); + + XDROutPacketAddFixed (&call,dir->opaque,NFS_FHSIZE); + XDROutPacketAddString (&call,filename); + + replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_LOOKUP,&call); + + if (!replyBuf) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return EHOSTUNREACH; + } + + XDRInPacketSetTo(&reply,replyBuf,0); + + if (!is_successful_reply(&reply)) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return B_ERROR; + } + + status=XDRInPacketGetInt32(&reply); + + if (status!=NFS_OK) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return map_nfs_to_system_error(status); + } + + XDRInPacketGetFixed (&reply,fhandle->opaque,NFS_FHSIZE); + + if (st) + get_nfs_attr (&reply,st); + + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return B_OK; +} + +status_t nfs_getattr (fs_nspace *ns, const nfs_fhandle *fhandle, + struct stat *st) +{ + struct XDROutPacket call; + struct XDRInPacket reply; + uint8 *replyBuf; + int32 status; + + XDROutPacketInit (&call); + XDRInPacketInit (&reply); + + XDROutPacketAddFixed (&call,fhandle->opaque,NFS_FHSIZE); + + replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_GETATTR,&call); + + if (!replyBuf) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return EHOSTUNREACH; + } + + XDRInPacketSetTo (&reply,replyBuf,0); + + if (!is_successful_reply(&reply)) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return B_ERROR; + } + + status=XDRInPacketGetInt32(&reply); + + if (status!=NFS_OK) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return map_nfs_to_system_error(status); + } + + get_nfs_attr (&reply,st); + + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return B_OK; +} + +extern status_t +nfs_truncate_file(fs_nspace *ns, const nfs_fhandle *fhandle, struct stat *st) +{ + struct XDROutPacket call; + struct XDRInPacket reply; + uint8 *replyBuf; + int32 status; + + XDROutPacketInit (&call); + XDRInPacketInit (&reply); + + XDROutPacketAddFixed(&call,fhandle->opaque,NFS_FHSIZE); + + XDROutPacketAddInt32 (&call,-1); + XDROutPacketAddInt32 (&call,-1); + XDROutPacketAddInt32 (&call,-1); + XDROutPacketAddInt32 (&call,0); + XDROutPacketAddInt32 (&call,time(NULL)); + XDROutPacketAddInt32 (&call,0); + XDROutPacketAddInt32 (&call,time(NULL)); + XDROutPacketAddInt32 (&call,0); + + replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_SETATTR,&call); + + if (!replyBuf) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return EHOSTUNREACH; + } + + XDRInPacketSetTo(&reply,replyBuf,0); + + if (!is_successful_reply(&reply)) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return B_ERROR; + } + + status=XDRInPacketGetInt32(&reply); + + if (status!=NFS_OK) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return map_nfs_to_system_error(status); + } + + if (st) + get_nfs_attr (&reply,st); + + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return B_OK; +} + +void get_nfs_attr (struct XDRInPacket *reply, struct stat *st) +{ + nfs_ftype ftype=(nfs_ftype)XDRInPacketGetInt32(reply); + st->st_mode=XDRInPacketGetInt32(reply); + + st->st_dev=0; // just to be sure + st->st_nlink=XDRInPacketGetInt32(reply); + st->st_uid=XDRInPacketGetInt32(reply); + st->st_gid=XDRInPacketGetInt32(reply); + st->st_size=XDRInPacketGetInt32(reply); +#if 0 + XDRInPacketGetInt32(reply); // blksize + st->st_blksize=NFS_MAXDATA; +#else + st->st_blksize=XDRInPacketGetInt32(reply); +#endif + st->st_rdev=XDRInPacketGetInt32(reply); + XDRInPacketGetInt32(reply); // blocks + XDRInPacketGetInt32(reply); // fsid + st->st_ino=XDRInPacketGetInt32(reply); + st->st_atime=XDRInPacketGetInt32(reply); + XDRInPacketGetInt32(reply); // usecs + st->st_mtime=st->st_crtime=XDRInPacketGetInt32(reply); + XDRInPacketGetInt32(reply); // usecs + st->st_ctime=XDRInPacketGetInt32(reply); + XDRInPacketGetInt32(reply); // usecs +} + +status_t map_nfs_to_system_error (status_t nfsstatus) +{ + switch (nfsstatus) + { + case NFS_OK: + return B_OK; + + case NFSERR_PERM: + return EPERM; + + case NFSERR_NOENT: + return ENOENT; + + case NFSERR_IO: + return EIO; + + case NFSERR_NXIO: + return ENXIO; + + case NFSERR_ACCES: + return EACCES; + + case NFSERR_EXIST: + return EEXIST; + + case NFSERR_NODEV: + return ENODEV; + + case NFSERR_NOTDIR: + return ENOTDIR; + + case NFSERR_ISDIR: + return EISDIR; + + case NFSERR_FBIG: + return EFBIG; + + case NFSERR_NOSPC: + return ENOSPC; + + case NFSERR_ROFS: + return EROFS; + + case NFSERR_NAMETOOLONG: + return ENAMETOOLONG; + + case NFSERR_NOTEMPTY: + return ENOTEMPTY; + + case NFSERR_STALE: + return C_ERROR_STALE; + + default: + return B_ERROR; + } +} + +extern nfs_fhandle +handle_from_vnid(fs_nspace *ns, vnode_id vnid) +{ + fs_node *current; + + while (acquire_sem (ns->sem)==B_INTERRUPTED); + + current=ns->first; + + while ((current)&&(current->vnid!=vnid)) + current=current->next; + + while (release_sem (ns->sem)==B_INTERRUPTED); + + return current->fhandle; +} + +void insert_node (fs_nspace *ns, fs_node *node) +{ + fs_node *current; + + while (acquire_sem (ns->sem)==B_INTERRUPTED); + + current=ns->first; + + while ((current)&&(current->vnid!=node->vnid)) + current=current->next; + + if (current) + { + free(node); + while (release_sem (ns->sem)==B_INTERRUPTED); + return; + } + + node->next=ns->first; + ns->first=node; + + while (release_sem (ns->sem)==B_INTERRUPTED); +} + +void remove_node (fs_nspace *ns, vnode_id vnid) +{ + fs_node *current; + fs_node *previous; + + while(acquire_sem (ns->sem)==B_INTERRUPTED); + + current=ns->first; + previous=NULL; + + while ((current)&&(current->vnid!=vnid)) + { + previous=current; + current=current->next; + } + + if (current) + { + if (previous) + previous->next=current->next; + else + ns->first=current->next; + + free(current); + } + + while (release_sem (ns->sem)==B_INTERRUPTED); +} + +extern int +fs_read_vnode(fs_nspace *ns, vnode_id vnid, char r, fs_node **node) +{ + fs_node *current; + + if (!r) + { + while (acquire_sem (ns->sem)==B_INTERRUPTED); + } + + current=ns->first; + + while ((current)&&(current->vnid!=vnid)) + current=current->next; + + if (!current) + return EINVAL; + + *node=current; + + if (!r) + { + while (release_sem (ns->sem)==B_INTERRUPTED); + } + + return B_OK; +} + +extern int +fs_write_vnode(fs_nspace *ns, fs_node *node, char r) +{ + return B_OK; +} + +extern int +fs_walk(fs_nspace *ns, fs_node *base, const char *file, char **newpath, vnode_id *vnid) +{ + bool isLink; + fs_node *dummy; + status_t result; + //dprintf("nfs: walk(%s)\n", file);//XXX:mmu_man:debug + + if (!strcmp(".",file)) + { + *vnid=base->vnid; + isLink=false; + } + else + { + fs_node *newNode=(fs_node *)malloc(sizeof(fs_node)); + struct stat st; + + status_t result; + if ((result=nfs_lookup(ns,&base->fhandle,file,&newNode->fhandle,&st))vnid=st.st_ino; + *vnid=newNode->vnid; + + insert_node (ns,newNode); + + isLink=S_ISLNK(st.st_mode); + } + + if ((result=get_vnode (ns->nsid,*vnid,(void **)&dummy))nsid,*vnid); + return result; + } + + path[pathLen]=0; + + result=new_path(path,newpath); + + if (resultnsid,*vnid); + return result; + } + + return put_vnode (ns->nsid,*vnid); + } + + return B_OK; +} + +extern int +fs_opendir(fs_nspace *ns, fs_node *node, nfs_cookie **cookie) +{ + struct stat st; + nfs_fhandle fhandle; + + status_t result; + if ((result=nfs_getattr(ns,&node->fhandle,&st))opaque,0,NFS_COOKIESIZE); + + return B_OK; +} + +extern int +fs_closedir(fs_nspace *ns, fs_node *node, nfs_cookie *cookie) +{ + return B_OK; +} + +extern int +fs_rewinddir(fs_nspace *ns, fs_node *node, nfs_cookie *cookie) +{ + memset (cookie->opaque,0,NFS_COOKIESIZE); + + return B_OK; +} + +extern int +fs_readdir(fs_nspace *ns, fs_node *node, nfs_cookie *cookie, long *num, struct dirent *buf, size_t bufsize) +{ + int32 max=*num; + int32 eof; + + size_t count=min_c(6000,max*300); + + *num=0; + + do + { + vnode_id vnid; + char *filename; + uint8 *replyBuf; + struct XDROutPacket call; + struct XDRInPacket reply; + int32 status; + + XDROutPacketInit (&call); + XDRInPacketInit (&reply); + + XDROutPacketAddFixed (&call,node->fhandle.opaque,NFS_FHSIZE); + XDROutPacketAddFixed (&call,cookie->opaque,NFS_COOKIESIZE); + XDROutPacketAddInt32 (&call,count); + + replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_READDIR,&call); + + if (!replyBuf) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return B_ERROR; + } + + XDRInPacketSetTo(&reply,replyBuf,0); + + if (!is_successful_reply(&reply)) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return B_ERROR; + } + + status=XDRInPacketGetInt32(&reply); + + if (status!=NFS_OK) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return map_nfs_to_system_error(status); + } + + while (XDRInPacketGetInt32(&reply)==1) + { + nfs_cookie newCookie; + + vnid=XDRInPacketGetInt32(&reply); + filename=XDRInPacketGetString(&reply); + + XDRInPacketGetFixed(&reply,newCookie.opaque,NFS_COOKIESIZE); + + //if (strcmp(".",filename)&&strcmp("..",filename)) + //if ((ns->rootid != node->vnid) || (strcmp(".",filename)&&strcmp("..",filename))) + if (conf_ls_root_parent || ((ns->rootid != node->vnid) || strcmp("..",filename))) + { + status_t result; + struct stat st; + + fs_node *newNode=(fs_node *)malloc(sizeof(fs_node)); + newNode->vnid=vnid; + + if ((result=nfs_lookup(ns,&node->fhandle,filename,&newNode->fhandle,&st))d_dev=ns->nsid; + buf->d_pdev=ns->nsid; + buf->d_ino=vnid; + buf->d_pino=node->vnid; + buf->d_reclen=2*(sizeof(dev_t)+sizeof(ino_t))+sizeof(unsigned short)+strlen(filename)+1; + strcpy (buf->d_name,filename); +// if ((ns->rootid == node->vnid))//XXX:mmu_man:test +// dprintf("nfs: dirent %d {d:%ld pd:%ld i:%lld pi:%lld '%s'}\n", *num, buf->d_dev, buf->d_pdev, buf->d_ino, buf->d_pino, buf->d_name); + + bufsize-=buf->d_reclen; + buf=(struct dirent *)((char *)buf+buf->d_reclen); + + memcpy (cookie->opaque,newCookie.opaque,NFS_COOKIESIZE); + + (*num)++; + } + else { + memcpy (cookie->opaque,newCookie.opaque,NFS_COOKIESIZE); + } + + free (filename); + + if ((*num)==max) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return B_OK; + } + } + + eof=XDRInPacketGetInt32(&reply); + + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + } + while (eof==0); + + return B_OK; +} + +extern int +fs_free_dircookie(fs_nspace *ns, fs_node *node, nfs_cookie *cookie) +{ + free(cookie); + return B_OK; +} + +extern int +fs_rstat(fs_nspace *ns, fs_node *node, struct stat *st) +{ + nfs_fhandle fhandle; + + status_t result; + //dprintf("nfs: rstat()\n");//XXX:mmu_man:debug + if ((result=nfs_getattr(ns,&node->fhandle,st))st_dev=ns->nsid; +//st->st_nlink = 1; //XXX:mmu_man:test + return B_OK; +} + +extern void +fs_nspaceInit(struct fs_nspace *nspace) +{ + RPCPendingCallsInit (&nspace->pendingCalls); +} + +extern void +fs_nspaceDestroy(struct fs_nspace *nspace) +{ + RPCPendingCallsDestroy (&nspace->pendingCalls); +} + + +extern int +fs_mount(nspace_id nsid, const char *devname, ulong flags, struct mount_nfs_params *parms, size_t len, fs_nspace **data, vnode_id *vnid) +{ + status_t result; + fs_nspace *ns; + fs_node *rootNode; + struct stat st; + + if (parms==NULL) + return EINVAL; + +dprintf("nfs: mount(%d, %s, %08lx)\n", nsid, devname, flags); +dprintf("nfs: nfs_params(ip:%lu, server:%s, export:%s, uid:%d, gid:%d, hostname:%s)\n", + parms->serverIP, + parms->server, + parms->_export, + parms->uid, + parms->gid, + parms->hostname); + + if (!refcount) + read_config(); + + result = ksocket_init(); + if (result < B_OK) + return result; + + ns=(fs_nspace *)malloc(sizeof(fs_nspace)); + fs_nspaceInit (ns); + + ns->nsid=nsid; + + ns->params.serverIP=parms->serverIP; + ns->params.server=strdup(parms->server); + ns->params._export=strdup(parms->_export); + ns->params.uid=parms->uid; + ns->params.gid=parms->gid; + ns->params.hostname=strdup(parms->hostname); + ns->xid=0; + ns->mountAddr.sin_family=AF_INET; + ns->mountAddr.sin_addr.s_addr=htonl(parms->serverIP); + memset (ns->mountAddr.sin_zero,0,sizeof(ns->mountAddr.sin_zero)); + + + if ((result=create_socket(ns))params.hostname); + free (ns->params._export); + free (ns->params.server); + + fs_nspaceDestroy (ns); + free(ns); + + ksocket_cleanup(); + return result; + } + + if ((result=init_postoffice(ns))s); + free (ns->params.hostname); + free (ns->params._export); + free (ns->params.server); + + fs_nspaceDestroy (ns); + free(ns); + + ksocket_cleanup(); + return result; + } + + if ((result=get_remote_address(ns,MOUNT_PROGRAM,MOUNT_VERSION,PMAP_IPPROTO_UDP,&ns->mountAddr))params.hostname); + free (ns->params._export); + free (ns->params.server); + + fs_nspaceDestroy (ns); + free(ns); + + ksocket_cleanup(); + dprintf("nfs: error getting mountd address from portmapper: %s\n", strerror(result)); + return result; + } + + memcpy (&ns->nfsAddr,&ns->mountAddr,sizeof(ns->mountAddr)); +dprintf("nfs: mountd at %08lx:%d\n", ns->mountAddr.sin_addr.s_addr, ntohs(ns->mountAddr.sin_port)); + + if ((result=get_remote_address(ns,NFS_PROGRAM,NFS_VERSION,PMAP_IPPROTO_UDP,&ns->nfsAddr))params.hostname); + free (ns->params._export); + free (ns->params.server); + + fs_nspaceDestroy (ns); + free(ns); + + ksocket_cleanup(); + dprintf("nfs: error getting nfsd address from portmapper: %s\n", strerror(result)); + return result; + } +dprintf("nfs: nfsd at %08lx:%d\n", ns->nfsAddr.sin_addr.s_addr, ntohs(ns->nfsAddr.sin_port)); +// result = connect_socket(ns); +//dprintf("nfs: connect: %s\n", strerror(result)); + + if ((result=create_sem(1,"nfs_sem"))params.hostname); + free (ns->params._export); + free (ns->params.server); + + fs_nspaceDestroy (ns); + free(ns); + + ksocket_cleanup(); + return result; + } + + ns->sem=result; + + set_sem_owner (ns->sem,B_SYSTEM_TEAM); + + rootNode=(fs_node *)malloc(sizeof(fs_node)); + rootNode->next=NULL; + + if ((result=nfs_mount(ns,ns->params._export,&rootNode->fhandle))sem); + free(rootNode); + shutdown_postoffice(ns); + free (ns->params.hostname); + free (ns->params._export); + free (ns->params.server); + + fs_nspaceDestroy (ns); + free(ns); + + ksocket_cleanup(); + dprintf("nfs: error in nfs_mount: %s\n", strerror(result)); + return result; + } + + if ((result=nfs_getattr(ns,&rootNode->fhandle,&st))sem); + free(rootNode); + shutdown_postoffice(ns); + free (ns->params.hostname); + free (ns->params._export); + free (ns->params.server); + + fs_nspaceDestroy (ns); + free(ns); + + ksocket_cleanup(); + return result; + } + + ns->rootid=st.st_ino; + rootNode->vnid=ns->rootid; + + *vnid=ns->rootid; + + if ((result=new_vnode(nsid,*vnid,rootNode))sem); + free(rootNode); + shutdown_postoffice(ns); + free (ns->params.hostname); + free (ns->params._export); + free (ns->params.server); + + fs_nspaceDestroy (ns); + free(ns); + + ksocket_cleanup(); + return result; + } + + *data=ns; + + ns->first=rootNode; + + return B_OK; +} + +extern int +fs_unmount(fs_nspace *ns) +{ + free (ns->params.hostname); + free (ns->params._export); + free (ns->params.server); + + while (ns->first) + { + fs_node *next=ns->first->next; + free(ns->first); + ns->first=next; + } + + delete_sem (ns->sem); + shutdown_postoffice(ns); + fs_nspaceDestroy (ns); + free(ns); + ksocket_cleanup(); + return B_OK; +} + +extern int +fs_rfsstat(fs_nspace *ns, struct fs_info *info) +{ + struct XDROutPacket call; + struct XDRInPacket reply; + nfs_fhandle rootHandle=handle_from_vnid (ns,ns->rootid); + uint8 *replyBuf; + int32 status; + //dprintf("nfs: rfsstat()\n");//XXX:mmu_man:debug + + XDROutPacketInit (&call); + XDRInPacketInit (&reply); + + XDROutPacketAddFixed (&call,rootHandle.opaque,NFS_FHSIZE); + + replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_STATFS,&call); + + if (!replyBuf) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return EHOSTUNREACH; + } + + XDRInPacketSetTo(&reply,replyBuf,0); + + if (!is_successful_reply(&reply)) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return B_ERROR; + } + + status=XDRInPacketGetInt32(&reply); + + if (status!=NFS_OK) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + //dprintf("nfs: rfsstat() error 0x%08lx\n", map_nfs_to_system_error(status)); + return map_nfs_to_system_error(status); + } + + info->dev=ns->nsid; + info->root=ns->rootid; + info->flags=NFS_FS_FLAGS; + + XDRInPacketGetInt32(&reply); // tsize + + info->block_size=XDRInPacketGetInt32(&reply); + info->io_size=8192; + info->total_blocks=XDRInPacketGetInt32(&reply); + info->free_blocks=XDRInPacketGetInt32(&reply); + info->total_nodes=100; + info->free_nodes=100; + //strcpy (info->device_name,"nfs_device"); + strcpy (info->device_name,""); + strcpy (info->volume_name,"nfs://"); + strcat (info->volume_name,ns->params.server); + strcat (info->volume_name,ns->params._export); + //strcpy (info->fsh_name,"nfs_fsh"); + strcpy (info->fsh_name,"nfs"); + + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return B_OK; +} + +extern int +fs_open(fs_nspace *ns, fs_node *node, int omode, fs_file_cookie **cookie) +{ + struct stat st; + nfs_fhandle fhandle; + + status_t result; + if ((result=nfs_getattr(ns,&node->fhandle,&st))omode=omode; + (*cookie)->original_size=st.st_size; + (*cookie)->st=st; + + return B_OK; +} + +extern int +fs_close(fs_nspace *ns, fs_node *node, fs_file_cookie *cookie) +{ +/* //XXX:mmu_man:why that ?? makes Tracker go nuts updating the stats + if ((cookie->omode & O_RDWR)||(cookie->omode & O_WRONLY)) + return my_notify_listener (B_STAT_CHANGED,ns->nsid,0,0,node->vnid,NULL); +*/ + return B_OK; +} + +extern int +fs_free_cookie(fs_nspace *ns, fs_node *node, fs_file_cookie *cookie) +{ + if (cookie) + free(cookie); + return B_OK; +} + +extern int +fs_read(fs_nspace *ns, fs_node *node, fs_file_cookie *cookie, off_t pos, void *buf, size_t *len) +{ + size_t max=*len; + *len=0; + + if (!cookie) return EISDIR; /* do not permit reading of directories */ + while ((*len)fhandle.opaque,NFS_FHSIZE); + XDROutPacketAddInt32 (&call,pos); + XDROutPacketAddInt32 (&call,count); + XDROutPacketAddInt32 (&call,0); + + replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_READ,&call); + + if (!replyBuf) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return B_ERROR; + } + + XDRInPacketSetTo(&reply,replyBuf,0); + + if (!is_successful_reply(&reply)) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return B_ERROR; + } + + status=XDRInPacketGetInt32(&reply); + + if (status!=NFS_OK) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return map_nfs_to_system_error(status); + } + + get_nfs_attr (&reply,&st); + + cookie->st=st; + + readbytes=XDRInPacketGetDynamic(&reply,buf); + + buf=(char *)buf+readbytes; + (*len)+=readbytes; + pos+=readbytes; + + if (pos>=st.st_size) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + break; + } + + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + } + + return B_OK; +} + +extern int +fs_write(fs_nspace *ns, fs_node *node, fs_file_cookie *cookie, off_t pos, const void *buf, size_t *len) +{ + size_t bytesWritten=0; + + if (!cookie) return EISDIR; /* do not permit reading of directories */ + if (cookie->omode & O_APPEND) + pos+=cookie->original_size; + + while (bytesWritten<*len) + { + size_t count=min_c(NFS_MAXDATA,(*len)-bytesWritten); + + struct XDROutPacket call; + struct XDRInPacket reply; + int32 status; + uint8 *replyBuf; + struct stat st; + + XDROutPacketInit (&call); + XDRInPacketInit (&reply); + + XDROutPacketAddFixed (&call,&node->fhandle.opaque,NFS_FHSIZE); + XDROutPacketAddInt32 (&call,0); + XDROutPacketAddInt32 (&call,pos+bytesWritten); + XDROutPacketAddInt32 (&call,0); + XDROutPacketAddDynamic (&call,(const char *)buf+bytesWritten,count); + + replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_WRITE,&call); + + if (!replyBuf) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return B_ERROR; + } + + XDRInPacketSetTo (&reply,replyBuf,0); + + if (!is_successful_reply(&reply)) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return B_ERROR; + } + + status=XDRInPacketGetInt32(&reply); + + if (status!=NFS_OK) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return map_nfs_to_system_error(status); + } + + get_nfs_attr (&reply,&st); + + cookie->st=st; + + bytesWritten+=count; + + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + } + + return B_OK; +} + +extern int +fs_wstat(fs_nspace *ns, fs_node *node, struct stat *st, long mask) +{ + struct XDROutPacket call; + struct XDRInPacket reply; + + uint8 *replyBuf; + int32 status; + + XDROutPacketInit (&call); + XDRInPacketInit (&reply); + + XDROutPacketAddFixed (&call,node->fhandle.opaque,NFS_FHSIZE); + + XDROutPacketAddInt32 (&call,(mask & WSTAT_MODE) ? st->st_mode : -1); + XDROutPacketAddInt32 (&call,(mask & WSTAT_UID) ? st->st_uid : -1); + XDROutPacketAddInt32 (&call,(mask & WSTAT_GID) ? st->st_gid : -1); + XDROutPacketAddInt32 (&call,(mask & WSTAT_SIZE) ? st->st_size : -1); + XDROutPacketAddInt32 (&call,(mask & WSTAT_ATIME) ? st->st_atime : -1); + XDROutPacketAddInt32 (&call,(mask & WSTAT_ATIME) ? 0 : -1); + XDROutPacketAddInt32 (&call,(mask & WSTAT_MTIME) ? st->st_mtime : -1); + XDROutPacketAddInt32 (&call,(mask & WSTAT_MTIME) ? 0 : -1); + + replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_SETATTR,&call); + + if (!replyBuf) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return EHOSTUNREACH; + } + + XDRInPacketSetTo (&reply,replyBuf,0); + + if (!is_successful_reply(&reply)) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return B_ERROR; + } + + status=XDRInPacketGetInt32(&reply); + + if (status!=NFS_OK) + return map_nfs_to_system_error(status); + + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return my_notify_listener (B_STAT_CHANGED,ns->nsid,0,0,node->vnid,NULL); +} + +extern int +fs_wfsstat(fs_nspace *ns, struct fs_info *info, long mask) +{ + return B_OK; +} + +extern int +fs_create(fs_nspace *ns, fs_node *dir, const char *name, int omode, int perms, vnode_id *vnid, + fs_file_cookie **cookie) +{ + nfs_fhandle fhandle; + struct stat st; + + status_t result; + result=nfs_lookup(ns,&dir->fhandle,name,&fhandle,&st); + + if (result==B_OK) + { + void *dummy; + fs_node *newNode=(fs_node *)malloc(sizeof(fs_node)); + newNode->fhandle=fhandle; + newNode->vnid=st.st_ino; + insert_node (ns,newNode); + + *vnid=st.st_ino; + + if ((result=get_vnode(ns->nsid,*vnid,&dummy))omode=omode; + (*cookie)->original_size=st.st_size; + (*cookie)->st=st; + + return B_OK; + } + else if (result!=ENOENT) + return result; + else + { + struct XDROutPacket call; + struct XDRInPacket reply; + + uint8 *replyBuf; + int32 status; + + fs_node *newNode; + + if (!(omode & O_CREAT)) + return ENOENT; + + XDROutPacketInit (&call); + XDRInPacketInit (&reply); + + XDROutPacketAddFixed (&call,dir->fhandle.opaque,NFS_FHSIZE); + XDROutPacketAddString(&call,name); + XDROutPacketAddInt32 (&call,perms|S_IFREG); + XDROutPacketAddInt32 (&call,-1); + XDROutPacketAddInt32 (&call,-1); + XDROutPacketAddInt32 (&call,0); + XDROutPacketAddInt32 (&call,time(NULL)); + XDROutPacketAddInt32 (&call,0); + XDROutPacketAddInt32 (&call,time(NULL)); + XDROutPacketAddInt32 (&call,0); + + replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_CREATE,&call); + + if (!replyBuf) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return B_ERROR; + } + + XDRInPacketSetTo (&reply,replyBuf,0); + + if (!is_successful_reply(&reply)) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return B_ERROR; + } + + status=XDRInPacketGetInt32(&reply); + + if (status!=NFS_OK) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return map_nfs_to_system_error(status); + } + + XDRInPacketGetFixed (&reply,fhandle.opaque,NFS_FHSIZE); + + get_nfs_attr (&reply,&st); + + newNode=(fs_node *)malloc(sizeof(fs_node)); + newNode->fhandle=fhandle; + newNode->vnid=st.st_ino; + + insert_node (ns,newNode); + + *vnid=st.st_ino; + *cookie=(fs_file_cookie *)malloc(sizeof(fs_file_cookie)); + (*cookie)->omode=omode; + (*cookie)->original_size=st.st_size; + (*cookie)->st=st; + + result=new_vnode (ns->nsid,*vnid,newNode); + + if (resultnsid,dir->vnid,0,*vnid,name); + } +} + +extern int +fs_unlink(fs_nspace *ns, fs_node *dir, const char *name) +{ + status_t result; + fs_node *newNode; + fs_node *dummy; + + struct XDROutPacket call; + struct XDRInPacket reply; + + struct stat st; + nfs_fhandle fhandle; + uint8 *replyBuf; + + int32 status; + + XDROutPacketInit (&call); + XDRInPacketInit (&reply); + + if ((result=nfs_lookup(ns,&dir->fhandle,name,&fhandle,&st))fhandle=fhandle; + newNode->vnid=st.st_ino; + + insert_node (ns,newNode); + + if ((result=get_vnode(ns->nsid,st.st_ino,(void **)&dummy))nsid,st.st_ino))nsid,st.st_ino))fhandle.opaque,NFS_FHSIZE); + XDROutPacketAddString(&call,name); + + replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_REMOVE,&call); + + if (!replyBuf) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return EHOSTUNREACH; + } + + XDRInPacketSetTo(&reply,replyBuf,0); + + if (!is_successful_reply(&reply)) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return B_ERROR; + } + + status=XDRInPacketGetInt32(&reply); + + if (status!=NFS_OK) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return map_nfs_to_system_error(status); + } + + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + + return my_notify_listener (B_ENTRY_REMOVED,ns->nsid,dir->vnid,0,st.st_ino,name); +} + +extern int +fs_remove_vnode(fs_nspace *ns, fs_node *node, char r) +{ + remove_node (ns,node->vnid); + + return B_OK; +} + +extern int +fs_secure_vnode(fs_nspace *ns, fs_node *node) +{ + return B_OK; +} + +extern int +fs_mkdir(fs_nspace *ns, fs_node *dir, const char *name, int perms) +{ + nfs_fhandle fhandle; + struct stat st; + fs_node *newNode; + + status_t result; + uint8 *replyBuf; + int32 status; + + struct XDROutPacket call; + struct XDRInPacket reply; + + XDROutPacketInit (&call); + XDRInPacketInit (&reply); + + result=nfs_lookup(ns,&dir->fhandle,name,&fhandle,&st); + + if (result==B_OK) + { + void *dummy; + if ((result=get_vnode(ns->nsid,st.st_ino,&dummy))fhandle.opaque,NFS_FHSIZE); + XDROutPacketAddString(&call,name); + XDROutPacketAddInt32 (&call,perms|S_IFDIR); + XDROutPacketAddInt32 (&call,-1); + XDROutPacketAddInt32 (&call,-1); + XDROutPacketAddInt32 (&call,-1); + XDROutPacketAddInt32 (&call,time(NULL)); + XDROutPacketAddInt32 (&call,0); + XDROutPacketAddInt32 (&call,time(NULL)); + XDROutPacketAddInt32 (&call,0); + + replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_MKDIR,&call); + + if (!replyBuf) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return B_ERROR; + } + + XDRInPacketSetTo (&reply,replyBuf,0); + + if (!is_successful_reply(&reply)) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return B_ERROR; + } + + status=XDRInPacketGetInt32(&reply); + + if (status!=NFS_OK) + { + XDROutPacketDestroy (&call); + return map_nfs_to_system_error(status); + } + + XDRInPacketGetFixed(&reply,fhandle.opaque,NFS_FHSIZE); + + get_nfs_attr (&reply,&st); + + newNode=(fs_node *)malloc(sizeof(fs_node)); + newNode->fhandle=fhandle; + newNode->vnid=st.st_ino; + + insert_node (ns,newNode); + + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + + return my_notify_listener (B_ENTRY_CREATED,ns->nsid,dir->vnid,0,st.st_ino,name); +} + +extern int +fs_rename(fs_nspace *ns, fs_node *olddir, const char *oldname, fs_node *newdir, const char *newname) +{ + struct stat st; + nfs_fhandle fhandle; + status_t result; + struct XDROutPacket call; + struct XDRInPacket reply; + int32 status; + uint8 *replyBuf; + + XDROutPacketInit (&call); + XDRInPacketInit (&reply); + + if ((result=nfs_lookup(ns,&newdir->fhandle,newname,&fhandle,&st))==B_OK) + { + if (S_ISREG(st.st_mode)) + result=fs_unlink (ns,newdir,newname); + else + result=fs_rmdir (ns,newdir,newname); + + if (resultfhandle,oldname,&fhandle,&st))fhandle.opaque,NFS_FHSIZE); + XDROutPacketAddString(&call,oldname); + XDROutPacketAddFixed (&call,newdir->fhandle.opaque,NFS_FHSIZE); + XDROutPacketAddString(&call,newname); + + replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_RENAME,&call); + + if (!replyBuf) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return EHOSTUNREACH; + } + + XDRInPacketSetTo (&reply,replyBuf,0); + + if (!is_successful_reply(&reply)) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return B_ERROR; + } + + status=XDRInPacketGetInt32(&reply); + + if (status!=NFS_OK) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return map_nfs_to_system_error(status); + } + + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + + return my_notify_listener (B_ENTRY_MOVED,ns->nsid,olddir->vnid,newdir->vnid,st.st_ino,newname); +} + +extern int +fs_rmdir(fs_nspace *ns, fs_node *dir, const char *name) +{ + status_t result; + fs_node *newNode; + fs_node *dummy; + struct XDROutPacket call; + struct XDRInPacket reply; + int32 status; + uint8 *replyBuf; + + struct stat st; + nfs_fhandle fhandle; + + XDROutPacketInit(&call); + XDRInPacketInit(&reply); + + if ((result=nfs_lookup(ns,&dir->fhandle,name,&fhandle,&st))fhandle=fhandle; + newNode->vnid=st.st_ino; + + insert_node (ns,newNode); + + if ((result=get_vnode(ns->nsid,st.st_ino,(void **)&dummy))nsid,st.st_ino))nsid,st.st_ino))fhandle.opaque,NFS_FHSIZE); + XDROutPacketAddString(&call,name); + + replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_RMDIR,&call); + + if (!replyBuf) + { + XDRInPacketDestroy(&reply); + XDROutPacketDestroy(&call); + return EHOSTUNREACH; + } + + XDRInPacketSetTo (&reply,replyBuf,0); + + if (!is_successful_reply(&reply)) + { + XDRInPacketDestroy(&reply); + XDROutPacketDestroy(&call); + return B_ERROR; + } + + status=XDRInPacketGetInt32(&reply); + + if (status!=NFS_OK) + { + XDRInPacketDestroy(&reply); + XDROutPacketDestroy(&call); + return map_nfs_to_system_error(status); + } + + XDRInPacketDestroy(&reply); + XDROutPacketDestroy(&call); + return my_notify_listener (B_ENTRY_REMOVED,ns->nsid,dir->vnid,0,st.st_ino,name); +} + +extern int +fs_readlink(fs_nspace *ns, fs_node *node, char *buf, size_t *bufsize) +{ + struct XDROutPacket call; + uint8 *replyBuf; + int32 status; + size_t length; + char data[NFS_MAXPATHLEN]; + struct XDRInPacket reply; + + XDROutPacketInit (&call); + XDRInPacketInit(&reply); + + XDROutPacketAddFixed (&call,node->fhandle.opaque,NFS_FHSIZE); + + replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_READLINK,&call); + + if (!replyBuf) + { + XDRInPacketDestroy(&reply); + XDROutPacketDestroy (&call); + return EHOSTUNREACH; + } + + XDRInPacketSetTo (&reply,replyBuf,0); + + if (!is_successful_reply(&reply)) + { + XDRInPacketDestroy(&reply); + XDROutPacketDestroy (&call); + return B_ERROR; + } + + status=XDRInPacketGetInt32(&reply); + + if (status!=NFS_OK) + { + XDRInPacketDestroy(&reply); + XDROutPacketDestroy (&call); + return map_nfs_to_system_error(status); + } + + length=XDRInPacketGetDynamic(&reply,data); + + length=min_c(length,*bufsize); + memcpy (buf,data,length); + *bufsize=length; + + XDRInPacketDestroy(&reply); + XDROutPacketDestroy (&call); + return B_OK; +} + +extern int +fs_symlink(fs_nspace *ns, fs_node *dir, const char *name, const char *path) +{ + nfs_fhandle fhandle; + struct stat st; + struct XDROutPacket call; + struct XDRInPacket reply; + status_t result; + uint8 *replyBuf; + int32 status; + fs_node *newNode; + + XDROutPacketInit (&call); + XDRInPacketInit (&reply); + + result=nfs_lookup(ns,&dir->fhandle,name,&fhandle,&st); + + if (result==B_OK) + { + void *dummy; + if ((result=get_vnode(ns->nsid,st.st_ino,&dummy))fhandle.opaque,NFS_FHSIZE); + XDROutPacketAddString(&call,name); + XDROutPacketAddString(&call,path); + XDROutPacketAddInt32 (&call,S_IFLNK); + XDROutPacketAddInt32 (&call,-1); + XDROutPacketAddInt32 (&call,-1); + XDROutPacketAddInt32 (&call,-1); + XDROutPacketAddInt32 (&call,time(NULL)); + XDROutPacketAddInt32 (&call,0); + XDROutPacketAddInt32 (&call,time(NULL)); + XDROutPacketAddInt32 (&call,0); + + replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_SYMLINK,&call); + + if (!replyBuf) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return B_ERROR; + } + + XDRInPacketSetTo (&reply,replyBuf,0); + + if (!is_successful_reply(&reply)) + { + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return B_ERROR; + } + + status=XDRInPacketGetInt32(&reply); + +/* if (status!=NFS_OK) + return map_nfs_to_system_error(status); + + ignore status here, weird thing, nfsservers that is +*/ + + result=nfs_lookup(ns,&dir->fhandle,name,&fhandle,&st); + + if (resultfhandle=fhandle; + newNode->vnid=st.st_ino; + + insert_node (ns,newNode); + + result=my_notify_listener (B_ENTRY_CREATED,ns->nsid,dir->vnid,0,st.st_ino,name); + + XDRInPacketDestroy (&reply); + XDROutPacketDestroy (&call); + return result; +} + +int fs_access(void *ns, void *node, int mode) +{ + return B_OK; +} + diff --git a/src/add-ons/kernel/file_systems/nfs/nfs_add_on.h b/src/add-ons/kernel/file_systems/nfs/nfs_add_on.h new file mode 100644 index 0000000000..8dff5a84a2 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs/nfs_add_on.h @@ -0,0 +1,149 @@ +#ifndef _NFS_ADD_ON_H + +#define _NFS_ADD_ON_H + +#include "fsproto.h" +#include "RPCPendingCalls.h" +#include "XDROutPacket.h" +#include "XDRInPacket.h" +#include "nfs.h" + +#include +#include +#include + +struct mount_nfs_params +{ + unsigned int serverIP; + char *server; + char *_export; + uid_t uid; + gid_t gid; + char *hostname; +}; + +struct fs_node +{ + vnode_id vnid; + struct nfs_fhandle fhandle; + struct fs_node *next; +}; + +struct fs_nspace +{ + nspace_id nsid; + + thread_id tid; + bool quit; + int s; + struct RPCPendingCalls pendingCalls; + + struct sockaddr_in mountAddr,nfsAddr; + + int32 xid; + + vnode_id rootid; + + sem_id sem; + struct fs_node *first; + + struct mount_nfs_params params; + + bigtime_t last_rfsstat; + +}; + +void fs_nspaceInit (struct fs_nspace *nspace); +void fs_nspaceDestroy (struct fs_nspace *nspace); + +struct fs_file_cookie +{ + int omode; + off_t original_size; + struct stat st; +}; + +typedef struct fs_nspace fs_nspace; +typedef struct fs_node fs_node; +typedef struct nfs_cookie nfs_cookie; +typedef struct fs_file_cookie fs_file_cookie; +typedef struct nfs_fhandle nfs_fhandle; + +int fs_read_vnode(fs_nspace *ns, vnode_id vnid, char r, fs_node **node); +int fs_write_vnode(fs_nspace *ns, fs_node *node, char r); + +int fs_walk(fs_nspace *ns, fs_node *base, const char *file, char **newpath, + vnode_id *vnid); + +int fs_opendir(fs_nspace *ns, fs_node *node, nfs_cookie **cookie); +int fs_closedir(fs_nspace *ns, fs_node *node, nfs_cookie *cookie); +int fs_rewinddir(fs_nspace *ns, fs_node *node, nfs_cookie *cookie); +int fs_readdir(fs_nspace *ns, fs_node *node, nfs_cookie *cookie, long *num, + struct dirent *buf, size_t bufsize); + +int fs_free_dircookie(fs_nspace *ns, fs_node *node, nfs_cookie *cookie); +int fs_rstat(fs_nspace *ns, fs_node *node, struct stat *); +int fs_mount(nspace_id nsid, const char *devname, ulong flags, + struct mount_nfs_params *parms, size_t len, fs_nspace **data, vnode_id *vnid); +int fs_unmount(fs_nspace *ns); +int fs_rfsstat(fs_nspace *ns, struct fs_info *); + +int fs_open(fs_nspace *ns, fs_node *node, int omode, fs_file_cookie **cookie); +int fs_close(fs_nspace *ns, fs_node *node, fs_file_cookie *cookie); +int fs_free_cookie(fs_nspace *ns, fs_node *node, fs_file_cookie *cookie); +int fs_read(fs_nspace *ns, fs_node *node, fs_file_cookie *cookie, off_t pos, void *buf, + size_t *len); + +int fs_write(fs_nspace *ns, fs_node *node, fs_file_cookie *cookie, off_t pos, + const void *buf, size_t *len); + +int fs_wstat(fs_nspace *ns, fs_node *node, struct stat *, long mask); +int fs_wfsstat(fs_nspace *ns, struct fs_info *, long mask); +int fs_create(fs_nspace *ns, fs_node *dir, const char *name, + int omode, int perms, vnode_id *vnid, fs_file_cookie **cookie); + +int fs_unlink(fs_nspace *ns, fs_node *dir, const char *name); +int fs_remove_vnode(fs_nspace *ns, fs_node *node, char r); +int fs_secure_vnode(fs_nspace *ns, fs_node *node); + +int fs_mkdir(fs_nspace *ns, fs_node *dir, const char *name, int perms); + +int fs_rename(fs_nspace *ns, fs_node *olddir, const char *oldname, + fs_node *newdir, const char *newname); + +int fs_rmdir(fs_nspace *ns, fs_node *dir, const char *name); +int fs_readlink(fs_nspace *ns, fs_node *node, char *buf, size_t *bufsize); + +int fs_symlink(fs_nspace *ns, fs_node *dir, const char *name, + const char *path); + +status_t create_socket (fs_nspace *ns); +status_t init_postoffice (fs_nspace *ns); +void shutdown_postoffice (fs_nspace *ns); +status_t postoffice_func (fs_nspace *ns); + +extern uint8 *send_rpc_call(fs_nspace *ns, const struct sockaddr_in *addr, int32 prog, int32 vers, int32 proc, const struct XDROutPacket *packet); +extern bool is_successful_reply(struct XDRInPacket *reply); +extern status_t get_remote_address(fs_nspace *ns, int32 prog, int32 vers, int32 prot, struct sockaddr_in *addr); +extern status_t nfs_mount(fs_nspace *ns, const char *path, nfs_fhandle *fhandle); +extern status_t map_nfs_to_system_error(status_t nfsstatus); +extern void get_nfs_attr(struct XDRInPacket *reply, struct stat *st); +extern status_t nfs_lookup(fs_nspace *ns, const nfs_fhandle *dir, const char *filename, nfs_fhandle *fhandle, struct stat *st); +extern status_t nfs_truncate_file(fs_nspace *ns, const nfs_fhandle *fhandle, struct stat *st); + +nfs_fhandle handle_from_vnid (fs_nspace *ns, vnode_id vnid); + +extern status_t nfs_getattr(fs_nspace *ns, const nfs_fhandle *fhandle, struct stat *st); +extern void insert_node(fs_nspace *ns, fs_node *node); +extern void remove_node(fs_nspace *ns, vnode_id vnid); + +extern int fs_access(void *ns, void *node, int mode); + +enum +{ + C_ERROR_STALE=B_ERRORS_END+1 +}; + +#define USE_SYSTEM_AUTHENTICATION 1 + +#endif diff --git a/src/add-ons/kernel/file_systems/nfs/pmap.h b/src/add-ons/kernel/file_systems/nfs/pmap.h new file mode 100644 index 0000000000..daa0a2e376 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs/pmap.h @@ -0,0 +1,22 @@ +#ifndef _PMAP_H + +#define _PMAP_H + +const int32 PMAP_PORT = 111; /* portmapper port number */ +const int32 PMAP_VERSION = 2; +const int32 PMAP_PROGRAM = 100000; + +const int32 PMAP_IPPROTO_TCP = 6; /* protocol number for TCP/IP */ +const int32 PMAP_IPPROTO_UDP = 17; /* protocol number for UDP/IP */ + +enum +{ + PMAPPROC_NULL = 0, + PMAPPROC_SET = 1, + PMAPPROC_UNSET = 2, + PMAPPROC_GETPORT = 3, + PMAPPROC_DUMP = 4, + PMAPPROC_CALLIT = 5 +}; + +#endif diff --git a/src/add-ons/kernel/file_systems/nfs/rpc.h b/src/add-ons/kernel/file_systems/nfs/rpc.h new file mode 100644 index 0000000000..4d8f9e1285 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs/rpc.h @@ -0,0 +1,60 @@ +#ifndef _RPC_H + +#define _RPC_H + +const int32 RPC_VERSION = 2; + +typedef enum rpc_auth_flavor +{ + RPC_AUTH_NONE = 0, + RPC_AUTH_SYS = 1, + RPC_AUTH_SHORT = 2 +} rpc_auth_flavor; + +typedef enum rpc_msg_type +{ + RPC_CALL = 0, + RPC_REPLY = 1 +} rpc_msg_type; + +typedef enum rpc_reply_stat +{ + RPC_MSG_ACCEPTED = 0, + RPC_MSG_DENIED = 1 +} rpc_reply_stat; + +typedef enum rpc_accept_stat +{ + RPC_SUCCESS = 0, /* RPC executed successfully */ + RPC_PROG_UNAVAIL = 1, /* remote hasn't exported program */ + RPC_PROG_MISMATCH = 2, /* remote can't support version # */ + RPC_PROC_UNAVAIL = 3, /* program can't support procedure */ + RPC_GARBAGE_ARGS = 4, /* procedure can't decode params */ + RPC_SYSTEM_ERR = 5 /* errors like memory allocation failure */ +} rpc_accept_stat; + +typedef enum rpc_reject_stat +{ + RPC_RPC_MISMATCH = 0, /* RPC version number != 2 */ + RPC_AUTH_ERROR = 1 /* remote can't authenticate caller */ +} rpc_reject_stat; + +typedef enum rpc_auth_stat +{ + RPC_AUTH_OK = 0, /* success */ + /* + * failed at remote end + */ + RPC_AUTH_BADCRED = 1, /* bad credential (seal broken) */ + RPC_AUTH_REJECTEDCRED = 2, /* client must begin new session */ + RPC_AUTH_BADVERF = 3, /* bad verifier (seal broken) */ + RPC_AUTH_REJECTEDVERF = 4, /* verifier expired or replayed */ + RPC_AUTH_TOOWEAK = 5, /* rejected for security reasons */ + /* + * failed locally + */ + RPC_AUTH_INVALIDRESP = 6, /* bogus response verifier */ + RPC_AUTH_FAILED = 7 /* reason unknown */ +} rpc_auth_stat; + +#endif