From 0eab0ebd9469601638a7c8bfa24daecd5110d26f Mon Sep 17 00:00:00 2001 From: Adam Reichold Date: Sat, 26 Dec 2015 14:35:36 +0100 Subject: [PATCH] Move the two low-level file I/O helper to their respective single place of usage. --- rtengine/imageio.cc | 38 +++++++++++++++++++++++++++++----- rtengine/myfile.cc | 20 +++++++++++++++++- rtengine/safegtk.cc | 50 --------------------------------------------- rtengine/safegtk.h | 6 +----- 4 files changed, 53 insertions(+), 61 deletions(-) diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc index 32f28a868..29946bafb 100644 --- a/rtengine/imageio.cc +++ b/rtengine/imageio.cc @@ -47,9 +47,37 @@ using namespace std; using namespace rtengine; using namespace rtengine::procparams; -Glib::ustring safe_locale_to_utf8 (const std::string& src); -Glib::ustring ImageIO::errorMsg[6] = {"Success", "Cannot read file.", "Invalid header.", "Error while reading header.", "File reading error", "Image format not supported."}; +namespace +{ +// Opens a file for binary writing and request exclusive lock (cases were you need "wb" mode plus locking) +FILE* g_fopen_withBinaryAndLock(const Glib::ustring& fname) +{ + FILE* f = NULL; + +#ifdef WIN32 + + // Use native function to disallow sharing, i.e. lock the file for exclusive access. + // This is important to e.g. prevent Windows Explorer from crashing RT due to concurrently scanning an image file. + std::unique_ptr wfname (reinterpret_cast(g_utf8_to_utf16 (fname.c_str (), -1, NULL, NULL, NULL)), g_free); + + HANDLE hFile = CreateFileW ( wfname.get (), GENERIC_READ | GENERIC_WRITE, 0 /* no sharing allowed */, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile != INVALID_HANDLE_VALUE) { + f = _fdopen (_open_osfhandle ((intptr_t)hFile, 0), "wb"); + } + +#else + + f = ::g_fopen (fname.c_str (), "wb"); + +#endif + + return f; +} + +} + +Glib::ustring ImageIO::errorMsg[6] = {"Success", "Cannot read file.", "Invalid header.", "Error while reading header.", "File reading error", "Image format not supported."}; // For only copying the raw input data void ImageIO::setMetadata (const rtexif::TagDirectory* eroot) @@ -888,7 +916,7 @@ int ImageIO::loadPPMFromMemory(const char* buffer, int width, int height, bool s int ImageIO::savePNG (Glib::ustring fname, int compression, volatile int bps) { - FILE *file = safe_g_fopen_WriteBinLock (fname); + FILE *file = g_fopen_withBinaryAndLock (fname); if (!file) { return IMIO_CANNOTWRITEFILE; @@ -982,7 +1010,7 @@ int ImageIO::savePNG (Glib::ustring fname, int compression, volatile int bps) int ImageIO::saveJPEG (Glib::ustring fname, int quality, int subSamp) { - FILE *file = safe_g_fopen_WriteBinLock (fname); + FILE *file = g_fopen_withBinaryAndLock (fname); if (!file) { return IMIO_CANNOTWRITEFILE; @@ -1183,7 +1211,7 @@ int ImageIO::saveTIFF (Glib::ustring fname, int bps, bool uncompressed) // TODO the following needs to be looked into - do we really need two ways to write a Tiff file ? if (exifRoot && uncompressed) { - FILE *file = safe_g_fopen_WriteBinLock (fname); + FILE *file = g_fopen_withBinaryAndLock (fname); if (!file) { delete [] linebuffer; diff --git a/rtengine/myfile.cc b/rtengine/myfile.cc index 1ff457234..729466f79 100644 --- a/rtengine/myfile.cc +++ b/rtengine/myfile.cc @@ -68,7 +68,25 @@ int munmap(void *start, size_t length) IMFILE* fopen (const char* fname) { - int fd = safe_open_ReadOnly(fname); + int fd = -1; + +#ifdef WIN32 + + { + // First convert UTF8 to UTF16, then use Windows function to open the file and convert back to file descriptor. + std::unique_ptr wfname (reinterpret_cast(g_utf8_to_utf16 (fname, -1, NULL, NULL, NULL)), g_free); + + HANDLE hFile = CreateFileW (wfname.get (), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile != INVALID_HANDLE_VALUE) { + fd = _open_osfhandle((intptr_t)hFile, 0); + } + } + +#else + + fd = ::g_open (fname, O_RDONLY); + +#endif if ( fd < 0 ) { return 0; diff --git a/rtengine/safegtk.cc b/rtengine/safegtk.cc index ef15a4d3a..a21590edb 100644 --- a/rtengine/safegtk.cc +++ b/rtengine/safegtk.cc @@ -80,56 +80,6 @@ std::string safe_locale_from_utf8 (const Glib::ustring& utf8_str) return str; } -// Opens a file for binary writing and request exclusive lock (cases were you need "wb" mode plus locking) -// (Important on Windows to prevent Explorer to crash RT when parallel scanning e.g. a currently written image file) -FILE * safe_g_fopen_WriteBinLock(const Glib::ustring& fname) -{ - FILE* f = NULL; - -#ifdef WIN32 - // g_fopen just uses _wfopen internally on Windows, does not lock access and has no options to set this - // so use a native function to work around this problem - wchar_t *wFname = (wchar_t*)g_utf8_to_utf16 (fname.c_str(), -1, NULL, NULL, NULL); - HANDLE hFile = CreateFileW(wFname, GENERIC_READ | GENERIC_WRITE, 0 /* no sharing allowed */, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - g_free(wFname); - - if (hFile == INVALID_HANDLE_VALUE) { - f = NULL; - } else { - f = _fdopen( _open_osfhandle((intptr_t)hFile, 0) , "wb"); - } - -#else - f = safe_g_fopen(fname, "wb"); -#endif - - return f; -} - -// Covers old UNIX ::open, which expects ANSI instead of UTF8 on Windows -int safe_open_ReadOnly(const char *fname) -{ - int fd = -1; - -#ifdef WIN32 - // First convert UTF8 to UTF16, then use Windows function to open - wchar_t *wFname = (wchar_t*)g_utf8_to_utf16 (fname, -1, NULL, NULL, NULL); - HANDLE hFile = CreateFileW(wFname, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - g_free(wFname); - - // convert back to old file descriptor format - if (hFile != INVALID_HANDLE_VALUE) { - fd = _open_osfhandle((intptr_t)hFile, 0); - } - -#else - fd = ::open(fname, O_RDONLY); -#endif - - return fd; -} - - FILE * safe_g_fopen(const Glib::ustring& src, const gchar *mode) { return g_fopen(src.c_str(), mode); diff --git a/rtengine/safegtk.h b/rtengine/safegtk.h index 560f1700c..60d57686f 100644 --- a/rtengine/safegtk.h +++ b/rtengine/safegtk.h @@ -6,12 +6,8 @@ #include Glib::ustring safe_filename_to_utf8 (const std::string& src); -Glib::ustring safe_locale_to_utf8 (const std::string& src); // from rtengine +Glib::ustring safe_locale_to_utf8 (const std::string& src); std::string safe_locale_from_utf8 (const Glib::ustring& utf8_str); -std::string safe_filename_from_utf8 (const Glib::ustring& utf8_str); - -FILE * safe_g_fopen_WriteBinLock(const Glib::ustring& fname); -int safe_open_ReadOnly(const char *fname); FILE * safe_g_fopen(const Glib::ustring& src, const gchar *mode); bool safe_file_test (const Glib::ustring& filename, Glib::FileTest test);