示例#1
0
文件: winfs.c 项目: Logan-lu/flinux
static int winfs_link(struct mount_point *mp, struct file *f, const char *newpath)
{
	AcquireSRWLockShared(&f->rw_lock);
	struct winfs_file *winfile = (struct winfs_file *) f;
	NTSTATUS status;
	int r = 0;
	char buf[sizeof(FILE_LINK_INFORMATION) + PATH_MAX * 2];
	FILE_LINK_INFORMATION *info = (FILE_LINK_INFORMATION *)buf;
	info->ReplaceIfExists = FALSE;
	info->RootDirectory = NULL;
	info->FileNameLength = 2 * filename_to_nt_pathname(mp, newpath, info->FileName, PATH_MAX);
	if (info->FileNameLength == 0)
	{
		r = -L_ENOENT;
		goto out;
	}
	IO_STATUS_BLOCK status_block;
	status = NtSetInformationFile(winfile->handle, &status_block, info, info->FileNameLength + sizeof(FILE_LINK_INFORMATION), FileLinkInformation);
	if (!NT_SUCCESS(status))
	{
		log_warning("NtSetInformationFile() failed, status: %x.", status);
		r = -L_ENOENT;
		goto out;
	}
out:
	ReleaseSRWLockShared(&f->rw_lock);
	return r;
}
示例#2
0
文件: winfs.c 项目: Logan-lu/flinux
static int winfs_unlink(struct mount_point *mp, const char *pathname)
{
	WCHAR wpathname[PATH_MAX];
	int len = filename_to_nt_pathname(mp, pathname, wpathname, PATH_MAX);
	if (len <= 0)
		return -L_ENOENT;

	UNICODE_STRING object_name;
	RtlInitCountedUnicodeString(&object_name, wpathname, len * sizeof(WCHAR));

	OBJECT_ATTRIBUTES attr;
	attr.Length = sizeof(OBJECT_ATTRIBUTES);
	attr.RootDirectory = NULL;
	attr.ObjectName = &object_name;
	attr.Attributes = 0;
	attr.SecurityDescriptor = NULL;
	attr.SecurityQualityOfService = NULL;
	IO_STATUS_BLOCK status_block;
	NTSTATUS status;
	HANDLE handle;
	status = NtOpenFile(&handle, DELETE, &attr, &status_block, FILE_SHARE_DELETE, FILE_NON_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT);
	if (!NT_SUCCESS(status))
	{
		if (status != STATUS_SHARING_VIOLATION)
		{
			log_warning("NtOpenFile() failed, status: %x", status);
			return -L_ENOENT;
		}
		/* This file has open handles in some processes, even we set delete disposition flags
		 * The actual deletion of the file will be delayed to the last handle closing
		 * To make the file disappear from its parent directory immediately, we move the file
		 * to Windows recycle bin prior to deletion.
		 */
		status = NtOpenFile(&handle, DELETE, &attr, &status_block, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
			FILE_NON_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT);
		if (!NT_SUCCESS(status))
		{
			log_warning("NtOpenFile() failed, status: %x", status);
			return -L_EBUSY;
		}
		status = move_to_recycle_bin(handle, wpathname);
		if (!NT_SUCCESS(status))
			return -L_EBUSY;
	}
	/* Set disposition flag */
	FILE_DISPOSITION_INFORMATION info;
	info.DeleteFile = TRUE;
	status = NtSetInformationFile(handle, &status_block, &info, sizeof(info), FileDispositionInformation);
	if (!NT_SUCCESS(status))
	{
		log_warning("NtSetInformation(FileDispositionInformation) failed, status: %x", status);
		return -L_EBUSY;
	}
	NtClose(handle);
	return 0;
}
示例#3
0
文件: winfs.c 项目: Logan-lu/flinux
static int winfs_symlink(struct mount_point *mp, const char *target, const char *linkpath)
{
	WCHAR wlinkpath[PATH_MAX];
	int len = filename_to_nt_pathname(mp, linkpath, wlinkpath, PATH_MAX);
	if (len <= 0)
		return -L_ENOENT;

	UNICODE_STRING pathname;
	RtlInitCountedUnicodeString(&pathname, wlinkpath, len * sizeof(WCHAR));
	IO_STATUS_BLOCK status_block;
	OBJECT_ATTRIBUTES attr;
	attr.Length = sizeof(OBJECT_ATTRIBUTES);
	attr.RootDirectory = NULL;
	attr.ObjectName = &pathname;
	attr.Attributes = 0;
	attr.SecurityDescriptor = NULL;
	attr.SecurityQualityOfService = NULL;
	HANDLE handle;
	NTSTATUS status = NtCreateFile(&handle, SYNCHRONIZE | FILE_WRITE_DATA, &attr, &status_block, NULL,
		FILE_ATTRIBUTE_SYSTEM, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_CREATE,
		FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);

	if (!NT_SUCCESS(status))
	{
		if (status == STATUS_OBJECT_NAME_EXISTS || status == STATUS_OBJECT_NAME_COLLISION)
		{
			log_warning("File already exists.");
			return -L_EEXIST;
		}
		log_warning("NtCreateFile() failed, status: %x", status);
		return -L_ENOENT;
	}

	DWORD num_written;
	if (!WriteFile(handle, WINFS_SYMLINK_HEADER, WINFS_SYMLINK_HEADER_LEN, &num_written, NULL) || num_written < WINFS_SYMLINK_HEADER_LEN)
	{
		log_warning("WriteFile() failed, error code: %d.", GetLastError());
		NtClose(handle);
		return -L_EIO;
	}
	DWORD targetlen = strlen(target);
	if (!WriteFile(handle, target, targetlen, &num_written, NULL) || num_written < targetlen)
	{
		log_warning("WriteFile() failed, error code: %d.", GetLastError());
		NtClose(handle);
		return -L_EIO;
	}
	NtClose(handle);
	return 0;
}
示例#4
0
文件: winfs.c 项目: Logan-lu/flinux
static int winfs_rename(struct mount_point *mp, struct file *f, const char *newpath)
{
	AcquireSRWLockShared(&f->rw_lock);
	struct winfs_file *winfile = (struct winfs_file *)f;
	char buf[sizeof(FILE_RENAME_INFORMATION) + PATH_MAX * 2];
	NTSTATUS status;
	int r = 0;
	int retry_count = 5;
retry:
	if (--retry_count == 0)
	{
		r = -L_EPERM;
		goto out;
	}
	FILE_RENAME_INFORMATION *info = (FILE_RENAME_INFORMATION *)buf;
	info->ReplaceIfExists = TRUE;
	info->RootDirectory = NULL;
	info->FileNameLength = 2 * filename_to_nt_pathname(mp, newpath, info->FileName, PATH_MAX);
	if (info->FileNameLength == 0)
	{
		r = -L_ENOENT;
		goto out;
	}
	IO_STATUS_BLOCK status_block;
	status = NtSetInformationFile(winfile->handle, &status_block, info, info->FileNameLength + sizeof(FILE_RENAME_INFORMATION), FileRenameInformation);
	if (!NT_SUCCESS(status))
	{
		if (status == STATUS_ACCESS_DENIED)
		{
			/* The destination exists and the operation cannot be completed via a native operation.
			 * We remove the destination file first, then move this file again.
			 */
			r = winfs_unlink(mp, newpath);
			if (r)
				goto out;
			goto retry;
		}
		log_warning("NtSetInformationFile() failed, status: %x", status);
		r = -L_ENOENT;
		goto out;
	}
out:
	ReleaseSRWLockShared(&f->rw_lock);
	return r;
}
示例#5
0
文件: winfs.c 项目: dke2015/flinux
static int winfs_rename(struct file *f, const char *newpath)
{
    struct winfs_file *winfile = (struct winfs_file *)f;
    char buf[sizeof(FILE_RENAME_INFORMATION) + PATH_MAX * 2];
    NTSTATUS status;
    FILE_RENAME_INFORMATION *info = (FILE_RENAME_INFORMATION *)buf;
    info->ReplaceIfExists = TRUE; /* TODO: This should be worked on to provide true Linux semantics (refer to unlink()) */
    info->RootDirectory = NULL;
    info->FileNameLength = 2 * filename_to_nt_pathname(newpath, info->FileName, PATH_MAX);
    if (info->FileNameLength == 0)
        return -ENOENT;
    IO_STATUS_BLOCK status_block;
    status = NtSetInformationFile(winfile->handle, &status_block, info, info->FileNameLength + sizeof(FILE_RENAME_INFORMATION), FileRenameInformation);
    if (!NT_SUCCESS(status))
    {
        log_warning("NtSetInformationFile() failed, status: %x\n", status);
        return -ENOENT;
    }
    return 0;
}
示例#6
0
文件: winfs.c 项目: dke2015/flinux
static int winfs_link(struct file *f, const char *newpath)
{
    struct winfs_file *winfile = (struct winfs_file *) f;
    NTSTATUS status;
    char buf[sizeof(FILE_LINK_INFORMATION) + PATH_MAX * 2];
    FILE_LINK_INFORMATION *info = (FILE_LINK_INFORMATION *)buf;
    info->ReplaceIfExists = FALSE;
    info->RootDirectory = NULL;
    info->FileNameLength = 2 * filename_to_nt_pathname(newpath, info->FileName, PATH_MAX);
    if (info->FileNameLength == 0)
        return -ENOENT;
    IO_STATUS_BLOCK status_block;
    status = NtSetInformationFile(winfile->handle, &status_block, info, info->FileNameLength + sizeof(FILE_LINK_INFORMATION), FileLinkInformation);
    if (!NT_SUCCESS(status))
    {
        log_warning("NtSetInformationFile() failed, status: %x.\n", status);
        return -ENOENT;
    }
    return 0;
}
示例#7
0
文件: winfs.c 项目: Logan-lu/flinux
/* Open a file
 * Return values:
 *  < 0 => errno
 * == 0 => Opening file succeeded
 *  > 0 => It is a symlink which needs to be redirected (target written)
 */
