BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / kernel / file_systems / nfs4 / RequestBuilder.cpp
blobe518f86681ddde65335e15785299af6b662e0049
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 "RequestBuilder.h"
12 #include <errno.h>
13 #include <string.h>
15 #include <util/Random.h>
17 #include "Cookie.h"
18 #include "OpenState.h"
19 #include "RPCCallback.h"
20 #include "RPCCallbackServer.h"
23 RequestBuilder::RequestBuilder(Procedure proc)
25 fOpCount(0),
26 fProcedure(proc),
27 fRequest(NULL)
29 _InitHeader();
33 RequestBuilder::~RequestBuilder()
35 delete fRequest;
39 void
40 RequestBuilder::_InitHeader()
42 fRequest = RPC::Call::Create(fProcedure, RPC::Auth::CreateSys(),
43 RPC::Auth::CreateNone());
45 if (fRequest == NULL)
46 return;
48 if (fProcedure == ProcCompound) {
49 fRequest->Stream().AddOpaque(NULL, 0);
50 fRequest->Stream().AddUInt(0);
52 fOpCountPosition = fRequest->Stream().Current();
53 fRequest->Stream().AddUInt(0);
58 status_t
59 RequestBuilder::Access()
61 if (fProcedure != ProcCompound)
62 return B_BAD_VALUE;
63 if (fRequest == NULL)
64 return B_NO_MEMORY;
66 fRequest->Stream().AddUInt(OpAccess);
67 fRequest->Stream().AddUInt(ACCESS4_READ | ACCESS4_LOOKUP | ACCESS4_MODIFY
68 | ACCESS4_EXTEND | ACCESS4_DELETE | ACCESS4_EXECUTE);
69 fOpCount++;
71 return B_OK;
75 status_t
76 RequestBuilder::Close(uint32 seq, const uint32* id, uint32 stateSeq)
78 if (fProcedure != ProcCompound)
79 return B_BAD_VALUE;
80 if (fRequest == NULL)
81 return B_NO_MEMORY;
83 fRequest->Stream().AddUInt(OpClose);
84 fRequest->Stream().AddUInt(seq);
85 fRequest->Stream().AddUInt(stateSeq);
86 fRequest->Stream().AddUInt(id[0]);
87 fRequest->Stream().AddUInt(id[1]);
88 fRequest->Stream().AddUInt(id[2]);
90 fOpCount++;
92 return B_OK;
96 status_t
97 RequestBuilder::Commit(uint64 offset, uint32 count)
99 if (fProcedure != ProcCompound)
100 return B_BAD_VALUE;
101 if (fRequest == NULL)
102 return B_NO_MEMORY;
104 fRequest->Stream().AddUInt(OpCommit);
105 fRequest->Stream().AddUHyper(offset);
106 fRequest->Stream().AddUInt(count);
108 fOpCount++;
110 return B_OK;
114 status_t
115 RequestBuilder::Create(FileType type, const char* name, AttrValue* attr,
116 uint32 count, const char* path)
118 if (fProcedure != ProcCompound)
119 return B_BAD_VALUE;
120 if (fRequest == NULL)
121 return B_NO_MEMORY;
122 if (type == NF4LNK && path == NULL)
123 return B_BAD_VALUE;
124 if (name == NULL)
125 return B_BAD_VALUE;
126 if (type == NF4BLK || type == NF4CHR)
127 return B_BAD_VALUE;
129 fRequest->Stream().AddUInt(OpCreate);
130 fRequest->Stream().AddUInt(type);
131 if (type == NF4LNK)
132 fRequest->Stream().AddString(path);
133 fRequest->Stream().AddString(name);
134 _EncodeAttrs(fRequest->Stream(), attr, count);
136 fOpCount++;
138 return B_OK;
142 status_t
143 RequestBuilder::DelegReturn(const uint32* id, uint32 seq)
145 if (fProcedure != ProcCompound)
146 return B_BAD_VALUE;
147 if (fRequest == NULL)
148 return B_NO_MEMORY;
150 fRequest->Stream().AddUInt(OpDelegReturn);
152 fRequest->Stream().AddUInt(seq);
153 fRequest->Stream().AddUInt(id[0]);
154 fRequest->Stream().AddUInt(id[1]);
155 fRequest->Stream().AddUInt(id[2]);
157 fOpCount++;
159 return B_OK;
163 status_t
164 RequestBuilder::GetAttr(Attribute* attrs, uint32 count)
166 if (fProcedure != ProcCompound)
167 return B_BAD_VALUE;
168 if (fRequest == NULL)
169 return B_NO_MEMORY;
171 fRequest->Stream().AddUInt(OpGetAttr);
172 _AttrBitmap(fRequest->Stream(), attrs, count);
174 fOpCount++;
176 return B_OK;
180 status_t
181 RequestBuilder::GetFH()
183 if (fProcedure != ProcCompound)
184 return B_BAD_VALUE;
185 if (fRequest == NULL)
186 return B_NO_MEMORY;
188 fRequest->Stream().AddUInt(OpGetFH);
189 fOpCount++;
191 return B_OK;
195 void
196 RequestBuilder::_GenerateLockOwner(XDR::WriteStream& stream,
197 OpenState* state, LockOwner* owner)
199 stream.AddUHyper(state->fClientID);
201 uint64 lockOwner[2];
202 lockOwner[0] = owner->fOwner;
203 lockOwner[1] = state->fInfo.fFileId;
204 stream.AddOpaque(lockOwner, sizeof(lockOwner));
208 status_t
209 RequestBuilder::Lock(OpenState* state, LockInfo* lock, uint32* sequence,
210 bool reclaim)
212 if (fProcedure != ProcCompound)
213 return B_BAD_VALUE;
214 if (fRequest == NULL)
215 return B_NO_MEMORY;
217 fRequest->Stream().AddUInt(OpLock);
219 fRequest->Stream().AddInt(lock->fType);
220 fRequest->Stream().AddBoolean(reclaim);
222 fRequest->Stream().AddUHyper(lock->fStart);
223 fRequest->Stream().AddUHyper(lock->fLength);
225 if (lock->fOwner->fStateId[0] == 0 && lock->fOwner->fStateId[1] == 0
226 && lock->fOwner->fStateId[2] == 0) {
228 fRequest->Stream().AddBoolean(true); // new lock owner
230 // open seq stateid
231 fRequest->Stream().AddUInt(*sequence);
232 fRequest->Stream().AddUInt(state->fStateSeq);
233 fRequest->Stream().AddUInt(state->fStateID[0]);
234 fRequest->Stream().AddUInt(state->fStateID[1]);
235 fRequest->Stream().AddUInt(state->fStateID[2]);
237 // lock seq owner
238 fRequest->Stream().AddUInt(lock->fOwner->fSequence++);
239 _GenerateLockOwner(fRequest->Stream(), state, lock->fOwner);
241 } else {
242 fRequest->Stream().AddBoolean(false); // old lock owner
243 (*sequence)--;
245 // lock stateid seq
246 fRequest->Stream().AddUInt(lock->fOwner->fStateSeq);
247 fRequest->Stream().AddUInt(lock->fOwner->fStateId[0]);
248 fRequest->Stream().AddUInt(lock->fOwner->fStateId[1]);
249 fRequest->Stream().AddUInt(lock->fOwner->fStateId[2]);
251 fRequest->Stream().AddUInt(lock->fOwner->fSequence++);
254 fOpCount++;
256 return B_OK;
260 status_t
261 RequestBuilder::LockT(LockType type, uint64 pos, uint64 len,
262 OpenState* state)
264 if (fProcedure != ProcCompound)
265 return B_BAD_VALUE;
266 if (fRequest == NULL)
267 return B_NO_MEMORY;
269 fRequest->Stream().AddUInt(OpLockT);
271 fRequest->Stream().AddInt(type);
273 fRequest->Stream().AddUHyper(pos);
274 fRequest->Stream().AddUHyper(len);
276 fRequest->Stream().AddUHyper(state->fClientID);
278 uint32 owner = find_thread(NULL);
279 fRequest->Stream().AddOpaque(&owner, sizeof(owner));
281 fOpCount++;
283 return B_OK;
287 status_t
288 RequestBuilder::LockU(LockInfo* lock)
290 if (fProcedure != ProcCompound)
291 return B_BAD_VALUE;
292 if (fRequest == NULL)
293 return B_NO_MEMORY;
295 fRequest->Stream().AddUInt(OpLockU);
297 fRequest->Stream().AddInt(lock->fType);
299 fRequest->Stream().AddUInt(lock->fOwner->fSequence++);
300 fRequest->Stream().AddUInt(lock->fOwner->fStateSeq);
301 fRequest->Stream().AddUInt(lock->fOwner->fStateId[0]);
302 fRequest->Stream().AddUInt(lock->fOwner->fStateId[1]);
303 fRequest->Stream().AddUInt(lock->fOwner->fStateId[2]);
305 fRequest->Stream().AddUHyper(lock->fStart);
306 fRequest->Stream().AddUHyper(lock->fLength);
308 fOpCount++;
310 return B_OK;
314 status_t
315 RequestBuilder::Link(const char* name)
317 if (fProcedure != ProcCompound)
318 return B_BAD_VALUE;
319 if (fRequest == NULL)
320 return B_NO_MEMORY;
321 if (name == NULL)
322 return B_BAD_VALUE;
324 fRequest->Stream().AddUInt(OpLink);
325 fRequest->Stream().AddString(name);
326 fOpCount++;
328 return B_OK;
332 status_t
333 RequestBuilder::LookUp(const char* name)
335 if (fProcedure != ProcCompound)
336 return B_BAD_VALUE;
337 if (fRequest == NULL)
338 return B_NO_MEMORY;
339 if (name == NULL)
340 return B_BAD_VALUE;
342 fRequest->Stream().AddUInt(OpLookUp);
343 fRequest->Stream().AddString(name, strlen(name));
344 fOpCount++;
346 return B_OK;
350 status_t
351 RequestBuilder::LookUpUp()
353 if (fProcedure != ProcCompound)
354 return B_BAD_VALUE;
355 if (fRequest == NULL)
356 return B_NO_MEMORY;
358 fRequest->Stream().AddUInt(OpLookUpUp);
359 fOpCount++;
361 return B_OK;
365 status_t
366 RequestBuilder::Nverify(AttrValue* attr, uint32 count)
368 if (fProcedure != ProcCompound)
369 return B_BAD_VALUE;
370 if (fRequest == NULL)
371 return B_NO_MEMORY;
373 fRequest->Stream().AddUInt(OpNverify);
374 _EncodeAttrs(fRequest->Stream(), attr, count);
376 fOpCount++;
378 return B_OK;
382 status_t
383 RequestBuilder::Open(OpenClaim claim, uint32 seq, uint32 access, uint64 id,
384 OpenCreate oc, uint64 ownerId, const char* name, AttrValue* attr,
385 uint32 count, bool excl, OpenDelegation delegationType)
387 if (fProcedure != ProcCompound)
388 return B_BAD_VALUE;
389 if (fRequest == NULL)
390 return B_NO_MEMORY;
392 fRequest->Stream().AddUInt(OpOpen);
393 fRequest->Stream().AddUInt(seq);
394 fRequest->Stream().AddUInt(access);
395 fRequest->Stream().AddUInt(0); // deny none
396 fRequest->Stream().AddUHyper(id);
398 char owner[128];
399 int pos = 0;
400 *(uint64*)(owner + pos) = ownerId;
401 pos += sizeof(uint64);
403 fRequest->Stream().AddOpaque(owner, pos);
405 fRequest->Stream().AddUInt(oc);
406 if (oc == OPEN4_CREATE) {
407 fRequest->Stream().AddInt(excl ? GUARDED4 : UNCHECKED4);
408 _EncodeAttrs(fRequest->Stream(), attr, count);
411 fRequest->Stream().AddUInt(claim);
412 switch (claim) {
413 case CLAIM_NULL:
414 fRequest->Stream().AddString(name, strlen(name));
415 break;
416 case CLAIM_PREVIOUS:
417 fRequest->Stream().AddUInt(delegationType);
418 break;
419 default:
420 return B_UNSUPPORTED;
423 fOpCount++;
425 return B_OK;
429 status_t
430 RequestBuilder::OpenConfirm(uint32 seq, const uint32* id, uint32 stateSeq)
432 if (fProcedure != ProcCompound)
433 return B_BAD_VALUE;
434 if (fRequest == NULL)
435 return B_NO_MEMORY;
437 fRequest->Stream().AddUInt(OpOpenConfirm);
438 fRequest->Stream().AddUInt(stateSeq);
439 fRequest->Stream().AddUInt(id[0]);
440 fRequest->Stream().AddUInt(id[1]);
441 fRequest->Stream().AddUInt(id[2]);
442 fRequest->Stream().AddUInt(seq);
444 fOpCount++;
446 return B_OK;
450 status_t
451 RequestBuilder::OpenAttrDir(bool create)
453 if (fProcedure != ProcCompound)
454 return B_BAD_VALUE;
455 if (fRequest == NULL)
456 return B_NO_MEMORY;
458 fRequest->Stream().AddUInt(OpOpenAttrDir);
459 fRequest->Stream().AddBoolean(create);
461 fOpCount++;
463 return B_OK;
467 status_t
468 RequestBuilder::PutFH(const FileHandle& fh)
470 if (fProcedure != ProcCompound)
471 return B_BAD_VALUE;
472 if (fRequest == NULL)
473 return B_NO_MEMORY;
475 fRequest->Stream().AddUInt(OpPutFH);
476 fRequest->Stream().AddOpaque(fh.fData, fh.fSize);
477 fOpCount++;
479 return B_OK;
483 status_t
484 RequestBuilder::PutRootFH()
486 if (fProcedure != ProcCompound)
487 return B_BAD_VALUE;
488 if (fRequest == NULL)
489 return B_NO_MEMORY;
491 fRequest->Stream().AddUInt(OpPutRootFH);
492 fOpCount++;
494 return B_OK;
498 status_t
499 RequestBuilder::Read(const uint32* id, uint32 stateSeq, uint64 pos, uint32 len)
501 if (fProcedure != ProcCompound)
502 return B_BAD_VALUE;
503 if (fRequest == NULL)
504 return B_NO_MEMORY;
506 fRequest->Stream().AddUInt(OpRead);
507 fRequest->Stream().AddUInt(stateSeq);
508 fRequest->Stream().AddUInt(id[0]);
509 fRequest->Stream().AddUInt(id[1]);
510 fRequest->Stream().AddUInt(id[2]);
511 fRequest->Stream().AddUHyper(pos);
512 fRequest->Stream().AddUInt(len);
514 fOpCount++;
516 return B_OK;
520 status_t
521 RequestBuilder::ReadDir(uint64 cookie, uint64 cookieVerf, Attribute* attrs,
522 uint32 attrCount)
524 if (fProcedure != ProcCompound)
525 return B_BAD_VALUE;
526 if (fRequest == NULL)
527 return B_NO_MEMORY;
529 fRequest->Stream().AddUInt(OpReadDir);
530 fRequest->Stream().AddUHyper(cookie);
531 fRequest->Stream().AddUHyper(cookieVerf);
533 // consider predicting this values basing on count or buffer size
534 fRequest->Stream().AddUInt(0x2000);
535 fRequest->Stream().AddUInt(0x8000);
536 _AttrBitmap(fRequest->Stream(), attrs, attrCount);
538 fOpCount++;
540 return B_OK;
544 status_t
545 RequestBuilder::ReadLink()
547 if (fProcedure != ProcCompound)
548 return B_BAD_VALUE;
549 if (fRequest == NULL)
550 return B_NO_MEMORY;
552 fRequest->Stream().AddUInt(OpReadLink);
554 fOpCount++;
556 return B_OK;
560 status_t
561 RequestBuilder::Remove(const char* file)
563 if (fProcedure != ProcCompound)
564 return B_BAD_VALUE;
565 if (fRequest == NULL)
566 return B_NO_MEMORY;
568 fRequest->Stream().AddUInt(OpRemove);
569 fRequest->Stream().AddString(file);
571 fOpCount++;
573 return B_OK;
577 status_t
578 RequestBuilder::Rename(const char* from, const char* to)
580 if (fProcedure != ProcCompound)
581 return B_BAD_VALUE;
582 if (fRequest == NULL)
583 return B_NO_MEMORY;
585 fRequest->Stream().AddUInt(OpRename);
586 fRequest->Stream().AddString(from);
587 fRequest->Stream().AddString(to);
589 fOpCount++;
591 return B_OK;
595 status_t
596 RequestBuilder::Renew(uint64 clientId)
598 if (fProcedure != ProcCompound)
599 return B_BAD_VALUE;
600 if (fRequest == NULL)
601 return B_NO_MEMORY;
603 fRequest->Stream().AddUInt(OpRenew);
604 fRequest->Stream().AddUHyper(clientId);
606 fOpCount++;
608 return B_OK;
612 status_t
613 RequestBuilder::SaveFH()
615 if (fProcedure != ProcCompound)
616 return B_BAD_VALUE;
617 if (fRequest == NULL)
618 return B_NO_MEMORY;
620 fRequest->Stream().AddUInt(OpSaveFH);
621 fOpCount++;
623 return B_OK;
627 status_t
628 RequestBuilder::SetAttr(const uint32* id, uint32 stateSeq, AttrValue* attr,
629 uint32 count)
631 if (fProcedure != ProcCompound)
632 return B_BAD_VALUE;
633 if (fRequest == NULL)
634 return B_NO_MEMORY;
636 fRequest->Stream().AddUInt(OpSetAttr);
637 fRequest->Stream().AddUInt(stateSeq);
638 if (id != NULL) {
639 fRequest->Stream().AddUInt(id[0]);
640 fRequest->Stream().AddUInt(id[1]);
641 fRequest->Stream().AddUInt(id[2]);
642 } else {
643 fRequest->Stream().AddUInt(0);
644 fRequest->Stream().AddUInt(0);
645 fRequest->Stream().AddUInt(0);
647 _EncodeAttrs(fRequest->Stream(), attr, count);
649 fOpCount++;
651 return B_OK;
655 status_t
656 RequestBuilder::SetClientID(RPC::Server* server)
658 if (fProcedure != ProcCompound)
659 return B_BAD_VALUE;
660 if (fRequest == NULL)
661 return B_NO_MEMORY;
663 fRequest->Stream().AddUInt(OpSetClientID);
664 uint64 verifier = get_random<uint64>();
665 fRequest->Stream().AddUHyper(verifier);
667 status_t result = _GenerateClientId(fRequest->Stream(), server);
668 if (result != B_OK)
669 return result;
671 fRequest->Stream().AddUInt(0x40000000);
673 if (server->GetCallback() != NULL) {
674 ASSERT(server->GetCallback()->CBServer() != NULL);
676 uint32 id = server->GetCallback()->ID();
678 PeerAddress local = server->GetCallback()->CBServer()->LocalID();
679 PeerAddress servAddr = server->LocalID();
680 servAddr.SetPort(local.Port());
682 fRequest->Stream().AddString(local.ProtocolString());
684 char* uAddr = servAddr.UniversalAddress();
685 if (uAddr == NULL)
686 return B_NO_MEMORY;
687 fRequest->Stream().AddString(uAddr);
688 free(uAddr);
690 fRequest->Stream().AddUInt(id);
691 } else {
692 fRequest->Stream().AddString("");
693 fRequest->Stream().AddString("");
694 fRequest->Stream().AddUInt(0);
697 fOpCount++;
699 return B_OK;
703 status_t
704 RequestBuilder::_GenerateClientId(XDR::WriteStream& stream,
705 const RPC::Server* server)
707 char id[512] = "HAIKU:kernel:";
708 int pos = strlen(id);
710 PeerAddress local = server->LocalID();
712 memcpy(id + pos, server->ID().InAddr(), server->ID().InAddrSize());
713 pos += sizeof(server->ID().InAddrSize());
715 memcpy(id + pos, local.InAddr(), local.InAddrSize());
716 pos += sizeof(local.InAddrSize());
718 *(uint16*)(id + pos) = server->ID().Port();
719 pos += sizeof(uint16);
721 *(uint16*)(id + pos) = server->ID().fProtocol;
722 pos += sizeof(uint16);
724 stream.AddOpaque(id, pos);
726 return B_OK;
730 status_t
731 RequestBuilder::SetClientIDConfirm(uint64 id, uint64 ver)
733 if (fProcedure != ProcCompound)
734 return B_BAD_VALUE;
735 if (fRequest == NULL)
736 return B_NO_MEMORY;
738 fRequest->Stream().AddUInt(OpSetClientIDConfirm);
739 fRequest->Stream().AddUHyper(id);
740 fRequest->Stream().AddUHyper(ver);
742 fOpCount++;
744 return B_OK;
748 status_t
749 RequestBuilder::Verify(AttrValue* attr, uint32 count)
751 if (fProcedure != ProcCompound)
752 return B_BAD_VALUE;
753 if (fRequest == NULL)
754 return B_NO_MEMORY;
756 fRequest->Stream().AddUInt(OpVerify);
757 _EncodeAttrs(fRequest->Stream(), attr, count);
759 fOpCount++;
761 return B_OK;
765 status_t
766 RequestBuilder::Write(const uint32* id, uint32 stateSeq, const void* buffer,
767 uint64 pos, uint32 len, bool stable)
769 if (fProcedure != ProcCompound)
770 return B_BAD_VALUE;
771 if (fRequest == NULL)
772 return B_NO_MEMORY;
774 fRequest->Stream().AddUInt(OpWrite);
775 fRequest->Stream().AddUInt(stateSeq);
776 fRequest->Stream().AddUInt(id[0]);
777 fRequest->Stream().AddUInt(id[1]);
778 fRequest->Stream().AddUInt(id[2]);
779 fRequest->Stream().AddUHyper(pos);
780 fRequest->Stream().AddInt(stable ? FILE_SYNC4 : UNSTABLE4);
781 fRequest->Stream().AddOpaque(buffer, len);
783 fOpCount++;
785 return B_OK;
789 status_t
790 RequestBuilder::ReleaseLockOwner(OpenState* state, LockOwner* owner)
792 if (fProcedure != ProcCompound)
793 return B_BAD_VALUE;
794 if (fRequest == NULL)
795 return B_NO_MEMORY;
797 fRequest->Stream().AddUInt(OpReleaseLockOwner);
798 _GenerateLockOwner(fRequest->Stream(), state, owner);
800 fOpCount++;
802 return B_OK;
806 RPC::Call*
807 RequestBuilder::Request()
809 if (fProcedure == ProcCompound)
810 fRequest->Stream().InsertUInt(fOpCountPosition, fOpCount);
812 if (fRequest == NULL || fRequest->Stream().Error() == B_OK)
813 return fRequest;
814 else
815 return NULL;
819 void
820 RequestBuilder::_AttrBitmap(XDR::WriteStream& stream, Attribute* attrs,
821 uint32 count)
823 // 2 is safe in NFS4, not in NFS4.1 though
824 uint32 bitmap[2];
825 memset(bitmap, 0, sizeof(bitmap));
826 for (uint32 i = 0; i < count; i++) {
827 bitmap[attrs[i] / 32] |= 1 << attrs[i] % 32;
830 uint32 bcount = bitmap[1] != 0 ? 2 : 1;
831 stream.AddUInt(bcount);
832 for (uint32 i = 0; i < bcount; i++)
833 stream.AddUInt(bitmap[i]);
837 void
838 RequestBuilder::_EncodeAttrs(XDR::WriteStream& stream, AttrValue* attr,
839 uint32 count)
841 if (count == 0) {
842 stream.AddUInt(0);
843 stream.AddOpaque(NULL, 0);
844 return;
847 Attribute* attrs
848 = reinterpret_cast<Attribute*>(malloc(sizeof(Attribute) * count));
849 for (uint32 i = 0; i < count; i++)
850 attrs[i] = static_cast<Attribute>(attr[i].fAttribute);
851 _AttrBitmap(stream, attrs, count);
852 free(attrs);
854 uint32 i = 0;
855 XDR::WriteStream str;
856 if (i < count && attr[i].fAttribute == FATTR4_TYPE) {
857 str.AddUInt(attr[i].fData.fValue32);
858 i++;
861 if (i < count && attr[i].fAttribute == FATTR4_SIZE) {
862 str.AddUHyper(attr[i].fData.fValue64);
863 i++;
866 if (i < count && attr[i].fAttribute == FATTR4_FILEHANDLE) {
867 FileHandle* fh = reinterpret_cast<FileHandle*>(attr[i].fData.fPointer);
868 str.AddOpaque(fh->fData, fh->fSize);
869 i++;
872 if (i < count && attr[i].fAttribute == FATTR4_FILEID) {
873 str.AddUHyper(attr[i].fData.fValue64);
874 i++;
877 if (i < count && attr[i].fAttribute == FATTR4_MODE) {
878 str.AddUInt(attr[i].fData.fValue32);
879 i++;
882 if (i < count && attr[i].fAttribute == FATTR4_OWNER) {
883 str.AddString(reinterpret_cast<char*>(attr[i].fData.fPointer));
884 i++;
887 if (i < count && attr[i].fAttribute == FATTR4_OWNER_GROUP) {
888 str.AddString(reinterpret_cast<char*>(attr[i].fData.fPointer));
889 i++;
892 if (i < count && attr[i].fAttribute == FATTR4_TIME_ACCESS_SET) {
893 str.AddInt(1); // SET_TO_CLIENT_TIME4
895 struct timespec* ts
896 = reinterpret_cast<timespec*>(attr[i].fData.fPointer);
897 str.AddHyper(ts->tv_sec);
898 str.AddUInt(ts->tv_nsec);
900 i++;
903 if (i < count && attr[i].fAttribute == FATTR4_TIME_MODIFY_SET) {
904 str.AddInt(1); // SET_TO_CLIENT_TIME4
906 struct timespec* ts
907 = reinterpret_cast<timespec*>(attr[i].fData.fPointer);
908 str.AddHyper(ts->tv_sec);
909 str.AddUInt(ts->tv_nsec);
911 i++;
914 stream.AddOpaque(str);