$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r74851 - in branches/release: boost boost/filesystem boost/filesystem/v3 libs/filesystem libs/filesystem/v3/doc libs/filesystem/v3/src libs/filesystem/v3/test libs/filesystem/v3/test/msvc10
From: bdawes_at_[hidden]
Date: 2011-10-09 09:54:10
Author: bemandawes
Date: 2011-10-09 09:54:09 EDT (Sun, 09 Oct 2011)
New Revision: 74851
URL: http://svn.boost.org/trac/boost/changeset/74851
Log:
Merge trunk, including hash and canonical support
Added:
   branches/release/libs/filesystem/v3/test/locale_info.cpp
      - copied unchanged from r74850, /trunk/libs/filesystem/v3/test/locale_info.cpp
Properties modified: 
   branches/release/boost/filesystem/   (props changed)
   branches/release/boost/filesystem.hpp   (props changed)
   branches/release/libs/filesystem/   (props changed)
Text files modified: 
   branches/release/boost/filesystem/v3/operations.hpp               |    15 ++++                                    
   branches/release/boost/filesystem/v3/path.hpp                     |    18 ++++                                    
   branches/release/libs/filesystem/v3/doc/reference.html            |   122 ++++++++++++++++++++++++++--------      
   branches/release/libs/filesystem/v3/doc/release_history.html      |    22 ++++++                                  
   branches/release/libs/filesystem/v3/src/operations.cpp            |    84 ++++++++++++++++++++++++                
   branches/release/libs/filesystem/v3/test/msvc10/filesystem-v3.sln |     2                                         
   branches/release/libs/filesystem/v3/test/operations_test.cpp      |   138 ++++++++++++++++++++++++++++----------- 
   branches/release/libs/filesystem/v3/test/path_unit_test.cpp       |     7 ++                                      
   8 files changed, 333 insertions(+), 75 deletions(-)
Modified: branches/release/boost/filesystem/v3/operations.hpp
==============================================================================
--- branches/release/boost/filesystem/v3/operations.hpp	(original)
+++ branches/release/boost/filesystem/v3/operations.hpp	2011-10-09 09:54:09 EDT (Sun, 09 Oct 2011)
@@ -142,6 +142,8 @@
     BOOST_FILESYSTEM_DECL
     path initial_path(system::error_code* ec=0);
     BOOST_FILESYSTEM_DECL
+    path canonical(const path& p, const path& base, system::error_code* ec=0);
+    BOOST_FILESYSTEM_DECL
     void copy(const path& from, const path& to, system::error_code* ec=0);
     BOOST_FILESYSTEM_DECL
     void copy_directory(const path& from, const path& to, system::error_code* ec=0);
@@ -268,7 +270,17 @@
   path absolute(const path& p, const path& base=current_path());
   //  If base.is_absolute(), throws nothing. Thus no need for ec argument
 
