vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / kernel / file_systems / nfs4 / NFS4Inode.cpp
blob1a3ab1f4a26cfc88f0bf0f3122d525e477b15141
1 /*
2 * Copyright 2012 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Paweł Dziepak, pdziepak@quarnos.org
7 */
10 #include <AutoDeleter.h>
12 #include "IdMap.h"
13 #include "Inode.h"
14 #include "NFS4Inode.h"
15 #include "Request.h"
18 status_t
19 NFS4Inode::GetChangeInfo(uint64* change, bool attrDir)
21 ASSERT(change != NULL);
23 uint32 attempt = 0;
24 do {
25 RPC::Server* serv = fFileSystem->Server();
26 Request request(serv, fFileSystem);
27 RequestBuilder& req = request.Builder();
29 if (attrDir)
30 req.PutFH(fInfo.fAttrDir);
31 else
32 req.PutFH(fInfo.fHandle);
34 Attribute attr[] = { FATTR4_CHANGE };
35 req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
37 status_t result = request.Send();
38 if (result != B_OK)
39 return result;
41 ReplyInterpreter& reply = request.Reply();
43 if (HandleErrors(attempt, reply.NFS4Error(), serv))
44 continue;
46 reply.PutFH();
48 AttrValue* values;
49 uint32 count;
50 result = reply.GetAttr(&values, &count);
51 if (result != B_OK)
52 return result;
54 // FATTR4_CHANGE is mandatory
55 *change = values[0].fData.fValue64;
56 delete[] values;
58 return B_OK;
59 } while (true);
63 status_t
64 NFS4Inode::CommitWrites()
66 uint32 attempt = 0;
67 do {
68 RPC::Server* serv = fFileSystem->Server();
69 Request request(serv, fFileSystem);
70 RequestBuilder& req = request.Builder();
72 req.PutFH(fInfo.fHandle);
73 req.Commit(0, 0);
75 status_t result = request.Send();
76 if (result != B_OK)
77 return result;
79 ReplyInterpreter& reply = request.Reply();
81 if (HandleErrors(attempt, reply.NFS4Error(), serv))
82 continue;
84 reply.PutFH();
85 return reply.Commit();
86 } while (true);
90 status_t
91 NFS4Inode::Access(uint32* allowed)
93 ASSERT(allowed != NULL);
95 uint32 attempt = 0;
96 do {
97 RPC::Server* serv = fFileSystem->Server();
98 Request request(serv, fFileSystem);
99 RequestBuilder& req = request.Builder();
101 req.PutFH(fInfo.fHandle);
102 req.Access();
104 status_t result = request.Send();
105 if (result != B_OK)
106 return result;
108 ReplyInterpreter& reply = request.Reply();
110 if (HandleErrors(attempt, reply.NFS4Error(), serv))
111 continue;
113 reply.PutFH();
115 return reply.Access(NULL, allowed);
116 } while (true);
120 status_t
121 NFS4Inode::LookUp(const char* name, uint64* change, uint64* fileID,
122 FileHandle* handle, bool parent)
124 ASSERT(name != NULL);
126 uint32 attempt = 0;
127 do {
128 RPC::Server* serv = fFileSystem->Server();
129 Request request(serv, fFileSystem);
130 RequestBuilder& req = request.Builder();
132 (void)parent; // TODO: add support for named attributes
133 req.PutFH(fInfo.fHandle);
135 if (change != NULL) {
136 Attribute dirAttr[] = { FATTR4_CHANGE };
137 req.GetAttr(dirAttr, sizeof(dirAttr) / sizeof(Attribute));
140 if (!strcmp(name, ".."))
141 req.LookUpUp();
142 else
143 req.LookUp(name);
145 if (handle != NULL)
146 req.GetFH();
148 Attribute attr[] = { FATTR4_FSID, FATTR4_FILEID };
149 req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
151 status_t result = request.Send();
152 if (result != B_OK)
153 return result;
155 ReplyInterpreter& reply = request.Reply();
157 if (HandleErrors(attempt, reply.NFS4Error(), serv))
158 continue;
160 reply.PutFH();
162 AttrValue* values;
163 uint32 count;
164 if (change != NULL) {
165 result = reply.GetAttr(&values, &count);
166 if (result != B_OK)
167 return result;
169 *change = values[0].fData.fValue64;
170 delete[] values;
173 if (!strcmp(name, ".."))
174 result = reply.LookUpUp();
175 else
176 result = reply.LookUp();
177 if (result != B_OK)
178 return result;
180 if (handle != NULL)
181 reply.GetFH(handle);
183 result = reply.GetAttr(&values, &count);
184 if (result != B_OK)
185 return result;
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;
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;
202 delete[] values;
204 return B_OK;
205 } while (true);
209 status_t
210 NFS4Inode::Link(Inode* dir, const char* name, ChangeInfo* changeInfo)
212 ASSERT(dir != NULL);
213 ASSERT(name != NULL);
214 ASSERT(changeInfo != NULL);
216 uint32 attempt = 0;
217 do {
218 RPC::Server* serv = fFileSystem->Server();
219 Request request(serv, fFileSystem);
220 RequestBuilder& req = request.Builder();
222 req.PutFH(fInfo.fHandle);
223 req.SaveFH();
224 req.PutFH(dir->fInfo.fHandle);
225 req.Link(name);
227 status_t result = request.Send();
228 if (result != B_OK)
229 return result;
231 ReplyInterpreter& reply = request.Reply();
233 if (HandleErrors(attempt, reply.NFS4Error(), serv))
234 continue;
236 reply.PutFH();
237 reply.SaveFH();
238 reply.PutFH();
240 return reply.Link(&changeInfo->fBefore, &changeInfo->fAfter,
241 changeInfo->fAtomic);
242 } while (true);
246 status_t
247 NFS4Inode::ReadLink(void* buffer, size_t* length)
249 ASSERT(buffer != NULL);
250 ASSERT(length != NULL);
252 uint32 attempt = 0;
253 do {
254 RPC::Server* serv = fFileSystem->Server();
255 Request request(serv, fFileSystem);
256 RequestBuilder& req = request.Builder();
258 req.PutFH(fInfo.fHandle);
259 req.ReadLink();
261 status_t result = request.Send();
262 if (result != B_OK)
263 return result;
265 ReplyInterpreter& reply = request.Reply();
267 if (HandleErrors(attempt, reply.NFS4Error(), serv))
268 continue;
270 reply.PutFH();
272 uint32 size;
273 result = reply.ReadLink(buffer, &size, *length);
274 *length = static_cast<size_t>(size);
276 return result;
277 } while (true);
281 status_t
282 NFS4Inode::GetStat(AttrValue** values, uint32* count, OpenAttrCookie* cookie)
284 ASSERT(values != NULL);
285 ASSERT(count != NULL);
287 uint32 attempt = 0;
288 do {
289 RPC::Server* serv = fFileSystem->Server();
290 Request request(serv, fFileSystem);
291 RequestBuilder& req = request.Builder();
293 if (cookie != NULL)
294 req.PutFH(cookie->fOpenState->fInfo.fHandle);
295 else
296 req.PutFH(fInfo.fHandle);
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));
304 status_t result = request.Send(cookie);
305 if (result != B_OK)
306 return result;
308 ReplyInterpreter& reply = request.Reply();
310 if (HandleErrors(attempt, reply.NFS4Error(), serv))
311 continue;
313 reply.PutFH();
315 return reply.GetAttr(values, count);
316 } while (true);
320 status_t
321 NFS4Inode::WriteStat(OpenState* state, AttrValue* attrs, uint32 attrCount)
323 ASSERT(attrs != NULL);
325 uint32 attempt = 0;
326 do {
327 RPC::Server* serv = fFileSystem->Server();
328 Request request(serv, fFileSystem);
329 RequestBuilder& req = request.Builder();
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);
339 status_t result = request.Send();
340 if (result != B_OK)
341 return result;
343 ReplyInterpreter& reply = request.Reply();
345 if (HandleErrors(attempt, reply.NFS4Error(), serv))
346 continue;
348 reply.PutFH();
349 result = reply.SetAttr();
351 if (result != B_OK)
352 return result;
354 return B_OK;
355 } while (true);
359 status_t
360 NFS4Inode::RenameNode(Inode* from, Inode* to, const char* fromName,
361 const char* toName, ChangeInfo* fromChange, ChangeInfo* toChange,
362 uint64* fileID, bool attribute)
364 ASSERT(from != NULL);
365 ASSERT(to != NULL);
366 ASSERT(fromName != NULL);
367 ASSERT(toName != NULL);
368 ASSERT(fromChange != NULL);
369 ASSERT(toChange != NULL);
371 uint32 attempt = 0;
372 do {
373 RPC::Server* server = from->fFileSystem->Server();
374 Request request(server, from->fFileSystem);
375 RequestBuilder& req = request.Builder();
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);
388 if (!attribute) {
389 req.LookUp(toName);
390 Attribute attr[] = { FATTR4_FILEID };
391 req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
394 status_t result = request.Send();
395 if (result != B_OK)
396 return result;
398 ReplyInterpreter& reply = request.Reply();
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;
409 reply.PutFH();
410 reply.SaveFH();
411 reply.PutFH();
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;
419 if (!attribute) {
420 result = reply.LookUp();
421 if (result != B_OK)
422 return result;
424 AttrValue* values;
425 uint32 count;
426 result = reply.GetAttr(&values, &count);
427 if (result != B_OK)
428 return result;
430 if (count == 0)
431 *fileID = from->fFileSystem->AllocFileId();
432 else
433 *fileID = values[0].fData.fValue64;
435 delete[] values;
438 return B_OK;
439 } while (true);
443 status_t
444 NFS4Inode::CreateFile(const char* name, int mode, int perms, OpenState* state,
445 ChangeInfo* changeInfo, uint64* fileID, FileHandle* handle,
446 OpenDelegationData* delegation)
448 ASSERT(name != NULL);
449 ASSERT(state != NULL);
450 ASSERT(changeInfo != NULL);
451 ASSERT(handle != NULL);
452 ASSERT(delegation != NULL);
454 bool confirm;
455 status_t result;
457 uint32 attempt = 0;
458 uint32 sequence = fFileSystem->OpenOwnerSequenceLock();
459 do {
460 state->fClientID = fFileSystem->NFSServer()->ClientId();
462 RPC::Server* serv = fFileSystem->Server();
463 Request request(serv, fFileSystem);
464 RequestBuilder& req = request.Builder();
466 req.PutFH(fInfo.fHandle);
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++;
476 cattr[i].fAttribute = FATTR4_MODE;
477 cattr[i].fFreePointer = false;
478 cattr[i].fData.fValue32 = perms;
479 i++;
481 req.Open(CLAIM_NULL, sequence, sModeToAccess(mode),
482 state->fClientID, OPEN4_CREATE, fFileSystem->OpenOwner(), name,
483 cattr, i, (mode & O_EXCL) == O_EXCL);
485 req.GetFH();
487 if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) {
488 Attribute attr[] = { FATTR4_FILEID };
489 req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
492 result = request.Send();
493 if (result != B_OK) {
494 fFileSystem->OpenOwnerSequenceUnlock(sequence);
495 return result;
498 ReplyInterpreter& reply = request.Reply();
500 result = reply.PutFH();
501 if (result == B_OK)
502 sequence += IncrementSequence(reply.NFS4Error());
504 if (HandleErrors(attempt, reply.NFS4Error(), serv, NULL, state,
505 &sequence)) {
506 continue;
509 result = reply.Open(state->fStateID, &state->fStateSeq, &confirm,
510 delegation, changeInfo);
511 if (result != B_OK) {
512 fFileSystem->OpenOwnerSequenceUnlock(sequence);
513 return result;
516 reply.GetFH(handle);
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;
527 *fileID = values[0].fData.fValue64;
529 delete[] values;
530 } else
531 *fileID = fFileSystem->AllocFileId();
533 break;
534 } while (true);
536 state->fOpened = true;
538 if (confirm)
539 result = ConfirmOpen(*handle, state, &sequence);
541 fFileSystem->OpenOwnerSequenceUnlock(sequence);
542 return result;
546 status_t
547 NFS4Inode::OpenFile(OpenState* state, int mode, OpenDelegationData* delegation)
549 ASSERT(state != NULL);
550 ASSERT(delegation != NULL);
552 bool confirm;
553 status_t result;
555 uint32 attempt = 0;
556 uint32 sequence = fFileSystem->OpenOwnerSequenceLock();
557 do {
558 state->fClientID = fFileSystem->NFSServer()->ClientId();
560 RPC::Server* serv = fFileSystem->Server();
561 Request request(serv, fFileSystem);
562 RequestBuilder& req = request.Builder();
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);
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();
591 result = request.Send();
592 if (result != B_OK) {
593 fFileSystem->OpenOwnerSequenceUnlock(sequence);
594 return result;
597 ReplyInterpreter& reply = request.Reply();
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;
610 result = reply.Verify();
611 if (result != B_OK && reply.NFS4Error() == NFS4ERR_NOT_SAME) {
612 fFileSystem->OpenOwnerSequenceUnlock(sequence);
613 return B_ENTRY_NOT_FOUND;
617 result = reply.PutFH();
618 if (result == B_OK)
619 sequence += IncrementSequence(reply.NFS4Error());
621 if (HandleErrors(attempt, reply.NFS4Error(), serv, NULL, state,
622 &sequence)) {
623 continue;
626 result = reply.Open(state->fStateID, &state->fStateSeq, &confirm,
627 delegation);
628 if (result != B_OK) {
629 fFileSystem->OpenOwnerSequenceUnlock(sequence);
630 return result;
633 FileHandle handle;
634 result = reply.GetFH(&handle);
635 if (result != B_OK) {
636 fFileSystem->OpenOwnerSequenceUnlock(sequence);
637 return result;
640 break;
641 } while (true);
643 state->fOpened = true;
645 if (confirm)
646 result = ConfirmOpen(fInfo.fHandle, state, &sequence);
648 fFileSystem->OpenOwnerSequenceUnlock(sequence);
649 return result;
653 status_t
654 NFS4Inode::OpenAttr(OpenState* state, const char* name, int mode,
655 OpenDelegationData* delegation, bool create)
657 ASSERT(name != NULL);
658 ASSERT(state != NULL);
659 ASSERT(delegation != NULL);
661 bool confirm;
662 status_t result;
664 uint32 attempt = 0;
665 uint32 sequence = fFileSystem->OpenOwnerSequenceLock();
666 do {
667 state->fClientID = fFileSystem->NFSServer()->ClientId();
669 RPC::Server* serv = fFileSystem->Server();
670 Request request(serv, fFileSystem);
671 RequestBuilder& req = request.Builder();
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();
679 result = request.Send();
680 if (result != B_OK) {
681 fFileSystem->OpenOwnerSequenceUnlock(sequence);
682 return result;
685 ReplyInterpreter& reply = request.Reply();
687 result = reply.PutFH();
688 if (result == B_OK)
689 sequence += IncrementSequence(reply.NFS4Error());
691 if (HandleErrors(attempt, reply.NFS4Error(), serv, NULL, state,
692 &sequence)) {
693 continue;
696 result = reply.Open(state->fStateID, &state->fStateSeq, &confirm,
697 delegation);
699 reply.GetFH(&state->fInfo.fHandle);
701 if (result != B_OK) {
702 fFileSystem->OpenOwnerSequenceUnlock(sequence);
703 return result;
706 break;
707 } while (true);
709 state->fOpened = true;
711 if (confirm)
712 result = ConfirmOpen(state->fInfo.fHandle, state, &sequence);
714 fFileSystem->OpenOwnerSequenceUnlock(sequence);
715 return result;
719 status_t
720 NFS4Inode::ReadFile(OpenStateCookie* cookie, OpenState* state, uint64 position,
721 uint32* length, void* buffer, bool* eof)
723 ASSERT(state != NULL);
724 ASSERT(length != NULL);
725 ASSERT(buffer != NULL);
726 ASSERT(eof != NULL);
728 uint32 attempt = 0;
729 do {
730 RPC::Server* serv = fFileSystem->Server();
731 Request request(serv, fFileSystem);
732 RequestBuilder& req = request.Builder();
734 req.PutFH(state->fInfo.fHandle);
735 req.Read(state->fStateID, state->fStateSeq, position, *length);
737 status_t result = request.Send(cookie);
738 if (result != B_OK)
739 return result;
741 ReplyInterpreter& reply = request.Reply();
743 if (HandleErrors(attempt, reply.NFS4Error(), serv, cookie, state))
744 continue;
746 reply.PutFH();
747 result = reply.Read(buffer, length, eof);
748 if (result != B_OK)
749 return result;
751 return B_OK;
752 } while (true);
756 status_t
757 NFS4Inode::WriteFile(OpenStateCookie* cookie, OpenState* state, uint64 position,
758 uint32* length, const void* buffer, bool commit)
760 ASSERT(state != NULL);
761 ASSERT(length != NULL);
762 ASSERT(buffer != NULL);
764 uint32 attempt = 0;
765 do {
766 RPC::Server* serv = fFileSystem->Server();
767 Request request(serv, fFileSystem);
768 RequestBuilder& req = request.Builder();
770 req.PutFH(state->fInfo.fHandle);
772 req.Write(state->fStateID, state->fStateSeq, buffer, position, *length,
773 commit);
775 status_t result = request.Send(cookie);
776 if (result != B_OK)
777 return result;
779 ReplyInterpreter& reply = request.Reply();
781 if (HandleErrors(attempt, reply.NFS4Error(), serv, cookie, state))
782 continue;
784 reply.PutFH();
786 result = reply.Write(length);
787 if (result != B_OK)
788 return result;
790 return B_OK;
791 } while (true);
795 status_t
796 NFS4Inode::CreateObject(const char* name, const char* path, int mode,
797 FileType type, ChangeInfo* changeInfo, uint64* fileID, FileHandle* handle,
798 bool parent)
800 ASSERT(name != NULL);
801 ASSERT(changeInfo != NULL);
802 ASSERT(handle != NULL);
804 uint32 attempt = 0;
805 do {
806 RPC::Server* serv = fFileSystem->Server();
807 Request request(serv, fFileSystem);
808 RequestBuilder& req = request.Builder();
810 (void)parent; // TODO: support named attributes
811 req.PutFH(fInfo.fHandle);
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++;
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;
831 req.GetFH();
833 if (fileID != NULL) {
834 Attribute attr[] = { FATTR4_FILEID };
835 req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
838 status_t result = request.Send();
839 if (result != B_OK)
840 return result;
842 ReplyInterpreter& reply = request.Reply();
844 if (HandleErrors(attempt, reply.NFS4Error(), serv))
845 continue;
847 reply.PutFH();
848 result = reply.Create(&changeInfo->fBefore, &changeInfo->fAfter,
849 changeInfo->fAtomic);
850 if (result != B_OK)
851 return result;
853 result = reply.GetFH(handle);
854 if (result != B_OK)
855 return result;
857 if (fileID != NULL) {
858 AttrValue* values;
859 uint32 count;
860 result = reply.GetAttr(&values, &count);
861 if (result != B_OK)
862 return result;
864 if (count == 0)
865 *fileID = fFileSystem->AllocFileId();
866 else
867 *fileID = values[0].fData.fValue64;
869 delete[] values;
872 return B_OK;
873 } while (true);
877 status_t
878 NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo,
879 uint64* fileID)
881 ASSERT(name != NULL);
882 ASSERT(changeInfo != NULL);
884 uint32 attempt = 0;
885 do {
886 RPC::Server* serv = fFileSystem->Server();
887 Request request(serv, fFileSystem);
888 RequestBuilder& req = request.Builder();
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);
901 if (type != NF4NAMEDATTR) {
902 Attribute idAttr[] = { FATTR4_FILEID };
903 req.GetAttr(idAttr, sizeof(idAttr) / sizeof(Attribute));
906 req.PutFH(fInfo.fHandle);
907 req.Remove(name);
909 status_t result = request.Send();
910 if (result != B_OK)
911 return result;
913 ReplyInterpreter& reply = request.Reply();
915 if (HandleErrors(attempt, reply.NFS4Error(), serv))
916 continue;
918 reply.PutFH();
919 result = reply.LookUp();
920 if (result != B_OK)
921 return result;
923 if (type == NF4DIR)
924 result = reply.Verify();
925 else
926 result = reply.Nverify();
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;
935 if (type != NF4NAMEDATTR) {
936 AttrValue* values;
937 uint32 count;
938 result = reply.GetAttr(&values, &count);
939 if (result != B_OK)
940 return result;
942 if (count == 0)
943 *fileID = fFileSystem->AllocFileId();
944 else
945 *fileID = values[0].fData.fValue64;
946 delete[] values;
949 reply.PutFH();
950 return reply.Remove(&changeInfo->fBefore, &changeInfo->fAfter,
951 changeInfo->fAtomic);
952 } while (true);
956 status_t
957 NFS4Inode::ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie,
958 bool* eof, uint64* change, uint64* dirCookie, uint64* dirCookieVerf,
959 bool attribute)
961 ASSERT(dirents != NULL);
962 ASSERT(count != NULL);
963 ASSERT(eof != NULL);
965 uint32 attempt = 0;
966 do {
967 RPC::Server* serv = fFileSystem->Server();
968 Request request(serv, fFileSystem);
969 RequestBuilder& req = request.Builder();
971 if (attribute)
972 req.PutFH(fInfo.fAttrDir);
973 else
974 req.PutFH(fInfo.fHandle);
976 Attribute dirAttr[] = { FATTR4_CHANGE };
977 if (*change == 0)
978 req.GetAttr(dirAttr, sizeof(dirAttr) / sizeof(Attribute));
980 Attribute attr[] = { FATTR4_FSID, FATTR4_FILEID };
981 req.ReadDir(*dirCookie, *dirCookieVerf, attr,
982 sizeof(attr) / sizeof(Attribute));
984 req.GetAttr(dirAttr, sizeof(dirAttr) / sizeof(Attribute));
986 status_t result = request.Send(cookie);
987 if (result != B_OK)
988 return result;
990 ReplyInterpreter& reply = request.Reply();
992 if (HandleErrors(attempt, reply.NFS4Error(), serv))
993 continue;
995 reply.PutFH();
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;
1004 ArrayDeleter<AttrValue> beforeDeleter(before);
1006 result = reply.ReadDir(dirCookie, dirCookieVerf, dirents, count, eof);
1007 if (result != B_OK)
1008 return result;
1010 ArrayDeleter<DirEntry> entriesDeleter(*dirents);
1012 AttrValue* after;
1013 result = reply.GetAttr(&after, &attrCount);
1014 if (result != B_OK)
1015 return result;
1017 ArrayDeleter<AttrValue> afterDeleter(after);
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;
1026 entriesDeleter.Detach();
1027 return B_OK;
1028 } while (true);
1032 status_t
1033 NFS4Inode::OpenAttrDir(FileHandle* handle)
1035 ASSERT(handle != NULL);
1037 uint32 attempt = 0;
1038 do {
1039 RPC::Server* serv = fFileSystem->Server();
1040 Request request(serv, fFileSystem);
1041 RequestBuilder& req = request.Builder();
1043 req.PutFH(fInfo.fHandle);
1044 req.OpenAttrDir(true);
1045 req.GetFH();
1047 status_t result = request.Send();
1048 if (result != B_OK)
1049 return result;
1051 ReplyInterpreter& reply = request.Reply();
1053 if (HandleErrors(attempt, reply.NFS4Error(), serv))
1054 continue;
1056 reply.PutFH();
1057 result = reply.OpenAttrDir();
1058 if (result != B_OK)
1059 return result;
1061 return reply.GetFH(handle);
1062 } while (true);
1066 status_t
1067 NFS4Inode::TestLock(OpenFileCookie* cookie, LockType* type, uint64* position,
1068 uint64* length, bool& conflict)
1070 ASSERT(cookie != NULL);
1071 ASSERT(type != NULL);
1072 ASSERT(position != NULL);
1073 ASSERT(length != NULL);
1075 uint32 attempt = 0;
1076 do {
1077 RPC::Server* serv = fFileSystem->Server();
1078 Request request(serv, fFileSystem);
1079 RequestBuilder& req = request.Builder();
1081 req.PutFH(fInfo.fHandle);
1082 req.LockT(*type, *position, *length, cookie->fOpenState);
1084 status_t result = request.Send();
1085 if (result != B_OK)
1086 return result;
1088 ReplyInterpreter& reply = request.Reply();
1089 if (reply.NFS4Error() != NFS4ERR_DENIED) {
1090 if (HandleErrors(attempt, reply.NFS4Error(), serv, cookie))
1091 continue;
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;
1102 return result;
1103 } while (true);
1105 return B_OK;
1109 status_t
1110 NFS4Inode::AcquireLock(OpenFileCookie* cookie, LockInfo* lockInfo, bool wait)
1112 ASSERT(cookie != NULL);
1113 ASSERT(lockInfo != NULL);
1115 uint32 attempt = 0;
1116 uint32 sequence = fFileSystem->OpenOwnerSequenceLock();
1117 do {
1118 MutexLocker ownerLocker(lockInfo->fOwner->fLock);
1120 RPC::Server* serv = fFileSystem->Server();
1121 Request request(serv, fFileSystem);
1122 RequestBuilder& req = request.Builder();
1124 req.PutFH(fInfo.fHandle);
1125 req.Lock(cookie->fOpenState, lockInfo, &sequence);
1127 status_t result = request.Send();
1128 if (result != B_OK) {
1129 fFileSystem->OpenOwnerSequenceUnlock(sequence);
1130 return result;
1133 ReplyInterpreter& reply = request.Reply();
1135 result = reply.PutFH();
1136 if (result == B_OK)
1137 sequence += IncrementSequence(reply.NFS4Error());
1139 result = reply.Lock(lockInfo);
1141 ownerLocker.Unlock();
1143 if (reply.NFS4Error() != NFS4ERR_DENIED || wait) {
1144 if (HandleErrors(attempt, reply.NFS4Error(), serv, cookie, NULL,
1145 &sequence)) {
1146 continue;
1150 fFileSystem->OpenOwnerSequenceUnlock(sequence);
1151 if (result != B_OK)
1152 return result;
1154 return B_OK;
1155 } while (true);
1159 status_t
1160 NFS4Inode::ReleaseLock(OpenFileCookie* cookie, LockInfo* lockInfo)
1162 ASSERT(cookie != NULL);
1163 ASSERT(lockInfo != NULL);
1165 uint32 attempt = 0;
1166 do {
1167 MutexLocker ownerLocker(lockInfo->fOwner->fLock);
1169 RPC::Server* serv = fFileSystem->Server();
1170 Request request(serv, fFileSystem);
1171 RequestBuilder& req = request.Builder();
1173 req.PutFH(fInfo.fHandle);
1174 req.LockU(lockInfo);
1176 status_t result = request.Send();
1177 if (result != B_OK)
1178 return result;
1180 ReplyInterpreter& reply = request.Reply();
1182 reply.PutFH();
1183 result = reply.LockU(lockInfo);
1185 ownerLocker.Unlock();
1186 if (HandleErrors(attempt, reply.NFS4Error(), serv, cookie))
1187 continue;
1189 if (result != B_OK)
1190 return result;
1192 return B_OK;
1193 } while (true);