xref: /haiku/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp (revision 78fc85a6ba25da91d4a0a591d53e0fad073f50d9)
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 
702a73e4c5SPawel Dziepak 		return reply.Create();
712a73e4c5SPawel Dziepak 	} while (true);
722a73e4c5SPawel Dziepak }
732a73e4c5SPawel Dziepak 
742a73e4c5SPawel Dziepak 
752a73e4c5SPawel Dziepak status_t
762a73e4c5SPawel Dziepak Inode::OpenDir(OpenDirCookie* cookie)
772a73e4c5SPawel Dziepak {
782a73e4c5SPawel Dziepak 	if (fType != NF4DIR)
792a73e4c5SPawel Dziepak 		return B_NOT_A_DIRECTORY;
802a73e4c5SPawel Dziepak 
812a73e4c5SPawel Dziepak 	do {
8200a8558cSPawel Dziepak 		RPC::Server* serv = fFileSystem->Server();
832a73e4c5SPawel Dziepak 		Request request(serv);
842a73e4c5SPawel Dziepak 		RequestBuilder& req = request.Builder();
852a73e4c5SPawel Dziepak 
86a28e8732SPawel Dziepak 		req.PutFH(fInfo.fHandle);
872a73e4c5SPawel Dziepak 		req.Access();
882a73e4c5SPawel Dziepak 
892a73e4c5SPawel Dziepak 		status_t result = request.Send();
902a73e4c5SPawel Dziepak 		if (result != B_OK)
912a73e4c5SPawel Dziepak 			return result;
922a73e4c5SPawel Dziepak 
932a73e4c5SPawel Dziepak 		ReplyInterpreter& reply = request.Reply();
942a73e4c5SPawel Dziepak 
952a73e4c5SPawel Dziepak 		if (_HandleErrors(reply.NFS4Error(), serv))
962a73e4c5SPawel Dziepak 			continue;
972a73e4c5SPawel Dziepak 
982a73e4c5SPawel Dziepak 		reply.PutFH();
992a73e4c5SPawel Dziepak 
1002a73e4c5SPawel Dziepak 		uint32 allowed;
1012a73e4c5SPawel Dziepak 		result = reply.Access(NULL, &allowed);
1022a73e4c5SPawel Dziepak 		if (result != B_OK)
1032a73e4c5SPawel Dziepak 			return result;
1042a73e4c5SPawel Dziepak 
1052a73e4c5SPawel Dziepak 		if (allowed & ACCESS4_READ != ACCESS4_READ)
1062a73e4c5SPawel Dziepak 			return B_PERMISSION_DENIED;
1072a73e4c5SPawel Dziepak 
10800a8558cSPawel Dziepak 		cookie->fFileSystem = fFileSystem;
1092a73e4c5SPawel Dziepak 		cookie->fCookie = 0;
1102a73e4c5SPawel Dziepak 		cookie->fCookieVerf = 2;
1112a73e4c5SPawel Dziepak 
112*78fc85a6SPawel Dziepak 		fFileSystem->Root()->MakeInfoInvalid();
113*78fc85a6SPawel Dziepak 
1142a73e4c5SPawel Dziepak 		return B_OK;
1152a73e4c5SPawel Dziepak 	} while (true);
1162a73e4c5SPawel Dziepak }
1172a73e4c5SPawel Dziepak 
1182a73e4c5SPawel Dziepak 
1192a73e4c5SPawel Dziepak status_t
1202a73e4c5SPawel Dziepak Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie,
1212a73e4c5SPawel Dziepak 	bool* eof)
1222a73e4c5SPawel Dziepak {
1232a73e4c5SPawel Dziepak 	do {
12400a8558cSPawel Dziepak 		RPC::Server* serv = fFileSystem->Server();
1252a73e4c5SPawel Dziepak 		Request request(serv);
1262a73e4c5SPawel Dziepak 		RequestBuilder& req = request.Builder();
1272a73e4c5SPawel Dziepak 
128a28e8732SPawel Dziepak 		req.PutFH(fInfo.fHandle);
1292a73e4c5SPawel Dziepak 
1302a73e4c5SPawel Dziepak 		Attribute attr[] = { FATTR4_FSID, FATTR4_FILEID };
1312a73e4c5SPawel Dziepak 		req.ReadDir(*count, cookie->fCookie, cookie->fCookieVerf, attr,
1322a73e4c5SPawel Dziepak 			sizeof(attr) / sizeof(Attribute));
1332a73e4c5SPawel Dziepak 
1342a73e4c5SPawel Dziepak 		status_t result = request.Send(cookie);
1352a73e4c5SPawel Dziepak 		if (result != B_OK)
1362a73e4c5SPawel Dziepak 			return result;
1372a73e4c5SPawel Dziepak 
1382a73e4c5SPawel Dziepak 		ReplyInterpreter& reply = request.Reply();
1392a73e4c5SPawel Dziepak 
1402a73e4c5SPawel Dziepak 		if (_HandleErrors(reply.NFS4Error(), serv))
1412a73e4c5SPawel Dziepak 			continue;
1422a73e4c5SPawel Dziepak 
1432a73e4c5SPawel Dziepak 		reply.PutFH();
1442a73e4c5SPawel Dziepak 		return reply.ReadDir(&cookie->fCookie, &cookie->fCookieVerf, dirents,
1452a73e4c5SPawel Dziepak 			count, eof);
1462a73e4c5SPawel Dziepak 	} while (true);
1472a73e4c5SPawel Dziepak }
1482a73e4c5SPawel Dziepak 
1492a73e4c5SPawel Dziepak 
1502a73e4c5SPawel Dziepak status_t
1512a73e4c5SPawel Dziepak Inode::_FillDirEntry(struct dirent* de, ino_t id, const char* name, uint32 pos,
1522a73e4c5SPawel Dziepak 	uint32 size)
1532a73e4c5SPawel Dziepak {
1542a73e4c5SPawel Dziepak 	uint32 nameSize = strlen(name);
1552a73e4c5SPawel Dziepak 	const uint32 entSize = sizeof(struct dirent);
1562a73e4c5SPawel Dziepak 
1572a73e4c5SPawel Dziepak 	if (pos + entSize + nameSize > size)
1582a73e4c5SPawel Dziepak 		return B_BUFFER_OVERFLOW;
1592a73e4c5SPawel Dziepak 
16000a8558cSPawel Dziepak 	de->d_dev = fFileSystem->DevId();
1612a73e4c5SPawel Dziepak 	de->d_ino = id;
1622a73e4c5SPawel Dziepak 	de->d_reclen = entSize + nameSize;
1632a73e4c5SPawel Dziepak 	if (de->d_reclen % 8 != 0)
1642a73e4c5SPawel Dziepak 		de->d_reclen += 8 - de->d_reclen % 8;
1652a73e4c5SPawel Dziepak 
1662a73e4c5SPawel Dziepak 	strcpy(de->d_name, name);
1672a73e4c5SPawel Dziepak 
1682a73e4c5SPawel Dziepak 	return B_OK;
1692a73e4c5SPawel Dziepak }
1702a73e4c5SPawel Dziepak 
1712a73e4c5SPawel Dziepak 
1722a73e4c5SPawel Dziepak status_t
1732a73e4c5SPawel Dziepak Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size)
1742a73e4c5SPawel Dziepak {
1752a73e4c5SPawel Dziepak 	do {
17600a8558cSPawel Dziepak 		RPC::Server* serv = fFileSystem->Server();
1772a73e4c5SPawel Dziepak 		Request request(serv);
1782a73e4c5SPawel Dziepak 		RequestBuilder& req = request.Builder();
1792a73e4c5SPawel Dziepak 
180a28e8732SPawel Dziepak 		req.PutFH(fInfo.fHandle);
1812a73e4c5SPawel Dziepak 		req.LookUpUp();
1822a73e4c5SPawel Dziepak 		req.GetFH();
1832a73e4c5SPawel Dziepak 
18400a8558cSPawel Dziepak 		if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) {
1852a73e4c5SPawel Dziepak 			Attribute attr[] = { FATTR4_FILEID };
1862a73e4c5SPawel Dziepak 			req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
1872a73e4c5SPawel Dziepak 		}
1882a73e4c5SPawel Dziepak 
1892a73e4c5SPawel Dziepak 		status_t result = request.Send();
1902a73e4c5SPawel Dziepak 		if (result != B_OK)
1912a73e4c5SPawel Dziepak 			return result;
1922a73e4c5SPawel Dziepak 
1932a73e4c5SPawel Dziepak 		ReplyInterpreter& reply = request.Reply();
1942a73e4c5SPawel Dziepak 
1952a73e4c5SPawel Dziepak 		if (_HandleErrors(reply.NFS4Error(), serv))
1962a73e4c5SPawel Dziepak 			continue;
1972a73e4c5SPawel Dziepak 
1982a73e4c5SPawel Dziepak 		reply.PutFH();
1992a73e4c5SPawel Dziepak 		result = reply.LookUpUp();
2002a73e4c5SPawel Dziepak 		if (result != B_OK)
2012a73e4c5SPawel Dziepak 			return result;
2022a73e4c5SPawel Dziepak 
20300a8558cSPawel Dziepak 		FileHandle fh;
2042a73e4c5SPawel Dziepak 		reply.GetFH(&fh);
2052a73e4c5SPawel Dziepak 
2062a73e4c5SPawel Dziepak 		uint64 fileId;
20700a8558cSPawel Dziepak 		if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) {
2082a73e4c5SPawel Dziepak 			AttrValue* values;
2092a73e4c5SPawel Dziepak 			uint32 count;
2102a73e4c5SPawel Dziepak 			reply.GetAttr(&values, &count);
2112a73e4c5SPawel Dziepak 			if (result != B_OK)
2122a73e4c5SPawel Dziepak 				return result;
2132a73e4c5SPawel Dziepak 
2142a73e4c5SPawel Dziepak 			fileId = values[0].fData.fValue64;
2152a73e4c5SPawel Dziepak 			delete[] values;
2162a73e4c5SPawel Dziepak 		} else
21700a8558cSPawel Dziepak 			fileId = fFileSystem->AllocFileId();
2182a73e4c5SPawel Dziepak 
2192a73e4c5SPawel Dziepak 		return _FillDirEntry(de, _FileIdToInoT(fileId), "..", pos, size);
2202a73e4c5SPawel Dziepak 	} while (true);
2212a73e4c5SPawel Dziepak }
2222a73e4c5SPawel Dziepak 
2232a73e4c5SPawel Dziepak // TODO: Currently inode numbers returned by ReadDir are virtually random.
2242a73e4c5SPawel Dziepak // Apparently Haiku does not use that information (contrary to inode number
2252a73e4c5SPawel Dziepak // returned by LookUp) so fixing it can wait until directory caches are
2262a73e4c5SPawel Dziepak // implemented.
2272a73e4c5SPawel Dziepak // When directories are cached client should store inode numbers it assigned
2282a73e4c5SPawel Dziepak // to directroy entries and use them consequently.
2292a73e4c5SPawel Dziepak status_t
2302a73e4c5SPawel Dziepak Inode::ReadDir(void* _buffer, uint32 size, uint32* _count,
2312a73e4c5SPawel Dziepak 	OpenDirCookie* cookie)
2322a73e4c5SPawel Dziepak {
2332a73e4c5SPawel Dziepak 	uint32 count = 0;
2342a73e4c5SPawel Dziepak 	uint32 pos = 0;
2352a73e4c5SPawel Dziepak 	uint32 this_count;
2362a73e4c5SPawel Dziepak 	bool eof = false;
2372a73e4c5SPawel Dziepak 
2382a73e4c5SPawel Dziepak 	char* buffer = reinterpret_cast<char*>(_buffer);
2392a73e4c5SPawel Dziepak 
2402a73e4c5SPawel Dziepak 	if (cookie->fCookie == 0 && cookie->fCookieVerf == 2 && count < *_count) {
2412a73e4c5SPawel Dziepak 		struct dirent* de = reinterpret_cast<dirent*>(buffer + pos);
2422a73e4c5SPawel Dziepak 
243a28e8732SPawel Dziepak 		_FillDirEntry(de, fInfo.fFileId, ".", pos, size);
2442a73e4c5SPawel Dziepak 
2452a73e4c5SPawel Dziepak 		pos += de->d_reclen;
2462a73e4c5SPawel Dziepak 		count++;
2472a73e4c5SPawel Dziepak 		cookie->fCookieVerf--;
2482a73e4c5SPawel Dziepak 	}
2492a73e4c5SPawel Dziepak 
2502a73e4c5SPawel Dziepak 	if (cookie->fCookie == 0 && cookie->fCookieVerf == 1 && count < *_count) {
2512a73e4c5SPawel Dziepak 		struct dirent* de = reinterpret_cast<dirent*>(buffer + pos);
2522a73e4c5SPawel Dziepak 
253a28e8732SPawel Dziepak 		if (strcmp(fInfo.fName, "/"))
2542a73e4c5SPawel Dziepak 			_ReadDirUp(de, pos, size);
2552a73e4c5SPawel Dziepak 		else
256a28e8732SPawel Dziepak 			_FillDirEntry(de, _FileIdToInoT(fInfo.fFileId), "..", pos, size);
2572a73e4c5SPawel Dziepak 
2582a73e4c5SPawel Dziepak 		pos += de->d_reclen;
2592a73e4c5SPawel Dziepak 		count++;
2602a73e4c5SPawel Dziepak 		cookie->fCookieVerf--;
2612a73e4c5SPawel Dziepak 	}
2622a73e4c5SPawel Dziepak 
2632a73e4c5SPawel Dziepak 	bool overflow = false;
2642a73e4c5SPawel Dziepak 	while (count < *_count && !eof) {
2652a73e4c5SPawel Dziepak 		this_count = *_count - count;
2662a73e4c5SPawel Dziepak 		DirEntry* dirents;
2672a73e4c5SPawel Dziepak 
2682a73e4c5SPawel Dziepak 		status_t result = _ReadDirOnce(&dirents, &this_count, cookie, &eof);
2692a73e4c5SPawel Dziepak 		if (result != B_OK)
2702a73e4c5SPawel Dziepak 			return result;
2712a73e4c5SPawel Dziepak 
2722a73e4c5SPawel Dziepak 		uint32 i, entries = 0;
2732a73e4c5SPawel Dziepak 		for (i = 0; i < min_c(this_count, *_count - count); i++) {
2742a73e4c5SPawel Dziepak 			struct dirent* de = reinterpret_cast<dirent*>(buffer + pos);
2752a73e4c5SPawel Dziepak 
2762a73e4c5SPawel Dziepak 			// FATTR4_FSID is mandatory
2772a73e4c5SPawel Dziepak 			void* data = dirents[i].fAttrs[0].fData.fPointer;
27800a8558cSPawel Dziepak 			FileSystemId* fsid = reinterpret_cast<FileSystemId*>(data);
27900a8558cSPawel Dziepak 			if (*fsid != fFileSystem->FsId())
2802a73e4c5SPawel Dziepak 				continue;
2812a73e4c5SPawel Dziepak 
2822a73e4c5SPawel Dziepak 			ino_t id;
2832a73e4c5SPawel Dziepak 			if (dirents[i].fAttrCount == 2)
2842a73e4c5SPawel Dziepak 				id = _FileIdToInoT(dirents[i].fAttrs[1].fData.fValue64);
2852a73e4c5SPawel Dziepak 			else
28600a8558cSPawel Dziepak 				id = _FileIdToInoT(fFileSystem->AllocFileId());
2872a73e4c5SPawel Dziepak 
2882a73e4c5SPawel Dziepak 			const char* name = dirents[i].fName;
2892a73e4c5SPawel Dziepak 			if (_FillDirEntry(de, id, name, pos, size) == B_BUFFER_OVERFLOW) {
2902a73e4c5SPawel Dziepak 				eof = true;
2912a73e4c5SPawel Dziepak 				overflow = true;
2922a73e4c5SPawel Dziepak 				break;
2932a73e4c5SPawel Dziepak 			}
2942a73e4c5SPawel Dziepak 
2952a73e4c5SPawel Dziepak 			pos += de->d_reclen;
2962a73e4c5SPawel Dziepak 			entries++;
2972a73e4c5SPawel Dziepak 		}
2982a73e4c5SPawel Dziepak 		delete[] dirents;
2992a73e4c5SPawel Dziepak 		count += entries;
3002a73e4c5SPawel Dziepak 	}
3012a73e4c5SPawel Dziepak 
3022a73e4c5SPawel Dziepak 	if (count == 0 && overflow)
3032a73e4c5SPawel Dziepak 		return B_BUFFER_OVERFLOW;
3042a73e4c5SPawel Dziepak 
3052a73e4c5SPawel Dziepak 	*_count = count;
3062a73e4c5SPawel Dziepak 
3072a73e4c5SPawel Dziepak 	return B_OK;
3082a73e4c5SPawel Dziepak }
3092a73e4c5SPawel Dziepak 
310