xref: /haiku/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp (revision 6b9a91eb660bb88915f900678e3f3609b71135d1)
12a73e4c5SPawel Dziepak /*
22a73e4c5SPawel Dziepak  * Copyright 2012 Haiku, Inc. All rights reserved.
32a73e4c5SPawel Dziepak  * Distributed under the terms of the MIT License.
42a73e4c5SPawel Dziepak  *
52a73e4c5SPawel Dziepak  * Authors:
62a73e4c5SPawel Dziepak  *		Paweł Dziepak, pdziepak@quarnos.org
72a73e4c5SPawel Dziepak  */
82a73e4c5SPawel Dziepak 
92a73e4c5SPawel Dziepak 
102a73e4c5SPawel Dziepak #include "Inode.h"
112a73e4c5SPawel Dziepak 
122a73e4c5SPawel Dziepak #include <dirent.h>
132a73e4c5SPawel Dziepak #include <string.h>
142a73e4c5SPawel Dziepak 
15b2cea80cSPawel Dziepak #include "IdMap.h"
162a73e4c5SPawel Dziepak #include "Request.h"
172a73e4c5SPawel Dziepak #include "RootInode.h"
182a73e4c5SPawel Dziepak 
192a73e4c5SPawel Dziepak 
202a73e4c5SPawel Dziepak status_t
212a73e4c5SPawel Dziepak Inode::CreateDir(const char* name, int mode)
222a73e4c5SPawel Dziepak {
238f57d30eSPawel Dziepak 	bool badOwner = false;
248f57d30eSPawel Dziepak 
252a73e4c5SPawel Dziepak 	do {
2600a8558cSPawel Dziepak 		RPC::Server* serv = fFileSystem->Server();
272a73e4c5SPawel Dziepak 		Request request(serv);
282a73e4c5SPawel Dziepak 		RequestBuilder& req = request.Builder();
292a73e4c5SPawel Dziepak 
30a28e8732SPawel Dziepak 		req.PutFH(fInfo.fHandle);
312a73e4c5SPawel Dziepak 
32b2cea80cSPawel Dziepak 		uint32 i = 0;
33b2cea80cSPawel Dziepak 		AttrValue cattr[3];
34b2cea80cSPawel Dziepak 		cattr[i].fAttribute = FATTR4_MODE;
35b2cea80cSPawel Dziepak 		cattr[i].fFreePointer = false;
36b2cea80cSPawel Dziepak 		cattr[i].fData.fValue32 = mode;
37b2cea80cSPawel Dziepak 		i++;
38b2cea80cSPawel Dziepak 
3900a8558cSPawel Dziepak 		if (!badOwner && fFileSystem->IsAttrSupported(FATTR4_OWNER)) {
40b2cea80cSPawel Dziepak 			cattr[i].fAttribute = FATTR4_OWNER;
41b2cea80cSPawel Dziepak 			cattr[i].fFreePointer = true;
42b2cea80cSPawel Dziepak 			cattr[i].fData.fPointer = gIdMapper->GetOwner(getuid());
43b2cea80cSPawel Dziepak 			i++;
44ed097dd0SPawel Dziepak 		}
45b2cea80cSPawel Dziepak 
4600a8558cSPawel Dziepak 		if (!badOwner && fFileSystem->IsAttrSupported(FATTR4_OWNER_GROUP)) {
47b2cea80cSPawel Dziepak 			cattr[i].fAttribute = FATTR4_OWNER_GROUP;
48b2cea80cSPawel Dziepak 			cattr[i].fFreePointer = true;
49b2cea80cSPawel Dziepak 			cattr[i].fData.fPointer = gIdMapper->GetOwnerGroup(getgid());
50b2cea80cSPawel Dziepak 			i++;
51ed097dd0SPawel Dziepak 		}
52b2cea80cSPawel Dziepak 
53b2cea80cSPawel Dziepak 		req.Create(NF4DIR, name, cattr, i);
542a73e4c5SPawel Dziepak 
552a73e4c5SPawel Dziepak 		status_t result = request.Send();
562a73e4c5SPawel Dziepak 		if (result != B_OK)
572a73e4c5SPawel Dziepak 			return result;
582a73e4c5SPawel Dziepak 
592a73e4c5SPawel Dziepak 		ReplyInterpreter& reply = request.Reply();
602a73e4c5SPawel Dziepak 
618f57d30eSPawel Dziepak 		if (reply.NFS4Error() == NFS4ERR_BADOWNER) {
628f57d30eSPawel Dziepak 			badOwner = true;
638f57d30eSPawel Dziepak 			continue;
648f57d30eSPawel Dziepak 		}
652a73e4c5SPawel Dziepak 		if (_HandleErrors(reply.NFS4Error(), serv))
662a73e4c5SPawel Dziepak 			continue;
672a73e4c5SPawel Dziepak 
682a73e4c5SPawel Dziepak 		reply.PutFH();
692a73e4c5SPawel Dziepak 
707b6f80feSPawel Dziepak 		uint64 before, after;
717b6f80feSPawel Dziepak 		bool atomic;
727b6f80feSPawel Dziepak 		result = reply.Create(&before, &after, atomic);
737b6f80feSPawel Dziepak 
747b6f80feSPawel Dziepak 		fFileSystem->Root()->MakeInfoInvalid();
757b6f80feSPawel Dziepak 
767b6f80feSPawel Dziepak 		if (fCache->Lock() == B_OK) {
777b6f80feSPawel Dziepak 			if (atomic && fCache->ChangeInfo() == before) {
787b6f80feSPawel Dziepak 				// TODO: update cache
797b6f80feSPawel Dziepak 				//fCache->AddEntry(name, );
807b6f80feSPawel Dziepak 				fCache->SetChangeInfo(after);
817b6f80feSPawel Dziepak 			} else if (fCache->ChangeInfo() != before)
827b6f80feSPawel Dziepak 				fCache->Trash();
837b6f80feSPawel Dziepak 			fCache->Unlock();
847b6f80feSPawel Dziepak 		}
857b6f80feSPawel Dziepak 
867b6f80feSPawel Dziepak 		return result;
872a73e4c5SPawel Dziepak 	} while (true);
882a73e4c5SPawel Dziepak }
892a73e4c5SPawel Dziepak 
902a73e4c5SPawel Dziepak 
912a73e4c5SPawel Dziepak status_t
922a73e4c5SPawel Dziepak Inode::OpenDir(OpenDirCookie* cookie)
932a73e4c5SPawel Dziepak {
942a73e4c5SPawel Dziepak 	if (fType != NF4DIR)
952a73e4c5SPawel Dziepak 		return B_NOT_A_DIRECTORY;
962a73e4c5SPawel Dziepak 
972a73e4c5SPawel Dziepak 	do {
9800a8558cSPawel Dziepak 		RPC::Server* serv = fFileSystem->Server();
992a73e4c5SPawel Dziepak 		Request request(serv);
1002a73e4c5SPawel Dziepak 		RequestBuilder& req = request.Builder();
1012a73e4c5SPawel Dziepak 
102a28e8732SPawel Dziepak 		req.PutFH(fInfo.fHandle);
1032a73e4c5SPawel Dziepak 		req.Access();
1042a73e4c5SPawel Dziepak 
1052a73e4c5SPawel Dziepak 		status_t result = request.Send();
1062a73e4c5SPawel Dziepak 		if (result != B_OK)
1072a73e4c5SPawel Dziepak 			return result;
1082a73e4c5SPawel Dziepak 
1092a73e4c5SPawel Dziepak 		ReplyInterpreter& reply = request.Reply();
1102a73e4c5SPawel Dziepak 
1112a73e4c5SPawel Dziepak 		if (_HandleErrors(reply.NFS4Error(), serv))
1122a73e4c5SPawel Dziepak 			continue;
1132a73e4c5SPawel Dziepak 
1142a73e4c5SPawel Dziepak 		reply.PutFH();
1152a73e4c5SPawel Dziepak 
1162a73e4c5SPawel Dziepak 		uint32 allowed;
1172a73e4c5SPawel Dziepak 		result = reply.Access(NULL, &allowed);
1182a73e4c5SPawel Dziepak 		if (result != B_OK)
1192a73e4c5SPawel Dziepak 			return result;
1202a73e4c5SPawel Dziepak 
1212a73e4c5SPawel Dziepak 		if (allowed & ACCESS4_READ != ACCESS4_READ)
1222a73e4c5SPawel Dziepak 			return B_PERMISSION_DENIED;
1232a73e4c5SPawel Dziepak 
12400a8558cSPawel Dziepak 		cookie->fFileSystem = fFileSystem;
125*6b9a91ebSPawel Dziepak 		cookie->fSpecial = 0;
12609dbdd36SPawel Dziepak 		cookie->fSnapshot = NULL;
12709dbdd36SPawel Dziepak 		cookie->fCurrent = NULL;
12809dbdd36SPawel Dziepak 		cookie->fEOF = false;
1292a73e4c5SPawel Dziepak 
13078fc85a6SPawel Dziepak 		fFileSystem->Root()->MakeInfoInvalid();
13178fc85a6SPawel Dziepak 
1322a73e4c5SPawel Dziepak 		return B_OK;
1332a73e4c5SPawel Dziepak 	} while (true);
1342a73e4c5SPawel Dziepak }
1352a73e4c5SPawel Dziepak 
1362a73e4c5SPawel Dziepak 
1372a73e4c5SPawel Dziepak status_t
1382a73e4c5SPawel Dziepak Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie,
13909dbdd36SPawel Dziepak 	bool* eof, uint64* change, uint64* dirCookie, uint64* dirCookieVerf)
1402a73e4c5SPawel Dziepak {
1412a73e4c5SPawel Dziepak 	do {
14200a8558cSPawel Dziepak 		RPC::Server* serv = fFileSystem->Server();
1432a73e4c5SPawel Dziepak 		Request request(serv);
1442a73e4c5SPawel Dziepak 		RequestBuilder& req = request.Builder();
1452a73e4c5SPawel Dziepak 
146a28e8732SPawel Dziepak 		req.PutFH(fInfo.fHandle);
1472a73e4c5SPawel Dziepak 
14809dbdd36SPawel Dziepak 		Attribute dirAttr[] = { FATTR4_CHANGE };
14909dbdd36SPawel Dziepak 		if (*change == 0)
15009dbdd36SPawel Dziepak 			req.GetAttr(dirAttr, sizeof(dirAttr) / sizeof(Attribute));
15109dbdd36SPawel Dziepak 
1522a73e4c5SPawel Dziepak 		Attribute attr[] = { FATTR4_FSID, FATTR4_FILEID };
15309dbdd36SPawel Dziepak 		req.ReadDir(*count, *dirCookie, *dirCookieVerf, attr,
1542a73e4c5SPawel Dziepak 			sizeof(attr) / sizeof(Attribute));
1552a73e4c5SPawel Dziepak 
15609dbdd36SPawel Dziepak 		req.GetAttr(dirAttr, sizeof(dirAttr) / sizeof(Attribute));
15709dbdd36SPawel Dziepak 
1582a73e4c5SPawel Dziepak 		status_t result = request.Send(cookie);
1592a73e4c5SPawel Dziepak 		if (result != B_OK)
1602a73e4c5SPawel Dziepak 			return result;
1612a73e4c5SPawel Dziepak 
1622a73e4c5SPawel Dziepak 		ReplyInterpreter& reply = request.Reply();
1632a73e4c5SPawel Dziepak 
1642a73e4c5SPawel Dziepak 		if (_HandleErrors(reply.NFS4Error(), serv))
1652a73e4c5SPawel Dziepak 			continue;
1662a73e4c5SPawel Dziepak 
1672a73e4c5SPawel Dziepak 		reply.PutFH();
16809dbdd36SPawel Dziepak 
16909dbdd36SPawel Dziepak 		AttrValue* before = NULL;
17009dbdd36SPawel Dziepak 		uint32 attrCount;
17109dbdd36SPawel Dziepak 		if (*change == 0) {
17209dbdd36SPawel Dziepak 			result = reply.GetAttr(&before, &attrCount);
17309dbdd36SPawel Dziepak 			if (result != B_OK)
17409dbdd36SPawel Dziepak 				return result;
17509dbdd36SPawel Dziepak 		}
17609dbdd36SPawel Dziepak 
17709dbdd36SPawel Dziepak 		result = reply.ReadDir(dirCookie, dirCookieVerf, dirents,
1782a73e4c5SPawel Dziepak 			count, eof);
17909dbdd36SPawel Dziepak 		if (result != B_OK) {
18009dbdd36SPawel Dziepak 			delete[] before;
18109dbdd36SPawel Dziepak 			return result;
18209dbdd36SPawel Dziepak 		}
18309dbdd36SPawel Dziepak 
18409dbdd36SPawel Dziepak 		AttrValue* after;
18509dbdd36SPawel Dziepak 		result = reply.GetAttr(&after, &attrCount);
18609dbdd36SPawel Dziepak 		if (result != B_OK) {
18709dbdd36SPawel Dziepak 			delete[] before;
18809dbdd36SPawel Dziepak 			return result;
18909dbdd36SPawel Dziepak 		}
19009dbdd36SPawel Dziepak 
19109dbdd36SPawel Dziepak 		if (*change == 0 && before[0].fData.fValue64 == after[0].fData.fValue64
19209dbdd36SPawel Dziepak 			|| *change == after[0].fData.fValue64)
19309dbdd36SPawel Dziepak 			*change = after[0].fData.fValue64;
19409dbdd36SPawel Dziepak 		else
19509dbdd36SPawel Dziepak 			return B_ERROR;
19609dbdd36SPawel Dziepak 
19709dbdd36SPawel Dziepak 		delete[] before;
19809dbdd36SPawel Dziepak 		delete[] after;
19909dbdd36SPawel Dziepak 
20009dbdd36SPawel Dziepak 		return B_OK;
2012a73e4c5SPawel Dziepak 	} while (true);
2022a73e4c5SPawel Dziepak }
2032a73e4c5SPawel Dziepak 
2042a73e4c5SPawel Dziepak 
2052a73e4c5SPawel Dziepak status_t
2062a73e4c5SPawel Dziepak Inode::_FillDirEntry(struct dirent* de, ino_t id, const char* name, uint32 pos,
2072a73e4c5SPawel Dziepak 	uint32 size)
2082a73e4c5SPawel Dziepak {
2092a73e4c5SPawel Dziepak 	uint32 nameSize = strlen(name);
2102a73e4c5SPawel Dziepak 	const uint32 entSize = sizeof(struct dirent);
2112a73e4c5SPawel Dziepak 
2122a73e4c5SPawel Dziepak 	if (pos + entSize + nameSize > size)
2132a73e4c5SPawel Dziepak 		return B_BUFFER_OVERFLOW;
2142a73e4c5SPawel Dziepak 
21500a8558cSPawel Dziepak 	de->d_dev = fFileSystem->DevId();
2162a73e4c5SPawel Dziepak 	de->d_ino = id;
2172a73e4c5SPawel Dziepak 	de->d_reclen = entSize + nameSize;
2182a73e4c5SPawel Dziepak 	if (de->d_reclen % 8 != 0)
2192a73e4c5SPawel Dziepak 		de->d_reclen += 8 - de->d_reclen % 8;
2202a73e4c5SPawel Dziepak 
2212a73e4c5SPawel Dziepak 	strcpy(de->d_name, name);
2222a73e4c5SPawel Dziepak 
2232a73e4c5SPawel Dziepak 	return B_OK;
2242a73e4c5SPawel Dziepak }
2252a73e4c5SPawel Dziepak 
2262a73e4c5SPawel Dziepak 
2272a73e4c5SPawel Dziepak status_t
2282a73e4c5SPawel Dziepak Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size)
2292a73e4c5SPawel Dziepak {
2302a73e4c5SPawel Dziepak 	do {
23100a8558cSPawel Dziepak 		RPC::Server* serv = fFileSystem->Server();
2322a73e4c5SPawel Dziepak 		Request request(serv);
2332a73e4c5SPawel Dziepak 		RequestBuilder& req = request.Builder();
2342a73e4c5SPawel Dziepak 
235a28e8732SPawel Dziepak 		req.PutFH(fInfo.fHandle);
2362a73e4c5SPawel Dziepak 		req.LookUpUp();
2372a73e4c5SPawel Dziepak 		req.GetFH();
2382a73e4c5SPawel Dziepak 
23900a8558cSPawel Dziepak 		if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) {
2402a73e4c5SPawel Dziepak 			Attribute attr[] = { FATTR4_FILEID };
2412a73e4c5SPawel Dziepak 			req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
2422a73e4c5SPawel Dziepak 		}
2432a73e4c5SPawel Dziepak 
2442a73e4c5SPawel Dziepak 		status_t result = request.Send();
2452a73e4c5SPawel Dziepak 		if (result != B_OK)
2462a73e4c5SPawel Dziepak 			return result;
2472a73e4c5SPawel Dziepak 
2482a73e4c5SPawel Dziepak 		ReplyInterpreter& reply = request.Reply();
2492a73e4c5SPawel Dziepak 
2502a73e4c5SPawel Dziepak 		if (_HandleErrors(reply.NFS4Error(), serv))
2512a73e4c5SPawel Dziepak 			continue;
2522a73e4c5SPawel Dziepak 
2532a73e4c5SPawel Dziepak 		reply.PutFH();
2542a73e4c5SPawel Dziepak 		result = reply.LookUpUp();
2552a73e4c5SPawel Dziepak 		if (result != B_OK)
2562a73e4c5SPawel Dziepak 			return result;
2572a73e4c5SPawel Dziepak 
25800a8558cSPawel Dziepak 		FileHandle fh;
2592a73e4c5SPawel Dziepak 		reply.GetFH(&fh);
2602a73e4c5SPawel Dziepak 
2612a73e4c5SPawel Dziepak 		uint64 fileId;
26200a8558cSPawel Dziepak 		if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) {
2632a73e4c5SPawel Dziepak 			AttrValue* values;
2642a73e4c5SPawel Dziepak 			uint32 count;
2652a73e4c5SPawel Dziepak 			reply.GetAttr(&values, &count);
2662a73e4c5SPawel Dziepak 			if (result != B_OK)
2672a73e4c5SPawel Dziepak 				return result;
2682a73e4c5SPawel Dziepak 
2692a73e4c5SPawel Dziepak 			fileId = values[0].fData.fValue64;
2702a73e4c5SPawel Dziepak 			delete[] values;
2712a73e4c5SPawel Dziepak 		} else
27200a8558cSPawel Dziepak 			fileId = fFileSystem->AllocFileId();
2732a73e4c5SPawel Dziepak 
2742a73e4c5SPawel Dziepak 		return _FillDirEntry(de, _FileIdToInoT(fileId), "..", pos, size);
2752a73e4c5SPawel Dziepak 	} while (true);
2762a73e4c5SPawel Dziepak }
2772a73e4c5SPawel Dziepak 
27809dbdd36SPawel Dziepak 
2792a73e4c5SPawel Dziepak status_t
28009dbdd36SPawel Dziepak Inode::_GetDirSnapshot(DirectoryCacheSnapshot** _snapshot,
28109dbdd36SPawel Dziepak 	OpenDirCookie* cookie, uint64* _change)
2822a73e4c5SPawel Dziepak {
28309dbdd36SPawel Dziepak 	DirectoryCacheSnapshot* snapshot = new DirectoryCacheSnapshot;
28409dbdd36SPawel Dziepak 	if (snapshot == NULL)
28509dbdd36SPawel Dziepak 		return B_NO_MEMORY;
28609dbdd36SPawel Dziepak 
28709dbdd36SPawel Dziepak 	uint64 change = 0;
28809dbdd36SPawel Dziepak 	uint64 dirCookie = 0;
28909dbdd36SPawel Dziepak 	uint64 dirCookieVerf = 0;
2902a73e4c5SPawel Dziepak 	bool eof = false;
2912a73e4c5SPawel Dziepak 
29209dbdd36SPawel Dziepak 	while (!eof) {
29309dbdd36SPawel Dziepak 		uint32 count;
29409dbdd36SPawel Dziepak 		DirEntry* dirents;
2952a73e4c5SPawel Dziepak 
29609dbdd36SPawel Dziepak 		status_t result = _ReadDirOnce(&dirents, &count, cookie, &eof, &change,
29709dbdd36SPawel Dziepak 			&dirCookie, &dirCookieVerf);
29809dbdd36SPawel Dziepak 		if (result != B_OK) {
29909dbdd36SPawel Dziepak 			delete snapshot;
30009dbdd36SPawel Dziepak 			return result;
30109dbdd36SPawel Dziepak 		}
30209dbdd36SPawel Dziepak 
30309dbdd36SPawel Dziepak 		uint32 i;
30409dbdd36SPawel Dziepak 		for (i = 0; i < count; i++) {
30509dbdd36SPawel Dziepak 
30609dbdd36SPawel Dziepak 			// FATTR4_FSID is mandatory
30709dbdd36SPawel Dziepak 			void* data = dirents[i].fAttrs[0].fData.fPointer;
30809dbdd36SPawel Dziepak 			FileSystemId* fsid = reinterpret_cast<FileSystemId*>(data);
30909dbdd36SPawel Dziepak 			if (*fsid != fFileSystem->FsId())
31009dbdd36SPawel Dziepak 				continue;
31109dbdd36SPawel Dziepak 
31209dbdd36SPawel Dziepak 			ino_t id;
31309dbdd36SPawel Dziepak 			if (dirents[i].fAttrCount == 2)
31409dbdd36SPawel Dziepak 				id = _FileIdToInoT(dirents[i].fAttrs[1].fData.fValue64);
31509dbdd36SPawel Dziepak 			else
31609dbdd36SPawel Dziepak 				id = _FileIdToInoT(fFileSystem->AllocFileId());
31709dbdd36SPawel Dziepak 
31809dbdd36SPawel Dziepak 			NameCacheEntry* entry = new NameCacheEntry(dirents[i].fName, id);
31909dbdd36SPawel Dziepak 			if (entry == NULL || entry->fName == NULL) {
32009dbdd36SPawel Dziepak 				if (entry->fName == NULL)
32109dbdd36SPawel Dziepak 					delete entry;
32209dbdd36SPawel Dziepak 				delete snapshot;
32309dbdd36SPawel Dziepak 				delete[] dirents;
32409dbdd36SPawel Dziepak 				return B_NO_MEMORY;
32509dbdd36SPawel Dziepak 			}
32609dbdd36SPawel Dziepak 			snapshot->fEntries.Add(entry);
32709dbdd36SPawel Dziepak 		}
32809dbdd36SPawel Dziepak 
32909dbdd36SPawel Dziepak 		delete[] dirents;
33009dbdd36SPawel Dziepak 	}
33109dbdd36SPawel Dziepak 
33209dbdd36SPawel Dziepak 	*_snapshot = snapshot;
33309dbdd36SPawel Dziepak 	*_change = change;
33409dbdd36SPawel Dziepak 
33509dbdd36SPawel Dziepak 	return B_OK;
33609dbdd36SPawel Dziepak }
33709dbdd36SPawel Dziepak 
3382a73e4c5SPawel Dziepak 
33909dbdd36SPawel Dziepak status_t
34009dbdd36SPawel Dziepak Inode::ReadDir(void* _buffer, uint32 size, uint32* _count,
34109dbdd36SPawel Dziepak 	OpenDirCookie* cookie)
34209dbdd36SPawel Dziepak {
34309dbdd36SPawel Dziepak 	if (cookie->fEOF) {
34409dbdd36SPawel Dziepak 		*_count = 0;
34509dbdd36SPawel Dziepak 		return B_OK;
34609dbdd36SPawel Dziepak 	}
3472a73e4c5SPawel Dziepak 
34809dbdd36SPawel Dziepak 	status_t result;
34909dbdd36SPawel Dziepak 	if (cookie->fSnapshot == NULL) {
35009dbdd36SPawel Dziepak 		fFileSystem->Revalidator().Lock();
35109dbdd36SPawel Dziepak 		if (fCache->Lock() != B_OK) {
35209dbdd36SPawel Dziepak 			fCache->ResetAndLock();
35309dbdd36SPawel Dziepak 		} else {
35409dbdd36SPawel Dziepak 			fFileSystem->Revalidator().RemoveDirectory(fCache);
35509dbdd36SPawel Dziepak 		}
35609dbdd36SPawel Dziepak 
35709dbdd36SPawel Dziepak 		cookie->fSnapshot = fCache->GetSnapshot();
35809dbdd36SPawel Dziepak 		if (cookie->fSnapshot == NULL) {
35909dbdd36SPawel Dziepak 			uint64 change;
36009dbdd36SPawel Dziepak 			result = _GetDirSnapshot(&cookie->fSnapshot, cookie, &change);
36109dbdd36SPawel Dziepak 			if (result != B_OK) {
36209dbdd36SPawel Dziepak 				fCache->Unlock();
36309dbdd36SPawel Dziepak 				fFileSystem->Revalidator().Unlock();
3642a73e4c5SPawel Dziepak 				return result;
36509dbdd36SPawel Dziepak 			}
36609dbdd36SPawel Dziepak 			fCache->ValidateChangeInfo(change);
36709dbdd36SPawel Dziepak 			fCache->SetSnapshot(cookie->fSnapshot);
36809dbdd36SPawel Dziepak 		}
36909dbdd36SPawel Dziepak 		cookie->fSnapshot->AcquireReference();
37009dbdd36SPawel Dziepak 		fFileSystem->Revalidator().AddDirectory(fCache);
37109dbdd36SPawel Dziepak 		fCache->Unlock();
37209dbdd36SPawel Dziepak 		fFileSystem->Revalidator().Unlock();
37309dbdd36SPawel Dziepak 	}
3742a73e4c5SPawel Dziepak 
37509dbdd36SPawel Dziepak 	char* buffer = reinterpret_cast<char*>(_buffer);
37609dbdd36SPawel Dziepak 	uint32 pos = 0;
377*6b9a91ebSPawel Dziepak 	uint32 i = 0;
378*6b9a91ebSPawel Dziepak 	bool overflow = false;
379*6b9a91ebSPawel Dziepak 
380*6b9a91ebSPawel Dziepak 	if (cookie->fSpecial == 0 && i < *_count) {
381*6b9a91ebSPawel Dziepak 		struct dirent* de = reinterpret_cast<dirent*>(buffer + pos);
382*6b9a91ebSPawel Dziepak 
383*6b9a91ebSPawel Dziepak 		status_t result;
384*6b9a91ebSPawel Dziepak 		result = _FillDirEntry(de, fInfo.fFileId, ".", pos, size);
385*6b9a91ebSPawel Dziepak 
386*6b9a91ebSPawel Dziepak 		if (result == B_BUFFER_OVERFLOW)
387*6b9a91ebSPawel Dziepak 			overflow = true;
388*6b9a91ebSPawel Dziepak 		else if (result == B_OK) {
389*6b9a91ebSPawel Dziepak 			pos += de->d_reclen;
390*6b9a91ebSPawel Dziepak 			i++;
391*6b9a91ebSPawel Dziepak 			cookie->fSpecial++;
392*6b9a91ebSPawel Dziepak 		} else
393*6b9a91ebSPawel Dziepak 			return result;
394*6b9a91ebSPawel Dziepak 	}
395*6b9a91ebSPawel Dziepak 
396*6b9a91ebSPawel Dziepak 	if (cookie->fSpecial == 1 && i < *_count) {
397*6b9a91ebSPawel Dziepak 		struct dirent* de = reinterpret_cast<dirent*>(buffer + pos);
398*6b9a91ebSPawel Dziepak 
399*6b9a91ebSPawel Dziepak 		status_t result;
400*6b9a91ebSPawel Dziepak 		if (strcmp(fInfo.fName, "/"))
401*6b9a91ebSPawel Dziepak 			result = _ReadDirUp(de, pos, size);
402*6b9a91ebSPawel Dziepak 		else
403*6b9a91ebSPawel Dziepak 			result = _FillDirEntry(de, _FileIdToInoT(fInfo.fFileId), "..", pos, size);
404*6b9a91ebSPawel Dziepak 
405*6b9a91ebSPawel Dziepak 		if (result == B_BUFFER_OVERFLOW)
406*6b9a91ebSPawel Dziepak 			overflow = true;
407*6b9a91ebSPawel Dziepak 		else if (result == B_OK) {
408*6b9a91ebSPawel Dziepak 			pos += de->d_reclen;
409*6b9a91ebSPawel Dziepak 			i++;
410*6b9a91ebSPawel Dziepak 			cookie->fSpecial++;
411*6b9a91ebSPawel Dziepak 		} else
412*6b9a91ebSPawel Dziepak 			return result;
413*6b9a91ebSPawel Dziepak 	}
41409dbdd36SPawel Dziepak 
41509dbdd36SPawel Dziepak 	MutexLocker _(cookie->fSnapshot->fLock);
416*6b9a91ebSPawel Dziepak 	for (; !overflow && i < *_count; i++) {
4172a73e4c5SPawel Dziepak 		struct dirent* de = reinterpret_cast<dirent*>(buffer + pos);
4182a73e4c5SPawel Dziepak 
41909dbdd36SPawel Dziepak 		if (cookie->fCurrent == NULL)
42009dbdd36SPawel Dziepak 			cookie->fCurrent = cookie->fSnapshot->fEntries.Head();
42109dbdd36SPawel Dziepak 		else {
42209dbdd36SPawel Dziepak 			cookie->fCurrent
42309dbdd36SPawel Dziepak 				= cookie->fSnapshot->fEntries.GetNext(cookie->fCurrent);
42409dbdd36SPawel Dziepak 		}
4252a73e4c5SPawel Dziepak 
42609dbdd36SPawel Dziepak 		if (cookie->fCurrent == NULL) {
42709dbdd36SPawel Dziepak 			cookie->fEOF = true;
42809dbdd36SPawel Dziepak 			break;
42909dbdd36SPawel Dziepak 		}
4302a73e4c5SPawel Dziepak 
43109dbdd36SPawel Dziepak 		if (_FillDirEntry(de, cookie->fCurrent->fNode, cookie->fCurrent->fName,
43209dbdd36SPawel Dziepak 			pos, size) == B_BUFFER_OVERFLOW) {
4332a73e4c5SPawel Dziepak 			overflow = true;
4342a73e4c5SPawel Dziepak 			break;
4352a73e4c5SPawel Dziepak 		}
4362a73e4c5SPawel Dziepak 
4372a73e4c5SPawel Dziepak 		pos += de->d_reclen;
4382a73e4c5SPawel Dziepak 	}
4392a73e4c5SPawel Dziepak 
44009dbdd36SPawel Dziepak 	if (i == 0 && overflow)
4412a73e4c5SPawel Dziepak 		return B_BUFFER_OVERFLOW;
4422a73e4c5SPawel Dziepak 
44309dbdd36SPawel Dziepak 	*_count = i;
4442a73e4c5SPawel Dziepak 
4452a73e4c5SPawel Dziepak 	return B_OK;
4462a73e4c5SPawel Dziepak }
4472a73e4c5SPawel Dziepak 
448