-# ifndef BOOST_FILESYSTEM_NO_DEPRECATED
+  inline
+  path canonical(const path& p, const path& base=current_path())
+                                       {return detail::canonical(p, base);}
+  inline
+  path canonical(const path& p, system::error_code& ec)
+                                       {return detail::canonical(p, current_path(), &ec);}
+  inline
+  path canonical(const path& p, const path& base, system::error_code& ec)
+                                       {return detail::canonical(p, base, &ec);}
+
+ # ifndef BOOST_FILESYSTEM_NO_DEPRECATED
   inline
   path complete(const path& p)
   {
@@ -990,6 +1002,7 @@
   {
     using filesystem3::absolute;
     using filesystem3::block_file;
+    using filesystem3::canonical;
     using filesystem3::character_file;
 //    using filesystem3::copy;
     using filesystem3::copy_file;
Modified: branches/release/boost/filesystem/v3/path.hpp
==============================================================================
--- branches/release/boost/filesystem/v3/path.hpp	(original)
+++ branches/release/boost/filesystem/v3/path.hpp	2011-10-09 09:54:09 EDT (Sun, 09 Oct 2011)
@@ -29,6 +29,7 @@
 #include <boost/shared_ptr.hpp>
 #include <boost/io/detail/quoted_manip.hpp>
 #include <boost/static_assert.hpp>
+#include <boost/functional/hash_fwd.hpp>
 #include <string>
 #include <iterator>
 #include <cstring>
@@ -559,18 +560,31 @@
     const path::value_type* l(lhs.c_str());
     while ((*l == *rhs || (*l == L'\\' && *rhs == L'/') || (*l == L'/' && *rhs == L'\\'))
       && *l) { ++l; ++rhs; }
-    return *l == *rhs || (*l == L'\\' && *rhs == L'/') || (*l == L'/' && *rhs == L'\\');  
+    return *l == *rhs;
   }
   inline bool operator==(const path& lhs, const path& rhs)              { return lhs == rhs.c_str(); }
   inline bool operator==(const path& lhs, const path::string_type& rhs) { return lhs == rhs.c_str(); }
   inline bool operator==(const path::string_type& lhs, const path& rhs) { return rhs == lhs.c_str(); }
   inline bool operator==(const path::value_type* lhs, const path& rhs)  { return rhs == lhs; }
+
+  inline std::size_t hash_value(const path& x)
+  {
+    std::size_t seed = 0;
+    for(const path::value_type* it = x.c_str(); *it; ++it)
+      hash_combine(seed, *it == '/' ? L'\\' : *it);
+    return seed;
+  }
 # else   // BOOST_POSIX_API
   inline bool operator==(const path& lhs, const path& rhs)              { return lhs.native() == rhs.native(); }
   inline bool operator==(const path& lhs, const path::string_type& rhs) { return lhs.native() == rhs; }
   inline bool operator==(const path& lhs, const path::value_type* rhs)  { return lhs.native() == rhs; }
   inline bool operator==(const path::string_type& lhs, const path& rhs) { return lhs == rhs.native(); }
   inline bool operator==(const path::value_type* lhs, const path& rhs)  { return lhs == rhs.native(); }
+
+  inline std::size_t hash_value(const path& x)
+  {
+    return hash_range(x.native().begin(), x.native().end());
+  }
 # endif
 
   inline bool operator!=(const path& lhs, const path& rhs)              { return !(lhs == rhs); }
@@ -592,7 +606,7 @@
   operator<<(std::basic_ostream<Char, Traits>& os, const path& p)
   {
     return os
-      << boost::io::quoted(p.string<std::basic_string<Char> >(), static_cast<Char>('&'));
+      << boost::io::quoted(p.template string<std::basic_string<Char> >(), static_cast<Char>('&'));
   }
   
   template <class Char, class Traits>
Modified: branches/release/libs/filesystem/v3/doc/reference.html
==============================================================================
--- branches/release/libs/filesystem/v3/doc/reference.html	(original)
+++ branches/release/libs/filesystem/v3/doc/reference.html	2011-10-09 09:54:09 EDT (Sun, 09 Oct 2011)
@@ -8,6 +8,15 @@
 <title>Filesystem V3 Reference
 </title>
 <link rel="stylesheet" type="text/css" href="../../../../doc/src/minimal.css">
+<style type="text/css">
+ pre {background-color:#D7EEFF}
+ body
+ { 
+   font-family: sans-serif;
+   max-width : 8.5in;
+   margin: 1em;
+ }
+</style>
 </head>
 
 <body>
@@ -50,7 +59,7 @@
     <a href="#Definitions">Definitions</a><br>
     <a href="#Conformance">Conformance</a><br>
     <a href="#Header-filesystem-synopsis">
-    Header <filesystem> synopsis</a><br>
+    Header <boost/filesystem.hpp> synopsis</a><br>
     <a href="#Error-reporting">Error reporting</a><br>
     <a href="#class-path">Class path</a><br>
         path constructors<br>
@@ -89,6 +98,7 @@
     <a href="#Operational-functions">
     Operational functions</a><br>
      absolute<br>
+     canonical<br>
      copy<br>
      copy_directory<br>
      copy_file<br>
@@ -158,11 +168,13 @@
   \</code>,<code> /</code>, and<code> |</code> <i>--end note]</i></p>
 </blockquote>
 <p><b><i><a name="Path">Path</a>:</i></b> A sequence of elements that identify 
-a location within a filesystem. The elements are the <i>root-name<sub>opt</sub></i>, <i>
+the location of a file within a filesystem. The elements are the <i>root-name<sub>opt</sub></i>, <i>
 root-directory<sub>opt</sub></i>, and an optional sequence of filenames. [<i>Note:</i> 
 A pathname is the concrete representation of a path. <i>--end note</i>]</p>
-<p><b><i><a name="Absolute-path">Absolute path</a>:</i></b> A path that uniquely 
-identifies a file. The format is implementation defined. </p>
+<p><b><i><a name="Absolute-path">Absolute path</a>:</i></b> A path that 
+unambiguously 
+identifies the location of a file within a filesystem without reference to an 
+additional starting location. The format is implementation defined. </p>
 <blockquote>
   <p><i>[Note:</i> For POSIX-like implementations, including<b> </b>Unix 
   variants, Linux, and Mac OS X, only paths 
@@ -173,9 +185,13 @@
   specifier followed by a slash, or begin with two slashes, are absolute paths. <i>--end 
   note]</i></p>
 </blockquote>
-<p><b><a name="Relative-path">Relative path</a>:</b> A path that uniquely 
-identifies a file only when considered relative to some other path. [<i>Note:</i> 
+<p><b><a name="Relative-path">Relative path</a>:</b> A path that only 
+unambiguously 
+identifies the location of a file within a filesystem when resolved relative to 
+a starting location. The format is implementation defined. [<i>Note:</i> 
 Paths "." and ".." are considered to be relative paths. <i>--end note</i>]</p>
+<p><b><a name="Canonical-path">Canonical path</a>:</b> An absolute path that has 
+no elements which are symbolic links, and no dot or dot dot elements.</p>
 <p><i><b><a name="Pathname">Pathname</a>:</b> </i>A character string that represents a 
 path. Pathnames are formatted according to the generic pathname format or the 
 native pathname format.</p>
@@ -288,7 +304,7 @@
 is unreasonable for a program to detect them prior to calling the function. <i>
 -- end note</i>]</p>
 </blockquote>
-<h2><a name="Header-filesystem-synopsis">Header <code><boost/filesystem></code> synopsis</a></h2>
+<h2><a name="Header-filesystem-synopsis">Header <code><boost/filesystem.hpp></code> synopsis</a></h2>
 <pre>  namespace boost
   {
     namespace filesystem
@@ -298,6 +314,7 @@
       void swap(path& lhs, path& rhs);
       bool lexicographical_compare(path::iterator first1, path::iterator last1,
                                    path::iterator first2, path::iterator last2);
+      std::size_t hash_value(const path& p);
 
       bool operator==(const path& lhs, const path& rhs);
       bool operator!=(const path& lhs, const path& rhs);
@@ -354,6 +371,10 @@
 
       path         absolute(const path& p, const path& base=current_path());
 
+      path         canonical(const path& p, const path& base = current_path());
+      path         canonical(const path& p, system::error_code& ec);
+      path         canonical(const path& p, const path& base, system::error_code& ec);
+
       void         copy(const path& from, const path& to);
       void         copy(const path& from, const path& to, system::error_code& ec);
 
@@ -736,7 +757,7 @@
 
 <h3> <a name="path-constructors"> <code>
 <font size="4">path</font></code> constructors</a></h3>
-<pre>path();</pre>
+<pre><span style="background-color: #D7EEFF">path();</span></pre>
 <blockquote>
   <p><i>Postcondition:</i> <code>empty()</code>.</p>
   </blockquote>
@@ -987,7 +1008,7 @@
   <p><i>Returns:</i> <code>empty() ? path() : *--end()</code></p>
   <p>[<i>Example:</i></p>
   <blockquote>
-    <pre><code>std::cout << path("/foo/bar.txt").filename();</code> // outputs "<code>bar.txt</code>" (without the quotes)</pre>
+    <pre><code>std::cout << path("/foo/bar.txt").filename();</code> // outputs "<code>bar.txt</code>"</pre>
   </blockquote>
   <p> <i>--end example</i>]</p>
 </blockquote>
@@ -1001,8 +1022,8 @@
   p.filename()</code>.</p>
   <p>[<i>Example:</i></p>
   <blockquote>
-    <pre><code>std::cout << path("/foo/bar.txt").stem();</code> // outputs "<code>bar</code>" (without the quotes)</pre>
-    <pre>path p = "foo.bar.baz.tar";
+    <pre><code>std::cout << path("/foo/bar.txt").stem();</code> // outputs "<code>bar</code>"
+path p = "foo.bar.baz.tar";
 for (; !p.extension().empty(); p = p.stem())
   std::cout << p.extension() << '\n';
   // outputs: .tar
@@ -1023,7 +1044,7 @@
   as alternate data streams or partitioned dataset names.</p>
   <p>[<i>Example:</i></p>
   <blockquote>
-    <pre><code>std::cout << path("/foo/bar.txt").extension(); //</code> outputs "<code>.txt</code>" (without the quotes)</pre>
+    <pre><code>std::cout << path("/foo/bar.txt").extension(); //</code> outputs "<code>.txt</code>"</pre>
   </blockquote>
   <p> <i>--end example</i>]</p>
   <p>[<i>Note:<b> </b></i>The dot is included in the return value so that 
@@ -1175,6 +1196,14 @@
   due to the <code>path</code> iterator's value type itself being <code>path</code>.
   <i>--end note</i>]</p>
 </blockquote>
+<pre>std::size_t <a name="hash_value">hash_value</a> (const path& p);</pre>
+<blockquote>
+  <p><i>Returns:</i> A hash value for the path <code>p</code>. If
+  for two paths, <code>p1 == p2</code> then
+  <code>hash_value(p1) == hash_value(p2)</code>.</p>
+  <p>This allows paths to be used with
+  Boost.Hash.</p>
+</blockquote>
 <pre>bool operator< (const path& lhs, const path& rhs);</pre>
 <blockquote>
   <p><i>Returns:</i> <code>return lexicographical_compare(lhs.begin(), lhs.end(), 
@@ -1226,7 +1255,8 @@
 to ensure that paths with embedded spaces will round trip correctly. Ampersand (<code>&</code>) 
 is used as an escape character, so the path can itself contain double quotes.</p>
 <pre>template <class Char, class Traits>
-std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os, const path& p)
+std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os,
+                                             const path& p)
 </pre>
 <blockquote>
   <p><i>Effects:</i> 
@@ -1236,7 +1266,8 @@
    <code>os</code></p>
 </blockquote>
 <pre>template <class Char, class Traits>
-inline std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& is, path& p)
+inline std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& is,
+                                                    path& p)
 </pre>
 <blockquote>
   <p><i>Effects:  </i>
