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 { 230dbff361SPawel Dziepak return CreateObject(name, NULL, mode, NF4DIR); 242a73e4c5SPawel Dziepak } 252a73e4c5SPawel Dziepak 262a73e4c5SPawel Dziepak 272a73e4c5SPawel Dziepak status_t 282a73e4c5SPawel Dziepak Inode::OpenDir(OpenDirCookie* cookie) 292a73e4c5SPawel Dziepak { 302a73e4c5SPawel Dziepak if (fType != NF4DIR) 312a73e4c5SPawel Dziepak return B_NOT_A_DIRECTORY; 322a73e4c5SPawel Dziepak 330dbff361SPawel Dziepak status_t result = Access(R_OK); 342a73e4c5SPawel Dziepak if (result != B_OK) 352a73e4c5SPawel Dziepak return result; 362a73e4c5SPawel Dziepak 3700a8558cSPawel Dziepak cookie->fFileSystem = fFileSystem; 386b9a91ebSPawel Dziepak cookie->fSpecial = 0; 3909dbdd36SPawel Dziepak cookie->fSnapshot = NULL; 4009dbdd36SPawel Dziepak cookie->fCurrent = NULL; 4109dbdd36SPawel Dziepak cookie->fEOF = false; 42f7c35cf4SPawel Dziepak cookie->fAttrDir = false; 43f7c35cf4SPawel Dziepak 44f7c35cf4SPawel Dziepak return B_OK; 45f7c35cf4SPawel Dziepak } 46f7c35cf4SPawel Dziepak 47f7c35cf4SPawel Dziepak 48f7c35cf4SPawel Dziepak status_t 49f7c35cf4SPawel Dziepak Inode::OpenAttrDir(OpenDirCookie* cookie) 50f7c35cf4SPawel Dziepak { 51f7c35cf4SPawel Dziepak cookie->fFileSystem = fFileSystem; 52f7c35cf4SPawel Dziepak cookie->fSpecial = 0; 53f7c35cf4SPawel Dziepak cookie->fSnapshot = NULL; 54f7c35cf4SPawel Dziepak cookie->fCurrent = NULL; 55f7c35cf4SPawel Dziepak cookie->fEOF = false; 56f7c35cf4SPawel Dziepak cookie->fAttrDir = true; 57f7c35cf4SPawel Dziepak 5820d1b02eSPawel Dziepak return LoadAttrDirHandle(); 5920d1b02eSPawel Dziepak } 6020d1b02eSPawel Dziepak 6120d1b02eSPawel Dziepak 6220d1b02eSPawel Dziepak status_t 6320d1b02eSPawel Dziepak Inode::LoadAttrDirHandle() 6420d1b02eSPawel Dziepak { 65*a5ae9b47SPawel Dziepak if (!fFileSystem->NamedAttrs()) 66*a5ae9b47SPawel Dziepak return B_UNSUPPORTED; 67*a5ae9b47SPawel Dziepak 68f7c35cf4SPawel Dziepak if (fInfo.fAttrDir.fSize == 0) { 69f7c35cf4SPawel Dziepak FileHandle handle; 70f7c35cf4SPawel Dziepak 71f7c35cf4SPawel Dziepak status_t result = NFS4Inode::OpenAttrDir(&handle); 72*a5ae9b47SPawel Dziepak if (result == B_UNSUPPORTED) 73*a5ae9b47SPawel Dziepak fFileSystem->SetNamedAttrs(false); 74*a5ae9b47SPawel Dziepak 75f7c35cf4SPawel Dziepak if (result != B_OK) 76f7c35cf4SPawel Dziepak return result; 77f7c35cf4SPawel Dziepak 78f7c35cf4SPawel Dziepak fInfo.fAttrDir = handle; 79f7c35cf4SPawel Dziepak } 802a73e4c5SPawel Dziepak 812a73e4c5SPawel Dziepak return B_OK; 822a73e4c5SPawel Dziepak } 832a73e4c5SPawel Dziepak 842a73e4c5SPawel Dziepak 852a73e4c5SPawel Dziepak status_t 860dbff361SPawel Dziepak Inode::FillDirEntry(struct dirent* de, ino_t id, const char* name, uint32 pos, 872a73e4c5SPawel Dziepak uint32 size) 882a73e4c5SPawel Dziepak { 892a73e4c5SPawel Dziepak uint32 nameSize = strlen(name); 902a73e4c5SPawel Dziepak const uint32 entSize = sizeof(struct dirent); 912a73e4c5SPawel Dziepak 922a73e4c5SPawel Dziepak if (pos + entSize + nameSize > size) 932a73e4c5SPawel Dziepak return B_BUFFER_OVERFLOW; 942a73e4c5SPawel Dziepak 9500a8558cSPawel Dziepak de->d_dev = fFileSystem->DevId(); 962a73e4c5SPawel Dziepak de->d_ino = id; 972a73e4c5SPawel Dziepak de->d_reclen = entSize + nameSize; 982a73e4c5SPawel Dziepak if (de->d_reclen % 8 != 0) 992a73e4c5SPawel Dziepak de->d_reclen += 8 - de->d_reclen % 8; 1002a73e4c5SPawel Dziepak 1012a73e4c5SPawel Dziepak strcpy(de->d_name, name); 1022a73e4c5SPawel Dziepak 1032a73e4c5SPawel Dziepak return B_OK; 1042a73e4c5SPawel Dziepak } 1052a73e4c5SPawel Dziepak 1062a73e4c5SPawel Dziepak 1072a73e4c5SPawel Dziepak status_t 1080dbff361SPawel Dziepak Inode::ReadDirUp(struct dirent* de, uint32 pos, uint32 size) 1092a73e4c5SPawel Dziepak { 1102a73e4c5SPawel Dziepak do { 11100a8558cSPawel Dziepak RPC::Server* serv = fFileSystem->Server(); 1122a73e4c5SPawel Dziepak Request request(serv); 1132a73e4c5SPawel Dziepak RequestBuilder& req = request.Builder(); 1142a73e4c5SPawel Dziepak 115a28e8732SPawel Dziepak req.PutFH(fInfo.fHandle); 1162a73e4c5SPawel Dziepak req.LookUpUp(); 1172a73e4c5SPawel Dziepak req.GetFH(); 1182a73e4c5SPawel Dziepak 11900a8558cSPawel Dziepak if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) { 1202a73e4c5SPawel Dziepak Attribute attr[] = { FATTR4_FILEID }; 1212a73e4c5SPawel Dziepak req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); 1222a73e4c5SPawel Dziepak } 1232a73e4c5SPawel Dziepak 1242a73e4c5SPawel Dziepak status_t result = request.Send(); 1252a73e4c5SPawel Dziepak if (result != B_OK) 1262a73e4c5SPawel Dziepak return result; 1272a73e4c5SPawel Dziepak 1282a73e4c5SPawel Dziepak ReplyInterpreter& reply = request.Reply(); 1292a73e4c5SPawel Dziepak 1300dbff361SPawel Dziepak if (HandleErrors(reply.NFS4Error(), serv)) 1312a73e4c5SPawel Dziepak continue; 1322a73e4c5SPawel Dziepak 1332a73e4c5SPawel Dziepak reply.PutFH(); 1342a73e4c5SPawel Dziepak result = reply.LookUpUp(); 1352a73e4c5SPawel Dziepak if (result != B_OK) 1362a73e4c5SPawel Dziepak return result; 1372a73e4c5SPawel Dziepak 13800a8558cSPawel Dziepak FileHandle fh; 1392a73e4c5SPawel Dziepak reply.GetFH(&fh); 1402a73e4c5SPawel Dziepak 1412a73e4c5SPawel Dziepak uint64 fileId; 14200a8558cSPawel Dziepak if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) { 1432a73e4c5SPawel Dziepak AttrValue* values; 1442a73e4c5SPawel Dziepak uint32 count; 1452a73e4c5SPawel Dziepak reply.GetAttr(&values, &count); 1462a73e4c5SPawel Dziepak if (result != B_OK) 1472a73e4c5SPawel Dziepak return result; 1482a73e4c5SPawel Dziepak 1492a73e4c5SPawel Dziepak fileId = values[0].fData.fValue64; 1502a73e4c5SPawel Dziepak delete[] values; 1512a73e4c5SPawel Dziepak } else 15200a8558cSPawel Dziepak fileId = fFileSystem->AllocFileId(); 1532a73e4c5SPawel Dziepak 1540dbff361SPawel Dziepak return FillDirEntry(de, FileIdToInoT(fileId), "..", pos, size); 1552a73e4c5SPawel Dziepak } while (true); 1562a73e4c5SPawel Dziepak } 1572a73e4c5SPawel Dziepak 15809dbdd36SPawel Dziepak 1592a73e4c5SPawel Dziepak status_t 1600dbff361SPawel Dziepak Inode::GetDirSnapshot(DirectoryCacheSnapshot** _snapshot, 1612314d073SPawel Dziepak OpenDirCookie* cookie, uint64* _change, bool attribute) 1622a73e4c5SPawel Dziepak { 16309dbdd36SPawel Dziepak DirectoryCacheSnapshot* snapshot = new DirectoryCacheSnapshot; 16409dbdd36SPawel Dziepak if (snapshot == NULL) 16509dbdd36SPawel Dziepak return B_NO_MEMORY; 16609dbdd36SPawel Dziepak 16709dbdd36SPawel Dziepak uint64 change = 0; 16809dbdd36SPawel Dziepak uint64 dirCookie = 0; 16909dbdd36SPawel Dziepak uint64 dirCookieVerf = 0; 1702a73e4c5SPawel Dziepak bool eof = false; 1712a73e4c5SPawel Dziepak 17209dbdd36SPawel Dziepak while (!eof) { 17309dbdd36SPawel Dziepak uint32 count; 17409dbdd36SPawel Dziepak DirEntry* dirents; 1752a73e4c5SPawel Dziepak 1760dbff361SPawel Dziepak status_t result = ReadDirOnce(&dirents, &count, cookie, &eof, &change, 1772314d073SPawel Dziepak &dirCookie, &dirCookieVerf, attribute); 17809dbdd36SPawel Dziepak if (result != B_OK) { 17909dbdd36SPawel Dziepak delete snapshot; 18009dbdd36SPawel Dziepak return result; 18109dbdd36SPawel Dziepak } 18209dbdd36SPawel Dziepak 18309dbdd36SPawel Dziepak uint32 i; 18409dbdd36SPawel Dziepak for (i = 0; i < count; i++) { 18509dbdd36SPawel Dziepak 18609dbdd36SPawel Dziepak // FATTR4_FSID is mandatory 18709dbdd36SPawel Dziepak void* data = dirents[i].fAttrs[0].fData.fPointer; 18809dbdd36SPawel Dziepak FileSystemId* fsid = reinterpret_cast<FileSystemId*>(data); 18909dbdd36SPawel Dziepak if (*fsid != fFileSystem->FsId()) 19009dbdd36SPawel Dziepak continue; 19109dbdd36SPawel Dziepak 19209dbdd36SPawel Dziepak ino_t id; 1932314d073SPawel Dziepak if (!attribute) { 19409dbdd36SPawel Dziepak if (dirents[i].fAttrCount == 2) 1950dbff361SPawel Dziepak id = FileIdToInoT(dirents[i].fAttrs[1].fData.fValue64); 19609dbdd36SPawel Dziepak else 1970dbff361SPawel Dziepak id = FileIdToInoT(fFileSystem->AllocFileId()); 198f7c35cf4SPawel Dziepak } else 199f7c35cf4SPawel Dziepak id = 0; 20009dbdd36SPawel Dziepak 20109dbdd36SPawel Dziepak NameCacheEntry* entry = new NameCacheEntry(dirents[i].fName, id); 20209dbdd36SPawel Dziepak if (entry == NULL || entry->fName == NULL) { 20309dbdd36SPawel Dziepak if (entry->fName == NULL) 20409dbdd36SPawel Dziepak delete entry; 20509dbdd36SPawel Dziepak delete snapshot; 20609dbdd36SPawel Dziepak delete[] dirents; 20709dbdd36SPawel Dziepak return B_NO_MEMORY; 20809dbdd36SPawel Dziepak } 20909dbdd36SPawel Dziepak snapshot->fEntries.Add(entry); 21009dbdd36SPawel Dziepak } 21109dbdd36SPawel Dziepak 21209dbdd36SPawel Dziepak delete[] dirents; 21309dbdd36SPawel Dziepak } 21409dbdd36SPawel Dziepak 21509dbdd36SPawel Dziepak *_snapshot = snapshot; 21609dbdd36SPawel Dziepak *_change = change; 21709dbdd36SPawel Dziepak 21809dbdd36SPawel Dziepak return B_OK; 21909dbdd36SPawel Dziepak } 22009dbdd36SPawel Dziepak 2212a73e4c5SPawel Dziepak 22209dbdd36SPawel Dziepak status_t 22309dbdd36SPawel Dziepak Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, 22409dbdd36SPawel Dziepak OpenDirCookie* cookie) 22509dbdd36SPawel Dziepak { 22609dbdd36SPawel Dziepak if (cookie->fEOF) { 22709dbdd36SPawel Dziepak *_count = 0; 22809dbdd36SPawel Dziepak return B_OK; 22909dbdd36SPawel Dziepak } 2302a73e4c5SPawel Dziepak 23109dbdd36SPawel Dziepak status_t result; 232f7c35cf4SPawel Dziepak DirectoryCache* cache = cookie->fAttrDir ? fAttrCache : fCache; 23309dbdd36SPawel Dziepak if (cookie->fSnapshot == NULL) { 23409dbdd36SPawel Dziepak fFileSystem->Revalidator().Lock(); 235f7c35cf4SPawel Dziepak if (cache->Lock() != B_OK) { 236f7c35cf4SPawel Dziepak cache->ResetAndLock(); 23709dbdd36SPawel Dziepak } else { 238f7c35cf4SPawel Dziepak fFileSystem->Revalidator().RemoveDirectory(cache); 23909dbdd36SPawel Dziepak } 24009dbdd36SPawel Dziepak 241f7c35cf4SPawel Dziepak cookie->fSnapshot = cache->GetSnapshot(); 24209dbdd36SPawel Dziepak if (cookie->fSnapshot == NULL) { 24309dbdd36SPawel Dziepak uint64 change; 2442314d073SPawel Dziepak result = GetDirSnapshot(&cookie->fSnapshot, cookie, &change, 2452314d073SPawel Dziepak cookie->fAttrDir); 24609dbdd36SPawel Dziepak if (result != B_OK) { 247f7c35cf4SPawel Dziepak cache->Unlock(); 24809dbdd36SPawel Dziepak fFileSystem->Revalidator().Unlock(); 2492a73e4c5SPawel Dziepak return result; 25009dbdd36SPawel Dziepak } 251f7c35cf4SPawel Dziepak cache->ValidateChangeInfo(change); 252f7c35cf4SPawel Dziepak cache->SetSnapshot(cookie->fSnapshot); 25309dbdd36SPawel Dziepak } 25409dbdd36SPawel Dziepak cookie->fSnapshot->AcquireReference(); 255f7c35cf4SPawel Dziepak fFileSystem->Revalidator().AddDirectory(cache); 256f7c35cf4SPawel Dziepak cache->Unlock(); 25709dbdd36SPawel Dziepak fFileSystem->Revalidator().Unlock(); 25809dbdd36SPawel Dziepak } 2592a73e4c5SPawel Dziepak 26009dbdd36SPawel Dziepak char* buffer = reinterpret_cast<char*>(_buffer); 26109dbdd36SPawel Dziepak uint32 pos = 0; 2626b9a91ebSPawel Dziepak uint32 i = 0; 2636b9a91ebSPawel Dziepak bool overflow = false; 2646b9a91ebSPawel Dziepak 265f7c35cf4SPawel Dziepak if (cookie->fSpecial == 0 && i < *_count && !cookie->fAttrDir) { 2666b9a91ebSPawel Dziepak struct dirent* de = reinterpret_cast<dirent*>(buffer + pos); 2676b9a91ebSPawel Dziepak 2686b9a91ebSPawel Dziepak status_t result; 2690dbff361SPawel Dziepak result = FillDirEntry(de, fInfo.fFileId, ".", pos, size); 2706b9a91ebSPawel Dziepak 2716b9a91ebSPawel Dziepak if (result == B_BUFFER_OVERFLOW) 2726b9a91ebSPawel Dziepak overflow = true; 2736b9a91ebSPawel Dziepak else if (result == B_OK) { 2746b9a91ebSPawel Dziepak pos += de->d_reclen; 2756b9a91ebSPawel Dziepak i++; 2766b9a91ebSPawel Dziepak cookie->fSpecial++; 2776b9a91ebSPawel Dziepak } else 2786b9a91ebSPawel Dziepak return result; 2796b9a91ebSPawel Dziepak } 2806b9a91ebSPawel Dziepak 281f7c35cf4SPawel Dziepak if (cookie->fSpecial == 1 && i < *_count && !cookie->fAttrDir) { 2826b9a91ebSPawel Dziepak struct dirent* de = reinterpret_cast<dirent*>(buffer + pos); 2836b9a91ebSPawel Dziepak 2846b9a91ebSPawel Dziepak status_t result; 2850dbff361SPawel Dziepak result = ReadDirUp(de, pos, size); 2868afd81baSPawel Dziepak if (result == B_ENTRY_NOT_FOUND) { 2870dbff361SPawel Dziepak result = FillDirEntry(de, FileIdToInoT(fInfo.fFileId), "..", pos, 2880dbff361SPawel Dziepak size); 2890dbff361SPawel Dziepak } 2906b9a91ebSPawel Dziepak 2916b9a91ebSPawel Dziepak if (result == B_BUFFER_OVERFLOW) 2926b9a91ebSPawel Dziepak overflow = true; 2936b9a91ebSPawel Dziepak else if (result == B_OK) { 2946b9a91ebSPawel Dziepak pos += de->d_reclen; 2956b9a91ebSPawel Dziepak i++; 2966b9a91ebSPawel Dziepak cookie->fSpecial++; 2976b9a91ebSPawel Dziepak } else 2986b9a91ebSPawel Dziepak return result; 2996b9a91ebSPawel Dziepak } 30009dbdd36SPawel Dziepak 30109dbdd36SPawel Dziepak MutexLocker _(cookie->fSnapshot->fLock); 3026b9a91ebSPawel Dziepak for (; !overflow && i < *_count; i++) { 3032a73e4c5SPawel Dziepak struct dirent* de = reinterpret_cast<dirent*>(buffer + pos); 3042a73e4c5SPawel Dziepak 30509dbdd36SPawel Dziepak if (cookie->fCurrent == NULL) 30609dbdd36SPawel Dziepak cookie->fCurrent = cookie->fSnapshot->fEntries.Head(); 30709dbdd36SPawel Dziepak else { 30809dbdd36SPawel Dziepak cookie->fCurrent 30909dbdd36SPawel Dziepak = cookie->fSnapshot->fEntries.GetNext(cookie->fCurrent); 31009dbdd36SPawel Dziepak } 3112a73e4c5SPawel Dziepak 31209dbdd36SPawel Dziepak if (cookie->fCurrent == NULL) { 31309dbdd36SPawel Dziepak cookie->fEOF = true; 31409dbdd36SPawel Dziepak break; 31509dbdd36SPawel Dziepak } 3162a73e4c5SPawel Dziepak 3170dbff361SPawel Dziepak if (FillDirEntry(de, cookie->fCurrent->fNode, cookie->fCurrent->fName, 31809dbdd36SPawel Dziepak pos, size) == B_BUFFER_OVERFLOW) { 3192a73e4c5SPawel Dziepak overflow = true; 3202a73e4c5SPawel Dziepak break; 3212a73e4c5SPawel Dziepak } 3222a73e4c5SPawel Dziepak 3232a73e4c5SPawel Dziepak pos += de->d_reclen; 3242a73e4c5SPawel Dziepak } 3252a73e4c5SPawel Dziepak 32609dbdd36SPawel Dziepak if (i == 0 && overflow) 3272a73e4c5SPawel Dziepak return B_BUFFER_OVERFLOW; 3282a73e4c5SPawel Dziepak 32909dbdd36SPawel Dziepak *_count = i; 3302a73e4c5SPawel Dziepak 3312a73e4c5SPawel Dziepak return B_OK; 3322a73e4c5SPawel Dziepak } 3332a73e4c5SPawel Dziepak 334