Ticket #5277: operations.cpp

File operations.cpp, 60.8 KB (added by anonymous, 12 years ago)
Line 
1// operations.cpp --------------------------------------------------------------------//
2
3// Copyright 2002-2009 Beman Dawes
4// Copyright 2001 Dietmar Kuehl
5
6// Distributed under the Boost Software License, Version 1.0.
7// See http://www.boost.org/LICENSE_1_0.txt
8
9// See library home page at http://www.boost.org/libs/filesystem
10
11//--------------------------------------------------------------------------------------//
12
13#include <boost/config.hpp>
14#if !defined( BOOST_NO_STD_WSTRING )
15// Boost.Filesystem V3 and later requires std::wstring support.
16// During the transition to V3, libraries are compiled with both V2 and V3 sources.
17// On old compilers that don't support V3 anyhow, we just skip everything so the compile
18// will succeed and the library can be built.
19
20// define BOOST_FILESYSTEM_SOURCE so that <boost/filesystem/config.hpp> knows
21// the library is being built (possibly exporting rather than importing code)
22
23#define BOOST_FILESYSTEM_SOURCE
24
25#ifndef BOOST_SYSTEM_NO_DEPRECATED
26# define BOOST_SYSTEM_NO_DEPRECATED
27#endif
28
29#ifndef _POSIX_PTHREAD_SEMANTICS
30# define _POSIX_PTHREAD_SEMANTICS // Sun readdir_r()needs this
31#endif
32
33#if !(defined(__HP_aCC) && defined(_ILP32) && \
34 !defined(_STATVFS_ACPP_PROBLEMS_FIXED))
35#define _FILE_OFFSET_BITS 64 // at worst, these defines may have no effect,
36#endif
37#define __USE_FILE_OFFSET64 // but that is harmless on Windows and on POSIX
38 // 64-bit systems or on 32-bit systems which don't have files larger
39 // than can be represented by a traditional POSIX/UNIX off_t type.
40 // OTOH, defining them should kick in 64-bit off_t's (and thus
41 // st_size)on 32-bit systems that provide the Large File
42 // Support (LFS)interface, such as Linux, Solaris, and IRIX.
43 // The defines are given before any headers are included to
44 // ensure that they are available to all included headers.
45 // That is required at least on Solaris, and possibly on other
46 // systems as well.
47
48#include <boost/filesystem/v3/operations.hpp>
49#include <boost/scoped_array.hpp>
50#include <boost/detail/workaround.hpp>
51#include <cstdlib> // for malloc, free
52#include <vector>
53
54#ifdef BOOST_FILEYSTEM_INCLUDE_IOSTREAM
55# include <iostream>
56#endif
57
58namespace fs = boost::filesystem3;
59using boost::filesystem3::path;
60using boost::filesystem3::filesystem_error;
61using boost::system::error_code;
62using boost::system::error_category;
63using boost::system::system_category;
64using std::string;
65using std::wstring;
66
67# ifdef BOOST_POSIX_API
68
69# include <sys/types.h>
70# if !defined(__APPLE__) && !defined(__OpenBSD__)
71# include <sys/statvfs.h>
72# define BOOST_STATVFS statvfs
73# define BOOST_STATVFS_F_FRSIZE vfs.f_frsize
74# else
75# ifdef __OpenBSD__
76# include <sys/param.h>
77# endif
78# include <sys/mount.h>
79# define BOOST_STATVFS statfs
80# define BOOST_STATVFS_F_FRSIZE static_cast<boost::uintmax_t>(vfs.f_bsize)
81# endif
82# include <dirent.h>
83# include <unistd.h>
84# include <fcntl.h>
85# include <utime.h>
86# include "limits.h"
87
88# else // BOOST_WINDOW_API
89
90# if (defined(__MINGW32__) || defined(__CYGWIN__)) && !defined(WINVER)
91 // Versions of MinGW or Cygwin that support Filesystem V3 support at least WINVER 0x501.
92 // See MinGW's windef.h
93# define WINVER 0x501
94# endif
95# include <windows.h>
96# include <winnt.h>
97# if !defined(_WIN32_WINNT)
98# define _WIN32_WINNT 0x0500
99# endif
100# if defined(__BORLANDC__) || defined(__MWERKS__)
101# if defined(__BORLANDC__)
102 using std::time_t;
103# endif
104# include <utime.h>
105# else
106# include <sys/utime.h>
107# endif
108
109// REPARSE_DATA_BUFFER related definitions are found in ntifs.h, which is part of the
110// Windows Device Driver Kit. Since that's inconvenient, the definitions are provided
111// here. See http://msdn.microsoft.com/en-us/library/ms791514.aspx
112
113#if !defined(REPARSE_DATA_BUFFER_HEADER_SIZE) // mingw winnt.h does provide the defs
114
115#define SYMLINK_FLAG_RELATIVE 1
116
117typedef struct _REPARSE_DATA_BUFFER {
118 ULONG ReparseTag;
119 USHORT ReparseDataLength;
120 USHORT Reserved;
121 union {
122 struct {
123 USHORT SubstituteNameOffset;
124 USHORT SubstituteNameLength;
125 USHORT PrintNameOffset;
126 USHORT PrintNameLength;
127 ULONG Flags;
128 WCHAR PathBuffer[1];
129 /* Example of distinction between substitute and print names:
130 mklink /d ldrive c:\
131 SubstituteName: c:\\??\
132 PrintName: c:\
133 */
134 } SymbolicLinkReparseBuffer;
135 struct {
136 USHORT SubstituteNameOffset;
137 USHORT SubstituteNameLength;
138 USHORT PrintNameOffset;
139 USHORT PrintNameLength;
140 WCHAR PathBuffer[1];
141 } MountPointReparseBuffer;
142 struct {
143 UCHAR DataBuffer[1];
144 } GenericReparseBuffer;
145 };
146} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
147
148#define REPARSE_DATA_BUFFER_HEADER_SIZE \
149 FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer)
150
151#endif
152
153#ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE
154#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE ( 16 * 1024 )
155#endif
156
157# ifndef FSCTL_GET_REPARSE_POINT
158# define FSCTL_GET_REPARSE_POINT 0x900a8
159# endif
160
161# ifndef IO_REPARSE_TAG_SYMLINK
162# define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
163# endif
164
165# endif // BOOST_WINDOWS_API
166
167// BOOST_FILESYSTEM_STATUS_CACHE enables file_status cache in
168// dir_itr_increment. The config tests are placed here because some of the
169// macros being tested come from dirent.h.
170//
171// TODO: find out what macros indicate dirent::d_type present in more libraries
172# if defined(BOOST_WINDOWS_API)\
173 || defined(_DIRENT_HAVE_D_TYPE)// defined by GNU C library if d_type present
174# define BOOST_FILESYSTEM_STATUS_CACHE
175# endif
176
177#include <sys/stat.h> // even on Windows some functions use stat()
178#include <string>
179#include <cstring>
180#include <cstdio> // for remove, rename
181#include <cerrno>
182#include <cassert>
183// #include <iostream> // for debugging only; comment out when not in use
184
185#if defined(__QNXNTO__)
186#include <stdio.h>
187#endif
188
189// POSIX/Windows macros ----------------------------------------------------//
190
191// Portions of the POSIX and Windows API's are very similar, except for name,
192// order of arguments, and meaning of zero/non-zero returns. The macros below
193// abstract away those differences. They follow Windows naming and order of
194// arguments, and return true to indicate no error occurred. [POSIX naming,
195// order of arguments, and meaning of return were followed initially, but
196// found to be less clear and cause more coding errors.]
197
198# if defined(BOOST_POSIX_API)
199
200// POSIX uses a 0 return to indicate success
201# define BOOST_ERRNO errno
202# define BOOST_SET_CURRENT_DIRECTORY(P)(::chdir(P)== 0)
203# define BOOST_CREATE_DIRECTORY(P)(::mkdir(P, S_IRWXU|S_IRWXG|S_IRWXO)== 0)
204# define BOOST_CREATE_HARD_LINK(F,T)(::link(T, F)== 0)
205# define BOOST_CREATE_SYMBOLIC_LINK(F,T,Flag)(::symlink(T, F)== 0)
206# define BOOST_REMOVE_DIRECTORY(P)(::rmdir(P)== 0)
207# define BOOST_DELETE_FILE(P)(::unlink(P)== 0)
208# define BOOST_COPY_DIRECTORY(F,T)(!(::stat(from.c_str(), &from_stat)!= 0\
209 || ::mkdir(to.c_str(),from_stat.st_mode)!= 0))
210# define BOOST_COPY_FILE(F,T,FailIfExistsBool)copy_file_api(F, T, FailIfExistsBool)
211# define BOOST_MOVE_FILE(OLD,NEW)(::rename(OLD, NEW)== 0)
212# define BOOST_RESIZE_FILE(P,SZ)(::truncate(P, SZ)== 0)
213
214# define BOOST_ERROR_NOT_SUPPORTED ENOSYS
215# define BOOST_ERROR_ALREADY_EXISTS EEXIST
216
217# else // BOOST_WINDOWS_API
218
219// Windows uses a non-0 return to indicate success
220# define BOOST_ERRNO ::GetLastError()
221# define BOOST_SET_CURRENT_DIRECTORY(P)(::SetCurrentDirectoryW(P)!= 0)
222# define BOOST_CREATE_DIRECTORY(P)(::CreateDirectoryW(P, 0)!= 0)
223# define BOOST_CREATE_HARD_LINK(F,T)(create_hard_link_api(F, T, 0)!= 0)
224# define BOOST_CREATE_SYMBOLIC_LINK(F,T,Flag)(create_symbolic_link_api(F, T, Flag)!= 0)
225# define BOOST_REMOVE_DIRECTORY(P)(::RemoveDirectoryW(P)!= 0)
226# define BOOST_DELETE_FILE(P)(::DeleteFileW(P)!= 0)
227# define BOOST_COPY_DIRECTORY(F,T)(::CreateDirectoryExW(F, T, 0)!= 0)
228# define BOOST_COPY_FILE(F,T,FailIfExistsBool)(::CopyFileW(F, T, FailIfExistsBool)!= 0)
229# define BOOST_MOVE_FILE(OLD,NEW)(::MoveFileExW(OLD, NEW, MOVEFILE_REPLACE_EXISTING)!= 0)
230# define BOOST_RESIZE_FILE(P,SZ)(resize_file_api(P, SZ)!= 0)
231# define BOOST_READ_SYMLINK(P,T)
232
233# define BOOST_ERROR_ALREADY_EXISTS ERROR_ALREADY_EXISTS
234# define BOOST_ERROR_NOT_SUPPORTED ERROR_NOT_SUPPORTED
235
236# endif
237
238//--------------------------------------------------------------------------------------//
239// //
240// helpers (all operating systems) //
241// //
242//--------------------------------------------------------------------------------------//
243
244namespace
245{
246
247# ifdef BOOST_POSIX_API
248 const char dot = '.';
249# else
250 const wchar_t dot = L'.';
251# endif
252
253 fs::file_type query_file_type(const path& p, error_code* ec);
254
255 boost::filesystem3::directory_iterator end_dir_itr;
256
257 const std::size_t buf_size(128);
258 const error_code ok;
259
260 bool error(bool was_error, error_code* ec, const string& message)
261 {
262 if (!was_error)
263 {
264 if (ec != 0) ec->clear();
265 }
266 else
267 { // error
268 if (ec == 0)
269 BOOST_FILESYSTEM_THROW(filesystem_error(message,
270 error_code(BOOST_ERRNO, system_category())));
271 else
272 ec->assign(BOOST_ERRNO, system_category());
273 }
274 return was_error;
275 }
276
277 bool error(bool was_error, const path& p, error_code* ec, const string& message)
278 {
279 if (!was_error)
280 {
281 if (ec != 0) ec->clear();
282 }
283 else
284 { // error
285 if (ec == 0)
286 BOOST_FILESYSTEM_THROW(filesystem_error(message,
287 p, error_code(BOOST_ERRNO, system_category())));
288 else
289 ec->assign(BOOST_ERRNO, system_category());
290 }
291 return was_error;
292 }
293
294 bool error(bool was_error, const path& p1, const path& p2, error_code* ec,
295 const string& message)
296 {
297 if (!was_error)
298 {
299 if (ec != 0) ec->clear();
300 }
301 else
302 { // error
303 if (ec == 0)
304 BOOST_FILESYSTEM_THROW(filesystem_error(message,
305 p1, p2, error_code(BOOST_ERRNO, system_category())));
306 else
307 ec->assign(BOOST_ERRNO, system_category());
308 }
309 return was_error;
310 }
311
312 bool error(bool was_error, const error_code& result,
313 const path& p, error_code* ec, const string& message)
314 // Overwrites ec if there has already been an error
315 {
316 if (!was_error)
317 {
318 if (ec != 0) ec->clear();
319 }
320 else
321 { // error
322 if (ec == 0)
323 BOOST_FILESYSTEM_THROW(filesystem_error(message, p, result));
324 else
325 *ec = result;
326 }
327 return was_error;
328 }
329
330 bool error(bool was_error, const error_code& result,
331 const path& p1, const path& p2, error_code* ec, const string& message)
332 // Overwrites ec if there has already been an error
333 {
334 if (!was_error)
335 {
336 if (ec != 0) ec->clear();
337 }
338 else
339 { // error
340 if (ec == 0)
341 BOOST_FILESYSTEM_THROW(filesystem_error(message, p1, p2, result));
342 else
343 *ec = result;
344 }
345 return was_error;
346 }
347
348 bool is_empty_directory(const path& p)
349 {
350 return fs::directory_iterator(p)== end_dir_itr;
351 }
352
353 bool remove_directory(const path& p) // true if succeeds
354 { return BOOST_REMOVE_DIRECTORY(p.c_str()); }
355
356 bool remove_file(const path& p) // true if succeeds
357 { return BOOST_DELETE_FILE(p.c_str()); }
358
359 // called by remove and remove_all_aux
360 bool remove_file_or_directory(const path& p, fs::file_type type, error_code* ec)
361 // return true if file removed, false if not removed
362 {
363 if (type == fs::file_not_found)
364 {
365 if (ec != 0) ec->clear();
366 return false;
367 }
368
369 if (type == fs::directory_file
370# ifdef BOOST_WINDOWS_API
371 || type == fs::_detail_directory_symlink
372# endif
373 )
374 {
375 if (error(!remove_directory(p), p, ec, "boost::filesystem::remove"))
376 return false;
377 }
378 else
379 {
380 if (error(!remove_file(p), p, ec, "boost::filesystem::remove"))
381 return false;
382 }
383 return true;
384 }
385
386 boost::uintmax_t remove_all_aux(const path& p, fs::file_type type,
387 error_code* ec)
388 {
389 boost::uintmax_t count = 1;
390
391 if (type == fs::directory_file) // but not a directory symlink
392 {
393 for (fs::directory_iterator itr(p);
394 itr != end_dir_itr; ++itr)
395 {
396 fs::file_type tmp_type = query_file_type(itr->path(), ec);
397 if (ec != 0 && *ec)
398 return count;
399 count += remove_all_aux(itr->path(), tmp_type, ec);
400 }
401 }
402 remove_file_or_directory(p, type, ec);
403 return count;
404 }
405
406#ifdef BOOST_POSIX_API
407
408//--------------------------------------------------------------------------------------//
409// //
410// POSIX-specific helpers //
411// //
412//--------------------------------------------------------------------------------------//
413
414 bool not_found_error(int errval)
415 {
416 return errno == ENOENT || errno == ENOTDIR;
417 }
418
419 bool // true if ok
420 copy_file_api(const std::string& from_p,
421 const std::string& to_p, bool fail_if_exists)
422 {
423 const std::size_t buf_sz = 32768;
424 boost::scoped_array<char> buf(new char [buf_sz]);
425 int infile=-1, outfile=-1; // -1 means not open
426
427 // bug fixed: code previously did a stat()on the from_file first, but that
428 // introduced a gratuitous race condition; the stat()is now done after the open()
429
430 if ((infile = ::open(from_p.c_str(), O_RDONLY))< 0)
431 { return false; }
432
433 struct stat from_stat;
434 if (::stat(from_p.c_str(), &from_stat)!= 0)
435 { return false; }
436
437 int oflag = O_CREAT | O_WRONLY | O_TRUNC;
438 if (fail_if_exists)
439 oflag |= O_EXCL;
440 if ((outfile = ::open(to_p.c_str(), oflag, from_stat.st_mode))< 0)
441 {
442 int open_errno = errno;
443 BOOST_ASSERT(infile >= 0);
444 ::close(infile);
445 errno = open_errno;
446 return false;
447 }
448
449 ssize_t sz, sz_read=1, sz_write;
450 while (sz_read > 0
451 && (sz_read = ::read(infile, buf.get(), buf_sz))> 0)
452 {
453 // Allow for partial writes - see Advanced Unix Programming (2nd Ed.),
454 // Marc Rochkind, Addison-Wesley, 2004, page 94
455 sz_write = 0;
456 do
457 {
458 if ((sz = ::write(outfile, buf.get() + sz_write,
459 sz_read - sz_write))< 0)
460 {
461 sz_read = sz; // cause read loop termination
462 break; // and error to be thrown after closes
463 }
464 sz_write += sz;
465 } while (sz_write < sz_read);
466 }
467
468 if (::close(infile)< 0)sz_read = -1;
469 if (::close(outfile)< 0)sz_read = -1;
470
471 return sz_read >= 0;
472 }
473
474 inline fs::file_type query_file_type(const path& p, error_code* ec)
475 {
476 return fs::detail::symlink_status(p, ec).type();
477 }
478
479# else
480
481//--------------------------------------------------------------------------------------//
482// //
483// Windows-specific helpers //
484// //
485//--------------------------------------------------------------------------------------//
486
487 bool not_found_error(int errval)
488 {
489 return errval == ERROR_FILE_NOT_FOUND
490 || errval == ERROR_PATH_NOT_FOUND
491 || errval == ERROR_INVALID_NAME // "tools/jam/src/:sys:stat.h", "//foo"
492 || errval == ERROR_INVALID_DRIVE // USB card reader with no card inserted
493 || errval == ERROR_NOT_READY // CD/DVD drive with no disc inserted
494 || errval == ERROR_INVALID_PARAMETER // ":sys:stat.h"
495 || errval == ERROR_BAD_PATHNAME // "//nosuch" on Win64
496 || errval == ERROR_BAD_NETPATH; // "//nosuch" on Win32
497 }
498
499 // these constants come from inspecting some Microsoft sample code
500 std::time_t to_time_t(const FILETIME & ft)
501 {
502 __int64 t = (static_cast<__int64>(ft.dwHighDateTime)<< 32)
503 + ft.dwLowDateTime;
504# if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 // > VC++ 7.0
505 t -= 116444736000000000LL;
506# else
507 t -= 116444736000000000;
508# endif
509 t /= 10000000;
510 return static_cast<std::time_t>(t);
511 }
512
513 void to_FILETIME(std::time_t t, FILETIME & ft)
514 {
515 __int64 temp = t;
516 temp *= 10000000;
517# if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 // > VC++ 7.0
518 temp += 116444736000000000LL;
519# else
520 temp += 116444736000000000;
521# endif
522 ft.dwLowDateTime = static_cast<DWORD>(temp);
523 ft.dwHighDateTime = static_cast<DWORD>(temp >> 32);
524 }
525
526 // Thanks to Jeremy Maitin-Shepard for much help and for permission to
527 // base the equivalent()implementation on portions of his
528 // file-equivalence-win32.cpp experimental code.
529
530 struct handle_wrapper
531 {
532 HANDLE handle;
533 handle_wrapper(HANDLE h)
534 : handle(h){}
535 ~handle_wrapper()
536 {
537 if (handle != INVALID_HANDLE_VALUE)
538 ::CloseHandle(handle);
539 }
540 };
541
542 HANDLE create_file_handle(const path& p, DWORD dwDesiredAccess,
543 DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes,
544 DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,
545 HANDLE hTemplateFile)
546 {
547 return ::CreateFileW(p.c_str(), dwDesiredAccess, dwShareMode,
548 lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes,
549 hTemplateFile);
550 }
551
552 bool is_reparse_point_a_symlink(const path& p)
553 {
554 handle_wrapper h(create_file_handle(p, FILE_READ_EA,
555 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING,
556 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL));
557 if (h.handle == INVALID_HANDLE_VALUE)
558 return false;
559
560 boost::scoped_array<char> buf(new char [MAXIMUM_REPARSE_DATA_BUFFER_SIZE]);
561
562 // Query the reparse data
563 DWORD dwRetLen;
564 BOOL result = ::DeviceIoControl(h.handle, FSCTL_GET_REPARSE_POINT, NULL, 0, buf.get(),
565 MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &dwRetLen, NULL);
566 if (!result) return false;
567
568 return reinterpret_cast<const REPARSE_DATA_BUFFER*>(buf.get())
569 ->ReparseTag == IO_REPARSE_TAG_SYMLINK;
570 }
571
572 inline std::size_t get_full_path_name(
573 const path& src, std::size_t len, wchar_t* buf, wchar_t** p)
574 {
575 return static_cast<std::size_t>(
576 ::GetFullPathNameW(src.c_str(), static_cast<DWORD>(len), buf, p));
577 }
578
579 fs::file_status process_status_failure(const path& p, error_code* ec)
580 {
581 int errval(::GetLastError());
582 if (ec != 0) // always report errval, even though some
583 ec->assign(errval, system_category()); // errval values are not status_errors
584
585 if (not_found_error(errval))
586 {
587 return fs::file_status(fs::file_not_found);
588 }
589 else if ((errval == ERROR_SHARING_VIOLATION))
590 {
591 return fs::file_status(fs::type_unknown);
592 }
593 if (ec == 0)
594 BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status",
595 p, error_code(errval, system_category())));
596 return fs::file_status(fs::status_error);
597 }
598
599 // differs from symlink_status() in that directory symlinks are reported as
600 // _detail_directory_symlink, as required on Windows by remove() and its helpers.
601 fs::file_type query_file_type(const path& p, error_code* ec)
602 {
603 DWORD attr(::GetFileAttributesW(p.c_str()));
604 if (attr == 0xFFFFFFFF)
605 {
606 return process_status_failure(p, ec).type();
607 }
608
609 if (ec != 0) ec->clear();
610
611 if (attr & FILE_ATTRIBUTE_REPARSE_POINT)
612 {
613 if (is_reparse_point_a_symlink(p))
614 return (attr & FILE_ATTRIBUTE_DIRECTORY)
615 ? fs::_detail_directory_symlink
616 : fs::symlink_file;
617 return fs::reparse_file;
618 }
619
620 return (attr & FILE_ATTRIBUTE_DIRECTORY)
621 ? fs::directory_file
622 : fs::regular_file;
623 }
624
625 BOOL resize_file_api(const wchar_t* p, boost::uintmax_t size)
626 {
627 HANDLE handle = CreateFileW(p, GENERIC_WRITE, 0, 0, OPEN_EXISTING,
628 FILE_ATTRIBUTE_NORMAL, 0);
629 LARGE_INTEGER sz;
630 sz.QuadPart = size;
631 return handle != INVALID_HANDLE_VALUE
632 && ::SetFilePointerEx(handle, sz, 0, FILE_BEGIN)
633 && ::SetEndOfFile(handle)
634 && ::CloseHandle(handle);
635 }
636
637 // Windows kernel32.dll functions that may or may not be present
638 // must be accessed through pointers
639
640 typedef BOOL (WINAPI *PtrCreateHardLinkW)(
641 /*__in*/ LPCWSTR lpFileName,
642 /*__in*/ LPCWSTR lpExistingFileName,
643 /*__reserved*/ LPSECURITY_ATTRIBUTES lpSecurityAttributes
644 );
645
646 PtrCreateHardLinkW create_hard_link_api = PtrCreateHardLinkW(
647 ::GetProcAddress(
648 ::GetModuleHandle(TEXT("kernel32.dll")), "CreateHardLinkW"));
649
650 typedef BOOLEAN (WINAPI *PtrCreateSymbolicLinkW)(
651 /*__in*/ LPCWSTR lpSymlinkFileName,
652 /*__in*/ LPCWSTR lpTargetFileName,
653 /*__in*/ DWORD dwFlags
654 );
655
656 PtrCreateSymbolicLinkW create_symbolic_link_api = PtrCreateSymbolicLinkW(
657 ::GetProcAddress(
658 ::GetModuleHandle(TEXT("kernel32.dll")), "CreateSymbolicLinkW"));
659
660#endif
661
662//#ifdef BOOST_WINDOWS_API
663//
664//
665// inline bool get_free_disk_space(const std::wstring& ph,
666// PULARGE_INTEGER avail, PULARGE_INTEGER total, PULARGE_INTEGER free)
667// { return ::GetDiskFreeSpaceExW(ph.c_str(), avail, total, free)!= 0; }
668//
669//#endif
670
671} // unnamed namespace
672
673//--------------------------------------------------------------------------------------//
674// //
675// operations functions declared in operations.hpp //
676// in alphabetic order //
677// //
678//--------------------------------------------------------------------------------------//
679
680namespace boost
681{
682namespace filesystem3
683{
684
685 BOOST_FILESYSTEM_DECL
686 path absolute(const path& p, const path& base)
687 {
688// if ( p.empty() || p.is_absolute() )
689// return p;
690// // recursively calling absolute is sub-optimal, but is simple
691// path abs_base(base.is_absolute() ? base : absolute(base));
692//# ifdef BOOST_WINDOWS_API
693// if (p.has_root_directory())
694// return abs_base.root_name() / p;
695// // !p.has_root_directory
696// if (p.has_root_name())
697// return p.root_name()
698// / abs_base.root_directory() / abs_base.relative_path() / p.relative_path();
699// // !p.has_root_name()
700//# endif
701// return abs_base / p;
702
703 // recursively calling absolute is sub-optimal, but is sure and simple
704 path abs_base(base.is_absolute() ? base : absolute(base));
705
706 // store expensive to compute values that are needed multiple times
707 path p_root_name (p.root_name());
708 path base_root_name (abs_base.root_name());
709 path p_root_directory (p.root_directory());
710
711 if (p.empty())
712 return abs_base;
713
714 if (!p_root_name.empty()) // p.has_root_name()
715 {
716 if (p_root_directory.empty()) // !p.has_root_directory()
717 return p_root_name / abs_base.root_directory()
718 / abs_base.relative_path() / p.relative_path();
719 // p is absolute, so fall through to return p at end of block
720 }
721
722 else if (!p_root_directory.empty()) // p.has_root_directory()
723 {
724# ifdef BOOST_POSIX_API
725 // POSIX can have root name it it is a network path
726 if (base_root_name.empty()) // !abs_base.has_root_name()
727 return p;
728# endif
729 return base_root_name / p;
730 }
731
732 else
733 {
734 return abs_base / p;
735 }
736
737 return p; // p.is_absolute() is true
738 }
739
740namespace detail
741{
742 BOOST_FILESYSTEM_DECL bool possible_large_file_size_support()
743 {
744# ifdef BOOST_POSIX_API
745 struct stat lcl_stat;
746 return sizeof(lcl_stat.st_size)> 4;
747# else
748 return true;
749# endif
750 }
751
752 BOOST_FILESYSTEM_DECL
753 void copy(const path& from, const path& to, system::error_code* ec)
754 {
755 file_status s(symlink_status(from, *ec));
756 if (ec != 0 && *ec) return;
757
758 if(is_symlink(s))
759 {
760 copy_symlink(from, to, *ec);
761 }
762 else if(is_directory(s))
763 {
764 copy_directory(from, to, *ec);
765 }
766 else if(is_regular_file(s))
767 {
768 copy_file(from, to, copy_option::fail_if_exists, *ec);
769 }
770 else
771 {
772 if (ec == 0)
773 BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::copy",
774 from, to, error_code(BOOST_ERROR_NOT_SUPPORTED, system_category())));
775 ec->assign(BOOST_ERROR_NOT_SUPPORTED, system_category());
776 }
777 }
778
779 BOOST_FILESYSTEM_DECL
780 void copy_directory(const path& from, const path& to, system::error_code* ec)
781 {
782# ifdef BOOST_POSIX_API
783 struct stat from_stat;
784# endif
785 error(!BOOST_COPY_DIRECTORY(from.c_str(), to.c_str()),
786 from, to, ec, "boost::filesystem::copy_directory");
787 }
788
789 BOOST_FILESYSTEM_DECL
790 void copy_file(const path& from, const path& to,
791 BOOST_SCOPED_ENUM(copy_option)option,
792 error_code* ec)
793 {
794 error(!BOOST_COPY_FILE(from.c_str(), to.c_str(),
795 option == copy_option::fail_if_exists),
796 from, to, ec, "boost::filesystem::copy_file");
797 }
798
799 BOOST_FILESYSTEM_DECL
800 void copy_symlink(const path& existing_symlink, const path& new_symlink,
801 system::error_code* ec)
802 {
803# if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0600
804 error(true, error_code(BOOST_ERROR_NOT_SUPPORTED, system_category()),
805 new_symlink, existing_symlink, ec,
806 "boost::filesystem::copy_symlink");
807
808# else // modern Windows or BOOST_POSIX_API
809 path p(read_symlink(existing_symlink, ec));
810 if (ec != 0 && *ec) return;
811 create_symlink(p, new_symlink, ec);
812
813# endif
814 }
815
816 BOOST_FILESYSTEM_DECL
817 bool create_directories(const path& p, system::error_code* ec)
818 {
819 if (p.empty() || exists(p))
820 {
821 if (!p.empty() && !is_directory(p))
822 {
823 if (ec == 0)
824 BOOST_FILESYSTEM_THROW(filesystem_error(
825 "boost::filesystem::create_directories", p,
826 error_code(system::errc::file_exists, system::generic_category())));
827 else ec->assign(system::errc::file_exists, system::generic_category());
828 }
829 return false;
830 }
831
832 // First create branch, by calling ourself recursively
833 create_directories(p.parent_path(), ec);
834 // Now that parent's path exists, create the directory
835 create_directory(p, ec);
836 return true;
837 }
838
839 BOOST_FILESYSTEM_DECL
840 bool create_directory(const path& p, error_code* ec)
841 {
842 if (BOOST_CREATE_DIRECTORY(p.c_str()))
843 {
844 if (ec != 0) ec->clear();
845 return true;
846 }
847
848 // attempt to create directory failed
849 int errval(BOOST_ERRNO); // save reason for failure
850 error_code dummy;
851 if (errval == BOOST_ERROR_ALREADY_EXISTS && is_directory(p, dummy))
852 {
853 if (ec != 0) ec->clear();
854 return false;
855 }
856
857 // attempt to create directory failed && it doesn't already exist
858 if (ec == 0)
859 BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::create_directory",
860 p, error_code(errval, system_category())));
861 else
862 ec->assign(errval, system_category());
863 return false;
864 }
865
866 BOOST_FILESYSTEM_DECL
867 void create_directory_symlink(const path& to, const path& from,
868 system::error_code* ec)
869 {
870# if defined(BOOST_WINDOWS_API) && _WIN32_WINNT < 0x0600 // SDK earlier than Vista and Server 2008
871
872 error(true, error_code(BOOST_ERROR_NOT_SUPPORTED, system_category()), to, from, ec,
873 "boost::filesystem::create_directory_symlink");
874# else
875
876# if defined(BOOST_WINDOWS_API) && _WIN32_WINNT >= 0x0600
877 // see if actually supported by Windows runtime dll
878 if (error(!create_symbolic_link_api,
879 error_code(BOOST_ERROR_NOT_SUPPORTED, system_category()),
880 to, from, ec,
881 "boost::filesystem::create_directory_symlink"))
882 return;
883# endif
884
885 error(!BOOST_CREATE_SYMBOLIC_LINK(from.c_str(), to.c_str(), SYMBOLIC_LINK_FLAG_DIRECTORY),
886 to, from, ec, "boost::filesystem::create_directory_symlink");
887# endif
888 }
889
890 BOOST_FILESYSTEM_DECL
891 void create_hard_link(const path& to, const path& from, error_code* ec)
892 {
893
894# if defined(BOOST_WINDOWS_API) && _WIN32_WINNT < 0x0500 // SDK earlier than Win 2K
895
896 error(true, error_code(BOOST_ERROR_NOT_SUPPORTED, system_category()), to, from, ec,
897 "boost::filesystem::create_hard_link");
898# else
899
900# if defined(BOOST_WINDOWS_API) && _WIN32_WINNT >= 0x0500
901 // see if actually supported by Windows runtime dll
902 if (error(!create_hard_link_api,
903 error_code(BOOST_ERROR_NOT_SUPPORTED, system_category()),
904 to, from, ec,
905 "boost::filesystem::create_hard_link"))
906 return;
907# endif
908
909 error(!BOOST_CREATE_HARD_LINK(from.c_str(), to.c_str()), to, from, ec,
910 "boost::filesystem::create_hard_link");
911# endif
912 }
913
914 BOOST_FILESYSTEM_DECL
915 void create_symlink(const path& to, const path& from, error_code* ec)
916 {
917# if defined(BOOST_WINDOWS_API) && _WIN32_WINNT < 0x0600 // SDK earlier than Vista and Server 2008
918 error(true, error_code(BOOST_ERROR_NOT_SUPPORTED, system_category()), to, from, ec,
919 "boost::filesystem::create_directory_symlink");
920# else
921
922# if defined(BOOST_WINDOWS_API) && _WIN32_WINNT >= 0x0600
923 // see if actually supported by Windows runtime dll
924 if (error(!create_symbolic_link_api,
925 error_code(BOOST_ERROR_NOT_SUPPORTED, system_category()),
926 to, from, ec,
927 "boost::filesystem::create_symlink"))
928 return;
929# endif
930
931 error(!BOOST_CREATE_SYMBOLIC_LINK(from.c_str(), to.c_str(), 0),
932 to, from, ec, "boost::filesystem::create_symlink");
933# endif
934 }
935
936 BOOST_FILESYSTEM_DECL
937 path current_path(error_code* ec)
938 {
939# ifdef BOOST_POSIX_API
940 path cur;
941 for (long path_max = 128;; path_max *=2)// loop 'til buffer large enough
942 {
943 boost::scoped_array<char>
944 buf(new char[static_cast<std::size_t>(path_max)]);
945 if (::getcwd(buf.get(), static_cast<std::size_t>(path_max))== 0)
946 {
947 if (error(errno != ERANGE
948 // bug in some versions of the Metrowerks C lib on the Mac: wrong errno set
949# if defined(__MSL__) && (defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__))
950 && errno != 0
951# endif
952 , ec, "boost::filesystem::current_path"))
953 {
954 break;
955 }
956 }
957 else
958 {
959 cur = buf.get();
960 if (ec != 0) ec->clear();
961 break;
962 }
963 }
964 return cur;
965
966# else
967 DWORD sz;
968 if ((sz = ::GetCurrentDirectoryW(0, NULL))== 0)sz = 1;
969 boost::scoped_array<path::value_type> buf(new path::value_type[sz]);
970 error(::GetCurrentDirectoryW(sz, buf.get())== 0, ec,
971 "boost::filesystem::current_path");
972 return path(buf.get());
973# endif
974 }
975
976
977 BOOST_FILESYSTEM_DECL
978 void current_path(const path& p, system::error_code* ec)
979 {
980 error(!BOOST_SET_CURRENT_DIRECTORY(p.c_str()),
981 p, ec, "boost::filesystem::current_path");
982 }
983
984 BOOST_FILESYSTEM_DECL
985 bool equivalent(const path& p1, const path& p2, system::error_code* ec)
986 {
987# ifdef BOOST_POSIX_API
988 struct stat s2;
989 int e2(::stat(p2.c_str(), &s2));
990 struct stat s1;
991 int e1(::stat(p1.c_str(), &s1));
992
993 if (e1 != 0 || e2 != 0)
994 {
995 // if one is invalid and the other isn't then they aren't equivalent,
996 // but if both are invalid then it is an error
997 error (e1 != 0 && e2 != 0, p1, p2, ec, "boost::filesystem::equivalent");
998 return false;
999 }
1000
1001 // both stats now known to be valid
1002 return s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino
1003 // According to the POSIX stat specs, "The st_ino and st_dev fields
1004 // taken together uniquely identify the file within the system."
1005 // Just to be sure, size and mod time are also checked.
1006 && s1.st_size == s2.st_size && s1.st_mtime == s2.st_mtime;
1007
1008# else // Windows
1009
1010 // Note well: Physical location on external media is part of the
1011 // equivalence criteria. If there are no open handles, physical location
1012 // can change due to defragmentation or other relocations. Thus handles
1013 // must be held open until location information for both paths has
1014 // been retrieved.
1015
1016 // p2 is done first, so any error reported is for p1
1017 handle_wrapper h2(
1018 create_file_handle(
1019 p2.c_str(),
1020 0,
1021 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
1022 0,
1023 OPEN_EXISTING,
1024 FILE_FLAG_BACKUP_SEMANTICS,
1025 0));
1026
1027 handle_wrapper h1(
1028 create_file_handle(
1029 p1.c_str(),
1030 0,
1031 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
1032 0,
1033 OPEN_EXISTING,
1034 FILE_FLAG_BACKUP_SEMANTICS,
1035 0));
1036
1037 if (h1.handle == INVALID_HANDLE_VALUE
1038 || h2.handle == INVALID_HANDLE_VALUE)
1039 {
1040 // if one is invalid and the other isn't, then they aren't equivalent,
1041 // but if both are invalid then it is an error
1042 error(h1.handle == INVALID_HANDLE_VALUE
1043 && h2.handle == INVALID_HANDLE_VALUE, p1, p2, ec,
1044 "boost::filesystem::equivalent");
1045 return false;
1046 }
1047
1048 // at this point, both handles are known to be valid
1049
1050 BY_HANDLE_FILE_INFORMATION info1, info2;
1051
1052 if (error(!::GetFileInformationByHandle(h1.handle, &info1),
1053 p1, p2, ec, "boost::filesystem::equivalent"))
1054 return false;
1055
1056 if (error(!::GetFileInformationByHandle(h2.handle, &info2),
1057 p1, p2, ec, "boost::filesystem::equivalent"))
1058 return false;
1059
1060 // In theory, volume serial numbers are sufficient to distinguish between
1061 // devices, but in practice VSN's are sometimes duplicated, so last write
1062 // time and file size are also checked.
1063 return
1064 info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber
1065 && info1.nFileIndexHigh == info2.nFileIndexHigh
1066 && info1.nFileIndexLow == info2.nFileIndexLow
1067 && info1.nFileSizeHigh == info2.nFileSizeHigh
1068 && info1.nFileSizeLow == info2.nFileSizeLow
1069 && info1.ftLastWriteTime.dwLowDateTime
1070 == info2.ftLastWriteTime.dwLowDateTime
1071 && info1.ftLastWriteTime.dwHighDateTime
1072 == info2.ftLastWriteTime.dwHighDateTime;
1073
1074# endif
1075 }
1076
1077 BOOST_FILESYSTEM_DECL
1078 boost::uintmax_t file_size(const path& p, error_code* ec)
1079 {
1080# ifdef BOOST_POSIX_API
1081
1082 struct stat path_stat;
1083 if (error(::stat(p.c_str(), &path_stat)!= 0,
1084 p, ec, "boost::filesystem::file_size"))
1085 return static_cast<boost::uintmax_t>(-1);
1086 if (error(!S_ISREG(path_stat.st_mode),
1087 error_code(EPERM, system_category()),
1088 p, ec, "boost::filesystem::file_size"))
1089 return static_cast<boost::uintmax_t>(-1);
1090
1091 return static_cast<boost::uintmax_t>(path_stat.st_size);
1092
1093# else // Windows
1094
1095 // assume uintmax_t is 64-bits on all Windows compilers
1096
1097 WIN32_FILE_ATTRIBUTE_DATA fad;
1098
1099 if (error(::GetFileAttributesExW(p.c_str(), ::GetFileExInfoStandard, &fad)== 0,
1100 p, ec, "boost::filesystem::file_size"))
1101 return static_cast<boost::uintmax_t>(-1);
1102
1103 if (error((fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)!= 0,
1104 error_code(ERROR_NOT_SUPPORTED, system_category()),
1105 p, ec, "boost::filesystem::file_size"))
1106 return static_cast<boost::uintmax_t>(-1);
1107
1108 return (static_cast<boost::uintmax_t>(fad.nFileSizeHigh)
1109 << (sizeof(fad.nFileSizeLow)*8)) + fad.nFileSizeLow;
1110# endif
1111 }
1112
1113 BOOST_FILESYSTEM_DECL
1114 boost::uintmax_t hard_link_count(const path& p, system::error_code* ec)
1115 {
1116# ifdef BOOST_POSIX_API
1117
1118 struct stat path_stat;
1119 return error(::stat(p.c_str(), &path_stat)!= 0,
1120 p, ec, "boost::filesystem::hard_link_count")
1121 ? 0
1122 : static_cast<boost::uintmax_t>(path_stat.st_nlink);
1123
1124# else // Windows
1125
1126 // Link count info is only available through GetFileInformationByHandle
1127 BY_HANDLE_FILE_INFORMATION info;
1128 handle_wrapper h(
1129 create_file_handle(p.c_str(), 0,
1130 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
1131 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0));
1132 return
1133 !error(h.handle == INVALID_HANDLE_VALUE,
1134 p, ec, "boost::filesystem::hard_link_count")
1135 && !error(::GetFileInformationByHandle(h.handle, &info)== 0,
1136 p, ec, "boost::filesystem::hard_link_count")
1137 ? info.nNumberOfLinks
1138 : 0;
1139# endif
1140 }
1141
1142 BOOST_FILESYSTEM_DECL
1143 path initial_path(error_code* ec)
1144 {
1145 static path init_path;
1146 if (init_path.empty())
1147 init_path = current_path(ec);
1148 else if (ec != 0) ec->clear();
1149 return init_path;
1150 }
1151
1152 BOOST_FILESYSTEM_DECL
1153 bool is_empty(const path& p, system::error_code* ec)
1154 {
1155# ifdef BOOST_POSIX_API
1156
1157 struct stat path_stat;
1158 if (error(::stat(p.c_str(), &path_stat)!= 0,
1159 p, ec, "boost::filesystem::is_empty"))
1160 return false;
1161 return S_ISDIR(path_stat.st_mode)
1162 ? is_empty_directory(p)
1163 : path_stat.st_size == 0;
1164# else
1165
1166 WIN32_FILE_ATTRIBUTE_DATA fad;
1167 if (error(::GetFileAttributesExW(p.c_str(), ::GetFileExInfoStandard, &fad)== 0,
1168 p, ec, "boost::filesystem::is_empty"))
1169 return false;
1170
1171 if (ec != 0) ec->clear();
1172 return
1173 (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1174 ? is_empty_directory(p)
1175 : (!fad.nFileSizeHigh && !fad.nFileSizeLow);
1176# endif
1177 }
1178
1179 BOOST_FILESYSTEM_DECL
1180 std::time_t last_write_time(const path& p, system::error_code* ec)
1181 {
1182# ifdef BOOST_POSIX_API
1183
1184 struct stat path_stat;
1185 if (error(::stat(p.c_str(), &path_stat)!= 0,
1186 p, ec, "boost::filesystem::last_write_time"))
1187 return std::time_t(-1);
1188 return path_stat.st_mtime;
1189
1190# else
1191
1192 handle_wrapper hw(
1193 create_file_handle(p.c_str(), 0,
1194 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
1195 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0));
1196
1197 if (error(hw.handle == INVALID_HANDLE_VALUE,
1198 p, ec, "boost::filesystem::last_write_time"))
1199 return std::time_t(-1);
1200
1201 FILETIME lwt;
1202
1203 if (error(::GetFileTime(hw.handle, 0, 0, &lwt)== 0,
1204 p, ec, "boost::filesystem::last_write_time"))
1205 return std::time_t(-1);
1206
1207 return to_time_t(lwt);
1208# endif
1209 }
1210
1211 BOOST_FILESYSTEM_DECL
1212 void last_write_time(const path& p, const std::time_t new_time,
1213 system::error_code* ec)
1214 {
1215# ifdef BOOST_POSIX_API
1216
1217 struct stat path_stat;
1218 if (error(::stat(p.c_str(), &path_stat)!= 0,
1219 p, ec, "boost::filesystem::last_write_time"))
1220 return;
1221 ::utimbuf buf;
1222 buf.actime = path_stat.st_atime; // utime()updates access time too:-(
1223 buf.modtime = new_time;
1224 error(::utime(p.c_str(), &buf)!= 0,
1225 p, ec, "boost::filesystem::last_write_time");
1226
1227# else
1228
1229 handle_wrapper hw(
1230 create_file_handle(p.c_str(), FILE_WRITE_ATTRIBUTES,
1231 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
1232 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0));
1233
1234 if (error(hw.handle == INVALID_HANDLE_VALUE,
1235 p, ec, "boost::filesystem::last_write_time"))
1236 return;
1237
1238 FILETIME lwt;
1239 to_FILETIME(new_time, lwt);
1240
1241 error(::SetFileTime(hw.handle, 0, 0, &lwt)== 0,
1242 p, ec, "boost::filesystem::last_write_time");
1243# endif
1244 }
1245
1246 BOOST_FILESYSTEM_DECL
1247 path read_symlink(const path& p, system::error_code* ec)
1248 {
1249 path symlink_path;
1250
1251# ifdef BOOST_POSIX_API
1252
1253 for (std::size_t path_max = 64;; path_max *= 2)// loop 'til buffer large enough
1254 {
1255 boost::scoped_array<char> buf(new char[path_max]);
1256 ssize_t result;
1257 if ((result=::readlink(p.c_str(), buf.get(), path_max))== -1)
1258 {
1259 if (ec == 0)
1260 BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::read_symlink",
1261 p, error_code(errno, system_category())));
1262 else ec->assign(errno, system_category());
1263 break;
1264 }
1265 else
1266 {
1267 if(result != static_cast<ssize_t>(path_max))
1268 {
1269 symlink_path.assign(buf.get(), buf.get() + result);
1270 if (ec != 0) ec->clear();
1271 break;
1272 }
1273 }
1274 }
1275
1276# elif _WIN32_WINNT < 0x0600 // SDK earlier than Vista and Server 2008
1277 error(true, error_code(BOOST_ERROR_NOT_SUPPORTED, system_category()), p, ec,
1278 "boost::filesystem::read_symlink");
1279# else // Vista and Server 2008 SDK, or later
1280
1281 union info_t
1282 {
1283 char buf[REPARSE_DATA_BUFFER_HEADER_SIZE+MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
1284 REPARSE_DATA_BUFFER rdb;
1285 } info;
1286
1287 handle_wrapper h(
1288 create_file_handle(p.c_str(), GENERIC_READ, 0, 0, OPEN_EXISTING,
1289 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0));
1290
1291 if (error(h.handle == INVALID_HANDLE_VALUE, p, ec, "boost::filesystem::read_symlink"))
1292 return symlink_path;
1293
1294 DWORD sz;
1295
1296 if (!error(::DeviceIoControl(h.handle, FSCTL_GET_REPARSE_POINT,
1297 0, 0, info.buf, sizeof(info), &sz, 0) == 0, p, ec,
1298 "boost::filesystem::read_symlink" ))
1299 symlink_path.assign(
1300 static_cast<wchar_t*>(info.rdb.SymbolicLinkReparseBuffer.PathBuffer)
1301 + info.rdb.SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(wchar_t),
1302 static_cast<wchar_t*>(info.rdb.SymbolicLinkReparseBuffer.PathBuffer)
1303 + info.rdb.SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(wchar_t)
1304 + info.rdb.SymbolicLinkReparseBuffer.PrintNameLength/sizeof(wchar_t));
1305# endif
1306 return symlink_path;
1307 }
1308
1309 BOOST_FILESYSTEM_DECL
1310 bool remove(const path& p, error_code* ec)
1311 {
1312 error_code tmp_ec;
1313 file_type type = query_file_type(p, &tmp_ec);
1314 if (error(type == status_error, tmp_ec, p, ec,
1315 "boost::filesystem::remove"))
1316 return false;
1317
1318 // Since POSIX remove() is specified to work with either files or directories, in a
1319 // perfect world it could just be called. But some important real-world operating
1320 // systems (Windows, Mac OS X, for example) don't implement the POSIX spec. So
1321 // remove_file_or_directory() is always called to kep it simple.
1322 return remove_file_or_directory(p, type, ec);
1323 }
1324
1325 BOOST_FILESYSTEM_DECL
1326 boost::uintmax_t remove_all(const path& p, error_code* ec)
1327 {
1328 error_code tmp_ec;
1329 file_type type = query_file_type(p, &tmp_ec);
1330 if (error(type == status_error, tmp_ec, p, ec,
1331 "boost::filesystem::remove_all"))
1332 return 0;
1333
1334 return (type != status_error && type != file_not_found) // exists
1335 ? remove_all_aux(p, type, ec)
1336 : 0;
1337 }
1338
1339 BOOST_FILESYSTEM_DECL
1340 void rename(const path& old_p, const path& new_p, error_code* ec)
1341 {
1342 error(!BOOST_MOVE_FILE(old_p.c_str(), new_p.c_str()), old_p, new_p, ec,
1343 "boost::filesystem::rename");
1344 }
1345
1346 BOOST_FILESYSTEM_DECL
1347 void resize_file(const path& p, uintmax_t size, system::error_code* ec)
1348 {
1349 error(!BOOST_RESIZE_FILE(p.c_str(), size), p, ec, "boost::filesystem::resize_file");
1350 }
1351
1352 BOOST_FILESYSTEM_DECL
1353 space_info space(const path& p, error_code* ec)
1354 {
1355# ifdef BOOST_POSIX_API
1356 struct BOOST_STATVFS vfs;
1357 space_info info;
1358 if (!error(::BOOST_STATVFS(p.c_str(), &vfs)!= 0,
1359 p, ec, "boost::filesystem::space"))
1360 {
1361 info.capacity
1362 = static_cast<boost::uintmax_t>(vfs.f_blocks)* BOOST_STATVFS_F_FRSIZE;
1363 info.free
1364 = static_cast<boost::uintmax_t>(vfs.f_bfree)* BOOST_STATVFS_F_FRSIZE;
1365 info.available
1366 = static_cast<boost::uintmax_t>(vfs.f_bavail)* BOOST_STATVFS_F_FRSIZE;
1367 }
1368
1369# else
1370 ULARGE_INTEGER avail, total, free;
1371 space_info info;
1372
1373 if (!error(::GetDiskFreeSpaceExW(p.c_str(), &avail, &total, &free)== 0,
1374 p, ec, "boost::filesystem::space"))
1375 {
1376 info.capacity
1377 = (static_cast<boost::uintmax_t>(total.HighPart)<< 32)
1378 + total.LowPart;
1379 info.free
1380 = (static_cast<boost::uintmax_t>(free.HighPart)<< 32)
1381 + free.LowPart;
1382 info.available
1383 = (static_cast<boost::uintmax_t>(avail.HighPart)<< 32)
1384 + avail.LowPart;
1385 }
1386
1387# endif
1388
1389 else
1390 {
1391 info.capacity = info.free = info.available = 0;
1392 }
1393 return info;
1394 }
1395
1396 BOOST_FILESYSTEM_DECL
1397 file_status status(const path& p, error_code* ec)
1398 {
1399# ifdef BOOST_POSIX_API
1400
1401 struct stat path_stat;
1402 if (::stat(p.c_str(), &path_stat)!= 0)
1403 {
1404 if (ec != 0) // always report errno, even though some
1405 ec->assign(errno, system_category()); // errno values are not status_errors
1406
1407 if (not_found_error(errno))
1408 {
1409 return fs::file_status(fs::file_not_found);
1410 }
1411 if (ec == 0)
1412 BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status",
1413 p, error_code(errno, system_category())));
1414 return fs::file_status(fs::status_error);
1415 }
1416 if (ec != 0) ec->clear();;
1417 if (S_ISDIR(path_stat.st_mode))
1418 return fs::file_status(fs::directory_file);
1419 if (S_ISREG(path_stat.st_mode))
1420 return fs::file_status(fs::regular_file);
1421 if (S_ISBLK(path_stat.st_mode))
1422 return fs::file_status(fs::block_file);
1423 if (S_ISCHR(path_stat.st_mode))
1424 return fs::file_status(fs::character_file);
1425 if (S_ISFIFO(path_stat.st_mode))
1426 return fs::file_status(fs::fifo_file);
1427 if (S_ISSOCK(path_stat.st_mode))
1428 return fs::file_status(fs::socket_file);
1429 return fs::file_status(fs::type_unknown);
1430
1431# else // Windows
1432
1433 DWORD attr(::GetFileAttributesW(p.c_str()));
1434 if (attr == 0xFFFFFFFF)
1435 {
1436 return process_status_failure(p, ec);
1437 }
1438
1439 // reparse point handling
1440 if (attr & FILE_ATTRIBUTE_REPARSE_POINT)
1441 {
1442 handle_wrapper h(
1443 create_file_handle(
1444 p.c_str(),
1445 0, // dwDesiredAccess; attributes only
1446 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
1447 0, // lpSecurityAttributes
1448 OPEN_EXISTING,
1449 FILE_FLAG_BACKUP_SEMANTICS,
1450 0)); // hTemplateFile
1451 if (h.handle == INVALID_HANDLE_VALUE)
1452 {
1453 return process_status_failure(p, ec);
1454 }
1455
1456 if (!is_reparse_point_a_symlink(p))
1457 return file_status(reparse_file);
1458 }
1459
1460 if (ec != 0) ec->clear();
1461 return (attr & FILE_ATTRIBUTE_DIRECTORY)
1462 ? file_status(directory_file)
1463 : file_status(regular_file);
1464
1465# endif
1466 }
1467
1468 BOOST_FILESYSTEM_DECL
1469 file_status symlink_status(const path& p, error_code* ec)
1470 {
1471# ifdef BOOST_POSIX_API
1472
1473 struct stat path_stat;
1474 if (::lstat(p.c_str(), &path_stat)!= 0)
1475 {
1476 if (ec != 0) // always report errno, even though some
1477 ec->assign(errno, system_category()); // errno values are not status_errors
1478
1479 if (errno == ENOENT || errno == ENOTDIR) // these are not errors
1480 {
1481 return fs::file_status(fs::file_not_found);
1482 }
1483 if (ec == 0)
1484 BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status",
1485 p, error_code(errno, system_category())));
1486 return fs::file_status(fs::status_error);
1487 }
1488 if (ec != 0) ec->clear();
1489 if (S_ISREG(path_stat.st_mode))
1490 return fs::file_status(fs::regular_file);
1491 if (S_ISDIR(path_stat.st_mode))
1492 return fs::file_status(fs::directory_file);
1493 if (S_ISLNK(path_stat.st_mode))
1494 return fs::file_status(fs::symlink_file);
1495 if (S_ISBLK(path_stat.st_mode))
1496 return fs::file_status(fs::block_file);
1497 if (S_ISCHR(path_stat.st_mode))
1498 return fs::file_status(fs::character_file);
1499 if (S_ISFIFO(path_stat.st_mode))
1500 return fs::file_status(fs::fifo_file);
1501 if (S_ISSOCK(path_stat.st_mode))
1502 return fs::file_status(fs::socket_file);
1503 return fs::file_status(fs::type_unknown);
1504
1505# else // Windows
1506
1507 DWORD attr(::GetFileAttributesW(p.c_str()));
1508 if (attr == 0xFFFFFFFF)
1509 {
1510 return process_status_failure(p, ec);
1511 }
1512
1513 if (ec != 0) ec->clear();
1514
1515 if (attr & FILE_ATTRIBUTE_REPARSE_POINT)
1516 return is_reparse_point_a_symlink(p)
1517 ? file_status(symlink_file)
1518 : file_status(reparse_file);
1519
1520 return (attr & FILE_ATTRIBUTE_DIRECTORY)
1521 ? file_status(directory_file)
1522 : file_status(regular_file);
1523
1524# endif
1525 }
1526
1527 // contributed by Jeff Flinn
1528 BOOST_FILESYSTEM_DECL
1529 path temp_directory_path(system::error_code* ec)
1530 {
1531# ifdef BOOST_POSIX_API
1532 const char* val = 0;
1533
1534 (val = std::getenv("TMPDIR" )) ||
1535 (val = std::getenv("TMP" )) ||
1536 (val = std::getenv("TEMP" )) ||
1537 (val = std::getenv("TEMPDIR"));
1538
1539 path p((val!=0) ? val : "/tmp");
1540
1541 if (p.empty() || (ec&&!is_directory(p, *ec))||(!ec&&!is_directory(p)))
1542 {
1543 errno = ENOTDIR;
1544 error(true, p, ec, "boost::filesystem::temp_directory_path");
1545 return p;
1546 }
1547
1548 return p;
1549
1550# else // Windows
1551
1552 std::vector<path::value_type> buf(GetTempPathW(0, NULL));
1553
1554 if (buf.empty() || GetTempPathW(buf.size(), &buf[0])==0)
1555 {
1556 if(!buf.empty()) ::SetLastError(ENOTDIR);
1557 error(true, ec, "boost::filesystem::temp_directory_path");
1558 return path();
1559 }
1560
1561 buf.pop_back();
1562
1563 path p(buf.begin(), buf.end());
1564
1565 if ((ec&&!is_directory(p, *ec))||(!ec&&!is_directory(p)))
1566 {
1567 ::SetLastError(ENOTDIR);
1568 error(true, p, ec, "boost::filesystem::temp_directory_path");
1569 return path();
1570 }
1571
1572 return p;
1573# endif
1574 }
1575
1576 BOOST_FILESYSTEM_DECL
1577 path system_complete(const path& p, system::error_code* ec)
1578 {
1579# ifdef BOOST_POSIX_API
1580 return (p.empty() || p.is_absolute())
1581 ? p : current_path()/ p;
1582
1583# else
1584 if (p.empty())
1585 {
1586 if (ec != 0) ec->clear();
1587 return p;
1588 }
1589 wchar_t buf[buf_size];
1590 wchar_t* pfn;
1591 std::size_t len = get_full_path_name(p, buf_size, buf, &pfn);
1592
1593 if (error(len == 0, p, ec, "boost::filesystem::system_complete"))
1594 return path();
1595
1596 if (len < buf_size)// len does not include null termination character
1597 return path(&buf[0]);
1598
1599 boost::scoped_array<wchar_t> big_buf(new wchar_t[len]);
1600
1601 return error(get_full_path_name(p, len , big_buf.get(), &pfn)== 0,
1602 p, ec, "boost::filesystem::system_complete")
1603 ? path()
1604 : path(big_buf.get());
1605# endif
1606 }
1607
1608} // namespace detail
1609
1610//--------------------------------------------------------------------------------------//
1611// //
1612// directory_entry //
1613// //
1614//--------------------------------------------------------------------------------------//
1615
1616 file_status
1617 directory_entry::m_get_status(system::error_code* ec) const
1618 {
1619 if (!status_known(m_status))
1620 {
1621 // optimization: if the symlink status is known, and it isn't a symlink,
1622 // then status and symlink_status are identical so just copy the
1623 // symlink status to the regular status.
1624 if (status_known(m_symlink_status)
1625 && !is_symlink(m_symlink_status))
1626 {
1627 m_status = m_symlink_status;
1628 if (ec != 0) ec->clear();
1629 }
1630 else m_status = detail::status(m_path, ec);
1631 }
1632 else if (ec != 0) ec->clear();
1633 return m_status;
1634 }
1635
1636 file_status
1637 directory_entry::m_get_symlink_status(system::error_code* ec) const
1638 {
1639 if (!status_known(m_symlink_status))
1640 m_symlink_status = detail::symlink_status(m_path, ec);
1641 else if (ec != 0) ec->clear();
1642 return m_symlink_status;
1643 }
1644
1645// dispatch directory_entry supplied here rather than in
1646// <boost/filesystem/path_traits.hpp>, thus avoiding header circularity.
1647// test cases are in operations_unit_test.cpp
1648
1649namespace path_traits
1650{
1651 void dispatch(const directory_entry & de,
1652# ifdef BOOST_WINDOWS_API
1653 std::wstring& to,
1654# else
1655 std::string& to,
1656# endif
1657 const codecvt_type &)
1658 {
1659 to = de.path().native();
1660 }
1661
1662} // namespace path_traits
1663} // namespace filesystem3
1664} // namespace boost
1665
1666//--------------------------------------------------------------------------------------//
1667// //
1668// directory_iterator //
1669// //
1670//--------------------------------------------------------------------------------------//
1671
1672namespace
1673{
1674# ifdef BOOST_POSIX_API
1675
1676 error_code path_max(std::size_t & result)
1677 // this code is based on Stevens and Rago, Advanced Programming in the
1678 // UNIX envirnment, 2nd Ed., ISBN 0-201-43307-9, page 49
1679 {
1680# ifdef PATH_MAX
1681 static std::size_t max = PATH_MAX;
1682# else
1683 static std::size_t max = 0;
1684# endif
1685 if (max == 0)
1686 {
1687 errno = 0;
1688 long tmp = ::pathconf("/", _PC_NAME_MAX);
1689 if (tmp < 0)
1690 {
1691 if (errno == 0)// indeterminate
1692 max = 4096; // guess
1693 else return error_code(errno, system_category());
1694 }
1695 else max = static_cast<std::size_t>(tmp + 1); // relative root
1696 }
1697 result = max;
1698 return ok;
1699 }
1700
1701 error_code dir_itr_first(void *& handle, void *& buffer,
1702 const char* dir, string& target,
1703 fs::file_status &, fs::file_status &)
1704 {
1705 if ((handle = ::opendir(dir))== 0)
1706 return error_code(errno, system_category());
1707 target = string("."); // string was static but caused trouble
1708 // when iteration called from dtor, after
1709 // static had already been destroyed
1710 std::size_t path_size (0); // initialization quiets gcc warning (ticket #3509)
1711 error_code ec = path_max(path_size);
1712 if (ec)return ec;
1713 dirent de;
1714 buffer = std::malloc((sizeof(dirent) - sizeof(de.d_name))
1715 + path_size + 1); // + 1 for "/0"
1716 return ok;
1717 }
1718
1719 // warning: the only dirent member updated is d_name
1720 inline int readdir_r_simulator(DIR * dirp, struct dirent * entry,
1721 struct dirent ** result)// *result set to 0 on end of directory
1722 {
1723 errno = 0;
1724
1725# if !defined(__CYGWIN__)\
1726 && defined(_POSIX_THREAD_SAFE_FUNCTIONS)\
1727 && defined(_SC_THREAD_SAFE_FUNCTIONS)\
1728 && (_POSIX_THREAD_SAFE_FUNCTIONS+0 >= 0)\
1729 && (!defined(__hpux) || defined(_REENTRANT)) \
1730 && (!defined(_AIX) || defined(__THREAD_SAFE))
1731 if (::sysconf(_SC_THREAD_SAFE_FUNCTIONS)>= 0)
1732 { return ::readdir_r(dirp, entry, result); }
1733# endif
1734
1735 struct dirent * p;
1736 *result = 0;
1737 if ((p = ::readdir(dirp))== 0)
1738 return errno;
1739 std::strcpy(entry->d_name, p->d_name);
1740 *result = entry;
1741 return 0;
1742 }
1743
1744 error_code dir_itr_increment(void *& handle, void *& buffer,
1745 string& target, fs::file_status & sf, fs::file_status & symlink_sf)
1746 {
1747 BOOST_ASSERT(buffer != 0);
1748 dirent * entry(static_cast<dirent *>(buffer));
1749 dirent * result;
1750 int return_code;
1751 if ((return_code = readdir_r_simulator(static_cast<DIR*>(handle),
1752 entry, &result))!= 0)return error_code(errno, system_category());
1753 if (result == 0)
1754 return fs::detail::dir_itr_close(handle, buffer);
1755 target = entry->d_name;
1756# ifdef BOOST_FILESYSTEM_STATUS_CACHE
1757 if (entry->d_type == DT_UNKNOWN) // filesystem does not supply d_type value
1758 {
1759 sf = symlink_sf = fs::file_status(fs::status_error);
1760 }
1761 else // filesystem supplies d_type value
1762 {
1763 if (entry->d_type == DT_DIR)
1764 sf = symlink_sf = fs::file_status(fs::directory_file);
1765 else if (entry->d_type == DT_REG)
1766 sf = symlink_sf = fs::file_status(fs::regular_file);
1767 else if (entry->d_type == DT_LNK)
1768 {
1769 sf = fs::file_status(fs::status_error);
1770 symlink_sf = fs::file_status(fs::symlink_file);
1771 }
1772 else sf = symlink_sf = fs::file_status(fs::status_error);
1773 }
1774# else
1775 sf = symlink_sf = fs::file_status(fs::status_error);
1776# endif
1777 return ok;
1778 }
1779
1780# else // BOOST_WINDOWS_API
1781
1782 error_code dir_itr_first(void *& handle, const fs::path& dir,
1783 wstring& target, fs::file_status & sf, fs::file_status & symlink_sf)
1784 // Note: an empty root directory has no "." or ".." entries, so this
1785 // causes a ERROR_FILE_NOT_FOUND error which we do not considered an
1786 // error. It is treated as eof instead.
1787 {
1788 // use a form of search Sebastian Martel reports will work with Win98
1789 wstring dirpath(dir.wstring());
1790 dirpath += (dirpath.empty()
1791 || (dirpath[dirpath.size()-1] != L'\\'
1792 && dirpath[dirpath.size()-1] != L'/'
1793 && dirpath[dirpath.size()-1] != L':'))? L"\\*" : L"*";
1794
1795 WIN32_FIND_DATAW data;
1796 if ((handle = ::FindFirstFileW(dirpath.c_str(), &data))
1797 == INVALID_HANDLE_VALUE)
1798 {
1799 handle = 0;
1800 return error_code( (::GetLastError() == ERROR_FILE_NOT_FOUND
1801 // Windows Mobile returns ERROR_NO_MORE_FILES; see ticket #3551
1802 || ::GetLastError() == ERROR_NO_MORE_FILES)
1803 ? 0 : ::GetLastError(), system_category() );
1804 }
1805 target = data.cFileName;
1806 if (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
1807 // reparse points are complex, so don't try to handle them here
1808 { sf.type(fs::status_error); symlink_sf.type(fs::status_error); }
1809 else if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1810 { sf.type(fs::directory_file); symlink_sf.type(fs::directory_file); }
1811 else
1812 { sf.type(fs::regular_file); symlink_sf.type(fs::regular_file); }
1813 return error_code();
1814 }
1815
1816 error_code dir_itr_increment(void *& handle, wstring& target,
1817 fs::file_status & sf, fs::file_status & symlink_sf)
1818 {
1819 WIN32_FIND_DATAW data;
1820 if (::FindNextFileW(handle, &data)== 0)// fails
1821 {
1822 int error = ::GetLastError();
1823 fs::detail::dir_itr_close(handle);
1824 return error_code(error == ERROR_NO_MORE_FILES ? 0 : error, system_category());
1825 }
1826 target = data.cFileName;
1827 if (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
1828 // reparse points are complex, so don't try to handle them here
1829 { sf.type(fs::status_error); symlink_sf.type(fs::status_error); }
1830 else if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1831 { sf.type(fs::directory_file); symlink_sf.type(fs::directory_file); }
1832 else
1833 { sf.type(fs::regular_file); symlink_sf.type(fs::regular_file); }
1834 return error_code();
1835 }
1836#endif
1837
1838 const error_code not_found_error_code (
1839# ifdef BOOST_WINDOWS_API
1840 ERROR_PATH_NOT_FOUND
1841# else
1842 ENOENT
1843# endif
1844 , system_category());
1845
1846} // unnamed namespace
1847
1848namespace boost
1849{
1850namespace filesystem3
1851{
1852
1853namespace detail
1854{
1855 // dir_itr_close is called both from the ~dir_itr_imp()destructor
1856 // and dir_itr_increment()
1857 BOOST_FILESYSTEM_DECL
1858 system::error_code dir_itr_close( // never throws
1859 void *& handle
1860# if defined(BOOST_POSIX_API)
1861 , void *& buffer
1862# endif
1863 )
1864 {
1865# ifdef BOOST_POSIX_API
1866 std::free(buffer);
1867 buffer = 0;
1868 if (handle == 0)return ok;
1869 DIR * h(static_cast<DIR*>(handle));
1870 handle = 0;
1871 return error_code(::closedir(h)== 0 ? 0 : errno, system_category());
1872
1873# else
1874 if (handle != 0)
1875 {
1876 ::FindClose(handle);
1877 handle = 0;
1878 }
1879 return ok;
1880
1881# endif
1882 }
1883
1884 void directory_iterator_construct(directory_iterator& it,
1885 const path& p, system::error_code* ec)
1886 {
1887 if (error(p.empty(), not_found_error_code, p, ec,
1888 "boost::filesystem::directory_iterator::construct"))return;
1889
1890 path::string_type filename;
1891 file_status file_stat, symlink_file_stat;
1892 error_code result = dir_itr_first(it.m_imp->handle,
1893# if defined(BOOST_POSIX_API)
1894 it.m_imp->buffer,
1895# endif
1896 p.c_str(), filename, file_stat, symlink_file_stat);
1897
1898 if (result)
1899 {
1900 it.m_imp.reset();
1901 error(true, result, p,
1902 ec, "boost::filesystem::directory_iterator::construct");
1903 return;
1904 }
1905
1906 if (it.m_imp->handle == 0)it.m_imp.reset(); // eof, so make end iterator
1907 else // not eof
1908 {
1909 it.m_imp->dir_entry.assign(p / filename,
1910 file_stat, symlink_file_stat);
1911 if (filename[0] == dot // dot or dot-dot
1912 && (filename.size()== 1
1913 || (filename[1] == dot
1914 && filename.size()== 2)))
1915 { it.increment(); }
1916 }
1917 }
1918
1919 void directory_iterator_increment(directory_iterator& it,
1920 system::error_code* ec)
1921 {
1922 BOOST_ASSERT(it.m_imp.get() && "attempt to increment end iterator");
1923 BOOST_ASSERT(it.m_imp->handle != 0 && "internal program error");
1924
1925 path::string_type filename;
1926 file_status file_stat, symlink_file_stat;
1927 system::error_code temp_ec;
1928
1929 for (;;)
1930 {
1931 temp_ec = dir_itr_increment(it.m_imp->handle,
1932# if defined(BOOST_POSIX_API)
1933 it.m_imp->buffer,
1934# endif
1935 filename, file_stat, symlink_file_stat);
1936
1937 if (temp_ec)
1938 {
1939 it.m_imp.reset();
1940 if (ec == 0)
1941 BOOST_FILESYSTEM_THROW(
1942 filesystem_error("boost::filesystem::directory_iterator::operator++",
1943 it.m_imp->dir_entry.path().parent_path(),
1944 error_code(BOOST_ERRNO, system_category())));
1945 ec->assign(BOOST_ERRNO, system_category());
1946 return;
1947 }
1948 else if (ec != 0) ec->clear();
1949
1950 if (it.m_imp->handle == 0) // eof, make end
1951 {
1952 it.m_imp.reset();
1953 return;
1954 }
1955
1956 if (!(filename[0] == dot // !(dot or dot-dot)
1957 && (filename.size()== 1
1958 || (filename[1] == dot
1959 && filename.size()== 2))))
1960 {
1961 it.m_imp->dir_entry.replace_filename(
1962 filename, file_stat, symlink_file_stat);
1963 return;
1964 }
1965 }
1966 }
1967} // namespace detail
1968} // namespace filesystem3
1969} // namespace boost
1970
1971#endif // no wide character support