1 /*
2 * Copyright 2012 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Paweł Dziepak, pdziepak@quarnos.org
7 */
8
9
10 #include <AutoDeleter.h>
11
12 #include "IdMap.h"
13 #include "Inode.h"
14 #include "NFS4Inode.h"
15 #include "Request.h"
16
17
18 status_t
GetChangeInfo(uint64 * change,bool attrDir)19 NFS4Inode::GetChangeInfo(uint64* change, bool attrDir)
20 {
21 ASSERT(change != NULL);
22
23 uint32 attempt = 0;
24 do {
25 RPC::Server* serv = fFileSystem->Server();
26 Request request(serv, fFileSystem);
27 RequestBuilder& req = request.Builder();
28
29 if (attrDir)
30 req.PutFH(fInfo.fAttrDir);
31 else
32 req.PutFH(fInfo.fHandle);
33
34 Attribute attr[] = { FATTR4_CHANGE };
35 req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
36
37 status_t result = request.Send();
38 if (result != B_OK)
39 return result;
40
41 ReplyInterpreter& reply = request.Reply();
42
43 if (HandleErrors(attempt, reply.NFS4Error(), serv))
44 continue;
45
46 reply.PutFH();
47
48 AttrValue* values;
49 uint32 count;
50 result = reply.GetAttr(&values, &count);
51 if (result != B_OK)
52 return result;
53
54 // FATTR4_CHANGE is mandatory
55 *change = values[0].fData.fValue64;
56 delete[] values;
57
58 return B_OK;
59 } while (true);
60 }
61
62
63 status_t
CommitWrites()64 NFS4Inode::CommitWrites()
65 {
66 uint32 attempt = 0;
67 do {
68 RPC::Server* serv = fFileSystem->Server();
69 Request request(serv, fFileSystem);
70 RequestBuilder& req = request.Builder();
71
72 req.PutFH(fInfo.fHandle);
73 req.Commit(0, 0);
74
75 status_t result = request.Send();
76 if (result != B_OK)
77 return result;
78
79 ReplyInterpreter& reply = request.Reply();
80
81 if (HandleErrors(attempt, reply.NFS4Error(), serv))
82 continue;
83
84 reply.PutFH();
85 return reply.Commit();
86 } while (true);
87 }
88
89
90 status_t
Access(uint32 * allowed)91 NFS4Inode::Access(uint32* allowed)
92 {
93 ASSERT(allowed != NULL);
94
95 uint32 attempt = 0;
96 do {
97 RPC::Server* serv = fFileSystem->Server();
98 Request request(serv, fFileSystem);
99 RequestBuilder& req = request.Builder();
100
101 req.PutFH(fInfo.fHandle);
102 req.Access();
103
104 status_t result = request.Send();
105 if (result != B_OK)
106 return result;
107
108 ReplyInterpreter& reply = request.Reply();
109
110 if (HandleErrors(attempt, reply.NFS4Error(), serv))
111 continue;
112
113 reply.PutFH();
114
115 return reply.Access(NULL, allowed);
116 } while (true);
117 }
118
119
120 status_t
LookUp(const char * name,uint64 * change,uint64 * fileID,FileHandle * handle,bool parent)121 NFS4Inode::LookUp(const char* name, uint64* change, uint64* fileID,
122 FileHandle* handle, bool parent)
123 {
124 ASSERT(name != NULL);
125
126 uint32 attempt = 0;
127 do {
128 RPC::Server* serv = fFileSystem->Server();
129 Request request(serv, fFileSystem);
130 RequestBuilder& req = request.Builder();
131
132 (void)parent; // TODO: add support for named attributes
133 req.PutFH(fInfo.fHandle);
134
135 if (change != NULL) {
136 Attribute dirAttr[] = { FATTR4_CHANGE };
137 req.GetAttr(dirAttr, sizeof(dirAttr) / sizeof(Attribute));
138 }
139
140 if (!strcmp(name, ".."))
141 req.LookUpUp();
142 else
143 req.LookUp(name);
144
145 if (handle != NULL)
146 req.GetFH();
147
148 Attribute attr[] = { FATTR4_FSID, FATTR4_FILEID };
149 req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
150
151 status_t result = request.Send();
152 if (result != B_OK)
153 return result;
154
155 ReplyInterpreter& reply = request.Reply();
156
157 if (HandleErrors(attempt, reply.NFS4Error(), serv))
158 continue;
159
160 reply.PutFH();
161
162 AttrValue* values;
163 uint32 count;
164 if (change != NULL) {
165 result = reply.GetAttr(&values, &count);
166 if (result != B_OK)
167 return result;
168
169 *change = values[0].fData.fValue64;
170 delete[] values;
171 }
172
173 if (!strcmp(name, ".."))
174 result = reply.LookUpUp();
175 else
176 result = reply.LookUp();
177 if (result != B_OK)
178 return result;
179
180 if (handle != NULL)
181 reply.GetFH(handle);
182
183 result = reply.GetAttr(&values, &count);
184 if (result != B_OK)
185 return result;
186
187 // FATTR4_FSID is mandatory
188 FileSystemId* fsid
189 = reinterpret_cast<FileSystemId*>(values[0].fData.fPointer);
190 if (*fsid != fFileSystem->FsId()) {
191 delete[] values;
192 return B_ENTRY_NOT_FOUND;
193 }
194
195 if (fileID != NULL) {
196 if (count < 2 || values[1].fAttribute != FATTR4_FILEID)
197 *fileID = fFileSystem->AllocFileId();
198 else
199 *fileID = values[1].fData.fValue64;
200 }
201
202 delete[] values;
203
204 return B_OK;
205 } while (true);
206 }
207
208
209 status_t
Link(Inode * dir,const char * name,ChangeInfo * changeInfo)210 NFS4Inode::Link(Inode* dir, const char* name, ChangeInfo* changeInfo)
211 {
212 ASSERT(dir != NULL);
213 ASSERT(name != NULL);
214 ASSERT(changeInfo != NULL);
215
216 uint32 attempt = 0;
217 do {
218 RPC::Server* serv = fFileSystem->Server();
219 Request request(serv, fFileSystem);
220 RequestBuilder& req = request.Builder();
221
222 req.PutFH(fInfo.fHandle);
223 req.SaveFH();
224 req.PutFH(dir->fInfo.fHandle);
225 req.Link(name);
226
227 status_t result = request.Send();
228 if (result != B_OK)
229 return result;
230
231 ReplyInterpreter& reply = request.Reply();
232
233 if (HandleErrors(attempt, reply.NFS4Error(), serv))
234 continue;
235
236 reply.PutFH();
237 reply.SaveFH();
238 reply.PutFH();
239
240 return reply.Link(&changeInfo->fBefore, &changeInfo->fAfter,
241 changeInfo->fAtomic);
242 } while (true);
243 }
244
245
246 status_t
ReadLink(void * buffer,size_t * length)247 NFS4Inode::ReadLink(void* buffer, size_t* length)
248 {
249 ASSERT(buffer != NULL);
250 ASSERT(length != NULL);
251
252 uint32 attempt = 0;
253 do {
254 RPC::Server* serv = fFileSystem->Server();
255 Request request(serv, fFileSystem);
256 RequestBuilder& req = request.Builder();
257
258 req.PutFH(fInfo.fHandle);
259 req.ReadLink();
260
261 status_t result = request.Send();
262 if (result != B_OK)
263 return result;
264
265 ReplyInterpreter& reply = request.Reply();
266
267 if (HandleErrors(attempt, reply.NFS4Error(), serv))
268 continue;
269
270 reply.PutFH();
271
272 uint32 size;
273 result = reply.ReadLink(buffer, &size, *length);
274 *length = static_cast<size_t>(size);
275
276 return result;
277 } while (true);
278 }
279
280
281 status_t
GetStat(AttrValue ** values,uint32 * count,OpenAttrCookie * cookie)282 NFS4Inode::GetStat(AttrValue** values, uint32* count, OpenAttrCookie* cookie)
283 {
284 ASSERT(values != NULL);
285 ASSERT(count != NULL);
286
287 uint32 attempt = 0;
288 do {
289 RPC::Server* serv = fFileSystem->Server();
290 Request request(serv, fFileSystem);
291 RequestBuilder& req = request.Builder();
292
293 if (cookie != NULL)
294 req.PutFH(cookie->fOpenState->fInfo.fHandle);
295 else
296 req.PutFH(fInfo.fHandle);
297
298 Attribute attr[] = { FATTR4_SIZE, FATTR4_MODE, FATTR4_NUMLINKS,
299 FATTR4_OWNER, FATTR4_OWNER_GROUP,
300 FATTR4_TIME_ACCESS, FATTR4_TIME_CREATE,
301 FATTR4_TIME_METADATA, FATTR4_TIME_MODIFY };
302 req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
303
304 status_t result = request.Send(cookie);
305 if (result != B_OK)
306 return result;
307
308 ReplyInterpreter& reply = request.Reply();
309
310 if (HandleErrors(attempt, reply.NFS4Error(), serv))
311 continue;
312
313 reply.PutFH();
314
315 return reply.GetAttr(values, count);
316 } while (true);
317 }
318
319
320 status_t
WriteStat(OpenState * state,AttrValue * attrs,uint32 attrCount)321 NFS4Inode::WriteStat(OpenState* state, AttrValue* attrs, uint32 attrCount)
322 {
323 ASSERT(attrs != NULL);
324
325 uint32 attempt = 0;
326 do {
327 RPC::Server* serv = fFileSystem->Server();
328 Request request(serv, fFileSystem);
329 RequestBuilder& req = request.Builder();
330
331 if (state != NULL) {
332 req.PutFH(state->fInfo.fHandle);
333 req.SetAttr(state->fStateID, state->fStateSeq, attrs, attrCount);
334 } else {
335 req.PutFH(fInfo.fHandle);
336 req.SetAttr(NULL, 0, attrs, attrCount);
337 }
338
339 status_t result = request.Send();
340 if (result != B_OK)
341 return result;
342
343 ReplyInterpreter& reply = request.Reply();
344
345 if (HandleErrors(attempt, reply.NFS4Error(), serv))
346 continue;
347
348 reply.PutFH();
349 result = reply.SetAttr();
350
351 if (result != B_OK)
352 return result;
353
354 return B_OK;
355 } while (true);
356 }
357
358
359 status_t
RenameNode(Inode * from,Inode * to,const char * fromName,const char * toName,ChangeInfo * fromChange,ChangeInfo * toChange,uint64 * fileID,bool attribute)360 NFS4Inode::RenameNode(Inode* from, Inode* to, const char* fromName,
361 const char* toName, ChangeInfo* fromChange, ChangeInfo* toChange,
362 uint64* fileID, bool attribute)
363 {
364 ASSERT(from != NULL);
365 ASSERT(to != NULL);
366 ASSERT(fromName != NULL);
367 ASSERT(toName != NULL);
368 ASSERT(fromChange != NULL);
369 ASSERT(toChange != NULL);
370
371 uint32 attempt = 0;
372 do {
373 RPC::Server* server = from->fFileSystem->Server();
374 Request request(server, from->fFileSystem);
375 RequestBuilder& req = request.Builder();
376
377 if (attribute)
378 req.PutFH(from->fInfo.fAttrDir);
379 else
380 req.PutFH(from->fInfo.fHandle);
381 req.SaveFH();
382 if (attribute)
383 req.PutFH(to->fInfo.fAttrDir);
384 else
385 req.PutFH(to->fInfo.fHandle);
386 req.Rename(fromName, toName);
387
388 if (!attribute) {
389 req.LookUp(toName);
390 Attribute attr[] = { FATTR4_FILEID };
391 req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
392 }
393
394 status_t result = request.Send();
395 if (result != B_OK)
396 return result;
397
398 ReplyInterpreter& reply = request.Reply();
399
400 // If we have to wait, migrate to another server, etc then the first
401 // HandleErrors() will do that. However, if the file handles
402 // were invalid then we need to update both Inodes.
403 bool retry = from->HandleErrors(attempt, reply.NFS4Error(), server);
404 if (IsFileHandleInvalid(reply.NFS4Error()))
405 retry |= to->HandleErrors(attempt, reply.NFS4Error(), server);
406 if (retry)
407 continue;
408
409 reply.PutFH();
410 reply.SaveFH();
411 reply.PutFH();
412
413 result = reply.Rename(&fromChange->fBefore, &fromChange->fAfter,
414 fromChange->fAtomic, &toChange->fBefore, &toChange->fAfter,
415 toChange->fAtomic);
416 if (result != B_OK)
417 return result;
418
419 if (!attribute) {
420 result = reply.LookUp();
421 if (result != B_OK)
422 return result;
423
424 AttrValue* values;
425 uint32 count;
426 result = reply.GetAttr(&values, &count);
427 if (result != B_OK)
428 return result;
429
430 if (count == 0)
431 *fileID = from->fFileSystem->AllocFileId();
432 else
433 *fileID = values[0].fData.fValue64;
434
435 delete[] values;
436 }
437
438 return B_OK;
439 } while (true);
440 }
441
442
443 status_t
CreateFile(const char * name,int mode,int perms,OpenState * state,ChangeInfo * changeInfo,uint64 * fileID,FileHandle * handle,OpenDelegationData * delegation)444 NFS4Inode::CreateFile(const char* name, int mode, int perms, OpenState* state,
445 ChangeInfo* changeInfo, uint64* fileID, FileHandle* handle,
446 OpenDelegationData* delegation)
447 {
448 ASSERT(name != NULL);
449 ASSERT(state != NULL);
450 ASSERT(changeInfo != NULL);
451 ASSERT(handle != NULL);
452 ASSERT(delegation != NULL);
453
454 bool confirm;
455 status_t result;
456
457 uint32 attempt = 0;
458 uint32 sequence = fFileSystem->OpenOwnerSequenceLock();
459 do {
460 state->fClientID = fFileSystem->NFSServer()->ClientId();
461
462 RPC::Server* serv = fFileSystem->Server();
463 Request request(serv, fFileSystem);
464 RequestBuilder& req = request.Builder();
465
466 req.PutFH(fInfo.fHandle);
467
468 AttrValue cattr[2];
469 uint32 i = 0;
470 if ((mode & O_TRUNC) == O_TRUNC) {
471 cattr[i].fAttribute = FATTR4_SIZE;
472 cattr[i].fFreePointer = false;
473 cattr[i].fData.fValue64 = 0;
474 i++;
475 }
476 cattr[i].fAttribute = FATTR4_MODE;
477 cattr[i].fFreePointer = false;
478 cattr[i].fData.fValue32 = perms;
479 i++;
480
481 req.Open(CLAIM_NULL, sequence, sModeToAccess(mode),
482 state->fClientID, OPEN4_CREATE, fFileSystem->OpenOwner(), name,
483 cattr, i, (mode & O_EXCL) == O_EXCL);
484
485 req.GetFH();
486
487 if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) {
488 Attribute attr[] = { FATTR4_FILEID };
489 req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
490 }
491
492 result = request.Send();
493 if (result != B_OK) {
494 fFileSystem->OpenOwnerSequenceUnlock(sequence);
495 return result;
496 }
497
498 ReplyInterpreter& reply = request.Reply();
499
500 result = reply.PutFH();
501 if (result == B_OK)
502 sequence += IncrementSequence(reply.NFS4Error());
503
504 if (HandleErrors(attempt, reply.NFS4Error(), serv, NULL, state,
505 &sequence)) {
506 continue;
507 }
508
509 result = reply.Open(state->fStateID, &state->fStateSeq, &confirm,
510 delegation, changeInfo);
511 if (result != B_OK) {
512 fFileSystem->OpenOwnerSequenceUnlock(sequence);
513 return result;
514 }
515
516 reply.GetFH(handle);
517
518 if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) {
519 AttrValue* values;
520 uint32 count;
521 result = reply.GetAttr(&values, &count);
522 if (result != B_OK) {
523 fFileSystem->OpenOwnerSequenceUnlock(sequence);
524 return result;
525 }
526
527 *fileID = values[0].fData.fValue64;
528
529 delete[] values;
530 } else
531 *fileID = fFileSystem->AllocFileId();
532
533 break;
534 } while (true);
535
536 state->fOpened = true;
537
538 if (confirm)
539 result = ConfirmOpen(*handle, state, &sequence);
540
541 fFileSystem->OpenOwnerSequenceUnlock(sequence);
542 return result;
543 }
544
545
546 status_t
OpenFile(OpenState * state,int mode,OpenDelegationData * delegation)547 NFS4Inode::OpenFile(OpenState* state, int mode, OpenDelegationData* delegation)
548 {
549 ASSERT(state != NULL);
550 ASSERT(delegation != NULL);
551
552 bool confirm;
553 status_t result;
554
555 uint32 attempt = 0;
556 uint32 sequence = fFileSystem->OpenOwnerSequenceLock();
557 do {
558 state->fClientID = fFileSystem->NFSServer()->ClientId();
559
560 RPC::Server* serv = fFileSystem->Server();
561 Request request(serv, fFileSystem);
562 RequestBuilder& req = request.Builder();
563
564 // Since we are opening the file using a pair (parentFH, name) we
565 // need to check for race conditions.
566 if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) {
567 req.PutFH(fInfo.fNames->fNames.Head()->fParent->fHandle);
568 req.LookUp(fInfo.fNames->fNames.Head()->fName);
569 AttrValue attr;
570 attr.fAttribute = FATTR4_FILEID;
571 attr.fFreePointer = false;
572 attr.fData.fValue64 = fInfo.fFileId;
573 req.Verify(&attr, 1);
574 } else if (fFileSystem->ExpireType() == FH4_PERSISTENT) {
575 req.PutFH(fInfo.fNames->fNames.Head()->fParent->fHandle);
576 req.LookUp(fInfo.fNames->fNames.Head()->fName);
577 AttrValue attr;
578 attr.fAttribute = FATTR4_FILEHANDLE;
579 attr.fFreePointer = true;
580 attr.fData.fPointer = malloc(sizeof(fInfo.fHandle));
581 memcpy(attr.fData.fPointer, &fInfo.fHandle, sizeof(fInfo.fHandle));
582 req.Verify(&attr, 1);
583 }
584
585 req.PutFH(fInfo.fNames->fNames.Head()->fParent->fHandle);
586 req.Open(CLAIM_NULL, sequence, sModeToAccess(mode), state->fClientID,
587 OPEN4_NOCREATE, fFileSystem->OpenOwner(),
588 fInfo.fNames->fNames.Head()->fName);
589 req.GetFH();
590
591 result = request.Send();
592 if (result != B_OK) {
593 fFileSystem->OpenOwnerSequenceUnlock(sequence);
594 return result;
595 }
596
597 ReplyInterpreter& reply = request.Reply();
598
599 // Verify if the file we want to open is the file this Inode
600 // represents.
601 if (fFileSystem->IsAttrSupported(FATTR4_FILEID)
602 || fFileSystem->ExpireType() == FH4_PERSISTENT) {
603 reply.PutFH();
604 result = reply.LookUp();
605 if (result != B_OK) {
606 fFileSystem->OpenOwnerSequenceUnlock(sequence);
607 return result;
608 }
609
610 result = reply.Verify();
611 if (result != B_OK && reply.NFS4Error() == NFS4ERR_NOT_SAME) {
612 fFileSystem->OpenOwnerSequenceUnlock(sequence);
613 return B_ENTRY_NOT_FOUND;
614 }
615 }
616
617 result = reply.PutFH();
618 if (result == B_OK)
619 sequence += IncrementSequence(reply.NFS4Error());
620
621 if (HandleErrors(attempt, reply.NFS4Error(), serv, NULL, state,
622 &sequence)) {
623 continue;
624 }
625
626 result = reply.Open(state->fStateID, &state->fStateSeq, &confirm,
627 delegation);
628 if (result != B_OK) {
629 fFileSystem->OpenOwnerSequenceUnlock(sequence);
630 return result;
631 }
632
633 FileHandle handle;
634 result = reply.GetFH(&handle);
635 if (result != B_OK) {
636 fFileSystem->OpenOwnerSequenceUnlock(sequence);
637 return result;
638 }
639
640 break;
641 } while (true);
642
643 state->fOpened = true;
644
645 if (confirm)
646 result = ConfirmOpen(fInfo.fHandle, state, &sequence);
647
648 fFileSystem->OpenOwnerSequenceUnlock(sequence);
649 return result;
650 }
651
652
653 status_t
OpenAttr(OpenState * state,const char * name,int mode,OpenDelegationData * delegation,bool create)654 NFS4Inode::OpenAttr(OpenState* state, const char* name, int mode,
655 OpenDelegationData* delegation, bool create)
656 {
657 ASSERT(name != NULL);
658 ASSERT(state != NULL);
659 ASSERT(delegation != NULL);
660
661 bool confirm;
662 status_t result;
663
664 uint32 attempt = 0;
665 uint32 sequence = fFileSystem->OpenOwnerSequenceLock();
666 do {
667 state->fClientID = fFileSystem->NFSServer()->ClientId();
668
669 RPC::Server* serv = fFileSystem->Server();
670 Request request(serv, fFileSystem);
671 RequestBuilder& req = request.Builder();
672
673 req.PutFH(fInfo.fAttrDir);
674 req.Open(CLAIM_NULL, sequence, sModeToAccess(mode), state->fClientID,
675 create ? OPEN4_CREATE : OPEN4_NOCREATE, fFileSystem->OpenOwner(),
676 name);
677 req.GetFH();
678
679 result = request.Send();
680 if (result != B_OK) {
681 fFileSystem->OpenOwnerSequenceUnlock(sequence);
682 return result;
683 }
684
685 ReplyInterpreter& reply = request.Reply();
686
687 result = reply.PutFH();
688 if (result == B_OK)
689 sequence += IncrementSequence(reply.NFS4Error());
690
691 if (HandleErrors(attempt, reply.NFS4Error(), serv, NULL, state,
692 &sequence)) {
693 continue;
694 }
695
696 result = reply.Open(state->fStateID, &state->fStateSeq, &confirm,
697 delegation);
698
699 reply.GetFH(&state->fInfo.fHandle);
700
701 if (result != B_OK) {
702 fFileSystem->OpenOwnerSequenceUnlock(sequence);
703 return result;
704 }
705
706 break;
707 } while (true);
708
709 state->fOpened = true;
710
711 if (confirm)
712 result = ConfirmOpen(state->fInfo.fHandle, state, &sequence);
713
714 fFileSystem->OpenOwnerSequenceUnlock(sequence);
715 return result;
716 }
717
718
719 status_t
ReadFile(OpenStateCookie * cookie,OpenState * state,uint64 position,uint32 * length,void * buffer,bool * eof)720 NFS4Inode::ReadFile(OpenStateCookie* cookie, OpenState* state, uint64 position,
721 uint32* length, void* buffer, bool* eof)
722 {
723 ASSERT(state != NULL);
724 ASSERT(length != NULL);
725 ASSERT(buffer != NULL);
726 ASSERT(eof != NULL);
727
728 uint32 attempt = 0;
729 do {
730 RPC::Server* serv = fFileSystem->Server();
731 Request request(serv, fFileSystem);
732 RequestBuilder& req = request.Builder();
733
734 req.PutFH(state->fInfo.fHandle);
735 req.Read(state->fStateID, state->fStateSeq, position, *length);
736
737 status_t result = request.Send(cookie);
738 if (result != B_OK)
739 return result;
740
741 ReplyInterpreter& reply = request.Reply();
742
743 if (HandleErrors(attempt, reply.NFS4Error(), serv, cookie, state))
744 continue;
745
746 reply.PutFH();
747 result = reply.Read(buffer, length, eof);
748 if (result != B_OK)
749 return result;
750
751 return B_OK;
752 } while (true);
753 }
754
755
756 status_t
WriteFile(OpenStateCookie * cookie,OpenState * state,uint64 position,uint32 * length,const void * buffer,bool commit)757 NFS4Inode::WriteFile(OpenStateCookie* cookie, OpenState* state, uint64 position,
758 uint32* length, const void* buffer, bool commit)
759 {
760 ASSERT(state != NULL);
761 ASSERT(length != NULL);
762 ASSERT(buffer != NULL);
763
764 uint32 attempt = 0;
765 do {
766 RPC::Server* serv = fFileSystem->Server();
767 Request request(serv, fFileSystem);
768 RequestBuilder& req = request.Builder();
769
770 req.PutFH(state->fInfo.fHandle);
771
772 req.Write(state->fStateID, state->fStateSeq, buffer, position, *length,
773 commit);
774
775 status_t result = request.Send(cookie);
776 if (result != B_OK)
777 return result;
778
779 ReplyInterpreter& reply = request.Reply();
780
781 if (HandleErrors(attempt, reply.NFS4Error(), serv, cookie, state))
782 continue;
783
784 reply.PutFH();
785
786 result = reply.Write(length);
787 if (result != B_OK)
788 return result;
789
790 return B_OK;
791 } while (true);
792 }
793
794
795 status_t
CreateObject(const char * name,const char * path,int mode,FileType type,ChangeInfo * changeInfo,uint64 * fileID,FileHandle * handle,bool parent)796 NFS4Inode::CreateObject(const char* name, const char* path, int mode,
797 FileType type, ChangeInfo* changeInfo, uint64* fileID, FileHandle* handle,
798 bool parent)
799 {
800 ASSERT(name != NULL);
801 ASSERT(changeInfo != NULL);
802 ASSERT(handle != NULL);
803
804 uint32 attempt = 0;
805 do {
806 RPC::Server* serv = fFileSystem->Server();
807 Request request(serv, fFileSystem);
808 RequestBuilder& req = request.Builder();
809
810 (void)parent; // TODO: support named attributes
811 req.PutFH(fInfo.fHandle);
812
813 uint32 i = 0;
814 AttrValue cattr[1];
815 cattr[i].fAttribute = FATTR4_MODE;
816 cattr[i].fFreePointer = false;
817 cattr[i].fData.fValue32 = mode;
818 i++;
819
820 switch (type) {
821 case NF4DIR:
822 req.Create(NF4DIR, name, cattr, i);
823 break;
824 case NF4LNK:
825 req.Create(NF4LNK, name, cattr, i, path);
826 break;
827 default:
828 return B_BAD_VALUE;
829 }
830
831 req.GetFH();
832
833 if (fileID != NULL) {
834 Attribute attr[] = { FATTR4_FILEID };
835 req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
836 }
837
838 status_t result = request.Send();
839 if (result != B_OK)
840 return result;
841
842 ReplyInterpreter& reply = request.Reply();
843
844 if (HandleErrors(attempt, reply.NFS4Error(), serv))
845 continue;
846
847 reply.PutFH();
848 result = reply.Create(&changeInfo->fBefore, &changeInfo->fAfter,
849 changeInfo->fAtomic);
850 if (result != B_OK)
851 return result;
852
853 result = reply.GetFH(handle);
854 if (result != B_OK)
855 return result;
856
857 if (fileID != NULL) {
858 AttrValue* values;
859 uint32 count;
860 result = reply.GetAttr(&values, &count);
861 if (result != B_OK)
862 return result;
863
864 if (count == 0)
865 *fileID = fFileSystem->AllocFileId();
866 else
867 *fileID = values[0].fData.fValue64;
868
869 delete[] values;
870 }
871
872 return B_OK;
873 } while (true);
874 }
875
876
877 status_t
RemoveObject(const char * name,FileType type,ChangeInfo * changeInfo,uint64 * fileID)878 NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo,
879 uint64* fileID)
880 {
881 ASSERT(name != NULL);
882 ASSERT(changeInfo != NULL);
883
884 uint32 attempt = 0;
885 do {
886 RPC::Server* serv = fFileSystem->Server();
887 Request request(serv, fFileSystem);
888 RequestBuilder& req = request.Builder();
889
890 req.PutFH(fInfo.fHandle);
891 req.LookUp(name);
892 AttrValue attr;
893 attr.fAttribute = FATTR4_TYPE;
894 attr.fFreePointer = false;
895 attr.fData.fValue32 = NF4DIR;
896 if (type == NF4DIR)
897 req.Verify(&attr, 1);
898 else
899 req.Nverify(&attr, 1);
900
901 if (type != NF4NAMEDATTR) {
902 Attribute idAttr[] = { FATTR4_FILEID };
903 req.GetAttr(idAttr, sizeof(idAttr) / sizeof(Attribute));
904 }
905
906 req.PutFH(fInfo.fHandle);
907 req.Remove(name);
908
909 status_t result = request.Send();
910 if (result != B_OK)
911 return result;
912
913 ReplyInterpreter& reply = request.Reply();
914
915 if (HandleErrors(attempt, reply.NFS4Error(), serv))
916 continue;
917
918 reply.PutFH();
919 result = reply.LookUp();
920 if (result != B_OK)
921 return result;
922
923 if (type == NF4DIR)
924 result = reply.Verify();
925 else
926 result = reply.Nverify();
927
928 if (result == NFS4ERR_SAME && type != NF4DIR)
929 return B_IS_A_DIRECTORY;
930 if (result == NFS4ERR_NOT_SAME && type == NF4DIR)
931 return B_NOT_A_DIRECTORY;
932 if (result != B_OK)
933 return result;
934
935 if (type != NF4NAMEDATTR) {
936 AttrValue* values;
937 uint32 count;
938 result = reply.GetAttr(&values, &count);
939 if (result != B_OK)
940 return result;
941
942 if (count == 0)
943 *fileID = fFileSystem->AllocFileId();
944 else
945 *fileID = values[0].fData.fValue64;
946 delete[] values;
947 }
948
949 reply.PutFH();
950 return reply.Remove(&changeInfo->fBefore, &changeInfo->fAfter,
951 changeInfo->fAtomic);
952 } while (true);
953 }
954
955
956 status_t
ReadDirOnce(DirEntry ** dirents,uint32 * count,OpenDirCookie * cookie,bool * eof,uint64 * change,uint64 * dirCookie,uint64 * dirCookieVerf,bool attribute)957 NFS4Inode::ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie,
958 bool* eof, uint64* change, uint64* dirCookie, uint64* dirCookieVerf,
959 bool attribute)
960 {
961 ASSERT(dirents != NULL);
962 ASSERT(count != NULL);
963 ASSERT(eof != NULL);
964
965 uint32 attempt = 0;
966 do {
967 RPC::Server* serv = fFileSystem->Server();
968 Request request(serv, fFileSystem);
969 RequestBuilder& req = request.Builder();
970
971 if (attribute)
972 req.PutFH(fInfo.fAttrDir);
973 else
974 req.PutFH(fInfo.fHandle);
975
976 Attribute dirAttr[] = { FATTR4_CHANGE };
977 if (*change == 0)
978 req.GetAttr(dirAttr, sizeof(dirAttr) / sizeof(Attribute));
979
980 Attribute attr[] = { FATTR4_FSID, FATTR4_FILEID };
981 req.ReadDir(*dirCookie, *dirCookieVerf, attr,
982 sizeof(attr) / sizeof(Attribute));
983
984 req.GetAttr(dirAttr, sizeof(dirAttr) / sizeof(Attribute));
985
986 status_t result = request.Send(cookie);
987 if (result != B_OK)
988 return result;
989
990 ReplyInterpreter& reply = request.Reply();
991
992 if (HandleErrors(attempt, reply.NFS4Error(), serv))
993 continue;
994
995 reply.PutFH();
996
997 AttrValue* before = NULL;
998 uint32 attrCount;
999 if (*change == 0) {
1000 result = reply.GetAttr(&before, &attrCount);
1001 if (result != B_OK)
1002 return result;
1003 }
1004 ArrayDeleter<AttrValue> beforeDeleter(before);
1005
1006 result = reply.ReadDir(dirCookie, dirCookieVerf, dirents, count, eof);
1007 if (result != B_OK)
1008 return result;
1009
1010 ArrayDeleter<DirEntry> entriesDeleter(*dirents);
1011
1012 AttrValue* after;
1013 result = reply.GetAttr(&after, &attrCount);
1014 if (result != B_OK)
1015 return result;
1016
1017 ArrayDeleter<AttrValue> afterDeleter(after);
1018
1019 if ((*change == 0
1020 && before[0].fData.fValue64 == after[0].fData.fValue64)
1021 || *change == after[0].fData.fValue64)
1022 *change = after[0].fData.fValue64;
1023 else
1024 return B_ERROR;
1025
1026 entriesDeleter.Detach();
1027 return B_OK;
1028 } while (true);
1029 }
1030
1031
1032 status_t
OpenAttrDir(FileHandle * handle)1033 NFS4Inode::OpenAttrDir(FileHandle* handle)
1034 {
1035 ASSERT(handle != NULL);
1036
1037 uint32 attempt = 0;
1038 do {
1039 RPC::Server* serv = fFileSystem->Server();
1040 Request request(serv, fFileSystem);
1041 RequestBuilder& req = request.Builder();
1042
1043 req.PutFH(fInfo.fHandle);
1044 req.OpenAttrDir(true);
1045 req.GetFH();
1046
1047 status_t result = request.Send();
1048 if (result != B_OK)
1049 return result;
1050
1051 ReplyInterpreter& reply = request.Reply();
1052
1053 if (HandleErrors(attempt, reply.NFS4Error(), serv))
1054 continue;
1055
1056 reply.PutFH();
1057 result = reply.OpenAttrDir();
1058 if (result != B_OK)
1059 return result;
1060
1061 return reply.GetFH(handle);
1062 } while (true);
1063 }
1064
1065
1066 status_t
TestLock(OpenFileCookie * cookie,LockType * type,uint64 * position,uint64 * length,bool & conflict)1067 NFS4Inode::TestLock(OpenFileCookie* cookie, LockType* type, uint64* position,
1068 uint64* length, bool& conflict)
1069 {
1070 ASSERT(cookie != NULL);
1071 ASSERT(type != NULL);
1072 ASSERT(position != NULL);
1073 ASSERT(length != NULL);
1074
1075 uint32 attempt = 0;
1076 do {
1077 RPC::Server* serv = fFileSystem->Server();
1078 Request request(serv, fFileSystem);
1079 RequestBuilder& req = request.Builder();
1080
1081 req.PutFH(fInfo.fHandle);
1082 req.LockT(*type, *position, *length, cookie->fOpenState);
1083
1084 status_t result = request.Send();
1085 if (result != B_OK)
1086 return result;
1087
1088 ReplyInterpreter& reply = request.Reply();
1089 if (reply.NFS4Error() != NFS4ERR_DENIED) {
1090 if (HandleErrors(attempt, reply.NFS4Error(), serv, cookie))
1091 continue;
1092 }
1093
1094 reply.PutFH();
1095 result = reply.LockT(position, length, type);
1096 if (reply.NFS4Error() == NFS4ERR_DENIED) {
1097 conflict = true;
1098 result = B_OK;
1099 } else if (reply.NFS4Error() == NFS4_OK)
1100 conflict = false;
1101
1102 return result;
1103 } while (true);
1104
1105 return B_OK;
1106 }
1107
1108
1109 status_t
AcquireLock(OpenFileCookie * cookie,LockInfo * lockInfo,bool wait)1110 NFS4Inode::AcquireLock(OpenFileCookie* cookie, LockInfo* lockInfo, bool wait)
1111 {
1112 ASSERT(cookie != NULL);
1113 ASSERT(lockInfo != NULL);
1114
1115 uint32 attempt = 0;
1116 uint32 sequence = fFileSystem->OpenOwnerSequenceLock();
1117 do {
1118 MutexLocker ownerLocker(lockInfo->fOwner->fLock);
1119
1120 RPC::Server* serv = fFileSystem->Server();
1121 Request request(serv, fFileSystem);
1122 RequestBuilder& req = request.Builder();
1123
1124 req.PutFH(fInfo.fHandle);
1125 req.Lock(cookie->fOpenState, lockInfo, &sequence);
1126
1127 status_t result = request.Send();
1128 if (result != B_OK) {
1129 fFileSystem->OpenOwnerSequenceUnlock(sequence);
1130 return result;
1131 }
1132
1133 ReplyInterpreter& reply = request.Reply();
1134
1135 result = reply.PutFH();
1136 if (result == B_OK)
1137 sequence += IncrementSequence(reply.NFS4Error());
1138
1139 result = reply.Lock(lockInfo);
1140
1141 ownerLocker.Unlock();
1142
1143 if (reply.NFS4Error() != NFS4ERR_DENIED || wait) {
1144 if (HandleErrors(attempt, reply.NFS4Error(), serv, cookie, NULL,
1145 &sequence)) {
1146 continue;
1147 }
1148 }
1149
1150 fFileSystem->OpenOwnerSequenceUnlock(sequence);
1151 if (result != B_OK)
1152 return result;
1153
1154 return B_OK;
1155 } while (true);
1156 }
1157
1158
1159 status_t
ReleaseLock(OpenFileCookie * cookie,LockInfo * lockInfo)1160 NFS4Inode::ReleaseLock(OpenFileCookie* cookie, LockInfo* lockInfo)
1161 {
1162 ASSERT(cookie != NULL);
1163 ASSERT(lockInfo != NULL);
1164
1165 uint32 attempt = 0;
1166 do {
1167 MutexLocker ownerLocker(lockInfo->fOwner->fLock);
1168
1169 RPC::Server* serv = fFileSystem->Server();
1170 Request request(serv, fFileSystem);
1171 RequestBuilder& req = request.Builder();
1172
1173 req.PutFH(fInfo.fHandle);
1174 req.LockU(lockInfo);
1175
1176 status_t result = request.Send();
1177 if (result != B_OK)
1178 return result;
1179
1180 ReplyInterpreter& reply = request.Reply();
1181
1182 reply.PutFH();
1183 result = reply.LockU(lockInfo);
1184
1185 ownerLocker.Unlock();
1186 if (HandleErrors(attempt, reply.NFS4Error(), serv, cookie))
1187 continue;
1188
1189 if (result != B_OK)
1190 return result;
1191
1192 return B_OK;
1193 } while (true);
1194 }
1195
1196