00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include <ncbi_pch.hpp>
00033 #include <corelib/ncbifile.hpp>
00034 #include <corelib/ncbi_limits.h>
00035 #include <corelib/ncbi_system.hpp>
00036 #include <corelib/ncbi_safe_static.hpp>
00037 #include <corelib/error_codes.hpp>
00038
00039 #include <stdio.h>
00040
00041 #if defined(NCBI_OS_MSWIN)
00042 # include "ncbi_os_mswin_p.hpp"
00043 # include <corelib/ncbi_limits.hpp>
00044 # include <io.h>
00045 # include <direct.h>
00046 # include <sys/utime.h>
00047 # include <fcntl.h>
00048
00049 #elif defined(NCBI_OS_UNIX)
00050 # include <unistd.h>
00051 # include <dirent.h>
00052 # include <pwd.h>
00053 # include <fcntl.h>
00054 # include <sys/time.h>
00055 # include <sys/mman.h>
00056 # ifdef HAVE_SYS_STATVFS_H
00057 # include <sys/statvfs.h>
00058 # endif
00059 # include <sys/param.h>
00060 # ifdef HAVE_SYS_MOUNT_H
00061 # include <sys/mount.h>
00062 # endif
00063 # ifdef HAVE_SYS_VFS_H
00064 # include <sys/vfs.h>
00065 # endif
00066 # include <utime.h>
00067 # include <pwd.h>
00068 # include <grp.h>
00069 # if !defined(MAP_FAILED)
00070 # define MAP_FAILED ((void *) -1)
00071 # endif
00072
00073 #else
00074 # error "File API defined for MS Windows and UNIX platforms only"
00075
00076 #endif
00077
00078
00079 #define NCBI_USE_ERRCODE_X Corelib_File
00080
00081
00082 BEGIN_NCBI_SCOPE
00083
00084
00085
00086
00087 #undef DIR_SEPARATOR
00088 #undef DIR_SEPARATOR_ALT
00089 #undef DIR_SEPARATORS
00090 #undef DISK_SEPARATOR
00091 #undef ALL_SEPARATORS
00092 #undef ALL_OS_SEPARATORS
00093
00094 #define DIR_PARENT ".."
00095 #define DIR_CURRENT "."
00096 #define ALL_OS_SEPARATORS ":/\\"
00097
00098 #if defined(NCBI_OS_MSWIN)
00099 # define DIR_SEPARATOR '\\'
00100 # define DIR_SEPARATOR_ALT '/'
00101 # define DISK_SEPARATOR ':'
00102 # define DIR_SEPARATORS "/\\"
00103 # define ALL_SEPARATORS ":/\\"
00104 #elif defined(NCBI_OS_UNIX)
00105 # define DIR_SEPARATOR '/'
00106 # define DIR_SEPARATORS "/"
00107 # define ALL_SEPARATORS "/"
00108 #endif
00109
00110
00111 #define F_ISSET(flags, mask) ((flags & (mask)) == (mask))
00112
00113
00114 const size_t kDefaultBufferSize = 32*1024;
00115
00116
00117 static CSafeStaticRef< CFileDeleteList > s_DeleteAtExitFileList;
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127 NCBI_PARAM_DECL(string, NCBI, TmpDir);
00128 NCBI_PARAM_DEF (string, NCBI, TmpDir, kEmptyStr);
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138 NCBI_PARAM_DECL(bool, NCBI, DeleteReadOnlyFiles);
00139 NCBI_PARAM_DEF_EX(bool, NCBI, DeleteReadOnlyFiles, false,
00140 eParam_NoThread, NCBI_CONFIG__DeleteReadOnlyFiles);
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151 #define DEFAULT_LOGGING_VALUE false
00152
00153 NCBI_PARAM_DECL(bool, NCBI, FileAPILogging);
00154 NCBI_PARAM_DEF_EX(bool, NCBI, FileAPILogging, DEFAULT_LOGGING_VALUE,
00155 eParam_NoThread, NCBI_CONFIG__FileAPILogging);
00156
00157 #define LOG_ERROR(log_message) \
00158 { \
00159 int saved_error = errno; \
00160 if (NCBI_PARAM_TYPE(NCBI, FileAPILogging)::GetDefault()) { \
00161 ERR_POST(log_message << ": " << strerror(saved_error)); \
00162 } \
00163 errno = saved_error; \
00164 }
00165
00166 #define LOG_ERROR_AND_RETURN(log_message) \
00167 { \
00168 if (NCBI_PARAM_TYPE(NCBI, FileAPILogging)::GetDefault()) { \
00169 ERR_POST(log_message); \
00170 } \
00171 return false; \
00172 }
00173
00174 #define LOG_ERROR_AND_RETURN_ERRNO(log_message) \
00175 { \
00176 int saved_error = errno; \
00177 if (NCBI_PARAM_TYPE(NCBI, FileAPILogging)::GetDefault()) { \
00178 ERR_POST(log_message << ": " << strerror(saved_error)); \
00179 } \
00180 errno = saved_error; \
00181 return false; \
00182 }
00183
00184
00185
00186
00187
00188
00189 CDirEntry::CDirEntry(const string& name)
00190 {
00191 Reset(name);
00192 m_DefaultMode[eUser] = m_DefaultModeGlobal[eFile][eUser];
00193 m_DefaultMode[eGroup] = m_DefaultModeGlobal[eFile][eGroup];
00194 m_DefaultMode[eOther] = m_DefaultModeGlobal[eFile][eOther];
00195 m_DefaultMode[eSpecial] = m_DefaultModeGlobal[eFile][eSpecial];
00196 }
00197
00198
00199 CDirEntry::CDirEntry(const CDirEntry& other)
00200 : m_Path(other.m_Path)
00201 {
00202 m_DefaultMode[eUser] = other.m_DefaultMode[eUser];
00203 m_DefaultMode[eGroup] = other.m_DefaultMode[eGroup];
00204 m_DefaultMode[eOther] = other.m_DefaultMode[eOther];
00205 m_DefaultMode[eSpecial] = other.m_DefaultMode[eSpecial];
00206 }
00207
00208
00209 CDirEntry::~CDirEntry(void)
00210 {
00211 return;
00212 }
00213
00214
00215 CDirEntry* CDirEntry::CreateObject(EType type, const string& path)
00216 {
00217 CDirEntry *ptr = 0;
00218 switch ( type ) {
00219 case eFile:
00220 ptr = new CFile(path);
00221 break;
00222 case eDir:
00223 ptr = new CDir(path);
00224 break;
00225 case eLink:
00226 ptr = new CSymLink(path);
00227 break;
00228 default:
00229 ptr = new CDirEntry(path);
00230 break;
00231 }
00232 return ptr;
00233 }
00234
00235
00236 void CDirEntry::Reset(const string& path)
00237 {
00238 m_Path = path;
00239 size_t len = path.length();
00240
00241 if ((len == 1) && IsPathSeparator(path[0])) {
00242 return;
00243 }
00244
00245 # if defined(DISK_SEPARATOR)
00246 if ( (len == 2 || len == 3) && (path[1] == DISK_SEPARATOR) ) {
00247 return;
00248 }
00249 # endif
00250 m_Path = DeleteTrailingPathSeparator(path);
00251 }
00252
00253
00254 CDirEntry::TMode CDirEntry::m_DefaultModeGlobal[eUnknown][4] =
00255 {
00256
00257 { CDirEntry::fDefaultUser, CDirEntry::fDefaultGroup,
00258 CDirEntry::fDefaultOther, 0 },
00259
00260 { CDirEntry::fDefaultDirUser, CDirEntry::fDefaultDirGroup,
00261 CDirEntry::fDefaultDirOther, 0 },
00262
00263 { CDirEntry::fDefaultUser, CDirEntry::fDefaultGroup,
00264 CDirEntry::fDefaultOther, 0 },
00265
00266 { CDirEntry::fDefaultUser, CDirEntry::fDefaultGroup,
00267 CDirEntry::fDefaultOther, 0 },
00268
00269 { CDirEntry::fDefaultUser, CDirEntry::fDefaultGroup,
00270 CDirEntry::fDefaultOther, 0 },
00271
00272 { CDirEntry::fDefaultUser, CDirEntry::fDefaultGroup,
00273 CDirEntry::fDefaultOther, 0 },
00274
00275 { CDirEntry::fDefaultUser, CDirEntry::fDefaultGroup,
00276 CDirEntry::fDefaultOther, 0 },
00277
00278 { CDirEntry::fDefaultUser, CDirEntry::fDefaultGroup,
00279 CDirEntry::fDefaultOther, 0 }
00280 };
00281
00282
00283
00284 const char* CDirEntry::m_BackupSuffix = ".bak";
00285
00286
00287 CDirEntry& CDirEntry::operator= (const CDirEntry& other)
00288 {
00289 if (this != &other) {
00290 m_Path = other.m_Path;
00291 m_DefaultMode[eUser] = other.m_DefaultMode[eUser];
00292 m_DefaultMode[eGroup] = other.m_DefaultMode[eGroup];
00293 m_DefaultMode[eOther] = other.m_DefaultMode[eOther];
00294 m_DefaultMode[eSpecial] = other.m_DefaultMode[eSpecial];
00295 }
00296 return *this;
00297 }
00298
00299
00300 void CDirEntry::SplitPath(const string& path, string* dir,
00301 string* base, string* ext)
00302 {
00303
00304 size_t pos = path.find_last_of(ALL_SEPARATORS);
00305 string filename = (pos == NPOS) ? path : path.substr(pos+1);
00306
00307
00308 if ( dir ) {
00309 *dir = (pos == NPOS) ? kEmptyStr : path.substr(0, pos+1);
00310 }
00311
00312 pos = filename.rfind('.');
00313 if ( base ) {
00314 *base = (pos == NPOS) ? filename : filename.substr(0, pos);
00315 }
00316 if ( ext ) {
00317 *ext = (pos == NPOS) ? kEmptyStr : filename.substr(pos);
00318 }
00319 }
00320
00321
00322 void CDirEntry::SplitPathEx(const string& path,
00323 string* disk, string* dir,
00324 string* base, string* ext)
00325 {
00326 size_t start_pos = 0;
00327
00328
00329 if ( disk ) {
00330 if ( isalpha((unsigned char)path[0]) && path[1] == ':' ) {
00331 *disk = path.substr(0, 2);
00332 start_pos = 2;
00333 } else {
00334 *disk = kEmptyStr;
00335 }
00336 }
00337
00338 size_t pos = path.find_last_of(ALL_OS_SEPARATORS);
00339 string filename = (pos == NPOS) ? path : path.substr(pos+1);
00340
00341 if ( dir ) {
00342 *dir = (pos == NPOS) ? kEmptyStr :
00343 path.substr(start_pos, pos - start_pos + 1);
00344 }
00345
00346 pos = filename.rfind('.');
00347 if ( base ) {
00348 *base = (pos == NPOS) ? filename : filename.substr(0, pos);
00349 }
00350 if ( ext ) {
00351 *ext = (pos == NPOS) ? kEmptyStr : filename.substr(pos);
00352 }
00353 }
00354
00355
00356 string CDirEntry::MakePath(const string& dir, const string& base,
00357 const string& ext)
00358 {
00359 string path;
00360
00361
00362 if ( dir.length() ) {
00363 path = AddTrailingPathSeparator(dir);
00364 }
00365 path += base;
00366
00367 if ( ext.length() && ext.at(0) != '.' ) {
00368 path += '.';
00369 }
00370 path += ext;
00371
00372 return path;
00373 }
00374
00375
00376 char CDirEntry::GetPathSeparator(void)
00377 {
00378 return DIR_SEPARATOR;
00379 }
00380
00381
00382 bool CDirEntry::IsPathSeparator(const char c)
00383 {
00384 #if defined(DISK_SEPARATOR)
00385 if ( c == DISK_SEPARATOR ) {
00386 return true;
00387 }
00388 #endif
00389 #if defined(DIR_SEPARATOR_ALT)
00390 if ( c == DIR_SEPARATOR_ALT ) {
00391 return true;
00392 }
00393 #endif
00394 return c == DIR_SEPARATOR;
00395 }
00396
00397
00398 string CDirEntry::AddTrailingPathSeparator(const string& path)
00399 {
00400 size_t len = path.length();
00401 if (len && string(ALL_SEPARATORS).rfind(path.at(len - 1)) == NPOS) {
00402 return path + GetPathSeparator();
00403 }
00404 return path;
00405 }
00406
00407
00408 string CDirEntry::DeleteTrailingPathSeparator(const string& path)
00409 {
00410 size_t pos = path.find_last_not_of(DIR_SEPARATORS);
00411 if (pos + 1 < path.length()) {
00412 return path.substr(0, pos + 1);
00413 }
00414 return path;
00415 }
00416
00417
00418 string CDirEntry::GetDir(EIfEmptyPath mode) const
00419 {
00420 string dir;
00421 SplitPath(GetPath(), &dir);
00422 if ( dir.empty() && mode == eIfEmptyPath_Current &&
00423 !GetPath().empty() ) {
00424 return string(DIR_CURRENT) + DIR_SEPARATOR;
00425 }
00426 return dir;
00427 }
00428
00429
00430 bool CDirEntry::IsAbsolutePath(const string& path)
00431 {
00432 if ( path.empty() )
00433 return false;
00434
00435 #if defined(NCBI_OS_MSWIN)
00436
00437 if ( ( isalpha((unsigned char)path[0]) && path[1] == ':' &&
00438 (path[2] == '/' || path[2] == '\\') ) ||
00439 (path[0] == '\\' && path[1] == '\\') ) {
00440 return true;
00441 }
00442 #elif defined(NCBI_OS_UNIX)
00443 if ( path[0] == '/' )
00444 return true;
00445 #endif
00446 return false;
00447 }
00448
00449
00450 bool CDirEntry::IsAbsolutePathEx(const string& path)
00451 {
00452 if ( path.empty() )
00453 return false;
00454
00455
00456
00457 if ( ( isalpha((unsigned char)path[0]) && path[1] == ':' &&
00458 (path[2] == '/' || path[2] == '\\') ) ||
00459 (path[0] == '\\' && path[1] == '\\') ) {
00460 return true;
00461 }
00462
00463 if ( path[0] == '/' )
00464
00465
00466
00467 return true;
00468
00469
00470 return false;
00471 }
00472
00473
00474
00475
00476
00477 static void s_StripDir(const string& dir, vector<string> * dir_parts)
00478 {
00479 dir_parts->clear();
00480 if ( dir.empty() )
00481 return;
00482
00483 const char sep = CDirEntry::GetPathSeparator();
00484
00485 size_t sep_pos = 0;
00486 size_t last_ind = dir.length() - 1;
00487 size_t part_start = 0;
00488 for (;;) {
00489 sep_pos = dir.find(sep, sep_pos);
00490 if (sep_pos == NPOS) {
00491 dir_parts->push_back(string(dir, part_start,
00492 dir.length() - part_start));
00493 break;
00494 }
00495
00496
00497 if (sep_pos == 0) {
00498 dir_parts->push_back(string(1, sep));
00499 } else {
00500 dir_parts->push_back(string(dir, part_start, sep_pos -part_start));
00501 }
00502
00503 sep_pos++;
00504 part_start = sep_pos;
00505 if (sep_pos >= last_ind)
00506 break;
00507 }
00508
00509 }
00510
00511
00512 string CDirEntry::CreateRelativePath( const string& path_from,
00513 const string& path_to )
00514 {
00515 string path;
00516
00517 if ( !IsAbsolutePath(path_from) ) {
00518 NCBI_THROW(CFileException, eRelativePath,
00519 "path_from is not absolute path");
00520 }
00521
00522 if ( !IsAbsolutePath(path_to) ) {
00523 NCBI_THROW(CFileException, eRelativePath,
00524 "path_to is not absolute path");
00525 }
00526
00527
00528 string dir_from;
00529 SplitPath(AddTrailingPathSeparator(path_from), &dir_from);
00530 vector<string> dir_from_parts;
00531 s_StripDir(dir_from, &dir_from_parts);
00532 if ( dir_from_parts.empty() ) {
00533 NCBI_THROW(CFileException, eRelativePath,
00534 "path_from is empty path");
00535 }
00536
00537
00538 string dir_to;
00539 string base_to;
00540 string ext_to;
00541 SplitPath(path_to, &dir_to, &base_to, &ext_to);
00542 vector<string> dir_to_parts;
00543 s_StripDir(dir_to, &dir_to_parts);
00544 if ( dir_to_parts.empty() ) {
00545 NCBI_THROW(CFileException, eRelativePath,
00546 "path_to is empty path");
00547 }
00548
00549
00550 #ifdef NCBI_OS_MSWIN
00551 # define DIR_PARTS_CMP_MODE NStr::eNocase
00552 #else
00553 # define DIR_PARTS_CMP_MODE NStr::eCase
00554 #endif
00555
00556
00557 if (NStr::Compare(dir_from_parts.front(),
00558 dir_to_parts.front(),
00559 DIR_PARTS_CMP_MODE) != 0) {
00560 NCBI_THROW(CFileException, eRelativePath,
00561 "roots of input paths are different");
00562 }
00563
00564 size_t min_parts = min(dir_from_parts.size(), dir_to_parts.size());
00565 size_t common_length = min_parts;
00566 for (size_t i = 0; i < min_parts; i++) {
00567 if (NStr::Compare(dir_from_parts[i],
00568 dir_to_parts[i],
00569 DIR_PARTS_CMP_MODE) != 0) {
00570 common_length = i;
00571 break;
00572 }
00573 }
00574
00575 for (size_t i = common_length; i < dir_from_parts.size(); i++) {
00576 path += "..";
00577 path += GetPathSeparator();
00578 }
00579 for (size_t i = common_length; i < dir_to_parts.size(); i++) {
00580 path += dir_to_parts[i];
00581 path += GetPathSeparator();
00582 }
00583
00584 return path + base_to + ext_to;
00585 }
00586
00587
00588 string CDirEntry::CreateAbsolutePath(const string& path)
00589 {
00590 if ( IsAbsolutePath(path) ) {
00591 return path;
00592 }
00593 #if defined(NCBI_OS_MSWIN)
00594 if ( path.find(DISK_SEPARATOR) != NPOS ) {
00595 NCBI_THROW(CFileException, eRelativePath,
00596 "Path must not contain disk separator: " + path);
00597 }
00598 if ( !path.empty() && (path[0] == '/' || path[0] == '\\') ) {
00599 NCBI_THROW(CFileException, eRelativePath,
00600 "Path that starts with slash is not absolute"
00601 " on MS Windows: " + path);
00602 }
00603 #endif
00604 string result = CDirEntry::ConcatPath(CDir::GetCwd(), path);
00605 result = CDirEntry::NormalizePath(result);
00606 return result;
00607 }
00608
00609
00610 string CDirEntry::ConvertToOSPath(const string& path)
00611 {
00612
00613 if ( path.empty() || IsAbsolutePathEx(path) ) {
00614 return path;
00615 }
00616
00617 string xpath = path;
00618
00619 #if defined(DIR_PARENT)
00620 if ( NStr::EndsWith(xpath, DIR_PARENT) ) {
00621 xpath += DIR_SEPARATOR;
00622 }
00623 #endif
00624 #if defined(DIR_CURRENT)
00625 if ( NStr::EndsWith(xpath, DIR_CURRENT) ) {
00626 xpath += DIR_SEPARATOR;
00627 }
00628 #endif
00629
00630 for (size_t i = 0; i < xpath.length(); i++) {
00631 char c = xpath[i];
00632 if ( c == '\\' || c == '/' || c == ':') {
00633 xpath[i] = DIR_SEPARATOR;
00634 }
00635 }
00636
00637 xpath = NormalizePath(xpath);
00638
00639 return xpath;
00640 }
00641
00642
00643 string CDirEntry::ConcatPath(const string& first, const string& second)
00644 {
00645
00646 string path = AddTrailingPathSeparator(NStr::TruncateSpaces(first));
00647
00648 string part = NStr::TruncateSpaces(second);
00649 if ( !path.empty() && part.length() > 0 && part[0] == DIR_SEPARATOR ) {
00650 part.erase(0,1);
00651 }
00652
00653 path += part;
00654 return path;
00655 }
00656
00657
00658 string CDirEntry::ConcatPathEx(const string& first, const string& second)
00659 {
00660
00661 string path = NStr::TruncateSpaces(first);
00662
00663
00664
00665 size_t pos = path.length();
00666 if ( pos && string(ALL_OS_SEPARATORS).find(path.at(pos-1)) == NPOS ) {
00667
00668 char sep = GetPathSeparator();
00669 size_t sep_pos = path.find_last_of(ALL_OS_SEPARATORS);
00670 if ( sep_pos != NPOS ) {
00671 sep = path.at(sep_pos);
00672 }
00673 path += sep;
00674 }
00675
00676 string part = NStr::TruncateSpaces(second);
00677 if ( part.length() > 0 &&
00678 string(ALL_OS_SEPARATORS).find(part[0]) != NPOS ) {
00679 part.erase(0,1);
00680 }
00681
00682 path += part;
00683 return path;
00684 }
00685
00686
00687 string CDirEntry::NormalizePath(const string& path, EFollowLinks follow_links)
00688 {
00689 if ( path.empty() ) {
00690 return path;
00691 }
00692 static const char kSeps[] = { DIR_SEPARATOR,
00693 #ifdef DIR_SEPARATOR_ALT
00694 DIR_SEPARATOR_ALT,
00695 #endif
00696 '\0' };
00697
00698 list<string> head;
00699 list<string> tail;
00700 string current;
00701 int link_depth = 0;
00702
00703
00704 # ifdef DISK_SEPARATOR
00705 if ( path.find(DISK_SEPARATOR) == NPOS ) {
00706 current = DeleteTrailingPathSeparator(path);
00707 } else {
00708 current = path;
00709 }
00710 # else
00711 current = DeleteTrailingPathSeparator(path);
00712 # endif
00713 if ( current.empty() ) {
00714
00715 return string(1, DIR_SEPARATOR);
00716 }
00717
00718 while ( !current.empty() || !tail.empty() ) {
00719 list<string> pretail;
00720 if ( !current.empty() ) {
00721 NStr::Split(current, kSeps, pretail, NStr::eNoMergeDelims);
00722 current.erase();
00723 if (pretail.front().empty()
00724 #ifdef DISK_SEPARATOR
00725 || pretail.front().find(DISK_SEPARATOR) != NPOS
00726 #endif
00727 ) {
00728
00729 head.clear();
00730 #ifdef NCBI_OS_MSWIN
00731
00732 static const char* const kUNC[] = { "", "", "?", "UNC" };
00733 list<string>::iterator it = pretail.begin();
00734 unsigned int matched = 0;
00735 while (matched < 4 && it != pretail.end()
00736 && !NStr::CompareNocase(*it, kUNC[matched])) {
00737 ++it;
00738 ++matched;
00739 }
00740 pretail.erase(pretail.begin(), it);
00741 switch (matched) {
00742 case 2: case 4:
00743 head.push_back(kEmptyStr);
00744
00745 case 1:
00746 head.push_back(kEmptyStr);
00747 break;
00748 case 3:
00749 break;
00750 }
00751 #endif
00752 }
00753 tail.splice(tail.begin(), pretail);
00754 }
00755
00756 string next;
00757 if (!tail.empty()) {
00758 next = tail.front();
00759 tail.pop_front();
00760 }
00761 if ( !head.empty() ) {
00762 string& last = head.back();
00763 if (last == DIR_CURRENT) {
00764 if (!next.empty()) {
00765 head.pop_back();
00766 _ASSERT(head.empty());
00767 }
00768 } else if (next == DIR_CURRENT) {
00769
00770 continue;
00771 #ifdef DISK_SEPARATOR
00772 } else if (!last.empty() && last[last.size()-1] == DISK_SEPARATOR) {
00773
00774 #endif
00775 } else if (next.empty()) {
00776 continue;
00777 } else if (next == DIR_PARENT) {
00778 #ifdef DISK_SEPARATOR
00779 SIZE_TYPE pos;
00780 #endif
00781
00782 if (last.empty()) {
00783
00784 continue;
00785 #ifdef DISK_SEPARATOR
00786 } else if ((pos = last.find(DISK_SEPARATOR) != NPOS)) {
00787 last.erase(pos + 1);
00788 #endif
00789 } else if (last != DIR_PARENT) {
00790 head.pop_back();
00791 continue;
00792 }
00793 }
00794 }
00795 #ifdef NCBI_OS_UNIX
00796
00797 if ( follow_links ) {
00798 string s(head.empty() ? next
00799 : NStr::Join(head, string(1, DIR_SEPARATOR))
00800 + DIR_SEPARATOR + next);
00801 char buf[PATH_MAX];
00802 int length = (int)readlink(s.c_str(), buf, sizeof(buf));
00803 if (length > 0) {
00804 current.assign(buf, length);
00805 if (++link_depth >= 1024) {
00806 ERR_POST_X(1, Warning << "CDirEntry::NormalizePath():"
00807 " Reached symlink depth limit " <<
00808 link_depth << " when resolving " << path);
00809 follow_links = eIgnoreLinks;
00810 }
00811 continue;
00812 }
00813 }
00814 #endif
00815
00816 head.push_back(next);
00817 }
00818
00819
00820 if ( (head.size() == 0) ||
00821 (head.size() == 2 && head.front() == DIR_CURRENT &&
00822 head.back().empty()) ) {
00823
00824 return DIR_CURRENT;
00825 }
00826 if (head.size() == 1 && head.front().empty()) {
00827
00828 return string(1, DIR_SEPARATOR);
00829 }
00830
00831 return NStr::Join(head, string(1, DIR_SEPARATOR));
00832 }
00833
00834
00835 bool CDirEntry::GetMode(TMode* usr_mode, TMode* grp_mode,
00836 TMode* oth_mode, TSpecialModeBits* special) const
00837 {
00838 struct stat st;
00839 if (stat(GetPath().c_str(), &st) != 0) {
00840 LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::GetMode():"
00841 " stat() failed for " << GetPath());
00842 }
00843
00844 if (usr_mode) {
00845 *usr_mode = (
00846 #if defined(S_IRUSR)
00847 (st.st_mode & S_IRUSR ? fRead : 0) |
00848 #elif defined(S_IREAD)
00849 (st.st_mode & S_IREAD ? fRead : 0) |
00850 #endif
00851 #if defined(S_IWUSR)
00852 (st.st_mode & S_IWUSR ? fWrite : 0) |
00853 #elif defined(S_IWRITE)
00854 (st.st_mode & S_IWRITE ? fWrite : 0) |
00855 #endif
00856 #if defined(S_IXUSR)
00857 (st.st_mode & S_IXUSR ? fExecute : 0) |
00858 #elif defined(S_IEXEC)
00859 (st.st_mode & S_IEXEC ? fExecute : 0) |
00860 #endif
00861 0);
00862 }
00863
00864 #ifdef NCBI_OS_MSWIN
00865 if (grp_mode) *grp_mode = 0;
00866 if (oth_mode) *oth_mode = 0;
00867 if (special) *special = 0;
00868
00869 #else
00870
00871
00872 if (grp_mode) {
00873 *grp_mode = (
00874 #ifdef S_IRGRP
00875 (st.st_mode & S_IRGRP ? fRead : 0) |
00876 #endif
00877 #ifdef S_IWGRP
00878 (st.st_mode & S_IWGRP ? fWrite : 0) |
00879 #endif
00880 #ifdef S_IXGRP
00881 (st.st_mode & S_IXGRP ? fExecute : 0) |
00882 #endif
00883 0);
00884 }
00885
00886 if (oth_mode) {
00887 *oth_mode = (
00888 #ifdef S_IROTH
00889 (st.st_mode & S_IROTH ? fRead : 0) |
00890 #endif
00891 #ifdef S_IWOTH
00892 (st.st_mode & S_IWOTH ? fWrite : 0) |
00893 #endif
00894 #ifdef S_IXOTH
00895 (st.st_mode & S_IXOTH ? fExecute : 0) |
00896 #endif
00897 0);
00898 }
00899
00900 if (special) {
00901 *special = (
00902 #ifdef S_ISUID
00903 (st.st_mode & S_ISUID ? CDirEntry::fSetUID : 0) |
00904 #endif
00905 #ifdef S_ISGID
00906 (st.st_mode & S_ISGID ? CDirEntry::fSetGID : 0) |
00907 #endif
00908 #ifdef S_ISVTX
00909 (st.st_mode & S_ISVTX ? CDirEntry::fSticky : 0) |
00910 #endif
00911 0);
00912 }
00913 #endif // NCBI_OS_MSWIN
00914
00915 return true;
00916 }
00917
00918
00919 bool CDirEntry::SetMode(TMode user_mode, TMode group_mode,
00920 TMode other_mode, TSpecialModeBits special) const
00921 {
00922 if (user_mode == fDefault) {
00923 user_mode = m_DefaultMode[eUser];
00924 }
00925 if (group_mode == fDefault) {
00926 group_mode = m_DefaultMode[eGroup];
00927 }
00928 if (other_mode == fDefault) {
00929 other_mode = m_DefaultMode[eOther];
00930 }
00931 if (special == 0) {
00932 special = m_DefaultMode[eSpecial];
00933 }
00934 mode_t mode = MakeModeT(user_mode, group_mode, other_mode, special);
00935
00936 if ( chmod(GetPath().c_str(), mode) != 0 ) {
00937 LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::SetMode():"
00938 " chmod() failed for " << GetPath());
00939 }
00940 return true;
00941 }
00942
00943
00944 void CDirEntry::SetDefaultModeGlobal(EType entry_type, TMode user_mode,
00945 TMode group_mode, TMode other_mode,
00946 TSpecialModeBits special)
00947 {
00948 if ( entry_type >= eUnknown ) {
00949 return;
00950 }
00951 if ( entry_type == eDir ) {
00952 if ( user_mode == fDefault ) {
00953 user_mode = fDefaultDirUser;
00954 }
00955 if ( group_mode == fDefault ) {
00956 group_mode = fDefaultDirGroup;
00957 }
00958 if ( other_mode == fDefault ) {
00959 other_mode = fDefaultDirOther;
00960 }
00961 } else {
00962 if ( user_mode == fDefault ) {
00963 user_mode = fDefaultUser;
00964 }
00965 if ( group_mode == fDefault ) {
00966 group_mode = fDefaultGroup;
00967 }
00968 if ( other_mode == fDefault ) {
00969 other_mode = fDefaultOther;
00970 }
00971 }
00972 if ( special == 0 ) {
00973 special = m_DefaultModeGlobal[entry_type][eSpecial];
00974 }
00975 m_DefaultModeGlobal[entry_type][eUser] = user_mode;
00976 m_DefaultModeGlobal[entry_type][eGroup] = group_mode;
00977 m_DefaultModeGlobal[entry_type][eOther] = other_mode;
00978 m_DefaultModeGlobal[entry_type][eSpecial] = special;
00979 }
00980
00981
00982 void CDirEntry::SetDefaultMode(EType entry_type, TMode user_mode,
00983 TMode group_mode, TMode other_mode,
00984 TSpecialModeBits special)
00985 {
00986 if ( user_mode == fDefault ) {
00987 user_mode = m_DefaultModeGlobal[entry_type][eUser];
00988 }
00989 if ( group_mode == fDefault ) {
00990 group_mode = m_DefaultModeGlobal[entry_type][eGroup];
00991 }
00992 if ( other_mode == fDefault ) {
00993 other_mode = m_DefaultModeGlobal[entry_type][eOther];
00994 }
00995 if ( special == 0 ) {
00996 special = m_DefaultModeGlobal[entry_type][eSpecial];
00997 }
00998 m_DefaultMode[eUser] = user_mode;
00999 m_DefaultMode[eGroup] = group_mode;
01000 m_DefaultMode[eOther] = other_mode;
01001 m_DefaultMode[eSpecial] = special;
01002 }
01003
01004
01005 void CDirEntry::GetDefaultModeGlobal(EType entry_type, TMode* user_mode,
01006 TMode* group_mode, TMode* other_mode,
01007 TSpecialModeBits* special)
01008 {
01009 if ( user_mode ) {
01010 *user_mode = m_DefaultModeGlobal[entry_type][eUser];
01011 }
01012 if ( group_mode ) {
01013 *group_mode = m_DefaultModeGlobal[entry_type][eGroup];
01014 }
01015 if ( other_mode ) {
01016 *other_mode = m_DefaultModeGlobal[entry_type][eOther];
01017 }
01018 if ( special ) {
01019 *special = m_DefaultModeGlobal[entry_type][eSpecial];
01020 }
01021 }
01022
01023
01024 void CDirEntry::GetDefaultMode(TMode* user_mode, TMode* group_mode,
01025 TMode* other_mode,
01026 TSpecialModeBits* special) const
01027 {
01028 if ( user_mode ) {
01029 *user_mode = m_DefaultMode[eUser];
01030 }
01031 if ( group_mode ) {
01032 *group_mode = m_DefaultMode[eGroup];
01033 }
01034 if ( other_mode ) {
01035 *other_mode = m_DefaultMode[eOther];
01036 }
01037 if ( special ) {
01038 *special = m_DefaultMode[eSpecial];
01039 }
01040 }
01041
01042
01043
01044
01045 mode_t CDirEntry::MakeModeT(TMode usr_mode,
01046 TMode grp_mode,
01047 TMode oth_mode,
01048 TSpecialModeBits special)
01049 {
01050 mode_t mode = (
01051
01052 #ifdef S_ISUID
01053 (special & fSetUID ? S_ISUID : 0) |
01054 #endif
01055 #ifdef S_ISGID
01056 (special & fSetGID ? S_ISGID : 0) |
01057 #endif
01058 #ifdef S_ISVTX
01059 (special & fSticky ? S_ISVTX : 0) |
01060 #endif
01061
01062 #if defined(S_IRUSR)
01063 (usr_mode & fRead ? S_IRUSR : 0) |
01064 #elif defined(S_IREAD)
01065 (usr_mode & fRead ? S_IREAD : 0) |
01066 #endif
01067 #if defined(S_IWUSR)
01068 (usr_mode & fWrite ? S_IWUSR : 0) |
01069 #elif defined(S_IWRITE)
01070 (usr_mode & fWrite ? S_IWRITE : 0) |
01071 #endif
01072 #if defined(S_IXUSR)
01073 (usr_mode & fExecute ? S_IXUSR : 0) |
01074 #elif defined(S_IEXEC)
01075 (usr_mode & fExecute ? S_IEXEC : 0) |
01076 #endif
01077 #ifdef S_IRGRP
01078 (grp_mode & fRead ? S_IRGRP : 0) |
01079 #endif
01080 #ifdef S_IWGRP
01081 (grp_mode & fWrite ? S_IWGRP : 0) |
01082 #endif
01083 #ifdef S_IXGRP
01084 (grp_mode & fExecute ? S_IXGRP : 0) |
01085 #endif
01086 #ifdef S_IROTH
01087 (oth_mode & fRead ? S_IROTH : 0) |
01088 #endif
01089 #ifdef S_IWOTH
01090 (oth_mode & fWrite ? S_IWOTH : 0) |
01091 #endif
01092 #ifdef S_IXOTH
01093 (oth_mode & fExecute ? S_IXOTH : 0) |
01094 #endif
01095 0);
01096 return mode;
01097 }
01098
01099
01100 #if defined(NCBI_OS_UNIX) && !defined(HAVE_EUIDACCESS) && !defined(EFF_ONLY_OK)
01101
01102
01103
01104 # if defined(NCBI_COMPILER_GCC) && NCBI_COMPILER_VERSION < 300
01105 # define CAS_ARG1 void
01106 # define CAS_CAST static_cast<const struct stat*>
01107 # else
01108 # define CAS_ARG1 struct stat
01109 # define CAS_CAST
01110 #endif
01111
01112 static bool s_CheckAccessStat(const CAS_ARG1* p, int amode)
01113 {
01114 const struct stat& st = *CAS_CAST(p);
01115 uid_t uid = geteuid();
01116
01117
01118 if (uid == st.st_uid) {
01119 if ( (!(amode & R_OK) || (st.st_mode & S_IRUSR)) &&
01120 (!(amode & W_OK) || (st.st_mode & S_IWUSR)) &&
01121 (!(amode & X_OK) || (st.st_mode & S_IXUSR)) )
01122 return true;
01123 }
01124
01125
01126 int ngroups = 0;
01127 gid_t gids[NGROUPS_MAX + 1];
01128 gids[0] = getegid();
01129 ngroups = getgroups((int)(sizeof(gids)/sizeof(gids[0])-1), gids+1);
01130 if (ngroups < 0) {
01131 ngroups = 1;
01132 } else {
01133 ngroups++;
01134 }
01135 for (int i = 1; i < ngroups; i++) {
01136 if (gids[i] == uid) {
01137 if (i < --ngroups) {
01138 memmove(&gids[i], &gids[i+1], sizeof(gids[0])*(ngroups-i));
01139 }
01140 break;
01141 }
01142 }
01143
01144
01145 for (int i = 0; i < ngroups; i++) {
01146 if (gids[i] == st.st_gid) {
01147 if ( (!(amode & R_OK) || (st.st_mode & S_IRGRP)) &&
01148 (!(amode & W_OK) || (st.st_mode & S_IWGRP)) &&
01149 (!(amode & X_OK) || (st.st_mode & S_IXGRP)) )
01150 return true;
01151 }
01152 }
01153
01154
01155 if ( (!(amode & R_OK) || (st.st_mode & S_IROTH)) &&
01156 (!(amode & W_OK) || (st.st_mode & S_IWOTH)) &&
01157 (!(amode & X_OK) || (st.st_mode & S_IXOTH)) )
01158 return true;
01159
01160
01161 return false;
01162 }
01163
01164
01165 static bool s_CheckAccessPath(const char* path, int amode)
01166 {
01167 if (!path) {
01168 errno = 0;
01169 return false;
01170 }
01171 if (!*path) {
01172 errno = ENOENT;
01173 return false;
01174 }
01175 struct stat st;
01176 if (stat(path, &st) != 0)
01177 return false;
01178
01179 if (!s_CheckAccessStat(&st, amode)) {
01180 errno = EACCES;
01181 return false;
01182 }
01183
01184 return true;
01185 }
01186
01187 #endif // defined(NCBI_OS_UNIX)
01188
01189
01190 bool CDirEntry::CheckAccess(TMode access_mode) const
01191 {
01192 #if defined(NCBI_OS_MSWIN)
01193
01194
01195 ACCESS_MASK mask = 0;
01196 if ( CWinSecurity::GetFilePermissions(GetPath(), &mask) ) {
01197 TMode perm = ( (mask & FILE_READ_DATA ? fRead : 0) |
01198 (mask & FILE_WRITE_DATA ? fWrite : 0) |
01199 (mask & FILE_EXECUTE ? fExecute : 0) );
01200 return (access_mode & perm) > 0;
01201 }
01202 return false;
01203
01204 #elif defined(NCBI_OS_UNIX)
01205 int amode = F_OK;
01206 if ( access_mode & fRead) amode |= R_OK;
01207 if ( access_mode & fWrite) amode |= W_OK;
01208 if ( access_mode & fExecute) amode |= X_OK;
01209
01210
01211 # if defined(HAVE_EUIDACCESS)
01212 return euidaccess(GetPath().c_str(), amode) == 0;
01213
01214 # elif defined(EFF_ONLY_OK)
01215
01216 amode |= EFF_ONLY_OK;
01217 return access(GetPath().c_str(), amode) == 0;
01218
01219 # else
01220
01221
01222
01223 if (getuid() == geteuid() && getgid() == getegid()) {
01224 return access(GetPath().c_str(), amode) == 0;
01225 }
01226
01227
01228
01229
01230 return s_CheckAccessPath(GetPath().c_str(), amode);
01231
01232 # endif
01233 #endif
01234 }
01235
01236
01237 #ifdef NCBI_OS_MSWIN
01238
01239 bool s_FileTimeToCTime(const FILETIME& filetime, CTime& t)
01240 {
01241
01242 t.Clear();
01243
01244 if ( !filetime.dwLowDateTime && !filetime.dwHighDateTime ) {
01245
01246 return true;
01247 }
01248 SYSTEMTIME system;
01249 FILETIME local;
01250
01251
01252 if ( !FileTimeToLocalFileTime(&filetime, &local) ) {
01253 return false;
01254 }
01255
01256 if ( !FileTimeToSystemTime(&local, &system) ) {
01257 return false;
01258 }
01259
01260
01261 CTime newtime(system.wYear,
01262 system.wMonth,
01263 system.wDay,
01264 system.wHour,
01265 system.wMinute,
01266 system.wSecond,
01267 system.wMilliseconds *
01268 (kNanoSecondsPerSecond / kMilliSecondsPerSecond),
01269 CTime::eLocal,
01270 t.GetTimeZonePrecision());
01271
01272
01273 if ( t.GetTimeZone() == CTime::eLocal ) {
01274 t = newtime;
01275 } else {
01276 t = newtime.GetGmtTime();
01277 }
01278 return true;
01279 }
01280
01281
01282 void s_UnixTimeToFileTime(time_t t, long nanosec, FILETIME& filetime)
01283 {
01284
01285 LONGLONG res;
01286
01287 res = Int32x32To64(t, 10000000) + 116444736000000000 + nanosec/100;
01288 filetime.dwLowDateTime = (DWORD)res;
01289 filetime.dwHighDateTime = (DWORD)(res >> 32);
01290 }
01291
01292 #endif // NCBI_OS_MSWIN
01293
01294
01295 bool CDirEntry::GetTime(CTime* modification,
01296 CTime* last_access,
01297 CTime* creation) const
01298 {
01299 #ifdef NCBI_OS_MSWIN
01300 HANDLE handle;
01301 WIN32_FIND_DATA buf;
01302
01303
01304 handle = FindFirstFile(GetPath().c_str(), &buf);
01305 if ( handle == INVALID_HANDLE_VALUE ) {
01306
01307
01308 return false;
01309 }
01310 FindClose(handle);
01311
01312
01313 if ( modification &&
01314 !s_FileTimeToCTime(buf.ftLastWriteTime, *modification) ) {
01315 LOG_ERROR_AND_RETURN("CDirEntry::GetTime():"
01316 " Cannot get modification time for "
01317 << GetPath());
01318 }
01319 if ( last_access &&
01320 !s_FileTimeToCTime(buf.ftLastAccessTime, *last_access) ) {
01321 LOG_ERROR_AND_RETURN("CDirEntry::GetTime():"
01322 " Cannot get access time for " << GetPath());
01323 }
01324 if ( creation &&
01325 !s_FileTimeToCTime(buf.ftCreationTime, *creation) ) {
01326 LOG_ERROR_AND_RETURN("CDirEntry::GetTime():"
01327 " Cannot get creation time for " << GetPath());
01328 }
01329 return true;
01330
01331 #else // NCBI_OS_UNIX
01332
01333 struct SStat st;
01334 if ( !Stat(&st) ) {
01335
01336 return false;
01337 }
01338 if ( modification ) {
01339 modification->SetTimeT(st.orig.st_mtime);
01340 if ( st.mtime_nsec )
01341 modification->SetNanoSecond(st.mtime_nsec);
01342 }
01343 if ( last_access ) {
01344 last_access->SetTimeT(st.orig.st_atime);
01345 if ( st.atime_nsec )
01346 last_access->SetNanoSecond(st.atime_nsec);
01347 }
01348 if ( creation ) {
01349 creation->SetTimeT(st.orig.st_ctime);
01350 if ( st.ctime_nsec )
01351 creation->SetNanoSecond(st.ctime_nsec);
01352 }
01353 return true;
01354 #endif
01355 }
01356
01357
01358 bool CDirEntry::SetTime(CTime* modification,
01359 CTime* last_access,
01360 CTime* creation) const
01361 {
01362 #ifdef NCBI_OS_MSWIN
01363 if ( !modification && !last_access && !creation ) {
01364 return true;
01365 }
01366
01367 FILETIME x_modification, x_last_access, x_creation;
01368 LPFILETIME p_modification = NULL, p_last_access = NULL, p_creation = NULL;
01369
01370
01371 if ( modification ) {
01372 s_UnixTimeToFileTime(modification->GetTimeT(),
01373 modification->NanoSecond(), x_modification);
01374 p_modification = &x_modification;
01375 }
01376 if ( last_access ) {
01377 s_UnixTimeToFileTime(last_access->GetTimeT(),
01378 last_access->NanoSecond(), x_last_access);
01379 p_last_access = &x_last_access;
01380 }
01381 if ( creation ) {
01382 s_UnixTimeToFileTime(creation->GetTimeT(),
01383 creation->NanoSecond(), x_creation);
01384 p_creation = &x_creation;
01385 }
01386
01387
01388 HANDLE h = CreateFile(GetPath().c_str(), FILE_WRITE_ATTRIBUTES,
01389 FILE_SHARE_READ, NULL, OPEN_EXISTING,
01390 FILE_FLAG_BACKUP_SEMANTICS , NULL);
01391 if ( h == INVALID_HANDLE_VALUE ) {
01392 LOG_ERROR_AND_RETURN("CDirEntry::SetTime():"
01393 " Cannot open " << GetPath());
01394 }
01395 if ( !SetFileTime(h, p_creation, p_last_access, p_modification) ) {
01396 CloseHandle(h);
01397 LOG_ERROR_AND_RETURN("CDirEntry::SetTime():"
01398 " Cannot set new time for " << GetPath());
01399 }
01400 CloseHandle(h);
01401
01402 return true;
01403
01404 #else // NCBI_OS_UNIX
01405 if ( !modification && !last_access ) {
01406 return true;
01407 }
01408
01409 # ifdef HAVE_UTIMES
01410
01411 CTime x_modification, x_last_access;
01412
01413 if ( !modification || !last_access ) {
01414 if ( !GetTime(modification ? 0 : &x_modification,
01415 last_access ? 0 : &x_last_access,
01416 0 ) ) {
01417 return false;
01418 }
01419 if (!modification) {
01420 modification = &x_modification;
01421 } else {
01422 last_access = &x_last_access;
01423 }
01424 }
01425
01426
01427 struct timeval tvp[2];
01428 tvp[0].tv_sec = last_access->GetTimeT();
01429 tvp[0].tv_usec = last_access->NanoSecond() / 1000;
01430 tvp[1].tv_sec = modification->GetTimeT();
01431 tvp[1].tv_usec = modification->NanoSecond() / 1000;
01432
01433 # ifdef HAVE_LUTIMES
01434 bool ut_res = lutimes(GetPath().c_str(), tvp) == 0;
01435 # else
01436 bool ut_res = utimes(GetPath().c_str(), tvp) == 0;
01437 # endif
01438 if ( !ut_res ) {
01439 LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::SetTime():"
01440 " Cannot change time for " << GetPath());
01441 }
01442 return true;
01443
01444 # else
01445
01446
01447
01448
01449 time_t x_modification, x_last_access;
01450
01451 if ((!modification || !last_access)
01452 && !GetTimeT(&x_modification,
01453 &x_last_access,
01454 0 )) {
01455 return false;
01456 }
01457
01458
01459 struct utimbuf times;
01460 times.modtime = modification ? modification->GetTimeT() : x_modification;
01461 times.actime = last_access ? last_access->GetTimeT() : x_last_access;
01462 if ( utime(GetPath().c_str(), ×) != 0 ) {
01463 LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::SetTime():"
01464 " Cannot change time for " << GetPath());
01465 }
01466 return true;
01467
01468 # endif // HAVE_UTIMES
01469
01470 #endif
01471 }
01472
01473
01474 bool CDirEntry::GetTimeT(time_t* modification,
01475 time_t* last_access,
01476 time_t* creation) const
01477 {
01478 struct stat st;
01479 if (stat(GetPath().c_str(), &st) != 0) {
01480 LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::GetTimeT():"
01481 " stat() failed for " << GetPath());
01482 }
01483 if ( modification ) {
01484 *modification = st.st_mtime;
01485 }
01486 if ( last_access ) {
01487 *last_access = st.st_atime;
01488 }
01489 if ( creation ) {
01490 *creation = st.st_ctime;
01491 }
01492 return true;
01493 }
01494
01495
01496 bool CDirEntry::SetTimeT(time_t* modification,
01497 time_t* last_access,
01498 time_t* creation) const
01499 {
01500 #ifdef NCBI_OS_MSWIN
01501 if ( !modification && !last_access && !creation ) {
01502 return true;
01503 }
01504
01505 FILETIME x_modification, x_last_access, x_creation;
01506 LPFILETIME p_modification = NULL, p_last_access = NULL, p_creation = NULL;
01507
01508
01509 if ( modification ) {
01510 s_UnixTimeToFileTime(*modification, 0, x_modification);
01511 p_modification = &x_modification;
01512 }
01513 if ( last_access ) {
01514 s_UnixTimeToFileTime(*last_access, 0, x_last_access);
01515 p_last_access = &x_last_access;
01516 }
01517 if ( creation ) {
01518 s_UnixTimeToFileTime(*creation, 0, x_creation);
01519 p_creation = &x_creation;
01520 }
01521
01522
01523 HANDLE h = CreateFile(GetPath().c_str(), FILE_WRITE_ATTRIBUTES,
01524 FILE_SHARE_READ, NULL, OPEN_EXISTING,
01525 FILE_FLAG_BACKUP_SEMANTICS , NULL);
01526 if ( h == INVALID_HANDLE_VALUE ) {
01527 LOG_ERROR_AND_RETURN("CDirEntry::SetTimeT():"
01528 " Cannot open " << GetPath());
01529 return false;
01530 }
01531 if ( !SetFileTime(h, p_creation, p_last_access, p_modification) ) {
01532 CloseHandle(h);
01533 LOG_ERROR_AND_RETURN("CDirEntry::SetTimeT():"
01534 " Cannot set new time for " << GetPath());
01535 }
01536 CloseHandle(h);
01537
01538 return true;
01539
01540 #else // NCBI_OS_UNIX
01541 if ( !modification && !last_access )
01542 return true;
01543
01544 time_t x_modification, x_last_access;
01545 if ((!modification || !last_access)
01546 && !GetTimeT(&x_modification,
01547 &x_last_access,
01548 0 )) {
01549 return false;
01550 }
01551
01552
01553 struct utimbuf times;
01554 times.modtime = modification ? *modification : x_modification;
01555 times.actime = last_access ? *last_access : x_last_access;
01556 if ( utime(GetPath().c_str(), ×) != 0 ) {
01557 LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::SetTimeT():"
01558 " Cannot change time for " << GetPath());
01559 }
01560 return true;
01561
01562 #endif
01563 }
01564
01565
01566 bool CDirEntry::Stat(struct SStat *buffer, EFollowLinks follow_links) const
01567 {
01568 if ( !buffer ) {
01569 errno = EFAULT;
01570 LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::Stat():"
01571 " NULL stat buffer passed for "
01572 << GetPath());
01573 }
01574
01575 int errcode;
01576 #ifdef NCBI_OS_MSWIN
01577 errcode = stat(GetPath().c_str(), &buffer->orig);
01578 #else // NCBI_OS_UNIX
01579 if (follow_links == eFollowLinks) {
01580 errcode = stat(GetPath().c_str(), &buffer->orig);
01581 } else {
01582 errcode = lstat(GetPath().c_str(), &buffer->orig);
01583 }
01584 #endif
01585 if (errcode != 0) {
01586 return false;
01587 }
01588
01589
01590 buffer->atime_nsec = 0;
01591 buffer->mtime_nsec = 0;
01592 buffer->ctime_nsec = 0;
01593
01594 #ifdef NCBI_OS_UNIX
01595
01596
01597
01598
01599
01600 # if !defined(__GLIBC_PREREQ)
01601 # define __GLIBC_PREREQ(x, y) 0
01602 # endif
01603
01604 # if defined(NCBI_OS_LINUX) && __GLIBC_PREREQ(2,3)
01605 # if defined(__USE_MISC)
01606 buffer->atime_nsec = buffer->orig.st_atim.tv_nsec;
01607 buffer->mtime_nsec = buffer->orig.st_mtim.tv_nsec;
01608 buffer->ctime_nsec = buffer->orig.st_ctim.tv_nsec;
01609 # else
01610 buffer->atime_nsec = buffer->orig.st_atimensec;
01611 buffer->mtime_nsec = buffer->orig.st_mtimensec;
01612 buffer->ctime_nsec = buffer->orig.st_ctimensec;
01613 # endif
01614 # endif
01615
01616
01617 # if defined(NCBI_OS_SOLARIS)
01618 # if !defined(_XOPEN_SOURCE) && !defined(_POSIX_C_SOURCE) || \
01619 defined(__EXTENSIONS__)
01620 buffer->atime_nsec = buffer->orig.st_atim.tv_nsec;
01621 buffer->mtime_nsec = buffer->orig.st_mtim.tv_nsec;
01622 buffer->ctime_nsec = buffer->orig.st_ctim.tv_nsec;
01623 # else
01624 buffer->atime_nsec = buffer->orig.st_atim.__tv_nsec;
01625 buffer->mtime_nsec = buffer->orig.st_mtim.__tv_nsec;
01626 buffer->ctime_nsec = buffer->orig.st_ctim.__tv_nsec;
01627 # endif
01628 # endif
01629
01630
01631 # if defined(NCBI_OS_BSD) || defined(NCBI_OS_DARWIN)
01632 # if defined(_POSIX_SOURCE)
01633 buffer->atime_nsec = buffer->orig.st_atimensec;
01634 buffer->mtime_nsec = buffer->orig.st_mtimensec;
01635 buffer->ctime_nsec = buffer->orig.st_ctimensec;
01636 # else
01637 buffer->atime_nsec = buffer->orig.st_atimespec.tv_nsec;
01638 buffer->mtime_nsec = buffer->orig.st_mtimespec.tv_nsec;
01639 buffer->ctime_nsec = buffer->orig.st_ctimespec.tv_nsec;
01640 # endif
01641 # endif
01642
01643
01644 # if defined(NCBI_OS_IRIX)
01645 # if defined(tv_sec)
01646 buffer->atime_nsec = buffer->orig.st_atim.__tv_nsec;
01647 buffer->mtime_nsec = buffer->orig.st_mtim.__tv_nsec;
01648 buffer->ctime_nsec = buffer->orig.st_ctim.__tv_nsec;
01649 # else
01650 buffer->atime_nsec = buffer->orig.st_atim.tv_nsec;
01651 buffer->mtime_nsec = buffer->orig.st_mtim.tv_nsec;
01652 buffer->ctime_nsec = buffer->orig.st_ctim.tv_nsec;
01653 # endif
01654 # endif
01655
01656 #endif // NCBI_OS_UNIX
01657
01658 return true;
01659 }
01660
01661
01662 CDirEntry::EType CDirEntry::GetType(EFollowLinks follow) const
01663 {
01664 struct stat st;
01665 int errcode;
01666
01667 #if defined(NCBI_OS_MSWIN)
01668 errcode = stat(GetPath().c_str(), &st);
01669 #else // NCBI_OS_UNIX
01670 if (follow == eFollowLinks) {
01671 errcode = stat(GetPath().c_str(), &st);
01672 } else {
01673 errcode = lstat(GetPath().c_str(), &st);
01674 }
01675 #endif
01676 if (errcode != 0) {
01677 return eUnknown;
01678 }
01679 return GetType(st);
01680 }
01681
01682
01683 #define NCBI_IS_TYPE(mode, mask) (((mode) & S_IFMT) == (mask))
01684
01685 CDirEntry::EType CDirEntry::GetType(const struct stat& st)
01686 {
01687 unsigned int mode = (unsigned int)st.st_mode;
01688
01689 #ifdef S_ISDIR
01690 if (S_ISDIR(mode))
01691 #else
01692 if (NCBI_IS_TYPE(mode, S_IFDIR))
01693 #endif
01694 return eDir;
01695
01696 #ifdef S_ISCHR
01697 if (S_ISCHR(mode))
01698 #else
01699 if (NCBI_IS_TYPE(mode, S_IFCHR))
01700 #endif
01701 return eCharSpecial;
01702
01703 #ifdef NCBI_OS_MSWIN
01704 if (NCBI_IS_TYPE(mode, _S_IFIFO))
01705 return ePipe;
01706 #else
01707
01708 # ifdef S_ISFIFO
01709 if (S_ISFIFO(mode))
01710 # else
01711 if (NCBI_IS_TYPE(mode, S_IFIFO))
01712 # endif
01713 return ePipe;
01714
01715 # ifdef S_ISLNK
01716 if (S_ISLNK(mode))
01717 # else
01718 if (NCBI_IS_TYPE(mode, S_IFLNK))
01719 # endif
01720 return eLink;
01721
01722 # ifdef S_ISSOCK
01723 if (S_ISSOCK(mode))
01724 # else
01725 if (NCBI_IS_TYPE(mode, S_IFSOCK))
01726 # endif
01727 return eSocket;
01728
01729 # ifdef S_ISBLK
01730 if (S_ISBLK(mode))
01731 # else
01732 if (NCBI_IS_TYPE(mode, S_IFBLK))
01733 # endif
01734 return eBlockSpecial;
01735
01736 # ifdef S_IFDOOR
01737
01738 # ifdef S_ISDOOR
01739 if (S_ISDOOR(mode))
01740 # else
01741 if (NCBI_IS_TYPE(mode, S_IFDOOR))
01742 # endif
01743 return eDoor;
01744 # endif
01745
01746 #endif //NCBI_OS_MSWIN
01747
01748
01749 #ifdef S_ISREG
01750 if (S_ISREG(mode))
01751 #else
01752 if (NCBI_IS_TYPE(mode, S_IFREG))
01753 #endif
01754 return eFile;
01755
01756 return eUnknown;
01757 }
01758
01759
01760 string CDirEntry::LookupLink(void) const
01761 {
01762 #ifdef NCBI_OS_MSWIN
01763 return kEmptyStr;
01764
01765 #else // NCBI_OS_UNIX
01766 char buf[PATH_MAX];
01767 string name;
01768 int length = (int)readlink(GetPath().c_str(), buf, sizeof(buf));
01769 if (length > 0) {
01770 name.assign(buf, length);
01771 }
01772 return name;
01773 #endif
01774 }
01775
01776
01777 void CDirEntry::DereferenceLink(void)
01778 {
01779 #ifdef NCBI_OS_MSWIN
01780
01781 return;
01782 #endif
01783 string prev;
01784 while ( IsLink() ) {
01785 string name = LookupLink();
01786 if ( name.empty() || name == prev ) {
01787 return;
01788 }
01789 prev = name;
01790 if ( IsAbsolutePath(name) ) {
01791 Reset(name);
01792 } else {
01793 string path = NormalizePath(MakePath(GetDir(), name));
01794 Reset(path);
01795 }
01796 }
01797 }
01798
01799
01800 void CDirEntry::DereferencePath(void)
01801 {
01802 #ifdef NCBI_OS_MSWIN
01803
01804 return;
01805 #endif
01806
01807 DereferenceLink();
01808
01809
01810 string path = GetPath();
01811 size_t pos = path.find_last_of(ALL_SEPARATORS);
01812 if (pos == NPOS) {
01813 return;
01814 }
01815 string filename = path.substr(pos+1);
01816 string dirname = path.substr(0, pos);
01817 if ( dirname.empty() ) {
01818 return;
01819 }
01820
01821 CDirEntry e(dirname);
01822 e.DereferencePath();
01823 Reset(MakePath(e.GetPath(), filename));
01824 }
01825
01826
01827 bool CDirEntry::Copy(const string& path, TCopyFlags flags, size_t buf_size)
01828 const
01829 {
01830
01831 bool follow = F_ISSET(flags, fCF_FollowLinks);
01832 EType type = GetType(follow ? eFollowLinks : eIgnoreLinks);
01833 switch (type) {
01834 case eFile:
01835 {
01836 CFile entry(GetPath());
01837 return entry.Copy(path, flags, buf_size);
01838 }
01839 case eDir:
01840 {
01841 CDir entry(GetPath());
01842 return entry.Copy(path, flags, buf_size);
01843 }
01844 case eLink:
01845 {
01846 CSymLink entry(GetPath());
01847 return entry.Copy(path, flags, buf_size);
01848 }
01849 case eUnknown:
01850 {
01851 return false;
01852 }
01853 default:
01854 break;
01855 }
01856
01857
01858 return (flags & fCF_SkipUnsupported) == fCF_SkipUnsupported;
01859 }
01860
01861
01862 bool CDirEntry::Rename(const string& newname, TRenameFlags flags)
01863 {
01864 CDirEntry src(*this);
01865 CDirEntry dst(newname);
01866
01867
01868 if ( F_ISSET(flags, fRF_FollowLinks) ) {
01869 src.DereferenceLink();
01870 dst.DereferenceLink();
01871 }
01872
01873 EType src_type = src.GetType();
01874 if ( src_type == eUnknown ) {
01875 LOG_ERROR_AND_RETURN("CDirEntry::Rename():"
01876 " Source path does not exist: " << src.GetPath());
01877 }
01878 EType dst_type = dst.GetType();
01879
01880
01881 if ( dst_type != eUnknown ) {
01882
01883 if ( F_ISSET(flags, fRF_EqualTypes) && (src_type != dst_type) ) {
01884 LOG_ERROR_AND_RETURN("CDirEntry::Rename():"
01885 " Both source and destination exist"
01886 " and have different types: "
01887 << src.GetPath() << " and " << dst.GetPath());
01888 }
01889
01890 if ( !F_ISSET(flags, fRF_Overwrite) ) {
01891 LOG_ERROR_AND_RETURN("CDirEntry::Rename():"
01892 " Destination path already exists: "
01893 << dst.GetPath());
01894 }
01895
01896 if ( F_ISSET(flags, fRF_Update) && !src.IsNewer(dst.GetPath(), 0)) {
01897 return src.Remove();
01898 }
01899
01900 if ( F_ISSET(flags, fRF_Backup) ) {
01901
01902
01903 CDirEntry dst_tmp(dst);
01904 if ( !dst_tmp.Backup(GetBackupSuffix(), eBackup_Rename) ) {
01905 LOG_ERROR_AND_RETURN("CDirEntry::Rename():"
01906 " Cannot backup " << dst.GetPath());
01907 }
01908 }
01909
01910 if ( F_ISSET(flags, fRF_Overwrite) ) {
01911 if ( dst.Exists() ) {
01912 dst.Remove();
01913 }
01914 }
01915 }
01916
01917
01918
01919
01920 if ( dst.Exists() ) {
01921 LOG_ERROR_AND_RETURN("CDirEntry::Rename():"
01922 " Destination path exists: " << GetPath());
01923 }
01924
01925 if ( rename(src.GetPath().c_str(), dst.GetPath().c_str()) != 0 ) {
01926 #ifdef NCBI_OS_MSWIN
01927 if ( errno != EACCES ) {
01928 LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::Rename():"
01929 " rename() failed for " << GetPath());
01930 }
01931 #else // NCBI_OS_UNIX
01932 if ( errno != EXDEV ) {
01933 LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::Rename():"
01934 " rename() failed for " << GetPath());
01935 }
01936 #endif // NCBI_OS_...
01937
01938
01939 auto_ptr<CDirEntry>
01940 e(CDirEntry::CreateObject(src_type, src.GetPath()));
01941 if ( !e->Copy(dst.GetPath(), fCF_Recursive | fCF_PreserveAll ) ) {
01942 auto_ptr<CDirEntry>
01943 tmp(CDirEntry::CreateObject(src_type, dst.GetPath()));
01944 tmp->Remove(eRecursive);
01945 return false;
01946 }
01947
01948 if ( !e->Remove(eRecursive) ) {
01949
01950
01951 return false;
01952 }
01953 }
01954 Reset(newname);
01955 return true;
01956 }
01957
01958
01959 bool CDirEntry::Remove(EDirRemoveMode mode) const
01960 {
01961
01962 if ( IsDir(eIgnoreLinks) ) {
01963 CDir dir(GetPath());
01964 return dir.Remove(mode);
01965 }
01966
01967 if ( remove(GetPath().c_str()) != 0 ) {
01968 switch (errno) {
01969 case ENOENT:
01970 if (mode == eRecursiveIgnoreMissing)
01971 return true;
01972 break;
01973
01974 #if defined(NCBI_OS_MSWIN)
01975 case EACCES:
01976 if (NCBI_PARAM_TYPE(NCBI, DeleteReadOnlyFiles)::GetDefault()) {
01977 if (!SetMode(eDefault))
01978 return false;
01979 if (remove(GetPath().c_str()) == 0)
01980 return true;
01981 }
01982 #endif
01983 }
01984 LOG_ERROR_AND_RETURN_ERRNO(
01985 "CDirEntry::Remove():"
01986 " remove() failed for " << GetPath());
01987 }
01988 return true;
01989 }
01990
01991
01992 bool CDirEntry::Backup(const string& suffix, EBackupMode mode,
01993 TCopyFlags copyflags, size_t copybufsize)
01994 {
01995 string backup_name = DeleteTrailingPathSeparator(GetPath()) +
01996 (suffix.empty() ? string(GetBackupSuffix()) : suffix);
01997 switch (mode) {
01998 case eBackup_Copy:
01999 {
02000 TCopyFlags flags = copyflags;
02001 flags &= ~(fCF_Update | fCF_Backup);
02002 flags |= (fCF_Overwrite | fCF_TopDirOnly);
02003 return Copy(backup_name, flags, copybufsize);
02004 }
02005 case eBackup_Rename:
02006 return Rename(backup_name, fRF_Overwrite);
02007 default:
02008 _TROUBLE;
02009 }
02010 return false;
02011 }
02012
02013
02014 bool CDirEntry::IsNewer(const string& entry_name, TIfAbsent2 if_absent) const
02015 {
02016 CDirEntry entry(entry_name);
02017 CTime this_time;
02018 CTime entry_time;
02019 int v = 0;
02020
02021 if ( !GetTime(&this_time) ) {
02022 v += 1;
02023 }
02024 if ( !entry.GetTime(&entry_time) ) {
02025 v += 2;
02026 }
02027 if ( v == 0 ) {
02028 return this_time > entry_time;
02029 }
02030 if ( if_absent ) {
02031 switch(v) {
02032 case 1:
02033 if ( if_absent &
02034 (fNoThisHasPath_Newer | fNoThisHasPath_NotNewer) )
02035 return (if_absent & fNoThisHasPath_Newer) > 0;
02036 break;
02037 case 2:
02038 if ( if_absent &
02039 (fHasThisNoPath_Newer | fHasThisNoPath_NotNewer) )
02040 return (if_absent & fHasThisNoPath_Newer) > 0;
02041 break;
02042 case 3:
02043 if ( if_absent &
02044 (fNoThisNoPath_Newer | fNoThisNoPath_NotNewer) )
02045 return (if_absent & fNoThisNoPath_Newer) > 0;
02046 break;
02047 }
02048 }
02049
02050 NCBI_THROW(CFileException, eNotExists,
02051 "Directory entry does not exist");
02052
02053 return false;
02054 }
02055
02056
02057 bool CDirEntry::IsNewer(time_t tm, EIfAbsent if_absent) const
02058 {
02059 time_t current;
02060 if ( !GetTimeT(¤t) ) {
02061 switch(if_absent) {
02062 case eIfAbsent_Newer:
02063 return true;
02064 case eIfAbsent_NotNewer:
02065 return false;
02066 case eIfAbsent_Throw:
02067 default:
02068 NCBI_THROW(CFileException, eNotExists,
02069 "Directory entry does not exist");
02070 }
02071 }
02072 return current > tm;
02073 }
02074
02075
02076 bool CDirEntry::IsNewer(const CTime& tm, EIfAbsent if_absent) const
02077 {
02078 CTime current;
02079 if ( !GetTime(¤t) ) {
02080 switch(if_absent) {
02081 case eIfAbsent_Newer:
02082 return true;
02083 case eIfAbsent_NotNewer:
02084 return false;
02085 case eIfAbsent_Throw:
02086 default:
02087 NCBI_THROW(CFileException, eNotExists,
02088 "Directory entry does not exist");
02089 }
02090 }
02091 return current > tm;
02092 }
02093
02094
02095 bool CDirEntry::IsIdentical(const string& entry_name,
02096 EFollowLinks follow_links) const
02097 {
02098 #if defined(NCBI_OS_UNIX)
02099 struct SStat st1, st2;
02100 if ( !Stat(&st1, follow_links) ) {
02101 LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::IsIdentical():"
02102 " Cannot find " << GetPath());
02103 }
02104 if ( !CDirEntry(entry_name).Stat(&st2, follow_links) ) {
02105 LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::IsIdentical():"
02106 " Cannot find " << entry_name);
02107 }
02108 return st1.orig.st_dev == st2.orig.st_dev &&
02109 st1.orig.st_ino == st2.orig.st_ino;
02110 #else
02111 return NormalizePath(GetPath(), follow_links) ==
02112 NormalizePath(entry_name, follow_links);
02113 #endif
02114 }
02115
02116
02117 bool CDirEntry::GetOwner(string* owner, string* group,
02118 EFollowLinks follow) const
02119 {
02120 if ( !owner && !group ) {
02121 return false;
02122 }
02123
02124 #if defined(NCBI_OS_MSWIN)
02125
02126 return CWinSecurity::GetFileOwner(GetPath(), owner, group);
02127
02128 #elif defined(NCBI_OS_UNIX)
02129
02130 struct stat st;
02131 int errcode;
02132
02133 if ( follow == eFollowLinks ) {
02134 errcode = stat(GetPath().c_str(), &st);
02135 } else {
02136 errcode = lstat(GetPath().c_str(), &st);
02137 }
02138 if ( errcode != 0 ) {
02139 LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::GetOwner():"
02140 " stat() failed for " << GetPath());
02141 }
02142
02143 if ( owner ) {
02144 struct passwd *pw = getpwuid(st.st_uid);
02145 if (pw) {
02146 (*owner).assign(pw->pw_name);
02147 } else {
02148 NStr::UIntToString(*owner, st.st_uid);
02149 }
02150 }
02151 if ( group ) {
02152 struct group *gr = getgrgid(st.st_gid);
02153 if ( gr ) {
02154 (*group).assign(gr->gr_name);
02155 } else {
02156 NStr::UIntToString(*group, st.st_gid);
02157 }
02158 }
02159 return true;
02160 #endif
02161 }
02162
02163
02164 bool CDirEntry::SetOwner(const string& owner, const string& group,
02165 EFollowLinks follow) const
02166 {
02167 #if defined(NCBI_OS_MSWIN)
02168
02169
02170 return CWinSecurity::SetFileOwner(GetPath(), owner);
02171
02172 #elif defined(NCBI_OS_UNIX)
02173
02174 if ( owner.empty() && group.empty() ) {
02175 return false;
02176 }
02177
02178 struct stat st;
02179 int errcode;
02180
02181 if ( follow == eFollowLinks ) {
02182 errcode = stat(GetPath().c_str(), &st);
02183 } else {
02184 errcode = lstat(GetPath().c_str(), &st);
02185 }
02186 if ( errcode != 0 ) {
02187 LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::GetOwner():"
02188 " stat() failed for " << GetPath());
02189 }
02190
02191 uid_t uid = uid_t(-1);
02192 gid_t gid = gid_t(-1);
02193
02194 if ( !owner.empty() ) {
02195 struct passwd *pw = getpwnam(owner.c_str());
02196 if ( !pw ) {
02197 uid = (uid_t) NStr::StringToUInt(owner.c_str(),
02198 NStr::fConvErr_NoThrow, 0);
02199 if ( errno )
02200 LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::SetOwner():"
02201 " Invalid owner name " << owner);
02202 } else {
02203 uid = pw->pw_uid;
02204 }
02205 }
02206 if ( !group.empty() ) {
02207 struct group *gr = getgrnam(group.c_str());
02208 if ( !gr ) {
02209 gid = (gid_t) NStr::StringToUInt(group.c_str(),
02210 NStr::fConvErr_NoThrow, 0);
02211 if ( errno )
02212 LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::SetOwner():"
02213 " Invalid group name " << group);
02214 } else {
02215 gid = gr->gr_gid;
02216 }
02217 }
02218
02219 if ( follow == eFollowLinks ) {
02220 if ( chown(GetPath().c_str(), uid, gid) ) {
02221 LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::SetOwner():"
02222 " Cannot change owner for "
02223 << GetPath());
02224 }
02225 } else {
02226 # if defined(HAVE_LCHOWN)
02227 if ( lchown(GetPath().c_str(), uid, gid) ) {
02228 LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::SetOwner():"
02229 " Cannot change owner for "
02230 << GetPath());
02231 }
02232 # endif
02233 }
02234 return true;
02235
02236 #endif
02237 }
02238
02239
02240 string CDirEntry::GetTmpName(ETmpFileCreationMode mode)
02241 {
02242 #if defined(NCBI_OS_MSWIN) || defined(NCBI_OS_UNIX)
02243 return GetTmpNameEx(kEmptyStr, kEmptyStr, mode);
02244 #else
02245 if (mode == eTmpFileCreate) {
02246 ERR_POST_X(2, Warning <<
02247 "Temporary file cannot be auto-created on this platform,"
02248 " so return its name only");
02249 }
02250 char* filename = tempnam(0,0);
02251 if ( !filename ) {
02252 return kEmptyStr;
02253 }
02254 string res(filename);
02255 free(filename);
02256 return res;
02257 #endif
02258 }
02259
02260
02261 #if !defined(NCBI_OS_UNIX)
02262
02263 static string s_StdGetTmpName(const char* dir, const char* prefix)
02264 {
02265 char* filename = tempnam(dir, prefix);
02266 if ( !filename ) {
02267 return kEmptyStr;
02268 }
02269 string str(filename);
02270 free(filename);
02271 return str;
02272 }
02273
02274 #endif
02275
02276
02277 string CDirEntry::GetTmpNameEx(const string& dir,
02278 const string& prefix,
02279 ETmpFileCreationMode mode)
02280 {
02281 #if defined(NCBI_OS_MSWIN) || defined(NCBI_OS_UNIX)
02282 string x_dir = dir;
02283 if ( x_dir.empty() ) {
02284
02285 x_dir = NCBI_PARAM_TYPE(NCBI,TmpDir)::GetThreadDefault();
02286 if ( x_dir.empty() ) {
02287
02288 x_dir = CDir::GetTmpDir();
02289 }
02290 }
02291 if ( !x_dir.empty() ) {
02292 x_dir = AddTrailingPathSeparator(x_dir);
02293 }
02294 string fn;
02295
02296 # if defined(NCBI_OS_UNIX)
02297 string pattern = x_dir + prefix + "XXXXXX";
02298 AutoPtr<char, CDeleter<char> > filename(strdup(pattern.c_str()));
02299 int fd = mkstemp(filename.get());
02300 close(fd);
02301 if (mode != eTmpFileCreate) {
02302 remove(filename.get());
02303 }
02304 fn = filename.get();
02305
02306 # elif defined(NCBI_OS_MSWIN)
02307 char buffer[MAX_PATH];
02308 HANDLE hFile = INVALID_HANDLE_VALUE;
02309 srand((unsigned)time(0));
02310 unsigned long ofs = rand();
02311
02312 while ( ofs < numeric_limits<unsigned long>::max() ) {
02313 _ultoa((unsigned long)ofs, buffer, 24);
02314 fn = x_dir + prefix + buffer;
02315 hFile = CreateFile(fn.c_str(), GENERIC_ALL, 0, NULL,
02316 CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY, NULL);
02317 if (hFile != INVALID_HANDLE_VALUE) {
02318 break;
02319 }
02320 ofs++;
02321 }
02322 CloseHandle(hFile);
02323 if (ofs == numeric_limits<unsigned long>::max() ) {
02324 return kEmptyStr;
02325 }
02326 if (mode != eTmpFileCreate) {
02327 remove(fn.c_str());
02328 }
02329
02330 # endif
02331
02332 #else // defined(NCBI_OS_MSWIN) || defined(NCBI_OS_UNIX)
02333 if (mode == eTmpFileCreate) {
02334 ERR_POST_X(3, Warning << "CFile::GetTmpNameEx():"
02335 " Temporary file cannot be auto-created on this platform,"
02336 " so return its name only");
02337 }
02338 fn = s_StdGetTmpName(dir.c_str(), prefix.c_str());
02339 #endif
02340 return fn;
02341 }
02342
02343
02344 class CTmpStream : public fstream
02345 {
02346 public:
02347
02348 CTmpStream(const char* s, IOS_BASE::openmode mode) : fstream(s, mode)
02349 {
02350 m_FileName = s;
02351
02352
02353 CFile(s).Remove();
02354 }
02355
02356 #if defined(NCBI_OS_MSWIN)
02357 CTmpStream(const char* s, FILE* file) : fstream(file)
02358 {
02359 m_FileName = s;
02360 }
02361 #endif
02362
02363 virtual ~CTmpStream(void)
02364 {
02365 close();
02366 if ( !m_FileName.empty() ) {
02367 CFile(m_FileName).Remove();
02368 }
02369 }
02370
02371 protected:
02372 string m_FileName;
02373 };
02374
02375
02376 fstream* CDirEntry::CreateTmpFile(const string& filename,
02377 ETextBinary text_binary,
02378 EAllowRead allow_read)
02379 {
02380 string tmpname = filename.empty() ? GetTmpName(eTmpFileCreate) : filename;
02381 if ( tmpname.empty() ) {
02382 LOG_ERROR("CDirEntry::CreateTmpFile():"
02383 " Cannot get temporary file name");
02384 return 0;
02385 }
02386 #if defined(NCBI_OS_MSWIN)
02387
02388
02389
02390
02391
02392
02393
02394
02395 char mode[6] = "w+TDb";
02396 if (text_binary != eBinary) {
02397 mode[4] = '\0';
02398 }
02399 FILE* file = fopen(tmpname.c_str(), mode);
02400 if ( !file ) {
02401 return 0;
02402 }
02403
02404 fstream* stream = new CTmpStream(tmpname.c_str(), file);
02405
02406
02407 #else
02408
02409 ios::openmode mode = ios::out | ios::trunc;
02410 if ( text_binary == eBinary ) {
02411 mode = mode | ios::binary;
02412 }
02413 if ( allow_read == eAllowRead ) {
02414 mode = mode | ios::in;
02415 }
02416 fstream* stream = new CTmpStream(tmpname.c_str(), mode);
02417 #endif
02418
02419 if ( !stream->good() ) {
02420 delete stream;
02421 return 0;
02422 }
02423 return stream;
02424 }
02425
02426
02427 fstream* CDirEntry::CreateTmpFileEx(const string& dir, const string& prefix,
02428 ETextBinary text_binary,
02429 EAllowRead allow_read)
02430 {
02431 return CreateTmpFile(GetTmpNameEx(dir, prefix, eTmpFileCreate),
02432 text_binary, allow_read);
02433 }
02434
02435
02436
02437
02438
02439
02440
02441
02442
02443
02444
02445
02446 static bool s_CopyAttrs(const char* from, const char* to,
02447 CDirEntry::EType type, CDirEntry::TCopyFlags flags)
02448 {
02449 #if defined(NCBI_OS_UNIX)
02450
02451 CDirEntry::SStat st;
02452 if ( !CDirEntry(from).Stat(&st) ) {
02453 LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::s_CopyAttr():"
02454 " stat() failed for " << from);
02455 }
02456
02457
02458
02459
02460 if ( F_ISSET(flags, CDirEntry::fCF_PreserveTime) ) {
02461 # if defined(HAVE_UTIMES)
02462 struct timeval tvp[2];
02463 tvp[0].tv_sec = st.orig.st_atime;
02464 tvp[0].tv_usec = st.atime_nsec / 1000;
02465 tvp[1].tv_sec = st.orig.st_mtime;
02466 tvp[1].tv_usec = st.mtime_nsec / 1000;
02467 # if defined(HAVE_LUTIMES)
02468 if (lutimes(to, tvp)) {
02469 LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::s_CopyAttr():"
02470 " lutimes() failed for " << to);
02471 }
02472 # else
02473 if (utimes(to, tvp)) {
02474 LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::s_CopyAttr():"
02475 " utimes() failed for " << to);
02476 }
02477 # endif
02478 # else // !HAVE_UTIMES
02479
02480
02481 struct utimbuf times;
02482 times.actime = st.orig.st_atime;
02483 times.modtime = st.orig.st_mtime;
02484 if (utime(to, ×)) {
02485 LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::s_CopyAttr():"
02486 " utime() failed for " << to);
02487 }
02488 # endif // HAVE_UTIMES
02489 }
02490
02491
02492
02493
02494
02495 if ( F_ISSET(flags, CDirEntry::fCF_PreserveOwner) ) {
02496 if ( type == CDirEntry::eLink ) {
02497 # if defined(HAVE_LCHOWN)
02498 if ( lchown(to, st.orig.st_uid, st.orig.st_gid) ) {
02499 if (errno != EPERM) {
02500 LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::s_CopyAttr():"
02501 " lchown() failed for " << to);
02502 }
02503 }
02504 # endif
02505
02506
02507 return true;
02508 } else {
02509
02510
02511
02512 if ( chown(to, st.orig.st_uid, st.orig.st_gid) ) {
02513 if ( errno != EPERM ) {
02514 LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::s_CopyAttr():"
02515 " chown() failed for " << to);
02516 }
02517 st.orig.st_mode &= ~(S_ISUID | S_ISGID);
02518 }
02519 }
02520 }
02521
02522
02523 if ( F_ISSET(flags, CDirEntry::fCF_PreservePerm) &&
02524 type != CDirEntry::eLink ) {
02525 if ( chmod(to, st.orig.st_mode) ) {
02526 LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::s_CopyAttr():"
02527 " chmod() failed for " << to);
02528 }
02529 }
02530 return true;
02531
02532
02533 #elif defined(NCBI_OS_MSWIN)
02534
02535 CDirEntry efrom(from), eto(to);
02536
02537 WIN32_FILE_ATTRIBUTE_DATA attr;
02538 if ( !::GetFileAttributesEx(from, GetFileExInfoStandard, &attr) ) {
02539 return false;
02540 }
02541
02542
02543 if ( F_ISSET(flags, CDirEntry::fCF_PreserveTime) ) {
02544 HANDLE h = CreateFile(to, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ, NULL,
02545 OPEN_EXISTING,
02546 FILE_FLAG_BACKUP_SEMANTICS , NULL);
02547 if ( h == INVALID_HANDLE_VALUE ) {
02548 LOG_ERROR_AND_RETURN("CDirEntry::s_CopyAttr():"
02549 " Cannot open " << to);
02550 }
02551 if ( !SetFileTime(h, &attr.ftCreationTime, &attr.ftLastAccessTime,
02552 &attr.ftLastWriteTime) ) {
02553 CloseHandle(h);
02554 LOG_ERROR_AND_RETURN("CDirEntry::s_CopyAttr():"
02555 " Cannot change time for " << to);
02556 }
02557 CloseHandle(h);
02558 }
02559
02560
02561 if ( F_ISSET(flags, CDirEntry::fCF_PreservePerm) ) {
02562 if ( !::SetFileAttributes(to, attr.dwFileAttributes) ) {
02563 LOG_ERROR_AND_RETURN("CDirEntry::s_CopyAttr():"
02564 " Cannot change pemissions for " << to);
02565 }
02566 }
02567
02568
02569 if ( F_ISSET(flags, CDirEntry::fCF_PreserveOwner) ) {
02570 string owner, group;
02571
02572
02573 if ( efrom.GetOwner(&owner, &group) ) {
02574 eto.SetOwner(owner, group);
02575 }
02576 }
02577
02578 return true;
02579 #endif
02580 }
02581
02582
02583
02584
02585
02586
02587
02588
02589 CFile::~CFile(void)
02590 {
02591 return;
02592 }
02593
02594
02595 Int8 CFile::GetLength(void) const
02596 {
02597 #if defined(NCBI_OS_MSWIN)
02598 struct __stat64 buf;
02599 if ( _stat64(GetPath().c_str(), &buf) != 0 ) {
02600
02601 return -1;
02602 }
02603 #else
02604 struct stat buf;
02605 if ( stat(GetPath().c_str(), &buf) != 0 ) {
02606
02607 return -1;
02608 }
02609 #endif
02610 return buf.st_size;
02611 }
02612
02613
02614 #if !defined(NCBI_OS_MSWIN)
02615
02616
02617 bool s_CopyFile(const char* src, const char* dst, size_t buf_size)
02618 {
02619 CNcbiIfstream is(src, IOS_BASE::binary | IOS_BASE::in);
02620 CNcbiOfstream os(dst, IOS_BASE::binary | IOS_BASE::out | IOS_BASE::trunc);
02621
02622 if ( !buf_size ) {
02623 if (CFile(src).GetLength() == 0) {
02624 return true;
02625 }
02626
02627 os << is.rdbuf();
02628 return os.good() ? true : false;
02629 }
02630
02631 AutoPtr< char, ArrayDeleter<char> > buf_ptr(new char[buf_size]);
02632 char* buf = buf_ptr.get();
02633 bool failed = false;
02634
02635 streamsize nread;
02636 do {
02637 is.read(buf, buf_size);
02638 nread = is.gcount();
02639 if ( nread ) {
02640 if (!os.write(buf, nread)) {
02641 failed = true;
02642 break;
02643 }
02644 }
02645 } while (is && nread);
02646
02647 return !failed;
02648 }
02649
02650 #endif
02651
02652
02653 bool CFile::Copy(const string& newname, TCopyFlags flags, size_t buf_size) const
02654 {
02655 CFile src(*this);
02656 CFile dst(newname);
02657
02658
02659 if ( F_ISSET(flags, fCF_FollowLinks) ) {
02660 src.DereferenceLink();
02661 dst.DereferenceLink();
02662 }
02663
02664 EType src_type = src.GetType();
02665 if ( src_type != eFile ) {
02666 LOG_ERROR_AND_RETURN("CFile::Copy():"
02667 " Source is not a file: " << GetPath());
02668 }
02669
02670 EType dst_type = dst.GetType();
02671 bool dst_exists = (dst_type != eUnknown);
02672
02673
02674 if ( dst_exists ) {
02675
02676
02677 #if defined(NCBI_OS_UNIX)
02678 if ( src.IsIdentical(dst.GetPath()) ) {
02679 return false;
02680 }
02681 #endif
02682
02683
02684 if ( F_ISSET(flags, fCF_EqualTypes) && (src_type != dst_type) ) {
02685 LOG_ERROR_AND_RETURN("CFile::Copy():"
02686 " Destination is not a file: "
02687 << dst.GetPath());
02688 }
02689
02690 if ( !F_ISSET(flags, fCF_Overwrite) ) {
02691 LOG_ERROR_AND_RETURN("CFile::Copy():"
02692 " Destination file exists: "
02693 << dst.GetPath());
02694 }
02695
02696 if ( F_ISSET(flags, fCF_Update) && !src.IsNewer(dst.GetPath(),0) ) {
02697 return true;
02698 }
02699
02700 if ( F_ISSET(flags, fCF_Backup) ) {
02701
02702
02703 CDirEntry dst_tmp(dst);
02704 if ( !dst_tmp.Backup(GetBackupSuffix(), eBackup_Rename) ) {
02705 LOG_ERROR_AND_RETURN("CFile::Copy():"
02706 " Cannot backup " << dst.GetPath());
02707 }
02708 }
02709 }
02710
02711
02712 #if defined(NCBI_OS_MSWIN)
02713 if ( !::CopyFile(src.GetPath().c_str(), dst.GetPath().c_str(), FALSE) )
02714 LOG_ERROR_AND_RETURN("CFile::Copy():"
02715 " Cannot copy "
02716 << src.GetPath() << " to " << dst.GetPath());
02717 #else
02718 if ( !s_CopyFile(src.GetPath().c_str(), dst.GetPath().c_str(), buf_size) ){
02719 LOG_ERROR_AND_RETURN("CFile::Copy():"
02720 " Cannot copy "
02721 << src.GetPath() << " to " << dst.GetPath());
02722 }
02723 #endif
02724
02725
02726 if ( F_ISSET(flags, fCF_Verify) && !src.Compare(dst.GetPath()) ) {
02727 LOG_ERROR_AND_RETURN("CFile::Copy():"
02728 " Copy verification for "
02729 << src.GetPath() << " and " << dst.GetPath()
02730 << " failed");
02731 }
02732
02733
02734 #if defined(NCBI_OS_MSWIN)
02735
02736
02737 flags &= ~(fCF_PreservePerm | fCF_PreserveTime);
02738 #endif
02739 if ( flags & fCF_PreserveAll ) {
02740 if ( !s_CopyAttrs(src.GetPath().c_str(),
02741 dst.GetPath().c_str(), eFile, flags) ) {
02742 return false;
02743 }
02744 } else {
02745 if ( !dst.SetMode(fDefault, fDefault, fDefault) ) {
02746 return false;
02747 }
02748 }
02749 return true;
02750 }
02751
02752
02753 bool CFile::Compare(const string& file, size_t buf_size) const
02754 {
02755 if ( CFile(GetPath()).GetLength() != CFile(file).GetLength() ) {
02756 return false;
02757 }
02758 CNcbiIfstream f1(GetPath().c_str(), IOS_BASE::binary | IOS_BASE::in);
02759 CNcbiIfstream f2(file.c_str(), IOS_BASE::binary | IOS_BASE::in);
02760
02761 if ( !buf_size ) {
02762 buf_size = kDefaultBufferSize;
02763 }
02764 char* buf1 = new char[buf_size];
02765 char* buf2 = new char[buf_size];
02766 bool equal = true;
02767
02768 while ( f1.good() && f2.good() ) {
02769
02770 f1.read(buf1, buf_size);
02771 f2.read(buf2, buf_size);
02772 if ( f1.gcount() != f2.gcount() ) {
02773 equal = false;
02774 break;
02775 }
02776
02777 if ( memcmp(buf1, buf2, f1.gcount()) != 0 ) {
02778 equal = false;
02779 break;
02780 }
02781 }
02782
02783 delete[] buf1;
02784 delete[] buf2;
02785
02786
02787 return equal && f1.eof() && f2.eof();
02788 }
02789
02790 static inline char
02791 x_GetChar(CNcbiIfstream& f, CFile::ECompareText mode,
02792 char* buf, size_t buf_size, char*& pos, streamsize& sizeleft)
02793 {
02794 char c = '\0';
02795 do {
02796 if (sizeleft == 0) {
02797 f.read(buf, buf_size);
02798 sizeleft = f.gcount();
02799 pos = buf;
02800 }
02801 if (sizeleft > 0) {
02802 c = *pos;
02803 ++pos;
02804 --sizeleft;
02805 } else {
02806 return '\0';
02807 }
02808 } while ( (mode == CFile::eIgnoreEol && (c == '\n' || c == '\r')) ||
02809 (mode == CFile::eIgnoreWs && isspace((unsigned char)c))
02810 );
02811 return c;
02812 }
02813
02814 bool CFile::CompareTextContents(const string& file, ECompareText mode,
02815 size_t buf_size) const
02816 {
02817 CNcbiIfstream f1(GetPath().c_str(), IOS_BASE::in);
02818 CNcbiIfstream f2(file.c_str(), IOS_BASE::in);
02819 if ( !buf_size ) {
02820 buf_size = kDefaultBufferSize;
02821 }
02822 char* buf1 = new char[buf_size];
02823 char* buf2 = new char[buf_size];
02824 streamsize size1=0, size2=0;
02825 char *pos1=0, *pos2=0;
02826 bool equal = true;
02827 while ( equal ) {
02828 char c1 = x_GetChar(f1,mode,buf1,buf_size,pos1,size1);
02829 char c2 = x_GetChar(f2,mode,buf2,buf_size,pos2,size2);
02830 equal = c1 == c2;
02831 if (!c1 || !c2) {
02832 break;
02833 }
02834 }
02835 delete[] buf1;
02836 delete[] buf2;
02837 return equal && f1.eof() && f2.eof();
02838 }
02839
02840
02841
02842
02843
02844
02845 #if defined(NCBI_OS_UNIX)
02846
02847 static bool s_GetHomeByUID(string& home)
02848 {
02849
02850 struct passwd* pwd;
02851
02852 if ((pwd = getpwuid(getuid())) == 0) {
02853 LOG_ERROR_AND_RETURN_ERRNO("s_GetHomeByUID(): getpwuid() failed");
02854 }
02855 home = pwd->pw_dir;
02856 return true;
02857 }
02858
02859 static bool s_GetHomeByLOGIN(string& home)
02860 {
02861 char* ptr = 0;
02862
02863 if ( !(ptr = getenv("USER")) ) {
02864 if ( !(ptr = getenv("LOGNAME")) ) {
02865 if ( !(ptr = getlogin()) ) {
02866 LOG_ERROR_AND_RETURN_ERRNO("s_GetHomeByLOGIN():"
02867 " Unable to get user name");
02868 }
02869 }
02870 }
02871
02872 struct passwd* pwd = getpwnam(ptr);
02873 if ( !pwd || pwd->pw_dir[0] == '\0') {
02874 LOG_ERROR_AND_RETURN_ERRNO("s_GetHomeByLOGIN():"
02875 " getpwnam() failed");
02876 }
02877 home = pwd->pw_dir;
02878 return true;
02879 }
02880
02881 #endif // NCBI_OS_UNIX
02882
02883
02884 string CDir::GetHome(void)
02885 {
02886 char* str;
02887 string home;
02888
02889 #if defined(NCBI_OS_MSWIN)
02890
02891
02892 str = getenv("APPDATA");
02893 if ( str ) {
02894 home = str;
02895 } else {
02896
02897 str = getenv("USERPROFILE");
02898 if ( str ) {
02899 home = str;
02900 }
02901 }
02902 #elif defined(NCBI_OS_UNIX)
02903
02904 str = getenv("HOME");
02905 if ( str ) {
02906 home = str;
02907 } else {
02908
02909
02910 if ( !s_GetHomeByUID(home) ) {
02911 s_GetHomeByLOGIN(home);
02912 }
02913 }
02914 #endif
02915
02916
02917 return AddTrailingPathSeparator(home);
02918 }
02919
02920
02921 string CDir::GetTmpDir(void)
02922 {
02923 string tmp;
02924
02925 #if defined(NCBI_OS_UNIX)
02926
02927 char* tmpdir = getenv("TMPDIR");
02928 if ( tmpdir ) {
02929 tmp = tmpdir;
02930 } else {
02931 # if defined(P_tmpdir)
02932 tmp = P_tmpdir;
02933 # else
02934 tmp = "/tmp";
02935 # endif
02936 }
02937
02938 #elif defined(NCBI_OS_MSWIN)
02939
02940 char* tmpdir = getenv("TEMP");
02941 if ( tmpdir ) {
02942 tmp = tmpdir;
02943 } else {
02944 # if defined(P_tmpdir)
02945 tmp = P_tmpdir;
02946 # else
02947 tmp = CDir::GetHome();
02948 # endif
02949 }
02950
02951 #endif
02952
02953 return tmp;
02954 }
02955
02956
02957 string CDir::GetCwd()
02958 {
02959 string cwd;
02960
02961 #if defined(NCBI_OS_UNIX)
02962 char buf[4096];
02963 if ( getcwd(buf, sizeof(buf) - 1) ) {
02964 cwd = buf;
02965 }
02966 #elif defined(NCBI_OS_MSWIN)
02967 char buf[4096];
02968 if ( _getcwd(buf, sizeof(buf) - 1) ) {
02969 cwd = buf;
02970 }
02971 #endif
02972 return cwd;
02973 }
02974
02975
02976 bool CDir::SetCwd(const string& dir)
02977 {
02978 #if defined(NCBI_OS_UNIX)
02979 if ( chdir(dir.c_str()) != 0 ) {
02980 LOG_ERROR_AND_RETURN_ERRNO("CDir::SetCwd():"
02981 " Cannot change directory to " << dir);
02982 }
02983 return true;
02984 #elif defined(NCBI_OS_MSWIN)
02985 if ( _chdir(dir.c_str()) != 0 ) {
02986 LOG_ERROR_AND_RETURN_ERRNO("CDir::SetCwd():"
02987 " Cannot change directory to " << dir);
02988 }
02989 return true;
02990 #else
02991 return false;
02992 #endif
02993 }
02994
02995
02996 CDir::~CDir(void)
02997 {
02998 return;
02999 }
03000
03001
03002 bool CDirEntry::MatchesMask(const string& name,
03003 const vector<string>& masks,
03004 NStr::ECase use_case)
03005 {
03006 if ( masks.empty() ) {
03007 return true;
03008 }
03009 ITERATE(vector<string>, itm, masks) {
03010 const string& mask = *itm;
03011 if ( MatchesMask(name, mask, use_case) ) {
03012 return true;
03013 }
03014 }
03015 return false;
03016 }
03017
03018
03019
03020
03021 #if defined(NCBI_OS_MSWIN)
03022
03023
03024 void s_SetFindFileError(void)
03025 {
03026 DWORD err = GetLastError();
03027 switch (err) {
03028 case ERROR_NO_MORE_FILES:
03029 case ERROR_FILE_NOT_FOUND:
03030 case ERROR_PATH_NOT_FOUND:
03031 errno = ENOENT;
03032 break;
03033 case ERROR_NOT_ENOUGH_MEMORY:
03034 errno = ENOMEM;
03035 break;
03036 default:
03037 errno = EINVAL;
03038 break;
03039 }
03040 }
03041
03042 # define IS_RECURSIVE_ENTRY \
03043 ( (flags & CDir::fIgnoreRecursive) && \
03044 ((::strcmp(entry.cFileName, ".") == 0) || \
03045 (::strcmp(entry.cFileName, "..") == 0)) )
03046
03047 void s_AddEntry(CDir::TEntries* contents, const string& base_path,
03048 const WIN32_FIND_DATA& entry, CDir::TGetEntriesFlags flags)
03049 {
03050 const string name = (flags & CDir::fIgnorePath) ?
03051 entry.cFileName :
03052 base_path + entry.cFileName;
03053
03054 if (flags & CDir::fCreateObjects) {
03055 CDirEntry::EType type = (entry.dwFileAttributes &
03056 FILE_ATTRIBUTE_DIRECTORY)
03057 ? CDirEntry::eDir : CDirEntry::eFile;
03058 contents->push_back(CDirEntry::CreateObject(type, name));
03059 } else {
03060 contents->push_back(new CDirEntry(name));
03061 }
03062 }
03063
03064 #else // NCBI_OS_UNIX
03065
03066 # define IS_RECURSIVE_ENTRY \
03067 ( (flags & CDir::fIgnoreRecursive) && \
03068 ((::strcmp(entry->d_name, ".") == 0) || \
03069 (::strcmp(entry->d_name, "..") == 0)) )
03070
03071 void s_AddEntry(CDir::TEntries* contents, const string& base_path,
03072 const struct dirent* entry, CDir::TGetEntriesFlags flags)
03073 {
03074 const string name = (flags & CDir::fIgnorePath) ?
03075 entry->d_name :
03076 base_path + entry->d_name;
03077
03078 if (flags & CDir::fCreateObjects) {
03079 CDirEntry::EType type = CDir::eUnknown;
03080 # if defined(_DIRENT_HAVE_D_TYPE)
03081 struct stat st;
03082 if (entry->d_type) {
03083 st.st_mode = DTTOIF(entry->d_type);
03084 type = CDirEntry::GetType(st);
03085 }
03086 # endif
03087 if (type == CDir::eUnknown) {
03088 if (flags & CDir::fIgnorePath) {
03089 const string path = base_path + entry->d_name;
03090 type = CDirEntry(path).GetType();
03091 } else {
03092 type = CDirEntry(name).GetType();
03093 }
03094 }
03095 contents->push_back(CDirEntry::CreateObject(type, name));
03096 } else {
03097 contents->push_back(new CDirEntry(name));
03098 }
03099 }
03100
03101 #endif
03102
03103
03104 CDir::TEntries CDir::GetEntries(const string& mask,
03105 TGetEntriesFlags flags) const
03106 {
03107 CMaskFileName masks;
03108 if ( !mask.empty() ) {
03109 masks.Add(mask);
03110 }
03111 return GetEntries(masks, flags);
03112 }
03113
03114
03115 CDir::TEntries* CDir::GetEntriesPtr(const string& mask,
03116 TGetEntriesFlags flags) const
03117 {
03118 CMaskFileName masks;
03119 if ( !mask.empty() ) {
03120 masks.Add(mask);
03121 }
03122 return GetEntriesPtr(masks, flags);
03123 }
03124
03125
03126 CDir::TEntries CDir::GetEntries(const vector<string>& masks,
03127 TGetEntriesFlags flags) const
03128 {
03129 auto_ptr<TEntries> contents(GetEntriesPtr(masks, flags));
03130 return *contents.get();
03131 }
03132
03133
03134 CDir::TEntries* CDir::GetEntriesPtr(const vector<string>& masks,
03135 TGetEntriesFlags flags) const
03136 {
03137 if ( masks.empty() ) {
03138 return GetEntriesPtr("", flags);
03139 }
03140 TEntries* contents = new(TEntries);
03141 string base_path = AddTrailingPathSeparator(GetPath().empty() ? DIR_CURRENT : GetPath());
03142 NStr::ECase use_case = (flags & fNoCase) ? NStr::eNocase : NStr::eCase;
03143
03144 #if defined(NCBI_OS_MSWIN)
03145
03146
03147 string pattern = base_path + string("*");
03148
03149 WIN32_FIND_DATA entry;
03150 HANDLE handle;
03151
03152 handle = FindFirstFile(pattern.c_str(), &entry);
03153 if (handle != INVALID_HANDLE_VALUE) {
03154
03155 do {
03156 if (!IS_RECURSIVE_ENTRY) {
03157 ITERATE(vector<string>, it, masks) {
03158 const string& mask = *it;
03159 if ( mask.empty() ||
03160 MatchesMask(entry.cFileName, mask, use_case) ) {
03161 s_AddEntry(contents, base_path, entry, flags);
03162 break;
03163 }
03164 }
03165 }
03166 } while (FindNextFile(handle, &entry));
03167 FindClose(handle);
03168 } else {
03169 s_SetFindFileError();
03170 }
03171
03172 #elif defined(NCBI_OS_UNIX)
03173 DIR* dir = opendir(base_path.c_str());
03174 if ( dir ) {
03175 while (struct dirent* entry = readdir(dir)) {
03176 if (IS_RECURSIVE_ENTRY) {
03177 continue;
03178 }
03179 ITERATE(vector<string>, it, masks) {
03180 const string& mask = *it;
03181 if ( mask.empty() ||
03182 MatchesMask(entry->d_name, mask, use_case) ) {
03183 s_AddEntry(contents, base_path, entry, flags);
03184 break;
03185 }
03186 }
03187 }
03188 closedir(dir);
03189 }
03190 #endif
03191 return contents;
03192 }
03193
03194
03195 CDir::TEntries CDir::GetEntries(const CMask& masks,
03196 TGetEntriesFlags flags) const
03197 {
03198 auto_ptr<TEntries> contents(GetEntriesPtr(masks, flags));
03199 return *contents.get();
03200 }
03201
03202
03203 CDir::TEntries* CDir::GetEntriesPtr(const CMask& masks,
03204 TGetEntriesFlags flags) const
03205 {
03206 TEntries* contents = new(TEntries);
03207 string base_path = AddTrailingPathSeparator(GetPath().empty() ? DIR_CURRENT : GetPath());
03208 NStr::ECase use_case = (flags & fNoCase) ? NStr::eNocase : NStr::eCase;
03209
03210 #if defined(NCBI_OS_MSWIN)
03211
03212 string pattern = base_path + "*";
03213
03214 WIN32_FIND_DATA entry;
03215 HANDLE handle;
03216
03217 handle = FindFirstFile(pattern.c_str(), &entry);
03218 if (handle != INVALID_HANDLE_VALUE) {
03219 do {
03220 if ( !IS_RECURSIVE_ENTRY &&
03221 masks.Match(entry.cFileName, use_case) ) {
03222 s_AddEntry(contents, base_path, entry, flags);
03223 }
03224 } while ( FindNextFile(handle, &entry) );
03225 FindClose(handle);
03226 } else {
03227 s_SetFindFileError();
03228 }
03229
03230 #elif defined(NCBI_OS_UNIX)
03231 DIR* dir = opendir(base_path.c_str());
03232 if ( dir ) {
03233 while (struct dirent* entry = readdir(dir)) {
03234 if ( !IS_RECURSIVE_ENTRY &&
03235 masks.Match(entry->d_name, use_case) ) {
03236 s_AddEntry(contents, base_path, entry, flags);
03237 }
03238 }
03239 closedir(dir);
03240 }
03241 #endif
03242 return contents;
03243 }
03244
03245
03246 bool CDir::Create(void) const
03247 {
03248 TMode user_mode, group_mode, other_mode;
03249 TSpecialModeBits special;
03250 GetDefaultMode(&user_mode, &group_mode, &other_mode, &special);
03251 mode_t mode = MakeModeT(user_mode, group_mode, other_mode, special);
03252
03253 #if defined(NCBI_OS_MSWIN)
03254 errno = 0;
03255 if ( mkdir(GetPath().c_str()) != 0 && errno != EEXIST ) {
03256 LOG_ERROR_AND_RETURN_ERRNO("CDir::Create():"
03257 " Cannot create directory " << GetPath());
03258 }
03259
03260 #elif defined(NCBI_OS_UNIX)
03261 errno = 0;
03262
03263 if ( mkdir(GetPath().c_str(), mode) != 0 && errno != EEXIST ) {
03264 LOG_ERROR_AND_RETURN_ERRNO("CDir::Create():"
03265 " Cannot create directory " << GetPath());
03266 }
03267
03268 #endif
03269 if ( chmod(GetPath().c_str(), mode) != 0 ) {
03270 LOG_ERROR_AND_RETURN_ERRNO("CDir::Create():"
03271 " Cannot set mode for directory "
03272 << GetPath());
03273 }
03274 return true;
03275 }
03276
03277
03278 bool CDir::CreatePath(void) const
03279 {
03280 if ( Exists() ) {
03281 return true;
03282 }
03283 string path(GetPath());
03284 if ( path.empty() ) {
03285 return true;
03286 }
03287 if ( path[path.length()-1] == GetPathSeparator() ) {
03288 path.erase(path.length() - 1);
03289 }
03290 string path_up = GetDir();
03291 if ( path_up == path ) {
03292
03293 LOG_ERROR_AND_RETURN("CDir::CreatePath():"
03294 " Disk name not specified: " << path);
03295 }
03296
03297 CDir dir_up(*this);
03298 dir_up.Reset(path_up);
03299
03300 if ( dir_up.CreatePath() ) {
03301
03302 return Create();
03303 }
03304 return false;
03305 }
03306
03307
03308 bool CDir::Copy(const string& newname, TCopyFlags flags, size_t buf_size) const
03309 {
03310 CDir src(*this);
03311 CDir dst(newname);
03312
03313
03314 bool follow = F_ISSET(flags, fCF_FollowLinks);
03315 if ( follow ) {
03316 src.DereferenceLink();
03317 dst.DereferenceLink();
03318 }
03319
03320 EType src_type = src.GetType();
03321 if ( src_type != eDir ) {
03322 LOG_ERROR_AND_RETURN("CDir::Copy():"
03323 " Source is not a directory: " << src.GetPath());
03324 }
03325 EType dst_type = dst.GetType();
03326 bool dst_exists = (dst_type != eUnknown);
03327
03328
03329 if ( dst_exists ) {
03330
03331 if ( src.IsIdentical(dst.GetPath()) ) {
03332 LOG_ERROR_AND_RETURN("CDir::Copy():"
03333 " Source and destination are the same: "
03334 << src.GetPath());
03335 }
03336
03337 if ( F_ISSET(flags, fCF_EqualTypes) && (src_type != dst_type) ) {
03338 LOG_ERROR_AND_RETURN("CDir::Copy():"
03339 " Destination is not a directory: "
03340 << dst.GetPath());
03341 }
03342
03343
03344
03345 if ( F_ISSET(flags, fCF_TopDirOnly) ) {
03346
03347 if ( !F_ISSET(flags, fCF_Overwrite) ) {
03348 LOG_ERROR_AND_RETURN("CDir::Copy():"
03349 " Destination directory already exists: "
03350 << dst.GetPath());
03351 }
03352
03353 if ( F_ISSET(flags, fCF_Update) &&
03354 !src.IsNewer(dst.GetPath(), 0) ) {
03355 return true;
03356 }
03357
03358 if ( F_ISSET(flags, fCF_Backup) ) {
03359
03360
03361 CDirEntry dst_tmp(dst);
03362 if ( !dst_tmp.Backup(GetBackupSuffix(), eBackup_Rename) ) {
03363 LOG_ERROR_AND_RETURN("CDir::Copy():"
03364 " Cannot backup destination"
03365 " directory: " << dst.GetPath());
03366 }
03367
03368 if ( !dst.CreatePath() ) {
03369 LOG_ERROR_AND_RETURN("CDir::Copy():"
03370 " Cannot create target directory: "
03371 << dst.GetPath());
03372 }
03373 }
03374
03375
03376 flags &= ~(fCF_TopDirOnly | fCF_Update | fCF_Backup);
03377 }
03378 } else {
03379
03380 if ( !dst.CreatePath() ) {
03381 LOG_ERROR_AND_RETURN("CDir::Copy():"
03382 " Cannot create target directory: "
03383 << dst.GetPath());
03384 }
03385 }
03386
03387
03388 auto_ptr<TEntries> contents(src.GetEntriesPtr("*", fIgnoreRecursive));
03389
03390
03391 ITERATE(TEntries, e, *contents.get()) {
03392 CDirEntry& entry = **e;
03393 if ( !F_ISSET(flags, fCF_Recursive) &&
03394 entry.IsDir(follow ? eFollowLinks : eIgnoreLinks)) {
03395 continue;
03396 }
03397
03398 if ( !entry.CopyToDir(dst.GetPath(), flags, buf_size) ) {
03399 LOG_ERROR_AND_RETURN("CDir::Copy():"
03400 " Cannot copy " << entry.GetPath()
03401 << " to directory " << dst.GetPath());
03402 }
03403 }
03404
03405
03406 if ( flags & fCF_PreserveAll ) {
03407 if ( !s_CopyAttrs(src.GetPath().c_str(),
03408 dst.GetPath().c_str(), eDir, flags) ) {
03409 return false;
03410 }
03411 } else {
03412 if ( !dst.SetMode(fDefault, fDefault, fDefault) ) {
03413 return false;
03414 }
03415 }
03416 return true;
03417 }
03418
03419
03420 bool CDir::Remove(EDirRemoveMode mode) const
03421 {
03422
03423 if ( mode == eOnlyEmpty ) {
03424 if ( rmdir(GetPath().c_str()) != 0 ) {
03425 LOG_ERROR_AND_RETURN_ERRNO("CDir::Remove():"
03426 " Cannot remove (by implication empty)"
03427 " directory " << GetPath());
03428 }
03429 return true;
03430 }
03431
03432 auto_ptr<TEntries> contents(GetEntriesPtr());
03433
03434
03435 ITERATE(TEntries, entry, *contents.get()) {
03436 string name = (*entry)->GetName();
03437 if ( name == "." || name == ".." ||
03438 name == string(1, GetPathSeparator()) ) {
03439 continue;
03440 }
03441
03442 CDirEntry item(GetPath() + GetPathSeparator() + name);
03443
03444 if (mode == eRecursive || mode == eRecursiveIgnoreMissing) {
03445 if (!item.Remove(mode)) {
03446 return false;
03447 }
03448 } else if ( item.IsDir(eIgnoreLinks) ) {
03449
03450 if ( mode != eTopDirOnly ) {
03451 item.Remove(eOnlyEmpty);
03452 }
03453 continue;
03454 } else if ( !item.Remove() ) {
03455 return false;
03456 }
03457 }
03458
03459
03460 if ( rmdir(GetPath().c_str()) != 0 ) {
03461 LOG_ERROR_AND_RETURN_ERRNO("CDir::Remove():"
03462 " Cannot remove directory " << GetPath());
03463 }
03464 return true;
03465 }
03466
03467
03468
03469
03470
03471
03472
03473 CSymLink::~CSymLink(void)
03474 {
03475 return;
03476 }
03477
03478
03479 bool CSymLink::Create(const string& path) const
03480 {
03481 #if defined(NCBI_OS_UNIX)
03482 char buf[PATH_MAX + 1];
03483 int len = (int) readlink(GetPath().c_str(), buf, sizeof(buf) - 1);
03484 if (len >= 0) {
03485 buf[len] = '\0';
03486 if (strcmp(buf, path.c_str()) == 0) {
03487 return true;
03488 }
03489 }
03490
03491 return symlink(path.c_str(), GetPath().c_str()) != 0 ? false : true;
03492 #else
03493 LOG_ERROR_AND_RETURN("CSymLink::Create():"
03494 " Symbolic links not supported on this platform: "
03495 << path);
03496 #endif
03497 }
03498
03499
03500 bool CSymLink::Copy(const string& new_path, TCopyFlags flags, size_t buf_size) const
03501 {
03502 #if defined(NCBI_OS_UNIX)
03503
03504
03505 if ( F_ISSET(flags, fCF_FollowLinks) ) {
03506 switch ( GetType(eFollowLinks) ) {
03507 case eFile:
03508 return CFile(*this).Copy(new_path, flags, buf_size);
03509 case eDir:
03510 return CDir(*this).Copy(new_path, flags, buf_size);
03511 case eLink:
03512 return CSymLink(*this).Copy(new_path, flags, buf_size);
03513 default:
03514 return CDirEntry(*this).Copy(new_path, flags, buf_size);
03515 }
03516
03517 }
03518
03519
03520 EType src_type = GetType(eIgnoreLinks);
03521 if ( src_type == eUnknown ) {
03522 LOG_ERROR_AND_RETURN("CSymLink::Copy():"
03523 " Unknown entry type " << GetPath());
03524 }
03525 CSymLink dst(new_path);
03526 EType dst_type = dst.GetType(eIgnoreLinks);
03527 bool dst_exists = (dst_type != eUnknown);
03528
03529
03530 if ( dst_exists ) {
03531
03532 if ( IsIdentical(dst.GetPath()) ) {
03533 LOG_ERROR_AND_RETURN("CSymLink::Copy():"
03534 " Source and destination are the same: "
03535 << GetPath());
03536 }
03537
03538 if ( F_ISSET(flags, fCF_EqualTypes) && (src_type != dst_type) ) {
03539 LOG_ERROR_AND_RETURN("CSymLink::Copy():"
03540 " Cannot copy entries with different types: "
03541 << GetPath());
03542 }
03543
03544 if ( !F_ISSET(flags, fCF_Overwrite) ) {
03545 LOG_ERROR_AND_RETURN("CSymLink::Copy():"
03546 " Destination already exists: "
03547 << dst.GetPath());
03548 }
03549
03550 if ( F_ISSET(flags, fCF_Update) && !IsNewer(dst.GetPath(), 0)) {
03551 return true;
03552 }
03553
03554 if ( F_ISSET(flags, fCF_Backup) ) {
03555
03556
03557 CDirEntry dst_tmp(dst);
03558 if ( !dst_tmp.Backup(GetBackupSuffix(), eBackup_Rename) ) {
03559 LOG_ERROR_AND_RETURN("CSymLink::Copy():"
03560 " Cannot backup destination: "
03561 << dst.GetPath());
03562 }
03563 }
03564
03565 if ( F_ISSET(flags, fCF_Overwrite) ) {
03566 dst.Remove();
03567 }
03568 }
03569
03570
03571 char buf[PATH_MAX+1];
03572 int len = (int)readlink(GetPath().c_str(), buf, sizeof(buf)-1);
03573 if ( len < 1 ) {
03574 LOG_ERROR_AND_RETURN("CSymLink::Copy():"
03575 " Cannot create new symbolic link to "
03576 << GetPath());
03577 }
03578 buf[len] = '\0';
03579 if ( symlink(buf, new_path.c_str()) ) {
03580 LOG_ERROR_AND_RETURN_ERRNO("CSymLink::Copy():"
03581 " Cannot create new symbolic link to "
03582 << GetPath());
03583 }
03584
03585
03586 if ( flags & fCF_PreserveAll ) {
03587 if (!s_CopyAttrs(GetPath().c_str(), new_path.c_str(), eLink, flags)) {
03588 return false;
03589 }
03590 }
03591 return true;
03592 #else
03593 return CParent::Copy(new_path, flags, buf_size);
03594 #endif
03595 }
03596
03597
03598
03599
03600
03601
03602
03603
03604
03605
03606 enum EFileSystemInfo {
03607 fFSI_Type = (1<<1),
03608 fFSI_DiskSpace = (1<<2),
03609 fFSI_BlockSize = (1<<3),
03610 fFSI_FileNameMax = (1<<4),
03611 fFSI_All = 0xFF
03612 };
03613 typedef int TFileSystemInfo;
03614
03615
03616 struct SFileSystem {
03617 const char* name;
03618 CFileUtil::EFileSystemType type;
03619 };
03620
03621
03622 static const SFileSystem s_FileSystem[] = {
03623 { "ADFS", CFileUtil::eADFS },
03624 { "ADVFS", CFileUtil::eAdvFS },
03625 { "AFFS", CFileUtil::eAFFS },
03626 { "AUTOFS", CFileUtil::eAUTOFS },
03627 { "CACHEFS", CFileUtil::eCacheFS },
03628 { "CD9669", CFileUtil::eCDFS },
03629 { "CDFS", CFileUtil::eCDFS },
03630 { "DEVFS", CFileUtil::eDEVFS },
03631 { "DFS", CFileUtil::eDFS },
03632 { "DOS", CFileUtil::eFAT },
03633 { "EXT", CFileUtil::eExt },
03634 { "EXT2", CFileUtil::eExt2 },
03635 { "EXT3", CFileUtil::eExt3 },
03636 { "FAT", CFileUtil::eFAT },
03637 { "FAT32", CFileUtil::eFAT32 },
03638 { "FDFS", CFileUtil::eFDFS },
03639 { "FFM", CFileUtil::eFFM },
03640 { "FFS", CFileUtil::eFFS },
03641 { "HFS", CFileUtil::eHFS },
03642 { "HSFS", CFileUtil::eHSFS },
03643 { "HPFS", CFileUtil::eHPFS },
03644 { "JFS", CFileUtil::eJFS },
03645 { "LOFS", CFileUtil::eLOFS },
03646 { "MFS", CFileUtil::eMFS },
03647 { "MSFS", CFileUtil::eMSFS },
03648 { "NFS", CFileUtil::eNFS },
03649 { "NFS2", CFileUtil::eNFS },
03650 { "NFSV2", CFileUtil::eNFS },
03651 { "NFS3", CFileUtil::eNFS },
03652 { "NFSV3", CFileUtil::eNFS },
03653 { "NFS4", CFileUtil::eNFS },
03654 { "NFSV4", CFileUtil::eNFS },
03655 { "NTFS", CFileUtil::eNTFS },
03656 { "PCFS", CFileUtil::eFAT },
03657 { "PROC", CFileUtil::ePROC },
03658 { "PROCFS", CFileUtil::ePROC },
03659 { "RFS", CFileUtil::eRFS },
03660 { "SMBFS", CFileUtil::eSMBFS },
03661 { "SPECFS", CFileUtil::eSPECFS },
03662 { "TMP", CFileUtil::eTMPFS },
03663 { "UFS", CFileUtil::eUFS },
03664 { "VXFS", CFileUtil::eVxFS },
03665 { "XFS", CFileUtil::eXFS }
03666 };
03667
03668
03669
03670
03671 #define GET_STATVFS_INFO \
03672 struct statvfs st; \
03673 memset(&st, 0, sizeof(st)); \
03674 if (statvfs(path.c_str(), &st) != 0) { \
03675 NCBI_THROW(CFileErrnoException, eFileSystemInfo, msg); \
03676 } \
03677 if (st.f_frsize) { \
03678 info->free_space = (Uint8)st.f_frsize * st.f_bavail; \
03679 info->block_size = (unsigned long)st.f_frsize; \
03680 } else { \
03681 info->free_space = (Uint8)st.f_bsize * st.f_bavail; \
03682 info->block_size = (unsigned long)st.f_bsize; \
03683 } \
03684 info->total_space = (Uint8)st.f_bsize * st.f_blocks
03685
03686
03687 #define GET_STATFS_INFO \
03688 struct statfs st; \
03689 memset(&st, 0, sizeof(st)); \
03690 if (statfs(path.c_str(), &st) != 0) { \
03691 NCBI_THROW(CFileErrnoException, eFileSystemInfo, msg); \
03692 } \
03693 info->free_space = (Uint8)st.f_bsize * st.f_bavail; \
03694 info->total_space = (Uint8)st.f_bsize * st.f_blocks; \
03695 info->block_size = (unsigned long)st.f_bsize
03696
03697
03698 void s_GetFileSystemInfo(const string& path,
03699 CFileUtil::SFileSystemInfo* info,
03700 TFileSystemInfo flags)
03701 {
03702 if ( !info ) {
03703 NCBI_THROW(CCoreException, eInvalidArg,
03704 "s_GetFileSystemInfo(path, NULL) is not allowed");
03705 }
03706 memset(info, 0, sizeof(*info));
03707 string msg = string("Cannot get system information for ") + path;
03708 char* fs_name_ptr = 0;
03709
03710 #if defined(NCBI_OS_MSWIN)
03711
03712 string xpath = path;
03713
03714 if ( path[0] != '\\' || path[1] != '\\' ) {
03715 if ( !isalpha((unsigned char)path[0]) || path[1] != DISK_SEPARATOR ) {
03716
03717
03718 if ( CDirEntry(path).Exists() ) {
03719 xpath = CDir::GetCwd();
03720 }
03721 }
03722
03723 xpath[2] = '\\';
03724 xpath.resize(3);
03725 }
03726
03727
03728 char fs_name[MAX_PATH+1];
03729 if (flags & (fFSI_Type | fFSI_FileNameMax)) {
03730 DWORD filename_max;
03731 DWORD fs_flags;
03732
03733 if ( !::GetVolumeInformation(xpath.c_str(),
03734 NULL, 0,
03735 NULL,
03736 &filename_max,
03737 &fs_flags,
03738 fs_name, sizeof(fs_name)) ) {
03739 NCBI_THROW(CFileErrnoException, eFileSystemInfo, msg);
03740 }
03741 info->filename_max = filename_max;
03742 fs_name_ptr = fs_name;
03743 }
03744
03745
03746 if (flags & fFSI_DiskSpace) {
03747 if ( !::GetDiskFreeSpaceEx(xpath.c_str(),
03748 (PULARGE_INTEGER)&info->free_space,
03749 (PULARGE_INTEGER)&info->total_space, 0) ) {
03750 NCBI_THROW(CFileErrnoException, eFileSystemInfo, msg);
03751 }
03752 }
03753
03754
03755 if (flags & fFSI_BlockSize) {
03756 DWORD dwSectPerClust;
03757 DWORD dwBytesPerSect;
03758 if ( !::GetDiskFreeSpace(xpath.c_str(),
03759 &dwSectPerClust, &dwBytesPerSect,
03760 NULL, NULL) ) {
03761 NCBI_THROW(CFileErrnoException, eFileSystemInfo, msg);
03762 }
03763 info->block_size = dwBytesPerSect * dwSectPerClust;
03764 }
03765
03766 #else // defined(NCBI_OS_MSWIN)
03767
03768 # ifdef _PC_NAME_MAX
03769 info->filename_max = pathconf(path.c_str(), _PC_NAME_MAX);
03770 # else
03771 # define NEED_NAME_MAX
03772 # endif
03773
03774 # if defined(NCBI_OS_LINUX) && defined(HAVE_STATFS)
03775
03776 GET_STATFS_INFO;
03777 if (flags & fFSI_Type) {
03778 switch (st.f_type) {
03779 case 0xADF5: info->fs_type = CFileUtil::eADFS; break;
03780 case 0xADFF: info->fs_type = CFileUtil::eFFS; break;
03781 case 0x012FF7B9: info->fs_type = CFileUtil::eAFS; break;
03782 case 0x0187: info->fs_type = CFileUtil::eAUTOFS; break;
03783 case 0x1BADFACE: info->fs_type = CFileUtil::eBFS; break;
03784 case 0xFF534D42: info->fs_type = CFileUtil::eCIFS; break;
03785 case 0x73757245: info->fs_type = CFileUtil::eCODA; break;
03786 case 0x012FF7B7: info->fs_type = CFileUtil::eCOH; break;
03787 case 0x28CD3D45: info->fs_type = CFileUtil::eCRAMFS; break;
03788 case 0x1373: info->fs_type = CFileUtil::eDEVFS; break;
03789 case 0x137D: info->fs_type = CFileUtil::eExt; break;
03790 case 0xEF51:
03791 case 0xEF53: info->fs_type = CFileUtil::eExt2; break;
03792 case 0x4244: info->fs_type = CFileUtil::eHFS; break;
03793 case 0xF995E849: info->fs_type = CFileUtil::eHPFS; break;
03794 case 0x4004:
03795 case 0x4000:
03796 case 0x9660: info->fs_type = CFileUtil::eCDFS; break;
03797 case 0x3153464A: info->fs_type = CFileUtil::eJFS; break;
03798 case 0x07C0: info->fs_type = CFileUtil::eJFFS; break;
03799 case 0x72B6: info->fs_type = CFileUtil::eJFFS2; break;
03800 case 0x137F:
03801 case 0x138F: info->fs_type = CFileUtil::eMinix; break;
03802 case 0x2468:
03803 case 0x2478: info->fs_type = CFileUtil::eMinix2; break;
03804 case 0x4d44: info->fs_type = CFileUtil::eFAT; break;
03805 case 0x564C: info->fs_type = CFileUtil::eNCPFS; break;
03806 case 0x6969: info->fs_type = CFileUtil::eNFS; break;
03807 case 0x5346544E: info->fs_type = CFileUtil::eNTFS; break;
03808 case 0x9fA1: info->fs_type = CFileUtil::eOPENPROM; break;
03809 case 0x9fA0: info->fs_type = CFileUtil::ePROC; break;
03810 case 0x002F: info->fs_type = CFileUtil::eQNX4; break;
03811 case 0x7275: info->fs_type = CFileUtil::eROMFS; break;
03812 case 0x517B: info->fs_type = CFileUtil::eSMBFS; break;
03813 case 0x62656572: info->fs_type = CFileUtil::eSYSFS; break;
03814 case 0x012FF7B6: info->fs_type = CFileUtil::eSYSV2; break;
03815 case 0x012FF7B5: info->fs_type = CFileUtil::eSYSV4; break;
03816 case 0x01021994: info->fs_type = CFileUtil::eTMPFS; break;
03817 case 0x15013346: info->fs_type = CFileUtil::eUDF; break;
03818 case 0x00011954: info->fs_type = CFileUtil::eUFS; break;
03819 case 0x9fA2: info->fs_type = CFileUtil::eUSBDEVICE;break;
03820 case 0x012FF7B8: info->fs_type = CFileUtil::eV7; break;
03821 case 0xa501FCF5: info->fs_type = CFileUtil::eVxFS; break;
03822 case 0x565a4653: info->fs_type = CFileUtil::eVZFS; break;
03823 case 0x012FF7B4: info->fs_type = CFileUtil::eXENIX; break;
03824 case 0x58465342: info->fs_type = CFileUtil::eXFS; break;
03825 case 0x012FD16D: info->fs_type = CFileUtil::eXIAFS; break;
03826 default: info->fs_type = CFileUtil::eUnknown; break;
03827 }
03828 }
03829 #ifdef NEED_NAME_MAX
03830 info->filename_max = (unsigned long)st.f_namelen;
03831 #endif
03832
03833 # elif (defined(NCBI_OS_SOLARIS) || defined(NCBI_OS_IRIX) || \
03834 defined(NCBI_OS_OSF1)) && defined(HAVE_STATVFS)
03835
03836 GET_STATVFS_INFO;
03837 #ifdef NEED_NAME_MAX
03838 info->filename_max = (unsigned long)st.f_namemax;
03839 #endif
03840 fs_name_ptr = st.f_basetype;
03841
03842 # elif (defined(NCBI_OS_BSD) || defined(NCBI_OS_DARWIN)) && \
03843 defined(HAVE_STATFS)
03844
03845 GET_STATFS_INFO;
03846 #ifdef NEED_NAME_MAX
03847 info->filename_max = (unsigned long)st.f_namelen;
03848 #endif
03849 fs_name_ptr = st.f_fstypename;
03850
03851 # elif defined(NCBI_OS_OSF1) && defined(HAVE_STATVFS)
03852
03853 GET_STATVFS_INFO;
03854 #ifdef NEED_NAME_MAX
03855 info->filename_max = (unsigned long)st.f_namelen;
03856 #endif
03857 fs_name_ptr = st.f_fstypename;
03858
03859 # else
03860
03861 # if defined(HAVE_STATVFS)
03862 GET_STATVFS_INFO;
03863 # elif defined(HAVE_STATFS)
03864 GET_STATFS_INFO;
03865 # endif
03866 # endif
03867 #endif
03868
03869
03870 if ((flags & fFSI_Type) && fs_name_ptr) {
03871 for (size_t i=0;
03872 i < sizeof(s_FileSystem)/sizeof(s_FileSystem[0]); i++) {
03873 if ( NStr::EqualNocase(fs_name_ptr, s_FileSystem[i].name) ) {
03874 info->fs_type = s_FileSystem[i].type;
03875 break;
03876 }
03877 }
03878 }
03879 }
03880
03881
03882 void CFileUtil::GetFileSystemInfo(const string& path,
03883 CFileUtil::SFileSystemInfo* info)
03884 {
03885 s_GetFileSystemInfo(path, info, fFSI_All);
03886 }
03887
03888
03889 Uint8 CFileUtil::GetFreeDiskSpace(const string& path)
03890 {
03891 SFileSystemInfo info;
03892 s_GetFileSystemInfo(path, &info, fFSI_DiskSpace);
03893 return info.free_space;
03894 }
03895
03896
03897 Uint8 CFileUtil::GetTotalDiskSpace(const string& path)
03898 {
03899 SFileSystemInfo info;
03900 s_GetFileSystemInfo(path, &info, fFSI_DiskSpace);
03901 return info.total_space;
03902 }
03903
03904
03905
03906
03907
03908
03909
03910
03911 CFileDeleteList::~CFileDeleteList()
03912 {
03913 ITERATE (TNames, name, m_Names) {
03914 CDirEntry entry(*name);
03915 if ( entry.IsDir()) {
03916 CDir(*name).Remove(CDir::eRecursiveIgnoreMissing);
03917 } else {
03918 entry.Remove();
03919 }
03920 }
03921 }
03922
03923
03924 void CFileDeleteAtExit::Add(const string& entryname)
03925 {
03926 s_DeleteAtExitFileList->Add(entryname);
03927 }
03928
03929 const CFileDeleteList& CFileDeleteAtExit::GetDeleteList(void)
03930 {
03931 return *s_DeleteAtExitFileList;
03932 }
03933
03934 void CFileDeleteAtExit::SetDeleteList(CFileDeleteList& list)
03935 {
03936 *s_DeleteAtExitFileList = list;
03937 }
03938
03939
03940
03941
03942
03943
03944
03945
03946 CTmpFile::CTmpFile(ERemoveMode remove_file)
03947 {
03948 m_FileName = CFile::GetTmpName();
03949 if ( m_FileName.empty() ) {
03950 NCBI_THROW(CFileException, eTmpFile,
03951 "Cannot generate temporary file name");
03952 }
03953 m_RemoveOnDestruction = remove_file;
03954 }
03955
03956 CTmpFile::CTmpFile(const string& file_name, ERemoveMode remove_file)
03957 : m_FileName(file_name),
03958 m_RemoveOnDestruction(remove_file)
03959 {
03960 return;
03961 }
03962
03963 CTmpFile::~CTmpFile()
03964 {
03965
03966 m_InFile.reset();
03967 m_OutFile.reset();
03968
03969
03970 if (m_RemoveOnDestruction == eRemove) {
03971 unlink(m_FileName.c_str());
03972 }
03973 }
03974
03975 enum EIfExists {
03976
03977
03978 eIfExists_Throw,
03979
03980 eIfExists_Reset,
03981
03982 eIfExists_ReturnCurrent
03983 };
03984
03985
03986
03987 const string& CTmpFile::GetFileName(void) const
03988 {
03989 return m_FileName;
03990 }
03991
03992
03993 CNcbiIstream& CTmpFile::AsInputFile(EIfExists if_exists,
03994 IOS_BASE::openmode mode)
03995 {
03996 if ( m_InFile.get() ) {
03997 switch (if_exists) {
03998 case eIfExists_Throw:
03999 NCBI_THROW(CFileException, eTmpFile,
04000 "AsInputFile() is already called");
04001
04002 break;
04003 case eIfExists_Reset:
04004
04005 break;
04006 case eIfExists_ReturnCurrent:
04007 return *m_InFile;
04008 }
04009 }
04010 mode |= IOS_BASE::in;
04011 m_InFile.reset(new CNcbiIfstream(m_FileName.c_str()));
04012 return *m_InFile;
04013 }
04014
04015
04016 CNcbiOstream& CTmpFile::AsOutputFile(EIfExists if_exists,
04017 IOS_BASE::openmode mode)
04018 {
04019 if ( m_OutFile.get() ) {
04020 switch (if_exists) {
04021 case eIfExists_Throw:
04022 NCBI_THROW(CFileException, eTmpFile,
04023 "AsOutputFile() is already called");
04024
04025 break;
04026 case eIfExists_Reset:
04027
04028 break;
04029 case eIfExists_ReturnCurrent:
04030 return *m_OutFile;
04031 }
04032 }
04033 mode |= IOS_BASE::out;
04034 m_OutFile.reset(new CNcbiOfstream(m_FileName.c_str()));
04035 return *m_OutFile;
04036 }
04037
04038
04039
04040
04041
04042
04043
04044
04045 static unsigned long s_VirtualMemoryPageSize = 0;
04046
04047
04048
04049 struct SMemoryFileHandle {
04050 #if defined(NCBI_OS_MSWIN)
04051 HANDLE hMap;
04052 #else
04053 int hMap;
04054 #endif
04055 string sFileName;
04056 };
04057
04058
04059 struct SMemoryFileAttrs {
04060 #if defined(NCBI_OS_MSWIN)
04061 DWORD map_protect;
04062 DWORD map_access;
04063 DWORD file_share;
04064 DWORD file_access;
04065 #else
04066 int map_protect;
04067 int map_access;
04068 int file_access;
04069 #endif
04070 };
04071
04072
04073
04074 static SMemoryFileAttrs*
04075 s_TranslateAttrs(CMemoryFile_Base::EMemMapProtect protect_attr,
04076 CMemoryFile_Base::EMemMapShare share_attr)
04077 {
04078 SMemoryFileAttrs* attrs = new SMemoryFileAttrs();
04079 memset(attrs, 0, sizeof(SMemoryFileAttrs));
04080
04081 #if defined(NCBI_OS_MSWIN)
04082
04083 switch (protect_attr) {
04084 case CMemoryFile_Base::eMMP_Read:
04085 attrs->map_access = FILE_MAP_READ;
04086
04087
04088
04089
04090 attrs->map_protect = PAGE_READONLY;
04091 attrs->file_access = GENERIC_READ;
04092 break;
04093 case CMemoryFile_Base::eMMP_Write:
04094 case CMemoryFile_Base::eMMP_ReadWrite:
04095
04096
04097 if (share_attr == CMemoryFile_Base::eMMS_Shared ) {
04098 attrs->map_access = FILE_MAP_ALL_ACCESS;
04099 } else {
04100 attrs->map_access = FILE_MAP_COPY;
04101 }
04102 attrs->map_protect = PAGE_READWRITE;
04103
04104 attrs->file_access = GENERIC_READ | GENERIC_WRITE;
04105 break;
04106 default:
04107 _TROUBLE;
04108 }
04109 if ( share_attr == CMemoryFile_Base::eMMS_Shared ) {
04110 attrs->file_share = FILE_SHARE_READ | FILE_SHARE_WRITE;
04111 } else {
04112 attrs->file_share = FILE_SHARE_READ;
04113 }
04114
04115 #elif defined(NCBI_OS_UNIX)
04116
04117 switch (share_attr) {
04118 case CMemoryFile_Base::eMMS_Shared:
04119 attrs->map_access = MAP_SHARED;
04120
04121 attrs->file_access = O_RDWR;
04122 break;
04123 case CMemoryFile_Base::eMMS_Private:
04124 attrs->map_access = MAP_PRIVATE;
04125
04126
04127
04128 attrs->file_access = O_RDONLY;
04129 break;
04130 default:
04131 _TROUBLE;
04132 }
04133 switch (protect_attr) {
04134 case CMemoryFile_Base::eMMP_Read:
04135 attrs->map_protect = PROT_READ;
04136 attrs->file_access = O_RDONLY;
04137 break;
04138 case CMemoryFile_Base::eMMP_Write:
04139 attrs->map_protect = PROT_WRITE;
04140 break;
04141 case CMemoryFile_Base::eMMP_ReadWrite:
04142 attrs->map_protect = PROT_READ | PROT_WRITE;
04143 break;
04144 default:
04145 _TROUBLE;
04146 }
04147
04148 #endif
04149 return attrs;
04150 }
04151
04152
04153 CMemoryFile_Base::CMemoryFile_Base(void)
04154 {
04155
04156 if ( !IsSupported() ) {
04157 NCBI_THROW(CFileException, eMemoryMap,
04158 "Memory-mapping is not supported by the C++ Toolkit"
04159 " on this platform");
04160 }
04161 if ( !s_VirtualMemoryPageSize ) {
04162 s_VirtualMemoryPageSize = GetVirtualMemoryPageSize();
04163 }
04164 }
04165
04166
04167 bool CMemoryFile_Base::IsSupported(void)
04168 {
04169 #if defined(NCBI_OS_MSWIN) || defined(NCBI_OS_UNIX)
04170 return true;
04171 #else
04172 return false;
04173 #endif
04174 }
04175
04176
04177 #if !defined(HAVE_MADVISE)
04178 bool CMemoryFile_Base::MemMapAdviseAddr(void*, size_t, EMemMapAdvise) {
04179 return true;
04180 }
04181 #else
04182 bool CMemoryFile_Base::MemMapAdviseAddr(void* addr, size_t len,
04183 EMemMapAdvise advise)
04184 {
04185 int adv;
04186 if ( !addr || !len ) {
04187 return false;
04188 }
04189 switch (advise) {
04190 case eMMA_Random:
04191 adv = MADV_RANDOM; break;
04192 case eMMA_Sequential:
04193 adv = MADV_SEQUENTIAL; break;
04194 case eMMA_WillNeed:
04195 adv = MADV_WILLNEED; break;
04196 case eMMA_DontNeed:
04197 adv = MADV_DONTNEED; break;
04198 default:
04199 adv = MADV_NORMAL;
04200 }
04201
04202 if ( madvise((char*) addr, len, adv) != 0 ) {
04203 LOG_ERROR_AND_RETURN_ERRNO("CMemoryFile_Base::MemMapAdviseAddr():"
04204 " madvise() failed");
04205 }
04206 return true;
04207 }
04208 #endif
04209
04210
04211 #if defined(NCBI_OS_MSWIN)
04212 string s_LastErrorMessage(void)
04213 {
04214 char* ptr = NULL;
04215 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
04216 FORMAT_MESSAGE_FROM_SYSTEM |
04217 FORMAT_MESSAGE_MAX_WIDTH_MASK |
04218 FORMAT_MESSAGE_IGNORE_INSERTS,
04219 "%0", GetLastError(),
04220 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
04221 (LPTSTR)&ptr, 0, NULL);
04222 string errmsg = ptr ? ptr : "Unknown reason";
04223 LocalFree(ptr);
04224 return errmsg;
04225 }
04226 #endif
04227
04228 CMemoryFileSegment::CMemoryFileSegment(SMemoryFileHandle& handle,
04229 SMemoryFileAttrs& attrs,
04230 off_t offset,
04231 size_t length)
04232 : m_DataPtr(0), m_Offset(offset), m_Length(length),
04233 m_DataPtrReal(0), m_OffsetReal(offset), m_LengthReal(length)
04234 {
04235 if ( m_Offset < 0 ) {
04236 NCBI_THROW(CFileException, eMemoryMap,
04237 "File offset may not be negative");
04238 }
04239 if ( !m_Length ) {
04240 NCBI_THROW(CFileException, eMemoryMap,
04241 "File mapping region size must be greater than 0");
04242 }
04243
04244 if ( !s_VirtualMemoryPageSize ) {
04245 NCBI_THROW(CFileException, eMemoryMap,
04246 "Cannot determine virtual page size");
04247 }
04248
04249 if ( m_Offset % s_VirtualMemoryPageSize ) {
04250 m_OffsetReal -= (m_Offset % s_VirtualMemoryPageSize);
04251 m_LengthReal += (m_Offset % s_VirtualMemoryPageSize);
04252 }
04253
04254 string errmsg;
04255 #if defined(NCBI_OS_MSWIN)
04256 DWORD offset_hi = DWORD(Int8(m_OffsetReal) >> 32);
04257 DWORD offset_low = DWORD(Int8(m_OffsetReal) & 0xFFFFFFFF);
04258 m_DataPtrReal = MapViewOfFile(handle.hMap, attrs.map_access,
04259 offset_hi, offset_low, m_LengthReal);
04260 if ( !m_DataPtrReal ) {
04261 errmsg = s_LastErrorMessage();
04262 }
04263
04264 #elif defined(NCBI_OS_UNIX)
04265 errno = 0;
04266 m_DataPtrReal = mmap(0, m_LengthReal, attrs.map_protect,
04267 attrs.map_access, handle.hMap, m_OffsetReal);
04268 if ( m_DataPtrReal == MAP_FAILED ) {
04269 m_DataPtrReal = 0;
04270 errmsg = strerror(errno);
04271 }
04272 #endif
04273 if ( !m_DataPtrReal ) {
04274 NCBI_THROW(CFileException, eMemoryMap,
04275 "Cannot map file '" +
04276 handle.sFileName + "' to memory (offset=" +
04277 NStr::Int8ToString(m_Offset) + ", length=" +
04278 NStr::Int8ToString(m_Length) + "): " + errmsg);
04279 }
04280
04281 m_DataPtr = (char*)m_DataPtrReal + (m_Offset - m_OffsetReal);
04282 }
04283
04284
04285 CMemoryFileSegment::~CMemoryFileSegment(void)
04286 {
04287 Unmap();
04288 }
04289
04290
04291 bool CMemoryFileSegment::Flush(void) const
04292 {
04293 if ( !m_DataPtr ) {
04294 return false;
04295 }
04296 bool status;
04297 #if defined(NCBI_OS_MSWIN)
04298 status = (FlushViewOfFile(m_DataPtrReal, m_LengthReal) != 0);
04299 #elif defined(NCBI_OS_UNIX)
04300 status = (msync((char*)m_DataPtrReal, m_LengthReal, MS_SYNC) == 0);
04301 #endif
04302 if ( !status ) {
04303 LOG_ERROR_AND_RETURN_ERRNO("CMemoryFileSegment::Flush():"
04304 " Cannot flush memory segment");
04305 }
04306 return status;
04307 }
04308
04309
04310 bool CMemoryFileSegment::Unmap(void)
04311 {
04312
04313 if ( !m_DataPtr ) {
04314 return true;
04315 }
04316 bool status;
04317 #if defined(NCBI_OS_MSWIN)
04318 status = (UnmapViewOfFile(m_DataPtrReal) != 0);
04319 #elif defined(NCBI_OS_UNIX)
04320 status = (munmap((char*)m_DataPtrReal, (size_t) m_LengthReal) == 0);
04321 #endif
04322 if ( status ) {
04323 m_DataPtr = 0;
04324 } else {
04325 LOG_ERROR_AND_RETURN_ERRNO("CMemoryFileSegment::Unmap():"
04326 " Cannot unmap memory segment");
04327 }
04328 return status;
04329 }
04330
04331
04332 void CMemoryFileSegment::x_Verify(void) const
04333 {
04334 if ( m_DataPtr ) {
04335 return;
04336 }
04337 NCBI_THROW(CFileException, eMemoryMap, "File not mapped");
04338 }
04339
04340
04341 bool CMemoryFileSegment::MemMapAdvise(EMemMapAdvise advise) const
04342 {
04343 if ( !m_DataPtr ) {
04344 return false;
04345 }
04346 return MemMapAdviseAddr(m_DataPtrReal, m_LengthReal, advise);
04347 }
04348
04349
04350 CMemoryFileMap::CMemoryFileMap(const string& file_name,
04351 EMemMapProtect protect,
04352 EMemMapShare share,
04353 EOpenMode mode,
04354 Uint8 max_file_len)
04355 : m_FileName(file_name), m_Handle(0), m_Attrs(0)
04356 {
04357 #if defined(NCBI_OS_MSWIN)
04358
04359 m_FileName = NStr::Replace(m_FileName, "\\", "/");
04360 #endif
04361
04362
04363 m_Attrs = s_TranslateAttrs(protect, share);
04364
04365
04366 if ( mode == eCreate ) {
04367 x_Create(max_file_len);
04368 }
04369
04370 Int8 file_size = GetFileSize();
04371 if ( file_size < 0 ) {
04372 if ( m_Attrs ) {
04373 delete m_Attrs;
04374 m_Attrs = 0;
04375 }
04376 NCBI_THROW(CFileException, eMemoryMap,
04377 "To be memory mapped the file must exist: " + m_FileName);
04378 }
04379
04380 if ( mode == eExtend && max_file_len > (Uint8)file_size) {
04381 x_Extend(max_file_len - file_size);
04382 file_size = (Int8)max_file_len;
04383 }
04384
04385
04386 if ( file_size == 0 ) {
04387
04388 m_Handle = new SMemoryFileHandle();
04389 m_Handle->hMap = kInvalidHandle;
04390 m_Handle->sFileName = m_FileName;
04391 return;
04392 }
04393 x_Open();
04394 }
04395
04396
04397 CMemoryFileMap::~CMemoryFileMap(void)
04398 {
04399
04400 x_Close();
04401
04402 if ( m_Attrs ) {
04403 delete m_Attrs;
04404 }
04405 }
04406
04407
04408 void* CMemoryFileMap::Map(off_t offset, size_t length)
04409 {
04410 if ( !m_Handle || (m_Handle->hMap == kInvalidHandle) ) {
04411
04412
04413 return 0;
04414 }
04415
04416 if ( !length ) {
04417 Int8 file_size = GetFileSize() - offset;
04418 if ( (Uint8)file_size > get_limits(length).max() ) {
04419 NCBI_THROW(CFileException, eMemoryMap,
04420 "File too big for memory mapping " \
04421 "(file \"" + m_FileName +"\", "
04422 "offset=" + NStr::Int8ToString(offset) + ", " \
04423 "length=" + NStr::Int8ToString(length) + ")");
04424 } else if ( file_size > 0 ) {
04425 length = (size_t)file_size;
04426 } else {
04427 NCBI_THROW(CFileException, eMemoryMap,
04428 "Mapping region offset specified beyond file size");
04429 }
04430 }
04431
04432 CMemoryFileSegment* segment =
04433 new CMemoryFileSegment(*m_Handle, *m_Attrs, offset, length);
04434 void* ptr = segment->GetPtr();
04435 if ( !ptr ) {
04436 delete segment;
04437 NCBI_THROW(CFileException, eMemoryMap,
04438 "Cannot map (file \"" + m_FileName +"\", "
04439 "offset=" + NStr::Int8ToString(offset) + ", " \
04440 "length=" + NStr::Int8ToString(length) + ")");
04441 }
04442 m_Segments[ptr] = segment;
04443 return ptr;
04444 }
04445
04446
04447 bool CMemoryFileMap::Unmap(void* ptr)
04448 {
04449
04450 bool status = false;
04451 TSegments::iterator segment = m_Segments.find(ptr);
04452 if ( segment != m_Segments.end() ) {
04453 status = segment->second->Unmap();
04454 if ( status ) {
04455 delete segment->second;
04456 m_Segments.erase(segment);
04457 }
04458 }
04459 if ( !status ) {
04460 LOG_ERROR_AND_RETURN_ERRNO("CMemoryFileMap::Unmap():"
04461 " Memory segment not found");
04462 }
04463 return status;
04464 }
04465
04466
04467 bool CMemoryFileMap::UnmapAll(void)
04468 {
04469 bool status = true;
04470 void* key_to_delete = 0;
04471 ITERATE(TSegments, it, m_Segments) {
04472 if ( key_to_delete ) {
04473 m_Segments.erase(key_to_delete);
04474 }
04475 bool unmapped = it->second->Unmap();
04476 if ( status ) {
04477 status = unmapped;
04478 }
04479 if ( unmapped ) {
04480 key_to_delete = it->first;
04481 delete it->second;
04482 } else {
04483 key_to_delete = 0;
04484 }
04485 }
04486 if ( key_to_delete ) {
04487 m_Segments.erase(key_to_delete);
04488 }
04489 return status;
04490 }
04491
04492
04493 void CMemoryFileMap::x_Open(void)
04494 {
04495 m_Handle = new SMemoryFileHandle();
04496 m_Handle->hMap = kInvalidHandle;
04497 m_Handle->sFileName = m_FileName;
04498
04499 string errmsg;
04500
04501 for (;;) {
04502
04503 #if defined(NCBI_OS_MSWIN)
04504 errmsg = ": ";
04505
04506
04507
04508 HANDLE hMap = OpenFileMapping(m_Attrs->map_access, false,
04509 m_FileName.c_str());
04510 if ( !hMap ) {
04511
04512
04513
04514
04515
04516
04517
04518 HANDLE hFile;
04519 DWORD x_file_access = GENERIC_READ | GENERIC_WRITE;
04520 DWORD x_map_protect = PAGE_READWRITE;
04521
04522 hFile = CreateFile(m_FileName.c_str(), x_file_access,
04523 m_Attrs->file_share, NULL,
04524 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
04525 if ( (hFile == INVALID_HANDLE_VALUE) &&
04526 (m_Attrs->file_access != x_file_access) ) {
04527 hFile = CreateFile(m_FileName.c_str(), m_Attrs->file_access,
04528 m_Attrs->file_share, NULL,
04529 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,NULL);
04530 x_map_protect = m_Attrs->map_protect;
04531 }
04532 if ( hFile == INVALID_HANDLE_VALUE ) {
04533 errmsg += s_LastErrorMessage();
04534 break;
04535 }
04536
04537
04538
04539 hMap = CreateFileMapping(hFile, NULL,
04540 x_map_protect,
04541 0, 0, m_FileName.c_str());
04542 if ( !hMap &&
04543 (m_Attrs->map_protect != x_map_protect) ) {
04544 hMap = CreateFileMapping(hFile, NULL,
04545 m_Attrs->map_protect,
04546 0, 0, m_FileName.c_str());
04547 }
04548 CloseHandle(hFile);
04549 if ( !hMap ) {
04550 errmsg += s_LastErrorMessage();
04551 break;
04552 }
04553 }
04554 m_Handle->hMap = hMap;
04555
04556 #elif defined(NCBI_OS_UNIX)
04557
04558 m_Handle->hMap = open(m_FileName.c_str(), m_Attrs->file_access);
04559 if ( m_Handle->hMap < 0 ) {
04560 break;
04561 }
04562 #endif
04563
04564 return;
04565 }
04566
04567 x_Close();
04568 NCBI_THROW(CFileException, eMemoryMap,
04569 "CMemoryFile: Cannot memory map file \"" + m_FileName + '"');
04570 }
04571
04572
04573 void CMemoryFileMap::x_Close()
04574 {
04575
04576 ITERATE(TSegments, it, m_Segments) {
04577 delete it->second;
04578 }
04579 m_Segments.clear();
04580
04581
04582 if ( m_Handle ) {
04583 if ( m_Handle->hMap != kInvalidHandle ) {
04584 #if defined(NCBI_OS_MSWIN)
04585 CloseHandle(m_Handle->hMap);
04586 #elif defined(NCBI_OS_UNIX)
04587 close(m_Handle->hMap);
04588 #endif
04589 }
04590 delete m_Handle;
04591 m_Handle = 0;
04592 }
04593 }
04594
04595
04596 void s_AppendZeros(int fd, Uint8 length)
04597 {
04598 char* buf = new char[kDefaultBufferSize];
04599 memset(buf, '\0', kDefaultBufferSize);
04600 string errmsg;
04601 do {
04602 int x_written = (int)write(fd, (void*) buf,
04603 length > kDefaultBufferSize ? kDefaultBufferSize :
04604 (unsigned int)length);
04605 if ( x_written < 0 ) {
04606 if (errno != EINTR) {
04607 errmsg = strerror(errno);
04608 break;
04609 }
04610 continue;
04611 }
04612 length -= x_written;
04613 }
04614 while (length);
04615
04616
04617 delete[] buf;
04618 close(fd);
04619 if ( length ) {
04620 NCBI_THROW(CFileException, eMemoryMap, "CMemoryFileMap:"
04621 " Cannot extend file size: " + errmsg);
04622 }
04623
04624 }
04625
04626
04627 void CMemoryFileMap::x_Create(Uint8 length)
04628 {
04629 int pmode = S_IREAD;
04630 #if defined(NCBI_OS_MSWIN)
04631 if (m_Attrs->file_access & (GENERIC_READ | GENERIC_WRITE))
04632 #elif defined(NCBI_OS_UNIX)
04633 if (m_Attrs->file_access & O_RDWR)
04634 #endif
04635 pmode |= S_IWRITE;
04636
04637
04638 #ifdef NCBI_OS_MSWIN
04639 int fd = _creat(m_FileName.c_str(), pmode);
04640 #else
04641 int fd = creat(m_FileName.c_str(), pmode);
04642 #endif
04643 if ( fd < 0 ) {
04644 NCBI_THROW(CFileException, eMemoryMap, "CMemoryFileMap:"
04645 " Cannot create file \"" + m_FileName + '"');
04646 }
04647
04648 s_AppendZeros(fd, length);
04649 }
04650
04651
04652 void CMemoryFileMap::x_Extend(Uint8 length)
04653 {
04654
04655 #if defined(NCBI_OS_MSWIN)
04656 int fd = _open(m_FileName.c_str(), O_BINARY | O_APPEND | O_WRONLY, 0);
04657 #else
04658 int fd = open(m_FileName.c_str(), O_APPEND | O_WRONLY, 0);
04659 #endif
04660 if ( fd < 0 ) {
04661 NCBI_THROW(CFileException, eMemoryMap, "CMemoryFileMap:"
04662 " Cannot open file \"" + m_FileName +
04663 "\" to change its size");
04664 }
04665
04666 s_AppendZeros(fd, length);
04667 }
04668
04669
04670 CMemoryFileSegment*
04671 CMemoryFileMap::x_GetMemoryFileSegment(void* ptr) const
04672 {
04673 if ( !m_Handle && (m_Handle->hMap == kInvalidHandle) ) {
04674 NCBI_THROW(CFileException, eMemoryMap, "CMemoryFileMap:"
04675 " File is not mapped");
04676 }
04677 TSegments::const_iterator segment = m_Segments.find(ptr);
04678 if ( segment == m_Segments.end() ) {
04679 NCBI_THROW(CFileException, eMemoryMap, "CMemoryFileMap:"
04680 " Cannot find mapped file segment"
04681 " with specified address");
04682 }
04683 return segment->second;
04684 }
04685
04686
04687 CMemoryFile::CMemoryFile(const string& file_name,
04688 EMemMapProtect protect,
04689 EMemMapShare share,
04690 off_t offset,
04691 size_t length,
04692 EOpenMode mode,
04693 Uint8 max_file_len)
04694
04695 : CMemoryFileMap(file_name, protect, share, mode, max_file_len), m_Ptr(0)
04696 {
04697
04698 if ( !m_Handle || (m_Handle->hMap == kInvalidHandle) ) {
04699 return;
04700 }
04701 Map(offset, length);
04702 }
04703
04704
04705 void* CMemoryFile::Map(off_t offset, size_t length)
04706 {
04707
04708 if ( m_Ptr ) {
04709 Unmap();
04710 }
04711 m_Ptr = CMemoryFileMap::Map(offset, length);
04712 return m_Ptr;
04713 }
04714
04715
04716 bool CMemoryFile::Unmap()
04717 {
04718 if ( !m_Ptr ) {
04719 return true;
04720 }
04721 bool status = CMemoryFileMap::Unmap(m_Ptr);
04722 m_Ptr = 0;
04723 return status;
04724 }
04725
04726
04727 void* CMemoryFile::Extend(size_t length)
04728 {
04729 x_Verify();
04730
04731
04732 CMemoryFileSegment* segment = x_GetMemoryFileSegment(m_Ptr);
04733 off_t offset = segment->GetOffset();
04734
04735
04736 Int8 file_size = GetFileSize();
04737
04738
04739 if ( !length ) {
04740 Int8 fs = file_size - offset;
04741 if ( (Uint8)fs > get_limits(length).max() ) {
04742 NCBI_THROW(CFileException, eMemoryMap,
04743 "Specified length of the mapping region"
04744 " is too big"
04745 " (length=" + NStr::Int8ToString(length) + ')');
04746 } else if ( fs > 0 ) {
04747 length = (size_t)fs;
04748 } else {
04749 NCBI_THROW(CFileException, eMemoryMap,
04750 "Specified offset of the mapping region"
04751 " exceeds the file size");
04752 }
04753 }
04754
04755
04756 if (Int8(offset + length) > file_size) {
04757 x_Close();
04758 m_Ptr = 0;
04759 x_Extend(offset + length - file_size);
04760 x_Open();
04761 }
04762
04763 Map(offset, length);
04764 return GetPtr();
04765 }
04766
04767
04768 void CMemoryFile::x_Verify(void) const
04769 {
04770 if ( m_Ptr ) {
04771 return;
04772 }
04773 NCBI_THROW(CFileException, eMemoryMap, "CMemoryFile: File is not mapped");
04774 }
04775
04776
04777
04778
04779
04780
04781
04782
04783 const char* CFileException::GetErrCodeString(void) const
04784 {
04785 switch (GetErrCode()) {
04786 case eMemoryMap: return "eMemoryMap";
04787 case eRelativePath: return "eRelativePath";
04788 case eNotExists: return "eNotExists";
04789 case eFileIO: return "eFileIO";
04790 case eTmpFile: return "eTmpFile";
04791 default: return CException::GetErrCodeString();
04792 }
04793 }
04794
04795 const char* CFileErrnoException::GetErrCodeString(void) const
04796 {
04797 switch (GetErrCode()) {
04798 case eFileSystemInfo: return "eFileSystemInfo";
04799 case eFileLock: return "eFileLock";
04800 case eFileIO: return "eFileIO";
04801 default: return CException::GetErrCodeString();
04802 }
04803 }
04804
04805
04806
04807
04808
04809
04810
04811
04812 void x_Glob(const string& path,
04813 const list<string>& parts,
04814 list<string>::const_iterator next,
04815 list<string>& result,
04816 TFindFiles flags)
04817 {
04818 vector<string> paths;
04819 paths.push_back(path);
04820 vector<string> masks;
04821 masks.push_back(*next);
04822 bool last = ++next == parts.end();
04823 TFindFiles ff = flags;
04824 if ( !last ) {
04825 ff &= ~(fFF_File | fFF_Recursive);
04826 ff |= fFF_Dir;
04827 }
04828 list<string> found;
04829 FindFiles(found, paths.begin(), paths.end(), masks, ff);
04830 if ( last ) {
04831 result.insert(result.end(), found.begin(), found.end());
04832 }
04833 else {
04834 if ( !found.empty() ) {
04835 ITERATE(list<string>, it, found) {
04836 x_Glob(CDirEntry::AddTrailingPathSeparator(*it),
04837 parts, next, result, flags);
04838 }
04839 }
04840 else {
04841 x_Glob(CDirEntry::AddTrailingPathSeparator(path + masks.front()),
04842 parts, next, result, flags);
04843 }
04844 }
04845 }
04846
04847
04848 void FindFiles(const string& pattern,
04849 list<string>& result,
04850 TFindFiles flags)
04851 {
04852 string kDirSep(1, CDirEntry::GetPathSeparator());
04853 string abs_path = CDirEntry::CreateAbsolutePath(pattern);
04854 string search_path = kDirSep;
04855
04856 list<string> parts;
04857 NStr::Split(abs_path, kDirSep, parts);
04858 if ( parts.empty() ) {
04859 return;
04860 }
04861
04862 #if defined(DISK_SEPARATOR)
04863
04864
04865 string kNetSep(2, CDirEntry::GetPathSeparator());
04866 bool is_network = pattern.find(kNetSep) == 0;
04867 if ( is_network ) {
04868 search_path = kNetSep + parts.front() + kDirSep;
04869 parts.erase(parts.begin());
04870 }
04871 else {
04872 string disk;
04873 CDirEntry::SplitPathEx(abs_path, &disk);
04874 if ( disk.empty() ) {
04875
04876 CDirEntry::SplitPathEx(CDir::GetCwd(), &disk);
04877 if ( !disk.empty() ) {
04878 search_path = disk + kDirSep;
04879 }
04880 }
04881 else {
04882 search_path = disk;
04883
04884 if (abs_path[disk.size()] == DIR_SEPARATOR) {
04885 parts.erase(parts.begin());
04886 search_path += kDirSep;
04887 }
04888 else {
04889
04890 string temp = parts.front().substr(disk.size());
04891 parts.erase(parts.begin());
04892 parts.insert(parts.begin(), temp);
04893 }
04894 }
04895 }
04896 #endif
04897
04898 x_Glob(search_path, parts, parts.begin(), result, flags);
04899 }
04900
04901
04902
04903
04904
04905
04906
04907
04908 CFileIO::CFileIO(void)
04909 : m_Handle(kInvalidHandle), m_CloseHandle(false)
04910 {
04911 return;
04912 }
04913
04914
04915 CFileIO::~CFileIO()
04916 {
04917 if (m_Handle == kInvalidHandle) {
04918 return;
04919 }
04920 Close();
04921 }
04922
04923
04924 void CFileIO::Open(const string& filename,
04925 EOpenMode open_mode,
04926 EAccessMode access_mode,
04927 EShareMode share_mode)
04928 {
04929 #if defined(NCBI_OS_MSWIN)
04930
04931
04932 DWORD dwAccessMode, dwShareMode, dwOpenMode;
04933
04934 switch (open_mode) {
04935 case eCreate:
04936 dwOpenMode = CREATE_ALWAYS;
04937 break;
04938 case eCreateNew:
04939 dwOpenMode = CREATE_NEW;
04940 break;
04941 case eOpen:
04942 dwOpenMode = OPEN_EXISTING;
04943 break;
04944 case eOpenAlways:
04945 dwOpenMode = OPEN_ALWAYS;
04946 break;
04947 case eTruncate:
04948 dwOpenMode = TRUNCATE_EXISTING;
04949 break;
04950 default:
04951 _TROUBLE;
04952 }
04953 switch (access_mode) {
04954 case eRead:
04955 dwAccessMode = GENERIC_READ;
04956 break;
04957 case eWrite:
04958 dwAccessMode = GENERIC_WRITE;
04959 break;
04960 case eReadWrite:
04961 dwAccessMode = GENERIC_READ | GENERIC_WRITE;
04962 break;
04963 default:
04964 _TROUBLE;
04965 };
04966 switch (share_mode) {
04967 case eShareRead:
04968 dwShareMode = FILE_SHARE_READ;
04969 break;
04970 case eShareWrite:
04971 dwShareMode = FILE_SHARE_WRITE;
04972 break;
04973 case eShare:
04974 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
04975 break;
04976 case eExclusive:
04977 dwShareMode = 0;
04978 break;
04979 default:
04980 _TROUBLE;
04981 }
04982
04983 m_Handle = CreateFile(filename.c_str(), dwAccessMode,
04984 dwShareMode, NULL, dwOpenMode,
04985 FILE_ATTRIBUTE_NORMAL, NULL);
04986
04987 #elif defined(NCBI_OS_UNIX)
04988
04989
04990 # if defined(O_BINARY)
04991 int flags = O_BINARY;
04992 # else
04993 int flags = 0;
04994 # endif
04995 mode_t mode = 0;
04996
04997 switch (open_mode) {
04998 case eCreate:
04999 flags |= (O_CREAT | O_TRUNC);
05000 break;
05001 case eCreateNew:
05002 if ( CFile(filename).Exists() ) {
05003 NCBI_THROW(CFileException, eFileIO,
05004 "Open mode is eCreateNew but file already exists: "
05005 + filename );
05006 }
05007 flags |= O_CREAT;
05008 break;
05009 case eOpen:
05010
05011 break;
05012 case eOpenAlways:
05013 if ( !CFile(filename).Exists() ) {
05014 flags |= O_CREAT;
05015 }
05016 break;
05017 case eTruncate:
05018 flags |= O_TRUNC;
05019 break;
05020 default:
05021 _TROUBLE;
05022 }
05023 switch (access_mode) {
05024 case eRead:
05025 flags |= O_RDONLY;
05026 mode |= S_IREAD;
05027 break;
05028 case eWrite:
05029 flags |= O_WRONLY;
05030 mode |= S_IWRITE;
05031 break;
05032 case eReadWrite:
05033 flags |= O_RDWR;
05034 mode |= (S_IREAD | S_IWRITE);
05035 break;
05036 default:
05037 _TROUBLE;
05038 };
05039
05040 share_mode = eShare;
05041
05042
05043 m_Handle = open(filename.c_str(), flags, mode);
05044
05045 #endif
05046
05047 if (m_Handle == kInvalidHandle) {
05048 NCBI_THROW(CFileErrnoException, eFileIO,
05049 "Cannot open file " + filename);
05050 }
05051 m_CloseHandle = true;
05052 }
05053
05054
05055 void CFileIO::Close(void)
05056 {
05057 if (m_CloseHandle) {
05058 #if defined(NCBI_OS_MSWIN)
05059 CloseHandle(m_Handle);
05060 #elif defined(NCBI_OS_UNIX)
05061 close(m_Handle);
05062 #endif
05063 }
05064 m_Handle = kInvalidHandle;
05065 m_CloseHandle = false;
05066 }
05067
05068
05069 ssize_t CFileIO::Read(void* buf, size_t count) const
05070 {
05071 #if defined(NCBI_OS_MSWIN)
05072 DWORD n = 0;
05073 if (count > ULONG_MAX) {
05074 count = ULONG_MAX;
05075 }
05076 if ( ::ReadFile(m_Handle, buf, (DWORD)count, &n, NULL) == 0 ) {
05077 return GetLastError() == ERROR_HANDLE_EOF? 0 : -1;
05078 }
05079 #elif defined(NCBI_OS_UNIX)
05080 ssize_t n = 0;
05081 while ((n = read(int(m_Handle), buf, count)) < 0) {
05082 if (errno != EINTR) {
05083 return -1;
05084 }
05085 }
05086 #endif
05087 return n;
05088 }
05089
05090
05091 ssize_t CFileIO::Write(const void* buf, size_t count) const
05092 {
05093 #if defined(NCBI_OS_MSWIN)
05094 DWORD n = 0;
05095 if (count > ULONG_MAX) {
05096 count = ULONG_MAX;
05097 }
05098 if ( WriteFile(m_Handle, buf, (DWORD)count, &n, NULL) == 0 ) {
05099 return -1;
05100 }
05101 #elif defined(NCBI_OS_UNIX)
05102 ssize_t n = write(int(m_Handle), buf, count);
05103 #endif
05104 return n;
05105 }
05106
05107
05108 void CFileIO::Flush(void) const
05109 {
05110 bool res;
05111 #if defined(NCBI_OS_MSWIN)
05112 res = (FlushFileBuffers(m_Handle) == TRUE);
05113 #elif defined(NCBI_OS_UNIX)
05114 res = (fsync(m_Handle) == 0);
05115 #endif
05116 if ( !res ) {
05117 NCBI_THROW(CFileErrnoException, eFileIO, "Cannot flush");
05118 }
05119 }
05120
05121
05122 void CFileIO::SetFileHandle(TFileHandle handle)
05123 {
05124
05125 Close();
05126
05127 m_Handle = handle;
05128 }
05129
05130
05131 ssize_t CFileIO::GetFilePos(void) const
05132 {
05133 #if defined(NCBI_OS_MSWIN)
05134 LARGE_INTEGER ofs;
05135 LARGE_INTEGER pos;
05136 ofs.QuadPart = 0;
05137 pos.QuadPart = 0;
05138 BOOL res = SetFilePointerEx(m_Handle, ofs, &pos, FILE_CURRENT);
05139 if (res) {
05140 return (ssize_t)pos.QuadPart;
05141 }
05142 #elif defined(NCBI_OS_UNIX)
05143 off_t pos = lseek(m_Handle, 0, SEEK_CUR);
05144 if (pos != -1) {
05145 return (ssize_t)pos;
05146 }
05147 #endif
05148 return -1;
05149 }
05150
05151
05152 void CFileIO::SetFilePos(off_t offset, EPositionMoveMethod move_method) const
05153 {
05154 #if defined(NCBI_OS_MSWIN)
05155 DWORD from = 0;
05156 switch (move_method) {
05157 case eBegin:
05158 from = FILE_BEGIN;
05159 break;
05160 case eCurrent:
05161 from = FILE_CURRENT;
05162 break;
05163 case eEnd:
05164 from = FILE_END;
05165 break;
05166 default:
05167 _TROUBLE;
05168 }
05169 LARGE_INTEGER ofs;
05170 ofs.QuadPart = offset;
05171 bool res = (SetFilePointerEx(m_Handle, ofs, NULL, from) == TRUE);
05172 #elif defined(NCBI_OS_UNIX)
05173 int from = 0;
05174 switch (move_method) {
05175 case eBegin:
05176 from = SEEK_SET;
05177 break;
05178 case eCurrent:
05179 from = SEEK_CUR;
05180 break;
05181 case eEnd:
05182 from = SEEK_END;
05183 break;
05184 default:
05185 _TROUBLE;
05186 }
05187 bool res = (lseek(m_Handle, offset, from) != -1);
05188 #endif
05189 if ( !res ) {
05190 NCBI_THROW(CFileErrnoException, eFileIO,
05191 "SetFilePos() failed"
05192 " (offset=" + NStr::Int8ToString(offset) +
05193 ", method=" + NStr::IntToString(move_method) + ')');
05194 }
05195 }
05196
05197
05198 void CFileIO::SetFileSize(size_t length, EPositionMoveMethod pos) const
05199 {
05200 #if defined(NCBI_OS_MSWIN)
05201 BOOL res = true;
05202
05203 LARGE_INTEGER ofs;
05204 LARGE_INTEGER saved;
05205 ofs.QuadPart = 0;
05206 saved.QuadPart = 0;
05207
05208 if (pos == eCurrent) {
05209 res = SetFilePointerEx(m_Handle, ofs, &saved, FILE_CURRENT);
05210 }
05211 if (res) {
05212
05213 ofs.QuadPart = length;
05214 res = SetFilePointerEx(m_Handle, ofs, NULL, FILE_BEGIN);
05215
05216 if (res) {
05217 res = SetEndOfFile(m_Handle);
05218 }
05219
05220 if (res) {
05221 if (pos == eBegin) {
05222
05223 ofs.QuadPart = 0;
05224 res = SetFilePointerEx(m_Handle, ofs, NULL, FILE_BEGIN);
05225 }
05226 else if (pos == eCurrent) {
05227 res = SetFilePointerEx(m_Handle, saved, NULL, FILE_BEGIN);
05228 }
05229
05230 }
05231 }
05232 #elif defined(NCBI_OS_UNIX)
05233 bool res = (ftruncate(m_Handle, (off_t)length) != -1);
05234
05235 if (res && (pos != eCurrent)) {
05236 SetFilePos(0, pos);
05237 }
05238 #endif
05239 if ( !res ) {
05240 NCBI_THROW(CFileErrnoException, eFileIO,
05241 "SetFileSize() failed"
05242 " (length=" + NStr::UInt8ToString(length) + ')');
05243 }
05244 }
05245
05246
05247
05248
05249
05250
05251
05252
05253 CFileReader::CFileReader(const string& filename, EShareMode share_mode)
05254 {
05255 m_File.Open(filename, eOpen, eRead, share_mode);
05256 }
05257
05258
05259 CFileReader::CFileReader(TFileHandle handle)
05260 {
05261 m_File.SetFileHandle(handle);
05262 return;
05263 }
05264
05265
05266 IReader* CFileReader::New(const string& filename, EShareMode share_mode)
05267 {
05268 if ( filename == "-" ) {
05269 #if defined(NCBI_OS_MSWIN)
05270 TFileHandle handle = GetStdHandle(STD_INPUT_HANDLE);
05271 #elif defined(NCBI_OS_UNIX)
05272 TFileHandle handle = 0;
05273 #endif
05274 return new CFileReader(handle);
05275 }
05276 else {
05277 return new CFileReader(filename, share_mode);
05278 }
05279 }
05280
05281
05282 ERW_Result CFileReader::Read(void* buf, size_t count, size_t* bytes_read)
05283 {
05284 if ( bytes_read ) {
05285 *bytes_read = 0;
05286 }
05287 if ( !count ) {
05288 return eRW_Success;
05289 }
05290 ssize_t n = m_File.Read(buf, count);
05291 if ( n == -1 ) {
05292 return eRW_Error;
05293 }
05294 if ( bytes_read ) {
05295 *bytes_read = n;
05296 }
05297 return n? eRW_Success : eRW_Eof;
05298 }
05299
05300
05301 ERW_Result CFileReader::PendingCount(size_t* )
05302 {
05303 return eRW_NotImplemented;
05304 }
05305
05306
05307
05308
05309
05310
05311
05312 CFileWriter::CFileWriter(const string& filename,
05313 EOpenMode open_mode,
05314 EShareMode share_mode)
05315 {
05316 m_File.Open(filename, open_mode, eWrite, share_mode);
05317 }
05318
05319
05320 CFileWriter::CFileWriter(TFileHandle handle)
05321 {
05322 m_File.SetFileHandle(handle);
05323 return;
05324 }
05325
05326
05327 IWriter* CFileWriter::New(const string& filename,
05328 EOpenMode open_mode,
05329 EShareMode share_mode)
05330 {
05331 return new CFileWriter(filename, open_mode, share_mode);
05332 }
05333
05334
05335 ERW_Result CFileWriter::Write(const void* buf,
05336 size_t count, size_t* bytes_written)
05337 {
05338 if ( bytes_written ) {
05339 *bytes_written = 0;
05340 }
05341 if ( !count ) {
05342 return eRW_Success;
05343 }
05344 ssize_t n = m_File.Write(buf, count);
05345 if ( n == -1 ) {
05346 return eRW_Error;
05347 }
05348 if ( bytes_written ) {
05349 *bytes_written = n;
05350 }
05351 return n? eRW_Success : eRW_Error;
05352 }
05353
05354
05355 ERW_Result CFileWriter::Flush(void)
05356 {
05357 return eRW_Success;
05358 }
05359
05360
05361
05362
05363
05364
05365
05366 CFileReaderWriter::CFileReaderWriter(const string& filename,
05367 EOpenMode open_mode,
05368 EShareMode share_mode)
05369 {
05370 m_File.Open(filename, open_mode, eReadWrite, share_mode);
05371 }
05372
05373
05374 CFileReaderWriter::CFileReaderWriter(TFileHandle handle)
05375 {
05376 m_File.SetFileHandle(handle);
05377 return;
05378 }
05379
05380
05381 IReaderWriter* CFileReaderWriter::New(const string& filename,
05382 EOpenMode open_mode,
05383 EShareMode share_mode)
05384 {
05385 return new CFileReaderWriter(filename, open_mode, share_mode);
05386 }
05387
05388
05389 ERW_Result CFileReaderWriter::Read(void* buf,
05390 size_t count, size_t* bytes_read)
05391 {
05392 if ( bytes_read ) {
05393 *bytes_read = 0;
05394 }
05395 if ( !count ) {
05396 return eRW_Success;
05397 }
05398 ssize_t n = m_File.Read(buf, count);
05399 if ( n == -1 ) {
05400 return eRW_Error;
05401 }
05402 if ( bytes_read ) {
05403 *bytes_read = n;
05404 }
05405 return n? eRW_Success : eRW_Eof;
05406 }
05407
05408
05409 ERW_Result CFileReaderWriter::PendingCount(size_t* )
05410 {
05411 return eRW_NotImplemented;
05412 }
05413
05414
05415 ERW_Result CFileReaderWriter::Write(const void* buf,
05416 size_t count, size_t* bytes_written)
05417 {
05418 if ( bytes_written ) {
05419 *bytes_written = 0;
05420 }
05421 if ( !count ) {
05422 return eRW_Success;
05423 }
05424 ssize_t n = m_File.Write(buf, count);
05425 if ( n == -1 ) {
05426 return eRW_Error;
05427 }
05428 if ( bytes_written ) {
05429 *bytes_written = n;
05430 }
05431 return n? eRW_Success : eRW_Error;
05432 }
05433
05434
05435 ERW_Result CFileReaderWriter::Flush(void)
05436 {
05437 try {
05438 m_File.Flush();
05439 } catch (CFileException&) {
05440 return eRW_Error;
05441 }
05442 return eRW_Success;
05443 }
05444
05445
05446
05447
05448
05449
05450
05451
05452
05453 #define F_CLEAN_REDUNDANT(group) \
05454 if (F_ISSET(m_Flags, (group))) \
05455 m_Flags &= ~unsigned((group) & ~unsigned(fDefault))
05456
05457
05458 struct SLock {
05459 SLock(void) {};
05460 SLock(off_t off, size_t len) {
05461 Reset(off, len);
05462 }
05463 #if defined(NCBI_OS_MSWIN)
05464 void Reset(off_t off, size_t len)
05465 {
05466
05467
05468 if (len) {
05469 length_lo = (DWORD)(len & 0xFFFFFFFF);
05470 length_hi = (DWORD)((Int8(len) >> 32) & 0xFFFFFFFF);
05471 } else {
05472 length_lo = 0;
05473 length_hi = 0xFFFFFFFF;
05474 }
05475 };
05476 DWORD offset_lo;
05477 DWORD offset_hi;
05478 DWORD length_lo;
05479 DWORD length_hi;
05480 #elif defined(NCBI_OS_UNIX)
05481 void Reset(off_t off, size_t len) {
05482 offset = off;
05483 length = len;
05484 }
05485 off_t offset;
05486 size_t length;
05487 #endif
05488 };
05489
05490
05491 CFileLock::CFileLock(const string& filename, TFlags flags, EType type,
05492 off_t offset, size_t length)
05493 : m_Handle(kInvalidHandle), m_CloseHandle(false), m_Flags(flags),
05494 m_IsLocked(false), m_Lock(0)
05495 {
05496 x_Init(filename.c_str(), type, offset, length);
05497 }
05498
05499
05500 CFileLock::CFileLock(const char* filename, TFlags flags, EType type,
05501 off_t offset, size_t length)
05502 : m_Handle(kInvalidHandle), m_CloseHandle(false), m_Flags(flags),
05503 m_IsLocked(false), m_Lock(0)
05504 {
05505 x_Init(filename, type, offset, length);
05506 }
05507
05508
05509 CFileLock::CFileLock(TFileHandle handle, TFlags flags, EType type,
05510 off_t offset, size_t length)
05511 : m_Handle(handle), m_CloseHandle(false), m_Flags(flags),
05512 m_IsLocked(false), m_Lock(0)
05513 {
05514 x_Init(0, type, offset, length);
05515 }
05516
05517
05518 void CFileLock::x_Init(const char* filename, EType type, off_t offset, size_t length)
05519 {
05520
05521 F_CLEAN_REDUNDANT(fLockNow | fLockLater);
05522 F_CLEAN_REDUNDANT(fAutoUnlock | fNoAutoUnlock);
05523
05524
05525 if (filename) {
05526 #if defined(NCBI_OS_MSWIN)
05527 m_Handle = CreateFile(filename, GENERIC_READ,
05528 FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
05529 #elif defined(NCBI_OS_UNIX)
05530 m_Handle = open(filename, O_RDWR);
05531 #endif
05532 }
05533 if (m_Handle == kInvalidHandle) {
05534 NCBI_THROW(CFileErrnoException, eFileLock,
05535 "Cannot open file " + string(filename));
05536 }
05537 if (filename) {
05538 m_CloseHandle = true;
05539 }
05540 m_Lock = new SLock;
05541
05542
05543 if (F_ISSET(m_Flags, fLockNow)) {
05544 Lock(type, offset, length);
05545 }
05546 }
05547
05548
05549 CFileLock::~CFileLock()
05550 {
05551 if (m_Handle == kInvalidHandle) {
05552 return;
05553 }
05554 try {
05555
05556 if (F_ISSET(m_Flags, fAutoUnlock)) {
05557 Unlock();
05558 }
05559 } catch(CException& e) {
05560 NCBI_REPORT_EXCEPTION_X(4,
05561 "CFileLock::~CFileLock():"
05562 " Cannot unlock", e);
05563 }
05564
05565 if (m_CloseHandle) {
05566 #if defined(NCBI_OS_MSWIN)
05567 CloseHandle(m_Handle);
05568 #elif defined(NCBI_OS_UNIX)
05569 close(m_Handle);
05570 #endif
05571 }
05572 return;
05573 }
05574
05575
05576 void CFileLock::Lock(EType type, off_t offset, size_t length)
05577 {
05578
05579 if (m_IsLocked) {
05580 Unlock();
05581 }
05582
05583 m_Lock->Reset(offset, length);
05584
05585 #if defined(NCBI_OS_MSWIN)
05586 DWORD flags = LOCKFILE_FAIL_IMMEDIATELY;
05587 if (type == eExclusive) {
05588 flags |= LOCKFILE_EXCLUSIVE_LOCK;
05589 }
05590 OVERLAPPED overlapped;
05591 overlapped.hEvent = 0;
05592 overlapped.Offset = m_Lock->offset_lo;
05593 overlapped.OffsetHigh = m_Lock->offset_hi;
05594 bool res = LockFileEx(m_Handle, flags, 0,
05595 m_Lock->length_lo, m_Lock->length_hi,
05596 &overlapped) == TRUE;
05597 #elif defined(NCBI_OS_UNIX)
05598 struct flock fl;
05599 fl.l_type = (type == eShared) ? F_RDLCK : F_WRLCK;
05600 fl.l_whence = SEEK_SET;
05601 fl.l_start = m_Lock->offset;
05602 fl.l_len = m_Lock->length;
05603 fl.l_pid = getpid();
05604
05605 int err;
05606 do {
05607 err = fcntl(m_Handle, F_SETLK, &fl);
05608 } while (err && (errno == EINTR));
05609 bool res = (err == 0);
05610
05611 #endif
05612 if (!res) {
05613 NCBI_THROW(CFileErrnoException, eFileLock, "CFileLock::Lock():"
05614 " Cannot lock");
05615 }
05616 m_IsLocked = true;
05617 return;
05618 }
05619
05620
05621 void CFileLock::Unlock(void)
05622 {
05623 if (!m_IsLocked) {
05624 return;
05625 }
05626 #if defined(NCBI_OS_MSWIN)
05627 OVERLAPPED overlapped;
05628 overlapped.hEvent = 0;
05629 overlapped.Offset = m_Lock->offset_lo;
05630 overlapped.OffsetHigh = m_Lock->offset_hi;
05631 bool res = UnlockFileEx(m_Handle, 0,
05632 m_Lock->length_lo, m_Lock->length_hi,
05633 &overlapped) == TRUE;
05634
05635 #elif defined(NCBI_OS_UNIX)
05636 struct flock fl;
05637 fl.l_type = F_UNLCK;
05638 fl.l_whence = SEEK_SET;
05639 fl.l_start = m_Lock->offset;
05640 fl.l_len = m_Lock->length;
05641 fl.l_pid = getpid();
05642
05643 int err;
05644 do {
05645 err = fcntl(m_Handle, F_SETLK, &fl);
05646 } while (err && (errno == EINTR));
05647 bool res = (err == 0);
05648
05649 #endif
05650 if (!res) {
05651 NCBI_THROW(CFileErrnoException, eFileLock, "CFileLock::Unlock():"
05652 " Cannot unlock");
05653 }
05654 m_IsLocked = false;
05655 return;
05656 }
05657
05658
05659
05660
05661
05662
05663
05664 void CFileAPI::SetLogging(ESwitch on_off_default)
05665 {
05666 NCBI_PARAM_TYPE(NCBI, FileAPILogging)::SetDefault(
05667 on_off_default != eDefault ?
05668 on_off_default != eOff : DEFAULT_LOGGING_VALUE);
05669 }
05670
05671 void CFileAPI::SetDeleteReadOnlyFiles(ESwitch on_off_default)
05672 {
05673 NCBI_PARAM_TYPE(NCBI, DeleteReadOnlyFiles)::SetDefault(
05674 on_off_default == eOn);
05675 }
05676
05677 END_NCBI_SCOPE
05678
05679