nfs_add_on.c revision 00405f22
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	free(pending->buffer);
350
351	/* mmu_man */
352	if (call) /* if the call has been found and removed (atomic op), the sem hasn't been released */
353		SemaphorePoolPut(&ns->pendingCalls.fPool, pending->sem);
354	else
355		delete_sem(pending->sem); /* else it's in an unknown state, forget it */
356
357	PendingCallDestroy(pending);
358	free(pending);
359
360	XDROutPacketDestroy (&rpc_call);
361	return NULL;
362}
363
364
365bool
366is_successful_reply(struct XDRInPacket *reply)
367{
368	bool success = false;
369
370	int32 xid = XDRInPacketGetInt32(reply);
371	rpc_msg_type mtype=(rpc_msg_type)XDRInPacketGetInt32(reply);
372	rpc_reply_stat replyStat=(rpc_reply_stat)XDRInPacketGetInt32(reply);
373	(void)xid;
374	(void)mtype;
375
376	if (replyStat == RPC_MSG_DENIED) {
377		rpc_reject_stat rejectStat = (rpc_reject_stat)XDRInPacketGetInt32(reply);
378
379		if (rejectStat == RPC_RPC_MISMATCH) {
380			int32 low=XDRInPacketGetInt32(reply);
381			int32 high=XDRInPacketGetInt32(reply);
382
383			dprintf ("nfs: RPC_MISMATCH (%ld,%ld)", low, high);
384		} else {
385			rpc_auth_stat authStat = (rpc_auth_stat)XDRInPacketGetInt32(reply);
386
387			dprintf  ("nfs: RPC_AUTH_ERROR (%d)", authStat);
388		}
389	} else {
390		rpc_auth_flavor flavor = (rpc_auth_flavor)XDRInPacketGetInt32(reply);
391		char body[400];
392		size_t bodyLength = XDRInPacketGetDynamic(reply, body);
393
394		rpc_accept_stat acceptStat = (rpc_accept_stat)XDRInPacketGetInt32(reply);
395		(void)flavor;
396		(void)bodyLength;
397
398		if (acceptStat == RPC_PROG_MISMATCH) {
399			int32 low = XDRInPacketGetInt32(reply);
400			int32 high = XDRInPacketGetInt32(reply);
401
402			dprintf ("nfs: RPC_PROG_MISMATCH (%ld,%ld)", low, high);
403		} else if (acceptStat != RPC_SUCCESS)
404			dprintf ("nfs: Accepted but failed (%d)", acceptStat);
405		else
406			success = true;
407	}
408
409	return success;
410}
411
412
413status_t
414get_remote_address(fs_nspace *ns, int32 prog, int32 vers, int32 prot,
415	struct sockaddr_in *addr)
416{
417	struct XDROutPacket call;
418	uint8 *replyBuf;
419
420	XDROutPacketInit (&call);
421
422	addr->sin_port=htons(PMAP_PORT);
423
424	XDROutPacketAddInt32 (&call,prog);
425	XDROutPacketAddInt32 (&call,vers);
426	XDROutPacketAddInt32 (&call,prot);
427	XDROutPacketAddInt32 (&call,0);
428
429	replyBuf=send_rpc_call (ns,addr,PMAP_PROGRAM,PMAP_VERSION,PMAPPROC_GETPORT,&call);
430
431	if (replyBuf)
432	{
433		struct XDRInPacket reply;
434		XDRInPacketInit (&reply);
435
436		XDRInPacketSetTo (&reply,replyBuf,0);
437
438		if (is_successful_reply(&reply))
439		{
440			addr->sin_port=htons(XDRInPacketGetInt32(&reply));
441			memset (addr->sin_zero,0,sizeof(addr->sin_zero));
442
443			XDRInPacketDestroy(&reply);
444			XDROutPacketDestroy (&call);
445			return B_OK;
446		}
447
448		XDRInPacketDestroy(&reply);
449	}
450
451	XDROutPacketDestroy (&call);
452	return EHOSTUNREACH;
453}
454
455status_t nfs_mount (fs_nspace *ns, const char *path, nfs_fhandle *fhandle)
456{
457	struct XDROutPacket call;
458	struct XDRInPacket reply;
459	uint8 *replyBuf;
460	int32 fhstatus;
461
462	XDROutPacketInit (&call);
463	XDRInPacketInit (&reply);
464
465	XDROutPacketAddString (&call,path);
466
467	replyBuf=send_rpc_call (ns,&ns->mountAddr,MOUNT_PROGRAM,MOUNT_VERSION,MOUNTPROC_MNT,&call);
468
469	if (!replyBuf)
470	{
471		XDRInPacketDestroy (&reply);
472		XDROutPacketDestroy (&call);
473		return EHOSTUNREACH;
474	}
475
476	XDRInPacketSetTo (&reply,replyBuf,0);
477
478	if (!is_successful_reply(&reply))
479	{
480		XDRInPacketDestroy (&reply);
481		XDROutPacketDestroy (&call);
482		return B_ERROR;
483	}
484
485	fhstatus=XDRInPacketGetInt32(&reply);
486
487	if (fhstatus!=0)
488	{
489		XDRInPacketDestroy (&reply);
490		XDROutPacketDestroy (&call);
491		return map_nfs_to_system_error(fhstatus);
492	}
493
494	XDRInPacketGetFixed (&reply,fhandle->opaque,NFS_FHSIZE);
495
496	XDRInPacketDestroy (&reply);
497	XDROutPacketDestroy (&call);
498	return B_OK;
499}
500
501status_t nfs_lookup (fs_nspace *ns, const nfs_fhandle *dir, const char *filename, nfs_fhandle *fhandle,
502						struct stat *st)
503{
504	struct XDROutPacket call;
505	struct XDRInPacket reply;
506	int32 status;
507	uint8 *replyBuf;
508
509	XDROutPacketInit (&call);
510	XDRInPacketInit (&reply);
511
512	XDROutPacketAddFixed (&call,dir->opaque,NFS_FHSIZE);
513	XDROutPacketAddString (&call,filename);
514
515	replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_LOOKUP,&call);
516
517	if (!replyBuf)
518	{
519		XDRInPacketDestroy (&reply);
520		XDROutPacketDestroy (&call);
521		return EHOSTUNREACH;
522	}
523
524	XDRInPacketSetTo(&reply,replyBuf,0);
525
526	if (!is_successful_reply(&reply))
527	{
528		XDRInPacketDestroy (&reply);
529		XDROutPacketDestroy (&call);
530		return B_ERROR;
531	}
532
533	status=XDRInPacketGetInt32(&reply);
534
535	if (status!=NFS_OK)
536	{
537		XDRInPacketDestroy (&reply);
538		XDROutPacketDestroy (&call);
539		return map_nfs_to_system_error(status);
540	}
541
542	XDRInPacketGetFixed (&reply,fhandle->opaque,NFS_FHSIZE);
543
544	if (st)
545		get_nfs_attr (&reply,st);
546
547	XDRInPacketDestroy (&reply);
548	XDROutPacketDestroy (&call);
549	return B_OK;
550}
551
552
553status_t
554nfs_getattr(fs_nspace *ns, const nfs_fhandle *fhandle, struct stat *st)
555{
556	struct XDROutPacket call;
557	struct XDRInPacket reply;
558	uint8 *replyBuf;
559	int32 status;
560
561	XDROutPacketInit(&call);
562	XDRInPacketInit(&reply);
563
564	XDROutPacketAddFixed(&call, fhandle->opaque, NFS_FHSIZE);
565
566	replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION,
567		NFSPROC_GETATTR, &call);
568	if (replyBuf == NULL) {
569		XDRInPacketDestroy(&reply);
570		XDROutPacketDestroy(&call);
571		return EHOSTUNREACH;
572	}
573
574	XDRInPacketSetTo(&reply, replyBuf, 0);
575
576	if (!is_successful_reply(&reply)) {
577		XDRInPacketDestroy(&reply);
578		XDROutPacketDestroy(&call);
579		return B_ERROR;
580	}
581
582	status = XDRInPacketGetInt32(&reply);
583	if (status != NFS_OK) {
584		XDRInPacketDestroy(&reply);
585		XDROutPacketDestroy(&call);
586		return map_nfs_to_system_error(status);
587	}
588
589	get_nfs_attr(&reply, st);
590
591	XDRInPacketDestroy(&reply);
592	XDROutPacketDestroy(&call);
593	return B_OK;
594}
595
596
597status_t
598nfs_truncate_file(fs_nspace *ns, const nfs_fhandle *fhandle, struct stat *st)
599{
600	struct XDROutPacket call;
601	struct XDRInPacket reply;
602	uint8 *replyBuf;
603	int32 status;
604
605	XDROutPacketInit(&call);
606	XDRInPacketInit(&reply);
607
608	XDROutPacketAddFixed(&call, fhandle->opaque, NFS_FHSIZE);
609
610	XDROutPacketAddInt32(&call, -1);
611	XDROutPacketAddInt32(&call, -1);
612	XDROutPacketAddInt32(&call, -1);
613	XDROutPacketAddInt32(&call, 0);
614	XDROutPacketAddInt32(&call, time(NULL));
615	XDROutPacketAddInt32(&call, 0);
616	XDROutPacketAddInt32(&call, time(NULL));
617	XDROutPacketAddInt32(&call, 0);
618
619	replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION,
620		NFSPROC_SETATTR, &call);
621	if (replyBuf == NULL) {
622		XDRInPacketDestroy(&reply);
623		XDROutPacketDestroy(&call);
624		return EHOSTUNREACH;
625	}
626
627	XDRInPacketSetTo(&reply, replyBuf, 0);
628
629	if (!is_successful_reply(&reply)) {
630		XDRInPacketDestroy(&reply);
631		XDROutPacketDestroy(&call);
632		return B_ERROR;
633	}
634
635	status = XDRInPacketGetInt32(&reply);
636	if (status != NFS_OK) {
637		XDRInPacketDestroy(&reply);
638		XDROutPacketDestroy(&call);
639		return map_nfs_to_system_error(status);
640	}
641
642	if (st)
643		get_nfs_attr(&reply,st);
644
645	XDRInPacketDestroy(&reply);
646	XDROutPacketDestroy(&call);
647	return B_OK;
648}
649
650
651void
652get_nfs_attr(struct XDRInPacket *reply, struct stat *st)
653{
654	nfs_ftype ftype=(nfs_ftype)XDRInPacketGetInt32(reply);
655	(void) ftype;
656	st->st_mode=XDRInPacketGetInt32(reply);
657
658	st->st_dev=0;	// just to be sure
659	st->st_nlink=XDRInPacketGetInt32(reply);
660	st->st_uid=XDRInPacketGetInt32(reply);
661	st->st_gid=XDRInPacketGetInt32(reply);
662	st->st_size=XDRInPacketGetInt32(reply);
663#if 0
664	XDRInPacketGetInt32(reply);	// blksize
665	st->st_blksize=NFS_MAXDATA;
666#else
667	st->st_blksize=XDRInPacketGetInt32(reply);
668#endif
669	st->st_rdev=XDRInPacketGetInt32(reply);
670	XDRInPacketGetInt32(reply);	// blocks
671	XDRInPacketGetInt32(reply);	// fsid
672	st->st_ino=XDRInPacketGetInt32(reply);
673	st->st_atime=XDRInPacketGetInt32(reply);
674	XDRInPacketGetInt32(reply);	// usecs
675	st->st_mtime=st->st_crtime=XDRInPacketGetInt32(reply);
676	XDRInPacketGetInt32(reply);	// usecs
677	st->st_ctime=XDRInPacketGetInt32(reply);
678	XDRInPacketGetInt32(reply);	// usecs
679}
680
681
682status_t
683map_nfs_to_system_error(status_t nfsstatus)
684{
685	switch (nfsstatus) {
686		case NFS_OK:
687			return B_OK;
688
689		case NFSERR_PERM:
690			return EPERM;
691
692		case NFSERR_NOENT:
693			return ENOENT;
694
695		case NFSERR_IO:
696			return EIO;
697
698		case NFSERR_NXIO:
699			return ENXIO;
700
701		case NFSERR_ACCES:
702			return EACCES;
703
704		case NFSERR_EXIST:
705			return EEXIST;
706
707		case NFSERR_NODEV:
708			return ENODEV;
709
710		case NFSERR_NOTDIR:
711			return ENOTDIR;
712
713		case NFSERR_ISDIR:
714			return EISDIR;
715
716		case NFSERR_FBIG:
717			return EFBIG;
718
719		case NFSERR_NOSPC:
720			return ENOSPC;
721
722		case NFSERR_ROFS:
723			return EROFS;
724
725		case NFSERR_NAMETOOLONG:
726			return ENAMETOOLONG;
727
728		case NFSERR_NOTEMPTY:
729			return ENOTEMPTY;
730
731		case NFSERR_STALE:
732			return C_ERROR_STALE;
733
734		default:
735			return B_ERROR;
736	}
737}
738
739
740nfs_fhandle
741handle_from_vnid(fs_nspace *ns, ino_t vnid)
742{
743	fs_node *current;
744
745	while (acquire_sem(ns->sem) == B_INTERRUPTED);
746
747	current = ns->first;
748
749	while (current != NULL && current->vnid != vnid)
750		current = current->next;
751
752	while (release_sem(ns->sem) == B_INTERRUPTED);
753
754	return current->fhandle;
755}
756
757
758void
759insert_node(fs_nspace *ns, fs_node *node)
760{
761	fs_node *current;
762
763	while (acquire_sem (ns->sem)==B_INTERRUPTED);
764
765	current=ns->first;
766
767	while ((current)&&(current->vnid!=node->vnid))
768		current=current->next;
769
770	if (current)
771	{
772		free(node);
773		while (release_sem (ns->sem)==B_INTERRUPTED);
774		return;
775	}
776
777	node->next=ns->first;
778	ns->first=node;
779
780	while (release_sem (ns->sem)==B_INTERRUPTED);
781}
782
783
784void
785remove_node(fs_nspace *ns, ino_t vnid)
786{
787	fs_node *current;
788	fs_node *previous;
789
790	while(acquire_sem (ns->sem)==B_INTERRUPTED);
791
792	current=ns->first;
793	previous=NULL;
794
795	while (current != NULL && current->vnid != vnid) {
796		previous = current;
797		current = current->next;
798	}
799
800	if (current) {
801		if (previous)
802			previous->next=current->next;
803		else
804			ns->first=current->next;
805
806		free(current);
807	}
808
809	while (release_sem (ns->sem)==B_INTERRUPTED);
810}
811
812
813//	#pragma mark -
814
815
816static status_t
817fs_read_vnode(fs_volume *_volume, ino_t vnid, fs_vnode *_node, int *_type,
818		uint32 *_flags, bool r)
819
820{
821	fs_nspace *ns;
822	fs_node *current;
823
824	ns = _volume->private_volume;
825
826	if (!r)
827	{
828		while (acquire_sem (ns->sem)==B_INTERRUPTED);
829	}
830
831	current=ns->first;
832
833	while ((current)&&(current->vnid!=vnid))
834		current=current->next;
835
836	if (!current)
837		return EINVAL;
838
839	current->vnid = vnid;
840	_node->private_node = current;
841	_node->ops = &sNFSVnodeOps;
842	*_type = 0;
843	*_flags = 0;
844
845	if (!r)
846	{
847		while (release_sem (ns->sem)==B_INTERRUPTED);
848	}
849
850	return B_OK;
851}
852
853
854static status_t
855fs_release_vnode(fs_volume *_volume, fs_vnode *node, bool r)
856{
857	(void) _volume;
858	(void) node;
859	(void) r;
860	return B_OK;
861}
862
863
864static status_t
865fs_walk(fs_volume *_volume, fs_vnode *_base, const char *file, ino_t *vnid)
866{
867	bool isLink;
868	fs_node *dummy;
869	status_t result;
870	fs_nspace *ns;
871	fs_node *base;
872	//dprintf("nfs: walk(%s)\n", file);//XXX:mmu_man:debug
873
874	ns = _volume->private_volume;
875	base = _base->private_node;
876
877	if (!strcmp(".",file))
878	{
879		*vnid=base->vnid;
880		isLink=false;
881	}
882	else
883	{
884		fs_node *newNode=(fs_node *)malloc(sizeof(fs_node));
885		struct stat st;
886
887		if ((result=nfs_lookup(ns,&base->fhandle,file,&newNode->fhandle,&st))<B_OK)
888		{
889			free(newNode);
890			return result;
891		}
892
893		newNode->vnid=st.st_ino;
894		*vnid=newNode->vnid;
895
896		insert_node (ns,newNode);
897
898		isLink=S_ISLNK(st.st_mode);
899	}
900
901	if ((result=get_vnode (_volume,*vnid,(void **)&dummy,NULL))<B_OK)
902		return result;
903
904	return B_OK;
905}
906
907
908static status_t
909fs_opendir(fs_volume *_volume, fs_vnode *_node, void **_cookie)
910{
911	fs_nspace *ns;
912	fs_node *node;
913	nfs_cookie **cookie;
914
915	struct stat st;
916	status_t result;
917
918	ns = _volume->private_volume;
919	node = _node->private_node;
920	cookie = (nfs_cookie **)_cookie;
921
922	if ((result=nfs_getattr(ns,&node->fhandle,&st))<B_OK)
923		return result;
924
925	if (!S_ISDIR(st.st_mode))
926		return ENOTDIR;
927
928	*cookie=(nfs_cookie *)malloc(sizeof(nfs_cookie));
929	memset ((*cookie)->opaque,0,NFS_COOKIESIZE);
930
931	return B_OK;
932}
933
934
935static status_t
936fs_closedir(fs_volume *_volume, fs_vnode *_node, void *cookie)
937{
938	(void) _volume;
939	(void) _node;
940	(void) cookie;
941	return B_OK;
942}
943
944
945static status_t
946fs_rewinddir(fs_volume *_volume, fs_vnode *_node, void *_cookie)
947{
948	nfs_cookie *cookie = (nfs_cookie *)_cookie;
949	(void) _volume;
950	(void) _node;
951	memset (cookie->opaque,0,NFS_COOKIESIZE);
952
953	return B_OK;
954}
955
956
957static status_t
958fs_readdir(fs_volume *_volume, fs_vnode *_node, void *_cookie,
959		struct dirent *buf, size_t bufsize, uint32 *num)
960{
961	nfs_cookie *cookie = (nfs_cookie *)_cookie;
962	int32 max=*num;
963	int32 eof;
964
965	fs_nspace *ns;
966	fs_node *node;
967
968	size_t count=min_c(6000,max*300);
969
970	*num=0;
971
972	ns = _volume->private_volume;
973	node = _node->private_node;
974
975	do
976	{
977		ino_t vnid;
978		char *filename;
979		uint8 *replyBuf;
980		struct XDROutPacket call;
981		struct XDRInPacket reply;
982		int32 status;
983
984		XDROutPacketInit (&call);
985		XDRInPacketInit (&reply);
986
987		XDROutPacketAddFixed (&call,node->fhandle.opaque,NFS_FHSIZE);
988		XDROutPacketAddFixed (&call,cookie->opaque,NFS_COOKIESIZE);
989		XDROutPacketAddInt32 (&call,count);
990
991		replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_READDIR,&call);
992
993		if (!replyBuf)
994		{
995			XDRInPacketDestroy (&reply);
996			XDROutPacketDestroy (&call);
997			return B_ERROR;
998		}
999
1000		XDRInPacketSetTo(&reply,replyBuf,0);
1001
1002		if (!is_successful_reply(&reply))
1003		{
1004			XDRInPacketDestroy (&reply);
1005			XDROutPacketDestroy (&call);
1006			return B_ERROR;
1007		}
1008
1009		status=XDRInPacketGetInt32(&reply);
1010
1011		if (status!=NFS_OK)
1012		{
1013			XDRInPacketDestroy (&reply);
1014			XDROutPacketDestroy (&call);
1015			return map_nfs_to_system_error(status);
1016		}
1017
1018		while (XDRInPacketGetInt32(&reply)==1)
1019		{
1020			nfs_cookie newCookie;
1021
1022			vnid=XDRInPacketGetInt32(&reply);
1023			filename=XDRInPacketGetString(&reply);
1024
1025			XDRInPacketGetFixed(&reply,newCookie.opaque,NFS_COOKIESIZE);
1026
1027			//if (strcmp(".",filename)&&strcmp("..",filename))
1028			//if ((ns->rootid != node->vnid) || (strcmp(".",filename)&&strcmp("..",filename)))
1029			if (conf_ls_root_parent || ((ns->rootid != node->vnid) || strcmp("..",filename)))
1030			{
1031				status_t result;
1032				struct stat st;
1033
1034				fs_node *newNode=(fs_node *)malloc(sizeof(fs_node));
1035				newNode->vnid=vnid;
1036
1037				if ((result=nfs_lookup(ns,&node->fhandle,filename,&newNode->fhandle,&st))<B_OK)
1038				{
1039					free (filename);
1040					free(newNode);
1041					XDRInPacketDestroy (&reply);
1042					XDROutPacketDestroy (&call);
1043					return result;
1044				}
1045
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	_vol->private_volume = ns;
1326
1327	ns->first=rootNode;
1328
1329	return B_OK;
1330
1331err_publish:
1332	// XXX: unmount ??
1333err_mount:
1334	free(rootNode);
1335err_rootvn:
1336	delete_sem (ns->sem);
1337err_sem:
1338	shutdown_postoffice(ns);
1339	goto err_socket;
1340err_postoffice:
1341	close(ns->s);
1342err_socket:
1343err_params:
1344	free (ns->params.hostname);
1345	free (ns->params._export);
1346	free (ns->params.server);
1347
1348	fs_nspaceDestroy (ns);
1349	free(ns);
1350err_nspace:
1351
1352	if (result >= 0) {
1353		dprintf("nfs:bad error from mount!\n");
1354		result = EINVAL;
1355	}
1356	dprintf("nfs: error in nfs_mount: %s\n", strerror(result));
1357	return result;
1358}
1359
1360
1361static status_t
1362fs_unmount(fs_volume *_volume)
1363{
1364	fs_nspace *ns = (fs_nspace *)_volume->private_volume;
1365	free(ns->params.hostname);
1366	free(ns->params._export);
1367	free(ns->params.server);
1368
1369	while (ns->first) {
1370		fs_node *next = ns->first->next;
1371		free(ns->first);
1372		ns->first = next;
1373	}
1374
1375	// We need to put the reference to our root node ourselves
1376	put_vnode(_volume, ns->rootid);
1377
1378	delete_sem(ns->sem);
1379	shutdown_postoffice(ns);
1380	fs_nspaceDestroy(ns);
1381	free(ns);
1382	return B_OK;
1383}
1384
1385
1386static status_t
1387fs_rfsstat(fs_volume *_volume, struct fs_info *info)
1388{
1389	fs_nspace *ns;
1390	struct XDROutPacket call;
1391	struct XDRInPacket reply;
1392	nfs_fhandle rootHandle;
1393	uint8 *replyBuf;
1394	int32 status;
1395
1396	ns = (fs_nspace *)_volume->private_volume;
1397
1398	rootHandle = handle_from_vnid (ns,ns->rootid);
1399	//dprintf("nfs: rfsstat()\n");//XXX:mmu_man:debug
1400
1401	XDROutPacketInit(&call);
1402	XDRInPacketInit(&reply);
1403
1404	XDROutPacketAddFixed(&call, rootHandle.opaque, NFS_FHSIZE);
1405
1406	replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION,
1407		NFSPROC_STATFS, &call);
1408	if (replyBuf == NULL) {
1409		XDRInPacketDestroy(&reply);
1410		XDROutPacketDestroy(&call);
1411		return EHOSTUNREACH;
1412	}
1413
1414	XDRInPacketSetTo(&reply, replyBuf, 0);
1415
1416	if (!is_successful_reply(&reply)) {
1417		XDRInPacketDestroy(&reply);
1418		XDROutPacketDestroy(&call);
1419		return B_ERROR;
1420	}
1421
1422	status = XDRInPacketGetInt32(&reply);
1423	if (status != NFS_OK) {
1424		XDRInPacketDestroy(&reply);
1425		XDROutPacketDestroy(&call);
1426		//dprintf("nfs: rfsstat() error 0x%08lx\n", map_nfs_to_system_error(status));
1427		return map_nfs_to_system_error(status);
1428	}
1429
1430	info->dev = ns->nsid;
1431	info->root = ns->rootid;
1432	info->flags = NFS_FS_FLAGS;
1433
1434	XDRInPacketGetInt32(&reply);	// tsize
1435
1436	info->block_size = XDRInPacketGetInt32(&reply);
1437	info->io_size = 8192;
1438	info->total_blocks = XDRInPacketGetInt32(&reply);
1439	info->free_blocks = XDRInPacketGetInt32(&reply);
1440	info->total_nodes = 100;
1441	info->free_nodes = 100;
1442	strcpy(info->volume_name, "nfs://");
1443	strcat(info->volume_name, ns->params.server);
1444	strcat(info->volume_name, ns->params._export);
1445	strcpy(info->fsh_name, "nfs");
1446
1447	XDRInPacketDestroy(&reply);
1448	XDROutPacketDestroy(&call);
1449	return B_OK;
1450}
1451
1452
1453static status_t
1454fs_open(fs_volume *_volume, fs_vnode *_node, int omode, void **_cookie)
1455{
1456	fs_nspace *ns;
1457	fs_node *node;
1458	struct stat st;
1459	status_t result;
1460	fs_file_cookie **cookie;
1461
1462	ns = _volume->private_volume;
1463	node = _node->private_node;
1464	cookie = (fs_file_cookie **)_cookie;
1465
1466	if ((result=nfs_getattr(ns,&node->fhandle,&st))<B_OK)
1467		return result;
1468
1469	if (S_ISDIR(st.st_mode)) {
1470		/* permit opening of directories */
1471		if (conf_allow_dir_open) {
1472			*cookie = NULL;
1473			return B_OK;
1474		} else
1475			return EISDIR;
1476	}
1477
1478	*cookie=(fs_file_cookie *)malloc(sizeof(fs_file_cookie));
1479	(*cookie)->omode=omode;
1480	(*cookie)->original_size=st.st_size;
1481	(*cookie)->st=st;
1482
1483	return B_OK;
1484}
1485
1486
1487static status_t
1488fs_close(fs_volume *_volume, fs_vnode *_node, void *cookie)
1489{
1490	(void) _volume;
1491	(void) _node;
1492	(void) cookie;
1493/*	//XXX:mmu_man:why that ?? makes Tracker go nuts updating the stats
1494	if ((cookie->omode & O_RDWR)||(cookie->omode & O_WRONLY))
1495		return my_notify_listener (B_STAT_CHANGED,ns->nsid,0,0,node->vnid,NULL);
1496*/
1497	return B_OK;
1498}
1499
1500
1501static status_t
1502fs_free_cookie(fs_volume *_volume, fs_vnode *_node, void *cookie)
1503{
1504	(void) _volume;
1505	(void) _node;
1506	free(cookie);
1507	return B_OK;
1508}
1509
1510
1511static status_t
1512fs_read(fs_volume *_volume, fs_vnode *_node, void *_cookie, off_t pos,
1513	void *buf, size_t *len)
1514{
1515	fs_nspace *ns;
1516	fs_node *node;
1517	fs_file_cookie *cookie;
1518	size_t max = *len;
1519	*len = 0;
1520
1521	ns = _volume->private_volume;
1522	node = _node->private_node;
1523	cookie = (fs_file_cookie *)_cookie;
1524
1525	if (!cookie)
1526		return EISDIR; /* do not permit reading of directories */
1527
1528	while ((*len) < max) {
1529		size_t count = min_c(NFS_MAXDATA, max-(*len));
1530		struct XDROutPacket call;
1531		struct XDRInPacket reply;
1532		int32 status;
1533		uint8 *replyBuf;
1534		struct stat st;
1535		size_t readbytes;
1536
1537		XDROutPacketInit(&call);
1538		XDRInPacketInit(&reply);
1539
1540		XDROutPacketAddFixed(&call, &node->fhandle.opaque, NFS_FHSIZE);
1541		XDROutPacketAddInt32(&call, pos);
1542		XDROutPacketAddInt32(&call, count);
1543		XDROutPacketAddInt32(&call, 0);
1544
1545		replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION,
1546			NFSPROC_READ, &call);
1547		if (replyBuf == NULL) {
1548			XDRInPacketDestroy(&reply);
1549			XDROutPacketDestroy(&call);
1550			return B_ERROR;
1551		}
1552
1553		XDRInPacketSetTo(&reply, replyBuf, 0);
1554
1555		if (!is_successful_reply(&reply)) {
1556			XDRInPacketDestroy(&reply);
1557			XDROutPacketDestroy(&call);
1558			return B_ERROR;
1559		}
1560
1561		status = XDRInPacketGetInt32(&reply);
1562		if (status != NFS_OK) {
1563			XDRInPacketDestroy(&reply);
1564			XDROutPacketDestroy(&call);
1565			return map_nfs_to_system_error(status);
1566		}
1567
1568		get_nfs_attr(&reply, &st);
1569		cookie->st = st;
1570
1571		readbytes = XDRInPacketGetDynamic(&reply, buf);
1572
1573		buf = (char *)buf + readbytes;
1574		(*len) += readbytes;
1575		pos += readbytes;
1576
1577		XDRInPacketDestroy(&reply);
1578		XDROutPacketDestroy(&call);
1579
1580		if (pos >= st.st_size)
1581			break;
1582	}
1583
1584	return B_OK;
1585}
1586
1587
1588static status_t
1589fs_write(fs_volume *_volume, fs_vnode *_node, void *_cookie, off_t pos,
1590	const void *buf, size_t *len)
1591{
1592	fs_nspace *ns;
1593	fs_node *node;
1594	fs_file_cookie *cookie;
1595	size_t bytesWritten = 0;
1596
1597	ns = _volume->private_volume;
1598	node = _node->private_node;
1599	cookie = (fs_file_cookie *)_cookie;
1600
1601	if (!cookie)
1602		return EISDIR; /* do not permit reading of directories */
1603	if (cookie->omode & O_APPEND)
1604		pos+=cookie->original_size;
1605
1606	while (bytesWritten < *len) {
1607		size_t count=min_c(NFS_MAXDATA,(*len)-bytesWritten);
1608
1609		struct XDROutPacket call;
1610		struct XDRInPacket reply;
1611		int32 status;
1612		uint8 *replyBuf;
1613		struct stat st;
1614
1615		XDROutPacketInit (&call);
1616		XDRInPacketInit (&reply);
1617
1618		XDROutPacketAddFixed (&call,&node->fhandle.opaque,NFS_FHSIZE);
1619		XDROutPacketAddInt32 (&call,0);
1620		XDROutPacketAddInt32 (&call,pos+bytesWritten);
1621		XDROutPacketAddInt32 (&call,0);
1622		XDROutPacketAddDynamic (&call,(const char *)buf+bytesWritten,count);
1623
1624		replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_WRITE,&call);
1625
1626		if (!replyBuf)
1627		{
1628			XDRInPacketDestroy (&reply);
1629			XDROutPacketDestroy (&call);
1630			return B_ERROR;
1631		}
1632
1633		XDRInPacketSetTo (&reply,replyBuf,0);
1634
1635		if (!is_successful_reply(&reply))
1636		{
1637			XDRInPacketDestroy (&reply);
1638			XDROutPacketDestroy (&call);
1639			return B_ERROR;
1640		}
1641
1642		status=XDRInPacketGetInt32(&reply);
1643
1644		if (status!=NFS_OK)
1645		{
1646			XDRInPacketDestroy (&reply);
1647			XDROutPacketDestroy (&call);
1648			return map_nfs_to_system_error(status);
1649		}
1650
1651		get_nfs_attr (&reply,&st);
1652
1653		cookie->st=st;
1654
1655		bytesWritten+=count;
1656
1657		XDRInPacketDestroy (&reply);
1658		XDROutPacketDestroy (&call);
1659	}
1660
1661	return B_OK;
1662}
1663
1664static status_t
1665fs_wstat(fs_volume *_volume, fs_vnode *_node, const struct stat *st, uint32 mask)
1666{
1667	fs_nspace *ns;
1668	fs_node *node;
1669	struct XDROutPacket call;
1670	struct XDRInPacket reply;
1671
1672	uint8 *replyBuf;
1673	int32 status;
1674
1675	ns = _volume->private_volume;
1676	node = _node->private_node;
1677
1678	XDROutPacketInit (&call);
1679	XDRInPacketInit (&reply);
1680
1681	XDROutPacketAddFixed (&call,node->fhandle.opaque,NFS_FHSIZE);
1682
1683	XDROutPacketAddInt32 (&call,(mask & WSTAT_MODE) ? st->st_mode : -1);
1684	XDROutPacketAddInt32 (&call,(mask & WSTAT_UID) ? st->st_uid : -1);
1685	XDROutPacketAddInt32 (&call,(mask & WSTAT_GID) ? st->st_gid : -1);
1686	XDROutPacketAddInt32 (&call,(mask & WSTAT_SIZE) ? st->st_size : -1);
1687	XDROutPacketAddInt32 (&call,(mask & WSTAT_ATIME) ? st->st_atime : -1);
1688	XDROutPacketAddInt32 (&call,(mask & WSTAT_ATIME) ? 0 : -1);
1689	XDROutPacketAddInt32 (&call,(mask & WSTAT_MTIME) ? st->st_mtime : -1);
1690	XDROutPacketAddInt32 (&call,(mask & WSTAT_MTIME) ? 0 : -1);
1691
1692	replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_SETATTR,&call);
1693
1694	if (!replyBuf)
1695	{
1696		XDRInPacketDestroy (&reply);
1697		XDROutPacketDestroy (&call);
1698		return EHOSTUNREACH;
1699	}
1700
1701	XDRInPacketSetTo (&reply,replyBuf,0);
1702
1703	if (!is_successful_reply(&reply))
1704	{
1705		XDRInPacketDestroy (&reply);
1706		XDROutPacketDestroy (&call);
1707		return B_ERROR;
1708	}
1709
1710	status=XDRInPacketGetInt32(&reply);
1711
1712	if (status!=NFS_OK)
1713		return map_nfs_to_system_error(status);
1714
1715	XDRInPacketDestroy (&reply);
1716	XDROutPacketDestroy (&call);
1717
1718	return notify_stat_changed (_volume->id, node->vnid, mask);
1719}
1720
1721static status_t
1722fs_wfsstat(fs_volume *_volume, const struct fs_info *info, uint32 mask)
1723{
1724	(void) _volume;
1725	(void) info;
1726	(void) mask;
1727	return B_OK;
1728}
1729
1730static status_t
1731fs_create(fs_volume *_volume, fs_vnode *_dir, const char *name, int omode, int perms, void **_cookie, ino_t *vnid)
1732{
1733	nfs_fhandle fhandle;
1734	struct stat st;
1735	fs_file_cookie **cookie;
1736
1737	fs_nspace *ns;
1738	fs_node *dir;
1739
1740	status_t result;
1741
1742	ns = _volume->private_volume;
1743	dir = _dir->private_node;
1744	cookie = (fs_file_cookie **)_cookie;
1745
1746	result=nfs_lookup(ns,&dir->fhandle,name,&fhandle,&st);
1747
1748	if (result==B_OK)
1749	{
1750		void *dummy;
1751		fs_node *newNode=(fs_node *)malloc(sizeof(fs_node));
1752		newNode->fhandle=fhandle;
1753		newNode->vnid=st.st_ino;
1754		insert_node (ns,newNode);
1755
1756		*vnid=st.st_ino;
1757
1758		if ((result=get_vnode(_volume,*vnid,&dummy,NULL))<B_OK)
1759			return result;
1760
1761		if (S_ISDIR(st.st_mode))
1762			return EISDIR;
1763
1764		if (omode & O_EXCL)
1765			return EEXIST;
1766
1767		if (omode & O_TRUNC)
1768		{
1769			if ((result=nfs_truncate_file(ns,&fhandle,NULL))<B_OK)
1770				return result;
1771		}
1772
1773		*cookie=(fs_file_cookie *)malloc(sizeof(fs_file_cookie));
1774		(*cookie)->omode=omode;
1775		(*cookie)->original_size=st.st_size;
1776		(*cookie)->st=st;
1777
1778		return B_OK;
1779	}
1780	else if (result!=ENOENT)
1781		return result;
1782	else
1783	{
1784		struct XDROutPacket call;
1785		struct XDRInPacket reply;
1786
1787		uint8 *replyBuf;
1788		int32 status;
1789
1790		fs_node *newNode;
1791
1792		if (!(omode & O_CREAT))
1793			return ENOENT;
1794
1795		XDROutPacketInit (&call);
1796		XDRInPacketInit (&reply);
1797
1798		XDROutPacketAddFixed (&call,dir->fhandle.opaque,NFS_FHSIZE);
1799		XDROutPacketAddString(&call,name);
1800		XDROutPacketAddInt32 (&call,perms|S_IFREG);
1801		XDROutPacketAddInt32 (&call,-1);
1802		XDROutPacketAddInt32 (&call,-1);
1803		XDROutPacketAddInt32 (&call,0);
1804		XDROutPacketAddInt32 (&call,time(NULL));
1805		XDROutPacketAddInt32 (&call,0);
1806		XDROutPacketAddInt32 (&call,time(NULL));
1807		XDROutPacketAddInt32 (&call,0);
1808
1809		replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_CREATE,&call);
1810
1811		if (!replyBuf)
1812		{
1813			XDRInPacketDestroy (&reply);
1814			XDROutPacketDestroy (&call);
1815			return B_ERROR;
1816		}
1817
1818		XDRInPacketSetTo (&reply,replyBuf,0);
1819
1820		if (!is_successful_reply(&reply))
1821		{
1822			XDRInPacketDestroy (&reply);
1823			XDROutPacketDestroy (&call);
1824			return B_ERROR;
1825		}
1826
1827		status=XDRInPacketGetInt32(&reply);
1828
1829		if (status!=NFS_OK)
1830		{
1831			XDRInPacketDestroy (&reply);
1832			XDROutPacketDestroy (&call);
1833			return map_nfs_to_system_error(status);
1834		}
1835
1836		XDRInPacketGetFixed (&reply,fhandle.opaque,NFS_FHSIZE);
1837
1838		get_nfs_attr (&reply,&st);
1839
1840		newNode=(fs_node *)malloc(sizeof(fs_node));
1841		newNode->fhandle=fhandle;
1842		newNode->vnid=st.st_ino;
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
1902	insert_node (ns,newNode);
1903
1904	if ((result=get_vnode(_volume,st.st_ino,(void **)&dummy,NULL))<B_OK)
1905	{
1906		XDRInPacketDestroy (&reply);
1907		XDROutPacketDestroy (&call);
1908		return result;
1909	}
1910
1911	if (!S_ISREG(st.st_mode)&&!S_ISLNK(st.st_mode))
1912	{
1913		XDRInPacketDestroy (&reply);
1914		XDROutPacketDestroy (&call);
1915		return EISDIR;
1916	}
1917
1918	if ((result=remove_vnode(_volume,st.st_ino))<B_OK)
1919	{
1920		XDRInPacketDestroy (&reply);
1921		XDROutPacketDestroy (&call);
1922		return result;
1923	}
1924
1925	if ((result=put_vnode(_volume,st.st_ino))<B_OK)
1926	{
1927		XDRInPacketDestroy (&reply);
1928		XDROutPacketDestroy (&call);
1929		return result;
1930	}
1931
1932	XDROutPacketAddFixed (&call,dir->fhandle.opaque,NFS_FHSIZE);
1933	XDROutPacketAddString(&call,name);
1934
1935	replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_REMOVE,&call);
1936
1937	if (!replyBuf)
1938	{
1939		XDRInPacketDestroy (&reply);
1940		XDROutPacketDestroy (&call);
1941		return EHOSTUNREACH;
1942	}
1943
1944	XDRInPacketSetTo(&reply,replyBuf,0);
1945
1946	if (!is_successful_reply(&reply))
1947	{
1948		XDRInPacketDestroy (&reply);
1949		XDROutPacketDestroy (&call);
1950		return B_ERROR;
1951	}
1952
1953	status=XDRInPacketGetInt32(&reply);
1954
1955	if (status!=NFS_OK)
1956	{
1957		XDRInPacketDestroy (&reply);
1958		XDROutPacketDestroy (&call);
1959		return map_nfs_to_system_error(status);
1960	}
1961
1962	XDRInPacketDestroy (&reply);
1963	XDROutPacketDestroy (&call);
1964
1965	return notify_entry_removed (_volume->id, dir->vnid, name, st.st_ino);
1966}
1967
1968static status_t
1969fs_remove_vnode(fs_volume *_volume, fs_vnode *_node, bool r)
1970{
1971	fs_nspace *ns = _volume->private_volume;
1972	fs_node *node = _node->private_node;
1973
1974	(void) r;
1975
1976	remove_node (ns,node->vnid);
1977
1978	return B_OK;
1979}
1980
1981static status_t
1982fs_mkdir(fs_volume *_volume, fs_vnode *_dir, const char *name, int perms, ino_t *_newVnodeID)
1983{
1984	fs_nspace *ns;
1985	fs_node *dir;
1986
1987	nfs_fhandle fhandle;
1988	struct stat st;
1989	fs_node *newNode;
1990
1991	status_t result;
1992	uint8 *replyBuf;
1993	int32 status;
1994
1995	struct XDROutPacket call;
1996	struct XDRInPacket reply;
1997
1998	ns = _volume->private_volume;
1999	dir = _dir->private_node;
2000
2001	XDROutPacketInit (&call);
2002	XDRInPacketInit (&reply);
2003
2004	result=nfs_lookup(ns,&dir->fhandle,name,&fhandle,&st);
2005
2006	if (result==B_OK)
2007	{
2008		//void *dummy;
2009
2010		XDRInPacketDestroy (&reply);
2011		XDROutPacketDestroy (&call);
2012		// XXX: either OK or not get_vnode !!! ??
2013		//if ((result=get_vnode(_volume,st.st_ino,&dummy))<B_OK)
2014		//	return result;
2015		return EEXIST;
2016	}
2017	else if (result!=ENOENT)
2018	{
2019		XDRInPacketDestroy (&reply);
2020		XDROutPacketDestroy (&call);
2021		return result;
2022	}
2023
2024	XDROutPacketAddFixed (&call,dir->fhandle.opaque,NFS_FHSIZE);
2025	XDROutPacketAddString(&call,name);
2026	XDROutPacketAddInt32 (&call,perms|S_IFDIR);
2027	XDROutPacketAddInt32 (&call,-1);
2028	XDROutPacketAddInt32 (&call,-1);
2029	XDROutPacketAddInt32 (&call,-1);
2030	XDROutPacketAddInt32 (&call,time(NULL));
2031	XDROutPacketAddInt32 (&call,0);
2032	XDROutPacketAddInt32 (&call,time(NULL));
2033	XDROutPacketAddInt32 (&call,0);
2034
2035	replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_MKDIR,&call);
2036
2037	if (!replyBuf)
2038	{
2039		XDRInPacketDestroy (&reply);
2040		XDROutPacketDestroy (&call);
2041		return B_ERROR;
2042	}
2043
2044	XDRInPacketSetTo (&reply,replyBuf,0);
2045
2046	if (!is_successful_reply(&reply))
2047	{
2048		XDRInPacketDestroy (&reply);
2049		XDROutPacketDestroy (&call);
2050		return B_ERROR;
2051	}
2052
2053	status=XDRInPacketGetInt32(&reply);
2054
2055	if (status!=NFS_OK)
2056	{
2057		XDROutPacketDestroy (&call);
2058		return map_nfs_to_system_error(status);
2059	}
2060
2061	XDRInPacketGetFixed(&reply,fhandle.opaque,NFS_FHSIZE);
2062
2063	get_nfs_attr (&reply,&st);
2064
2065	newNode=(fs_node *)malloc(sizeof(fs_node));
2066	newNode->fhandle=fhandle;
2067	newNode->vnid=st.st_ino;
2068
2069	*_newVnodeID = newNode->vnid;
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
2196	insert_node (ns,newNode);
2197
2198	if ((result=get_vnode(_volume,st.st_ino,(void **)&dummy,NULL))<B_OK)
2199	{
2200		XDRInPacketDestroy(&reply);
2201		XDROutPacketDestroy(&call);
2202		return result;
2203	}
2204
2205	if (!S_ISDIR(st.st_mode))
2206	{
2207		XDRInPacketDestroy(&reply);
2208		XDROutPacketDestroy(&call);
2209		return ENOTDIR;
2210	}
2211
2212	if ((result=remove_vnode(_volume,st.st_ino))<B_OK)
2213	{
2214		XDRInPacketDestroy(&reply);
2215		XDROutPacketDestroy(&call);
2216		return result;
2217	}
2218
2219	if ((result=put_vnode(_volume,st.st_ino))<B_OK)
2220	{
2221		XDRInPacketDestroy(&reply);
2222		XDROutPacketDestroy(&call);
2223		return result;
2224	}
2225
2226	XDROutPacketAddFixed (&call,dir->fhandle.opaque,NFS_FHSIZE);
2227	XDROutPacketAddString(&call,name);
2228
2229	replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_RMDIR,&call);
2230
2231	if (!replyBuf)
2232	{
2233		XDRInPacketDestroy(&reply);
2234		XDROutPacketDestroy(&call);
2235		return EHOSTUNREACH;
2236	}
2237
2238	XDRInPacketSetTo (&reply,replyBuf,0);
2239
2240	if (!is_successful_reply(&reply))
2241	{
2242		XDRInPacketDestroy(&reply);
2243		XDROutPacketDestroy(&call);
2244		return B_ERROR;
2245	}
2246
2247	status=XDRInPacketGetInt32(&reply);
2248
2249	if (status!=NFS_OK)
2250	{
2251		XDRInPacketDestroy(&reply);
2252		XDROutPacketDestroy(&call);
2253		return map_nfs_to_system_error(status);
2254	}
2255
2256	XDRInPacketDestroy(&reply);
2257	XDROutPacketDestroy(&call);
2258	return notify_entry_removed (_volume->id, dir->vnid, name, st.st_ino);
2259}
2260
2261static status_t
2262fs_readlink(fs_volume *_volume, fs_vnode *_node, char *buf, size_t *bufsize)
2263{
2264	struct XDROutPacket call;
2265	uint8 *replyBuf;
2266	int32 status;
2267	size_t length;
2268	char data[NFS_MAXPATHLEN];
2269	struct XDRInPacket reply;
2270	fs_nspace *ns;
2271	fs_node *node;
2272
2273	ns = _volume->private_volume;
2274	node = _node->private_node;
2275
2276	XDROutPacketInit (&call);
2277	XDRInPacketInit(&reply);
2278
2279	XDROutPacketAddFixed (&call,node->fhandle.opaque,NFS_FHSIZE);
2280
2281	replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_READLINK,&call);
2282
2283	if (!replyBuf)
2284	{
2285		XDRInPacketDestroy(&reply);
2286		XDROutPacketDestroy (&call);
2287		return EHOSTUNREACH;
2288	}
2289
2290	XDRInPacketSetTo (&reply,replyBuf,0);
2291
2292	if (!is_successful_reply(&reply))
2293	{
2294		XDRInPacketDestroy(&reply);
2295		XDROutPacketDestroy (&call);
2296		return B_ERROR;
2297	}
2298
2299	status=XDRInPacketGetInt32(&reply);
2300
2301	if (status!=NFS_OK)
2302	{
2303		XDRInPacketDestroy(&reply);
2304		XDROutPacketDestroy (&call);
2305		return map_nfs_to_system_error(status);
2306	}
2307
2308	length=XDRInPacketGetDynamic(&reply,data);
2309
2310	length=min_c(length,*bufsize);
2311	memcpy (buf,data,length);
2312	*bufsize=length;
2313
2314	XDRInPacketDestroy(&reply);
2315	XDROutPacketDestroy (&call);
2316	return B_OK;
2317}
2318
2319static status_t
2320fs_symlink(fs_volume *_volume, fs_vnode *_dir, const char *name, const char *path, int mode)
2321{
2322	fs_nspace *ns;
2323	fs_node *dir;
2324	nfs_fhandle fhandle;
2325	struct stat st;
2326	struct XDROutPacket call;
2327	struct XDRInPacket reply;
2328	status_t result;
2329	uint8 *replyBuf;
2330	int32 status;
2331	fs_node *newNode;
2332
2333	ns = _volume->private_volume;
2334	dir = _dir->private_node;
2335
2336	XDROutPacketInit (&call);
2337	XDRInPacketInit (&reply);
2338
2339	result=nfs_lookup(ns,&dir->fhandle,name,&fhandle,&st);
2340
2341	if (result==B_OK)
2342	{
2343		void *dummy;
2344		if ((result=get_vnode(_volume,st.st_ino,&dummy,NULL))<B_OK)
2345			return result;
2346
2347		XDRInPacketDestroy (&reply);
2348		XDROutPacketDestroy (&call);
2349		return EEXIST;
2350	}
2351	else if (result!=ENOENT)
2352	{
2353		XDRInPacketDestroy (&reply);
2354		XDROutPacketDestroy (&call);
2355		return result;
2356	}
2357
2358	XDROutPacketAddFixed (&call,dir->fhandle.opaque,NFS_FHSIZE);
2359	XDROutPacketAddString(&call,name);
2360	XDROutPacketAddString(&call,path);
2361	XDROutPacketAddInt32 (&call,S_IFLNK);
2362	XDROutPacketAddInt32 (&call,-1);
2363	XDROutPacketAddInt32 (&call,-1);
2364	XDROutPacketAddInt32 (&call,-1);
2365	XDROutPacketAddInt32 (&call,time(NULL));
2366	XDROutPacketAddInt32 (&call,0);
2367	XDROutPacketAddInt32 (&call,time(NULL));
2368	XDROutPacketAddInt32 (&call,0);
2369
2370	replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_SYMLINK,&call);
2371
2372	if (!replyBuf)
2373	{
2374		XDRInPacketDestroy (&reply);
2375		XDROutPacketDestroy (&call);
2376		return B_ERROR;
2377	}
2378
2379	XDRInPacketSetTo (&reply,replyBuf,0);
2380
2381	if (!is_successful_reply(&reply))
2382	{
2383		XDRInPacketDestroy (&reply);
2384		XDROutPacketDestroy (&call);
2385		return B_ERROR;
2386	}
2387
2388	status=XDRInPacketGetInt32(&reply);
2389
2390/*	if (status!=NFS_OK)
2391		return map_nfs_to_system_error(status);
2392
2393	ignore status here, weird thing, nfsservers that is
2394*/
2395
2396	result=nfs_lookup(ns,&dir->fhandle,name,&fhandle,&st);
2397
2398	if (result<B_OK)
2399	{
2400		XDRInPacketDestroy (&reply);
2401		XDROutPacketDestroy (&call);
2402		return result;
2403	}
2404
2405	newNode=(fs_node *)malloc(sizeof(fs_node));
2406	newNode->fhandle=fhandle;
2407	newNode->vnid=st.st_ino;
2408
2409	insert_node (ns,newNode);
2410
2411	result = notify_entry_created (_volume->id, dir->vnid, name, st.st_ino);
2412
2413	XDRInPacketDestroy (&reply);
2414	XDROutPacketDestroy (&call);
2415	return result;
2416}
2417
2418
2419static status_t
2420fs_access(fs_volume *_volume, fs_vnode *node, int mode)
2421{
2422	(void) _volume;
2423	(void) node;
2424	(void) mode;
2425	/* XXX */
2426	return B_OK;
2427}
2428
2429
2430static status_t
2431nfs_std_ops(int32 op, ...)
2432{
2433	switch (op) {
2434		case B_MODULE_INIT:
2435			return B_OK;
2436		case B_MODULE_UNINIT:
2437			return B_OK;
2438
2439		default:
2440			return B_ERROR;
2441	}
2442}
2443
2444fs_volume_ops sNFSVolumeOps = {
2445	&fs_unmount,
2446	&fs_rfsstat,
2447	&fs_wfsstat,
2448	NULL,			// no sync!
2449	&fs_read_vnode,
2450
2451	/* index directory & index operations */
2452	NULL,	// &fs_open_index_dir
2453	NULL,	// &fs_close_index_dir
2454	NULL,	// &fs_free_index_dir_cookie
2455	NULL,	// &fs_read_index_dir
2456	NULL,	// &fs_rewind_index_dir
2457
2458	NULL,	// &fs_create_index
2459	NULL,	// &fs_remove_index
2460	NULL,	// &fs_stat_index
2461
2462	/* query operations */
2463	NULL,	// &fs_open_query,
2464	NULL,	// &fs_close_query,
2465	NULL,	// &fs_free_query_cookie,
2466	NULL,	// &fs_read_query,
2467	NULL,	// &fs_rewind_query,
2468};
2469
2470fs_vnode_ops sNFSVnodeOps = {
2471	/* vnode operations */
2472	&fs_walk,
2473	NULL, // fs_get_vnode_name
2474	&fs_release_vnode,
2475	&fs_remove_vnode,
2476
2477	/* VM file access */
2478	NULL, 	// &fs_can_page
2479	NULL,	// &fs_read_pages
2480	NULL, 	// &fs_write_pages
2481
2482	NULL,	// &fs_get_file_map,
2483
2484	NULL, 	// &fs_ioctl
2485	NULL,	// &fs_setflags,
2486	NULL,	// &fs_select
2487	NULL,	// &fs_deselect
2488	NULL, 	// &fs_fsync
2489
2490	&fs_readlink,
2491	&fs_symlink,
2492
2493	NULL,	// &fs_link,
2494	&fs_unlink,
2495	&fs_rename,
2496
2497	&fs_access,
2498	&fs_rstat,
2499	&fs_wstat,
2500
2501	/* file operations */
2502	&fs_create,
2503	&fs_open,
2504	&fs_close,
2505	&fs_free_cookie,
2506	&fs_read,
2507	&fs_write,
2508
2509	/* directory operations */
2510	&fs_mkdir,
2511	&fs_rmdir,
2512	&fs_opendir,
2513	&fs_closedir,
2514	&fs_free_dircookie,
2515	&fs_readdir,
2516	&fs_rewinddir,
2517
2518	/* attribute directory operations */
2519	NULL,	// &fs_open_attrdir,
2520	NULL,	// &fs_close_attrdir,
2521	NULL,	// &fs_free_attrdircookie,
2522	NULL,	// &fs_read_attrdir,
2523	NULL,	// &fs_rewind_attrdir,
2524
2525	/* attribute operations */
2526	NULL,	// &fs_create_attr
2527	NULL,	// &fs_open_attr_h,
2528	NULL,	// &fs_close_attr_h,
2529	NULL,	// &fs_free_attr_cookie_h,
2530	NULL,	// &fs_read_attr_h,
2531	NULL,	// &fs_write_attr_h,
2532
2533	NULL,	// &fs_read_attr_stat_h,
2534	NULL,	// &fs_write_attr_stat
2535	NULL,	// &fs_rename_attr
2536	NULL,	// &fs_remove_attr
2537};
2538
2539file_system_module_info sNFSFileSystem = {
2540	{
2541		"file_systems/nfs" B_CURRENT_FS_API_VERSION,
2542		0,
2543		nfs_std_ops,
2544	},
2545	"nfs",				// short name
2546	"Network File System v2",	// pretty name
2547	B_DISK_SYSTEM_SUPPORTS_WRITING, // DDM flags
2548
2549	// scanning
2550	NULL,	// fs_identify_partition,
2551	NULL,	// fs_scan_partition,
2552	NULL,	// fs_free_identify_partition_cookie,
2553	NULL,	// free_partition_content_cookie()
2554
2555	&fs_mount,
2556};
2557
2558module_info *modules[] = {
2559	(module_info *)&sNFSFileSystem,
2560	NULL,
2561};
2562
2563