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