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