status_t Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, OpenDelegationData* data, ino_t* id) { ASSERT(name != NULL); ASSERT(cookie != NULL); ASSERT(data != NULL); cookie->fMode = mode; cookie->fLocks = NULL; OpenState* state = new(std::nothrow) OpenState; if (state == NULL) return B_NO_MEMORY; status_t result = CreateState(name, mode, perms, state, data); if (result != B_OK) { delete state; return result; } cookie->fOpenState = state; cookie->fFileSystem = fFileSystem; *id = FileIdToInoT(state->fInfo.fFileId); fFileSystem->AddOpenFile(state); fFileSystem->Root()->MakeInfoInvalid(); notify_entry_created(fFileSystem->DevId(), ID(), name, *id); return B_OK; }
status_t Inode::ReadDirUp(struct dirent* de, uint32 pos, uint32 size) { ASSERT(de != NULL); uint32 attempt = 0; do { RPC::Server* serv = fFileSystem->Server(); Request request(serv, fFileSystem); RequestBuilder& req = request.Builder(); req.PutFH(fInfo.fHandle); req.LookUpUp(); req.GetFH(); if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) { Attribute attr[] = { FATTR4_FILEID }; req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); } status_t result = request.Send(); if (result != B_OK) return result; ReplyInterpreter& reply = request.Reply(); if (HandleErrors(attempt, reply.NFS4Error(), serv)) continue; reply.PutFH(); result = reply.LookUpUp(); if (result != B_OK) return result; FileHandle fh; reply.GetFH(&fh); uint64 fileId; if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) { AttrValue* values; uint32 count; result = reply.GetAttr(&values, &count); if (result != B_OK) return result; fileId = values[0].fData.fValue64; delete[] values; } else fileId = fFileSystem->AllocFileId(); return FillDirEntry(de, FileIdToInoT(fileId), "..", pos, size); } while (true); }
status_t Inode::CreateState(const char* name, int mode, int perms, OpenState* state, OpenDelegationData* delegationData) { ASSERT(name != NULL); ASSERT(state != NULL); ASSERT(delegationData != NULL); uint64 fileID; FileHandle handle; ChangeInfo changeInfo; status_t result = CreateFile(name, mode, perms, state, &changeInfo, &fileID, &handle, delegationData); if (result != B_OK) return result; FileInfo fileInfo; fileInfo.fFileId = fileID; fileInfo.fHandle = handle; fFileSystem->InoIdMap()->AddName(fileInfo, fInfo.fNames, name, FileIdToInoT(fileID)); fCache->Lock(); if (fCache->Valid()) { if (changeInfo.fAtomic && fCache->ChangeInfo() == changeInfo.fBefore) { fCache->AddEntry(name, fileID, true); fCache->SetChangeInfo(changeInfo.fAfter); } else fCache->Trash(); } fCache->Unlock(); state->fFileSystem = fFileSystem; state->fInfo = fileInfo; state->fMode = mode & O_RWMASK; return B_OK; }
status_t Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, OpenDirCookie* cookie) { ASSERT(_buffer != NULL); ASSERT(_count != NULL); ASSERT(cookie != NULL); if (cookie->fEOF) { *_count = 0; return B_OK; } status_t result; DirectoryCache* cache = cookie->fAttrDir ? fAttrCache : fCache; if (cookie->fSnapshot == NULL) { cache->Lock(); result = cache->Revalidate(); if (result != B_OK) { cache->Unlock(); return result; } DirectoryCacheSnapshot* snapshot; result = cache->GetSnapshot(&snapshot); if (result != B_OK) { cache->Unlock(); return result; } cookie->fSnapshot = new DirectoryCacheSnapshot(*snapshot); cache->Unlock(); if (cookie->fSnapshot == NULL) return B_NO_MEMORY; } char* buffer = reinterpret_cast<char*>(_buffer); uint32 pos = 0; uint32 i = 0; bool overflow = false; if (cookie->fSpecial == 0 && i < *_count && !cookie->fAttrDir) { struct dirent* de = reinterpret_cast<dirent*>(buffer + pos); status_t result; result = FillDirEntry(de, fInfo.fFileId, ".", pos, size); if (result == B_BUFFER_OVERFLOW) overflow = true; else if (result == B_OK) { pos += de->d_reclen; i++; cookie->fSpecial++; } else return result; } if (cookie->fSpecial == 1 && i < *_count && !cookie->fAttrDir) { struct dirent* de = reinterpret_cast<dirent*>(buffer + pos); status_t result; result = ReadDirUp(de, pos, size); if (result == B_ENTRY_NOT_FOUND) { result = FillDirEntry(de, FileIdToInoT(fInfo.fFileId), "..", pos, size); } if (result == B_BUFFER_OVERFLOW) overflow = true; else if (result == B_OK) { pos += de->d_reclen; i++; cookie->fSpecial++; } else return result; } MutexLocker _(cookie->fSnapshot->fLock); for (; !overflow && i < *_count; i++) { struct dirent* de = reinterpret_cast<dirent*>(buffer + pos); NameCacheEntry* temp = cookie->fCurrent; if (cookie->fCurrent == NULL) cookie->fCurrent = cookie->fSnapshot->fEntries.Head(); else { cookie->fCurrent = cookie->fSnapshot->fEntries.GetNext(cookie->fCurrent); } if (cookie->fCurrent == NULL) { cookie->fEOF = true; break; } if (FillDirEntry(de, cookie->fCurrent->fNode, cookie->fCurrent->fName, pos, size) == B_BUFFER_OVERFLOW) { cookie->fCurrent = temp; overflow = true; break; } pos += de->d_reclen; } if (i == 0 && overflow) return B_BUFFER_OVERFLOW; *_count = i; return B_OK; }
status_t Inode::GetDirSnapshot(DirectoryCacheSnapshot** _snapshot, OpenDirCookie* cookie, uint64* _change, bool attribute) { ASSERT(_snapshot != NULL); DirectoryCacheSnapshot* snapshot = new DirectoryCacheSnapshot; if (snapshot == NULL) return B_NO_MEMORY; uint64 change = 0; uint64 dirCookie = 0; uint64 dirCookieVerf = 0; bool eof = false; while (!eof) { uint32 count; DirEntry* dirents; status_t result = ReadDirOnce(&dirents, &count, cookie, &eof, &change, &dirCookie, &dirCookieVerf, attribute); if (result != B_OK) { delete snapshot; return result; } uint32 i; for (i = 0; i < count; i++) { // FATTR4_FSID is mandatory void* data = dirents[i].fAttrs[0].fData.fPointer; FileSystemId* fsid = reinterpret_cast<FileSystemId*>(data); if (*fsid != fFileSystem->FsId()) continue; if (strstr(dirents[i].fName, "-haiku-attrs") != NULL) continue; ino_t id; if (!attribute) { if (dirents[i].fAttrCount == 2) id = FileIdToInoT(dirents[i].fAttrs[1].fData.fValue64); else id = FileIdToInoT(fFileSystem->AllocFileId()); } else id = 0; const char* name = dirents[i].fName; if (attribute) name = FileToAttrName(name); if (name == NULL) { delete snapshot; delete[] dirents; return B_NO_MEMORY; } NameCacheEntry* entry = new NameCacheEntry(name, id); if (attribute) free(const_cast<char*>(name)); if (entry == NULL || entry->fName == NULL) { if (entry != NULL) delete entry; delete snapshot; delete[] dirents; return B_NO_MEMORY; } snapshot->fEntries.Add(entry); } delete[] dirents; } *_snapshot = snapshot; *_change = change; return B_OK; }