static int open_file(HANDLE *hFile, struct mount_point *mp, const char *pathname,
	DWORD desired_access, DWORD create_disposition, DWORD attributes,
	int flags, BOOL bInherit, char *target, int buflen, char *drive_letter)
{
	WCHAR buf[PATH_MAX];
	UNICODE_STRING name;
	name.Buffer = buf;
	name.MaximumLength = name.Length = 2 * filename_to_nt_pathname(mp, pathname, buf, PATH_MAX);
	if (name.Length == 0)
		return -L_ENOENT;
	*drive_letter = buf[4];

	OBJECT_ATTRIBUTES attr;
	attr.Length = sizeof(OBJECT_ATTRIBUTES);
	attr.RootDirectory = NULL;
	attr.ObjectName = &name;
	attr.Attributes = (bInherit? OBJ_INHERIT: 0);
	attr.SecurityDescriptor = NULL;
	attr.SecurityQualityOfService = NULL;

	NTSTATUS status;
	IO_STATUS_BLOCK status_block;
	HANDLE handle;
	DWORD create_options = FILE_SYNCHRONOUS_IO_NONALERT; /* For synchronous I/O */
	if (desired_access & GENERIC_ALL)
		create_options |= FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REMOTE_INSTANCE;
	else
	{
		if (desired_access & GENERIC_READ)
			create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
		if (desired_access & GENERIC_WRITE)
			create_options |= FILE_OPEN_REMOTE_INSTANCE;
	}
	desired_access |= SYNCHRONIZE | FILE_READ_ATTRIBUTES;
	status = NtCreateFile(&handle, desired_access, &attr, &status_block, NULL,
		attributes, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
		create_disposition, create_options, NULL, 0);
	if (status == STATUS_OBJECT_NAME_COLLISION)
	{
		log_warning("File already exists.");
		return -L_EEXIST;
	}
	else if (!NT_SUCCESS(status))
	{
		log_warning("Unhandled NtCreateFile error, status: %x, returning ENOENT.", status);
		return -L_ENOENT;
	}

	FILE_ATTRIBUTE_TAG_INFORMATION attribute_info;
	status = NtQueryInformationFile(handle, &status_block, &attribute_info, sizeof(attribute_info), FileAttributeTagInformation);
	if (!NT_SUCCESS(status))
	{
		log_error("NtQueryInformationFile(FileAttributeTagInformation) failed, status: %x", status);
		NtClose(handle);
		return -L_EIO;
	}
	/* Test if the file is a symlink */
	int is_symlink = 0;
	if (!(attribute_info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (attribute_info.FileAttributes & FILE_ATTRIBUTE_SYSTEM))
	{
		/* The file has system flag set. A potential symbolic link. */
		if (!(desired_access & GENERIC_READ))
		{
			/* But the handle does not have READ access, try reopening file */
			HANDLE read_handle = ReOpenFile(handle, desired_access | GENERIC_READ,
				FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_FLAG_BACKUP_SEMANTICS);
			if (read_handle == INVALID_HANDLE_VALUE)
			{
				log_warning("Reopen symlink file failed, error code %d. Assume not symlink.", GetLastError());
				*hFile = handle;
				return 0;
			}
			NtClose(handle);
			handle = read_handle;
		}
		if (winfs_read_symlink_unsafe(handle, target, buflen) > 0)
		{
			if (!(flags & O_NOFOLLOW))
			{
				NtClose(handle);
				return 1;
			}
			if (!(flags & O_PATH))
			{
				NtClose(handle);
				log_info("Specified O_NOFOLLOW but not O_PATH, returning ELOOP.");
				return -L_ELOOP;
			}
		}
	}
	else if (!(attribute_info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (flags & O_DIRECTORY))
	{
		log_warning("Not a directory.");
		return -L_ENOTDIR;
	}
	*hFile = handle;
	return 0;
}