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