예제 #1
0
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;

}
예제 #2
0
파일: TeaSafe.cpp 프로젝트: airk42/teasafe
    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;
    }
예제 #3
0
파일: Inode.cpp 프로젝트: AmirAbrams/haiku
Inode::~Inode()
{
	TRACE("Inode destructor\n");
	file_cache_delete(FileCache());
	file_map_delete(Map());
	TRACE("Inode destructor: Done\n");
}
예제 #4
0
파일: Inode.cpp 프로젝트: jiangxilong/haiku
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");
}
예제 #5
0
파일: Inode.cpp 프로젝트: jiangxilong/haiku
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;
}
예제 #6
0
파일: Inode.cpp 프로젝트: jiangxilong/haiku
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);
}
예제 #7
0
파일: Inode.cpp 프로젝트: DonCN/haiku
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);
}
예제 #8
0
파일: TeaSafe.cpp 프로젝트: airk42/teasafe
 void
 TeaSafe::resetFileCache()
 {
     StateLock lock(m_stateMutex);
     FileCache().swap(m_fileCache);
 }
예제 #9
0
파일: Inode.cpp 프로젝트: AmirAbrams/haiku
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;

}
예제 #10
0
파일: Inode.cpp 프로젝트: jiangxilong/haiku
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(), &timespec);
	SetModificationTime(&timespec);

	// 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;
}