$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r74950 - in trunk: boost/filesystem/v3 libs/filesystem/v3/src libs/filesystem/v3/test libs/filesystem/v3/test/msvc10
From: bdawes_at_[hidden]
Date: 2011-10-15 12:02:23
Author: bemandawes
Date: 2011-10-15 12:02:20 EDT (Sat, 15 Oct 2011)
New Revision: 74950
URL: http://svn.boost.org/trac/boost/changeset/74950
Log:
Add support for permissions. Docs to follow.
Text files modified: 
   trunk/boost/filesystem/v3/operations.hpp               |   140 +++++++++++++++++++++---                
   trunk/libs/filesystem/v3/src/operations.cpp            |   226 +++++++++++++++++++++++++++++++-------- 
   trunk/libs/filesystem/v3/test/msvc10/filesystem-v3.sln |    10 +                                       
   trunk/libs/filesystem/v3/test/operations_test.cpp      |    83 ++++++++++++--                          
   trunk/libs/filesystem/v3/test/operations_unit_test.cpp |    58 +++++++---                              
   trunk/libs/filesystem/v3/test/path_test.cpp            |     2                                         
   6 files changed, 422 insertions(+), 97 deletions(-)
Modified: trunk/boost/filesystem/v3/operations.hpp
==============================================================================
--- trunk/boost/filesystem/v3/operations.hpp	(original)
+++ trunk/boost/filesystem/v3/operations.hpp	2011-10-15 12:02:20 EDT (Sat, 15 Oct 2011)
@@ -55,9 +55,7 @@
   {
 
 //--------------------------------------------------------------------------------------//
-//                                                                                      //
-//                            support classes and enums                                 //
-//                                                                                      //
+//                                     file_type                                        //
 //--------------------------------------------------------------------------------------//
 
   enum file_type
@@ -82,27 +80,96 @@
     _detail_directory_symlink  // internal use only; never exposed to users
   };
 
+//--------------------------------------------------------------------------------------//
+//                                       perms                                          //
+//--------------------------------------------------------------------------------------//
+
+  enum perms
+  {
+    no_perms = 0,       // file_not_found is no_perms rather than perms_not_known
+
+    // POSIX equivalent macros given in comments.
+    // Values are from POSIX and are given in octal per the POSIX standard.
+
+    // permission bits
+    
+    owner_read = 0400,  // S_IRUSR, Read permission, owner
+    owner_write = 0200, // S_IWUSR, Write permission, owner
+    owner_exe = 0100,   // S_IXUSR, Execute/search permission, owner
+    owner_all = 0700,   // S_IRWXU, Read, write, execute/search by owner
+
+    group_read = 040,   // S_IRGRP, Read permission, group
+    group_write = 020,  // S_IWGRP, Write permission, group
+    group_exe = 010,    // S_IXGRP, Execute/search permission, group
+    group_all = 070,    // S_IRWXG, Read, write, execute/search by group
+
+    others_read = 04,   // S_IROTH, Read permission, others
+    others_write = 02,  // S_IWOTH, Write permission, others
+    others_exe = 01,    // S_IXOTH, Execute/search permission, others
+    others_all = 07,    // S_IRWXO, Read, write, execute/search by others
+
+    all_all = owner_all|group_all|others_all,  // 0777
+
+    // other POSIX bits
+
+    set_uid_on_exe = 04000, // S_ISUID, Set-user-ID on execution
+    set_gid_on_exe = 02000, // S_ISGID, Set-group-ID on execution
+    sticky_bit     = 01000, // S_ISVTX,
+                            // (POSIX XSI) On directories, restricted deletion flag 
+	                          // (V7) 'sticky bit': save swapped text even after use 
+                            // (SunOS) On non-directories: don't cache this file
+                            // (SVID-v4.2) On directories: restricted deletion flag
+                            // Also see http://en.wikipedia.org/wiki/Sticky_bit
+
+    perms_mask = all_all|set_uid_on_exe|set_gid_on_exe|sticky_bit,  // 07777
+
+    perms_not_known = 0xFFFF, // present when directory_entry cache not loaded
+
+    // options for permissions() function
+
+    add_perms = 0x1000,     // adds the given permission bits to the current bits
+    remove_perms = 0x2000,  // removes the given permission bits from the current bits;
+                            // choose add_perms or remove_perms, not both; if neither add_perms
+                            // nor remove_perms is given, replace the current bits with
+                            // the given bits.
+
+    symlink_perms = 0x4000  // on POSIX, don't resolve symlinks; implied on Windows
+  };
+
+  BOOST_BITMASK(perms);
+
+//--------------------------------------------------------------------------------------//
+//                                    file_status                                       //
+//--------------------------------------------------------------------------------------//
+
   class BOOST_FILESYSTEM_DECL file_status
   {
   public:
-    file_status() : m_value(status_error) {}
-    explicit file_status(file_type v) : m_value(v) {}
-
-    void type(file_type v)    { m_value = v; }
-    file_type type() const    { return m_value; }
+    file_status() : m_value(status_error), m_perms(perms_not_known) {}
+    explicit file_status(file_type v, perms prms = perms_not_known)
+      : m_value(v), m_perms(prms) {}
+
+    // observers
+    file_type  type() const                       { return m_value; }
+    perms      permissions() const                { return m_perms; } 
+
+    // modifiers
+    void       type(file_type v)                  { m_value = v; }
+    void       permissions(perms prms)            { m_perms = prms; }
 
-    bool operator==(const file_status& rhs) const { return type() == rhs.type(); }
+    bool operator==(const file_status& rhs) const { return type() == rhs.type() && 
+                                                    permissions() == rhs.permissions(); }
     bool operator!=(const file_status& rhs) const { return !(*this == rhs); }
 
   private:
-    // the internal representation is unspecified so that additional state
-    // information such as permissions can be added in the future; this
-    // implementation just uses file_type as the internal representation
-
-    file_type m_value;
+    file_type   m_value;
+    enum perms  m_perms;
   };
 
