]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/boost/libs/filesystem/src/operations.cpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / libs / filesystem / src / operations.cpp
index b5e0f661ba674260a6e87f99e52b9de8d9718d2e..4114e02a1a3ccb9634b8e9d81c1cf334dec6a38a 100644 (file)
@@ -101,6 +101,7 @@ using std::wstring;
       // See MinGW's windef.h
 #     define WINVER 0x501
 #   endif
+#   include <cwchar>
 #   include <io.h>
 #   include <windows.h>
 #   include <winnt.h>
@@ -328,9 +329,10 @@ namespace
 
   //  general helpers  -----------------------------------------------------------------//
 
-  bool is_empty_directory(const path& p)
+  bool is_empty_directory(const path& p, error_code* ec)
   {
-    return fs::directory_iterator(p)== end_dir_itr;
+    return (ec != 0 ? fs::directory_iterator(p, *ec) : fs::directory_iterator(p))
+      == end_dir_itr;
   }
 
   bool not_found_error(int errval); // forward declaration
@@ -382,16 +384,25 @@ namespace
     error_code* ec)
   {
     boost::uintmax_t count = 1;
-
     if (type == fs::directory_file)  // but not a directory symlink
     {
-      for (fs::directory_iterator itr(p);
-            itr != end_dir_itr; ++itr)
+      fs::directory_iterator itr;
+      if (ec != 0)
+      {
+        itr = fs::directory_iterator(p, *ec);
+        if (*ec)
+          return count;
+      }
+      else
+        itr = fs::directory_iterator(p);
+      for (; itr != end_dir_itr; ++itr)
       {
         fs::file_type tmp_type = query_file_type(itr->path(), ec);
         if (ec != 0 && *ec)
           return count;
         count += remove_all_aux(itr->path(), tmp_type, ec);
+        if (ec != 0 && *ec)
+          return count;
       }
     }
     remove_file_or_directory(p, type, ec);
@@ -507,25 +518,115 @@ namespace
       || errval == ERROR_BAD_PATHNAME  // "//nosuch" on Win64
       || errval == ERROR_BAD_NETPATH;  // "//nosuch" on Win32
   }
+  
+  // File name case-insensitive comparison needs to be locale- and collation-independent. 
+  // The approach used below follows a combined strategy described in the following
+  // articles:
+  // http://archives.miloush.net/michkap/archive/2005/10/17/481600.html
+  // http://archives.miloush.net/michkap/archive/2007/09/14/4900107.html
+  // http://archives.miloush.net/michkap/archive/2007/10/12/5396685.html
+  // CompareStringOrdinal is only available on newer systems and is just a wrapper of
+  // RtlCompareUnicodeString, but measurements showed that RtlEqualUnicodeString has better
+  // performance. Therefore we use RtlEqualUnicodeString, and if that does not exist 
+  // we perform the equivalent characterwise comparsion using LCMapString and uppercase 
+  // binary equality. Instead of calling RtlInitUnicodeString we use wcslen directly
+  // because that results in better performance as well.
+
+  //  Windows ntdll.dll functions that may or may not be present
+  //  must be accessed through pointers
+  typedef struct _UNICODE_STRING {
+    USHORT Length;
+    USHORT MaximumLength;
+    PWSTR  Buffer;
+  } UNICODE_STRING;
 
-// some distributions of mingw as early as GLIBCXX__ 20110325 have _stricmp, but the
-// offical 4.6.2 release with __GLIBCXX__ 20111026  doesn't. Play it safe for now, and
-// only use _stricmp if _MSC_VER is defined
-#if defined(_MSC_VER) // || (defined(__GLIBCXX__) && __GLIBCXX__ >= 20110325)
-#  define BOOST_FILESYSTEM_STRICMP _stricmp
-#else
-#  define BOOST_FILESYSTEM_STRICMP strcmp
+  typedef const UNICODE_STRING *PCUNICODE_STRING;
+
+  typedef BOOLEAN (WINAPI *PtrRtlEqualUnicodeString)(
+    /*_In_*/ PCUNICODE_STRING String1,
+    /*_In_*/ PCUNICODE_STRING String2,
+    /*_In_*/ BOOLEAN          CaseInSensitive
+  );
+
+  PtrRtlEqualUnicodeString rtl_equal_unicode_string_api = PtrRtlEqualUnicodeString(
+    ::GetProcAddress(
+      ::GetModuleHandleW(L"ntdll.dll"), "RtlEqualUnicodeString"));
+
+#ifndef LOCALE_INVARIANT
+#  define LOCALE_INVARIANT (MAKELCID(MAKELANGID(LANG_INVARIANT, SUBLANG_NEUTRAL), SORT_DEFAULT))
 #endif
 
