ncbifile.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:62k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: ncbifile.cpp,v $
  4.  * PRODUCTION Revision 1000.5  2004/06/01 19:09:09  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.78
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: ncbifile.cpp,v 1000.5 2004/06/01 19:09:09 gouriano Exp $
  10.  * ===========================================================================
  11.  *
  12.  *                            PUBLIC DOMAIN NOTICE
  13.  *               National Center for Biotechnology Information
  14.  *
  15.  *  This software/database is a "United States Government Work" under the
  16.  *  terms of the United States Copyright Act.  It was written as part of
  17.  *  the author's official duties as a United States Government employee and
  18.  *  thus cannot be copyrighted.  This software/database is freely available
  19.  *  to the public for use. The National Library of Medicine and the U.S.
  20.  *  Government have not placed any restriction on its use or reproduction.
  21.  *
  22.  *  Although all reasonable efforts have been taken to ensure the accuracy
  23.  *  and reliability of the software and data, the NLM and the U.S.
  24.  *  Government do not and cannot warrant the performance or results that
  25.  *  may be obtained by using this software or data. The NLM and the U.S.
  26.  *  Government disclaim all warranties, express or implied, including
  27.  *  warranties of performance, merchantability or fitness for any particular
  28.  *  purpose.
  29.  *
  30.  *  Please cite the author in any work or product based on this material.
  31.  *
  32.  * ===========================================================================
  33.  *
  34.  * Author: Vladimir Ivanov
  35.  *
  36.  * File Description:   Files and directories accessory functions
  37.  *
  38.  */
  39. #include <ncbi_pch.hpp>
  40. #include <corelib/ncbifile.hpp>
  41. #if !defined(NCBI_OS_MAC)
  42. #  include <sys/types.h>
  43. #  if defined(HAVE_SYS_STAT_H)
  44. #    include <sys/stat.h>
  45. #  endif
  46. #endif
  47. #include <stdio.h>
  48. #if defined(NCBI_OS_MSWIN)
  49. #  include <corelib/ncbi_os_mswin.hpp>
  50. #  include <corelib/ncbi_limits.hpp>
  51. #  include <io.h>
  52. #  include <direct.h>
  53. #  include <sys/utime.h>
  54. #elif defined(NCBI_OS_UNIX)
  55. #  include <unistd.h>
  56. #  include <dirent.h>
  57. #  include <pwd.h>
  58. #  include <fcntl.h>
  59. #  include <sys/mman.h>
  60. #  include <utime.h>
  61. #  if !defined(MAP_FAILED)
  62. #    define MAP_FAILED ((void *) -1)
  63. #  endif
  64. #  if defined(NCBI_COMPILER_MW_MSL)
  65. #    include <ncbi_mslextras.h>
  66. #  endif
  67. #elif defined(NCBI_OS_MAC)
  68. #  include <fcntl.h>
  69. #  include <corelib/ncbi_os_mac.hpp>
  70. #  include <Script.h>
  71. #  include <Gestalt.h>
  72. #  include <Folders.h>
  73. #endif  /* NCBI_OS_MSWIN, NCBI_OS_UNIX, NCBI_OS_MAC */
  74. BEGIN_NCBI_SCOPE
  75. // Path separators
  76. #undef  DIR_SEPARATOR
  77. #undef  DIR_SEPARATOR_ALT
  78. #undef  DIR_SEPARATORS
  79. #undef  DISK_SEPARATOR
  80. #undef  ALL_SEPARATORS
  81. #undef  ALL_OS_SEPARATORS
  82. #define DIR_PARENT  ".."
  83. #define DIR_CURRENT "."
  84. #define ALL_OS_SEPARATORS   ":/\"
  85. #if defined(NCBI_OS_MSWIN)
  86. #  define DIR_SEPARATOR     '\'
  87. #  define DIR_SEPARATOR_ALT '/'
  88. #  define DISK_SEPARATOR    ':'
  89. #  define DIR_SEPARATORS    "/\"
  90. #  define ALL_SEPARATORS    ":/\"
  91. #elif defined(NCBI_OS_UNIX)
  92. #  define DIR_SEPARATOR     '/'
  93. #  define DIR_SEPARATORS    "/"
  94. #  define ALL_SEPARATORS    "/"
  95. #elif defined(NCBI_OS_MAC)
  96. #  define DIR_SEPARATOR     ':'
  97. #  define DIR_SEPARATORS    ':'
  98. #  define ALL_SEPARATORS    ":"
  99. #  undef  DIR_PARENT
  100. #  undef  DIR_CURRENT
  101. #endif
  102. //////////////////////////////////////////////////////////////////////////////
  103. //
  104. // Static functions
  105. //
  106. #if defined(NCBI_OS_MAC)
  107. static const FSSpec sNullFSS = {0, 0, "p"};
  108. static bool operator== (const FSSpec& one, const FSSpec& other)
  109. {
  110.     return one.vRefNum == other.vRefNum
  111.         && one.parID   == other.parID
  112.         && PString(one.name) == PString(other.name);
  113. }
  114. #endif  /* NCBI_OS_MAC */
  115. // Construct real entry mode from parts. Parameters can not have "fDefault" 
  116. // value.
  117. static CDirEntry::TMode s_ConstructMode(CDirEntry::TMode user_mode, 
  118.                                         CDirEntry::TMode group_mode, 
  119.                                         CDirEntry::TMode other_mode)
  120. {
  121.     CDirEntry::TMode mode = 0;
  122.     mode |= (user_mode  << 6);
  123.     mode |= (group_mode << 3);
  124.     mode |= other_mode;
  125.     return mode;
  126. }
  127. //////////////////////////////////////////////////////////////////////////////
  128. //
  129. // CDirEntry
  130. //
  131. CDirEntry::CDirEntry()
  132. #if defined(NCBI_OS_MAC)
  133.     : m_FSS(new FSSpec(sNullFSS))
  134. #endif
  135. {
  136. }
  137. #if defined(NCBI_OS_MAC)
  138. CDirEntry::CDirEntry(const CDirEntry& other) : m_FSS(new FSSpec(*other.m_FSS))
  139. {
  140.     m_DefaultMode[eUser]  = other.m_DefaultMode[eUser];
  141.     m_DefaultMode[eGroup] = other.m_DefaultMode[eGroup];
  142.     m_DefaultMode[eOther] = other.m_DefaultMode[eOther];
  143. }
  144. CDirEntry&
  145. CDirEntry::operator= (const CDirEntry& other)
  146. {
  147.     *m_FSS = *other.m_FSS;
  148.     m_DefaultMode[eUser]  = other.m_DefaultMode[eUser];
  149.     m_DefaultMode[eGroup] = other.m_DefaultMode[eGroup];
  150.     m_DefaultMode[eOther] = other.m_DefaultMode[eOther];
  151.     return *this;
  152. }
  153. CDirEntry::CDirEntry(const FSSpec& fss) : m_FSS(new FSSpec(fss))
  154. {
  155.     m_DefaultMode[eUser]  = m_DefaultModeGlobal[eFile][eUser];
  156.     m_DefaultMode[eGroup] = m_DefaultModeGlobal[eFile][eGroup];
  157.     m_DefaultMode[eOther] = m_DefaultModeGlobal[eFile][eOther];
  158. }
  159. #endif
  160. CDirEntry::CDirEntry(const string& name)
  161. #if defined(NCBI_OS_MAC)
  162.     : m_FSS(new FSSpec(sNullFSS))
  163. #endif
  164. {
  165.     Reset(name);
  166.     m_DefaultMode[eUser]  = m_DefaultModeGlobal[eFile][eUser];
  167.     m_DefaultMode[eGroup] = m_DefaultModeGlobal[eFile][eGroup];
  168.     m_DefaultMode[eOther] = m_DefaultModeGlobal[eFile][eOther];
  169. }
  170. #if defined(NCBI_OS_MAC)
  171. bool CDirEntry::operator== (const CDirEntry& other) const
  172. {
  173.     return *m_FSS == *other.m_FSS;
  174. }
  175. const FSSpec& CDirEntry::FSS() const
  176. {
  177.     return *m_FSS;
  178. }
  179. #endif
  180. CDirEntry::TMode CDirEntry::m_DefaultModeGlobal[eUnknown][3] =
  181. {
  182.     // eFile
  183.     { CDirEntry::fDefaultUser, CDirEntry::fDefaultGroup, 
  184.           CDirEntry::fDefaultOther },
  185.     // eDir
  186.     { CDirEntry::fDefaultDirUser, CDirEntry::fDefaultDirGroup, 
  187.           CDirEntry::fDefaultDirOther },
  188.     // ePipe
  189.     { CDirEntry::fDefaultUser, CDirEntry::fDefaultGroup, 
  190.           CDirEntry::fDefaultOther },
  191.     // eLink
  192.     { CDirEntry::fDefaultUser, CDirEntry::fDefaultGroup, 
  193.           CDirEntry::fDefaultOther },
  194.     // eSocket
  195.     { CDirEntry::fDefaultUser, CDirEntry::fDefaultGroup, 
  196.           CDirEntry::fDefaultOther },
  197.     // eDoor
  198.     { CDirEntry::fDefaultUser, CDirEntry::fDefaultGroup, 
  199.           CDirEntry::fDefaultOther },
  200.     // eBlockSpecial
  201.     { CDirEntry::fDefaultUser, CDirEntry::fDefaultGroup, 
  202.           CDirEntry::fDefaultOther },
  203.     // eCharSpecial
  204.     { CDirEntry::fDefaultUser, CDirEntry::fDefaultGroup, 
  205.           CDirEntry::fDefaultOther }
  206. };
  207. #if defined(NCBI_OS_MAC)
  208. void CDirEntry::Reset(const string& path)
  209. {
  210.     OSErr err = MacPathname2FSSpec(path.c_str(), m_FSS);
  211.     if (err != noErr  &&  err != fnfErr) {
  212.         *m_FSS = sNullFSS;
  213.     }
  214. }
  215. string CDirEntry::GetPath(void) const
  216. {
  217.     OSErr err;
  218.     char* path;
  219.     err = MacFSSpec2FullPathname(&FSS(), &path);
  220.     if (err != noErr) {
  221.         return kEmptyStr;
  222.     }
  223.     return string(path);
  224. }
  225. #endif
  226. CDirEntry::~CDirEntry(void)
  227. {
  228. #if defined(NCBI_OS_MAC)
  229.     delete m_FSS;
  230. #endif
  231. }
  232. void CDirEntry::SplitPath(const string& path, string* dir,
  233.                           string* base, string* ext)
  234. {
  235.     // Get file name
  236.     size_t pos = path.find_last_of(ALL_SEPARATORS);
  237.     string filename = (pos == NPOS) ? path : path.substr(pos+1);
  238.     // Get dir
  239.     if ( dir ) {
  240.         *dir = (pos == NPOS) ? kEmptyStr : path.substr(0, pos+1);
  241.     }
  242.     // Split file name to base and extension
  243.     pos = filename.rfind('.');
  244.     if ( base ) {
  245.         *base = (pos == NPOS) ? filename : filename.substr(0, pos);
  246.     }
  247.     if ( ext ) {
  248.         *ext = (pos == NPOS) ? kEmptyStr : filename.substr(pos);
  249.     }
  250. }
  251. string CDirEntry::MakePath(const string& dir, const string& base, 
  252.                            const string& ext)
  253. {
  254.     string path;
  255.     // Adding "dir" and file base
  256.     if ( dir.length() ) {
  257.         path = AddTrailingPathSeparator(dir);
  258.     }
  259.     path += base;
  260.     // Adding extension
  261.     if ( ext.length()  &&  ext.at(0) != '.' ) {
  262.         path += '.';
  263.     }
  264.     path += ext;
  265.     // Return result
  266.     return path;
  267. }
  268. char CDirEntry::GetPathSeparator(void) 
  269. {
  270.     return DIR_SEPARATOR;
  271. }
  272. bool CDirEntry::IsPathSeparator(const char c)
  273. {
  274. #if defined(DISK_SEPARATOR)
  275.     if ( c == DISK_SEPARATOR ) {
  276.         return true;
  277.     }
  278. #endif
  279. #if defined(DIR_SEPARATOR_ALT)
  280.     if ( c == DIR_SEPARATOR_ALT ) {
  281.         return true;
  282.     }
  283. #endif
  284.     return c == DIR_SEPARATOR;
  285. }
  286. string CDirEntry::AddTrailingPathSeparator(const string& path)
  287. {
  288.     size_t len = path.length();
  289. #if defined(NCBI_OS_MAC)
  290.     if ( !len ) {
  291.         return string(1,GetPathSeparator());
  292.     }
  293. #endif
  294.     if (len  &&  string(ALL_SEPARATORS).rfind(path.at(len - 1)) == NPOS) {
  295.         return path + GetPathSeparator();
  296.     }
  297.     return path;
  298. }
  299. string CDirEntry::DeleteTrailingPathSeparator(const string& path)
  300. {
  301.     size_t pos = path.find_last_not_of(DIR_SEPARATORS);
  302.     if (pos + 1 < path.length()) {
  303.         return path.substr(0, pos + 1);
  304.     }
  305.     return path;
  306. }
  307. bool CDirEntry::IsAbsolutePath(const string& path)
  308. {
  309.     if ( path.empty() )
  310.         return false;
  311.     char first = path[0];
  312. #if defined(NCBI_OS_MAC)
  313.     if ( path.find(DIR_SEPARATOR) != NPOS  &&  first != DIR_SEPARATOR )
  314.         return true;
  315. #else
  316.     if ( IsPathSeparator(first) )
  317.         return true;
  318. #endif
  319. #if defined(DISK_SEPARATOR)
  320.     if ( path.find(DISK_SEPARATOR) != NPOS )
  321.         return true;
  322. #endif
  323.     return false;
  324. }
  325. bool CDirEntry::IsAbsolutePathEx(const string& path)
  326. {
  327.     if ( path.empty() )
  328.         return false;
  329.     char first = path[0];
  330.     // MAC or WIN absolute
  331.     if ( path.find(':') != NPOS  &&  first != ':' )
  332.         return true;
  333.     // MAC relative path
  334.     if ( first == ':' )
  335.         return false;
  336.     // UNIX or WIN absolute
  337.     if ( first == '\' || first == '/' )
  338.         return true;
  339.     // Else - relative
  340.     return false;
  341. }
  342. /// Helper : strips dir to parts:
  343. ///     c:ab     will be <c:><a><b>
  344. ///     /usr/bin/   will be </><usr><bin>
  345. static void s_StripDir(const string& dir, vector<string> * dir_parts)
  346. {
  347.     dir_parts->clear();
  348.     if ( dir.empty() ) 
  349.         return;
  350.     const char sep = CDirEntry::GetPathSeparator();
  351.     size_t sep_pos = 0;
  352.     size_t last_ind = dir.length() - 1;
  353.     size_t part_start = 0;
  354.     for (;;) {
  355.         sep_pos = dir.find(sep, sep_pos);
  356.         if (sep_pos == NPOS) {
  357.             dir_parts->push_back(string(dir, part_start,
  358.                                         dir.length() - part_start));
  359.             break;
  360.         }
  361.         // If path starts from '/' - it's a root directory
  362.         if (sep_pos == 0) {
  363.             dir_parts->push_back(string(1, sep));
  364.         } else {
  365.             dir_parts->push_back(string(dir, part_start, sep_pos - part_start));
  366.         }
  367.         sep_pos++;
  368.         part_start = sep_pos;
  369.         if (sep_pos >= last_ind) 
  370.             break;
  371.     }
  372. }
  373. string CDirEntry::CreateRelativePath( const string& path_from, 
  374.                                       const string& path_to )
  375. {
  376. #if defined(NCBI_OS_MSWIN)  ||  defined(NCBI_OS_UNIX)
  377.     string path; // the result    
  378.     
  379.     if ( !IsAbsolutePath(path_from) ) {
  380.         NCBI_THROW(CFileException, eRelativePath, 
  381.                    "path_from is not absolute path");
  382.     }
  383.     if ( !IsAbsolutePath(path_to) ) {
  384.         NCBI_THROW(CFileException, eRelativePath, 
  385.                    "path_to is not absolute path");
  386.     }
  387.     // Split and strip FROM
  388.     string dir_from;
  389.     SplitPath(AddTrailingPathSeparator(path_from), &dir_from);
  390.     vector<string> dir_from_parts;
  391.     s_StripDir(dir_from, &dir_from_parts);
  392.     if ( dir_from_parts.empty() ) {
  393.         NCBI_THROW(CFileException, eRelativePath, 
  394.                    "path_from is empty path");
  395.     }
  396.     // Split and strip TO
  397.     string dir_to;
  398.     string base_to;
  399.     string ext_to;
  400.     SplitPath(path_to, &dir_to, &base_to, &ext_to);    
  401.     vector<string> dir_to_parts;
  402.     s_StripDir(dir_to, &dir_to_parts);
  403.     if ( dir_to_parts.empty() ) {
  404.         NCBI_THROW(CFileException, eRelativePath, 
  405.                    "path_to is empty path");
  406.     }
  407. //Platform-dependent compare mode
  408. #ifdef NCBI_OS_MSWIN
  409. # define DIR_PARTS_CMP_MODE NStr::eNocase
  410. #endif
  411. #ifdef NCBI_OS_UNIX
  412. # define DIR_PARTS_CMP_MODE NStr::eCase
  413. #endif
  414.     // Roots must be the same to create relative path from one to another
  415.     if (NStr::Compare(dir_from_parts.front(), 
  416.                       dir_to_parts.front(), 
  417.                       DIR_PARTS_CMP_MODE) != 0) {
  418.         NCBI_THROW(CFileException, eRelativePath, 
  419.                    "roots of input pathes are different");
  420.     }
  421.     size_t min_parts = min(dir_from_parts.size(), dir_to_parts.size());
  422.     size_t common_length = min_parts;
  423.     for (size_t i = 0; i < min_parts; i++) {
  424.         if (NStr::Compare(dir_from_parts[i], 
  425.                           dir_to_parts[i],
  426.                           DIR_PARTS_CMP_MODE) != 0) {
  427.             common_length = i;
  428.             break;
  429.         }
  430.     }
  431.     for (size_t i = common_length; i < dir_from_parts.size(); i++) {
  432.         path += "..";
  433.         path += GetPathSeparator();
  434.     }
  435.     for (size_t i = common_length; i < dir_to_parts.size(); i++) {
  436.         path += dir_to_parts[i];
  437.         path += GetPathSeparator();
  438.     }
  439.     
  440.     return path + base_to + ext_to;
  441. #else
  442.     NCBI_THROW(CFileException, eRelativePath, 
  443.                "not implemented");
  444.     return string();
  445. #endif
  446. }
  447. string CDirEntry::ConvertToOSPath(const string& path)
  448. {
  449.     // Not process empty and absolute path
  450.     if ( path.empty() || IsAbsolutePathEx(path) ) {
  451.         return path;
  452.     }
  453.     // Now we have relative "path"
  454.     string xpath = path;
  455.     // Add trailing separator if path ends with DIR_PARENT or DIR_CURRENT
  456. #if defined(DIR_PARENT)
  457.     if ( NStr::EndsWith(xpath, DIR_PARENT) )  {
  458.         xpath += DIR_SEPARATOR;
  459.     }
  460. #endif
  461. #if defined(DIR_CURRENT)
  462.     if ( NStr::EndsWith(xpath, DIR_CURRENT) )  {
  463.         xpath += DIR_SEPARATOR;
  464.     }
  465. #endif
  466.     // Replace each path separator with the current OS separator character
  467.     for (size_t i = 0; i < xpath.length(); i++) {
  468.         char c = xpath[i];
  469.         if ( c == '\' || c == '/' || c == ':') {
  470.             xpath[i] = DIR_SEPARATOR;
  471.         }
  472.     }
  473. #if defined(NCBI_OS_MAC)
  474.     // Fix current and parent refs in the path for MAC
  475.     string xsearch= "..:";
  476.     size_t pos = 0;
  477.     while ((pos = xpath.find(xsearch)) != NPOS) {
  478.         xpath.replace(pos, xsearch.length(), ":");
  479.         if ( xpath.substr(pos + 1, 2) == ".:" )  {
  480.             xpath.erase(pos + 1, 2);
  481.         } else {
  482.             if ( xpath.substr(pos + 1, xsearch.length()) != xsearch )  {
  483.                 xpath.insert(pos,":");
  484.             }
  485.         }
  486.     }
  487.     xpath = NStr::Replace(xpath, ".:", kEmptyStr);
  488.     // Add leading ":" (criterion of relativity of the dir)
  489.     if ( xpath[0] != ':' ) {
  490.         xpath = ":" + xpath;
  491.     }
  492. #else
  493.     // Fix current and parent refs in the path after conversion from MAC path
  494.     // Replace all "::" to "/../"
  495.     string xsearch  = string(2,DIR_SEPARATOR);
  496.     string xreplace = string(1,DIR_SEPARATOR) + DIR_PARENT + DIR_SEPARATOR;
  497.     size_t pos = 0;
  498.     while ((pos = xpath.find(xsearch, pos)) != NPOS ) {
  499.         xpath.replace(pos, xsearch.length(), xreplace);
  500.     }
  501.     // Remove leading ":" in the relative path on non-MAC platforms 
  502.     if ( xpath[0] == DIR_SEPARATOR ) {
  503.         xpath.erase(0,1);
  504.     }
  505.     // Replace something like "../aaa/../bbb/ccc" with "../bbb/ccc"
  506.     xpath = NormalizePath(xpath);
  507. #endif
  508.     return xpath;
  509. }
  510. string CDirEntry::ConcatPath(const string& first, const string& second)
  511. {
  512.     // Prepare first part of path
  513.     string path = AddTrailingPathSeparator(NStr::TruncateSpaces(first));
  514.     // Remove leading separator in "second" part
  515.     string part = NStr::TruncateSpaces(second);
  516.     if ( part.length() > 0  &&  part[0] == DIR_SEPARATOR ) {
  517.         part.erase(0,1);
  518.     }
  519.     // Add second part
  520.     path += part;
  521.     return path;
  522. }
  523. string CDirEntry::ConcatPathEx(const string& first, const string& second)
  524. {
  525.     // Prepare first part of path
  526.     string path = NStr::TruncateSpaces(first);
  527.     // Add trailing path separator to first part (OS independence)
  528.     size_t pos = path.length();
  529. #if defined(NCBI_OS_MAC)
  530.     if ( !pos ) {
  531.         path = string(1,GetPathSeparator());
  532.     }
  533. #endif
  534.     if ( pos  &&  string(ALL_OS_SEPARATORS).find(path.at(pos-1)) == NPOS ) {
  535.         // Find used path separator
  536.         char sep = GetPathSeparator();
  537.         size_t sep_pos = path.find_last_of(ALL_OS_SEPARATORS);
  538.         if ( sep_pos != NPOS ) {
  539.             sep = path.at(sep_pos);
  540.         }
  541.         path += sep;
  542.     }
  543.     // Remove leading separator in "second" part
  544.     string part = NStr::TruncateSpaces(second);
  545.     if ( part.length() > 0  &&
  546.          string(ALL_OS_SEPARATORS).find(part[0]) != NPOS ) {
  547.         part.erase(0,1);
  548.     }
  549.     // Add second part
  550.     path += part;
  551.     return path;
  552. }
  553. string CDirEntry::NormalizePath(const string& path, EFollowLinks follow_links)
  554. {
  555. #if defined(NCBI_OS_MSWIN)  ||  defined(NCBI_OS_UNIX)
  556.     static const char kSeps[] = { DIR_SEPARATOR,
  557. #  ifdef DIR_SEPARATOR_ALT
  558.                                   DIR_SEPARATOR_ALT,
  559. #  endif
  560.                                   '' };
  561.     list<string> head;              // already resolved to our satisfaction
  562.     string       current    = path; // to resolve next
  563.     list<string> tail;              // to resolve afterwards
  564.     int          link_depth = 0;
  565.     while ( !current.empty()  ||  !tail.empty() ) {
  566.         list<string> pretail;
  567.         if ( !current.empty() ) {
  568.             NStr::Split(current, kSeps, pretail, NStr::eNoMergeDelims);
  569.             current.erase();
  570.             if (pretail.front().empty()
  571. #  ifdef DISK_SEPARATOR
  572.                 ||  pretail.front().find(DISK_SEPARATOR) != NPOS
  573. #  endif
  574.                 ) {
  575.                 // absolute path
  576.                 head.clear();
  577. #  ifdef NCBI_OS_MSWIN
  578.                 // Remove leading "\?". Replace leading "\?UNC" with "\"
  579.                 static const char* const kUNC[] = { "", "", "?", "UNC" };
  580.                 list<string>::iterator it = pretail.begin();
  581.                 unsigned int matched = 0;
  582.                 while (matched < 4  &&  it != pretail.end()
  583.                        &&  !NStr::CompareNocase(*it, kUNC[matched])) {
  584.                     ++it;
  585.                     ++matched;
  586.                 }
  587.                 pretail.erase(pretail.begin(), it);
  588.                 switch (matched) {
  589.                 case 2: case 4: // got a UNC path (\... or \?UNC...)
  590.                     head.push_back(kEmptyStr);
  591.                     // fall through
  592.                 case 1: case 3/*?*/: // normal volume-less absolute path
  593.                     head.push_back(kEmptyStr);
  594.                     break;
  595.                 }
  596. #  endif
  597.             }
  598.             tail.splice(tail.begin(), pretail);
  599.         }
  600.         string next = tail.front();
  601.         tail.pop_front();
  602.         if ( !head.empty() ) { // empty heads should accept anything
  603.             string& last = head.back();
  604.             if (last == DIR_CURRENT) {
  605.                 head.pop_back();
  606.                 _ASSERT(head.empty());
  607.             } else if (next == DIR_CURRENT) {
  608.                 continue; // leave out, since we already have content
  609. #  ifdef DISK_SEPARATOR
  610.             } else if (last[last.size()-1] == DISK_SEPARATOR) {
  611.                 // allow almost anything right after a volume specification
  612. #  endif
  613.             } else if (next.empty()) {
  614.                 continue; // leave out empty components in most cases
  615.             } else if (next == DIR_PARENT) {
  616. #  ifdef DISK_SEPARATOR
  617.                 SIZE_TYPE pos;
  618. #  endif
  619.                 // back up if possible, assuming existing path to be "physical"
  620.                 if (last.empty()) {
  621.                     // already at the root; .. is a no-op
  622.                     continue;
  623. #  ifdef DISK_SEPARATOR
  624.                 } else if ((pos = last.find(DISK_SEPARATOR) != NPOS)) {
  625.                     last.erase(pos + 1);
  626. #  endif
  627.                 } else if (last != DIR_PARENT) {
  628.                     head.pop_back();
  629.                     continue;
  630.                 }
  631.             }
  632.         }
  633. #  ifdef NCBI_OS_UNIX
  634.         // Is there a Windows equivalent for readlink?
  635.         if (follow_links) {
  636.             string s(head.empty() ? next
  637.                      : NStr::Join(head, string(1, DIR_SEPARATOR))
  638.                      + DIR_SEPARATOR + next);
  639.             char buf[PATH_MAX];
  640.             int  length = readlink(s.c_str(), buf, sizeof(buf));
  641.             if (length > 0) {
  642.                 current.assign(buf, length);
  643.                 if (++link_depth >= 1024) {
  644.                     ERR_POST(Warning << "CDirEntry::NormalizePath: "
  645.                              "Reached symlink depth limit " << link_depth
  646.                              << " when resolving " << path);
  647.                     follow_links = eIgnoreLinks;
  648.                 }
  649.                 continue;
  650.             }
  651.         }
  652. #  endif
  653.         // normal case: just append the next element to head
  654.         head.push_back(next);
  655.     }
  656.     return NStr::Join(head, string(1, DIR_SEPARATOR));
  657. #else // Not Unix or  Windows
  658.     // NOT implemented!
  659.     return path;
  660. #endif
  661. }
  662. // Match "name" against the filename "mask", returning TRUE if
  663. // it matches, FALSE if not.  
  664. //
  665. bool CDirEntry::MatchesMask(const char* name, const char* mask) 
  666. {
  667.     return NStr::MatchesMask(name, mask);
  668. }
  669. bool CDirEntry::GetMode(TMode* user_mode, TMode* group_mode, TMode* other_mode)
  670.     const
  671. {
  672. #if defined(NCBI_OS_MAC)
  673.     FSSpec fss = FSS();
  674.     OSErr err = FSpCheckObjectLock(&fss);
  675.     if (err != noErr  &&  err != fLckdErr) {
  676.         return false;
  677.     }
  678.     bool locked = (err == fLckdErr);
  679.     TMode mode = fRead | (locked ? 0 : fWrite);
  680.     // User
  681.     if (user_mode) {
  682.         *user_mode = mode;
  683.     }
  684.     // Group
  685.     if (group_mode) {
  686.         *group_mode = mode;
  687.     }
  688.     // Other
  689.     if (other_mode) {
  690.         *other_mode = mode;
  691.     }
  692.     return true;
  693. #else
  694.     struct stat st;
  695.     if (stat(GetPath().c_str(), &st) != 0) {
  696.         return false;
  697.     }
  698.     // Other
  699.     if (other_mode) {
  700.         *other_mode = st.st_mode & 0007;
  701.     }
  702.     st.st_mode >>= 3;
  703.     // Group
  704.     if (group_mode) {
  705.         *group_mode = st.st_mode & 0007;
  706.     }
  707.     st.st_mode >>= 3;
  708.     // User
  709.     if (user_mode) {
  710.         *user_mode = st.st_mode & 0007;
  711.     }
  712.     return true;
  713. #endif
  714. }
  715. bool CDirEntry::SetMode(TMode user_mode, TMode group_mode, TMode other_mode)
  716.     const
  717. {
  718.     if (user_mode == fDefault) {
  719.         user_mode = m_DefaultMode[eUser];
  720.     }
  721. #if defined(NCBI_OS_MAC)
  722.     bool wantLocked = (user_mode & fWrite) == 0;
  723.     FSSpec fss = FSS();
  724.     OSErr  err = FSpCheckObjectLock(&fss);
  725.     if (err != noErr  &&  err != fLckdErr) {
  726.         return false;
  727.     }
  728.     bool locked = (err == fLckdErr);
  729.     if (locked == wantLocked) {
  730.         return true;
  731.     }
  732.     err = wantLocked 
  733.         ? ::FSpSetFLock(&fss) 
  734.         : ::FSpRstFLock(&fss);
  735.     return err == noErr;
  736. #else
  737.     if (group_mode == fDefault) {
  738.         group_mode = m_DefaultMode[eGroup];
  739.     }
  740.     if (other_mode == fDefault) {
  741.         other_mode = m_DefaultMode[eOther];
  742.     }
  743.     TMode mode = s_ConstructMode(user_mode, group_mode, other_mode);
  744.     return chmod(GetPath().c_str(), mode) == 0;
  745. #endif
  746. }
  747. void CDirEntry::SetDefaultModeGlobal(EType entry_type, TMode user_mode, 
  748.                                      TMode group_mode, TMode other_mode)
  749. {
  750.     if (entry_type >= eUnknown ) {
  751.         return;
  752.     }
  753.     if (entry_type == eDir ) {
  754.         if ( user_mode == fDefault ) {
  755.             user_mode = fDefaultDirUser;
  756.         }
  757.         if ( group_mode == fDefault ) {
  758.             group_mode = fDefaultDirGroup;
  759.         }
  760.         if ( other_mode == fDefault ) {
  761.             other_mode = fDefaultDirOther;
  762.         }
  763.     } else {
  764.         if ( user_mode == fDefault ) {
  765.             user_mode = fDefaultUser;
  766.         }
  767.         if ( group_mode == fDefault ) {
  768.             group_mode = fDefaultGroup;
  769.         }
  770.         if ( other_mode == fDefault ) {
  771.             other_mode = fDefaultOther;
  772.         }
  773.     }
  774.     m_DefaultModeGlobal[entry_type][eUser]  = user_mode;
  775.     m_DefaultModeGlobal[entry_type][eGroup] = group_mode;
  776.     m_DefaultModeGlobal[entry_type][eOther] = other_mode;
  777. }
  778. void CDirEntry::SetDefaultMode(EType entry_type, TMode user_mode, 
  779.                                TMode group_mode, TMode other_mode)
  780. {
  781.     if ( user_mode == fDefault ) {
  782.         user_mode = m_DefaultModeGlobal[entry_type][eUser];
  783.     }
  784.     if ( group_mode == fDefault ) {
  785.         group_mode = m_DefaultModeGlobal[entry_type][eGroup];
  786.     }
  787.     if ( other_mode == fDefault ) {
  788.         other_mode = m_DefaultModeGlobal[entry_type][eOther];
  789.     }
  790.     m_DefaultMode[eUser]  = user_mode;
  791.     m_DefaultMode[eGroup] = group_mode;
  792.     m_DefaultMode[eOther] = other_mode;
  793. }
  794. void CDirEntry::GetDefaultModeGlobal(EType  entry_type, TMode* user_mode,
  795.                                      TMode* group_mode, TMode* other_mode)
  796. {
  797.     if ( user_mode ) {
  798.         *user_mode = m_DefaultModeGlobal[entry_type][eUser];
  799.     }
  800.     if ( group_mode ) {
  801.         *group_mode = m_DefaultModeGlobal[entry_type][eGroup];
  802.     }
  803.     if ( other_mode ) {
  804.         *other_mode = m_DefaultModeGlobal[entry_type][eOther];
  805.     }
  806. }
  807. void CDirEntry::GetDefaultMode(TMode* user_mode, TMode* group_mode,
  808.                                TMode* other_mode) const
  809. {
  810.     if ( user_mode ) {
  811.         *user_mode = m_DefaultMode[eUser];
  812.     }
  813.     if ( group_mode ) {
  814.         *group_mode = m_DefaultMode[eGroup];
  815.     }
  816.     if ( other_mode ) {
  817.         *other_mode = m_DefaultMode[eOther];
  818.     }
  819. }
  820. bool CDirEntry::GetTime(CTime *modification,
  821.                         CTime *creation, CTime *last_access) const
  822. {
  823.     struct stat st;
  824.     if (stat(GetPath().c_str(), &st) != 0) {
  825.         return false;
  826.     }
  827.     if (modification) {
  828.         modification->SetTimeT(st.st_mtime);
  829.     }
  830.     if (creation) {
  831.         creation->SetTimeT(st.st_ctime);
  832.     }
  833.     if (last_access) {
  834.         last_access->SetTimeT(st.st_atime);
  835.     }
  836.     return true;
  837. }
  838. bool CDirEntry::SetTime(CTime *modification, CTime *last_access) const
  839. {
  840.     struct utimbuf times;
  841.     times.modtime = modification ? modification->GetTimeT() : time(0);
  842.     times.actime = last_access ? last_access->GetTimeT() : time(0);
  843.     return utime(GetPath().c_str(), &times) == 0;
  844. }
  845.  
  846. CDirEntry::EType CDirEntry::GetType(EFollowLinks follow) const
  847. {
  848. #if defined(NCBI_OS_MAC)
  849.     OSErr   err;
  850.     long    dirID;
  851.     Boolean isDir;
  852.     err = FSpGetDirectoryID(&FSS(), &dirID, &isDir);
  853.     if ( err ) {
  854.         return eUnknown;
  855.     }
  856.     return isDir ? eDir : eFile;
  857. #else
  858.     struct stat st;
  859.     int         errcode;
  860. #  if defined(NCBI_OS_MSWIN)
  861.     errcode = stat(GetPath().c_str(), &st);
  862. #  elif defined(NCBI_OS_UNIX)
  863.     if (follow == eFollowLinks) {
  864.         errcode = stat(GetPath().c_str(), &st);
  865.     } else {
  866.         errcode = lstat(GetPath().c_str(), &st);
  867.     }
  868. #  endif
  869.     if (errcode != 0) {
  870.         return eUnknown;
  871.     }
  872.     unsigned int mode = st.st_mode & S_IFMT;
  873.     switch (mode) {
  874.     case S_IFDIR:
  875.         return eDir;
  876.     case S_IFCHR:
  877.         return eCharSpecial;
  878. #  if defined(NCBI_OS_MSWIN)
  879.     case _S_IFIFO:
  880.         return ePipe;
  881. #  elif defined(NCBI_OS_UNIX)
  882.     case S_IFIFO:
  883.         return ePipe;
  884.     case S_IFLNK:
  885.         return eLink;
  886.     case S_IFSOCK:
  887.         return eSocket;
  888.     case S_IFBLK:
  889.         return eBlockSpecial;
  890. #    if defined(S_IFDOOR) /* only Solaris seems to have this */
  891.     case S_IFDOOR:
  892.         return eDoor;
  893. #    endif
  894. #  endif
  895.     }
  896.     // Check regular file bit last
  897.     if ( (st.st_mode & S_IFREG)  == S_IFREG ) {
  898.         return eFile;
  899.     }
  900.     return eUnknown;
  901. #endif
  902. }
  903. bool CDirEntry::Rename(const string& newname)
  904. {
  905. #if defined(NCBI_OS_MAC)
  906.     const int maxFilenameLength = 31;
  907.     if (newname.length() > maxFilenameLength) return false;
  908.     Str31 newNameStr;
  909.     Pstrcpy(newNameStr, newname.c_str());
  910.     OSErr err = FSpRename(&FSS(), newNameStr);
  911.     if (err != noErr) return false;
  912. #else
  913.     if (rename(GetPath().c_str(), newname.c_str()) != 0) {
  914.         return false;
  915.     }
  916. #endif
  917.     Reset(newname);
  918.     return true;
  919. }
  920. bool CDirEntry::Remove(EDirRemoveMode mode) const
  921. {
  922. #if defined(NCBI_OS_MAC)
  923.     OSErr err = ::FSpDelete(&FSS());
  924.     return err == noErr;
  925. #else
  926.     if ( IsDir(eIgnoreLinks) ) {
  927.         if (mode == eOnlyEmpty) {
  928.             return rmdir(GetPath().c_str()) == 0;
  929.         } else {
  930.             CDir dir(GetPath());
  931.             return dir.Remove(eRecursive);
  932.         }
  933.     } else {
  934.         return remove(GetPath().c_str()) == 0;
  935.     }
  936. #endif
  937. }
  938. //////////////////////////////////////////////////////////////////////////////
  939. //
  940. // CFile
  941. //
  942. CFile::CFile(const string& filename) : CParent(filename)
  943.     // Set default mode
  944.     SetDefaultMode(eFile, fDefault, fDefault, fDefault);
  945. }
  946. CFile::~CFile(void)
  947.     return;
  948. }
  949. Int8 CFile::GetLength(void) const
  950. {
  951. #if defined(NCBI_OS_MAC)
  952.     long dataSize, rsrcSize;
  953.     OSErr err = FSpGetFileSize(&FSS(), &dataSize, &rsrcSize);
  954.     if (err != noErr) {
  955.         return -1;
  956.     } else {
  957.         return dataSize;
  958.     }
  959. #else
  960.     struct stat buf;
  961.     if ( stat(GetPath().c_str(), &buf) != 0 ) {
  962.         return -1;
  963.     }
  964.     return buf.st_size;
  965. #endif
  966. }
  967. string CFile::GetTmpName(ETmpFileCreationMode mode)
  968. {
  969. #if defined(NCBI_OS_MSWIN)  ||  defined(NCBI_OS_UNIX)
  970.     return GetTmpNameEx(kEmptyStr, kEmptyStr, mode);
  971. #else
  972.     if (mode == eTmpFileCreate) {
  973.         ERR_POST(Warning << "CFile::GetTmpNameEx: "
  974.                  "The temporary file cannot be auto-created on this " 
  975.                  "platform, returns its name only");
  976.     }
  977.     char* filename = tempnam(0,0);
  978.     if ( !filename ) {
  979.         return kEmptyStr;
  980.     }
  981.     string res(filename);
  982.     free(filename);
  983.     return res;
  984. #endif
  985. }
  986. #if !defined(NCBI_OS_UNIX)
  987. static string s_StdGetTmpName(const char* dir, const char* prefix)
  988. {
  989.     char* filename = tempnam(dir, prefix);
  990.     if ( !filename ) {
  991.         return kEmptyStr;
  992.     }
  993.     string str(filename);
  994.     free(filename);
  995.     return str;
  996. }
  997. #endif
  998. string CFile::GetTmpNameEx(const string&        dir, 
  999.                            const string&        prefix,
  1000.                            ETmpFileCreationMode mode)
  1001. {
  1002. #if defined(NCBI_OS_MSWIN)  ||  defined(NCBI_OS_UNIX)
  1003.     string x_dir = dir;
  1004.     if ( x_dir.empty() ) {
  1005.         x_dir = CDir::GetTmpDir();
  1006.     }
  1007.     if ( !x_dir.empty() ) {
  1008.         x_dir = AddTrailingPathSeparator(x_dir);
  1009.     }
  1010.     string fn;
  1011. #  if defined(NCBI_OS_UNIX)
  1012.     string pattern = x_dir + prefix + "XXXXXX";
  1013.     AutoPtr<char, CDeleter<char> > filename(strdup(pattern.c_str()));
  1014.     int fd = mkstemp(filename.get());
  1015.     close(fd);
  1016.     if (mode != eTmpFileCreate) {
  1017.         remove(filename.get());
  1018.     }
  1019.     fn = filename.get();
  1020. #  elif defined(NCBI_OS_MSWIN)
  1021.     if (mode == eTmpFileGetName) {
  1022.         fn = s_StdGetTmpName(dir.c_str(), prefix.c_str());
  1023.     } else {
  1024.         char   buffer[MAX_PATH];
  1025.         HANDLE hFile = INVALID_HANDLE_VALUE;
  1026.         srand((unsigned)time(0));
  1027.         unsigned long ofs = rand();
  1028.         while ( ofs < numeric_limits<unsigned long>::max() ) {
  1029.             _ultoa((unsigned long)ofs, buffer, 24);
  1030.             fn = x_dir + prefix + buffer;
  1031.             hFile = CreateFile(fn.c_str(), GENERIC_ALL, 0, NULL,
  1032.                                CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY, NULL);
  1033.             if (hFile != INVALID_HANDLE_VALUE) {
  1034.                 break;
  1035.             }
  1036.             ofs++;
  1037.         }
  1038.         CloseHandle(hFile);
  1039.         if (ofs == numeric_limits<unsigned long>::max() ) {
  1040.             return kEmptyStr;
  1041.         }
  1042.         if (mode != eTmpFileCreate) {
  1043.             remove(fn.c_str());
  1044.         }
  1045.     }
  1046. #  endif
  1047. #else // defined(NCBI_OS_MSWIN)  ||  defined(NCBI_OS_UNIX)
  1048.     if (mode == eTmpFileCreate) {
  1049.         ERR_POST(Warning << "CFile::GetTmpNameEx: "
  1050.                  "The file cannot be auto-created on this platform, " 
  1051.                  "return its name only");
  1052.     }
  1053.     fn = s_StdGetTmpName(dir.c_str(), prefix.c_str());
  1054. #endif
  1055.     return fn;
  1056. }
  1057. class CTmpStream : public fstream
  1058. {
  1059. public:
  1060.     CTmpStream(const char *s, IOS_BASE::openmode mode) : fstream(s, mode) 
  1061.     {
  1062.         m_FileName = s; 
  1063.     }
  1064.     virtual ~CTmpStream(void) 
  1065.     { 
  1066.         close();
  1067.         CFile(m_FileName).Remove();
  1068.     }
  1069. protected:
  1070.     string m_FileName;
  1071. };
  1072. fstream* CFile::CreateTmpFile(const string& filename, 
  1073.                               ETextBinary text_binary,
  1074.                               EAllowRead  allow_read)
  1075. {
  1076.     ios::openmode mode = ios::out | ios::trunc;
  1077.     if ( text_binary == eBinary ) {
  1078.         mode = mode | ios::binary;
  1079.     }
  1080.     if ( allow_read == eAllowRead ) {
  1081.         mode = mode | ios::in;
  1082.     }
  1083.     string tmpname = filename.empty() ? GetTmpName(eTmpFileCreate) : filename;
  1084.     if ( tmpname.empty() ) {
  1085.         return 0;
  1086.     }
  1087.     fstream* stream = new CTmpStream(tmpname.c_str(), mode);
  1088.     return stream;
  1089. }
  1090. fstream* CFile::CreateTmpFileEx(const string& dir, const string& prefix,
  1091.                                 ETextBinary text_binary, 
  1092.                                 EAllowRead allow_read)
  1093. {
  1094.     return CreateTmpFile(GetTmpNameEx(dir, prefix, eTmpFileCreate),
  1095.                          text_binary, allow_read);
  1096. }
  1097. //////////////////////////////////////////////////////////////////////////////
  1098. //
  1099. // CDir
  1100. //
  1101. CDir::CDir(void)
  1102. {
  1103.     return;
  1104. }
  1105. #if defined(NCBI_OS_MAC)
  1106. CDir::CDir(const FSSpec& fss) : CParent(fss)
  1107. {
  1108.     // Set default mode
  1109.     SetDefaultMode(eDir, fDefault, fDefault, fDefault);
  1110. }
  1111. #endif
  1112. CDir::CDir(const string& dirname) : CParent(dirname)
  1113. {
  1114.     // Set default mode
  1115.     SetDefaultMode(eDir, fDefault, fDefault, fDefault);
  1116. }
  1117. #if defined(NCBI_OS_UNIX)
  1118. static bool s_GetHomeByUID(string& home)
  1119. {
  1120.     // Get the info using user ID
  1121.     struct passwd *pwd;
  1122.     if ((pwd = getpwuid(getuid())) == 0) {
  1123.         return false;
  1124.     }
  1125.     home = pwd->pw_dir;
  1126.     return true;
  1127. }
  1128. static bool s_GetHomeByLOGIN(string& home)
  1129. {
  1130.     char* ptr = 0;
  1131.     // Get user name
  1132.     if ( !(ptr = getenv("USER")) ) {
  1133.         if ( !(ptr = getenv("LOGNAME")) ) {
  1134.             if ( !(ptr = getlogin()) ) {
  1135.                 return false;
  1136.             }
  1137.         }
  1138.     }
  1139.     // Get home dir for this user
  1140.     struct passwd* pwd = getpwnam(ptr);
  1141.     if ( !pwd ||  pwd->pw_dir[0] == '') {
  1142.         return false;
  1143.     }
  1144.     home = pwd->pw_dir;
  1145.     return true;
  1146. }
  1147. #endif // NCBI_OS_UNIX
  1148. string CDir::GetHome(void)
  1149. {
  1150.     char*  str;
  1151.     string home;
  1152. #if defined(NCBI_OS_MSWIN)
  1153.     // Get home dir from environment variables
  1154.     // like - C:Documents and SettingsuserApplication Data
  1155.     str = getenv("APPDATA");
  1156.     if ( str ) {
  1157.         home = str;
  1158.     } else {
  1159.         // like - C:Documents and Settingsuser
  1160.         str = getenv("USERPROFILE");
  1161.         if ( str ) {
  1162.             home = str;
  1163.         }
  1164.     }
  1165.    
  1166. #elif defined(NCBI_OS_UNIX)
  1167.     // Try get home dir from environment variable
  1168.     str = getenv("HOME");
  1169.     if ( str ) {
  1170.         home = str;
  1171.     } else {
  1172.         // Try to retrieve the home dir -- first use user's ID, and if failed, 
  1173.         // then use user's login name.
  1174.         if ( !s_GetHomeByUID(home) ) { 
  1175.             s_GetHomeByLOGIN(home);
  1176.         }
  1177.     }
  1178.    
  1179. #elif defined(NCBI_OS_MAC)
  1180.     // Make sure we can use FindFolder() if not, report error
  1181.     long gesResponse;
  1182.     if (Gestalt(gestaltFindFolderAttr, &gesResponse) != noErr  ||
  1183.         (gesResponse & (1 << gestaltFindFolderPresent) == 0)) {
  1184.         return kEmptyStr;
  1185.     }
  1186.     // Store the current active directory
  1187.     long  saveDirID;
  1188.     short saveVRefNum;
  1189.     HGetVol((StringPtr) 0, &saveVRefNum, &saveDirID);
  1190.     // Find the preferences folder in the active System folder
  1191.     short vRefNum;
  1192.     long  dirID;
  1193.     OSErr err = FindFolder(kOnSystemDisk, kPreferencesFolderType,
  1194.                            kCreateFolder, &vRefNum, &dirID);
  1195.     FSSpec spec;
  1196.     if (err == noErr) {
  1197.         char dummy[FILENAME_MAX+1];
  1198.         dummy [0] = '';
  1199.         err = FSMakeFSSpec(vRefNum, dirID, (StringPtr) dummy, &spec);
  1200.     }
  1201.     // Restore the current active directory
  1202.     HSetVol((StringPtr) 0, saveVRefNum, saveDirID);
  1203.     // Convert to C++ string
  1204.     if (err == noErr) {
  1205.         str = 0;
  1206.         err = MacFSSpec2FullPathname(&spec, &str);
  1207.         home = str;
  1208.     }
  1209. #endif 
  1210.     // Add trailing separator if needed
  1211.     return AddTrailingPathSeparator(home);
  1212. }
  1213. string CDir::GetTmpDir(void)
  1214. {
  1215.     string tmp;
  1216. #if defined(NCBI_OS_UNIX)
  1217.     char* tmpdir = getenv("TMPDIR");
  1218.     if ( tmpdir ) {
  1219.         tmp = tmpdir;
  1220.     } else  {
  1221. #  if defined(P_tmpdir)
  1222.         tmp = P_tmpdir;
  1223. #  else
  1224.         tmp = "/tmp";
  1225. #  endif
  1226.     }
  1227. #elif defined(NCBI_OS_MSWIN)
  1228.     char* tmpdir = getenv("TEMP");
  1229.     if ( tmpdir ) {
  1230.         tmp = tmpdir;
  1231.     } else  {
  1232. #  if defined(P_tmpdir)
  1233.         tmp = P_tmpdir;
  1234. #  else
  1235.         tmp = CDir::GetHome();
  1236. #  endif
  1237.     }
  1238. #endif
  1239.     return tmp;
  1240. }
  1241. string CDir::GetCwd()
  1242. {
  1243.     string cwd;
  1244. #if defined(NCBI_OS_UNIX)
  1245.     char buf[4096];
  1246.     if (getcwd(buf, sizeof(buf) - 1)) {
  1247.         cwd = buf;
  1248.     }
  1249. #elif defined(NCBI_OS_MSWIN)
  1250.     char buf[4096];
  1251.     if (_getcwd(buf, sizeof(buf) - 1)) {
  1252.         cwd = buf;
  1253.     }
  1254. #endif
  1255.     return cwd;
  1256. }
  1257. CDir::~CDir(void)
  1258. {
  1259.     return;
  1260. }
  1261. #if defined(NCBI_OS_MAC)
  1262. static const CDirEntry MacGetIndexedItem(const CDir& container, SInt16 index)
  1263. {
  1264.     FSSpec dir = container.FSS();
  1265.     FSSpec fss;     // FSSpec of item gotten.
  1266.     SInt16 actual;  // Actual number of items gotten.  Should be one or zero.
  1267.     SInt16 itemIndex = index;
  1268.     OSErr err = GetDirItems(dir.vRefNum, dir.parID, dir.name, true, true, 
  1269.                             &fss, 1, &actual, &itemIndex);
  1270.     if (err != noErr) {
  1271.         throw err;
  1272.     }
  1273.     return CDirEntry(fss);
  1274. }
  1275. #endif
  1276. CDir::TEntries CDir::GetEntries(const string&   mask,
  1277.                                 EGetEntriesMode mode) const
  1278. {
  1279.     TEntries contents;
  1280.     string x_mask    = mask.empty() ? string("*") : mask;
  1281.     string path_base = GetPath();
  1282.     if ( path_base[path_base.size() - 1] != GetPathSeparator() ) {
  1283.         path_base += GetPathSeparator();
  1284.     }
  1285. #if defined(NCBI_OS_MSWIN)
  1286.     // Append to the "path" mask for all files in directory
  1287.     string pattern = path_base + x_mask;
  1288.     // Open directory stream and try read info about first entry
  1289.     struct _finddata_t entry;
  1290.     long desc = _findfirst(pattern.c_str(), &entry);  // get first entry's name
  1291.     if (desc != -1) {
  1292.         CDirEntry* dir_entry = new CDirEntry(path_base + entry.name);
  1293.         if (mode == eIgnoreRecursive) {
  1294.             if ((::strcmp(entry.name, ".") == 0) ||
  1295.                 (::strcmp(entry.name, "..") == 0)) 
  1296.             {
  1297.                 delete dir_entry;
  1298.                 dir_entry = 0;
  1299.             }
  1300.         }
  1301.         if (dir_entry)
  1302.             contents.push_back(dir_entry);
  1303.         while ( _findnext(desc, &entry) != -1 ) {
  1304.             if (mode == eIgnoreRecursive) {
  1305.                 if ((::strcmp(entry.name, ".") == 0) ||
  1306.                     (::strcmp(entry.name, "..") == 0)) continue;
  1307.             }
  1308.             contents.push_back(new CDirEntry(path_base + entry.name));
  1309.         }
  1310.         _findclose(desc);
  1311.     }
  1312. #elif defined(NCBI_OS_UNIX)
  1313.     DIR* dir = opendir(GetPath().c_str());
  1314.     if ( dir ) {
  1315.         while (struct dirent* entry = readdir(dir)) {
  1316.             if ( MatchesMask(entry->d_name, x_mask.c_str()) ) {
  1317.                 if (mode == eIgnoreRecursive) {
  1318.                     if ((::strcmp(entry->d_name, ".") == 0) ||
  1319.                         (::strcmp(entry->d_name, "..") == 0)) continue;
  1320.                 }
  1321.                 contents.push_back(new CDirEntry(path_base + entry->d_name));
  1322.             }
  1323.         }
  1324.         closedir(dir);
  1325.     }
  1326. #elif defined(NCBI_OS_MAC)
  1327.     try {
  1328.         for (int index = 1;  ;  index++) {
  1329.             CDirEntry entry = MacGetIndexedItem(*this, index);
  1330.             if ( MatchesMask(entry.GetName().c_str(), x_mask.c_str()) ) {
  1331.                 contents.push_back(new CDirEntry(entry));
  1332.             }
  1333.         }
  1334.     } catch (OSErr& err) {
  1335.         if (err != fnfErr) {
  1336.             throw COSErrException_Mac(err, "CDir::GetEntries() ");
  1337.         }
  1338.     }
  1339. #endif
  1340.     return contents;
  1341. }
  1342. CDir::TEntries CDir::GetEntries(const vector<string>&  masks,
  1343.                                 EGetEntriesMode        mode) const
  1344. {
  1345.     if (masks.empty())
  1346.         return GetEntries();
  1347.     TEntries contents;
  1348.     string path_base = GetPath();
  1349.     if ( path_base[path_base.size() - 1] != GetPathSeparator() ) {
  1350.         path_base += GetPathSeparator();
  1351.     }
  1352. #if defined(NCBI_OS_MSWIN)
  1353.     // Append to the "path" mask for all files in directory
  1354.     string pattern = path_base + string("*");
  1355.     bool skip_recursive_entry;
  1356.     // Open directory stream and try read info about first entry
  1357.     struct _finddata_t entry;
  1358.     long desc = _findfirst(pattern.c_str(), &entry);  // get first entry's name
  1359.     if (desc != -1) {
  1360.         skip_recursive_entry =
  1361.             (mode == eIgnoreRecursive) &&
  1362.             ((::strcmp(entry.name, ".") == 0) ||
  1363.              (::strcmp(entry.name, "..") == 0));
  1364.         // check all masks
  1365.         if (!skip_recursive_entry) {
  1366.             ITERATE(vector<string>, it, masks) {
  1367.                 const string& mask = *it;
  1368.                 if (mask.empty()) {
  1369.                     contents.push_back(new CDirEntry(path_base + entry.name));
  1370.                     break;
  1371.                 }
  1372.                 if (MatchesMask(entry.name, mask.c_str()) ) {
  1373.                     contents.push_back(new CDirEntry(path_base + entry.name));
  1374.                     break;
  1375.                 }                
  1376.             } // ITERATE
  1377.         }
  1378.         while ( _findnext(desc, &entry) != -1 ) {
  1379.             skip_recursive_entry =
  1380.                 (mode == eIgnoreRecursive) &&
  1381.                 ((::strcmp(entry.name, ".") == 0) ||
  1382.                  (::strcmp(entry.name, "..") == 0));
  1383.             if (skip_recursive_entry) {
  1384.                 continue;
  1385.             }
  1386.             ITERATE(vector<string>, it, masks) {
  1387.                 const string& mask = *it;
  1388.                 if (mask.empty()) {
  1389.                     contents.push_back(new CDirEntry(path_base + entry.name));
  1390.                     break;
  1391.                 }
  1392.                 if (MatchesMask(entry.name, mask.c_str()) ) {
  1393.                     contents.push_back(new CDirEntry(path_base + entry.name));
  1394.                     break;
  1395.                 }
  1396.             } // ITERATE
  1397.         }
  1398.         _findclose(desc);
  1399.     }
  1400. #elif defined(NCBI_OS_UNIX)
  1401.     DIR* dir = opendir(GetPath().c_str());
  1402.     if ( dir ) {
  1403.         while (struct dirent* entry = readdir(dir)) {
  1404.             bool skip_recursive_entry =
  1405.                     (mode == eIgnoreRecursive) &&
  1406.                     ((::strcmp(entry->d_name, ".") == 0) ||
  1407.                      (::strcmp(entry->d_name, "..") == 0));
  1408.             if (skip_recursive_entry) {
  1409.                 continue;
  1410.             }
  1411.             ITERATE(vector<string>, it, masks) {
  1412.                 const string& mask = *it;
  1413.                 if (mask.empty()) {
  1414.                     contents.push_back(
  1415.                          new CDirEntry(path_base + entry->d_name));
  1416.                     break;
  1417.                 }
  1418.                 if ( MatchesMask(entry->d_name, mask.c_str()) ) {
  1419.                     contents.push_back(
  1420.                          new CDirEntry(path_base + entry->d_name));
  1421.                     break;
  1422.                 }
  1423.             } // ITERATE
  1424.         } // while
  1425.         closedir(dir);
  1426.     }
  1427. #elif defined(NCBI_OS_MAC)
  1428.     try {
  1429.         for (int index = 1;  ;  index++) {
  1430.             CDirEntry entry = MacGetIndexedItem(*this, index);
  1431.             ITERATE(vector<string>, it, masks) {
  1432.                 const string& mask = *it;
  1433.                 if (mask.empty()) {
  1434.                     contents.push_back(new CDirEntry(entry));
  1435.                     break;
  1436.                 }
  1437.                 if ( MatchesMask(entry.GetName().c_str(), mask.c_str()) ) {
  1438.                     contents.push_back(new CDirEntry(entry));
  1439.                     break;
  1440.                 }
  1441.             }
  1442.         }
  1443.     } catch (OSErr& err) {
  1444.         if (err != fnfErr) {
  1445.             throw COSErrException_Mac(err, "CDir::GetEntries() ");
  1446.         }
  1447.     }
  1448. #endif
  1449.     return contents;
  1450. }
  1451. bool CDir::Create(void) const
  1452. {
  1453.     TMode user_mode, group_mode, other_mode;
  1454.     GetDefaultMode(&user_mode, &group_mode, &other_mode);
  1455.     TMode mode = s_ConstructMode(user_mode, group_mode, other_mode);
  1456. #if defined(NCBI_OS_MSWIN)
  1457.     if ( mkdir(GetPath().c_str()) != 0 ) {
  1458.         return false;
  1459.     }
  1460.     return chmod(GetPath().c_str(), mode) == 0;
  1461. #elif defined(NCBI_OS_UNIX)
  1462.     return mkdir(GetPath().c_str(), mode) == 0;
  1463. #elif defined(NCBI_OS_MAC)
  1464.     OSErr err;
  1465.     long dirID;
  1466.     err = ::FSpDirCreate(&FSS(), smRoman, &dirID);
  1467.     return err == noErr;
  1468. #endif
  1469. }
  1470. bool CDir::CreatePath(void) const
  1471. {
  1472.     if (Exists()) {
  1473.         return true;
  1474.     }
  1475.     string path(GetPath());
  1476.     if (path.empty()) {
  1477.         return true;
  1478.     }
  1479.     if (path[path.length()-1] == GetPathSeparator()) {
  1480.         path.erase(path.length() - 1);
  1481.     }
  1482.     CDir dir_this(path);
  1483.     if (dir_this.Exists()) {
  1484.         return true;
  1485.     }
  1486.     string path_up = dir_this.GetDir();
  1487.     if (path_up == path) {
  1488.         // special case: is this a disk name?
  1489.         return true;
  1490.     } 
  1491.     CDir dir_up(path_up);
  1492.     if (dir_up.CreatePath()) {
  1493.         return dir_this.Create();
  1494.     }
  1495.     return false;
  1496. }
  1497. bool CDir::Remove(EDirRemoveMode mode) const
  1498. {
  1499.     // Remove directory as empty
  1500.     if ( mode == eOnlyEmpty ) {
  1501.         return CParent::Remove(eOnlyEmpty);
  1502.     }
  1503.     // Read all entryes in derectory
  1504.     TEntries contents = GetEntries();
  1505.     // Remove
  1506.     ITERATE(TEntries, entry, contents) {
  1507.         string name = (*entry)->GetName();
  1508. #if defined(NCBI_OS_MAC)
  1509.         CDirEntry& item = **entry;
  1510. #else
  1511.         if ( name == "."  ||  name == ".."  ||  
  1512.              name == string(1,GetPathSeparator()) ) {
  1513.             continue;
  1514.         }
  1515.         // Get entry item with full pathname
  1516.         CDirEntry item(GetPath() + GetPathSeparator() + name);
  1517. #endif
  1518.         if ( mode == eRecursive ) {
  1519.             if ( !item.Remove(eRecursive) ) {
  1520.                 return false;
  1521.             }
  1522.         } else {
  1523.             if ( item.IsDir(eIgnoreLinks) ) {
  1524.                 continue;
  1525.             }
  1526.             if ( !item.Remove() ) {
  1527.                 return false;
  1528.             }
  1529.         }
  1530.     }
  1531.     // Remove main directory
  1532.     return CParent::Remove(eOnlyEmpty);
  1533. }
  1534. //////////////////////////////////////////////////////////////////////////////
  1535. //
  1536. // CMemoryFile
  1537. //
  1538. // Platform-dependent memory file handle definition
  1539. struct SMemoryFileHandle {
  1540. #if defined(NCBI_OS_MSWIN)
  1541.     HANDLE  hMap;
  1542. #else
  1543.     int     hDummy;
  1544. #endif
  1545. };
  1546. bool CMemoryFile::IsSupported(void)
  1547. {
  1548. #if defined(NCBI_OS_MAC)
  1549.     return false;
  1550. #else
  1551.     return true;
  1552. #endif
  1553. }
  1554. CMemoryFile::CMemoryFile(const string&  file_name,
  1555.                          EMemMapProtect protect,
  1556.                          EMemMapShare   share)
  1557.     : m_Handle(0), m_Size(-1), m_DataPtr(0)
  1558. {
  1559.     x_Map(file_name, protect, share);
  1560.     if (GetSize() < 0) {
  1561.         NCBI_THROW(CFileException, eMemoryMap,
  1562.                    "File memory mapping cannot be created");
  1563.     }
  1564. }
  1565. CMemoryFile::~CMemoryFile(void)
  1566. {
  1567.     Unmap();
  1568. }
  1569. void CMemoryFile::x_Map(const string&  file_name,
  1570.                         EMemMapProtect protect_attr,
  1571.                         EMemMapShare   share_attr)
  1572. {
  1573.     if ( !IsSupported() )
  1574.         return;
  1575.     m_Handle = new SMemoryFileHandle();
  1576.     for (;;) { // quasi-TRY block
  1577.         CFile file(file_name);
  1578.         m_Size = file.GetLength();
  1579.         if (m_Size < 0)
  1580.             break;
  1581.         // Special case
  1582.         if (m_Size == 0)
  1583.             return;
  1584. #if defined(NCBI_OS_MSWIN)
  1585.         // Name of a file-mapping object cannot contain ''
  1586.         string x_name = NStr::Replace(file_name, "\", "/");
  1587.         // Translate attributes 
  1588.         DWORD map_protect = 0, map_access = 0, file_share = 0, file_access = 0;
  1589.         switch (protect_attr) {
  1590.             case eMMP_Read:
  1591.                 map_access  = FILE_MAP_READ;
  1592.                 map_protect = PAGE_READONLY;
  1593.                 file_access = GENERIC_READ;
  1594.                 break;
  1595.             case eMMP_Write:
  1596.             case eMMP_ReadWrite:
  1597.                 // On MS Windows platform Write & ReadWrite access
  1598.                 // to the mapped memory is equivalent
  1599.                 if  (share_attr == eMMS_Shared ) {
  1600.                     map_access = FILE_MAP_ALL_ACCESS;
  1601.                 } else {
  1602.                     map_access = FILE_MAP_COPY;
  1603.                 }
  1604.                 map_protect = PAGE_READWRITE;
  1605.                 // So the file also must be open for reading and writing
  1606.                 file_access = GENERIC_READ | GENERIC_WRITE;
  1607.                 break;
  1608.             default:
  1609.                 _TROUBLE;
  1610.         }
  1611.         if (share_attr == eMMS_Shared) {
  1612.             file_share = FILE_SHARE_READ | FILE_SHARE_WRITE;
  1613.         } else {
  1614.             file_share = 0;
  1615.         }
  1616.         // If failed to attach to an existing file-mapping object then
  1617.         // create a new one (based on the specified file)
  1618.         m_Handle->hMap = OpenFileMapping(map_access, false, x_name.c_str());
  1619.         if ( !m_Handle->hMap ) { 
  1620.             HANDLE hFile = CreateFile(x_name.c_str(), file_access, 
  1621.                                       file_share, NULL, OPEN_EXISTING, 
  1622.                                       FILE_ATTRIBUTE_NORMAL, NULL);
  1623.             if (hFile == INVALID_HANDLE_VALUE)
  1624.                 break;
  1625.             m_Handle->hMap = CreateFileMapping(hFile, NULL, map_protect,
  1626.                                                0, 0, x_name.c_str());
  1627.             CloseHandle(hFile);
  1628.             if ( !m_Handle->hMap )
  1629.                 break;
  1630.         }
  1631.         m_DataPtr = MapViewOfFile(m_Handle->hMap, map_access,
  1632.                                   0, 0, m_Size);
  1633.         if ( !m_DataPtr ) {
  1634.             CloseHandle(m_Handle->hMap);
  1635.             break;
  1636.         }
  1637. #elif defined(NCBI_OS_UNIX)
  1638.         // Translate attributes 
  1639.         int map_protect = 0, map_share = 0, file_access = 0;
  1640.         switch (protect_attr) {
  1641.             case eMMP_Read:
  1642.                 map_protect = PROT_READ;
  1643.                 file_access = O_RDONLY;
  1644.                 break;
  1645.             case eMMP_Write:
  1646.                 map_protect = PROT_WRITE;
  1647.                 if  (share_attr == eMMS_Shared ) {
  1648.                     // Must be read + write
  1649.                     file_access = O_RDWR;
  1650.                 } else {
  1651.                     file_access = O_RDONLY;
  1652.                 }
  1653.                 break;
  1654.             case eMMP_ReadWrite:
  1655.                 map_protect = PROT_READ | PROT_WRITE;
  1656.                 if  (share_attr == eMMS_Shared ) {
  1657.                     file_access = O_RDWR;
  1658.                 } else {
  1659.                     file_access = O_RDONLY;
  1660.                 }
  1661.                 break;
  1662.             default:
  1663.                 _TROUBLE;
  1664.         }
  1665.         switch (share_attr) {
  1666.             case eMMS_Shared:
  1667.                 map_share = MAP_SHARED;
  1668.                 break;
  1669.             case eMMS_Private:
  1670.                 map_share = MAP_PRIVATE;
  1671.                 break;
  1672.             default:
  1673.                 _TROUBLE;
  1674.         }
  1675.         // Open file
  1676.         int fd = open(file_name.c_str(), file_access);
  1677.         if (fd < 0) {
  1678.             break;
  1679.         }
  1680.         // Map file to memory
  1681.         m_DataPtr = mmap(0, (size_t) m_Size, map_protect, map_share, fd, 0);
  1682.         close(fd);
  1683.         if (m_DataPtr == MAP_FAILED) {
  1684.             break;
  1685.         }
  1686. #endif
  1687.         // Success
  1688.         return;
  1689.     }
  1690.     // Error; cleanup
  1691.     delete m_Handle;
  1692.     m_Handle = 0;
  1693.     m_Size = -1;
  1694. }
  1695. bool CMemoryFile::Flush(void) const
  1696. {
  1697.     // If file is not mapped do nothing
  1698.     if ( !m_Handle )
  1699.         return false;
  1700.     bool status = false;
  1701. #if defined(NCBI_OS_MSWIN)
  1702.     status = (FlushViewOfFile(m_DataPtr, 0) != 0);
  1703. #elif defined(NCBI_OS_UNIX)
  1704.     status = (msync((char*)m_DataPtr, (size_t) m_Size, MS_SYNC) == 0);
  1705. #endif
  1706.     return status;
  1707. }
  1708. bool CMemoryFile::Unmap(void)
  1709. {
  1710.     // If file is not mapped do nothing
  1711.     if ( !m_Handle )
  1712.         return true;
  1713.     bool status = false;
  1714. #if defined(NCBI_OS_MSWIN)
  1715.     status = (UnmapViewOfFile(m_DataPtr) != 0);
  1716.     if ( status  &&  m_Handle->hMap )
  1717.         status = (CloseHandle(m_Handle->hMap) != 0);
  1718. #elif defined(NCBI_OS_UNIX)
  1719.     status = (munmap((char*)m_DataPtr, (size_t) m_Size) == 0);
  1720. #endif
  1721.     delete m_Handle;
  1722.     // Reinitialize members
  1723.     m_Handle = 0;
  1724.     m_DataPtr = 0;
  1725.     m_Size = -1;
  1726.     return status;
  1727. }
  1728. #if !defined(HAVE_MADVISE)
  1729. bool CMemoryFile::MemMapAdviseAddr(void*, size_t, EMemMapAdvise) {
  1730.     return true;
  1731. }
  1732. bool CMemoryFile::MemMapAdvise(EMemMapAdvise) {
  1733.     return true;
  1734. }
  1735. #else  /* HAVE_MADVISE */
  1736. bool CMemoryFile::MemMapAdviseAddr(void* addr, size_t len,
  1737.                                    EMemMapAdvise advise)
  1738. {
  1739.     int adv;
  1740.     if (!addr || !len) {
  1741.         return false;
  1742.     }
  1743.     switch (advise) {
  1744.     case eMMA_Random:
  1745.         adv = MADV_RANDOM;     break;
  1746.     case eMMA_Sequential:
  1747.         adv = MADV_SEQUENTIAL; break;
  1748.     case eMMA_WillNeed:
  1749.         adv = MADV_WILLNEED;   break;
  1750.     case eMMA_DontNeed:
  1751.         adv = MADV_DONTNEED;   break;
  1752.     default:
  1753.         adv = MADV_NORMAL;
  1754.     }
  1755.     // Conversion type of "addr" to char* -- Sun Solaris fix
  1756.     return madvise((char*)addr, len, adv) == 0;
  1757. }
  1758. bool CMemoryFile::MemMapAdvise(EMemMapAdvise advise)
  1759. {
  1760.     if (m_DataPtr  &&   m_Size > 0) {
  1761.         return MemMapAdviseAddr(m_DataPtr, m_Size, advise);
  1762.     } else {
  1763.         return false;
  1764.     }
  1765. }
  1766. #endif  /* HAVE_MADVISE */
  1767. END_NCBI_SCOPE
  1768. /*
  1769.  * ===========================================================================
  1770.  * $Log: ncbifile.cpp,v $
  1771.  * Revision 1000.5  2004/06/01 19:09:09  gouriano
  1772.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.78
  1773.  *
  1774.  * Revision 1.78  2004/05/18 16:51:34  ivanov
  1775.  * Added CDir::GetTmpDir()
  1776.  *
  1777.  * Revision 1.77  2004/05/14 13:59:27  gorelenk
  1778.  * Added include of ncbi_pch.hpp
  1779.  *
  1780.  * Revision 1.76  2004/04/29 15:14:34  kuznets
  1781.  * + Generic FindFile algorithm capable of recursive searches
  1782.  * CDir::GetEntries received additional parameter to ignore self
  1783.  * recursive directory entries (".", "..")
  1784.  *
  1785.  * Revision 1.75  2004/04/28 19:04:29  ucko
  1786.  * Give GetType(), IsFile(), and IsDir() an optional EFollowLinks
  1787.  * parameter (currently only honored on Unix).
  1788.  *
  1789.  * Revision 1.74  2004/04/28 15:56:49  ivanov
  1790.  * CDirEntry::GetType(): fixed bug with incorrect entry type determination
  1791.  * on some platforms
  1792.  *
  1793.  * Revision 1.73  2004/04/21 11:24:53  ivanov
  1794.  * Define s_StdGetTmpName() for all platforms except NCBI_OS_UNIX
  1795.  *
  1796.  * Revision 1.72  2004/03/17 15:39:54  ivanov
  1797.  * CFile:: Fixed possible race condition concerned with temporary file name
  1798.  * generation. Added ETmpFileCreationMode enum. Fixed GetTmpName[Ex] and
  1799.  * CreateTmpFile[Ex] class methods.
  1800.  *
  1801.  * Revision 1.71  2004/03/05 12:26:43  ivanov
  1802.  * Moved CDirEntry::MatchesMask() to NStr class.
  1803.  *
  1804.  * Revision 1.70  2004/02/12 19:50:34  ivanov
  1805.  * Fixed CDirEntry::DeleteTrailingPathSeparator and CDir::CreatePath()
  1806.  * to avoid creating empty directories with disk name in the case if
  1807.  * specified path contains it.
  1808.  *
  1809.  * Revision 1.69  2004/02/11 20:49:57  gorelenk
  1810.  * Implemented case-insensitivity of CreateRelativePath on NCBI_OS_MSWIN.
  1811.  *
  1812.  * Revision 1.68  2004/02/11 20:30:21  gorelenk
  1813.  * Added case-insensitive test of root dirs inside CreateRelativePath.
  1814.  *
  1815.  * Revision 1.67  2004/01/07 13:58:28  ucko
  1816.  * Add missing first argument to string constructor in s_StripDir.
  1817.  *
  1818.  * Revision 1.66  2004/01/05 21:40:54  gorelenk
  1819.  * += Exception throwing in CDirEntry::CreateRelativePath()
  1820.  *
  1821.  * Revision 1.65  2004/01/05 20:04:05  gorelenk
  1822.  * + CDirEntry::CreateRelativePath()
  1823.  *
  1824.  * Revision 1.64  2003/11/28 16:51:48  ivanov
  1825.  * Fixed CDirEntry::SetTime() to set current time if parameter is empty
  1826.  *
  1827.  * Revision 1.63  2003/11/28 16:22:42  ivanov
  1828.  * + CDirEntry::SetTime()
  1829.  *
  1830.  * Revision 1.62  2003/11/05 15:36:23  kuznets
  1831.  * Implemented new variant of CDir::GetEntries()
  1832.  *
  1833.  * Revision 1.61  2003/10/23 12:10:51  ucko
  1834.  * Use AutoPtr with CDeleter rather than auto_ptr, which is *not*
  1835.  * guaranteed to be appropriate for malloc()ed memory.
  1836.  *
  1837.  * Revision 1.60  2003/10/22 13:25:47  ivanov
  1838.  * GetTmpName[Ex]:  replaced tempnam() with mkstemp() for UNIX
  1839.  *
  1840.  * Revision 1.59  2003/10/08 15:45:09  ivanov
  1841.  * Added CDirEntry::DeleteTrailingPathSeparator()
  1842.  *
  1843.  * Revision 1.58  2003/10/01 14:32:09  ucko
  1844.  * +EFollowLinks
  1845.  *
  1846.  * Revision 1.57  2003/09/30 15:08:51  ucko
  1847.  * Reworked CDirEntry::NormalizePath, which now handles .. correctly in
  1848.  * all cases and optionally resolves symlinks (on Unix).
  1849.  *
  1850.  * Revision 1.56  2003/09/17 20:55:02  ivanov
  1851.  * NormalizePath: added more processing for MS Windows paths
  1852.  *
  1853.  * Revision 1.55  2003/09/16 18:54:26  ivanov
  1854.  * NormalizePath(): added replacing double dir separators with single one
  1855.  *
  1856.  * Revision 1.54  2003/09/16 16:03:00  ivanov
  1857.  * MakePath():  don't add separator to directory name if it is an empty string
  1858.  *
  1859.  * Revision 1.53  2003/09/16 15:17:16  ivanov
  1860.  * + CDirEntry::NormalizePath()
  1861.  *
  1862.  * Revision 1.52  2003/08/29 16:54:28  ivanov
  1863.  * GetTmpName(): use tempname() instead tmpname()
  1864.  *
  1865.  * Revision 1.51  2003/08/21 20:32:48  ivanov
  1866.  * CDirEntry::GetType(): use lstat() instead stat() on UNIX
  1867.  *
  1868.  * Revision 1.50  2003/08/08 13:37:17  siyan
  1869.  * Changed GetTmpNameExt to GetTmpNameEx in CFile, as this is the more
  1870.  * appropriate name.
  1871.  *
  1872.  * Revision 1.49  2003/06/18 18:57:43  rsmith
  1873.  * alternate implementation of GetTmpNameExt replacing tempnam with mktemp for
  1874.  * library missing tempnam.
  1875.  *
  1876.  * Revision 1.48  2003/05/29 17:21:04  gouriano
  1877.  * added CreatePath() which creates directories recursively
  1878.  *
  1879.  * Revision 1.47  2003/04/11 14:04:49  ivanov
  1880.  * Fixed CDirEntry::GetMode (Mac OS) - store a mode only for a notzero pointers.
  1881.  * Fixed CDir::GetEntries -- do not try to close a dir handle if it was
  1882.  * not opened.
  1883.  *
  1884.  * Revision 1.46  2003/04/04 16:02:37  lavr
  1885.  * Lines wrapped at 79th column; some minor reformatting
  1886.  *
  1887.  * Revision 1.45  2003/04/03 14:15:48  rsmith
  1888.  * combine pp symbols NCBI_COMPILER_METROWERKS & _MSL_USING_MW_C_HEADERS
  1889.  * into NCBI_COMPILER_MW_MSL
  1890.  *
  1891.  * Revision 1.44  2003/04/02 16:22:34  rsmith
  1892.  * clean up metrowerks ifdefs.
  1893.  *
  1894.  * Revision 1.43  2003/04/02 13:29:29  rsmith
  1895.  * include ncbi_mslextras.h when compiling with MSL libs in Codewarrior.
  1896.  *
  1897.  * Revision 1.42  2003/03/10 18:57:08  kuznets
  1898.  * iterate->ITERATE
  1899.  *
  1900.  * Revision 1.41  2003/02/28 21:06:02  ivanov
  1901.  * Added close() call to CTmpStream destructor before the file deleting.
  1902.  *
  1903.  * Revision 1.40  2003/02/14 19:30:50  ivanov
  1904.  * Added mode ios::trunc by default for files creates in CFile::CreateTmpFile().
  1905.  * Get read of some warnings - initialize variables in CMemoryFile::x_Map().
  1906.  *
  1907.  * Revision 1.39  2003/02/06 16:14:28  ivanov
  1908.  * CMemomyFile::x_Map(): changed file access attribute from O_RDWR to
  1909.  * O_RDONLY in case of private sharing.
  1910.  *
  1911.  * Revision 1.38  2003/02/05 22:07:15  ivanov
  1912.  * Added protect and sharing parameters to the CMemoryFile constructor.
  1913.  * Added CMemoryFile::Flush() method.
  1914.  *
  1915.  * Revision 1.37  2003/01/16 13:27:56  dicuccio
  1916.  * Added CDir::GetCwd()
  1917.  *
  1918.  * Revision 1.36  2002/11/05 15:46:49  dicuccio
  1919.  * Changed CDir::GetEntries() to store fully qualified path names - this permits
  1920.  * CDirEntry::GetType() to work on files outside of the local directory.
  1921.  *
  1922.  * Revision 1.35  2002/10/01 17:23:57  gouriano
  1923.  * more fine-tuning of ConvertToOSPath
  1924.  *
  1925.  * Revision 1.34  2002/10/01 17:02:53  gouriano
  1926.  * minor modification of ConvertToOSPath
  1927.  *
  1928.  * Revision 1.33  2002/10/01 14:18:45  gouriano
  1929.  * "optimize" result of ConvertToOSPath
  1930.  *
  1931.  * Revision 1.32  2002/09/19 20:05:42  vasilche
  1932.  * Safe initialization of static mutexes
  1933.  *
  1934.  * Revision 1.31  2002/09/17 20:44:58  lavr
  1935.  * Add comment in unreachable return from CDirEntry::MatchesMask()
  1936.  *
  1937.  * Revision 1.30  2002/09/05 18:35:38  vakatov
  1938.  * Formal code rearrangement to get rid of comp.warnings;  some nice-ification
  1939.  *
  1940.  * Revision 1.29  2002/07/18 20:22:59  lebedev
  1941.  * NCBI_OS_MAC: fcntl.h added
  1942.  *
  1943.  * Revision 1.28  2002/07/15 18:17:24  gouriano
  1944.  * renamed CNcbiException and its descendents
  1945.  *
  1946.  * Revision 1.27  2002/07/11 19:28:30  ivanov
  1947.  * Removed test stuff from MemMapAdvise[Addr]
  1948.  *
  1949.  * Revision 1.26  2002/07/11 19:21:30  ivanov
  1950.  * Added CMemoryFile::MemMapAdvise[Addr]()
  1951.  *
  1952.  * Revision 1.25  2002/07/11 14:18:27  gouriano
  1953.  * exceptions replaced by CNcbiException-type ones
  1954.  *
  1955.  * Revision 1.24  2002/06/07 16:11:37  ivanov
  1956.  * Chenget GetTime() -- using CTime instead time_t, modification time
  1957.  * by default
  1958.  *
  1959.  * Revision 1.23  2002/06/07 15:21:06  ivanov
  1960.  * Added CDirEntry::GetTime()
  1961.  *
  1962.  * Revision 1.22  2002/05/01 22:59:00  vakatov
  1963.  * A couple of (size_t) type casts to avoid compiler warnings in 64-bit
  1964.  *
  1965.  * Revision 1.21  2002/04/11 21:08:02  ivanov
  1966.  * CVS log moved to end of the file
  1967.  *
  1968.  * Revision 1.20  2002/04/01 18:49:54  ivanov
  1969.  * Added class CMemoryFile. Added including <windows.h> under MS Windows
  1970.  *
  1971.  * Revision 1.19  2002/03/25 17:08:17  ucko
  1972.  * Centralize treatment of Cygwin as Unix rather than Windows in configure.
  1973.  *
  1974.  * Revision 1.18  2002/03/22 20:00:01  ucko
  1975.  * Tweak to work on Cygwin.  (Use Unix rather than MSWIN code).
  1976.  *
  1977.  * Revision 1.17  2002/02/07 21:05:47  kans
  1978.  * implemented GetHome (FindFolder kPreferencesFolderType) for Mac
  1979.  *
  1980.  * Revision 1.16  2002/01/24 22:18:02  ivanov
  1981.  * Changed CDirEntry::Remove() and CDir::Remove()
  1982.  *
  1983.  * Revision 1.15  2002/01/22 21:21:09  ivanov
  1984.  * Fixed typing error
  1985.  *
  1986.  * Revision 1.14  2002/01/22 19:27:39  ivanov
  1987.  * Added realization ConcatPathEx()
  1988.  *
  1989.  * Revision 1.13  2002/01/20 06:13:34  vakatov
  1990.  * Fixed warning;  formatted the source code
  1991.  *
  1992.  * Revision 1.12  2002/01/10 16:46:36  ivanov
  1993.  * Added CDir::GetHome() and some CDirEntry:: path processing functions
  1994.  *
  1995.  * Revision 1.11  2001/12/26 21:21:05  ucko
  1996.  * Conditionalize deletion of m_FSS on NCBI_OS_MAC.
  1997.  *
  1998.  * Revision 1.10  2001/12/26 20:58:22  juran
  1999.  * Use an FSSpec* member instead of an FSSpec, so a forward declaration can
  2000.  * be used.
  2001.  * Add copy constructor and assignment operator for CDirEntry on Mac OS,
  2002.  * thus avoiding memberwise copy which would blow up upon deleting the
  2003.  * pointer twice.
  2004.  *
  2005.  * Revision 1.9  2001/12/18 21:36:38  juran
  2006.  * Remove unneeded Mac headers.
  2007.  * (Required functions copied to ncbi_os_mac.cpp)
  2008.  * MoveRename PStr to PString in ncbi_os_mac.hpp.
  2009.  * Don't use MoreFiles xxxCompat functions.  They're for System 6.
  2010.  * Don't use global scope operator on functions copied into NCBI scope.
  2011.  *
  2012.  * Revision 1.8  2001/11/19 23:38:44  vakatov
  2013.  * Fix to compile with SUN WorkShop (and maybe other) compiler(s)
  2014.  *
  2015.  * Revision 1.7  2001/11/19 18:10:13  juran
  2016.  * Whitespace.
  2017.  *
  2018.  * Revision 1.6  2001/11/15 16:34:12  ivanov
  2019.  * Moved from util to corelib
  2020.  *
  2021.  * Revision 1.5  2001/11/06 14:34:11  ivanov
  2022.  * Fixed compile errors in CDir::Contents() under MS Windows
  2023.  *
  2024.  * Revision 1.4  2001/11/01 21:02:25  ucko
  2025.  * Fix to work on non-MacOS platforms again.
  2026.  *
  2027.  * Revision 1.3  2001/11/01 20:06:48  juran
  2028.  * Replace directory streams with Contents() method.
  2029.  * Implement and test Mac OS platform.
  2030.  *
  2031.  * Revision 1.2  2001/09/19 16:22:18  ucko
  2032.  * S_IFDOOR is nonportable; make sure it exists before using it.
  2033.  * Fix type of second argument to CTmpStream's constructor (caught by gcc 3).
  2034.  *
  2035.  * Revision 1.1  2001/09/19 13:06:09  ivanov
  2036.  * Initial revision
  2037.  *
  2038.  * ===========================================================================
  2039.  */