aboutsummaryrefslogtreecommitdiff
path: root/butl
diff options
context:
space:
mode:
Diffstat (limited to 'butl')
-rw-r--r--butl/buildfile41
-rw-r--r--butl/filesystem35
-rw-r--r--butl/filesystem.cxx61
-rw-r--r--butl/pager.cxx7
-rw-r--r--butl/path.cxx50
-rw-r--r--butl/process.cxx49
-rw-r--r--butl/win32-utility52
-rw-r--r--butl/win32-utility.cxx51
8 files changed, 235 insertions, 111 deletions
diff --git a/butl/buildfile b/butl/buildfile
index db33ef7..5c939af 100644
--- a/butl/buildfile
+++ b/butl/buildfile
@@ -2,26 +2,27 @@
# copyright : Copyright (c) 2014-2016 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
-lib{butl}: \
-{hxx cxx}{ base64 } \
-{hxx cxx}{ char-scanner } \
-{hxx cxx}{ fdstream } \
-{hxx ixx cxx}{ filesystem } \
-{hxx }{ multi-index } \
-{hxx }{ optional } \
-{hxx cxx}{ pager } \
-{hxx ixx txx cxx}{ path } \
-{hxx }{ path-io } \
-{hxx }{ path-map } \
-{hxx txx }{ prefix-map } \
-{hxx ixx cxx}{ process } \
-{hxx cxx}{ sha256 } \
-{hxx txx }{ string-table } \
-{hxx cxx}{ timestamp } \
-{hxx cxx}{ triplet } \
-{hxx }{ utility } \
-{hxx }{ vector-view } \
-{hxx }{ version }
+lib{butl}: \
+{hxx cxx}{ base64 } \
+{hxx cxx}{ char-scanner } \
+{hxx cxx}{ fdstream } \
+{hxx ixx cxx}{ filesystem } \
+{hxx }{ multi-index } \
+{hxx }{ optional } \
+{hxx cxx}{ pager } \
+{hxx ixx txx cxx}{ path } \
+{hxx }{ path-io } \
+{hxx }{ path-map } \
+{hxx txx }{ prefix-map } \
+{hxx ixx cxx}{ process } \
+{hxx cxx}{ sha256 } \
+{hxx txx }{ string-table } \
+{hxx cxx}{ timestamp } \
+{hxx cxx}{ triplet } \
+{hxx }{ utility } \
+{hxx }{ vector-view } \
+{hxx }{ version } \
+{hxx cxx}{ win32-utility }
# This one is included into sha256.cxx so treat it as file to exclude
# from the compilation.
diff --git a/butl/filesystem b/butl/filesystem
index ab39f36..565f465 100644
--- a/butl/filesystem
+++ b/butl/filesystem
@@ -120,6 +120,41 @@ namespace butl
using auto_rmfile = auto_rm<path>;
using auto_rmdir = auto_rm<dir_path>; // Note: recursive (rm_r).
+ // Create a symbolic link to a file (default) or directory (third argument
+ // is true). Throw std::system_error on failures.
+ //
+ // Note that Windows symlinks are currently not supported.
+ //
+ void
+ mksymlink (const path& target, const path& link, bool dir = false);
+
+ // Create a symbolic link to a directory. Throw std::system_error on
+ // failures.
+ //
+ inline void
+ mksymlink (const dir_path& target, const dir_path& link)
+ {
+ mksymlink (target, link, true);
+ }
+
+ // Create a hard link to a file (default) or directory (third argument is
+ // true). Throw std::system_error on failures.
+ //
+ // Note that on Linix, FreeBSD and some other platforms the target can not
+ // be a directory. While Windows support directories (via junktions), this
+ // is currently not implemented.
+ //
+ void
+ mkhardlink (const path& target, const path& link, bool dir = false);
+
+ // Create a hard link to a directory. Throw std::system_error on failures.
+ //
+ inline void
+ mkhardlink (const dir_path& target, const dir_path& link)
+ {
+ mkhardlink (target, link, true);
+ }
+
// Return timestamp_nonexistent if the entry at the specified path
// does not exist or is not a path. All other errors are reported
// by throwing std::system_error. Note that this function resolves
diff --git a/butl/filesystem.cxx b/butl/filesystem.cxx
index a2d6434..c3d21cd 100644
--- a/butl/filesystem.cxx
+++ b/butl/filesystem.cxx
@@ -4,18 +4,23 @@
#include <butl/filesystem>
-#include <errno.h> // errno, E*
-#include <unistd.h> // stat, rmdir(), unlink()
-#include <sys/types.h> // stat
-#include <sys/stat.h> // stat(), lstat(), S_IS*, mkdir()
-
#ifndef _WIN32
# include <dirent.h> // struct dirent, *dir()
+# include <unistd.h> // symlink(), link()
#else
-# include <io.h> // _find*()
-# include <direct.h> // _mkdir()
+# include <butl/win32-utility>
+
+# include <io.h> // _find*()
+# include <direct.h> // _mkdir()
+
+# include <cassert>
#endif
+#include <errno.h> // errno, E*
+#include <unistd.h> // stat, rmdir(), unlink()
+#include <sys/types.h> // stat
+#include <sys/stat.h> // stat(), lstat(), S_IS*, mkdir()
+
#include <memory> // unique_ptr
#include <system_error>
@@ -152,6 +157,48 @@ namespace butl
return r;
}
+#ifndef _WIN32
+ void
+ mksymlink (const path& target, const path& link, bool)
+ {
+ if (symlink (target.string ().c_str (), link.string ().c_str ()) == -1)
+ throw system_error (errno, system_category ());
+ }
+
+ void
+ mkhardlink (const path& target, const path& link, bool)
+ {
+ if (::link (target.string ().c_str (), link.string ().c_str ()) == -1)
+ throw system_error (errno, system_category ());
+ }
+
+#else
+
+ void
+ mksymlink (const path&, const path&, bool)
+ {
+ throw system_error (ENOSYS, system_category (), "symlinks not supported");
+ }
+
+ void
+ mkhardlink (const path& target, const path& link, bool dir)
+ {
+ if (!dir)
+ {
+ if (!CreateHardLinkA (link.string ().c_str (),
+ target.string ().c_str (),
+ nullptr))
+ {
+ string e (win32::last_error_msg ());
+ throw system_error (EIO, system_category (), e);
+ }
+ }
+ else
+ throw system_error (
+ ENOSYS, system_category (), "directory hard links not supported");
+ }
+#endif
+
// Figuring out whether we have the nanoseconds in struct stat. Some
// platforms (e.g., FreeBSD), may provide some "compatibility" #define's,
// so use the second argument to not end up with the same signatures.
diff --git a/butl/pager.cxx b/butl/pager.cxx
index 9999bb0..0f29bb4 100644
--- a/butl/pager.cxx
+++ b/butl/pager.cxx
@@ -11,11 +11,8 @@
# include <chrono>
# include <thread> // this_thread::sleep_for()
#else
-# ifndef WIN32_LEAN_AND_MEAN
-# define WIN32_LEAN_AND_MEAN
-# endif
-# include <windows.h> // GetConsoleScreenBufferInfo(), GetStdHandle(),
- // Sleep()
+# include <butl/win32-utility>
+
# include <io.h> // _close()
#endif
diff --git a/butl/path.cxx b/butl/path.cxx
index 92b0d6c..1693c86 100644
--- a/butl/path.cxx
+++ b/butl/path.cxx
@@ -5,15 +5,12 @@
#include <butl/path>
#ifdef _WIN32
+# include <butl/win32-utility>
+
# include <stdlib.h> // _MAX_PATH, _wgetenv()
# include <direct.h> // _[w]getcwd(), _[w]chdir()
-# ifndef WIN32_LEAN_AND_MEAN
-# define WIN32_LEAN_AND_MEAN
-# endif
-# include <windows.h> // GetTempPath*(), FormatMessageA(), LocalFree()
# include <shlobj.h> // SHGetFolderPath*(), CSIDL_PROFILE
# include <winerror.h> // SUCCEEDED()
-# include <memory> // unique_ptr
#else
# include <pwd.h> // struct passwd, getpwuid_r()
# include <errno.h> // EINVAL
@@ -23,6 +20,7 @@
# include <string.h> // strlen(), strcpy()
# include <sys/stat.h> // stat(), S_IS*
# include <sys/types.h> // stat
+
# include <vector>
#endif
@@ -40,6 +38,10 @@
using namespace std;
+#ifdef _WIN32
+using namespace butl::win32;
+#endif
+
namespace butl
{
char const* invalid_path_base::
@@ -84,39 +86,7 @@ namespace butl
#endif
}
-#ifdef _WIN32
- struct msg_deleter
- {
- void operator() (char* p) const {LocalFree (p);}
- };
-
- static string
- error_msg (DWORD e)
- {
- char* msg;
- if (!FormatMessageA (
- FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS |
- FORMAT_MESSAGE_MAX_WIDTH_MASK,
- 0,
- e,
- MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
- (char*)&msg,
- 0,
- 0))
- return "unknown error code " + to_string (e);
-
- unique_ptr<char, msg_deleter> m (msg);
- return msg;
- }
-
- inline static string
- last_error ()
- {
- return error_msg (GetLastError ());
- }
-#else
+#ifndef _WIN32
static const char*
temp_directory ()
{
@@ -179,7 +149,7 @@ namespace butl
if (r == 0)
{
- string e (last_error ());
+ string e (last_error_msg ());
throw system_error (ENOTDIR, system_category (), e);
}
@@ -301,7 +271,7 @@ namespace butl
if (r == 0)
{
- string e (last_error ());
+ string e (last_error_msg ());
throw system_error (ENOTDIR, system_category (), e);
}
#else
diff --git a/butl/process.cxx b/butl/process.cxx
index 588c0b6..aaab915 100644
--- a/butl/process.cxx
+++ b/butl/process.cxx
@@ -8,10 +8,8 @@
# include <unistd.h> // execvp, fork, dup2, pipe, chdir, *_FILENO, getpid
# include <sys/wait.h> // waitpid
#else
-# ifndef WIN32_LEAN_AND_MEAN
-# define WIN32_LEAN_AND_MEAN
-# endif
-# include <windows.h> // CreatePipe(), CreateProcess()
+# include <butl/win32-utility>
+
# include <io.h> // _open_osfhandle(), _get_osfhandle(), _close()
# include <fcntl.h> // _O_TEXT
# include <stdlib.h> // getenv()
@@ -21,6 +19,7 @@
# include <memory> // unique_ptr
# include <butl/path>
+# include <butl/win32-utility>
#endif
#include <cassert>
@@ -29,6 +28,10 @@
using namespace std;
+#ifdef _WIN32
+using namespace butl::win32;
+#endif
+
namespace butl
{
class auto_fd
@@ -226,38 +229,6 @@ namespace butl
#else // _WIN32
- struct msg_deleter
- {
- void operator() (char* p) const {LocalFree (p);}
- };
-
- static string
- error (DWORD e)
- {
- char* msg;
- if (!FormatMessageA (
- FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS |
- FORMAT_MESSAGE_MAX_WIDTH_MASK,
- 0,
- e,
- MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
- (char*)&msg,
- 0,
- 0))
- return "unknown error code " + to_string (e);
-
- unique_ptr<char, msg_deleter> m (msg);
- return msg;
- }
-
- static inline string
- last_error ()
- {
- return error (GetLastError ());
- }
-
static path
path_search (const path& f)
{
@@ -383,7 +354,7 @@ namespace butl
auto fail = [](const char* m = nullptr)
{
- throw process_error (m == nullptr ? last_error () : m);
+ throw process_error (m == nullptr ? last_error_msg () : m);
};
// Create a pipe and clear the inherit flag on the parent side.
@@ -605,7 +576,7 @@ namespace butl
handle = 0; // We have tried.
if (e != NO_ERROR)
- throw process_error (error (e));
+ throw process_error (error_msg (e));
status = s;
}
@@ -631,7 +602,7 @@ namespace butl
handle = 0; // We have tried.
if (e != NO_ERROR)
- throw process_error (error (e));
+ throw process_error (error_msg (e));
status = s;
}
diff --git a/butl/win32-utility b/butl/win32-utility
new file mode 100644
index 0000000..c74eb66
--- /dev/null
+++ b/butl/win32-utility
@@ -0,0 +1,52 @@
+// file : butl/win32-utility -*- C++ -*-
+// copyright : Copyright (c) 2014-2016 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#ifndef BUTL_WIN32_UTILITY
+#define BUTL_WIN32_UTILITY
+
+// Use this header to include <windows.h> and a couple of Win32-specific
+// utilities.
+//
+
+#ifdef _WIN32
+
+// Try to include <windows.h> so that it doesn't mess other things up.
+//
+#ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# ifndef NOMINMAX // No min and max macros.
+# define NOMINMAX
+# include <windows.h>
+# undef NOMINMAX
+# else
+# include <windows.h>
+# endif
+# undef WIN32_LEAN_AND_MEAN
+#else
+# ifndef NOMINMAX
+# define NOMINMAX
+# include <windows.h>
+# undef NOMINMAX
+# else
+# include <windows.h>
+# endif
+#endif
+
+#include <string>
+
+namespace butl
+{
+ namespace win32
+ {
+ std::string
+ error_msg (DWORD code);
+
+ std::string
+ last_error_msg ();
+ }
+};
+
+#endif // _WIN32
+
+#endif // BUTL_WIN32_UTILITY
diff --git a/butl/win32-utility.cxx b/butl/win32-utility.cxx
new file mode 100644
index 0000000..cf44d4d
--- /dev/null
+++ b/butl/win32-utility.cxx
@@ -0,0 +1,51 @@
+// file : butl/win32-utility.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2016 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <butl/win32-utility>
+
+#ifdef _WIN32
+
+#include <memory> // unique_ptr
+
+using namespace std;
+
+namespace butl
+{
+ namespace win32
+ {
+ struct msg_deleter
+ {
+ void operator() (char* p) const {LocalFree (p);}
+ };
+
+ string
+ error_msg (DWORD code)
+ {
+ char* msg;
+ if (!FormatMessageA (
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS |
+ FORMAT_MESSAGE_MAX_WIDTH_MASK,
+ 0,
+ code,
+ MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (char*)&msg,
+ 0,
+ 0))
+ return "unknown error code " + to_string (code);
+
+ unique_ptr<char, msg_deleter> m (msg);
+ return msg;
+ }
+
+ string
+ last_error_msg ()
+ {
+ return error_msg (GetLastError ());
+ }
+ }
+}
+
+#endif // _WIN32