@@ -1258,9 +1289,12 @@
       public:
         filesystem_error();
         filesystem_error(const filesystem_error&);
-        filesystem_error(const std::string& what_arg, system::error_code ec);
-        filesystem_error(const std::string& what_arg, const path& p1, system::error_code ec);
-        filesystem_error(const std::string& what_arg, const path& p1, const path& p2, system::error_code ec);
+        filesystem_error(const std::string& what_arg,
+          system::error_code ec);
+        filesystem_error(const std::string& what_arg,
+          const path& p1, system::error_code ec);
+        filesystem_error(const std::string& what_arg,
+          const path& p1, const path& p2, system::error_code ec);
 
         filesystem_error& filesystem_error(const filesystem_error&);
        ~filesystem_error();
@@ -1385,6 +1419,7 @@
   string.</p>
 </blockquote>
 <h3><a name="Class-directory_entry">Class <code>directory_entry</code></a></h3>
+<div dir="ltr">
 <pre>  namespace boost
   {
     namespace filesystem
@@ -1396,13 +1431,16 @@
         // constructors and destructor
         directory_entry();
         directory_entry(const directory_entry&);
-        explicit directory_entry(const path_type& p, file_status st=file_status(), file_status symlink_st=file_status());
+        explicit directory_entry(const path_type& p, file_status st=file_status(),
+          file_status symlink_st=file_status());
        ~directory_entry(); 
 
         // modifiers
         directory_entry& operator=(const directory_entry&);
-        void assign(const path_type& p, file_status st=file_status(), file_status symlink_st=file_status());
-        void replace_filename(const path& p, file_status st=file_status(), file_status symlink_st=file_status());
+        void assign(const path_type& p, file_status st=file_status(),
+          file_status symlink_st=file_status());
+        void replace_filename(const path& p, file_status st=file_status(),
+          file_status symlink_st=file_status());
 
         // observers
         const path&  path() const;
@@ -1426,6 +1464,7 @@
 
     } // namespace filesystem
   } // namespace boost</pre>
