49 #ifdef _FORTIFY_SOURCE
50 # undef _FORTIFY_SOURCE
52 #define _FORTIFY_SOURCE 0
56 #if !defined(NCBI_OS_UNIX) && !defined(NCBI_OS_MSWIN)
57 # error "Class CTar can be defined on UNIX and MS-Windows platforms only!"
60 #if defined(NCBI_OS_UNIX)
61 # include "../../../corelib/ncbi_os_unix_p.hpp"
66 # include <sys/mkdev.h>
68 # ifdef HAVE_SYS_SYSMACROS_H
69 # include <sys/sysmacros.h>
71 # ifdef NCBI_OS_DARWIN
75 # define makedev makedev
77 # if !defined(major) || !defined(minor) || !defined(makedev)
78 # error "Device macros undefined in this UNIX build!"
80 #elif defined(NCBI_OS_MSWIN)
81 # include "../../../corelib/ncbi_os_mswin_p.hpp"
83 typedef unsigned int mode_t;
84 typedef unsigned int uid_t;
85 typedef unsigned int gid_t;
89 #define NCBI_USE_ERRCODE_X Util_Compress
90 #define NCBI_MODULE NCBITAR
107 ptr[--
len] = char(
'0' +
char(
val & 7));
119 size_t i = *ptr ? 0 : 1;
120 while (
i <
len && ptr[
i]) {
121 if (!
isspace((
unsigned char) ptr[
i]))
127 while (
i <
len &&
'0' <= ptr[
i] && ptr[
i] <=
'7') {
130 val |= ptr[
i++] -
'0';
132 while (
i <
len && ptr[
i]) {
133 if (!
isspace((
unsigned char) ptr[
i]))
145 ptr[--
len] = (
unsigned char)(
val & 0xFF);
178 val = *ptr++ &
'\x3F';
184 val |= (
unsigned char)(*ptr++);
253 #elif defined(S_IREAD)
258 #elif defined(S_IWRITE)
263 #elif defined(S_IEXEC)
304 #elif defined(S_IREAD)
309 #elif defined(S_IWRITE)
314 #elif defined(S_IEXEC)
319 #elif defined(S_IREAD)
331 #elif defined(S_IREAD)
342 #if defined(S_IFMT) || defined(_S_IFMT)
349 if (!(
mask & 07777)) {
357 static size_t s_Length(
const char* ptr,
size_t maxsize)
359 const char* pos = (
const char*) memchr(ptr,
'\0', maxsize);
360 return pos ? (size_t)(pos - ptr) : maxsize;
371 #define ALIGN_SIZE(size) (((size) + (BLOCK_SIZE-1)) & ~(BLOCK_SIZE-1))
372 #define OFFSET_OF(size) ( (size) & (BLOCK_SIZE-1))
373 #define BLOCK_OF(pos) ((pos) >> 9)
374 #define SIZE_OF(blk) ((blk) << 9)
377 #define BLOCK_SIZE SIZE_OF(1)
438 size_t len =
sizeof(h->
checksum) - (isgnu ? 2 : 1);
442 unsigned long checksum = 0;
443 const unsigned char* p = (
const unsigned char*) block->
buffer;
486 if (
sizeof(
int) >= 4 &&
sizeof(
m_Stat.
orig.st_rdev) >= 4) {
487 return (*((
unsigned int*) &
m_Stat.
orig.st_rdev) >> 16) & 0xFFFF;
490 return (
unsigned int)(-1);
501 if (
sizeof(
int) >= 4 &&
sizeof(
m_Stat.
orig.st_rdev) >= 4) {
502 return *((
unsigned int*) &
m_Stat.
orig.st_rdev) & 0xFFFF;
505 return (
unsigned int)(-1);
512 memset(
buf,
'-',
sizeof(
buf));
585 string user(
info.GetUserName());
589 string group(
info.GetGroupName());
593 return user +
'/' + group;
607 unsigned int major =
info.GetMajor();
608 unsigned int minor =
info.GetMinor();
616 info.GetSize() == 0) {
634 os <<
" -> " <<
info.GetLinkName();
654 if (!strerr || !*strerr
658 ::sprintf(errbuf,
"Error %d", x_errno);
659 }
else if (x_errno != -1) {
660 ::sprintf(errbuf,
"Error 0x%08X", (
unsigned int) x_errno);
662 ::strcpy (errbuf,
"Unknown error (-1)");
667 return string(
": ") + strerr;
672 const string& entryname)
689 if (!entryname.empty()) {
690 result +=
", while in '" + entryname +
'\'';
707 for (
size_t i = 0;
i <
len; ++
i) {
718 if (!
text && maxsize > 1 && !*field) {
729 return check && !retval.empty() ?
"\\0" + retval : retval;
733 #if !defined(__GNUC__) && !defined(offsetof)
734 # define offsetof(T, F) ((char*) &(((T*) 0)->F) - (char*) 0)
737 #define TAR_PRINTABLE_EX(field, text, size) \
738 "@" + s_OffsetAsString((size_t) offsetof(STarHeader, field)) + \
739 "[" NCBI_AS_STRING(field) "]:" + \
740 string(14 - sizeof(NCBI_AS_STRING(field)), ' ') + \
741 '"' + s_Printable(h->field, size, text || excpt) + '"'
743 #define TAR_PRINTABLE(field, text) \
744 TAR_PRINTABLE_EX(field, text, sizeof(h->field))
747 #define TAR_GNU_REGION "[gnu.region]: "
748 #define TAR_GNU_CONTIND "[gnu.contind]: "
751 const char* contind,
bool excpt =
false)
759 if (
memcchr(sparse,
'\0', 24)) {
760 offset = (size_t)(sparse - (
const char*) h);
768 if (ok_off & ok_len) {
802 }
while (sparse < contind);
806 offset = (size_t)(contind - (
const char*) h);
809 + (*contind ?
"\" [to-be-cont'd]" :
"\" [last]");
816 size_t size = bmap.size();
818 for (
size_t n = 0;
n <
size; ++
n) {
846 if (
ok && (ok < 0 || val > 7)) {
849 dump +=
" (base-256)";
856 if (
ok && (ok < 0 || val > 7)) {
859 dump +=
" (base-256)";
866 if (
ok && (ok < 0 || val > 7)) {
869 dump +=
" w/o map(s)!";
872 dump +=
" (base-256)";
898 const char* tname = 0;
905 if (namelen && h->
name[namelen - 1] ==
'/')
906 tname =
"legacy regular entry (dir)";
909 tname =
"legacy regular entry (file)";
916 tname =
"legacy hard link";
918 tname =
"legacy hard link - not FULLY supported";
920 tname += h->
typeflag[0] !=
'\1' ? 7 : 0;
926 tname =
"legacy symbolic link";
928 tname =
"legacy symbolic link - not FULLY supported";
930 tname += h->
typeflag[0] !=
'\2' ? 7 : 0;
936 tname =
"character device";
942 tname =
"block device";
955 tname =
"contiguous";
958 tname =
"global extended header";
965 tname =
"extended (POSIX 1003.1-2001 [PAX]) header"
966 " - not FULLY supported";
968 tname =
"extended (POSIX 1003.1-2001 [PAX] by Sun) header"
969 " - not FULLY supported";
972 tname =
"extended header";
976 tname =
"Solaris ACL";
980 tname =
"GNU extension: directory dump";
984 tname =
"Solaris extended attribute file";
989 tname =
"Inode metadata only";
994 tname =
"GNU extension: long link";
1000 tname =
"GNU extension: long name";
1006 tname =
"GNU extension: multi-volume entry";
1009 tname =
"STAR extension: multi-volume entry";
1017 tname =
"GNU extension (obsolete): long filename(s)";
1025 tname =
"GNU extension: sparse file";
1030 tname =
"STAR extension: sparse file";
1038 tname =
"Volume header";
1044 tname =
"local vendor enhancement / user-defined extension";
1046 dump += (
" [" +
string(tname ? tname :
"reserved")
1049 :
" -- NOT SUPPORTED]\n"));
1056 tname =
"legacy (V7)";
1060 tname =
"old GNU (NCBI)";
1067 tname =
"ustar (NCBI)";
1074 tname =
"posix (NCBI)";
1105 if (
ok &&
val > 7) {
1112 if (
ok &&
val > 7) {
1121 const char* realsize = h->
star.prefix + 107;
1125 +
"[star.realsize]:\""
1127 if (
ok && (ok < 0 || val > 7)) {
1130 dump +=
" (base-256)";
1143 if (
ok ||
val > 7) {
1159 if (
ok ||
val > 7) {
1168 tname = (
const char*) &h->
star +
sizeof(h->
star);
1177 if (
ok ||
val > 7) {
1193 if (
ok ||
val > 7) {
1209 h->
gnu.contind, excpt);
1210 if (
memcchr(h->
gnu.realsize,
'\0',
sizeof(h->
gnu.realsize))) {
1212 sizeof(h->
gnu.realsize));
1215 if (
ok && (ok < 0 || val > 7)) {
1219 dump +=
" (base-256)";
1222 tname = (
const char*) &h->
gnu +
sizeof(h->
gnu);
1224 tname = h->
gnu.ctime +
sizeof(h->
gnu.ctime);
1238 while (&tname[
n] < (
const char*) h +
BLOCK_SIZE) {
1240 size_t offset = (size_t)(&tname[
n] - (
const char*) h);
1245 const char* e = (
const char*) memchr(&tname[
n],
'\0',
len);
1247 len = (size_t)(e - &tname[
n]);
1261 if (ok < 0 || val > 7 || okaytime) {
1263 if (ok < 0 || val > 7) {
1267 dump +=
"] (base-256)";
1268 }
else if (okaytime) {
1287 #undef TAR_PRINTABLE
1295 ios.setstate(
state);
1308 : m_FileName(filename),
1310 m_Stream(*m_FileStream),
1311 m_ZeroBlockCount(0),
1312 m_BufferSize(
SIZE_OF(blocking_factor)),
1330 m_ZeroBlockCount(0),
1331 m_BufferSize(
SIZE_OF(blocking_factor)),
1363 #define TAR_THROW(who, errcode, message) \
1364 NCBI_THROW(CTarException, errcode, \
1365 s_PositionAsString(who->m_FileName, who->m_StreamPos, \
1366 who->m_BufferSize, \
1367 who->m_Current.GetName()) + (message))
1369 #define TAR_THROW_EX(who, errcode, message, hdr, fmt) \
1370 TAR_THROW(who, errcode, \
1371 who->m_Flags & fDumpEntryHeaders \
1372 ? string(message) + ":\n" + s_DumpHeader(hdr, fmt, true) \
1375 #define TAR_POST(subcode, severity, message) \
1376 ERR_POST_X(subcode, (severity) << \
1377 s_PositionAsString(m_FileName, m_StreamPos, m_BufferSize,\
1378 m_Current.GetName()) + (message))
1385 if (pagesize < 4096 || (pagesize & (pagesize - 1))) {
1388 size_t pagemask = pagesize - 1;
1438 int x_errno = errno;
1442 "Archive flush failed" +
s_OSReason(x_errno));
1445 "Archive flush failed" +
s_OSReason(x_errno));
1458 if (::truncate(filename.c_str(), (off_t) filesize) != 0)
1461 #ifdef NCBI_OS_MSWIN
1463 HANDLE handle = ::CreateFile(x_filename.c_str(), GENERIC_WRITE,
1464 0,
NULL, OPEN_EXISTING,
1465 FILE_ATTRIBUTE_NORMAL,
NULL);
1467 LARGE_INTEGER x_filesize;
1468 x_filesize.QuadPart = filesize;
1469 if (!::SetFilePointerEx(handle, x_filesize,
NULL, FILE_BEGIN)
1470 || !::SetEndOfFile(handle)) {
1471 x_error = (
int) ::GetLastError();
1473 bool closed = ::CloseHandle(handle) ?
true :
false;
1474 if (!x_error && !closed) {
1475 x_error = (
int) ::GetLastError();
1478 x_error = (
int) ::GetLastError();
1490 int x_errno = errno;
1492 "Cannot close archive" +
s_OSReason(x_errno));
1520 }
else if (action !=
eAppend) {
1528 "Pending changes may be discarded"
1529 " upon reopen of in-stream archive");
1537 "Archive I/O stream is in bad state");
1546 #ifdef NCBI_OS_MSWIN
1548 HANDLE handle = (
HANDLE) _get_osfhandle(_fileno(stdin));
1549 if (GetFileType(handle) != FILE_TYPE_DISK) {
1598 int x_errno = errno;
1600 "Cannot open archive" +
s_OSReason(x_errno));
1609 "Archive file is in bad state");
1661 _ASSERT(temp && temp->size() < 2);
1662 if (temp->size() < 1) {
1683 IOS_BASE::iostate iostate =
m_Stream.rdstate();
1685 #ifdef NCBI_COMPILER_MIPSPRO
1692 xread = is->gcount();
1704 # ifdef NCBI_COMPILER_WORKSHOP
1720 + (xread ?
")" :
"): EOF"));
1728 nread += (size_t) xread;
1759 if (!nwrite ||
m_Bad) {
1767 if (avail > nwrite) {
1770 size_t advance = avail;
1771 if (src && src != (
const char*)(-1L)) {
1781 size_t nwritten = 0;
1784 streamsize xwritten;
1785 IOS_BASE::iostate iostate =
m_Stream.rdstate();
1806 if (xwritten <= 0) {
1809 if (src != (
const char*)(-1L)) {
1811 "Archive write failed" +
s_OSReason(x_errno));
1814 "Archive write failed" +
s_OSReason(x_errno));
1817 nwritten += (size_t) xwritten;
1853 const char* p = (
const char*) memchr(
str,
'.',
len);
1856 }
else if (fraq == (
string*)(-1L)) {
1866 if (*p ==
'.' && ++p !=
str +
len) {
1867 len -= (size_t)(p -
str);
1869 for (
size_t n = 0;
n <
len; ++
n) {
1870 if (!
isdigit((
unsigned char) p[
n])) {
1874 if (assign && fraq) {
1875 fraq->assign(p,
len);
1887 for (
size_t i = 0;
i <
len; ++
i) {
1888 unsigned char c = (
unsigned char)
str[
i];
1908 size_t len = fraq.size();
1921 result = (long)((temp + 5) / 10);
1930 Uint8 major = 0, minor = 0,
size = 0, sparse = 0, uid = 0, gid = 0;
1931 Uint8 mtime = 0, atime = 0, ctime = 0,
dummy = 0;
1932 string mtime_fraq, atime_fraq, ctime_fraq;
1933 string path, linkpath, name, uname, gname;
1934 string* nodot = (
string*)(-1L);
1935 const struct SPAXParseTable {
1941 {
"mtime", &mtime, &mtime_fraq,
fPAXMtime },
1942 {
"atime", &atime, &atime_fraq,
fPAXAtime },
1943 {
"ctime", &ctime, &ctime_fraq,
fPAXCtime },
1947 {
"uid", &uid, nodot,
fPAXUid },
1948 {
"gid", &gid, nodot,
fPAXGid },
1951 {
"linkpath", 0, &linkpath,
fPAXNone },
1957 {
"GNU.sparse.realsize", &sparse, nodot,
fPAXSparse },
1958 {
"GNU.sparse.major", &major, nodot,
fPAXSparse },
1959 {
"GNU.sparse.minor", &minor, nodot,
fPAXSparse },
1961 {
"GNU.sparse.name", 0, &name,
fPAXNone },
1963 {
"SCHILY.realsize", &sparse, nodot,
fPAXSparse }
1965 const char* s = data.c_str();
1967 size_t l = data.size();
1976 if (!(e = (
char*) memchr(s,
'\n', l))) {
1980 if (!
isdigit((
unsigned char)(*s)) || !(
len = strtoul(s, &k, 10))
1981 || errno || s +
len - 1 != e || (*k !=
' ' && *k !=
'\t')
1982 || !(v = (
char*) memchr(k,
'=', (
size_t)(e - k)))
1983 || !(klen = (
size_t)(v++ - ++k))
1984 || memchr(k,
' ', klen) || memchr(k,
'\t', klen)
1985 || !(vlen = (
size_t)(e - v))) {
1987 "Skipping malformed PAX data");
1991 for (
size_t n = 0;
n <
sizeof(parser) /
sizeof(parser[0]); ++
n) {
1992 if (strlen(parser[
n].
key) == klen
1993 && memcmp(parser[
n].
key, k, klen) == 0) {
1994 if (!parser[
n].
val) {
1995 if (parser[
n].
str) {
1996 parser[
n].str->assign(v, vlen);
1999 parser[
n].
str, parser[
n].bit)) {
2001 "Ignoring bad numeric \""
2003 +
"\" in PAX value \""
2006 parsed |= parser[
n].bit;
2014 "Ignoring unrecognized PAX value \""
2028 "Ignoring PAX GNU sparse file size "
2030 +
" when real size "
2032 +
" is also present");
2033 }
else if (!
dummy && major == 1 && minor == 0) {
2035 if (!name.empty()) {
2036 if (!path.empty()) {
2038 "Replacing PAX file name \"" + path
2039 +
"\" with GNU sparse file name \"" + name
2047 }
else if (!sparse) {
2074 const string& entryname,
const STarHeader* h,
2085 || !*h->
gnu.contind)
2093 const string& entryname,
const STarHeader* h,
2094 const char* contind,
Uint8 datasize)
2100 +
"GNU sparse file map header (cont'd):\n"
2110 const string& entryname,
2111 const vector< pair<Uint8, Uint8> >& bmap)
2116 +
"PAX GNU/1.0 sparse file map data:\n"
2123 size_t zeroblock_count,
bool eot =
false)
2130 : (eot ?
"End-Of-Tape" :
"End-Of-File")) +
'\n');
2137 return '0' <= c && c <=
'7' ?
true :
false;
2145 size_t nread =
sizeof(block->
buffer);
2152 "Unexpected EOF in archive");
2158 if (memcmp(h->
magic,
"ustar", 6) == 0) {
2159 if ((h->
star.prefix[
sizeof(h->
star.prefix) - 1] ==
'\0'
2167 }
else if (memcmp(h->
magic,
"ustar ", 8) == 0) {
2170 }
else if (memcmp(h->
magic,
"\0\0\0\0\0", 6) == 0) {
2175 "Unrecognized header format", h, fmt);
2185 for (
size_t i = 0;
i <
sizeof(block->
buffer); ++
i) {
2196 "Bad checksum", h, fmt);
2205 unsigned int usum = 0;
2206 const char* p = block->
buffer;
2207 for (
size_t i = 0;
i <
sizeof(block->
buffer); ++
i) {
2209 usum += (
unsigned char)(*p);
2213 for (
size_t j = 0; j <
sizeof(h->
checksum); ++j) {
2215 usum -= (
unsigned char)(*p) -
' ';
2220 if (checksum != ssum && (
unsigned int) checksum != usum) {
2221 string message =
"Header checksum failed";
2223 message +=
", expected ";
2224 if (usum != (
unsigned int) ssum) {
2225 message +=
"either ";
2231 if (usum != (
unsigned int) ssum) {
2233 if ((
unsigned int) ssum > 7) {
2255 ? 107 :
sizeof(h->
star.prefix));
2272 "Bad entry mode", h, fmt);
2280 "Bad user ID", h, fmt);
2288 "Bad group ID", h, fmt);
2296 "Bad entry size", h, fmt);
2302 " This run-time may not support large TAR entries"
2303 " (have you built it --with-lfs?)"
2310 "Bad modification time", h, fmt);
2332 "Bad last access time", h, fmt);
2342 "Bad creation time", h, fmt);
2355 if (namelen && h->
name[namelen - 1] ==
'/') {
2378 "Non-zero hard-link size ("
2380 +
") is ignored (non-PAX)");
2392 "Bad device minor number", h, fmt);
2394 usum = (
unsigned int)
val;
2397 "Bad device major number", h, fmt);
2404 (
unsigned int)((
val << 16) | usum);
2419 " *** Contiguous TAR entries processed as regular files"
2445 "Repetitious PAX headers,"
2446 " archive may be corrupt");
2466 ? h->
gnu.realsize : h->
star.prefix + 107;
2468 ?
sizeof(h->
gnu.realsize) : 12;
2480 const char* contind = h->
gnu.contind;
2486 "Unexpected EOF in GNU sparse file map"
2487 " extended header");
2490 contind = block->
buffer + (24 * 21);
2510 string(
"Unexpected EOF in ") +
2520 data.append(xbuf, nread);
2526 data.resize(strlen(data.c_str()));
2538 :
"Long link name: \"")
2545 ? data.size() && data[data.size() - 1] ==
'\n'
2552 if (!
val || !data.size()) {
2554 "Skipping " +
string(
val ?
"empty" :
"zero-sized")
2555 +
" extended header data");
2603 memcpy(block->
buffer +
sizeof(*block) - 4,
"NCBI", 4);
2619 +
"' too long in entry '" + name +
'\'');
2627 +
"' too long in entry '" + name +
'\'');
2644 "Cannot store file mode");
2655 "Cannot store user ID");
2665 "Cannot store group ID");
2676 "Cannot store file size");
2691 "Cannot store modification time");
2694 bool device =
false;
2709 "Cannot store major number");
2714 "Cannot store minor number");
2727 "Do not know how to archive entry '" + name
2729 +
": Internal error");
2736 size_t len = usr.size();
2738 memcpy(h->
uname, usr.c_str(),
len);
2743 memcpy(h->
gname, grp.c_str(),
len);
2754 strcpy(h->
magic,
"ustar");
2759 memcpy(h->
magic,
"ustar ", 8);
2770 "Cannot store checksum");
2786 const char* src = name.c_str();
2787 size_t len = name.size();
2791 memcpy(dst, src,
len);
2795 bool packed =
false;
2796 if (!link &&
len <=
sizeof(h->
prefix) + 1 +
sizeof(h->
name)) {
2802 while (
i > 0 && src[--
i] !=
'/');
2803 if (
i &&
len -
i <=
sizeof(h->
name) + 1) {
2805 memcpy(h->
name, src +
i + 1,
len -
i - 1);
2814 memcpy(dst, src,
size);
2825 strcpy(h->
name,
"././@LongLink");
2836 memcpy(h->
magic,
"ustar ", 8);
2869 "In-stream update may result in gapped tar archive");
2896 "Archive backspace error in record reget");
2907 #if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION <= 1101
2912 "Archive backspace error in record reset");
2921 const list<CTempString>& elems,
2926 if (elems.empty()) {
2927 return mask->Match(name, acase);
2929 if (elems.size() == 1) {
2930 return mask->Match(elems.front(), acase);
2934 temp = temp.empty() ?
string(*e) :
string(*e) +
'/' + temp;
2935 if (
mask->Match(temp, acase)) {
2967 "Interspersing zero block ignored");
2991 status !=
eEOF ?
true :
false);
2995 "Orphaned extended information ignored");
2999 "Unexpected EOF in archive");
3003 ?
"Incomplete EOT in archive"
3004 :
"Missing EOT in archive");
3024 "Unused extended header replaced");
3036 || !xinfo.
GetName().empty()) {
3038 "Unused long name \"" + xinfo.
GetName()
3069 if (!xinfo.
GetName().empty()) {
3128 "Ignoring sparse data for non-plain file");
3146 "Empty entry name in archive");
3163 list<CTempString> elems;
3203 #ifdef NCBI_OS_MSWIN
3204 if (
isalpha((
unsigned char) path[0]) && path[1] ==
':') {
3207 }
else if ((path[0] ==
'/' || path[0] ==
'\\') &&
3208 (path[1] ==
'/' || path[1] ==
'\\')) {
3210 path.erase(0, path.find_first_of(
"/\\", 2));
3213 if (path[0] ==
'/' || path[0] ==
'\\') {
3217 path.assign(1,
'.');
3231 #ifdef NCBI_OS_MSWIN
3244 if (retval.size() > base_dir.size()) {
3245 retval.erase(0, base_dir.size());
3247 retval.assign(1,
'.');
3252 #ifdef NCBI_OS_MSWIN
3253 if (
isalpha((
unsigned char) retval[0]) && retval[1] ==
':') {
3256 }
else if (retval[0] ==
'/' && retval[1] ==
'/') {
3258 pos = retval.find(
'/', 2);
3265 while (pos < retval.size() && retval[pos] ==
'/') {
3269 retval.erase(0, pos);
3271 pos = retval.size();
3272 while (pos > 0 && retval[pos - 1] ==
'/') {
3275 if (pos < retval.size()) {
3337 unique_ptr<CDirEntry> dst
3344 unique_ptr<CDirEntry> src;
3351 dst->DereferenceLink();
3359 bool extracted =
false;
3391 if (dst_type != src->GetType()) {
3407 "Failed to backup '" + dst->GetPath() +
'\''
3413 if ( dst->Exists()) {
3417 int x_errno = errno ?: EEXIST;
3419 int x_errno = errno;
3426 "Cannot extract '" + dst->GetPath() +
'\''
3436 umask(u & ~(S_IRUSR | S_IWUSR | S_IXUSR));
3450 }
else if (!pending->Restore()) {
3451 int x_errno = errno;
3453 "Cannot restore '" + dst->GetPath()
3460 unique_ptr<CDirEntry> dst
3478 #ifndef NCBI_COMPILER_WORKSHOP
3486 if (
m_Stream.rdbuf()->PUBSEEKOFF(fskip, IOS_BASE::cur)
3494 "Cannot fast skip in file archive,"
3495 " reverting to slow skip");
3506 "Archive skip failed (EOF)");
3522 unique_ptr<CDirEntry> src_ptr;
3523 bool extracted =
true;
3538 int x_errno = errno;
3540 "Cannot create directory '" + dir.
GetPath() +
'\''
3550 src = src_ptr.get();
3568 int x_errno = errno;
3570 "Cannot hard-link '" + src->
GetPath()
3571 +
"' and '" + dst->
GetPath() +
'\''
3578 "Cannot hard-link '" + src->
GetPath()
3579 +
"' and '" + dst->
GetPath() +
"' via copy");
3599 const CDir* dir =
dynamic_cast<const CDir*
>(dst);
3603 "Cannot create directory '" + dst->
GetPath() +
'\''
3605 ?
string(
": Internal error")
3619 string error =
"Cannot create symlink '" + dst->
GetPath()
3622 ?
string(
": Internal error")
3624 if (!symlink || x_errno != ENOTSUP
3650 int x_errno = ENOTSUP;
3651 string reason =
": Feature not supported by host OS";
3655 =
"Cannot create FIFO '" + dst->
GetPath() +
'\'' + reason;
3681 int x_errno = ENOTSUP;
3682 string reason =
": Feature not supported by host OS";
3687 ?
"character" :
"block")
3688 +
" device '" + dst->
GetPath() +
'\'' + reason;
3729 int x_errno = errno;
3731 "Cannot create file '" + dst->
GetPath() +
'\''
3739 bool okay = ofs.good();
3740 if (okay)
while (
size) {
3746 "Unexpected EOF in archive");
3751 okay = ofs.write(data, (streamsize) nread) ?
true :
false;
3763 if (!okay || !ofs.good()) {
3764 int x_errno = errno;
3766 "Cannot " +
string(okay ?
"close" :
"write")
3777 for (
n = 0;
n < nread; ++
n) {
3778 if (!
isprint((
unsigned char) data[
n])) {
3782 line.append(data,
n);
3784 if (data[
n] ==
'\n') {
3798 if (
size >= nread) {
3816 #ifdef NCBI_OS_MSWIN
3817 # define NCBI_FILE_WO "wb"
3819 # define NCBI_FILE_WO "w"
3832 "Unexpected EOF in archive");
3835 if (
size >= nread) {
3847 "Cannot expand sparse file '" + dst->
GetPath()
3848 +
"': Region count is "
3849 +
string(num.empty() ?
"missing" :
"invalid")
3850 +
" (\"" + num +
"\")");
3855 vector< pair<Uint8, Uint8> > bmap(
n);
3859 for (
int k = 0; k < 2; ++k) {
3865 "Cannot expand sparse file '" + dst->
GetPath()
3867 +
string(k == 0 ?
"offset" :
"region size")
3869 +
string(num.empty() ?
"missing" :
"invalid")
3870 +
" (\"" + num +
"\")");
3874 bmap[
i] = pair<Uint8, Uint8>(
val[0],
val[1]);
3885 int x_errno = errno;
3887 "Cannot create file '" + dst->
GetPath() +
'\''
3899 Uint8 top = bmap[
i].first + bmap[
i].second;
3903 if (!bmap[
i].second) {
3918 "Cannot read archive data for sparse file '"
3919 + dst->
GetPath() +
"', region #"
3923 :
string(
": End-of-data")));
3932 size_t xread = nread;
3933 if (xread > bmap[
i].second -
done) {
3934 xread = (size_t)(bmap[
i].second -
done);
3936 if (::fwrite(data, 1, xread,
fp.get()) != xread) {
3937 if (!(x_error = errno)) {
3945 }
while (
done < bmap[
i].second);
3952 bool closed = ::fclose(
fp.release()) == 0 ?
true :
false;
3953 if (!x_error && !closed) {
3962 #ifdef NCBI_OS_MSWIN
3964 DWORD rv = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
3965 FORMAT_MESSAGE_FROM_SYSTEM |
3966 FORMAT_MESSAGE_MAX_WIDTH_MASK |
3967 FORMAT_MESSAGE_IGNORE_INSERTS,
3969 MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
3976 ::LocalFree((HLOCAL)
str);
3978 if (reason.empty()) {
3989 "Cannot write sparse file '" + dst->
GetPath() +
'\''+ reason);
4003 unique_ptr<CDirEntry> path_ptr;
4008 path = path_ptr.get();
4015 CTime modification(
info.GetModificationTime());
4016 CTime last_access(
info.GetLastAccessTime());
4021 if (!path->
SetTime(&modification, &last_access, &creation)) {
4024 "Cannot restore date/time of '" + path->
GetPath() +
'\''
4038 if (!
info.GetUserName().empty() || !
info.GetGroupName().empty()) {
4039 unsigned int uid, gid;
4042 || (!
info.GetGroupName().empty()
4045 || (uid ==
info.GetUserId() && gid ==
info.GetGroupId())) {
4073 if (
mode & (S_ISUID | S_ISGID)) {
4074 mode &= ~(S_ISUID | S_ISGID);
4086 s_TarToMode(perm, &user, &group, &other, &special_bits);
4088 info.GetMode(&user, &group, &other, &special_bits);
4095 "Cannot " +
string(perm ?
"change" :
"restore")
4096 +
" mode bits of '" + path->
GetPath() +
'\''
4106 #ifdef NCBI_OS_MSWIN
4120 unique_ptr<CDir::TEntries> dir;
4124 unsigned int uid = 0, gid = 0;
4136 if (!entry.
Stat(&st, follow_links)) {
4137 int x_errno = errno;
4139 "Cannot get status of '" + path +
'\''+
s_OSReason(x_errno));
4147 "Empty entry name not allowed");
4150 list<CTempString> elems;
4153 if (find(elems.begin(), elems.end(),
"..") != elems.end()) {
4155 "Name '" + temp +
"' embeds parent directory (\"..\")");
4175 "Empty link name not allowed");
4180 follow_links, &uid, &gid);
4189 #ifdef NCBI_OS_MSWIN
4191 st.
orig.st_uid = (uid_t) uid;
4192 st.
orig.st_gid = (gid_t) gid;
4208 if (!temp.empty()) {
4231 <= e->GetModificationCTime()) {
4271 "Cannot list directory '" + path +
'\'' +
s_OSReason(x_errno);
4285 unique_ptr<TEntries> add =
x_Append((*e)->GetPath(), toc);
4295 "Skipping non-archiveable "
4297 +
" '" + path +
'\'');
4304 "Unable to archive '" + path +
'\'');
4313 "Skipping unsupported source '" + path
4334 temp.resize(temp.size() - 1);
4338 "Empty entry name not allowed");
4341 list<CTempString> elems;
4344 if (find(elems.begin(), elems.end(),
"..") != elems.end()) {
4346 "Name '" + temp +
"' embeds parent directory (\"..\")");
4358 "Bad input file stream");
4376 # ifdef HAVE_GETUMASK
4394 #ifdef NCBI_OS_MSWIN
4399 unsigned int uid = 0, gid = 0;
4432 avail = (size_t)
size;
4443 xread = is.gcount();
4452 ifstream* ifs =
dynamic_cast<ifstream*
>(&is);
4455 +
string(ifs ?
"file" :
"stream")
4459 avail = (size_t) xread;
4484 int x_errno = errno;
4503 if (idx < 0 ||
sizeof(
m_Mask)/
sizeof(
m_Mask[0]) <= (
size_t) idx){
4524 size_t blocking_factor,
4525 const string& base_dir)
4538 size_t namelen = name.size() + 1;
4575 if (
m_Bad || !count) {
4592 count = (size_t) left;
4612 buf = (
char*)
buf + read;
4630 "Read error while streaming");
4650 if (!left &&
m_Eof) {
4661 if (sb_avail != -1) {
4662 avail = (size_t) sb_avail;
4665 *count = avail > left ? (size_t) left : avail;
4673 unique_ptr<CTar> tar(
new CTar(is, 1));