1
// **********************************************************************
3
// Copyright (c) 2003-2009 ZeroC, Inc. All rights reserved.
5
// This copy of Ice is licensed to you under the terms described in the
6
// ICE_LICENSE file included in this distribution.
8
// **********************************************************************
11
// We need to include io.h first to get the proper signature for
18
#include <IceUtil/DisableWarnings.h>
19
#include <IceUtil/IceUtil.h>
20
#include <IceUtil/StringUtil.h>
21
#define ICE_PATCH2_API_EXPORTS
22
#include <IcePatch2/Util.h>
23
#include <openssl/sha.h>
39
const char* IcePatch2::checksumFile = "IcePatch2.sum";
40
const char* IcePatch2::logFile = "IcePatch2.log";
43
// Solaris 9 and before doesn't have scandir() or alphasort().
48
ice_scandir(const char* dir, struct dirent*** namelist,
49
int (*select)(const struct dirent*),
50
int (*compar)(const void*, const void*))
57
if((d = opendir(dir)) == 0)
63
while((entry = readdir(d)) != 0)
65
if(select == 0 || (select != 0 && (*select)(entry)))
67
*namelist = (struct dirent**)realloc((void*)(*namelist), (size_t)((i + 1) * sizeof(struct dirent*)));
74
entrysize = sizeof(struct dirent) - sizeof(entry->d_name) + strlen(entry->d_name) + 1;
75
(*namelist)[i] = (struct dirent*)malloc(entrysize);
76
if((*namelist)[i] == 0)
81
memcpy((*namelist)[i], entry, entrysize);
98
qsort((void *)(*namelist), (size_t)i, sizeof(struct dirent *), compar);
104
extern "C" static int
105
ice_alphasort(const void* v1, const void* v2)
107
const struct dirent **a = (const struct dirent **)v1;
108
const struct dirent **b = (const struct dirent **)v2;
109
return(strcmp((*a)->d_name, (*b)->d_name));
116
using namespace IcePatch2;
119
IcePatch2::writeFileInfo(FILE* fp, const FileInfo& info)
121
int rc = fprintf(fp, "%s\t%s\t%d\t%d\n",
122
IceUtilInternal::escapeString(info.path, "").c_str(),
123
bytesToString(info.checksum).c_str(),
125
static_cast<int>(info.executable));
130
IcePatch2::readFileInfo(FILE* fp, FileInfo& info)
134
while(fgets(buf, static_cast<int>(sizeof(buf)), fp) != 0)
138
size_t len = strlen(buf);
139
if(buf[len - 1] == '\n')
149
istringstream is(data);
152
getline(is, s, '\t');
153
IceUtilInternal::unescapeString(s, 0, s.size(), info.path);
155
getline(is, s, '\t');
156
info.checksum = stringToBytes(s);
159
is >> info.executable;
165
IcePatch2::bytesToString(const ByteSeq& bytes)
170
for(ByteSeq::const_iterator p = bytes.begin(); p != bytes.end(); ++p)
172
s << setw(2) << setfill('0') << hex << static_cast<int>(*p);
178
static const char* toHex = "0123456789abcdef";
181
s.resize(bytes.size() * 2);
183
for(unsigned int i = 0; i < bytes.size(); ++i)
185
s[i * 2] = toHex[(bytes[i] >> 4) & 0xf];
186
s[i * 2 + 1] = toHex[bytes[i] & 0xf];
193
IcePatch2::stringToBytes(const string& str)
196
bytes.reserve((str.size() + 1) / 2);
198
for(unsigned int i = 0; i + 1 < str.size(); i += 2)
201
istringstream is(str.substr(i, 2));
208
for(int j = 0; j < 2; ++j)
212
if(c >= '0' && c <= '9')
216
else if(c >= 'a' && c <= 'f')
218
byte |= 10 + c - 'a';
220
else if(c >= 'A' && c <= 'F')
222
byte |= 10 + c - 'A';
231
bytes.push_back(static_cast<Byte>(byte));
238
IcePatch2::simplify(const string& path)
240
string result = path;
242
string::size_type pos;
246
if(result.find("\\\\") == 0)
251
for(; pos < result.size(); ++pos)
253
if(result[pos] == '\\')
261
while((pos = result.find("//", pos)) != string::npos)
263
result.erase(pos, 1);
267
while((pos = result.find("/./", pos)) != string::npos)
269
result.erase(pos, 2);
272
while(result.substr(0, 4) == "/../")
277
if(result.substr(0, 2) == "./")
283
(result.size() == 4 && isalpha(static_cast<unsigned char>(result[0])) && result[1] == ':' &&
284
result[2] == '/' && result[3] == '.'))
286
return result.substr(0, result.size() - 1);
289
if(result.size() >= 2 && result.substr(result.size() - 2, 2) == "/.")
291
result.erase(result.size() - 2, 2);
294
if(result == "/" || (result.size() == 3 && isalpha(static_cast<unsigned char>(result[0])) && result[1] == ':' &&
300
if(result.size() >= 1 && result[result.size() - 1] == '/')
302
result.erase(result.size() - 1);
314
IcePatch2::isRoot(const string& pa)
316
string path = simplify(pa);
318
return path == "/" || path.size() == 3 && isalpha(static_cast<unsigned char>(path[0])) && path[1] == ':' &&
326
IcePatch2::getSuffix(const string& pa)
328
const string path = simplify(pa);
330
string::size_type dotPos = path.rfind('.');
331
string::size_type slashPos = path.rfind('/');
333
if(dotPos == string::npos || (slashPos != string::npos && slashPos > dotPos))
338
return path.substr(dotPos + 1);
342
IcePatch2::getWithoutSuffix(const string& pa)
344
const string path = simplify(pa);
346
string::size_type dotPos = path.rfind('.');
347
string::size_type slashPos = path.rfind('/');
349
if(dotPos == string::npos || (slashPos != string::npos && slashPos > dotPos))
354
return path.substr(0, dotPos);
358
IcePatch2::ignoreSuffix(const string& path)
360
string suffix = getSuffix(path);
361
return suffix == "md5" // For legacy IcePatch.
362
|| suffix == "tot" // For legacy IcePatch.
364
|| suffix == "bz2temp";
368
IcePatch2::getBasename(const string& pa)
370
const string path = simplify(pa);
372
string::size_type pos = path.rfind('/');
373
if(pos == string::npos)
379
return path.substr(pos + 1);
384
IcePatch2::getDirname(const string& pa)
386
const string path = simplify(pa);
388
string::size_type pos = path.rfind('/');
389
if(pos == string::npos)
395
return path.substr(0, pos);
400
IcePatch2::rename(const string& fromPa, const string& toPa)
403
const string fromPath = simplify(fromPa);
404
const string toPath = simplify(toPa);
406
OS::remove(toPath); // We ignore errors, as the file we are renaming to might not exist.
408
if(OS::rename(fromPath ,toPath) == -1)
410
throw "cannot rename `" + fromPath + "' to `" + toPath + "': " + IceUtilInternal::lastErrorToString();
415
IcePatch2::remove(const string& pa)
417
const string path = simplify(pa);
420
if(OS::osstat(path, &buf) == -1)
422
throw "cannot stat `" + path + "':\n" + IceUtilInternal::lastErrorToString();
425
if(S_ISDIR(buf.st_mode))
427
if(OS::rmdir(path) == -1)
433
throw "cannot remove directory `" + path + "':\n" + IceUtilInternal::lastErrorToString();
438
if(OS::remove(path) == -1)
440
throw "cannot remove file `" + path + "':\n" + IceUtilInternal::lastErrorToString();
446
IcePatch2::removeRecursive(const string& pa)
448
const string path = simplify(pa);
451
if(OS::osstat(path, &buf) == -1)
453
throw "cannot stat `" + path + "':\n" + IceUtilInternal::lastErrorToString();
456
if(S_ISDIR(buf.st_mode))
458
StringSeq paths = readDirectory(path);
459
for(StringSeq::const_iterator p = paths.begin(); p != paths.end(); ++p)
461
removeRecursive(path + '/' + *p);
466
if(OS::rmdir(path) == -1)
468
throw "cannot remove directory `" + path + "':\n" + IceUtilInternal::lastErrorToString();
474
if(OS::remove(path) == -1)
476
throw "cannot remove file `" + path + "':\n" + IceUtilInternal::lastErrorToString();
482
IcePatch2::readDirectory(const string& pa)
484
const string path = simplify(pa);
489
const wstring fs = IceUtil::stringToWstring(simplify(path + "/*"));
491
# ifdef __BCPLUSPLUS__
493
int h = _wfindfirst(fs.c_str(), &data, FA_DIREC);
496
if(_doserrno == ENMFILE)
500
throw "cannot read directory `" + path + "':\n" + IceUtilInternal::lastErrorToString();
506
string name = IceUtil::wstringToString(data.ff_name);
507
assert(!name.empty());
509
if(name != ".." && name != ".")
511
result.push_back(name);
514
if(_wfindnext(&data) == -1)
521
string ex = "cannot read directory `" + path + "':\n" + IceUtilInternal::lastErrorToString();
529
struct _wfinddata_t data;
531
# if defined(_MSC_VER) && (_MSC_VER < 1300)
532
long h = _wfindfirst(fs.c_str(), &data);
534
intptr_t h = _wfindfirst(fs.c_str(), &data);
538
throw "cannot read directory `" + path + "':\n" + IceUtilInternal::lastErrorToString();
543
string name = IceUtil::wstringToString(data.name);
544
assert(!name.empty());
546
if(name != ".." && name != ".")
548
result.push_back(name);
551
if(_wfindnext(h, &data) == -1)
558
string ex = "cannot read directory `" + path + "':\n" + IceUtilInternal::lastErrorToString();
567
sort(result.begin(), result.end());
572
struct dirent **namelist;
574
int n = ice_scandir(path.c_str(), &namelist, 0, ice_alphasort);
576
int n = scandir(path.c_str(), &namelist, 0, alphasort);
580
throw "cannot read directory `" + path + "':\n" + IceUtilInternal::lastErrorToString();
584
result.reserve(n - 2);
586
for(int i = 0; i < n; ++i)
588
string name = namelist[i]->d_name;
589
assert(!name.empty());
593
if(name != ".." && name != ".")
595
result.push_back(name);
606
IcePatch2::createDirectory(const string& pa)
608
const string path = simplify(pa);
610
if(OS::mkdir(path, 0777) == -1)
614
throw "cannot create directory `" + path + "':\n" + IceUtilInternal::lastErrorToString();
620
IcePatch2::createDirectoryRecursive(const string& pa)
622
const string path = simplify(pa);
624
string dir = getDirname(path);
627
createDirectoryRecursive(dir);
630
if(!isRoot(path + "/"))
633
if(OS::osstat(path, &buf) != -1)
635
if(S_ISDIR(buf.st_mode))
641
if(OS::mkdir(path, 0777) == -1)
645
throw "cannot create directory `" + path + "':\n" + IceUtilInternal::lastErrorToString();
652
IcePatch2::compressBytesToFile(const string& pa, const ByteSeq& bytes, Int pos)
654
const string path = simplify(pa);
656
FILE* stdioFile = OS::fopen(path, "wb");
659
throw "cannot open `" + path + "' for writing:\n" + IceUtilInternal::lastErrorToString();
663
BZFILE* bzFile = BZ2_bzWriteOpen(&bzError, stdioFile, 5, 0, 0);
666
string ex = "BZ2_bzWriteOpen failed";
667
if(bzError == BZ_IO_ERROR)
669
ex += string(": ") + IceUtilInternal::lastErrorToString();
675
BZ2_bzWrite(&bzError, bzFile, const_cast<Byte*>(&bytes[pos]), static_cast<int>(bytes.size() - pos));
678
string ex = "BZ2_bzWrite failed";
679
if(bzError == BZ_IO_ERROR)
681
ex += string(": ") + IceUtilInternal::lastErrorToString();
683
BZ2_bzWriteClose(&bzError, bzFile, 0, 0, 0);
688
BZ2_bzWriteClose(&bzError, bzFile, 0, 0, 0);
691
string ex = "BZ2_bzWriteClose failed";
692
if(bzError == BZ_IO_ERROR)
694
ex += string(": ") + IceUtilInternal::lastErrorToString();
704
IcePatch2::decompressFile(const string& pa)
706
const string path = simplify(pa);
707
const string pathBZ2 = path + ".bz2";
710
FILE* stdioFileBZ2 = 0;
716
fp = OS::fopen(path, "wb");
719
throw "cannot open `" + path + "' for writing:\n" + IceUtilInternal::lastErrorToString();
722
stdioFileBZ2 = OS::fopen(pathBZ2, "rb");
725
throw "cannot open `" + pathBZ2 + "' for reading:\n" + IceUtilInternal::lastErrorToString();
728
#ifdef __BCPLUSPLUS__
730
// The BZ2_bzReadOpen/BZ2_bzRead/BZ2_bzReadClose functions fail with BCC
733
if(OS::osstat(pathBZ2, &buf) == -1)
735
throw "cannot stat `" + pathBZ2 + "':\n" + IceUtilInternal::lastErrorToString();
738
ByteSeq compressedBytes(buf.st_size);
739
if(fread(&compressedBytes[0], buf.st_size, 1, stdioFileBZ2) != 1)
741
throw "cannot read from `" + pathBZ2 + "':\n" + IceUtilInternal::lastErrorToString();
744
ByteSeq uncompressedBytes;
745
unsigned int uncompressedLen = buf.st_size * 2;
748
uncompressedBytes.resize(uncompressedLen);
749
int bzError = BZ2_bzBuffToBuffDecompress(&uncompressedBytes[0], &uncompressedLen, &compressedBytes[0],
755
else if(bzError == BZ_OUTBUFF_FULL)
757
uncompressedLen *= 2;
762
string ex = "BZ2_bzBuffToBuffDecompress failed";
763
if(bzError == BZ_IO_ERROR)
765
ex += string(": ") + IceUtilInternal::lastErrorToString();
771
if(fwrite(&uncompressedBytes[0], uncompressedLen, 1, fp) != 1)
773
throw "cannot write to `" + path + "':\n" + IceUtilInternal::lastErrorToString();
776
bzFile = BZ2_bzReadOpen(&bzError, stdioFileBZ2, 0, 0, 0, 0);
779
string ex = "BZ2_bzReadOpen failed";
780
if(bzError == BZ_IO_ERROR)
782
ex += string(": ") + IceUtilInternal::lastErrorToString();
787
const Int numBZ2 = 64 * 1024;
788
Byte bytesBZ2[numBZ2];
790
while(bzError != BZ_STREAM_END)
792
int sz = BZ2_bzRead(&bzError, bzFile, bytesBZ2, numBZ2);
793
if(bzError != BZ_OK && bzError != BZ_STREAM_END)
795
string ex = "BZ2_bzRead failed";
796
if(bzError == BZ_IO_ERROR)
798
ex += string(": ") + IceUtilInternal::lastErrorToString();
805
long pos = ftell(stdioFileBZ2);
808
throw "cannot get read position for `" + pathBZ2 + "':\n" + IceUtilInternal::lastErrorToString();
811
if(fwrite(bytesBZ2, sz, 1, fp) != 1)
813
throw "cannot write to `" + path + "':\n" + IceUtilInternal::lastErrorToString();
818
BZ2_bzReadClose(&bzError, bzFile);
822
string ex = "BZ2_bzReadClose failed";
823
if(bzError == BZ_IO_ERROR)
825
ex += string(": ") + IceUtilInternal::lastErrorToString();
835
BZ2_bzReadClose(&bzError, bzFile);
837
if(stdioFileBZ2 != 0)
839
fclose(stdioFileBZ2);
848
fclose(stdioFileBZ2);
853
IcePatch2::setFileFlags(const string& pa, const FileInfo& info)
855
#ifndef _WIN32 // Windows doesn't support the executable flag
856
const string path = simplify(pa);
858
if(OS::osstat(path, &buf) == -1)
860
throw "cannot stat `" + path + "':\n" + IceUtilInternal::lastErrorToString();
862
chmod(path.c_str(), info.executable ? buf.st_mode | S_IXUSR : buf.st_mode & ~S_IXUSR);
867
getFileInfoSeqInt(const string& basePath, const string& relPath, int compress, GetFileInfoSeqCB* cb,
868
FileInfoSeq& infoSeq)
870
if(relPath == checksumFile || relPath == logFile)
875
const string path = simplify(basePath + '/' + relPath);
877
if(ignoreSuffix(path))
879
const string pathWithoutSuffix = getWithoutSuffix(path);
881
if(ignoreSuffix(pathWithoutSuffix))
883
if(cb && !cb->remove(relPath))
888
remove(path); // Removing file with suffix for another file that already has a suffix.
893
if(OS::osstat(getWithoutSuffix(path), &buf) == -1)
897
if(cb && !cb->remove(relPath))
902
remove(path); // Removing orphaned file.
906
throw "cannot stat `" + path + "':\n" + IceUtilInternal::lastErrorToString();
909
else if(buf.st_size == 0)
911
if(cb && !cb->remove(relPath))
916
remove(path); // Removing file with suffix for empty file.
924
if(OS::osstat(path, &buf) == -1)
926
throw "cannot stat `" + path + "':\n" + IceUtilInternal::lastErrorToString();
929
if(S_ISDIR(buf.st_mode))
934
info.executable = false;
936
ByteSeq bytes(relPath.size());
937
copy(relPath.begin(), relPath.end(), bytes.begin());
939
ByteSeq bytesSHA(20);
942
SHA1(reinterpret_cast<unsigned char*>(&bytes[0]), bytes.size(),
943
reinterpret_cast<unsigned char*>(&bytesSHA[0]));
947
fill(bytesSHA.begin(), bytesSHA.end(), 0);
949
info.checksum.swap(bytesSHA);
951
infoSeq.push_back(info);
953
StringSeq content = readDirectory(path);
954
for(StringSeq::const_iterator p = content.begin(); p != content.end() ; ++p)
956
if(!getFileInfoSeqInt(basePath, simplify(relPath + '/' + *p), compress, cb, infoSeq))
962
else if(S_ISREG(buf.st_mode))
968
info.executable = false; // Windows doesn't support the executable flag
970
info.executable = buf.st_mode & S_IXUSR;
973
OS::structstat bufBZ2;
974
const string pathBZ2 = path + ".bz2";
975
bool doCompress = false;
976
if(buf.st_size != 0 && compress > 0)
979
// compress == 0: Never compress.
980
// compress == 1: Compress if necessary.
981
// compress >= 2: Always compress.
983
if(compress >= 2 || OS::osstat(pathBZ2, &bufBZ2) == -1 || buf.st_mtime >= bufBZ2.st_mtime)
985
if(cb && !cb->compress(relPath))
994
info.size = static_cast<Int>(bufBZ2.st_size);
998
if(cb && !cb->checksum(relPath))
1003
ByteSeq bytesSHA(20);
1005
if(relPath.size() + buf.st_size == 0)
1007
fill(bytesSHA.begin(), bytesSHA.end(), 0);
1013
if(relPath.size() != 0)
1015
SHA1_Update(&ctx, reinterpret_cast<const void*>(relPath.c_str()), relPath.size());
1018
if(buf.st_size != 0)
1020
#ifdef __BCPLUSPLUS__
1022
// The BZ2_bzWriteOpen/BZ2_bzWrite/BZ2_bzWriteClose functions fail with BCC
1026
int fd = OS::open(path.c_str(), O_BINARY|O_RDONLY);
1029
throw "cannot open `" + path + "' for reading:\n" + IceUtilInternal::lastErrorToString();
1032
ByteSeq uncompressedBytes(buf.st_size);
1034
if(read(fd, &uncompressedBytes[0], buf.st_size) == -1)
1037
throw "cannot read from `" + path + "':\n" + IceUtilInternal::lastErrorToString();
1040
unsigned int compressedLen = buf.st_size * 1.01 + 600;
1041
ByteSeq compressedBytes(compressedLen);
1043
int bzError = BZ2_bzBuffToBuffCompress(&compressedBytes[0], &compressedLen,
1044
&uncompressedBytes[0], buf.st_size, 5, 0, 0);
1045
if(bzError != BZ_OK)
1047
string ex = "BZ2_bzBuffToBuffCompress failed";
1048
if(bzError == BZ_IO_ERROR)
1050
ex += string(": ") + IceUtilInternal::lastErrorToString();
1057
const string pathBZ2Temp = path + ".bz2temp";
1058
FILE* stdioFile = OS::fopen(pathBZ2Temp, "wb");
1059
if(fwrite(&compressedBytes[0], compressedLen, 1, stdioFile) != 1)
1062
throw "cannot write to `" + pathBZ2Temp + "':\n" + IceUtilInternal::lastErrorToString();
1066
rename(pathBZ2Temp, pathBZ2);
1068
info.size = compressedLen;
1072
int fd = OS::open(path.c_str(), O_BINARY|O_RDONLY);
1075
throw "cannot open `" + path + "' for reading:\n" + IceUtilInternal::lastErrorToString();
1078
#ifndef __BCPLUSPLUS__
1079
const string pathBZ2Temp = path + ".bz2temp";
1080
FILE* stdioFile = 0;
1085
stdioFile = OS::fopen(simplify(pathBZ2Temp), "wb");
1088
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
1093
throw "cannot open `" + pathBZ2Temp + "' for writing:\n" + IceUtilInternal::lastErrorToString();
1096
bzFile = BZ2_bzWriteOpen(&bzError, stdioFile, 5, 0, 0);
1097
if(bzError != BZ_OK)
1099
string ex = "BZ2_bzWriteOpen failed";
1100
if(bzError == BZ_IO_ERROR)
1102
ex += string(": ") + IceUtilInternal::lastErrorToString();
1105
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
1115
unsigned int bytesLeft = static_cast<unsigned int>(buf.st_size);
1116
while(bytesLeft > 0)
1118
ByteSeq bytes(min(bytesLeft, 1024u*1024));
1120
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
1121
_read(fd, &bytes[0], static_cast<unsigned int>(bytes.size()))
1123
read(fd, &bytes[0], static_cast<unsigned int>(bytes.size()))
1127
#ifndef __BCPLUSPLUS__
1134
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
1139
throw "cannot read from `" + path + "':\n" + IceUtilInternal::lastErrorToString();
1141
bytesLeft -= static_cast<unsigned int>(bytes.size());
1143
#ifndef __BCPLUSPLUS__
1146
BZ2_bzWrite(&bzError, bzFile, const_cast<Byte*>(&bytes[0]), static_cast<int>(bytes.size()));
1147
if(bzError != BZ_OK)
1149
string ex = "BZ2_bzWrite failed";
1150
if(bzError == BZ_IO_ERROR)
1152
ex += string(": ") + IceUtilInternal::lastErrorToString();
1154
BZ2_bzWriteClose(&bzError, bzFile, 0, 0, 0);
1156
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
1166
SHA1_Update(&ctx, reinterpret_cast<const void*>(&bytes[0]), bytes.size());
1169
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
1175
#ifndef __BCPLUSPLUS__
1178
BZ2_bzWriteClose(&bzError, bzFile, 0, 0, 0);
1179
if(bzError != BZ_OK)
1181
string ex = "BZ2_bzWriteClose failed";
1182
if(bzError == BZ_IO_ERROR)
1184
ex += string(": ") + IceUtilInternal::lastErrorToString();
1192
rename(pathBZ2Temp, pathBZ2);
1194
if(OS::osstat(pathBZ2, &bufBZ2) == -1)
1196
throw "cannot stat `" + pathBZ2 + "':\n" + IceUtilInternal::lastErrorToString();
1199
info.size = static_cast<Int>(bufBZ2.st_size);
1204
SHA1_Final(reinterpret_cast<unsigned char*>(&bytesSHA[0]), &ctx);
1207
info.checksum.swap(bytesSHA);
1209
infoSeq.push_back(info);
1217
IcePatch2::getFileInfoSeq(const string& basePath, int compress, GetFileInfoSeqCB* cb,
1218
FileInfoSeq& infoSeq)
1220
return getFileInfoSeqSubDir(basePath, ".", compress, cb, infoSeq);
1224
IcePatch2::getFileInfoSeqSubDir(const string& basePa, const string& relPa, int compress, GetFileInfoSeqCB* cb,
1225
FileInfoSeq& infoSeq)
1227
const string basePath = simplify(basePa);
1228
const string relPath = simplify(relPa);
1230
if(!getFileInfoSeqInt(basePath, relPath, compress, cb, infoSeq))
1235
sort(infoSeq.begin(), infoSeq.end(), FileInfoLess());
1236
infoSeq.erase(unique(infoSeq.begin(), infoSeq.end(), FileInfoEqual()), infoSeq.end());
1242
IcePatch2::saveFileInfoSeq(const string& pa, const FileInfoSeq& infoSeq)
1245
const string path = simplify(pa + '/' + checksumFile);
1247
FILE* fp = OS::fopen(path, "w");
1250
throw "cannot open `" + path + "' for writing:\n" + IceUtilInternal::lastErrorToString();
1254
for(FileInfoSeq::const_iterator p = infoSeq.begin(); p != infoSeq.end(); ++p)
1256
if(!writeFileInfo(fp, *p))
1258
throw "error writing `" + path + "':\n" + IceUtilInternal::lastErrorToString();
1271
const string pathLog = simplify(pa + '/' + logFile);
1284
IcePatch2::loadFileInfoSeq(const string& pa, FileInfoSeq& infoSeq)
1287
const string path = simplify(pa + '/' + checksumFile);
1289
FILE* fp = OS::fopen(path, "r");
1292
throw "cannot open `" + path + "' for reading:\n" + IceUtilInternal::lastErrorToString();
1298
if(readFileInfo(fp, info))
1300
infoSeq.push_back(info);
1309
sort(infoSeq.begin(), infoSeq.end(), FileInfoLess());
1310
infoSeq.erase(unique(infoSeq.begin(), infoSeq.end(), FileInfoEqual()), infoSeq.end());
1314
const string pathLog = simplify(pa + '/' + logFile);
1316
FILE* fp = OS::fopen(pathLog, "r");
1331
if(!readFileInfo(fp, info))
1338
remove.push_back(info);
1342
update.push_back(info);
1347
sort(remove.begin(), remove.end(), FileInfoLess());
1348
remove.erase(unique(remove.begin(), remove.end(), FileInfoEqual()), remove.end());
1350
sort(update.begin(), update.end(), FileInfoLess());
1351
update.erase(unique(update.begin(), update.end(), FileInfoEqual()), update.end());
1353
FileInfoSeq newInfoSeq;
1354
newInfoSeq.reserve(infoSeq.size());
1356
set_difference(infoSeq.begin(),
1360
back_inserter(newInfoSeq),
1363
infoSeq.swap(newInfoSeq);
1366
newInfoSeq.reserve(infoSeq.size());
1368
set_union(infoSeq.begin(),
1372
back_inserter(newInfoSeq),
1375
infoSeq.swap(newInfoSeq);
1377
saveFileInfoSeq(pa, infoSeq);
1383
IcePatch2::getFileTree0(const FileInfoSeq& infoSeq, FileTree0& tree0)
1385
tree0.nodes.resize(256);
1386
tree0.checksum.resize(20);
1388
ByteSeq allChecksums0;
1389
allChecksums0.resize(256 * 20);
1390
ByteSeq::iterator c0 = allChecksums0.begin();
1392
for(int i = 0; i < 256; ++i, c0 += 20)
1394
FileTree1& tree1 = tree0.nodes[i];
1396
tree1.files.clear();
1397
tree1.checksum.resize(20);
1399
FileInfoSeq::const_iterator p;
1401
for(p = infoSeq.begin(); p != infoSeq.end(); ++p)
1403
if(i == static_cast<int>(p->checksum[0]))
1405
tree1.files.push_back(*p);
1409
ByteSeq allChecksums1;
1410
allChecksums1.resize(tree1.files.size() * 21); // 20 bytes for the checksum + 1 byte for the flag
1411
ByteSeq::iterator c1 = allChecksums1.begin();
1413
for(p = tree1.files.begin(); p != tree1.files.end(); ++p, c1 += 21)
1415
copy(p->checksum.begin(), p->checksum.end(), c1);
1416
*(c1 + 20) = p->executable;
1419
if(!allChecksums1.empty())
1421
SHA1(reinterpret_cast<unsigned char*>(&allChecksums1[0]), allChecksums1.size(),
1422
reinterpret_cast<unsigned char*>(&tree1.checksum[0]));
1426
fill(tree1.checksum.begin(), tree1.checksum.end(), 0);
1429
copy(tree1.checksum.begin(), tree1.checksum.end(), c0);
1432
if(!allChecksums0.empty())
1434
SHA1(reinterpret_cast<unsigned char*>(&allChecksums0[0]), allChecksums0.size(),
1435
reinterpret_cast<unsigned char*>(&tree0.checksum[0]));
1439
fill(tree0.checksum.begin(), tree0.checksum.end(), 0);