Esempio n. 1
0
static status_t
ext2_lookup(fs_volume* _volume, fs_vnode* _directory, const char* name,
	ino_t* _vnodeID)
{
	TRACE("ext2_lookup: name address: %p\n", name);
	TRACE("ext2_lookup: name: %s\n", name);
	Volume* volume = (Volume*)_volume->private_volume;
	Inode* directory = (Inode*)_directory->private_node;

	// check access permissions
	status_t status = directory->CheckPermissions(X_OK);
	if (status < B_OK)
		return status;

	HTree htree(volume, directory);
	DirectoryIterator* iterator;

	status = htree.Lookup(name, &iterator);
	if (status != B_OK)
		return status;

	ObjectDeleter<DirectoryIterator> iteratorDeleter(iterator);

	status = iterator->FindEntry(name, _vnodeID);
	if (status != B_OK)
		return status;

	return get_vnode(volume->FSVolume(), *_vnodeID, NULL);
}
Esempio n. 2
0
static status_t
ext2_open(fs_volume* _volume, fs_vnode* _node, int openMode, void** _cookie)
{
	Volume* volume = (Volume*)_volume->private_volume;
	Inode* inode = (Inode*)_node->private_node;

	// opening a directory read-only is allowed, although you can't read
	// any data from it.
	if (inode->IsDirectory() && (openMode & O_RWMASK) != 0)
		return B_IS_A_DIRECTORY;

	status_t status =  inode->CheckPermissions(open_mode_to_access(openMode)
		| (openMode & O_TRUNC ? W_OK : 0));
	if (status != B_OK)
		return status;

	// Prepare the cookie
	file_cookie* cookie = new(std::nothrow) file_cookie;
	if (cookie == NULL)
		return B_NO_MEMORY;
	ObjectDeleter<file_cookie> cookieDeleter(cookie);

	cookie->open_mode = openMode & EXT2_OPEN_MODE_USER_MASK;
	cookie->last_size = inode->Size();
	cookie->last_notification = system_time();

	MethodDeleter<Inode, status_t> fileCacheEnabler(&Inode::EnableFileCache);
	if ((openMode & O_NOCACHE) != 0) {
		status = inode->DisableFileCache();
		if (status != B_OK)
			return status;
		fileCacheEnabler.SetTo(inode);
	}

	// Should we truncate the file?
	if ((openMode & O_TRUNC) != 0) {
		if ((openMode & O_RWMASK) == O_RDONLY)
			return B_NOT_ALLOWED;

		Transaction transaction(volume->GetJournal());
		inode->WriteLockInTransaction(transaction);

		status_t status = inode->Resize(transaction, 0);
		if (status == B_OK)
			status = inode->WriteBack(transaction);
		if (status == B_OK)
			status = transaction.Done();
		if (status != B_OK)
			return status;

		// TODO: No need to notify file size changed?
	}

	fileCacheEnabler.Detach();
	cookieDeleter.Detach();
	*_cookie = cookie;

	return B_OK;
}
Esempio n. 3
0
static status_t
ext2_unlink(fs_volume* _volume, fs_vnode* _directory, const char* name)
{
	TRACE("ext2_unlink()\n");
	if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
		return B_NOT_ALLOWED;

	Volume* volume = (Volume*)_volume->private_volume;
	Inode* directory = (Inode*)_directory->private_node;

	status_t status = directory->CheckPermissions(W_OK);
	if (status != B_OK)
		return status;

	TRACE("ext2_unlink(): Starting transaction\n");
	Transaction transaction(volume->GetJournal());

	directory->WriteLockInTransaction(transaction);

	TRACE("ext2_unlink(): Looking up for directory entry\n");
	HTree htree(volume, directory);
	DirectoryIterator* directoryIterator;

	status = htree.Lookup(name, &directoryIterator);
	if (status != B_OK)
		return status;

	ino_t id;
	status = directoryIterator->FindEntry(name, &id);
	if (status != B_OK)
		return status;

	Vnode vnode(volume, id);
	Inode* inode;
	status = vnode.Get(&inode);
	if (status != B_OK)
		return status;

	inode->WriteLockInTransaction(transaction);

	status = inode->Unlink(transaction);
	if (status != B_OK)
		return status;

	status = directoryIterator->RemoveEntry(transaction);
	if (status != B_OK)
		return status;

	entry_cache_remove(volume->ID(), directory->ID(), name);

	status = transaction.Done();
	if (status != B_OK)
		entry_cache_add(volume->ID(), directory->ID(), name, id);
	else
		notify_entry_removed(volume->ID(), directory->ID(), name, id);

	return status;
}
Esempio n. 4
0
static status_t
ext2_open_dir(fs_volume* _volume, fs_vnode* _node, void** _cookie)
{
	Inode* inode = (Inode*)_node->private_node;
	status_t status = inode->CheckPermissions(R_OK);
	if (status < B_OK)
		return status;

	if (!inode->IsDirectory())
		return B_NOT_A_DIRECTORY;

	DirectoryIterator* iterator = new(std::nothrow) DirectoryIterator(inode);
	if (iterator == NULL)
		return B_NO_MEMORY;

	*_cookie = iterator;
	return B_OK;
}
Esempio n. 5
0
static status_t
btrfs_lookup(fs_volume* _volume, fs_vnode* _directory, const char* name,
	ino_t* _vnodeID)
{
	TRACE("btrfs_lookup: name address: %p (%s)\n", name, name);
	Volume* volume = (Volume*)_volume->private_volume;
	Inode* directory = (Inode*)_directory->private_node;

	// check access permissions
	status_t status = directory->CheckPermissions(X_OK);
	if (status < B_OK)
		return status;

	status = DirectoryIterator(directory).Lookup(name, strlen(name), _vnodeID);
	if (status != B_OK)
		return status;
	
	return get_vnode(volume->FSVolume(), *_vnodeID, NULL);
}
Esempio n. 6
0
static status_t
ext2_create_dir(fs_volume* _volume, fs_vnode* _directory, const char* name,
	int mode)
{
	TRACE("ext2_create_dir()\n");
	Volume* volume = (Volume*)_volume->private_volume;
	Inode* directory = (Inode*)_directory->private_node;

	if (volume->IsReadOnly())
		return B_READ_ONLY_DEVICE;

	if (!directory->IsDirectory())
		return B_BAD_TYPE;

	status_t status = directory->CheckPermissions(W_OK);
	if (status != B_OK)
		return status;

	TRACE("ext2_create_dir(): Starting transaction\n");
	Transaction transaction(volume->GetJournal());

	ino_t id;
	status = Inode::Create(transaction, directory, name,
		S_DIRECTORY | (mode & S_IUMSK), 0, EXT2_TYPE_DIRECTORY, NULL, &id);
	if (status != B_OK)
		return status;

	put_vnode(volume->FSVolume(), id);

	entry_cache_add(volume->ID(), directory->ID(), name, id);

	status = transaction.Done();
	if (status != B_OK) {
		entry_cache_remove(volume->ID(), directory->ID(), name);
		return status;
	}

	notify_entry_created(volume->ID(), directory->ID(), name, id);

	TRACE("ext2_create_dir(): Done\n");

	return B_OK;
}
Esempio n. 7
0
static status_t
btrfs_open(fs_volume* /*_volume*/, fs_vnode* _node, int openMode,
	void** _cookie)
{
	Inode* inode = (Inode*)_node->private_node;

	// opening a directory read-only is allowed, although you can't read
	// any data from it.
	if (inode->IsDirectory() && (openMode & O_RWMASK) != 0)
		return B_IS_A_DIRECTORY;

	status_t status =  inode->CheckPermissions(open_mode_to_access(openMode)
		| (openMode & O_TRUNC ? W_OK : 0));
	if (status != B_OK)
		return status;

	// Prepare the cookie
	file_cookie* cookie = new(std::nothrow) file_cookie;
	if (cookie == NULL)
		return B_NO_MEMORY;
	ObjectDeleter<file_cookie> cookieDeleter(cookie);

	cookie->open_mode = openMode & BTRFS_OPEN_MODE_USER_MASK;
	cookie->last_size = inode->Size();
	cookie->last_notification = system_time();

	if ((openMode & O_NOCACHE) != 0 && inode->FileCache() != NULL) {
		// Disable the file cache, if requested?
		status = file_cache_disable(inode->FileCache());
		if (status != B_OK)
			return status;
	}

	cookieDeleter.Detach();
	*_cookie = cookie;

	return B_OK;
}
Esempio n. 8
0
static status_t
btrfs_access(fs_volume* _volume, fs_vnode* _node, int accessMode)
{
	Inode* inode = (Inode*)_node->private_node;
	return inode->CheckPermissions(accessMode);
}
Esempio n. 9
0
/*static*/ status_t
Inode::Create(Transaction& transaction, Inode* parent, const char* name,
	int32 mode, int openMode, uint8 type, bool* _created, ino_t* _id,
	Inode** _inode, fs_vnode_ops* vnodeOps, uint32 publishFlags)
{
	TRACE("Inode::Create()\n");
	Volume* volume = transaction.GetVolume();

	DirectoryIterator* entries = NULL;
	ObjectDeleter<DirectoryIterator> entriesDeleter;

	if (parent != NULL) {
		parent->WriteLockInTransaction(transaction);

		TRACE("Inode::Create(): Looking up entry destination\n");
		HTree htree(volume, parent);

		status_t status = htree.Lookup(name, &entries);
		if (status == B_ENTRY_NOT_FOUND) {
			panic("We need to add the first node.\n");
			return B_ERROR;
		}
		if (status != B_OK)
			return status;
		entriesDeleter.SetTo(entries);

		TRACE("Inode::Create(): Looking up to see if file already exists\n");
		ino_t entryID;

		status = entries->FindEntry(name, &entryID);
		if (status == B_OK) {
			// File already exists
			TRACE("Inode::Create(): File already exists\n");
			if (S_ISDIR(mode) || S_ISLNK(mode) || (openMode & O_EXCL) != 0)
				return B_FILE_EXISTS;

			Vnode vnode(volume, entryID);
			Inode* inode;

			status = vnode.Get(&inode);
			if (status != B_OK) {
				TRACE("Inode::Create() Failed to get the inode from the "
					"vnode\n");
				return B_ENTRY_NOT_FOUND;
			}

			if (inode->IsDirectory() && (openMode & O_RWMASK) != O_RDONLY)
				return B_IS_A_DIRECTORY;
			if ((openMode & O_DIRECTORY) != 0 && !inode->IsDirectory())
				return B_NOT_A_DIRECTORY;

			if (inode->CheckPermissions(open_mode_to_access(openMode)
					| ((openMode & O_TRUNC) != 0 ? W_OK : 0)) != B_OK)
				return B_NOT_ALLOWED;

			if ((openMode & O_TRUNC) != 0) {
				// Truncate requested
				TRACE("Inode::Create(): Truncating file\n");
				inode->WriteLockInTransaction(transaction);

				status = inode->Resize(transaction, 0);
				if (status != B_OK)
					return status;
			}

			if (_created != NULL)
				*_created = false;
			if (_id != NULL)
				*_id = inode->ID();
			if (_inode != NULL)
				*_inode = inode;

			if (_id != NULL || _inode != NULL)
				vnode.Keep();

			TRACE("Inode::Create(): Done opening file\n");
			return B_OK;
		/*} else if ((mode & S_ATTR_DIR) == 0) {
			TRACE("Inode::Create(): (mode & S_ATTR_DIR) == 0\n");
			return B_BAD_VALUE;*/
		} else if ((openMode & O_DIRECTORY) != 0) {
			TRACE("Inode::Create(): (openMode & O_DIRECTORY) != 0\n");
			return B_ENTRY_NOT_FOUND;
		}

		// Return to initial position
		TRACE("Inode::Create(): Restarting iterator\n");
		entries->Restart();
	}

	status_t status;
	if (parent != NULL) {
		status = parent->CheckPermissions(W_OK);
		if (status != B_OK)
			return status;
	}

	TRACE("Inode::Create(): Allocating inode\n");
	ino_t id;
	status = volume->AllocateInode(transaction, parent, mode, id);
	if (status != B_OK) {
		ERROR("Inode::Create(): AllocateInode() failed\n");
		return status;
	}

	if (entries != NULL) {
		size_t nameLength = strlen(name);
		status = entries->AddEntry(transaction, name, nameLength, id, type);
		if (status != B_OK) {
			ERROR("Inode::Create(): AddEntry() failed\n");
			return status;
		}
	}

	TRACE("Inode::Create(): Creating inode\n");
	Inode* inode = new(std::nothrow) Inode(volume);
	if (inode == NULL)
		return B_NO_MEMORY;

	TRACE("Inode::Create(): Getting node structure\n");
	ext2_inode& node = inode->Node();
	TRACE("Inode::Create(): Initializing inode data\n");
	memset(&node, 0, sizeof(ext2_inode));
	node.SetMode(mode);
	node.SetUserID(geteuid());
	node.SetGroupID(parent != NULL ? parent->Node().GroupID() : getegid());
	node.SetNumLinks(inode->IsDirectory() ? 2 : 1);
	TRACE("Inode::Create(): Updating time\n");
	struct timespec timespec;
	_BigtimeToTimespec(real_time_clock_usecs(), &timespec);
	inode->SetAccessTime(&timespec);
	inode->SetCreationTime(&timespec);
	inode->SetModificationTime(&timespec);
	node.SetFlags(parent->Flags() & EXT2_INODE_INHERITED);
	if (volume->HasExtentsFeature() 
		&& (inode->IsDirectory() || inode->IsFile())) {
		node.SetFlag(EXT2_INODE_EXTENTS);
		ExtentStream stream(volume, &node.extent_stream, 0);
		stream.Init();
		ASSERT(stream.Check());
	}

	if (sizeof(ext2_inode) < volume->InodeSize())
		node.SetExtraInodeSize(sizeof(ext2_inode) - EXT2_INODE_NORMAL_SIZE);

	TRACE("Inode::Create(): Updating ID\n");
	inode->fID = id;

	if (inode->IsDirectory()) {
		TRACE("Inode::Create(): Initializing directory\n");
		status = inode->InitDirectory(transaction, parent);
		if (status != B_OK) {
			ERROR("Inode::Create(): InitDirectory() failed\n");
			delete inode;
			return status;
		}
	}

	// TODO: Maybe it can be better
	/*if (volume->HasExtendedAttributes()) {
		TRACE("Inode::Create(): Initializing extended attributes\n");
		uint32 blockGroup = 0;
		uint32 pos = 0;
		uint32 allocated;

		status = volume->AllocateBlocks(transaction, 1, 1, blockGroup, pos,
			allocated);
		if (status != B_OK)
			return status;

		// Clear the new block
		uint32 blockNum = volume->FirstDataBlock() + pos +
			volume->BlocksPerGroup() * blockGroup;
		CachedBlock cached(volume);
		cached.SetToWritable(transaction, blockNum, true);

		node.SetExtendedAttributesBlock(blockNum);
	}*/

	TRACE("Inode::Create(): Saving inode\n");
	status = inode->WriteBack(transaction);
	if (status != B_OK) {
		delete inode;
		return status;
	}

	TRACE("Inode::Create(): Creating vnode\n");

	Vnode vnode;
	status = vnode.Publish(transaction, inode, vnodeOps, publishFlags);
	if (status != B_OK)
		return status;

	if (!inode->IsSymLink()) {
		// Vnode::Publish doesn't publish symlinks
		if (!inode->IsDirectory()) {
			status = inode->EnableFileCache();
			if (status != B_OK)
				return status;
		}

		inode->WriteLockInTransaction(transaction);
	}

	if (_created)
		*_created = true;
	if (_id != NULL)
		*_id = id;
	if (_inode != NULL)
		*_inode = inode;

	if (_id != NULL || _inode != NULL)
		vnode.Keep();

	TRACE("Inode::Create(): Deleting entries iterator\n");
	DirectoryIterator* iterator = entriesDeleter.Detach();
	TRACE("Inode::Create(): Entries iterator: %p\n", entries);
	delete iterator;
	TRACE("Inode::Create(): Done\n");

	return B_OK;
}
Esempio n. 10
0
static status_t
ext2_rename(fs_volume* _volume, fs_vnode* _oldDir, const char* oldName,
	fs_vnode* _newDir, const char* newName)
{
	TRACE("ext2_rename()\n");

	Volume* volume = (Volume*)_volume->private_volume;
	Inode* oldDirectory = (Inode*)_oldDir->private_node;
	Inode* newDirectory = (Inode*)_newDir->private_node;

	if (oldDirectory == newDirectory && strcmp(oldName, newName) == 0)
		return B_OK;

	Transaction transaction(volume->GetJournal());

	oldDirectory->WriteLockInTransaction(transaction);
	if (oldDirectory != newDirectory)
		newDirectory->WriteLockInTransaction(transaction);

	status_t status = oldDirectory->CheckPermissions(W_OK);
	if (status == B_OK)
		status = newDirectory->CheckPermissions(W_OK);
	if (status != B_OK)
		return status;

	HTree oldHTree(volume, oldDirectory);
	DirectoryIterator* oldIterator;

	status = oldHTree.Lookup(oldName, &oldIterator);
	if (status != B_OK)
		return status;

	ObjectDeleter<DirectoryIterator> oldIteratorDeleter(oldIterator);

	ino_t oldID;
	status = oldIterator->FindEntry(oldName, &oldID);
	if (status != B_OK)
		return status;

	if (oldDirectory != newDirectory) {
		TRACE("ext2_rename(): Different parent directories\n");
		CachedBlock cached(volume);

		ino_t parentID = newDirectory->ID();
		ino_t oldDirID = oldDirectory->ID();

		do {
			Vnode vnode(volume, parentID);
			Inode* parent;

			status = vnode.Get(&parent);
			if (status != B_OK)
				return B_IO_ERROR;

			fsblock_t blockNum;
			status = parent->FindBlock(0, blockNum);
			if (status != B_OK)
				return status;

			const HTreeRoot* data = (const HTreeRoot*)cached.SetTo(blockNum);
			parentID = data->dotdot.InodeID();
		} while (parentID != oldID && parentID != oldDirID
			&& parentID != EXT2_ROOT_NODE);

		if (parentID == oldID)
			return B_BAD_VALUE;
	}

	HTree newHTree(volume, newDirectory);
	DirectoryIterator* newIterator;

	status = newHTree.Lookup(newName, &newIterator);
	if (status != B_OK)
		return status;

	ObjectDeleter<DirectoryIterator> newIteratorDeleter(newIterator);

	Vnode vnode(volume, oldID);
	Inode* inode;

	status = vnode.Get(&inode);
	if (status != B_OK)
		return status;

	uint8 fileType;

	// TODO: Support all file types?
	if (inode->IsDirectory())
		fileType = EXT2_TYPE_DIRECTORY;
	else if (inode->IsSymLink())
		fileType = EXT2_TYPE_SYMLINK;
	else
		fileType = EXT2_TYPE_FILE;

	// Add entry in destination directory
	ino_t existentID;
	status = newIterator->FindEntry(newName, &existentID);
	if (status == B_OK) {
		if (existentID == oldID) {
			// Remove entry in oldID
			// return inode->Unlink();
			return B_BAD_VALUE;
		}

		Vnode vnodeExistent(volume, existentID);
		Inode* existent;

		if (vnodeExistent.Get(&existent) != B_OK)
			return B_NAME_IN_USE;

		if (existent->IsDirectory() != inode->IsDirectory()) {
			return existent->IsDirectory() ? B_IS_A_DIRECTORY
				: B_NOT_A_DIRECTORY;
		}

		// TODO: Perhaps we have to revert this in case of error?
		status = newIterator->ChangeEntry(transaction, oldID, fileType);
		if (status != B_OK)
			return status;

		notify_entry_removed(volume->ID(), newDirectory->ID(), newName,
			existentID);
	} else if (status == B_ENTRY_NOT_FOUND) {
		newIterator->Restart();

		status = newIterator->AddEntry(transaction, newName, strlen(newName),
			oldID, fileType);
		if (status != B_OK)
			return status;
	} else
		return status;

	// Remove entry from source folder
	status = oldIterator->RemoveEntry(transaction);
	if (status != B_OK)
		return status;

	inode->WriteLockInTransaction(transaction);

	if (oldDirectory != newDirectory && inode->IsDirectory()) {
		DirectoryIterator inodeIterator(inode);

		status = inodeIterator.FindEntry("..");
		if (status == B_ENTRY_NOT_FOUND) {
			TRACE("Corrupt file system. Missing \"..\" in directory %"
				B_PRIdINO "\n", inode->ID());
			return B_BAD_DATA;
		} else if (status != B_OK)
			return status;

		inodeIterator.ChangeEntry(transaction, newDirectory->ID(),
			(uint8)EXT2_TYPE_DIRECTORY);
	}

	status = inode->WriteBack(transaction);
	if (status != B_OK)
		return status;

	entry_cache_remove(volume->ID(), oldDirectory->ID(), oldName);
	entry_cache_add(volume->ID(), newDirectory->ID(), newName, oldID);

	status = transaction.Done();
	if (status != B_OK) {
		entry_cache_remove(volume->ID(), oldDirectory->ID(), newName);
		entry_cache_add(volume->ID(), newDirectory->ID(), oldName, oldID);

		return status;
	}

	notify_entry_moved(volume->ID(), oldDirectory->ID(), oldName,
		newDirectory->ID(), newName, oldID);

	return B_OK;
}
Esempio n. 11
0
static status_t
ext2_create_symlink(fs_volume* _volume, fs_vnode* _directory, const char* name,
	const char* path, int mode)
{
	TRACE("ext2_create_symlink()\n");

	Volume* volume = (Volume*)_volume->private_volume;
	Inode* directory = (Inode*)_directory->private_node;

	if (volume->IsReadOnly())
		return B_READ_ONLY_DEVICE;

	if (!directory->IsDirectory())
		return B_BAD_TYPE;

	status_t status = directory->CheckPermissions(W_OK);
	if (status != B_OK)
		return status;

	TRACE("ext2_create_symlink(): Starting transaction\n");
	Transaction transaction(volume->GetJournal());

	Inode* link;
	ino_t id;
	status = Inode::Create(transaction, directory, name, S_SYMLINK | 0777,
		0, (uint8)EXT2_TYPE_SYMLINK, NULL, &id, &link);
	if (status != B_OK)
		return status;

	// TODO: We have to prepare the link before publishing?

	size_t length = strlen(path);
	TRACE("ext2_create_symlink(): Path (%s) length: %d\n", path, (int)length);
	if (length < EXT2_SHORT_SYMLINK_LENGTH) {
		strcpy(link->Node().symlink, path);
		link->Node().SetSize((uint32)length);

		TRACE("ext2_create_symlink(): Publishing vnode\n");
		publish_vnode(volume->FSVolume(), id, link, &gExt2VnodeOps,
			link->Mode(), 0);
		put_vnode(volume->FSVolume(), id);
	} else {
		TRACE("ext2_create_symlink(): Publishing vnode\n");
		publish_vnode(volume->FSVolume(), id, link, &gExt2VnodeOps,
			link->Mode(), 0);
		put_vnode(volume->FSVolume(), id);

		if (!link->HasFileCache()) {
			status = link->CreateFileCache();
			if (status != B_OK)
				return status;
		}

		size_t written = length;
		status = link->WriteAt(transaction, 0, (const uint8*)path, &written);
		if (status == B_OK && written != length)
			status = B_IO_ERROR;
	}

	if (status == B_OK)
		status = link->WriteBack(transaction);

	entry_cache_add(volume->ID(), directory->ID(), name, id);

	status = transaction.Done();
	if (status != B_OK) {
		entry_cache_remove(volume->ID(), directory->ID(), name);
		return status;
	}

	notify_entry_created(volume->ID(), directory->ID(), name, id);

	TRACE("ext2_create_symlink(): Done\n");

	return status;
}
Esempio n. 12
0
status_t
ext2_write_stat(fs_volume* _volume, fs_vnode* _node, const struct stat* stat,
	uint32 mask)
{
	TRACE("ext2_write_stat\n");
	Volume* volume = (Volume*)_volume->private_volume;

	if (volume->IsReadOnly())
		return B_READ_ONLY_DEVICE;

	Inode* inode = (Inode*)_node->private_node;

	ext2_inode& node = inode->Node();
	bool updateTime = false;
	uid_t uid = geteuid();

	bool isOwnerOrRoot = uid == 0 || uid == (uid_t)node.UserID();
	bool hasWriteAccess = inode->CheckPermissions(W_OK) == B_OK;

	TRACE("ext2_write_stat: Starting transaction\n");
	Transaction transaction(volume->GetJournal());
	inode->WriteLockInTransaction(transaction);

	if ((mask & B_STAT_SIZE) != 0 && inode->Size() != stat->st_size) {
		if (inode->IsDirectory())
			return B_IS_A_DIRECTORY;
		if (!inode->IsFile())
			return B_BAD_VALUE;
		if (!hasWriteAccess)
			return B_NOT_ALLOWED;

		TRACE("ext2_write_stat: Old size: %ld, new size: %ld\n",
			(long)inode->Size(), (long)stat->st_size);

		off_t oldSize = inode->Size();

		status_t status = inode->Resize(transaction, stat->st_size);
		if(status != B_OK)
			return status;

		if ((mask & B_STAT_SIZE_INSECURE) == 0) {
			rw_lock_write_unlock(inode->Lock());
			inode->FillGapWithZeros(oldSize, inode->Size());
			rw_lock_write_lock(inode->Lock());
		}

		updateTime = true;
	}

	if ((mask & B_STAT_MODE) != 0) {
		// only the user or root can do that
		if (!isOwnerOrRoot)
			return B_NOT_ALLOWED;
		node.UpdateMode(stat->st_mode, S_IUMSK);
		updateTime = true;
	}

	if ((mask & B_STAT_UID) != 0) {
		// only root should be allowed
		if (uid != 0)
			return B_NOT_ALLOWED;
		node.SetUserID(stat->st_uid);
		updateTime = true;
	}

	if ((mask & B_STAT_GID) != 0) {
		// only the user or root can do that
		if (!isOwnerOrRoot)
			return B_NOT_ALLOWED;
		node.SetGroupID(stat->st_gid);
		updateTime = true;
	}

	if ((mask & B_STAT_MODIFICATION_TIME) != 0 || updateTime
		|| (mask & B_STAT_CHANGE_TIME) != 0) {
		// the user or root can do that or any user with write access
		if (!isOwnerOrRoot && !hasWriteAccess)
			return B_NOT_ALLOWED;
		struct timespec newTimespec = { 0, 0};

		if ((mask & B_STAT_MODIFICATION_TIME) != 0)
			newTimespec = stat->st_mtim;

		if ((mask & B_STAT_CHANGE_TIME) != 0
			&& stat->st_ctim.tv_sec > newTimespec.tv_sec)
			newTimespec = stat->st_ctim;

		if (newTimespec.tv_sec == 0)
			Inode::_BigtimeToTimespec(real_time_clock_usecs(), &newTimespec);

		inode->SetModificationTime(&newTimespec);
	}
	if ((mask & B_STAT_CREATION_TIME) != 0) {
		// the user or root can do that or any user with write access
		if (!isOwnerOrRoot && !hasWriteAccess)
			return B_NOT_ALLOWED;
		inode->SetCreationTime(&stat->st_crtim);
	}

	status_t status = inode->WriteBack(transaction);
	if (status == B_OK)
		status = transaction.Done();
	if (status == B_OK)
		notify_stat_changed(volume->ID(), -1, inode->ID(), mask);

	return status;
}