-  inline bool status_known(file_status f) { return f.type() != status_error; }
+  inline bool type_present(file_status f) { return f.type() != status_error; }
+  inline bool permissions_present(file_status f)
+                                          {return f.permissions() != perms_not_known;}
+  inline bool status_known(file_status f) { return type_present(f) && permissions_present(f); }
   inline bool exists(file_status f)       { return f.type() != status_error
                                                 && f.type() != file_not_found; }
   inline bool is_regular_file(file_status f){ return f.type() == regular_file; }
@@ -159,7 +226,7 @@
     bool create_directory(const path& p, system::error_code* ec=0);
     BOOST_FILESYSTEM_DECL
     void create_directory_symlink(const path& to, const path& from,
-                                   system::error_code* ec=0);
+                                  system::error_code* ec=0);
     BOOST_FILESYSTEM_DECL
     void create_hard_link(const path& to, const path& from, system::error_code* ec=0);
     BOOST_FILESYSTEM_DECL
@@ -178,7 +245,9 @@
     std::time_t last_write_time(const path& p, system::error_code* ec=0);
     BOOST_FILESYSTEM_DECL
     void last_write_time(const path& p, const std::time_t new_time,
-                     system::error_code* ec=0);
+                         system::error_code* ec=0);
+    BOOST_FILESYSTEM_DECL
+    void permissions(const path& p, perms prms, system::error_code* ec=0);
     BOOST_FILESYSTEM_DECL
     path read_symlink(const path& p, system::error_code* ec=0);
     BOOST_FILESYSTEM_DECL
@@ -280,7 +349,7 @@
   path canonical(const path& p, const path& base, system::error_code& ec)
                                        {return detail::canonical(p, base, &ec);}
 
