xref: /haiku/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp (revision 7b6f80fee2eee9724b8146cc480c0ffe87b25c32)
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 
70*7b6f80feSPawel Dziepak 		uint64 before, after;
71*7b6f80feSPawel Dziepak 		bool atomic;
72*7b6f80feSPawel Dziepak 		result = reply.Create(&before, &after, atomic);
73*7b6f80feSPawel Dziepak 
74*7b6f80feSPawel Dziepak 		fFileSystem->Root()->MakeInfoInvalid();
75*7b6f80feSPawel Dziepak 
76*7b6f80feSPawel Dziepak 		if (fCache->Lock() == B_OK) {
77*7b6f80feSPawel Dziepak 			if (atomic && fCache->ChangeInfo() == before) {
78*7b6f80feSPawel Dziepak 				// TODO: update cache
79*7b6f80feSPawel Dziepak 				//fCache->AddEntry(name, );
80*7b6f80feSPawel Dziepak 				fCache->SetChangeInfo(after);
81*7b6f80feSPawel Dziepak 			} else if (fCache->ChangeInfo() != before)
82*7b6f80feSPawel Dziepak 				fCache->Trash();
83*7b6f80feSPawel Dziepak 			fCache->Unlock();
84*7b6f80feSPawel Dziepak 		}
85*7b6f80feSPawel Dziepak 
86*7b6f80feSPawel 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;
1252a73e4c5SPawel Dziepak 		cookie->fCookie = 0;
1262a73e4c5SPawel Dziepak 		cookie->fCookieVerf = 2;
1272a73e4c5SPawel Dziepak 
12878fc85a6SPawel Dziepak 		fFileSystem->Root()->MakeInfoInvalid();
12978fc85a6SPawel Dziepak 
1302a73e4c5SPawel Dziepak 		return B_OK;
1312a73e4c5SPawel Dziepak 	} while (true);
1322a73e4c5SPawel Dziepak }
1332a73e4c5SPawel Dziepak 
1342a73e4c5SPawel Dziepak 
1352a73e4c5SPawel Dziepak status_t
1362a73e4c5SPawel Dziepak Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie,
1372a73e4c5SPawel Dziepak 	bool* eof)
1382a73e4c5SPawel Dziepak {
1392a73e4c5SPawel Dziepak 	do {
14000a8558cSPawel Dziepak 		RPC::Server* serv = fFileSystem->Server();
1412a73e4c5SPawel Dziepak 		Request request(serv);
1422a73e4c5SPawel Dziepak 		RequestBuilder& req = request.Builder();
1432a73e4c5SPawel Dziepak 
144a28e8732SPawel Dziepak 		req.PutFH(fInfo.fHandle);
1452a73e4c5SPawel Dziepak 
1462a73e4c5SPawel Dziepak 		Attribute attr[] = { FATTR4_FSID, FATTR4_FILEID };
1472a73e4c5SPawel Dziepak 		req.ReadDir(*count, cookie->fCookie, cookie->fCookieVerf, attr,
1482a73e4c5SPawel Dziepak 			sizeof(attr) / sizeof(Attribute));
1492a73e4c5SPawel Dziepak 
1502a73e4c5SPawel Dziepak 		status_t result = request.Send(cookie);
1512a73e4c5SPawel Dziepak 		if (result != B_OK)
1522a73e4c5SPawel Dziepak 			return result;
1532a73e4c5SPawel Dziepak 
1542a73e4c5SPawel Dziepak 		ReplyInterpreter& reply = request.Reply();
1552a73e4c5SPawel Dziepak 
1562a73e4c5SPawel Dziepak 		if (_HandleErrors(reply.NFS4Error(), serv))
1572a73e4c5SPawel Dziepak 			continue;
1582a73e4c5SPawel Dziepak 
1592a73e4c5SPawel Dziepak 		reply.PutFH();
1602a73e4c5SPawel Dziepak 		return reply.ReadDir(&cookie->fCookie, &cookie->fCookieVerf, dirents,
1612a73e4c5SPawel Dziepak 			count, eof);
1622a73e4c5SPawel Dziepak 	} while (true);
1632a73e4c5SPawel Dziepak }
1642a73e4c5SPawel Dziepak 
1652a73e4c5SPawel Dziepak 
1662a73e4c5SPawel Dziepak status_t
1672a73e4c5SPawel Dziepak Inode::_FillDirEntry(struct dirent* de, ino_t id, const char* name, uint32 pos,
1682a73e4c5SPawel Dziepak 	uint32 size)
1692a73e4c5SPawel Dziepak {
1702a73e4c5SPawel Dziepak 	uint32 nameSize = strlen(name);
1712a73e4c5SPawel Dziepak 	const uint32 entSize = sizeof(struct dirent);
1722a73e4c5SPawel Dziepak 
1732a73e4c5SPawel Dziepak 	if (pos + entSize + nameSize > size)
1742a73e4c5SPawel Dziepak 		return B_BUFFER_OVERFLOW;
1752a73e4c5SPawel Dziepak 
17600a8558cSPawel Dziepak 	de->d_dev = fFileSystem->DevId();
1772a73e4c5SPawel Dziepak 	de->d_ino = id;
1782a73e4c5SPawel Dziepak 	de->d_reclen = entSize + nameSize;
1792a73e4c5SPawel Dziepak 	if (de->d_reclen % 8 != 0)
1802a73e4c5SPawel Dziepak 		de->d_reclen += 8 - de->d_reclen % 8;
1812a73e4c5SPawel Dziepak 
1822a73e4c5SPawel Dziepak 	strcpy(de->d_name, name);
1832a73e4c5SPawel Dziepak 
1842a73e4c5SPawel Dziepak 	return B_OK;
1852a73e4c5SPawel Dziepak }
1862a73e4c5SPawel Dziepak 
1872a73e4c5SPawel Dziepak 
1882a73e4c5SPawel Dziepak status_t
1892a73e4c5SPawel Dziepak Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size)
1902a73e4c5SPawel Dziepak {
1912a73e4c5SPawel Dziepak 	do {
19200a8558cSPawel Dziepak 		RPC::Server* serv = fFileSystem->Server();
1932a73e4c5SPawel Dziepak 		Request request(serv);
1942a73e4c5SPawel Dziepak 		RequestBuilder& req = request.Builder();
1952a73e4c5SPawel Dziepak 
196a28e8732SPawel Dziepak 		req.PutFH(fInfo.fHandle);
1972a73e4c5SPawel Dziepak 		req.LookUpUp();
1982a73e4c5SPawel Dziepak 		req.GetFH();
1992a73e4c5SPawel Dziepak 
20000a8558cSPawel Dziepak 		if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) {
2012a73e4c5SPawel Dziepak 			Attribute attr[] = { FATTR4_FILEID };
2022a73e4c5SPawel Dziepak 			req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
2032a73e4c5SPawel Dziepak 		}
2042a73e4c5SPawel Dziepak 
2052a73e4c5SPawel Dziepak 		status_t result = request.Send();
2062a73e4c5SPawel Dziepak 		if (result != B_OK)
2072a73e4c5SPawel Dziepak 			return result;
2082a73e4c5SPawel Dziepak 
2092a73e4c5SPawel Dziepak 		ReplyInterpreter& reply = request.Reply();
2102a73e4c5SPawel Dziepak 
2112a73e4c5SPawel Dziepak 		if (_HandleErrors(reply.NFS4Error(), serv))
2122a73e4c5SPawel Dziepak 			continue;
2132a73e4c5SPawel Dziepak 
2142a73e4c5SPawel Dziepak 		reply.PutFH();
2152a73e4c5SPawel Dziepak 		result = reply.LookUpUp();
2162a73e4c5SPawel Dziepak 		if (result != B_OK)
2172a73e4c5SPawel Dziepak 			return result;
2182a73e4c5SPawel Dziepak 
21900a8558cSPawel Dziepak 		FileHandle fh;
2202a73e4c5SPawel Dziepak 		reply.GetFH(&fh);
2212a73e4c5SPawel Dziepak 
2222a73e4c5SPawel Dziepak 		uint64 fileId;
22300a8558cSPawel Dziepak 		if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) {
2242a73e4c5SPawel Dziepak 			AttrValue* values;
2252a73e4c5SPawel Dziepak 			uint32 count;
2262a73e4c5SPawel Dziepak 			reply.GetAttr(&values, &count);
2272a73e4c5SPawel Dziepak 			if (result != B_OK)
2282a73e4c5SPawel Dziepak 				return result;
2292a73e4c5SPawel Dziepak 
2302a73e4c5SPawel Dziepak 			fileId = values[0].fData.fValue64;
2312a73e4c5SPawel Dziepak 			delete[] values;
2322a73e4c5SPawel Dziepak 		} else
23300a8558cSPawel Dziepak 			fileId = fFileSystem->AllocFileId();
2342a73e4c5SPawel Dziepak 
2352a73e4c5SPawel Dziepak 		return _FillDirEntry(de, _FileIdToInoT(fileId), "..", pos, size);
2362a73e4c5SPawel Dziepak 	} while (true);
2372a73e4c5SPawel Dziepak }
2382a73e4c5SPawel Dziepak 
2392a73e4c5SPawel Dziepak // TODO: Currently inode numbers returned by ReadDir are virtually random.
2402a73e4c5SPawel Dziepak // Apparently Haiku does not use that information (contrary to inode number
2412a73e4c5SPawel Dziepak // returned by LookUp) so fixing it can wait until directory caches are
2422a73e4c5SPawel Dziepak // implemented.
2432a73e4c5SPawel Dziepak // When directories are cached client should store inode numbers it assigned
2442a73e4c5SPawel Dziepak // to directroy entries and use them consequently.
2452a73e4c5SPawel Dziepak status_t
2462a73e4c5SPawel Dziepak Inode::ReadDir(void* _buffer, uint32 size, uint32* _count,
2472a73e4c5SPawel Dziepak 	OpenDirCookie* cookie)
2482a73e4c5SPawel Dziepak {
2492a73e4c5SPawel Dziepak 	uint32 count = 0;
2502a73e4c5SPawel Dziepak 	uint32 pos = 0;
2512a73e4c5SPawel Dziepak 	uint32 this_count;
2522a73e4c5SPawel Dziepak 	bool eof = false;
2532a73e4c5SPawel Dziepak 
2542a73e4c5SPawel Dziepak 	char* buffer = reinterpret_cast<char*>(_buffer);
2552a73e4c5SPawel Dziepak 
2562a73e4c5SPawel Dziepak 	if (cookie->fCookie == 0 && cookie->fCookieVerf == 2 && count < *_count) {
2572a73e4c5SPawel Dziepak 		struct dirent* de = reinterpret_cast<dirent*>(buffer + pos);
2582a73e4c5SPawel Dziepak 
259a28e8732SPawel Dziepak 		_FillDirEntry(de, fInfo.fFileId, ".", pos, size);
2602a73e4c5SPawel Dziepak 
2612a73e4c5SPawel Dziepak 		pos += de->d_reclen;
2622a73e4c5SPawel Dziepak 		count++;
2632a73e4c5SPawel Dziepak 		cookie->fCookieVerf--;
2642a73e4c5SPawel Dziepak 	}
2652a73e4c5SPawel Dziepak 
2662a73e4c5SPawel Dziepak 	if (cookie->fCookie == 0 && cookie->fCookieVerf == 1 && count < *_count) {
2672a73e4c5SPawel Dziepak 		struct dirent* de = reinterpret_cast<dirent*>(buffer + pos);
2682a73e4c5SPawel Dziepak 
269a28e8732SPawel Dziepak 		if (strcmp(fInfo.fName, "/"))
2702a73e4c5SPawel Dziepak 			_ReadDirUp(de, pos, size);
2712a73e4c5SPawel Dziepak 		else
272a28e8732SPawel Dziepak 			_FillDirEntry(de, _FileIdToInoT(fInfo.fFileId), "..", pos, size);
2732a73e4c5SPawel Dziepak 
2742a73e4c5SPawel Dziepak 		pos += de->d_reclen;
2752a73e4c5SPawel Dziepak 		count++;
2762a73e4c5SPawel Dziepak 		cookie->fCookieVerf--;
2772a73e4c5SPawel Dziepak 	}
2782a73e4c5SPawel Dziepak 
2792a73e4c5SPawel Dziepak 	bool overflow = false;
2802a73e4c5SPawel Dziepak 	while (count < *_count && !eof) {
2812a73e4c5SPawel Dziepak 		this_count = *_count - count;
2822a73e4c5SPawel Dziepak 		DirEntry* dirents;
2832a73e4c5SPawel Dziepak 
2842a73e4c5SPawel Dziepak 		status_t result = _ReadDirOnce(&dirents, &this_count, cookie, &eof);
2852a73e4c5SPawel Dziepak 		if (result != B_OK)
2862a73e4c5SPawel Dziepak 			return result;
2872a73e4c5SPawel Dziepak 
2882a73e4c5SPawel Dziepak 		uint32 i, entries = 0;
2892a73e4c5SPawel Dziepak 		for (i = 0; i < min_c(this_count, *_count - count); i++) {
2902a73e4c5SPawel Dziepak 			struct dirent* de = reinterpret_cast<dirent*>(buffer + pos);
2912a73e4c5SPawel Dziepak 
2922a73e4c5SPawel Dziepak 			// FATTR4_FSID is mandatory
2932a73e4c5SPawel Dziepak 			void* data = dirents[i].fAttrs[0].fData.fPointer;
29400a8558cSPawel Dziepak 			FileSystemId* fsid = reinterpret_cast<FileSystemId*>(data);
29500a8558cSPawel Dziepak 			if (*fsid != fFileSystem->FsId())
2962a73e4c5SPawel Dziepak 				continue;
2972a73e4c5SPawel Dziepak 
2982a73e4c5SPawel Dziepak 			ino_t id;
2992a73e4c5SPawel Dziepak 			if (dirents[i].fAttrCount == 2)
3002a73e4c5SPawel Dziepak 				id = _FileIdToInoT(dirents[i].fAttrs[1].fData.fValue64);
3012a73e4c5SPawel Dziepak 			else
30200a8558cSPawel Dziepak 				id = _FileIdToInoT(fFileSystem->AllocFileId());
3032a73e4c5SPawel Dziepak 
3042a73e4c5SPawel Dziepak 			const char* name = dirents[i].fName;
3052a73e4c5SPawel Dziepak 			if (_FillDirEntry(de, id, name, pos, size) == B_BUFFER_OVERFLOW) {
3062a73e4c5SPawel Dziepak 				eof = true;
3072a73e4c5SPawel Dziepak 				overflow = true;
3082a73e4c5SPawel Dziepak 				break;
3092a73e4c5SPawel Dziepak 			}
3102a73e4c5SPawel Dziepak 
3112a73e4c5SPawel Dziepak 			pos += de->d_reclen;
3122a73e4c5SPawel Dziepak 			entries++;
3132a73e4c5SPawel Dziepak 		}
3142a73e4c5SPawel Dziepak 		delete[] dirents;
3152a73e4c5SPawel Dziepak 		count += entries;
3162a73e4c5SPawel Dziepak 	}
3172a73e4c5SPawel Dziepak 
3182a73e4c5SPawel Dziepak 	if (count == 0 && overflow)
3192a73e4c5SPawel Dziepak 		return B_BUFFER_OVERFLOW;
3202a73e4c5SPawel Dziepak 
3212a73e4c5SPawel Dziepak 	*_count = count;
3222a73e4c5SPawel Dziepak 
3232a73e4c5SPawel Dziepak 	return B_OK;
3242a73e4c5SPawel Dziepak }
3252a73e4c5SPawel Dziepak 
326