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