コード例 #1
0
ファイル: winfs.c プロジェクト: dke2015/flinux
static size_t winfs_readlink(struct file *f, char *target, size_t buflen)
{
    struct winfs_file *winfile = (struct winfs_file *) f;
    int r = winfs_read_symlink(winfile->handle, target, (int)buflen);
    if (r == 0)
        return -EINVAL;
    return r;
}
コード例 #2
0
ファイル: winfs.c プロジェクト: dke2015/flinux
static int winfs_stat(struct file *f, struct newstat *buf)
{
    struct winfs_file *winfile = (struct winfs_file *) f;
    BY_HANDLE_FILE_INFORMATION info;
    if (!GetFileInformationByHandle(winfile->handle, &info))
    {
        log_warning("GetFileInformationByHandle() failed.\n");
        return -1; /* TODO */
    }
    /* Programs (ld.so) may use st_dev and st_ino to identity files so these must be unique for each file. */
    INIT_STRUCT_NEWSTAT_PADDING(buf);
    buf->st_dev = mkdev(8, 0); // (8, 0): /dev/sda
    //buf->st_ino = ((uint64_t)info.nFileIndexHigh << 32ULL) + info.nFileIndexLow;
    /* Hash 64 bit inode to 32 bit to fix legacy applications
     * We may later add an option for changing this behaviour
     */
    buf->st_ino = info.nFileIndexHigh ^ info.nFileIndexLow;
    if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
        buf->st_mode = 0555;
    else
        buf->st_mode = 0755;
    if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
    {
        buf->st_mode |= S_IFDIR;
        buf->st_size = 0;
    }
    else
    {
        int r;
        if ((info.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
                && (r = winfs_read_symlink(winfile->handle, NULL, 0)) > 0)
        {
            buf->st_mode |= S_IFLNK;
            buf->st_size = r;
        }
        else
        {
            buf->st_mode |= S_IFREG;
            buf->st_size = ((uint64_t)info.nFileSizeHigh << 32ULL) + info.nFileSizeLow;
        }
    }
    buf->st_nlink = info.nNumberOfLinks;
    buf->st_uid = 0;
    buf->st_gid = 0;
    buf->st_rdev = 0;
    buf->st_blksize = PAGE_SIZE;
    buf->st_blocks = (buf->st_size + buf->st_blksize - 1) / buf->st_blksize;
    buf->st_atime = filetime_to_unix_sec(&info.ftLastAccessTime);
    buf->st_atime_nsec = filetime_to_unix_nsec(&info.ftLastAccessTime);
    buf->st_mtime = filetime_to_unix_sec(&info.ftLastWriteTime);
    buf->st_mtime_nsec = filetime_to_unix_nsec(&info.ftLastWriteTime);
    buf->st_ctime = filetime_to_unix_sec(&info.ftCreationTime);
    buf->st_ctime_nsec = filetime_to_unix_nsec(&info.ftCreationTime);
    return 0;
}
コード例 #3
0
ファイル: winfs.c プロジェクト: dke2015/flinux
static int winfs_open(const char *pathname, int flags, int mode, struct file **fp, char *target, int buflen)
{
    /* TODO: mode */
    DWORD desiredAccess, shareMode, creationDisposition;
    HANDLE handle;
    FILE_ATTRIBUTE_TAG_INFO attributeInfo;
    WCHAR wpathname[PATH_MAX];
    struct winfs_file *file;
    int pathlen = strlen(pathname);

    if (utf8_to_utf16_filename(pathname, pathlen + 1, wpathname, PATH_MAX) <= 0)
        return -ENOENT;
    if (wpathname[0] == 0)
    {
        /* CreateFile() does not accept empty filename. */
        wpathname[0] = '.';
        wpathname[1] = 0;
    }

    if (flags & O_PATH)
        desiredAccess = 0;
    else if (flags & O_RDWR)
        desiredAccess = GENERIC_READ | GENERIC_WRITE;
    else if (flags & O_WRONLY)
        desiredAccess = GENERIC_WRITE;
    else
        desiredAccess = GENERIC_READ;
    if (flags & __O_DELETE)
        desiredAccess |= DELETE;
    shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
    creationDisposition;
    if (flags & O_EXCL)
        creationDisposition = CREATE_NEW;
    else if (flags & O_CREAT)
        creationDisposition = OPEN_ALWAYS;
    else
        creationDisposition = OPEN_EXISTING;
    //log_debug("CreateFileW(): %s\n", pathname);
    SECURITY_ATTRIBUTES attr;
    attr.nLength = sizeof(SECURITY_ATTRIBUTES);
    attr.lpSecurityDescriptor = NULL;
    attr.bInheritHandle = (fp != NULL);
    handle = CreateFileW(wpathname, desiredAccess, shareMode, &attr, creationDisposition, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, NULL);
    if (handle == INVALID_HANDLE_VALUE)
    {
        DWORD err = GetLastError();
        if (err == ERROR_FILE_EXISTS || err == ERROR_ALREADY_EXISTS)
        {
            log_warning("File already exists.\n");
            return -EEXIST;
        }
        else
        {
            log_warning("Unhandled CreateFileW() failure, error code: %d, returning ENOENT.\n", GetLastError());
            return -ENOENT;
        }
    }
    if (!GetFileInformationByHandleEx(handle, FileAttributeTagInfo, &attributeInfo, sizeof(attributeInfo)))
    {
        CloseHandle(handle);
        return -EIO;
    }
    /* Test if the file is a symlink */
    int is_symlink = 0;
    if (attributeInfo.FileAttributes != INVALID_FILE_ATTRIBUTES && (attributeInfo.FileAttributes & FILE_ATTRIBUTE_SYSTEM))
    {
        log_info("The file has system flag set.\n");
        if (!(desiredAccess & GENERIC_READ))
        {
            /* We need to get a readable handle */
            log_info("But the handle does not have READ access, try reopening file...\n");
            HANDLE read_handle = ReOpenFile(handle, desiredAccess | GENERIC_READ, shareMode, FILE_FLAG_BACKUP_SEMANTICS);
            if (read_handle == INVALID_HANDLE_VALUE)
            {
                log_warning("Reopen file failed, error code %d. Assume not symlink.\n", GetLastError());
                goto after_symlink_test;
            }
            CloseHandle(handle);
            log_info("Reopen succeeded.\n");
            handle = read_handle;
        }
        if (winfs_read_symlink(handle, target, buflen) > 0)
        {
            if (!(flags & O_NOFOLLOW))
            {
                CloseHandle(handle);
                return 1;
            }
            if (!(flags & O_PATH))
            {
                CloseHandle(handle);
                log_info("Specified O_NOFOLLOW but not O_PATH, returning ELOOP.\n");
                return -ELOOP;
            }
            is_symlink = 1;
        }
        log_info("Opening file directly.\n");
    }
    else if (attributeInfo.FileAttributes != INVALID_FILE_ATTRIBUTES && !(attributeInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (flags & O_DIRECTORY))
    {
        log_warning("Not a directory.\n");
        return -ENOTDIR;
    }

after_symlink_test:
    if (!is_symlink && (flags & O_TRUNC) && ((flags & O_WRONLY) || (flags & O_RDWR)))
    {
        /* Truncate the file */
        FILE_END_OF_FILE_INFORMATION info;
        info.EndOfFile.QuadPart = 0;
        IO_STATUS_BLOCK status_block;
        NTSTATUS status = NtSetInformationFile(handle, &status_block, &info, sizeof(info), FileEndOfFileInformation);
        if (!NT_SUCCESS(status))
            log_error("NtSetInformationFile() failed, status: %x\n", status);
    }

    if (fp)
    {
        file = (struct winfs_file *)kmalloc(sizeof(struct winfs_file) + pathlen);
        file->base_file.op_vtable = &winfs_ops;
        file->base_file.ref = 1;
        file->base_file.flags = flags;
        file->handle = handle;
        file->restart_scan = 1;
        file->pathlen = pathlen;
        memcpy(file->pathname, pathname, pathlen);
        *fp = (struct file *)file;
    }
    else
        CloseHandle(handle);
    return 0;
}
コード例 #4
0
ファイル: winfs.c プロジェクト: bsns/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, const char *pathname, DWORD desired_access, DWORD create_disposition,
	int flags, BOOL bInherit, char *target, int buflen)
{
	WCHAR buf[PATH_MAX];
	UNICODE_STRING name;
	name.Buffer = buf;
	name.MaximumLength = name.Length = 2 * filename_to_nt_pathname(pathname, buf, PATH_MAX);
	if (name.Length == 0)
		return -ENOENT;

	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,
		FILE_ATTRIBUTE_NORMAL, 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.\n");
		return -EEXIST;
	}
	else if (!NT_SUCCESS(status))
	{
		log_warning("Unhandled NtCreateFile error, status: %x, returning ENOENT.\n", status);
		return -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\n", status);
		NtClose(handle);
		return -EIO;
	}
	/* Test if the file is a symlink */
	int is_symlink = 0;
	if (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.\n", GetLastError());
				return 0;
			}
			CloseHandle(handle);
			handle = read_handle;
		}
		if (winfs_read_symlink(handle, target, buflen) > 0)
		{
			if (!(flags & O_NOFOLLOW))
			{
				CloseHandle(handle);
				return 1;
			}
			if (!(flags & O_PATH))
			{
				CloseHandle(handle);
				log_info("Specified O_NOFOLLOW but not O_PATH, returning ELOOP.\n");
				return -ELOOP;
			}
		}
	}
	else if (!(attribute_info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (flags & O_DIRECTORY))
	{
		log_warning("Not a directory.\n");
		return -ENOTDIR;
	}
	*hFile = handle;
	return 0;
}