nfs_add_on.c revision 34b5fabe
1#include <posix/stdlib.h>
2
3#include "nfs_add_on.h"
4#include "ksocket.h"
5
6#include "rpc.h"
7#include "pmap.h"
8#include "nfs.h"
9#include "mount.h"
10#include <errno.h>
11#include <string.h>
12#include <KernelExport.h>
13#include <driver_settings.h>
14#include <sys/stat.h>
15#include <dirent.h>
16#include <SupportDefs.h>
17#include <ByteOrder.h>
18#include <netinet/udp.h>
19
20/* Haiku requires a string for mount params... */
21#define PARAMS_AS_STRING 1
22
23#ifndef UDP_SIZE_MAX
24#define UDP_SIZE_MAX 65515
25#endif
26#define B_UDP_MAX_SIZE UDP_SIZE_MAX
27
28/* declare gSocket and others */
29KSOCKET_MODULE_DECL;
30
31/* *** configuration *** */
32
33//#define NFS_FS_FLAGS B_FS_IS_SHARED
34#define NFS_FS_FLAGS B_FS_IS_SHARED|B_FS_IS_PERSISTENT
35
36/* port numbers: most NFS servers insist on the client port to be < 1024 (secure option) */
37/* ports to bind() to; we start at conf_high_port, then go down */
38static int16 conf_high_port = 1023;
39static int16 conf_low_port = 900;
40
41/* Allow open() to open directories too */
42static bool conf_allow_dir_open = true;
43
44/* Do we list ".." in readdir(rootid) ? (the VFS corrects the dirents anyway) */
45/* this seems to be mandatory for Dano... BEntry::GetPath() needs that */
46static bool conf_ls_root_parent = true;
47
48/* timeout when waiting for an answer to a call */
49static bigtime_t conf_call_timeout = 2000000;
50
51/* number of retries when waiting for an anwser to a call */
52static unsigned long conf_call_tries = 3;
53
54/* don't check who the answers come from for requests */
55bool conf_no_check_ip_xid = false;
56
57/* *** DEBUG stuff *** */
58//#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); })
59#define my_notify_listener notify_listener
60
61static vint32 refcount = 0; /* we only want to read the config once ? */
62
63static status_t read_config(void)
64{
65	void *handle;
66	const char *str, *endptr;
67	int32 value = 0;
68
69	handle = load_driver_settings("nfs");
70	if (handle == NULL)
71		return ENOENT;
72
73	str = get_driver_parameter(handle, "high_port", NULL, NULL);
74	if (str) {
75		endptr = str + strlen(str);
76		conf_high_port = (int16)strtoul(str, &endptr, 10);
77	}
78	str = get_driver_parameter(handle, "low_port", NULL, NULL);
79	if (str) {
80		endptr = str + strlen(str);
81		conf_low_port = (int16)strtoul(str, &endptr, 10);
82	}
83
84	conf_allow_dir_open = get_driver_boolean_parameter(handle, "allow_dir_open", conf_allow_dir_open, true);
85	conf_ls_root_parent = get_driver_boolean_parameter(handle, "ls_root_parent", conf_ls_root_parent, false);
86	conf_no_check_ip_xid = get_driver_boolean_parameter(handle, "no_check_ip_xid", conf_no_check_ip_xid, false);
87
88	str = get_driver_parameter(handle, "call_timeout", NULL, NULL);
89	if (str) {
90		endptr = str + strlen(str);
91		conf_call_timeout = (bigtime_t)1000 * strtoul(str, &endptr, 10);
92		if (conf_call_timeout < 1000)
93			conf_call_timeout = 1000;
94	}
95
96	str = get_driver_parameter(handle, "call_tries", NULL, NULL);
97	if (str) {
98		endptr = str + strlen(str);
99		conf_call_tries = strtoul(str, &endptr, 10);
100	}
101
102	unload_driver_settings(handle);
103	return B_OK;
104}
105
106extern status_t
107create_socket(fs_nspace *ns)
108{
109	struct sockaddr_in addr;
110	uint16 port=conf_high_port;
111
112	ns->s=ksocket(AF_INET,SOCK_DGRAM,0);
113
114	if (ns->s<0)
115		return errno;
116
117	do
118	{
119		addr.sin_family=AF_INET;
120		addr.sin_addr.s_addr=htonl(INADDR_ANY);
121		//addr.sin_addr.s_addr=htonl(INADDR_LOOPBACK);
122		addr.sin_port=htons(port);
123		memset (addr.sin_zero,0,sizeof(addr.sin_zero));
124
125		if (kbind(ns->s,(const struct sockaddr *)&addr,sizeof(addr))<0)
126		{
127			if (errno!=EADDRINUSE)
128			{
129				int result=errno;
130				kclosesocket(ns->s);
131				return result;
132			}
133
134			port--;
135			if (port==conf_low_port)
136			{
137				kclosesocket(ns->s);
138				return B_ERROR;
139			}
140		}
141		else
142			break;//return B_OK;
143	}
144	while (true);
145
146	// doesn't seem to help with autoincrementing port on source address...
147	addr.sin_addr = ns->mountAddr.sin_addr;
148	addr.sin_port = htons(111);
149	//kconnect(ns->s,(const struct sockaddr *)&addr,sizeof(addr));
150
151	return B_OK;
152}
153
154extern status_t
155connect_socket(fs_nspace *ns)
156{
157	uint16 port=conf_high_port;
158
159	struct sockaddr_in addr;
160	addr.sin_family=AF_INET;
161	addr.sin_addr.s_addr=htonl(INADDR_ANY);
162	//addr.sin_addr.s_addr=htonl(INADDR_LOOPBACK);
163	addr.sin_port=htons(port);
164	memset (addr.sin_zero,0,sizeof(addr.sin_zero));
165
166	if (kconnect(ns->s,(const struct sockaddr *)&ns->nfsAddr,sizeof(ns->nfsAddr))<0)
167	{
168		return -1;
169	}
170	return B_OK;
171}
172
173extern status_t
174init_postoffice(fs_nspace *ns)
175{
176	status_t result;
177
178	ns->tid=spawn_kernel_thread ((thread_func)postoffice_func,"NFSv2 Postoffice",B_NORMAL_PRIORITY,ns);
179
180	if (ns->tid<B_OK)
181		return ns->tid;
182
183	ns->quit=false;
184
185	result=resume_thread (ns->tid);
186
187	if (result<B_OK)
188	{
189		kill_thread (ns->tid);
190
191		return result;
192	}
193
194	return B_OK;
195}
196
197extern void
198shutdown_postoffice(fs_nspace *ns)
199{
200	struct sockaddr addr;
201	int addrSize;
202	status_t result;
203
204	ns->quit=true;
205	kclosesocket(ns->s);
206
207	wait_for_thread (ns->tid,&result);
208}
209
210extern status_t
211postoffice_func(fs_nspace *ns)
212{
213	uint8 *buffer=(uint8 *)malloc(B_UDP_MAX_SIZE);
214
215	while (!ns->quit)
216	{
217		struct sockaddr_in from;
218		int fromLen=sizeof(from);
219
220		ssize_t bytes=krecvfrom (ns->s,buffer,B_UDP_MAX_SIZE,0,(struct sockaddr *)&from,&fromLen);
221
222		if (bytes>=4)
223		{
224			struct PendingCall *call;
225			int32 xid=B_BENDIAN_TO_HOST_INT32(*((int32 *)buffer));
226
227			call=RPCPendingCallsFindAndRemovePendingCall(&ns->pendingCalls,xid,&from);
228
229			if (call)
230			{
231				call->buffer=(uint8 *)malloc(bytes);
232				memcpy (call->buffer,buffer,bytes);
233
234				while (release_sem (call->sem)==B_INTERRUPTED);
235			} else {
236				dprintf("nfs: postoffice: can't find pending call to remove for xid %d\n", xid);
237			}
238		}
239	}
240
241	free (buffer);
242
243	return B_OK;
244}
245
246uint8 *send_rpc_call (fs_nspace *ns, const struct sockaddr_in *addr,
247							int32 prog, int32 vers, int32 proc,
248							const struct XDROutPacket *packet)
249{
250	int32 xid;
251	size_t authSize;
252	struct PendingCall *pending;
253	int32 retries=conf_call_tries;
254	status_t result;
255	struct PendingCall *call;
256
257	struct XDROutPacket rpc_call;
258	XDROutPacketInit (&rpc_call);
259
260	xid=atomic_add(&ns->xid,1);
261#ifdef DEBUG_XID
262	//dbgprintxid(logfd1, xid);
263#endif
264
265	XDROutPacketAddInt32(&rpc_call,xid);
266	XDROutPacketAddInt32(&rpc_call,RPC_CALL);
267	XDROutPacketAddInt32(&rpc_call,RPC_VERSION);
268	XDROutPacketAddInt32(&rpc_call,prog);
269	XDROutPacketAddInt32(&rpc_call,vers);
270	XDROutPacketAddInt32(&rpc_call,proc);
271
272#if !defined(USE_SYSTEM_AUTHENTICATION)
273	XDROutPacketAddInt32(&rpc_call,RPC_AUTH_NONE);
274	XDROutPacketAddDynamic (&rpc_call,NULL,0);
275#else
276	XDROutPacketAddInt32(&rpc_call,RPC_AUTH_SYS);
277	authSize=4+4+((strlen(ns->params.server)+3)&~3)+4+4+4;
278	XDROutPacketAddInt32(&rpc_call,authSize);
279	XDROutPacketAddInt32(&rpc_call,0);
280	XDROutPacketAddString(&rpc_call,ns->params.server);
281	XDROutPacketAddInt32(&rpc_call,ns->params.uid);
282	XDROutPacketAddInt32(&rpc_call,ns->params.gid);
283	XDROutPacketAddInt32(&rpc_call,0);
284#endif
285
286	XDROutPacketAddInt32(&rpc_call,RPC_AUTH_NONE);
287	XDROutPacketAddDynamic (&rpc_call,NULL,0);
288
289	XDROutPacketAppend (&rpc_call,packet);
290
291	pending=RPCPendingCallsAddPendingCall(&ns->pendingCalls,xid,addr);
292#ifdef DEBUG_XID
293	checksemstate(xid, pending->sem, 0);
294#endif
295
296	do
297	{
298		ssize_t bytes;
299		do
300		{
301			bytes=ksendto (ns->s,(const void *)XDROutPacketBuffer(&rpc_call),
302								XDROutPacketLength(&rpc_call),0,
303							(const struct sockaddr *)addr,sizeof(*addr));
304		}
305		while ((bytes<0)&&(errno==EINTR));
306
307		do
308		{
309			result=acquire_sem_etc (pending->sem,1,B_TIMEOUT,(retries)?(conf_call_timeout):(2*conf_call_timeout));
310		}
311		while (result==B_INTERRUPTED);
312
313		retries--;
314	}
315	while ((result==B_TIMED_OUT)&&(retries>=0));
316
317	if (result>=B_OK)
318	{
319		uint8 *buffer=pending->buffer;
320		pending->buffer=NULL;
321		SemaphorePoolPut(&ns->pendingCalls.fPool,pending->sem);
322
323		PendingCallDestroy(pending);
324		free(pending);
325
326		XDROutPacketDestroy (&rpc_call);
327		return buffer;
328	}
329
330	// we timed out
331
332	call=RPCPendingCallsFindAndRemovePendingCall(&ns->pendingCalls,xid,addr);
333
334	kmessage ("nfs: xid %d timed out, removing from queue",xid);
335
336#if 0
337	if (call==NULL)
338	{
339#if 1
340		//XXX:mmu_man:???
341		while (acquire_sem(pending->sem)==B_INTERRUPTED);
342#else
343		status_t err;
344		/* NOTE(mmu_man): there can be a race condition here where the sem is returned
345		 * to the pool without the correct value, compromising the next call using it.
346		 * however it seems waiting forever can lead to lockups...
347		 */
348		while ((err = acquire_sem_etc(pending->sem,1,B_TIMEOUT,5000000))==B_INTERRUPTED);
349		dprintf("nfs: acquire(pending->sem) = 0x%08lx\n", err);
350		if (err == B_TIMED_OUT)
351			dprintf("nfs: timed out waiting on sem\n");
352#endif
353	}
354#endif
355
356	free(pending->buffer);
357
358	/* mmu_man */
359	if (call) /* if the call has been found and removed (atomic op), the sem hasn't been released */
360		SemaphorePoolPut(&ns->pendingCalls.fPool,pending->sem);
361	else
362		delete_sem(pending->sem); /* else it's in an unknown state, forget it */
363
364	PendingCallDestroy (pending);
365	free(pending);
366
367	XDROutPacketDestroy (&rpc_call);
368	return NULL;
369}
370
371bool is_successful_reply (struct XDRInPacket *reply)
372{
373	bool success=false;
374
375	int32 xid=XDRInPacketGetInt32(reply);
376	rpc_msg_type mtype=(rpc_msg_type)XDRInPacketGetInt32(reply);
377	rpc_reply_stat replyStat=(rpc_reply_stat)XDRInPacketGetInt32(reply);
378
379	if (replyStat==RPC_MSG_DENIED)
380	{
381		rpc_reject_stat rejectStat=(rpc_reject_stat)XDRInPacketGetInt32(reply);
382
383		if (rejectStat==RPC_RPC_MISMATCH)
384		{
385			int32 low=XDRInPacketGetInt32(reply);
386			int32 high=XDRInPacketGetInt32(reply);
387
388			kmessage ("RPC_MISMATCH (%d,%d)",low,high);
389		}
390		else
391		{
392			rpc_auth_stat authStat=(rpc_auth_stat)XDRInPacketGetInt32(reply);
393
394			kmessage ("RPC_AUTH_ERROR (%d)",authStat);
395		}
396	}
397	else
398	{
399		rpc_auth_flavor flavor=(rpc_auth_flavor)XDRInPacketGetInt32(reply);
400		char body[400];
401		size_t bodyLength=XDRInPacketGetDynamic(reply,body);
402
403		rpc_accept_stat acceptStat=(rpc_accept_stat)XDRInPacketGetInt32(reply);
404
405		if (acceptStat==RPC_PROG_MISMATCH)
406		{
407			int32 low=XDRInPacketGetInt32(reply);
408			int32 high=XDRInPacketGetInt32(reply);
409
410			kmessage ("RPC_PROG_MISMATCH (%d,%d)",low,high);
411		}
412		else if (acceptStat!=RPC_SUCCESS)
413			kmessage ("Accepted but failed (%d)",acceptStat);
414		else
415			success=true;
416	}
417
418	return success;
419}
420
421status_t get_remote_address (fs_nspace *ns, int32 prog, int32 vers, int32 prot, struct sockaddr_in *addr)
422{
423	struct XDROutPacket call;
424	uint8 *replyBuf;
425
426	XDROutPacketInit (&call);
427
428	addr->sin_port=htons(PMAP_PORT);
429
430	XDROutPacketAddInt32 (&call,prog);
431	XDROutPacketAddInt32 (&call,vers);
432	XDROutPacketAddInt32 (&call,prot);
433	XDROutPacketAddInt32 (&call,0);
434
435	replyBuf=send_rpc_call (ns,addr,PMAP_PROGRAM,PMAP_VERSION,PMAPPROC_GETPORT,&call);
436
437	if (replyBuf)
438	{
439		struct XDRInPacket reply;
440		XDRInPacketInit (&reply);
441
442		XDRInPacketSetTo (&reply,replyBuf,0);
443
444		if (is_successful_reply(&reply))
445		{
446			addr->sin_port=htons(XDRInPacketGetInt32(&reply));
447			memset (addr->sin_zero,0,sizeof(addr->sin_zero));
448
449			XDRInPacketDestroy(&reply);
450			XDROutPacketDestroy (&call);
451			return B_OK;
452		}
453
454		XDRInPacketDestroy(&reply);
455	}
456
457	XDROutPacketDestroy (&call);
458	return EHOSTUNREACH;
459}
460
461status_t nfs_mount (fs_nspace *ns, const char *path, nfs_fhandle *fhandle)
462{
463	struct XDROutPacket call;
464	struct XDRInPacket reply;
465	uint8 *replyBuf;
466	int32 fhstatus;
467
468	XDROutPacketInit (&call);
469	XDRInPacketInit (&reply);
470
471	XDROutPacketAddString (&call,path);
472
473	replyBuf=send_rpc_call (ns,&ns->mountAddr,MOUNT_PROGRAM,MOUNT_VERSION,MOUNTPROC_MNT,&call);
474
475	if (!replyBuf)
476	{
477		XDRInPacketDestroy (&reply);
478		XDROutPacketDestroy (&call);
479		return EHOSTUNREACH;
480	}
481
482	XDRInPacketSetTo (&reply,replyBuf,0);
483
484	if (!is_successful_reply(&reply))
485	{
486		XDRInPacketDestroy (&reply);
487		XDROutPacketDestroy (&call);
488		return B_ERROR;
489	}
490
491	fhstatus=XDRInPacketGetInt32(&reply);
492
493	if (fhstatus!=0)
494	{
495		XDRInPacketDestroy (&reply);
496		XDROutPacketDestroy (&call);
497		return map_nfs_to_system_error(fhstatus);
498	}
499
500	XDRInPacketGetFixed (&reply,fhandle->opaque,NFS_FHSIZE);
501
502	XDRInPacketDestroy (&reply);
503	XDROutPacketDestroy (&call);
504	return B_OK;
505}
506
507status_t nfs_lookup (fs_nspace *ns, const nfs_fhandle *dir, const char *filename, nfs_fhandle *fhandle,
508						struct stat *st)
509{
510	struct XDROutPacket call;
511	struct XDRInPacket reply;
512	int32 status;
513	uint8 *replyBuf;
514
515	XDROutPacketInit (&call);
516	XDRInPacketInit (&reply);
517
518	XDROutPacketAddFixed (&call,dir->opaque,NFS_FHSIZE);
519	XDROutPacketAddString (&call,filename);
520
521	replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_LOOKUP,&call);
522
523	if (!replyBuf)
524	{
525		XDRInPacketDestroy (&reply);
526		XDROutPacketDestroy (&call);
527		return EHOSTUNREACH;
528	}
529
530	XDRInPacketSetTo(&reply,replyBuf,0);
531
532	if (!is_successful_reply(&reply))
533	{
534		XDRInPacketDestroy (&reply);
535		XDROutPacketDestroy (&call);
536		return B_ERROR;
537	}
538
539	status=XDRInPacketGetInt32(&reply);
540
541	if (status!=NFS_OK)
542	{
543		XDRInPacketDestroy (&reply);
544		XDROutPacketDestroy (&call);
545		return map_nfs_to_system_error(status);
546	}
547
548	XDRInPacketGetFixed (&reply,fhandle->opaque,NFS_FHSIZE);
549
550	if (st)
551		get_nfs_attr (&reply,st);
552
553	XDRInPacketDestroy (&reply);
554	XDROutPacketDestroy (&call);
555	return B_OK;
556}
557
558status_t nfs_getattr (fs_nspace *ns, const nfs_fhandle *fhandle,
559						struct stat *st)
560{
561	struct XDROutPacket call;
562	struct XDRInPacket reply;
563	uint8 *replyBuf;
564	int32 status;
565
566	XDROutPacketInit (&call);
567	XDRInPacketInit (&reply);
568
569	XDROutPacketAddFixed (&call,fhandle->opaque,NFS_FHSIZE);
570
571	replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_GETATTR,&call);
572
573	if (!replyBuf)
574	{
575		XDRInPacketDestroy (&reply);
576		XDROutPacketDestroy (&call);
577		return EHOSTUNREACH;
578	}
579
580	XDRInPacketSetTo (&reply,replyBuf,0);
581
582	if (!is_successful_reply(&reply))
583	{
584		XDRInPacketDestroy (&reply);
585		XDROutPacketDestroy (&call);
586		return B_ERROR;
587	}
588
589	status=XDRInPacketGetInt32(&reply);
590
591	if (status!=NFS_OK)
592	{
593		XDRInPacketDestroy (&reply);
594		XDROutPacketDestroy (&call);
595		return map_nfs_to_system_error(status);
596	}
597
598	get_nfs_attr (&reply,st);
599
600	XDRInPacketDestroy (&reply);
601	XDROutPacketDestroy (&call);
602	return B_OK;
603}
604
605extern status_t
606nfs_truncate_file(fs_nspace *ns, const nfs_fhandle *fhandle, struct stat *st)
607{
608	struct XDROutPacket call;
609	struct XDRInPacket reply;
610	uint8 *replyBuf;
611	int32 status;
612
613	XDROutPacketInit (&call);
614	XDRInPacketInit (&reply);
615
616	XDROutPacketAddFixed(&call,fhandle->opaque,NFS_FHSIZE);
617
618	XDROutPacketAddInt32 (&call,-1);
619	XDROutPacketAddInt32 (&call,-1);
620	XDROutPacketAddInt32 (&call,-1);
621	XDROutPacketAddInt32 (&call,0);
622	XDROutPacketAddInt32 (&call,time(NULL));
623	XDROutPacketAddInt32 (&call,0);
624	XDROutPacketAddInt32 (&call,time(NULL));
625	XDROutPacketAddInt32 (&call,0);
626
627	replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_SETATTR,&call);
628
629	if (!replyBuf)
630	{
631		XDRInPacketDestroy (&reply);
632		XDROutPacketDestroy (&call);
633		return EHOSTUNREACH;
634	}
635
636	XDRInPacketSetTo(&reply,replyBuf,0);
637
638	if (!is_successful_reply(&reply))
639	{
640		XDRInPacketDestroy (&reply);
641		XDROutPacketDestroy (&call);
642		return B_ERROR;
643	}
644
645	status=XDRInPacketGetInt32(&reply);
646
647	if (status!=NFS_OK)
648	{
649		XDRInPacketDestroy (&reply);
650		XDROutPacketDestroy (&call);
651		return map_nfs_to_system_error(status);
652	}
653
654	if (st)
655		get_nfs_attr (&reply,st);
656
657	XDRInPacketDestroy (&reply);
658	XDROutPacketDestroy (&call);
659	return B_OK;
660}
661
662void get_nfs_attr (struct XDRInPacket *reply, struct stat *st)
663{
664	nfs_ftype ftype=(nfs_ftype)XDRInPacketGetInt32(reply);
665	st->st_mode=XDRInPacketGetInt32(reply);
666
667	st->st_dev=0;	// just to be sure
668	st->st_nlink=XDRInPacketGetInt32(reply);
669	st->st_uid=XDRInPacketGetInt32(reply);
670	st->st_gid=XDRInPacketGetInt32(reply);
671	st->st_size=XDRInPacketGetInt32(reply);
672#if 0
673	XDRInPacketGetInt32(reply);	// blksize
674	st->st_blksize=NFS_MAXDATA;
675#else
676	st->st_blksize=XDRInPacketGetInt32(reply);
677#endif
678	st->st_rdev=XDRInPacketGetInt32(reply);
679	XDRInPacketGetInt32(reply);	// blocks
680	XDRInPacketGetInt32(reply);	// fsid
681	st->st_ino=XDRInPacketGetInt32(reply);
682	st->st_atime=XDRInPacketGetInt32(reply);
683	XDRInPacketGetInt32(reply);	// usecs
684	st->st_mtime=st->st_crtime=XDRInPacketGetInt32(reply);
685	XDRInPacketGetInt32(reply);	// usecs
686	st->st_ctime=XDRInPacketGetInt32(reply);
687	XDRInPacketGetInt32(reply);	// usecs
688}
689
690status_t map_nfs_to_system_error (status_t nfsstatus)
691{
692	switch (nfsstatus)
693	{
694		case NFS_OK:
695			return B_OK;
696
697		case NFSERR_PERM:
698			return EPERM;
699
700		case NFSERR_NOENT:
701			return ENOENT;
702
703		case NFSERR_IO:
704			return EIO;
705
706		case NFSERR_NXIO:
707			return ENXIO;
708
709		case NFSERR_ACCES:
710			return EACCES;
711
712		case NFSERR_EXIST:
713			return EEXIST;
714
715		case NFSERR_NODEV:
716			return ENODEV;
717
718		case NFSERR_NOTDIR:
719			return ENOTDIR;
720
721		case NFSERR_ISDIR:
722			return EISDIR;
723
724		case NFSERR_FBIG:
725			return EFBIG;
726
727		case NFSERR_NOSPC:
728			return ENOSPC;
729
730		case NFSERR_ROFS:
731			return EROFS;
732
733		case NFSERR_NAMETOOLONG:
734			return ENAMETOOLONG;
735
736		case NFSERR_NOTEMPTY:
737			return ENOTEMPTY;
738
739		case NFSERR_STALE:
740			return C_ERROR_STALE;
741
742		default:
743			return B_ERROR;
744	}
745}
746
747extern nfs_fhandle
748handle_from_vnid(fs_nspace *ns, vnode_id vnid)
749{
750	fs_node *current;
751
752	while (acquire_sem (ns->sem)==B_INTERRUPTED);
753
754	current=ns->first;
755
756	while ((current)&&(current->vnid!=vnid))
757		current=current->next;
758
759	while (release_sem (ns->sem)==B_INTERRUPTED);
760
761	return current->fhandle;
762}
763
764void insert_node (fs_nspace *ns, fs_node *node)
765{
766	fs_node *current;
767
768	while (acquire_sem (ns->sem)==B_INTERRUPTED);
769
770	current=ns->first;
771
772	while ((current)&&(current->vnid!=node->vnid))
773		current=current->next;
774
775	if (current)
776	{
777		free(node);
778		while (release_sem (ns->sem)==B_INTERRUPTED);
779		return;
780	}
781
782	node->next=ns->first;
783	ns->first=node;
784
785	while (release_sem (ns->sem)==B_INTERRUPTED);
786}
787
788void remove_node (fs_nspace *ns, vnode_id vnid)
789{
790	fs_node *current;
791	fs_node *previous;
792
793	while(acquire_sem (ns->sem)==B_INTERRUPTED);
794
795	current=ns->first;
796	previous=NULL;
797
798	while ((current)&&(current->vnid!=vnid))
799	{
800		previous=current;
801		current=current->next;
802	}
803
804	if (current)
805	{
806		if (previous)
807			previous->next=current->next;
808		else
809			ns->first=current->next;
810
811		free(current);
812	}
813
814	while (release_sem (ns->sem)==B_INTERRUPTED);
815}
816
817extern int
818#ifdef __HAIKU__
819fs_read_vnode(fs_nspace *ns, vnode_id vnid, fs_node **node, char r)
820#else
821fs_read_vnode(fs_nspace *ns, vnode_id vnid, char r, fs_node **node)
822#endif
823{
824	fs_node *current;
825
826	if (!r)
827	{
828		while (acquire_sem (ns->sem)==B_INTERRUPTED);
829	}
830
831	current=ns->first;
832
833	while ((current)&&(current->vnid!=vnid))
834		current=current->next;
835
836	if (!current)
837		return EINVAL;
838
839	*node=current;
840
841	if (!r)
842	{
843		while (release_sem (ns->sem)==B_INTERRUPTED);
844	}
845
846	return B_OK;
847}
848
849extern int
850#ifdef __HAIKU__
851fs_release_vnode(fs_nspace *ns, fs_node *node, char r)
852#else
853fs_write_vnode(fs_nspace *ns, fs_node *node, char r)
854#endif
855{
856	return B_OK;
857}
858
859#ifdef __HAIKU__
860extern int
861fs_get_vnode_name(fs_nspace *ns, fs_node *node, char *buffer, size_t len)
862{
863	return ENOSYS;
864}
865#endif
866
867extern int
868#ifdef __HAIKU__
869fs_walk(fs_nspace *ns, fs_node *base, const char *file, vnode_id *vnid, int *type)
870#else
871fs_walk(fs_nspace *ns, fs_node *base, const char *file, char **newpath, vnode_id *vnid)
872#endif
873{
874	bool isLink;
875	fs_node *dummy;
876	status_t result;
877	//dprintf("nfs: walk(%s)\n", file);//XXX:mmu_man:debug
878
879	if (!strcmp(".",file))
880	{
881		*vnid=base->vnid;
882#ifdef __HAIKU__
883		*type = S_IFDIR;
884#endif
885		isLink=false;
886	}
887	else
888	{
889		fs_node *newNode=(fs_node *)malloc(sizeof(fs_node));
890		struct stat st;
891
892		status_t result;
893		if ((result=nfs_lookup(ns,&base->fhandle,file,&newNode->fhandle,&st))<B_OK)
894		{
895			free(newNode);
896			return result;
897		}
898
899		newNode->vnid=st.st_ino;
900		*vnid=newNode->vnid;
901#ifdef __HAIKU__
902		*type = st.st_mode & S_IFMT;
903#endif
904
905		insert_node (ns,newNode);
906
907		isLink=S_ISLNK(st.st_mode);
908	}
909
910	if ((result=get_vnode (ns->nsid,*vnid,(void **)&dummy))<B_OK)
911		return result;
912
913#ifndef __HAIKU__
914	if ((isLink)&&(newpath))
915	{
916		char path[NFS_MAXPATHLEN+1];
917		size_t pathLen=NFS_MAXPATHLEN;
918
919		if ((result=fs_readlink(ns,dummy,path,&pathLen))<B_OK)
920		{
921			put_vnode (ns->nsid,*vnid);
922			return result;
923		}
924
925		path[pathLen]=0;
926
927		result=new_path(path,newpath);
928
929		if (result<B_OK)
930		{
931			put_vnode (ns->nsid,*vnid);
932			return result;
933		}
934
935		return put_vnode (ns->nsid,*vnid);
936	}
937#endif
938
939	return B_OK;
940}
941
942extern int
943fs_opendir(fs_nspace *ns, fs_node *node, nfs_cookie **cookie)
944{
945	struct stat st;
946	nfs_fhandle fhandle;
947
948	status_t result;
949	if ((result=nfs_getattr(ns,&node->fhandle,&st))<B_OK)
950		return result;
951
952	if (!S_ISDIR(st.st_mode))
953		return ENOTDIR;
954
955	*cookie=(nfs_cookie *)malloc(sizeof(nfs_cookie));
956	memset ((*cookie)->opaque,0,NFS_COOKIESIZE);
957
958	return B_OK;
959}
960
961extern int
962fs_closedir(fs_nspace *ns, fs_node *node, nfs_cookie *cookie)
963{
964	return B_OK;
965}
966
967extern int
968fs_rewinddir(fs_nspace *ns, fs_node *node, nfs_cookie *cookie)
969{
970	memset (cookie->opaque,0,NFS_COOKIESIZE);
971
972	return B_OK;
973}
974
975extern int
976#ifdef __HAIKU__
977fs_readdir(fs_nspace *ns, fs_node *node, nfs_cookie *cookie, struct dirent *buf, size_t bufsize, uint32 *num)
978#else
979fs_readdir(fs_nspace *ns, fs_node *node, nfs_cookie *cookie, long *num, struct dirent *buf, size_t bufsize)
980#endif
981{
982	int32 max=*num;
983	int32 eof;
984
985	size_t count=min_c(6000,max*300);
986
987	*num=0;
988
989	do
990	{
991		vnode_id vnid;
992		char *filename;
993		uint8 *replyBuf;
994		struct XDROutPacket call;
995		struct XDRInPacket reply;
996		int32 status;
997
998		XDROutPacketInit (&call);
999		XDRInPacketInit (&reply);
1000
1001		XDROutPacketAddFixed (&call,node->fhandle.opaque,NFS_FHSIZE);
1002		XDROutPacketAddFixed (&call,cookie->opaque,NFS_COOKIESIZE);
1003		XDROutPacketAddInt32 (&call,count);
1004
1005		replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_READDIR,&call);
1006
1007		if (!replyBuf)
1008		{
1009			XDRInPacketDestroy (&reply);
1010			XDROutPacketDestroy (&call);
1011			return B_ERROR;
1012		}
1013
1014		XDRInPacketSetTo(&reply,replyBuf,0);
1015
1016		if (!is_successful_reply(&reply))
1017		{
1018			XDRInPacketDestroy (&reply);
1019			XDROutPacketDestroy (&call);
1020			return B_ERROR;
1021		}
1022
1023		status=XDRInPacketGetInt32(&reply);
1024
1025		if (status!=NFS_OK)
1026		{
1027			XDRInPacketDestroy (&reply);
1028			XDROutPacketDestroy (&call);
1029			return map_nfs_to_system_error(status);
1030		}
1031
1032		while (XDRInPacketGetInt32(&reply)==1)
1033		{
1034			nfs_cookie newCookie;
1035
1036			vnid=XDRInPacketGetInt32(&reply);
1037			filename=XDRInPacketGetString(&reply);
1038
1039			XDRInPacketGetFixed(&reply,newCookie.opaque,NFS_COOKIESIZE);
1040
1041			//if (strcmp(".",filename)&&strcmp("..",filename))
1042			//if ((ns->rootid != node->vnid) || (strcmp(".",filename)&&strcmp("..",filename)))
1043			if (conf_ls_root_parent || ((ns->rootid != node->vnid) || strcmp("..",filename)))
1044			{
1045				status_t result;
1046				struct stat st;
1047
1048				fs_node *newNode=(fs_node *)malloc(sizeof(fs_node));
1049				newNode->vnid=vnid;
1050
1051				if ((result=nfs_lookup(ns,&node->fhandle,filename,&newNode->fhandle,&st))<B_OK)
1052				{
1053					free (filename);
1054					free(newNode);
1055					XDRInPacketDestroy (&reply);
1056					XDROutPacketDestroy (&call);
1057					return result;
1058				}
1059
1060				insert_node (ns,newNode);
1061
1062				if (bufsize<2*(sizeof(dev_t)+sizeof(ino_t))+sizeof(unsigned short)+strlen(filename)+1)
1063				{
1064					XDRInPacketDestroy (&reply);
1065					XDROutPacketDestroy (&call);
1066					return B_OK;
1067				}
1068
1069				buf->d_dev=ns->nsid;
1070				buf->d_pdev=ns->nsid;
1071				buf->d_ino=vnid;
1072				buf->d_pino=node->vnid;
1073				buf->d_reclen=2*(sizeof(dev_t)+sizeof(ino_t))+sizeof(unsigned short)+strlen(filename)+1;
1074				strcpy (buf->d_name,filename);
1075//				if ((ns->rootid == node->vnid))//XXX:mmu_man:test
1076//					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);
1077
1078				bufsize-=buf->d_reclen;
1079				buf=(struct dirent *)((char *)buf+buf->d_reclen);
1080
1081				memcpy (cookie->opaque,newCookie.opaque,NFS_COOKIESIZE);
1082
1083				(*num)++;
1084			}
1085			else {
1086				memcpy (cookie->opaque,newCookie.opaque,NFS_COOKIESIZE);
1087			}
1088
1089			free (filename);
1090
1091			if ((*num)==max)
1092			{
1093				XDRInPacketDestroy (&reply);
1094				XDROutPacketDestroy (&call);
1095				return B_OK;
1096			}
1097		}
1098
1099		eof=XDRInPacketGetInt32(&reply);
1100
1101		XDRInPacketDestroy (&reply);
1102		XDROutPacketDestroy (&call);
1103	}
1104	while (eof==0);
1105
1106	return B_OK;
1107}
1108
1109extern int
1110fs_free_dircookie(fs_nspace *ns, fs_node *node, nfs_cookie *cookie)
1111{
1112	free(cookie);
1113	return B_OK;
1114}
1115
1116extern int
1117fs_rstat(fs_nspace *ns, fs_node *node, struct stat *st)
1118{
1119	nfs_fhandle fhandle;
1120
1121	status_t result;
1122	//dprintf("nfs: rstat()\n");//XXX:mmu_man:debug
1123	if ((result=nfs_getattr(ns,&node->fhandle,st))<B_OK)
1124		return result;
1125
1126	st->st_dev=ns->nsid;
1127//st->st_nlink = 1; //XXX:mmu_man:test
1128	return B_OK;
1129}
1130
1131extern void
1132fs_nspaceInit(struct fs_nspace *nspace)
1133{
1134	RPCPendingCallsInit (&nspace->pendingCalls);
1135}
1136
1137extern void
1138fs_nspaceDestroy(struct fs_nspace *nspace)
1139{
1140	RPCPendingCallsDestroy (&nspace->pendingCalls);
1141}
1142
1143#ifdef PARAMS_AS_STRING
1144int parse_nfs_params(const char *str, struct mount_nfs_params *params)
1145{
1146	char *p, *e;
1147	long v;
1148	int i;
1149	// sprintf(buf, "nfs:%s:%s,uid=%u,gid=%u,hostname=%s",
1150	if (!str || !params)
1151		return EINVAL;
1152	if (strncmp(str, "nfs:", 4))
1153		return EINVAL;
1154dprintf("nfs:ip!\n");
1155	p = str + 4;
1156	e = strchr(p, ':');
1157	if (!e)
1158		return EINVAL;
1159	params->server = malloc(e - p);
1160	strncpy(params->server, p, e - p);
1161	// hack
1162	params->serverIP = 0;
1163	v = strtol(p, &p, 10);
1164dprintf("IP:%ld.", v);
1165	if (!p)
1166		return EINVAL;
1167	params->serverIP |= (v << 24);
1168	p++;
1169	v = strtol(p, &p, 10);
1170dprintf("%ld.", v);
1171	if (!p)
1172		return EINVAL;
1173	params->serverIP |= (v << 16);
1174	p++;
1175	v = strtol(p, &p, 10);
1176dprintf("%ld.", v);
1177	if (!p)
1178		return EINVAL;
1179	params->serverIP |= (v << 8);
1180	p++;
1181	v = strtol(p, &p, 10);
1182dprintf("%ld\n", v);
1183	if (!p)
1184		return EINVAL;
1185	params->serverIP |= (v);
1186	if (*p++ != ':')
1187		return EINVAL;
1188
1189	e = strchr(p, ',');
1190	i = (e) ? (e - p) : (strlen(p));
1191
1192	params->_export = malloc(i);
1193	strncpy(params->_export, p, i);
1194
1195	p = strstr(str, "hostname=");
1196	if (!p)
1197		return EINVAL;
1198dprintf("nfs:hn!\n");
1199	p += 9;
1200	e = strchr(p, ',');
1201	i = (e) ? (e - p) : (strlen(p));
1202
1203	params->hostname = malloc(i);
1204	strncpy(params->hostname, p, i);
1205
1206	p = strstr(str, "uid=");
1207dprintf("nfs:uid!\n");
1208	if (p) {
1209		p += 4;
1210		v = strtol(p, &p, 10);
1211		params->uid = v;
1212	}
1213dprintf("nfs:gid!\n");
1214	p = strstr(str, "gid=");
1215	if (p) {
1216		p += 4;
1217		v = strtol(p, &p, 10);
1218		params->gid = v;
1219	}
1220	dprintf("nfs: ip:%08lx server:'%s' export:'%s' hostname:'%s' uid=%d gid=%d \n",
1221		params->serverIP, params->server, params->_export,
1222		params->hostname, params->uid, params->gid);
1223	return B_OK;
1224}
1225#endif
1226
1227extern int
1228#ifdef __HAIKU__
1229fs_mount(nspace_id nsid, const char *devname, uint32 flags, const char *_parms, fs_nspace **data, vnode_id *vnid)
1230#else
1231fs_mount(nspace_id nsid, const char *devname, ulong flags, const char *_parms, size_t len, fs_nspace **data, vnode_id *vnid)
1232#endif
1233{
1234#ifndef PARAMS_AS_STRING
1235	struct mount_nfs_params *parms = (struct mount_nfs_params *)_parms; // XXX: FIXME
1236#endif
1237	status_t result;
1238	fs_nspace *ns;
1239	fs_node *rootNode;
1240	struct stat st;
1241#ifndef __HAIKU__
1242	(void) len;
1243#endif
1244
1245	if (_parms==NULL)
1246		return EINVAL;
1247
1248dprintf("nfs: mount(%d, %s, %08lx)\n", nsid, devname, flags);
1249#ifndef PARAMS_AS_STRING
1250dprintf("nfs: nfs_params(ip:%lu, server:%s, export:%s, uid:%d, gid:%d, hostname:%s)\n",
1251        parms->serverIP,
1252        parms->server,
1253        parms->_export,
1254        parms->uid,
1255        parms->gid,
1256        parms->hostname);
1257#else
1258dprintf("nfs: nfs_params: %s\n", _parms);
1259#endif
1260
1261	// HAIKU: this should go to std_ops
1262	if (!refcount)
1263		read_config();
1264
1265	result = ksocket_init();
1266	if (result < B_OK)
1267		return result;
1268
1269	result = ENOMEM;
1270	ns=(fs_nspace *)malloc(sizeof(fs_nspace));
1271	if (!ns)
1272		goto err_nspace;
1273	fs_nspaceInit (ns);
1274
1275	ns->nsid=nsid;
1276
1277	ns->params.server=NULL;
1278	ns->params._export=NULL;
1279	ns->params.hostname=NULL;
1280#ifdef PARAMS_AS_STRING
1281	if ((result = parse_nfs_params(_parms, &ns->params)) < 0)
1282		goto err_params;
1283#else
1284	ns->params.serverIP=parms->serverIP;
1285	ns->params.server=strdup(parms->server);
1286	ns->params._export=strdup(parms->_export);
1287	ns->params.uid=parms->uid;
1288	ns->params.gid=parms->gid;
1289	ns->params.hostname=strdup(parms->hostname);
1290#endif
1291	ns->xid=0;
1292	ns->mountAddr.sin_family=AF_INET;
1293	ns->mountAddr.sin_addr.s_addr=htonl(ns->params.serverIP);
1294	memset (ns->mountAddr.sin_zero,0,sizeof(ns->mountAddr.sin_zero));
1295
1296	if ((result=create_socket(ns))<B_OK)
1297		goto err_socket;
1298
1299	if ((result=init_postoffice(ns))<B_OK)
1300		goto err_postoffice;
1301
1302	if ((result=get_remote_address(ns,MOUNT_PROGRAM,MOUNT_VERSION,PMAP_IPPROTO_UDP,&ns->mountAddr))<B_OK)
1303		goto err_sem;
1304
1305	memcpy (&ns->nfsAddr,&ns->mountAddr,sizeof(ns->mountAddr));
1306dprintf("nfs: mountd at %08lx:%d\n", ns->mountAddr.sin_addr.s_addr, ntohs(ns->mountAddr.sin_port));
1307
1308	if ((result=get_remote_address(ns,NFS_PROGRAM,NFS_VERSION,PMAP_IPPROTO_UDP,&ns->nfsAddr))<B_OK)
1309		goto err_sem;
1310dprintf("nfs: nfsd at %08lx:%d\n", ns->nfsAddr.sin_addr.s_addr, ntohs(ns->nfsAddr.sin_port));
1311//	result = connect_socket(ns);
1312//dprintf("nfs: connect: %s\n", strerror(result));
1313
1314	if ((result=create_sem(1,"nfs_sem"))<B_OK)
1315		goto err_sem;
1316
1317	ns->sem=result;
1318
1319	set_sem_owner (ns->sem,B_SYSTEM_TEAM);
1320
1321	result = ENOMEM;
1322	rootNode=(fs_node *)malloc(sizeof(fs_node));
1323	if (!rootNode)
1324		goto err_rootvn;
1325	rootNode->next=NULL;
1326
1327	if ((result=nfs_mount(ns,ns->params._export,&rootNode->fhandle))<B_OK)
1328		goto err_mount;
1329
1330	if ((result=nfs_getattr(ns,&rootNode->fhandle,&st))<B_OK)
1331		goto err_publish;
1332
1333	ns->rootid=st.st_ino;
1334	rootNode->vnid=ns->rootid;
1335
1336	*vnid=ns->rootid;
1337
1338	if ((result=publish_vnode(nsid,*vnid,rootNode))<B_OK)
1339		goto err_publish;
1340
1341	*data=ns;
1342
1343	ns->first=rootNode;
1344
1345	return B_OK;
1346
1347err_publish:
1348	// XXX: unmount ??
1349err_mount:
1350	free(rootNode);
1351err_rootvn:
1352	delete_sem (ns->sem);
1353err_sem:
1354	shutdown_postoffice(ns);
1355	goto err_socket;
1356err_postoffice:
1357	kclosesocket(ns->s);
1358err_socket:
1359err_params:
1360	free (ns->params.hostname);
1361	free (ns->params._export);
1362	free (ns->params.server);
1363
1364	fs_nspaceDestroy (ns);
1365	free(ns);
1366err_nspace:
1367
1368	ksocket_cleanup();
1369	if (result >= 0) {
1370		dprintf("nfs:bad error from mount!\n");
1371		result = EINVAL;
1372	}
1373	dprintf("nfs: error in nfs_mount: %s\n", strerror(result));
1374	return result;
1375}
1376
1377extern int
1378fs_unmount(fs_nspace *ns)
1379{
1380	free (ns->params.hostname);
1381	free (ns->params._export);
1382	free (ns->params.server);
1383
1384	while (ns->first)
1385	{
1386		fs_node *next=ns->first->next;
1387		free(ns->first);
1388		ns->first=next;
1389	}
1390
1391	// Unlike in BeOS, we need to put the reference to our root node ourselves
1392#ifdef __HAIKU__
1393	put_vnode(ns->nsid, ns->rootid);
1394#endif
1395
1396	delete_sem (ns->sem);
1397	shutdown_postoffice(ns);
1398	fs_nspaceDestroy (ns);
1399	free(ns);
1400	ksocket_cleanup();
1401	return B_OK;
1402}
1403
1404extern int
1405fs_rfsstat(fs_nspace *ns, struct fs_info *info)
1406{
1407	struct XDROutPacket call;
1408	struct XDRInPacket reply;
1409	nfs_fhandle rootHandle=handle_from_vnid (ns,ns->rootid);
1410	uint8 *replyBuf;
1411	int32 status;
1412	//dprintf("nfs: rfsstat()\n");//XXX:mmu_man:debug
1413
1414	XDROutPacketInit (&call);
1415	XDRInPacketInit (&reply);
1416
1417	XDROutPacketAddFixed (&call,rootHandle.opaque,NFS_FHSIZE);
1418
1419	replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_STATFS,&call);
1420
1421	if (!replyBuf)
1422	{
1423		XDRInPacketDestroy (&reply);
1424		XDROutPacketDestroy (&call);
1425		return EHOSTUNREACH;
1426	}
1427
1428	XDRInPacketSetTo(&reply,replyBuf,0);
1429
1430	if (!is_successful_reply(&reply))
1431	{
1432		XDRInPacketDestroy (&reply);
1433		XDROutPacketDestroy (&call);
1434		return B_ERROR;
1435	}
1436
1437	status=XDRInPacketGetInt32(&reply);
1438
1439	if (status!=NFS_OK)
1440	{
1441		XDRInPacketDestroy (&reply);
1442		XDROutPacketDestroy (&call);
1443		//dprintf("nfs: rfsstat() error 0x%08lx\n", map_nfs_to_system_error(status));
1444		return map_nfs_to_system_error(status);
1445	}
1446
1447	info->dev=ns->nsid;
1448	info->root=ns->rootid;
1449	info->flags=NFS_FS_FLAGS;
1450
1451	XDRInPacketGetInt32(&reply);	// tsize
1452
1453	info->block_size=XDRInPacketGetInt32(&reply);
1454	info->io_size=8192;
1455	info->total_blocks=XDRInPacketGetInt32(&reply);
1456	info->free_blocks=XDRInPacketGetInt32(&reply);
1457	info->total_nodes=100;
1458	info->free_nodes=100;
1459	//strcpy (info->device_name,"nfs_device");
1460	strcpy (info->device_name,"");
1461	strcpy (info->volume_name,"nfs://");
1462	strcat (info->volume_name,ns->params.server);
1463	strcat (info->volume_name,ns->params._export);
1464	//strcpy (info->fsh_name,"nfs_fsh");
1465	strcpy (info->fsh_name,"nfs");
1466
1467	XDRInPacketDestroy (&reply);
1468	XDROutPacketDestroy (&call);
1469	return B_OK;
1470}
1471
1472extern int
1473fs_open(fs_nspace *ns, fs_node *node, int omode, fs_file_cookie **cookie)
1474{
1475	struct stat st;
1476	nfs_fhandle fhandle;
1477
1478	status_t result;
1479	if ((result=nfs_getattr(ns,&node->fhandle,&st))<B_OK)
1480		return result;
1481
1482	if (S_ISDIR(st.st_mode)) {
1483		/* permit opening of directories */
1484		if (conf_allow_dir_open) {
1485			*cookie = NULL;
1486			return B_OK;
1487		} else
1488			return EISDIR;
1489	}
1490
1491	*cookie=(fs_file_cookie *)malloc(sizeof(fs_file_cookie));
1492	(*cookie)->omode=omode;
1493	(*cookie)->original_size=st.st_size;
1494	(*cookie)->st=st;
1495
1496	return B_OK;
1497}
1498
1499extern int
1500fs_close(fs_nspace *ns, fs_node *node, fs_file_cookie *cookie)
1501{
1502/*	//XXX:mmu_man:why that ?? makes Tracker go nuts updating the stats
1503	if ((cookie->omode & O_RDWR)||(cookie->omode & O_WRONLY))
1504		return my_notify_listener (B_STAT_CHANGED,ns->nsid,0,0,node->vnid,NULL);
1505*/
1506	return B_OK;
1507}
1508
1509extern int
1510fs_free_cookie(fs_nspace *ns, fs_node *node, fs_file_cookie *cookie)
1511{
1512	if (cookie)
1513		free(cookie);
1514	return B_OK;
1515}
1516
1517extern int
1518fs_read(fs_nspace *ns, fs_node *node, fs_file_cookie *cookie, off_t pos, void *buf, size_t *len)
1519{
1520	size_t max=*len;
1521	*len=0;
1522
1523	if (!cookie) return EISDIR; /* do not permit reading of directories */
1524	while ((*len)<max)
1525	{
1526		size_t count=min_c(NFS_MAXDATA,max-(*len));
1527
1528		struct XDROutPacket call;
1529		struct XDRInPacket reply;
1530
1531		int32 status;
1532		uint8 *replyBuf;
1533
1534		struct stat st;
1535		size_t readbytes;
1536
1537		XDROutPacketInit (&call);
1538		XDRInPacketInit (&reply);
1539
1540		XDROutPacketAddFixed (&call,&node->fhandle.opaque,NFS_FHSIZE);
1541		XDROutPacketAddInt32 (&call,pos);
1542		XDROutPacketAddInt32 (&call,count);
1543		XDROutPacketAddInt32 (&call,0);
1544
1545		replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_READ,&call);
1546
1547		if (!replyBuf)
1548		{
1549			XDRInPacketDestroy (&reply);
1550			XDROutPacketDestroy (&call);
1551			return B_ERROR;
1552		}
1553
1554		XDRInPacketSetTo(&reply,replyBuf,0);
1555
1556		if (!is_successful_reply(&reply))
1557		{
1558			XDRInPacketDestroy (&reply);
1559			XDROutPacketDestroy (&call);
1560			return B_ERROR;
1561		}
1562
1563		status=XDRInPacketGetInt32(&reply);
1564
1565		if (status!=NFS_OK)
1566		{
1567			XDRInPacketDestroy (&reply);
1568			XDROutPacketDestroy (&call);
1569			return map_nfs_to_system_error(status);
1570		}
1571
1572		get_nfs_attr (&reply,&st);
1573
1574		cookie->st=st;
1575
1576		readbytes=XDRInPacketGetDynamic(&reply,buf);
1577
1578		buf=(char *)buf+readbytes;
1579		(*len)+=readbytes;
1580		pos+=readbytes;
1581
1582		if (pos>=st.st_size)
1583		{
1584			XDRInPacketDestroy (&reply);
1585			XDROutPacketDestroy (&call);
1586			break;
1587		}
1588
1589		XDRInPacketDestroy (&reply);
1590		XDROutPacketDestroy (&call);
1591	}
1592
1593	return B_OK;
1594}
1595
1596extern int
1597fs_write(fs_nspace *ns, fs_node *node, fs_file_cookie *cookie, off_t pos, const void *buf, size_t *len)
1598{
1599	size_t bytesWritten=0;
1600
1601	if (!cookie) return EISDIR; /* do not permit reading of directories */
1602	if (cookie->omode & O_APPEND)
1603		pos+=cookie->original_size;
1604
1605	while (bytesWritten<*len)
1606	{
1607		size_t count=min_c(NFS_MAXDATA,(*len)-bytesWritten);
1608
1609		struct XDROutPacket call;
1610		struct XDRInPacket reply;
1611		int32 status;
1612		uint8 *replyBuf;
1613		struct stat st;
1614
1615		XDROutPacketInit (&call);
1616		XDRInPacketInit (&reply);
1617
1618		XDROutPacketAddFixed (&call,&node->fhandle.opaque,NFS_FHSIZE);
1619		XDROutPacketAddInt32 (&call,0);
1620		XDROutPacketAddInt32 (&call,pos+bytesWritten);
1621		XDROutPacketAddInt32 (&call,0);
1622		XDROutPacketAddDynamic (&call,(const char *)buf+bytesWritten,count);
1623
1624		replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_WRITE,&call);
1625
1626		if (!replyBuf)
1627		{
1628			XDRInPacketDestroy (&reply);
1629			XDROutPacketDestroy (&call);
1630			return B_ERROR;
1631		}
1632
1633		XDRInPacketSetTo (&reply,replyBuf,0);
1634
1635		if (!is_successful_reply(&reply))
1636		{
1637			XDRInPacketDestroy (&reply);
1638			XDROutPacketDestroy (&call);
1639			return B_ERROR;
1640		}
1641
1642		status=XDRInPacketGetInt32(&reply);
1643
1644		if (status!=NFS_OK)
1645		{
1646			XDRInPacketDestroy (&reply);
1647			XDROutPacketDestroy (&call);
1648			return map_nfs_to_system_error(status);
1649		}
1650
1651		get_nfs_attr (&reply,&st);
1652
1653		cookie->st=st;
1654
1655		bytesWritten+=count;
1656
1657		XDRInPacketDestroy (&reply);
1658		XDROutPacketDestroy (&call);
1659	}
1660
1661	return B_OK;
1662}
1663
1664extern int
1665fs_wstat(fs_nspace *ns, fs_node *node, struct stat *st, long mask)
1666{
1667	struct XDROutPacket call;
1668	struct XDRInPacket reply;
1669
1670	uint8 *replyBuf;
1671	int32 status;
1672
1673	XDROutPacketInit (&call);
1674	XDRInPacketInit (&reply);
1675
1676	XDROutPacketAddFixed (&call,node->fhandle.opaque,NFS_FHSIZE);
1677
1678	XDROutPacketAddInt32 (&call,(mask & WSTAT_MODE) ? st->st_mode : -1);
1679	XDROutPacketAddInt32 (&call,(mask & WSTAT_UID) ? st->st_uid : -1);
1680	XDROutPacketAddInt32 (&call,(mask & WSTAT_GID) ? st->st_gid : -1);
1681	XDROutPacketAddInt32 (&call,(mask & WSTAT_SIZE) ? st->st_size : -1);
1682	XDROutPacketAddInt32 (&call,(mask & WSTAT_ATIME) ? st->st_atime : -1);
1683	XDROutPacketAddInt32 (&call,(mask & WSTAT_ATIME) ? 0 : -1);
1684	XDROutPacketAddInt32 (&call,(mask & WSTAT_MTIME) ? st->st_mtime : -1);
1685	XDROutPacketAddInt32 (&call,(mask & WSTAT_MTIME) ? 0 : -1);
1686
1687	replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_SETATTR,&call);
1688
1689	if (!replyBuf)
1690	{
1691		XDRInPacketDestroy (&reply);
1692		XDROutPacketDestroy (&call);
1693		return EHOSTUNREACH;
1694	}
1695
1696	XDRInPacketSetTo (&reply,replyBuf,0);
1697
1698	if (!is_successful_reply(&reply))
1699	{
1700		XDRInPacketDestroy (&reply);
1701		XDROutPacketDestroy (&call);
1702		return B_ERROR;
1703	}
1704
1705	status=XDRInPacketGetInt32(&reply);
1706
1707	if (status!=NFS_OK)
1708		return map_nfs_to_system_error(status);
1709
1710	XDRInPacketDestroy (&reply);
1711	XDROutPacketDestroy (&call);
1712	return my_notify_listener (B_STAT_CHANGED,ns->nsid,0,0,node->vnid,NULL);
1713}
1714
1715extern int
1716fs_wfsstat(fs_nspace *ns, struct fs_info *info, long mask)
1717{
1718	return B_OK;
1719}
1720
1721extern int
1722#ifdef __HAIKU__
1723fs_create(fs_nspace *ns, fs_node *dir, const char *name, int omode, int perms, fs_file_cookie **cookie, vnode_id *vnid)
1724#else
1725fs_create(fs_nspace *ns, fs_node *dir, const char *name, int omode, int perms, vnode_id *vnid, fs_file_cookie **cookie)
1726#endif
1727{
1728	nfs_fhandle fhandle;
1729	struct stat st;
1730
1731	status_t result;
1732	result=nfs_lookup(ns,&dir->fhandle,name,&fhandle,&st);
1733
1734	if (result==B_OK)
1735	{
1736		void *dummy;
1737		fs_node *newNode=(fs_node *)malloc(sizeof(fs_node));
1738		newNode->fhandle=fhandle;
1739		newNode->vnid=st.st_ino;
1740		insert_node (ns,newNode);
1741
1742		*vnid=st.st_ino;
1743
1744		if ((result=get_vnode(ns->nsid,*vnid,&dummy))<B_OK)
1745			return result;
1746
1747		if (S_ISDIR(st.st_mode))
1748			return EISDIR;
1749
1750		if (omode & O_EXCL)
1751			return EEXIST;
1752
1753		if (omode & O_TRUNC)
1754		{
1755			if ((result=nfs_truncate_file(ns,&fhandle,NULL))<B_OK)
1756				return result;
1757		}
1758
1759		*cookie=(fs_file_cookie *)malloc(sizeof(fs_file_cookie));
1760		(*cookie)->omode=omode;
1761		(*cookie)->original_size=st.st_size;
1762		(*cookie)->st=st;
1763
1764		return B_OK;
1765	}
1766	else if (result!=ENOENT)
1767		return result;
1768	else
1769	{
1770		struct XDROutPacket call;
1771		struct XDRInPacket reply;
1772
1773		uint8 *replyBuf;
1774		int32 status;
1775
1776		fs_node *newNode;
1777
1778		if (!(omode & O_CREAT))
1779			return ENOENT;
1780
1781		XDROutPacketInit (&call);
1782		XDRInPacketInit (&reply);
1783
1784		XDROutPacketAddFixed (&call,dir->fhandle.opaque,NFS_FHSIZE);
1785		XDROutPacketAddString(&call,name);
1786		XDROutPacketAddInt32 (&call,perms|S_IFREG);
1787		XDROutPacketAddInt32 (&call,-1);
1788		XDROutPacketAddInt32 (&call,-1);
1789		XDROutPacketAddInt32 (&call,0);
1790		XDROutPacketAddInt32 (&call,time(NULL));
1791		XDROutPacketAddInt32 (&call,0);
1792		XDROutPacketAddInt32 (&call,time(NULL));
1793		XDROutPacketAddInt32 (&call,0);
1794
1795		replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_CREATE,&call);
1796
1797		if (!replyBuf)
1798		{
1799			XDRInPacketDestroy (&reply);
1800			XDROutPacketDestroy (&call);
1801			return B_ERROR;
1802		}
1803
1804		XDRInPacketSetTo (&reply,replyBuf,0);
1805
1806		if (!is_successful_reply(&reply))
1807		{
1808			XDRInPacketDestroy (&reply);
1809			XDROutPacketDestroy (&call);
1810			return B_ERROR;
1811		}
1812
1813		status=XDRInPacketGetInt32(&reply);
1814
1815		if (status!=NFS_OK)
1816		{
1817			XDRInPacketDestroy (&reply);
1818			XDROutPacketDestroy (&call);
1819			return map_nfs_to_system_error(status);
1820		}
1821
1822		XDRInPacketGetFixed (&reply,fhandle.opaque,NFS_FHSIZE);
1823
1824		get_nfs_attr (&reply,&st);
1825
1826		newNode=(fs_node *)malloc(sizeof(fs_node));
1827		newNode->fhandle=fhandle;
1828		newNode->vnid=st.st_ino;
1829
1830		insert_node (ns,newNode);
1831
1832		*vnid=st.st_ino;
1833		*cookie=(fs_file_cookie *)malloc(sizeof(fs_file_cookie));
1834		(*cookie)->omode=omode;
1835		(*cookie)->original_size=st.st_size;
1836		(*cookie)->st=st;
1837
1838		result=new_vnode (ns->nsid,*vnid,newNode);
1839
1840		if (result<B_OK)
1841		{
1842			XDRInPacketDestroy (&reply);
1843			XDROutPacketDestroy (&call);
1844			return result;
1845		}
1846
1847		XDRInPacketDestroy (&reply);
1848		XDROutPacketDestroy (&call);
1849		return my_notify_listener (B_ENTRY_CREATED,ns->nsid,dir->vnid,0,*vnid,name);
1850	}
1851}
1852
1853extern int
1854fs_unlink(fs_nspace *ns, fs_node *dir, const char *name)
1855{
1856	status_t result;
1857	fs_node *newNode;
1858	fs_node *dummy;
1859
1860	struct XDROutPacket call;
1861	struct XDRInPacket reply;
1862
1863	struct stat st;
1864	nfs_fhandle fhandle;
1865	uint8 *replyBuf;
1866
1867	int32 status;
1868
1869	XDROutPacketInit (&call);
1870	XDRInPacketInit (&reply);
1871
1872	if ((result=nfs_lookup(ns,&dir->fhandle,name,&fhandle,&st))<B_OK)
1873	{
1874		XDRInPacketDestroy (&reply);
1875		XDROutPacketDestroy (&call);
1876		return result;
1877	}
1878
1879	newNode=(fs_node *)malloc(sizeof(fs_node));
1880	newNode->fhandle=fhandle;
1881	newNode->vnid=st.st_ino;
1882
1883	insert_node (ns,newNode);
1884
1885	if ((result=get_vnode(ns->nsid,st.st_ino,(void **)&dummy))<B_OK)
1886	{
1887		XDRInPacketDestroy (&reply);
1888		XDROutPacketDestroy (&call);
1889		return result;
1890	}
1891
1892	if (!S_ISREG(st.st_mode)&&!S_ISLNK(st.st_mode))
1893	{
1894		XDRInPacketDestroy (&reply);
1895		XDROutPacketDestroy (&call);
1896		return EISDIR;
1897	}
1898
1899	if ((result=remove_vnode(ns->nsid,st.st_ino))<B_OK)
1900	{
1901		XDRInPacketDestroy (&reply);
1902		XDROutPacketDestroy (&call);
1903		return result;
1904	}
1905
1906	if ((result=put_vnode(ns->nsid,st.st_ino))<B_OK)
1907	{
1908		XDRInPacketDestroy (&reply);
1909		XDROutPacketDestroy (&call);
1910		return result;
1911	}
1912
1913	XDROutPacketAddFixed (&call,dir->fhandle.opaque,NFS_FHSIZE);
1914	XDROutPacketAddString(&call,name);
1915
1916	replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_REMOVE,&call);
1917
1918	if (!replyBuf)
1919	{
1920		XDRInPacketDestroy (&reply);
1921		XDROutPacketDestroy (&call);
1922		return EHOSTUNREACH;
1923	}
1924
1925	XDRInPacketSetTo(&reply,replyBuf,0);
1926
1927	if (!is_successful_reply(&reply))
1928	{
1929		XDRInPacketDestroy (&reply);
1930		XDROutPacketDestroy (&call);
1931		return B_ERROR;
1932	}
1933
1934	status=XDRInPacketGetInt32(&reply);
1935
1936	if (status!=NFS_OK)
1937	{
1938		XDRInPacketDestroy (&reply);
1939		XDROutPacketDestroy (&call);
1940		return map_nfs_to_system_error(status);
1941	}
1942
1943	XDRInPacketDestroy (&reply);
1944	XDROutPacketDestroy (&call);
1945
1946	return my_notify_listener (B_ENTRY_REMOVED,ns->nsid,dir->vnid,0,st.st_ino,name);
1947}
1948
1949extern int
1950fs_remove_vnode(fs_nspace *ns, fs_node *node, char r)
1951{
1952	remove_node (ns,node->vnid);
1953
1954	return B_OK;
1955}
1956
1957#ifndef __HAIKU__
1958extern int
1959fs_secure_vnode(fs_nspace *ns, fs_node *node)
1960{
1961	return B_OK;
1962}
1963#endif
1964
1965extern int
1966fs_mkdir(fs_nspace *ns, fs_node *dir, const char *name, int perms)
1967{
1968	nfs_fhandle fhandle;
1969	struct stat st;
1970	fs_node *newNode;
1971
1972	status_t result;
1973	uint8 *replyBuf;
1974	int32 status;
1975
1976	struct XDROutPacket call;
1977	struct XDRInPacket reply;
1978
1979	XDROutPacketInit (&call);
1980	XDRInPacketInit (&reply);
1981
1982	result=nfs_lookup(ns,&dir->fhandle,name,&fhandle,&st);
1983
1984	if (result==B_OK)
1985	{
1986		void *dummy;
1987
1988		XDRInPacketDestroy (&reply);
1989		XDROutPacketDestroy (&call);
1990		// XXX: either OK or not get_vnode !!! ??
1991		//if ((result=get_vnode(ns->nsid,st.st_ino,&dummy))<B_OK)
1992		//	return result;
1993		return EEXIST;
1994	}
1995	else if (result!=ENOENT)
1996	{
1997		XDRInPacketDestroy (&reply);
1998		XDROutPacketDestroy (&call);
1999		return result;
2000	}
2001
2002	XDROutPacketAddFixed (&call,dir->fhandle.opaque,NFS_FHSIZE);
2003	XDROutPacketAddString(&call,name);
2004	XDROutPacketAddInt32 (&call,perms|S_IFDIR);
2005	XDROutPacketAddInt32 (&call,-1);
2006	XDROutPacketAddInt32 (&call,-1);
2007	XDROutPacketAddInt32 (&call,-1);
2008	XDROutPacketAddInt32 (&call,time(NULL));
2009	XDROutPacketAddInt32 (&call,0);
2010	XDROutPacketAddInt32 (&call,time(NULL));
2011	XDROutPacketAddInt32 (&call,0);
2012
2013	replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_MKDIR,&call);
2014
2015	if (!replyBuf)
2016	{
2017		XDRInPacketDestroy (&reply);
2018		XDROutPacketDestroy (&call);
2019		return B_ERROR;
2020	}
2021
2022	XDRInPacketSetTo (&reply,replyBuf,0);
2023
2024	if (!is_successful_reply(&reply))
2025	{
2026		XDRInPacketDestroy (&reply);
2027		XDROutPacketDestroy (&call);
2028		return B_ERROR;
2029	}
2030
2031	status=XDRInPacketGetInt32(&reply);
2032
2033	if (status!=NFS_OK)
2034	{
2035		XDROutPacketDestroy (&call);
2036		return map_nfs_to_system_error(status);
2037	}
2038
2039	XDRInPacketGetFixed(&reply,fhandle.opaque,NFS_FHSIZE);
2040
2041	get_nfs_attr (&reply,&st);
2042
2043	newNode=(fs_node *)malloc(sizeof(fs_node));
2044	newNode->fhandle=fhandle;
2045	newNode->vnid=st.st_ino;
2046
2047	insert_node (ns,newNode);
2048
2049	XDRInPacketDestroy (&reply);
2050	XDROutPacketDestroy (&call);
2051
2052	return my_notify_listener (B_ENTRY_CREATED,ns->nsid,dir->vnid,0,st.st_ino,name);
2053}
2054
2055extern int
2056fs_rename(fs_nspace *ns, fs_node *olddir, const char *oldname, fs_node *newdir, const char *newname)
2057{
2058	struct stat st;
2059	nfs_fhandle fhandle;
2060	status_t result;
2061	struct XDROutPacket call;
2062	struct XDRInPacket reply;
2063	int32 status;
2064	uint8 *replyBuf;
2065
2066	XDROutPacketInit (&call);
2067	XDRInPacketInit (&reply);
2068
2069	if ((result=nfs_lookup(ns,&newdir->fhandle,newname,&fhandle,&st))==B_OK)
2070	{
2071		if (S_ISREG(st.st_mode))
2072			result=fs_unlink (ns,newdir,newname);
2073		else
2074			result=fs_rmdir (ns,newdir,newname);
2075
2076		if (result<B_OK)
2077		{
2078			XDRInPacketDestroy (&reply);
2079			XDROutPacketDestroy (&call);
2080			return result;
2081		}
2082	}
2083
2084	if ((result=nfs_lookup(ns,&olddir->fhandle,oldname,&fhandle,&st))<B_OK)
2085	{
2086		XDRInPacketDestroy (&reply);
2087		XDROutPacketDestroy (&call);
2088		return result;
2089	}
2090
2091	XDROutPacketAddFixed (&call,olddir->fhandle.opaque,NFS_FHSIZE);
2092	XDROutPacketAddString(&call,oldname);
2093	XDROutPacketAddFixed (&call,newdir->fhandle.opaque,NFS_FHSIZE);
2094	XDROutPacketAddString(&call,newname);
2095
2096	replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_RENAME,&call);
2097
2098	if (!replyBuf)
2099	{
2100		XDRInPacketDestroy (&reply);
2101		XDROutPacketDestroy (&call);
2102		return EHOSTUNREACH;
2103	}
2104
2105	XDRInPacketSetTo (&reply,replyBuf,0);
2106
2107	if (!is_successful_reply(&reply))
2108	{
2109		XDRInPacketDestroy (&reply);
2110		XDROutPacketDestroy (&call);
2111		return B_ERROR;
2112	}
2113
2114	status=XDRInPacketGetInt32(&reply);
2115
2116	if (status!=NFS_OK)
2117	{
2118		XDRInPacketDestroy (&reply);
2119		XDROutPacketDestroy (&call);
2120		return map_nfs_to_system_error(status);
2121	}
2122
2123	XDRInPacketDestroy (&reply);
2124	XDROutPacketDestroy (&call);
2125
2126	return my_notify_listener (B_ENTRY_MOVED,ns->nsid,olddir->vnid,newdir->vnid,st.st_ino,newname);
2127}
2128
2129extern int
2130fs_rmdir(fs_nspace *ns, fs_node *dir, const char *name)
2131{
2132	status_t result;
2133	fs_node *newNode;
2134	fs_node *dummy;
2135	struct XDROutPacket call;
2136	struct XDRInPacket reply;
2137	int32 status;
2138	uint8 *replyBuf;
2139
2140	struct stat st;
2141	nfs_fhandle fhandle;
2142
2143	XDROutPacketInit(&call);
2144	XDRInPacketInit(&reply);
2145
2146	if ((result=nfs_lookup(ns,&dir->fhandle,name,&fhandle,&st))<B_OK)
2147	{
2148		XDRInPacketDestroy(&reply);
2149		XDROutPacketDestroy(&call);
2150		return result;
2151	}
2152
2153	newNode=(fs_node *)malloc(sizeof(fs_node));
2154	newNode->fhandle=fhandle;
2155	newNode->vnid=st.st_ino;
2156
2157	insert_node (ns,newNode);
2158
2159	if ((result=get_vnode(ns->nsid,st.st_ino,(void **)&dummy))<B_OK)
2160	{
2161		XDRInPacketDestroy(&reply);
2162		XDROutPacketDestroy(&call);
2163		return result;
2164	}
2165
2166	if (!S_ISDIR(st.st_mode))
2167	{
2168		XDRInPacketDestroy(&reply);
2169		XDROutPacketDestroy(&call);
2170		return ENOTDIR;
2171	}
2172
2173	if ((result=remove_vnode(ns->nsid,st.st_ino))<B_OK)
2174	{
2175		XDRInPacketDestroy(&reply);
2176		XDROutPacketDestroy(&call);
2177		return result;
2178	}
2179
2180	if ((result=put_vnode(ns->nsid,st.st_ino))<B_OK)
2181	{
2182		XDRInPacketDestroy(&reply);
2183		XDROutPacketDestroy(&call);
2184		return result;
2185	}
2186
2187	XDROutPacketAddFixed (&call,dir->fhandle.opaque,NFS_FHSIZE);
2188	XDROutPacketAddString(&call,name);
2189
2190	replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_RMDIR,&call);
2191
2192	if (!replyBuf)
2193	{
2194		XDRInPacketDestroy(&reply);
2195		XDROutPacketDestroy(&call);
2196		return EHOSTUNREACH;
2197	}
2198
2199	XDRInPacketSetTo (&reply,replyBuf,0);
2200
2201	if (!is_successful_reply(&reply))
2202	{
2203		XDRInPacketDestroy(&reply);
2204		XDROutPacketDestroy(&call);
2205		return B_ERROR;
2206	}
2207
2208	status=XDRInPacketGetInt32(&reply);
2209
2210	if (status!=NFS_OK)
2211	{
2212		XDRInPacketDestroy(&reply);
2213		XDROutPacketDestroy(&call);
2214		return map_nfs_to_system_error(status);
2215	}
2216
2217	XDRInPacketDestroy(&reply);
2218	XDROutPacketDestroy(&call);
2219	return my_notify_listener (B_ENTRY_REMOVED,ns->nsid,dir->vnid,0,st.st_ino,name);
2220}
2221
2222extern int
2223fs_readlink(fs_nspace *ns, fs_node *node, char *buf, size_t *bufsize)
2224{
2225	struct XDROutPacket call;
2226	uint8 *replyBuf;
2227	int32 status;
2228	size_t length;
2229	char data[NFS_MAXPATHLEN];
2230	struct XDRInPacket reply;
2231
2232	XDROutPacketInit (&call);
2233	XDRInPacketInit(&reply);
2234
2235	XDROutPacketAddFixed (&call,node->fhandle.opaque,NFS_FHSIZE);
2236
2237	replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_READLINK,&call);
2238
2239	if (!replyBuf)
2240	{
2241		XDRInPacketDestroy(&reply);
2242		XDROutPacketDestroy (&call);
2243		return EHOSTUNREACH;
2244	}
2245
2246	XDRInPacketSetTo (&reply,replyBuf,0);
2247
2248	if (!is_successful_reply(&reply))
2249	{
2250		XDRInPacketDestroy(&reply);
2251		XDROutPacketDestroy (&call);
2252		return B_ERROR;
2253	}
2254
2255	status=XDRInPacketGetInt32(&reply);
2256
2257	if (status!=NFS_OK)
2258	{
2259		XDRInPacketDestroy(&reply);
2260		XDROutPacketDestroy (&call);
2261		return map_nfs_to_system_error(status);
2262	}
2263
2264	length=XDRInPacketGetDynamic(&reply,data);
2265
2266	length=min_c(length,*bufsize);
2267	memcpy (buf,data,length);
2268	*bufsize=length;
2269
2270	XDRInPacketDestroy(&reply);
2271	XDROutPacketDestroy (&call);
2272	return B_OK;
2273}
2274
2275extern int
2276#ifdef __HAIKU__
2277fs_symlink(fs_nspace *ns, fs_node *dir, const char *name, const char *path, int mode)
2278#else
2279fs_symlink(fs_nspace *ns, fs_node *dir, const char *name, const char *path)
2280#endif
2281{
2282	nfs_fhandle fhandle;
2283	struct stat st;
2284	struct XDROutPacket call;
2285	struct XDRInPacket reply;
2286	status_t result;
2287	uint8 *replyBuf;
2288	int32 status;
2289	fs_node *newNode;
2290
2291	XDROutPacketInit (&call);
2292	XDRInPacketInit (&reply);
2293
2294	result=nfs_lookup(ns,&dir->fhandle,name,&fhandle,&st);
2295
2296	if (result==B_OK)
2297	{
2298		void *dummy;
2299		if ((result=get_vnode(ns->nsid,st.st_ino,&dummy))<B_OK)
2300			return result;
2301
2302		XDRInPacketDestroy (&reply);
2303		XDROutPacketDestroy (&call);
2304		return EEXIST;
2305	}
2306	else if (result!=ENOENT)
2307	{
2308		XDRInPacketDestroy (&reply);
2309		XDROutPacketDestroy (&call);
2310		return result;
2311	}
2312
2313	XDROutPacketAddFixed (&call,dir->fhandle.opaque,NFS_FHSIZE);
2314	XDROutPacketAddString(&call,name);
2315	XDROutPacketAddString(&call,path);
2316	XDROutPacketAddInt32 (&call,S_IFLNK);
2317	XDROutPacketAddInt32 (&call,-1);
2318	XDROutPacketAddInt32 (&call,-1);
2319	XDROutPacketAddInt32 (&call,-1);
2320	XDROutPacketAddInt32 (&call,time(NULL));
2321	XDROutPacketAddInt32 (&call,0);
2322	XDROutPacketAddInt32 (&call,time(NULL));
2323	XDROutPacketAddInt32 (&call,0);
2324
2325	replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_SYMLINK,&call);
2326
2327	if (!replyBuf)
2328	{
2329		XDRInPacketDestroy (&reply);
2330		XDROutPacketDestroy (&call);
2331		return B_ERROR;
2332	}
2333
2334	XDRInPacketSetTo (&reply,replyBuf,0);
2335
2336	if (!is_successful_reply(&reply))
2337	{
2338		XDRInPacketDestroy (&reply);
2339		XDROutPacketDestroy (&call);
2340		return B_ERROR;
2341	}
2342
2343	status=XDRInPacketGetInt32(&reply);
2344
2345/*	if (status!=NFS_OK)
2346		return map_nfs_to_system_error(status);
2347
2348	ignore status here, weird thing, nfsservers that is
2349*/
2350
2351	result=nfs_lookup(ns,&dir->fhandle,name,&fhandle,&st);
2352
2353	if (result<B_OK)
2354	{
2355		XDRInPacketDestroy (&reply);
2356		XDROutPacketDestroy (&call);
2357		return result;
2358	}
2359
2360	newNode=(fs_node *)malloc(sizeof(fs_node));
2361	newNode->fhandle=fhandle;
2362	newNode->vnid=st.st_ino;
2363
2364	insert_node (ns,newNode);
2365
2366	result=my_notify_listener (B_ENTRY_CREATED,ns->nsid,dir->vnid,0,st.st_ino,name);
2367
2368	XDRInPacketDestroy (&reply);
2369	XDROutPacketDestroy (&call);
2370	return result;
2371}
2372
2373int	fs_access(void *ns, void *node, int mode)
2374{
2375	/* XXX */
2376	return B_OK;
2377}
2378
2379#ifdef __HAIKU__
2380
2381static status_t
2382nfs_std_ops(int32 op, ...)
2383{
2384	switch (op) {
2385		case B_MODULE_INIT:
2386			dprintf("nfs:std_ops(INIT)\n");
2387			return B_OK;
2388		case B_MODULE_UNINIT:
2389			dprintf("nfs:std_ops(UNINIT)\n");
2390			return B_OK;
2391		default:
2392			return B_ERROR;
2393	}
2394}
2395
2396
2397static file_system_module_info sNFSModule = {
2398	{
2399		"file_systems/nfs" B_CURRENT_FS_API_VERSION,
2400		0,
2401		nfs_std_ops,
2402	},
2403
2404	"Network File System v2",
2405
2406	// scanning
2407	NULL,	// fs_identify_partition,
2408	NULL,	// fs_scan_partition,
2409	NULL,	// fs_free_identify_partition_cookie,
2410	NULL,	// free_partition_content_cookie()
2411
2412	&fs_mount,
2413	&fs_unmount,
2414	&fs_rfsstat,
2415	&fs_wfsstat,
2416	NULL,	// &fs_sync,
2417
2418	/* vnode operations */
2419	&fs_walk,
2420	&fs_get_vnode_name,
2421	&fs_read_vnode,
2422	&fs_release_vnode,
2423	&fs_remove_vnode,
2424
2425	/* VM file access */
2426	NULL, 	// &fs_can_page
2427	NULL,	// &fs_read_pages
2428	NULL, 	// &fs_write_pages
2429
2430	NULL,	// &fs_get_file_map,
2431
2432	NULL, 	// &fs_ioctl
2433	NULL,	// &fs_setflags,
2434	NULL,	// &fs_select
2435	NULL,	// &fs_deselect
2436	NULL, 	// &fs_fsync
2437
2438	&fs_readlink,
2439	NULL,	// &fs_write link,
2440	&fs_symlink,
2441
2442	NULL,	// &fs_link,
2443	&fs_unlink,
2444	&fs_rename,
2445
2446	&fs_access,
2447	&fs_rstat,
2448	&fs_wstat,
2449
2450	/* file operations */
2451	&fs_create,
2452	&fs_open,
2453	&fs_close,
2454	&fs_free_cookie,
2455	&fs_read,
2456	&fs_write,
2457
2458	/* directory operations */
2459	&fs_mkdir,
2460	&fs_rmdir,
2461	&fs_opendir,
2462	&fs_closedir,
2463	&fs_free_dircookie,
2464	&fs_readdir,
2465	&fs_rewinddir,
2466
2467	/* attribute directory operations */
2468	NULL,	// &fs_open_attrdir,
2469	NULL,	// &fs_close_attrdir,
2470	NULL,	// &fs_free_attrdircookie,
2471	NULL,	// &fs_read_attrdir,
2472	NULL,	// &fs_rewind_attrdir,
2473
2474	/* attribute operations */
2475	NULL,	// &fs_create_attr
2476	NULL,	// &fs_open_attr_h,
2477	NULL,	// &fs_close_attr_h,
2478	NULL,	// &fs_free_attr_cookie_h,
2479	NULL,	// &fs_read_attr_h,
2480	NULL,	// &fs_write_attr_h,
2481
2482	NULL,	// &fs_read_attr_stat_h,
2483	NULL,	// &fs_write_attr_stat
2484	NULL,	// &fs_rename_attr
2485	NULL,	// &fs_remove_attr
2486
2487	/* index directory & index operations */
2488	NULL,	// &fs_open_index_dir
2489	NULL,	// &fs_close_index_dir
2490	NULL,	// &fs_free_index_dir_cookie
2491	NULL,	// &fs_read_index_dir
2492	NULL,	// &fs_rewind_index_dir
2493
2494	NULL,	// &fs_create_index
2495	NULL,	// &fs_remove_index
2496	NULL,	// &fs_stat_index
2497
2498	/* query operations */
2499	NULL,	// &fs_open_query,
2500	NULL,	// &fs_close_query,
2501	NULL,	// &fs_free_query_cookie,
2502	NULL,	// &fs_read_query,
2503	NULL,	// &fs_rewind_query,
2504};
2505
2506module_info *modules[] = {
2507	(module_info *)&sNFSModule,
2508	NULL,
2509};
2510
2511
2512#else
2513
2514_EXPORT vnode_ops fs_entry =
2515{
2516	(op_read_vnode *)&fs_read_vnode,
2517	(op_write_vnode *)&fs_write_vnode,
2518	(op_remove_vnode *)&fs_remove_vnode,
2519	(op_secure_vnode *)&fs_secure_vnode,
2520	(op_walk *)&fs_walk,
2521	(op_access *)&fs_access,
2522	(op_create *)&fs_create,
2523	(op_mkdir *)&fs_mkdir,
2524	(op_symlink *)&fs_symlink,
2525	NULL, //	&fs_link,
2526	(op_rename *)&fs_rename,
2527	(op_unlink *)&fs_unlink,
2528	(op_rmdir *)&fs_rmdir,
2529	(op_readlink *)&fs_readlink,
2530	(op_opendir *)&fs_opendir,
2531	(op_closedir *)&fs_closedir,
2532	(op_free_cookie *)&fs_free_dircookie,
2533	(op_rewinddir *)&fs_rewinddir,
2534	(op_readdir *)&fs_readdir,
2535	(op_open *)&fs_open,
2536	(op_close *)&fs_close,
2537	(op_free_cookie *)&fs_free_cookie,
2538	(op_read *)&fs_read,
2539	(op_write *)&fs_write,
2540	NULL, //	&fs_readv,
2541	NULL, //	&fs_writev,
2542	NULL, //	&fs_ioctl,
2543	NULL, //	&fs_setflags,
2544	(op_rstat *)&fs_rstat,
2545	(op_wstat *)&fs_wstat,
2546	NULL, //	&fs_fsync,
2547	NULL, //	&fs_initialize,
2548	(op_mount *)&fs_mount,
2549	(op_unmount *)&fs_unmount,
2550	NULL, //	&fs_sync,
2551	(op_rfsstat *)&fs_rfsstat,
2552	(op_wfsstat *)&fs_wfsstat,
2553	NULL, //	&fs_select,
2554	NULL, //	&fs_deselect,
2555	NULL, //	&fs_open_indexdir,
2556	NULL, //	&fs_close_indexdir,
2557	NULL, //	&fs_free_indexdircookie,
2558	NULL, //	&fs_rewind_indexdir,
2559	NULL, //	&fs_read_indexdir,
2560	NULL, //	&fs_create_index,
2561	NULL, //	&fs_remove_index,
2562	NULL, //	&fs_rename_index,
2563	NULL, //	&fs_stat_index,
2564	NULL, //	&fs_open_attrdir,
2565	NULL, //	&fs_close_attrdir,
2566	NULL, //	&fs_free_attrdircookie,
2567	NULL, //	&fs_rewind_attrdir,
2568	NULL, //	&fs_read_attrdir,
2569	NULL, //	&fs_write_attr,
2570	NULL, //	&fs_read_attr,
2571	NULL, //	&fs_remove_attr,
2572	NULL, //	&fs_rename_attr,
2573	NULL, //	&fs_stat_attr,
2574	NULL, //	&fs_open_query,
2575	NULL, //	&fs_close_query,
2576	NULL, //	&fs_free_querycookie,
2577	NULL, //	&fs_read_query
2578};
2579
2580_EXPORT int32 api_version=B_CUR_FS_API_VERSION;
2581
2582#endif
2583