cmake: supernova - missing include_directories() for Jack
[supercollider.git] / external_libraries / boost / libs / filesystem / v3 / src / operations.cpp
blob226f10769066ea3968da684aa65ae31596e29cd8
1 // operations.cpp --------------------------------------------------------------------//
3 // Copyright 2002-2009 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,
16 #endif
17 #if !defined(__PGI)
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
27 // systems as well.
28 #else
29 #define _FILE_OFFSET_BITS 64
30 #endif
32 #include <boost/config.hpp>
33 #if !defined( BOOST_NO_STD_WSTRING )
34 // Boost.Filesystem V3 and later requires std::wstring support.
35 // During the transition to V3, libraries are compiled with both V2 and V3 sources.
36 // On old compilers that don't support V3 anyhow, we just skip everything so the compile
37 // will succeed and the library can be built.
39 // define BOOST_FILESYSTEM_SOURCE so that <boost/filesystem/config.hpp> knows
40 // the library is being built (possibly exporting rather than importing code)
42 #define BOOST_FILESYSTEM_SOURCE
44 #ifndef BOOST_SYSTEM_NO_DEPRECATED
45 # define BOOST_SYSTEM_NO_DEPRECATED
46 #endif
48 #ifndef _POSIX_PTHREAD_SEMANTICS
49 # define _POSIX_PTHREAD_SEMANTICS // Sun readdir_r()needs this
50 #endif
52 #include <boost/filesystem/v3/operations.hpp>
53 #include <boost/scoped_array.hpp>
54 #include <boost/detail/workaround.hpp>
55 #include <vector>
56 #include <cstdlib> // for malloc, free
57 #include <sys/stat.h> // even on Windows some functions use stat()
58 #include <cstring>
59 #include <cstdio> // for remove, rename
60 #if defined(__QNXNTO__) // see ticket #5355
61 # include <stdio.h>
62 #endif
63 #include <cerrno>
65 #ifdef BOOST_FILEYSTEM_INCLUDE_IOSTREAM
66 # include <iostream>
67 #endif
69 namespace fs = boost::filesystem3;
70 using boost::filesystem3::path;
71 using boost::filesystem3::filesystem_error;
72 using boost::filesystem3::perms;
73 using boost::system::error_code;
74 using boost::system::error_category;
75 using boost::system::system_category;
76 using std::string;
77 using std::wstring;
79 # ifdef BOOST_POSIX_API
81 const fs::path dot_path(".");
82 const fs::path dot_dot_path("..");
83 # include <sys/types.h>
84 # if !defined(__APPLE__) && !defined(__OpenBSD__)
85 # include <sys/statvfs.h>
86 # define BOOST_STATVFS statvfs
87 # define BOOST_STATVFS_F_FRSIZE vfs.f_frsize
88 # else
89 # ifdef __OpenBSD__
90 # include <sys/param.h>
91 # endif
92 # include <sys/mount.h>
93 # define BOOST_STATVFS statfs
94 # define BOOST_STATVFS_F_FRSIZE static_cast<boost::uintmax_t>(vfs.f_bsize)
95 # endif
96 # include <dirent.h>
97 # include <unistd.h>
98 # include <fcntl.h>
99 # include <utime.h>
100 # include "limits.h"
102 # else // BOOST_WINDOW_API
104 const fs::path dot_path(L".");
105 const fs::path dot_dot_path(L"..");
106 # if (defined(__MINGW32__) || defined(__CYGWIN__)) && !defined(WINVER)
107 // Versions of MinGW or Cygwin that support Filesystem V3 support at least WINVER 0x501.
108 // See MinGW's windef.h
109 # define WINVER 0x501
110 # endif
111 # include <io.h>
112 # include <windows.h>
113 # include <winnt.h>
114 # if !defined(_WIN32_WINNT)
115 # define _WIN32_WINNT 0x0500
116 # endif
117 # if defined(__BORLANDC__) || defined(__MWERKS__)
118 # if defined(__BORLANDC__)
119 using std::time_t;
120 # endif
121 # include <utime.h>
122 # else
123 # include <sys/utime.h>
124 # endif
126 // REPARSE_DATA_BUFFER related definitions are found in ntifs.h, which is part of the
127 // Windows Device Driver Kit. Since that's inconvenient, the definitions are provided
128 // here. See http://msdn.microsoft.com/en-us/library/ms791514.aspx
130 #if !defined(REPARSE_DATA_BUFFER_HEADER_SIZE) // mingw winnt.h does provide the defs
132 #define SYMLINK_FLAG_RELATIVE 1
134 typedef struct _REPARSE_DATA_BUFFER {
135 ULONG ReparseTag;
136 USHORT ReparseDataLength;
137 USHORT Reserved;
138 union {
139 struct {
140 USHORT SubstituteNameOffset;
141 USHORT SubstituteNameLength;
142 USHORT PrintNameOffset;
143 USHORT PrintNameLength;
144 ULONG Flags;
145 WCHAR PathBuffer[1];
146 /* Example of distinction between substitute and print names:
147 mklink /d ldrive c:\
148 SubstituteName: c:\\??\
149 PrintName: c:\
151 } SymbolicLinkReparseBuffer;
152 struct {
153 USHORT SubstituteNameOffset;
154 USHORT SubstituteNameLength;
155 USHORT PrintNameOffset;
156 USHORT PrintNameLength;
157 WCHAR PathBuffer[1];
158 } MountPointReparseBuffer;
159 struct {
160 UCHAR DataBuffer[1];
161 } GenericReparseBuffer;
163 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
165 #define REPARSE_DATA_BUFFER_HEADER_SIZE \
166 FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer)
168 #endif
170 #ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE
171 #define MAXIMUM_REPARSE_DATA_BUFFER_SIZE ( 16 * 1024 )
172 #endif
174 # ifndef FSCTL_GET_REPARSE_POINT
175 # define FSCTL_GET_REPARSE_POINT 0x900a8
176 # endif
178 # ifndef IO_REPARSE_TAG_SYMLINK
179 # define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
180 # endif
182 # endif // BOOST_WINDOWS_API
184 // BOOST_FILESYSTEM_STATUS_CACHE enables file_status cache in
185 // dir_itr_increment. The config tests are placed here because some of the
186 // macros being tested come from dirent.h.
188 // TODO: find out what macros indicate dirent::d_type present in more libraries
189 # if defined(BOOST_WINDOWS_API)\
190 || defined(_DIRENT_HAVE_D_TYPE)// defined by GNU C library if d_type present
191 # define BOOST_FILESYSTEM_STATUS_CACHE
192 # endif
194 // POSIX/Windows macros ----------------------------------------------------//
196 // Portions of the POSIX and Windows API's are very similar, except for name,
197 // order of arguments, and meaning of zero/non-zero returns. The macros below
198 // abstract away those differences. They follow Windows naming and order of
199 // arguments, and return true to indicate no error occurred. [POSIX naming,
200 // order of arguments, and meaning of return were followed initially, but
201 // found to be less clear and cause more coding errors.]
203 # if defined(BOOST_POSIX_API)
205 // POSIX uses a 0 return to indicate success
206 # define BOOST_ERRNO errno
207 # define BOOST_SET_CURRENT_DIRECTORY(P)(::chdir(P)== 0)
208 # define BOOST_CREATE_DIRECTORY(P)(::mkdir(P, S_IRWXU|S_IRWXG|S_IRWXO)== 0)
209 # define BOOST_CREATE_HARD_LINK(F,T)(::link(T, F)== 0)
210 # define BOOST_CREATE_SYMBOLIC_LINK(F,T,Flag)(::symlink(T, F)== 0)
211 # define BOOST_REMOVE_DIRECTORY(P)(::rmdir(P)== 0)
212 # define BOOST_DELETE_FILE(P)(::unlink(P)== 0)
213 # define BOOST_COPY_DIRECTORY(F,T)(!(::stat(from.c_str(), &from_stat)!= 0\
214 || ::mkdir(to.c_str(),from_stat.st_mode)!= 0))
215 # define BOOST_COPY_FILE(F,T,FailIfExistsBool)copy_file_api(F, T, FailIfExistsBool)
216 # define BOOST_MOVE_FILE(OLD,NEW)(::rename(OLD, NEW)== 0)
217 # define BOOST_RESIZE_FILE(P,SZ)(::truncate(P, SZ)== 0)
219 # define BOOST_ERROR_NOT_SUPPORTED ENOSYS
220 # define BOOST_ERROR_ALREADY_EXISTS EEXIST
222 # else // BOOST_WINDOWS_API
224 // Windows uses a non-0 return to indicate success
225 # define BOOST_ERRNO ::GetLastError()
226 # define BOOST_SET_CURRENT_DIRECTORY(P)(::SetCurrentDirectoryW(P)!= 0)
227 # define BOOST_CREATE_DIRECTORY(P)(::CreateDirectoryW(P, 0)!= 0)
228 # define BOOST_CREATE_HARD_LINK(F,T)(create_hard_link_api(F, T, 0)!= 0)
229 # define BOOST_CREATE_SYMBOLIC_LINK(F,T,Flag)(create_symbolic_link_api(F, T, Flag)!= 0)
230 # define BOOST_REMOVE_DIRECTORY(P)(::RemoveDirectoryW(P)!= 0)
231 # define BOOST_DELETE_FILE(P)(::DeleteFileW(P)!= 0)
232 # define BOOST_COPY_DIRECTORY(F,T)(::CreateDirectoryExW(F, T, 0)!= 0)
233 # define BOOST_COPY_FILE(F,T,FailIfExistsBool)(::CopyFileW(F, T, FailIfExistsBool)!= 0)
234 # define BOOST_MOVE_FILE(OLD,NEW)(::MoveFileExW(OLD, NEW, MOVEFILE_REPLACE_EXISTING)!= 0)
235 # define BOOST_RESIZE_FILE(P,SZ)(resize_file_api(P, SZ)!= 0)
236 # define BOOST_READ_SYMLINK(P,T)
238 # define BOOST_ERROR_ALREADY_EXISTS ERROR_ALREADY_EXISTS
239 # define BOOST_ERROR_NOT_SUPPORTED ERROR_NOT_SUPPORTED
241 # endif
243 //--------------------------------------------------------------------------------------//
244 // //
245 // helpers (all operating systems) //
246 // //
247 //--------------------------------------------------------------------------------------//
249 namespace
252 fs::file_type query_file_type(const path& p, error_code* ec);
254 boost::filesystem3::directory_iterator end_dir_itr;
256 const std::size_t buf_size(128);
257 const error_code ok;
259 bool error(bool was_error, error_code* ec, const string& message)
261 if (!was_error)
263 if (ec != 0) ec->clear();
265 else
266 { // error
267 if (ec == 0)
268 BOOST_FILESYSTEM_THROW(filesystem_error(message,
269 error_code(BOOST_ERRNO, system_category())));
270 else
271 ec->assign(BOOST_ERRNO, system_category());
273 return was_error;
276 bool error(bool was_error, const path& p, error_code* ec, const string& message)
278 if (!was_error)
280 if (ec != 0) ec->clear();
282 else
283 { // error
284 if (ec == 0)
285 BOOST_FILESYSTEM_THROW(filesystem_error(message,
286 p, error_code(BOOST_ERRNO, system_category())));
287 else
288 ec->assign(BOOST_ERRNO, system_category());
290 return was_error;
293 bool error(bool was_error, const path& p1, const path& p2, error_code* ec,
294 const string& message)
296 if (!was_error)
298 if (ec != 0) ec->clear();
300 else
301 { // error
302 if (ec == 0)
303 BOOST_FILESYSTEM_THROW(filesystem_error(message,
304 p1, p2, error_code(BOOST_ERRNO, system_category())));
305 else
306 ec->assign(BOOST_ERRNO, system_category());
308 return was_error;
311 bool error(bool was_error, const error_code& result,
312 const path& p, error_code* ec, const string& message)
313 // Overwrites ec if there has already been an error
315 if (!was_error)
317 if (ec != 0) ec->clear();
319 else
320 { // error
321 if (ec == 0)
322 BOOST_FILESYSTEM_THROW(filesystem_error(message, p, result));
323 else
324 *ec = result;
326 return was_error;
329 bool error(bool was_error, const error_code& result,
330 const path& p1, const path& p2, error_code* ec, const string& message)
331 // Overwrites ec if there has already been an error
333 if (!was_error)
335 if (ec != 0) ec->clear();
337 else
338 { // error
339 if (ec == 0)
340 BOOST_FILESYSTEM_THROW(filesystem_error(message, p1, p2, result));
341 else
342 *ec = result;
344 return was_error;
347 bool is_empty_directory(const path& p)
349 return fs::directory_iterator(p)== end_dir_itr;
352 bool remove_directory(const path& p) // true if succeeds
353 { return BOOST_REMOVE_DIRECTORY(p.c_str()); }
355 bool remove_file(const path& p) // true if succeeds
356 { return BOOST_DELETE_FILE(p.c_str()); }
358 // called by remove and remove_all_aux
359 bool remove_file_or_directory(const path& p, fs::file_type type, error_code* ec)
360 // return true if file removed, false if not removed
362 if (type == fs::file_not_found)
364 if (ec != 0) ec->clear();
365 return false;
368 if (type == fs::directory_file
369 # ifdef BOOST_WINDOWS_API
370 || type == fs::_detail_directory_symlink
371 # endif
374 if (error(!remove_directory(p), p, ec, "boost::filesystem::remove"))
375 return false;
377 else
379 if (error(!remove_file(p), p, ec, "boost::filesystem::remove"))
380 return false;
382 return true;
385 boost::uintmax_t remove_all_aux(const path& p, fs::file_type type,
386 error_code* ec)
388 boost::uintmax_t count = 1;
390 if (type == fs::directory_file) // but not a directory symlink
392 for (fs::directory_iterator itr(p);
393 itr != end_dir_itr; ++itr)
395 fs::file_type tmp_type = query_file_type(itr->path(), ec);
396 if (ec != 0 && *ec)
397 return count;
398 count += remove_all_aux(itr->path(), tmp_type, ec);
401 remove_file_or_directory(p, type, ec);
402 return count;
405 #ifdef BOOST_POSIX_API
407 //--------------------------------------------------------------------------------------//
408 // //
409 // POSIX-specific helpers //
410 // //
411 //--------------------------------------------------------------------------------------//
413 const char dot = '.';
415 bool not_found_error(int errval)
417 return errno == ENOENT || errno == ENOTDIR;
420 bool // true if ok
421 copy_file_api(const std::string& from_p,
422 const std::string& to_p, bool fail_if_exists)
424 const std::size_t buf_sz = 32768;
425 boost::scoped_array<char> buf(new char [buf_sz]);
426 int infile=-1, outfile=-1; // -1 means not open
428 // bug fixed: code previously did a stat()on the from_file first, but that
429 // introduced a gratuitous race condition; the stat()is now done after the open()
431 if ((infile = ::open(from_p.c_str(), O_RDONLY))< 0)
432 { return false; }
434 struct stat from_stat;
435 if (::stat(from_p.c_str(), &from_stat)!= 0)
437 ::close(infile);
438 return false;
441 int oflag = O_CREAT | O_WRONLY | O_TRUNC;
442 if (fail_if_exists)
443 oflag |= O_EXCL;
444 if ((outfile = ::open(to_p.c_str(), oflag, from_stat.st_mode))< 0)
446 int open_errno = errno;
447 BOOST_ASSERT(infile >= 0);
448 ::close(infile);
449 errno = open_errno;
450 return false;
453 ssize_t sz, sz_read=1, sz_write;
454 while (sz_read > 0
455 && (sz_read = ::read(infile, buf.get(), buf_sz))> 0)
457 // Allow for partial writes - see Advanced Unix Programming (2nd Ed.),
458 // Marc Rochkind, Addison-Wesley, 2004, page 94
459 sz_write = 0;
462 if ((sz = ::write(outfile, buf.get() + sz_write,
463 sz_read - sz_write))< 0)
465 sz_read = sz; // cause read loop termination
466 break; // and error to be thrown after closes
468 sz_write += sz;
469 } while (sz_write < sz_read);
472 if (::close(infile)< 0)sz_read = -1;
473 if (::close(outfile)< 0)sz_read = -1;
475 return sz_read >= 0;
478 inline fs::file_type query_file_type(const path& p, error_code* ec)
480 return fs::detail::symlink_status(p, ec).type();
483 # else
485 //--------------------------------------------------------------------------------------//
486 // //
487 // Windows-specific helpers //
488 // //
489 //--------------------------------------------------------------------------------------//
491 const wchar_t dot = L'.';
493 bool not_found_error(int errval)
495 return errval == ERROR_FILE_NOT_FOUND
496 || errval == ERROR_PATH_NOT_FOUND
497 || errval == ERROR_INVALID_NAME // "tools/jam/src/:sys:stat.h", "//foo"
498 || errval == ERROR_INVALID_DRIVE // USB card reader with no card inserted
499 || errval == ERROR_NOT_READY // CD/DVD drive with no disc inserted
500 || errval == ERROR_INVALID_PARAMETER // ":sys:stat.h"
501 || errval == ERROR_BAD_PATHNAME // "//nosuch" on Win64
502 || errval == ERROR_BAD_NETPATH; // "//nosuch" on Win32
505 // some distributions of mingw as early as GLIBCXX__ 20110325 have _stricmp, but the
506 // offical 4.6.2 release with __GLIBCXX__ 20111026 doesn't. Play it safe for now, and
507 // only use _stricmp if _MSC_VER is defined
508 #if defined(_MSC_VER) // || (defined(__GLIBCXX__) && __GLIBCXX__ >= 20110325)
509 # define BOOST_FILESYSTEM_STRICMP _stricmp
510 #else
511 # define BOOST_FILESYSTEM_STRICMP strcmp
512 #endif
514 perms make_permissions(const path& p, DWORD attr)
516 perms prms = fs::owner_read | fs::group_read | fs::others_read;
517 if ((attr & FILE_ATTRIBUTE_READONLY) == 0)
518 prms |= fs::owner_write | fs::group_write | fs::others_write;
519 if (BOOST_FILESYSTEM_STRICMP(p.extension().string().c_str(), ".exe") == 0
520 || BOOST_FILESYSTEM_STRICMP(p.extension().string().c_str(), ".com") == 0
521 || BOOST_FILESYSTEM_STRICMP(p.extension().string().c_str(), ".bat") == 0
522 || BOOST_FILESYSTEM_STRICMP(p.extension().string().c_str(), ".cmd") == 0)
523 prms |= fs::owner_exe | fs::group_exe | fs::others_exe;
524 return prms;
527 // these constants come from inspecting some Microsoft sample code
528 std::time_t to_time_t(const FILETIME & ft)
530 __int64 t = (static_cast<__int64>(ft.dwHighDateTime)<< 32)
531 + ft.dwLowDateTime;
532 # if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 // > VC++ 7.0
533 t -= 116444736000000000LL;
534 # else
535 t -= 116444736000000000;
536 # endif
537 t /= 10000000;
538 return static_cast<std::time_t>(t);
541 void to_FILETIME(std::time_t t, FILETIME & ft)
543 __int64 temp = t;
544 temp *= 10000000;
545 # if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 // > VC++ 7.0
546 temp += 116444736000000000LL;
547 # else
548 temp += 116444736000000000;
549 # endif
550 ft.dwLowDateTime = static_cast<DWORD>(temp);
551 ft.dwHighDateTime = static_cast<DWORD>(temp >> 32);
554 // Thanks to Jeremy Maitin-Shepard for much help and for permission to
555 // base the equivalent()implementation on portions of his
556 // file-equivalence-win32.cpp experimental code.
558 struct handle_wrapper
560 HANDLE handle;
561 handle_wrapper(HANDLE h)
562 : handle(h){}
563 ~handle_wrapper()
565 if (handle != INVALID_HANDLE_VALUE)
566 ::CloseHandle(handle);
570 HANDLE create_file_handle(const path& p, DWORD dwDesiredAccess,
571 DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes,
572 DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,
573 HANDLE hTemplateFile)
575 return ::CreateFileW(p.c_str(), dwDesiredAccess, dwShareMode,
576 lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes,
577 hTemplateFile);
580 bool is_reparse_point_a_symlink(const path& p)
582 handle_wrapper h(create_file_handle(p, FILE_READ_EA,
583 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING,
584 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL));
585 if (h.handle == INVALID_HANDLE_VALUE)
586 return false;
588 boost::scoped_array<char> buf(new char [MAXIMUM_REPARSE_DATA_BUFFER_SIZE]);
590 // Query the reparse data
591 DWORD dwRetLen;
592 BOOL result = ::DeviceIoControl(h.handle, FSCTL_GET_REPARSE_POINT, NULL, 0, buf.get(),
593 MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &dwRetLen, NULL);
594 if (!result) return false;
596 return reinterpret_cast<const REPARSE_DATA_BUFFER*>(buf.get())
597 ->ReparseTag == IO_REPARSE_TAG_SYMLINK;
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);
621 if (ec == 0)
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
644 : fs::symlink_file;
645 return fs::reparse_file;
648 return (attr & FILE_ATTRIBUTE_DIRECTORY)
649 ? fs::directory_file
650 : fs::regular_file;
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);
657 LARGE_INTEGER sz;
658 sz.QuadPart = size;
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(
675 ::GetProcAddress(
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(
685 ::GetProcAddress(
686 ::GetModuleHandle(TEXT("kernel32.dll")), "CreateSymbolicLinkW"));
688 #endif
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; }
697 //#endif
699 } // unnamed namespace
701 //--------------------------------------------------------------------------------------//
702 // //
703 // operations functions declared in operations.hpp //
704 // in alphabetic order //
705 // //
706 //--------------------------------------------------------------------------------------//
708 namespace boost
710 namespace filesystem3
713 BOOST_FILESYSTEM_DECL
714 path absolute(const path& p, const path& base)
716 // if ( p.empty() || p.is_absolute() )
717 // return p;
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()
728 //# endif
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());
739 if (p.empty())
740 return abs_base;
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()
755 return p;
756 # endif
757 return base_root_name / p;
760 else
762 return abs_base / p;
765 return p; // p.is_absolute() is true
768 namespace detail
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;
775 # else
776 return true;
777 # endif
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 result;
786 system::error_code local_ec;
787 file_status stat (status(source, local_ec));
789 if (stat.type() == fs::file_not_found)
791 if (ec == 0)
792 BOOST_FILESYSTEM_THROW(filesystem_error(
793 "boost::filesystem::canonical", source,
794 error_code(system::errc::no_such_file_or_directory, system::generic_category())));
795 ec->assign(system::errc::no_such_file_or_directory, system::generic_category());
796 return result;
798 else if (local_ec)
800 if (ec == 0)
801 BOOST_FILESYSTEM_THROW(filesystem_error(
802 "boost::filesystem::canonical", source, local_ec));
803 *ec = local_ec;
804 return result;
807 bool scan (true);
808 while (scan)
810 scan = false;
811 result.clear();
812 for (path::iterator itr = source.begin(); itr != source.end(); ++itr)
814 if (*itr == dot_path)
815 continue;
816 if (*itr == dot_dot_path)
818 result.remove_filename();
819 continue;
822 result /= *itr;
824 bool is_sym (is_symlink(detail::symlink_status(result, ec)));
825 if (ec && *ec)
826 return path();
828 if (is_sym)
830 path link(detail::read_symlink(result, ec));
831 if (ec && *ec)
832 return path();
833 result.remove_filename();
835 if (link.is_absolute())
837 for (++itr; itr != source.end(); ++itr)
838 link /= *itr;
839 source = link;
841 else // link is relative
843 path new_source(result);
844 new_source /= link;
845 for (++itr; itr != source.end(); ++itr)
846 new_source /= *itr;
847 source = new_source;
849 scan = true; // symlink causes scan to be restarted
850 break;
854 if (ec != 0)
855 ec->clear();
856 BOOST_ASSERT_MSG(result.is_absolute(), "canonical() implementation error; please report");
857 return result;
860 BOOST_FILESYSTEM_DECL
861 void copy(const path& from, const path& to, system::error_code* ec)
863 file_status s(symlink_status(from, *ec));
864 if (ec != 0 && *ec) return;
866 if(is_symlink(s))
868 copy_symlink(from, to, *ec);
870 else if(is_directory(s))
872 copy_directory(from, to, *ec);
874 else if(is_regular_file(s))
876 copy_file(from, to, copy_option::fail_if_exists, *ec);
878 else
880 if (ec == 0)
881 BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::copy",
882 from, to, error_code(BOOST_ERROR_NOT_SUPPORTED, system_category())));
883 ec->assign(BOOST_ERROR_NOT_SUPPORTED, system_category());
887 BOOST_FILESYSTEM_DECL
888 void copy_directory(const path& from, const path& to, system::error_code* ec)
890 # ifdef BOOST_POSIX_API
891 struct stat from_stat;
892 # endif
893 error(!BOOST_COPY_DIRECTORY(from.c_str(), to.c_str()),
894 from, to, ec, "boost::filesystem::copy_directory");
897 BOOST_FILESYSTEM_DECL
898 void copy_file(const path& from, const path& to,
899 BOOST_SCOPED_ENUM(copy_option)option,
900 error_code* ec)
902 error(!BOOST_COPY_FILE(from.c_str(), to.c_str(),
903 option == copy_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);
921 # endif
924 BOOST_FILESYSTEM_DECL
925 bool create_directories(const path& p, system::error_code* ec)
927 if (p.empty() || exists(p))
929 if (!p.empty() && !is_directory(p))
931 if (ec == 0)
932 BOOST_FILESYSTEM_THROW(filesystem_error(
933 "boost::filesystem::create_directories", p,
934 error_code(system::errc::file_exists, system::generic_category())));
935 else ec->assign(system::errc::file_exists, system::generic_category());
937 return false;
940 // First create branch, by calling ourself recursively
941 create_directories(p.parent_path(), ec);
942 // Now that parent's path exists, create the directory
943 create_directory(p, ec);
944 return true;
947 BOOST_FILESYSTEM_DECL
948 bool create_directory(const path& p, error_code* ec)
950 if (BOOST_CREATE_DIRECTORY(p.c_str()))
952 if (ec != 0) ec->clear();
953 return true;
956 // attempt to create directory failed
957 int errval(BOOST_ERRNO); // save reason for failure
958 error_code dummy;
959 if (errval == BOOST_ERROR_ALREADY_EXISTS && is_directory(p, dummy))
961 if (ec != 0) ec->clear();
962 return false;
965 // attempt to create directory failed && it doesn't already exist
966 if (ec == 0)
967 BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::create_directory",
968 p, error_code(errval, system_category())));
969 else
970 ec->assign(errval, system_category());
971 return false;
974 BOOST_FILESYSTEM_DECL
975 void create_directory_symlink(const path& to, const path& from,
976 system::error_code* ec)
978 # if defined(BOOST_WINDOWS_API) && _WIN32_WINNT < 0x0600 // SDK earlier than Vista and Server 2008
980 error(true, error_code(BOOST_ERROR_NOT_SUPPORTED, system_category()), to, from, ec,
981 "boost::filesystem::create_directory_symlink");
982 # else
984 # if defined(BOOST_WINDOWS_API) && _WIN32_WINNT >= 0x0600
985 // see if actually supported by Windows runtime dll
986 if (error(!create_symbolic_link_api,
987 error_code(BOOST_ERROR_NOT_SUPPORTED, system_category()),
988 to, from, ec,
989 "boost::filesystem::create_directory_symlink"))
990 return;
991 # endif
993 error(!BOOST_CREATE_SYMBOLIC_LINK(from.c_str(), to.c_str(), SYMBOLIC_LINK_FLAG_DIRECTORY),
994 to, from, ec, "boost::filesystem::create_directory_symlink");
995 # endif
998 BOOST_FILESYSTEM_DECL
999 void create_hard_link(const path& to, const path& from, error_code* ec)
1002 # if defined(BOOST_WINDOWS_API) && _WIN32_WINNT < 0x0500 // SDK earlier than Win 2K
1004 error(true, error_code(BOOST_ERROR_NOT_SUPPORTED, system_category()), to, from, ec,
1005 "boost::filesystem::create_hard_link");
1006 # else
1008 # if defined(BOOST_WINDOWS_API) && _WIN32_WINNT >= 0x0500
1009 // see if actually supported by Windows runtime dll
1010 if (error(!create_hard_link_api,
1011 error_code(BOOST_ERROR_NOT_SUPPORTED, system_category()),
1012 to, from, ec,
1013 "boost::filesystem::create_hard_link"))
1014 return;
1015 # endif
1017 error(!BOOST_CREATE_HARD_LINK(from.c_str(), to.c_str()), to, from, ec,
1018 "boost::filesystem::create_hard_link");
1019 # endif
1022 BOOST_FILESYSTEM_DECL
1023 void create_symlink(const path& to, const path& from, error_code* ec)
1025 # if defined(BOOST_WINDOWS_API) && _WIN32_WINNT < 0x0600 // SDK earlier than Vista and Server 2008
1026 error(true, error_code(BOOST_ERROR_NOT_SUPPORTED, system_category()), to, from, ec,
1027 "boost::filesystem::create_directory_symlink");
1028 # else
1030 # if defined(BOOST_WINDOWS_API) && _WIN32_WINNT >= 0x0600
1031 // see if actually supported by Windows runtime dll
1032 if (error(!create_symbolic_link_api,
1033 error_code(BOOST_ERROR_NOT_SUPPORTED, system_category()),
1034 to, from, ec,
1035 "boost::filesystem::create_symlink"))
1036 return;
1037 # endif
1039 error(!BOOST_CREATE_SYMBOLIC_LINK(from.c_str(), to.c_str(), 0),
1040 to, from, ec, "boost::filesystem::create_symlink");
1041 # endif
1044 BOOST_FILESYSTEM_DECL
1045 path current_path(error_code* ec)
1047 # ifdef BOOST_POSIX_API
1048 path cur;
1049 for (long path_max = 128;; path_max *=2)// loop 'til buffer large enough
1051 boost::scoped_array<char>
1052 buf(new char[static_cast<std::size_t>(path_max)]);
1053 if (::getcwd(buf.get(), static_cast<std::size_t>(path_max))== 0)
1055 if (error(errno != ERANGE
1056 // bug in some versions of the Metrowerks C lib on the Mac: wrong errno set
1057 # if defined(__MSL__) && (defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__))
1058 && errno != 0
1059 # endif
1060 , ec, "boost::filesystem::current_path"))
1062 break;
1065 else
1067 cur = buf.get();
1068 if (ec != 0) ec->clear();
1069 break;
1072 return cur;
1074 # else
1075 DWORD sz;
1076 if ((sz = ::GetCurrentDirectoryW(0, NULL))== 0)sz = 1;
1077 boost::scoped_array<path::value_type> buf(new path::value_type[sz]);
1078 error(::GetCurrentDirectoryW(sz, buf.get())== 0, ec,
1079 "boost::filesystem::current_path");
1080 return path(buf.get());
1081 # endif
1085 BOOST_FILESYSTEM_DECL
1086 void current_path(const path& p, system::error_code* ec)
1088 error(!BOOST_SET_CURRENT_DIRECTORY(p.c_str()),
1089 p, ec, "boost::filesystem::current_path");
1092 BOOST_FILESYSTEM_DECL
1093 bool equivalent(const path& p1, const path& p2, system::error_code* ec)
1095 # ifdef BOOST_POSIX_API
1096 struct stat s2;
1097 int e2(::stat(p2.c_str(), &s2));
1098 struct stat s1;
1099 int e1(::stat(p1.c_str(), &s1));
1101 if (e1 != 0 || e2 != 0)
1103 // if one is invalid and the other isn't then they aren't equivalent,
1104 // but if both are invalid then it is an error
1105 error (e1 != 0 && e2 != 0, p1, p2, ec, "boost::filesystem::equivalent");
1106 return false;
1109 // both stats now known to be valid
1110 return s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino
1111 // According to the POSIX stat specs, "The st_ino and st_dev fields
1112 // taken together uniquely identify the file within the system."
1113 // Just to be sure, size and mod time are also checked.
1114 && s1.st_size == s2.st_size && s1.st_mtime == s2.st_mtime;
1116 # else // Windows
1118 // Note well: Physical location on external media is part of the
1119 // equivalence criteria. If there are no open handles, physical location
1120 // can change due to defragmentation or other relocations. Thus handles
1121 // must be held open until location information for both paths has
1122 // been retrieved.
1124 // p2 is done first, so any error reported is for p1
1125 handle_wrapper h2(
1126 create_file_handle(
1127 p2.c_str(),
1129 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
1131 OPEN_EXISTING,
1132 FILE_FLAG_BACKUP_SEMANTICS,
1133 0));
1135 handle_wrapper h1(
1136 create_file_handle(
1137 p1.c_str(),
1139 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
1141 OPEN_EXISTING,
1142 FILE_FLAG_BACKUP_SEMANTICS,
1143 0));
1145 if (h1.handle == INVALID_HANDLE_VALUE
1146 || h2.handle == INVALID_HANDLE_VALUE)
1148 // if one is invalid and the other isn't, then they aren't equivalent,
1149 // but if both are invalid then it is an error
1150 error(h1.handle == INVALID_HANDLE_VALUE
1151 && h2.handle == INVALID_HANDLE_VALUE, p1, p2, ec,
1152 "boost::filesystem::equivalent");
1153 return false;
1156 // at this point, both handles are known to be valid
1158 BY_HANDLE_FILE_INFORMATION info1, info2;
1160 if (error(!::GetFileInformationByHandle(h1.handle, &info1),
1161 p1, p2, ec, "boost::filesystem::equivalent"))
1162 return false;
1164 if (error(!::GetFileInformationByHandle(h2.handle, &info2),
1165 p1, p2, ec, "boost::filesystem::equivalent"))
1166 return false;
1168 // In theory, volume serial numbers are sufficient to distinguish between
1169 // devices, but in practice VSN's are sometimes duplicated, so last write
1170 // time and file size are also checked.
1171 return
1172 info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber
1173 && info1.nFileIndexHigh == info2.nFileIndexHigh
1174 && info1.nFileIndexLow == info2.nFileIndexLow
1175 && info1.nFileSizeHigh == info2.nFileSizeHigh
1176 && info1.nFileSizeLow == info2.nFileSizeLow
1177 && info1.ftLastWriteTime.dwLowDateTime
1178 == info2.ftLastWriteTime.dwLowDateTime
1179 && info1.ftLastWriteTime.dwHighDateTime
1180 == info2.ftLastWriteTime.dwHighDateTime;
1182 # endif
1185 BOOST_FILESYSTEM_DECL
1186 boost::uintmax_t file_size(const path& p, error_code* ec)
1188 # ifdef BOOST_POSIX_API
1190 struct stat path_stat;
1191 if (error(::stat(p.c_str(), &path_stat)!= 0,
1192 p, ec, "boost::filesystem::file_size"))
1193 return static_cast<boost::uintmax_t>(-1);
1194 if (error(!S_ISREG(path_stat.st_mode),
1195 error_code(EPERM, system_category()),
1196 p, ec, "boost::filesystem::file_size"))
1197 return static_cast<boost::uintmax_t>(-1);
1199 return static_cast<boost::uintmax_t>(path_stat.st_size);
1201 # else // Windows
1203 // assume uintmax_t is 64-bits on all Windows compilers
1205 WIN32_FILE_ATTRIBUTE_DATA fad;
1207 if (error(::GetFileAttributesExW(p.c_str(), ::GetFileExInfoStandard, &fad)== 0,
1208 p, ec, "boost::filesystem::file_size"))
1209 return static_cast<boost::uintmax_t>(-1);
1211 if (error((fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)!= 0,
1212 error_code(ERROR_NOT_SUPPORTED, system_category()),
1213 p, ec, "boost::filesystem::file_size"))
1214 return static_cast<boost::uintmax_t>(-1);
1216 return (static_cast<boost::uintmax_t>(fad.nFileSizeHigh)
1217 << (sizeof(fad.nFileSizeLow)*8)) + fad.nFileSizeLow;
1218 # endif
1221 BOOST_FILESYSTEM_DECL
1222 boost::uintmax_t hard_link_count(const path& p, system::error_code* ec)
1224 # ifdef BOOST_POSIX_API
1226 struct stat path_stat;
1227 return error(::stat(p.c_str(), &path_stat)!= 0,
1228 p, ec, "boost::filesystem::hard_link_count")
1230 : static_cast<boost::uintmax_t>(path_stat.st_nlink);
1232 # else // Windows
1234 // Link count info is only available through GetFileInformationByHandle
1235 BY_HANDLE_FILE_INFORMATION info;
1236 handle_wrapper h(
1237 create_file_handle(p.c_str(), 0,
1238 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
1239 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0));
1240 return
1241 !error(h.handle == INVALID_HANDLE_VALUE,
1242 p, ec, "boost::filesystem::hard_link_count")
1243 && !error(::GetFileInformationByHandle(h.handle, &info)== 0,
1244 p, ec, "boost::filesystem::hard_link_count")
1245 ? info.nNumberOfLinks
1246 : 0;
1247 # endif
1250 BOOST_FILESYSTEM_DECL
1251 path initial_path(error_code* ec)
1253 static path init_path;
1254 if (init_path.empty())
1255 init_path = current_path(ec);
1256 else if (ec != 0) ec->clear();
1257 return init_path;
1260 BOOST_FILESYSTEM_DECL
1261 bool is_empty(const path& p, system::error_code* ec)
1263 # ifdef BOOST_POSIX_API
1265 struct stat path_stat;
1266 if (error(::stat(p.c_str(), &path_stat)!= 0,
1267 p, ec, "boost::filesystem::is_empty"))
1268 return false;
1269 return S_ISDIR(path_stat.st_mode)
1270 ? is_empty_directory(p)
1271 : path_stat.st_size == 0;
1272 # else
1274 WIN32_FILE_ATTRIBUTE_DATA fad;
1275 if (error(::GetFileAttributesExW(p.c_str(), ::GetFileExInfoStandard, &fad)== 0,
1276 p, ec, "boost::filesystem::is_empty"))
1277 return false;
1279 if (ec != 0) ec->clear();
1280 return
1281 (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1282 ? is_empty_directory(p)
1283 : (!fad.nFileSizeHigh && !fad.nFileSizeLow);
1284 # endif
1287 BOOST_FILESYSTEM_DECL
1288 std::time_t last_write_time(const path& p, system::error_code* ec)
1290 # ifdef BOOST_POSIX_API
1292 struct stat path_stat;
1293 if (error(::stat(p.c_str(), &path_stat)!= 0,
1294 p, ec, "boost::filesystem::last_write_time"))
1295 return std::time_t(-1);
1296 return path_stat.st_mtime;
1298 # else
1300 handle_wrapper hw(
1301 create_file_handle(p.c_str(), 0,
1302 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
1303 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0));
1305 if (error(hw.handle == INVALID_HANDLE_VALUE,
1306 p, ec, "boost::filesystem::last_write_time"))
1307 return std::time_t(-1);
1309 FILETIME lwt;
1311 if (error(::GetFileTime(hw.handle, 0, 0, &lwt)== 0,
1312 p, ec, "boost::filesystem::last_write_time"))
1313 return std::time_t(-1);
1315 return to_time_t(lwt);
1316 # endif
1319 BOOST_FILESYSTEM_DECL
1320 void last_write_time(const path& p, const std::time_t new_time,
1321 system::error_code* ec)
1323 # ifdef BOOST_POSIX_API
1325 struct stat path_stat;
1326 if (error(::stat(p.c_str(), &path_stat)!= 0,
1327 p, ec, "boost::filesystem::last_write_time"))
1328 return;
1329 ::utimbuf buf;
1330 buf.actime = path_stat.st_atime; // utime()updates access time too:-(
1331 buf.modtime = new_time;
1332 error(::utime(p.c_str(), &buf)!= 0,
1333 p, ec, "boost::filesystem::last_write_time");
1335 # else
1337 handle_wrapper hw(
1338 create_file_handle(p.c_str(), FILE_WRITE_ATTRIBUTES,
1339 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
1340 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0));
1342 if (error(hw.handle == INVALID_HANDLE_VALUE,
1343 p, ec, "boost::filesystem::last_write_time"))
1344 return;
1346 FILETIME lwt;
1347 to_FILETIME(new_time, lwt);
1349 error(::SetFileTime(hw.handle, 0, 0, &lwt)== 0,
1350 p, ec, "boost::filesystem::last_write_time");
1351 # endif
1354 # ifdef BOOST_POSIX_API
1355 const perms active_bits(all_all | set_uid_on_exe | set_gid_on_exe | sticky_bit);
1356 inline mode_t mode_cast(perms prms) { return prms & active_bits; }
1357 # endif
1359 BOOST_FILESYSTEM_DECL
1360 void permissions(const path& p, perms prms, system::error_code* ec)
1362 BOOST_ASSERT_MSG(!((prms & add_perms) && (prms & remove_perms)),
1363 "add_perms and remove_perms are mutually exclusive");
1365 if ((prms & add_perms) && (prms & remove_perms)) // precondition failed
1366 return;
1368 # ifdef BOOST_POSIX_API
1369 error_code local_ec;
1370 file_status current_status((prms & symlink_perms)
1371 ? fs::symlink_status(p, local_ec)
1372 : fs::status(p, local_ec));
1373 if (local_ec)
1375 if (ec == 0)
1376 BOOST_FILESYSTEM_THROW(filesystem_error(
1377 "boost::filesystem::permissions", p, local_ec));
1378 else
1379 *ec = local_ec;
1380 return;
1383 if (prms & add_perms)
1384 prms |= current_status.permissions();
1385 else if (prms & remove_perms)
1386 prms = current_status.permissions() & ~prms;
1388 // Mac OS X Lion and some other platforms don't support fchmodat()
1389 # if defined(AT_FDCWD) && defined(AT_SYMLINK_NOFOLLOW) \
1390 && (!defined(__SUNPRO_CC) || __SUNPRO_CC > 0x5100)
1391 if (::fchmodat(AT_FDCWD, p.c_str(), mode_cast(prms),
1392 !(prms & symlink_perms) ? 0 : AT_SYMLINK_NOFOLLOW))
1393 # else // fallback if fchmodat() not supported
1394 if (::chmod(p.c_str(), mode_cast(prms)))
1395 # endif
1397 if (ec == 0)
1398 BOOST_FILESYSTEM_THROW(filesystem_error(
1399 "boost::filesystem::permissions", p,
1400 error_code(errno, system::generic_category())));
1401 else
1402 ec->assign(errno, system::generic_category());
1405 # else // Windows
1407 // if not going to alter FILE_ATTRIBUTE_READONLY, just return
1408 if (!(!((prms & (add_perms | remove_perms)))
1409 || (prms & (owner_write|group_write|others_write))))
1410 return;
1412 DWORD attr = ::GetFileAttributesW(p.c_str());
1414 if (error(attr == 0, p, ec, "boost::filesystem::permissions"))
1415 return;
1417 if (prms & add_perms)
1418 attr &= ~FILE_ATTRIBUTE_READONLY;
1419 else if (prms & remove_perms)
1420 attr |= FILE_ATTRIBUTE_READONLY;
1421 else if (prms & (owner_write|group_write|others_write))
1422 attr &= ~FILE_ATTRIBUTE_READONLY;
1423 else
1424 attr |= FILE_ATTRIBUTE_READONLY;
1426 error(::SetFileAttributesW(p.c_str(), attr) == 0,
1427 p, ec, "boost::filesystem::permissions");
1428 # endif
1431 BOOST_FILESYSTEM_DECL
1432 path read_symlink(const path& p, system::error_code* ec)
1434 path symlink_path;
1436 # ifdef BOOST_POSIX_API
1438 for (std::size_t path_max = 64;; path_max *= 2)// loop 'til buffer large enough
1440 boost::scoped_array<char> buf(new char[path_max]);
1441 ssize_t result;
1442 if ((result=::readlink(p.c_str(), buf.get(), path_max))== -1)
1444 if (ec == 0)
1445 BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::read_symlink",
1446 p, error_code(errno, system_category())));
1447 else ec->assign(errno, system_category());
1448 break;
1450 else
1452 if(result != static_cast<ssize_t>(path_max))
1454 symlink_path.assign(buf.get(), buf.get() + result);
1455 if (ec != 0) ec->clear();
1456 break;
1461 # elif _WIN32_WINNT < 0x0600 // SDK earlier than Vista and Server 2008
1462 error(true, error_code(BOOST_ERROR_NOT_SUPPORTED, system_category()), p, ec,
1463 "boost::filesystem::read_symlink");
1464 # else // Vista and Server 2008 SDK, or later
1466 union info_t
1468 char buf[REPARSE_DATA_BUFFER_HEADER_SIZE+MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
1469 REPARSE_DATA_BUFFER rdb;
1470 } info;
1472 handle_wrapper h(
1473 create_file_handle(p.c_str(), GENERIC_READ, 0, 0, OPEN_EXISTING,
1474 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0));
1476 if (error(h.handle == INVALID_HANDLE_VALUE, p, ec, "boost::filesystem::read_symlink"))
1477 return symlink_path;
1479 DWORD sz;
1481 if (!error(::DeviceIoControl(h.handle, FSCTL_GET_REPARSE_POINT,
1482 0, 0, info.buf, sizeof(info), &sz, 0) == 0, p, ec,
1483 "boost::filesystem::read_symlink" ))
1484 symlink_path.assign(
1485 static_cast<wchar_t*>(info.rdb.SymbolicLinkReparseBuffer.PathBuffer)
1486 + info.rdb.SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(wchar_t),
1487 static_cast<wchar_t*>(info.rdb.SymbolicLinkReparseBuffer.PathBuffer)
1488 + info.rdb.SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(wchar_t)
1489 + info.rdb.SymbolicLinkReparseBuffer.PrintNameLength/sizeof(wchar_t));
1490 # endif
1491 return symlink_path;
1494 BOOST_FILESYSTEM_DECL
1495 bool remove(const path& p, error_code* ec)
1497 error_code tmp_ec;
1498 file_type type = query_file_type(p, &tmp_ec);
1499 if (error(type == status_error, tmp_ec, p, ec,
1500 "boost::filesystem::remove"))
1501 return false;
1503 // Since POSIX remove() is specified to work with either files or directories, in a
1504 // perfect world it could just be called. But some important real-world operating
1505 // systems (Windows, Mac OS X, for example) don't implement the POSIX spec. So
1506 // remove_file_or_directory() is always called to kep it simple.
1507 return remove_file_or_directory(p, type, ec);
1510 BOOST_FILESYSTEM_DECL
1511 boost::uintmax_t remove_all(const path& p, error_code* ec)
1513 error_code tmp_ec;
1514 file_type type = query_file_type(p, &tmp_ec);
1515 if (error(type == status_error, tmp_ec, p, ec,
1516 "boost::filesystem::remove_all"))
1517 return 0;
1519 return (type != status_error && type != file_not_found) // exists
1520 ? remove_all_aux(p, type, ec)
1521 : 0;
1524 BOOST_FILESYSTEM_DECL
1525 void rename(const path& old_p, const path& new_p, error_code* ec)
1527 error(!BOOST_MOVE_FILE(old_p.c_str(), new_p.c_str()), old_p, new_p, ec,
1528 "boost::filesystem::rename");
1531 BOOST_FILESYSTEM_DECL
1532 void resize_file(const path& p, uintmax_t size, system::error_code* ec)
1534 error(!BOOST_RESIZE_FILE(p.c_str(), size), p, ec, "boost::filesystem::resize_file");
1537 BOOST_FILESYSTEM_DECL
1538 space_info space(const path& p, error_code* ec)
1540 # ifdef BOOST_POSIX_API
1541 struct BOOST_STATVFS vfs;
1542 space_info info;
1543 if (!error(::BOOST_STATVFS(p.c_str(), &vfs)!= 0,
1544 p, ec, "boost::filesystem::space"))
1546 info.capacity
1547 = static_cast<boost::uintmax_t>(vfs.f_blocks)* BOOST_STATVFS_F_FRSIZE;
1548 info.free
1549 = static_cast<boost::uintmax_t>(vfs.f_bfree)* BOOST_STATVFS_F_FRSIZE;
1550 info.available
1551 = static_cast<boost::uintmax_t>(vfs.f_bavail)* BOOST_STATVFS_F_FRSIZE;
1554 # else
1555 ULARGE_INTEGER avail, total, free;
1556 space_info info;
1558 if (!error(::GetDiskFreeSpaceExW(p.c_str(), &avail, &total, &free)== 0,
1559 p, ec, "boost::filesystem::space"))
1561 info.capacity
1562 = (static_cast<boost::uintmax_t>(total.HighPart)<< 32)
1563 + total.LowPart;
1564 info.free
1565 = (static_cast<boost::uintmax_t>(free.HighPart)<< 32)
1566 + free.LowPart;
1567 info.available
1568 = (static_cast<boost::uintmax_t>(avail.HighPart)<< 32)
1569 + avail.LowPart;
1572 # endif
1574 else
1576 info.capacity = info.free = info.available = 0;
1578 return info;
1581 BOOST_FILESYSTEM_DECL
1582 file_status status(const path& p, error_code* ec)
1584 # ifdef BOOST_POSIX_API
1586 struct stat path_stat;
1587 if (::stat(p.c_str(), &path_stat)!= 0)
1589 if (ec != 0) // always report errno, even though some
1590 ec->assign(errno, system_category()); // errno values are not status_errors
1592 if (not_found_error(errno))
1594 return fs::file_status(fs::file_not_found, fs::no_perms);
1596 if (ec == 0)
1597 BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status",
1598 p, error_code(errno, system_category())));
1599 return fs::file_status(fs::status_error);
1601 if (ec != 0) ec->clear();;
1602 if (S_ISDIR(path_stat.st_mode))
1603 return fs::file_status(fs::directory_file,
1604 static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
1605 if (S_ISREG(path_stat.st_mode))
1606 return fs::file_status(fs::regular_file,
1607 static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
1608 if (S_ISBLK(path_stat.st_mode))
1609 return fs::file_status(fs::block_file,
1610 static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
1611 if (S_ISCHR(path_stat.st_mode))
1612 return fs::file_status(fs::character_file,
1613 static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
1614 if (S_ISFIFO(path_stat.st_mode))
1615 return fs::file_status(fs::fifo_file,
1616 static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
1617 if (S_ISSOCK(path_stat.st_mode))
1618 return fs::file_status(fs::socket_file,
1619 static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
1620 return fs::file_status(fs::type_unknown);
1622 # else // Windows
1624 DWORD attr(::GetFileAttributesW(p.c_str()));
1625 if (attr == 0xFFFFFFFF)
1627 return process_status_failure(p, ec);
1630 // reparse point handling;
1631 // since GetFileAttributesW does not resolve symlinks, try to open a file
1632 // handle to discover if the file exists
1633 if (attr & FILE_ATTRIBUTE_REPARSE_POINT)
1635 handle_wrapper h(
1636 create_file_handle(
1637 p.c_str(),
1638 0, // dwDesiredAccess; attributes only
1639 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
1640 0, // lpSecurityAttributes
1641 OPEN_EXISTING,
1642 FILE_FLAG_BACKUP_SEMANTICS,
1643 0)); // hTemplateFile
1644 if (h.handle == INVALID_HANDLE_VALUE)
1646 return process_status_failure(p, ec);
1649 if (!is_reparse_point_a_symlink(p))
1650 return file_status(reparse_file, make_permissions(p, attr));
1653 if (ec != 0) ec->clear();
1654 return (attr & FILE_ATTRIBUTE_DIRECTORY)
1655 ? file_status(directory_file, make_permissions(p, attr))
1656 : file_status(regular_file, make_permissions(p, attr));
1658 # endif
1661 BOOST_FILESYSTEM_DECL
1662 file_status symlink_status(const path& p, error_code* ec)
1664 # ifdef BOOST_POSIX_API
1666 struct stat path_stat;
1667 if (::lstat(p.c_str(), &path_stat)!= 0)
1669 if (ec != 0) // always report errno, even though some
1670 ec->assign(errno, system_category()); // errno values are not status_errors
1672 if (errno == ENOENT || errno == ENOTDIR) // these are not errors
1674 return fs::file_status(fs::file_not_found, fs::no_perms);
1676 if (ec == 0)
1677 BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status",
1678 p, error_code(errno, system_category())));
1679 return fs::file_status(fs::status_error);
1681 if (ec != 0) ec->clear();
1682 if (S_ISREG(path_stat.st_mode))
1683 return fs::file_status(fs::regular_file,
1684 static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
1685 if (S_ISDIR(path_stat.st_mode))
1686 return fs::file_status(fs::directory_file,
1687 static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
1688 if (S_ISLNK(path_stat.st_mode))
1689 return fs::file_status(fs::symlink_file,
1690 static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
1691 if (S_ISBLK(path_stat.st_mode))
1692 return fs::file_status(fs::block_file,
1693 static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
1694 if (S_ISCHR(path_stat.st_mode))
1695 return fs::file_status(fs::character_file,
1696 static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
1697 if (S_ISFIFO(path_stat.st_mode))
1698 return fs::file_status(fs::fifo_file,
1699 static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
1700 if (S_ISSOCK(path_stat.st_mode))
1701 return fs::file_status(fs::socket_file,
1702 static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
1703 return fs::file_status(fs::type_unknown);
1705 # else // Windows
1707 DWORD attr(::GetFileAttributesW(p.c_str()));
1708 if (attr == 0xFFFFFFFF)
1710 return process_status_failure(p, ec);
1713 if (ec != 0) ec->clear();
1715 if (attr & FILE_ATTRIBUTE_REPARSE_POINT)
1716 return is_reparse_point_a_symlink(p)
1717 ? file_status(symlink_file, make_permissions(p, attr))
1718 : file_status(reparse_file, make_permissions(p, attr));
1720 return (attr & FILE_ATTRIBUTE_DIRECTORY)
1721 ? file_status(directory_file, make_permissions(p, attr))
1722 : file_status(regular_file, make_permissions(p, attr));
1724 # endif
1727 // contributed by Jeff Flinn
1728 BOOST_FILESYSTEM_DECL
1729 path temp_directory_path(system::error_code* ec)
1731 # ifdef BOOST_POSIX_API
1732 const char* val = 0;
1734 (val = std::getenv("TMPDIR" )) ||
1735 (val = std::getenv("TMP" )) ||
1736 (val = std::getenv("TEMP" )) ||
1737 (val = std::getenv("TEMPDIR"));
1739 path p((val!=0) ? val : "/tmp");
1741 if (p.empty() || (ec&&!is_directory(p, *ec))||(!ec&&!is_directory(p)))
1743 errno = ENOTDIR;
1744 error(true, p, ec, "boost::filesystem::temp_directory_path");
1745 return p;
1748 return p;
1750 # else // Windows
1752 std::vector<path::value_type> buf(GetTempPathW(0, NULL));
1754 if (buf.empty() || GetTempPathW(buf.size(), &buf[0])==0)
1756 if(!buf.empty()) ::SetLastError(ENOTDIR);
1757 error(true, ec, "boost::filesystem::temp_directory_path");
1758 return path();
1761 buf.pop_back();
1763 path p(buf.begin(), buf.end());
1765 if ((ec&&!is_directory(p, *ec))||(!ec&&!is_directory(p)))
1767 ::SetLastError(ENOTDIR);
1768 error(true, p, ec, "boost::filesystem::temp_directory_path");
1769 return path();
1772 return p;
1773 # endif
1776 BOOST_FILESYSTEM_DECL
1777 path system_complete(const path& p, system::error_code* ec)
1779 # ifdef BOOST_POSIX_API
1780 return (p.empty() || p.is_absolute())
1781 ? p : current_path()/ p;
1783 # else
1784 if (p.empty())
1786 if (ec != 0) ec->clear();
1787 return p;
1789 wchar_t buf[buf_size];
1790 wchar_t* pfn;
1791 std::size_t len = get_full_path_name(p, buf_size, buf, &pfn);
1793 if (error(len == 0, p, ec, "boost::filesystem::system_complete"))
1794 return path();
1796 if (len < buf_size)// len does not include null termination character
1797 return path(&buf[0]);
1799 boost::scoped_array<wchar_t> big_buf(new wchar_t[len]);
1801 return error(get_full_path_name(p, len , big_buf.get(), &pfn)== 0,
1802 p, ec, "boost::filesystem::system_complete")
1803 ? path()
1804 : path(big_buf.get());
1805 # endif
1808 } // namespace detail
1810 //--------------------------------------------------------------------------------------//
1811 // //
1812 // directory_entry //
1813 // //
1814 //--------------------------------------------------------------------------------------//
1816 file_status
1817 directory_entry::m_get_status(system::error_code* ec) const
1819 if (!status_known(m_status))
1821 // optimization: if the symlink status is known, and it isn't a symlink,
1822 // then status and symlink_status are identical so just copy the
1823 // symlink status to the regular status.
1824 if (status_known(m_symlink_status)
1825 && !is_symlink(m_symlink_status))
1827 m_status = m_symlink_status;
1828 if (ec != 0) ec->clear();
1830 else m_status = detail::status(m_path, ec);
1832 else if (ec != 0) ec->clear();
1833 return m_status;
1836 file_status
1837 directory_entry::m_get_symlink_status(system::error_code* ec) const
1839 if (!status_known(m_symlink_status))
1840 m_symlink_status = detail::symlink_status(m_path, ec);
1841 else if (ec != 0) ec->clear();
1842 return m_symlink_status;
1845 // dispatch directory_entry supplied here rather than in
1846 // <boost/filesystem/path_traits.hpp>, thus avoiding header circularity.
1847 // test cases are in operations_unit_test.cpp
1849 namespace path_traits
1851 void dispatch(const directory_entry & de,
1852 # ifdef BOOST_WINDOWS_API
1853 std::wstring& to,
1854 # else
1855 std::string& to,
1856 # endif
1857 const codecvt_type &)
1859 to = de.path().native();
1862 } // namespace path_traits
1863 } // namespace filesystem3
1864 } // namespace boost
1866 //--------------------------------------------------------------------------------------//
1867 // //
1868 // directory_iterator //
1869 // //
1870 //--------------------------------------------------------------------------------------//
1872 namespace
1874 # ifdef BOOST_POSIX_API
1876 error_code path_max(std::size_t & result)
1877 // this code is based on Stevens and Rago, Advanced Programming in the
1878 // UNIX envirnment, 2nd Ed., ISBN 0-201-43307-9, page 49
1880 # ifdef PATH_MAX
1881 static std::size_t max = PATH_MAX;
1882 # else
1883 static std::size_t max = 0;
1884 # endif
1885 if (max == 0)
1887 errno = 0;
1888 long tmp = ::pathconf("/", _PC_NAME_MAX);
1889 if (tmp < 0)
1891 if (errno == 0)// indeterminate
1892 max = 4096; // guess
1893 else return error_code(errno, system_category());
1895 else max = static_cast<std::size_t>(tmp + 1); // relative root
1897 result = max;
1898 return ok;
1901 #if defined(__PGI) && defined(__USE_FILE_OFFSET64)
1902 #define dirent dirent64
1903 #endif
1905 error_code dir_itr_first(void *& handle, void *& buffer,
1906 const char* dir, string& target,
1907 fs::file_status &, fs::file_status &)
1909 if ((handle = ::opendir(dir))== 0)
1910 return error_code(errno, system_category());
1911 target = string("."); // string was static but caused trouble
1912 // when iteration called from dtor, after
1913 // static had already been destroyed
1914 std::size_t path_size (0); // initialization quiets gcc warning (ticket #3509)
1915 error_code ec = path_max(path_size);
1916 if (ec)return ec;
1917 dirent de;
1918 buffer = std::malloc((sizeof(dirent) - sizeof(de.d_name))
1919 + path_size + 1); // + 1 for "/0"
1920 return ok;
1923 // warning: the only dirent member updated is d_name
1924 inline int readdir_r_simulator(DIR * dirp, struct dirent * entry,
1925 struct dirent ** result)// *result set to 0 on end of directory
1927 errno = 0;
1929 # if !defined(__CYGWIN__)\
1930 && defined(_POSIX_THREAD_SAFE_FUNCTIONS)\
1931 && defined(_SC_THREAD_SAFE_FUNCTIONS)\
1932 && (_POSIX_THREAD_SAFE_FUNCTIONS+0 >= 0)\
1933 && (!defined(__hpux) || defined(_REENTRANT)) \
1934 && (!defined(_AIX) || defined(__THREAD_SAFE))
1935 if (::sysconf(_SC_THREAD_SAFE_FUNCTIONS)>= 0)
1936 { return ::readdir_r(dirp, entry, result); }
1937 # endif
1939 struct dirent * p;
1940 *result = 0;
1941 if ((p = ::readdir(dirp))== 0)
1942 return errno;
1943 std::strcpy(entry->d_name, p->d_name);
1944 *result = entry;
1945 return 0;
1948 error_code dir_itr_increment(void *& handle, void *& buffer,
1949 string& target, fs::file_status & sf, fs::file_status & symlink_sf)
1951 BOOST_ASSERT(buffer != 0);
1952 dirent * entry(static_cast<dirent *>(buffer));
1953 dirent * result;
1954 int return_code;
1955 if ((return_code = readdir_r_simulator(static_cast<DIR*>(handle), entry, &result))!= 0)
1956 return error_code(errno, system_category());
1957 if (result == 0)
1958 return fs::detail::dir_itr_close(handle, buffer);
1959 target = entry->d_name;
1960 # ifdef BOOST_FILESYSTEM_STATUS_CACHE
1961 if (entry->d_type == DT_UNKNOWN) // filesystem does not supply d_type value
1963 sf = symlink_sf = fs::file_status(fs::status_error);
1965 else // filesystem supplies d_type value
1967 if (entry->d_type == DT_DIR)
1968 sf = symlink_sf = fs::file_status(fs::directory_file);
1969 else if (entry->d_type == DT_REG)
1970 sf = symlink_sf = fs::file_status(fs::regular_file);
1971 else if (entry->d_type == DT_LNK)
1973 sf = fs::file_status(fs::status_error);
1974 symlink_sf = fs::file_status(fs::symlink_file);
1976 else sf = symlink_sf = fs::file_status(fs::status_error);
1978 # else
1979 sf = symlink_sf = fs::file_status(fs::status_error);
1980 # endif
1981 return ok;
1984 # else // BOOST_WINDOWS_API
1986 error_code dir_itr_first(void *& handle, const fs::path& dir,
1987 wstring& target, fs::file_status & sf, fs::file_status & symlink_sf)
1988 // Note: an empty root directory has no "." or ".." entries, so this
1989 // causes a ERROR_FILE_NOT_FOUND error which we do not considered an
1990 // error. It is treated as eof instead.
1992 // use a form of search Sebastian Martel reports will work with Win98
1993 wstring dirpath(dir.wstring());
1994 dirpath += (dirpath.empty()
1995 || (dirpath[dirpath.size()-1] != L'\\'
1996 && dirpath[dirpath.size()-1] != L'/'
1997 && dirpath[dirpath.size()-1] != L':'))? L"\\*" : L"*";
1999 WIN32_FIND_DATAW data;
2000 if ((handle = ::FindFirstFileW(dirpath.c_str(), &data))
2001 == INVALID_HANDLE_VALUE)
2003 handle = 0; // signal eof
2004 return error_code( (::GetLastError() == ERROR_FILE_NOT_FOUND
2005 // Windows Mobile returns ERROR_NO_MORE_FILES; see ticket #3551
2006 || ::GetLastError() == ERROR_NO_MORE_FILES)
2007 ? 0 : ::GetLastError(), system_category() );
2009 target = data.cFileName;
2010 if (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
2011 // reparse points are complex, so don't try to handle them here; instead just mark
2012 // them as status_error which causes directory_entry caching to call status()
2013 // and symlink_status() which do handle reparse points fully
2015 sf.type(fs::status_error);
2016 symlink_sf.type(fs::status_error);
2018 else
2020 if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2022 sf.type(fs::directory_file);
2023 symlink_sf.type(fs::directory_file);
2025 else
2027 sf.type(fs::regular_file);
2028 symlink_sf.type(fs::regular_file);
2030 sf.permissions(make_permissions(data.cFileName, data.dwFileAttributes));
2031 symlink_sf.permissions(sf.permissions());
2033 return error_code();
2036 error_code dir_itr_increment(void *& handle, wstring& target,
2037 fs::file_status & sf, fs::file_status & symlink_sf)
2039 WIN32_FIND_DATAW data;
2040 if (::FindNextFileW(handle, &data)== 0)// fails
2042 int error = ::GetLastError();
2043 fs::detail::dir_itr_close(handle);
2044 return error_code(error == ERROR_NO_MORE_FILES ? 0 : error, system_category());
2046 target = data.cFileName;
2047 if (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
2048 // reparse points are complex, so don't try to handle them here; instead just mark
2049 // them as status_error which causes directory_entry caching to call status()
2050 // and symlink_status() which do handle reparse points fully
2052 sf.type(fs::status_error);
2053 symlink_sf.type(fs::status_error);
2055 else
2057 if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2059 sf.type(fs::directory_file);
2060 symlink_sf.type(fs::directory_file);
2062 else
2064 sf.type(fs::regular_file);
2065 symlink_sf.type(fs::regular_file);
2067 sf.permissions(make_permissions(data.cFileName, data.dwFileAttributes));
2068 symlink_sf.permissions(sf.permissions());
2070 return error_code();
2072 #endif
2074 const error_code not_found_error_code (
2075 # ifdef BOOST_WINDOWS_API
2076 ERROR_PATH_NOT_FOUND
2077 # else
2078 ENOENT
2079 # endif
2080 , system_category());
2082 } // unnamed namespace
2084 namespace boost
2086 namespace filesystem3
2089 namespace detail
2091 // dir_itr_close is called both from the ~dir_itr_imp()destructor
2092 // and dir_itr_increment()
2093 BOOST_FILESYSTEM_DECL
2094 system::error_code dir_itr_close( // never throws
2095 void *& handle
2096 # if defined(BOOST_POSIX_API)
2097 , void *& buffer
2098 # endif
2101 # ifdef BOOST_POSIX_API
2102 std::free(buffer);
2103 buffer = 0;
2104 if (handle == 0)return ok;
2105 DIR * h(static_cast<DIR*>(handle));
2106 handle = 0;
2107 return error_code(::closedir(h)== 0 ? 0 : errno, system_category());
2109 # else
2110 if (handle != 0)
2112 ::FindClose(handle);
2113 handle = 0;
2115 return ok;
2117 # endif
2120 void directory_iterator_construct(directory_iterator& it,
2121 const path& p, system::error_code* ec)
2123 if (error(p.empty(), not_found_error_code, p, ec,
2124 "boost::filesystem::directory_iterator::construct"))
2125 return;
2127 path::string_type filename;
2128 file_status file_stat, symlink_file_stat;
2129 error_code result = dir_itr_first(it.m_imp->handle,
2130 # if defined(BOOST_POSIX_API)
2131 it.m_imp->buffer,
2132 # endif
2133 p.c_str(), filename, file_stat, symlink_file_stat);
2135 if (result)
2137 it.m_imp.reset();
2138 error(true, result, p,
2139 ec, "boost::filesystem::directory_iterator::construct");
2140 return;
2143 if (it.m_imp->handle == 0)
2144 it.m_imp.reset(); // eof, so make end iterator
2145 else // not eof
2147 it.m_imp->dir_entry.assign(p / filename, file_stat, symlink_file_stat);
2148 if (filename[0] == dot // dot or dot-dot
2149 && (filename.size()== 1
2150 || (filename[1] == dot
2151 && filename.size()== 2)))
2152 { it.increment(*ec); }
2156 void directory_iterator_increment(directory_iterator& it,
2157 system::error_code* ec)
2159 BOOST_ASSERT_MSG(it.m_imp.get(), "attempt to increment end iterator");
2160 BOOST_ASSERT_MSG(it.m_imp->handle != 0, "internal program error");
2162 path::string_type filename;
2163 file_status file_stat, symlink_file_stat;
2164 system::error_code temp_ec;
2166 for (;;)
2168 temp_ec = dir_itr_increment(it.m_imp->handle,
2169 # if defined(BOOST_POSIX_API)
2170 it.m_imp->buffer,
2171 # endif
2172 filename, file_stat, symlink_file_stat);
2174 if (temp_ec) // happens if filesystem is corrupt, such as on a damaged optical disc
2176 path error_path(it.m_imp->dir_entry.path().parent_path()); // fix ticket #5900
2177 it.m_imp.reset();
2178 if (ec == 0)
2179 BOOST_FILESYSTEM_THROW(
2180 filesystem_error("boost::filesystem::directory_iterator::operator++",
2181 error_path,
2182 error_code(BOOST_ERRNO, system_category())));
2183 ec->assign(BOOST_ERRNO, system_category());
2184 return;
2186 else if (ec != 0) ec->clear();
2188 if (it.m_imp->handle == 0) // eof, make end
2190 it.m_imp.reset();
2191 return;
2194 if (!(filename[0] == dot // !(dot or dot-dot)
2195 && (filename.size()== 1
2196 || (filename[1] == dot
2197 && filename.size()== 2))))
2199 it.m_imp->dir_entry.replace_filename(
2200 filename, file_stat, symlink_file_stat);
2201 return;
2205 } // namespace detail
2206 } // namespace filesystem3
2207 } // namespace boost
2209 #endif // no wide character support