+  bool equal_string_ordinal_ic_1(const wchar_t* s1, const wchar_t* s2)
+  {
+    std::size_t len1 = std::wcslen(s1);
+    UNICODE_STRING us1;
+    us1.Buffer = const_cast<wchar_t*>(s1);
+    us1.Length = static_cast<USHORT>(sizeof(*s1) * len1);
+    us1.MaximumLength = static_cast<USHORT>(us1.Length + sizeof(*s1));
+    std::size_t len2 = std::wcslen(s2);
+    UNICODE_STRING us2;
+    us2.Buffer = const_cast<wchar_t*>(s2);
+    us2.Length = static_cast<USHORT>(sizeof(*s2) * len2);
+    us2.MaximumLength = static_cast<USHORT>(us2.Length + sizeof(*s2));
+    BOOLEAN res = rtl_equal_unicode_string_api(&us1, &us2, TRUE);
+    return res != FALSE;
+  }
+
+  inline
+  wchar_t to_upper_invariant(wchar_t input)
+  {
+    wchar_t result;
+    // According to 
+    // https://msdn.microsoft.com/en-us/library/windows/desktop/dd318144(v=vs.85).aspx
+    // "When transforming between uppercase and lowercase, the function always maps a 
+    // single character to a single character."
+    int res = ::LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, &input, 1, &result, 1); 
+    if (res != 0)
+      return result;
+    assert(!"LCMapStringW failed to convert a character to upper case");
+    return input; // Should never happen, but this is a safe fallback.
+  }
+  
+  bool equal_string_ordinal_ic_2(const wchar_t* s1, const wchar_t* s2)
+  {
+    for (;; ++s1, ++s2)
+    {
+      const wchar_t c1 = *s1;
+      const wchar_t c2 = *s2;
+      if (c1 == c2)
+      {
+        if (!c1)
+          return true; // We have reached the end of both strings, no difference found.
+      }
+      else
+      {
+        if (!c1 || !c2)
+          return false; // We have reached the end of one string
+        // This needs to be upper case to match the behavior of the operating system,
+        // see http://archives.miloush.net/michkap/archive/2005/10/17/481600.html
+        const wchar_t u1 = to_upper_invariant(c1);
+        const wchar_t u2 = to_upper_invariant(c2);
+        if (u1 != u2)
+          return false; // strings are different
+      }
+    }
+  }  
+  
+  typedef bool (*Ptr_equal_string_ordinal_ic)(const wchar_t*, const wchar_t*);
+
+  Ptr_equal_string_ordinal_ic equal_string_ordinal_ic = 
+    rtl_equal_unicode_string_api ? equal_string_ordinal_ic_1 : equal_string_ordinal_ic_2;
+  
   perms make_permissions(const path& p, DWORD attr)
   {
     perms prms = fs::owner_read | fs::group_read | fs::others_read;
     if  ((attr & FILE_ATTRIBUTE_READONLY) == 0)
       prms |= fs::owner_write | fs::group_write | fs::others_write;
-    if (BOOST_FILESYSTEM_STRICMP(p.extension().string().c_str(), ".exe") == 0
-      || BOOST_FILESYSTEM_STRICMP(p.extension().string().c_str(), ".com") == 0
-      || BOOST_FILESYSTEM_STRICMP(p.extension().string().c_str(), ".bat") == 0
-      || BOOST_FILESYSTEM_STRICMP(p.extension().string().c_str(), ".cmd") == 0)
+    path ext = p.extension();
+    if (equal_string_ordinal_ic(ext.c_str(), L".exe")
+      || equal_string_ordinal_ic(ext.c_str(), L".com")
+      || equal_string_ordinal_ic(ext.c_str(), L".bat")
+      || equal_string_ordinal_ic(ext.c_str(), L".cmd"))
       prms |= fs::owner_exe | fs::group_exe | fs::others_exe;
     return prms;
   }
