mingw32: Use HANDLE only for MinGW32 build

pull/38/head
Tatsuhiro Tsujikawa 2012-12-15 18:28:46 +09:00
parent 8c3e08f15a
commit de1ca6d6b8
5 changed files with 114 additions and 84 deletions

View File

@ -57,13 +57,13 @@ namespace aria2 {
AbstractDiskWriter::AbstractDiskWriter(const std::string& filename) AbstractDiskWriter::AbstractDiskWriter(const std::string& filename)
: filename_(filename), : filename_(filename),
fd_(-1), fd_(A2_BAD_FD),
#ifdef __MINGW32__
mapView_(0),
#else // !__MINGW32__
#endif // !__MINGW32__
readOnly_(false), readOnly_(false),
enableMmap_(false), enableMmap_(false),
#ifdef __MINGW32__
hn_(INVALID_HANDLE_VALUE),
mapView_(0),
#endif // __MINGW32__
mapaddr_(0), mapaddr_(0),
maplen_(0) maplen_(0)
@ -117,7 +117,14 @@ void AbstractDiskWriter::openFile(int64_t totalLength)
try { try {
openExistingFile(totalLength); openExistingFile(totalLength);
} catch(RecoverableException& e) { } catch(RecoverableException& e) {
if(e.getErrNum() == ENOENT) { if(
#ifdef __MINGW32__
e.getErrNum() == ERROR_FILE_NOT_FOUND ||
e.getErrNum() == ERROR_PATH_NOT_FOUND
#else // !__MINGW32__
e.getErrNum() == ENOENT
#endif // !__MINGW32__
) {
initAndOpenFile(totalLength); initAndOpenFile(totalLength);
} else { } else {
throw; throw;
@ -152,53 +159,55 @@ void AbstractDiskWriter::closeFile()
maplen_ = 0; maplen_ = 0;
} }
#endif // HAVE_MMAP || defined __MINGW32__ #endif // HAVE_MMAP || defined __MINGW32__
if(fd_ != -1) { if(fd_ != A2_BAD_FD) {
#ifdef __MINGW32__
CloseHandle(fd_);
#else // !__MINGW32__
close(fd_); close(fd_);
fd_ = -1; #endif // !__MINGW32__
fd_ = A2_BAD_FD;
} }
} }
namespace { namespace {
// TODO I tried CreateFile, but ReadFile fails with "Access Denied" #ifdef __MINGW32__
// when reading (not fully populated) sparse files on NTFS. HANDLE openFileWithFlags(const std::string& filename, int flags,
// error_code::Value errCode)
// HANDLE openFileWithFlags(const std::string& filename, int flags, {
// error_code::Value errCode) HANDLE hn;
// { DWORD desiredAccess = 0;
// HANDLE hn; DWORD sharedMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
// DWORD desiredAccess = 0; DWORD creationDisp = 0;
// DWORD sharedMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
// DWORD creationDisp = 0; if(flags & O_RDWR) {
// if(flags & O_RDONLY) { desiredAccess = GENERIC_READ | GENERIC_WRITE;
// desiredAccess |= GENERIC_READ; } else if(flags & O_WRONLY) {
// } else if(flags & O_RDWR) { desiredAccess = GENERIC_WRITE;
// desiredAccess |= GENERIC_READ | GENERIC_WRITE; } else {
// } desiredAccess = GENERIC_READ;
// if(flags & O_CREAT) { }
// if(flags & O_TRUNC) { if(flags & O_CREAT) {
// creationDisp |= CREATE_ALWAYS; if(flags & O_TRUNC) {
// } else { creationDisp |= CREATE_ALWAYS;
// creationDisp |= CREATE_NEW; } else {
// } creationDisp |= CREATE_NEW;
// } else { }
// creationDisp |= OPEN_EXISTING; } else {
// } creationDisp |= OPEN_EXISTING;
// hn = CreateFileW(utf8ToWChar(filename).c_str(), }
// desiredAccess, sharedMode, 0, creationDisp, hn = CreateFileW(utf8ToWChar(filename).c_str(), desiredAccess, sharedMode,
// FILE_ATTRIBUTE_NORMAL, 0); /* lpSecurityAttributes */ 0, creationDisp,
// if(hn == INVALID_HANDLE_VALUE) { FILE_ATTRIBUTE_NORMAL, /* hTemplateFile */ 0);
// int errNum = GetLastError(); if(hn == INVALID_HANDLE_VALUE) {
// throw DL_ABORT_EX3(errNum, fmt(EX_FILE_OPEN, int errNum = GetLastError();
// filename.c_str(), throw DL_ABORT_EX3(errNum, fmt(EX_FILE_OPEN,
// fileStrerror(errNum).c_str()), filename.c_str(),
// errCode); fileStrerror(errNum).c_str()),
// } errCode);
// DWORD bytesReturned; }
// if(!DeviceIoControl(hn, FSCTL_SET_SPARSE, 0, 0, 0, 0, &bytesReturned, 0)) { return hn;
// A2_LOG_WARN(fmt("Making file sparse failed or pending: %s", }
// fileStrerror(GetLastError()).c_str())); #else // !__MINGW32__
// }
// return hn;
int openFileWithFlags(const std::string& filename, int flags, int openFileWithFlags(const std::string& filename, int flags,
error_code::Value errCode) error_code::Value errCode)
{ {
@ -217,6 +226,7 @@ int openFileWithFlags(const std::string& filename, int flags,
#endif // __APPLE__ && __MACH__ #endif // __APPLE__ && __MACH__
return fd; return fd;
} }
#endif // !__MINGW32__
} // namespace } // namespace
#ifdef __MINGW32__ #ifdef __MINGW32__
@ -237,9 +247,6 @@ void AbstractDiskWriter::openExistingFile(int64_t totalLength)
flags |= O_RDWR; flags |= O_RDWR;
} }
fd_ = openFileWithFlags(filename_, flags, error_code::FILE_OPEN_ERROR); fd_ = openFileWithFlags(filename_, flags, error_code::FILE_OPEN_ERROR);
#ifdef __MINGW32__
hn_ = getWin32Handle(fd_);
#endif // __MINGW32__
} }
void AbstractDiskWriter::createFile(int addFlags) void AbstractDiskWriter::createFile(int addFlags)
@ -248,9 +255,6 @@ void AbstractDiskWriter::createFile(int addFlags)
util::mkdirs(File(filename_).getDirname()); util::mkdirs(File(filename_).getDirname());
fd_ = openFileWithFlags(filename_, O_CREAT|O_RDWR|O_TRUNC|O_BINARY|addFlags, fd_ = openFileWithFlags(filename_, O_CREAT|O_RDWR|O_TRUNC|O_BINARY|addFlags,
error_code::FILE_CREATE_ERROR); error_code::FILE_CREATE_ERROR);
#ifdef __MINGW32__
hn_ = getWin32Handle(fd_);
#endif // __MINGW32__
} }
ssize_t AbstractDiskWriter::writeDataInternal(const unsigned char* data, ssize_t AbstractDiskWriter::writeDataInternal(const unsigned char* data,
@ -263,6 +267,14 @@ ssize_t AbstractDiskWriter::writeDataInternal(const unsigned char* data,
ssize_t writtenLength = 0; ssize_t writtenLength = 0;
seek(offset); seek(offset);
while((size_t)writtenLength < len) { while((size_t)writtenLength < len) {
#ifdef __MINGW32__
DWORD nwrite;
if(WriteFile(fd_, data+writtenLength, len-writtenLength, &nwrite, 0)) {
writtenLength += nwrite;
} else {
return -1;
}
#else // !__MINGW32__
ssize_t ret = 0; ssize_t ret = 0;
while((ret = write(fd_, data+writtenLength, len-writtenLength)) == -1 && while((ret = write(fd_, data+writtenLength, len-writtenLength)) == -1 &&
errno == EINTR); errno == EINTR);
@ -270,6 +282,7 @@ ssize_t AbstractDiskWriter::writeDataInternal(const unsigned char* data,
return -1; return -1;
} }
writtenLength += ret; writtenLength += ret;
#endif // !__MINGW32__
} }
return writtenLength; return writtenLength;
} }
@ -289,9 +302,18 @@ ssize_t AbstractDiskWriter::readDataInternal(unsigned char* data, size_t len,
return readlen; return readlen;
} else { } else {
seek(offset); seek(offset);
#ifdef __MINGW32__
DWORD nread;
if(ReadFile(fd_, data, len, &nread, 0)) {
return nread;
} else {
return -1;
}
#else // !__MINGW32__
ssize_t ret = 0; ssize_t ret = 0;
while((ret = read(fd_, data, len)) == -1 && errno == EINTR); while((ret = read(fd_, data, len)) == -1 && errno == EINTR);
return ret; return ret;
#endif // !__MINGW32__
} }
} }
@ -300,7 +322,7 @@ void AbstractDiskWriter::seek(int64_t offset)
#ifdef __MINGW32__ #ifdef __MINGW32__
LARGE_INTEGER fileLength; LARGE_INTEGER fileLength;
fileLength.QuadPart = offset; fileLength.QuadPart = offset;
if(SetFilePointerEx(hn_, fileLength, 0, FILE_BEGIN) == 0) if(SetFilePointerEx(fd_, fileLength, 0, FILE_BEGIN) == 0)
#else // !__MINGW32__ #else // !__MINGW32__
if(a2lseek(fd_, offset, SEEK_SET) == (off_t)-1) if(a2lseek(fd_, offset, SEEK_SET) == (off_t)-1)
#endif // !__MINGW32__ #endif // !__MINGW32__
@ -343,7 +365,7 @@ void AbstractDiskWriter::ensureMmapWrite(size_t len, int64_t offset)
int errNum = 0; int errNum = 0;
if(static_cast<int64_t>(len + offset) <= filesize) { if(static_cast<int64_t>(len + offset) <= filesize) {
#ifdef __MINGW32__ #ifdef __MINGW32__
mapView_ = CreateFileMapping(hn_, 0, PAGE_READWRITE, mapView_ = CreateFileMapping(fd_, 0, PAGE_READWRITE,
filesize >> 32, filesize & 0xffffffffu, filesize >> 32, filesize & 0xffffffffu,
0); 0);
if(mapView_) { if(mapView_) {
@ -384,18 +406,24 @@ void AbstractDiskWriter::writeData(const unsigned char* data, size_t len, int64_
{ {
ensureMmapWrite(len, offset); ensureMmapWrite(len, offset);
if(writeDataInternal(data, len, offset) < 0) { if(writeDataInternal(data, len, offset) < 0) {
int errNum = errno; int errNum = fileError();
// If errNum is ENOSPC(not enough space in device), throw if(
// DownloadFailureException and abort download instantly. // If the error indicates disk full situation, throw
if(errNum == ENOSPC) { // DownloadFailureException and abort download instantly.
#ifdef __MINGW32__
errNum == ERROR_DISK_FULL || errNum == ERROR_HANDLE_DISK_FULL
#else // !__MINGW32__
errNum == ENOSPC
#endif // !__MINGW32__
) {
throw DOWNLOAD_FAILURE_EXCEPTION3 throw DOWNLOAD_FAILURE_EXCEPTION3
(errNum, fmt(EX_FILE_WRITE, filename_.c_str(), (errNum, fmt(EX_FILE_WRITE, filename_.c_str(),
util::safeStrerror(errNum).c_str()), fileStrerror(errNum).c_str()),
error_code::NOT_ENOUGH_DISK_SPACE); error_code::NOT_ENOUGH_DISK_SPACE);
} else { } else {
throw DL_ABORT_EX3 throw DL_ABORT_EX3
(errNum, fmt(EX_FILE_WRITE, filename_.c_str(), (errNum, fmt(EX_FILE_WRITE, filename_.c_str(),
util::safeStrerror(errNum).c_str()), fileStrerror(errNum).c_str()),
error_code::FILE_IO_ERROR); error_code::FILE_IO_ERROR);
} }
} }
@ -405,10 +433,10 @@ ssize_t AbstractDiskWriter::readData(unsigned char* data, size_t len, int64_t of
{ {
ssize_t ret; ssize_t ret;
if((ret = readDataInternal(data, len, offset)) < 0) { if((ret = readDataInternal(data, len, offset)) < 0) {
int errNum = errno; int errNum = fileError();
throw DL_ABORT_EX3 throw DL_ABORT_EX3
(errNum, fmt(EX_FILE_READ, filename_.c_str(), (errNum, fmt(EX_FILE_READ, filename_.c_str(),
util::safeStrerror(errNum).c_str()), fileStrerror(errNum).c_str()),
error_code::FILE_IO_ERROR); error_code::FILE_IO_ERROR);
} }
return ret; return ret;
@ -416,14 +444,14 @@ ssize_t AbstractDiskWriter::readData(unsigned char* data, size_t len, int64_t of
void AbstractDiskWriter::truncate(int64_t length) void AbstractDiskWriter::truncate(int64_t length)
{ {
if(fd_ == -1) { if(fd_ == A2_BAD_FD) {
throw DL_ABORT_EX("File not yet opened."); throw DL_ABORT_EX("File not yet opened.");
} }
#ifdef __MINGW32__ #ifdef __MINGW32__
// Since mingw32's ftruncate cannot handle over 2GB files, we use // Since mingw32's ftruncate cannot handle over 2GB files, we use
// SetEndOfFile instead. // SetEndOfFile instead.
seek(length); seek(length);
if(SetEndOfFile(hn_) == 0) if(SetEndOfFile(fd_) == 0)
#else // !__MINGW32__ #else // !__MINGW32__
if(ftruncate(fd_, length) == -1) if(ftruncate(fd_, length) == -1)
#endif // !__MINGW32__ #endif // !__MINGW32__
@ -437,7 +465,7 @@ void AbstractDiskWriter::truncate(int64_t length)
void AbstractDiskWriter::allocate(int64_t offset, int64_t length) void AbstractDiskWriter::allocate(int64_t offset, int64_t length)
{ {
if(fd_ == -1) { if(fd_ == A2_BAD_FD) {
throw DL_ABORT_EX("File not yet opened."); throw DL_ABORT_EX("File not yet opened.");
} }
#ifdef HAVE_SOME_FALLOCATE #ifdef HAVE_SOME_FALLOCATE

View File

@ -44,18 +44,17 @@ class AbstractDiskWriter : public DiskWriter {
private: private:
std::string filename_; std::string filename_;
#ifdef __MINGW32__
HANDLE fd_;
// The handle for memory mapped file. mmap equivalent in Windows.
HANDLE mapView_;
#else // !__MINGW32__
int fd_; int fd_;
#endif // !__MINGW32__
bool readOnly_; bool readOnly_;
bool enableMmap_; bool enableMmap_;
#ifdef __MINGW32__
// This handle is retrieved from fd_ using _get_osfhandle(). It is
// used for Win32 API functions which only accept HANDLE.
HANDLE hn_;
// The handle for memory mapped file. mmap equivalent in Windows.
HANDLE mapView_;
#endif // __MINGW32__
unsigned char* mapaddr_; unsigned char* mapaddr_;
int64_t maplen_; int64_t maplen_;

View File

@ -161,4 +161,10 @@
#define OPEN_MODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH #define OPEN_MODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH
#define DIR_OPEN_MODE S_IRWXU|S_IRWXG|S_IRWXO #define DIR_OPEN_MODE S_IRWXU|S_IRWXG|S_IRWXO
#ifdef __MINGW32__
# define A2_BAD_FD INVALID_HANDLE_VALUE
#else // !__MINGW32__
# define A2_BAD_FD -1
#endif // !__MINGW32__
#endif // D_A2IO_H #endif // D_A2IO_H

View File

@ -24,16 +24,9 @@ namespace aria2 {
void createFile(const std::string& path, size_t length) void createFile(const std::string& path, size_t length)
{ {
File(File(path).getDirname()).mkdirs(); File(File(path).getDirname()).mkdirs();
int fd = creat(path.c_str(), OPEN_MODE); DefaultDiskWriter dw(path);
if(fd == -1) { dw.initAndOpenFile();
throw FATAL_EXCEPTION(fmt("Could not create file=%s. cause:%s", dw.truncate(length);
path.c_str(),
strerror(errno)));
}
if(-1 == ftruncate(fd, length)) {
throw FATAL_EXCEPTION(fmt("ftruncate failed. cause:%s", strerror(errno)));
}
close(fd);
} }
std::string readFile(const std::string& path) std::string readFile(const std::string& path)

View File

@ -101,9 +101,13 @@ void TimeTest::testOperatorLess()
void TimeTest::testToHTTPDate() void TimeTest::testToHTTPDate()
{ {
// This test disabled for MinGW32, because the garbage will be
// displayed and it hides real errors.
#ifndef __MINGW32__
Time t(1220714793); Time t(1220714793);
CPPUNIT_ASSERT_EQUAL(std::string("Sat, 06 Sep 2008 15:26:33 GMT"), CPPUNIT_ASSERT_EQUAL(std::string("Sat, 06 Sep 2008 15:26:33 GMT"),
t.toHTTPDate()); t.toHTTPDate());
#endif // !__MINGW32__
} }
void TimeTest::testElapsed() void TimeTest::testElapsed()