status_t Inode::ReadAt(off_t pos, uint8* buffer, size_t* _length) { size_t length = *_length; // set/check boundaries for pos/length if (pos < 0) { ERROR("inode %" B_PRIdINO ": ReadAt failed(pos %lld, length %lu)\n", ID(), pos, length); return B_BAD_VALUE; } if (pos >= Size() || length == 0) { TRACE("inode %" B_PRIdINO ": ReadAt 0 (pos %lld, length %lu)\n", ID(), pos, length); *_length = 0; return B_NO_ERROR; } // the file cache doesn't seem to like non block aligned file offset // so we avoid the file cache for inline extents struct btrfs_key search_key; search_key.SetType(BTRFS_KEY_TYPE_EXTENT_DATA); search_key.SetObjectID(fID); search_key.SetOffset(pos + 1); btrfs_extent_data *extent_data; status_t status = fVolume->FSTree()->FindPrevious(search_key, (void**)&extent_data); if (status != B_OK) { ERROR("Inode::FindBlock(): Couldn't find extent_data 0x%lx\n", status); return status; } if (FileCache() != NULL && extent_data->Type() == BTRFS_EXTENT_DATA_REGULAR) { TRACE("inode %" B_PRIdINO ": ReadAt cache (pos %lld, length %lu)\n", ID(), pos, length); free(extent_data); return file_cache_read(FileCache(), NULL, pos, buffer, _length); } TRACE("Inode::ReadAt(%" B_PRIdINO ") key.Offset() %lld\n", ID(), search_key.Offset()); off_t diff = pos - search_key.Offset(); if (extent_data->Type() != BTRFS_EXTENT_DATA_INLINE) panic("unknown extent type; %d\n", extent_data->Type()); *_length = min_c(extent_data->MemoryBytes() - diff, *_length); memcpy(buffer, extent_data->inline_data, *_length); free(extent_data); return B_OK; }
SharedFile TeaSafe::setAndGetCachedFile(std::string const &path, SharedCompoundFolder const &parentEntry, OpenDisposition openMode) const { // very strictly limit the size of the cache to being able to hold // on to one entry only. TODO. does this mean that a map is a map // idea? We could just use a single pair. if(m_fileCache.size() > 1) { FileCache().swap(m_fileCache); } auto it(m_fileCache.find(path)); if(it != m_fileCache.end()) { // note: need to also check if the openMode is different to the cached // version in which case the cached version should probably be rebuilt if(!it->second->getOpenDisposition().equals(openMode)) { m_fileCache.erase(path); } else { return it->second; } } auto sf(std::make_shared<File>(parentEntry->getFile(boost::filesystem::path(path).filename().string(), openMode))); m_fileCache.insert(std::make_pair(path, sf)); return sf; }
Inode::~Inode() { TRACE("Inode destructor\n"); file_cache_delete(FileCache()); file_map_delete(Map()); TRACE("Inode destructor: Done\n"); }
Inode::~Inode() { TRACE("Inode destructor\n"); if (fCached) { TRACE("Deleting the file cache and file map\n"); file_cache_delete(FileCache()); file_map_delete(Map()); } TRACE("Inode destructor: Done\n"); }
status_t Inode::DisableFileCache() { TRACE("Inode::DisableFileCache()\n"); if (!fCached) return B_OK; file_cache_delete(FileCache()); file_map_delete(Map()); fCached = false; return B_OK; }
status_t Inode::ReadAt(off_t pos, uint8* buffer, size_t* _length) { size_t length = *_length; // set/check boundaries for pos/length if (pos < 0) { ERROR("inode %lld: ReadAt failed(pos %lld, length %lu)\n", ID(), pos, length); return B_BAD_VALUE; } if (pos >= Size() || length == 0) { TRACE("inode %lld: ReadAt 0 (pos %lld, length %lu)\n", ID(), pos, length); *_length = 0; return B_NO_ERROR; } return file_cache_read(FileCache(), NULL, pos, buffer, _length); }
status_t Inode::Resize(Transaction& transaction, off_t size) { TRACE("Inode::Resize() ID:%" B_PRIdINO " size: %" B_PRIdOFF "\n", ID(), size); if (size < 0) return B_BAD_VALUE; off_t oldSize = Size(); if (size == oldSize) return B_OK; TRACE("Inode::Resize(): old size: %" B_PRIdOFF ", new size: %" B_PRIdOFF "\n", oldSize, size); status_t status; if (size > oldSize) { status = _EnlargeDataStream(transaction, size); if (status != B_OK) { // Restore original size _ShrinkDataStream(transaction, oldSize); } } else status = _ShrinkDataStream(transaction, size); TRACE("Inode::Resize(): Updating file map and cache\n"); if (status != B_OK) return status; file_cache_set_size(FileCache(), size); file_map_set_size(Map(), size); TRACE("Inode::Resize(): Writing back inode changes. Size: %" B_PRIdOFF "\n", Size()); return WriteBack(transaction); }
void TeaSafe::resetFileCache() { StateLock lock(m_stateMutex); FileCache().swap(m_fileCache); }
status_t Inode::ReadAt(off_t pos, uint8* buffer, size_t* _length) { size_t length = *_length; // set/check boundaries for pos/length if (pos < 0) { ERROR("inode %" B_PRIdINO ": ReadAt failed(pos %" B_PRIdOFF ", length %lu)\n", ID(), pos, length); return B_BAD_VALUE; } if (pos >= Size() || length == 0) { TRACE("inode %" B_PRIdINO ": ReadAt 0 (pos %" B_PRIdOFF ", length %lu)\n", ID(), pos, length); *_length = 0; return B_NO_ERROR; } // the file cache doesn't seem to like non block aligned file offset // so we avoid the file cache for inline extents struct btrfs_key search_key; search_key.SetType(BTRFS_KEY_TYPE_EXTENT_DATA); search_key.SetObjectID(fID); search_key.SetOffset(pos + 1); size_t item_size; btrfs_extent_data *extent_data; status_t status = fVolume->FSTree()->FindPrevious(search_key, (void**)&extent_data, &item_size); if (status != B_OK) { ERROR("Inode::FindBlock(): Couldn't find extent_data 0x%" B_PRIx32 "\n", status); return status; } uint8 compression = extent_data->Compression(); if (FileCache() != NULL && extent_data->Type() == BTRFS_EXTENT_DATA_REGULAR) { TRACE("inode %" B_PRIdINO ": ReadAt cache (pos %" B_PRIdOFF ", length %lu)\n", ID(), pos, length); free(extent_data); if (compression == BTRFS_EXTENT_COMPRESS_NONE) return file_cache_read(FileCache(), NULL, pos, buffer, _length); else if (compression == BTRFS_EXTENT_COMPRESS_ZLIB) panic("zlib isn't unsupported for regular extent\n"); else panic("unknown extent compression; %d\n", compression); } TRACE("Inode::ReadAt(%" B_PRIdINO ") key.Offset() %" B_PRId64 "\n", ID(), search_key.Offset()); off_t diff = pos - search_key.Offset(); if (extent_data->Type() != BTRFS_EXTENT_DATA_INLINE) panic("unknown extent type; %d\n", extent_data->Type()); *_length = min_c(extent_data->Size() - diff, *_length); if (compression == BTRFS_EXTENT_COMPRESS_NONE) memcpy(buffer, extent_data->inline_data, *_length); else if (compression == BTRFS_EXTENT_COMPRESS_ZLIB) { char in[2048]; z_stream zStream = { (Bytef*)in, // next in sizeof(in), // avail in 0, // total in NULL, // next out 0, // avail out 0, // total out 0, // msg 0, // state Z_NULL, // zalloc Z_NULL, // zfree Z_NULL, // opaque 0, // data type 0, // adler 0, // reserved }; int status; ssize_t offset = 0; size_t inline_size = item_size - 13; bool headerRead = false; TRACE("Inode::ReadAt(%" B_PRIdINO ") diff %" B_PRIdOFF " size %" B_PRIuSIZE "\n", ID(), diff, item_size); do { ssize_t bytesRead = min_c(sizeof(in), inline_size - offset); memcpy(in, extent_data->inline_data + offset, bytesRead); if (bytesRead != (ssize_t)sizeof(in)) { if (bytesRead <= 0) { status = Z_STREAM_ERROR; break; } } zStream.avail_in = bytesRead; zStream.next_in = (Bytef*)in; if (!headerRead) { headerRead = true; zStream.avail_out = length; zStream.next_out = (Bytef*)buffer; status = inflateInit2(&zStream, 15); if (status != Z_OK) { free(extent_data); return B_ERROR; } } status = inflate(&zStream, Z_SYNC_FLUSH); offset += bytesRead; if (diff > 0) { zStream.next_out -= max_c(bytesRead, diff); diff -= max_c(bytesRead, diff); } if (zStream.avail_in != 0 && status != Z_STREAM_END) { TRACE("Inode::ReadAt() didn't read whole block: %s\n", zStream.msg); } } while (status == Z_OK); inflateEnd(&zStream); if (status != Z_STREAM_END) { TRACE("Inode::ReadAt() inflating failed: %d!\n", status); free(extent_data); return B_BAD_DATA; } *_length = zStream.total_out; } else panic("unknown extent compression; %d\n", compression); free(extent_data); return B_OK; }
status_t Inode::WriteAt(Transaction& transaction, off_t pos, const uint8* buffer, size_t* _length) { TRACE("Inode::WriteAt(%lld, %p, *(%p) = %ld)\n", pos, buffer, _length, *_length); ReadLocker readLocker(fLock); if (IsFileCacheDisabled()) return B_BAD_VALUE; if (pos < 0) return B_BAD_VALUE; readLocker.Unlock(); TRACE("Inode::WriteAt(): Starting transaction\n"); transaction.Start(fVolume->GetJournal()); WriteLocker writeLocker(fLock); TRACE("Inode::WriteAt(): Updating modification time\n"); struct timespec timespec; _BigtimeToTimespec(real_time_clock_usecs(), ×pec); SetModificationTime(×pec); // NOTE: Debugging info to find why sometimes resize doesn't happen size_t length = *_length; #ifdef TRACE_EXT2 off_t oldEnd = pos + length; TRACE("Inode::WriteAt(): Old calc for end? %x:%x\n", (int)(oldEnd >> 32), (int)(oldEnd & 0xFFFFFFFF)); #endif off_t end = pos + (off_t)length; off_t oldSize = Size(); TRACE("Inode::WriteAt(): Old size: %x:%x, new size: %x:%x\n", (int)(oldSize >> 32), (int)(oldSize & 0xFFFFFFFF), (int)(end >> 32), (int)(end & 0xFFFFFFFF)); if (end > oldSize) { status_t status = Resize(transaction, end); if (status != B_OK) { *_length = 0; WriteLockInTransaction(transaction); return status; } status = WriteBack(transaction); if (status != B_OK) { *_length = 0; WriteLockInTransaction(transaction); return status; } } writeLocker.Unlock(); if (oldSize < pos) FillGapWithZeros(oldSize, pos); if (length == 0) { // Probably just changed the file size with the pos parameter return B_OK; } TRACE("Inode::WriteAt(): Performing write: %p, %lld, %p, %ld\n", FileCache(), pos, buffer, *_length); status_t status = file_cache_write(FileCache(), NULL, pos, buffer, _length); WriteLockInTransaction(transaction); TRACE("Inode::WriteAt(): Done\n"); return status; }