diff options
| author | Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com> | 2012-11-30 01:20:49 +0900 |
|---|---|---|
| committer | Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com> | 2012-11-30 01:20:49 +0900 |
| commit | b95f15b462a0481d3197409eb1ac552d17e53fb6 (patch) | |
| tree | 7aa993a8188fae2c86193102c7382a254a7f7d3f /src | |
| parent | 53dcfea6a8ef14491cbf04efa7d3fdcc802c43e7 (diff) | |
Use Win32 API for file I/O in AbstractDiskWriter
Now file has been opened by aria2 is now readable by other processes.
Diffstat (limited to 'src')
| -rw-r--r-- | src/AbstractDiskWriter.cc | 176 | ||||
| -rw-r--r-- | src/AbstractDiskWriter.h | 5 |
2 files changed, 140 insertions, 41 deletions
diff --git a/src/AbstractDiskWriter.cc b/src/AbstractDiskWriter.cc index 889c6696..085c9310 100644 --- a/src/AbstractDiskWriter.cc +++ b/src/AbstractDiskWriter.cc @@ -53,11 +53,17 @@ #include "error_code.h" #include "LogFactory.h" +#ifdef __MINGW32__ +# define A2_BAD_FILE_DESCRIPTOR INVALID_HANDLE_VALUE +#else // !__MINGW32__ +# define A2_BAD_FILE_DESCRIPTOR -1 +#endif // !__MINGW32__ + namespace aria2 { AbstractDiskWriter::AbstractDiskWriter(const std::string& filename) : filename_(filename), - fd_(-1), + fd_(A2_BAD_FILE_DESCRIPTOR), readOnly_(false), enableMmap_(false), mapaddr_(0), @@ -69,12 +75,51 @@ AbstractDiskWriter::~AbstractDiskWriter() closeFile(); } +namespace { +int fileError() +{ +#ifdef __MINGW32__ + return GetLastError(); +#else // !__MINGW32__ + return errno; +#endif // !__MINGW32__ +} +} // namespace + +namespace { +std::string fileStrerror(int errNum) +{ +#ifdef __MINGW32__ + static char buf[256]; + if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + 0, + errNum, + // Default language + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &buf, + sizeof(buf), + 0) == 0) { + snprintf(buf, sizeof(buf), "File IO error %x", errNum); + } + return buf; +#else // !__MINGW32__ + return util::safeStrerror(errNum); +#endif // !__MINGW32__ +} +} // namespace + void AbstractDiskWriter::openFile(int64_t totalLength) { try { openExistingFile(totalLength); } catch(RecoverableException& e) { - if(e.getErrNum() == ENOENT) { + if( +#ifdef __MINGW32__ + e.getErrNum() == ERROR_FILE_NOT_FOUND +#else // !__MINGW32__ + e.getErrNum() == ENOENT +#endif // !__MINGW32__ + ) { initAndOpenFile(totalLength); } else { throw; @@ -98,24 +143,61 @@ void AbstractDiskWriter::closeFile() maplen_ = 0; } #endif // HAVE_MMAP - if(fd_ != -1) { + if(fd_ != A2_BAD_FILE_DESCRIPTOR) { +#ifdef __MINGW32__ + CloseHandle(fd_); +#else // !__MINGW32__ close(fd_); - fd_ = -1; +#endif // !__MINGW32__ + fd_ = A2_BAD_FILE_DESCRIPTOR; } } namespace { +#ifdef __MINGW32__ +HANDLE openFileWithFlags(const std::string& filename, int flags, + error_code::Value errCode) +{ + HANDLE hn; + DWORD desiredAccess = 0, sharedMode = FILE_SHARE_READ, creationDisp = 0; + if(flags & O_RDONLY) { + desiredAccess |= GENERIC_READ; + } else if(flags & O_RDWR) { + desiredAccess |= GENERIC_READ | GENERIC_WRITE; + } + if(flags & O_CREAT) { + if(flags & O_TRUNC) { + creationDisp |= CREATE_ALWAYS; + } else { + creationDisp |= CREATE_NEW; + } + } else { + creationDisp |= OPEN_EXISTING; + } + hn = CreateFileW(utf8ToWChar(filename).c_str(), + desiredAccess, sharedMode, 0, creationDisp, + FILE_ATTRIBUTE_NORMAL, 0); + if(hn == INVALID_HANDLE_VALUE) { + int errNum = GetLastError(); + throw DL_ABORT_EX3(errNum, fmt(EX_FILE_OPEN, + filename.c_str(), + fileStrerror(errNum).c_str()), + errCode); + } + return hn; +} +#else // !__MINGW32__ int openFileWithFlags(const std::string& filename, int flags, error_code::Value errCode) { int fd; - while((fd = a2open(utf8ToWChar(filename).c_str(), flags, OPEN_MODE)) == -1 + while((fd = a2open(filename.c_str(), flags, OPEN_MODE)) == -1 && errno == EINTR); if(fd < 0) { int errNum = errno; throw DL_ABORT_EX3(errNum, fmt(EX_FILE_OPEN, filename.c_str(), - util::safeStrerror(errNum).c_str()), + fileStrerror(errNum).c_str()), errCode); } #if defined(__APPLE__) && defined(__MACH__) @@ -123,6 +205,7 @@ int openFileWithFlags(const std::string& filename, int flags, #endif // __APPLE__ && __MACH__ return fd; } +#endif // !__MINGW32__ } // namespace void AbstractDiskWriter::openExistingFile(int64_t totalLength) @@ -154,12 +237,19 @@ ssize_t AbstractDiskWriter::writeDataInternal(const unsigned char* data, ssize_t writtenLength = 0; seek(offset); while((size_t)writtenLength < len) { +#ifdef __MINGW32__ + DWORD ret; + if(!WriteFile(fd_, data, len, &ret, 0)) { + return -1; + } +#else // !__MINGW32__ ssize_t ret = 0; while((ret = write(fd_, data+writtenLength, len-writtenLength)) == -1 && errno == EINTR); if(ret == -1) { return -1; } +#endif // !__MINGW32__ writtenLength += ret; } return writtenLength; @@ -179,20 +269,34 @@ ssize_t AbstractDiskWriter::readDataInternal(unsigned char* data, size_t len, memcpy(data, mapaddr_ + offset, readlen); return readlen; } else { - ssize_t ret = 0; seek(offset); +#ifdef __MINGW32__ + DWORD ret; + if(!ReadFile(fd_, data, len, &ret, 0)) { + ret = -1; + } +#else // !__MINGW32__ + ssize_t ret = 0; while((ret = read(fd_, data, len)) == -1 && errno == EINTR); +#endif // !__MINGW32__ return ret; } } void AbstractDiskWriter::seek(int64_t offset) { +#ifdef __MINGW32__ + LARGE_INTEGER fileLength; + fileLength.QuadPart = offset; + if(SetFilePointerEx(fd_, fileLength, 0, FILE_BEGIN) == 0) { + int errNum = GetLastError(); +#else // !__MINGW32__ if(a2lseek(fd_, offset, SEEK_SET) == (off_t)-1) { int errNum = errno; +#endif // !__MINGW32__ throw DL_ABORT_EX2(fmt(EX_FILE_SEEK, filename_.c_str(), - util::safeStrerror(errNum).c_str()), + fileStrerror(errNum).c_str()), error_code::FILE_IO_ERROR); } } @@ -234,22 +338,25 @@ void AbstractDiskWriter::writeData(const unsigned char* data, size_t len, int64_ { ensureMmapWrite(len, offset); if(writeDataInternal(data, len, offset) < 0) { - int errNum = errno; - // If errno is ENOSPC(not enough space in device), throw + int errNum = fileError(); + // If errNum is ENOSPC(not enough space in device) (or + // ERROR_HANDLE_DISK_FULL on MinGW), throw // DownloadFailureException and abort download instantly. - if(errNum == ENOSPC) { + if( +#ifdef __MINGW32__ + errNum == ERROR_HANDLE_DISK_FULL +#else // !__MINGW32__ + errNum == ENOSPC +#endif // !__MINGW32__ + ) { throw DOWNLOAD_FAILURE_EXCEPTION3 (errNum, - fmt(EX_FILE_WRITE, - filename_.c_str(), - util::safeStrerror(errNum).c_str()), + fmt(EX_FILE_WRITE, filename_.c_str(), fileStrerror(errNum).c_str()), error_code::NOT_ENOUGH_DISK_SPACE); } else { throw DL_ABORT_EX3 (errNum, - fmt(EX_FILE_WRITE, - filename_.c_str(), - util::safeStrerror(errNum).c_str()), + fmt(EX_FILE_WRITE, filename_.c_str(), fileStrerror(errNum).c_str()), error_code::FILE_IO_ERROR); } } @@ -259,12 +366,10 @@ ssize_t AbstractDiskWriter::readData(unsigned char* data, size_t len, int64_t of { ssize_t ret; if((ret = readDataInternal(data, len, offset)) < 0) { - int errNum = errno; + int errNum = fileError(); throw DL_ABORT_EX3 (errNum, - fmt(EX_FILE_READ, - filename_.c_str(), - util::safeStrerror(errNum).c_str()), + fmt(EX_FILE_READ, filename_.c_str(), fileStrerror(errNum).c_str()), error_code::FILE_IO_ERROR); } return ret; @@ -272,15 +377,14 @@ ssize_t AbstractDiskWriter::readData(unsigned char* data, size_t len, int64_t of void AbstractDiskWriter::truncate(int64_t length) { - if(fd_ == -1) { - throw DL_ABORT_EX("File not opened."); + if(fd_ == A2_BAD_FILE_DESCRIPTOR) { + throw DL_ABORT_EX("File not yet opened."); } #ifdef __MINGW32__ - // Since mingw32's ftruncate cannot handle over 2GB files, we use SetEndOfFile - // instead. - HANDLE handle = LongToHandle(_get_osfhandle(fd_)); + // Since mingw32's ftruncate cannot handle over 2GB files, we use + // SetEndOfFile instead. seek(length); - if(SetEndOfFile(handle) == 0) { + if(SetEndOfFile(fd_) == 0) { throw DL_ABORT_EX2(fmt("SetEndOfFile failed. cause: %lx", GetLastError()), error_code::FILE_IO_ERROR); @@ -298,23 +402,13 @@ void AbstractDiskWriter::truncate(int64_t length) void AbstractDiskWriter::allocate(int64_t offset, int64_t length) { -#ifdef HAVE_SOME_FALLOCATE - if(fd_ == -1) { + if(fd_ == A2_BAD_FILE_DESCRIPTOR) { throw DL_ABORT_EX("File not yet opened."); } +#ifdef HAVE_SOME_FALLOCATE # ifdef __MINGW32__ - LARGE_INTEGER fileLength; - fileLength.QuadPart = offset+length; - HANDLE handle = LongToHandle(_get_osfhandle(fd_)); - int r; - r = SetFilePointerEx(handle, fileLength, 0, FILE_BEGIN); - if(r == 0) { - throw DL_ABORT_EX2(fmt("SetFilePointerEx failed. cause: %lx", - GetLastError()), - error_code::FILE_IO_ERROR); - } - r = SetEndOfFile(handle); - if(r == 0) { + seek(offset+length); + if(SetEndOfFile(fd_) == 0) { throw DL_ABORT_EX2(fmt("SetEndOfFile failed. cause: %lx", GetLastError()), error_code::FILE_IO_ERROR); diff --git a/src/AbstractDiskWriter.h b/src/AbstractDiskWriter.h index e5834aa1..282aaffd 100644 --- a/src/AbstractDiskWriter.h +++ b/src/AbstractDiskWriter.h @@ -43,7 +43,12 @@ namespace aria2 { class AbstractDiskWriter : public DiskWriter { private: std::string filename_; + +#ifdef __MINGW32__ + HANDLE fd_; +#else // !__MINGW32__ int fd_; +#endif // !__MINGW32__ bool readOnly_; |
