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