- # ifndef BOOST_FILESYSTEM_NO_DEPRECATED
+# ifndef BOOST_FILESYSTEM_NO_DEPRECATED
   inline
   path complete(const path& p)
   {
@@ -410,6 +479,13 @@
   void last_write_time(const path& p, const std::time_t new_time, system::error_code& ec)
                                        {detail::last_write_time(p, new_time, &ec);}
   inline
+  void permissions(const path& p, perms prms)
+                                       {detail::permissions(p, prms);}
+  inline
+  void permissions(const path& p, perms prms, system::error_code& ec)
+                                       {detail::permissions(p, prms, &ec);}
+
+  inline
   path read_symlink(const path& p)     {return detail::read_symlink(p);}
 
   inline
@@ -1000,6 +1076,30 @@
 {
   namespace filesystem
   {
+    // permissions
+    using filesystem3::no_perms;
+    using filesystem3::owner_read;
+    using filesystem3::owner_write;
+    using filesystem3::owner_exe;
+    using filesystem3::owner_all;
+    using filesystem3::group_read;
+    using filesystem3::group_write;
+    using filesystem3::group_exe;
+    using filesystem3::group_all;
+    using filesystem3::others_read;
+    using filesystem3::others_write;
+    using filesystem3::others_exe;
+    using filesystem3::others_all;
+    using filesystem3::all_all;
+    using filesystem3::set_uid_on_exe;
+    using filesystem3::set_gid_on_exe;
+    using filesystem3::sticky_bit;
+    using filesystem3::perms_mask;
+    using filesystem3::perms_not_known;
+    using filesystem3::add_perms;
+    using filesystem3::remove_perms;
+    using filesystem3::symlink_perms;
+
     using filesystem3::absolute;
     using filesystem3::block_file;
     using filesystem3::canonical;
@@ -1034,6 +1134,9 @@
     using filesystem3::is_regular_file;
     using filesystem3::is_symlink;
     using filesystem3::last_write_time;
+    using filesystem3::permissions;
+    using filesystem3::permissions_present;
+    using filesystem3::perms;
     using filesystem3::read_symlink;
     using filesystem3::recursive_directory_iterator;
     using filesystem3::regular_file;
@@ -1053,6 +1156,7 @@
     using filesystem3::symlink_status;
     using filesystem3::system_complete;
     using filesystem3::temp_directory_path;
+    using filesystem3::type_present;
     using filesystem3::type_unknown;
     using filesystem3::unique_path;
 # ifndef BOOST_FILESYSTEM_NO_DEPRECATED
Modified: trunk/libs/filesystem/v3/src/operations.cpp
==============================================================================
--- trunk/libs/filesystem/v3/src/operations.cpp	(original)
+++ trunk/libs/filesystem/v3/src/operations.cpp	2011-10-15 12:02:20 EDT (Sat, 15 Oct 2011)
@@ -69,6 +69,7 @@
 namespace fs = boost::filesystem3;
 using boost::filesystem3::path;
 using boost::filesystem3::filesystem_error;
+using boost::filesystem3::perms;
 using boost::system::error_code;
 using boost::system::error_category;
 using boost::system::system_category;
@@ -107,6 +108,7 @@
       // See MinGW's windef.h
 #     define WINVER 0x501
 #   endif
+#   include <io.h>
 #   include <windows.h>
 #   include <winnt.h>
 #   if !defined(_WIN32_WINNT)
@@ -247,12 +249,6 @@
 namespace
 {
 
-# ifdef BOOST_POSIX_API
-  const char dot = '.';
-# else
-  const wchar_t dot = L'.';
-# endif
-
   fs::file_type query_file_type(const path& p, error_code* ec);
 
   boost::filesystem3::directory_iterator end_dir_itr;
@@ -414,6 +410,8 @@
 //                                                                                      //
 //--------------------------------------------------------------------------------------//
 
+  const char dot = '.';
+
   bool not_found_error(int errval)
   {
     return errno == ENOENT || errno == ENOTDIR;
@@ -490,6 +488,8 @@
 //                                                                                      //
 //--------------------------------------------------------------------------------------//
 
+  const wchar_t dot = L'.';
+
   bool not_found_error(int errval)
   {
     return errval == ERROR_FILE_NOT_FOUND
@@ -502,6 +502,19 @@
       || errval == ERROR_BAD_NETPATH;  // "//nosuch" on Win32
   }
 
+  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 (_stricmp(p.extension().string().c_str(), ".exe") == 0
+      || _stricmp(p.extension().string().c_str(), ".com") == 0
+      || _stricmp(p.extension().string().c_str(), ".bat") == 0
+      || _stricmp(p.extension().string().c_str(), ".cmd") == 0)
+      prms |= fs::owner_exe | fs::group_exe | fs::others_exe;
+    return prms;
+  }
+
   // these constants come from inspecting some Microsoft sample code
   std::time_t to_time_t(const FILETIME & ft)
   {
@@ -590,7 +603,7 @@
 
     if (not_found_error(errval))
     {
-      return fs::file_status(fs::file_not_found);
+      return fs::file_status(fs::file_not_found, fs::no_perms);
     }
     else if ((errval == ERROR_SHARING_VIOLATION))
     {
@@ -755,6 +768,21 @@
 #   endif
   }
 
+# ifdef BOOST_POSIX_API
+    const perms active_bits(all_all | set_uid_on_exe | set_gid_on_exe | sticky_bit);
+    inline mode_t mode_cast(perms prms) { return prms & active_bits; }
+# else
+    inline int mode_cast(perms prms)
+    { 
+      //  Windows _wchmod() can only make a file read-only and there is only one
+      //  such attribute bit for the file. Files are always readable. Get over it.
+      return (prms & (owner_write|group_write|others_write)
+                ? _S_IREAD | _S_IWRITE
+                : _S_IREAD
+             );
+    }
+# endif
+
   BOOST_FILESYSTEM_DECL
   path canonical(const path& p, const path& base, system::error_code* ec)
   {
@@ -1330,6 +1358,62 @@
   }
 
   BOOST_FILESYSTEM_DECL
+  void permissions(const path& p, perms prms, system::error_code* ec)
+  {
+    BOOST_ASSERT_MSG(!((prms & add_perms) && (prms & remove_perms)),
+      "add_perms and remove_perms are mutually exclusive");
+
+    if ((prms & add_perms) && (prms & remove_perms))  // precondition failed
+      return;
+
+    error_code local_ec;
+    file_status current_status((prms & symlink_perms)
+                               ? fs::symlink_status(p, local_ec)
+                               : fs::status(p, local_ec));
+    if (local_ec)
+    {
+      if (ec == 0)
+      BOOST_FILESYSTEM_THROW(filesystem_error(
+          "boost::filesystem::permissions", p, local_ec));
+      else
+        *ec = local_ec;
+      return;
+    }
+
+    if (prms & add_perms)
+      prms |= current_status.permissions();
+    else if (prms & remove_perms)
+    {
+#   ifdef BOOST_WINDOWS_API
+      if (prms & (owner_write|group_write|others_write))
+        prms |= owner_write|group_write|others_write;
+#   endif
+      prms = current_status.permissions() & ~prms;
+    }
+
+# ifdef BOOST_POSIX_API
+    // Mac OS X Lion and some other platforms don't support fchmodat()  
+#   if defined(AT_FDCWD) && defined(AT_SYMLINK_NOFOLLOW)
+      if (::fchmodat(AT_FDCWD, p.c_str(), mode_cast(prms),
+           !(prms & symlink_perms) ? 0 : AT_SYMLINK_NOFOLLOW))
+#   else  // fallback if fchmodat() not supported
+      if (::chmod(p.c_str(), mode_cast(prms)))
+#   endif
+# else
+    if (::_wchmod(p.c_str(), mode_cast(prms)))  // if error
+# endif
+    {
+      if (ec == 0)
+      BOOST_FILESYSTEM_THROW(filesystem_error(
+          "boost::filesystem::permissions", p,
+          error_code(errno, system::generic_category())));
+      else
+        ec->assign(errno, system::generic_category());
+    }
+
+  }
+
+  BOOST_FILESYSTEM_DECL
   path read_symlink(const path& p, system::error_code* ec)
   {
     path symlink_path;
@@ -1492,7 +1576,7 @@
 
       if (not_found_error(errno))
       {
-        return fs::file_status(fs::file_not_found);
+        return fs::file_status(fs::file_not_found, fs::no_perms);
       }
       if (ec == 0)
         BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status",
@@ -1501,17 +1585,23 @@
     }
     if (ec != 0) ec->clear();;
     if (S_ISDIR(path_stat.st_mode))
-      return fs::file_status(fs::directory_file);
+      return fs::file_status(fs::directory_file,
+        static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
     if (S_ISREG(path_stat.st_mode))
-      return fs::file_status(fs::regular_file);
+      return fs::file_status(fs::regular_file,
+        static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
     if (S_ISBLK(path_stat.st_mode))
-      return fs::file_status(fs::block_file);
+      return fs::file_status(fs::block_file,
+        static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
     if (S_ISCHR(path_stat.st_mode))
-      return fs::file_status(fs::character_file);
+      return fs::file_status(fs::character_file,
+        static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
     if (S_ISFIFO(path_stat.st_mode))
-      return fs::file_status(fs::fifo_file);
+      return fs::file_status(fs::fifo_file,
+        static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
     if (S_ISSOCK(path_stat.st_mode))
-      return fs::file_status(fs::socket_file);
+      return fs::file_status(fs::socket_file,
+        static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
     return fs::file_status(fs::type_unknown);
 
 #   else  // Windows
@@ -1522,7 +1612,9 @@
       return process_status_failure(p, ec);
     }
 
-    //  reparse point handling
+    //  reparse point handling;
+    //    since GetFileAttributesW does not resolve symlinks, try to open a file
+    //    handle to discover if the file exists
     if (attr & FILE_ATTRIBUTE_REPARSE_POINT)
     {
       handle_wrapper h(
@@ -1540,13 +1632,13 @@
       }
 
       if (!is_reparse_point_a_symlink(p))
-        return file_status(reparse_file);
+        return file_status(reparse_file, make_permissions(p, attr));
     }
 
     if (ec != 0) ec->clear();
     return (attr & FILE_ATTRIBUTE_DIRECTORY)
-      ? file_status(directory_file)
-      : file_status(regular_file);
+      ? file_status(directory_file, make_permissions(p, attr))
+      : file_status(regular_file, make_permissions(p, attr));
 
 #   endif
   }
@@ -1564,7 +1656,7 @@
 
       if (errno == ENOENT || errno == ENOTDIR) // these are not errors
       {
-        return fs::file_status(fs::file_not_found);
+        return fs::file_status(fs::file_not_found, fs::no_perms);
       }
       if (ec == 0)
         BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status",
@@ -1573,19 +1665,26 @@
     }
     if (ec != 0) ec->clear();
     if (S_ISREG(path_stat.st_mode))
-      return fs::file_status(fs::regular_file);
+      return fs::file_status(fs::regular_file,
+        static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
     if (S_ISDIR(path_stat.st_mode))
-      return fs::file_status(fs::directory_file);
+      return fs::file_status(fs::directory_file,
+        static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
     if (S_ISLNK(path_stat.st_mode))
-      return fs::file_status(fs::symlink_file);
+      return fs::file_status(fs::symlink_file,
+        static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
     if (S_ISBLK(path_stat.st_mode))
-      return fs::file_status(fs::block_file);
+      return fs::file_status(fs::block_file,
+        static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
     if (S_ISCHR(path_stat.st_mode))
-      return fs::file_status(fs::character_file);
+      return fs::file_status(fs::character_file,
+        static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
     if (S_ISFIFO(path_stat.st_mode))
-      return fs::file_status(fs::fifo_file);
+      return fs::file_status(fs::fifo_file,
+        static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
     if (S_ISSOCK(path_stat.st_mode))
-      return fs::file_status(fs::socket_file);
+      return fs::file_status(fs::socket_file,
+        static_cast<perms>(path_stat.st_mode) & fs::perms_mask);
     return fs::file_status(fs::type_unknown);
 
 #   else  // Windows
@@ -1600,12 +1699,12 @@
 
     if (attr & FILE_ATTRIBUTE_REPARSE_POINT)
       return is_reparse_point_a_symlink(p)
-             ? file_status(symlink_file)
-             : file_status(reparse_file);
+             ? file_status(symlink_file, make_permissions(p, attr))
+             : file_status(reparse_file, make_permissions(p, attr));
 
     return (attr & FILE_ATTRIBUTE_DIRECTORY)
-      ? file_status(directory_file)
-      : file_status(regular_file);
+      ? file_status(directory_file, make_permissions(p, attr))
+      : file_status(regular_file, make_permissions(p, attr));
 
 #   endif
   }
@@ -1838,8 +1937,8 @@
     dirent * entry(static_cast<dirent *>(buffer));
     dirent * result;
     int return_code;
-    if ((return_code = readdir_r_simulator(static_cast<DIR*>(handle),
-      entry, &result))!= 0)return error_code(errno, system_category());
+    if ((return_code = readdir_r_simulator(static_cast<DIR*>(handle), entry, &result))!= 0)
+      return error_code(errno, system_category());
     if (result == 0)
       return fs::detail::dir_itr_close(handle, buffer);
     target = entry->d_name;
@@ -1886,7 +1985,7 @@
     if ((handle = ::FindFirstFileW(dirpath.c_str(), &data))
       == INVALID_HANDLE_VALUE)
     { 
-      handle = 0;
+      handle = 0;  // signal eof
       return error_code( (::GetLastError() == ERROR_FILE_NOT_FOUND
                        // Windows Mobile returns ERROR_NO_MORE_FILES; see ticket #3551                                           
                        || ::GetLastError() == ERROR_NO_MORE_FILES) 
@@ -1894,12 +1993,28 @@
     }
     target = data.cFileName;
     if (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
-      // reparse points are complex, so don't try to handle them here
-      { sf.type(fs::status_error); symlink_sf.type(fs::status_error); }
-    else if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-      { sf.type(fs::directory_file); symlink_sf.type(fs::directory_file); }
+    // reparse points are complex, so don't try to handle them here; instead just mark
+    // them as status_error which causes directory_entry caching to call status()
+    // and symlink_status() which do handle reparse points fully
+    {
+      sf.type(fs::status_error);
+      symlink_sf.type(fs::status_error);
+    }
     else
-      { sf.type(fs::regular_file); symlink_sf.type(fs::regular_file); }
+    {
+      if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+      {
+        sf.type(fs::directory_file);
+        symlink_sf.type(fs::directory_file);
+      }
+      else
+      {
+        sf.type(fs::regular_file);
+        symlink_sf.type(fs::regular_file);
+      }
+      sf.permissions(make_permissions(data.cFileName, data.dwFileAttributes));
+      symlink_sf.permissions(sf.permissions());
+    }
     return error_code();
   }
 
@@ -1915,12 +2030,28 @@
     }
     target = data.cFileName;
     if (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
-      // reparse points are complex, so don't try to handle them here
-      { sf.type(fs::status_error); symlink_sf.type(fs::status_error); }
-    else if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-      { sf.type(fs::directory_file); symlink_sf.type(fs::directory_file); }
+    // reparse points are complex, so don't try to handle them here; instead just mark
+    // them as status_error which causes directory_entry caching to call status()
+    // and symlink_status() which do handle reparse points fully
+    {
+      sf.type(fs::status_error);
+      symlink_sf.type(fs::status_error);
+    }
     else
-      { sf.type(fs::regular_file); symlink_sf.type(fs::regular_file); }
+    {
+      if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+      {
+        sf.type(fs::directory_file);
+        symlink_sf.type(fs::directory_file);
+      }
+      else
+      {
+        sf.type(fs::regular_file);
+        symlink_sf.type(fs::regular_file);
+      }
+      sf.permissions(make_permissions(data.cFileName, data.dwFileAttributes));
+      symlink_sf.permissions(sf.permissions());
+    }
     return error_code();
   }
 #endif
@@ -1975,7 +2106,8 @@
     const path& p, system::error_code* ec)    
   {
     if (error(p.empty(), not_found_error_code, p, ec,
-       "boost::filesystem::directory_iterator::construct"))return;
+              "boost::filesystem::directory_iterator::construct"))
+      return;
 
     path::string_type filename;
     file_status file_stat, symlink_file_stat;
@@ -1993,11 +2125,11 @@
       return;
     }
     
-    if (it.m_imp->handle == 0)it.m_imp.reset(); // eof, so make end iterator
+    if (it.m_imp->handle == 0)
+      it.m_imp.reset(); // eof, so make end iterator
     else // not eof
     {
-      it.m_imp->dir_entry.assign(p / filename,
-        file_stat, symlink_file_stat);
+      it.m_imp->dir_entry.assign(p / filename, file_stat, symlink_file_stat);
       if (filename[0] == dot // dot or dot-dot
         && (filename.size()== 1
           || (filename[1] == dot
Modified: trunk/libs/filesystem/v3/test/msvc10/filesystem-v3.sln
==============================================================================
--- trunk/libs/filesystem/v3/test/msvc10/filesystem-v3.sln	(original)
+++ trunk/libs/filesystem/v3/test/msvc10/filesystem-v3.sln	2011-10-15 12:02:20 EDT (Sat, 15 Oct 2011)
@@ -73,6 +73,12 @@
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "locale_info", "locale_info\locale_info.vcxproj", "{3667C35E-78D5-43D4-AAC2-349145E4341D}"
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ticket_5850", "ticket_5850\ticket_5850.vcxproj", "{B1FA4137-7B08-4113-9EC0-F3BAFEFBE2B7}"
+	ProjectSection(ProjectDependencies) = postProject
+		{F94CCADD-A90B-480C-A304-C19D015D36B1} = {F94CCADD-A90B-480C-A304-C19D015D36B1}
+		{FFD738F7-96F0-445C-81EA-551665EF53D1} = {FFD738F7-96F0-445C-81EA-551665EF53D1}
+	EndProjectSection
+EndProject
 Global
         GlobalSection(SolutionConfigurationPlatforms) = preSolution
                 Debug|Win32 = Debug|Win32
@@ -167,6 +173,10 @@
                 {3667C35E-78D5-43D4-AAC2-349145E4341D}.Debug|Win32.Build.0 = Debug|Win32
                 {3667C35E-78D5-43D4-AAC2-349145E4341D}.Release|Win32.ActiveCfg = Release|Win32
                 {3667C35E-78D5-43D4-AAC2-349145E4341D}.Release|Win32.Build.0 = Release|Win32
+		{B1FA4137-7B08-4113-9EC0-F3BAFEFBE2B7}.Debug|Win32.ActiveCfg = Debug|Win32
+		{B1FA4137-7B08-4113-9EC0-F3BAFEFBE2B7}.Debug|Win32.Build.0 = Debug|Win32
+		{B1FA4137-7B08-4113-9EC0-F3BAFEFBE2B7}.Release|Win32.ActiveCfg = Release|Win32
+		{B1FA4137-7B08-4113-9EC0-F3BAFEFBE2B7}.Release|Win32.Build.0 = Release|Win32
         EndGlobalSection
         GlobalSection(SolutionProperties) = preSolution
                 HideSolutionNode = FALSE
Modified: trunk/libs/filesystem/v3/test/operations_test.cpp
==============================================================================
--- trunk/libs/filesystem/v3/test/operations_test.cpp	(original)
+++ trunk/libs/filesystem/v3/test/operations_test.cpp	2011-10-15 12:02:20 EDT (Sat, 15 Oct 2011)
@@ -95,8 +95,10 @@
 {
   typedef int errno_t;
   std::string platform(BOOST_PLATFORM);
-  bool report_throws;
+  bool report_throws = false;
   bool cleanup = true;
+  bool skip_long_windows_tests = false;
+
   fs::directory_iterator end_itr;
   fs::path dir;
   fs::path d1;
@@ -113,7 +115,7 @@
 
   const char* temp_dir_name = "v3_operations_test";
 
-  void create_file(const fs::path & ph, const std::string & contents)
+  void create_file(const fs::path & ph, const std::string & contents = std::string())
   {
     std::ofstream f(ph.BOOST_FILESYSTEM_C_STR);
     if (!f)
@@ -800,6 +802,45 @@
     fs::create_symlink("doesnotexist", "", ec);
     BOOST_TEST(ec);
   }
+
+  //  permissions_tests  ---------------------------------------------------------------//
+
+  void permissions_tests()
+  {
+    cout << "permissions_tests..." << endl;
+
+    fs::path p(dir / "permissions.txt");
+    create_file(p);
+
+    if (platform == "POSIX")
+    {
+      cout << "  fs::status(p).permissions() " << std::oct << fs::status(p).permissions()
+        << std::dec << endl;
+      BOOST_TEST(fs::status(p).permissions() == 0644);
+      fs::permissions(p, fs::owner_all);
+      BOOST_TEST(fs::status(p).permissions() == fs::owner_all);
+
+      fs::permissions(p, fs::add_perms | fs::group_all);
+      BOOST_TEST(fs::status(p).permissions() == (fs::owner_all | fs::group_all));
+
+      fs::permissions(p, fs::remove_perms | fs::group_all);
+      BOOST_TEST(fs::status(p).permissions() == fs::owner_all);
+
+      // some POSIX platforms cache permissions during directory iteration, some don't
+      // so test that iteration finds the correct permissions
+      for (fs::directory_iterator itr(dir); itr != fs::directory_iterator(); ++itr)
+        if (itr->path().filename() == fs::path("permissions.txt"))
+          BOOST_TEST(itr->status().permissions() == fs::owner_all);
+    }
+    else // Windows
+    {
+      BOOST_TEST(fs::status(p).permissions() == 0666);
+      fs::permissions(p, fs::remove_perms | fs::group_write);
+      BOOST_TEST(fs::status(p).permissions() == 0444);
+      fs::permissions(p, fs::add_perms | fs::group_write);
+      BOOST_TEST(fs::status(p).permissions() == 0666);
+    }
+  }
   
   //  rename_tests  --------------------------------------------------------------------//
 
@@ -917,6 +958,8 @@
     BOOST_TEST(!fs::is_regular_file(ng));
     BOOST_TEST(!fs::is_symlink(ng));
     fs::file_status stat(fs::status(ng));
+    BOOST_TEST(fs::type_present(stat));
+    BOOST_TEST(fs::permissions_present(stat));
     BOOST_TEST(fs::status_known(stat));
     BOOST_TEST(!fs::exists(stat));
     BOOST_TEST(!fs::is_directory(stat));
@@ -924,6 +967,8 @@
     BOOST_TEST(!fs::is_other(stat));
     BOOST_TEST(!fs::is_symlink(stat));
     stat = fs::status("");
+    BOOST_TEST(fs::type_present(stat));
+    BOOST_TEST(fs::permissions_present(stat));
     BOOST_TEST(fs::status_known(stat));
     BOOST_TEST(!fs::exists(stat));
     BOOST_TEST(!fs::is_directory(stat));
@@ -1059,7 +1104,7 @@
     fs::file_status s = fs::status(p);
     BOOST_TEST(!fs::exists(s));
     BOOST_TEST_EQ(s.type(), fs::file_not_found);
-    BOOST_TEST(fs::status_known(s));
+    BOOST_TEST(fs::type_present(s));
     BOOST_TEST(!fs::is_regular_file(s));
     BOOST_TEST(!fs::is_directory(s));
     BOOST_TEST(!fs::is_symlink(s));
@@ -1093,7 +1138,7 @@
 
     BOOST_TEST(!fs::exists(s));
     BOOST_TEST_EQ(s.type(), fs::file_not_found);
-    BOOST_TEST(fs::status_known(s));
+    BOOST_TEST(fs::type_present(s));
     BOOST_TEST(!fs::is_regular_file(s));
     BOOST_TEST(!fs::is_directory(s));
     BOOST_TEST(!fs::is_symlink(s));
@@ -1529,12 +1574,17 @@
     // Windows only tests
     if (platform == "Windows")
     {
-      cout << "Window specific tests..."
-        "\n (may take several seconds)" << endl;
+      cout << "Window specific tests..." << endl;
+      if (!skip_long_windows_tests)
+      {
+        cout << "  (may take several seconds)"<< endl;
+
+        BOOST_TEST(!fs::exists(fs::path("//share-not")));
+        BOOST_TEST(!fs::exists(fs::path("//share-not/")));
+        BOOST_TEST(!fs::exists(fs::path("//share-not/foo")));
+      }
+      cout << endl;
 
-      BOOST_TEST(!fs::exists(fs::path("//share-not")));
-      BOOST_TEST(!fs::exists(fs::path("//share-not/")));
-      BOOST_TEST(!fs::exists(fs::path("//share-not/foo")));
       BOOST_TEST(!fs::exists("tools/jam/src/:sys:stat.h")); // !exists() if ERROR_INVALID_NAME
       BOOST_TEST(!fs::exists(":sys:stat.h")); // !exists() if ERROR_INVALID_PARAMETER
       BOOST_TEST(dir.string().size() > 1
@@ -1814,7 +1864,6 @@
 
 int cpp_main(int argc, char* argv[])
 {
-
 // document state of critical macros
 #ifdef BOOST_POSIX_API
   cout << "BOOST_POSIX_API is defined\n";
@@ -1823,8 +1872,15 @@
   cout << "BOOST_WINDOWS_API is defined\n";
 #endif
 
-  if (argc > 1 && *argv[1]=='-' && *(argv[1]+1)=='t') report_throws = true;
-  if (argc > 1 && *argv[1]=='-' && *(argv[1]+1)=='x') cleanup = false;
+  for (; argc > 1; --argc, ++argv)
+  {
+    if (*argv[1]=='-' && *(argv[1]+1)=='t')
+      report_throws = true;
+    else if (*argv[1]=='-' && *(argv[1]+1)=='x')
+      cleanup = false;
+    else if (*argv[1]=='-' && *(argv[1]+1)=='w')
+      skip_long_windows_tests = true;
+  }
 
   // The choice of platform to test is make at runtime rather than compile-time
   // so that compile errors for all platforms will be detected even though
@@ -1859,6 +1915,7 @@
   initial_tests();
   predicate_and_status_tests();
   exception_tests();
+  platform_specific_tests();
   create_directory_tests();
   current_directory_tests();
   space_tests();
@@ -1894,6 +1951,7 @@
   resize_file_tests();
   absolute_tests();
   canonical_basic_tests();
+  permissions_tests();
   copy_file_tests(f1, d1);
   if (create_symlink_ok)  // only if symlinks supported
   {
@@ -1912,7 +1970,6 @@
   write_time_tests(dir);
   
   temp_directory_path_tests();
-  platform_specific_tests();
   
   cout << "testing complete" << endl;
 
Modified: trunk/libs/filesystem/v3/test/operations_unit_test.cpp
==============================================================================
--- trunk/libs/filesystem/v3/test/operations_unit_test.cpp	(original)
+++ trunk/libs/filesystem/v3/test/operations_unit_test.cpp	2011-10-15 12:02:20 EDT (Sat, 15 Oct 2011)
@@ -40,6 +40,7 @@
 using namespace boost::filesystem;
 using namespace boost::system;
 using std::cout;
+using std::endl;
 using std::string;
 
 #define CHECK(x) check(x, __FILE__, __LINE__)
@@ -53,21 +54,40 @@
 
     ++::boost::detail::test_errors();
 
-    std::cout << file << '(' << line << "): test failed\n";
+    cout << file << '(' << line << "): test failed\n";
+  }
+
+  //  file_status_test  ----------------------------------------------------------------//
+
+  void file_status_test()
+  {
+    cout << "file_status test..." << endl;
+
+    file_status s = status(".");
+    int v = s.permissions();
+    cout << "  status(\".\") permissions are "
+      << std::oct << (v & 0777) << std::dec << endl; 
+    CHECK((v & 0400) == 0400);
+
+    s = symlink_status(".");
+    v = s.permissions();
+    cout << "  symlink_status(\".\") permissions are "
+      << std::oct << (v & 0777) << std::dec << endl; 
+    CHECK((v & 0400) == 0400);
   }
 
   //  query_test  ----------------------------------------------------------------------//
 
   void query_test()
   {
-    std::cout << "query test..." << std::endl;
+    cout << "query test..." << endl;
 
     error_code ec;
 
     CHECK(file_size("no-such-file", ec) == static_cast<boost::uintmax_t>(-1));
     CHECK(ec == errc::no_such_file_or_directory);
 
-    CHECK(status("no-such-file") == file_status(file_not_found));
+    CHECK(status("no-such-file") == file_status(file_not_found, no_perms));
 
     CHECK(exists("/"));
     CHECK(is_directory("/"));
@@ -76,8 +96,8 @@
     exists("/", ec);
     if (ec)
     {
-      std::cout << "exists(\"/\", ec) resulted in non-zero ec.value()" << std::endl;
-      std::cout << "ec value: " << ec.value() << ", message: "<< ec.message() << std::endl;
+      cout << "exists(\"/\", ec) resulted in non-zero ec.value()" << endl;
+      cout << "ec value: " << ec.value() << ", message: "<< ec.message() << endl;
     }
     CHECK(!ec);
 
@@ -92,7 +112,7 @@
 
   void directory_iterator_test()
   {
-    std::cout << "directory_iterator_test..." << std::endl;
+    cout << "directory_iterator_test..." << endl;
 
     directory_iterator end;
 
@@ -123,14 +143,14 @@
 //      cout << "  " << it->path().string() << "\n";
     }
 
-    std::cout << "directory_iterator_test complete" << std::endl;
+    cout << "directory_iterator_test complete" << endl;
   }
 
   //  operations_test  -------------------------------------------------------//
 
   void operations_test()
   {
-    std::cout << "operations test..." << std::endl;
+    cout << "operations test..." << endl;
 
     error_code ec;
 
@@ -155,13 +175,14 @@
 
   void directory_entry_test()
   {
-    std::cout << "directory_entry test..." << std::endl;
+    cout << "directory_entry test..." << endl;
 
-    directory_entry de("foo.bar", file_status(regular_file), file_status(directory_file));
+    directory_entry de("foo.bar",
+      file_status(regular_file, owner_all), file_status(directory_file, group_all));
 
     CHECK(de.path() == "foo.bar");
-    CHECK(de.status() == file_status(regular_file));
-    CHECK(de.symlink_status() == file_status(directory_file));
+    CHECK(de.status() == file_status(regular_file, owner_all));
+    CHECK(de.symlink_status() == file_status(directory_file, group_all));
     CHECK(de < directory_entry("goo.bar"));
     CHECK(de == directory_entry("foo.bar"));
     CHECK(de != directory_entry("goo.bar"));
@@ -173,7 +194,7 @@
 
   void directory_entry_overload_test()
   {
-    std::cout << "directory_entry overload test..." << std::endl;
+    cout << "directory_entry overload test..." << endl;
 
     directory_iterator it(".");
     path p(*it);
@@ -183,7 +204,7 @@
 
   void error_handling_test()
   {
-    std::cout << "error handling test..." << std::endl;
+    cout << "error handling test..." << endl;
 
     bool threw(false);
     try
@@ -198,7 +219,7 @@
     }
     catch (...)
     {
-      cout << "\nunexpected exception type caught" << std::endl;
+      cout << "\nunexpected exception type caught" << endl;
     }
 
     CHECK(threw);
@@ -227,8 +248,9 @@
   cout << "BOOST_FILESYSTEM_DECL" << BOOST_STRINGIZE(=BOOST_FILESYSTEM_DECL) << "\n";
   cout << "BOOST_SYMBOL_VISIBLE" << BOOST_STRINGIZE(=BOOST_SYMBOL_VISIBLE) << "\n";
   
-  cout << "current_path() is " << current_path().string() << std::endl;
+  cout << "current_path() is " << current_path().string() << endl;
 
+  file_status_test();
   query_test();
   directory_iterator_test();
   operations_test();
@@ -236,8 +258,8 @@
   directory_entry_overload_test();
   error_handling_test();
 
-  std::cout << unique_path() << std::endl;
-  std::cout << unique_path("foo-%%%%%-%%%%%-bar") << std::endl;
+  cout << unique_path() << endl;
+  cout << unique_path("foo-%%%%%-%%%%%-bar") << endl;
   
   return ::boost::report_errors();
 }
Modified: trunk/libs/filesystem/v3/test/path_test.cpp
==============================================================================
--- trunk/libs/filesystem/v3/test/path_test.cpp	(original)
+++ trunk/libs/filesystem/v3/test/path_test.cpp	2011-10-15 12:02:20 EDT (Sat, 15 Oct 2011)
@@ -1603,7 +1603,7 @@
     BOOST_TEST(!fs::portable_file_name(std::string("foo.")));
   }
   
-  //  replace_extension_tests  ---------------------------------------------------//
+  //  replace_extension_tests  ---------------------------------------------------------//
 
   void replace_extension_tests()
   {