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