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