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