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 && !defined(__VXWORKS__)
76 # include <sys/statvfs.h>
77 # define BOOST_STATVFS statvfs
78 # define BOOST_STATVFS_F_FRSIZE vfs.f_frsize
81 # include <sys/param.h>
82 # elif defined(__ANDROID__)
85 # if !defined(__VXWORKS__)
86 # include <sys/mount.h>
88 # define BOOST_STATVFS statfs
89 # define BOOST_STATVFS_F_FRSIZE static_cast<boost::uintmax_t>(vfs.f_bsize)
97 # else // BOOST_WINDOW_API
99 # if (defined(__MINGW32__) || defined(__CYGWIN__)) && !defined(WINVER)
100 // Versions of MinGW or Cygwin that support Filesystem V3 support at least WINVER 0x501.
101 // See MinGW's windef.h
102 # define WINVER 0x501
105 # include <windows.h>
107 # if !defined(_WIN32_WINNT)
108 # define _WIN32_WINNT 0x0500
110 # if defined(__BORLANDC__) || defined(__MWERKS__)
111 # if defined(__BORLANDC__)
116 # include <sys/utime.h>
119 // REPARSE_DATA_BUFFER related definitions are found in ntifs.h, which is part of the
120 // Windows Device Driver Kit. Since that's inconvenient, the definitions are provided
121 // here. See http://msdn.microsoft.com/en-us/library/ms791514.aspx
123 #if !defined(REPARSE_DATA_BUFFER_HEADER_SIZE) // mingw winnt.h does provide the defs
125 #define SYMLINK_FLAG_RELATIVE 1
127 typedef struct _REPARSE_DATA_BUFFER
{
129 USHORT ReparseDataLength
;
133 USHORT SubstituteNameOffset
;
134 USHORT SubstituteNameLength
;
135 USHORT PrintNameOffset
;
136 USHORT PrintNameLength
;
139 /* Example of distinction between substitute and print names:
141 SubstituteName: c:\\??\
144 } SymbolicLinkReparseBuffer
;
146 USHORT SubstituteNameOffset
;
147 USHORT SubstituteNameLength
;
148 USHORT PrintNameOffset
;
149 USHORT PrintNameLength
;
151 } MountPointReparseBuffer
;
154 } GenericReparseBuffer
;
156 } REPARSE_DATA_BUFFER
, *PREPARSE_DATA_BUFFER
;
158 #define REPARSE_DATA_BUFFER_HEADER_SIZE \
159 FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer)
163 #ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE
164 #define MAXIMUM_REPARSE_DATA_BUFFER_SIZE ( 16 * 1024 )
167 # ifndef FSCTL_GET_REPARSE_POINT
168 # define FSCTL_GET_REPARSE_POINT 0x900a8
171 # ifndef IO_REPARSE_TAG_SYMLINK
172 # define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
175 inline std::wstring
wgetenv(const wchar_t* name
)
177 // use vector since for C++03 basic_string is not required to be contiguous
178 std::vector
<wchar_t> buf(::GetEnvironmentVariableW(name
, NULL
, 0));
180 // C++03 vector does not have data() so use &buf[0]
182 || ::GetEnvironmentVariableW(name
, &buf
[0], static_cast<DWORD
>(buf
.size())) == 0)
183 ? std::wstring() : std::wstring(&buf
[0]);
186 # endif // BOOST_WINDOWS_API
188 // BOOST_FILESYSTEM_STATUS_CACHE enables file_status cache in
189 // dir_itr_increment. The config tests are placed here because some of the
190 // macros being tested come from dirent.h.
192 // TODO: find out what macros indicate dirent::d_type present in more libraries
193 # if defined(BOOST_WINDOWS_API)\
194 || defined(_DIRENT_HAVE_D_TYPE)// defined by GNU C library if d_type present
195 # define BOOST_FILESYSTEM_STATUS_CACHE
198 // POSIX/Windows macros ----------------------------------------------------//
200 // Portions of the POSIX and Windows API's are very similar, except for name,
201 // order of arguments, and meaning of zero/non-zero returns. The macros below
202 // abstract away those differences. They follow Windows naming and order of
203 // arguments, and return true to indicate no error occurred. [POSIX naming,
204 // order of arguments, and meaning of return were followed initially, but
205 // found to be less clear and cause more coding errors.]
207 # if defined(BOOST_POSIX_API)
211 // POSIX uses a 0 return to indicate success
212 # define BOOST_ERRNO errno
213 # define BOOST_SET_CURRENT_DIRECTORY(P)(::chdir(P)== 0)
214 # define BOOST_CREATE_DIRECTORY(P)(::mkdir(P, S_IRWXU|S_IRWXG|S_IRWXO)== 0)
215 # define BOOST_CREATE_HARD_LINK(F,T)(::link(T, F)== 0)
216 # define BOOST_CREATE_SYMBOLIC_LINK(F,T,Flag)(::symlink(T, F)== 0)
217 # define BOOST_REMOVE_DIRECTORY(P)(::rmdir(P)== 0)
218 # define BOOST_DELETE_FILE(P)(::unlink(P)== 0)
219 # define BOOST_COPY_DIRECTORY(F,T)(!(::stat(from.c_str(), &from_stat)!= 0\
220 || ::mkdir(to.c_str(),from_stat.st_mode)!= 0))
221 # define BOOST_COPY_FILE(F,T,FailIfExistsBool)copy_file_api(F, T, FailIfExistsBool)
222 # define BOOST_MOVE_FILE(OLD,NEW)(::rename(OLD, NEW)== 0)
223 # define BOOST_RESIZE_FILE(P,SZ)(::truncate(P, SZ)== 0)
225 # define BOOST_ERROR_NOT_SUPPORTED ENOSYS
226 # define BOOST_ERROR_ALREADY_EXISTS EEXIST
228 # else // BOOST_WINDOWS_API
232 // Windows uses a non-0 return to indicate success
233 # define BOOST_ERRNO ::GetLastError()
234 # define BOOST_SET_CURRENT_DIRECTORY(P)(::SetCurrentDirectoryW(P)!= 0)
235 # define BOOST_CREATE_DIRECTORY(P)(::CreateDirectoryW(P, 0)!= 0)
236 # define BOOST_CREATE_HARD_LINK(F,T)(create_hard_link_api(F, T, 0)!= 0)
237 # define BOOST_CREATE_SYMBOLIC_LINK(F,T,Flag)(create_symbolic_link_api(F, T, Flag)!= 0)
238 # define BOOST_REMOVE_DIRECTORY(P)(::RemoveDirectoryW(P)!= 0)
239 # define BOOST_DELETE_FILE(P)(::DeleteFileW(P)!= 0)
240 # define BOOST_COPY_DIRECTORY(F,T)(::CreateDirectoryExW(F, T, 0)!= 0)
241 # define BOOST_COPY_FILE(F,T,FailIfExistsBool)(::CopyFileW(F, T, FailIfExistsBool)!= 0)
242 # define BOOST_MOVE_FILE(OLD,NEW)(::MoveFileExW(OLD, NEW, MOVEFILE_REPLACE_EXISTING|MOVEFILE_COPY_ALLOWED)!= 0)
243 # define BOOST_RESIZE_FILE(P,SZ)(resize_file_api(P, SZ)!= 0)
244 # define BOOST_READ_SYMLINK(P,T)
246 # define BOOST_ERROR_ALREADY_EXISTS ERROR_ALREADY_EXISTS
247 # define BOOST_ERROR_NOT_SUPPORTED ERROR_NOT_SUPPORTED
251 //--------------------------------------------------------------------------------------//
253 // helpers (all operating systems) //
255 //--------------------------------------------------------------------------------------//
260 fs::file_type
query_file_type(const path
& p
, error_code
* ec
);
262 boost::filesystem::directory_iterator end_dir_itr
;
264 // error handling helpers ----------------------------------------------------------//
266 bool error(err_t error_num
, error_code
* ec
, const char* message
);
267 bool error(err_t error_num
, const path
& p
, error_code
* ec
, const char* message
);
268 bool error(err_t error_num
, const path
& p1
, const path
& p2
, error_code
* ec
,
269 const char* message
);
273 // error_num is value of errno on POSIX, error code (from ::GetLastError()) on Windows.
274 // Interface changed 30 Jan 15 to have caller supply error_num as ::SetLastError()
275 // values were apparently getting cleared before they could be retrieved by error().
277 bool error(err_t error_num
, error_code
* ec
, const char* message
)
281 if (ec
!= 0) ec
->clear();
286 BOOST_FILESYSTEM_THROW(filesystem_error(message
,
287 error_code(error_num
, system_category())));
289 ec
->assign(error_num
, system_category());
291 return error_num
!= 0;
294 bool error(err_t error_num
, const path
& p
, error_code
* ec
, const char* message
)
298 if (ec
!= 0) ec
->clear();
303 BOOST_FILESYSTEM_THROW(filesystem_error(message
,
304 p
, error_code(error_num
, system_category())));
306 ec
->assign(error_num
, system_category());
308 return error_num
!= 0;
311 bool error(err_t error_num
, const path
& p1
, const path
& p2
, error_code
* ec
,
316 if (ec
!= 0) ec
->clear();
321 BOOST_FILESYSTEM_THROW(filesystem_error(message
,
322 p1
, p2
, error_code(error_num
, system_category())));
324 ec
->assign(error_num
, system_category());
326 return error_num
!= 0;
329 // general helpers -----------------------------------------------------------------//
331 bool is_empty_directory(const path
& p
)
333 return fs::directory_iterator(p
)== end_dir_itr
;
336 bool not_found_error(int errval
); // forward declaration
338 // only called if directory exists
339 bool remove_directory(const path
& p
) // true if succeeds or not found
341 return BOOST_REMOVE_DIRECTORY(p
.c_str())
342 || not_found_error(BOOST_ERRNO
); // mitigate possible file system race. See #11166
345 // only called if file exists
346 bool remove_file(const path
& p
) // true if succeeds or not found
348 return BOOST_DELETE_FILE(p
.c_str())
349 || not_found_error(BOOST_ERRNO
); // mitigate possible file system race. See #11166
352 // called by remove and remove_all_aux
353 bool remove_file_or_directory(const path
& p
, fs::file_type type
, error_code
* ec
)
354 // return true if file removed, false if not removed
356 if (type
== fs::file_not_found
)
358 if (ec
!= 0) ec
->clear();
362 if (type
== fs::directory_file
363 # ifdef BOOST_WINDOWS_API
364 || type
== fs::_detail_directory_symlink
368 if (error(!remove_directory(p
) ? BOOST_ERRNO
: 0, p
, ec
,
369 "boost::filesystem::remove"))
374 if (error(!remove_file(p
) ? BOOST_ERRNO
: 0, p
, ec
,
375 "boost::filesystem::remove"))
381 boost::uintmax_t remove_all_aux(const path
& p
, fs::file_type type
,
384 boost::uintmax_t count
= 1;
386 if (type
== fs::directory_file
) // but not a directory symlink
388 for (fs::directory_iterator
itr(p
);
389 itr
!= end_dir_itr
; ++itr
)
391 fs::file_type tmp_type
= query_file_type(itr
->path(), ec
);
394 count
+= remove_all_aux(itr
->path(), tmp_type
, ec
);
397 remove_file_or_directory(p
, type
, ec
);
401 #ifdef BOOST_POSIX_API
403 //--------------------------------------------------------------------------------------//
405 // POSIX-specific helpers //
407 //--------------------------------------------------------------------------------------//
409 const char dot
= '.';
411 bool not_found_error(int errval
)
413 return errno
== ENOENT
|| errno
== ENOTDIR
;
417 copy_file_api(const std::string
& from_p
,
418 const std::string
& to_p
, bool fail_if_exists
)
420 const std::size_t buf_sz
= 32768;
421 boost::scoped_array
<char> buf(new char [buf_sz
]);
422 int infile
=-1, outfile
=-1; // -1 means not open
424 // bug fixed: code previously did a stat()on the from_file first, but that
425 // introduced a gratuitous race condition; the stat()is now done after the open()
427 if ((infile
= ::open(from_p
.c_str(), O_RDONLY
))< 0)
430 struct stat from_stat
;
431 if (::stat(from_p
.c_str(), &from_stat
)!= 0)
437 int oflag
= O_CREAT
| O_WRONLY
| O_TRUNC
;
440 if ((outfile
= ::open(to_p
.c_str(), oflag
, from_stat
.st_mode
))< 0)
442 int open_errno
= errno
;
443 BOOST_ASSERT(infile
>= 0);
449 ssize_t sz
, sz_read
=1, sz_write
;
451 && (sz_read
= ::read(infile
, buf
.get(), buf_sz
)) > 0)
453 // Allow for partial writes - see Advanced Unix Programming (2nd Ed.),
454 // Marc Rochkind, Addison-Wesley, 2004, page 94
458 BOOST_ASSERT(sz_read
- sz_write
> 0); // #1
459 // ticket 4438 claimed possible infinite loop if write returns 0. My analysis
460 // is that POSIX specifies 0 return only if 3rd arg is 0, and that will never
461 // happen due to loop entry and coninuation conditions. BOOST_ASSERT #1 above
462 // and #2 below added to verify that analysis.
463 if ((sz
= ::write(outfile
, buf
.get() + sz_write
,
464 sz_read
- sz_write
)) < 0)
466 sz_read
= sz
; // cause read loop termination
467 break; // and error reported after closes
469 BOOST_ASSERT(sz
> 0); // #2
471 } while (sz_write
< sz_read
);
474 if (::close(infile
)< 0)
476 if (::close(outfile
)< 0)
482 inline fs::file_type
query_file_type(const path
& p
, error_code
* ec
)
484 return fs::detail::symlink_status(p
, ec
).type();
489 //--------------------------------------------------------------------------------------//
491 // Windows-specific helpers //
493 //--------------------------------------------------------------------------------------//
495 const std::size_t buf_size
=128;
497 const wchar_t dot
= L
'.';
499 bool not_found_error(int errval
)
501 return errval
== ERROR_FILE_NOT_FOUND
502 || errval
== ERROR_PATH_NOT_FOUND
503 || errval
== ERROR_INVALID_NAME
// "tools/jam/src/:sys:stat.h", "//foo"
504 || errval
== ERROR_INVALID_DRIVE
// USB card reader with no card inserted
505 || errval
== ERROR_NOT_READY
// CD/DVD drive with no disc inserted
506 || errval
== ERROR_INVALID_PARAMETER
// ":sys:stat.h"
507 || errval
== ERROR_BAD_PATHNAME
// "//nosuch" on Win64
508 || errval
== ERROR_BAD_NETPATH
; // "//nosuch" on Win32
511 // some distributions of mingw as early as GLIBCXX__ 20110325 have _stricmp, but the
512 // offical 4.6.2 release with __GLIBCXX__ 20111026 doesn't. Play it safe for now, and
513 // only use _stricmp if _MSC_VER is defined
514 #if defined(_MSC_VER) // || (defined(__GLIBCXX__) && __GLIBCXX__ >= 20110325)
515 # define BOOST_FILESYSTEM_STRICMP _stricmp
517 # define BOOST_FILESYSTEM_STRICMP strcmp
520 perms
make_permissions(const path
& p
, DWORD attr
)
522 perms prms
= fs::owner_read
| fs::group_read
| fs::others_read
;
523 if ((attr
& FILE_ATTRIBUTE_READONLY
) == 0)
524 prms
|= fs::owner_write
| fs::group_write
| fs::others_write
;
525 if (BOOST_FILESYSTEM_STRICMP(p
.extension().string().c_str(), ".exe") == 0
526 || BOOST_FILESYSTEM_STRICMP(p
.extension().string().c_str(), ".com") == 0
527 || BOOST_FILESYSTEM_STRICMP(p
.extension().string().c_str(), ".bat") == 0
528 || BOOST_FILESYSTEM_STRICMP(p
.extension().string().c_str(), ".cmd") == 0)
529 prms
|= fs::owner_exe
| fs::group_exe
| fs::others_exe
;
533 // these constants come from inspecting some Microsoft sample code
534 std::time_t to_time_t(const FILETIME
& ft
)
536 __int64 t
= (static_cast<__int64
>(ft
.dwHighDateTime
)<< 32)
538 # if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 // > VC++ 7.0
539 t
-= 116444736000000000LL;
541 t
-= 116444736000000000;
544 return static_cast<std::time_t>(t
);
547 void to_FILETIME(std::time_t t
, FILETIME
& ft
)
551 # if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 // > VC++ 7.0
552 temp
+= 116444736000000000LL;
554 temp
+= 116444736000000000;
556 ft
.dwLowDateTime
= static_cast<DWORD
>(temp
);
557 ft
.dwHighDateTime
= static_cast<DWORD
>(temp
>> 32);
560 // Thanks to Jeremy Maitin-Shepard for much help and for permission to
561 // base the equivalent()implementation on portions of his
562 // file-equivalence-win32.cpp experimental code.
564 struct handle_wrapper
567 handle_wrapper(HANDLE h
)
571 if (handle
!= INVALID_HANDLE_VALUE
)
572 ::CloseHandle(handle
);
576 HANDLE
create_file_handle(const path
& p
, DWORD dwDesiredAccess
,
577 DWORD dwShareMode
, LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
578 DWORD dwCreationDisposition
, DWORD dwFlagsAndAttributes
,
579 HANDLE hTemplateFile
)
581 return ::CreateFileW(p
.c_str(), dwDesiredAccess
, dwShareMode
,
582 lpSecurityAttributes
, dwCreationDisposition
, dwFlagsAndAttributes
,
586 bool is_reparse_point_a_symlink(const path
& p
)
588 handle_wrapper
h(create_file_handle(p
, FILE_READ_EA
,
589 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
, NULL
, OPEN_EXISTING
,
590 FILE_FLAG_BACKUP_SEMANTICS
| FILE_FLAG_OPEN_REPARSE_POINT
, NULL
));
591 if (h
.handle
== INVALID_HANDLE_VALUE
)
594 boost::scoped_array
<char> buf(new char [MAXIMUM_REPARSE_DATA_BUFFER_SIZE
]);
596 // Query the reparse data
598 BOOL result
= ::DeviceIoControl(h
.handle
, FSCTL_GET_REPARSE_POINT
, NULL
, 0, buf
.get(),
599 MAXIMUM_REPARSE_DATA_BUFFER_SIZE
, &dwRetLen
, NULL
);
600 if (!result
) return false;
602 return reinterpret_cast<const REPARSE_DATA_BUFFER
*>(buf
.get())->ReparseTag
603 == IO_REPARSE_TAG_SYMLINK
604 // Issue 9016 asked that NTFS directory junctions be recognized as directories.
605 // That is equivalent to recognizing them as symlinks, and then the normal symlink
606 // mechanism will take care of recognizing them as directories.
608 // Directory junctions are very similar to symlinks, but have some performance
609 // and other advantages over symlinks. They can be created from the command line
610 // with "mklink /j junction-name target-path".
611 || reinterpret_cast<const REPARSE_DATA_BUFFER
*>(buf
.get())->ReparseTag
612 == IO_REPARSE_TAG_MOUNT_POINT
; // aka "directory junction" or "junction"
615 inline std::size_t get_full_path_name(
616 const path
& src
, std::size_t len
, wchar_t* buf
, wchar_t** p
)
618 return static_cast<std::size_t>(
619 ::GetFullPathNameW(src
.c_str(), static_cast<DWORD
>(len
), buf
, p
));
622 fs::file_status
process_status_failure(const path
& p
, error_code
* ec
)
624 int errval(::GetLastError());
625 if (ec
!= 0) // always report errval, even though some
626 ec
->assign(errval
, system_category()); // errval values are not status_errors
628 if (not_found_error(errval
))
630 return fs::file_status(fs::file_not_found
, fs::no_perms
);
632 else if ((errval
== ERROR_SHARING_VIOLATION
))
634 return fs::file_status(fs::type_unknown
);
637 BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status",
638 p
, error_code(errval
, system_category())));
639 return fs::file_status(fs::status_error
);
642 // differs from symlink_status() in that directory symlinks are reported as
643 // _detail_directory_symlink, as required on Windows by remove() and its helpers.
644 fs::file_type
query_file_type(const path
& p
, error_code
* ec
)
646 DWORD
attr(::GetFileAttributesW(p
.c_str()));
647 if (attr
== 0xFFFFFFFF)
649 return process_status_failure(p
, ec
).type();
652 if (ec
!= 0) ec
->clear();
654 if (attr
& FILE_ATTRIBUTE_REPARSE_POINT
)
656 if (is_reparse_point_a_symlink(p
))
657 return (attr
& FILE_ATTRIBUTE_DIRECTORY
)
658 ? fs::_detail_directory_symlink
660 return fs::reparse_file
;
663 return (attr
& FILE_ATTRIBUTE_DIRECTORY
)
668 BOOL
resize_file_api(const wchar_t* p
, boost::uintmax_t size
)
670 handle_wrapper
h(CreateFileW(p
, GENERIC_WRITE
, 0, 0, OPEN_EXISTING
,
671 FILE_ATTRIBUTE_NORMAL
, 0));
674 return h
.handle
!= INVALID_HANDLE_VALUE
675 && ::SetFilePointerEx(h
.handle
, sz
, 0, FILE_BEGIN
)
676 && ::SetEndOfFile(h
.handle
);
679 // Windows kernel32.dll functions that may or may not be present
680 // must be accessed through pointers
682 typedef BOOL (WINAPI
*PtrCreateHardLinkW
)(
683 /*__in*/ LPCWSTR lpFileName
,
684 /*__in*/ LPCWSTR lpExistingFileName
,
685 /*__reserved*/ LPSECURITY_ATTRIBUTES lpSecurityAttributes
688 PtrCreateHardLinkW create_hard_link_api
= PtrCreateHardLinkW(
690 ::GetModuleHandle(TEXT("kernel32.dll")), "CreateHardLinkW"));
692 typedef BOOLEAN (WINAPI
*PtrCreateSymbolicLinkW
)(
693 /*__in*/ LPCWSTR lpSymlinkFileName
,
694 /*__in*/ LPCWSTR lpTargetFileName
,
695 /*__in*/ DWORD dwFlags
698 PtrCreateSymbolicLinkW create_symbolic_link_api
= PtrCreateSymbolicLinkW(
700 ::GetModuleHandle(TEXT("kernel32.dll")), "CreateSymbolicLinkW"));
704 //#ifdef BOOST_WINDOWS_API
707 // inline bool get_free_disk_space(const std::wstring& ph,
708 // PULARGE_INTEGER avail, PULARGE_INTEGER total, PULARGE_INTEGER free)
709 // { return ::GetDiskFreeSpaceExW(ph.c_str(), avail, total, free)!= 0; }
713 } // unnamed namespace
715 //--------------------------------------------------------------------------------------//
717 // operations functions declared in operations.hpp //
718 // in alphabetic order //
720 //--------------------------------------------------------------------------------------//
727 BOOST_FILESYSTEM_DECL
728 path
absolute(const path
& p
, const path
& base
)
730 // if ( p.empty() || p.is_absolute() )
732 // // recursively calling absolute is sub-optimal, but is simple
733 // path abs_base(base.is_absolute() ? base : absolute(base));
734 //# ifdef BOOST_WINDOWS_API
735 // if (p.has_root_directory())
736 // return abs_base.root_name() / p;
737 // // !p.has_root_directory
738 // if (p.has_root_name())
739 // return p.root_name()
740 // / abs_base.root_directory() / abs_base.relative_path() / p.relative_path();
741 // // !p.has_root_name()
743 // return abs_base / p;
745 // recursively calling absolute is sub-optimal, but is sure and simple
746 path
abs_base(base
.is_absolute() ? base
: absolute(base
));
748 // store expensive to compute values that are needed multiple times
749 path
p_root_name (p
.root_name());
750 path
base_root_name (abs_base
.root_name());
751 path
p_root_directory (p
.root_directory());
756 if (!p_root_name
.empty()) // p.has_root_name()
758 if (p_root_directory
.empty()) // !p.has_root_directory()
759 return p_root_name
/ abs_base
.root_directory()
760 / abs_base
.relative_path() / p
.relative_path();
761 // p is absolute, so fall through to return p at end of block
764 else if (!p_root_directory
.empty()) // p.has_root_directory()
766 # ifdef BOOST_POSIX_API
767 // POSIX can have root name it it is a network path
768 if (base_root_name
.empty()) // !abs_base.has_root_name()
771 return base_root_name
/ p
;
779 return p
; // p.is_absolute() is true
784 BOOST_FILESYSTEM_DECL
bool possible_large_file_size_support()
786 # ifdef BOOST_POSIX_API
787 struct stat lcl_stat
;
788 return sizeof(lcl_stat
.st_size
)> 4;
794 BOOST_FILESYSTEM_DECL
795 path
canonical(const path
& p
, const path
& base
, system::error_code
* ec
)
797 path
source (p
.is_absolute() ? p
: absolute(p
, base
));
798 path
root(source
.root_path());
801 system::error_code local_ec
;
802 file_status
stat (status(source
, local_ec
));
804 if (stat
.type() == fs::file_not_found
)
807 BOOST_FILESYSTEM_THROW(filesystem_error(
808 "boost::filesystem::canonical", source
,
809 error_code(system::errc::no_such_file_or_directory
, system::generic_category())));
810 ec
->assign(system::errc::no_such_file_or_directory
, system::generic_category());
816 BOOST_FILESYSTEM_THROW(filesystem_error(
817 "boost::filesystem::canonical", source
, local_ec
));
827 for (path::iterator itr
= source
.begin(); itr
!= source
.end(); ++itr
)
829 if (*itr
== dot_path())
831 if (*itr
== dot_dot_path())
834 result
.remove_filename();
840 bool is_sym (is_symlink(detail::symlink_status(result
, ec
)));
846 path
link(detail::read_symlink(result
, ec
));
849 result
.remove_filename();
851 if (link
.is_absolute())
853 for (++itr
; itr
!= source
.end(); ++itr
)
857 else // link is relative
859 path
new_source(result
);
861 for (++itr
; itr
!= source
.end(); ++itr
)
865 scan
= true; // symlink causes scan to be restarted
872 BOOST_ASSERT_MSG(result
.is_absolute(), "canonical() implementation error; please report");
876 BOOST_FILESYSTEM_DECL
877 void copy(const path
& from
, const path
& to
, system::error_code
* ec
)
879 file_status
s(symlink_status(from
, *ec
));
880 if (ec
!= 0 && *ec
) return;
884 copy_symlink(from
, to
, *ec
);
886 else if(is_directory(s
))
888 copy_directory(from
, to
, *ec
);
890 else if(is_regular_file(s
))
892 copy_file(from
, to
, fs::copy_option::fail_if_exists
, *ec
);
897 BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::copy",
898 from
, to
, error_code(BOOST_ERROR_NOT_SUPPORTED
, system_category())));
899 ec
->assign(BOOST_ERROR_NOT_SUPPORTED
, system_category());
903 BOOST_FILESYSTEM_DECL
904 void copy_directory(const path
& from
, const path
& to
, system::error_code
* ec
)
906 # ifdef BOOST_POSIX_API
907 struct stat from_stat
;
909 error(!BOOST_COPY_DIRECTORY(from
.c_str(), to
.c_str()) ? BOOST_ERRNO
: 0,
910 from
, to
, ec
, "boost::filesystem::copy_directory");
913 BOOST_FILESYSTEM_DECL
914 void copy_file(const path
& from
, const path
& to
, copy_option option
, error_code
* ec
)
916 error(!BOOST_COPY_FILE(from
.c_str(), to
.c_str(),
917 option
== fail_if_exists
) ? BOOST_ERRNO
: 0,
918 from
, to
, ec
, "boost::filesystem::copy_file");
921 BOOST_FILESYSTEM_DECL
922 void copy_symlink(const path
& existing_symlink
, const path
& new_symlink
,
923 system::error_code
* ec
)
925 # if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0600
926 error(BOOST_ERROR_NOT_SUPPORTED
, new_symlink
, existing_symlink
, ec
,
927 "boost::filesystem::copy_symlink");
929 # else // modern Windows or BOOST_POSIX_API
930 path
p(read_symlink(existing_symlink
, ec
));
931 if (ec
!= 0 && *ec
) return;
932 create_symlink(p
, new_symlink
, ec
);
937 BOOST_FILESYSTEM_DECL
938 bool create_directories(const path
& p
, system::error_code
* ec
)
940 path
filename(p
.filename());
941 if ((filename
.native().size() == 1 && filename
.native()[0] == dot
)
942 || (filename
.native().size() == 2
943 && filename
.native()[0] == dot
&& filename
.native()[1] == dot
))
944 return create_directories(p
.parent_path(), ec
);
947 file_status p_status
= status(p
, local_ec
);
949 if (p_status
.type() == directory_file
)
956 path parent
= p
.parent_path();
957 BOOST_ASSERT_MSG(parent
!= p
, "internal error: p == p.parent_path()");
960 // determine if the parent exists
961 file_status parent_status
= status(parent
, local_ec
);
963 // if the parent does not exist, create the parent
964 if (parent_status
.type() == file_not_found
)
966 create_directories(parent
, local_ec
);
970 BOOST_FILESYSTEM_THROW(filesystem_error(
971 "boost::filesystem::create_directories", parent
, local_ec
));
979 // create the directory
980 return create_directory(p
, ec
);
983 BOOST_FILESYSTEM_DECL
984 bool create_directory(const path
& p
, error_code
* ec
)
986 if (BOOST_CREATE_DIRECTORY(p
.c_str()))
993 // attempt to create directory failed
994 int errval(BOOST_ERRNO
); // save reason for failure
996 if (errval
== BOOST_ERROR_ALREADY_EXISTS
&& is_directory(p
, dummy
))
1003 // attempt to create directory failed && it doesn't already exist
1005 BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::create_directory",
1006 p
, error_code(errval
, system_category())));
1008 ec
->assign(errval
, system_category());
1012 BOOST_FILESYSTEM_DECL
1013 void create_directory_symlink(const path
& to
, const path
& from
,
1014 system::error_code
* ec
)
1016 # if defined(BOOST_WINDOWS_API) && _WIN32_WINNT < 0x0600 // SDK earlier than Vista and Server 2008
1018 error(BOOST_ERROR_NOT_SUPPORTED
, to
, from
, ec
,
1019 "boost::filesystem::create_directory_symlink");
1022 # if defined(BOOST_WINDOWS_API) && _WIN32_WINNT >= 0x0600
1023 // see if actually supported by Windows runtime dll
1024 if (error(!create_symbolic_link_api
? BOOST_ERROR_NOT_SUPPORTED
: 0, to
, from
, ec
,
1025 "boost::filesystem::create_directory_symlink"))
1029 error(!BOOST_CREATE_SYMBOLIC_LINK(from
.c_str(), to
.c_str(),
1030 SYMBOLIC_LINK_FLAG_DIRECTORY
) ? BOOST_ERRNO
: 0,
1031 to
, from
, ec
, "boost::filesystem::create_directory_symlink");
1035 BOOST_FILESYSTEM_DECL
1036 void create_hard_link(const path
& to
, const path
& from
, error_code
* ec
)
1039 # if defined(BOOST_WINDOWS_API) && _WIN32_WINNT < 0x0500 // SDK earlier than Win 2K
1041 error(BOOST_ERROR_NOT_SUPPORTED
, to
, from
, ec
,
1042 "boost::filesystem::create_hard_link");
1045 # if defined(BOOST_WINDOWS_API) && _WIN32_WINNT >= 0x0500
1046 // see if actually supported by Windows runtime dll
1047 if (error(!create_hard_link_api
? BOOST_ERROR_NOT_SUPPORTED
: 0, to
, from
, ec
,
1048 "boost::filesystem::create_hard_link"))
1052 error(!BOOST_CREATE_HARD_LINK(from
.c_str(), to
.c_str()) ? BOOST_ERRNO
: 0, to
, from
, ec
,
1053 "boost::filesystem::create_hard_link");
1057 BOOST_FILESYSTEM_DECL
1058 void create_symlink(const path
& to
, const path
& from
, error_code
* ec
)
1060 # if defined(BOOST_WINDOWS_API) && _WIN32_WINNT < 0x0600 // SDK earlier than Vista and Server 2008
1061 error(BOOST_ERROR_NOT_SUPPORTED
, to
, from
, ec
,
1062 "boost::filesystem::create_directory_symlink");
1065 # if defined(BOOST_WINDOWS_API) && _WIN32_WINNT >= 0x0600
1066 // see if actually supported by Windows runtime dll
1067 if (error(!create_symbolic_link_api
? BOOST_ERROR_NOT_SUPPORTED
: 0, to
, from
, ec
,
1068 "boost::filesystem::create_symlink"))
1072 error(!BOOST_CREATE_SYMBOLIC_LINK(from
.c_str(), to
.c_str(), 0) ? BOOST_ERRNO
: 0,
1073 to
, from
, ec
, "boost::filesystem::create_symlink");
1077 BOOST_FILESYSTEM_DECL
1078 path
current_path(error_code
* ec
)
1080 # ifdef BOOST_POSIX_API
1082 for (long path_max
= 128;; path_max
*=2)// loop 'til buffer large enough
1084 boost::scoped_array
<char>
1085 buf(new char[static_cast<std::size_t>(path_max
)]);
1086 if (::getcwd(buf
.get(), static_cast<std::size_t>(path_max
))== 0)
1088 if (error(errno
!= ERANGE
? errno
: 0
1089 // bug in some versions of the Metrowerks C lib on the Mac: wrong errno set
1090 # if defined(__MSL__) && (defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__))
1093 , ec
, "boost::filesystem::current_path"))
1101 if (ec
!= 0) ec
->clear();
1109 if ((sz
= ::GetCurrentDirectoryW(0, NULL
)) == 0)sz
= 1;
1110 boost::scoped_array
<path::value_type
> buf(new path::value_type
[sz
]);
1111 error(::GetCurrentDirectoryW(sz
, buf
.get()) == 0 ? BOOST_ERRNO
: 0, ec
,
1112 "boost::filesystem::current_path");
1113 return path(buf
.get());
1118 BOOST_FILESYSTEM_DECL
1119 void current_path(const path
& p
, system::error_code
* ec
)
1121 error(!BOOST_SET_CURRENT_DIRECTORY(p
.c_str()) ? BOOST_ERRNO
: 0,
1122 p
, ec
, "boost::filesystem::current_path");
1125 BOOST_FILESYSTEM_DECL
1126 bool equivalent(const path
& p1
, const path
& p2
, system::error_code
* ec
)
1128 # ifdef BOOST_POSIX_API
1130 int e2(::stat(p2
.c_str(), &s2
));
1132 int e1(::stat(p1
.c_str(), &s1
));
1134 if (e1
!= 0 || e2
!= 0)
1136 // if one is invalid and the other isn't then they aren't equivalent,
1137 // but if both are invalid then it is an error
1138 error (e1
!= 0 && e2
!= 0, p1
, p2
, ec
, "boost::filesystem::equivalent");
1142 // both stats now known to be valid
1143 return s1
.st_dev
== s2
.st_dev
&& s1
.st_ino
== s2
.st_ino
1144 // According to the POSIX stat specs, "The st_ino and st_dev fields
1145 // taken together uniquely identify the file within the system."
1146 // Just to be sure, size and mod time are also checked.
1147 && s1
.st_size
== s2
.st_size
&& s1
.st_mtime
== s2
.st_mtime
;
1151 // Note well: Physical location on external media is part of the
1152 // equivalence criteria. If there are no open handles, physical location
1153 // can change due to defragmentation or other relocations. Thus handles
1154 // must be held open until location information for both paths has
1157 // p2 is done first, so any error reported is for p1
1162 FILE_SHARE_DELETE
| FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1165 FILE_FLAG_BACKUP_SEMANTICS
,
1172 FILE_SHARE_DELETE
| FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1175 FILE_FLAG_BACKUP_SEMANTICS
,
1178 if (h1
.handle
== INVALID_HANDLE_VALUE
1179 || h2
.handle
== INVALID_HANDLE_VALUE
)
1181 // if one is invalid and the other isn't, then they aren't equivalent,
1182 // but if both are invalid then it is an error
1183 error((h1
.handle
== INVALID_HANDLE_VALUE
1184 && h2
.handle
== INVALID_HANDLE_VALUE
) ? BOOST_ERROR_NOT_SUPPORTED
: 0, p1
, p2
, ec
,
1185 "boost::filesystem::equivalent");
1189 // at this point, both handles are known to be valid
1191 BY_HANDLE_FILE_INFORMATION info1
, info2
;
1193 if (error(!::GetFileInformationByHandle(h1
.handle
, &info1
) ? BOOST_ERRNO
: 0,
1194 p1
, p2
, ec
, "boost::filesystem::equivalent"))
1197 if (error(!::GetFileInformationByHandle(h2
.handle
, &info2
) ? BOOST_ERRNO
: 0,
1198 p1
, p2
, ec
, "boost::filesystem::equivalent"))
1201 // In theory, volume serial numbers are sufficient to distinguish between
1202 // devices, but in practice VSN's are sometimes duplicated, so last write
1203 // time and file size are also checked.
1205 info1
.dwVolumeSerialNumber
== info2
.dwVolumeSerialNumber
1206 && info1
.nFileIndexHigh
== info2
.nFileIndexHigh
1207 && info1
.nFileIndexLow
== info2
.nFileIndexLow
1208 && info1
.nFileSizeHigh
== info2
.nFileSizeHigh
1209 && info1
.nFileSizeLow
== info2
.nFileSizeLow
1210 && info1
.ftLastWriteTime
.dwLowDateTime
1211 == info2
.ftLastWriteTime
.dwLowDateTime
1212 && info1
.ftLastWriteTime
.dwHighDateTime
1213 == info2
.ftLastWriteTime
.dwHighDateTime
;
1218 BOOST_FILESYSTEM_DECL
1219 boost::uintmax_t file_size(const path
& p
, error_code
* ec
)
1221 # ifdef BOOST_POSIX_API
1223 struct stat path_stat
;
1224 if (error(::stat(p
.c_str(), &path_stat
)!= 0 ? BOOST_ERRNO
: 0,
1225 p
, ec
, "boost::filesystem::file_size"))
1226 return static_cast<boost::uintmax_t>(-1);
1227 if (error(!S_ISREG(path_stat
.st_mode
) ? EPERM
: 0,
1228 p
, ec
, "boost::filesystem::file_size"))
1229 return static_cast<boost::uintmax_t>(-1);
1231 return static_cast<boost::uintmax_t>(path_stat
.st_size
);
1235 // assume uintmax_t is 64-bits on all Windows compilers
1237 WIN32_FILE_ATTRIBUTE_DATA fad
;
1239 if (error(::GetFileAttributesExW(p
.c_str(), ::GetFileExInfoStandard
, &fad
)== 0
1240 ? BOOST_ERRNO
: 0, p
, ec
, "boost::filesystem::file_size"))
1241 return static_cast<boost::uintmax_t>(-1);
1243 if (error((fad
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)!= 0
1244 ? ERROR_NOT_SUPPORTED
: 0, p
, ec
, "boost::filesystem::file_size"))
1245 return static_cast<boost::uintmax_t>(-1);
1247 return (static_cast<boost::uintmax_t>(fad
.nFileSizeHigh
)
1248 << (sizeof(fad
.nFileSizeLow
)*8)) + fad
.nFileSizeLow
;
1252 BOOST_FILESYSTEM_DECL
1253 boost::uintmax_t hard_link_count(const path
& p
, system::error_code
* ec
)
1255 # ifdef BOOST_POSIX_API
1257 struct stat path_stat
;
1258 return error(::stat(p
.c_str(), &path_stat
)!= 0 ? BOOST_ERRNO
: 0,
1259 p
, ec
, "boost::filesystem::hard_link_count")
1261 : static_cast<boost::uintmax_t>(path_stat
.st_nlink
);
1265 // Link count info is only available through GetFileInformationByHandle
1266 BY_HANDLE_FILE_INFORMATION info
;
1268 create_file_handle(p
.c_str(), 0,
1269 FILE_SHARE_DELETE
| FILE_SHARE_READ
| FILE_SHARE_WRITE
, 0,
1270 OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
, 0));
1272 !error(h
.handle
== INVALID_HANDLE_VALUE
? BOOST_ERRNO
: 0,
1273 p
, ec
, "boost::filesystem::hard_link_count")
1274 && !error(::GetFileInformationByHandle(h
.handle
, &info
)== 0 ? BOOST_ERRNO
: 0,
1275 p
, ec
, "boost::filesystem::hard_link_count")
1276 ? info
.nNumberOfLinks
1281 BOOST_FILESYSTEM_DECL
1282 path
initial_path(error_code
* ec
)
1284 static path init_path
;
1285 if (init_path
.empty())
1286 init_path
= current_path(ec
);
1287 else if (ec
!= 0) ec
->clear();
1291 BOOST_FILESYSTEM_DECL
1292 bool is_empty(const path
& p
, system::error_code
* ec
)
1294 # ifdef BOOST_POSIX_API
1296 struct stat path_stat
;
1297 if (error(::stat(p
.c_str(), &path_stat
)!= 0,
1298 p
, ec
, "boost::filesystem::is_empty"))
1300 return S_ISDIR(path_stat
.st_mode
)
1301 ? is_empty_directory(p
)
1302 : path_stat
.st_size
== 0;
1305 WIN32_FILE_ATTRIBUTE_DATA fad
;
1306 if (error(::GetFileAttributesExW(p
.c_str(), ::GetFileExInfoStandard
, &fad
)== 0
1307 ? BOOST_ERRNO
: 0, p
, ec
, "boost::filesystem::is_empty"))
1310 if (ec
!= 0) ec
->clear();
1312 (fad
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
1313 ? is_empty_directory(p
)
1314 : (!fad
.nFileSizeHigh
&& !fad
.nFileSizeLow
);
1318 BOOST_FILESYSTEM_DECL
1319 std::time_t last_write_time(const path
& p
, system::error_code
* ec
)
1321 # ifdef BOOST_POSIX_API
1323 struct stat path_stat
;
1324 if (error(::stat(p
.c_str(), &path_stat
)!= 0 ? BOOST_ERRNO
: 0,
1325 p
, ec
, "boost::filesystem::last_write_time"))
1326 return std::time_t(-1);
1327 return path_stat
.st_mtime
;
1332 create_file_handle(p
.c_str(), 0,
1333 FILE_SHARE_DELETE
| FILE_SHARE_READ
| FILE_SHARE_WRITE
, 0,
1334 OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
, 0));
1336 if (error(hw
.handle
== INVALID_HANDLE_VALUE
? BOOST_ERRNO
: 0,
1337 p
, ec
, "boost::filesystem::last_write_time"))
1338 return std::time_t(-1);
1342 if (error(::GetFileTime(hw
.handle
, 0, 0, &lwt
)== 0 ? BOOST_ERRNO
: 0,
1343 p
, ec
, "boost::filesystem::last_write_time"))
1344 return std::time_t(-1);
1346 return to_time_t(lwt
);
1350 BOOST_FILESYSTEM_DECL
1351 void last_write_time(const path
& p
, const std::time_t new_time
,
1352 system::error_code
* ec
)
1354 # ifdef BOOST_POSIX_API
1356 struct stat path_stat
;
1357 if (error(::stat(p
.c_str(), &path_stat
)!= 0,
1358 p
, ec
, "boost::filesystem::last_write_time"))
1361 buf
.actime
= path_stat
.st_atime
; // utime()updates access time too:-(
1362 buf
.modtime
= new_time
;
1363 error(::utime(p
.c_str(), &buf
)!= 0 ? BOOST_ERRNO
: 0,
1364 p
, ec
, "boost::filesystem::last_write_time");
1369 create_file_handle(p
.c_str(), FILE_WRITE_ATTRIBUTES
,
1370 FILE_SHARE_DELETE
| FILE_SHARE_READ
| FILE_SHARE_WRITE
, 0,
1371 OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
, 0));
1373 if (error(hw
.handle
== INVALID_HANDLE_VALUE
? BOOST_ERRNO
: 0,
1374 p
, ec
, "boost::filesystem::last_write_time"))
1378 to_FILETIME(new_time
, lwt
);
1380 error(::SetFileTime(hw
.handle
, 0, 0, &lwt
)== 0 ? BOOST_ERRNO
: 0,
1381 p
, ec
, "boost::filesystem::last_write_time");
1385 # ifdef BOOST_POSIX_API
1386 const perms
active_bits(all_all
| set_uid_on_exe
| set_gid_on_exe
| sticky_bit
);
1387 inline mode_t
mode_cast(perms prms
) { return prms
& active_bits
; }
1390 BOOST_FILESYSTEM_DECL
1391 void permissions(const path
& p
, perms prms
, system::error_code
* ec
)
1393 BOOST_ASSERT_MSG(!((prms
& add_perms
) && (prms
& remove_perms
)),
1394 "add_perms and remove_perms are mutually exclusive");
1396 if ((prms
& add_perms
) && (prms
& remove_perms
)) // precondition failed
1399 # ifdef BOOST_POSIX_API
1400 error_code local_ec
;
1401 file_status
current_status((prms
& symlink_perms
)
1402 ? fs::symlink_status(p
, local_ec
)
1403 : fs::status(p
, local_ec
));
1407 BOOST_FILESYSTEM_THROW(filesystem_error(
1408 "boost::filesystem::permissions", p
, local_ec
));
1414 if (prms
& add_perms
)
1415 prms
|= current_status
.permissions();
1416 else if (prms
& remove_perms
)
1417 prms
= current_status
.permissions() & ~prms
;
1419 // OS X <10.10, iOS <8.0 and some other platforms don't support fchmodat().
1420 // Solaris (SunPro and gcc) only support fchmodat() on Solaris 11 and higher,
1421 // and a runtime check is too much trouble.
1422 // Linux does not support permissions on symbolic links and has no plans to
1423 // support them in the future. The chmod() code is thus more practical,
1424 // rather than always hitting ENOTSUP when sending in AT_SYMLINK_NO_FOLLOW.
1425 // - See the 3rd paragraph of
1426 // "Symbolic link ownership, permissions, and timestamps" at:
1427 // "http://man7.org/linux/man-pages/man7/symlink.7.html"
1428 // - See the fchmodat() Linux man page:
1429 // "http://man7.org/linux/man-pages/man2/fchmodat.2.html"
1430 # if defined(AT_FDCWD) && defined(AT_SYMLINK_NOFOLLOW) \
1431 && !(defined(__SUNPRO_CC) || defined(__sun) || defined(sun)) \
1432 && !(defined(linux) || defined(__linux) || defined(__linux__)) \
1433 && !(defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \
1434 && __MAC_OS_X_VERSION_MIN_REQUIRED < 101000) \
1435 && !(defined(__IPHONE_OS_VERSION_MIN_REQUIRED) \
1436 && __IPHONE_OS_VERSION_MIN_REQUIRED < 80000)
1437 if (::fchmodat(AT_FDCWD
, p
.c_str(), mode_cast(prms
),
1438 !(prms
& symlink_perms
) ? 0 : AT_SYMLINK_NOFOLLOW
))
1439 # else // fallback if fchmodat() not supported
1440 if (::chmod(p
.c_str(), mode_cast(prms
)))
1444 BOOST_FILESYSTEM_THROW(filesystem_error(
1445 "boost::filesystem::permissions", p
,
1446 error_code(errno
, system::generic_category())));
1448 ec
->assign(errno
, system::generic_category());
1453 // if not going to alter FILE_ATTRIBUTE_READONLY, just return
1454 if (!(!((prms
& (add_perms
| remove_perms
)))
1455 || (prms
& (owner_write
|group_write
|others_write
))))
1458 DWORD attr
= ::GetFileAttributesW(p
.c_str());
1460 if (error(attr
== 0 ? BOOST_ERRNO
: 0, p
, ec
, "boost::filesystem::permissions"))
1463 if (prms
& add_perms
)
1464 attr
&= ~FILE_ATTRIBUTE_READONLY
;
1465 else if (prms
& remove_perms
)
1466 attr
|= FILE_ATTRIBUTE_READONLY
;
1467 else if (prms
& (owner_write
|group_write
|others_write
))
1468 attr
&= ~FILE_ATTRIBUTE_READONLY
;
1470 attr
|= FILE_ATTRIBUTE_READONLY
;
1472 error(::SetFileAttributesW(p
.c_str(), attr
) == 0 ? BOOST_ERRNO
: 0,
1473 p
, ec
, "boost::filesystem::permissions");
1477 BOOST_FILESYSTEM_DECL
1478 path
read_symlink(const path
& p
, system::error_code
* ec
)
1482 # ifdef BOOST_POSIX_API
1484 for (std::size_t path_max
= 64;; path_max
*= 2)// loop 'til buffer large enough
1486 boost::scoped_array
<char> buf(new char[path_max
]);
1488 if ((result
=::readlink(p
.c_str(), buf
.get(), path_max
))== -1)
1491 BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::read_symlink",
1492 p
, error_code(errno
, system_category())));
1493 else ec
->assign(errno
, system_category());
1498 if(result
!= static_cast<ssize_t
>(path_max
))
1500 symlink_path
.assign(buf
.get(), buf
.get() + result
);
1501 if (ec
!= 0) ec
->clear();
1507 # elif _WIN32_WINNT < 0x0600 // SDK earlier than Vista and Server 2008
1508 error(BOOST_ERROR_NOT_SUPPORTED
, p
, ec
,
1509 "boost::filesystem::read_symlink");
1510 # else // Vista and Server 2008 SDK, or later
1514 char buf
[REPARSE_DATA_BUFFER_HEADER_SIZE
+MAXIMUM_REPARSE_DATA_BUFFER_SIZE
];
1515 REPARSE_DATA_BUFFER rdb
;
1519 create_file_handle(p
.c_str(), GENERIC_READ
, 0, 0, OPEN_EXISTING
,
1520 FILE_FLAG_BACKUP_SEMANTICS
| FILE_FLAG_OPEN_REPARSE_POINT
, 0));
1522 if (error(h
.handle
== INVALID_HANDLE_VALUE
? BOOST_ERRNO
: 0,
1523 p
, ec
, "boost::filesystem::read_symlink"))
1524 return symlink_path
;
1528 if (!error(::DeviceIoControl(h
.handle
, FSCTL_GET_REPARSE_POINT
,
1529 0, 0, info
.buf
, sizeof(info
), &sz
, 0) == 0 ? BOOST_ERRNO
: 0, p
, ec
,
1530 "boost::filesystem::read_symlink" ))
1531 symlink_path
.assign(
1532 static_cast<wchar_t*>(info
.rdb
.SymbolicLinkReparseBuffer
.PathBuffer
)
1533 + info
.rdb
.SymbolicLinkReparseBuffer
.PrintNameOffset
/sizeof(wchar_t),
1534 static_cast<wchar_t*>(info
.rdb
.SymbolicLinkReparseBuffer
.PathBuffer
)
1535 + info
.rdb
.SymbolicLinkReparseBuffer
.PrintNameOffset
/sizeof(wchar_t)
1536 + info
.rdb
.SymbolicLinkReparseBuffer
.PrintNameLength
/sizeof(wchar_t));
1538 return symlink_path
;
1541 BOOST_FILESYSTEM_DECL
1542 path
relative(const path
& p
, const path
& base
, error_code
* ec
)
1545 path
wc_base(weakly_canonical(base
, &tmp_ec
));
1546 if (error(tmp_ec
.value(), base
, ec
, "boost::filesystem::relative"))
1548 path
wc_p(weakly_canonical(p
, &tmp_ec
));
1549 if (error(tmp_ec
.value(), base
, ec
, "boost::filesystem::relative"))
1551 return wc_p
.lexically_relative(wc_base
);
1554 BOOST_FILESYSTEM_DECL
1555 bool remove(const path
& p
, error_code
* ec
)
1558 file_type type
= query_file_type(p
, &tmp_ec
);
1559 if (error(type
== status_error
? tmp_ec
.value() : 0, p
, ec
,
1560 "boost::filesystem::remove"))
1563 // Since POSIX remove() is specified to work with either files or directories, in a
1564 // perfect world it could just be called. But some important real-world operating
1565 // systems (Windows, Mac OS X, for example) don't implement the POSIX spec. So
1566 // remove_file_or_directory() is always called to keep it simple.
1567 return remove_file_or_directory(p
, type
, ec
);
1570 BOOST_FILESYSTEM_DECL
1571 boost::uintmax_t remove_all(const path
& p
, error_code
* ec
)
1574 file_type type
= query_file_type(p
, &tmp_ec
);
1575 if (error(type
== status_error
? tmp_ec
.value() : 0, p
, ec
,
1576 "boost::filesystem::remove_all"))
1579 return (type
!= status_error
&& type
!= file_not_found
) // exists
1580 ? remove_all_aux(p
, type
, ec
)
1584 BOOST_FILESYSTEM_DECL
1585 void rename(const path
& old_p
, const path
& new_p
, error_code
* ec
)
1587 error(!BOOST_MOVE_FILE(old_p
.c_str(), new_p
.c_str()) ? BOOST_ERRNO
: 0, old_p
, new_p
,
1588 ec
, "boost::filesystem::rename");
1591 BOOST_FILESYSTEM_DECL
1592 void resize_file(const path
& p
, uintmax_t size
, system::error_code
* ec
)
1594 error(!BOOST_RESIZE_FILE(p
.c_str(), size
) ? BOOST_ERRNO
: 0, p
, ec
,
1595 "boost::filesystem::resize_file");
1598 BOOST_FILESYSTEM_DECL
1599 space_info
space(const path
& p
, error_code
* ec
)
1601 # ifdef BOOST_POSIX_API
1602 struct BOOST_STATVFS vfs
;
1604 if (!error(::BOOST_STATVFS(p
.c_str(), &vfs
)!= 0,
1605 p
, ec
, "boost::filesystem::space"))
1608 = static_cast<boost::uintmax_t>(vfs
.f_blocks
)* BOOST_STATVFS_F_FRSIZE
;
1610 = static_cast<boost::uintmax_t>(vfs
.f_bfree
)* BOOST_STATVFS_F_FRSIZE
;
1612 = static_cast<boost::uintmax_t>(vfs
.f_bavail
)* BOOST_STATVFS_F_FRSIZE
;
1616 ULARGE_INTEGER avail
, total
, free
;
1619 if (!error(::GetDiskFreeSpaceExW(p
.c_str(), &avail
, &total
, &free
)== 0,
1620 p
, ec
, "boost::filesystem::space"))
1623 = (static_cast<boost::uintmax_t>(total
.HighPart
)<< 32)
1626 = (static_cast<boost::uintmax_t>(free
.HighPart
)<< 32)
1629 = (static_cast<boost::uintmax_t>(avail
.HighPart
)<< 32)
1637 info
.capacity
= info
.free
= info
.available
= 0;
1642 BOOST_FILESYSTEM_DECL
1643 file_status
status(const path
& p
, error_code
* ec
)
1645 # ifdef BOOST_POSIX_API
1647 struct stat path_stat
;
1648 if (::stat(p
.c_str(), &path_stat
)!= 0)
1650 if (ec
!= 0) // always report errno, even though some
1651 ec
->assign(errno
, system_category()); // errno values are not status_errors
1653 if (not_found_error(errno
))
1655 return fs::file_status(fs::file_not_found
, fs::no_perms
);
1658 BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status",
1659 p
, error_code(errno
, system_category())));
1660 return fs::file_status(fs::status_error
);
1662 if (ec
!= 0) ec
->clear();;
1663 if (S_ISDIR(path_stat
.st_mode
))
1664 return fs::file_status(fs::directory_file
,
1665 static_cast<perms
>(path_stat
.st_mode
) & fs::perms_mask
);
1666 if (S_ISREG(path_stat
.st_mode
))
1667 return fs::file_status(fs::regular_file
,
1668 static_cast<perms
>(path_stat
.st_mode
) & fs::perms_mask
);
1669 if (S_ISBLK(path_stat
.st_mode
))
1670 return fs::file_status(fs::block_file
,
1671 static_cast<perms
>(path_stat
.st_mode
) & fs::perms_mask
);
1672 if (S_ISCHR(path_stat
.st_mode
))
1673 return fs::file_status(fs::character_file
,
1674 static_cast<perms
>(path_stat
.st_mode
) & fs::perms_mask
);
1675 if (S_ISFIFO(path_stat
.st_mode
))
1676 return fs::file_status(fs::fifo_file
,
1677 static_cast<perms
>(path_stat
.st_mode
) & fs::perms_mask
);
1678 if (S_ISSOCK(path_stat
.st_mode
))
1679 return fs::file_status(fs::socket_file
,
1680 static_cast<perms
>(path_stat
.st_mode
) & fs::perms_mask
);
1681 return fs::file_status(fs::type_unknown
);
1685 DWORD
attr(::GetFileAttributesW(p
.c_str()));
1686 if (attr
== 0xFFFFFFFF)
1688 return process_status_failure(p
, ec
);
1691 // reparse point handling;
1692 // since GetFileAttributesW does not resolve symlinks, try to open a file
1693 // handle to discover if the file exists
1694 if (attr
& FILE_ATTRIBUTE_REPARSE_POINT
)
1699 0, // dwDesiredAccess; attributes only
1700 FILE_SHARE_DELETE
| FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1701 0, // lpSecurityAttributes
1703 FILE_FLAG_BACKUP_SEMANTICS
,
1704 0)); // hTemplateFile
1705 if (h
.handle
== INVALID_HANDLE_VALUE
)
1707 return process_status_failure(p
, ec
);
1710 if (!is_reparse_point_a_symlink(p
))
1711 return file_status(reparse_file
, make_permissions(p
, attr
));
1714 if (ec
!= 0) ec
->clear();
1715 return (attr
& FILE_ATTRIBUTE_DIRECTORY
)
1716 ? file_status(directory_file
, make_permissions(p
, attr
))
1717 : file_status(regular_file
, make_permissions(p
, attr
));
1722 BOOST_FILESYSTEM_DECL
1723 file_status
symlink_status(const path
& p
, error_code
* ec
)
1725 # ifdef BOOST_POSIX_API
1727 struct stat path_stat
;
1728 if (::lstat(p
.c_str(), &path_stat
)!= 0)
1730 if (ec
!= 0) // always report errno, even though some
1731 ec
->assign(errno
, system_category()); // errno values are not status_errors
1733 if (errno
== ENOENT
|| errno
== ENOTDIR
) // these are not errors
1735 return fs::file_status(fs::file_not_found
, fs::no_perms
);
1738 BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status",
1739 p
, error_code(errno
, system_category())));
1740 return fs::file_status(fs::status_error
);
1742 if (ec
!= 0) ec
->clear();
1743 if (S_ISREG(path_stat
.st_mode
))
1744 return fs::file_status(fs::regular_file
,
1745 static_cast<perms
>(path_stat
.st_mode
) & fs::perms_mask
);
1746 if (S_ISDIR(path_stat
.st_mode
))
1747 return fs::file_status(fs::directory_file
,
1748 static_cast<perms
>(path_stat
.st_mode
) & fs::perms_mask
);
1749 if (S_ISLNK(path_stat
.st_mode
))
1750 return fs::file_status(fs::symlink_file
,
1751 static_cast<perms
>(path_stat
.st_mode
) & fs::perms_mask
);
1752 if (S_ISBLK(path_stat
.st_mode
))
1753 return fs::file_status(fs::block_file
,
1754 static_cast<perms
>(path_stat
.st_mode
) & fs::perms_mask
);
1755 if (S_ISCHR(path_stat
.st_mode
))
1756 return fs::file_status(fs::character_file
,
1757 static_cast<perms
>(path_stat
.st_mode
) & fs::perms_mask
);
1758 if (S_ISFIFO(path_stat
.st_mode
))
1759 return fs::file_status(fs::fifo_file
,
1760 static_cast<perms
>(path_stat
.st_mode
) & fs::perms_mask
);
1761 if (S_ISSOCK(path_stat
.st_mode
))
1762 return fs::file_status(fs::socket_file
,
1763 static_cast<perms
>(path_stat
.st_mode
) & fs::perms_mask
);
1764 return fs::file_status(fs::type_unknown
);
1768 DWORD
attr(::GetFileAttributesW(p
.c_str()));
1769 if (attr
== 0xFFFFFFFF)
1771 return process_status_failure(p
, ec
);
1774 if (ec
!= 0) ec
->clear();
1776 if (attr
& FILE_ATTRIBUTE_REPARSE_POINT
)
1777 return is_reparse_point_a_symlink(p
)
1778 ? file_status(symlink_file
, make_permissions(p
, attr
))
1779 : file_status(reparse_file
, make_permissions(p
, attr
));
1781 return (attr
& FILE_ATTRIBUTE_DIRECTORY
)
1782 ? file_status(directory_file
, make_permissions(p
, attr
))
1783 : file_status(regular_file
, make_permissions(p
, attr
));
1788 // contributed by Jeff Flinn
1789 BOOST_FILESYSTEM_DECL
1790 path
temp_directory_path(system::error_code
* ec
)
1792 # ifdef BOOST_POSIX_API
1793 const char* val
= 0;
1795 (val
= std::getenv("TMPDIR" )) ||
1796 (val
= std::getenv("TMP" )) ||
1797 (val
= std::getenv("TEMP" )) ||
1798 (val
= std::getenv("TEMPDIR"));
1801 const char* default_tmp
= "/data/local/tmp";
1803 const char* default_tmp
= "/tmp";
1805 path
p((val
!=0) ? val
: default_tmp
);
1807 if (p
.empty() || (ec
&&!is_directory(p
, *ec
))||(!ec
&&!is_directory(p
)))
1809 error(ENOTDIR
, p
, ec
, "boost::filesystem::temp_directory_path");
1817 const wchar_t* tmp_env
= L
"TMP";
1818 const wchar_t* temp_env
= L
"TEMP";
1819 const wchar_t* localappdata_env
= L
"LOCALAPPDATA";
1820 const wchar_t* userprofile_env
= L
"USERPROFILE";
1821 const wchar_t* env_list
[]
1822 = {tmp_env
, temp_env
, localappdata_env
, userprofile_env
, 0};
1825 for (int i
= 0; env_list
[i
]; ++i
)
1827 std::wstring env
= wgetenv(env_list
[i
]);
1834 if (exists(p
, lcl_ec
) && !lcl_ec
&& is_directory(p
, lcl_ec
) && !lcl_ec
)
1842 // use vector since in C++03 a string is not required to be contiguous
1843 std::vector
<wchar_t> buf(::GetWindowsDirectoryW(NULL
, 0));
1846 || ::GetWindowsDirectoryW(&buf
[0], static_cast<UINT
>(buf
.size())) == 0)
1848 error(::GetLastError(), ec
, "boost::filesystem::temp_directory_path");
1851 p
= &*buf
.begin(); // do not depend on buf.size(); see ticket #10388
1859 BOOST_FILESYSTEM_DECL
1860 path
system_complete(const path
& p
, system::error_code
* ec
)
1862 # ifdef BOOST_POSIX_API
1863 return (p
.empty() || p
.is_absolute())
1864 ? p
: current_path()/ p
;
1869 if (ec
!= 0) ec
->clear();
1872 wchar_t buf
[buf_size
];
1874 std::size_t len
= get_full_path_name(p
, buf_size
, buf
, &pfn
);
1876 if (error(len
== 0 ? BOOST_ERRNO
: 0, p
, ec
, "boost::filesystem::system_complete"))
1879 if (len
< buf_size
)// len does not include null termination character
1880 return path(&buf
[0]);
1882 boost::scoped_array
<wchar_t> big_buf(new wchar_t[len
]);
1884 return error(get_full_path_name(p
, len
, big_buf
.get(), &pfn
)== 0 ? BOOST_ERRNO
: 0,
1885 p
, ec
, "boost::filesystem::system_complete")
1887 : path(big_buf
.get());
1891 BOOST_FILESYSTEM_DECL
1892 path
weakly_canonical(const path
& p
, system::error_code
* ec
)
1896 system::error_code tmp_ec
;
1897 path::iterator itr
= p
.end();
1899 for (; !head
.empty(); --itr
)
1901 file_status head_status
= status(head
, tmp_ec
);
1902 if (error(head_status
.type() == fs::status_error
,
1903 head
, ec
, "boost::filesystem::weakly_canonical"))
1905 if (head_status
.type() != fs::file_not_found
)
1907 head
.remove_filename();
1910 bool tail_has_dots
= false;
1911 for (; itr
!= p
.end(); ++itr
)
1914 // for a later optimization, track if any dot or dot-dot elements are present
1915 if (itr
->native().size() <= 2
1916 && itr
->native()[0] == dot
1917 && (itr
->native().size() == 1 || itr
->native()[1] == dot
))
1918 tail_has_dots
= true;
1922 return p
.lexically_normal();
1923 head
= canonical(head
, tmp_ec
);
1924 if (error(tmp_ec
.value(), head
, ec
, "boost::filesystem::weakly_canonical"))
1928 : (tail_has_dots
// optimization: only normalize if tail had dot or dot-dot element
1929 ? (head
/tail
).lexically_normal()
1932 } // namespace detail
1934 //--------------------------------------------------------------------------------------//
1936 // directory_entry //
1938 //--------------------------------------------------------------------------------------//
1941 directory_entry::m_get_status(system::error_code
* ec
) const
1943 if (!status_known(m_status
))
1945 // optimization: if the symlink status is known, and it isn't a symlink,
1946 // then status and symlink_status are identical so just copy the
1947 // symlink status to the regular status.
1948 if (status_known(m_symlink_status
)
1949 && !is_symlink(m_symlink_status
))
1951 m_status
= m_symlink_status
;
1952 if (ec
!= 0) ec
->clear();
1954 else m_status
= detail::status(m_path
, ec
);
1956 else if (ec
!= 0) ec
->clear();
1961 directory_entry::m_get_symlink_status(system::error_code
* ec
) const
1963 if (!status_known(m_symlink_status
))
1964 m_symlink_status
= detail::symlink_status(m_path
, ec
);
1965 else if (ec
!= 0) ec
->clear();
1966 return m_symlink_status
;
1969 // dispatch directory_entry supplied here rather than in
1970 // <boost/filesystem/path_traits.hpp>, thus avoiding header circularity.
1971 // test cases are in operations_unit_test.cpp
1973 namespace path_traits
1975 void dispatch(const directory_entry
& de
,
1976 # ifdef BOOST_WINDOWS_API
1981 const codecvt_type
&)
1983 to
= de
.path().native();
1986 void dispatch(const directory_entry
& de
,
1987 # ifdef BOOST_WINDOWS_API
1994 to
= de
.path().native();
1996 } // namespace path_traits
1997 } // namespace filesystem
1998 } // namespace boost
2000 //--------------------------------------------------------------------------------------//
2002 // directory_iterator //
2004 //--------------------------------------------------------------------------------------//
2008 # ifdef BOOST_POSIX_API
2010 error_code
path_max(std::size_t & result
)
2011 // this code is based on Stevens and Rago, Advanced Programming in the
2012 // UNIX envirnment, 2nd Ed., ISBN 0-201-43307-9, page 49
2015 static std::size_t max
= PATH_MAX
;
2017 static std::size_t max
= 0;
2022 long tmp
= ::pathconf("/", _PC_NAME_MAX
);
2025 if (errno
== 0)// indeterminate
2026 max
= 4096; // guess
2027 else return error_code(errno
, system_category());
2029 else max
= static_cast<std::size_t>(tmp
+ 1); // relative root
2035 #if defined(__PGI) && defined(__USE_FILE_OFFSET64)
2036 #define dirent dirent64
2039 error_code
dir_itr_first(void *& handle
, void *& buffer
,
2040 const char* dir
, string
& target
,
2041 fs::file_status
&, fs::file_status
&)
2043 if ((handle
= ::opendir(dir
))== 0)
2044 return error_code(errno
, system_category());
2045 target
= string("."); // string was static but caused trouble
2046 // when iteration called from dtor, after
2047 // static had already been destroyed
2048 std::size_t path_size (0); // initialization quiets gcc warning (ticket #3509)
2049 error_code ec
= path_max(path_size
);
2052 buffer
= std::malloc((sizeof(dirent
) - sizeof(de
.d_name
))
2053 + path_size
+ 1); // + 1 for "/0"
2057 // warning: the only dirent member updated is d_name
2058 inline int readdir_r_simulator(DIR * dirp
, struct dirent
* entry
,
2059 struct dirent
** result
)// *result set to 0 on end of directory
2063 # if !defined(__CYGWIN__)\
2064 && defined(_POSIX_THREAD_SAFE_FUNCTIONS)\
2065 && defined(_SC_THREAD_SAFE_FUNCTIONS)\
2066 && (_POSIX_THREAD_SAFE_FUNCTIONS+0 >= 0)\
2067 && (!defined(__hpux) || defined(_REENTRANT)) \
2068 && (!defined(_AIX) || defined(__THREAD_SAFE))
2069 if (::sysconf(_SC_THREAD_SAFE_FUNCTIONS
)>= 0)
2070 { return ::readdir_r(dirp
, entry
, result
); }
2075 if ((p
= ::readdir(dirp
))== 0)
2077 std::strcpy(entry
->d_name
, p
->d_name
);
2082 error_code
dir_itr_increment(void *& handle
, void *& buffer
,
2083 string
& target
, fs::file_status
& sf
, fs::file_status
& symlink_sf
)
2085 BOOST_ASSERT(buffer
!= 0);
2086 dirent
* entry(static_cast<dirent
*>(buffer
));
2089 if ((return_code
= readdir_r_simulator(static_cast<DIR*>(handle
), entry
, &result
))!= 0)
2090 return error_code(errno
, system_category());
2092 return fs::detail::dir_itr_close(handle
, buffer
);
2093 target
= entry
->d_name
;
2094 # ifdef BOOST_FILESYSTEM_STATUS_CACHE
2095 if (entry
->d_type
== DT_UNKNOWN
) // filesystem does not supply d_type value
2097 sf
= symlink_sf
= fs::file_status(fs::status_error
);
2099 else // filesystem supplies d_type value
2101 if (entry
->d_type
== DT_DIR
)
2102 sf
= symlink_sf
= fs::file_status(fs::directory_file
);
2103 else if (entry
->d_type
== DT_REG
)
2104 sf
= symlink_sf
= fs::file_status(fs::regular_file
);
2105 else if (entry
->d_type
== DT_LNK
)
2107 sf
= fs::file_status(fs::status_error
);
2108 symlink_sf
= fs::file_status(fs::symlink_file
);
2110 else sf
= symlink_sf
= fs::file_status(fs::status_error
);
2113 sf
= symlink_sf
= fs::file_status(fs::status_error
);
2118 # else // BOOST_WINDOWS_API
2120 error_code
dir_itr_first(void *& handle
, const fs::path
& dir
,
2121 wstring
& target
, fs::file_status
& sf
, fs::file_status
& symlink_sf
)
2122 // Note: an empty root directory has no "." or ".." entries, so this
2123 // causes a ERROR_FILE_NOT_FOUND error which we do not considered an
2124 // error. It is treated as eof instead.
2126 // use a form of search Sebastian Martel reports will work with Win98
2127 wstring
dirpath(dir
.wstring());
2128 dirpath
+= (dirpath
.empty()
2129 || (dirpath
[dirpath
.size()-1] != L
'\\'
2130 && dirpath
[dirpath
.size()-1] != L
'/'
2131 && dirpath
[dirpath
.size()-1] != L
':'))? L
"\\*" : L
"*";
2133 WIN32_FIND_DATAW data
;
2134 if ((handle
= ::FindFirstFileW(dirpath
.c_str(), &data
))
2135 == INVALID_HANDLE_VALUE
)
2137 handle
= 0; // signal eof
2138 return error_code( (::GetLastError() == ERROR_FILE_NOT_FOUND
2139 // Windows Mobile returns ERROR_NO_MORE_FILES; see ticket #3551
2140 || ::GetLastError() == ERROR_NO_MORE_FILES
)
2141 ? 0 : ::GetLastError(), system_category() );
2143 target
= data
.cFileName
;
2144 if (data
.dwFileAttributes
& FILE_ATTRIBUTE_REPARSE_POINT
)
2145 // reparse points are complex, so don't try to handle them here; instead just mark
2146 // them as status_error which causes directory_entry caching to call status()
2147 // and symlink_status() which do handle reparse points fully
2149 sf
.type(fs::status_error
);
2150 symlink_sf
.type(fs::status_error
);
2154 if (data
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
2156 sf
.type(fs::directory_file
);
2157 symlink_sf
.type(fs::directory_file
);
2161 sf
.type(fs::regular_file
);
2162 symlink_sf
.type(fs::regular_file
);
2164 sf
.permissions(make_permissions(data
.cFileName
, data
.dwFileAttributes
));
2165 symlink_sf
.permissions(sf
.permissions());
2167 return error_code();
2170 error_code
dir_itr_increment(void *& handle
, wstring
& target
,
2171 fs::file_status
& sf
, fs::file_status
& symlink_sf
)
2173 WIN32_FIND_DATAW data
;
2174 if (::FindNextFileW(handle
, &data
)== 0)// fails
2176 int error
= ::GetLastError();
2177 fs::detail::dir_itr_close(handle
);
2178 return error_code(error
== ERROR_NO_MORE_FILES
? 0 : error
, system_category());
2180 target
= data
.cFileName
;
2181 if (data
.dwFileAttributes
& FILE_ATTRIBUTE_REPARSE_POINT
)
2182 // reparse points are complex, so don't try to handle them here; instead just mark
2183 // them as status_error which causes directory_entry caching to call status()
2184 // and symlink_status() which do handle reparse points fully
2186 sf
.type(fs::status_error
);
2187 symlink_sf
.type(fs::status_error
);
2191 if (data
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
2193 sf
.type(fs::directory_file
);
2194 symlink_sf
.type(fs::directory_file
);
2198 sf
.type(fs::regular_file
);
2199 symlink_sf
.type(fs::regular_file
);
2201 sf
.permissions(make_permissions(data
.cFileName
, data
.dwFileAttributes
));
2202 symlink_sf
.permissions(sf
.permissions());
2204 return error_code();
2208 const error_code
not_found_error_code (
2209 # ifdef BOOST_WINDOWS_API
2210 ERROR_PATH_NOT_FOUND
2214 , system_category());
2216 } // unnamed namespace
2220 namespace filesystem
2225 // dir_itr_close is called both from the ~dir_itr_imp()destructor
2226 // and dir_itr_increment()
2227 BOOST_FILESYSTEM_DECL
2228 system::error_code
dir_itr_close( // never throws
2230 # if defined(BOOST_POSIX_API)
2235 # ifdef BOOST_POSIX_API
2238 if (handle
== 0)return ok
;
2239 DIR * h(static_cast<DIR*>(handle
));
2241 return error_code(::closedir(h
)== 0 ? 0 : errno
, system_category());
2246 ::FindClose(handle
);
2254 void directory_iterator_construct(directory_iterator
& it
,
2255 const path
& p
, system::error_code
* ec
)
2257 if (error(p
.empty() ? not_found_error_code
.value() : 0, p
, ec
,
2258 "boost::filesystem::directory_iterator::construct"))
2261 path::string_type filename
;
2262 file_status file_stat
, symlink_file_stat
;
2263 error_code result
= dir_itr_first(it
.m_imp
->handle
,
2264 # if defined(BOOST_POSIX_API)
2267 p
.c_str(), filename
, file_stat
, symlink_file_stat
);
2272 error(result
.value(), p
,
2273 ec
, "boost::filesystem::directory_iterator::construct");
2277 if (it
.m_imp
->handle
== 0)
2278 it
.m_imp
.reset(); // eof, so make end iterator
2281 it
.m_imp
->dir_entry
.assign(p
/ filename
, file_stat
, symlink_file_stat
);
2282 if (filename
[0] == dot
// dot or dot-dot
2283 && (filename
.size()== 1
2284 || (filename
[1] == dot
2285 && filename
.size()== 2)))
2286 { it
.increment(*ec
); }
2290 void directory_iterator_increment(directory_iterator
& it
,
2291 system::error_code
* ec
)
2293 BOOST_ASSERT_MSG(it
.m_imp
.get(), "attempt to increment end iterator");
2294 BOOST_ASSERT_MSG(it
.m_imp
->handle
!= 0, "internal program error");
2296 path::string_type filename
;
2297 file_status file_stat
, symlink_file_stat
;
2298 system::error_code temp_ec
;
2302 temp_ec
= dir_itr_increment(it
.m_imp
->handle
,
2303 # if defined(BOOST_POSIX_API)
2306 filename
, file_stat
, symlink_file_stat
);
2308 if (temp_ec
) // happens if filesystem is corrupt, such as on a damaged optical disc
2310 path
error_path(it
.m_imp
->dir_entry
.path().parent_path()); // fix ticket #5900
2313 BOOST_FILESYSTEM_THROW(
2314 filesystem_error("boost::filesystem::directory_iterator::operator++",
2316 error_code(BOOST_ERRNO
, system_category())));
2317 ec
->assign(BOOST_ERRNO
, system_category());
2320 else if (ec
!= 0) ec
->clear();
2322 if (it
.m_imp
->handle
== 0) // eof, make end
2328 if (!(filename
[0] == dot
// !(dot or dot-dot)
2329 && (filename
.size()== 1
2330 || (filename
[1] == dot
2331 && filename
.size()== 2))))
2333 it
.m_imp
->dir_entry
.replace_filename(
2334 filename
, file_stat
, symlink_file_stat
);
2339 } // namespace detail
2340 } // namespace filesystem
2341 } // namespace boost