+</div>
 <p>A <code>directory_entry</code> object stores a <code>path object</code>, 
 a <code>file_status</code> object for non-symbolic link status, and a <code>
 file_status</code> object for symbolic link status. The <code>file_status</code> 
@@ -1943,7 +1982,7 @@
 <h4><a name="Function-specifications">Operational function specifications</a></h4>
 <pre>path <a name="absolute">absolute</a>(const path& p, const path& base=current_path());</pre>
   <blockquote>
-  <p><i>Returns:</i> A path composed according to to the 
+  <p><i>Returns:</i> A absolute path composed according to the 
   following table</p>
   <table border="1" cellpadding="5" cellspacing="0" bordercolor="#111111" style="border-collapse: collapse">
     <tr>
@@ -1965,11 +2004,31 @@
       <td align="center"><code>return absolute(base) / p</code></td>
     </tr>
   </table>
-  <p><i>Postcondition:</i> For the returned path, <code>rp,</code> <code>
-  rp.is_absolute()</code> is true.</p>
+  <p dir="ltr">[<i>Note:</i> For the returned path, <code>rp,</code> <code>
+  rp.is_absolute()</code> is true. <i>-- end note</i>]</p>
   <p><i>Throws:</i> If <code>base.is_absolute()</code> is true, throws only if 
   memory allocation fails.</p>
 </blockquote>
+<pre>path <a name="canonical">canonical</a>(const path& p, const path& base = current_path());
+path canonical(const path& p, system::error_code& ec);
+path canonical(const path& p, const path& base, system::error_code& ec);</pre>
+<blockquote>
+<p><i>Overview:</i> Converts <code>p</code>, which must exist, to an absolute 
+path that has no symbolic link, dot, 
+or dot-dot elements. </p>
+<p><i>Returns:</i> A canonical path that refers to 
+the same file system object as <code>absolute(p,base)</code>. For the overload 
+without a <code>base</code> argument, <code>base</code> is <code>current_path()</code>.</p>
+  <p><i>Throws:</i>  As specified in
+  <a href="#Error-reporting">
+  Error reporting</a>.</p>
+  
+  <p><i>Remarks:</i> <code>!exists(p)</code> is an error.</p>
+  
+  <p>[<i>Note:</i> Canonical pathnames allow security checking of a path (eg. 
+  does this path live in /home/goodguy or /home/badguy?)  -- end note]</p>
+  
+</blockquote>
 <pre>void <a name="copy">copy</a>(const path& from, const path& to);
 void copy(const path& from, const path& to, system::error_code& ec);</pre>
 <blockquote>
@@ -3236,7 +3295,7 @@
 <p>The Windows API has many functions that also have Unicode versions to permit 
 an extended-length path for a maximum total path length of 32,767 characters. 
 ... To specify an extended-length path, use the <b>"\\?\" prefix</b>. For 
-example, "\\?\D:\very long path". 
+example, "\\?\D:\very long path". 
 <i>[C++ string literals require backslashes be doubled, of course.]</i></p>
 </blockquote>
 <p>Because most Boost.Filesystem operational functions just pass the contents of 
