16f4c36e2SJérôme Duval/*
299768086Shyche * Copyright 2017, Ch��� V�� Gia Hy, cvghy116@gmail.com.
36f4c36e2SJérôme Duval * Copyright 2011, J��r��me Duval, korli@users.berlios.de.
45a95af70SAxel Dörfler * Copyright 2008-2014, Axel D��rfler, axeld@pinc-software.de.
5b1f9573fSJérôme Duval * Copyright 2005-2007, Ingo Weinhold, bonefish@cs.tu-berlin.de.
66f4c36e2SJérôme Duval * This file may be used under the terms of the MIT License.
76f4c36e2SJérôme Duval */
86f4c36e2SJérôme Duval
96f4c36e2SJérôme Duval
106f4c36e2SJérôme Duval#include "Inode.h"
116f4c36e2SJérôme Duval#include "CachedBlock.h"
12b44d924dShyche#include "CRCTable.h"
136f4c36e2SJérôme Duval#include "Utility.h"
146f4c36e2SJérôme Duval
156f4c36e2SJérôme Duval
166f4c36e2SJérôme Duval#undef ASSERT
176f4c36e2SJérôme Duval//#define TRACE_BTRFS
186f4c36e2SJérôme Duval#ifdef TRACE_BTRFS
196f4c36e2SJérôme Duval#	define TRACE(x...) dprintf("\33[34mbtrfs:\33[0m " x)
206f4c36e2SJérôme Duval#	define ASSERT(x) { if (!(x)) kernel_debugger("btrfs: assert failed: " #x "\n"); }
216f4c36e2SJérôme Duval#else
226f4c36e2SJérôme Duval#	define TRACE(x...) ;
236f4c36e2SJérôme Duval#	define ASSERT(x) ;
246f4c36e2SJérôme Duval#endif
256f4c36e2SJérôme Duval#define ERROR(x...) dprintf("\33[34mbtrfs:\33[0m " x)
266f4c36e2SJérôme Duval
276f4c36e2SJérôme Duval
286f4c36e2SJérôme DuvalInode::Inode(Volume* volume, ino_t id)
296f4c36e2SJérôme Duval	:
306f4c36e2SJérôme Duval	fVolume(volume),
316f4c36e2SJérôme Duval	fID(id),
326f4c36e2SJérôme Duval	fCache(NULL),
336f4c36e2SJérôme Duval	fMap(NULL)
346f4c36e2SJérôme Duval{
356f4c36e2SJérôme Duval	rw_lock_init(&fLock, "btrfs inode");
366f4c36e2SJérôme Duval
376f4c36e2SJérôme Duval	fInitStatus = UpdateNodeFromDisk();
386f4c36e2SJérôme Duval	if (fInitStatus == B_OK) {
396f4c36e2SJérôme Duval		if (!IsDirectory() && !IsSymLink()) {
406f4c36e2SJérôme Duval			fCache = file_cache_create(fVolume->ID(), ID(), Size());
416f4c36e2SJérôme Duval			fMap = file_map_create(fVolume->ID(), ID(), Size());
426f4c36e2SJérôme Duval		}
436f4c36e2SJérôme Duval	}
446f4c36e2SJérôme Duval}
456f4c36e2SJérôme Duval
466f4c36e2SJérôme Duval
4736a24fb3ShycheInode::Inode(Volume* volume, ino_t id, const btrfs_inode& item)
4836a24fb3Shyche	:
4936a24fb3Shyche	fVolume(volume),
5036a24fb3Shyche	fID(id),
5136a24fb3Shyche	fCache(NULL),
5236a24fb3Shyche	fMap(NULL),
5336a24fb3Shyche	fInitStatus(B_OK),
5436a24fb3Shyche	fNode(item)
5536a24fb3Shyche{
5636a24fb3Shyche	if (!IsDirectory() && !IsSymLink()) {
5736a24fb3Shyche		fCache = file_cache_create(fVolume->ID(), ID(), Size());
5836a24fb3Shyche		fMap = file_map_create(fVolume->ID(), ID(), Size());
5936a24fb3Shyche	}
6036a24fb3Shyche}
6136a24fb3Shyche
6236a24fb3Shyche
636f4c36e2SJérôme DuvalInode::Inode(Volume* volume)
646f4c36e2SJérôme Duval	:
656f4c36e2SJérôme Duval	fVolume(volume),
666f4c36e2SJérôme Duval	fID(0),
676f4c36e2SJérôme Duval	fCache(NULL),
686f4c36e2SJérôme Duval	fMap(NULL),
696f4c36e2SJérôme Duval	fInitStatus(B_NO_INIT)
706f4c36e2SJérôme Duval{
716f4c36e2SJérôme Duval	rw_lock_init(&fLock, "btrfs inode");
726f4c36e2SJérôme Duval}
736f4c36e2SJérôme Duval
746f4c36e2SJérôme Duval
756f4c36e2SJérôme DuvalInode::~Inode()
766f4c36e2SJérôme Duval{
776f4c36e2SJérôme Duval	TRACE("Inode destructor\n");
786f4c36e2SJérôme Duval	file_cache_delete(FileCache());
796f4c36e2SJérôme Duval	file_map_delete(Map());
806f4c36e2SJérôme Duval	TRACE("Inode destructor: Done\n");
816f4c36e2SJérôme Duval}
826f4c36e2SJérôme Duval
836f4c36e2SJérôme Duval
846f4c36e2SJérôme Duvalstatus_t
856f4c36e2SJérôme DuvalInode::InitCheck()
866f4c36e2SJérôme Duval{
876f4c36e2SJérôme Duval	return fInitStatus;
886f4c36e2SJérôme Duval}
896f4c36e2SJérôme Duval
906f4c36e2SJérôme Duval
916f4c36e2SJérôme Duvalstatus_t
926f4c36e2SJérôme DuvalInode::UpdateNodeFromDisk()
936f4c36e2SJérôme Duval{
94299aba38Shyche	btrfs_key search_key;
956f4c36e2SJérôme Duval	search_key.SetType(BTRFS_KEY_TYPE_INODE_ITEM);
966f4c36e2SJérôme Duval	search_key.SetObjectID(fID);
976f4c36e2SJérôme Duval	search_key.SetOffset(0);
983216460dShyche	BTree::Path path(fVolume->FSTree());
996f4c36e2SJérôme Duval
100299aba38Shyche	btrfs_inode* node;
1013216460dShyche	if (fVolume->FSTree()->FindExact(&path, search_key, (void**)&node)
1023216460dShyche		!= B_OK) {
1036f4c36e2SJérôme Duval		ERROR("Inode::UpdateNodeFromDisk(): Couldn't find inode %"
1046f4c36e2SJérôme Duval			B_PRIdINO "\n", fID);
1056f4c36e2SJérôme Duval		return B_ENTRY_NOT_FOUND;
1066f4c36e2SJérôme Duval	}
1076f4c36e2SJérôme Duval
108299aba38Shyche	memcpy(&fNode, node, sizeof(btrfs_inode));
1096f4c36e2SJérôme Duval	free(node);
1106f4c36e2SJérôme Duval	return B_OK;
1116f4c36e2SJérôme Duval}
1126f4c36e2SJérôme Duval
1136f4c36e2SJérôme Duval
11436a24fb3Shyche/*
11536a24fb3Shyche * Create new Inode object with inode_item
11636a24fb3Shyche */
11736a24fb3ShycheInode*
11836a24fb3ShycheInode::Create(Transaction& transaction, ino_t id, Inode* parent, int32 mode,
11936a24fb3Shyche	uint64 size, uint64 flags)
12036a24fb3Shyche{
12136a24fb3Shyche	TRACE("Inode::Create() id % " B_PRIu64 " mode %" B_PRId32 " flags %"
12236a24fb3Shyche		B_PRIu64"\n", id, flags, mode);
12336a24fb3Shyche
124aa08671dSLes De Ridder	Volume* volume = parent != NULL ?
125aa08671dSLes De Ridder		parent->GetVolume() : transaction.GetJournal()->GetVolume();
12636a24fb3Shyche	uint64 nbytes = size;	// allocated size
12736a24fb3Shyche	if (size > volume->MaxInlineSize())
12836a24fb3Shyche		nbytes = (size / volume->SectorSize() + 1) * volume->SectorSize();
12936a24fb3Shyche
13036a24fb3Shyche	btrfs_inode inode;
13136a24fb3Shyche
13236a24fb3Shyche	inode.generation = B_HOST_TO_LENDIAN_INT64(transaction.SystemID());
13336a24fb3Shyche	inode.transaction_id = B_HOST_TO_LENDIAN_INT64(transaction.SystemID());
13436a24fb3Shyche	inode.size = B_HOST_TO_LENDIAN_INT64(size);
13536a24fb3Shyche	inode.nbytes = B_HOST_TO_LENDIAN_INT64(nbytes);
13636a24fb3Shyche	inode.blockgroup = 0;	// normal inode only
13736a24fb3Shyche	inode.num_links = B_HOST_TO_LENDIAN_INT32(1);
13836a24fb3Shyche	inode.uid = B_HOST_TO_LENDIAN_INT32(geteuid());
139aa08671dSLes De Ridder	inode.gid = B_HOST_TO_LENDIAN_INT32(parent != NULL ?
140aa08671dSLes De Ridder		parent->GroupID() : getegid());
14136a24fb3Shyche	inode.mode = B_HOST_TO_LENDIAN_INT32(mode);;
14236a24fb3Shyche	inode.rdev = 0;	// normal file only
14336a24fb3Shyche	inode.flags = B_HOST_TO_LENDIAN_INT64(flags);
14436a24fb3Shyche	inode.sequence = 0;	// incremented each time mtime value is changed
14536a24fb3Shyche
14636a24fb3Shyche	uint64 now = real_time_clock_usecs();
14736a24fb3Shyche	struct timespec timespec;
14836a24fb3Shyche	timespec.tv_sec = now / 1000000;
14936a24fb3Shyche	timespec.tv_nsec = (now % 1000000) * 1000;
15036a24fb3Shyche	btrfs_inode::SetTime(inode.access_time, timespec);
15136a24fb3Shyche	btrfs_inode::SetTime(inode.creation_time, timespec);
15236a24fb3Shyche	btrfs_inode::SetTime(inode.change_time, timespec);
15336a24fb3Shyche	btrfs_inode::SetTime(inode.modification_time, timespec);
15436a24fb3Shyche
15536a24fb3Shyche	return new Inode(volume, id, inode);
15636a24fb3Shyche}
15736a24fb3Shyche
15836a24fb3Shyche
1596f4c36e2SJérôme Duvalstatus_t
1606f4c36e2SJérôme DuvalInode::CheckPermissions(int accessMode) const
1616f4c36e2SJérôme Duval{
1626f4c36e2SJérôme Duval	// you never have write access to a read-only volume
1636f4c36e2SJérôme Duval	if ((accessMode & W_OK) != 0 && fVolume->IsReadOnly())
1646f4c36e2SJérôme Duval		return B_READ_ONLY_DEVICE;
1656f4c36e2SJérôme Duval
1665a95af70SAxel Dörfler	return check_access_permissions(accessMode, Mode(), (gid_t)fNode.GroupID(),
1675a95af70SAxel Dörfler		(uid_t)fNode.UserID());
1686f4c36e2SJérôme Duval}
1696f4c36e2SJérôme Duval
1706f4c36e2SJérôme Duval
1716f4c36e2SJérôme Duvalstatus_t
1728864a6cbShycheInode::FindBlock(off_t pos, off_t& physical, off_t* _length)
1736f4c36e2SJérôme Duval{
174299aba38Shyche	btrfs_key search_key;
1756f4c36e2SJérôme Duval	search_key.SetType(BTRFS_KEY_TYPE_EXTENT_DATA);
1766f4c36e2SJérôme Duval	search_key.SetObjectID(fID);
1776f4c36e2SJérôme Duval	search_key.SetOffset(pos + 1);
1783216460dShyche	BTree::Path path(fVolume->FSTree());
1796f4c36e2SJérôme Duval
1808864a6cbShyche	btrfs_extent_data* extent_data;
1813216460dShyche	status_t status = fVolume->FSTree()->FindPrevious(&path, search_key,
1826f4c36e2SJérôme Duval		(void**)&extent_data);
1836f4c36e2SJérôme Duval	if (status != B_OK) {
184267a780aSJérôme Duval		ERROR("Inode::FindBlock(): Couldn't find extent_data 0x%" B_PRIx32
185267a780aSJérôme Duval			"\n", status);
1866f4c36e2SJérôme Duval		return status;
1876f4c36e2SJérôme Duval	}
1886f4c36e2SJérôme Duval
189267a780aSJérôme Duval	TRACE("Inode::FindBlock(%" B_PRIdINO ") key.Offset() %" B_PRId64 "\n",
190267a780aSJérôme Duval		ID(), search_key.Offset());
1916f4c36e2SJérôme Duval
1926f4c36e2SJérôme Duval	off_t diff = pos - search_key.Offset();
1936f4c36e2SJérôme Duval	off_t logical = 0;
1946f4c36e2SJérôme Duval	if (extent_data->Type() == BTRFS_EXTENT_DATA_REGULAR)
1956f4c36e2SJérôme Duval		logical = diff + extent_data->disk_offset;
1966f4c36e2SJérôme Duval	else
1976f4c36e2SJérôme Duval		panic("unknown extent type; %d\n", extent_data->Type());
1985a95af70SAxel Dörfler	status = fVolume->FindBlock(logical, physical);
1996f4c36e2SJérôme Duval	if (_length != NULL)
2006f4c36e2SJérôme Duval		*_length = extent_data->Size() - diff;
201267a780aSJérôme Duval	TRACE("Inode::FindBlock(%" B_PRIdINO ") %" B_PRIdOFF " physical %"
202267a780aSJérôme Duval		B_PRIdOFF "\n", ID(), pos, physical);
2035a95af70SAxel Dörfler
2046f4c36e2SJérôme Duval	free(extent_data);
2056f4c36e2SJérôme Duval	return status;
2066f4c36e2SJérôme Duval}
2076f4c36e2SJérôme Duval
2086f4c36e2SJérôme Duval
2096f4c36e2SJérôme Duvalstatus_t
2106f4c36e2SJérôme DuvalInode::ReadAt(off_t pos, uint8* buffer, size_t* _length)
2116f4c36e2SJérôme Duval{
2126f4c36e2SJérôme Duval	size_t length = *_length;
2136f4c36e2SJérôme Duval
2146f4c36e2SJérôme Duval	// set/check boundaries for pos/length
2156f4c36e2SJérôme Duval	if (pos < 0) {
2165a95af70SAxel Dörfler		ERROR("inode %" B_PRIdINO ": ReadAt failed(pos %" B_PRIdOFF
217267a780aSJérôme Duval			", length %lu)\n", ID(), pos, length);
2186f4c36e2SJérôme Duval		return B_BAD_VALUE;
2196f4c36e2SJérôme Duval	}
2206f4c36e2SJérôme Duval
2216f4c36e2SJérôme Duval	if (pos >= Size() || length == 0) {
222267a780aSJérôme Duval		TRACE("inode %" B_PRIdINO ": ReadAt 0 (pos %" B_PRIdOFF
223267a780aSJérôme Duval			", length %lu)\n", ID(), pos, length);
2246f4c36e2SJérôme Duval		*_length = 0;
2256f4c36e2SJérôme Duval		return B_NO_ERROR;
2266f4c36e2SJérôme Duval	}
2276f4c36e2SJérôme Duval
2286f4c36e2SJérôme Duval	// the file cache doesn't seem to like non block aligned file offset
2296f4c36e2SJérôme Duval	// so we avoid the file cache for inline extents
230299aba38Shyche	btrfs_key search_key;
2316f4c36e2SJérôme Duval	search_key.SetType(BTRFS_KEY_TYPE_EXTENT_DATA);
2326f4c36e2SJérôme Duval	search_key.SetObjectID(fID);
2336f4c36e2SJérôme Duval	search_key.SetOffset(pos + 1);
2343216460dShyche	BTree::Path path(fVolume->FSTree());
2356f4c36e2SJérôme Duval
23616de9db5Shyche	uint32 item_size;
2378864a6cbShyche	btrfs_extent_data* extent_data;
2383216460dShyche	status_t status = fVolume->FSTree()->FindPrevious(&path, search_key,
239b1f9573fSJérôme Duval		(void**)&extent_data, &item_size);
2406f4c36e2SJérôme Duval	if (status != B_OK) {
241267a780aSJérôme Duval		ERROR("Inode::FindBlock(): Couldn't find extent_data 0x%" B_PRIx32
242267a780aSJérôme Duval			"\n", status);
2436f4c36e2SJérôme Duval		return status;
2446f4c36e2SJérôme Duval	}
245efac84e7SRob Gill	MemoryDeleter deleter(extent_data);
246efac84e7SRob Gill
2476f4c36e2SJérôme Duval
248b1f9573fSJérôme Duval	uint8 compression = extent_data->Compression();
2496f4c36e2SJérôme Duval	if (FileCache() != NULL
2506f4c36e2SJérôme Duval		&& extent_data->Type() == BTRFS_EXTENT_DATA_REGULAR) {
2515a95af70SAxel Dörfler		TRACE("inode %" B_PRIdINO ": ReadAt cache (pos %" B_PRIdOFF ", length %lu)\n",
2526f4c36e2SJérôme Duval			ID(), pos, length);
253b1f9573fSJérôme Duval		if (compression == BTRFS_EXTENT_COMPRESS_NONE)
254b1f9573fSJérôme Duval			return file_cache_read(FileCache(), NULL, pos, buffer, _length);
255b1f9573fSJérôme Duval		else if (compression == BTRFS_EXTENT_COMPRESS_ZLIB)
256b1f9573fSJérôme Duval			panic("zlib isn't unsupported for regular extent\n");
257b1f9573fSJérôme Duval		else
258b1f9573fSJérôme Duval			panic("unknown extent compression; %d\n", compression);
259efac84e7SRob Gill		return B_BAD_DATA;
2606f4c36e2SJérôme Duval	}
2616f4c36e2SJérôme Duval
262267a780aSJérôme Duval	TRACE("Inode::ReadAt(%" B_PRIdINO ") key.Offset() %" B_PRId64 "\n", ID(),
2636f4c36e2SJérôme Duval		search_key.Offset());
2646f4c36e2SJérôme Duval
2656f4c36e2SJérôme Duval	off_t diff = pos - search_key.Offset();
266efac84e7SRob Gill	if (extent_data->Type() != BTRFS_EXTENT_DATA_INLINE) {
2676f4c36e2SJérôme Duval		panic("unknown extent type; %d\n", extent_data->Type());
268efac84e7SRob Gill		return B_BAD_DATA;
269efac84e7SRob Gill	}
2706f4c36e2SJérôme Duval
271b1f9573fSJérôme Duval	*_length = min_c(extent_data->Size() - diff, *_length);
272b1f9573fSJérôme Duval	if (compression == BTRFS_EXTENT_COMPRESS_NONE)
273b1f9573fSJérôme Duval		memcpy(buffer, extent_data->inline_data, *_length);
274b1f9573fSJérôme Duval	else if (compression == BTRFS_EXTENT_COMPRESS_ZLIB) {
275b1f9573fSJérôme Duval		char in[2048];
276b1f9573fSJérôme Duval		z_stream zStream = {
277b1f9573fSJérôme Duval			(Bytef*)in,		// next in
278b1f9573fSJérôme Duval			sizeof(in),		// avail in
279b1f9573fSJérôme Duval			0,				// total in
280b1f9573fSJérôme Duval			NULL,			// next out
281b1f9573fSJérôme Duval			0,				// avail out
282b1f9573fSJérôme Duval			0,				// total out
283b1f9573fSJérôme Duval			0,				// msg
284b1f9573fSJérôme Duval			0,				// state
285b1f9573fSJérôme Duval			Z_NULL,			// zalloc
286b1f9573fSJérôme Duval			Z_NULL,			// zfree
287b1f9573fSJérôme Duval			Z_NULL,			// opaque
288b1f9573fSJérôme Duval			0,				// data type
289b1f9573fSJérôme Duval			0,				// adler
290b1f9573fSJérôme Duval			0,				// reserved
291b1f9573fSJérôme Duval		};
292b1f9573fSJérôme Duval
293b1f9573fSJérôme Duval		int status;
294b1f9573fSJérôme Duval		ssize_t offset = 0;
29516de9db5Shyche		uint32 inline_size = item_size - 13;
296b1f9573fSJérôme Duval		bool headerRead = false;
297b1f9573fSJérôme Duval
298267a780aSJérôme Duval		TRACE("Inode::ReadAt(%" B_PRIdINO ") diff %" B_PRIdOFF " size %"
299267a780aSJérôme Duval			B_PRIuSIZE "\n", ID(), diff, item_size);
300b1f9573fSJérôme Duval
301b1f9573fSJérôme Duval		do {
302b1f9573fSJérôme Duval			ssize_t bytesRead = min_c(sizeof(in), inline_size - offset);
3034534d86dSAdrien Destugues			if (bytesRead <= 0) {
3044534d86dSAdrien Destugues				status = Z_STREAM_ERROR;
3054534d86dSAdrien Destugues				break;
306b1f9573fSJérôme Duval			}
3074534d86dSAdrien Destugues			memcpy(in, extent_data->inline_data + offset, bytesRead);
308b1f9573fSJérôme Duval
309b1f9573fSJérôme Duval			zStream.avail_in = bytesRead;
310b1f9573fSJérôme Duval			zStream.next_in = (Bytef*)in;
311b1f9573fSJérôme Duval
312b1f9573fSJérôme Duval			if (!headerRead) {
313b1f9573fSJérôme Duval				headerRead = true;
314b1f9573fSJérôme Duval
315b1f9573fSJérôme Duval				zStream.avail_out = length;
316b1f9573fSJérôme Duval				zStream.next_out = (Bytef*)buffer;
317b1f9573fSJérôme Duval
318b1f9573fSJérôme Duval				status = inflateInit2(&zStream, 15);
319b1f9573fSJérôme Duval				if (status != Z_OK) {
320b1f9573fSJérôme Duval					return B_ERROR;
321b1f9573fSJérôme Duval				}
322b1f9573fSJérôme Duval			}
323b1f9573fSJérôme Duval
324b1f9573fSJérôme Duval			status = inflate(&zStream, Z_SYNC_FLUSH);
325b1f9573fSJérôme Duval			offset += bytesRead;
326b1f9573fSJérôme Duval			if (diff > 0) {
327b1f9573fSJérôme Duval				zStream.next_out -= max_c(bytesRead, diff);
328b1f9573fSJérôme Duval				diff -= max_c(bytesRead, diff);
329b1f9573fSJérôme Duval			}
330b1f9573fSJérôme Duval
331b1f9573fSJérôme Duval			if (zStream.avail_in != 0 && status != Z_STREAM_END) {
332b1f9573fSJérôme Duval				TRACE("Inode::ReadAt() didn't read whole block: %s\n",
333b1f9573fSJérôme Duval					zStream.msg);
334b1f9573fSJérôme Duval			}
335b1f9573fSJérôme Duval		} while (status == Z_OK);
336b1f9573fSJérôme Duval
337b1f9573fSJérôme Duval		inflateEnd(&zStream);
338b1f9573fSJérôme Duval
339b1f9573fSJérôme Duval		if (status != Z_STREAM_END) {
340b1f9573fSJérôme Duval			TRACE("Inode::ReadAt() inflating failed: %d!\n", status);
341b1f9573fSJérôme Duval			return B_BAD_DATA;
342b1f9573fSJérôme Duval		}
343b1f9573fSJérôme Duval
344b1f9573fSJérôme Duval		*_length = zStream.total_out;
345b1f9573fSJérôme Duval
346efac84e7SRob Gill	} else {
347b1f9573fSJérôme Duval		panic("unknown extent compression; %d\n", compression);
348efac84e7SRob Gill		return B_BAD_DATA;
349efac84e7SRob Gill	}
3506f4c36e2SJérôme Duval	return B_OK;
3515a95af70SAxel Dörfler
3526f4c36e2SJérôme Duval}
3536f4c36e2SJérôme Duval
3546f4c36e2SJérôme Duval
3556f4c36e2SJérôme Duvalstatus_t
3568864a6cbShycheInode::FindParent(ino_t* id)
3576f4c36e2SJérôme Duval{
358299aba38Shyche	btrfs_key search_key;
3596f4c36e2SJérôme Duval	search_key.SetType(BTRFS_KEY_TYPE_INODE_REF);
3606f4c36e2SJérôme Duval	search_key.SetObjectID(fID);
3616f4c36e2SJérôme Duval	search_key.SetOffset(-1);
3623216460dShyche	BTree::Path path(fVolume->FSTree());
3636f4c36e2SJérôme Duval
3648864a6cbShyche	void* node_ref;
3653216460dShyche	if (fVolume->FSTree()->FindPrevious(&path, search_key, &node_ref) != B_OK) {
3666f4c36e2SJérôme Duval		ERROR("Inode::FindParent(): Couldn't find inode for %" B_PRIdINO "\n",
3676f4c36e2SJérôme Duval			fID);
3686f4c36e2SJérôme Duval		return B_ERROR;
3696f4c36e2SJérôme Duval	}
3706f4c36e2SJérôme Duval
3716f4c36e2SJérôme Duval	free(node_ref);
3726f4c36e2SJérôme Duval	*id = search_key.Offset();
3736f4c36e2SJérôme Duval	TRACE("Inode::FindParent() for %" B_PRIdINO ": %" B_PRIdINO "\n", fID,
3746f4c36e2SJérôme Duval		*id);
3755a95af70SAxel Dörfler
3766f4c36e2SJérôme Duval	return B_OK;
3776f4c36e2SJérôme Duval}
3786f4c36e2SJérôme Duval
379371935deShyche
380b44d924dShycheuint64
381b44d924dShycheInode::FindNextIndex(BTree::Path* path) const
382b44d924dShyche{
383b44d924dShyche	btrfs_key key;
384b44d924dShyche	key.SetObjectID(fID);
385b44d924dShyche	key.SetType(BTRFS_KEY_TYPE_DIR_INDEX);
386b44d924dShyche	key.SetOffset(-1);
387b44d924dShyche
388b44d924dShyche	if (fVolume->FSTree()->FindPrevious(path, key, NULL))
389b44d924dShyche		return 2;		// not found any dir index item
390b44d924dShyche
391b44d924dShyche	return key.Offset() + 1;
392b44d924dShyche}
393b44d924dShyche
394b44d924dShyche
395371935deShyche/* Insert inode_item
396371935deShyche */
397371935deShychestatus_t
398371935deShycheInode::Insert(Transaction& transaction, BTree::Path* path)
399371935deShyche{
400371935deShyche	BTree* tree = path->Tree();
401371935deShyche
402371935deShyche	btrfs_entry item;
403371935deShyche	item.key.SetObjectID(fID);
404371935deShyche	item.key.SetType(BTRFS_KEY_TYPE_INODE_ITEM);
405371935deShyche	item.key.SetOffset(0);
406371935deShyche	item.SetSize(sizeof(btrfs_inode));
407371935deShyche
408371935deShyche	void* data[1];
409371935deShyche	data[0] = (void*)&fNode;
410371935deShyche	status_t status = tree->InsertEntries(transaction, path, &item, data, 1);
411371935deShyche	if (status != B_OK)
412371935deShyche		return status;
413371935deShyche
414b44d924dShyche	return B_OK;
415b44d924dShyche}
416b44d924dShyche
417b44d924dShyche
4188042a045Shyche/* Remove inode_item
4198042a045Shyche */
4208042a045Shychestatus_t
4218042a045ShycheInode::Remove(Transaction& transaction, BTree::Path* path)
4228042a045Shyche{
4238042a045Shyche	BTree* tree = path->Tree();
4248042a045Shyche	btrfs_key key;
4258042a045Shyche	key.SetObjectID(fID);
4268042a045Shyche	key.SetType(BTRFS_KEY_TYPE_INODE_ITEM);
4278042a045Shyche	key.SetOffset(0);
4288042a045Shyche	status_t status = tree->RemoveEntries(transaction, path, key, NULL, 1);
4298042a045Shyche	if (status != B_OK)
4308042a045Shyche		return status;
4318042a045Shyche
4328042a045Shyche	return B_OK;
4338042a045Shyche}
4348042a045Shyche
4358042a045Shyche
436b44d924dShyche/* Insert 3 items: inode_ref, dir_item, dir_index
437b44d924dShyche * Basically, make a link between name and its node (location)
438b44d924dShyche */
439b44d924dShychestatus_t
440b44d924dShycheInode::MakeReference(Transaction& transaction, BTree::Path* path,
441b44d924dShyche	Inode* parent, const char* name, int32 mode)
442b44d924dShyche{
443b44d924dShyche	BTree* tree = fVolume->FSTree();
444b44d924dShyche	uint16 nameLength = strlen(name);
445b44d924dShyche	uint64 index = parent->FindNextIndex(path);
446b44d924dShyche
447b44d924dShyche	// insert inode_ref
4480a4cbf0dShyche	btrfs_inode_ref* inodeRef = (btrfs_inode_ref*)malloc(sizeof(btrfs_inode_ref)
4490a4cbf0dShyche		+ nameLength);
4500a4cbf0dShyche	if (inodeRef == NULL)
4510a4cbf0dShyche		return B_NO_MEMORY;
4520a4cbf0dShyche	inodeRef->index = index;
4530a4cbf0dShyche	inodeRef->SetName(name, nameLength);
454b44d924dShyche
4550a4cbf0dShyche	btrfs_entry entry;
456b44d924dShyche	entry.key.SetObjectID(fID);
457b44d924dShyche	entry.key.SetType(BTRFS_KEY_TYPE_INODE_REF);
458b44d924dShyche	entry.key.SetOffset(parent->ID());
4590a4cbf0dShyche	entry.SetSize(inodeRef->Length());
460b44d924dShyche
4610a4cbf0dShyche	status_t status = tree->InsertEntries(transaction, path, &entry,
4620a4cbf0dShyche		(void**)&inodeRef, 1);
4630a4cbf0dShyche	free(inodeRef);
464b44d924dShyche	if (status != B_OK)
465b44d924dShyche		return status;
466b44d924dShyche
467b44d924dShyche	// insert dir_entry
468b44d924dShyche	uint32 hash = calculate_crc((uint32)~1, (uint8*)name, nameLength);
4690a4cbf0dShyche	btrfs_dir_entry* directoryEntry =
4700a4cbf0dShyche		(btrfs_dir_entry*)malloc(sizeof(btrfs_dir_entry) + nameLength);
4710a4cbf0dShyche	if (directoryEntry == NULL)
4720a4cbf0dShyche		return B_NO_MEMORY;
4730a4cbf0dShyche	directoryEntry->location.SetObjectID(fID);
4740a4cbf0dShyche	directoryEntry->location.SetType(BTRFS_KEY_TYPE_INODE_ITEM);
4750a4cbf0dShyche	directoryEntry->location.SetOffset(0);
4760a4cbf0dShyche	directoryEntry->SetTransactionID(transaction.SystemID());
477b44d924dShyche	// TODO: xattribute, 0 for standard directory
4780a4cbf0dShyche	directoryEntry->SetName(name, nameLength);
4790a4cbf0dShyche	directoryEntry->SetAttributeData(NULL, 0);
4800a4cbf0dShyche	directoryEntry->type = get_filetype(mode);
481b44d924dShyche
482b44d924dShyche	entry.key.SetObjectID(parent->ID());
483b44d924dShyche	entry.key.SetType(BTRFS_KEY_TYPE_DIR_ITEM);
484b44d924dShyche	entry.key.SetOffset(hash);
4850a4cbf0dShyche	entry.SetSize(directoryEntry->Length());
486b44d924dShyche
4870a4cbf0dShyche	status = tree->InsertEntries(transaction, path, &entry,
4880a4cbf0dShyche		(void**)&directoryEntry, 1);
4890a4cbf0dShyche	if (status != B_OK) {
4900a4cbf0dShyche		free(directoryEntry);
491b44d924dShyche		return status;
4920a4cbf0dShyche	}
493b44d924dShyche
494b44d924dShyche	// insert dir_index (has same data with dir_entry)
495b44d924dShyche	entry.key.SetType(BTRFS_KEY_TYPE_DIR_INDEX);
496b44d924dShyche	entry.key.SetOffset(index);
497b44d924dShyche
4980a4cbf0dShyche	status = tree->InsertEntries(transaction, path, &entry,
4990a4cbf0dShyche		(void**)&directoryEntry, 1);
5000a4cbf0dShyche	if (status != B_OK) {
5010a4cbf0dShyche		free(directoryEntry);
502b44d924dShyche		return status;
5030a4cbf0dShyche	}
504371935deShyche
5050a4cbf0dShyche	free(directoryEntry);
506371935deShyche	return B_OK;
507371935deShyche}
508a9e85cb6Shyche
509a9e85cb6Shyche
510a9e85cb6Shyche// Remove the "name" and unlink it with inode.
511a9e85cb6Shychestatus_t
512a9e85cb6ShycheInode::Dereference(Transaction& transaction, BTree::Path* path, ino_t parentID,
513a9e85cb6Shyche	const char* name)
514a9e85cb6Shyche{
515a9e85cb6Shyche	BTree* tree = path->Tree();
516a9e85cb6Shyche
517a9e85cb6Shyche	// remove inode_ref item
518a9e85cb6Shyche	btrfs_key key;
519a9e85cb6Shyche	key.SetObjectID(fID);
520a9e85cb6Shyche	key.SetType(BTRFS_KEY_TYPE_INODE_REF);
521a9e85cb6Shyche	key.SetOffset(parentID);
522a9e85cb6Shyche	btrfs_inode_ref* inodeRef;
523a9e85cb6Shyche	status_t status = tree->RemoveEntries(transaction, path, key,
524a9e85cb6Shyche		(void**)&inodeRef, 1);
525a9e85cb6Shyche	if (status != B_OK)
526a9e85cb6Shyche		return status;
527a9e85cb6Shyche
528a9e85cb6Shyche	// remove dir_item
529a9e85cb6Shyche	uint32 hash = calculate_crc((uint32)~1, (uint8*)name, strlen(name));
530a9e85cb6Shyche	key.SetObjectID(parentID);
531a9e85cb6Shyche	key.SetType(BTRFS_KEY_TYPE_DIR_ITEM);
532a9e85cb6Shyche	key.SetOffset(hash);
533a9e85cb6Shyche	status = tree->RemoveEntries(transaction, path, key, NULL, 1);
534a9e85cb6Shyche	if (status != B_OK)
535a9e85cb6Shyche		return status;
536a9e85cb6Shyche
537a9e85cb6Shyche	// remove dir_index
538a9e85cb6Shyche	uint64 index = inodeRef->Index();
539a9e85cb6Shyche	free(inodeRef);
540a9e85cb6Shyche	key.SetType(BTRFS_KEY_TYPE_DIR_INDEX);
541a9e85cb6Shyche	key.SetOffset(index);
542a9e85cb6Shyche	status = tree->RemoveEntries(transaction, path, key, NULL, 1);
543a9e85cb6Shyche	if (status != B_OK)
544a9e85cb6Shyche		return status;
545a9e85cb6Shyche
546a9e85cb6Shyche	return B_OK;
547a9e85cb6Shyche}
548