aboutsummaryrefslogtreecommitdiff
path: root/lib/sqfs/src/io/win32.c
blob: fd10ab162cca87b56dc564434916011e0025efec (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/* SPDX-License-Identifier: LGPL-3.0-or-later */
/*
 * win32.c
 *
 * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
 */
#define SQFS_BUILDING_DLL
#include "config.h"

#include "sqfs/io.h"
#include "sqfs/error.h"
#include "compat.h"

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

int sqfs_native_file_open(sqfs_file_handle_t *out, const char *filename,
			  sqfs_u32 flags)
{
	int access_flags, creation_mode, share_mode;
	WCHAR *wpath = NULL;
	os_error_t err;
	DWORD length;

	*out = INVALID_HANDLE_VALUE;

	if (flags & ~SQFS_FILE_OPEN_ALL_FLAGS) {
		SetLastError(ERROR_INVALID_PARAMETER);
		return SQFS_ERROR_UNSUPPORTED;
	}

	if (flags & SQFS_FILE_OPEN_READ_ONLY) {
		access_flags = GENERIC_READ;
		creation_mode = OPEN_EXISTING;
		share_mode = FILE_SHARE_READ;
	} else {
		access_flags = GENERIC_READ | GENERIC_WRITE;
		share_mode = 0;

		if (flags & SQFS_FILE_OPEN_OVERWRITE) {
			creation_mode = CREATE_ALWAYS;
		} else {
			creation_mode = CREATE_NEW;
		}
	}

	if (flags & SQFS_FILE_OPEN_NO_CHARSET_XFRM) {
		*out = CreateFileA(filename, access_flags, share_mode, NULL,
				   creation_mode, FILE_ATTRIBUTE_NORMAL, NULL);
	} else {
		length = MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0);
		if (length <= 0)
			return SQFS_ERROR_INTERNAL;

		wpath = calloc(sizeof(wpath[0]), length + 1);
		if (wpath == NULL) {
			SetLastError(ERROR_NOT_ENOUGH_MEMORY);
			return SQFS_ERROR_ALLOC;
		}

		MultiByteToWideChar(CP_UTF8, 0, filename, -1,
				    wpath, length + 1);
		wpath[length] = '\0';

		*out = CreateFileW(wpath, access_flags, share_mode, NULL,
				   creation_mode, FILE_ATTRIBUTE_NORMAL,
				   NULL);

		err = get_os_error_state();
		free(wpath);
		set_os_error_state(err);
	}

	return (*out == INVALID_HANDLE_VALUE) ? SQFS_ERROR_IO : 0;
}

void sqfs_native_file_close(sqfs_file_handle_t hnd)
{
	CloseHandle(hnd);
}

int sqfs_native_file_duplicate(sqfs_file_handle_t in, sqfs_file_handle_t *out)
{
	HANDLE hProc = GetCurrentProcess();
	BOOL ret = DuplicateHandle(hProc, in, hProc, out, 0,
				   FALSE, DUPLICATE_SAME_ACCESS);

	return ret ? 0 : SQFS_ERROR_IO;
}

int sqfs_native_file_seek(sqfs_file_handle_t fd,
			  sqfs_s64 offset, sqfs_u32 flags)
{
	LARGE_INTEGER pos;
	DWORD whence;

	switch (flags & SQFS_FILE_SEEK_TYPE_MASK) {
	case SQFS_FILE_SEEK_START:   whence = FILE_BEGIN; break;
	case SQFS_FILE_SEEK_CURRENT: whence = FILE_CURRENT; break;
	case SQFS_FILE_SEEK_END:     whence = FILE_END; break;
	default:                     return SQFS_ERROR_UNSUPPORTED;
	}

	if (flags & ~(SQFS_FILE_SEEK_FLAG_MASK | SQFS_FILE_SEEK_TYPE_MASK))
		return SQFS_ERROR_UNSUPPORTED;

	if (GetFileType(fd) != FILE_TYPE_DISK)
		return SQFS_ERROR_UNSUPPORTED;

	pos.QuadPart = offset;
	if (!SetFilePointerEx(fd, pos, NULL, whence))
		return SQFS_ERROR_IO;

	if (flags & SQFS_FILE_SEEK_TRUNCATE) {
		if (!SetEndOfFile(fd))
			return SQFS_ERROR_IO;
	}

	return 0;
}

int sqfs_native_file_get_size(sqfs_file_handle_t hnd, sqfs_u64 *out)
{
	LARGE_INTEGER size;

	if (!GetFileSizeEx(hnd, &size)) {
		*out = 0;
		return SQFS_ERROR_IO;
	}

	*out = size.QuadPart;
	return 0;
}