@@ -3271,12 +3330,14 @@
 Witt were particularly helpful in refining the library.</p>
 <p>The create_directories, extension, basename, and replace_extension functions 
 were developed by Vladimir Prus. The temp_directory_path function was 
-contributed by Jeff Flinn.</p>
+contributed by Jeff Flinn. David Svoboda suggested the canonical function and 
+provided psuedo-code.</p>
 <p>Howard Hinnant and John Maddock reviewed a draft of the version 2 proposal, and 
 identified a number of mistakes or weaknesses, resulting in a more polished 
 final document.</p>
 <p>Peter Dimov suggested a single class path, with member templates to adapt to 
 multiple string types. His idea became the basis for the version 3 path design.</p>
+<p> </p>
 <h2><a name="References">References</a></h2>
 <table border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" width="100%">
   <tr>
@@ -3298,11 +3359,12 @@
   </tr>
 </table>
 <hr>
-<p>© Copyright Beman Dawes, 2002, 2006, 2007, 2009, 2010</p>
-<p>Distributed under the Boost Software License, Version 1.0. See
-www.boost.org/LICENSE_1_0.txt</p>
-<p>Revised
-<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B %Y" startspan -->12 April 2011<!--webbot bot="Timestamp" endspan i-checksum="28281" --></p>
+<p><font size="2">© Copyright Beman Dawes, 2002, 2006, 2007, 2009, 2010, 2011</font></p>
+<p><font size="2">Distributed under the Boost Software License, Version 1.0. See
+</font>
+www.boost.org/LICENSE_1_0.txt</p>
+<p><font size="2">Revised
+<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B %Y" startspan -->06 October 2011<!--webbot bot="Timestamp" endspan i-checksum="32189" --></font></p>
 
 </body>
 
Modified: branches/release/libs/filesystem/v3/doc/release_history.html
==============================================================================
--- branches/release/libs/filesystem/v3/doc/release_history.html	(original)
+++ branches/release/libs/filesystem/v3/doc/release_history.html	2011-10-09 09:54:09 EDT (Sun, 09 Oct 2011)
@@ -36,6 +36,22 @@
   </tr>
 </table>
 
