/mysql-workbench-gpl-5.2.40-src/library/base/file_utilities.cpp
C++ | 466 lines | 384 code | 42 blank | 40 comment | 76 complexity | 51dd3b7a400e56d8ff7d17272da572cf MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, LGPL-2.1, BSD-3-Clause-No-Nuclear-License-2014, BSD-3-Clause
- /*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
- #include "base/string_utilities.h"
- #include "base/file_utilities.h"
- #include <stdexcept>
- #include <glib.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <glib/gstdio.h>
- #ifdef _WIN32
- #include <windows.h>
- #else
- #include <errno.h>
- #include <fcntl.h>
- #include <sys/file.h>
- #endif
- namespace base {
-
- std::string format_file_error(const std::string &text, int err)
- {
- #ifdef _WIN32
- return strfmt("%s: error code %i", text.c_str(), err);
- #else
- return strfmt("%s: %s", text.c_str(), strerror(err));
- #endif
- }
- file_error::file_error(const std::string &text, int err)
- : std::runtime_error(format_file_error(text, err)), sys_error_code(err)
- {
- }
-
- error_code file_error::code()
- {
- #ifdef _WIN32
- switch (sys_error_code)
- {
- case 0:
- return success;
- case ERROR_FILE_NOT_FOUND:
- case ERROR_PATH_NOT_FOUND:
- return file_not_found;
- case ERROR_ALREADY_EXISTS:
- return already_exists;
- case ERROR_ACCESS_DENIED:
- return access_denied;
- default:
- return other_error;
- }
- #else
- switch (sys_error_code)
- {
- case 0:
- return success;
- case ENOENT:
- return file_not_found;
- case EEXIST:
- return already_exists;
- case EACCES:
- return access_denied;
- default:
- return other_error;
- }
- #endif
- }
-
- //--------------------------------------------------------------------------------------------------
- std::list<std::string> scan_for_files_matching(const std::string &pattern, bool recursive)
- {
- std::list<std::string> matches;
- gchar *path = g_dirname(pattern.c_str());
- if (!g_file_test(path, G_FILE_TEST_EXISTS))
- {
- g_free(path);
- return matches;
- }
- std::string pure_pattern = pattern.substr(strlen(path) + 1);
- GPatternSpec *pat = g_pattern_spec_new(g_basename(pattern.c_str()));
- GDir *dir;
- {
- GError *err = NULL;
- dir = g_dir_open(path ? path : ".", 0, &err);
- if (!dir)
- {
- std::string msg = strfmt("can't open %s: %s", path ? path : ".", err->message);
- g_error_free(err);
- g_pattern_spec_free(pat);
- throw std::runtime_error(msg);
- }
- }
- const gchar *filename;
- while ((filename = g_dir_read_name(dir)))
- {
- std::string full_path = strfmt("%s%s%s", path, G_DIR_SEPARATOR_S, filename);
- if (g_pattern_match_string(pat, filename))
- matches.push_back(full_path);
- if (recursive && g_file_test(full_path.c_str(), G_FILE_TEST_IS_DIR))
- {
- std::string subpattern = strfmt("%s%s%s", full_path.c_str(), G_DIR_SEPARATOR_S, pure_pattern.c_str());
- std::list<std::string> submatches = scan_for_files_matching(subpattern, true);
- if (submatches.size() > 0)
- matches.insert(matches.end(), submatches.begin(), submatches.end());
- }
- }
- g_dir_close(dir);
- g_pattern_spec_free(pat);
- return matches;
- }
- //--------------------------------------------------------------------------------------------------
- #ifdef _WIN32
- LockFile::LockFile(const std::string &path) throw (std::invalid_argument, std::runtime_error, file_locked_error)
- : path(path), handle(0)
- {
- std::wstring wpath(string_to_wstring(path));
- if (path.empty()) throw std::invalid_argument("invalid path");
- handle = CreateFileW(wpath.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL,
- OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- if (handle == INVALID_HANDLE_VALUE)
- {
- if (GetLastError() == ERROR_SHARING_VIOLATION)
- throw file_locked_error("File already locked");
- throw std::runtime_error(strfmt("Error creating lock file (%i)", GetLastError()));
- }
- char buffer[32];
- sprintf(buffer, "%i", GetCurrentProcessId());
- DWORD bytes_written;
- if (!WriteFile(handle, buffer, strlen(buffer), &bytes_written, NULL) || bytes_written != strlen(buffer))
- {
- CloseHandle(handle);
- DeleteFileW(wpath.c_str());
- throw std::runtime_error("Could not write to lock file");
- }
- }
-
- LockFile::~LockFile()
- {
- if (handle)
- CloseHandle(handle);
- DeleteFileW(string_to_wstring(path).c_str());
- }
-
- LockFile::Status LockFile::check(const std::string &path)
- {
- std::wstring wpath(string_to_wstring(path));
- // open the file and see if it's locked
- HANDLE h = CreateFileW(wpath.c_str(),
- GENERIC_WRITE,
- FILE_SHARE_WRITE|FILE_SHARE_READ,
- NULL,
- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
- if (h == INVALID_HANDLE_VALUE)
- {
- switch (GetLastError())
- {
- case ERROR_SHARING_VIOLATION:
- // if file cannot be opened for writing, it is locked...
- // so open it for reading to check the owner process id written in it
- h = CreateFileW(wpath.c_str(),
- GENERIC_READ,
- FILE_SHARE_WRITE|FILE_SHARE_READ,
- NULL,
- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
- if (h != INVALID_HANDLE_VALUE)
- {
- char buffer[32];
- DWORD bytes_read;
- if (ReadFile(h, buffer, sizeof(buffer), &bytes_read, NULL))
- {
- CloseHandle(h);
- buffer[bytes_read]= 0;
- if (atoi(buffer) == GetCurrentProcessId())
- return LockedSelf;
- return LockedOther;
- }
- CloseHandle(h);
- return LockedOther;
- }
- // if the file is locked for read, assume its locked by some unrelated process
- // since this class never locks it for read
- return LockedOther;
- //throw std::runtime_error(strfmt("Could not read process id from lock file (%i)", GetLastError());
- break;
- case ERROR_FILE_NOT_FOUND:
- return NotLocked;
- case ERROR_PATH_NOT_FOUND:
- throw std::invalid_argument("Invalid path");
- default:
- throw std::runtime_error(strfmt("Could not open lock file (%i)", GetLastError()));
- }
- }
- else
- {
- CloseHandle(h);
- // if the file could be opened with DENY_WRITE, it means no-one is locking it
- return NotLocked;
- }
- }
- #else
- LockFile::LockFile(const std::string &apath) throw (std::invalid_argument, std::runtime_error, file_locked_error)
- : path(apath)
- {
- if (path.empty()) throw std::invalid_argument("invalid path");
-
- fd = open(path.c_str(), O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
- if (fd < 0)
- {
- // this could mean lock exists, that it's a dangling file or that it's currently being locked by some other process/thread
- // we just go on and try to lock the file if the file already exists
- if (errno == ENOENT || errno == ENOTDIR)
- throw std::invalid_argument("invalid path");
-
- throw std::runtime_error(strfmt("%s creating lock file", g_strerror(errno)));
- }
- if (flock(fd, LOCK_EX|LOCK_NB) < 0)
- {
- close(fd);
- fd = -1;
- if (errno == EWOULDBLOCK)
- throw file_locked_error("file already locked");
- throw std::runtime_error(strfmt("%s while locking file", g_strerror(errno)));
- }
- ftruncate(fd, 0);
- char pid[32];
- snprintf(pid, sizeof(pid), "%i", getpid());
- if (write(fd, pid, strlen(pid)+1) < 0)
- {
- close(fd);
- throw std::runtime_error(strfmt("%s while locking file", g_strerror(errno)));
- }
- }
-
- LockFile::~LockFile()
- {
- if (fd >= 0)
- close(fd);
- unlink(path.c_str());
- }
-
- LockFile::Status LockFile::check(const std::string &path)
- {
- int fd = open(path.c_str(), O_RDONLY);
- if (fd < 0)
- return NotLocked;
- if (flock(fd, LOCK_EX|LOCK_NB) < 0)
- {
- char pid[32];
- // couldn't lock file, check if we own it ourselves
- int c = read(fd, pid, sizeof(pid)-1);
- close(fd);
- if (c < 0)
- return LockedOther;
- pid[c] = 0;
- if (atoi(pid) != getpid())
- return LockedOther;
- return LockedSelf;
- }
- else // nobody holds a lock on the file, so this is a leftover
- {
- flock(fd, LOCK_UN);
- close(fd);
- return NotLocked;
- }
- }
- #endif
- bool create_directory(const std::string &path, int mode)
- {
- #ifdef _WIN32
- if (!CreateDirectoryW(path_from_utf8(path).c_str(), NULL))
- {
- if (GetLastError() == ERROR_ALREADY_EXISTS)
- return false;
- throw file_error(strfmt("Could not create directory %s",
- path.c_str()), GetLastError());
- }
- #else
- if (g_mkdir(path_from_utf8(path).c_str(), mode) < 0)
- {
- if (errno == EEXIST)
- return false;
- throw file_error(strfmt("Could not create directory %s",
- path.c_str()), errno);
- }
- #endif
- return true;
- }
-
- void rename(const std::string &from, const std::string &to)
- {
- #ifdef _WIN32
- if (!MoveFile(path_from_utf8(from).c_str(), path_from_utf8(to).c_str()))
- throw file_error(strfmt("Could not rename file %s to %s", from.c_str(), to.c_str()), GetLastError());
- #else
- if (::g_rename(path_from_utf8(from).c_str(), path_from_utf8(to).c_str()) < 0)
- throw file_error(strfmt("Could not rename file %s to %s", from.c_str(), to.c_str()), errno);
- #endif
- }
- bool remove_recursive(const std::string &path)
- {
- GError *error= NULL;
- GDir* dir;
- const char *dir_entry;
- gchar *entry_path;
-
- dir= g_dir_open(path.c_str(), 0, &error);
- if (!dir && error)
- return false;
-
- while ((dir_entry= g_dir_read_name(dir)))
- {
- entry_path= g_build_filename(path.c_str(), dir_entry, NULL);
- if (g_file_test(entry_path, G_FILE_TEST_IS_DIR))
- (void) remove_recursive(entry_path);
- else
- (void) ::g_remove(entry_path);
- g_free(entry_path);
- }
-
- (void) g_rmdir(path.c_str());
-
- g_dir_close(dir);
- return true;
- }
-
- bool remove(const std::string &path)
- {
- #ifdef _WIN32
- if (is_directory(path))
- {
- if (!RemoveDirectoryW(path_from_utf8(path).c_str()))
- {
- if (GetLastError() == ERROR_FILE_NOT_FOUND
- || GetLastError() == ERROR_PATH_NOT_FOUND)
- return false;
- throw file_error(strfmt("Could not delete file %s", path.c_str()), GetLastError());
- }
- }
- else
- {
- if (!DeleteFileW(path_from_utf8(path).c_str()))
- {
- if (GetLastError() == ERROR_FILE_NOT_FOUND)
- return false;
- throw file_error(strfmt("Could not delete file %s", path.c_str()), GetLastError());
- }
- }
- #else
- if (::g_remove(path_from_utf8(path).c_str()) < 0)
- {
- if (errno == ENOENT)
- return false;
- throw file_error(strfmt("Could not delete file %s", path.c_str()), errno);
- }
- #endif
- return true;
- }
-
- bool file_exists(const std::string &path)
- {
- char *f = g_filename_from_utf8(path.c_str(), -1, NULL, NULL, NULL);
- if (g_file_test(f, G_FILE_TEST_EXISTS))
- {
- g_free(f);
- return true;
- }
- g_free(f);
- return false;
- }
- bool is_directory(const std::string &path)
- {
- char *f = g_filename_from_utf8(path.c_str(), -1, NULL, NULL, NULL);
- if (g_file_test(f, G_FILE_TEST_IS_DIR))
- {
- g_free(f);
- return true;
- }
- g_free(f);
- return false;
- }
- /*
- std::string make_path(const std::string &path, const std::string &filename)
- {
- if (path.empty())
- return filename;
-
- if (path[path.size()-1] == '/' || path[path.size()-1] == '\\')
- return path+filename;
- return path+G_DIR_SEPARATOR+filename;
- }*/
-
- std::string extension(const std::string &path)
- {
- std::string::size_type p = path.rfind('.');
- if (p != std::string::npos)
- {
- std::string ext(path.substr(p));
- if (ext.find('/') != std::string::npos || ext.find('\\') != std::string::npos)
- return "";
- return ext;
- }
- return "";
- }
-
- std::string dirname(const std::string &path)
- {
- char *dn = g_path_get_dirname(path.c_str());
- std::string tmp(dn);
- g_free(dn);
- return tmp;
- }
-
- std::string basename(const std::string &path)
- {
- char *dn = g_path_get_basename(path.c_str());
- std::string tmp(dn);
- g_free(dn);
- return tmp;
- }
-
- std::string strip_extension(const std::string &path)
- {
- std::string ext;
- if (!(ext = extension(path)).empty())
- {
- return path.substr(0, path.size() - ext.size());
- }
- return path;
- }
- };