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