xref: /haiku/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp (revision 4d120407378d6ec21783c076cdbb753e81a62eba)
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
21b352cbf6SPawel Dziepak Inode::CreateDir(const char* name, int mode, ino_t* id)
222a73e4c5SPawel Dziepak {
23b352cbf6SPawel Dziepak 	return CreateObject(name, NULL, mode, NF4DIR, id);
242a73e4c5SPawel Dziepak }
252a73e4c5SPawel Dziepak 
262a73e4c5SPawel Dziepak 
272a73e4c5SPawel Dziepak status_t
282a73e4c5SPawel Dziepak Inode::OpenDir(OpenDirCookie* cookie)
292a73e4c5SPawel Dziepak {
301e67a2cdSPawel Dziepak 	ASSERT(cookie != NULL);
311e67a2cdSPawel Dziepak 
322a73e4c5SPawel Dziepak 	if (fType != NF4DIR)
332a73e4c5SPawel Dziepak 		return B_NOT_A_DIRECTORY;
342a73e4c5SPawel Dziepak 
350dbff361SPawel Dziepak 	status_t result = Access(R_OK);
362a73e4c5SPawel Dziepak 	if (result != B_OK)
372a73e4c5SPawel Dziepak 		return result;
382a73e4c5SPawel Dziepak 
3900a8558cSPawel Dziepak 	cookie->fFileSystem = fFileSystem;
406b9a91ebSPawel Dziepak 	cookie->fSpecial = 0;
4109dbdd36SPawel Dziepak 	cookie->fSnapshot = NULL;
4209dbdd36SPawel Dziepak 	cookie->fCurrent = NULL;
4309dbdd36SPawel Dziepak 	cookie->fEOF = false;
44f7c35cf4SPawel Dziepak 	cookie->fAttrDir = false;
45f7c35cf4SPawel Dziepak 
46f7c35cf4SPawel Dziepak 	return B_OK;
47f7c35cf4SPawel Dziepak }
48f7c35cf4SPawel Dziepak 
49f7c35cf4SPawel Dziepak 
50f7c35cf4SPawel Dziepak status_t
51f7c35cf4SPawel Dziepak Inode::OpenAttrDir(OpenDirCookie* cookie)
52f7c35cf4SPawel Dziepak {
531e67a2cdSPawel Dziepak 	ASSERT(cookie != NULL);
541e67a2cdSPawel Dziepak 
55f7c35cf4SPawel Dziepak 	cookie->fFileSystem = fFileSystem;
56f7c35cf4SPawel Dziepak 	cookie->fSpecial = 0;
57f7c35cf4SPawel Dziepak 	cookie->fSnapshot = NULL;
58f7c35cf4SPawel Dziepak 	cookie->fCurrent = NULL;
59f7c35cf4SPawel Dziepak 	cookie->fEOF = false;
60f7c35cf4SPawel Dziepak 	cookie->fAttrDir = true;
61f7c35cf4SPawel Dziepak 
6220d1b02eSPawel Dziepak 	return LoadAttrDirHandle();
6320d1b02eSPawel Dziepak }
6420d1b02eSPawel Dziepak 
6520d1b02eSPawel Dziepak 
6620d1b02eSPawel Dziepak status_t
6720d1b02eSPawel Dziepak Inode::LoadAttrDirHandle()
6820d1b02eSPawel Dziepak {
6970472e11SPawel Dziepak 	if (fInfo.fAttrDir.fSize != 0)
7070472e11SPawel Dziepak 		return B_OK;
71a5ae9b47SPawel Dziepak 
72f7c35cf4SPawel Dziepak 	FileHandle handle;
7370472e11SPawel Dziepak 	status_t result;
74060a4636SPawel Dziepak 
75060a4636SPawel Dziepak 	if (fFileSystem->NamedAttrs()) {
76060a4636SPawel Dziepak 		result = NFS4Inode::OpenAttrDir(&handle);
77060a4636SPawel Dziepak 		if (result == B_OK) {
78060a4636SPawel Dziepak 			fInfo.fAttrDir = handle;
79060a4636SPawel Dziepak 			return B_OK;
80060a4636SPawel Dziepak 		}
81060a4636SPawel Dziepak 
82060a4636SPawel Dziepak 		if (result != B_UNSUPPORTED)
83060a4636SPawel Dziepak 			return result;
84060a4636SPawel Dziepak 
85060a4636SPawel Dziepak 		fFileSystem->SetNamedAttrs(false);
86060a4636SPawel Dziepak 	}
87060a4636SPawel Dziepak 
88060a4636SPawel Dziepak 	if (!fFileSystem->GetConfiguration().fEmulateNamedAttrs)
89060a4636SPawel Dziepak 		return B_UNSUPPORTED;
90060a4636SPawel Dziepak 
9170472e11SPawel Dziepak 	char* attrDir
92da950cb2SPawel Dziepak 		= reinterpret_cast<char*>(malloc(strlen(Name()) + 32));
9370472e11SPawel Dziepak 	if (attrDir == NULL)
9470472e11SPawel Dziepak 		return B_NO_MEMORY;
9570472e11SPawel Dziepak 	strcpy(attrDir, ".");
96da950cb2SPawel Dziepak 	strcat(attrDir, Name());
9770472e11SPawel Dziepak 	strcat(attrDir, "-haiku-attrs");
98f7c35cf4SPawel Dziepak 
9970472e11SPawel Dziepak 	result = NFS4Inode::LookUp(attrDir, NULL, NULL, &handle, true);
10070472e11SPawel Dziepak 	if (result == B_ENTRY_NOT_FOUND) {
10170472e11SPawel Dziepak 		ChangeInfo change;
10270472e11SPawel Dziepak 		struct stat st;
10370472e11SPawel Dziepak 		Stat(&st);
10470472e11SPawel Dziepak 		st.st_mode |= S_IXUSR | S_IXGRP | S_IXOTH;
10570472e11SPawel Dziepak 		result = NFS4Inode::CreateObject(attrDir, NULL, st.st_mode, NF4DIR,
10670472e11SPawel Dziepak 			&change, NULL, &handle, true);
10770472e11SPawel Dziepak 	}
10870472e11SPawel Dziepak 
10970472e11SPawel Dziepak 	free(attrDir);
110a5ae9b47SPawel Dziepak 
111f7c35cf4SPawel Dziepak 	if (result != B_OK)
112f7c35cf4SPawel Dziepak 		return result;
113f7c35cf4SPawel Dziepak 
114f7c35cf4SPawel Dziepak 	fInfo.fAttrDir = handle;
1152a73e4c5SPawel Dziepak 	return B_OK;
1162a73e4c5SPawel Dziepak }
1172a73e4c5SPawel Dziepak 
1182a73e4c5SPawel Dziepak 
1192a73e4c5SPawel Dziepak status_t
1200dbff361SPawel Dziepak Inode::FillDirEntry(struct dirent* de, ino_t id, const char* name, uint32 pos,
1212a73e4c5SPawel Dziepak 	uint32 size)
1222a73e4c5SPawel Dziepak {
1231e67a2cdSPawel Dziepak 	ASSERT(de != NULL);
1241e67a2cdSPawel Dziepak 	ASSERT(name != NULL);
1251e67a2cdSPawel Dziepak 
126eed5b716SPawel Dziepak 	uint32 nameSize = strlen(name) + 1;
1272a73e4c5SPawel Dziepak 	const uint32 entSize = sizeof(struct dirent);
1282a73e4c5SPawel Dziepak 
1292a73e4c5SPawel Dziepak 	if (pos + entSize + nameSize > size)
1302a73e4c5SPawel Dziepak 		return B_BUFFER_OVERFLOW;
1312a73e4c5SPawel Dziepak 
13200a8558cSPawel Dziepak 	de->d_dev = fFileSystem->DevId();
1332a73e4c5SPawel Dziepak 	de->d_ino = id;
1342a73e4c5SPawel Dziepak 	de->d_reclen = entSize + nameSize;
1352a73e4c5SPawel Dziepak 	if (de->d_reclen % 8 != 0)
1362a73e4c5SPawel Dziepak 		de->d_reclen += 8 - de->d_reclen % 8;
1372a73e4c5SPawel Dziepak 
1382a73e4c5SPawel Dziepak 	strcpy(de->d_name, name);
1392a73e4c5SPawel Dziepak 
1402a73e4c5SPawel Dziepak 	return B_OK;
1412a73e4c5SPawel Dziepak }
1422a73e4c5SPawel Dziepak 
1432a73e4c5SPawel Dziepak 
1442a73e4c5SPawel Dziepak status_t
1450dbff361SPawel Dziepak Inode::ReadDirUp(struct dirent* de, uint32 pos, uint32 size)
1462a73e4c5SPawel Dziepak {
1471e67a2cdSPawel Dziepak 	ASSERT(de != NULL);
1481e67a2cdSPawel Dziepak 
1492a73e4c5SPawel Dziepak 	do {
15000a8558cSPawel Dziepak 		RPC::Server* serv = fFileSystem->Server();
151060a4636SPawel Dziepak 		Request request(serv, fFileSystem);
1522a73e4c5SPawel Dziepak 		RequestBuilder& req = request.Builder();
1532a73e4c5SPawel Dziepak 
154a28e8732SPawel Dziepak 		req.PutFH(fInfo.fHandle);
1552a73e4c5SPawel Dziepak 		req.LookUpUp();
1562a73e4c5SPawel Dziepak 		req.GetFH();
1572a73e4c5SPawel Dziepak 
15800a8558cSPawel Dziepak 		if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) {
1592a73e4c5SPawel Dziepak 			Attribute attr[] = { FATTR4_FILEID };
1602a73e4c5SPawel Dziepak 			req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
1612a73e4c5SPawel Dziepak 		}
1622a73e4c5SPawel Dziepak 
1632a73e4c5SPawel Dziepak 		status_t result = request.Send();
1642a73e4c5SPawel Dziepak 		if (result != B_OK)
1652a73e4c5SPawel Dziepak 			return result;
1662a73e4c5SPawel Dziepak 
1672a73e4c5SPawel Dziepak 		ReplyInterpreter& reply = request.Reply();
1682a73e4c5SPawel Dziepak 
1690dbff361SPawel Dziepak 		if (HandleErrors(reply.NFS4Error(), serv))
1702a73e4c5SPawel Dziepak 			continue;
1712a73e4c5SPawel Dziepak 
1722a73e4c5SPawel Dziepak 		reply.PutFH();
1732a73e4c5SPawel Dziepak 		result = reply.LookUpUp();
1742a73e4c5SPawel Dziepak 		if (result != B_OK)
1752a73e4c5SPawel Dziepak 			return result;
1762a73e4c5SPawel Dziepak 
17700a8558cSPawel Dziepak 		FileHandle fh;
1782a73e4c5SPawel Dziepak 		reply.GetFH(&fh);
1792a73e4c5SPawel Dziepak 
1802a73e4c5SPawel Dziepak 		uint64 fileId;
18100a8558cSPawel Dziepak 		if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) {
1822a73e4c5SPawel Dziepak 			AttrValue* values;
1832a73e4c5SPawel Dziepak 			uint32 count;
1842a73e4c5SPawel Dziepak 			reply.GetAttr(&values, &count);
1852a73e4c5SPawel Dziepak 			if (result != B_OK)
1862a73e4c5SPawel Dziepak 				return result;
1872a73e4c5SPawel Dziepak 
1882a73e4c5SPawel Dziepak 			fileId = values[0].fData.fValue64;
1892a73e4c5SPawel Dziepak 			delete[] values;
1902a73e4c5SPawel Dziepak 		} else
19100a8558cSPawel Dziepak 			fileId = fFileSystem->AllocFileId();
1922a73e4c5SPawel Dziepak 
1930dbff361SPawel Dziepak 		return FillDirEntry(de, FileIdToInoT(fileId), "..", pos, size);
1942a73e4c5SPawel Dziepak 	} while (true);
1952a73e4c5SPawel Dziepak }
1962a73e4c5SPawel Dziepak 
19709dbdd36SPawel Dziepak 
19870472e11SPawel Dziepak static char*
19970472e11SPawel Dziepak FileToAttrName(const char* path)
20070472e11SPawel Dziepak {
2011e67a2cdSPawel Dziepak 	ASSERT(path != NULL);
2021e67a2cdSPawel Dziepak 
20370472e11SPawel Dziepak 	char* name = strdup(path);
20470472e11SPawel Dziepak 	if (name == NULL)
20570472e11SPawel Dziepak 		return NULL;
20670472e11SPawel Dziepak 
20770472e11SPawel Dziepak 	char* current = strpbrk(name, "#$");
20870472e11SPawel Dziepak 	while (current != NULL) {
20970472e11SPawel Dziepak 		switch (*current) {
21070472e11SPawel Dziepak 			case '#':
21170472e11SPawel Dziepak 				*current = '/';
21270472e11SPawel Dziepak 				break;
21370472e11SPawel Dziepak 			case '$':
21470472e11SPawel Dziepak 				*current = ':';
21570472e11SPawel Dziepak 				break;
21670472e11SPawel Dziepak 		}
21770472e11SPawel Dziepak 		current = strpbrk(name, "#$");
21870472e11SPawel Dziepak 	}
21970472e11SPawel Dziepak 
22070472e11SPawel Dziepak 	return name;
22170472e11SPawel Dziepak }
22270472e11SPawel Dziepak 
22370472e11SPawel Dziepak 
2242a73e4c5SPawel Dziepak status_t
2250dbff361SPawel Dziepak Inode::GetDirSnapshot(DirectoryCacheSnapshot** _snapshot,
2262314d073SPawel Dziepak 	OpenDirCookie* cookie, uint64* _change, bool attribute)
2272a73e4c5SPawel Dziepak {
2281e67a2cdSPawel Dziepak 	ASSERT(_snapshot != NULL);
2291e67a2cdSPawel Dziepak 
23009dbdd36SPawel Dziepak 	DirectoryCacheSnapshot* snapshot = new DirectoryCacheSnapshot;
23109dbdd36SPawel Dziepak 	if (snapshot == NULL)
23209dbdd36SPawel Dziepak 		return B_NO_MEMORY;
23309dbdd36SPawel Dziepak 
23409dbdd36SPawel Dziepak 	uint64 change = 0;
23509dbdd36SPawel Dziepak 	uint64 dirCookie = 0;
23609dbdd36SPawel Dziepak 	uint64 dirCookieVerf = 0;
2372a73e4c5SPawel Dziepak 	bool eof = false;
2382a73e4c5SPawel Dziepak 
23909dbdd36SPawel Dziepak 	while (!eof) {
24009dbdd36SPawel Dziepak 		uint32 count;
24109dbdd36SPawel Dziepak 		DirEntry* dirents;
2422a73e4c5SPawel Dziepak 
2430dbff361SPawel Dziepak 		status_t result = ReadDirOnce(&dirents, &count, cookie, &eof, &change,
2442314d073SPawel Dziepak 			&dirCookie, &dirCookieVerf, attribute);
24509dbdd36SPawel Dziepak 		if (result != B_OK) {
24609dbdd36SPawel Dziepak 			delete snapshot;
24709dbdd36SPawel Dziepak 			return result;
24809dbdd36SPawel Dziepak 		}
24909dbdd36SPawel Dziepak 
25009dbdd36SPawel Dziepak 		uint32 i;
25109dbdd36SPawel Dziepak 		for (i = 0; i < count; i++) {
25209dbdd36SPawel Dziepak 
25309dbdd36SPawel Dziepak 			// FATTR4_FSID is mandatory
25409dbdd36SPawel Dziepak 			void* data = dirents[i].fAttrs[0].fData.fPointer;
25509dbdd36SPawel Dziepak 			FileSystemId* fsid = reinterpret_cast<FileSystemId*>(data);
25609dbdd36SPawel Dziepak 			if (*fsid != fFileSystem->FsId())
25709dbdd36SPawel Dziepak 				continue;
25809dbdd36SPawel Dziepak 
25970472e11SPawel Dziepak 			if (strstr(dirents[i].fName, "-haiku-attrs") != NULL)
26070472e11SPawel Dziepak 				continue;
26170472e11SPawel Dziepak 
26209dbdd36SPawel Dziepak 			ino_t id;
2632314d073SPawel Dziepak 			if (!attribute) {
26409dbdd36SPawel Dziepak 				if (dirents[i].fAttrCount == 2)
2650dbff361SPawel Dziepak 					id = FileIdToInoT(dirents[i].fAttrs[1].fData.fValue64);
26609dbdd36SPawel Dziepak 				else
2670dbff361SPawel Dziepak 					id = FileIdToInoT(fFileSystem->AllocFileId());
268f7c35cf4SPawel Dziepak 			} else
269f7c35cf4SPawel Dziepak 				id = 0;
27009dbdd36SPawel Dziepak 
27170472e11SPawel Dziepak 			const char* name = dirents[i].fName;
27270472e11SPawel Dziepak 			if (attribute)
27370472e11SPawel Dziepak 				name = FileToAttrName(name);
27470472e11SPawel Dziepak 			if (name == NULL) {
27570472e11SPawel Dziepak 				delete snapshot;
27670472e11SPawel Dziepak 				delete[] dirents;
27770472e11SPawel Dziepak 				return B_NO_MEMORY;
27870472e11SPawel Dziepak 			}
27970472e11SPawel Dziepak 
28070472e11SPawel Dziepak 			NameCacheEntry* entry = new NameCacheEntry(name, id);
28170472e11SPawel Dziepak 			if (attribute)
28270472e11SPawel Dziepak 				free(const_cast<char*>(name));
28370472e11SPawel Dziepak 
28409dbdd36SPawel Dziepak 			if (entry == NULL || entry->fName == NULL) {
285eed5b716SPawel Dziepak 				if (entry != NULL)
28609dbdd36SPawel Dziepak 					delete entry;
28709dbdd36SPawel Dziepak 				delete snapshot;
28809dbdd36SPawel Dziepak 				delete[] dirents;
28909dbdd36SPawel Dziepak 				return B_NO_MEMORY;
29009dbdd36SPawel Dziepak 			}
29109dbdd36SPawel Dziepak 			snapshot->fEntries.Add(entry);
29209dbdd36SPawel Dziepak 		}
29309dbdd36SPawel Dziepak 
29409dbdd36SPawel Dziepak 		delete[] dirents;
29509dbdd36SPawel Dziepak 	}
29609dbdd36SPawel Dziepak 
29709dbdd36SPawel Dziepak 	*_snapshot = snapshot;
29809dbdd36SPawel Dziepak 	*_change = change;
29909dbdd36SPawel Dziepak 
30009dbdd36SPawel Dziepak 	return B_OK;
30109dbdd36SPawel Dziepak }
30209dbdd36SPawel Dziepak 
3032a73e4c5SPawel Dziepak 
30409dbdd36SPawel Dziepak status_t
30509dbdd36SPawel Dziepak Inode::ReadDir(void* _buffer, uint32 size, uint32* _count,
30609dbdd36SPawel Dziepak 	OpenDirCookie* cookie)
30709dbdd36SPawel Dziepak {
3081e67a2cdSPawel Dziepak 	ASSERT(_buffer != NULL);
3091e67a2cdSPawel Dziepak 	ASSERT(_count != NULL);
3101e67a2cdSPawel Dziepak 	ASSERT(cookie != NULL);
3111e67a2cdSPawel Dziepak 
31209dbdd36SPawel Dziepak 	if (cookie->fEOF) {
31309dbdd36SPawel Dziepak 		*_count = 0;
31409dbdd36SPawel Dziepak 		return B_OK;
31509dbdd36SPawel Dziepak 	}
3162a73e4c5SPawel Dziepak 
31709dbdd36SPawel Dziepak 	status_t result;
318f7c35cf4SPawel Dziepak 	DirectoryCache* cache = cookie->fAttrDir ? fAttrCache : fCache;
31909dbdd36SPawel Dziepak 	if (cookie->fSnapshot == NULL) {
320cae470f9SPawel Dziepak 		cache->Lock();
321*4d120407SPawel Dziepak 		result = cache->Revalidate();
32209dbdd36SPawel Dziepak 		if (result != B_OK) {
323f7c35cf4SPawel Dziepak 			cache->Unlock();
3242a73e4c5SPawel Dziepak 			return result;
32509dbdd36SPawel Dziepak 		}
326*4d120407SPawel Dziepak 
327*4d120407SPawel Dziepak 		DirectoryCacheSnapshot* snapshot = cache->GetSnapshot();
328*4d120407SPawel Dziepak 		ASSERT(snapshot != NULL);
329*4d120407SPawel Dziepak 
330eed5b716SPawel Dziepak 		cookie->fSnapshot = new DirectoryCacheSnapshot(*snapshot);
331f7c35cf4SPawel Dziepak 		cache->Unlock();
332*4d120407SPawel Dziepak 
333*4d120407SPawel Dziepak 		if (cookie->fSnapshot == NULL)
334*4d120407SPawel Dziepak 			return B_NO_MEMORY;
33509dbdd36SPawel Dziepak 	}
3362a73e4c5SPawel Dziepak 
33709dbdd36SPawel Dziepak 	char* buffer = reinterpret_cast<char*>(_buffer);
33809dbdd36SPawel Dziepak 	uint32 pos = 0;
3396b9a91ebSPawel Dziepak 	uint32 i = 0;
3406b9a91ebSPawel Dziepak 	bool overflow = false;
3416b9a91ebSPawel Dziepak 
342f7c35cf4SPawel Dziepak 	if (cookie->fSpecial == 0 && i < *_count && !cookie->fAttrDir) {
3436b9a91ebSPawel Dziepak 		struct dirent* de = reinterpret_cast<dirent*>(buffer + pos);
3446b9a91ebSPawel Dziepak 
3456b9a91ebSPawel Dziepak 		status_t result;
3460dbff361SPawel Dziepak 		result = FillDirEntry(de, fInfo.fFileId, ".", pos, size);
3476b9a91ebSPawel Dziepak 
3486b9a91ebSPawel Dziepak 		if (result == B_BUFFER_OVERFLOW)
3496b9a91ebSPawel Dziepak 			overflow = true;
3506b9a91ebSPawel Dziepak 		else if (result == B_OK) {
3516b9a91ebSPawel Dziepak 			pos += de->d_reclen;
3526b9a91ebSPawel Dziepak 			i++;
3536b9a91ebSPawel Dziepak 			cookie->fSpecial++;
3546b9a91ebSPawel Dziepak 		} else
3556b9a91ebSPawel Dziepak 			return result;
3566b9a91ebSPawel Dziepak 	}
3576b9a91ebSPawel Dziepak 
358f7c35cf4SPawel Dziepak 	if (cookie->fSpecial == 1 && i < *_count && !cookie->fAttrDir) {
3596b9a91ebSPawel Dziepak 		struct dirent* de = reinterpret_cast<dirent*>(buffer + pos);
3606b9a91ebSPawel Dziepak 
3616b9a91ebSPawel Dziepak 		status_t result;
3620dbff361SPawel Dziepak 		result = ReadDirUp(de, pos, size);
3638afd81baSPawel Dziepak 		if (result == B_ENTRY_NOT_FOUND) {
3640dbff361SPawel Dziepak 			result = FillDirEntry(de, FileIdToInoT(fInfo.fFileId), "..", pos,
3650dbff361SPawel Dziepak 				size);
3660dbff361SPawel Dziepak 		}
3676b9a91ebSPawel Dziepak 
3686b9a91ebSPawel Dziepak 		if (result == B_BUFFER_OVERFLOW)
3696b9a91ebSPawel Dziepak 			overflow = true;
3706b9a91ebSPawel Dziepak 		else if (result == B_OK) {
3716b9a91ebSPawel Dziepak 			pos += de->d_reclen;
3726b9a91ebSPawel Dziepak 			i++;
3736b9a91ebSPawel Dziepak 			cookie->fSpecial++;
3746b9a91ebSPawel Dziepak 		} else
3756b9a91ebSPawel Dziepak 			return result;
3766b9a91ebSPawel Dziepak 	}
37709dbdd36SPawel Dziepak 
37809dbdd36SPawel Dziepak 	MutexLocker _(cookie->fSnapshot->fLock);
3796b9a91ebSPawel Dziepak 	for (; !overflow && i < *_count; i++) {
3802a73e4c5SPawel Dziepak 		struct dirent* de = reinterpret_cast<dirent*>(buffer + pos);
381eed5b716SPawel Dziepak 		NameCacheEntry* temp = cookie->fCurrent;
3822a73e4c5SPawel Dziepak 
38309dbdd36SPawel Dziepak 		if (cookie->fCurrent == NULL)
38409dbdd36SPawel Dziepak 			cookie->fCurrent = cookie->fSnapshot->fEntries.Head();
38509dbdd36SPawel Dziepak 		else {
38609dbdd36SPawel Dziepak 			cookie->fCurrent
38709dbdd36SPawel Dziepak 				= cookie->fSnapshot->fEntries.GetNext(cookie->fCurrent);
38809dbdd36SPawel Dziepak 		}
3892a73e4c5SPawel Dziepak 
39009dbdd36SPawel Dziepak 		if (cookie->fCurrent == NULL) {
39109dbdd36SPawel Dziepak 			cookie->fEOF = true;
39209dbdd36SPawel Dziepak 			break;
39309dbdd36SPawel Dziepak 		}
3942a73e4c5SPawel Dziepak 
3950dbff361SPawel Dziepak 		if (FillDirEntry(de, cookie->fCurrent->fNode, cookie->fCurrent->fName,
39609dbdd36SPawel Dziepak 			pos, size) == B_BUFFER_OVERFLOW) {
397eed5b716SPawel Dziepak 			cookie->fCurrent = temp;
3982a73e4c5SPawel Dziepak 			overflow = true;
3992a73e4c5SPawel Dziepak 			break;
4002a73e4c5SPawel Dziepak 		}
4012a73e4c5SPawel Dziepak 
4022a73e4c5SPawel Dziepak 		pos += de->d_reclen;
4032a73e4c5SPawel Dziepak 	}
4042a73e4c5SPawel Dziepak 
40509dbdd36SPawel Dziepak 	if (i == 0 && overflow)
4062a73e4c5SPawel Dziepak 		return B_BUFFER_OVERFLOW;
4072a73e4c5SPawel Dziepak 
40809dbdd36SPawel Dziepak 	*_count = i;
4092a73e4c5SPawel Dziepak 
4102a73e4c5SPawel Dziepak 	return B_OK;
4112a73e4c5SPawel Dziepak }
4122a73e4c5SPawel Dziepak 
413