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