annotate foosdk/sdk/foobar2000/helpers/file_win32_wrapper.cpp @ 1:20d02a178406 default tip

*: check in everything else yay
author Paper <paper@tflc.us>
date Mon, 05 Jan 2026 02:15:46 -0500
parents
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
1
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
1 #include "StdAfx.h"
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
2
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
3 #ifdef _WIN32
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
4
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
5 #include "file_win32_wrapper.h"
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
6
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
7 namespace file_win32_helpers {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
8 t_filesize get_size(HANDLE p_handle) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
9 LARGE_INTEGER v = {};
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
10 WIN32_IO_OP(GetFileSizeEx(p_handle, &v));
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
11 return make_uint64(v);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
12 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
13 void seek(HANDLE p_handle,t_sfilesize p_position,file::t_seek_mode p_mode) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
14 union {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
15 t_int64 temp64;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
16 struct {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
17 DWORD temp_lo;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
18 LONG temp_hi;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
19 };
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
20 };
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
21
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
22 temp64 = p_position;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
23 SetLastError(ERROR_SUCCESS);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
24 temp_lo = SetFilePointer(p_handle,temp_lo,&temp_hi,(DWORD)p_mode);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
25 if (GetLastError() != ERROR_SUCCESS) exception_io_from_win32(GetLastError());
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
26 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
27
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
28 void fillOverlapped(OVERLAPPED & ol, HANDLE myEvent, t_filesize s) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
29 ol.hEvent = myEvent;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
30 ol.Offset = (DWORD)( s & 0xFFFFFFFF );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
31 ol.OffsetHigh = (DWORD)(s >> 32);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
32 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
33
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
34 void writeOverlappedPass(HANDLE handle, HANDLE myEvent, t_filesize position, const void * in,DWORD inBytes, abort_callback & abort) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
35 abort.check();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
36 if (inBytes == 0) return;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
37 OVERLAPPED ol = {};
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
38 fillOverlapped(ol, myEvent, position);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
39 ResetEvent(myEvent);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
40 DWORD bytesWritten;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
41 SetLastError(NO_ERROR);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
42 if (WriteFile( handle, in, inBytes, &bytesWritten, &ol)) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
43 // succeeded already?
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
44 if (bytesWritten != inBytes) throw exception_io();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
45 return;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
46 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
47
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
48 {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
49 const DWORD code = GetLastError();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
50 if (code != ERROR_IO_PENDING) exception_io_from_win32(code);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
51 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
52 const HANDLE handles[] = {myEvent, abort.get_abort_event()};
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
53 SetLastError(NO_ERROR);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
54 DWORD state = WaitForMultipleObjects(_countof(handles), handles, FALSE, INFINITE);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
55 if (state == WAIT_OBJECT_0) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
56 try {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
57 WIN32_IO_OP( GetOverlappedResult(handle,&ol,&bytesWritten,TRUE) );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
58 } catch(...) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
59 CancelIo(handle);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
60 throw;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
61 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
62 if (bytesWritten != inBytes) throw exception_io();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
63 return;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
64 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
65 CancelIo(handle);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
66 throw exception_aborted();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
67 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
68
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
69 void writeOverlapped(HANDLE handle, HANDLE myEvent, t_filesize & position, const void * in, size_t inBytes, abort_callback & abort) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
70 enum {writeMAX = 16*1024*1024};
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
71 size_t done = 0;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
72 while(done < inBytes) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
73 size_t delta = inBytes - done;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
74 if (delta > writeMAX) delta = writeMAX;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
75 writeOverlappedPass(handle, myEvent, position, (const BYTE*)in + done, (DWORD) delta, abort);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
76 done += delta;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
77 position += delta;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
78 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
79 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
80 void writeStreamOverlapped(HANDLE handle, HANDLE myEvent, const void * in, size_t inBytes, abort_callback & abort) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
81 enum {writeMAX = 16*1024*1024};
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
82 size_t done = 0;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
83 while(done < inBytes) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
84 size_t delta = inBytes - done;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
85 if (delta > writeMAX) delta = writeMAX;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
86 writeOverlappedPass(handle, myEvent, 0, (const BYTE*)in + done, (DWORD) delta, abort);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
87 done += delta;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
88 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
89 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
90
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
91 DWORD readOverlappedPass(HANDLE handle, HANDLE myEvent, t_filesize position, void * out, DWORD outBytes, abort_callback & abort) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
92 abort.check();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
93 if (outBytes == 0) return 0;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
94 OVERLAPPED ol = {};
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
95 fillOverlapped(ol, myEvent, position);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
96 ResetEvent(myEvent);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
97 DWORD bytesDone;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
98 SetLastError(NO_ERROR);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
99 if (ReadFile( handle, out, outBytes, &bytesDone, &ol)) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
100 // succeeded already?
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
101 return bytesDone;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
102 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
103
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
104 {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
105 const DWORD code = GetLastError();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
106 switch(code) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
107 case ERROR_HANDLE_EOF:
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
108 case ERROR_BROKEN_PIPE:
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
109 return 0;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
110 case ERROR_IO_PENDING:
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
111 break; // continue
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
112 default:
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
113 exception_io_from_win32(code);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
114 };
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
115 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
116
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
117 const HANDLE handles[] = {myEvent, abort.get_abort_event()};
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
118 SetLastError(NO_ERROR);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
119 DWORD state = WaitForMultipleObjects(_countof(handles), handles, FALSE, INFINITE);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
120 if (state == WAIT_OBJECT_0) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
121 SetLastError(NO_ERROR);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
122 if (!GetOverlappedResult(handle,&ol,&bytesDone,TRUE)) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
123 const DWORD code = GetLastError();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
124 if (code == ERROR_HANDLE_EOF || code == ERROR_BROKEN_PIPE) bytesDone = 0;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
125 else {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
126 CancelIo(handle);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
127 exception_io_from_win32(code);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
128 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
129 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
130 return bytesDone;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
131 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
132 CancelIo(handle);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
133 throw exception_aborted();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
134 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
135 size_t readOverlapped(HANDLE handle, HANDLE myEvent, t_filesize & position, void * out, size_t outBytes, abort_callback & abort) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
136 enum {readMAX = 16*1024*1024};
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
137 size_t done = 0;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
138 while(done < outBytes) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
139 size_t delta = outBytes - done;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
140 if (delta > readMAX) delta = readMAX;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
141 delta = readOverlappedPass(handle, myEvent, position, (BYTE*) out + done, (DWORD) delta, abort);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
142 if (delta == 0) break;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
143 done += delta;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
144 position += delta;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
145 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
146 return done;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
147 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
148
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
149 size_t readStreamOverlapped(HANDLE handle, HANDLE myEvent, void * out, size_t outBytes, abort_callback & abort) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
150 enum {readMAX = 16*1024*1024};
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
151 size_t done = 0;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
152 while(done < outBytes) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
153 size_t delta = outBytes - done;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
154 if (delta > readMAX) delta = readMAX;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
155 delta = readOverlappedPass(handle, myEvent, 0, (BYTE*) out + done, (DWORD) delta, abort);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
156 if (delta == 0) break;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
157 done += delta;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
158 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
159 return done;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
160 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
161
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
162 typedef BOOL (WINAPI * pCancelSynchronousIo_t)(HANDLE hThread);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
163
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
164
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
165 struct createFileData_t {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
166 LPCTSTR lpFileName;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
167 DWORD dwDesiredAccess;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
168 DWORD dwShareMode;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
169 LPSECURITY_ATTRIBUTES lpSecurityAttributes;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
170 DWORD dwCreationDisposition;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
171 DWORD dwFlagsAndAttributes;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
172 HANDLE hTemplateFile;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
173 HANDLE hResult;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
174 DWORD dwErrorCode;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
175 };
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
176
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
177 HANDLE createFile(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile, abort_callback & abort) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
178 abort.check();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
179
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
180 return CreateFile(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
181 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
182
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
183 size_t lowLevelIO(HANDLE hFile, const GUID & guid, size_t arg1, void * arg2, size_t arg2size, bool canWrite, abort_callback & abort) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
184 if ( guid == file_lowLevelIO::guid_flushFileBuffers ) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
185 if (!canWrite) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
186 PFC_ASSERT(!"File opened for reading, not writing");
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
187 throw exception_io_denied();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
188 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
189 WIN32_IO_OP( ::FlushFileBuffers(hFile) );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
190 return 1;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
191 } else if ( guid == file_lowLevelIO::guid_getFileTimes ) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
192 if ( arg2size == sizeof(file_lowLevelIO::filetimes_t) ) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
193 if (canWrite) WIN32_IO_OP(::FlushFileBuffers(hFile));
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
194 auto ft = reinterpret_cast<file_lowLevelIO::filetimes_t *>(arg2);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
195 static_assert(sizeof(t_filetimestamp) == sizeof(FILETIME), "struct sanity");
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
196 WIN32_IO_OP( GetFileTime( hFile, (FILETIME*)&ft->creation, (FILETIME*)&ft->lastAccess, (FILETIME*)&ft->lastWrite) );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
197 return 1;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
198 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
199 } else if ( guid == file_lowLevelIO::guid_setFileTimes ) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
200 if (arg2size == sizeof(file_lowLevelIO::filetimes_t)) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
201 if (!canWrite) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
202 PFC_ASSERT(!"File opened for reading, not writing");
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
203 throw exception_io_denied();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
204 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
205 WIN32_IO_OP(::FlushFileBuffers(hFile));
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
206 auto ft = reinterpret_cast<file_lowLevelIO::filetimes_t *>(arg2);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
207 static_assert(sizeof(t_filetimestamp) == sizeof(FILETIME), "struct sanity");
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
208 const FILETIME * pCreation = nullptr;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
209 const FILETIME * pLastAccess = nullptr;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
210 const FILETIME * pLastWrite = nullptr;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
211 if ( ft->creation != filetimestamp_invalid ) pCreation = (const FILETIME*)&ft->creation;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
212 if ( ft->lastAccess != filetimestamp_invalid ) pLastAccess = (const FILETIME*)&ft->lastAccess;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
213 if ( ft->lastWrite != filetimestamp_invalid ) pLastWrite = (const FILETIME*)&ft->lastWrite;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
214 WIN32_IO_OP( SetFileTime(hFile, pCreation, pLastAccess, pLastWrite) );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
215 return 1;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
216 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
217 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
218 return 0;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
219 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
220
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
221 t_filestats2 stats2_from_handle(HANDLE h, const wchar_t * fallbackPath, uint32_t flags, abort_callback& a) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
222 a.check();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
223 // Sadly GetFileInformationByHandle() is UNRELIABLE with certain net shares
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
224 BY_HANDLE_FILE_INFORMATION info = {};
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
225 if (GetFileInformationByHandle(h, &info)) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
226 return file_win32_helpers::translate_stats2(info);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
227 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
228
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
229 a.check();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
230 t_filestats2 ret;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
231
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
232 // ALWAYS get size, fail if bad handle
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
233 ret.m_size = get_size(h);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
234
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
235 if (flags & (stats2_timestamp | stats2_timestampCreate)) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
236 static_assert(sizeof(t_filetimestamp) == sizeof(FILETIME), "struct sanity");
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
237 FILETIME ftCreate = {}, ftWrite = {};
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
238 if (GetFileTime(h, &ftCreate, nullptr, &ftWrite)) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
239 ret.m_timestamp = make_uint64(ftWrite); ret.m_timestampCreate = make_uint64(ftCreate);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
240 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
241 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
242 if (flags & stats2_flags) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
243 // No other way to get this from handle?
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
244 if (fallbackPath != nullptr && *fallbackPath != 0) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
245 DWORD attr = GetFileAttributes(fallbackPath);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
246 if (attr != INVALID_FILE_ATTRIBUTES) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
247 attribs_from_win32(ret, attr);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
248 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
249 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
250 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
251 return ret;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
252 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
253 void attribs_from_win32(t_filestats2& out, DWORD in) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
254 out.set_readonly((in & FILE_ATTRIBUTE_READONLY) != 0);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
255 out.set_folder((in & FILE_ATTRIBUTE_DIRECTORY) != 0);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
256 out.set_hidden((in & FILE_ATTRIBUTE_HIDDEN) != 0);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
257 out.set_system((in & FILE_ATTRIBUTE_SYSTEM) != 0);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
258 out.set_remote(false);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
259 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
260
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
261
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
262 // Seek penalty query, effectively: is this an SSD?
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
263 // Credit:
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
264 // https://devblogs.microsoft.com/oldnewthing/20201023-00/?p=104395
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
265 static bool queryVolumeSeekPenalty(HANDLE hVolume, bool& out) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
266 STORAGE_PROPERTY_QUERY query = {};
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
267 query.PropertyId = StorageDeviceSeekPenaltyProperty;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
268 query.QueryType = PropertyStandardQuery;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
269 DWORD count = 1;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
270 DEVICE_SEEK_PENALTY_DESCRIPTOR result = {};
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
271 if (!DeviceIoControl(hVolume, IOCTL_STORAGE_QUERY_PROPERTY, &query, sizeof(query), &result, sizeof(result), &count, nullptr)) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
272 return false;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
273 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
274 out = result.IncursSeekPenalty;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
275 return true;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
276 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
277
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
278 static HANDLE GetVolumeHandleForFile(PCWSTR filePath) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
279 wchar_t volumePath[MAX_PATH] = {};
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
280 WIN32_OP_D(GetVolumePathName(filePath, volumePath, ARRAYSIZE(volumePath)));
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
281
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
282 wchar_t volumeName[MAX_PATH] = {};
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
283 WIN32_OP_D(GetVolumeNameForVolumeMountPoint(volumePath, volumeName, ARRAYSIZE(volumeName)));
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
284
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
285 auto length = wcslen(volumeName);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
286 if ( length == 0 ) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
287 PFC_ASSERT(!"???");
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
288 return NULL;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
289 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
290 if (length && volumeName[length - 1] == L'\\') {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
291 volumeName[length - 1] = L'\0';
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
292 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
293
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
294 HANDLE ret;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
295 WIN32_OP_D( ret = CreateFile(volumeName, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr) );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
296 return ret;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
297 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
298 bool querySeekPenalty(const wchar_t* nativePath, bool& out) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
299 CHandle h;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
300 h.Attach( GetVolumeHandleForFile( nativePath ) );
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
301 if (!h) return false;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
302 return queryVolumeSeekPenalty(h, out);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
303 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
304 bool querySeekPenalty(const char* fb2k_path, bool& out) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
305 const char * path = fb2k_path;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
306 if ( matchProtocol(path, "file")) path = afterProtocol(path);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
307 return querySeekPenalty(pfc::wideFromUTF8(path), out);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
308 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
309 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
310
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
311 #endif // _WIN32
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
312