-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathsysio_winapi.cpp
More file actions
312 lines (268 loc) · 8.34 KB
/
sysio_winapi.cpp
File metadata and controls
312 lines (268 loc) · 8.34 KB
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
// This is a personal academic project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
/*
* Floppy disk images unpack plugin for the Total Commander.
* Copyright (c) 2002, IvGzury ( ivgzury@hotmail.com )
* Copyright (c) 2022-2026, Oleg Farenyuk aka Indrekis ( indrekis@gmail.com )
*
* Oleg Farenyuk's code is released under the MIT License.
*
* Original IvGzury copyright message:
* This program is absolutely free software.
* If you have any remarks or problems, please don't
* hesitate to send me an email.
*/
#include "sysio_winapi.h"
bool file_exists(const char* path) {
DWORD attr = GetFileAttributesA(path);
return (attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY));
}
bool create_sized_file(const char* path, size_t size, uint8_t fill_byte) {
HANDLE hFile = CreateFileA(
path,
GENERIC_WRITE,
0,
nullptr,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
nullptr
);
if (hFile == INVALID_HANDLE_VALUE)
return false;
const size_t chunk_size = 1024*1024;
uint8_t* buffer = new uint8_t[chunk_size];
memset(buffer, fill_byte, chunk_size);
DWORD written = 0;
size_t total_written = 0;
while (total_written < size) {
DWORD to_write = static_cast<DWORD>(std::min(chunk_size, size - total_written));
if (!WriteFile(hFile, buffer, to_write, &written, nullptr)) {
CloseHandle(hFile);
return false;
}
total_written += written;
}
CloseHandle(hFile);
return true;
}
// INVALID_HANDLE_VALUE on error
file_handle_t open_file_shared_read(const char* filename) {
file_handle_t handle;
handle = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
return handle;
}
//! Opens for reading but allows writing by others
file_handle_t open_file_read_shared_write(const char* filename) {
file_handle_t handle;
handle = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
return handle;
}
file_handle_t open_file_write(const char* filename) {
file_handle_t handle;
handle = CreateFile(filename, GENERIC_WRITE | FILE_APPEND_DATA, FILE_SHARE_READ, 0, CREATE_NEW, 0, 0);
return handle;
}
file_handle_t open_file_overwrite(const char* filename) {
file_handle_t handle;
handle = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);
return handle;
}
//! Returns true if success
bool close_file(file_handle_t handle) {
// TODO: êîñòèëü, ïîô³êñèòè, êîëè âèïðàâëþ TODO â DeleteFiles
BY_HANDLE_FILE_INFORMATION info;
if (GetFileInformationByHandle(handle, &info)) {
return CloseHandle(handle);
}
else return true;
}
bool flush_file(file_handle_t handle) {
return FlushFileBuffers(handle);
}
bool delete_file(const char* filename) {
DWORD attrs = GetFileAttributes(filename);
if (attrs == INVALID_FILE_ATTRIBUTES)
return false;
if (attrs & FILE_ATTRIBUTE_READONLY) {
// TODO: Add asking user for confirmation?
SetFileAttributes(filename, attrs & ~FILE_ATTRIBUTE_READONLY);
}
return DeleteFile(filename);
}
bool delete_dir(const char* filename)
{
DWORD attrs = GetFileAttributes(filename);
if (attrs == INVALID_FILE_ATTRIBUTES) return false;
if (attrs & FILE_ATTRIBUTE_READONLY) {
SetFileAttributes(filename, attrs & ~FILE_ATTRIBUTE_READONLY);
}
return RemoveDirectory(filename);
}
bool get_temp_filename(char* buff, const char prefix[]) {
char dest_path[MAX_PATH];
auto dwRetVal = GetTempPath(MAX_PATH, // length of the buffer
dest_path); // buffer for path
if (dwRetVal > MAX_PATH || (dwRetVal == 0))
{
return false;
}
dwRetVal = GetTempFileName(dest_path, // directory for tmp files
prefix, // temp file name prefix -- 3 bytes used only
0, // create unique name
buff); // buffer for name
if (dwRetVal == 0) {
return false;
}
return true;
}
//! Returns true if success
bool set_file_pointer(file_handle_t handle, size_t offset) {
LARGE_INTEGER offs;
offs.QuadPart = offset;
return SetFilePointerEx(handle, offs, nullptr, FILE_BEGIN);
}
size_t read_file(file_handle_t handle, void* buffer_ptr, size_t size) {
bool res;
DWORD result = 0;
res = ReadFile(handle, buffer_ptr, static_cast<DWORD>(size), &result, nullptr); //-V2001
if (!res) {
return static_cast<size_t>(-1);
}
else {
return static_cast<size_t>(result);
}
}
size_t write_file(file_handle_t handle, const void* buffer_ptr, size_t size) {
bool res;
DWORD result = 0;
res = WriteFile(handle, buffer_ptr, static_cast<DWORD>(size), &result, nullptr); //-V2001
if (!res) {
return static_cast<size_t>(-1);
}
else {
return static_cast<size_t>(result);
}
}
bool set_file_datetime(file_handle_t handle, uint32_t file_datetime)
{
FILETIME LocTime, GlobTime;
DosDateTimeToFileTime(static_cast<uint16_t>(file_datetime >> 16),
static_cast<uint16_t>(file_datetime & static_cast<uint32_t>(0xFFFF)),
&LocTime);
LocalFileTimeToFileTime(&LocTime, &GlobTime);
SetFileTime(handle, nullptr, nullptr, &GlobTime);
return true; // TODO: Add error handling
}
void SystemTimeToFatFs(const SYSTEMTIME& st, uint16_t* pdate, uint16_t* ptime) {
// FatFS time encoding:
// Bits 15-11: hour (0–23)
// Bits 10-5 : minute (0–59)
// Bits 4-0 : second/2 (0–29)
*ptime = (WORD)((st.wHour << 11) | (st.wMinute << 5) | (st.wSecond / 2));
// FatFS date encoding:
// Bits 15-9: year from 1980 (0–127 for 1980–2107)
// Bits 8-5 : month (1–12)
// Bits 4-0 : day (1–31)
*pdate = (WORD)(((st.wYear - 1980) << 9) | (st.wMonth << 5) | st.wDay);
}
std::pair<uint16_t, uint16_t> get_file_datatime_for_FatFS(const char* filename) {
bool is_dir_v = is_dir(filename);
HANDLE handle = CreateFileA( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
is_dir_v ? FILE_FLAG_BACKUP_SEMANTICS : 0, NULL);
if (handle == INVALID_HANDLE_VALUE) {
return { -1, -1 };
}
FILETIME ftWrite;
if (!GetFileTime(handle, NULL, NULL, &ftWrite)) {
CloseHandle(handle);
return { -1, -1 };
}
SYSTEMTIME stUTC, stLocal;
FileTimeToSystemTime(&ftWrite, &stUTC);
SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal); // Is it OK?
std::pair<uint16_t, uint16_t> res;
SystemTimeToFatFs(stLocal, &res.first, &res.second);
CloseHandle(handle);
return res;
}
uint32_t get_current_datatime_for_FatFS() {
SYSTEMTIME tm, stLocal;
/* Get local time */
GetLocalTime(&tm);
SystemTimeToTzSpecificLocalTime(NULL, &tm, &stLocal); // Is it OK?
/* Pack date and time into a DWORD variable */
return (tm.wYear - 1980) << 25 | tm.wMonth << 21 | tm.wDay << 16 | tm.wHour << 11 | tm.wMinute << 5 | tm.wSecond >> 1;
}
bool set_file_attributes(const char* filename, uint32_t attribute){
return SetFileAttributes(filename, attribute);
}
uint32_t get_file_attributes(const char* filename)
{
return GetFileAttributes(filename);
}
bool is_dir(const char* filename)
{
auto res = get_file_attributes(filename);
if (res == INVALID_FILE_ATTRIBUTES)
return false; // Is this enough?
return res & FILE_ATTRIBUTE_DIRECTORY;
}
bool check_is_RO(uint32_t attr) {
return attr & FILE_ATTRIBUTE_READONLY;
}
bool check_is_Hidden(uint32_t attr) {
return attr & FILE_ATTRIBUTE_HIDDEN;
}
bool check_is_System(uint32_t attr) {
return attr & FILE_ATTRIBUTE_SYSTEM;
}
bool check_is_Archive(uint32_t attr) {
return attr & FILE_ATTRIBUTE_ARCHIVE;
}
size_t get_file_size(const char* filename)
{
WIN32_FILE_ATTRIBUTE_DATA fad;
if (!GetFileAttributesEx(filename, GetFileExInfoStandard, &fad))
return -1;
LARGE_INTEGER size;
size.HighPart = fad.nFileSizeHigh;
size.LowPart = fad.nFileSizeLow;
return size.QuadPart;
}
size_t get_file_size(file_handle_t handle)
{
LARGE_INTEGER size;
if (!GetFileSizeEx(handle, &size))
return -1;
return size.QuadPart;
}
uint32_t get_current_datetime()
{
SYSTEMTIME t = {0};
FILETIME ft = { 0 };
uint16_t dft[2] = { 0 };
GetSystemTime(&t);
SystemTimeToFileTime(&t, &ft);
FileTimeToDosDateTime(&ft, dft+1, dft);
return (static_cast<uint32_t>(dft[1]) << 16) + dft[0];
}
char simple_ucs16_to_local(wchar_t wc) {
char tc = '\0';
WideCharToMultiByte(CP_ACP, 0, &wc, -1, &tc, 1, NULL, NULL);
return tc;
}
int ucs16_to_local(char* outstr, const wchar_t* instr, size_t maxoutlen) {
if (instr != nullptr) {
// CP_ACP The system default Windows ANSI code page.
// TODO: error analysis
int res = WideCharToMultiByte(CP_ACP, 0, instr, static_cast<int>(maxoutlen),
outstr, static_cast<int>(maxoutlen), NULL, NULL);
if (res != 0)
return 0;
else
return GetLastError();
}
else {
return 1;
}
}