| |
10 |
10 |
|
| |
11 |
11 |
|
| |
12 |
12 |
|
| |
13 |
13 |
|
| |
14 |
14 |
|
| |
15 |
15 |
|
| |
16 |
16 |
|
| |
17 |
17 |
|
| |
18 |
18 |
|
| |
19 |
19 |
#include "stdafx.h" |
| |
20 |
20 |
#include "TLocalFilesystemFile.h" |
| |
21 |
21 |
#include "TBufferSizes.h" |
| |
22 |
22 |
#include "TCoreException.h" |
| |
23 |
23 |
#include "ErrorCodes.h" |
| |
24 |
24 |
#include <boost/numeric/conversion/cast.hpp> |
| |
25 |
25 |
#include "RoundingFunctions.h" |
| |
26 |
26 |
#include "TLocalFilesystem.h" |
| |
27 |
27 |
#include "TFileException.h" |
| |
28 |
28 |
#include "TFileInfo.h" |
| |
29 |
29 |
#include "StreamingHelpers.h" |
| |
30 |
|
#include "TOverlappedDataBufferQueue.h" |
| |
|
30 |
#include "TOverlappedMemoryPool.h" |
| |
31 |
31 |
#include "OverlappedCallbacks.h" |
| |
32 |
32 |
|
| |
33 |
33 |
namespace chcore |
| |
34 |
34 |
{ |
| |
35 |
35 |
|
| |
36 |
36 |
static_assert(TLocalFilesystemFile::MaxSectorSize <= TBufferSizes::BufferGranularity, "Buffer granularity must be equal to or bigger than the max sector size"); |
| |
37 |
37 |
|
| |
38 |
38 |
TLocalFilesystemFile::TLocalFilesystemFile(const TSmartPath& pathFile, bool bNoBuffering, const logger::TLogFileDataPtr& spLogFileData) : |
| |
39 |
39 |
m_pathFile(TLocalFilesystem::PrependPathExtensionIfNeeded(pathFile)), |
| |
40 |
40 |
m_hFile(INVALID_HANDLE_VALUE), |
| |
41 |
41 |
m_bNoBuffering(bNoBuffering), |
| |
42 |
42 |
m_spLog(logger::MakeLogger(spLogFileData, L"Filesystem-File")) |
| |
43 |
43 |
{ |
| |
44 |
44 |
if (pathFile.IsEmpty()) |
| |
45 |
45 |
throw TCoreException(eErr_InvalidArgument, L"pathFile", LOCATION); |
| |
46 |
46 |
} |
| |
47 |
47 |
|
| |
48 |
48 |
TLocalFilesystemFile::~TLocalFilesystemFile() |
| |
49 |
49 |
{ |
| |
50 |
50 |
try |
|
| |
170 |
170 |
if(!::SetEndOfFile(m_hFile)) |
| |
171 |
171 |
{ |
| |
172 |
172 |
DWORD dwLastError = GetLastError(); |
| |
173 |
173 |
LOG_ERROR(m_spLog) << L"Setting EOF failed" << GetFileInfoForLog(m_bNoBuffering); |
| |
174 |
174 |
throw TFileException(eErr_CannotTruncate, dwLastError, m_pathFile, L"Cannot mark the end of file", LOCATION); |
| |
175 |
175 |
} |
| |
176 |
176 |
|
| |
177 |
177 |
|
| |
178 |
178 |
if(bFileSettingsChanged) |
| |
179 |
179 |
{ |
| |
180 |
180 |
LOG_DEBUG(m_spLog) << L"Closing file due to mode change in truncate function" << GetFileInfoForLog(m_bNoBuffering); |
| |
181 |
181 |
|
| |
182 |
182 |
Close(); |
| |
183 |
183 |
} |
| |
184 |
184 |
} |
| |
185 |
185 |
|
| |
186 |
186 |
void TLocalFilesystemFile::ReadFile(TOverlappedDataBuffer& rBuffer) |
| |
187 |
187 |
{ |
| |
188 |
188 |
LOG_TRACE(m_spLog) << L"Requesting read of " << rBuffer.GetRequestedDataSize() << |
| |
189 |
189 |
L" bytes at position " << rBuffer.GetFilePosition() << |
| |
190 |
|
L"; buffer-order: " << rBuffer.GetBufferOrder() << |
| |
|
190 |
L"; buffer-order: " << rBuffer.GetFilePosition() << |
| |
191 |
191 |
GetFileInfoForLog(m_bNoBuffering); |
| |
192 |
192 |
|
| |
193 |
193 |
if (!IsOpen()) |
| |
194 |
194 |
{ |
| |
195 |
|
LOG_ERROR(m_spLog) << L"Read request failed - file not open" << L"; buffer-order: " << rBuffer.GetBufferOrder() << GetFileInfoForLog(m_bNoBuffering); |
| |
|
195 |
LOG_ERROR(m_spLog) << L"Read request failed - file not open" << L"; buffer-order: " << rBuffer.GetFilePosition() << GetFileInfoForLog(m_bNoBuffering); |
| |
196 |
196 |
throw TFileException(eErr_FileNotOpen, ERROR_INVALID_HANDLE, m_pathFile, L"Cannot read from closed file", LOCATION); |
| |
197 |
197 |
} |
| |
198 |
198 |
|
| |
199 |
199 |
if (!::ReadFileEx(m_hFile, rBuffer.GetBufferPtr(), rBuffer.GetRequestedDataSize(), &rBuffer, OverlappedReadCompleted)) |
| |
200 |
200 |
{ |
| |
201 |
201 |
DWORD dwLastError = GetLastError(); |
| |
202 |
202 |
switch (dwLastError) |
| |
203 |
203 |
{ |
| |
204 |
204 |
case ERROR_IO_PENDING: |
| |
205 |
|
LOG_TRACE(m_spLog) << L"Read requested and is pending" << L"; buffer-order: " << rBuffer.GetBufferOrder() << GetFileInfoForLog(m_bNoBuffering); |
| |
|
205 |
LOG_TRACE(m_spLog) << L"Read requested and is pending" << L"; buffer-order: " << rBuffer.GetFilePosition() << GetFileInfoForLog(m_bNoBuffering); |
| |
206 |
206 |
return; |
| |
207 |
207 |
|
| |
208 |
208 |
case ERROR_HANDLE_EOF: |
| |
209 |
209 |
{ |
| |
210 |
|
LOG_TRACE(m_spLog) << L"Read request marked as EOF" << L"; buffer-order: " << rBuffer.GetBufferOrder() << GetFileInfoForLog(m_bNoBuffering); |
| |
|
210 |
LOG_TRACE(m_spLog) << L"Read request marked as EOF" << L"; buffer-order: " << rBuffer.GetFilePosition() << GetFileInfoForLog(m_bNoBuffering); |
| |
211 |
211 |
|
| |
212 |
212 |
rBuffer.SetBytesTransferred(0); |
| |
213 |
213 |
rBuffer.SetStatusCode(0); |
| |
214 |
214 |
rBuffer.SetErrorCode(ERROR_SUCCESS); |
| |
215 |
215 |
rBuffer.SetLastPart(true); |
| |
216 |
216 |
|
| |
217 |
217 |
OverlappedReadCompleted(rBuffer.GetErrorCode(), 0, &rBuffer); |
| |
218 |
218 |
|
| |
219 |
219 |
break; |
| |
220 |
220 |
} |
| |
221 |
221 |
|
| |
222 |
222 |
default: |
| |
223 |
223 |
{ |
| |
224 |
|
LOG_ERROR(m_spLog) << L"Read request failed with error " << dwLastError << L"; buffer-order: " << rBuffer.GetBufferOrder() << GetFileInfoForLog(m_bNoBuffering); |
| |
|
224 |
LOG_ERROR(m_spLog) << L"Read request failed with error " << dwLastError << L"; buffer-order: " << rBuffer.GetFilePosition() << GetFileInfoForLog(m_bNoBuffering); |
| |
225 |
225 |
|
| |
226 |
226 |
throw TFileException(eErr_CannotReadFile, dwLastError, m_pathFile, L"Error reading data from file", LOCATION); |
| |
227 |
227 |
} |
| |
228 |
228 |
} |
| |
229 |
229 |
} |
| |
230 |
230 |
else |
| |
231 |
|
LOG_TRACE(m_spLog) << L"Read request succeeded" << L"; buffer-order: " << rBuffer.GetBufferOrder() << GetFileInfoForLog(m_bNoBuffering); |
| |
|
231 |
LOG_TRACE(m_spLog) << L"Read request succeeded" << L"; buffer-order: " << rBuffer.GetFilePosition() << GetFileInfoForLog(m_bNoBuffering); |
| |
232 |
232 |
} |
| |
233 |
233 |
|
| |
234 |
234 |
void TLocalFilesystemFile::WriteFile(TOverlappedDataBuffer& rBuffer) |
| |
235 |
235 |
{ |
| |
236 |
236 |
LOG_TRACE(m_spLog) << L"Requesting writing of " << rBuffer.GetRealDataSize() << |
| |
237 |
237 |
L" bytes at position " << rBuffer.GetFilePosition() << |
| |
238 |
|
L"; buffer-order: " << rBuffer.GetBufferOrder() << |
| |
|
238 |
L"; buffer-order: " << rBuffer.GetFilePosition() << |
| |
239 |
239 |
GetFileInfoForLog(m_bNoBuffering); |
| |
240 |
240 |
|
| |
241 |
241 |
if (!IsOpen()) |
| |
242 |
242 |
{ |
| |
243 |
|
LOG_ERROR(m_spLog) << L"Write request failed - file not open" << L"; buffer-order: " << rBuffer.GetBufferOrder() << GetFileInfoForLog(m_bNoBuffering); |
| |
|
243 |
LOG_ERROR(m_spLog) << L"Write request failed - file not open" << L"; buffer-order: " << rBuffer.GetFilePosition() << GetFileInfoForLog(m_bNoBuffering); |
| |
244 |
244 |
throw TFileException(eErr_FileNotOpen, ERROR_INVALID_HANDLE, m_pathFile, L"Cannot write to closed file", LOCATION); |
| |
245 |
245 |
} |
| |
246 |
246 |
|
| |
247 |
247 |
DWORD dwToWrite = boost::numeric_cast<DWORD>(rBuffer.GetRealDataSize()); |
| |
248 |
248 |
|
| |
249 |
249 |
if (m_bNoBuffering && rBuffer.IsLastPart()) |
| |
250 |
250 |
{ |
| |
251 |
251 |
dwToWrite = RoundUp<DWORD>(dwToWrite, MaxSectorSize); |
| |
252 |
|
LOG_TRACE(m_spLog) << L"Writing last part of file in no-buffering mode. Rounding up last write to " << dwToWrite << L"; buffer-order: " << rBuffer.GetBufferOrder() << GetFileInfoForLog(m_bNoBuffering); |
| |
|
252 |
LOG_TRACE(m_spLog) << L"Writing last part of file in no-buffering mode. Rounding up last write to " << dwToWrite << L"; buffer-order: " << rBuffer.GetFilePosition() << GetFileInfoForLog(m_bNoBuffering); |
| |
253 |
253 |
} |
| |
254 |
254 |
|
| |
255 |
255 |
if (!::WriteFileEx(m_hFile, rBuffer.GetBufferPtr(), dwToWrite, &rBuffer, OverlappedWriteCompleted)) |
| |
256 |
256 |
{ |
| |
257 |
257 |
DWORD dwLastError = GetLastError(); |
| |
258 |
258 |
if (dwLastError != ERROR_IO_PENDING) |
| |
259 |
259 |
{ |
| |
260 |
|
LOG_ERROR(m_spLog) << L"Write request failed with error " << dwLastError << L"; buffer-order: " << rBuffer.GetBufferOrder() << GetFileInfoForLog(m_bNoBuffering); |
| |
|
260 |
LOG_ERROR(m_spLog) << L"Write request failed with error " << dwLastError << L"; buffer-order: " << rBuffer.GetFilePosition() << GetFileInfoForLog(m_bNoBuffering); |
| |
261 |
261 |
throw TFileException(eErr_CannotWriteFile, dwLastError, m_pathFile, L"Error while writing to file", LOCATION); |
| |
262 |
262 |
} |
| |
263 |
263 |
|
| |
264 |
|
LOG_TRACE(m_spLog) << L"Write requested and is pending" << L"; buffer-order: " << rBuffer.GetBufferOrder() << GetFileInfoForLog(m_bNoBuffering); |
| |
|
264 |
LOG_TRACE(m_spLog) << L"Write requested and is pending" << L"; buffer-order: " << rBuffer.GetFilePosition() << GetFileInfoForLog(m_bNoBuffering); |
| |
265 |
265 |
} |
| |
266 |
266 |
else |
| |
267 |
|
LOG_TRACE(m_spLog) << L"Write request succeeded" << L"; buffer-order: " << rBuffer.GetBufferOrder() << GetFileInfoForLog(m_bNoBuffering); |
| |
|
267 |
LOG_TRACE(m_spLog) << L"Write request succeeded" << L"; buffer-order: " << rBuffer.GetFilePosition() << GetFileInfoForLog(m_bNoBuffering); |
| |
268 |
268 |
} |
| |
269 |
269 |
|
| |
270 |
270 |
void TLocalFilesystemFile::FinalizeFile(TOverlappedDataBuffer& rBuffer) |
| |
271 |
271 |
{ |
| |
272 |
272 |
LOG_TRACE(m_spLog) << L"Finalizing file" << |
| |
273 |
|
L"; buffer-order: " << rBuffer.GetBufferOrder() << |
| |
|
273 |
L"; buffer-order: " << rBuffer.GetFilePosition() << |
| |
274 |
274 |
GetFileInfoForLog(m_bNoBuffering); |
| |
275 |
275 |
|
| |
276 |
276 |
if (!IsOpen()) |
| |
277 |
277 |
{ |
| |
278 |
|
LOG_ERROR(m_spLog) << L"Cannot finalize file - file not open" << L"; buffer-order: " << rBuffer.GetBufferOrder() << GetFileInfoForLog(m_bNoBuffering); |
| |
|
278 |
LOG_ERROR(m_spLog) << L"Cannot finalize file - file not open" << L"; buffer-order: " << rBuffer.GetFilePosition() << GetFileInfoForLog(m_bNoBuffering); |
| |
279 |
279 |
throw TFileException(eErr_FileNotOpen, ERROR_INVALID_HANDLE, m_pathFile, L"Cannot write to closed file", LOCATION); |
| |
280 |
280 |
} |
| |
281 |
281 |
|
| |
282 |
282 |
if (m_bNoBuffering && rBuffer.IsLastPart()) |
| |
283 |
283 |
{ |
| |
284 |
284 |
DWORD dwToWrite = boost::numeric_cast<DWORD>(rBuffer.GetRealDataSize()); |
| |
285 |
285 |
DWORD dwReallyWritten = RoundUp<DWORD>(dwToWrite, MaxSectorSize); |
| |
286 |
286 |
|
| |
287 |
287 |
if (dwToWrite != dwReallyWritten) |
| |
288 |
288 |
{ |
| |
289 |
289 |
file_size_t fsNewFileSize = rBuffer.GetFilePosition() + dwToWrite; |
| |
290 |
290 |
|
| |
291 |
291 |
LOG_TRACE(m_spLog) << L"File need truncating - really written " << dwReallyWritten << |
| |
292 |
292 |
L", should write " << dwToWrite << |
| |
293 |
293 |
L". Truncating file to " << fsNewFileSize << |
| |
294 |
|
L"; buffer-order: " << rBuffer.GetBufferOrder() << |
| |
|
294 |
L"; buffer-order: " << rBuffer.GetFilePosition() << |
| |
295 |
295 |
GetFileInfoForLog(m_bNoBuffering); |
| |
296 |
296 |
|
| |
297 |
297 |
Truncate(fsNewFileSize); |
| |
298 |
298 |
} |
| |
299 |
299 |
} |
| |
300 |
300 |
} |
| |
301 |
301 |
|
| |
302 |
302 |
void TLocalFilesystemFile::InternalClose() |
| |
303 |
303 |
{ |
| |
304 |
304 |
if (m_hFile != INVALID_HANDLE_VALUE) |
| |
305 |
305 |
{ |
| |
306 |
306 |
LOG_DEBUG(m_spLog) << L"Closing file" << GetFileInfoForLog(m_bNoBuffering); |
| |
307 |
307 |
::CloseHandle(m_hFile); |
| |
308 |
308 |
} |
| |
309 |
309 |
m_hFile = INVALID_HANDLE_VALUE; |
| |
310 |
310 |
} |
| |
311 |
311 |
|
| |
312 |
312 |
std::wstring TLocalFilesystemFile::GetFileInfoForLog(bool bNoBuffering) const |
| |
313 |
313 |
{ |
| |
314 |
314 |
std::wstringstream wss; |