operations.cpp 61 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996
  1. // operations.cpp --------------------------------------------------------------------//
  2. // Copyright 2002-2009, 2014 Beman Dawes
  3. // Copyright 2001 Dietmar Kuehl
  4. // Distributed under the Boost Software License, Version 1.0.
  5. // See http://www.boost.org/LICENSE_1_0.txt
  6. // See library home page at http://www.boost.org/libs/filesystem
  7. //--------------------------------------------------------------------------------------//
  8. // define 64-bit offset macros BEFORE including boost/config.hpp (see ticket #5355)
  9. #if defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ < 24
  10. // Android fully supports 64-bit file offsets only for API 24 and above.
  11. //
  12. // Trying to define _FILE_OFFSET_BITS=64 for APIs below 24
  13. // leads to compilation failure for one or another reason,
  14. // depending on target Android API level, Android NDK version,
  15. // used STL, order of include paths and more.
  16. // For more information, please see:
  17. // - https://github.com/boostorg/filesystem/issues/65
  18. // - https://github.com/boostorg/filesystem/pull/69
  19. //
  20. // Android NDK developers consider it the expected behavior.
  21. // See their official position here:
  22. // - https://github.com/android-ndk/ndk/issues/501#issuecomment-326447479
  23. // - https://android.googlesource.com/platform/bionic/+/a34817457feee026e8702a1d2dffe9e92b51d7d1/docs/32-bit-abi.md#32_bit-abi-bugs
  24. //
  25. // Thus we do not define _FILE_OFFSET_BITS in such case.
  26. #else
  27. // Defining _FILE_OFFSET_BITS=64 should kick in 64-bit off_t's
  28. // (and thus st_size) on 32-bit systems that provide the Large File
  29. // Support (LFS) interface, such as Linux, Solaris, and IRIX.
  30. //
  31. // At the time of this comment writing (March 2018), on most systems
  32. // _FILE_OFFSET_BITS=64 definition is harmless:
  33. // either the definition is supported and enables 64-bit off_t,
  34. // or the definition is not supported and is ignored, in which case
  35. // off_t does not change its default size for the target system
  36. // (which may be 32-bit or 64-bit already).
  37. // Thus it makes sense to have _FILE_OFFSET_BITS=64 defined by default,
  38. // instead of listing every system that supports the definition.
  39. // Those few systems, on which _FILE_OFFSET_BITS=64 is harmful,
  40. // for example this definition causes compilation failure on those systems,
  41. // should be exempt from defining _FILE_OFFSET_BITS by adding
  42. // an appropriate #elif block above with the appropriate comment.
  43. //
  44. // _FILE_OFFSET_BITS must be defined before any headers are included
  45. // to ensure that the definition is available to all included headers.
  46. // That is required at least on Solaris, and possibly on other
  47. // systems as well.
  48. #define _FILE_OFFSET_BITS 64
  49. #endif
  50. #ifndef BOOST_SYSTEM_NO_DEPRECATED
  51. # define BOOST_SYSTEM_NO_DEPRECATED
  52. #endif
  53. #ifndef _POSIX_PTHREAD_SEMANTICS
  54. # define _POSIX_PTHREAD_SEMANTICS // Sun readdir_r() needs this
  55. #endif
  56. // Include Boost.Predef first so that windows.h is guaranteed to be not included
  57. #include <boost/predef/os/windows.h>
  58. #if BOOST_OS_WINDOWS
  59. #include <boost/winapi/config.hpp>
  60. #endif
  61. #include <boost/filesystem/config.hpp>
  62. #include <boost/filesystem/operations.hpp>
  63. #include <boost/filesystem/file_status.hpp>
  64. #include <boost/filesystem/exception.hpp>
  65. #include <boost/filesystem/directory.hpp>
  66. #include <boost/system/error_code.hpp>
  67. #include <boost/smart_ptr/scoped_array.hpp>
  68. #include <boost/detail/workaround.hpp>
  69. #include <boost/cstdint.hpp>
  70. #include <boost/assert.hpp>
  71. #include <new> // std::bad_alloc
  72. #include <limits>
  73. #include <string>
  74. #include <cstddef>
  75. #include <cstdlib> // for malloc, free
  76. #include <cstring>
  77. #include <cstdio> // for remove, rename
  78. #if defined(__QNXNTO__) // see ticket #5355
  79. # include <stdio.h>
  80. #endif
  81. #include <cerrno>
  82. #ifdef BOOST_FILEYSTEM_INCLUDE_IOSTREAM
  83. # include <iostream>
  84. #endif
  85. # ifdef BOOST_POSIX_API
  86. # include <sys/types.h>
  87. # include <sys/stat.h>
  88. # if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__ANDROID__) \
  89. && !defined(__VXWORKS__)
  90. # include <sys/statvfs.h>
  91. # define BOOST_STATVFS statvfs
  92. # define BOOST_STATVFS_F_FRSIZE vfs.f_frsize
  93. # else
  94. # ifdef __OpenBSD__
  95. # include <sys/param.h>
  96. # elif defined(__ANDROID__)
  97. # include <sys/vfs.h>
  98. # endif
  99. # if !defined(__VXWORKS__)
  100. # include <sys/mount.h>
  101. # endif
  102. # define BOOST_STATVFS statfs
  103. # define BOOST_STATVFS_F_FRSIZE static_cast<boost::uintmax_t>(vfs.f_bsize)
  104. # endif
  105. # include <unistd.h>
  106. # include <fcntl.h>
  107. # if _POSIX_C_SOURCE < 200809L
  108. # include <utime.h>
  109. # endif
  110. # include "limits.h"
  111. # else // BOOST_WINDOWS_API
  112. # include <boost/winapi/dll.hpp> // get_proc_address, GetModuleHandleW
  113. # include <cwchar>
  114. # include <io.h>
  115. # include <windows.h>
  116. # include <winnt.h>
  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
  125. #include "windows_tools.hpp"
  126. # endif // BOOST_WINDOWS_API
  127. #include "error_handling.hpp"
  128. namespace fs = boost::filesystem;
  129. using boost::filesystem::path;
  130. using boost::filesystem::filesystem_error;
  131. using boost::filesystem::perms;
  132. using boost::system::error_code;
  133. using boost::system::system_category;
  134. # if defined(BOOST_WINDOWS_API)
  135. // REPARSE_DATA_BUFFER related definitions are found in ntifs.h, which is part of the
  136. // Windows Device Driver Kit. Since that's inconvenient, the definitions are provided
  137. // here. See http://msdn.microsoft.com/en-us/library/ms791514.aspx
  138. #if !defined(REPARSE_DATA_BUFFER_HEADER_SIZE) // mingw winnt.h does provide the defs
  139. #define SYMLINK_FLAG_RELATIVE 1
  140. typedef struct _REPARSE_DATA_BUFFER {
  141. ULONG ReparseTag;
  142. USHORT ReparseDataLength;
  143. USHORT Reserved;
  144. union {
  145. struct {
  146. USHORT SubstituteNameOffset;
  147. USHORT SubstituteNameLength;
  148. USHORT PrintNameOffset;
  149. USHORT PrintNameLength;
  150. ULONG Flags;
  151. WCHAR PathBuffer[1];
  152. /* Example of distinction between substitute and print names:
  153. mklink /d ldrive c:\
  154. SubstituteName: c:\\??\
  155. PrintName: c:\
  156. */
  157. } SymbolicLinkReparseBuffer;
  158. struct {
  159. USHORT SubstituteNameOffset;
  160. USHORT SubstituteNameLength;
  161. USHORT PrintNameOffset;
  162. USHORT PrintNameLength;
  163. WCHAR PathBuffer[1];
  164. } MountPointReparseBuffer;
  165. struct {
  166. UCHAR DataBuffer[1];
  167. } GenericReparseBuffer;
  168. };
  169. } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
  170. #define REPARSE_DATA_BUFFER_HEADER_SIZE \
  171. FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer)
  172. #endif
  173. #ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE
  174. #define MAXIMUM_REPARSE_DATA_BUFFER_SIZE ( 16 * 1024 )
  175. #endif
  176. # ifndef FSCTL_GET_REPARSE_POINT
  177. # define FSCTL_GET_REPARSE_POINT 0x900a8
  178. # endif
  179. # ifndef IO_REPARSE_TAG_SYMLINK
  180. # define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
  181. # endif
  182. # endif // BOOST_WINDOWS_API
  183. // POSIX/Windows macros ----------------------------------------------------//
  184. // Portions of the POSIX and Windows API's are very similar, except for name,
  185. // order of arguments, and meaning of zero/non-zero returns. The macros below
  186. // abstract away those differences. They follow Windows naming and order of
  187. // arguments, and return true to indicate no error occurred. [POSIX naming,
  188. // order of arguments, and meaning of return were followed initially, but
  189. // found to be less clear and cause more coding errors.]
  190. # if defined(BOOST_POSIX_API)
  191. # define BOOST_SET_CURRENT_DIRECTORY(P)(::chdir(P)== 0)
  192. # define BOOST_CREATE_DIRECTORY(P)(::mkdir(P, S_IRWXU|S_IRWXG|S_IRWXO)== 0)
  193. # define BOOST_CREATE_HARD_LINK(F,T)(::link(T, F)== 0)
  194. # define BOOST_CREATE_SYMBOLIC_LINK(F,T,Flag)(::symlink(T, F)== 0)
  195. # define BOOST_REMOVE_DIRECTORY(P)(::rmdir(P)== 0)
  196. # define BOOST_DELETE_FILE(P)(::unlink(P)== 0)
  197. # define BOOST_COPY_DIRECTORY(F,T)(!(::stat(from.c_str(), &from_stat)!= 0\
  198. || ::mkdir(to.c_str(),from_stat.st_mode)!= 0))
  199. # define BOOST_COPY_FILE(F,T,FailIfExistsBool)copy_file_api(F, T, FailIfExistsBool)
  200. # define BOOST_MOVE_FILE(OLD,NEW)(::rename(OLD, NEW)== 0)
  201. # define BOOST_RESIZE_FILE(P,SZ)(::truncate(P, SZ)== 0)
  202. # else // BOOST_WINDOWS_API
  203. # define BOOST_SET_CURRENT_DIRECTORY(P)(::SetCurrentDirectoryW(P)!= 0)
  204. # define BOOST_CREATE_DIRECTORY(P)(::CreateDirectoryW(P, 0)!= 0)
  205. # define BOOST_CREATE_HARD_LINK(F,T)(create_hard_link_api(F, T, 0)!= 0)
  206. # define BOOST_CREATE_SYMBOLIC_LINK(F,T,Flag)(create_symbolic_link_api(F, T, Flag)!= 0)
  207. # define BOOST_REMOVE_DIRECTORY(P)(::RemoveDirectoryW(P)!= 0)
  208. # define BOOST_DELETE_FILE(P)(::DeleteFileW(P)!= 0)
  209. # define BOOST_COPY_DIRECTORY(F,T)(::CreateDirectoryExW(F, T, 0)!= 0)
  210. # define BOOST_COPY_FILE(F,T,FailIfExistsBool)(::CopyFileW(F, T, FailIfExistsBool)!= 0)
  211. # define BOOST_MOVE_FILE(OLD,NEW)(::MoveFileExW(OLD, NEW, MOVEFILE_REPLACE_EXISTING|MOVEFILE_COPY_ALLOWED)!= 0)
  212. # define BOOST_RESIZE_FILE(P,SZ)(resize_file_api(P, SZ)!= 0)
  213. # define BOOST_READ_SYMLINK(P,T)
  214. # endif
  215. namespace boost {
  216. namespace filesystem {
  217. namespace detail {
  218. //--------------------------------------------------------------------------------------//
  219. // //
  220. // helpers (all operating systems) //
  221. // //
  222. //--------------------------------------------------------------------------------------//
  223. namespace {
  224. // Absolute maximum path length, in bytes, that we're willing to accept from various system calls.
  225. // This value is arbitrary, it is supposed to be a hard limit to avoid memory exhaustion
  226. // in some of the algorithms below in case of some corrupted or maliciously broken filesystem.
  227. BOOST_CONSTEXPR_OR_CONST std::size_t absolute_path_max = 16u * 1024u * 1024u;
  228. fs::file_type query_file_type(const path& p, error_code* ec);
  229. // general helpers -----------------------------------------------------------------//
  230. bool is_empty_directory(const path& p, error_code* ec)
  231. {
  232. return (ec != 0 ? fs::directory_iterator(p, *ec) : fs::directory_iterator(p))
  233. == fs::directory_iterator();
  234. }
  235. bool not_found_error(int errval) BOOST_NOEXCEPT; // forward declaration
  236. // only called if directory exists
  237. bool remove_directory(const path& p) // true if succeeds or not found
  238. {
  239. return BOOST_REMOVE_DIRECTORY(p.c_str())
  240. || not_found_error(BOOST_ERRNO); // mitigate possible file system race. See #11166
  241. }
  242. // only called if file exists
  243. bool remove_file(const path& p) // true if succeeds or not found
  244. {
  245. return BOOST_DELETE_FILE(p.c_str())
  246. || not_found_error(BOOST_ERRNO); // mitigate possible file system race. See #11166
  247. }
  248. // called by remove and remove_all_aux
  249. bool remove_file_or_directory(const path& p, fs::file_type type, error_code* ec)
  250. // return true if file removed, false if not removed
  251. {
  252. if (type == fs::file_not_found)
  253. {
  254. if (ec != 0) ec->clear();
  255. return false;
  256. }
  257. if (type == fs::directory_file
  258. # ifdef BOOST_WINDOWS_API
  259. || type == fs::_detail_directory_symlink
  260. # endif
  261. )
  262. {
  263. if (error(!remove_directory(p) ? BOOST_ERRNO : 0, p, ec,
  264. "boost::filesystem::remove"))
  265. return false;
  266. }
  267. else
  268. {
  269. if (error(!remove_file(p) ? BOOST_ERRNO : 0, p, ec,
  270. "boost::filesystem::remove"))
  271. return false;
  272. }
  273. return true;
  274. }
  275. boost::uintmax_t remove_all_aux(const path& p, fs::file_type type,
  276. error_code* ec)
  277. {
  278. boost::uintmax_t count = 0;
  279. if (type == fs::directory_file) // but not a directory symlink
  280. {
  281. fs::directory_iterator itr;
  282. if (ec != 0)
  283. {
  284. itr = fs::directory_iterator(p, *ec);
  285. if (*ec)
  286. return count;
  287. }
  288. else
  289. itr = fs::directory_iterator(p);
  290. const fs::directory_iterator end_dit;
  291. while(itr != end_dit)
  292. {
  293. fs::file_type tmp_type = query_file_type(itr->path(), ec);
  294. if (ec != 0 && *ec)
  295. return count;
  296. count += remove_all_aux(itr->path(), tmp_type, ec);
  297. if (ec != 0 && *ec)
  298. return count;
  299. fs::detail::directory_iterator_increment(itr, ec);
  300. if (ec != 0 && *ec)
  301. return count;
  302. }
  303. }
  304. remove_file_or_directory(p, type, ec);
  305. if (ec != 0 && *ec)
  306. return count;
  307. return ++count;
  308. }
  309. #ifdef BOOST_POSIX_API
  310. //--------------------------------------------------------------------------------------//
  311. // //
  312. // POSIX-specific helpers //
  313. // //
  314. //--------------------------------------------------------------------------------------//
  315. BOOST_CONSTEXPR_OR_CONST char dot = '.';
  316. inline bool not_found_error(int errval) BOOST_NOEXCEPT
  317. {
  318. return errval == ENOENT || errval == ENOTDIR;
  319. }
  320. bool // true if ok
  321. copy_file_api(const std::string& from_p,
  322. const std::string& to_p, bool fail_if_exists)
  323. {
  324. BOOST_CONSTEXPR_OR_CONST std::size_t buf_sz = 65536;
  325. boost::scoped_array<char> buf(new char [buf_sz]);
  326. int infile=-1, outfile=-1; // -1 means not open
  327. // bug fixed: code previously did a stat()on the from_file first, but that
  328. // introduced a gratuitous race condition; the stat()is now done after the open()
  329. if ((infile = ::open(from_p.c_str(), O_RDONLY))< 0)
  330. { return false; }
  331. struct stat from_stat;
  332. if (::stat(from_p.c_str(), &from_stat)!= 0)
  333. {
  334. ::close(infile);
  335. return false;
  336. }
  337. int oflag = O_CREAT | O_WRONLY | O_TRUNC;
  338. if (fail_if_exists)
  339. oflag |= O_EXCL;
  340. if ((outfile = ::open(to_p.c_str(), oflag, from_stat.st_mode)) < 0)
  341. {
  342. const int open_errno = errno;
  343. BOOST_ASSERT(infile >= 0);
  344. ::close(infile);
  345. errno = open_errno;
  346. return false;
  347. }
  348. ssize_t sz, sz_read=1, sz_write;
  349. while (sz_read > 0
  350. && (sz_read = ::read(infile, buf.get(), buf_sz)) > 0)
  351. {
  352. // Allow for partial writes - see Advanced Unix Programming (2nd Ed.),
  353. // Marc Rochkind, Addison-Wesley, 2004, page 94
  354. sz_write = 0;
  355. do
  356. {
  357. BOOST_ASSERT(sz_read - sz_write > 0); // #1
  358. // ticket 4438 claimed possible infinite loop if write returns 0. My analysis
  359. // is that POSIX specifies 0 return only if 3rd arg is 0, and that will never
  360. // happen due to loop entry and coninuation conditions. BOOST_ASSERT #1 above
  361. // and #2 below added to verify that analysis.
  362. if ((sz = ::write(outfile, buf.get() + sz_write,
  363. sz_read - sz_write)) < 0)
  364. {
  365. sz_read = sz; // cause read loop termination
  366. break; // and error reported after closes
  367. }
  368. BOOST_ASSERT(sz > 0); // #2
  369. sz_write += sz;
  370. } while (sz_write < sz_read);
  371. }
  372. if (::close(infile)< 0)
  373. sz_read = -1;
  374. if (::close(outfile)< 0)
  375. sz_read = -1;
  376. return sz_read >= 0;
  377. }
  378. inline fs::file_type query_file_type(const path& p, error_code* ec)
  379. {
  380. return fs::detail::symlink_status(p, ec).type();
  381. }
  382. # else
  383. //--------------------------------------------------------------------------------------//
  384. // //
  385. // Windows-specific helpers //
  386. // //
  387. //--------------------------------------------------------------------------------------//
  388. BOOST_CONSTEXPR_OR_CONST std::size_t buf_size = 128;
  389. BOOST_CONSTEXPR_OR_CONST wchar_t dot = L'.';
  390. inline std::wstring wgetenv(const wchar_t* name)
  391. {
  392. // use a separate buffer since C++03 basic_string is not required to be contiguous
  393. const DWORD size = ::GetEnvironmentVariableW(name, NULL, 0);
  394. if (size > 0)
  395. {
  396. boost::scoped_array<wchar_t> buf(new wchar_t[size]);
  397. if (BOOST_LIKELY(::GetEnvironmentVariableW(name, buf.get(), size) > 0))
  398. return std::wstring(buf.get());
  399. }
  400. return std::wstring();
  401. }
  402. inline bool not_found_error(int errval) BOOST_NOEXCEPT
  403. {
  404. return errval == ERROR_FILE_NOT_FOUND
  405. || errval == ERROR_PATH_NOT_FOUND
  406. || errval == ERROR_INVALID_NAME // "tools/jam/src/:sys:stat.h", "//foo"
  407. || errval == ERROR_INVALID_DRIVE // USB card reader with no card inserted
  408. || errval == ERROR_NOT_READY // CD/DVD drive with no disc inserted
  409. || errval == ERROR_INVALID_PARAMETER // ":sys:stat.h"
  410. || errval == ERROR_BAD_PATHNAME // "//nosuch" on Win64
  411. || errval == ERROR_BAD_NETPATH; // "//nosuch" on Win32
  412. }
  413. // these constants come from inspecting some Microsoft sample code
  414. std::time_t to_time_t(const FILETIME & ft)
  415. {
  416. __int64 t = (static_cast<__int64>(ft.dwHighDateTime)<< 32)
  417. + ft.dwLowDateTime;
  418. # if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 // > VC++ 7.0
  419. t -= 116444736000000000LL;
  420. # else
  421. t -= 116444736000000000;
  422. # endif
  423. t /= 10000000;
  424. return static_cast<std::time_t>(t);
  425. }
  426. void to_FILETIME(std::time_t t, FILETIME & ft)
  427. {
  428. __int64 temp = t;
  429. temp *= 10000000;
  430. # if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 // > VC++ 7.0
  431. temp += 116444736000000000LL;
  432. # else
  433. temp += 116444736000000000;
  434. # endif
  435. ft.dwLowDateTime = static_cast<DWORD>(temp);
  436. ft.dwHighDateTime = static_cast<DWORD>(temp >> 32);
  437. }
  438. // Thanks to Jeremy Maitin-Shepard for much help and for permission to
  439. // base the equivalent()implementation on portions of his
  440. // file-equivalence-win32.cpp experimental code.
  441. struct handle_wrapper
  442. {
  443. HANDLE handle;
  444. handle_wrapper(HANDLE h)
  445. : handle(h){}
  446. ~handle_wrapper()
  447. {
  448. if (handle != INVALID_HANDLE_VALUE)
  449. ::CloseHandle(handle);
  450. }
  451. };
  452. HANDLE create_file_handle(const path& p, DWORD dwDesiredAccess,
  453. DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  454. DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,
  455. HANDLE hTemplateFile)
  456. {
  457. return ::CreateFileW(p.c_str(), dwDesiredAccess, dwShareMode,
  458. lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes,
  459. hTemplateFile);
  460. }
  461. bool is_reparse_point_a_symlink(const path& p)
  462. {
  463. handle_wrapper h(create_file_handle(p, FILE_READ_EA,
  464. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING,
  465. FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL));
  466. if (h.handle == INVALID_HANDLE_VALUE)
  467. return false;
  468. boost::scoped_array<char> buf(new char [MAXIMUM_REPARSE_DATA_BUFFER_SIZE]);
  469. // Query the reparse data
  470. DWORD dwRetLen;
  471. BOOL result = ::DeviceIoControl(h.handle, FSCTL_GET_REPARSE_POINT, NULL, 0, buf.get(),
  472. MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &dwRetLen, NULL);
  473. if (!result) return false;
  474. return reinterpret_cast<const REPARSE_DATA_BUFFER*>(buf.get())->ReparseTag
  475. == IO_REPARSE_TAG_SYMLINK
  476. // Issue 9016 asked that NTFS directory junctions be recognized as directories.
  477. // That is equivalent to recognizing them as symlinks, and then the normal symlink
  478. // mechanism will take care of recognizing them as directories.
  479. //
  480. // Directory junctions are very similar to symlinks, but have some performance
  481. // and other advantages over symlinks. They can be created from the command line
  482. // with "mklink /j junction-name target-path".
  483. || reinterpret_cast<const REPARSE_DATA_BUFFER*>(buf.get())->ReparseTag
  484. == IO_REPARSE_TAG_MOUNT_POINT; // aka "directory junction" or "junction"
  485. }
  486. inline std::size_t get_full_path_name(
  487. const path& src, std::size_t len, wchar_t* buf, wchar_t** p)
  488. {
  489. return static_cast<std::size_t>(
  490. ::GetFullPathNameW(src.c_str(), static_cast<DWORD>(len), buf, p));
  491. }
  492. fs::file_status process_status_failure(const path& p, error_code* ec)
  493. {
  494. int errval(::GetLastError());
  495. if (ec != 0) // always report errval, even though some
  496. ec->assign(errval, system_category()); // errval values are not status_errors
  497. if (not_found_error(errval))
  498. {
  499. return fs::file_status(fs::file_not_found, fs::no_perms);
  500. }
  501. else if (errval == ERROR_SHARING_VIOLATION)
  502. {
  503. return fs::file_status(fs::type_unknown);
  504. }
  505. if (ec == 0)
  506. BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status",
  507. p, error_code(errval, system_category())));
  508. return fs::file_status(fs::status_error);
  509. }
  510. // differs from symlink_status() in that directory symlinks are reported as
  511. // _detail_directory_symlink, as required on Windows by remove() and its helpers.
  512. fs::file_type query_file_type(const path& p, error_code* ec)
  513. {
  514. DWORD attr(::GetFileAttributesW(p.c_str()));
  515. if (attr == 0xFFFFFFFF)
  516. {
  517. return process_status_failure(p, ec).type();
  518. }
  519. if (ec != 0) ec->clear();
  520. if (attr & FILE_ATTRIBUTE_REPARSE_POINT)
  521. {
  522. if (is_reparse_point_a_symlink(p))
  523. return (attr & FILE_ATTRIBUTE_DIRECTORY)
  524. ? fs::_detail_directory_symlink
  525. : fs::symlink_file;
  526. return fs::reparse_file;
  527. }
  528. return (attr & FILE_ATTRIBUTE_DIRECTORY)
  529. ? fs::directory_file
  530. : fs::regular_file;
  531. }
  532. BOOL resize_file_api(const wchar_t* p, boost::uintmax_t size)
  533. {
  534. handle_wrapper h(CreateFileW(p, GENERIC_WRITE, 0, 0, OPEN_EXISTING,
  535. FILE_ATTRIBUTE_NORMAL, 0));
  536. LARGE_INTEGER sz;
  537. sz.QuadPart = size;
  538. return h.handle != INVALID_HANDLE_VALUE
  539. && ::SetFilePointerEx(h.handle, sz, 0, FILE_BEGIN)
  540. && ::SetEndOfFile(h.handle);
  541. }
  542. // Windows kernel32.dll functions that may or may not be present
  543. // must be accessed through pointers
  544. typedef BOOL (WINAPI *PtrCreateHardLinkW)(
  545. /*__in*/ LPCWSTR lpFileName,
  546. /*__in*/ LPCWSTR lpExistingFileName,
  547. /*__reserved*/ LPSECURITY_ATTRIBUTES lpSecurityAttributes
  548. );
  549. PtrCreateHardLinkW create_hard_link_api = PtrCreateHardLinkW(
  550. boost::winapi::get_proc_address(
  551. boost::winapi::GetModuleHandleW(L"kernel32.dll"), "CreateHardLinkW"));
  552. typedef BOOLEAN (WINAPI *PtrCreateSymbolicLinkW)(
  553. /*__in*/ LPCWSTR lpSymlinkFileName,
  554. /*__in*/ LPCWSTR lpTargetFileName,
  555. /*__in*/ DWORD dwFlags
  556. );
  557. PtrCreateSymbolicLinkW create_symbolic_link_api = PtrCreateSymbolicLinkW(
  558. boost::winapi::get_proc_address(
  559. boost::winapi::GetModuleHandleW(L"kernel32.dll"), "CreateSymbolicLinkW"));
  560. #endif
  561. //#ifdef BOOST_WINDOWS_API
  562. //
  563. //
  564. // inline bool get_free_disk_space(const std::wstring& ph,
  565. // PULARGE_INTEGER avail, PULARGE_INTEGER total, PULARGE_INTEGER free)
  566. // { return ::GetDiskFreeSpaceExW(ph.c_str(), avail, total, free)!= 0; }
  567. //
  568. //#endif
  569. } // unnamed namespace
  570. } // namespace detail
  571. //--------------------------------------------------------------------------------------//
  572. // //
  573. // operations functions declared in operations.hpp //
  574. // in alphabetic order //
  575. // //
  576. //--------------------------------------------------------------------------------------//
  577. BOOST_FILESYSTEM_DECL
  578. path absolute(const path& p, const path& base)
  579. {
  580. // if ( p.empty() || p.is_absolute() )
  581. // return p;
  582. // // recursively calling absolute is sub-optimal, but is simple
  583. // path abs_base(base.is_absolute() ? base : absolute(base));
  584. //# ifdef BOOST_WINDOWS_API
  585. // if (p.has_root_directory())
  586. // return abs_base.root_name() / p;
  587. // // !p.has_root_directory
  588. // if (p.has_root_name())
  589. // return p.root_name()
  590. // / abs_base.root_directory() / abs_base.relative_path() / p.relative_path();
  591. // // !p.has_root_name()
  592. //# endif
  593. // return abs_base / p;
  594. // recursively calling absolute is sub-optimal, but is sure and simple
  595. path abs_base(base.is_absolute() ? base : absolute(base));
  596. // store expensive to compute values that are needed multiple times
  597. path p_root_name (p.root_name());
  598. path base_root_name (abs_base.root_name());
  599. path p_root_directory (p.root_directory());
  600. if (p.empty())
  601. return abs_base;
  602. if (!p_root_name.empty()) // p.has_root_name()
  603. {
  604. if (p_root_directory.empty()) // !p.has_root_directory()
  605. return p_root_name / abs_base.root_directory()
  606. / abs_base.relative_path() / p.relative_path();
  607. // p is absolute, so fall through to return p at end of block
  608. }
  609. else if (!p_root_directory.empty()) // p.has_root_directory()
  610. {
  611. # ifdef BOOST_POSIX_API
  612. // POSIX can have root name it it is a network path
  613. if (base_root_name.empty()) // !abs_base.has_root_name()
  614. return p;
  615. # endif
  616. return base_root_name / p;
  617. }
  618. else
  619. {
  620. return abs_base / p;
  621. }
  622. return p; // p.is_absolute() is true
  623. }
  624. namespace detail {
  625. BOOST_FILESYSTEM_DECL bool possible_large_file_size_support()
  626. {
  627. # ifdef BOOST_POSIX_API
  628. typedef struct stat struct_stat;
  629. return sizeof(struct_stat().st_size) > 4;
  630. # else
  631. return true;
  632. # endif
  633. }
  634. BOOST_FILESYSTEM_DECL
  635. path canonical(const path& p, const path& base, system::error_code* ec)
  636. {
  637. path source (p.is_absolute() ? p : absolute(p, base));
  638. path root(source.root_path());
  639. path result;
  640. system::error_code local_ec;
  641. file_status stat (status(source, local_ec));
  642. if (stat.type() == fs::file_not_found)
  643. {
  644. if (ec == 0)
  645. BOOST_FILESYSTEM_THROW(filesystem_error(
  646. "boost::filesystem::canonical", source,
  647. error_code(system::errc::no_such_file_or_directory, system::generic_category())));
  648. ec->assign(system::errc::no_such_file_or_directory, system::generic_category());
  649. return result;
  650. }
  651. else if (local_ec)
  652. {
  653. if (ec == 0)
  654. BOOST_FILESYSTEM_THROW(filesystem_error(
  655. "boost::filesystem::canonical", source, local_ec));
  656. *ec = local_ec;
  657. return result;
  658. }
  659. bool scan = true;
  660. while (scan)
  661. {
  662. scan = false;
  663. result.clear();
  664. for (path::iterator itr = source.begin(); itr != source.end(); ++itr)
  665. {
  666. if (*itr == dot_path())
  667. continue;
  668. if (*itr == dot_dot_path())
  669. {
  670. if (result != root)
  671. result.remove_filename();
  672. continue;
  673. }
  674. result /= *itr;
  675. bool is_sym (is_symlink(detail::symlink_status(result, ec)));
  676. if (ec && *ec)
  677. return path();
  678. if (is_sym)
  679. {
  680. path link(detail::read_symlink(result, ec));
  681. if (ec && *ec)
  682. return path();
  683. result.remove_filename();
  684. if (link.is_absolute())
  685. {
  686. for (++itr; itr != source.end(); ++itr)
  687. link /= *itr;
  688. source = link;
  689. }
  690. else // link is relative
  691. {
  692. path new_source(result);
  693. new_source /= link;
  694. for (++itr; itr != source.end(); ++itr)
  695. new_source /= *itr;
  696. source = new_source;
  697. }
  698. scan = true; // symlink causes scan to be restarted
  699. break;
  700. }
  701. }
  702. }
  703. if (ec != 0)
  704. ec->clear();
  705. BOOST_ASSERT_MSG(result.is_absolute(), "canonical() implementation error; please report");
  706. return result;
  707. }
  708. BOOST_FILESYSTEM_DECL
  709. void copy(const path& from, const path& to, system::error_code* ec)
  710. {
  711. file_status s(detail::symlink_status(from, ec));
  712. if (ec != 0 && *ec) return;
  713. if(is_symlink(s))
  714. {
  715. detail::copy_symlink(from, to, ec);
  716. }
  717. else if(is_directory(s))
  718. {
  719. detail::copy_directory(from, to, ec);
  720. }
  721. else if(is_regular_file(s))
  722. {
  723. detail::copy_file(from, to, detail::fail_if_exists, ec);
  724. }
  725. else
  726. {
  727. if (ec == 0)
  728. BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::copy",
  729. from, to, error_code(BOOST_ERROR_NOT_SUPPORTED, system_category())));
  730. ec->assign(BOOST_ERROR_NOT_SUPPORTED, system_category());
  731. }
  732. }
  733. BOOST_FILESYSTEM_DECL
  734. void copy_directory(const path& from, const path& to, system::error_code* ec)
  735. {
  736. # ifdef BOOST_POSIX_API
  737. struct stat from_stat;
  738. # endif
  739. error(!BOOST_COPY_DIRECTORY(from.c_str(), to.c_str()) ? BOOST_ERRNO : 0,
  740. from, to, ec, "boost::filesystem::copy_directory");
  741. }
  742. BOOST_FILESYSTEM_DECL
  743. void copy_file(const path& from, const path& to, copy_option option, error_code* ec)
  744. {
  745. error(!BOOST_COPY_FILE(from.c_str(), to.c_str(),
  746. option == fail_if_exists) ? BOOST_ERRNO : 0,
  747. from, to, ec, "boost::filesystem::copy_file");
  748. }
  749. BOOST_FILESYSTEM_DECL
  750. void copy_symlink(const path& existing_symlink, const path& new_symlink,
  751. system::error_code* ec)
  752. {
  753. # if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0600
  754. error(BOOST_ERROR_NOT_SUPPORTED, new_symlink, existing_symlink, ec,
  755. "boost::filesystem::copy_symlink");
  756. # else // modern Windows or BOOST_POSIX_API
  757. path p(read_symlink(existing_symlink, ec));
  758. if (ec != 0 && *ec) return;
  759. create_symlink(p, new_symlink, ec);
  760. # endif
  761. }
  762. BOOST_FILESYSTEM_DECL
  763. bool create_directories(const path& p, system::error_code* ec)
  764. {
  765. if (p.empty())
  766. {
  767. if (ec == 0)
  768. BOOST_FILESYSTEM_THROW(filesystem_error(
  769. "boost::filesystem::create_directories", p,
  770. system::errc::make_error_code(system::errc::invalid_argument)));
  771. else
  772. ec->assign(system::errc::invalid_argument, system::generic_category());
  773. return false;
  774. }
  775. if (p.filename_is_dot() || p.filename_is_dot_dot())
  776. return create_directories(p.parent_path(), ec);
  777. error_code local_ec;
  778. file_status p_status = status(p, local_ec);
  779. if (p_status.type() == directory_file)
  780. {
  781. if (ec != 0)
  782. ec->clear();
  783. return false;
  784. }
  785. path parent = p.parent_path();
  786. BOOST_ASSERT_MSG(parent != p, "internal error: p == p.parent_path()");
  787. if (!parent.empty())
  788. {
  789. // determine if the parent exists
  790. file_status parent_status = status(parent, local_ec);
  791. // if the parent does not exist, create the parent
  792. if (parent_status.type() == file_not_found)
  793. {
  794. create_directories(parent, local_ec);
  795. if (local_ec)
  796. {
  797. if (ec == 0)
  798. BOOST_FILESYSTEM_THROW(filesystem_error(
  799. "boost::filesystem::create_directories", parent, local_ec));
  800. else
  801. *ec = local_ec;
  802. return false;
  803. }
  804. }
  805. }
  806. // create the directory
  807. return create_directory(p, ec);
  808. }
  809. BOOST_FILESYSTEM_DECL
  810. bool create_directory(const path& p, error_code* ec)
  811. {
  812. if (BOOST_CREATE_DIRECTORY(p.c_str()))
  813. {
  814. if (ec != 0)
  815. ec->clear();
  816. return true;
  817. }
  818. // attempt to create directory failed
  819. int errval(BOOST_ERRNO); // save reason for failure
  820. error_code dummy;
  821. if (is_directory(p, dummy))
  822. {
  823. if (ec != 0)
  824. ec->clear();
  825. return false;
  826. }
  827. // attempt to create directory failed && it doesn't already exist
  828. if (ec == 0)
  829. BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::create_directory",
  830. p, error_code(errval, system_category())));
  831. else
  832. ec->assign(errval, system_category());
  833. return false;
  834. }
  835. BOOST_FILESYSTEM_DECL
  836. void create_directory_symlink(const path& to, const path& from,
  837. system::error_code* ec)
  838. {
  839. # if defined(BOOST_WINDOWS_API) && _WIN32_WINNT < 0x0600 // SDK earlier than Vista and Server 2008
  840. error(BOOST_ERROR_NOT_SUPPORTED, to, from, ec,
  841. "boost::filesystem::create_directory_symlink");
  842. # else
  843. # if defined(BOOST_WINDOWS_API) && _WIN32_WINNT >= 0x0600
  844. // see if actually supported by Windows runtime dll
  845. if (error(!create_symbolic_link_api ? BOOST_ERROR_NOT_SUPPORTED : 0, to, from, ec,
  846. "boost::filesystem::create_directory_symlink"))
  847. return;
  848. # endif
  849. error(!BOOST_CREATE_SYMBOLIC_LINK(from.c_str(), to.c_str(),
  850. SYMBOLIC_LINK_FLAG_DIRECTORY) ? BOOST_ERRNO : 0,
  851. to, from, ec, "boost::filesystem::create_directory_symlink");
  852. # endif
  853. }
  854. BOOST_FILESYSTEM_DECL
  855. void create_hard_link(const path& to, const path& from, error_code* ec)
  856. {
  857. # if defined(BOOST_WINDOWS_API) && _WIN32_WINNT < 0x0500 // SDK earlier than Win 2K
  858. error(BOOST_ERROR_NOT_SUPPORTED, to, from, ec,
  859. "boost::filesystem::create_hard_link");
  860. # else
  861. # if defined(BOOST_WINDOWS_API) && _WIN32_WINNT >= 0x0500
  862. // see if actually supported by Windows runtime dll
  863. if (error(!create_hard_link_api ? BOOST_ERROR_NOT_SUPPORTED : 0, to, from, ec,
  864. "boost::filesystem::create_hard_link"))
  865. return;
  866. # endif
  867. error(!BOOST_CREATE_HARD_LINK(from.c_str(), to.c_str()) ? BOOST_ERRNO : 0, to, from, ec,
  868. "boost::filesystem::create_hard_link");
  869. # endif
  870. }
  871. BOOST_FILESYSTEM_DECL
  872. void create_symlink(const path& to, const path& from, error_code* ec)
  873. {
  874. # if defined(BOOST_WINDOWS_API) && _WIN32_WINNT < 0x0600 // SDK earlier than Vista and Server 2008
  875. error(BOOST_ERROR_NOT_SUPPORTED, to, from, ec,
  876. "boost::filesystem::create_directory_symlink");
  877. # else
  878. # if defined(BOOST_WINDOWS_API) && _WIN32_WINNT >= 0x0600
  879. // see if actually supported by Windows runtime dll
  880. if (error(!create_symbolic_link_api ? BOOST_ERROR_NOT_SUPPORTED : 0, to, from, ec,
  881. "boost::filesystem::create_symlink"))
  882. return;
  883. # endif
  884. error(!BOOST_CREATE_SYMBOLIC_LINK(from.c_str(), to.c_str(), 0) ? BOOST_ERRNO : 0,
  885. to, from, ec, "boost::filesystem::create_symlink");
  886. # endif
  887. }
  888. BOOST_FILESYSTEM_DECL
  889. path current_path(error_code* ec)
  890. {
  891. # ifdef BOOST_POSIX_API
  892. struct local
  893. {
  894. static bool getcwd_error(error_code* ec)
  895. {
  896. const int err = errno;
  897. return error((err != ERANGE
  898. // bug in some versions of the Metrowerks C lib on the Mac: wrong errno set
  899. # if defined(__MSL__) && (defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__))
  900. && err != 0
  901. # endif
  902. ) ? err : 0, ec, "boost::filesystem::current_path");
  903. }
  904. };
  905. path cur;
  906. char small_buf[1024];
  907. const char* p = ::getcwd(small_buf, sizeof(small_buf));
  908. if (BOOST_LIKELY(!!p))
  909. {
  910. cur = p;
  911. if (ec != 0) ec->clear();
  912. }
  913. else if (BOOST_LIKELY(!local::getcwd_error(ec)))
  914. {
  915. for (std::size_t path_max = sizeof(small_buf);; path_max *= 2u) // loop 'til buffer large enough
  916. {
  917. if (BOOST_UNLIKELY(path_max > absolute_path_max))
  918. {
  919. if (ec == 0)
  920. BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::current_path",
  921. error_code(ENAMETOOLONG, system_category())));
  922. else
  923. ec->assign(ENAMETOOLONG, system_category());
  924. break;
  925. }
  926. boost::scoped_array<char> buf(new char[path_max]);
  927. p = ::getcwd(buf.get(), path_max);
  928. if (BOOST_LIKELY(!!p))
  929. {
  930. cur = buf.get();
  931. if (ec != 0)
  932. ec->clear();
  933. break;
  934. }
  935. else if (BOOST_UNLIKELY(local::getcwd_error(ec)))
  936. {
  937. break;
  938. }
  939. }
  940. }
  941. return cur;
  942. # elif defined(UNDER_CE)
  943. // Windows CE has no current directory, so everything's relative to the root of the directory tree
  944. return L"\\";
  945. # else
  946. DWORD sz;
  947. if ((sz = ::GetCurrentDirectoryW(0, NULL)) == 0)sz = 1;
  948. boost::scoped_array<path::value_type> buf(new path::value_type[sz]);
  949. error(::GetCurrentDirectoryW(sz, buf.get()) == 0 ? BOOST_ERRNO : 0, ec,
  950. "boost::filesystem::current_path");
  951. return path(buf.get());
  952. # endif
  953. }
  954. BOOST_FILESYSTEM_DECL
  955. void current_path(const path& p, system::error_code* ec)
  956. {
  957. # ifdef UNDER_CE
  958. error(BOOST_ERROR_NOT_SUPPORTED, p, ec,
  959. "boost::filesystem::current_path");
  960. # else
  961. error(!BOOST_SET_CURRENT_DIRECTORY(p.c_str()) ? BOOST_ERRNO : 0,
  962. p, ec, "boost::filesystem::current_path");
  963. # endif
  964. }
  965. BOOST_FILESYSTEM_DECL
  966. bool equivalent(const path& p1, const path& p2, system::error_code* ec)
  967. {
  968. # ifdef BOOST_POSIX_API
  969. struct stat s2;
  970. int e2(::stat(p2.c_str(), &s2));
  971. struct stat s1;
  972. int e1(::stat(p1.c_str(), &s1));
  973. if (e1 != 0 || e2 != 0)
  974. {
  975. // if one is invalid and the other isn't then they aren't equivalent,
  976. // but if both are invalid then it is an error
  977. error (e1 != 0 && e2 != 0, p1, p2, ec, "boost::filesystem::equivalent");
  978. return false;
  979. }
  980. // both stats now known to be valid
  981. return s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino
  982. // According to the POSIX stat specs, "The st_ino and st_dev fields
  983. // taken together uniquely identify the file within the system."
  984. // Just to be sure, size and mod time are also checked.
  985. && s1.st_size == s2.st_size && s1.st_mtime == s2.st_mtime;
  986. # else // Windows
  987. // Note well: Physical location on external media is part of the
  988. // equivalence criteria. If there are no open handles, physical location
  989. // can change due to defragmentation or other relocations. Thus handles
  990. // must be held open until location information for both paths has
  991. // been retrieved.
  992. // p2 is done first, so any error reported is for p1
  993. handle_wrapper h2(
  994. create_file_handle(
  995. p2.c_str(),
  996. 0,
  997. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
  998. 0,
  999. OPEN_EXISTING,
  1000. FILE_FLAG_BACKUP_SEMANTICS,
  1001. 0));
  1002. handle_wrapper h1(
  1003. create_file_handle(
  1004. p1.c_str(),
  1005. 0,
  1006. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
  1007. 0,
  1008. OPEN_EXISTING,
  1009. FILE_FLAG_BACKUP_SEMANTICS,
  1010. 0));
  1011. if (h1.handle == INVALID_HANDLE_VALUE
  1012. || h2.handle == INVALID_HANDLE_VALUE)
  1013. {
  1014. // if one is invalid and the other isn't, then they aren't equivalent,
  1015. // but if both are invalid then it is an error
  1016. error((h1.handle == INVALID_HANDLE_VALUE
  1017. && h2.handle == INVALID_HANDLE_VALUE) ? BOOST_ERROR_NOT_SUPPORTED : 0, p1, p2, ec,
  1018. "boost::filesystem::equivalent");
  1019. return false;
  1020. }
  1021. // at this point, both handles are known to be valid
  1022. BY_HANDLE_FILE_INFORMATION info1, info2;
  1023. if (error(!::GetFileInformationByHandle(h1.handle, &info1) ? BOOST_ERRNO : 0,
  1024. p1, p2, ec, "boost::filesystem::equivalent"))
  1025. return false;
  1026. if (error(!::GetFileInformationByHandle(h2.handle, &info2) ? BOOST_ERRNO : 0,
  1027. p1, p2, ec, "boost::filesystem::equivalent"))
  1028. return false;
  1029. // In theory, volume serial numbers are sufficient to distinguish between
  1030. // devices, but in practice VSN's are sometimes duplicated, so last write
  1031. // time and file size are also checked.
  1032. return
  1033. info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber
  1034. && info1.nFileIndexHigh == info2.nFileIndexHigh
  1035. && info1.nFileIndexLow == info2.nFileIndexLow
  1036. && info1.nFileSizeHigh == info2.nFileSizeHigh
  1037. && info1.nFileSizeLow == info2.nFileSizeLow
  1038. && info1.ftLastWriteTime.dwLowDateTime
  1039. == info2.ftLastWriteTime.dwLowDateTime
  1040. && info1.ftLastWriteTime.dwHighDateTime
  1041. == info2.ftLastWriteTime.dwHighDateTime;
  1042. # endif
  1043. }
  1044. BOOST_FILESYSTEM_DECL
  1045. boost::uintmax_t file_size(const path& p, error_code* ec)
  1046. {
  1047. # ifdef BOOST_POSIX_API
  1048. struct stat path_stat;
  1049. if (error(::stat(p.c_str(), &path_stat)!= 0 ? BOOST_ERRNO : 0,
  1050. p, ec, "boost::filesystem::file_size"))
  1051. return static_cast<boost::uintmax_t>(-1);
  1052. if (error(!S_ISREG(path_stat.st_mode) ? EPERM : 0,
  1053. p, ec, "boost::filesystem::file_size"))
  1054. return static_cast<boost::uintmax_t>(-1);
  1055. return static_cast<boost::uintmax_t>(path_stat.st_size);
  1056. # else // Windows
  1057. // assume uintmax_t is 64-bits on all Windows compilers
  1058. WIN32_FILE_ATTRIBUTE_DATA fad;
  1059. if (error(::GetFileAttributesExW(p.c_str(), ::GetFileExInfoStandard, &fad)== 0
  1060. ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::file_size"))
  1061. return static_cast<boost::uintmax_t>(-1);
  1062. if (error((fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)!= 0
  1063. ? ERROR_NOT_SUPPORTED : 0, p, ec, "boost::filesystem::file_size"))
  1064. return static_cast<boost::uintmax_t>(-1);
  1065. return (static_cast<boost::uintmax_t>(fad.nFileSizeHigh)
  1066. << (sizeof(fad.nFileSizeLow)*8)) + fad.nFileSizeLow;
  1067. # endif
  1068. }
  1069. BOOST_FILESYSTEM_DECL
  1070. boost::uintmax_t hard_link_count(const path& p, system::error_code* ec)
  1071. {
  1072. # ifdef BOOST_POSIX_API
  1073. struct stat path_stat;
  1074. return error(::stat(p.c_str(), &path_stat)!= 0 ? BOOST_ERRNO : 0,
  1075. p, ec, "boost::filesystem::hard_link_count")
  1076. ? 0
  1077. : static_cast<boost::uintmax_t>(path_stat.st_nlink);
  1078. # else // Windows
  1079. // Link count info is only available through GetFileInformationByHandle
  1080. BY_HANDLE_FILE_INFORMATION info;
  1081. handle_wrapper h(
  1082. create_file_handle(p.c_str(), 0,
  1083. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
  1084. OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0));
  1085. return
  1086. !error(h.handle == INVALID_HANDLE_VALUE ? BOOST_ERRNO : 0,
  1087. p, ec, "boost::filesystem::hard_link_count")
  1088. && !error(::GetFileInformationByHandle(h.handle, &info)== 0 ? BOOST_ERRNO : 0,
  1089. p, ec, "boost::filesystem::hard_link_count")
  1090. ? info.nNumberOfLinks
  1091. : 0;
  1092. # endif
  1093. }
  1094. BOOST_FILESYSTEM_DECL
  1095. path initial_path(error_code* ec)
  1096. {
  1097. static path init_path;
  1098. if (init_path.empty())
  1099. init_path = current_path(ec);
  1100. else if (ec != 0) ec->clear();
  1101. return init_path;
  1102. }
  1103. BOOST_FILESYSTEM_DECL
  1104. bool is_empty(const path& p, system::error_code* ec)
  1105. {
  1106. # ifdef BOOST_POSIX_API
  1107. struct stat path_stat;
  1108. if (error(::stat(p.c_str(), &path_stat)!= 0,
  1109. p, ec, "boost::filesystem::is_empty"))
  1110. return false;
  1111. return S_ISDIR(path_stat.st_mode)
  1112. ? is_empty_directory(p, ec)
  1113. : path_stat.st_size == 0;
  1114. # else
  1115. WIN32_FILE_ATTRIBUTE_DATA fad;
  1116. if (error(::GetFileAttributesExW(p.c_str(), ::GetFileExInfoStandard, &fad)== 0
  1117. ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::is_empty"))
  1118. return false;
  1119. if (ec != 0) ec->clear();
  1120. return
  1121. (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  1122. ? is_empty_directory(p, ec)
  1123. : (!fad.nFileSizeHigh && !fad.nFileSizeLow);
  1124. # endif
  1125. }
  1126. BOOST_FILESYSTEM_DECL
  1127. std::time_t last_write_time(const path& p, system::error_code* ec)
  1128. {
  1129. # ifdef BOOST_POSIX_API
  1130. struct stat path_stat;
  1131. if (error(::stat(p.c_str(), &path_stat)!= 0 ? BOOST_ERRNO : 0,
  1132. p, ec, "boost::filesystem::last_write_time"))
  1133. return std::time_t(-1);
  1134. return path_stat.st_mtime;
  1135. # else
  1136. handle_wrapper hw(
  1137. create_file_handle(p.c_str(), 0,
  1138. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
  1139. OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0));
  1140. if (error(hw.handle == INVALID_HANDLE_VALUE ? BOOST_ERRNO : 0,
  1141. p, ec, "boost::filesystem::last_write_time"))
  1142. return std::time_t(-1);
  1143. FILETIME lwt;
  1144. if (error(::GetFileTime(hw.handle, 0, 0, &lwt)== 0 ? BOOST_ERRNO : 0,
  1145. p, ec, "boost::filesystem::last_write_time"))
  1146. return std::time_t(-1);
  1147. return to_time_t(lwt);
  1148. # endif
  1149. }
  1150. BOOST_FILESYSTEM_DECL
  1151. void last_write_time(const path& p, const std::time_t new_time,
  1152. system::error_code* ec)
  1153. {
  1154. # ifdef BOOST_POSIX_API
  1155. # if _POSIX_C_SOURCE >= 200809L
  1156. struct timespec times[2] = {};
  1157. // Keep the last access time unchanged
  1158. times[0].tv_nsec = UTIME_OMIT;
  1159. times[1].tv_sec = new_time;
  1160. if (BOOST_UNLIKELY(::utimensat(AT_FDCWD, p.c_str(), times, 0) != 0))
  1161. {
  1162. error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time");
  1163. return;
  1164. }
  1165. # else // _POSIX_C_SOURCE >= 200809L
  1166. struct stat path_stat;
  1167. if (error(::stat(p.c_str(), &path_stat)!= 0,
  1168. p, ec, "boost::filesystem::last_write_time"))
  1169. return;
  1170. ::utimbuf buf;
  1171. buf.actime = path_stat.st_atime; // utime()updates access time too:-(
  1172. buf.modtime = new_time;
  1173. error(::utime(p.c_str(), &buf)!= 0 ? BOOST_ERRNO : 0,
  1174. p, ec, "boost::filesystem::last_write_time");
  1175. # endif // _POSIX_C_SOURCE >= 200809L
  1176. # else
  1177. handle_wrapper hw(
  1178. create_file_handle(p.c_str(), FILE_WRITE_ATTRIBUTES,
  1179. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
  1180. OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0));
  1181. if (error(hw.handle == INVALID_HANDLE_VALUE ? BOOST_ERRNO : 0,
  1182. p, ec, "boost::filesystem::last_write_time"))
  1183. return;
  1184. FILETIME lwt;
  1185. to_FILETIME(new_time, lwt);
  1186. error(::SetFileTime(hw.handle, 0, 0, &lwt)== 0 ? BOOST_ERRNO : 0,
  1187. p, ec, "boost::filesystem::last_write_time");
  1188. # endif
  1189. }
  1190. # ifdef BOOST_POSIX_API
  1191. const perms active_bits(all_all | set_uid_on_exe | set_gid_on_exe | sticky_bit);
  1192. inline mode_t mode_cast(perms prms) { return prms & active_bits; }
  1193. # endif
  1194. BOOST_FILESYSTEM_DECL
  1195. void permissions(const path& p, perms prms, system::error_code* ec)
  1196. {
  1197. BOOST_ASSERT_MSG(!((prms & add_perms) && (prms & remove_perms)),
  1198. "add_perms and remove_perms are mutually exclusive");
  1199. if ((prms & add_perms) && (prms & remove_perms)) // precondition failed
  1200. return;
  1201. # ifdef BOOST_POSIX_API
  1202. error_code local_ec;
  1203. file_status current_status((prms & symlink_perms)
  1204. ? fs::symlink_status(p, local_ec)
  1205. : fs::status(p, local_ec));
  1206. if (local_ec)
  1207. {
  1208. if (ec == 0)
  1209. BOOST_FILESYSTEM_THROW(filesystem_error(
  1210. "boost::filesystem::permissions", p, local_ec));
  1211. else
  1212. *ec = local_ec;
  1213. return;
  1214. }
  1215. if (prms & add_perms)
  1216. prms |= current_status.permissions();
  1217. else if (prms & remove_perms)
  1218. prms = current_status.permissions() & ~prms;
  1219. // OS X <10.10, iOS <8.0 and some other platforms don't support fchmodat().
  1220. // Solaris (SunPro and gcc) only support fchmodat() on Solaris 11 and higher,
  1221. // and a runtime check is too much trouble.
  1222. // Linux does not support permissions on symbolic links and has no plans to
  1223. // support them in the future. The chmod() code is thus more practical,
  1224. // rather than always hitting ENOTSUP when sending in AT_SYMLINK_NO_FOLLOW.
  1225. // - See the 3rd paragraph of
  1226. // "Symbolic link ownership, permissions, and timestamps" at:
  1227. // "http://man7.org/linux/man-pages/man7/symlink.7.html"
  1228. // - See the fchmodat() Linux man page:
  1229. // "http://man7.org/linux/man-pages/man2/fchmodat.2.html"
  1230. # if defined(AT_FDCWD) && defined(AT_SYMLINK_NOFOLLOW) \
  1231. && !(defined(__SUNPRO_CC) || defined(__sun) || defined(sun)) \
  1232. && !(defined(linux) || defined(__linux) || defined(__linux__)) \
  1233. && !(defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \
  1234. && __MAC_OS_X_VERSION_MIN_REQUIRED < 101000) \
  1235. && !(defined(__IPHONE_OS_VERSION_MIN_REQUIRED) \
  1236. && __IPHONE_OS_VERSION_MIN_REQUIRED < 80000) \
  1237. && !(defined(__QNX__) && (_NTO_VERSION <= 700))
  1238. if (::fchmodat(AT_FDCWD, p.c_str(), mode_cast(prms),
  1239. !(prms & symlink_perms) ? 0 : AT_SYMLINK_NOFOLLOW))
  1240. # else // fallback if fchmodat() not supported
  1241. if (::chmod(p.c_str(), mode_cast(prms)))
  1242. # endif
  1243. {
  1244. const int err = errno;
  1245. if (ec == 0)
  1246. BOOST_FILESYSTEM_THROW(filesystem_error(
  1247. "boost::filesystem::permissions", p,
  1248. error_code(err, system::generic_category())));
  1249. else
  1250. ec->assign(err, system::generic_category());
  1251. }
  1252. # else // Windows
  1253. // if not going to alter FILE_ATTRIBUTE_READONLY, just return
  1254. if (!(!((prms & (add_perms | remove_perms)))
  1255. || (prms & (owner_write|group_write|others_write))))
  1256. return;
  1257. DWORD attr = ::GetFileAttributesW(p.c_str());
  1258. if (error(attr == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::permissions"))
  1259. return;
  1260. if (prms & add_perms)
  1261. attr &= ~FILE_ATTRIBUTE_READONLY;
  1262. else if (prms & remove_perms)
  1263. attr |= FILE_ATTRIBUTE_READONLY;
  1264. else if (prms & (owner_write|group_write|others_write))
  1265. attr &= ~FILE_ATTRIBUTE_READONLY;
  1266. else
  1267. attr |= FILE_ATTRIBUTE_READONLY;
  1268. error(::SetFileAttributesW(p.c_str(), attr) == 0 ? BOOST_ERRNO : 0,
  1269. p, ec, "boost::filesystem::permissions");
  1270. # endif
  1271. }
  1272. BOOST_FILESYSTEM_DECL
  1273. path read_symlink(const path& p, system::error_code* ec)
  1274. {
  1275. path symlink_path;
  1276. # ifdef BOOST_POSIX_API
  1277. const char* const path_str = p.c_str();
  1278. char small_buf[1024];
  1279. ssize_t result = ::readlink(path_str, small_buf, sizeof(small_buf));
  1280. if (BOOST_UNLIKELY(result < 0))
  1281. {
  1282. fail:
  1283. const int err = errno;
  1284. if (ec == 0)
  1285. BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::read_symlink",
  1286. p, error_code(err, system_category())));
  1287. else
  1288. ec->assign(err, system_category());
  1289. }
  1290. else if (BOOST_LIKELY(static_cast< std::size_t >(result) < sizeof(small_buf)))
  1291. {
  1292. symlink_path.assign(small_buf, small_buf + result);
  1293. if (ec != 0)
  1294. ec->clear();
  1295. }
  1296. else
  1297. {
  1298. for (std::size_t path_max = sizeof(small_buf) * 2u;; path_max *= 2u) // loop 'til buffer large enough
  1299. {
  1300. if (BOOST_UNLIKELY(path_max > absolute_path_max))
  1301. {
  1302. if (ec == 0)
  1303. BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::read_symlink",
  1304. p, error_code(ENAMETOOLONG, system_category())));
  1305. else
  1306. ec->assign(ENAMETOOLONG, system_category());
  1307. break;
  1308. }
  1309. boost::scoped_array<char> buf(new char[path_max]);
  1310. result = ::readlink(path_str, buf.get(), path_max);
  1311. if (BOOST_UNLIKELY(result < 0))
  1312. {
  1313. goto fail;
  1314. }
  1315. else if (BOOST_LIKELY(static_cast< std::size_t >(result) < path_max))
  1316. {
  1317. symlink_path.assign(buf.get(), buf.get() + result);
  1318. if (ec != 0) ec->clear();
  1319. break;
  1320. }
  1321. }
  1322. }
  1323. # elif _WIN32_WINNT < 0x0600 // SDK earlier than Vista and Server 2008
  1324. error(BOOST_ERROR_NOT_SUPPORTED, p, ec,
  1325. "boost::filesystem::read_symlink");
  1326. # else // Vista and Server 2008 SDK, or later
  1327. union info_t
  1328. {
  1329. char buf[REPARSE_DATA_BUFFER_HEADER_SIZE+MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
  1330. REPARSE_DATA_BUFFER rdb;
  1331. } info;
  1332. handle_wrapper h(
  1333. create_file_handle(p.c_str(), GENERIC_READ, 0, 0, OPEN_EXISTING,
  1334. FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0));
  1335. if (error(h.handle == INVALID_HANDLE_VALUE ? BOOST_ERRNO : 0,
  1336. p, ec, "boost::filesystem::read_symlink"))
  1337. return symlink_path;
  1338. DWORD sz;
  1339. if (!error(::DeviceIoControl(h.handle, FSCTL_GET_REPARSE_POINT,
  1340. 0, 0, info.buf, sizeof(info), &sz, 0) == 0 ? BOOST_ERRNO : 0, p, ec,
  1341. "boost::filesystem::read_symlink" ))
  1342. symlink_path.assign(
  1343. static_cast<wchar_t*>(info.rdb.SymbolicLinkReparseBuffer.PathBuffer)
  1344. + info.rdb.SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(wchar_t),
  1345. static_cast<wchar_t*>(info.rdb.SymbolicLinkReparseBuffer.PathBuffer)
  1346. + info.rdb.SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(wchar_t)
  1347. + info.rdb.SymbolicLinkReparseBuffer.PrintNameLength/sizeof(wchar_t));
  1348. # endif
  1349. return symlink_path;
  1350. }
  1351. BOOST_FILESYSTEM_DECL
  1352. path relative(const path& p, const path& base, error_code* ec)
  1353. {
  1354. error_code tmp_ec;
  1355. path wc_base(weakly_canonical(base, &tmp_ec));
  1356. if (error(tmp_ec.value(), base, ec, "boost::filesystem::relative"))
  1357. return path();
  1358. path wc_p(weakly_canonical(p, &tmp_ec));
  1359. if (error(tmp_ec.value(), base, ec, "boost::filesystem::relative"))
  1360. return path();
  1361. return wc_p.lexically_relative(wc_base);
  1362. }
  1363. BOOST_FILESYSTEM_DECL
  1364. bool remove(const path& p, error_code* ec)
  1365. {
  1366. error_code tmp_ec;
  1367. file_type type = query_file_type(p, &tmp_ec);
  1368. if (error(type == status_error ? tmp_ec.value() : 0, p, ec,
  1369. "boost::filesystem::remove"))
  1370. return false;
  1371. // Since POSIX remove() is specified to work with either files or directories, in a
  1372. // perfect world it could just be called. But some important real-world operating
  1373. // systems (Windows, Mac OS X, for example) don't implement the POSIX spec. So
  1374. // remove_file_or_directory() is always called to keep it simple.
  1375. return remove_file_or_directory(p, type, ec);
  1376. }
  1377. BOOST_FILESYSTEM_DECL
  1378. boost::uintmax_t remove_all(const path& p, error_code* ec)
  1379. {
  1380. error_code tmp_ec;
  1381. file_type type = query_file_type(p, &tmp_ec);
  1382. if (error(type == status_error ? tmp_ec.value() : 0, p, ec,
  1383. "boost::filesystem::remove_all"))
  1384. return 0;
  1385. return (type != status_error && type != file_not_found) // exists
  1386. ? remove_all_aux(p, type, ec)
  1387. : 0;
  1388. }
  1389. BOOST_FILESYSTEM_DECL
  1390. void rename(const path& old_p, const path& new_p, error_code* ec)
  1391. {
  1392. error(!BOOST_MOVE_FILE(old_p.c_str(), new_p.c_str()) ? BOOST_ERRNO : 0, old_p, new_p,
  1393. ec, "boost::filesystem::rename");
  1394. }
  1395. BOOST_FILESYSTEM_DECL
  1396. void resize_file(const path& p, uintmax_t size, system::error_code* ec)
  1397. {
  1398. # if defined(BOOST_POSIX_API)
  1399. if (BOOST_UNLIKELY(size > static_cast< uintmax_t >((std::numeric_limits< off_t >::max)()))) {
  1400. error(system::errc::file_too_large, p, ec, "boost::filesystem::resize_file");
  1401. return;
  1402. }
  1403. # endif
  1404. error(!BOOST_RESIZE_FILE(p.c_str(), size) ? BOOST_ERRNO : 0, p, ec,
  1405. "boost::filesystem::resize_file");
  1406. }
  1407. BOOST_FILESYSTEM_DECL
  1408. space_info space(const path& p, error_code* ec)
  1409. {
  1410. # ifdef BOOST_POSIX_API
  1411. struct BOOST_STATVFS vfs;
  1412. space_info info;
  1413. if (!error(::BOOST_STATVFS(p.c_str(), &vfs) ? BOOST_ERRNO : 0,
  1414. p, ec, "boost::filesystem::space"))
  1415. {
  1416. info.capacity
  1417. = static_cast<boost::uintmax_t>(vfs.f_blocks)* BOOST_STATVFS_F_FRSIZE;
  1418. info.free
  1419. = static_cast<boost::uintmax_t>(vfs.f_bfree)* BOOST_STATVFS_F_FRSIZE;
  1420. info.available
  1421. = static_cast<boost::uintmax_t>(vfs.f_bavail)* BOOST_STATVFS_F_FRSIZE;
  1422. }
  1423. # else
  1424. ULARGE_INTEGER avail, total, free;
  1425. space_info info;
  1426. if (!error(::GetDiskFreeSpaceExW(p.c_str(), &avail, &total, &free)== 0,
  1427. p, ec, "boost::filesystem::space"))
  1428. {
  1429. info.capacity
  1430. = (static_cast<boost::uintmax_t>(total.HighPart)<< 32)
  1431. + total.LowPart;
  1432. info.free
  1433. = (static_cast<boost::uintmax_t>(free.HighPart)<< 32)
  1434. + free.LowPart;
  1435. info.available
  1436. = (static_cast<boost::uintmax_t>(avail.HighPart)<< 32)
  1437. + avail.LowPart;
  1438. }
  1439. # endif
  1440. else
  1441. {
  1442. info.capacity = info.free = info.available = 0;
  1443. }
  1444. return info;
  1445. }
  1446. BOOST_FILESYSTEM_DECL
  1447. file_status status(const path& p, error_code* ec)
  1448. {
  1449. # ifdef BOOST_POSIX_API
  1450. struct stat path_stat;
  1451. if (::stat(p.c_str(), &path_stat)!= 0)
  1452. {
  1453. const int err = errno;
  1454. if (ec != 0) // always report errno, even though some
  1455. ec->assign(err, system_category()); // errno values are not status_errors
  1456. if (not_found_error(err))
  1457. {
  1458. return fs::file_status(fs::file_not_found, fs::no_perms);
  1459. }
  1460. if (ec == 0)
  1461. BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status",
  1462. p, error_code(err, system_category())));
  1463. return fs::file_status(fs::status_error);
  1464. }
  1465. if (ec != 0) ec->clear();;
  1466. if (S_ISDIR(path_stat.st_mode))
  1467. return fs::file_status(fs::directory_file,
  1468. static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
  1469. if (S_ISREG(path_stat.st_mode))
  1470. return fs::file_status(fs::regular_file,
  1471. static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
  1472. if (S_ISBLK(path_stat.st_mode))
  1473. return fs::file_status(fs::block_file,
  1474. static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
  1475. if (S_ISCHR(path_stat.st_mode))
  1476. return fs::file_status(fs::character_file,
  1477. static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
  1478. if (S_ISFIFO(path_stat.st_mode))
  1479. return fs::file_status(fs::fifo_file,
  1480. static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
  1481. if (S_ISSOCK(path_stat.st_mode))
  1482. return fs::file_status(fs::socket_file,
  1483. static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
  1484. return fs::file_status(fs::type_unknown);
  1485. # else // Windows
  1486. DWORD attr(::GetFileAttributesW(p.c_str()));
  1487. if (attr == 0xFFFFFFFF)
  1488. {
  1489. return process_status_failure(p, ec);
  1490. }
  1491. perms permissions = make_permissions(p, attr);
  1492. // reparse point handling;
  1493. // since GetFileAttributesW does not resolve symlinks, try to open a file
  1494. // handle to discover if the file exists
  1495. if (attr & FILE_ATTRIBUTE_REPARSE_POINT)
  1496. {
  1497. handle_wrapper h(
  1498. create_file_handle(
  1499. p.c_str(),
  1500. 0, // dwDesiredAccess; attributes only
  1501. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
  1502. 0, // lpSecurityAttributes
  1503. OPEN_EXISTING,
  1504. FILE_FLAG_BACKUP_SEMANTICS,
  1505. 0)); // hTemplateFile
  1506. if (h.handle == INVALID_HANDLE_VALUE)
  1507. {
  1508. return process_status_failure(p, ec);
  1509. }
  1510. if (!is_reparse_point_a_symlink(p))
  1511. return file_status(reparse_file, permissions);
  1512. }
  1513. if (ec != 0) ec->clear();
  1514. return (attr & FILE_ATTRIBUTE_DIRECTORY)
  1515. ? file_status(directory_file, permissions)
  1516. : file_status(regular_file, permissions);
  1517. # endif
  1518. }
  1519. BOOST_FILESYSTEM_DECL
  1520. file_status symlink_status(const path& p, error_code* ec)
  1521. {
  1522. # ifdef BOOST_POSIX_API
  1523. struct stat path_stat;
  1524. if (::lstat(p.c_str(), &path_stat)!= 0)
  1525. {
  1526. const int err = errno;
  1527. if (ec != 0) // always report errno, even though some
  1528. ec->assign(err, system_category()); // errno values are not status_errors
  1529. if (not_found_error(err)) // these are not errors
  1530. {
  1531. return fs::file_status(fs::file_not_found, fs::no_perms);
  1532. }
  1533. if (ec == 0)
  1534. BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status",
  1535. p, error_code(err, system_category())));
  1536. return fs::file_status(fs::status_error);
  1537. }
  1538. if (ec != 0) ec->clear();
  1539. if (S_ISREG(path_stat.st_mode))
  1540. return fs::file_status(fs::regular_file,
  1541. static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
  1542. if (S_ISDIR(path_stat.st_mode))
  1543. return fs::file_status(fs::directory_file,
  1544. static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
  1545. if (S_ISLNK(path_stat.st_mode))
  1546. return fs::file_status(fs::symlink_file,
  1547. static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
  1548. if (S_ISBLK(path_stat.st_mode))
  1549. return fs::file_status(fs::block_file,
  1550. static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
  1551. if (S_ISCHR(path_stat.st_mode))
  1552. return fs::file_status(fs::character_file,
  1553. static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
  1554. if (S_ISFIFO(path_stat.st_mode))
  1555. return fs::file_status(fs::fifo_file,
  1556. static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
  1557. if (S_ISSOCK(path_stat.st_mode))
  1558. return fs::file_status(fs::socket_file,
  1559. static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
  1560. return fs::file_status(fs::type_unknown);
  1561. # else // Windows
  1562. DWORD attr(::GetFileAttributesW(p.c_str()));
  1563. if (attr == 0xFFFFFFFF)
  1564. {
  1565. return process_status_failure(p, ec);
  1566. }
  1567. if (ec != 0) ec->clear();
  1568. perms permissions = make_permissions(p, attr);
  1569. if (attr & FILE_ATTRIBUTE_REPARSE_POINT)
  1570. return is_reparse_point_a_symlink(p)
  1571. ? file_status(symlink_file, permissions)
  1572. : file_status(reparse_file, permissions);
  1573. return (attr & FILE_ATTRIBUTE_DIRECTORY)
  1574. ? file_status(directory_file, permissions)
  1575. : file_status(regular_file, permissions);
  1576. # endif
  1577. }
  1578. // contributed by Jeff Flinn
  1579. BOOST_FILESYSTEM_DECL
  1580. path temp_directory_path(system::error_code* ec)
  1581. {
  1582. # ifdef BOOST_POSIX_API
  1583. const char* val = 0;
  1584. (val = std::getenv("TMPDIR" )) ||
  1585. (val = std::getenv("TMP" )) ||
  1586. (val = std::getenv("TEMP" )) ||
  1587. (val = std::getenv("TEMPDIR"));
  1588. # ifdef __ANDROID__
  1589. const char* default_tmp = "/data/local/tmp";
  1590. # else
  1591. const char* default_tmp = "/tmp";
  1592. # endif
  1593. path p((val != NULL) ? val : default_tmp);
  1594. if (p.empty() || (ec && !is_directory(p, *ec)) || (!ec && !is_directory(p)))
  1595. {
  1596. error(ENOTDIR, p, ec, "boost::filesystem::temp_directory_path");
  1597. return p;
  1598. }
  1599. return p;
  1600. # else // Windows
  1601. const wchar_t* tmp_env = L"TMP";
  1602. const wchar_t* temp_env = L"TEMP";
  1603. const wchar_t* localappdata_env = L"LOCALAPPDATA";
  1604. const wchar_t* userprofile_env = L"USERPROFILE";
  1605. const wchar_t* env_list[] = { tmp_env, temp_env, localappdata_env, userprofile_env };
  1606. path p;
  1607. for (unsigned int i = 0; i < sizeof(env_list) / sizeof(*env_list); ++i)
  1608. {
  1609. std::wstring env = wgetenv(env_list[i]);
  1610. if (!env.empty())
  1611. {
  1612. p = env;
  1613. if (i >= 2)
  1614. p /= L"Temp";
  1615. error_code lcl_ec;
  1616. if (exists(p, lcl_ec) && !lcl_ec && is_directory(p, lcl_ec) && !lcl_ec)
  1617. break;
  1618. p.clear();
  1619. }
  1620. }
  1621. if (p.empty())
  1622. {
  1623. // use a separate buffer since in C++03 a string is not required to be contiguous
  1624. const UINT size = ::GetWindowsDirectoryW(NULL, 0);
  1625. if (BOOST_UNLIKELY(size == 0))
  1626. {
  1627. getwindir_error:
  1628. int errval = ::GetLastError();
  1629. error(errval, ec, "boost::filesystem::temp_directory_path");
  1630. return path();
  1631. }
  1632. boost::scoped_array<wchar_t> buf(new wchar_t[size]);
  1633. if (BOOST_UNLIKELY(::GetWindowsDirectoryW(buf.get(), size) == 0))
  1634. goto getwindir_error;
  1635. p = buf.get(); // do not depend on initial buf size, see ticket #10388
  1636. p /= L"Temp";
  1637. }
  1638. return p;
  1639. # endif
  1640. }
  1641. BOOST_FILESYSTEM_DECL
  1642. path system_complete(const path& p, system::error_code* ec)
  1643. {
  1644. # ifdef BOOST_POSIX_API
  1645. return (p.empty() || p.is_absolute())
  1646. ? p : current_path() / p;
  1647. # else
  1648. if (p.empty())
  1649. {
  1650. if (ec != 0) ec->clear();
  1651. return p;
  1652. }
  1653. wchar_t buf[buf_size];
  1654. wchar_t* pfn;
  1655. std::size_t len = get_full_path_name(p, buf_size, buf, &pfn);
  1656. if (error(len == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::system_complete"))
  1657. return path();
  1658. if (len < buf_size)// len does not include null termination character
  1659. return path(&buf[0]);
  1660. boost::scoped_array<wchar_t> big_buf(new wchar_t[len]);
  1661. return error(get_full_path_name(p, len , big_buf.get(), &pfn)== 0 ? BOOST_ERRNO : 0,
  1662. p, ec, "boost::filesystem::system_complete")
  1663. ? path()
  1664. : path(big_buf.get());
  1665. # endif
  1666. }
  1667. BOOST_FILESYSTEM_DECL
  1668. path weakly_canonical(const path& p, system::error_code* ec)
  1669. {
  1670. path head(p);
  1671. path tail;
  1672. system::error_code tmp_ec;
  1673. path::iterator itr = p.end();
  1674. for (; !head.empty(); --itr)
  1675. {
  1676. file_status head_status = status(head, tmp_ec);
  1677. if (error(head_status.type() == fs::status_error,
  1678. head, ec, "boost::filesystem::weakly_canonical"))
  1679. return path();
  1680. if (head_status.type() != fs::file_not_found)
  1681. break;
  1682. head.remove_filename();
  1683. }
  1684. bool tail_has_dots = false;
  1685. for (; itr != p.end(); ++itr)
  1686. {
  1687. tail /= *itr;
  1688. // for a later optimization, track if any dot or dot-dot elements are present
  1689. if (itr->native().size() <= 2
  1690. && itr->native()[0] == dot
  1691. && (itr->native().size() == 1 || itr->native()[1] == dot))
  1692. tail_has_dots = true;
  1693. }
  1694. if (head.empty())
  1695. return p.lexically_normal();
  1696. head = canonical(head, tmp_ec);
  1697. if (error(tmp_ec.value(), head, ec, "boost::filesystem::weakly_canonical"))
  1698. return path();
  1699. return tail.empty()
  1700. ? head
  1701. : (tail_has_dots // optimization: only normalize if tail had dot or dot-dot element
  1702. ? (head/tail).lexically_normal()
  1703. : head/tail);
  1704. }
  1705. } // namespace detail
  1706. } // namespace filesystem
  1707. } // namespace boost