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