Bug Summary

File:obj-scan-build/nfs/../../nfs/ops.c
Location:line 1836, column 17
Description:The left operand of '+' is a garbage value

Annotated Source Code

1/* ops.c - Libnetfs callbacks for node operations in NFS client.
2 Copyright (C) 1994,95,96,97,99,2002,2011 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License as
6 published by the Free Software Foundation; either version 2, or (at
7 your option) any later version.
8
9 This program is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
17
18#include "nfs.h"
19#include <hurd/netfs.h>
20#include <netinet/in.h>
21#include <string.h>
22#include <fcntl.h>
23#include <stdio.h>
24#include <stddef.h>
25#include <dirent.h>
26#include <unistd.h>
27#include <maptime.h>
28
29/* We have fresh stat information for NP; the file attribute (fattr)
30 structure is at P. Update our entry. Return the address of the next
31 int after the fattr structure. */
32int *
33register_fresh_stat (struct node *np, int *p)
34{
35 int *ret;
36
37 ret = xdr_decode_fattr (p, &np->nn_stat);
38 np->nn->stat_updated = mapped_time->seconds;
39
40 switch (np->nn->dtrans)
41 {
42 case NOT_POSSIBLE:
43 case POSSIBLE:
44 break;
45
46 case SYMLINK:
47 np->nn_stat.st_size = strlen (np->nn->transarg.name);
48 np->nn_stat.st_mode = ((np->nn_stat.st_mode & ~S_IFMT0170000) | S_IFLNK0120000);
49 break;
50
51 case CHRDEV:
52 np->nn_stat.st_rdev = np->nn->transarg.indexes;
53 np->nn_stat.st_mode = ((np->nn_stat.st_mode & ~S_IFMT0170000) | S_IFCHR0020000);
54 break;
55
56 case BLKDEV:
57 np->nn_stat.st_rdev = np->nn->transarg.indexes;
58 np->nn_stat.st_mode = ((np->nn_stat.st_mode & ~S_IFMT0170000) | S_IFBLK0060000);
59 break;
60
61 case FIFO:
62 np->nn_stat.st_mode = ((np->nn_stat.st_mode & ~S_IFMT0170000) | S_IFIFO0010000);
63 break;
64
65 case SOCK:
66 np->nn_stat.st_mode = ((np->nn_stat.st_mode & ~S_IFMT0170000) | S_IFSOCK0140000);
67 break;
68 }
69
70 np->nn_stat.st_fsid = getpid ();
71 np->nn_stat.st_fstype = FSTYPE_NFS0x00000001;
72 np->nn_stat.st_gen = 0;
73 np->nn_stat.st_author = np->nn_stat.st_uid;
74 np->nn_stat.st_flags = 0;
75 np->nn_translated = np->nn_stat.st_mode & S_IFMT0170000;
76
77 return ret;
78}
79
80/* Handle returned wcc information for various calls. In protocol
81 version 2, this is just register_fresh_stat. In version 3, it
82 checks to see if stat information is present too. If this follows
83 an operation that we expect has modified the attributes, MOD should
84 be set. (This unpacks the post_op_attr XDR type.) */
85int *
86process_returned_stat (struct node *np, int *p, int mod)
87{
88 if (protocol_version == 2)
89 return register_fresh_stat (np, p);
90 else
91 {
92 int attrs_exist;
93
94 attrs_exist = ntohl (*p);
95 p++;
96 if (attrs_exist)
97 p = register_fresh_stat (np, p);
98 else if (mod)
99 /* We know that our values are now wrong */
100 np->nn->stat_updated = 0;
101 return p;
102 }
103}
104
105
106/* Handle returned wcc information for various calls. In protocol
107 version 2, this is just register_fresh_stat. In version 3, it does
108 the wcc_data interpretation too. If this follows an operation that
109 we expect has modified the attributes, MOD should be set.
110 (This unpacks the wcc_data XDR type.) */
111int *
112process_wcc_stat (struct node *np, int *p, int mod)
113{
114 if (protocol_version == 2)
115 return register_fresh_stat (np, p);
116 else
117 {
118 int attrs_exist;
119
120 /* First the pre_op_attr */
121 attrs_exist = ntohl (*p);
122 p++;
123 if (attrs_exist)
124 {
125 /* Just skip them for now */
126 p += 2 * sizeof (int); /* size */
127 p += 2 * sizeof (int); /* mtime */
128 p += 2 * sizeof (int); /* atime */
129 }
130
131 /* Now the post_op_attr */
132 return process_returned_stat (np, p, mod);
133 }
134}
135
136
137/* Implement the netfs_validate_stat callback as described in
138 <hurd/netfs.h>. */
139error_t
140netfs_validate_stat (struct node *np, struct iouser *cred)
141{
142 int *p;
143 void *rpcbuf;
144 error_t err;
145
146 if (mapped_time->seconds - np->nn->stat_updated < stat_timeout)
147 return 0;
148
149 p = nfs_initialize_rpc (NFSPROC_GETATTR (protocol_version)(protocol_version == 2 ? 1 : 1),
150 (struct iouser *) -1, 0, &rpcbuf, np, -1);
151 if (! p)
152 return errno(*__errno_location ());
153
154 p = xdr_encode_fhandle (p, &np->nn->handle);
155
156 err = conduct_rpc (&rpcbuf, &p);
157 if (!err)
158 {
159 err = nfs_error_trans (ntohl (*p));
160 p++;
161 }
162 if (!err)
163 register_fresh_stat (np, p);
164
165 free (rpcbuf);
166 return err;
167}
168
169/* Implement the netfs_attempt_chown callback as described in
170 <hurd/netfs.h>. */
171error_t
172netfs_attempt_chown (struct iouser *cred, struct node *np,
173 uid_t uid, gid_t gid)
174{
175 int *p;
176 void *rpcbuf;
177 error_t err;
178
179 p = nfs_initialize_rpc (NFSPROC_SETATTR (protocol_version)(protocol_version == 2 ? 2 : 2),
180 cred, 0, &rpcbuf, np, gid);
181 if (! p)
182 return errno(*__errno_location ());
183
184 p = xdr_encode_fhandle (p, &np->nn->handle);
185 p = xdr_encode_sattr_ids (p, uid, gid);
186 if (protocol_version == 3)
187 *(p++) = 0; /* guard_check == 0 */
188
189 err = conduct_rpc (&rpcbuf, &p);
190 if (!err)
191 {
192 err = nfs_error_trans (ntohl (*p));
193 p++;
194 if (!err || protocol_version == 3)
195 p = process_wcc_stat (np, p, !err);
196 }
197
198 free (rpcbuf);
199
200 return err;
201}
202
203/* Implement the netfs_attempt_chauthor callback as described in
204 <hurd/netfs.h>. */
205error_t
206netfs_attempt_chauthor (struct iouser *cred, struct node *rp,
207 uid_t author)
208{
209 return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff));
210}
211
212/* Implement the netfs_attempt_chmod callback as described in
213 <hurd/netfs.h>. */
214error_t
215netfs_attempt_chmod (struct iouser *cred, struct node *np,
216 mode_t mode)
217{
218 int *p;
219 void *rpcbuf;
220 error_t err;
221
222 if ((mode & S_IFMT0170000) != 0)
223 {
224 err = netfs_validate_stat (np, cred);
225 if (err)
226 return err;
227
228 /* Has the file type changed? (e.g. from symlink to
229 directory). */
230 if ((mode & S_IFMT0170000) != (np->nn_stat.st_mode & S_IFMT0170000))
231 {
232 char *f = 0;
233
234 if (np->nn->dtrans == NOT_POSSIBLE)
235 return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff));
236
237 if (np->nn->dtrans == SYMLINK)
238 f = np->nn->transarg.name;
239
240 switch (mode & S_IFMT0170000)
241 {
242 default:
243 return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff));
244
245 case S_IFIFO0010000:
246 np->nn->dtrans = FIFO;
247 np->nn->stat_updated = 0;
248 break;
249
250 case S_IFSOCK0140000:
251 np->nn->dtrans = SOCK;
252 np->nn->stat_updated = 0;
253 }
254 if (f)
255 free (f);
256 return 0;
257 }
258 }
259
260 p = nfs_initialize_rpc (NFSPROC_SETATTR (protocol_version)(protocol_version == 2 ? 2 : 2),
261 cred, 0, &rpcbuf, np, -1);
262 if (! p)
263 return errno(*__errno_location ());
264
265 p = xdr_encode_fhandle (p, &np->nn->handle);
266 p = xdr_encode_sattr_mode (p, mode);
267 if (protocol_version == 3)
268 *(p++) = 0; /* guard check == 0 */
269
270 err = conduct_rpc (&rpcbuf, &p);
271 if (!err)
272 {
273 err = nfs_error_trans (ntohl (*p));
274 p++;
275 if (!err || protocol_version == 3)
276 p = process_wcc_stat (np, p, !err);
277 }
278
279 free (rpcbuf);
280 return err;
281}
282
283/* Implement the netfs_attempt_chflags callback as described in
284 <hurd/netfs.h>. */
285error_t
286netfs_attempt_chflags (struct iouser *cred, struct node *np,
287 int flags)
288{
289 return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff));
290}
291
292/* Implement the netfs_attempt_utimes callback as described in
293 <hurd/netfs.h>. */
294error_t
295netfs_attempt_utimes (struct iouser *cred, struct node *np,
296 struct timespec *atime, struct timespec *mtime)
297{
298 int *p;
299 void *rpcbuf;
300 error_t err;
301 struct timeval tv;
302 struct timespec current;
303
304 /* XXX For version 3 we can actually do this right, but we don't
305 just yet. */
306 if (!atime || !mtime)
307 {
308 maptime_read (mapped_time, &tv);
309 current.tv_sec = tv.tv_sec;
310 current.tv_nsec = tv.tv_usec * 1000;
311 }
312
313 p = nfs_initialize_rpc (NFSPROC_SETATTR (protocol_version)(protocol_version == 2 ? 2 : 2),
314 cred, 0, &rpcbuf, np, -1);
315 if (! p)
316 return errno(*__errno_location ());
317
318 p = xdr_encode_fhandle (p, &np->nn->handle);
319 p = xdr_encode_sattr_times (p,
320 atime ?: &current,
321 mtime ?: &current);
322 if (protocol_version == 3)
323 *(p++) = 0; /* guard check == 0 */
324
325 err = conduct_rpc (&rpcbuf, &p);
326 if (!err)
327 {
328 err = nfs_error_trans (ntohl (*p));
329 p++;
330 if (!err || protocol_version == 3)
331 p = process_wcc_stat (np, p, !err);
332 }
333
334 free (rpcbuf);
335 return err;
336}
337
338/* Implement the netfs_attempt_set_size callback as described in
339 <hurd/netfs.h>. */
340error_t
341netfs_attempt_set_size (struct iouser *cred, struct node *np,
342 off_t size)
343{
344 int *p;
345 void *rpcbuf;
346 error_t err;
347
348 p = nfs_initialize_rpc (NFSPROC_SETATTR (protocol_version)(protocol_version == 2 ? 2 : 2),
349 cred, 0, &rpcbuf, np, -1);
350 if (! p)
351 return errno(*__errno_location ());
352
353 p = xdr_encode_fhandle (p, &np->nn->handle);
354 p = xdr_encode_sattr_size (p, size);
355 if (protocol_version == 3)
356 *(p++) = 0; /* guard_check == 0 */
357
358 err = conduct_rpc (&rpcbuf, &p);
359 if (!err)
360 {
361 err = nfs_error_trans (ntohl (*p));
362 p++;
363 if (!err || protocol_version == 3)
364 p = process_wcc_stat (np, p, !err);
365 }
366
367 /* If we got EACCES, but the user has the file open for writing,
368 then the NFS protocol has screwed us. There's nothing we can do,
369 except in the important case of opens with
370 O_TRUNC|O_CREAT|O_WRONLY|O_EXCL where the new mode does not allow
371 writing. RCS, for example, uses this to create lock files. So permit
372 cases where the O_TRUNC isn't doing anything to succeed if the user
373 does have the file open for writing. */
374 if (err == EACCES((0x10 << 26) | ((13) & 0x3fff)))
375 {
376 int error = netfs_validate_stat (np, cred);
377 if (!error && np->nn_stat.st_size == size)
378 err = 0;
379 }
380
381 free (rpcbuf);
382 return err;
383}
384
385/* Implement the netfs_attempt_statfs callback as described in
386 <hurd/netfs.h>. */
387error_t
388netfs_attempt_statfs (struct iouser *cred, struct node *np,
389 struct statfs *st)
390{
391 int *p;
392 void *rpcbuf;
393 error_t err;
394
395 p = nfs_initialize_rpc (NFS2PROC_STATFS17, cred, 0, &rpcbuf, np, -1);
396 if (! p)
397 return errno(*__errno_location ());
398
399 p = xdr_encode_fhandle (p, &np->nn->handle);
400
401 err = conduct_rpc (&rpcbuf, &p);
402 if (!err)
403 {
404 err = nfs_error_trans (ntohl (*p));
405 p++;
406 }
407
408 if (!err)
409 {
410 p++; /* skip IOSIZE field */
411 st->f_bsize = ntohl (*p);
412 p++;
413 st->f_blocks = ntohl (*p);
414 p++;
415 st->f_bfree = ntohl (*p);
416 p++;
417 st->f_bavail = ntohl (*p);
418 p++;
419 st->f_type = FSTYPE_NFS0x00000001;
420 st->f_files = 0;
421 st->f_ffree = 0;
422 st->f_fsid = getpid ();
423 st->f_namelen = 0;
424 }
425
426 free (rpcbuf);
427 return err;
428}
429
430/* Implement the netfs_attempt_sync callback as described in
431 <hurd/netfs.h>. */
432error_t
433netfs_attempt_sync (struct iouser *cred, struct node *np, int wait)
434{
435 /* We are already completely synchronous. */
436 return 0;
437}
438
439/* Implement the netfs_attempt_syncfs callback as described in
440 <hurd/netfs.h>. */
441error_t
442netfs_attempt_syncfs (struct iouser *cred, int wait)
443{
444 return 0;
445}
446
447/* Implement the netfs_attempt_read callback as described in
448 <hurd/netfs.h>. */
449error_t
450netfs_attempt_read (struct iouser *cred, struct node *np,
451 off_t offset, size_t *len, void *data)
452{
453 int *p;
454 void *rpcbuf;
455 size_t trans_len;
456 error_t err;
457 size_t amt, thisamt;
458 int eof;
459
460 for (amt = *len; amt;)
461 {
462 thisamt = amt;
463 if (thisamt > read_size)
464 thisamt = read_size;
465
466 p = nfs_initialize_rpc (NFSPROC_READ (protocol_version)(protocol_version == 2 ? 6 : 6),
467 cred, 0, &rpcbuf, np, -1);
468 if (! p)
469 return errno(*__errno_location ());
470
471 p = xdr_encode_fhandle (p, &np->nn->handle);
472 *(p++) = htonl (offset);
473 *(p++) = htonl (thisamt);
474 if (protocol_version == 2)
475 *(p++) = 0;
476
477 err = conduct_rpc (&rpcbuf, &p);
478 if (!err)
479 {
480 err = nfs_error_trans (ntohl (*p));
481 p++;
482
483 if (!err || protocol_version == 3)
484 p = process_returned_stat (np, p, !err);
485
486 if (err)
487 {
488 free (rpcbuf);
489 return err;
490 }
491
492 trans_len = ntohl (*p);
493 p++;
494 if (trans_len > thisamt)
495 trans_len = thisamt; /* ??? */
496
497 if (protocol_version == 3)
498 {
499 eof = ntohl (*p);
500 p++;
501 }
502 else
503 eof = (trans_len < thisamt);
504
505 memcpy (data, p, trans_len);
506 free (rpcbuf);
507
508 data += trans_len;
509 offset += trans_len;
510 amt -= trans_len;
511
512 if (eof)
513 {
514 *len -= amt;
515 return 0;
516 }
517 }
518 }
519 return 0;
520}
521
522/* Implement the netfs_attempt_write callback as described in
523 <hurd/netfs.h>. */
524error_t
525netfs_attempt_write (struct iouser *cred, struct node *np,
526 off_t offset, size_t *len, void *data)
527{
528 int *p;
529 void *rpcbuf;
530 error_t err;
531 size_t amt, thisamt;
532 size_t count;
533
534 for (amt = *len; amt;)
535 {
536 thisamt = amt;
537 if (thisamt > write_size)
538 thisamt = write_size;
539
540 p = nfs_initialize_rpc (NFSPROC_WRITE (protocol_version)(protocol_version == 2 ? 8 : 7),
541 cred, thisamt, &rpcbuf, np, -1);
542 if (! p)
543 return errno(*__errno_location ());
544
545 p = xdr_encode_fhandle (p, &np->nn->handle);
546 if (protocol_version == 2)
547 *(p++) = 0;
548 *(p++) = htonl (offset);
549 if (protocol_version == 2)
550 *(p++) = 0;
551 if (protocol_version == 3)
552 *(p++) = htonl (FILE_SYNC);
553 p = xdr_encode_data (p, data, thisamt);
554
555 err = conduct_rpc (&rpcbuf, &p);
556 if (!err)
557 {
558 err = nfs_error_trans (ntohl (*p));
559 p++;
560 if (!err || protocol_version == 3)
561 p = process_wcc_stat (np, p, !err);
562 if (!err)
563 {
564 if (protocol_version == 3)
565 {
566 count = ntohl (*p);
567 p++;
568 p++; /* ignore COMMITTED */
569 /* ignore verf for now */
570 p += NFS3_WRITEVERFSIZE8 / sizeof (int);
571 }
572 else
573 /* assume it wrote the whole thing */
574 count = thisamt;
575
576 amt -= count;
577 data += count;
578 offset += count;
579 }
580 }
581
582 free (rpcbuf);
583
584 if (err == EINTR((0x10 << 26) | ((4) & 0x3fff)) && amt != *len)
585 {
586 *len -= amt;
587 return 0;
588 }
589
590 if (err)
591 {
592 *len = 0;
593 return err;
594 }
595 }
596 return 0;
597}
598
599/* See if NAME exists in DIR for CRED. If so, return EEXIST. */
600error_t
601verify_nonexistent (struct iouser *cred, struct node *dir,
602 char *name)
603{
604 int *p;
605 void *rpcbuf;
606 error_t err;
607
608 /* Don't use the lookup cache for this; we want a full sync to
609 get as close to real exclusive create behavior as possible. */
610
611 assert (protocol_version == 2)((protocol_version == 2) ? (void) (0) : __assert_fail ("protocol_version == 2"
, "../../nfs/ops.c", 611, __PRETTY_FUNCTION__))
;
612
613 p = nfs_initialize_rpc (NFSPROC_LOOKUP (protocol_version)(protocol_version == 2 ? 4 : 3),
614 cred, 0, &rpcbuf, dir, -1);
615 if (! p)
616 return errno(*__errno_location ());
617
618 p = xdr_encode_fhandle (p, &dir->nn->handle);
619 p = xdr_encode_string (p, name);
620
621 err = conduct_rpc (&rpcbuf, &p);
622 if (!err)
623 {
624 err = nfs_error_trans (ntohl (*p));
625 p++;
626 }
627
628 free (rpcbuf);
629
630 if (!err)
631 return EEXIST((0x10 << 26) | ((17) & 0x3fff));
632 else
633 return 0;
634}
635
636/* Implement the netfs_attempt_lookup callback as described in
637 <hurd/netfs.h>. */
638error_t
639netfs_attempt_lookup (struct iouser *cred, struct node *np,
640 char *name, struct node **newnp)
641{
642 int *p;
643 void *rpcbuf;
644 error_t err;
645 char dirhandle[NFS3_FHSIZE64];
646 size_t dirlen;
647
648 /* Check the cache first. */
649 *newnp = check_lookup_cache (np, name);
650 if (*newnp)
651 {
652 if (*newnp == (struct node *) -1)
653 {
654 *newnp = 0;
655 return ENOENT((0x10 << 26) | ((2) & 0x3fff));
656 }
657 else
658 return 0;
659 }
660
661 p = nfs_initialize_rpc (NFSPROC_LOOKUP (protocol_version)(protocol_version == 2 ? 4 : 3),
662 cred, 0, &rpcbuf, np, -1);
663 if (! p)
664 return errno(*__errno_location ());
665
666 p = xdr_encode_fhandle (p, &np->nn->handle);
667 p = xdr_encode_string (p, name);
668
669 /* Remember the directory handle for later cache use. */
670
671 dirlen = np->nn->handle.size;
672 memcpy (dirhandle, np->nn->handle.data, dirlen);
673
674 pthread_mutex_unlock (&np->lock);
675
676 err = conduct_rpc (&rpcbuf, &p);
677 if (!err)
678 {
679 err = nfs_error_trans (ntohl (*p));
680 p++;
681 if (!err)
682 {
683 p = xdr_decode_fhandle (p, newnp);
684 p = process_returned_stat (*newnp, p, 1);
685 }
686 if (err)
687 *newnp = 0;
688 if (protocol_version == 3)
689 {
690 if (*newnp)
691 pthread_mutex_unlock (&(*newnp)->lock);
692 pthread_mutex_lock (&np->lock);
693 p = process_returned_stat (np, p, 0); /* XXX Do we have to lock np? */
694 pthread_mutex_unlock (&np->lock);
695 if (*newnp)
696 pthread_mutex_lock (&(*newnp)->lock);
697 }
698 }
699 else
700 *newnp = 0;
701
702 /* Notify the cache of the hit or miss. */
703 enter_lookup_cache (dirhandle, dirlen, *newnp, name);
704
705 free (rpcbuf);
706
707 return err;
708}
709
710/* Implement the netfs_attempt_mkdir callback as described in
711 <hurd/netfs.h>. */
712error_t
713netfs_attempt_mkdir (struct iouser *cred, struct node *np,
714 char *name, mode_t mode)
715{
716 int *p;
717 void *rpcbuf;
718 error_t err;
719 uid_t owner;
720 struct node *newnp;
721
722 if (cred->uids->num)
723 owner = cred->uids->ids[0];
724 else
725 {
726 err = netfs_validate_stat (np, cred);
727 owner = err ? 0 : np->nn_stat.st_uid;
728 mode &= ~S_ISUID04000;
729 }
730
731 purge_lookup_cache (np, name, strlen (name));
732
733 p = nfs_initialize_rpc (NFSPROC_MKDIR (protocol_version)(protocol_version == 2 ? 14 : 9),
734 cred, 0, &rpcbuf, np, -1);
735 if (! p)
736 return errno(*__errno_location ());
737
738 p = xdr_encode_fhandle (p, &np->nn->handle);
739 p = xdr_encode_string (p, name);
740 p = xdr_encode_create_state (p, mode, owner);
741
742 err = conduct_rpc (&rpcbuf, &p);
743 if (!err)
744 {
745 err = nfs_error_trans (ntohl (*p));
746 p++;
747 }
748
749 if (!err)
750 {
751 p = xdr_decode_fhandle (p, &newnp);
752 p = process_returned_stat (newnp, p, 1);
753
754 /* Did we set the owner correctly? If not, try, but ignore failures. */
755 if (!netfs_validate_stat (newnp, (struct iouser *) -1)
756 && newnp->nn_stat.st_uid != owner)
757 netfs_attempt_chown ((struct iouser *) -1, newnp, owner,
758 newnp->nn_stat.st_gid);
759
760 /* We don't actually return this. */
761 netfs_nput (newnp);
762 }
763
764 free (rpcbuf);
765 return err;
766}
767
768/* Implement the netfs_attempt_rmdir callback as described in
769 <hurd/netfs.h>. */
770error_t
771netfs_attempt_rmdir (struct iouser *cred, struct node *np,
772 char *name)
773{
774 int *p;
775 void *rpcbuf;
776 error_t err;
777
778 /* Should we do the same sort of thing here as with attempt_unlink? */
779
780 purge_lookup_cache (np, name, strlen (name));
781
782 p = nfs_initialize_rpc (NFSPROC_RMDIR (protocol_version)(protocol_version == 2 ? 15 : 13),
783 cred, 0, &rpcbuf, np, -1);
784 if (! p)
785 return errno(*__errno_location ());
786
787 p = xdr_encode_fhandle (p, &np->nn->handle);
788 p = xdr_encode_string (p, name);
789
790 err = conduct_rpc (&rpcbuf, &p);
791 if (!err)
792 {
793 err = nfs_error_trans (ntohl (*p));
794 p++;
795 if (protocol_version == 3)
796 p = process_wcc_stat (np, p, !err);
797 }
798
799 free (rpcbuf);
800 return err;
801}
802
803/* Implement the netfs_attempt_link callback as described in
804 <hurd/netfs.h>. */
805error_t
806netfs_attempt_link (struct iouser *cred, struct node *dir,
807 struct node *np, char *name, int excl)
808{
809 int *p;
810 void *rpcbuf;
811 error_t err = 0;
812
813 if (!excl)
814 {
815 /* We have no RPC available that will do an atomic replacement,
816 so we settle for second best; just doing an unlink and ignoring
817 any errors. */
818 pthread_mutex_lock (&dir->lock);
819 netfs_attempt_unlink (cred, dir, name);
820 pthread_mutex_unlock (&dir->lock);
821 }
822
823 /* If we have postponed a translator setting on an unlinked node,
824 then here's where we set it, by creating the new node instead of
825 doing a normal link. */
826
827 switch (np->nn->dtrans)
828 {
829 case POSSIBLE:
830 case NOT_POSSIBLE:
831 pthread_mutex_lock (&dir->lock);
832 p = nfs_initialize_rpc (NFSPROC_LINK (protocol_version)(protocol_version == 2 ? 12 : 15),
833 cred, 0, &rpcbuf, dir, -1);
834 if (! p)
835 {
836 pthread_mutex_unlock (&dir->lock);
837 return errno(*__errno_location ());
838 }
839
840 pthread_mutex_unlock (&dir->lock);
841
842 pthread_mutex_lock (&np->lock);
843 p = xdr_encode_fhandle (p, &np->nn->handle);
844 pthread_mutex_unlock (&np->lock);
845
846 pthread_mutex_lock (&dir->lock);
847 purge_lookup_cache (dir, name, strlen (name));
848
849 p = xdr_encode_fhandle (p, &dir->nn->handle);
850 p = xdr_encode_string (p, name);
851
852 err = conduct_rpc (&rpcbuf, &p);
853 if (!err)
854 {
855 err = nfs_error_trans (ntohl (*p));
856 p++;
857 }
858 pthread_mutex_unlock (&dir->lock);
859
860 free (rpcbuf);
861
862 break;
863
864 case SYMLINK:
865 pthread_mutex_lock (&dir->lock);
866 p = nfs_initialize_rpc (NFSPROC_SYMLINK (protocol_version)(protocol_version == 2 ? 13 : 10),
867 cred, 0, &rpcbuf, dir, -1);
868 if (! p)
869 {
870 pthread_mutex_unlock (&dir->lock);
871 return errno(*__errno_location ());
872 }
873
874 p = xdr_encode_fhandle (p, &dir->nn->handle);
875 pthread_mutex_unlock (&dir->lock);
876
877 p = xdr_encode_string (p, name);
878
879 pthread_mutex_lock (&np->lock);
880 err = netfs_validate_stat (np, cred);
881 if (err)
882 {
883 pthread_mutex_unlock (&np->lock);
884 free (rpcbuf);
885 return err;
886 }
887
888 if (protocol_version == 2)
889 {
890 p = xdr_encode_string (p, np->nn->transarg.name);
891 p = xdr_encode_sattr_stat (p, &np->nn_stat);
892 }
893 else
894 {
895 p = xdr_encode_sattr_stat (p, &np->nn_stat);
896 p = xdr_encode_string (p, np->nn->transarg.name);
897 }
898 pthread_mutex_unlock (&np->lock);
899
900 pthread_mutex_lock (&dir->lock);
901
902 purge_lookup_cache (dir, name, strlen (name));
903 err = conduct_rpc (&rpcbuf, &p);
904 if (!err)
905 {
906 err = nfs_error_trans (ntohl (*p));
907 p++;
908
909 if (protocol_version == 2 && !err)
910 {
911 free (rpcbuf);
912
913 /* NFSPROC_SYMLINK stupidly does not pass back an
914 fhandle, so we have to fetch one now. */
915 p = nfs_initialize_rpc (NFSPROC_LOOKUP (protocol_version)(protocol_version == 2 ? 4 : 3),
916 cred, 0, &rpcbuf, dir, -1);
917 if (! p)
918 {
919 pthread_mutex_unlock (&dir->lock);
920 return errno(*__errno_location ());
921 }
922 p = xdr_encode_fhandle (p, &dir->nn->handle);
923 p = xdr_encode_string (p, name);
924
925 pthread_mutex_unlock (&dir->lock);
926
927 err = conduct_rpc (&rpcbuf, &p);
928 if (!err)
929 {
930 err = nfs_error_trans (ntohl (*p));
931 p++;
932 }
933 if (!err)
934 {
935 pthread_mutex_lock (&np->lock);
936 p = recache_handle (p, np);
937 p = process_returned_stat (np, p, 1);
938 pthread_mutex_unlock (&np->lock);
939 }
940 if (err)
941 err = EGRATUITOUS((0x10 << 26) | ((105) & 0x3fff)); /* damn */
942 }
943 else if (protocol_version == 3)
944 {
945 if (!err)
946 {
947 pthread_mutex_unlock (&dir->lock);
948 pthread_mutex_lock (&np->lock);
949 p = recache_handle (p, np);
950 p = process_returned_stat (np, p, 1);
951 pthread_mutex_unlock (&np->lock);
952 pthread_mutex_lock (&dir->lock);
953 }
954 p = process_wcc_stat (dir, p, !err);
955 pthread_mutex_unlock (&dir->lock);
956 }
957 else
958 pthread_mutex_unlock (&dir->lock);
959 }
960 else
961 pthread_mutex_unlock (&dir->lock);
962
963 free (rpcbuf);
964 break;
965
966 case CHRDEV:
967 case BLKDEV:
968 case FIFO:
969 case SOCK:
970
971 if (protocol_version == 2)
972 {
973 pthread_mutex_lock (&dir->lock);
974 err = verify_nonexistent (cred, dir, name);
975 if (err)
976 return err;
977
978 p = nfs_initialize_rpc (NFSPROC_CREATE (protocol_version)(protocol_version == 2 ? 9 : 8),
979 cred, 0, &rpcbuf, dir, -1);
980 if (! p)
981 {
982 pthread_mutex_unlock (&dir->lock);
983 return errno(*__errno_location ());
984 }
985
986 p = xdr_encode_fhandle (p, &dir->nn->handle);
987 p = xdr_encode_string (p, name);
988 pthread_mutex_unlock (&dir->lock);
989
990 pthread_mutex_lock (&np->lock);
991 err = netfs_validate_stat (np, cred);
992 if (err)
993 {
994 pthread_mutex_unlock (&np->lock);
995 free (rpcbuf);
996 return err;
997 }
998
999 p = xdr_encode_sattr_stat (p, &np->nn_stat);
1000 pthread_mutex_unlock (&np->lock);
1001
1002 pthread_mutex_lock (&dir->lock);
1003 purge_lookup_cache (dir, name, strlen (name));
1004 pthread_mutex_unlock (&dir->lock); /* XXX Should this really be after the
1005 _lengthy_ (blocking) conduct_rpc? */
1006 err = conduct_rpc (&rpcbuf, &p);
1007 if (!err)
1008 {
1009 err = nfs_error_trans (ntohl (*p));
1010 p++;
1011 }
1012
1013 if (!err)
1014 {
1015 pthread_mutex_lock (&np->lock);
1016 p = recache_handle (p, np);
1017 register_fresh_stat (np, p);
1018 pthread_mutex_unlock (&np->lock);
1019 }
1020
1021 free (rpcbuf);
1022 }
1023 else /* protocol_version != 2 */
1024 {
1025 pthread_mutex_lock (&dir->lock);
1026 p = nfs_initialize_rpc (NFS3PROC_MKNOD11, cred, 0, &rpcbuf, dir, -1);
1027 if (! p)
1028 {
1029 pthread_mutex_unlock (&dir->lock);
1030 return errno(*__errno_location ());
1031 }
1032 p = xdr_encode_fhandle (p, &dir->nn->handle);
1033 p = xdr_encode_string (p, name);
1034 pthread_mutex_unlock (&dir->lock);
1035
1036 pthread_mutex_lock (&np->lock);
1037 err = netfs_validate_stat (np, cred);
1038 if (err)
1039 {
1040 pthread_mutex_unlock (&np->lock);
1041 free (rpcbuf);
1042 return err;
1043 }
1044 *(p++) = htonl (hurd_mode_to_nfs_type (np->nn_stat.st_mode));
1045 p = xdr_encode_sattr_stat (p, &np->nn_stat);
1046 if (np->nn->dtrans == BLKDEV || np->nn->dtrans == CHRDEV)
1047 {
1048 *(p++) = htonl (major (np->nn_stat.st_rdev)((int)(((unsigned int) (np->nn_stat.st_rdev) >> 8) &
0xff))
);
1049 *(p++) = htonl (minor (np->nn_stat.st_rdev)((int)((np->nn_stat.st_rdev) & 0xff)));
1050 }
1051 pthread_mutex_unlock (&np->lock);
1052
1053 purge_lookup_cache (dir, name, strlen (name));
1054 err = conduct_rpc (&rpcbuf, &p);
1055 if (!err)
1056 {
1057 err = nfs_error_trans (ntohl (*p));
1058 p++;
1059
1060 if (!err)
1061 {
1062 pthread_mutex_lock (&np->lock);
1063 p = recache_handle (p, np);
1064 p = process_returned_stat (np, p, 1);
1065 pthread_mutex_unlock (&np->lock);
1066 }
1067 pthread_mutex_lock (&dir->lock);
1068 p = process_wcc_stat (dir, p, !err);
1069 pthread_mutex_unlock (&dir->lock);
1070 }
1071 free (rpcbuf);
1072 }
1073 break;
1074 }
1075
1076 if (err)
1077 return err;
1078
1079 pthread_mutex_lock (&np->lock);
1080
1081 if (np->nn->dtrans == SYMLINK)
1082 free (np->nn->transarg.name);
1083 np->nn->dtrans = NOT_POSSIBLE;
1084
1085 /* If there is a dead-dir tag lying around, it's time to delete it now. */
1086 if (np->nn->dead_dir)
1087 {
1088 struct node *dir = np->nn->dead_dir;
1089 char *name = np->nn->dead_name;
1090 np->nn->dead_dir = 0;
1091 np->nn->dead_name = 0;
1092 pthread_mutex_unlock (&np->lock);
1093
1094 pthread_mutex_lock (&dir->lock);
1095 netfs_attempt_unlink ((struct iouser *)-1, dir, name);
1096 pthread_mutex_unlock (&dir->lock);
1097 }
1098 else
1099 pthread_mutex_unlock (&np->lock);
1100
1101 return 0;
1102}
1103
1104/* Implement the netfs_attempt_mkfile callback as described in
1105 <hurd/netfs.h>. */
1106error_t
1107netfs_attempt_mkfile (struct iouser *cred, struct node *dir,
1108 mode_t mode, struct node **newnp)
1109{
1110 error_t err;
1111 char *name;
1112 static int n = 0;
1113
1114 /* This is the best we can do. */
1115
1116 name = malloc (50);
1117 if (! name)
1118 return ENOMEM((0x10 << 26) | ((12) & 0x3fff));
1119
1120 do
1121 {
1122 sprintf (name, ".nfstmpgnu.%d", n++);
1123 err = netfs_attempt_create_file (cred, dir, name, mode, newnp);
1124 if (err == EEXIST((0x10 << 26) | ((17) & 0x3fff)))
1125 pthread_mutex_lock (&dir->lock); /* XXX is this right? does create need this
1126 and drop this on error? Doesn't look
1127 like it. */
1128 }
1129 while (err == EEXIST((0x10 << 26) | ((17) & 0x3fff)));
1130
1131 if (err)
1132 {
1133 free (name);
1134 return err;
1135 }
1136
1137 assert (!(*newnp)->nn->dead_dir)((!(*newnp)->nn->dead_dir) ? (void) (0) : __assert_fail
("!(*newnp)->nn->dead_dir", "../../nfs/ops.c", 1137, __PRETTY_FUNCTION__
))
;
1138 assert (!(*newnp)->nn->dead_name)((!(*newnp)->nn->dead_name) ? (void) (0) : __assert_fail
("!(*newnp)->nn->dead_name", "../../nfs/ops.c", 1138, __PRETTY_FUNCTION__
))
;
1139 netfs_nref (dir);
1140 (*newnp)->nn->dead_dir = dir;
1141 (*newnp)->nn->dead_name = name;
1142 if ((*newnp)->nn->dtrans == NOT_POSSIBLE)
1143 (*newnp)->nn->dtrans = POSSIBLE;
1144 return 0;
1145}
1146
1147/* Implement the netfs_attempt_create_file callback as described in
1148 <hurd/netfs.h>. */
1149error_t
1150netfs_attempt_create_file (struct iouser *cred, struct node *np,
1151 char *name, mode_t mode, struct node **newnp)
1152{
1153 int *p;
1154 void *rpcbuf;
1155 error_t err;
1156 uid_t owner;
1157
1158 if (cred->uids->num)
1159 owner = cred->uids->ids[0];
1160 else
1161 {
1162 err = netfs_validate_stat (np, cred);
1163 owner = err ? 0 : np->nn_stat.st_uid;
1164 mode &= ~S_ISUID04000;
1165 }
1166
1167 /* RFC 1094 says that create is always exclusive. But Sun doesn't
1168 actually *implement* the spec. No, of course not. So we have to do
1169 it for them. */
1170 if (protocol_version == 2)
1171 {
1172 err = verify_nonexistent (cred, np, name);
1173 if (err)
1174 {
1175 pthread_mutex_unlock (&np->lock);
1176 return err;
1177 }
1178 }
1179
1180 purge_lookup_cache (np, name, strlen (name));
1181
1182 p = nfs_initialize_rpc (NFSPROC_CREATE (protocol_version)(protocol_version == 2 ? 9 : 8),
1183 cred, 0, &rpcbuf, np, -1);
1184 if (! p)
1185 return errno(*__errno_location ());
1186
1187 p = xdr_encode_fhandle (p, &np->nn->handle);
1188 p = xdr_encode_string (p, name);
1189 if (protocol_version == 3)
1190 {
1191 /* We happen to know this is where the XID is. */
1192 int verf = *(int *)rpcbuf;
1193
1194 *(p++) = ntohl (EXCLUSIVE);
1195 /* 8 byte verf */
1196 *(p++) = ntohl (verf);
1197 p++;
1198 }
1199 else
1200 p = xdr_encode_create_state (p, mode, owner);
1201
1202 err = conduct_rpc (&rpcbuf, &p);
1203
1204 pthread_mutex_unlock (&np->lock);
1205
1206 if (!err)
1207 {
1208 err = nfs_error_trans (ntohl (*p));
1209 p++;
1210 if (!err)
1211 {
1212 p = xdr_decode_fhandle (p, newnp);
1213 p = process_returned_stat (*newnp, p, 1);
1214 }
1215 if (err)
1216 *newnp = 0;
1217 if (protocol_version == 3)
1218 {
1219 if (*newnp)
1220 pthread_mutex_unlock (&(*newnp)->lock);
1221 pthread_mutex_lock (&np->lock);
1222 p = process_wcc_stat (np, p, 1);
1223 pthread_mutex_unlock (&np->lock);
1224 if (*newnp)
1225 pthread_mutex_lock (&(*newnp)->lock);
1226 }
1227
1228 if (*newnp && !netfs_validate_stat (*newnp, (struct iouser *) -1)
1229 && (*newnp)->nn_stat.st_uid != owner)
1230 netfs_attempt_chown ((struct iouser *) -1, *newnp, owner, (*newnp)->nn_stat.st_gid);
1231 }
1232 else
1233 *newnp = 0;
1234
1235 free (rpcbuf);
1236 return err;
1237}
1238
1239/* Implement the netfs_attempt_unlink callback as described in
1240 <hurd/netfs.h>. */
1241error_t
1242netfs_attempt_unlink (struct iouser *cred, struct node *dir,
1243 char *name)
1244{
1245 int *p;
1246 void *rpcbuf;
1247 error_t err;
1248 struct node *np;
1249
1250 /* First lookup the node being removed */
1251 err = netfs_attempt_lookup (cred, dir, name, &np);
1252 if (err)
1253 {
1254 pthread_mutex_lock (&dir->lock);
1255 return err;
1256 }
1257
1258 /* Restore the locks to sanity. */
1259 pthread_mutex_unlock (&np->lock);
1260 pthread_mutex_lock (&dir->lock);
1261
1262 /* Purge the cache of entries for this node, so that we don't
1263 regard cache-held references as live. */
1264 purge_lookup_cache_node (np);
1265
1266 /* See if there are any other users of this node than the
1267 one we just got; if so, we must give this file another link
1268 so that when we delete the one we are asked for it doesn't go
1269 away entirely. */
1270 if (np->references > 1)
1271 {
1272 char *newname = 0;
1273 int n = 0;
1274
1275 pthread_mutex_unlock (&dir->lock);
1276
1277 newname = malloc (50);
1278 if (! newname)
1279 {
1280 pthread_mutex_lock (&dir->lock);
1281 netfs_nrele (np); /* XXX Is this the correct thing to do? */
1282 return ENOMEM((0x10 << 26) | ((12) & 0x3fff));
1283 }
1284
1285 do
1286 {
1287 sprintf (newname, ".nfs%txgnu.%d", (ptrdiff_t) np, n++);
1288 err = netfs_attempt_link (cred, dir, np, newname, 1);
1289 }
1290 while (err == EEXIST((0x10 << 26) | ((17) & 0x3fff)));
1291
1292 if (err)
1293 {
1294 free (newname);
1295 pthread_mutex_lock (&dir->lock);
1296 netfs_nrele (np);
1297 return err;
1298 }
1299
1300 /* Write down what name we gave it; we'll delete this when all
1301 our uses vanish. */
1302 pthread_mutex_lock (&np->lock);
1303
1304 if (np->nn->dead_dir)
1305 netfs_nrele (np->nn->dead_dir);
1306 netfs_nref (dir);
1307 np->nn->dead_dir = dir;
1308 if (np->nn->dead_name)
1309 free (np->nn->dead_name);
1310 np->nn->dead_name = newname;
1311 if (np->nn->dtrans == NOT_POSSIBLE)
1312 np->nn->dtrans = POSSIBLE;
1313
1314 netfs_nput (np);
1315 pthread_mutex_lock (&dir->lock);
1316 }
1317 else
1318 netfs_nrele (np);
1319
1320 p = nfs_initialize_rpc (NFSPROC_REMOVE (protocol_version)(protocol_version == 2 ? 10 : 12),
1321 cred, 0, &rpcbuf, dir, -1);
1322 if (! p)
1323 return errno(*__errno_location ());
1324
1325 p = xdr_encode_fhandle (p, &dir->nn->handle);
1326 p = xdr_encode_string (p, name);
1327
1328 err = conduct_rpc (&rpcbuf, &p);
1329 if (!err)
1330 {
1331 err = nfs_error_trans (ntohl (*p));
1332 p++;
1333 if (protocol_version == 3)
1334 p = process_wcc_stat (dir, p, !err);
1335 }
1336
1337 free (rpcbuf);
1338
1339 return err;
1340}
1341
1342/* Implement the netfs_attempt_rename callback as described in
1343 <hurd/netfs.h>. */
1344error_t
1345netfs_attempt_rename (struct iouser *cred, struct node *fromdir,
1346 char *fromname, struct node *todir, char *toname,
1347 int excl)
1348{
1349 int *p;
1350 void *rpcbuf;
1351 error_t err;
1352
1353 if (excl)
1354 {
1355 struct node *np;
1356
1357 /* Just do a lookup/link/unlink sequence. */
1358
1359 pthread_mutex_lock (&fromdir->lock);
1360 err = netfs_attempt_lookup (cred, fromdir, fromname, &np);
1361 pthread_mutex_unlock (&fromdir->lock);
1362 if (err)
1363 return err;
1364
1365 err = netfs_attempt_link (cred, todir, np, toname, 1);
1366 netfs_nput (np);
1367 if (err)
1368 return err;
1369
1370 pthread_mutex_lock (&fromdir->lock);
1371 err = netfs_attempt_unlink (cred, fromdir, fromname);
1372 pthread_mutex_unlock (&fromdir->lock);
1373
1374 /* If the unlink failed, then back out the link */
1375 if (err)
1376 {
1377 pthread_mutex_lock (&todir->lock);
1378 netfs_attempt_unlink (cred, todir, toname);
1379 pthread_mutex_unlock (&todir->lock);
1380 return err;
1381 }
1382
1383 return 0;
1384 }
1385
1386 pthread_mutex_lock (&fromdir->lock);
1387 purge_lookup_cache (fromdir, fromname, strlen (fromname));
1388 p = nfs_initialize_rpc (NFSPROC_RENAME (protocol_version)(protocol_version == 2 ? 11 : 14),
1389 cred, 0, &rpcbuf, fromdir, -1);
1390 if (! p)
1391 {
1392 pthread_mutex_unlock (&fromdir->lock);
1393 return errno(*__errno_location ());
1394 }
1395
1396 p = xdr_encode_fhandle (p, &fromdir->nn->handle);
1397 p = xdr_encode_string (p, fromname);
1398 pthread_mutex_unlock (&fromdir->lock);
1399
1400 pthread_mutex_lock (&todir->lock);
1401 purge_lookup_cache (todir, toname, strlen (toname));
1402 p = xdr_encode_fhandle (p, &todir->nn->handle);
1403 p = xdr_encode_string (p, toname);
1404 pthread_mutex_unlock (&todir->lock);
1405
1406 err = conduct_rpc (&rpcbuf, &p);
1407 if (!err)
1408 {
1409 err = nfs_error_trans (ntohl (*p));
1410 p++;
1411 if (protocol_version == 3) /* XXX Should we add `&& !err' ? */
1412 {
1413 pthread_mutex_lock (&fromdir->lock);
1414 p = process_wcc_stat (fromdir, p, !err);
1415 p = process_wcc_stat (todir, p, !err);
1416 }
1417 }
1418
1419 free (rpcbuf);
1420 return err;
1421}
1422
1423/* Implement the netfs_attempt_readlink callback as described in
1424 <hurd/netfs.h>. */
1425error_t
1426netfs_attempt_readlink (struct iouser *cred, struct node *np,
1427 char *buf)
1428{
1429 int *p;
1430 void *rpcbuf;
1431 error_t err;
1432
1433 if (np->nn->dtrans == SYMLINK)
1434 {
1435 strcpy (buf, np->nn->transarg.name);
1436 return 0;
1437 }
1438
1439 p = nfs_initialize_rpc (NFSPROC_READLINK (protocol_version)(protocol_version == 2 ? 5 : 5),
1440 cred, 0, &rpcbuf, np, -1);
1441 if (! p)
1442 return errno(*__errno_location ());
1443
1444 p = xdr_encode_fhandle (p, &np->nn->handle);
1445
1446 err = conduct_rpc (&rpcbuf, &p);
1447 if (!err)
1448 {
1449 err = nfs_error_trans (ntohl (*p));
1450 p++;
1451 if (protocol_version == 3)
1452 p = process_returned_stat (np, p, 0);
1453 if (!err)
1454 p = xdr_decode_string (p, buf);
1455 }
1456
1457 free (rpcbuf);
1458 return err;
1459}
1460
1461/* Implement the netfs_check_open_permissions callback as described in
1462 <hurd/netfs.h>. */
1463error_t
1464netfs_check_open_permissions (struct iouser *cred, struct node *np,
1465 int flags, int newnode)
1466{
1467 int modes;
1468
1469 if (newnode || (flags & (O_READ0x0001|O_WRITE0x0002|O_EXEC0x0004)) == 0)
1470 return 0;
1471
1472 netfs_report_access (cred, np, &modes);
1473 if ((flags & (O_READ0x0001|O_WRITE0x0002|O_EXEC0x0004)) == (flags & modes))
1474 return 0;
1475 else
1476 return EACCES((0x10 << 26) | ((13) & 0x3fff));
1477}
1478
1479/* Implement the netfs_report_access callback as described in
1480 <hurd/netfs.h>. */
1481error_t
1482netfs_report_access (struct iouser *cred,
1483 struct node *np,
1484 int *types)
1485{
1486 error_t err;
1487
1488 err = netfs_validate_stat (np, cred);
1489 if (err)
1490 return err;
1491
1492 if (protocol_version == 2)
1493 {
1494 /* Hope the server means the same thing for the bits as we do. */
1495 *types = 0;
1496 if (fshelp_access (&np->nn_stat, S_IREAD00400, cred) == 0)
1497 *types |= O_READ0x0001;
1498 if (fshelp_access (&np->nn_stat, S_IWRITE00200, cred) == 0)
1499 *types |= O_WRITE0x0002;
1500 if (fshelp_access (&np->nn_stat, S_IEXEC00100, cred) == 0)
1501 *types |= O_EXEC0x0004;
1502 return 0;
1503 }
1504 else
1505 {
1506 int *p;
1507 void *rpcbuf;
1508 error_t err;
1509 int ret;
1510 int write_check, execute_check;
1511
1512 if (S_ISDIR (np->nn_stat.st_mode)((((np->nn_stat.st_mode)) & 0170000) == (0040000)))
1513 {
1514 write_check = ACCESS3_MODIFY0x04 | ACCESS3_DELETE0x10 | ACCESS3_EXTEND0x08;
1515 execute_check = ACCESS3_LOOKUP0x02;
1516 }
1517 else
1518 {
1519 write_check = ACCESS3_MODIFY0x04;
1520 execute_check = ACCESS3_EXECUTE0x20;
1521 }
1522
1523 p = nfs_initialize_rpc (NFS3PROC_ACCESS4, cred, 0, &rpcbuf, np, -1);
1524 if (! p)
1525 return errno(*__errno_location ());
1526
1527 p = xdr_encode_fhandle (p, &np->nn->handle);
1528 *(p++) = htonl (ACCESS3_READ0x01 | write_check | execute_check);
1529
1530 err = conduct_rpc (&rpcbuf, &p);
1531 if (!err)
1532 {
1533 err = nfs_error_trans (ntohl (*p));
1534 p++;
1535 p = process_returned_stat (np, p, 0); /* XXX Should this be
1536 protected by the
1537 if (!err) ? */
1538 if (!err)
1539 {
1540 ret = ntohl (*p);
1541 p++;
1542 *types = ((ret & ACCESS3_READ0x01 ? O_READ0x0001 : 0)
1543 | (ret & write_check ? O_WRITE0x0002 : 0)
1544 | (ret & execute_check ? O_EXEC0x0004 : 0));
1545 }
1546 }
1547 return err;
1548 }
1549}
1550
1551/* These definitions have unfortunate side effects, don't use them,
1552 clever though they are. */
1553#if 0
1554/* Implement the netfs_check_open_permissions callback as described in
1555 <hurd/netfs.h>. */
1556error_t
1557netfs_check_open_permissions (struct iouser *cred, struct node *np,
1558 int flags, int newnode)
1559{
1560 char byte;
1561 error_t err;
1562 size_t len;
1563
1564 /* Sun derived nfs client implementations attempt to reproduce the
1565 server's permission restrictions by hoping they look like Unix,
1566 and using that to give errors at open time. Sadly, that loses
1567 here. So instead what we do is try and do what the user
1568 requested; if we can't, then we fail. Otherwise, we allow the
1569 open, but acknowledge that the server might still give an error
1570 later. (Even with our check, the server can revoke access, thus
1571 violiting Posix semantics; this means that erring on the side of
1572 permitting illegal opens won't harm otherwise correct programs,
1573 because they need to deal with revocation anyway.) We thus here
1574 have the advantage of working correctly with servers that allow
1575 things Unix denies. */
1576
1577 if ((flags & O_READ0x0001) == 0
1578 && (flags & O_WRITE0x0002) == 0
1579 && (flags & O_EXEC0x0004) == 0)
1580 return 0;
1581
1582 err = netfs_validate_stat (np, cred);
1583 if (err)
1584 return err;
1585
1586 switch (np->nn_stat.st_mode & S_IFMT0170000)
1587 {
1588 /* Don't know how to check, so return provisional success. */
1589 default:
1590 return 0;
1591
1592 case S_IFREG0100000:
1593 len = 1;
1594 err = netfs_attempt_read (cred, np, 0, &len, &byte);
1595 if (err)
1596 {
1597 if ((flags & O_READ0x0001) || (flags & O_EXEC0x0004))
1598 return err;
1599 else
1600 /* If we couldn't read a byte, but the user wasn't actually asking
1601 for read, then we shouldn't inhibit the open now. */
1602 return 0;
1603 }
1604
1605 if (len != 1)
1606 /* The file is empty; reads are known to be OK, but writes can't be
1607 tested, so no matter what, return success. */
1608 return 0;
1609
1610 if (flags & O_WRITE0x0002)
1611 {
1612 err = netfs_attempt_write (cred, np, 0, &len, &byte);
1613 return err;
1614 }
1615
1616 /* Try as we might, we couldn't get the server to bump us, so
1617 give (provisional) success. */
1618 return 0;
1619
1620 case S_IFDIR0040000:
1621 if (flags & O_READ0x0001)
1622 {
1623 void *rpcbuf;
1624 int *p;
1625
1626 /* Issue a readdir request; if it fails, then we can
1627 return failure. Otherwise, succeed. */
1628 p = nfs_initialize_rpc (NFSPROC_READDIR, cred, 0, &rpcbuf, np, -1);
1629 p = xdr_encode_fhandle (p, &np->nn->handle);
1630 *(p++) = 0;
1631 *(p++) = htonl (50);
1632 err = conduct_rpc (&rpcbuf, &p);
1633 if (!err)
1634 {
1635 err = nfs_error_trans (ntohl (*p));
1636 p++;
1637 }
1638 free (rpcbuf);
1639
1640 if (err)
1641 return err;
1642 }
1643 return 0;
1644 }
1645}
1646
1647/* Implement the netfs_report_access callback as described in
1648 <hurd/netfs.h>. */
1649void
1650netfs_report_access (struct iouser *cred,
1651 struct node *np,
1652 int *types)
1653{
1654 char byte;
1655 error_t err;
1656 size_t len;
1657
1658 /* Much the same logic as netfs_check_open_permissions, except that
1659 here we err on the side of denying access, and that we always
1660 have to check everything. */
1661
1662 *types = 0;
1663
1664 len = 1;
1665 err = netfs_attempt_read (cred, np, 0, &len, &byte);
1666 if (err)
1667 return;
1668 assert (len == 1 || len == 0)((len == 1 || len == 0) ? (void) (0) : __assert_fail ("len == 1 || len == 0"
, "../../nfs/ops.c", 1668, __PRETTY_FUNCTION__))
;
1669
1670 *types |= O_READ0x0001 | O_EXEC0x0004;
1671
1672 if (len == 1)
1673 {
1674 err = netfs_attempt_write (cred, np, 0, &len, &byte);
1675 if (!err)
1676 *types |= O_WRITE0x0002;
1677 }
1678 else
1679 {
1680 /* Oh, ugh. We have to try and write a byte and then truncate
1681 back. God help us if the file becomes unwritable in-between.
1682 But because of the use of this function (by setuid programs
1683 wanting to see if they should write user's files) we must
1684 check this and not just return a presumptive error. */
1685 byte = 0;
1686 err = netfs_attempt_write (cred, np, 0, &len, &byte);
1687 if (!err)
1688 *types |= O_WRITE0x0002;
1689 netfs_attempt_set_size (cred, np, 0);
1690 }
1691}
1692#endif
1693
1694/* Fetch the complete contents of DIR into a buffer of directs. Set
1695 *BUFP to that buffer. *BUFP must be freed by the caller when no
1696 longer needed. If an error occurs, don't touch *BUFP and return
1697 the error code. Set BUFSIZEP to the amount of data used inside
1698 *BUFP and TOTALENTRIES to the total number of entries copied. */
1699static error_t
1700fetch_directory (struct iouser *cred, struct node *dir,
1701 void **bufp, size_t *bufsizep, int *totalentries)
1702{
1703 void *buf;
1704 int cookie;
1705 int *p;
1706 void *rpcbuf;
1707 struct dirent *entry;
1708 void *bp;
1709 int bufmalloced;
1710 int eof;
1711 error_t err;
1712 int isnext;
1713
1714 bufmalloced = read_size;
1715
1716 buf = malloc (bufmalloced);
1717 if (! buf)
3
Assuming 'buf' is non-null
4
Taking false branch
1718 return ENOMEM((0x10 << 26) | ((12) & 0x3fff));
1719
1720 bp = buf;
1721 cookie = 0;
1722 eof = 0;
1723 *totalentries = 0;
1724
1725 while (!eof)
5
Loop condition is true. Entering loop body
14
Assuming 'eof' is 0
15
Loop condition is true. Entering loop body
24
Assuming 'eof' is 0
25
Loop condition is true. Entering loop body
1726 {
1727 /* Fetch new directory entries */
1728 p = nfs_initialize_rpc (NFSPROC_READDIR (protocol_version)(protocol_version == 2 ? 16 : 16),
6
Within the expansion of the macro 'NFSPROC_READDIR':
a
Assuming 'protocol_version' is not equal to 2
16
Within the expansion of the macro 'NFSPROC_READDIR':
a
Assuming 'protocol_version' is not equal to 2
26
Within the expansion of the macro 'NFSPROC_READDIR':
a
Assuming 'protocol_version' is not equal to 2
1729 cred, 0, &rpcbuf, dir, -1);
1730 if (! p)
7
Assuming 'p' is non-null
8
Taking false branch
17
Assuming 'p' is non-null
18
Taking false branch
27
Assuming 'p' is null
28
Taking true branch
1731 {
1732 free (buf);
1733 return errno(*__errno_location ());
1734 }
1735
1736 p = xdr_encode_fhandle (p, &dir->nn->handle);
1737 *(p++) = cookie;
1738 *(p++) = ntohl (read_size);
1739 err = conduct_rpc (&rpcbuf, &p);
1740 if (!err)
9
Assuming 'err' is 0
10
Taking true branch
19
Assuming 'err' is 0
20
Taking true branch
1741 {
1742 err = nfs_error_trans (ntohl (*p));
1743 p++;
1744 }
1745 if (err)
11
Assuming 'err' is 0
12
Taking false branch
21
Assuming 'err' is 0
22
Taking false branch
1746 {
1747 free (buf);
1748 return err;
1749 }
1750
1751 isnext = ntohl (*p);
1752 p++;
1753
1754 /* Now copy them one at a time. */
1755 while (isnext)
13
Loop condition is false. Execution continues on line 1802
23
Loop condition is false. Execution continues on line 1802
1756 {
1757 ino_t fileno;
1758 int namlen;
1759 int reclen;
1760
1761 fileno = ntohl (*p);
1762 p++;
1763 namlen = ntohl (*p);
1764 p++;
1765
1766 /* There's a hidden +1 here for the null byte and -1 because d_name
1767 has a size of one already in the sizeof. */
1768 reclen = sizeof (struct dirent) + namlen;
1769 reclen = (reclen + 3) & ~3; /* make it a multiple of four */
1770
1771 /* Expand buffer if necessary */
1772 if (bp + reclen > buf + bufmalloced)
1773 {
1774 char *newbuf;
1775
1776 newbuf = realloc (buf, bufmalloced *= 2);
1777 assert (newbuf)((newbuf) ? (void) (0) : __assert_fail ("newbuf", "../../nfs/ops.c"
, 1777, __PRETTY_FUNCTION__))
;
1778 if (newbuf != buf)
1779 bp = newbuf + (bp - buf);
1780 buf = newbuf;
1781 }
1782
1783 /* Fill in new entry */
1784 entry = (struct dirent *) bp;
1785 entry->d_filenod_ino = fileno;
1786 entry->d_reclen = reclen;
1787 entry->d_type = DT_UNKNOWNDT_UNKNOWN;
1788 entry->d_namlen = namlen;
1789 memcpy (entry->d_name, p, namlen);
1790 entry->d_name[namlen] = '\0';
1791
1792 p += INTSIZE (namlen)(((namlen)+3)>>2);
1793 bp = bp + entry->d_reclen;
1794
1795 ++*totalentries;
1796
1797 cookie = *(p++);
1798 isnext = ntohl (*p);
1799 p++;
1800 }
1801
1802 eof = ntohl (*p);
1803 p++;
1804 free (rpcbuf);
1805 }
1806
1807 /* Return it all to the user */
1808 *bufp = buf;
1809 *bufsizep = bufmalloced;
1810 return 0;
1811}
1812
1813
1814/* Implement the netfs_get_directs callback as described in
1815 <hurd/netfs.h>. */
1816error_t
1817netfs_get_dirents (struct iouser *cred, struct node *np,
1818 int entry, int nentries, char **data,
1819 mach_msg_type_number_t *datacnt,
1820 vm_size_t bufsiz, int *amt)
1821{
1822 void *buf;
1823 size_t our_bufsiz, allocsize;
1
Variable 'our_bufsiz' declared without an initial value
1824 void *bp;
1825 char *userdp;
1826 error_t err;
1827 int totalentries;
1828 int thisentry;
1829
1830 err = fetch_directory (cred, np, &buf, &our_bufsiz, &totalentries);
2
Calling 'fetch_directory'
29
Returning from 'fetch_directory'
1831 if (err)
30
Assuming 'err' is 0
31
Taking false branch
1832 return err;
1833
1834 /* Allocate enough space to hold the maximum we might return. */
1835 if (!bufsiz || bufsiz > our_bufsiz)
32
Assuming 'bufsiz' is 0
1836 allocsize = round_page (our_bufsiz)((((vm_offset_t) (our_bufsiz) + __vm_page_size - 1) / __vm_page_size
) * __vm_page_size)
;
33
Within the expansion of the macro 'round_page':
a
The left operand of '+' is a garbage value
1837 else
1838 allocsize = round_page (bufsiz)((((vm_offset_t) (bufsiz) + __vm_page_size - 1) / __vm_page_size
) * __vm_page_size)
;
1839 if (allocsize > *datacnt)
1840 *data = mmap (0, allocsize, PROT_READ0x04|PROT_WRITE0x02, MAP_ANON0x0002, 0, 0);
1841
1842 /* Skip ahead to the correct entry. */
1843 bp = buf;
1844 for (thisentry = 0; thisentry < entry;)
1845 {
1846 struct dirent *entry = (struct dirent *) bp;
1847 bp += entry->d_reclen;
1848 thisentry++;
1849 }
1850
1851 /* Now copy them one at a time */
1852 {
1853 int entries_copied;
1854
1855 for (entries_copied = 0, userdp = *data;
1856 (nentries == -1 || entries_copied < nentries)
1857 && (!bufsiz || userdp - *data < bufsiz)
1858 && thisentry < totalentries;)
1859 {
1860 struct dirent *entry = (struct dirent *) bp;
1861 memcpy (userdp, bp, entry->d_reclen);
1862 bp += entry->d_reclen;
1863 userdp += entry->d_reclen;
1864 entries_copied++;
1865 thisentry++;
1866 }
1867 *amt = entries_copied;
1868 }
1869
1870 free (buf);
1871
1872 /* If we allocated the buffer ourselves, but didn't use
1873 all the pages, free the extra. */
1874 if (allocsize > *datacnt
1875 && round_page (userdp - *data)((((vm_offset_t) (userdp - *data) + __vm_page_size - 1) / __vm_page_size
) * __vm_page_size)
< round_page (allocsize)((((vm_offset_t) (allocsize) + __vm_page_size - 1) / __vm_page_size
) * __vm_page_size)
)
1876 munmap ((caddr_t) round_page (userdp)((((vm_offset_t) (userdp) + __vm_page_size - 1) / __vm_page_size
) * __vm_page_size)
,
1877 round_page (allocsize)((((vm_offset_t) (allocsize) + __vm_page_size - 1) / __vm_page_size
) * __vm_page_size)
- round_page (userdp - *data)((((vm_offset_t) (userdp - *data) + __vm_page_size - 1) / __vm_page_size
) * __vm_page_size)
);
1878
1879 *datacnt = userdp - *data;
1880 return 0;
1881}
1882
1883
1884/* Implement the netfs_attempt_mksymlink callback as described in
1885 <hurd/netfs.h>. */
1886error_t
1887netfs_attempt_mksymlink (struct iouser *cred,
1888 struct node *np,
1889 char *arg)
1890{
1891 if (np->nn->dtrans == NOT_POSSIBLE)
1892 return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff));
1893
1894 if (np->nn->dtrans == SYMLINK)
1895 free (np->nn->transarg.name);
1896
1897 np->nn->transarg.name = malloc (strlen (arg) + 1);
1898 strcpy (np->nn->transarg.name, arg);
1899 np->nn->dtrans = SYMLINK;
1900 np->nn->stat_updated = 0;
1901 return 0;
1902}
1903
1904/* Implement the netfs_attempt_mkdev callback as described in
1905 <hurd/netfs.h>. */
1906error_t
1907netfs_attempt_mkdev (struct iouser *cred,
1908 struct node *np,
1909 mode_t type,
1910 dev_t indexes)
1911{
1912 if (np->nn->dtrans == NOT_POSSIBLE)
1913 return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff));
1914
1915 if (np->nn->dtrans == SYMLINK)
1916 free (np->nn->transarg.name);
1917
1918 np->nn->transarg.indexes = indexes;
1919 if (type == S_IFBLK0060000)
1920 np->nn->dtrans = BLKDEV;
1921 else
1922 np->nn->dtrans = CHRDEV;
1923 np->nn->stat_updated = 0;
1924 return 0;
1925}