@@ -687,7 +788,7 @@ namespace
 
   PtrCreateHardLinkW create_hard_link_api = PtrCreateHardLinkW(
     ::GetProcAddress(
-      ::GetModuleHandle(TEXT("kernel32.dll")), "CreateHardLinkW"));
+      ::GetModuleHandleW(L"kernel32.dll"), "CreateHardLinkW"));
 
   typedef BOOLEAN (WINAPI *PtrCreateSymbolicLinkW)(
     /*__in*/ LPCWSTR lpSymlinkFileName,
@@ -697,7 +798,7 @@ namespace
 
   PtrCreateSymbolicLinkW create_symbolic_link_api = PtrCreateSymbolicLinkW(
     ::GetProcAddress(
-      ::GetModuleHandle(TEXT("kernel32.dll")), "CreateSymbolicLinkW"));
+      ::GetModuleHandleW(L"kernel32.dll"), "CreateSymbolicLinkW"));
 
 #endif
 
@@ -937,12 +1038,20 @@ namespace detail
  BOOST_FILESYSTEM_DECL
   bool create_directories(const path& p, system::error_code* ec)
   {
-    path filename(p.filename());
-    if ((filename.native().size() == 1 && filename.native()[0] == dot)
-      || (filename.native().size() == 2
-        && filename.native()[0] == dot && filename.native()[1] == dot))
+   if (p.empty())
+   {
+     if (ec == 0)
+       BOOST_FILESYSTEM_THROW(filesystem_error(
+         "boost::filesystem::create_directories", p,
+         system::errc::make_error_code(system::errc::invalid_argument)));
+     else
+       ec->assign(system::errc::invalid_argument, system::generic_category());
+     return false;
+   }
+
+    if (p.filename_is_dot() || p.filename_is_dot_dot())
       return create_directories(p.parent_path(), ec);
-
+    
     error_code local_ec;
     file_status p_status = status(p, local_ec);
 
@@ -993,7 +1102,8 @@ namespace detail
     //  attempt to create directory failed
     int errval(BOOST_ERRNO);  // save reason for failure
     error_code dummy;
-    if (errval == BOOST_ERROR_ALREADY_EXISTS && is_directory(p, dummy))
+
+    if (is_directory(p, dummy))
     {
       if (ec != 0)
         ec->clear();
@@ -1006,6 +1116,7 @@ namespace detail
         p, error_code(errval, system_category())));
     else
       ec->assign(errval, system_category());
+
     return false;
   }
 
@@ -1298,7 +1409,7 @@ namespace detail
         p, ec, "boost::filesystem::is_empty"))
       return false;        
     return S_ISDIR(path_stat.st_mode)
-      ? is_empty_directory(p)
+      ? is_empty_directory(p, ec)
       : path_stat.st_size == 0;
 #   else
 
@@ -1310,7 +1421,7 @@ namespace detail
     if (ec != 0) ec->clear();
     return 
       (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-        ? is_empty_directory(p)
+        ? is_empty_directory(p, ec)
         : (!fad.nFileSizeHigh && !fad.nFileSizeLow);
 #   endif
   }
@@ -1601,7 +1712,7 @@ namespace detail
 #   ifdef BOOST_POSIX_API
     struct BOOST_STATVFS vfs;
     space_info info;
-    if (!error(::BOOST_STATVFS(p.c_str(), &vfs)!= 0,
+    if (!error(::BOOST_STATVFS(p.c_str(), &vfs) ? BOOST_ERRNO : 0,
       p, ec, "boost::filesystem::space"))
     {
       info.capacity