Beispiel #1
0
void
MetadataCache::NotifyChanges(const struct stat* oldStat,
	const struct stat* newStat)
{
	ASSERT(oldStat != NULL);
	ASSERT(newStat != NULL);

	uint32 flags = 0;
	if (oldStat->st_size != newStat->st_size)
		flags |= B_STAT_SIZE;
	if (oldStat->st_mode != newStat->st_mode)
		flags |= B_STAT_MODE;
	if (oldStat->st_uid != newStat->st_uid)
		flags |= B_STAT_UID;
	if (oldStat->st_gid != newStat->st_gid)
		flags |= B_STAT_GID;

	if (memcmp(&oldStat->st_atim, &newStat->st_atim,
		sizeof(struct timespec) == 0))
		flags |= B_STAT_ACCESS_TIME;

	if (memcmp(&oldStat->st_ctim, &newStat->st_ctim,
		sizeof(struct timespec) == 0))
		flags |= B_STAT_CHANGE_TIME;

	if (memcmp(&oldStat->st_crtim, &newStat->st_crtim,
		sizeof(struct timespec) == 0))
		flags |= B_STAT_CREATION_TIME;

	if (memcmp(&oldStat->st_mtim, &newStat->st_mtim,
		sizeof(struct timespec) == 0))
		flags |= B_STAT_MODIFICATION_TIME;

	notify_stat_changed(fInode->GetFileSystem()->DevId(), fInode->ID(), flags);
}
Beispiel #2
0
static status_t
btrfs_free_cookie(fs_volume* _volume, fs_vnode* _node, void* _cookie)
{
	file_cookie* cookie = (file_cookie*)_cookie;
	Volume* volume = (Volume*)_volume->private_volume;
	Inode* inode = (Inode*)_node->private_node;

	if (inode->Size() != cookie->last_size)
		notify_stat_changed(volume->ID(), inode->ID(), B_STAT_SIZE);

	delete cookie;
	return B_OK;
}
Beispiel #3
0
static status_t
ext2_write(fs_volume* _volume, fs_vnode* _node, void* _cookie, off_t pos,
	const void* buffer, size_t* _length)
{
	TRACE("ext2_write()\n");
	Volume* volume = (Volume*)_volume->private_volume;
	Inode* inode = (Inode*)_node->private_node;

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

	if (inode->IsDirectory()) {
		*_length = 0;
		return B_IS_A_DIRECTORY;
	}

	TRACE("ext2_write(): Preparing cookie\n");

	file_cookie* cookie = (file_cookie*)_cookie;

	if ((cookie->open_mode & O_APPEND) != 0)
		pos = inode->Size();

	TRACE("ext2_write(): Creating transaction\n");
	Transaction transaction;

	status_t status = inode->WriteAt(transaction, pos, (const uint8*)buffer,
		_length);
	if (status == B_OK)
		status = transaction.Done();
	if (status == B_OK) {
		TRACE("ext2_write(): Finalizing\n");
		ReadLocker lock(*inode->Lock());

		if (cookie->last_size != inode->Size()
			&& system_time() > cookie->last_notification
				+ INODE_NOTIFICATION_INTERVAL) {
			notify_stat_changed(volume->ID(), -1, inode->ID(),
				B_STAT_MODIFICATION_TIME | B_STAT_SIZE | B_STAT_INTERIM_UPDATE);
			cookie->last_size = inode->Size();
			cookie->last_notification = system_time();
		}
	}

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

	return status;
}
Beispiel #4
0
static status_t
ext2_free_cookie(fs_volume* _volume, fs_vnode* _node, void* _cookie)
{
	file_cookie* cookie = (file_cookie*)_cookie;
	Volume* volume = (Volume*)_volume->private_volume;
	Inode* inode = (Inode*)_node->private_node;

	if (inode->Size() != cookie->last_size)
		notify_stat_changed(volume->ID(), -1, inode->ID(), B_STAT_SIZE);

	if ((cookie->open_mode & O_NOCACHE) != 0)
		inode->EnableFileCache();

	delete cookie;
	return B_OK;
}
status_t
fs_write_attrib(fs_volume *_vol, fs_vnode *_node, void *_cookie,off_t pos,
	const void *buffer, size_t *_length)
{
	nspace *ns = (nspace *)_vol->private_volume;
	//vnode *node = (vnode *)_node->private_node;
	attrcookie *cookie = (attrcookie *)_cookie;
	ntfs_inode *ni = cookie->inode;
	ntfs_attr *na = cookie->stream;
	size_t  size = *_length;
	int total = 0;
	status_t result = B_NO_ERROR;

	TRACE("%s - ENTER!!\n", __FUNCTION__);
	if (ns->flags & B_FS_IS_READONLY) {
		ERROR("ntfs is read-only\n");
		return EROFS;
	}

	if (pos < 0) {
		*_length = 0;
		return EINVAL;
	}


	LOCK_VOL(ns);

	TRACE("%s - ENTER\n", __FUNCTION__);

	// it is a named stream
	if (na) {
		if (cookie->omode & O_APPEND)
			pos = na->data_size;

		if (pos + size > na->data_size) {
			ntfs_mark_free_space_outdated(ns);
			if (ntfs_attr_truncate(na, pos + size))
				size = na->data_size - pos;
			else
				notify_stat_changed(ns->id, MREF(ni->mft_no), B_STAT_SIZE);
		}

		while (size) {
			off_t bytesWritten = ntfs_attr_pwrite(na, pos, size, buffer);
			if (bytesWritten < (s64)size)
				ERROR("%s - ntfs_attr_pwrite returned less bytes than "
					"requested.\n", __FUNCTION__);
			if (bytesWritten <= 0) {
				ERROR(("%s - ntfs_attr_pwrite()<=0\n", __FUNCTION__));
				*_length = 0;
				result = EINVAL;
				goto exit;
			}
			size -= bytesWritten;
			pos += bytesWritten;
			total += bytesWritten;
		}

		*_length = total;
	} else {
		*_length = 0;
		return EINVAL;
	}

	
	if (total > 0)
		fs_ntfs_update_times(_vol, ni, NTFS_UPDATE_ATIME); // XXX needed ?

exit:
	
	TRACE("%s - EXIT, result is %s\n", __FUNCTION__, strerror(result));

	UNLOCK_VOL(ns);
	
	return result;
}
Beispiel #6
0
// _HandleRequest
status_t
KernelRequestHandler::_HandleRequest(NotifyListenerRequest* request)
{
	// check and execute the request
	status_t result = B_OK;
	if (fVolume && request->device != fVolume->GetID())
		result = B_BAD_VALUE;

	// get the names
	// name
	char* name = (char*)request->name.GetData();
	int32 nameLen = request->name.GetSize();
	if (name && (nameLen <= 0))
		name = NULL;
	else if (name)
		name[nameLen - 1] = '\0';	// NULL-terminate to be safe

	// old name
	char* oldName = (char*)request->oldName.GetData();
	int32 oldNameLen = request->oldName.GetSize();
	if (oldName && (oldNameLen <= 0))
		oldName = NULL;
	else if (oldName)
		oldName[oldNameLen - 1] = '\0';	// NULL-terminate to be safe

	// check the names
	if (result == B_OK) {
		switch (request->operation) {
			case B_ENTRY_MOVED:
				if (!oldName) {
					ERROR(("NotifyListenerRequest: NULL oldName for "
						"B_ENTRY_MOVED\n"));
					result = B_BAD_VALUE;
					break;
				}
				// fall through...
			case B_ENTRY_CREATED:
			case B_ENTRY_REMOVED:
			case B_ATTR_CHANGED:
				if (!name) {
					ERROR(("NotifyListenerRequest: NULL name for opcode: %"
						B_PRId32 "\n", request->operation));
					result = B_BAD_VALUE;
				}
				break;
			case B_STAT_CHANGED:
				break;
		}
	}

	// execute the request
	if (result == B_OK) {
		switch (request->operation) {
			case B_ENTRY_CREATED:
				PRINT(("notify_entry_created(%" B_PRId32 ", %" B_PRId64 ", "
					"\"%s\", %" B_PRId64 ")\n", request->device,
					request->directory, name, request->node));
				result = notify_entry_created(request->device,
					request->directory, name, request->node);
				break;

			case B_ENTRY_REMOVED:
				PRINT(("notify_entry_removed(%" B_PRId32 ", %" B_PRId64 ", "
					"\"%s\", %" B_PRId64 ")\n", request->device,
					request->directory, name, request->node));
				result = notify_entry_removed(request->device,
					request->directory, name, request->node);
				break;

			case B_ENTRY_MOVED:
				PRINT(("notify_entry_moved(%" B_PRId32 ", %" B_PRId64 ", "
					"\"%s\", %" B_PRId64 ", \"%s\", %" B_PRId64 ")\n",
					request->device, request->oldDirectory, oldName,
					request->directory, name, request->node));
				result = notify_entry_moved(request->device,
					request->oldDirectory, oldName, request->directory, name,
					request->node);
				break;

			case B_STAT_CHANGED:
				PRINT(("notify_stat_changed(%" B_PRId32 ", %" B_PRId64 ", "
					"0x%" B_PRIx32 ")\n", request->device, request->node,
					request->details));
				result = notify_stat_changed(request->device, request->node,
					request->details);
				break;

			case B_ATTR_CHANGED:
				PRINT(("notify_attribute_changed(%" B_PRId32 ", %" B_PRId64 ", "
					"\"%s\", 0x%" B_PRIx32 ")\n", request->device,
					request->node, name, (int32)request->details));
				result = notify_attribute_changed(request->device,
					request->node, name, (int32)request->details);
				break;

			default:
				ERROR(("NotifyQueryRequest: unsupported operation: %" B_PRId32
					"\n", request->operation));
				result = B_BAD_VALUE;
				break;
		}
	}

	// prepare the reply
	RequestAllocator allocator(fPort->GetPort());
	NotifyListenerReply* reply;
	status_t error = AllocateRequest(allocator, &reply);
	if (error != B_OK)
		return error;

	reply->error = result;

	// send the reply
	return fPort->SendRequest(&allocator);
}
Beispiel #7
0
status_t
fs_write_attrib(fs_volume *_vol, fs_vnode *_node, void *_cookie, off_t pos,
	const void *buffer, size_t *_length)
{
	nspace *ns = (nspace *)_vol->private_volume;
	vnode *node = (vnode *)_node->private_node;
	attrcookie *cookie = (attrcookie *)_cookie;
	ntfs_inode *ni = NULL;
	ntfs_attr *na = NULL;
	size_t  size = *_length;
	char *attr_name = NULL;
	char *real_name = NULL;
	int total = 0;
	status_t result = B_NO_ERROR;

	TRACE("%s - ENTER  vnode: %d\n", __FUNCTION__, node->vnid);
	
	if (ns->flags & B_FS_IS_READONLY) {		
		return B_READ_ONLY_DEVICE;
	}

	if (pos < 0) {
		*_length = 0;
		return EINVAL;
	}

	LOCK_VOL(ns);

	ni = ntfs_inode_open(ns->ntvol, node->vnid);
	if (ni == NULL) {
		result = errno;
		goto exit;
	}
	na = ntfs_attr_open(ni, AT_DATA, cookie->uname, cookie->uname_len);
	if (na == NULL) {
		result = errno;
		goto exit;		
	}		

	pos += sizeof(uint32);

	// it is a named stream
	if (na != NULL) {
		if (cookie->omode & O_APPEND)
			pos = na->data_size;

		if (pos + size > na->data_size) {
			ntfs_mark_free_space_outdated(ns);
			if (ntfs_attr_truncate(na, pos + size))
				size = na->data_size - pos;
			else
				notify_stat_changed(ns->id, MREF(ni->mft_no), B_STAT_SIZE);
		}

		while (size) {
			off_t bytesWritten = ntfs_attr_pwrite(na, pos, size, buffer);
			if (bytesWritten < (s64)size)
				ERROR("%s - ntfs_attr_pwrite returned less bytes than "
					"requested.\n", __FUNCTION__);
			if (bytesWritten <= 0) {
				ERROR("%s - ntfs_attr_pwrite()<=0\n", __FUNCTION__);
				*_length = 0;
				result = EINVAL;
				goto exit;
			}
			size -= bytesWritten;
			pos += bytesWritten;
			total += bytesWritten;
		}

		*_length = total;
	} else {
		*_length = 0;
		result =  EINVAL;
		goto exit;
	}
	
	if (ntfs_ucstombs(na->name, na->name_len, &attr_name, 0) >= 0) {
		if (attr_name != NULL) {
			if(strncmp(attr_name, kHaikuAttrPrefix, strlen(kHaikuAttrPrefix)) !=0 )
				goto exit;
			real_name = attr_name + strlen(kHaikuAttrPrefix);						
			notify_attribute_changed(ns->id, MREF(ni->mft_no),
				real_name, B_ATTR_CHANGED);
			free(attr_name);
		}
	}
		
exit:	
	if (na != NULL)
		ntfs_attr_close(na);
	if (ni != NULL)
		ntfs_inode_close(ni);
		
	TRACE("%s - EXIT, result is %s\n", __FUNCTION__, strerror(result));

	UNLOCK_VOL(ns);
	
	return result;
}
Beispiel #8
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;
}