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;
}
static status_t
ext2_create(fs_volume* _volume, fs_vnode* _directory, const char* name,
	int openMode, int mode, void** _cookie, ino_t* _vnodeID)
{
	Volume* volume = (Volume*)_volume->private_volume;
	Inode* directory = (Inode*)_directory->private_node;

	TRACE("ext2_create()\n");

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

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

	TRACE("ext2_create(): Creating cookie\n");

	// Allocate 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;
	cookie->last_size = 0;
	cookie->last_notification = system_time();

	TRACE("ext2_create(): Starting transaction\n");

	Transaction transaction(volume->GetJournal());

	TRACE("ext2_create(): Creating inode\n");

	Inode* inode;
	bool created;
	status_t status = Inode::Create(transaction, directory, name,
		S_FILE | (mode & S_IUMSK), openMode, EXT2_TYPE_FILE, &created, _vnodeID,
		&inode, &gExt2VnodeOps);
	if (status != B_OK)
		return status;

	TRACE("ext2_create(): Created inode\n");

	if ((openMode & O_NOCACHE) != 0) {
		status = inode->DisableFileCache();
		if (status != B_OK)
			return status;
	}

	entry_cache_add(volume->ID(), directory->ID(), name, *_vnodeID);

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

	*_cookie = cookie;
	cookieDeleter.Detach();

	if (created)
		notify_entry_created(volume->ID(), directory->ID(), name, *_vnodeID);

	return B_OK;
}