+<h2>1.48.0</h2>
+<ul>
+  <li>Added operational function canonical(), 
+  suggested by David Svoboda, who also provided pseudo-code.</li>
+  <li>Added hash_value() function for 
+  paths. (Daniel James)</li>
+  <li>Fix path inserter problem (#5764) 
+  reported for QNX6.3.2 host (gcc-3.3.5)</li>
+  <li>Fix problem of locale("") exception being thrown before main() starts on 
+  poorly configured (e.g. LANG="bad name") POSIX systems. Resolves the most 
+  serious aspect of tickets
+  #4688,
+  #5100,
+  #5289.</li>
+</ul>
+
 <h2>1.47.0</h2>
 <ul>
   <li>Program file_status.cpp added (V3). See boost-root/libs/filesystem/v3/example. 
@@ -46,6 +62,10 @@
 
 <h2>1.46.1</h2>
 
+<ul>
+  <li>Fix fstream problem for STLPort masquerading as Dinkumware (#5217).</li>
+</ul>
+
 <h2>1.46.0</h2>
 <ul>
   <li>Version 3 of the library is now the default.</li>
@@ -68,7 +88,7 @@
 </ul>
 <hr>
 <p>Revised
-<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->31 May, 2011<!--webbot bot="Timestamp" endspan i-checksum="13963" --></p>
+<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->03 October, 2011<!--webbot bot="Timestamp" endspan i-checksum="38359" --></p>
 <p>© Copyright Beman Dawes, 2011</p>
 <p> Use, modification, and distribution are subject to the Boost Software 
 License, Version 1.0. See <a href="http://www.boost.org/LICENSE_1_0.txt">
Modified: branches/release/libs/filesystem/v3/src/operations.cpp
==============================================================================
--- branches/release/libs/filesystem/v3/src/operations.cpp	(original)
+++ branches/release/libs/filesystem/v3/src/operations.cpp	2011-10-09 09:54:09 EDT (Sun, 09 Oct 2011)
@@ -77,6 +77,8 @@
 
 # ifdef BOOST_POSIX_API
 
+    const fs::path dot_path(".");
+    const fs::path dot_dot_path("..");
 #   include <sys/types.h>
 #   if !defined(__APPLE__) && !defined(__OpenBSD__)
 #     include <sys/statvfs.h>
@@ -98,6 +100,8 @@
 
 # else // BOOST_WINDOW_API
 
+    const fs::path dot_path(L".");
+    const fs::path dot_dot_path(L"..");
 #   if (defined(__MINGW32__) || defined(__CYGWIN__)) && !defined(WINVER)
       // Versions of MinGW or Cygwin that support Filesystem V3 support at least WINVER 0x501.
       // See MinGW's windef.h
@@ -752,6 +756,86 @@
   }
 
   BOOST_FILESYSTEM_DECL
+  path canonical(const path& p, const path& base, system::error_code* ec)
+  {
+    path source (p.is_absolute() ? p : absolute(p, base));
+    path result;
+
+    system::error_code local_ec;
+    file_status stat (status(source, local_ec));
+
+    if (stat.type() == fs::file_not_found)
+    {
+      if (ec == 0)
+        BOOST_FILESYSTEM_THROW(filesystem_error(
+          "boost::filesystem::canonical", source,
+          error_code(system::errc::no_such_file_or_directory, system::generic_category())));
+      ec->assign(system::errc::no_such_file_or_directory, system::generic_category());
+      return result;
+    }
+    else if (local_ec)
+    {
+      if (ec == 0)
+        BOOST_FILESYSTEM_THROW(filesystem_error(
+          "boost::filesystem::canonical", source, local_ec));
+      *ec = local_ec;
+      return result;
+    }
+
+    bool scan (true);
+    while (scan)
+    {
+      scan = false;
+      result.clear();
+      for (path::iterator itr = source.begin(); itr != source.end(); ++itr)
+      {
+        if (*itr == dot_path)
+          continue;
+        if (*itr == dot_dot_path)
+        {
+          result.remove_filename();
+          continue;
+        }
+
+        result /= *itr;
+
+        bool is_sym (is_symlink(detail::symlink_status(result, ec)));
+        if (ec && *ec)
+          return path();
+
+        if (is_sym)
+        {
+          path link(detail::read_symlink(result, ec));
+          if (ec && *ec)
+            return path();
+          result.remove_filename();
+
+          if (link.is_absolute())
+          {
+            for (++itr; itr != source.end(); ++itr)
+              link /= *itr;
+            source = link;
+          }
+          else // link is relative
+          {
+            path new_source(result);
+            new_source /= link;
+            for (++itr; itr != source.end(); ++itr)
+              new_source /= *itr;
+            source = new_source;
+          }
+          scan = true;  // symlink causes scan to be restarted
+          break;
+        }
+      }
+    }
+    if (ec != 0)
+      ec->clear();
+    BOOST_ASSERT_MSG(result.is_absolute(), "canonical() implementation error; please report");
+    return result;
+  }
+
+  BOOST_FILESYSTEM_DECL
   void copy(const path& from, const path& to, system::error_code* ec)
   {
     file_status s(symlink_status(from, *ec));
Modified: branches/release/libs/filesystem/v3/test/msvc10/filesystem-v3.sln
==============================================================================
--- branches/release/libs/filesystem/v3/test/msvc10/filesystem-v3.sln	(original)
+++ branches/release/libs/filesystem/v3/test/msvc10/filesystem-v3.sln	2011-10-09 09:54:09 EDT (Sun, 09 Oct 2011)
@@ -132,7 +132,9 @@
                 {256EA89A-E073-4CE8-B675-BE2FBC6B2691}.Release|Win32.ActiveCfg = Release|Win32
                 {256EA89A-E073-4CE8-B675-BE2FBC6B2691}.Release|Win32.Build.0 = Release|Win32
                 {FC5C770F-3017-4021-8DAF-C5DCA3FDF005}.Debug|Win32.ActiveCfg = Debug|Win32
+		{FC5C770F-3017-4021-8DAF-C5DCA3FDF005}.Debug|Win32.Build.0 = Debug|Win32
                 {FC5C770F-3017-4021-8DAF-C5DCA3FDF005}.Release|Win32.ActiveCfg = Release|Win32
+		{FC5C770F-3017-4021-8DAF-C5DCA3FDF005}.Release|Win32.Build.0 = Release|Win32
                 {5C9B3380-3C6E-45CC-986A-16D245E27E58}.Debug|Win32.ActiveCfg = Debug|Win32
                 {5C9B3380-3C6E-45CC-986A-16D245E27E58}.Debug|Win32.Build.0 = Debug|Win32
                 {5C9B3380-3C6E-45CC-986A-16D245E27E58}.Release|Win32.ActiveCfg = Release|Win32
Modified: branches/release/libs/filesystem/v3/test/operations_test.cpp
==============================================================================
--- branches/release/libs/filesystem/v3/test/operations_test.cpp	(original)
+++ branches/release/libs/filesystem/v3/test/operations_test.cpp	2011-10-09 09:54:09 EDT (Sun, 09 Oct 2011)
@@ -388,45 +388,46 @@
  
   void create_tree()
   {
+    cout << "creating test directories and files in " << dir << endl;
 
-  // create directory d1
-  BOOST_TEST(!fs::create_directory(dir));
-  BOOST_TEST(!fs::is_symlink(dir));
-  BOOST_TEST(!fs::is_symlink("nosuchfileordirectory"));
-  d1 = dir / "d1";
-  BOOST_TEST(fs::create_directory(d1));
-  BOOST_TEST(fs::exists(d1));
-  BOOST_TEST(fs::is_directory(d1));
-  BOOST_TEST(fs::is_empty(d1));
-
-  // create an empty file named "d1f1"
-  d1f1 = d1 / "d1f1";
-  create_file(d1f1, "");
-  BOOST_TEST(fs::exists(d1f1));
-  BOOST_TEST(!fs::is_directory(d1f1));
-  BOOST_TEST(fs::is_regular_file(d1f1));
-  BOOST_TEST(fs::is_empty(d1f1));
-  BOOST_TEST(fs::file_size(d1f1) == 0);
-  BOOST_TEST(fs::hard_link_count(d1f1) == 1);
-
-  // create an empty file named "f0"
-  f0 = dir / "f0";
-  create_file(f0, "");
-  BOOST_TEST(fs::exists(f0));
-  BOOST_TEST(!fs::is_directory(f0));
-  BOOST_TEST(fs::is_regular_file(f0));
-  BOOST_TEST(fs::is_empty(f0));
-  BOOST_TEST(fs::file_size(f0) == 0);
-  BOOST_TEST(fs::hard_link_count(f0) == 1);
-
-  // create a file named "f1"
-  f1 = dir / "f1";
-  create_file(f1, "file-f1");
-  BOOST_TEST(fs::exists(f1));
-  BOOST_TEST(!fs::is_directory(f1));
-  BOOST_TEST(fs::is_regular_file(f1));
-  BOOST_TEST(fs::file_size(f1) == 7);
-  verify_file(f1, "file-f1");
+    // create directory d1
+    BOOST_TEST(!fs::create_directory(dir));
+    BOOST_TEST(!fs::is_symlink(dir));
+    BOOST_TEST(!fs::is_symlink("nosuchfileordirectory"));
+    d1 = dir / "d1";
+    BOOST_TEST(fs::create_directory(d1));
+    BOOST_TEST(fs::exists(d1));
+    BOOST_TEST(fs::is_directory(d1));
+    BOOST_TEST(fs::is_empty(d1));
+
+    // create an empty file named "d1f1"
+    d1f1 = d1 / "d1f1";
+    create_file(d1f1, "");
+    BOOST_TEST(fs::exists(d1f1));
+    BOOST_TEST(!fs::is_directory(d1f1));
+    BOOST_TEST(fs::is_regular_file(d1f1));
+    BOOST_TEST(fs::is_empty(d1f1));
+    BOOST_TEST(fs::file_size(d1f1) == 0);
+    BOOST_TEST(fs::hard_link_count(d1f1) == 1);
+
+    // create an empty file named "f0"
+    f0 = dir / "f0";
+    create_file(f0, "");
+    BOOST_TEST(fs::exists(f0));
+    BOOST_TEST(!fs::is_directory(f0));
+    BOOST_TEST(fs::is_regular_file(f0));
+    BOOST_TEST(fs::is_empty(f0));
+    BOOST_TEST(fs::file_size(f0) == 0);
+    BOOST_TEST(fs::hard_link_count(f0) == 1);
+
+    // create a file named "f1"
+    f1 = dir / "f1";
+    create_file(f1, "file-f1");
+    BOOST_TEST(fs::exists(f1));
+    BOOST_TEST(!fs::is_directory(f1));
+    BOOST_TEST(fs::is_regular_file(f1));
+    BOOST_TEST(fs::file_size(f1) == 7);
+    verify_file(f1, "file-f1");
   }
 
   //  directory_iterator_tests  --------------------------------------------------------//
@@ -1228,11 +1229,12 @@
     cout << "absolute_tests..." << endl;
 
     BOOST_TEST_EQ(fs::absolute(""), fs::current_path() );
+    BOOST_TEST_EQ(fs::absolute("", ""), fs::current_path() );
     BOOST_TEST_EQ(fs::absolute(fs::current_path() / "foo/bar"), fs::current_path() / "foo/bar");
     BOOST_TEST_EQ(fs::absolute("foo"), fs::current_path() / "foo");
     BOOST_TEST_EQ(fs::absolute("foo", fs::current_path()), fs::current_path() / "foo");
     BOOST_TEST_EQ(fs::absolute("bar", "foo"), fs::current_path() / "foo" / "bar");
-    BOOST_TEST_EQ(fs::absolute("/foo"), fs::current_path().root_name().string() + "/foo");
+    BOOST_TEST_EQ(fs::absolute("/foo"), fs::current_path().root_path().string() + "foo");
 
 #  ifdef BOOST_WINDOWS_API
     BOOST_TEST_EQ(fs::absolute("a:foo", "b:/bar"), "a:/bar/foo");
@@ -1295,7 +1297,58 @@
 
   }
 
- //  copy_file_tests  -----------------------------------------------------------------//
+  //  canonical_basic_tests  -----------------------------------------------------------//
+
+  void canonical_basic_tests()
+  {
+    cout << "canonical_basic_tests..." << endl;
+
+    // error handling
+    error_code ec;
+    ec.clear();
+    fs::canonical("no-such-file", ec);
+    BOOST_TEST(ec);
+    ec.clear();
+    fs::canonical("no-such-file", "x", ec);
+    BOOST_TEST(ec);
+    bool ok(false);
+    try { fs::canonical("no-such-file"); }
+    catch (const fs::filesystem_error&) { ok = true; }
+    BOOST_TEST(ok);
+
+    // non-symlink tests; also see canonical_symlink_tests()
+    BOOST_TEST_EQ(fs::canonical(""), fs::current_path());
+    BOOST_TEST_EQ(fs::canonical("", fs::current_path()), fs::current_path());
+    BOOST_TEST_EQ(fs::canonical("", ""), fs::current_path());
+    BOOST_TEST_EQ(fs::canonical(fs::current_path()), fs::current_path());
+    BOOST_TEST_EQ(fs::canonical(fs::current_path(), ""), fs::current_path());
+    BOOST_TEST_EQ(fs::canonical(fs::current_path(), "no-such-file"), fs::current_path());
+
+    BOOST_TEST_EQ(fs::canonical("."), fs::current_path());
+    BOOST_TEST_EQ(fs::canonical(".."), fs::current_path().parent_path());
+    BOOST_TEST_EQ(fs::canonical("/"), fs::current_path().root_path());
+
+    fs::path relative_dir(dir.filename());
+    BOOST_TEST_EQ(fs::canonical(dir), dir);
+    BOOST_TEST_EQ(fs::canonical(relative_dir), dir);
+    BOOST_TEST_EQ(fs::canonical(dir / "f0"), dir / "f0");
+    BOOST_TEST_EQ(fs::canonical(relative_dir / "f0"), dir / "f0");
+    BOOST_TEST_EQ(fs::canonical(relative_dir / "./f0"), dir / "f0");
+    BOOST_TEST_EQ(fs::canonical(relative_dir / "d1/../f0"), dir / "f0");
+  }
+
+  //  canonical_symlink_tests  -----------------------------------------------------------//
+
+  void canonical_symlink_tests()
+  {
+    cout << "canonical_symlink_tests..." << endl;
+
+    fs::path relative_dir(dir.filename());
+    BOOST_TEST_EQ(fs::canonical(dir / "sym-d1/f2"), d1 / "f2");
+    BOOST_TEST_EQ(fs::canonical(relative_dir / "sym-d1/f2"), d1 / "f2");
+  }
+
+ //  copy_file_tests  ------------------------------------------------------------------//
 
   void copy_file_tests(const fs::path& f1, const fs::path& d1)
   {
@@ -1761,6 +1814,7 @@
 
 int cpp_main(int argc, char* argv[])
 {
+
 // document state of critical macros
 #ifdef BOOST_POSIX_API
   cout << "BOOST_POSIX_API is defined\n";
@@ -1805,7 +1859,6 @@
   initial_tests();
   predicate_and_status_tests();
   exception_tests();
-  platform_specific_tests();
   create_directory_tests();
   current_directory_tests();
   space_tests();
@@ -1840,11 +1893,13 @@
   create_symlink_tests();
   resize_file_tests();
   absolute_tests();
+  canonical_basic_tests();
   copy_file_tests(f1, d1);
   if (create_symlink_ok)  // only if symlinks supported
   {
     symlink_status_tests();
     copy_symlink_tests(f1, d1);
+    canonical_symlink_tests();
   }
   iterator_status_tests();  // lots of cases by now, so a good time to test
 //  dump_tree(dir);
@@ -1857,6 +1912,7 @@
   write_time_tests(dir);
   
   temp_directory_path_tests();
+  platform_specific_tests();
   
   cout << "testing complete" << endl;
 
Modified: branches/release/libs/filesystem/v3/test/path_unit_test.cpp
==============================================================================
--- branches/release/libs/filesystem/v3/test/path_unit_test.cpp	(original)
+++ branches/release/libs/filesystem/v3/test/path_unit_test.cpp	2011-10-09 09:54:09 EDT (Sun, 09 Oct 2011)
@@ -43,6 +43,7 @@
 #include <boost/detail/lightweight_test.hpp>
 #include <boost/detail/lightweight_main.hpp>
 #include <boost/smart_ptr.hpp>  // used constructor tests
+#include <boost/functional/hash.hpp>
 
 #include <iostream>
 #include <iomanip>
@@ -399,9 +400,12 @@
   {
     std::cout << "testing relationals..." << std::endl;
 
+    boost::hash<path> hash;
+
 # ifdef BOOST_WINDOWS_API
     // this is a critical use case to meet user expectations
     CHECK(path("c:\\abc") == path("c:/abc"));
+    CHECK(hash(path("c:\\abc")) == hash(path("c:/abc")));
 # endif
 
     const path p("bar");
@@ -431,6 +435,9 @@
     CHECK(L"baz" == p2);
     CHECK(wstring(L"baz") == p2);
 
+    CHECK(hash(p) == hash(p));
+    CHECK(hash(p) != hash(p2)); // Not strictly required, but desirable
+
     CHECK(!(p != p));
     CHECK(p != p2);
     CHECK(p2 != p);