nfs_add_on.c revision 55b36803
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__
865/* no reason to do it,
866 * the VFS does it the best possible way for an unix fs anyway.
867 * so we use NULL for this call.
868 */
869extern int
870fs_get_vnode_name(fs_nspace *ns, fs_node *node, char *buffer, size_t len)
871{
872	return ENOSYS;
873}
874#endif
875
876extern int
877#ifdef __HAIKU__
878fs_walk(fs_nspace *ns, fs_node *base, const char *file, vnode_id *vnid, int *type)
879#else
880fs_walk(fs_nspace *ns, fs_node *base, const char *file, char **newpath, vnode_id *vnid)
881#endif
882{
883	bool isLink;
884	fs_node *dummy;
885	status_t result;
886	//dprintf("nfs: walk(%s)\n", file);//XXX:mmu_man:debug
887
888	if (!strcmp(".",file))
889	{
890		*vnid=base->vnid;
891#ifdef __HAIKU__
892		*type = S_IFDIR;
893#endif
894		isLink=false;
895	}
896	else
897	{
898		fs_node *newNode=(fs_node *)malloc(sizeof(fs_node));
899		struct stat st;
900
901		if ((result=nfs_lookup(ns,&base->fhandle,file,&newNode->fhandle,&st))<B_OK)
902		{
903			free(newNode);
904			return result;
905		}
906
907		newNode->vnid=st.st_ino;
908		*vnid=newNode->vnid;
909#ifdef __HAIKU__
910		*type = st.st_mode & S_IFMT;
911#endif
912
913		insert_node (ns,newNode);
914
915		isLink=S_ISLNK(st.st_mode);
916	}
917
918	if ((result=get_vnode (ns->nsid,*vnid,(void **)&dummy))<B_OK)
919		return result;
920
921#ifndef __HAIKU__
922	if ((isLink)&&(newpath))
923	{
924		char path[NFS_MAXPATHLEN+1];
925		size_t pathLen=NFS_MAXPATHLEN;
926
927		if ((result=fs_readlink(ns,dummy,path,&pathLen))<B_OK)
928		{
929			put_vnode (ns->nsid,*vnid);
930			return result;
931		}
932
933		path[pathLen]=0;
934
935		result=new_path(path,newpath);
936
937		if (result<B_OK)
938		{
939			put_vnode (ns->nsid,*vnid);
940			return result;
941		}
942
943		return put_vnode (ns->nsid,*vnid);
944	}
945#endif
946
947	return B_OK;
948}
949
950extern int
951fs_opendir(fs_nspace *ns, fs_node *node, nfs_cookie **cookie)
952{
953	struct stat st;
954
955	status_t result;
956	if ((result=nfs_getattr(ns,&node->fhandle,&st))<B_OK)
957		return result;
958
959	if (!S_ISDIR(st.st_mode))
960		return ENOTDIR;
961
962	*cookie=(nfs_cookie *)malloc(sizeof(nfs_cookie));
963	memset ((*cookie)->opaque,0,NFS_COOKIESIZE);
964
965	return B_OK;
966}
967
968extern int
969fs_closedir(fs_nspace *ns, fs_node *node, nfs_cookie *cookie)
970{
971	(void) ns;
972	(void) node;
973	(void) cookie;
974	return B_OK;
975}
976
977extern int
978fs_rewinddir(fs_nspace *ns, fs_node *node, nfs_cookie *cookie)
979{
980	(void) ns;
981	(void) node;
982	memset (cookie->opaque,0,NFS_COOKIESIZE);
983
984	return B_OK;
985}
986
987extern int
988#ifdef __HAIKU__
989fs_readdir(fs_nspace *ns, fs_node *node, nfs_cookie *cookie, struct dirent *buf, size_t bufsize, uint32 *num)
990#else
991fs_readdir(fs_nspace *ns, fs_node *node, nfs_cookie *cookie, long *num, struct dirent *buf, size_t bufsize)
992#endif
993{
994	int32 max=*num;
995	int32 eof;
996
997	size_t count=min_c(6000,max*300);
998
999	*num=0;
1000
1001	do
1002	{
1003		vnode_id vnid;
1004		char *filename;
1005		uint8 *replyBuf;
1006		struct XDROutPacket call;
1007		struct XDRInPacket reply;
1008		int32 status;
1009
1010		XDROutPacketInit (&call);
1011		XDRInPacketInit (&reply);
1012
1013		XDROutPacketAddFixed (&call,node->fhandle.opaque,NFS_FHSIZE);
1014		XDROutPacketAddFixed (&call,cookie->opaque,NFS_COOKIESIZE);
1015		XDROutPacketAddInt32 (&call,count);
1016
1017		replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_READDIR,&call);
1018
1019		if (!replyBuf)
1020		{
1021			XDRInPacketDestroy (&reply);
1022			XDROutPacketDestroy (&call);
1023			return B_ERROR;
1024		}
1025
1026		XDRInPacketSetTo(&reply,replyBuf,0);
1027
1028		if (!is_successful_reply(&reply))
1029		{
1030			XDRInPacketDestroy (&reply);
1031			XDROutPacketDestroy (&call);
1032			return B_ERROR;
1033		}
1034
1035		status=XDRInPacketGetInt32(&reply);
1036
1037		if (status!=NFS_OK)
1038		{
1039			XDRInPacketDestroy (&reply);
1040			XDROutPacketDestroy (&call);
1041			return map_nfs_to_system_error(status);
1042		}
1043
1044		while (XDRInPacketGetInt32(&reply)==1)
1045		{
1046			nfs_cookie newCookie;
1047
1048			vnid=XDRInPacketGetInt32(&reply);
1049			filename=XDRInPacketGetString(&reply);
1050
1051			XDRInPacketGetFixed(&reply,newCookie.opaque,NFS_COOKIESIZE);
1052
1053			//if (strcmp(".",filename)&&strcmp("..",filename))
1054			//if ((ns->rootid != node->vnid) || (strcmp(".",filename)&&strcmp("..",filename)))
1055			if (conf_ls_root_parent || ((ns->rootid != node->vnid) || strcmp("..",filename)))
1056			{
1057				status_t result;
1058				struct stat st;
1059
1060				fs_node *newNode=(fs_node *)malloc(sizeof(fs_node));
1061				newNode->vnid=vnid;
1062
1063				if ((result=nfs_lookup(ns,&node->fhandle,filename,&newNode->fhandle,&st))<B_OK)
1064				{
1065					free (filename);
1066					free(newNode);
1067					XDRInPacketDestroy (&reply);
1068					XDROutPacketDestroy (&call);
1069					return result;
1070				}
1071
1072				insert_node (ns,newNode);
1073
1074				if (bufsize<2*(sizeof(dev_t)+sizeof(ino_t))+sizeof(unsigned short)+strlen(filename)+1)
1075				{
1076					XDRInPacketDestroy (&reply);
1077					XDROutPacketDestroy (&call);
1078					return B_OK;
1079				}
1080
1081				buf->d_dev=ns->nsid;
1082				buf->d_pdev=ns->nsid;
1083				buf->d_ino=vnid;
1084				buf->d_pino=node->vnid;
1085				buf->d_reclen=2*(sizeof(dev_t)+sizeof(ino_t))+sizeof(unsigned short)+strlen(filename)+1;
1086				strcpy (buf->d_name,filename);
1087//				if ((ns->rootid == node->vnid))//XXX:mmu_man:test
1088//					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);
1089
1090				bufsize-=buf->d_reclen;
1091				buf=(struct dirent *)((char *)buf+buf->d_reclen);
1092
1093				memcpy (cookie->opaque,newCookie.opaque,NFS_COOKIESIZE);
1094
1095				(*num)++;
1096			}
1097			else {
1098				memcpy (cookie->opaque,newCookie.opaque,NFS_COOKIESIZE);
1099			}
1100
1101			free (filename);
1102
1103			if ((*num)==max)
1104			{
1105				XDRInPacketDestroy (&reply);
1106				XDROutPacketDestroy (&call);
1107				return B_OK;
1108			}
1109		}
1110
1111		eof=XDRInPacketGetInt32(&reply);
1112
1113		XDRInPacketDestroy (&reply);
1114		XDROutPacketDestroy (&call);
1115	}
1116	while (eof==0);
1117
1118	return B_OK;
1119}
1120
1121extern int
1122fs_free_dircookie(fs_nspace *ns, fs_node *node, nfs_cookie *cookie)
1123{
1124	(void) ns;
1125	(void) node;
1126	free(cookie);
1127	return B_OK;
1128}
1129
1130extern int
1131fs_rstat(fs_nspace *ns, fs_node *node, struct stat *st)
1132{
1133	status_t result;
1134	//dprintf("nfs: rstat()\n");//XXX:mmu_man:debug
1135	if ((result=nfs_getattr(ns,&node->fhandle,st))<B_OK)
1136		return result;
1137
1138	st->st_dev=ns->nsid;
1139//st->st_nlink = 1; //XXX:mmu_man:test
1140	return B_OK;
1141}
1142
1143extern void
1144fs_nspaceInit(struct fs_nspace *nspace)
1145{
1146	RPCPendingCallsInit (&nspace->pendingCalls);
1147}
1148
1149extern void
1150fs_nspaceDestroy(struct fs_nspace *nspace)
1151{
1152	RPCPendingCallsDestroy (&nspace->pendingCalls);
1153}
1154
1155#ifdef PARAMS_AS_STRING
1156int parse_nfs_params(const char *str, struct mount_nfs_params *params)
1157{
1158	const char *p, *e;
1159	long v;
1160	int i;
1161	// sprintf(buf, "nfs:%s:%s,uid=%u,gid=%u,hostname=%s",
1162	if (!str || !params)
1163		return EINVAL;
1164	if (strncmp(str, "nfs:", 4))
1165		return EINVAL;
1166dprintf("nfs:ip!\n");
1167	p = str + 4;
1168	e = strchr(p, ':');
1169	if (!e)
1170		return EINVAL;
1171	params->server = malloc(e - p + 1);
1172	params->server[e-p] = '\0';
1173	strncpy(params->server, p, e - p);
1174	// hack
1175	params->serverIP = 0;
1176	v = strtol(p, (char **)&p, 10);
1177dprintf("IP:%ld.", v);
1178	if (!p)
1179		return EINVAL;
1180	params->serverIP |= (v << 24);
1181	p++;
1182	v = strtol(p, (char **)&p, 10);
1183dprintf("%ld.", v);
1184	if (!p)
1185		return EINVAL;
1186	params->serverIP |= (v << 16);
1187	p++;
1188	v = strtol(p, (char **)&p, 10);
1189dprintf("%ld.", v);
1190	if (!p)
1191		return EINVAL;
1192	params->serverIP |= (v << 8);
1193	p++;
1194	v = strtol(p, (char **)&p, 10);
1195dprintf("%ld\n", v);
1196	if (!p)
1197		return EINVAL;
1198	params->serverIP |= (v);
1199	if (*p++ != ':')
1200		return EINVAL;
1201
1202	e = strchr(p, ',');
1203	i = (e) ? (e - p) : (strlen(p));
1204
1205	params->_export = malloc(i+1);
1206	params->_export[i] = '\0';
1207	strncpy(params->_export, p, i);
1208
1209	p = strstr(str, "hostname=");
1210	if (!p)
1211		return EINVAL;
1212dprintf("nfs:hn!\n");
1213	p += 9;
1214	e = strchr(p, ',');
1215	i = (e) ? (e - p) : (strlen(p));
1216
1217	params->hostname = malloc(i+1);
1218	params->hostname[i] = '\0';
1219	strncpy(params->hostname, p, i);
1220
1221	p = strstr(str, "uid=");
1222dprintf("nfs:uid!\n");
1223	if (p) {
1224		p += 4;
1225		v = strtol(p, (char **)&p, 10);
1226		params->uid = v;
1227	}
1228dprintf("nfs:gid!\n");
1229	p = strstr(str, "gid=");
1230	if (p) {
1231		p += 4;
1232		v = strtol(p, (char **)&p, 10);
1233		params->gid = v;
1234	}
1235	dprintf("nfs: ip:%08x server:'%s' export:'%s' hostname:'%s' uid=%d gid=%d \n",
1236		params->serverIP, params->server, params->_export,
1237		params->hostname, params->uid, params->gid);
1238	return B_OK;
1239}
1240#endif
1241
1242extern int
1243#ifdef __HAIKU__
1244fs_mount(nspace_id nsid, const char *devname, uint32 flags, const char *_parms, fs_nspace **data, vnode_id *vnid)
1245#else
1246fs_mount(nspace_id nsid, const char *devname, ulong flags, const char *_parms, size_t len, fs_nspace **data, vnode_id *vnid)
1247#endif
1248{
1249#ifndef PARAMS_AS_STRING
1250	struct mount_nfs_params *parms = (struct mount_nfs_params *)_parms; // XXX: FIXME
1251#endif
1252	status_t result;
1253	fs_nspace *ns;
1254	fs_node *rootNode;
1255	struct stat st;
1256#ifndef __HAIKU__
1257	(void) len;
1258#endif
1259
1260	if (_parms==NULL)
1261		return EINVAL;
1262
1263dprintf("nfs: mount(%ld, %s, %08lx)\n", nsid, devname, flags);
1264#ifndef PARAMS_AS_STRING
1265dprintf("nfs: nfs_params(ip:%lu, server:%s, export:%s, uid:%d, gid:%d, hostname:%s)\n",
1266        parms->serverIP,
1267        parms->server,
1268        parms->_export,
1269        parms->uid,
1270        parms->gid,
1271        parms->hostname);
1272#else
1273dprintf("nfs: nfs_params: %s\n", _parms);
1274#endif
1275
1276	// HAIKU: this should go to std_ops
1277	if (!refcount)
1278		read_config();
1279
1280	result = ksocket_init();
1281	if (result < B_OK)
1282		return result;
1283
1284	result = ENOMEM;
1285	ns=(fs_nspace *)malloc(sizeof(fs_nspace));
1286	if (!ns)
1287		goto err_nspace;
1288	fs_nspaceInit (ns);
1289
1290	ns->nsid=nsid;
1291
1292	ns->params.server=NULL;
1293	ns->params._export=NULL;
1294	ns->params.hostname=NULL;
1295#ifdef PARAMS_AS_STRING
1296	if ((result = parse_nfs_params(_parms, &ns->params)) < 0)
1297		goto err_params;
1298#else
1299	ns->params.serverIP=parms->serverIP;
1300	ns->params.server=strdup(parms->server);
1301	ns->params._export=strdup(parms->_export);
1302	ns->params.uid=parms->uid;
1303	ns->params.gid=parms->gid;
1304	ns->params.hostname=strdup(parms->hostname);
1305#endif
1306	ns->xid=0;
1307	ns->mountAddr.sin_family=AF_INET;
1308	ns->mountAddr.sin_addr.s_addr=htonl(ns->params.serverIP);
1309	memset (ns->mountAddr.sin_zero,0,sizeof(ns->mountAddr.sin_zero));
1310
1311	if ((result=create_socket(ns))<B_OK)
1312		goto err_socket;
1313
1314	if ((result=init_postoffice(ns))<B_OK)
1315		goto err_postoffice;
1316
1317	if ((result=get_remote_address(ns,MOUNT_PROGRAM,MOUNT_VERSION,PMAP_IPPROTO_UDP,&ns->mountAddr))<B_OK)
1318		goto err_sem;
1319
1320	memcpy (&ns->nfsAddr,&ns->mountAddr,sizeof(ns->mountAddr));
1321dprintf("nfs: mountd at %08lx:%d\n", ns->mountAddr.sin_addr.s_addr, ntohs(ns->mountAddr.sin_port));
1322
1323	if ((result=get_remote_address(ns,NFS_PROGRAM,NFS_VERSION,PMAP_IPPROTO_UDP,&ns->nfsAddr))<B_OK)
1324		goto err_sem;
1325dprintf("nfs: nfsd at %08lx:%d\n", ns->nfsAddr.sin_addr.s_addr, ntohs(ns->nfsAddr.sin_port));
1326//	result = connect_socket(ns);
1327//dprintf("nfs: connect: %s\n", strerror(result));
1328
1329	if ((result=create_sem(1,"nfs_sem"))<B_OK)
1330		goto err_sem;
1331
1332	ns->sem=result;
1333
1334	set_sem_owner (ns->sem,B_SYSTEM_TEAM);
1335
1336	result = ENOMEM;
1337	rootNode=(fs_node *)malloc(sizeof(fs_node));
1338	if (!rootNode)
1339		goto err_rootvn;
1340	rootNode->next=NULL;
1341
1342	if ((result=nfs_mount(ns,ns->params._export,&rootNode->fhandle))<B_OK)
1343		goto err_mount;
1344
1345	if ((result=nfs_getattr(ns,&rootNode->fhandle,&st))<B_OK)
1346		goto err_publish;
1347
1348	ns->rootid=st.st_ino;
1349	rootNode->vnid=ns->rootid;
1350
1351	*vnid=ns->rootid;
1352
1353	if ((result=publish_vnode(nsid,*vnid,rootNode))<B_OK)
1354		goto err_publish;
1355
1356	*data=ns;
1357
1358	ns->first=rootNode;
1359
1360	return B_OK;
1361
1362err_publish:
1363	// XXX: unmount ??
1364err_mount:
1365	free(rootNode);
1366err_rootvn:
1367	delete_sem (ns->sem);
1368err_sem:
1369	shutdown_postoffice(ns);
1370	goto err_socket;
1371err_postoffice:
1372	kclosesocket(ns->s);
1373err_socket:
1374err_params:
1375	free (ns->params.hostname);
1376	free (ns->params._export);
1377	free (ns->params.server);
1378
1379	fs_nspaceDestroy (ns);
1380	free(ns);
1381err_nspace:
1382
1383	ksocket_cleanup();
1384	if (result >= 0) {
1385		dprintf("nfs:bad error from mount!\n");
1386		result = EINVAL;
1387	}
1388	dprintf("nfs: error in nfs_mount: %s\n", strerror(result));
1389	return result;
1390}
1391
1392extern int
1393fs_unmount(fs_nspace *ns)
1394{
1395	free (ns->params.hostname);
1396	free (ns->params._export);
1397	free (ns->params.server);
1398
1399	while (ns->first)
1400	{
1401		fs_node *next=ns->first->next;
1402		free(ns->first);
1403		ns->first=next;
1404	}
1405
1406	// Unlike in BeOS, we need to put the reference to our root node ourselves
1407#ifdef __HAIKU__
1408	put_vnode(ns->nsid, ns->rootid);
1409#endif
1410
1411	delete_sem (ns->sem);
1412	shutdown_postoffice(ns);
1413	fs_nspaceDestroy (ns);
1414	free(ns);
1415	ksocket_cleanup();
1416	return B_OK;
1417}
1418
1419extern int
1420fs_rfsstat(fs_nspace *ns, struct fs_info *info)
1421{
1422	struct XDROutPacket call;
1423	struct XDRInPacket reply;
1424	nfs_fhandle rootHandle=handle_from_vnid (ns,ns->rootid);
1425	uint8 *replyBuf;
1426	int32 status;
1427	//dprintf("nfs: rfsstat()\n");//XXX:mmu_man:debug
1428
1429	XDROutPacketInit (&call);
1430	XDRInPacketInit (&reply);
1431
1432	XDROutPacketAddFixed (&call,rootHandle.opaque,NFS_FHSIZE);
1433
1434	replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_STATFS,&call);
1435
1436	if (!replyBuf)
1437	{
1438		XDRInPacketDestroy (&reply);
1439		XDROutPacketDestroy (&call);
1440		return EHOSTUNREACH;
1441	}
1442
1443	XDRInPacketSetTo(&reply,replyBuf,0);
1444
1445	if (!is_successful_reply(&reply))
1446	{
1447		XDRInPacketDestroy (&reply);
1448		XDROutPacketDestroy (&call);
1449		return B_ERROR;
1450	}
1451
1452	status=XDRInPacketGetInt32(&reply);
1453
1454	if (status!=NFS_OK)
1455	{
1456		XDRInPacketDestroy (&reply);
1457		XDROutPacketDestroy (&call);
1458		//dprintf("nfs: rfsstat() error 0x%08lx\n", map_nfs_to_system_error(status));
1459		return map_nfs_to_system_error(status);
1460	}
1461
1462	info->dev=ns->nsid;
1463	info->root=ns->rootid;
1464	info->flags=NFS_FS_FLAGS;
1465
1466	XDRInPacketGetInt32(&reply);	// tsize
1467
1468	info->block_size=XDRInPacketGetInt32(&reply);
1469	info->io_size=8192;
1470	info->total_blocks=XDRInPacketGetInt32(&reply);
1471	info->free_blocks=XDRInPacketGetInt32(&reply);
1472	info->total_nodes=100;
1473	info->free_nodes=100;
1474	//strcpy (info->device_name,"nfs_device");
1475	strcpy (info->device_name,"");
1476	strcpy (info->volume_name,"nfs://");
1477	strcat (info->volume_name,ns->params.server);
1478	strcat (info->volume_name,ns->params._export);
1479	//strcpy (info->fsh_name,"nfs_fsh");
1480	strcpy (info->fsh_name,"nfs");
1481
1482	XDRInPacketDestroy (&reply);
1483	XDROutPacketDestroy (&call);
1484	return B_OK;
1485}
1486
1487extern int
1488fs_open(fs_nspace *ns, fs_node *node, int omode, fs_file_cookie **cookie)
1489{
1490	struct stat st;
1491
1492	status_t result;
1493	if ((result=nfs_getattr(ns,&node->fhandle,&st))<B_OK)
1494		return result;
1495
1496	if (S_ISDIR(st.st_mode)) {
1497		/* permit opening of directories */
1498		if (conf_allow_dir_open) {
1499			*cookie = NULL;
1500			return B_OK;
1501		} else
1502			return EISDIR;
1503	}
1504
1505	*cookie=(fs_file_cookie *)malloc(sizeof(fs_file_cookie));
1506	(*cookie)->omode=omode;
1507	(*cookie)->original_size=st.st_size;
1508	(*cookie)->st=st;
1509
1510	return B_OK;
1511}
1512
1513extern int
1514fs_close(fs_nspace *ns, fs_node *node, fs_file_cookie *cookie)
1515{
1516	(void) ns;
1517	(void) node;
1518	(void) cookie;
1519/*	//XXX:mmu_man:why that ?? makes Tracker go nuts updating the stats
1520	if ((cookie->omode & O_RDWR)||(cookie->omode & O_WRONLY))
1521		return my_notify_listener (B_STAT_CHANGED,ns->nsid,0,0,node->vnid,NULL);
1522*/
1523	return B_OK;
1524}
1525
1526extern int
1527fs_free_cookie(fs_nspace *ns, fs_node *node, fs_file_cookie *cookie)
1528{
1529	(void) ns;
1530	(void) node;
1531	if (cookie)
1532		free(cookie);
1533	return B_OK;
1534}
1535
1536extern int
1537fs_read(fs_nspace *ns, fs_node *node, fs_file_cookie *cookie, off_t pos, void *buf, size_t *len)
1538{
1539	size_t max=*len;
1540	*len=0;
1541
1542	if (!cookie) return EISDIR; /* do not permit reading of directories */
1543	while ((*len)<max)
1544	{
1545		size_t count=min_c(NFS_MAXDATA,max-(*len));
1546
1547		struct XDROutPacket call;
1548		struct XDRInPacket reply;
1549
1550		int32 status;
1551		uint8 *replyBuf;
1552
1553		struct stat st;
1554		size_t readbytes;
1555
1556		XDROutPacketInit (&call);
1557		XDRInPacketInit (&reply);
1558
1559		XDROutPacketAddFixed (&call,&node->fhandle.opaque,NFS_FHSIZE);
1560		XDROutPacketAddInt32 (&call,pos);
1561		XDROutPacketAddInt32 (&call,count);
1562		XDROutPacketAddInt32 (&call,0);
1563
1564		replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_READ,&call);
1565
1566		if (!replyBuf)
1567		{
1568			XDRInPacketDestroy (&reply);
1569			XDROutPacketDestroy (&call);
1570			return B_ERROR;
1571		}
1572
1573		XDRInPacketSetTo(&reply,replyBuf,0);
1574
1575		if (!is_successful_reply(&reply))
1576		{
1577			XDRInPacketDestroy (&reply);
1578			XDROutPacketDestroy (&call);
1579			return B_ERROR;
1580		}
1581
1582		status=XDRInPacketGetInt32(&reply);
1583
1584		if (status!=NFS_OK)
1585		{
1586			XDRInPacketDestroy (&reply);
1587			XDROutPacketDestroy (&call);
1588			return map_nfs_to_system_error(status);
1589		}
1590
1591		get_nfs_attr (&reply,&st);
1592
1593		cookie->st=st;
1594
1595		readbytes=XDRInPacketGetDynamic(&reply,buf);
1596
1597		buf=(char *)buf+readbytes;
1598		(*len)+=readbytes;
1599		pos+=readbytes;
1600
1601		if (pos>=st.st_size)
1602		{
1603			XDRInPacketDestroy (&reply);
1604			XDROutPacketDestroy (&call);
1605			break;
1606		}
1607
1608		XDRInPacketDestroy (&reply);
1609		XDROutPacketDestroy (&call);
1610	}
1611
1612	return B_OK;
1613}
1614
1615extern int
1616fs_write(fs_nspace *ns, fs_node *node, fs_file_cookie *cookie, off_t pos, const void *buf, size_t *len)
1617{
1618	size_t bytesWritten=0;
1619
1620	if (!cookie) return EISDIR; /* do not permit reading of directories */
1621	if (cookie->omode & O_APPEND)
1622		pos+=cookie->original_size;
1623
1624	while (bytesWritten<*len)
1625	{
1626		size_t count=min_c(NFS_MAXDATA,(*len)-bytesWritten);
1627
1628		struct XDROutPacket call;
1629		struct XDRInPacket reply;
1630		int32 status;
1631		uint8 *replyBuf;
1632		struct stat st;
1633
1634		XDROutPacketInit (&call);
1635		XDRInPacketInit (&reply);
1636
1637		XDROutPacketAddFixed (&call,&node->fhandle.opaque,NFS_FHSIZE);
1638		XDROutPacketAddInt32 (&call,0);
1639		XDROutPacketAddInt32 (&call,pos+bytesWritten);
1640		XDROutPacketAddInt32 (&call,0);
1641		XDROutPacketAddDynamic (&call,(const char *)buf+bytesWritten,count);
1642
1643		replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_WRITE,&call);
1644
1645		if (!replyBuf)
1646		{
1647			XDRInPacketDestroy (&reply);
1648			XDROutPacketDestroy (&call);
1649			return B_ERROR;
1650		}
1651
1652		XDRInPacketSetTo (&reply,replyBuf,0);
1653
1654		if (!is_successful_reply(&reply))
1655		{
1656			XDRInPacketDestroy (&reply);
1657			XDROutPacketDestroy (&call);
1658			return B_ERROR;
1659		}
1660
1661		status=XDRInPacketGetInt32(&reply);
1662
1663		if (status!=NFS_OK)
1664		{
1665			XDRInPacketDestroy (&reply);
1666			XDROutPacketDestroy (&call);
1667			return map_nfs_to_system_error(status);
1668		}
1669
1670		get_nfs_attr (&reply,&st);
1671
1672		cookie->st=st;
1673
1674		bytesWritten+=count;
1675
1676		XDRInPacketDestroy (&reply);
1677		XDROutPacketDestroy (&call);
1678	}
1679
1680	return B_OK;
1681}
1682
1683extern int
1684fs_wstat(fs_nspace *ns, fs_node *node, struct stat *st, long mask)
1685{
1686	struct XDROutPacket call;
1687	struct XDRInPacket reply;
1688
1689	uint8 *replyBuf;
1690	int32 status;
1691
1692	XDROutPacketInit (&call);
1693	XDRInPacketInit (&reply);
1694
1695	XDROutPacketAddFixed (&call,node->fhandle.opaque,NFS_FHSIZE);
1696
1697	XDROutPacketAddInt32 (&call,(mask & WSTAT_MODE) ? st->st_mode : -1);
1698	XDROutPacketAddInt32 (&call,(mask & WSTAT_UID) ? st->st_uid : -1);
1699	XDROutPacketAddInt32 (&call,(mask & WSTAT_GID) ? st->st_gid : -1);
1700	XDROutPacketAddInt32 (&call,(mask & WSTAT_SIZE) ? st->st_size : -1);
1701	XDROutPacketAddInt32 (&call,(mask & WSTAT_ATIME) ? st->st_atime : -1);
1702	XDROutPacketAddInt32 (&call,(mask & WSTAT_ATIME) ? 0 : -1);
1703	XDROutPacketAddInt32 (&call,(mask & WSTAT_MTIME) ? st->st_mtime : -1);
1704	XDROutPacketAddInt32 (&call,(mask & WSTAT_MTIME) ? 0 : -1);
1705
1706	replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_SETATTR,&call);
1707
1708	if (!replyBuf)
1709	{
1710		XDRInPacketDestroy (&reply);
1711		XDROutPacketDestroy (&call);
1712		return EHOSTUNREACH;
1713	}
1714
1715	XDRInPacketSetTo (&reply,replyBuf,0);
1716
1717	if (!is_successful_reply(&reply))
1718	{
1719		XDRInPacketDestroy (&reply);
1720		XDROutPacketDestroy (&call);
1721		return B_ERROR;
1722	}
1723
1724	status=XDRInPacketGetInt32(&reply);
1725
1726	if (status!=NFS_OK)
1727		return map_nfs_to_system_error(status);
1728
1729	XDRInPacketDestroy (&reply);
1730	XDROutPacketDestroy (&call);
1731	return my_notify_listener (B_STAT_CHANGED,ns->nsid,0,0,node->vnid,NULL);
1732}
1733
1734extern int
1735fs_wfsstat(fs_nspace *ns, struct fs_info *info, long mask)
1736{
1737	(void) ns;
1738	(void) info;
1739	(void) mask;
1740	return B_OK;
1741}
1742
1743extern int
1744#ifdef __HAIKU__
1745fs_create(fs_nspace *ns, fs_node *dir, const char *name, int omode, int perms, fs_file_cookie **cookie, vnode_id *vnid)
1746#else
1747fs_create(fs_nspace *ns, fs_node *dir, const char *name, int omode, int perms, vnode_id *vnid, fs_file_cookie **cookie)
1748#endif
1749{
1750	nfs_fhandle fhandle;
1751	struct stat st;
1752
1753	status_t result;
1754	result=nfs_lookup(ns,&dir->fhandle,name,&fhandle,&st);
1755
1756	if (result==B_OK)
1757	{
1758		void *dummy;
1759		fs_node *newNode=(fs_node *)malloc(sizeof(fs_node));
1760		newNode->fhandle=fhandle;
1761		newNode->vnid=st.st_ino;
1762		insert_node (ns,newNode);
1763
1764		*vnid=st.st_ino;
1765
1766		if ((result=get_vnode(ns->nsid,*vnid,&dummy))<B_OK)
1767			return result;
1768
1769		if (S_ISDIR(st.st_mode))
1770			return EISDIR;
1771
1772		if (omode & O_EXCL)
1773			return EEXIST;
1774
1775		if (omode & O_TRUNC)
1776		{
1777			if ((result=nfs_truncate_file(ns,&fhandle,NULL))<B_OK)
1778				return result;
1779		}
1780
1781		*cookie=(fs_file_cookie *)malloc(sizeof(fs_file_cookie));
1782		(*cookie)->omode=omode;
1783		(*cookie)->original_size=st.st_size;
1784		(*cookie)->st=st;
1785
1786		return B_OK;
1787	}
1788	else if (result!=ENOENT)
1789		return result;
1790	else
1791	{
1792		struct XDROutPacket call;
1793		struct XDRInPacket reply;
1794
1795		uint8 *replyBuf;
1796		int32 status;
1797
1798		fs_node *newNode;
1799
1800		if (!(omode & O_CREAT))
1801			return ENOENT;
1802
1803		XDROutPacketInit (&call);
1804		XDRInPacketInit (&reply);
1805
1806		XDROutPacketAddFixed (&call,dir->fhandle.opaque,NFS_FHSIZE);
1807		XDROutPacketAddString(&call,name);
1808		XDROutPacketAddInt32 (&call,perms|S_IFREG);
1809		XDROutPacketAddInt32 (&call,-1);
1810		XDROutPacketAddInt32 (&call,-1);
1811		XDROutPacketAddInt32 (&call,0);
1812		XDROutPacketAddInt32 (&call,time(NULL));
1813		XDROutPacketAddInt32 (&call,0);
1814		XDROutPacketAddInt32 (&call,time(NULL));
1815		XDROutPacketAddInt32 (&call,0);
1816
1817		replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_CREATE,&call);
1818
1819		if (!replyBuf)
1820		{
1821			XDRInPacketDestroy (&reply);
1822			XDROutPacketDestroy (&call);
1823			return B_ERROR;
1824		}
1825
1826		XDRInPacketSetTo (&reply,replyBuf,0);
1827
1828		if (!is_successful_reply(&reply))
1829		{
1830			XDRInPacketDestroy (&reply);
1831			XDROutPacketDestroy (&call);
1832			return B_ERROR;
1833		}
1834
1835		status=XDRInPacketGetInt32(&reply);
1836
1837		if (status!=NFS_OK)
1838		{
1839			XDRInPacketDestroy (&reply);
1840			XDROutPacketDestroy (&call);
1841			return map_nfs_to_system_error(status);
1842		}
1843
1844		XDRInPacketGetFixed (&reply,fhandle.opaque,NFS_FHSIZE);
1845
1846		get_nfs_attr (&reply,&st);
1847
1848		newNode=(fs_node *)malloc(sizeof(fs_node));
1849		newNode->fhandle=fhandle;
1850		newNode->vnid=st.st_ino;
1851
1852		insert_node (ns,newNode);
1853
1854		*vnid=st.st_ino;
1855		*cookie=(fs_file_cookie *)malloc(sizeof(fs_file_cookie));
1856		(*cookie)->omode=omode;
1857		(*cookie)->original_size=st.st_size;
1858		(*cookie)->st=st;
1859
1860		result=new_vnode (ns->nsid,*vnid,newNode);
1861
1862		if (result<B_OK)
1863		{
1864			XDRInPacketDestroy (&reply);
1865			XDROutPacketDestroy (&call);
1866			return result;
1867		}
1868
1869		XDRInPacketDestroy (&reply);
1870		XDROutPacketDestroy (&call);
1871		return my_notify_listener (B_ENTRY_CREATED,ns->nsid,dir->vnid,0,*vnid,name);
1872	}
1873}
1874
1875extern int
1876fs_unlink(fs_nspace *ns, fs_node *dir, const char *name)
1877{
1878	status_t result;
1879	fs_node *newNode;
1880	fs_node *dummy;
1881
1882	struct XDROutPacket call;
1883	struct XDRInPacket reply;
1884
1885	struct stat st;
1886	nfs_fhandle fhandle;
1887	uint8 *replyBuf;
1888
1889	int32 status;
1890
1891	XDROutPacketInit (&call);
1892	XDRInPacketInit (&reply);
1893
1894	if ((result=nfs_lookup(ns,&dir->fhandle,name,&fhandle,&st))<B_OK)
1895	{
1896		XDRInPacketDestroy (&reply);
1897		XDROutPacketDestroy (&call);
1898		return result;
1899	}
1900
1901	newNode=(fs_node *)malloc(sizeof(fs_node));
1902	newNode->fhandle=fhandle;
1903	newNode->vnid=st.st_ino;
1904
1905	insert_node (ns,newNode);
1906
1907	if ((result=get_vnode(ns->nsid,st.st_ino,(void **)&dummy))<B_OK)
1908	{
1909		XDRInPacketDestroy (&reply);
1910		XDROutPacketDestroy (&call);
1911		return result;
1912	}
1913
1914	if (!S_ISREG(st.st_mode)&&!S_ISLNK(st.st_mode))
1915	{
1916		XDRInPacketDestroy (&reply);
1917		XDROutPacketDestroy (&call);
1918		return EISDIR;
1919	}
1920
1921	if ((result=remove_vnode(ns->nsid,st.st_ino))<B_OK)
1922	{
1923		XDRInPacketDestroy (&reply);
1924		XDROutPacketDestroy (&call);
1925		return result;
1926	}
1927
1928	if ((result=put_vnode(ns->nsid,st.st_ino))<B_OK)
1929	{
1930		XDRInPacketDestroy (&reply);
1931		XDROutPacketDestroy (&call);
1932		return result;
1933	}
1934
1935	XDROutPacketAddFixed (&call,dir->fhandle.opaque,NFS_FHSIZE);
1936	XDROutPacketAddString(&call,name);
1937
1938	replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_REMOVE,&call);
1939
1940	if (!replyBuf)
1941	{
1942		XDRInPacketDestroy (&reply);
1943		XDROutPacketDestroy (&call);
1944		return EHOSTUNREACH;
1945	}
1946
1947	XDRInPacketSetTo(&reply,replyBuf,0);
1948
1949	if (!is_successful_reply(&reply))
1950	{
1951		XDRInPacketDestroy (&reply);
1952		XDROutPacketDestroy (&call);
1953		return B_ERROR;
1954	}
1955
1956	status=XDRInPacketGetInt32(&reply);
1957
1958	if (status!=NFS_OK)
1959	{
1960		XDRInPacketDestroy (&reply);
1961		XDROutPacketDestroy (&call);
1962		return map_nfs_to_system_error(status);
1963	}
1964
1965	XDRInPacketDestroy (&reply);
1966	XDROutPacketDestroy (&call);
1967
1968	return my_notify_listener (B_ENTRY_REMOVED,ns->nsid,dir->vnid,0,st.st_ino,name);
1969}
1970
1971extern int
1972fs_remove_vnode(fs_nspace *ns, fs_node *node, char r)
1973{
1974	(void) r;
1975	remove_node (ns,node->vnid);
1976
1977	return B_OK;
1978}
1979
1980#ifndef __HAIKU__
1981extern int
1982fs_secure_vnode(fs_nspace *ns, fs_node *node)
1983{
1984	(void) ns;
1985	(void) node;
1986	return B_OK;
1987}
1988#endif
1989
1990extern int
1991fs_mkdir(fs_nspace *ns, fs_node *dir, const char *name, int perms)
1992{
1993	nfs_fhandle fhandle;
1994	struct stat st;
1995	fs_node *newNode;
1996
1997	status_t result;
1998	uint8 *replyBuf;
1999	int32 status;
2000
2001	struct XDROutPacket call;
2002	struct XDRInPacket reply;
2003
2004	XDROutPacketInit (&call);
2005	XDRInPacketInit (&reply);
2006
2007	result=nfs_lookup(ns,&dir->fhandle,name,&fhandle,&st);
2008
2009	if (result==B_OK)
2010	{
2011		//void *dummy;
2012
2013		XDRInPacketDestroy (&reply);
2014		XDROutPacketDestroy (&call);
2015		// XXX: either OK or not get_vnode !!! ??
2016		//if ((result=get_vnode(ns->nsid,st.st_ino,&dummy))<B_OK)
2017		//	return result;
2018		return EEXIST;
2019	}
2020	else if (result!=ENOENT)
2021	{
2022		XDRInPacketDestroy (&reply);
2023		XDROutPacketDestroy (&call);
2024		return result;
2025	}
2026
2027	XDROutPacketAddFixed (&call,dir->fhandle.opaque,NFS_FHSIZE);
2028	XDROutPacketAddString(&call,name);
2029	XDROutPacketAddInt32 (&call,perms|S_IFDIR);
2030	XDROutPacketAddInt32 (&call,-1);
2031	XDROutPacketAddInt32 (&call,-1);
2032	XDROutPacketAddInt32 (&call,-1);
2033	XDROutPacketAddInt32 (&call,time(NULL));
2034	XDROutPacketAddInt32 (&call,0);
2035	XDROutPacketAddInt32 (&call,time(NULL));
2036	XDROutPacketAddInt32 (&call,0);
2037
2038	replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_MKDIR,&call);
2039
2040	if (!replyBuf)
2041	{
2042		XDRInPacketDestroy (&reply);
2043		XDROutPacketDestroy (&call);
2044		return B_ERROR;
2045	}
2046
2047	XDRInPacketSetTo (&reply,replyBuf,0);
2048
2049	if (!is_successful_reply(&reply))
2050	{
2051		XDRInPacketDestroy (&reply);
2052		XDROutPacketDestroy (&call);
2053		return B_ERROR;
2054	}
2055
2056	status=XDRInPacketGetInt32(&reply);
2057
2058	if (status!=NFS_OK)
2059	{
2060		XDROutPacketDestroy (&call);
2061		return map_nfs_to_system_error(status);
2062	}
2063
2064	XDRInPacketGetFixed(&reply,fhandle.opaque,NFS_FHSIZE);
2065
2066	get_nfs_attr (&reply,&st);
2067
2068	newNode=(fs_node *)malloc(sizeof(fs_node));
2069	newNode->fhandle=fhandle;
2070	newNode->vnid=st.st_ino;
2071
2072	insert_node (ns,newNode);
2073
2074	XDRInPacketDestroy (&reply);
2075	XDROutPacketDestroy (&call);
2076
2077	return my_notify_listener (B_ENTRY_CREATED,ns->nsid,dir->vnid,0,st.st_ino,name);
2078}
2079
2080extern int
2081fs_rename(fs_nspace *ns, fs_node *olddir, const char *oldname, fs_node *newdir, const char *newname)
2082{
2083	struct stat st;
2084	nfs_fhandle fhandle;
2085	status_t result;
2086	struct XDROutPacket call;
2087	struct XDRInPacket reply;
2088	int32 status;
2089	uint8 *replyBuf;
2090
2091	XDROutPacketInit (&call);
2092	XDRInPacketInit (&reply);
2093
2094	if ((result=nfs_lookup(ns,&newdir->fhandle,newname,&fhandle,&st))==B_OK)
2095	{
2096		if (S_ISREG(st.st_mode))
2097			result=fs_unlink (ns,newdir,newname);
2098		else
2099			result=fs_rmdir (ns,newdir,newname);
2100
2101		if (result<B_OK)
2102		{
2103			XDRInPacketDestroy (&reply);
2104			XDROutPacketDestroy (&call);
2105			return result;
2106		}
2107	}
2108
2109	if ((result=nfs_lookup(ns,&olddir->fhandle,oldname,&fhandle,&st))<B_OK)
2110	{
2111		XDRInPacketDestroy (&reply);
2112		XDROutPacketDestroy (&call);
2113		return result;
2114	}
2115
2116	XDROutPacketAddFixed (&call,olddir->fhandle.opaque,NFS_FHSIZE);
2117	XDROutPacketAddString(&call,oldname);
2118	XDROutPacketAddFixed (&call,newdir->fhandle.opaque,NFS_FHSIZE);
2119	XDROutPacketAddString(&call,newname);
2120
2121	replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_RENAME,&call);
2122
2123	if (!replyBuf)
2124	{
2125		XDRInPacketDestroy (&reply);
2126		XDROutPacketDestroy (&call);
2127		return EHOSTUNREACH;
2128	}
2129
2130	XDRInPacketSetTo (&reply,replyBuf,0);
2131
2132	if (!is_successful_reply(&reply))
2133	{
2134		XDRInPacketDestroy (&reply);
2135		XDROutPacketDestroy (&call);
2136		return B_ERROR;
2137	}
2138
2139	status=XDRInPacketGetInt32(&reply);
2140
2141	if (status!=NFS_OK)
2142	{
2143		XDRInPacketDestroy (&reply);
2144		XDROutPacketDestroy (&call);
2145		return map_nfs_to_system_error(status);
2146	}
2147
2148	XDRInPacketDestroy (&reply);
2149	XDROutPacketDestroy (&call);
2150
2151	return my_notify_listener (B_ENTRY_MOVED,ns->nsid,olddir->vnid,newdir->vnid,st.st_ino,newname);
2152}
2153
2154extern int
2155fs_rmdir(fs_nspace *ns, fs_node *dir, const char *name)
2156{
2157	status_t result;
2158	fs_node *newNode;
2159	fs_node *dummy;
2160	struct XDROutPacket call;
2161	struct XDRInPacket reply;
2162	int32 status;
2163	uint8 *replyBuf;
2164
2165	struct stat st;
2166	nfs_fhandle fhandle;
2167
2168	XDROutPacketInit(&call);
2169	XDRInPacketInit(&reply);
2170
2171	if ((result=nfs_lookup(ns,&dir->fhandle,name,&fhandle,&st))<B_OK)
2172	{
2173		XDRInPacketDestroy(&reply);
2174		XDROutPacketDestroy(&call);
2175		return result;
2176	}
2177
2178	newNode=(fs_node *)malloc(sizeof(fs_node));
2179	newNode->fhandle=fhandle;
2180	newNode->vnid=st.st_ino;
2181
2182	insert_node (ns,newNode);
2183
2184	if ((result=get_vnode(ns->nsid,st.st_ino,(void **)&dummy))<B_OK)
2185	{
2186		XDRInPacketDestroy(&reply);
2187		XDROutPacketDestroy(&call);
2188		return result;
2189	}
2190
2191	if (!S_ISDIR(st.st_mode))
2192	{
2193		XDRInPacketDestroy(&reply);
2194		XDROutPacketDestroy(&call);
2195		return ENOTDIR;
2196	}
2197
2198	if ((result=remove_vnode(ns->nsid,st.st_ino))<B_OK)
2199	{
2200		XDRInPacketDestroy(&reply);
2201		XDROutPacketDestroy(&call);
2202		return result;
2203	}
2204
2205	if ((result=put_vnode(ns->nsid,st.st_ino))<B_OK)
2206	{
2207		XDRInPacketDestroy(&reply);
2208		XDROutPacketDestroy(&call);
2209		return result;
2210	}
2211
2212	XDROutPacketAddFixed (&call,dir->fhandle.opaque,NFS_FHSIZE);
2213	XDROutPacketAddString(&call,name);
2214
2215	replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_RMDIR,&call);
2216
2217	if (!replyBuf)
2218	{
2219		XDRInPacketDestroy(&reply);
2220		XDROutPacketDestroy(&call);
2221		return EHOSTUNREACH;
2222	}
2223
2224	XDRInPacketSetTo (&reply,replyBuf,0);
2225
2226	if (!is_successful_reply(&reply))
2227	{
2228		XDRInPacketDestroy(&reply);
2229		XDROutPacketDestroy(&call);
2230		return B_ERROR;
2231	}
2232
2233	status=XDRInPacketGetInt32(&reply);
2234
2235	if (status!=NFS_OK)
2236	{
2237		XDRInPacketDestroy(&reply);
2238		XDROutPacketDestroy(&call);
2239		return map_nfs_to_system_error(status);
2240	}
2241
2242	XDRInPacketDestroy(&reply);
2243	XDROutPacketDestroy(&call);
2244	return my_notify_listener (B_ENTRY_REMOVED,ns->nsid,dir->vnid,0,st.st_ino,name);
2245}
2246
2247extern int
2248fs_readlink(fs_nspace *ns, fs_node *node, char *buf, size_t *bufsize)
2249{
2250	struct XDROutPacket call;
2251	uint8 *replyBuf;
2252	int32 status;
2253	size_t length;
2254	char data[NFS_MAXPATHLEN];
2255	struct XDRInPacket reply;
2256
2257	XDROutPacketInit (&call);
2258	XDRInPacketInit(&reply);
2259
2260	XDROutPacketAddFixed (&call,node->fhandle.opaque,NFS_FHSIZE);
2261
2262	replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_READLINK,&call);
2263
2264	if (!replyBuf)
2265	{
2266		XDRInPacketDestroy(&reply);
2267		XDROutPacketDestroy (&call);
2268		return EHOSTUNREACH;
2269	}
2270
2271	XDRInPacketSetTo (&reply,replyBuf,0);
2272
2273	if (!is_successful_reply(&reply))
2274	{
2275		XDRInPacketDestroy(&reply);
2276		XDROutPacketDestroy (&call);
2277		return B_ERROR;
2278	}
2279
2280	status=XDRInPacketGetInt32(&reply);
2281
2282	if (status!=NFS_OK)
2283	{
2284		XDRInPacketDestroy(&reply);
2285		XDROutPacketDestroy (&call);
2286		return map_nfs_to_system_error(status);
2287	}
2288
2289	length=XDRInPacketGetDynamic(&reply,data);
2290
2291	length=min_c(length,*bufsize);
2292	memcpy (buf,data,length);
2293	*bufsize=length;
2294
2295	XDRInPacketDestroy(&reply);
2296	XDROutPacketDestroy (&call);
2297	return B_OK;
2298}
2299
2300extern int
2301#ifdef __HAIKU__
2302fs_symlink(fs_nspace *ns, fs_node *dir, const char *name, const char *path, int mode)
2303#else
2304fs_symlink(fs_nspace *ns, fs_node *dir, const char *name, const char *path)
2305#endif
2306{
2307	nfs_fhandle fhandle;
2308	struct stat st;
2309	struct XDROutPacket call;
2310	struct XDRInPacket reply;
2311	status_t result;
2312	uint8 *replyBuf;
2313	int32 status;
2314	fs_node *newNode;
2315
2316	XDROutPacketInit (&call);
2317	XDRInPacketInit (&reply);
2318
2319	result=nfs_lookup(ns,&dir->fhandle,name,&fhandle,&st);
2320
2321	if (result==B_OK)
2322	{
2323		void *dummy;
2324		if ((result=get_vnode(ns->nsid,st.st_ino,&dummy))<B_OK)
2325			return result;
2326
2327		XDRInPacketDestroy (&reply);
2328		XDROutPacketDestroy (&call);
2329		return EEXIST;
2330	}
2331	else if (result!=ENOENT)
2332	{
2333		XDRInPacketDestroy (&reply);
2334		XDROutPacketDestroy (&call);
2335		return result;
2336	}
2337
2338	XDROutPacketAddFixed (&call,dir->fhandle.opaque,NFS_FHSIZE);
2339	XDROutPacketAddString(&call,name);
2340	XDROutPacketAddString(&call,path);
2341	XDROutPacketAddInt32 (&call,S_IFLNK);
2342	XDROutPacketAddInt32 (&call,-1);
2343	XDROutPacketAddInt32 (&call,-1);
2344	XDROutPacketAddInt32 (&call,-1);
2345	XDROutPacketAddInt32 (&call,time(NULL));
2346	XDROutPacketAddInt32 (&call,0);
2347	XDROutPacketAddInt32 (&call,time(NULL));
2348	XDROutPacketAddInt32 (&call,0);
2349
2350	replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_SYMLINK,&call);
2351
2352	if (!replyBuf)
2353	{
2354		XDRInPacketDestroy (&reply);
2355		XDROutPacketDestroy (&call);
2356		return B_ERROR;
2357	}
2358
2359	XDRInPacketSetTo (&reply,replyBuf,0);
2360
2361	if (!is_successful_reply(&reply))
2362	{
2363		XDRInPacketDestroy (&reply);
2364		XDROutPacketDestroy (&call);
2365		return B_ERROR;
2366	}
2367
2368	status=XDRInPacketGetInt32(&reply);
2369
2370/*	if (status!=NFS_OK)
2371		return map_nfs_to_system_error(status);
2372
2373	ignore status here, weird thing, nfsservers that is
2374*/
2375
2376	result=nfs_lookup(ns,&dir->fhandle,name,&fhandle,&st);
2377
2378	if (result<B_OK)
2379	{
2380		XDRInPacketDestroy (&reply);
2381		XDROutPacketDestroy (&call);
2382		return result;
2383	}
2384
2385	newNode=(fs_node *)malloc(sizeof(fs_node));
2386	newNode->fhandle=fhandle;
2387	newNode->vnid=st.st_ino;
2388
2389	insert_node (ns,newNode);
2390
2391	result=my_notify_listener (B_ENTRY_CREATED,ns->nsid,dir->vnid,0,st.st_ino,name);
2392
2393	XDRInPacketDestroy (&reply);
2394	XDROutPacketDestroy (&call);
2395	return result;
2396}
2397
2398int	fs_access(void *ns, void *node, int mode)
2399{
2400	(void) ns;
2401	(void) node;
2402	(void) mode;
2403	/* XXX */
2404	return B_OK;
2405}
2406
2407#ifdef __HAIKU__
2408
2409static status_t
2410nfs_std_ops(int32 op, ...)
2411{
2412	switch (op) {
2413		case B_MODULE_INIT:
2414			dprintf("nfs:std_ops(INIT)\n");
2415			return B_OK;
2416		case B_MODULE_UNINIT:
2417			dprintf("nfs:std_ops(UNINIT)\n");
2418			return B_OK;
2419		default:
2420			return B_ERROR;
2421	}
2422}
2423
2424
2425static file_system_module_info sNFSModule = {
2426	{
2427		"file_systems/nfs" B_CURRENT_FS_API_VERSION,
2428		0,
2429		nfs_std_ops,
2430	},
2431
2432	"Network File System v2",
2433
2434	// scanning
2435	NULL,	// fs_identify_partition,
2436	NULL,	// fs_scan_partition,
2437	NULL,	// fs_free_identify_partition_cookie,
2438	NULL,	// free_partition_content_cookie()
2439
2440	&fs_mount,
2441	&fs_unmount,
2442	&fs_rfsstat,
2443	&fs_wfsstat,
2444	NULL,	// &fs_sync,
2445
2446	/* vnode operations */
2447	&fs_walk,
2448	NULL,	// &fs_get_vnode_name,
2449	&fs_read_vnode,
2450	&fs_release_vnode,
2451	&fs_remove_vnode,
2452
2453	/* VM file access */
2454	NULL, 	// &fs_can_page
2455	NULL,	// &fs_read_pages
2456	NULL, 	// &fs_write_pages
2457
2458	NULL,	// &fs_get_file_map,
2459
2460	NULL, 	// &fs_ioctl
2461	NULL,	// &fs_setflags,
2462	NULL,	// &fs_select
2463	NULL,	// &fs_deselect
2464	NULL, 	// &fs_fsync
2465
2466	&fs_readlink,
2467	&fs_symlink,
2468
2469	NULL,	// &fs_link,
2470	&fs_unlink,
2471	&fs_rename,
2472
2473	&fs_access,
2474	&fs_rstat,
2475	&fs_wstat,
2476
2477	/* file operations */
2478	&fs_create,
2479	&fs_open,
2480	&fs_close,
2481	&fs_free_cookie,
2482	&fs_read,
2483	&fs_write,
2484
2485	/* directory operations */
2486	&fs_mkdir,
2487	&fs_rmdir,
2488	&fs_opendir,
2489	&fs_closedir,
2490	&fs_free_dircookie,
2491	&fs_readdir,
2492	&fs_rewinddir,
2493
2494	/* attribute directory operations */
2495	NULL,	// &fs_open_attrdir,
2496	NULL,	// &fs_close_attrdir,
2497	NULL,	// &fs_free_attrdircookie,
2498	NULL,	// &fs_read_attrdir,
2499	NULL,	// &fs_rewind_attrdir,
2500
2501	/* attribute operations */
2502	NULL,	// &fs_create_attr
2503	NULL,	// &fs_open_attr_h,
2504	NULL,	// &fs_close_attr_h,
2505	NULL,	// &fs_free_attr_cookie_h,
2506	NULL,	// &fs_read_attr_h,
2507	NULL,	// &fs_write_attr_h,
2508
2509	NULL,	// &fs_read_attr_stat_h,
2510	NULL,	// &fs_write_attr_stat
2511	NULL,	// &fs_rename_attr
2512	NULL,	// &fs_remove_attr
2513
2514	/* index directory & index operations */
2515	NULL,	// &fs_open_index_dir
2516	NULL,	// &fs_close_index_dir
2517	NULL,	// &fs_free_index_dir_cookie
2518	NULL,	// &fs_read_index_dir
2519	NULL,	// &fs_rewind_index_dir
2520
2521	NULL,	// &fs_create_index
2522	NULL,	// &fs_remove_index
2523	NULL,	// &fs_stat_index
2524
2525	/* query operations */
2526	NULL,	// &fs_open_query,
2527	NULL,	// &fs_close_query,
2528	NULL,	// &fs_free_query_cookie,
2529	NULL,	// &fs_read_query,
2530	NULL,	// &fs_rewind_query,
2531};
2532
2533module_info *modules[] = {
2534	(module_info *)&sNFSModule,
2535	NULL,
2536};
2537
2538
2539#else
2540
2541_EXPORT vnode_ops fs_entry =
2542{
2543	(op_read_vnode *)&fs_read_vnode,
2544	(op_write_vnode *)&fs_write_vnode,
2545	(op_remove_vnode *)&fs_remove_vnode,
2546	(op_secure_vnode *)&fs_secure_vnode,
2547	(op_walk *)&fs_walk,
2548	(op_access *)&fs_access,
2549	(op_create *)&fs_create,
2550	(op_mkdir *)&fs_mkdir,
2551	(op_symlink *)&fs_symlink,
2552	NULL, //	&fs_link,
2553	(op_rename *)&fs_rename,
2554	(op_unlink *)&fs_unlink,
2555	(op_rmdir *)&fs_rmdir,
2556	(op_readlink *)&fs_readlink,
2557	(op_opendir *)&fs_opendir,
2558	(op_closedir *)&fs_closedir,
2559	(op_free_cookie *)&fs_free_dircookie,
2560	(op_rewinddir *)&fs_rewinddir,
2561	(op_readdir *)&fs_readdir,
2562	(op_open *)&fs_open,
2563	(op_close *)&fs_close,
2564	(op_free_cookie *)&fs_free_cookie,
2565	(op_read *)&fs_read,
2566	(op_write *)&fs_write,
2567	NULL, //	&fs_readv,
2568	NULL, //	&fs_writev,
2569	NULL, //	&fs_ioctl,
2570	NULL, //	&fs_setflags,
2571	(op_rstat *)&fs_rstat,
2572	(op_wstat *)&fs_wstat,
2573	NULL, //	&fs_fsync,
2574	NULL, //	&fs_initialize,
2575	(op_mount *)&fs_mount,
2576	(op_unmount *)&fs_unmount,
2577	NULL, //	&fs_sync,
2578	(op_rfsstat *)&fs_rfsstat,
2579	(op_wfsstat *)&fs_wfsstat,
2580	NULL, //	&fs_select,
2581	NULL, //	&fs_deselect,
2582	NULL, //	&fs_open_indexdir,
2583	NULL, //	&fs_close_indexdir,
2584	NULL, //	&fs_free_indexdircookie,
2585	NULL, //	&fs_rewind_indexdir,
2586	NULL, //	&fs_read_indexdir,
2587	NULL, //	&fs_create_index,
2588	NULL, //	&fs_remove_index,
2589	NULL, //	&fs_rename_index,
2590	NULL, //	&fs_stat_index,
2591	NULL, //	&fs_open_attrdir,
2592	NULL, //	&fs_close_attrdir,
2593	NULL, //	&fs_free_attrdircookie,
2594	NULL, //	&fs_rewind_attrdir,
2595	NULL, //	&fs_read_attrdir,
2596	NULL, //	&fs_write_attr,
2597	NULL, //	&fs_read_attr,
2598	NULL, //	&fs_remove_attr,
2599	NULL, //	&fs_rename_attr,
2600	NULL, //	&fs_stat_attr,
2601	NULL, //	&fs_open_query,
2602	NULL, //	&fs_close_query,
2603	NULL, //	&fs_free_querycookie,
2604	NULL, //	&fs_read_query
2605};
2606
2607_EXPORT int32 api_version=B_CUR_FS_API_VERSION;
2608
2609#endif
2610