1 // operations.cpp --------------------------------------------------------------------//
3 // Copyright 2002-2009, 2014 Beman Dawes
4 // Copyright 2001 Dietmar Kuehl
6 // Distributed under the Boost Software License, Version 1.0.
7 // See http://www.boost.org/LICENSE_1_0.txt
9 // See library home page at http://www.boost.org/libs/filesystem
11 //--------------------------------------------------------------------------------------//
13 // define 64-bit offset macros BEFORE including boost/config.hpp (see ticket #5355)
14 #if !(defined(__HP_aCC) && defined(_ILP32) && !defined(_STATVFS_ACPP_PROBLEMS_FIXED))
15 #define _FILE_OFFSET_BITS 64 // at worst, these defines may have no effect,
18 #define __USE_FILE_OFFSET64 // but that is harmless on Windows and on POSIX
19 // 64-bit systems or on 32-bit systems which don't have files larger
20 // than can be represented by a traditional POSIX/UNIX off_t type.
21 // OTOH, defining them should kick in 64-bit off_t's (and thus
22 // st_size)on 32-bit systems that provide the Large File
23 // Support (LFS)interface, such as Linux, Solaris, and IRIX.
24 // The defines are given before any headers are included to
25 // ensure that they are available to all included headers.
26 // That is required at least on Solaris, and possibly on other
29 #define _FILE_OFFSET_BITS 64
32 // define BOOST_FILESYSTEM_SOURCE so that <boost/filesystem/config.hpp> knows
33 // the library is being built (possibly exporting rather than importing code)
34 #define BOOST_FILESYSTEM_SOURCE
36 #ifndef BOOST_SYSTEM_NO_DEPRECATED
37 # define BOOST_SYSTEM_NO_DEPRECATED
40 #ifndef _POSIX_PTHREAD_SEMANTICS
41 # define _POSIX_PTHREAD_SEMANTICS // Sun readdir_r()needs this
44 #include <boost/filesystem/operations.hpp>
45 #include <boost/scoped_array.hpp>
46 #include <boost/detail/workaround.hpp>
48 #include <cstdlib> // for malloc, free
50 #include <cstdio> // for remove, rename
51 #if defined(__QNXNTO__) // see ticket #5355
56 #ifdef BOOST_FILEYSTEM_INCLUDE_IOSTREAM
60 namespace fs = boost::filesystem;
61 using boost::filesystem::path;
62 using boost::filesystem::filesystem_error;
63 using boost::filesystem::perms;
64 using boost::system::error_code;
65 using boost::system::error_category;
66 using boost::system::system_category;
70 # ifdef BOOST_POSIX_API
72 # include <sys/types.h>
73 # include <sys/stat.h>
74 # if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__ANDROID__)
75 # include <sys/statvfs.h>
76 # define BOOST_STATVFS statvfs
77 # define BOOST_STATVFS_F_FRSIZE vfs.f_frsize
80 # include <sys/param.h>
81 # elif defined(__ANDROID__)
84 # include <sys/mount.h>
85 # define BOOST_STATVFS statfs
86 # define BOOST_STATVFS_F_FRSIZE static_cast<boost::uintmax_t>(vfs.f_bsize)
94 # else // BOOST_WINDOW_API
96 # if (defined(__MINGW32__) || defined(__CYGWIN__)) && !defined(WINVER)
97 // Versions of MinGW or Cygwin that support Filesystem V3 support at least WINVER 0x501.
98 // See MinGW's windef.h
102 # include <windows.h>
104 # if !defined(_WIN32_WINNT)
105 # define _WIN32_WINNT 0x0500
107 # if defined(__BORLANDC__) || defined(__MWERKS__)
108 # if defined(__BORLANDC__)
113 # include <sys/utime.h>
116 // REPARSE_DATA_BUFFER related definitions are found in ntifs.h, which is part of the
117 // Windows Device Driver Kit. Since that's inconvenient, the definitions are provided
118 // here. See http://msdn.microsoft.com/en-us/library/ms791514.aspx
120 #if !defined(REPARSE_DATA_BUFFER_HEADER_SIZE) // mingw winnt.h does provide the defs
122 #define SYMLINK_FLAG_RELATIVE 1
124 typedef struct _REPARSE_DATA_BUFFER {
126 USHORT ReparseDataLength;
130 USHORT SubstituteNameOffset;
131 USHORT SubstituteNameLength;
132 USHORT PrintNameOffset;
133 USHORT PrintNameLength;
136 /* Example of distinction between substitute and print names:
138 SubstituteName: c:\\??\
141 } SymbolicLinkReparseBuffer;
143 USHORT SubstituteNameOffset;
144 USHORT SubstituteNameLength;
145 USHORT PrintNameOffset;
146 USHORT PrintNameLength;
148 } MountPointReparseBuffer;
151 } GenericReparseBuffer;
153 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
155 #define REPARSE_DATA_BUFFER_HEADER_SIZE \
156 FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer)
160 #ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE
161 #define MAXIMUM_REPARSE_DATA_BUFFER_SIZE ( 16 * 1024 )
164 # ifndef FSCTL_GET_REPARSE_POINT
165 # define FSCTL_GET_REPARSE_POINT 0x900a8
168 # ifndef IO_REPARSE_TAG_SYMLINK
169 # define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
172 # endif // BOOST_WINDOWS_API
174 // BOOST_FILESYSTEM_STATUS_CACHE enables file_status cache in
175 // dir_itr_increment. The config tests are placed here because some of the
176 // macros being tested come from dirent.h.
178 // TODO: find out what macros indicate dirent::d_type present in more libraries
179 # if defined(BOOST_WINDOWS_API)\
180 || defined(_DIRENT_HAVE_D_TYPE)// defined by GNU C library if d_type present
181 # define BOOST_FILESYSTEM_STATUS_CACHE
184 // POSIX/Windows macros ----------------------------------------------------//
186 // Portions of the POSIX and Windows API's are very similar, except for name,
187 // order of arguments, and meaning of zero/non-zero returns. The macros below
188 // abstract away those differences. They follow Windows naming and order of
189 // arguments, and return true to indicate no error occurred. [POSIX naming,
190 // order of arguments, and meaning of return were followed initially, but
191 // found to be less clear and cause more coding errors.]
193 # if defined(BOOST_POSIX_API)
195 // POSIX uses a 0 return to indicate success
196 # define BOOST_ERRNO errno
197 # define BOOST_SET_CURRENT_DIRECTORY(P)(::chdir(P)== 0)
198 # define BOOST_CREATE_DIRECTORY(P)(::mkdir(P, S_IRWXU|S_IRWXG|S_IRWXO)== 0)
199 # define BOOST_CREATE_HARD_LINK(F,T)(::link(T, F)== 0)
200 # define BOOST_CREATE_SYMBOLIC_LINK(F,T,Flag)(::symlink(T, F)== 0)
201 # define BOOST_REMOVE_DIRECTORY(P)(::rmdir(P)== 0)
202 # define BOOST_DELETE_FILE(P)(::unlink(P)== 0)
203 # define BOOST_COPY_DIRECTORY(F,T)(!(::stat(from.c_str(), &from_stat)!= 0\
204 || ::mkdir(to.c_str(),from_stat.st_mode)!= 0))
205 # define BOOST_COPY_FILE(F,T,FailIfExistsBool)copy_file_api(F, T, FailIfExistsBool)
206 # define BOOST_MOVE_FILE(OLD,NEW)(::rename(OLD, NEW)== 0)
207 # define BOOST_RESIZE_FILE(P,SZ)(::truncate(P, SZ)== 0)
209 # define BOOST_ERROR_NOT_SUPPORTED ENOSYS
210 # define BOOST_ERROR_ALREADY_EXISTS EEXIST
212 # else // BOOST_WINDOWS_API
214 // Windows uses a non-0 return to indicate success
215 # define BOOST_ERRNO ::GetLastError()
216 # define BOOST_SET_CURRENT_DIRECTORY(P)(::SetCurrentDirectoryW(P)!= 0)
217 # define BOOST_CREATE_DIRECTORY(P)(::CreateDirectoryW(P, 0)!= 0)
218 # define BOOST_CREATE_HARD_LINK(F,T)(create_hard_link_api(F, T, 0)!= 0)
219 # define BOOST_CREATE_SYMBOLIC_LINK(F,T,Flag)(create_symbolic_link_api(F, T, Flag)!= 0)
220 # define BOOST_REMOVE_DIRECTORY(P)(::RemoveDirectoryW(P)!= 0)
221 # define BOOST_DELETE_FILE(P)(::DeleteFileW(P)!= 0)
222 # define BOOST_COPY_DIRECTORY(F,T)(::CreateDirectoryExW(F, T, 0)!= 0)
223 # define BOOST_COPY_FILE(F,T,FailIfExistsBool)(::CopyFileW(F, T, FailIfExistsBool)!= 0)
224 # define BOOST_MOVE_FILE(OLD,NEW)(::MoveFileExW(OLD, NEW, MOVEFILE_REPLACE_EXISTING|MOVEFILE_COPY_ALLOWED)!= 0)
225 # define BOOST_RESIZE_FILE(P,SZ)(resize_file_api(P, SZ)!= 0)
226 # define BOOST_READ_SYMLINK(P,T)
228 # define BOOST_ERROR_ALREADY_EXISTS ERROR_ALREADY_EXISTS
229 # define BOOST_ERROR_NOT_SUPPORTED ERROR_NOT_SUPPORTED
233 //--------------------------------------------------------------------------------------//
235 // helpers (all operating systems) //
237 //--------------------------------------------------------------------------------------//
242 fs::file_type query_file_type(const path& p, error_code* ec);
244 boost::filesystem::directory_iterator end_dir_itr;
248 bool error(bool was_error, error_code* ec, const string& message)
252 if (ec != 0) ec->clear();
257 BOOST_FILESYSTEM_THROW(filesystem_error(message,
258 error_code(BOOST_ERRNO, system_category())));
260 ec->assign(BOOST_ERRNO, system_category());
265 bool error(bool was_error, const path& p, error_code* ec, const string& message)
269 if (ec != 0) ec->clear();
274 BOOST_FILESYSTEM_THROW(filesystem_error(message,
275 p, error_code(BOOST_ERRNO, system_category())));
277 ec->assign(BOOST_ERRNO, system_category());
282 bool error(bool was_error, const path& p1, const path& p2, error_code* ec,
283 const string& message)
287 if (ec != 0) ec->clear();
292 BOOST_FILESYSTEM_THROW(filesystem_error(message,
293 p1, p2, error_code(BOOST_ERRNO, system_category())));
295 ec->assign(BOOST_ERRNO, system_category());
300 bool error(bool was_error, const error_code& result,
301 const path& p, error_code* ec, const string& message)
302 // Overwrites ec if there has already been an error
306 if (ec != 0) ec->clear();
311 BOOST_FILESYSTEM_THROW(filesystem_error(message, p, result));
318 bool error(bool was_error, const error_code& result,
319 const path& p1, const path& p2, error_code* ec, const string& message)
320 // Overwrites ec if there has already been an error
324 if (ec != 0) ec->clear();
329 BOOST_FILESYSTEM_THROW(filesystem_error(message, p1, p2, result));
336 bool is_empty_directory(const path& p)
338 return fs::directory_iterator(p)== end_dir_itr;
341 bool remove_directory(const path& p) // true if succeeds
342 { return BOOST_REMOVE_DIRECTORY(p.c_str()); }
344 bool remove_file(const path& p) // true if succeeds
345 { return BOOST_DELETE_FILE(p.c_str()); }
347 // called by remove and remove_all_aux
348 bool remove_file_or_directory(const path& p, fs::file_type type, error_code* ec)
349 // return true if file removed, false if not removed
351 if (type == fs::file_not_found)
353 if (ec != 0) ec->clear();
357 if (type == fs::directory_file
358 # ifdef BOOST_WINDOWS_API
359 || type == fs::_detail_directory_symlink
363 if (error(!remove_directory(p), p, ec, "boost::filesystem::remove"))
368 if (error(!remove_file(p), p, ec, "boost::filesystem::remove"))
374 boost::uintmax_t remove_all_aux(const path& p, fs::file_type type,
377 boost::uintmax_t count = 1;
379 if (type == fs::directory_file) // but not a directory symlink
381 for (fs::directory_iterator itr(p);
382 itr != end_dir_itr; ++itr)
384 fs::file_type tmp_type = query_file_type(itr->path(), ec);
387 count += remove_all_aux(itr->path(), tmp_type, ec);
390 remove_file_or_directory(p, type, ec);
394 #ifdef BOOST_POSIX_API
396 //--------------------------------------------------------------------------------------//
398 // POSIX-specific helpers //
400 //--------------------------------------------------------------------------------------//
402 const char dot = '.';
404 bool not_found_error(int errval)
406 return errno == ENOENT || errno == ENOTDIR;
410 copy_file_api(const std::string& from_p,
411 const std::string& to_p, bool fail_if_exists)
413 const std::size_t buf_sz = 32768;
414 boost::scoped_array<char> buf(new char [buf_sz]);
415 int infile=-1, outfile=-1; // -1 means not open
417 // bug fixed: code previously did a stat()on the from_file first, but that
418 // introduced a gratuitous race condition; the stat()is now done after the open()
420 if ((infile = ::open(from_p.c_str(), O_RDONLY))< 0)
423 struct stat from_stat;
424 if (::stat(from_p.c_str(), &from_stat)!= 0)
430 int oflag = O_CREAT | O_WRONLY | O_TRUNC;
433 if ((outfile = ::open(to_p.c_str(), oflag, from_stat.st_mode))< 0)
435 int open_errno = errno;
436 BOOST_ASSERT(infile >= 0);
442 ssize_t sz, sz_read=1, sz_write;
444 && (sz_read = ::read(infile, buf.get(), buf_sz))> 0)
446 // Allow for partial writes - see Advanced Unix Programming (2nd Ed.),
447 // Marc Rochkind, Addison-Wesley, 2004, page 94
451 if ((sz = ::write(outfile, buf.get() + sz_write,
452 sz_read - sz_write))< 0)
454 sz_read = sz; // cause read loop termination
455 break; // and error to be thrown after closes
458 } while (sz_write < sz_read);
461 if (::close(infile)< 0)sz_read = -1;
462 if (::close(outfile)< 0)sz_read = -1;
467 inline fs::file_type query_file_type(const path& p, error_code* ec)
469 return fs::detail::symlink_status(p, ec).type();
474 //--------------------------------------------------------------------------------------//
476 // Windows-specific helpers //
478 //--------------------------------------------------------------------------------------//
480 const std::size_t buf_size=128;
482 const wchar_t dot = L'.';
484 bool not_found_error(int errval)
486 return errval == ERROR_FILE_NOT_FOUND
487 || errval == ERROR_PATH_NOT_FOUND
488 || errval == ERROR_INVALID_NAME // "tools/jam/src/:sys:stat.h", "//foo"
489 || errval == ERROR_INVALID_DRIVE // USB card reader with no card inserted
490 || errval == ERROR_NOT_READY // CD/DVD drive with no disc inserted
491 || errval == ERROR_INVALID_PARAMETER // ":sys:stat.h"
492 || errval == ERROR_BAD_PATHNAME // "//nosuch" on Win64
493 || errval == ERROR_BAD_NETPATH; // "//nosuch" on Win32
496 // some distributions of mingw as early as GLIBCXX__ 20110325 have _stricmp, but the
497 // offical 4.6.2 release with __GLIBCXX__ 20111026 doesn't. Play it safe for now, and
498 // only use _stricmp if _MSC_VER is defined
499 #if defined(_MSC_VER) // || (defined(__GLIBCXX__) && __GLIBCXX__ >= 20110325)
500 # define BOOST_FILESYSTEM_STRICMP _stricmp
502 # define BOOST_FILESYSTEM_STRICMP strcmp
505 perms make_permissions(const path& p, DWORD attr)
507 perms prms = fs::owner_read | fs::group_read | fs::others_read;
508 if ((attr & FILE_ATTRIBUTE_READONLY) == 0)
509 prms |= fs::owner_write | fs::group_write | fs::others_write;
510 if (BOOST_FILESYSTEM_STRICMP(p.extension().string().c_str(), ".exe") == 0
511 || BOOST_FILESYSTEM_STRICMP(p.extension().string().c_str(), ".com") == 0
512 || BOOST_FILESYSTEM_STRICMP(p.extension().string().c_str(), ".bat") == 0
513 || BOOST_FILESYSTEM_STRICMP(p.extension().string().c_str(), ".cmd") == 0)
514 prms |= fs::owner_exe | fs::group_exe | fs::others_exe;
518 // these constants come from inspecting some Microsoft sample code
519 std::time_t to_time_t(const FILETIME & ft)
521 __int64 t = (static_cast<__int64>(ft.dwHighDateTime)<< 32)
523 # if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 // > VC++ 7.0
524 t -= 116444736000000000LL;
526 t -= 116444736000000000;
529 return static_cast<std::time_t>(t);
532 void to_FILETIME(std::time_t t, FILETIME & ft)
536 # if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 // > VC++ 7.0
537 temp += 116444736000000000LL;
539 temp += 116444736000000000;
541 ft.dwLowDateTime = static_cast<DWORD>(temp);
542 ft.dwHighDateTime = static_cast<DWORD>(temp >> 32);
545 // Thanks to Jeremy Maitin-Shepard for much help and for permission to
546 // base the equivalent()implementation on portions of his
547 // file-equivalence-win32.cpp experimental code.
549 struct handle_wrapper
552 handle_wrapper(HANDLE h)
556 if (handle != INVALID_HANDLE_VALUE)
557 ::CloseHandle(handle);
561 HANDLE create_file_handle(const path& p, DWORD dwDesiredAccess,
562 DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes,
563 DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,
564 HANDLE hTemplateFile)
566 return ::CreateFileW(p.c_str(), dwDesiredAccess, dwShareMode,
567 lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes,
571 bool is_reparse_point_a_symlink(const path& p)
573 handle_wrapper h(create_file_handle(p, FILE_READ_EA,
574 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING,
575 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL));
576 if (h.handle == INVALID_HANDLE_VALUE)
579 boost::scoped_array<char> buf(new char [MAXIMUM_REPARSE_DATA_BUFFER_SIZE]);
581 // Query the reparse data
583 BOOL result = ::DeviceIoControl(h.handle, FSCTL_GET_REPARSE_POINT, NULL, 0, buf.get(),
584 MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &dwRetLen, NULL);
585 if (!result) return false;
587 return reinterpret_cast<const REPARSE_DATA_BUFFER*>(buf.get())->ReparseTag
588 == IO_REPARSE_TAG_SYMLINK
589 // Issue 9016 asked that NTFS directory junctions be recognized as directories.
590 // That is equivalent to recognizing them as symlinks, and then the normal symlink
591 // mechanism will take care of recognizing them as directories.
593 // Directory junctions are very similar to symlinks, but have some performance
594 // and other advantages over symlinks. They can be created from the command line
595 // with "mklink /j junction-name target-path".
596 || reinterpret_cast<const REPARSE_DATA_BUFFER*>(buf.get())->ReparseTag
597 == IO_REPARSE_TAG_MOUNT_POINT; // aka "directory junction" or "junction"
600 inline std::size_t get_full_path_name(
601 const path& src, std::size_t len, wchar_t* buf, wchar_t** p)
603 return static_cast<std::size_t>(
604 ::GetFullPathNameW(src.c_str(), static_cast<DWORD>(len), buf, p));
607 fs::file_status process_status_failure(const path& p, error_code* ec)
609 int errval(::GetLastError());
610 if (ec != 0) // always report errval, even though some
611 ec->assign(errval, system_category()); // errval values are not status_errors
613 if (not_found_error(errval))
615 return fs::file_status(fs::file_not_found, fs::no_perms);
617 else if ((errval == ERROR_SHARING_VIOLATION))
619 return fs::file_status(fs::type_unknown);
622 BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status",
623 p, error_code(errval, system_category())));
624 return fs::file_status(fs::status_error);
627 // differs from symlink_status() in that directory symlinks are reported as
628 // _detail_directory_symlink, as required on Windows by remove() and its helpers.
629 fs::file_type query_file_type(const path& p, error_code* ec)
631 DWORD attr(::GetFileAttributesW(p.c_str()));
632 if (attr == 0xFFFFFFFF)
634 return process_status_failure(p, ec).type();
637 if (ec != 0) ec->clear();
639 if (attr & FILE_ATTRIBUTE_REPARSE_POINT)
641 if (is_reparse_point_a_symlink(p))
642 return (attr & FILE_ATTRIBUTE_DIRECTORY)
643 ? fs::_detail_directory_symlink
645 return fs::reparse_file;
648 return (attr & FILE_ATTRIBUTE_DIRECTORY)
653 BOOL resize_file_api(const wchar_t* p, boost::uintmax_t size)
655 HANDLE handle = CreateFileW(p, GENERIC_WRITE, 0, 0, OPEN_EXISTING,
656 FILE_ATTRIBUTE_NORMAL, 0);
659 return handle != INVALID_HANDLE_VALUE
660 && ::SetFilePointerEx(handle, sz, 0, FILE_BEGIN)
661 && ::SetEndOfFile(handle)
662 && ::CloseHandle(handle);
665 // Windows kernel32.dll functions that may or may not be present
666 // must be accessed through pointers
668 typedef BOOL (WINAPI *PtrCreateHardLinkW)(
669 /*__in*/ LPCWSTR lpFileName,
670 /*__in*/ LPCWSTR lpExistingFileName,
671 /*__reserved*/ LPSECURITY_ATTRIBUTES lpSecurityAttributes
674 PtrCreateHardLinkW create_hard_link_api = PtrCreateHardLinkW(
676 ::GetModuleHandle(TEXT("kernel32.dll")), "CreateHardLinkW"));
678 typedef BOOLEAN (WINAPI *PtrCreateSymbolicLinkW)(
679 /*__in*/ LPCWSTR lpSymlinkFileName,
680 /*__in*/ LPCWSTR lpTargetFileName,
681 /*__in*/ DWORD dwFlags
684 PtrCreateSymbolicLinkW create_symbolic_link_api = PtrCreateSymbolicLinkW(
686 ::GetModuleHandle(TEXT("kernel32.dll")), "CreateSymbolicLinkW"));
690 //#ifdef BOOST_WINDOWS_API
693 // inline bool get_free_disk_space(const std::wstring& ph,
694 // PULARGE_INTEGER avail, PULARGE_INTEGER total, PULARGE_INTEGER free)
695 // { return ::GetDiskFreeSpaceExW(ph.c_str(), avail, total, free)!= 0; }
699 } // unnamed namespace
701 //--------------------------------------------------------------------------------------//
703 // operations functions declared in operations.hpp //
704 // in alphabetic order //
706 //--------------------------------------------------------------------------------------//
713 BOOST_FILESYSTEM_DECL
714 path absolute(const path& p, const path& base)
716 // if ( p.empty() || p.is_absolute() )
718 // // recursively calling absolute is sub-optimal, but is simple
719 // path abs_base(base.is_absolute() ? base : absolute(base));
720 //# ifdef BOOST_WINDOWS_API
721 // if (p.has_root_directory())
722 // return abs_base.root_name() / p;
723 // // !p.has_root_directory
724 // if (p.has_root_name())
725 // return p.root_name()
726 // / abs_base.root_directory() / abs_base.relative_path() / p.relative_path();
727 // // !p.has_root_name()
729 // return abs_base / p;
731 // recursively calling absolute is sub-optimal, but is sure and simple
732 path abs_base(base.is_absolute() ? base : absolute(base));
734 // store expensive to compute values that are needed multiple times
735 path p_root_name (p.root_name());
736 path base_root_name (abs_base.root_name());
737 path p_root_directory (p.root_directory());
742 if (!p_root_name.empty()) // p.has_root_name()
744 if (p_root_directory.empty()) // !p.has_root_directory()
745 return p_root_name / abs_base.root_directory()
746 / abs_base.relative_path() / p.relative_path();
747 // p is absolute, so fall through to return p at end of block
750 else if (!p_root_directory.empty()) // p.has_root_directory()
752 # ifdef BOOST_POSIX_API
753 // POSIX can have root name it it is a network path
754 if (base_root_name.empty()) // !abs_base.has_root_name()
757 return base_root_name / p;
765 return p; // p.is_absolute() is true
770 BOOST_FILESYSTEM_DECL bool possible_large_file_size_support()
772 # ifdef BOOST_POSIX_API
773 struct stat lcl_stat;
774 return sizeof(lcl_stat.st_size)> 4;
780 BOOST_FILESYSTEM_DECL
781 path canonical(const path& p, const path& base, system::error_code* ec)
783 path source (p.is_absolute() ? p : absolute(p, base));
784 path root(source.root_path());
787 system::error_code local_ec;
788 file_status stat (status(source, local_ec));
790 if (stat.type() == fs::file_not_found)
793 BOOST_FILESYSTEM_THROW(filesystem_error(
794 "boost::filesystem::canonical", source,
795 error_code(system::errc::no_such_file_or_directory, system::generic_category())));
796 ec->assign(system::errc::no_such_file_or_directory, system::generic_category());
802 BOOST_FILESYSTEM_THROW(filesystem_error(
803 "boost::filesystem::canonical", source, local_ec));
813 for (path::iterator itr = source.begin(); itr != source.end(); ++itr)
815 if (*itr == dot_path())
817 if (*itr == dot_dot_path())
820 result.remove_filename();
826 bool is_sym (is_symlink(detail::symlink_status(result, ec)));
832 path link(detail::read_symlink(result, ec));
835 result.remove_filename();
837 if (link.is_absolute())
839 for (++itr; itr != source.end(); ++itr)
843 else // link is relative
845 path new_source(result);
847 for (++itr; itr != source.end(); ++itr)
851 scan = true; // symlink causes scan to be restarted
858 BOOST_ASSERT_MSG(result.is_absolute(), "canonical() implementation error; please report");
862 BOOST_FILESYSTEM_DECL
863 void copy(const path& from, const path& to, system::error_code* ec)
865 file_status s(symlink_status(from, *ec));
866 if (ec != 0 && *ec) return;
870 copy_symlink(from, to, *ec);
872 else if(is_directory(s))
874 copy_directory(from, to, *ec);
876 else if(is_regular_file(s))
878 copy_file(from, to, fs::copy_option::fail_if_exists, *ec);
883 BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::copy",
884 from, to, error_code(BOOST_ERROR_NOT_SUPPORTED, system_category())));
885 ec->assign(BOOST_ERROR_NOT_SUPPORTED, system_category());
889 BOOST_FILESYSTEM_DECL
890 void copy_directory(const path& from, const path& to, system::error_code* ec)
892 # ifdef BOOST_POSIX_API
893 struct stat from_stat;
895 error(!BOOST_COPY_DIRECTORY(from.c_str(), to.c_str()),
896 from, to, ec, "boost::filesystem::copy_directory");
899 BOOST_FILESYSTEM_DECL
900 void copy_file(const path& from, const path& to, copy_option option, error_code* ec)
902 error(!BOOST_COPY_FILE(from.c_str(), to.c_str(),
903 option == fail_if_exists),
904 from, to, ec, "boost::filesystem::copy_file");
907 BOOST_FILESYSTEM_DECL
908 void copy_symlink(const path& existing_symlink, const path& new_symlink,
909 system::error_code* ec)
911 # if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0600
912 error(true, error_code(BOOST_ERROR_NOT_SUPPORTED, system_category()),
913 new_symlink, existing_symlink, ec,
914 "boost::filesystem::copy_symlink");
916 # else // modern Windows or BOOST_POSIX_API
917 path p(read_symlink(existing_symlink, ec));
918 if (ec != 0 && *ec) return;
919 create_symlink(p, new_symlink, ec);
924 BOOST_FILESYSTEM_DECL
925 bool create_directories(const path& p, system::error_code* ec)
928 file_status p_status = status(p, local_ec);
930 if (p_status.type() == directory_file)
937 path parent = p.parent_path();
938 BOOST_ASSERT_MSG(parent != p, "internal error: p == p.parent_path()");
941 // determine if the parent exists
942 file_status parent_status = status(parent, local_ec);
944 // if the parent does not exist, create the parent
945 if (parent_status.type() == file_not_found)
947 create_directories(parent, local_ec);
951 BOOST_FILESYSTEM_THROW(filesystem_error(
952 "boost::filesystem::create_directories", parent, local_ec));
960 // create the directory
961 return create_directory(p, ec);
964 BOOST_FILESYSTEM_DECL
965 bool create_directory(const path& p, error_code* ec)
967 if (BOOST_CREATE_DIRECTORY(p.c_str()))
974 // attempt to create directory failed
975 int errval(BOOST_ERRNO); // save reason for failure
977 if (errval == BOOST_ERROR_ALREADY_EXISTS && is_directory(p, dummy))
984 // attempt to create directory failed && it doesn't already exist
986 BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::create_directory",
987 p, error_code(errval, system_category())));
989 ec->assign(errval, system_category());
993 BOOST_FILESYSTEM_DECL
994 void create_directory_symlink(const path& to, const path& from,
995 system::error_code* ec)
997 # if defined(BOOST_WINDOWS_API) && _WIN32_WINNT < 0x0600 // SDK earlier than Vista and Server 2008
999 error(true, error_code(BOOST_ERROR_NOT_SUPPORTED, system_category()), to, from, ec,
1000 "boost::filesystem::create_directory_symlink");
1003 # if defined(BOOST_WINDOWS_API) && _WIN32_WINNT >= 0x0600
1004 // see if actually supported by Windows runtime dll
1005 if (error(!create_symbolic_link_api,
1006 error_code(BOOST_ERROR_NOT_SUPPORTED, system_category()),
1008 "boost::filesystem::create_directory_symlink"))
1012 error(!BOOST_CREATE_SYMBOLIC_LINK(from.c_str(), to.c_str(), SYMBOLIC_LINK_FLAG_DIRECTORY),
1013 to, from, ec, "boost::filesystem::create_directory_symlink");
1017 BOOST_FILESYSTEM_DECL
1018 void create_hard_link(const path& to, const path& from, error_code* ec)
1021 # if defined(BOOST_WINDOWS_API) && _WIN32_WINNT < 0x0500 // SDK earlier than Win 2K
1023 error(true, error_code(BOOST_ERROR_NOT_SUPPORTED, system_category()), to, from, ec,
1024 "boost::filesystem::create_hard_link");
1027 # if defined(BOOST_WINDOWS_API) && _WIN32_WINNT >= 0x0500
1028 // see if actually supported by Windows runtime dll
1029 if (error(!create_hard_link_api,
1030 error_code(BOOST_ERROR_NOT_SUPPORTED, system_category()),
1032 "boost::filesystem::create_hard_link"))
1036 error(!BOOST_CREATE_HARD_LINK(from.c_str(), to.c_str()), to, from, ec,
1037 "boost::filesystem::create_hard_link");
1041 BOOST_FILESYSTEM_DECL
1042 void create_symlink(const path& to, const path& from, error_code* ec)
1044 # if defined(BOOST_WINDOWS_API) && _WIN32_WINNT < 0x0600 // SDK earlier than Vista and Server 2008
1045 error(true, error_code(BOOST_ERROR_NOT_SUPPORTED, system_category()), to, from, ec,
1046 "boost::filesystem::create_directory_symlink");
1049 # if defined(BOOST_WINDOWS_API) && _WIN32_WINNT >= 0x0600
1050 // see if actually supported by Windows runtime dll
1051 if (error(!create_symbolic_link_api,
1052 error_code(BOOST_ERROR_NOT_SUPPORTED, system_category()),
1054 "boost::filesystem::create_symlink"))
1058 error(!BOOST_CREATE_SYMBOLIC_LINK(from.c_str(), to.c_str(), 0),
1059 to, from, ec, "boost::filesystem::create_symlink");
1063 BOOST_FILESYSTEM_DECL
1064 path current_path(error_code* ec)
1066 # ifdef BOOST_POSIX_API
1068 for (long path_max = 128;; path_max *=2)// loop 'til buffer large enough
1070 boost::scoped_array<char>
1071 buf(new char[static_cast<std::size_t>(path_max)]);
1072 if (::getcwd(buf.get(), static_cast<std::size_t>(path_max))== 0)
1074 if (error(errno != ERANGE
1075 // bug in some versions of the Metrowerks C lib on the Mac: wrong errno set
1076 # if defined(__MSL__) && (defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__))
1079 , ec, "boost::filesystem::current_path"))
1087 if (ec != 0) ec->clear();
1095 if ((sz = ::GetCurrentDirectoryW(0, NULL))== 0)sz = 1;
1096 boost::scoped_array<path::value_type> buf(new path::value_type[sz]);
1097 error(::GetCurrentDirectoryW(sz, buf.get())== 0, ec,
1098 "boost::filesystem::current_path");
1099 return path(buf.get());
1104 BOOST_FILESYSTEM_DECL
1105 void current_path(const path& p, system::error_code* ec)
1107 error(!BOOST_SET_CURRENT_DIRECTORY(p.c_str()),
1108 p, ec, "boost::filesystem::current_path");
1111 BOOST_FILESYSTEM_DECL
1112 bool equivalent(const path& p1, const path& p2, system::error_code* ec)
1114 # ifdef BOOST_POSIX_API
1116 int e2(::stat(p2.c_str(), &s2));
1118 int e1(::stat(p1.c_str(), &s1));
1120 if (e1 != 0 || e2 != 0)
1122 // if one is invalid and the other isn't then they aren't equivalent,
1123 // but if both are invalid then it is an error
1124 error (e1 != 0 && e2 != 0, p1, p2, ec, "boost::filesystem::equivalent");
1128 // both stats now known to be valid
1129 return s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino
1130 // According to the POSIX stat specs, "The st_ino and st_dev fields
1131 // taken together uniquely identify the file within the system."
1132 // Just to be sure, size and mod time are also checked.
1133 && s1.st_size == s2.st_size && s1.st_mtime == s2.st_mtime;
1137 // Note well: Physical location on external media is part of the
1138 // equivalence criteria. If there are no open handles, physical location
1139 // can change due to defragmentation or other relocations. Thus handles
1140 // must be held open until location information for both paths has
1143 // p2 is done first, so any error reported is for p1
1148 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
1151 FILE_FLAG_BACKUP_SEMANTICS,
1158 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
1161 FILE_FLAG_BACKUP_SEMANTICS,
1164 if (h1.handle == INVALID_HANDLE_VALUE
1165 || h2.handle == INVALID_HANDLE_VALUE)
1167 // if one is invalid and the other isn't, then they aren't equivalent,
1168 // but if both are invalid then it is an error
1169 error(h1.handle == INVALID_HANDLE_VALUE
1170 && h2.handle == INVALID_HANDLE_VALUE, p1, p2, ec,
1171 "boost::filesystem::equivalent");
1175 // at this point, both handles are known to be valid
1177 BY_HANDLE_FILE_INFORMATION info1, info2;
1179 if (error(!::GetFileInformationByHandle(h1.handle, &info1),
1180 p1, p2, ec, "boost::filesystem::equivalent"))
1183 if (error(!::GetFileInformationByHandle(h2.handle, &info2),
1184 p1, p2, ec, "boost::filesystem::equivalent"))
1187 // In theory, volume serial numbers are sufficient to distinguish between
1188 // devices, but in practice VSN's are sometimes duplicated, so last write
1189 // time and file size are also checked.
1191 info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber
1192 && info1.nFileIndexHigh == info2.nFileIndexHigh
1193 && info1.nFileIndexLow == info2.nFileIndexLow
1194 && info1.nFileSizeHigh == info2.nFileSizeHigh
1195 && info1.nFileSizeLow == info2.nFileSizeLow
1196 && info1.ftLastWriteTime.dwLowDateTime
1197 == info2.ftLastWriteTime.dwLowDateTime
1198 && info1.ftLastWriteTime.dwHighDateTime
1199 == info2.ftLastWriteTime.dwHighDateTime;
1204 BOOST_FILESYSTEM_DECL
1205 boost::uintmax_t file_size(const path& p, error_code* ec)
1207 # ifdef BOOST_POSIX_API
1209 struct stat path_stat;
1210 if (error(::stat(p.c_str(), &path_stat)!= 0,
1211 p, ec, "boost::filesystem::file_size"))
1212 return static_cast<boost::uintmax_t>(-1);
1213 if (error(!S_ISREG(path_stat.st_mode),
1214 error_code(EPERM, system_category()),
1215 p, ec, "boost::filesystem::file_size"))
1216 return static_cast<boost::uintmax_t>(-1);
1218 return static_cast<boost::uintmax_t>(path_stat.st_size);
1222 // assume uintmax_t is 64-bits on all Windows compilers
1224 WIN32_FILE_ATTRIBUTE_DATA fad;
1226 if (error(::GetFileAttributesExW(p.c_str(), ::GetFileExInfoStandard, &fad)== 0,
1227 p, ec, "boost::filesystem::file_size"))
1228 return static_cast<boost::uintmax_t>(-1);
1230 if (error((fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)!= 0,
1231 error_code(ERROR_NOT_SUPPORTED, system_category()),
1232 p, ec, "boost::filesystem::file_size"))
1233 return static_cast<boost::uintmax_t>(-1);
1235 return (static_cast<boost::uintmax_t>(fad.nFileSizeHigh)
1236 << (sizeof(fad.nFileSizeLow)*8)) + fad.nFileSizeLow;
1240 BOOST_FILESYSTEM_DECL
1241 boost::uintmax_t hard_link_count(const path& p, system::error_code* ec)
1243 # ifdef BOOST_POSIX_API
1245 struct stat path_stat;
1246 return error(::stat(p.c_str(), &path_stat)!= 0,
1247 p, ec, "boost::filesystem::hard_link_count")
1249 : static_cast<boost::uintmax_t>(path_stat.st_nlink);
1253 // Link count info is only available through GetFileInformationByHandle
1254 BY_HANDLE_FILE_INFORMATION info;
1256 create_file_handle(p.c_str(), 0,
1257 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
1258 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0));
1260 !error(h.handle == INVALID_HANDLE_VALUE,
1261 p, ec, "boost::filesystem::hard_link_count")
1262 && !error(::GetFileInformationByHandle(h.handle, &info)== 0,
1263 p, ec, "boost::filesystem::hard_link_count")
1264 ? info.nNumberOfLinks
1269 BOOST_FILESYSTEM_DECL
1270 path initial_path(error_code* ec)
1272 static path init_path;
1273 if (init_path.empty())
1274 init_path = current_path(ec);
1275 else if (ec != 0) ec->clear();
1279 BOOST_FILESYSTEM_DECL
1280 bool is_empty(const path& p, system::error_code* ec)
1282 # ifdef BOOST_POSIX_API
1284 struct stat path_stat;
1285 if (error(::stat(p.c_str(), &path_stat)!= 0,
1286 p, ec, "boost::filesystem::is_empty"))
1288 return S_ISDIR(path_stat.st_mode)
1289 ? is_empty_directory(p)
1290 : path_stat.st_size == 0;
1293 WIN32_FILE_ATTRIBUTE_DATA fad;
1294 if (error(::GetFileAttributesExW(p.c_str(), ::GetFileExInfoStandard, &fad)== 0,
1295 p, ec, "boost::filesystem::is_empty"))
1298 if (ec != 0) ec->clear();
1300 (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1301 ? is_empty_directory(p)
1302 : (!fad.nFileSizeHigh && !fad.nFileSizeLow);
1306 BOOST_FILESYSTEM_DECL
1307 std::time_t last_write_time(const path& p, system::error_code* ec)
1309 # ifdef BOOST_POSIX_API
1311 struct stat path_stat;
1312 if (error(::stat(p.c_str(), &path_stat)!= 0,
1313 p, ec, "boost::filesystem::last_write_time"))
1314 return std::time_t(-1);
1315 return path_stat.st_mtime;
1320 create_file_handle(p.c_str(), 0,
1321 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
1322 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0));
1324 if (error(hw.handle == INVALID_HANDLE_VALUE,
1325 p, ec, "boost::filesystem::last_write_time"))
1326 return std::time_t(-1);
1330 if (error(::GetFileTime(hw.handle, 0, 0, &lwt)== 0,
1331 p, ec, "boost::filesystem::last_write_time"))
1332 return std::time_t(-1);
1334 return to_time_t(lwt);
1338 BOOST_FILESYSTEM_DECL
1339 void last_write_time(const path& p, const std::time_t new_time,
1340 system::error_code* ec)
1342 # ifdef BOOST_POSIX_API
1344 struct stat path_stat;
1345 if (error(::stat(p.c_str(), &path_stat)!= 0,
1346 p, ec, "boost::filesystem::last_write_time"))
1349 buf.actime = path_stat.st_atime; // utime()updates access time too:-(
1350 buf.modtime = new_time;
1351 error(::utime(p.c_str(), &buf)!= 0,
1352 p, ec, "boost::filesystem::last_write_time");
1357 create_file_handle(p.c_str(), FILE_WRITE_ATTRIBUTES,
1358 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
1359 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0));
1361 if (error(hw.handle == INVALID_HANDLE_VALUE,
1362 p, ec, "boost::filesystem::last_write_time"))
1366 to_FILETIME(new_time, lwt);
1368 error(::SetFileTime(hw.handle, 0, 0, &lwt)== 0,
1369 p, ec, "boost::filesystem::last_write_time");
1373 # ifdef BOOST_POSIX_API
1374 const perms active_bits(all_all | set_uid_on_exe | set_gid_on_exe | sticky_bit);
1375 inline mode_t mode_cast(perms prms) { return prms & active_bits; }
1378 BOOST_FILESYSTEM_DECL
1379 void permissions(const path& p, perms prms, system::error_code* ec)
1381 BOOST_ASSERT_MSG(!((prms & add_perms) && (prms & remove_perms)),
1382 "add_perms and remove_perms are mutually exclusive");
1384 if ((prms & add_perms) && (prms & remove_perms)) // precondition failed
1387 # ifdef BOOST_POSIX_API
1388 error_code local_ec;
1389 file_status current_status((prms & symlink_perms)
1390 ? fs::symlink_status(p, local_ec)
1391 : fs::status(p, local_ec));
1395 BOOST_FILESYSTEM_THROW(filesystem_error(
1396 "boost::filesystem::permissions", p, local_ec));
1402 if (prms & add_perms)
1403 prms |= current_status.permissions();
1404 else if (prms & remove_perms)
1405 prms = current_status.permissions() & ~prms;
1407 // Mac OS X Lion and some other platforms don't support fchmodat().
1408 // Solaris (SunPro and gcc) only support fchmodat() on Solaris 11 and higher,
1409 // and a runtime check is too much trouble.
1410 // Linux does not support permissions on symbolic links and has no plans to
1411 // support them in the future. The chmod() code is thus more practical,
1412 // rather than always hitting ENOTSUP when sending in AT_SYMLINK_NO_FOLLOW.
1413 // - See the 3rd paragraph of
1414 // "Symbolic link ownership, permissions, and timestamps" at:
1415 // "http://man7.org/linux/man-pages/man7/symlink.7.html"
1416 // - See the fchmodat() Linux man page:
1417 // "http://man7.org/linux/man-pages/man2/fchmodat.2.html"
1418 # if defined(AT_FDCWD) && defined(AT_SYMLINK_NOFOLLOW) \
1419 && !(defined(__SUNPRO_CC) || defined(__sun) || defined(sun)) \
1420 && !(defined(linux) || defined(__linux) || defined(__linux__))
1421 if (::fchmodat(AT_FDCWD, p.c_str(), mode_cast(prms),
1422 !(prms & symlink_perms) ? 0 : AT_SYMLINK_NOFOLLOW))
1423 # else // fallback if fchmodat() not supported
1424 if (::chmod(p.c_str(), mode_cast(prms)))
1428 BOOST_FILESYSTEM_THROW(filesystem_error(
1429 "boost::filesystem::permissions", p,
1430 error_code(errno, system::generic_category())));
1432 ec->assign(errno, system::generic_category());
1437 // if not going to alter FILE_ATTRIBUTE_READONLY, just return
1438 if (!(!((prms & (add_perms | remove_perms)))
1439 || (prms & (owner_write|group_write|others_write))))
1442 DWORD attr = ::GetFileAttributesW(p.c_str());
1444 if (error(attr == 0, p, ec, "boost::filesystem::permissions"))
1447 if (prms & add_perms)
1448 attr &= ~FILE_ATTRIBUTE_READONLY;
1449 else if (prms & remove_perms)
1450 attr |= FILE_ATTRIBUTE_READONLY;
1451 else if (prms & (owner_write|group_write|others_write))
1452 attr &= ~FILE_ATTRIBUTE_READONLY;
1454 attr |= FILE_ATTRIBUTE_READONLY;
1456 error(::SetFileAttributesW(p.c_str(), attr) == 0,
1457 p, ec, "boost::filesystem::permissions");
1461 BOOST_FILESYSTEM_DECL
1462 path read_symlink(const path& p, system::error_code* ec)
1466 # ifdef BOOST_POSIX_API
1468 for (std::size_t path_max = 64;; path_max *= 2)// loop 'til buffer large enough
1470 boost::scoped_array<char> buf(new char[path_max]);
1472 if ((result=::readlink(p.c_str(), buf.get(), path_max))== -1)
1475 BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::read_symlink",
1476 p, error_code(errno, system_category())));
1477 else ec->assign(errno, system_category());
1482 if(result != static_cast<ssize_t>(path_max))
1484 symlink_path.assign(buf.get(), buf.get() + result);
1485 if (ec != 0) ec->clear();
1491 # elif _WIN32_WINNT < 0x0600 // SDK earlier than Vista and Server 2008
1492 error(true, error_code(BOOST_ERROR_NOT_SUPPORTED, system_category()), p, ec,
1493 "boost::filesystem::read_symlink");
1494 # else // Vista and Server 2008 SDK, or later
1498 char buf[REPARSE_DATA_BUFFER_HEADER_SIZE+MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
1499 REPARSE_DATA_BUFFER rdb;
1503 create_file_handle(p.c_str(), GENERIC_READ, 0, 0, OPEN_EXISTING,
1504 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0));
1506 if (error(h.handle == INVALID_HANDLE_VALUE, p, ec, "boost::filesystem::read_symlink"))
1507 return symlink_path;
1511 if (!error(::DeviceIoControl(h.handle, FSCTL_GET_REPARSE_POINT,
1512 0, 0, info.buf, sizeof(info), &sz, 0) == 0, p, ec,
1513 "boost::filesystem::read_symlink" ))
1514 symlink_path.assign(
1515 static_cast<wchar_t*>(info.rdb.SymbolicLinkReparseBuffer.PathBuffer)
1516 + info.rdb.SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(wchar_t),
1517 static_cast<wchar_t*>(info.rdb.SymbolicLinkReparseBuffer.PathBuffer)
1518 + info.rdb.SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(wchar_t)
1519 + info.rdb.SymbolicLinkReparseBuffer.PrintNameLength/sizeof(wchar_t));
1521 return symlink_path;
1524 BOOST_FILESYSTEM_DECL
1525 bool remove(const path& p, error_code* ec)
1528 file_type type = query_file_type(p, &tmp_ec);
1529 if (error(type == status_error, tmp_ec, p, ec,
1530 "boost::filesystem::remove"))
1533 // Since POSIX remove() is specified to work with either files or directories, in a
1534 // perfect world it could just be called. But some important real-world operating
1535 // systems (Windows, Mac OS X, for example) don't implement the POSIX spec. So
1536 // remove_file_or_directory() is always called to kep it simple.
1537 return remove_file_or_directory(p, type, ec);
1540 BOOST_FILESYSTEM_DECL
1541 boost::uintmax_t remove_all(const path& p, error_code* ec)
1544 file_type type = query_file_type(p, &tmp_ec);
1545 if (error(type == status_error, tmp_ec, p, ec,
1546 "boost::filesystem::remove_all"))
1549 return (type != status_error && type != file_not_found) // exists
1550 ? remove_all_aux(p, type, ec)
1554 BOOST_FILESYSTEM_DECL
1555 void rename(const path& old_p, const path& new_p, error_code* ec)
1557 error(!BOOST_MOVE_FILE(old_p.c_str(), new_p.c_str()), old_p, new_p, ec,
1558 "boost::filesystem::rename");
1561 BOOST_FILESYSTEM_DECL
1562 void resize_file(const path& p, uintmax_t size, system::error_code* ec)
1564 error(!BOOST_RESIZE_FILE(p.c_str(), size), p, ec, "boost::filesystem::resize_file");
1567 BOOST_FILESYSTEM_DECL
1568 space_info space(const path& p, error_code* ec)
1570 # ifdef BOOST_POSIX_API
1571 struct BOOST_STATVFS vfs;
1573 if (!error(::BOOST_STATVFS(p.c_str(), &vfs)!= 0,
1574 p, ec, "boost::filesystem::space"))
1577 = static_cast<boost::uintmax_t>(vfs.f_blocks)* BOOST_STATVFS_F_FRSIZE;
1579 = static_cast<boost::uintmax_t>(vfs.f_bfree)* BOOST_STATVFS_F_FRSIZE;
1581 = static_cast<boost::uintmax_t>(vfs.f_bavail)* BOOST_STATVFS_F_FRSIZE;
1585 ULARGE_INTEGER avail, total, free;
1588 if (!error(::GetDiskFreeSpaceExW(p.c_str(), &avail, &total, &free)== 0,
1589 p, ec, "boost::filesystem::space"))
1592 = (static_cast<boost::uintmax_t>(total.HighPart)<< 32)
1595 = (static_cast<boost::uintmax_t>(free.HighPart)<< 32)
1598 = (static_cast<boost::uintmax_t>(avail.HighPart)<< 32)
1606 info.capacity = info.free = info.available = 0;
1611 BOOST_FILESYSTEM_DECL
1612 file_status status(const path& p, error_code* ec)
1614 # ifdef BOOST_POSIX_API
1616 struct stat path_stat;
1617 if (::stat(p.c_str(), &path_stat)!= 0)
1619 if (ec != 0) // always report errno, even though some
1620 ec->assign(errno, system_category()); // errno values are not status_errors
1622 if (not_found_error(errno))
1624 return fs::file_status(fs::file_not_found, fs::no_perms);
1627 BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status",
1628 p, error_code(errno, system_category())));
1629 return fs::file_status(fs::status_error);
1631 if (ec != 0) ec->clear();;
1632 if (S_ISDIR(path_stat.st_mode))
1633 return fs::file_status(fs::directory_file,
1634 static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
1635 if (S_ISREG(path_stat.st_mode))
1636 return fs::file_status(fs::regular_file,
1637 static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
1638 if (S_ISBLK(path_stat.st_mode))
1639 return fs::file_status(fs::block_file,
1640 static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
1641 if (S_ISCHR(path_stat.st_mode))
1642 return fs::file_status(fs::character_file,
1643 static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
1644 if (S_ISFIFO(path_stat.st_mode))
1645 return fs::file_status(fs::fifo_file,
1646 static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
1647 if (S_ISSOCK(path_stat.st_mode))
1648 return fs::file_status(fs::socket_file,
1649 static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
1650 return fs::file_status(fs::type_unknown);
1654 DWORD attr(::GetFileAttributesW(p.c_str()));
1655 if (attr == 0xFFFFFFFF)
1657 return process_status_failure(p, ec);
1660 // reparse point handling;
1661 // since GetFileAttributesW does not resolve symlinks, try to open a file
1662 // handle to discover if the file exists
1663 if (attr & FILE_ATTRIBUTE_REPARSE_POINT)
1668 0, // dwDesiredAccess; attributes only
1669 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
1670 0, // lpSecurityAttributes
1672 FILE_FLAG_BACKUP_SEMANTICS,
1673 0)); // hTemplateFile
1674 if (h.handle == INVALID_HANDLE_VALUE)
1676 return process_status_failure(p, ec);
1679 if (!is_reparse_point_a_symlink(p))
1680 return file_status(reparse_file, make_permissions(p, attr));
1683 if (ec != 0) ec->clear();
1684 return (attr & FILE_ATTRIBUTE_DIRECTORY)
1685 ? file_status(directory_file, make_permissions(p, attr))
1686 : file_status(regular_file, make_permissions(p, attr));
1691 BOOST_FILESYSTEM_DECL
1692 file_status symlink_status(const path& p, error_code* ec)
1694 # ifdef BOOST_POSIX_API
1696 struct stat path_stat;
1697 if (::lstat(p.c_str(), &path_stat)!= 0)
1699 if (ec != 0) // always report errno, even though some
1700 ec->assign(errno, system_category()); // errno values are not status_errors
1702 if (errno == ENOENT || errno == ENOTDIR) // these are not errors
1704 return fs::file_status(fs::file_not_found, fs::no_perms);
1707 BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status",
1708 p, error_code(errno, system_category())));
1709 return fs::file_status(fs::status_error);
1711 if (ec != 0) ec->clear();
1712 if (S_ISREG(path_stat.st_mode))
1713 return fs::file_status(fs::regular_file,
1714 static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
1715 if (S_ISDIR(path_stat.st_mode))
1716 return fs::file_status(fs::directory_file,
1717 static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
1718 if (S_ISLNK(path_stat.st_mode))
1719 return fs::file_status(fs::symlink_file,
1720 static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
1721 if (S_ISBLK(path_stat.st_mode))
1722 return fs::file_status(fs::block_file,
1723 static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
1724 if (S_ISCHR(path_stat.st_mode))
1725 return fs::file_status(fs::character_file,
1726 static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
1727 if (S_ISFIFO(path_stat.st_mode))
1728 return fs::file_status(fs::fifo_file,
1729 static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
1730 if (S_ISSOCK(path_stat.st_mode))
1731 return fs::file_status(fs::socket_file,
1732 static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
1733 return fs::file_status(fs::type_unknown);
1737 DWORD attr(::GetFileAttributesW(p.c_str()));
1738 if (attr == 0xFFFFFFFF)
1740 return process_status_failure(p, ec);
1743 if (ec != 0) ec->clear();
1745 if (attr & FILE_ATTRIBUTE_REPARSE_POINT)
1746 return is_reparse_point_a_symlink(p)
1747 ? file_status(symlink_file, make_permissions(p, attr))
1748 : file_status(reparse_file, make_permissions(p, attr));
1750 return (attr & FILE_ATTRIBUTE_DIRECTORY)
1751 ? file_status(directory_file, make_permissions(p, attr))
1752 : file_status(regular_file, make_permissions(p, attr));
1757 // contributed by Jeff Flinn
1758 BOOST_FILESYSTEM_DECL
1759 path temp_directory_path(system::error_code* ec)
1761 # ifdef BOOST_POSIX_API
1762 const char* val = 0;
1764 (val = std::getenv("TMPDIR" )) ||
1765 (val = std::getenv("TMP" )) ||
1766 (val = std::getenv("TEMP" )) ||
1767 (val = std::getenv("TEMPDIR"));
1769 path p((val!=0) ? val : "/tmp");
1771 if (p.empty() || (ec&&!is_directory(p, *ec))||(!ec&&!is_directory(p)))
1774 error(true, p, ec, "boost::filesystem::temp_directory_path");
1782 std::vector<path::value_type> buf(GetTempPathW(0, NULL));
1784 if (buf.empty() || GetTempPathW(buf.size(), &buf[0])==0)
1786 if(!buf.empty()) ::SetLastError(ENOTDIR);
1787 error(true, ec, "boost::filesystem::temp_directory_path");
1793 path p(buf.begin(), buf.end());
1795 if ((ec&&!is_directory(p, *ec))||(!ec&&!is_directory(p)))
1797 ::SetLastError(ENOTDIR);
1798 error(true, p, ec, "boost::filesystem::temp_directory_path");
1806 BOOST_FILESYSTEM_DECL
1807 path system_complete(const path& p, system::error_code* ec)
1809 # ifdef BOOST_POSIX_API
1810 return (p.empty() || p.is_absolute())
1811 ? p : current_path()/ p;
1816 if (ec != 0) ec->clear();
1819 wchar_t buf[buf_size];
1821 std::size_t len = get_full_path_name(p, buf_size, buf, &pfn);
1823 if (error(len == 0, p, ec, "boost::filesystem::system_complete"))
1826 if (len < buf_size)// len does not include null termination character
1827 return path(&buf[0]);
1829 boost::scoped_array<wchar_t> big_buf(new wchar_t[len]);
1831 return error(get_full_path_name(p, len , big_buf.get(), &pfn)== 0,
1832 p, ec, "boost::filesystem::system_complete")
1834 : path(big_buf.get());
1838 } // namespace detail
1840 //--------------------------------------------------------------------------------------//
1842 // directory_entry //
1844 //--------------------------------------------------------------------------------------//
1847 directory_entry::m_get_status(system::error_code* ec) const
1849 if (!status_known(m_status))
1851 // optimization: if the symlink status is known, and it isn't a symlink,
1852 // then status and symlink_status are identical so just copy the
1853 // symlink status to the regular status.
1854 if (status_known(m_symlink_status)
1855 && !is_symlink(m_symlink_status))
1857 m_status = m_symlink_status;
1858 if (ec != 0) ec->clear();
1860 else m_status = detail::status(m_path, ec);
1862 else if (ec != 0) ec->clear();
1867 directory_entry::m_get_symlink_status(system::error_code* ec) const
1869 if (!status_known(m_symlink_status))
1870 m_symlink_status = detail::symlink_status(m_path, ec);
1871 else if (ec != 0) ec->clear();
1872 return m_symlink_status;
1875 // dispatch directory_entry supplied here rather than in
1876 // <boost/filesystem/path_traits.hpp>, thus avoiding header circularity.
1877 // test cases are in operations_unit_test.cpp
1879 namespace path_traits
1881 void dispatch(const directory_entry & de,
1882 # ifdef BOOST_WINDOWS_API
1887 const codecvt_type &)
1889 to = de.path().native();
1892 void dispatch(const directory_entry & de,
1893 # ifdef BOOST_WINDOWS_API
1900 to = de.path().native();
1902 } // namespace path_traits
1903 } // namespace filesystem
1904 } // namespace boost
1906 //--------------------------------------------------------------------------------------//
1908 // directory_iterator //
1910 //--------------------------------------------------------------------------------------//
1914 # ifdef BOOST_POSIX_API
1916 error_code path_max(std::size_t & result)
1917 // this code is based on Stevens and Rago, Advanced Programming in the
1918 // UNIX envirnment, 2nd Ed., ISBN 0-201-43307-9, page 49
1921 static std::size_t max = PATH_MAX;
1923 static std::size_t max = 0;
1928 long tmp = ::pathconf("/", _PC_NAME_MAX);
1931 if (errno == 0)// indeterminate
1932 max = 4096; // guess
1933 else return error_code(errno, system_category());
1935 else max = static_cast<std::size_t>(tmp + 1); // relative root
1941 #if defined(__PGI) && defined(__USE_FILE_OFFSET64)
1942 #define dirent dirent64
1945 error_code dir_itr_first(void *& handle, void *& buffer,
1946 const char* dir, string& target,
1947 fs::file_status &, fs::file_status &)
1949 if ((handle = ::opendir(dir))== 0)
1950 return error_code(errno, system_category());
1951 target = string("."); // string was static but caused trouble
1952 // when iteration called from dtor, after
1953 // static had already been destroyed
1954 std::size_t path_size (0); // initialization quiets gcc warning (ticket #3509)
1955 error_code ec = path_max(path_size);
1958 buffer = std::malloc((sizeof(dirent) - sizeof(de.d_name))
1959 + path_size + 1); // + 1 for "/0"
1963 // warning: the only dirent member updated is d_name
1964 inline int readdir_r_simulator(DIR * dirp, struct dirent * entry,
1965 struct dirent ** result)// *result set to 0 on end of directory
1969 # if !defined(__CYGWIN__)\
1970 && defined(_POSIX_THREAD_SAFE_FUNCTIONS)\
1971 && defined(_SC_THREAD_SAFE_FUNCTIONS)\
1972 && (_POSIX_THREAD_SAFE_FUNCTIONS+0 >= 0)\
1973 && (!defined(__hpux) || defined(_REENTRANT)) \
1974 && (!defined(_AIX) || defined(__THREAD_SAFE))
1975 if (::sysconf(_SC_THREAD_SAFE_FUNCTIONS)>= 0)
1976 { return ::readdir_r(dirp, entry, result); }
1981 if ((p = ::readdir(dirp))== 0)
1983 std::strcpy(entry->d_name, p->d_name);
1988 error_code dir_itr_increment(void *& handle, void *& buffer,
1989 string& target, fs::file_status & sf, fs::file_status & symlink_sf)
1991 BOOST_ASSERT(buffer != 0);
1992 dirent * entry(static_cast<dirent *>(buffer));
1995 if ((return_code = readdir_r_simulator(static_cast<DIR*>(handle), entry, &result))!= 0)
1996 return error_code(errno, system_category());
1998 return fs::detail::dir_itr_close(handle, buffer);
1999 target = entry->d_name;
2000 # ifdef BOOST_FILESYSTEM_STATUS_CACHE
2001 if (entry->d_type == DT_UNKNOWN) // filesystem does not supply d_type value
2003 sf = symlink_sf = fs::file_status(fs::status_error);
2005 else // filesystem supplies d_type value
2007 if (entry->d_type == DT_DIR)
2008 sf = symlink_sf = fs::file_status(fs::directory_file);
2009 else if (entry->d_type == DT_REG)
2010 sf = symlink_sf = fs::file_status(fs::regular_file);
2011 else if (entry->d_type == DT_LNK)
2013 sf = fs::file_status(fs::status_error);
2014 symlink_sf = fs::file_status(fs::symlink_file);
2016 else sf = symlink_sf = fs::file_status(fs::status_error);
2019 sf = symlink_sf = fs::file_status(fs::status_error);
2024 # else // BOOST_WINDOWS_API
2026 error_code dir_itr_first(void *& handle, const fs::path& dir,
2027 wstring& target, fs::file_status & sf, fs::file_status & symlink_sf)
2028 // Note: an empty root directory has no "." or ".." entries, so this
2029 // causes a ERROR_FILE_NOT_FOUND error which we do not considered an
2030 // error. It is treated as eof instead.
2032 // use a form of search Sebastian Martel reports will work with Win98
2033 wstring dirpath(dir.wstring());
2034 dirpath += (dirpath.empty()
2035 || (dirpath[dirpath.size()-1] != L'\\'
2036 && dirpath[dirpath.size()-1] != L'/'
2037 && dirpath[dirpath.size()-1] != L':'))? L"\\*" : L"*";
2039 WIN32_FIND_DATAW data;
2040 if ((handle = ::FindFirstFileW(dirpath.c_str(), &data))
2041 == INVALID_HANDLE_VALUE)
2043 handle = 0; // signal eof
2044 return error_code( (::GetLastError() == ERROR_FILE_NOT_FOUND
2045 // Windows Mobile returns ERROR_NO_MORE_FILES; see ticket #3551
2046 || ::GetLastError() == ERROR_NO_MORE_FILES)
2047 ? 0 : ::GetLastError(), system_category() );
2049 target = data.cFileName;
2050 if (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
2051 // reparse points are complex, so don't try to handle them here; instead just mark
2052 // them as status_error which causes directory_entry caching to call status()
2053 // and symlink_status() which do handle reparse points fully
2055 sf.type(fs::status_error);
2056 symlink_sf.type(fs::status_error);
2060 if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2062 sf.type(fs::directory_file);
2063 symlink_sf.type(fs::directory_file);
2067 sf.type(fs::regular_file);
2068 symlink_sf.type(fs::regular_file);
2070 sf.permissions(make_permissions(data.cFileName, data.dwFileAttributes));
2071 symlink_sf.permissions(sf.permissions());
2073 return error_code();
2076 error_code dir_itr_increment(void *& handle, wstring& target,
2077 fs::file_status & sf, fs::file_status & symlink_sf)
2079 WIN32_FIND_DATAW data;
2080 if (::FindNextFileW(handle, &data)== 0)// fails
2082 int error = ::GetLastError();
2083 fs::detail::dir_itr_close(handle);
2084 return error_code(error == ERROR_NO_MORE_FILES ? 0 : error, system_category());
2086 target = data.cFileName;
2087 if (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
2088 // reparse points are complex, so don't try to handle them here; instead just mark
2089 // them as status_error which causes directory_entry caching to call status()
2090 // and symlink_status() which do handle reparse points fully
2092 sf.type(fs::status_error);
2093 symlink_sf.type(fs::status_error);
2097 if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2099 sf.type(fs::directory_file);
2100 symlink_sf.type(fs::directory_file);
2104 sf.type(fs::regular_file);
2105 symlink_sf.type(fs::regular_file);
2107 sf.permissions(make_permissions(data.cFileName, data.dwFileAttributes));
2108 symlink_sf.permissions(sf.permissions());
2110 return error_code();
2114 const error_code not_found_error_code (
2115 # ifdef BOOST_WINDOWS_API
2116 ERROR_PATH_NOT_FOUND
2120 , system_category());
2122 } // unnamed namespace
2126 namespace filesystem
2131 // dir_itr_close is called both from the ~dir_itr_imp()destructor
2132 // and dir_itr_increment()
2133 BOOST_FILESYSTEM_DECL
2134 system::error_code dir_itr_close( // never throws
2136 # if defined(BOOST_POSIX_API)
2141 # ifdef BOOST_POSIX_API
2144 if (handle == 0)return ok;
2145 DIR * h(static_cast<DIR*>(handle));
2147 return error_code(::closedir(h)== 0 ? 0 : errno, system_category());
2152 ::FindClose(handle);
2160 void directory_iterator_construct(directory_iterator& it,
2161 const path& p, system::error_code* ec)
2163 if (error(p.empty(), not_found_error_code, p, ec,
2164 "boost::filesystem::directory_iterator::construct"))
2167 path::string_type filename;
2168 file_status file_stat, symlink_file_stat;
2169 error_code result = dir_itr_first(it.m_imp->handle,
2170 # if defined(BOOST_POSIX_API)
2173 p.c_str(), filename, file_stat, symlink_file_stat);
2178 error(true, result, p,
2179 ec, "boost::filesystem::directory_iterator::construct");
2183 if (it.m_imp->handle == 0)
2184 it.m_imp.reset(); // eof, so make end iterator
2187 it.m_imp->dir_entry.assign(p / filename, file_stat, symlink_file_stat);
2188 if (filename[0] == dot // dot or dot-dot
2189 && (filename.size()== 1
2190 || (filename[1] == dot
2191 && filename.size()== 2)))
2192 { it.increment(*ec); }
2196 void directory_iterator_increment(directory_iterator& it,
2197 system::error_code* ec)
2199 BOOST_ASSERT_MSG(it.m_imp.get(), "attempt to increment end iterator");
2200 BOOST_ASSERT_MSG(it.m_imp->handle != 0, "internal program error");
2202 path::string_type filename;
2203 file_status file_stat, symlink_file_stat;
2204 system::error_code temp_ec;
2208 temp_ec = dir_itr_increment(it.m_imp->handle,
2209 # if defined(BOOST_POSIX_API)
2212 filename, file_stat, symlink_file_stat);
2214 if (temp_ec) // happens if filesystem is corrupt, such as on a damaged optical disc
2216 path error_path(it.m_imp->dir_entry.path().parent_path()); // fix ticket #5900
2219 BOOST_FILESYSTEM_THROW(
2220 filesystem_error("boost::filesystem::directory_iterator::operator++",
2222 error_code(BOOST_ERRNO, system_category())));
2223 ec->assign(BOOST_ERRNO, system_category());
2226 else if (ec != 0) ec->clear();
2228 if (it.m_imp->handle == 0) // eof, make end
2234 if (!(filename[0] == dot // !(dot or dot-dot)
2235 && (filename.size()== 1
2236 || (filename[1] == dot
2237 && filename.size()== 2))))
2239 it.m_imp->dir_entry.replace_filename(
2240 filename, file_stat, symlink_file_stat);
2245 } // namespace detail
2246 } // namespace filesystem
2247 } // namespace boost