Updated on behalf of schmidt9

This commit is contained in:
Howard Hinnant
2017-11-26 14:41:40 -05:00
parent 543315b700
commit 15a63ec819

View File

@@ -28,7 +28,7 @@
#include <Foundation/Foundation.h> #include <Foundation/Foundation.h>
#include <iostream> #include <fstream>
#include <zlib.h> #include <zlib.h>
#include <sys/stat.h> #include <sys/stat.h>
@@ -56,17 +56,17 @@ struct TarInfo
{ {
char objType; char objType;
std::string objName; std::string objName;
int64_t realContentSize; // writable size without padding zeroes size_t realContentSize; // writable size without padding zeroes
int64_t blocksContentSize; // adjusted size to 512 bytes blocks size_t blocksContentSize; // adjusted size to 512 bytes blocks
bool success; bool success;
}; };
std::string convertCFStringRefPathToCStringPath(CFStringRef ref); std::string convertCFStringRefPathToCStringPath(CFStringRef ref);
bool extractTzdata(CFURLRef homeUrl, CFURLRef archiveUrl, std::string destPath); bool extractTzdata(CFURLRef homeUrl, CFURLRef archiveUrl, std::string destPath);
TarInfo getTarObjectInfo(CFReadStreamRef readStream, int64_t location); TarInfo getTarObjectInfo(std::ifstream &readStream);
std::string getTarObject(CFReadStreamRef readStream, int64_t size); std::string getTarObject(std::ifstream &readStream, int64_t size);
bool writeFile(CFURLRef tzdataUrl, std::string fileName, std::string data, bool writeFile(const std::string &tzdataPath, const std::string &fileName,
int64_t realContentSize); const std::string &data, size_t realContentSize);
std::string std::string
get_current_timezone() get_current_timezone()
@@ -143,77 +143,49 @@ convertCFStringRefPathToCStringPath(CFStringRef ref)
return result; return result;
} }
bool extractTzdata(CFURLRef homeUrl, CFURLRef archiveUrl, std::string destPath) bool
extractTzdata(CFURLRef homeUrl, CFURLRef archiveUrl, std::string destPath)
{ {
const char *TAR_TMP_PATH = "/tmp.tar"; std::string TAR_TMP_PATH = "/tmp.tar";
CFStringRef homeStringRef = CFURLCopyPath(homeUrl);
auto homePath = convertCFStringRefPathToCStringPath(homeStringRef);
CFRelease(homeStringRef);
CFStringRef archiveStringRef = CFURLCopyPath(archiveUrl);
auto archivePath = convertCFStringRefPathToCStringPath(archiveStringRef);
CFRelease(archiveStringRef);
// create Library path // create Library path
CFStringRef libraryStr = CFStringCreateWithCString(NULL, INTERNAL_DIR, auto libraryPath = homePath + INTERNAL_DIR;
CFStringGetSystemEncoding());
CFURLRef libraryUrl = CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault,
homeUrl, libraryStr,
false);
// create tzdata path // create tzdata path
CFStringRef tzdataPathRef = CFStringCreateWithCString(NULL, std::string(std::string(INTERNAL_DIR) + "/" + TZDATA_DIR).c_str(), auto tzdataPath = libraryPath + "/" + TZDATA_DIR;
CFStringGetSystemEncoding());
CFURLRef tzdataPathUrl = CFURLCreateCopyAppendingPathComponent(NULL, homeUrl,
tzdataPathRef, false);
// create src archive path // -- replace %20 with " "
CFStringRef archivePath = CFURLCopyPath(archiveUrl); const std::string search = "%20";
gzFile tarFile = gzopen(convertCFStringRefPathToCStringPath(archivePath).c_str(), "rb"); const std::string replacement = " ";
size_t pos = 0;
while ((pos = archivePath.find(search, pos)) != std::string::npos) {
archivePath.replace(pos, search.length(), replacement);
pos += replacement.length();
}
gzFile tarFile = gzopen(archivePath.c_str(), "rb");
// create tar unpacking path // create tar unpacking path
CFStringRef tarName = CFStringCreateWithCString(NULL, TAR_TMP_PATH, auto tarPath = libraryPath + TAR_TMP_PATH;
CFStringGetSystemEncoding());
CFURLRef tarUrl = CFURLCreateCopyAppendingPathComponent(NULL, libraryUrl, tarName,
false);
CFStringRef tarPathRef = CFURLCopyPath(tarUrl);
auto tarPath = convertCFStringRefPathToCStringPath(tarPathRef);
// create tzdata directory // create tzdata directory
mkdir(destPath.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); mkdir(destPath.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
// create stream
CFWriteStreamRef writeStream = CFWriteStreamCreateWithFile(NULL, tarUrl);
bool success = true;
CFRelease(libraryStr);
CFRelease(libraryUrl);
CFRelease(tzdataPathRef);
CFRelease(archivePath);
CFRelease(tarName);
CFRelease(tarPathRef);
if (!CFWriteStreamOpen(writeStream))
{
CFStreamError err = CFWriteStreamGetError(writeStream);
if (err.domain == kCFStreamErrorDomainPOSIX)
{
printf("kCFStreamErrorDomainPOSIX %i\n", err.error);
}
else if(err.domain == kCFStreamErrorDomainMacOSStatus)
{
printf("kCFStreamErrorDomainMacOSStatus %i\n", err.error);
}
success = false;
}
if (!success)
{
CFRelease(tarUrl);
CFRelease(tzdataPathUrl);
CFRelease(writeStream);
return false;
}
// ======= extract tar ======== // ======= extract tar ========
std::ofstream os(tarPath.c_str(), std::ofstream::out | std::ofstream::app);
unsigned int bufferLength = 1024 * 256; // 256Kb unsigned int bufferLength = 1024 * 256; // 256Kb
void *buffer = malloc(bufferLength); unsigned char *buffer = (unsigned char *)malloc(bufferLength);
bool success = true;
while (true) while (true)
{ {
@@ -221,22 +193,15 @@ bool extractTzdata(CFURLRef homeUrl, CFURLRef archiveUrl, std::string destPath)
if (readBytes > 0) if (readBytes > 0)
{ {
CFIndex writtenBytes = CFWriteStreamWrite(writeStream, (unsigned char*)buffer, os.write((char *) &buffer[0], readBytes);
readBytes);
if (writtenBytes < 0)
{
CFStreamError err = CFWriteStreamGetError(writeStream);
printf("write stream error %i\n", err.error);
success = false;
break;
} }
} else
else if (readBytes == 0) if (readBytes == 0)
{ {
break; break;
} }
else if (readBytes == -1) else
if (readBytes == -1)
{ {
printf("decompression failed\n"); printf("decompression failed\n");
success = false; success = false;
@@ -250,15 +215,13 @@ bool extractTzdata(CFURLRef homeUrl, CFURLRef archiveUrl, std::string destPath)
} }
} }
CFWriteStreamClose(writeStream); os.close();
CFRelease(writeStream);
free(buffer); free(buffer);
gzclose(tarFile); gzclose(tarFile);
if (!success) if (!success)
{ {
CFRelease(tarUrl); remove(tarPath.c_str());
CFRelease(tzdataPathUrl);
return false; return false;
} }
@@ -272,43 +235,18 @@ bool extractTzdata(CFURLRef homeUrl, CFURLRef archiveUrl, std::string destPath)
if (res != 0) if (res != 0)
{ {
printf("error file size\n"); printf("error file size\n");
CFRelease(tarUrl); remove(tarPath.c_str());
CFRelease(tzdataPathUrl);
return false; return false;
} }
int64_t tarSize = stat_buf.st_size; int64_t tarSize = stat_buf.st_size;
// create read stream // create read stream
CFReadStreamRef readStream = CFReadStreamCreateWithFile(kCFAllocatorDefault, tarUrl); std::ifstream is(tarPath.c_str(), std::ifstream::in | std::ifstream::binary);
CFRelease(tarUrl);
if (!CFReadStreamOpen(readStream))
{
CFStreamError err = CFReadStreamGetError(readStream);
if (err.domain == kCFStreamErrorDomainPOSIX)
{
printf("kCFStreamErrorDomainPOSIX %i", err.error);
}
else if(err.domain == kCFStreamErrorDomainMacOSStatus)
{
printf("kCFStreamErrorDomainMacOSStatus %i", err.error);
}
success = false;
}
if (!success)
{
CFRelease(tzdataPathUrl);
CFRelease(readStream);
return false;
}
// process files // process files
while (location < tarSize) while (location < tarSize)
{ {
TarInfo info = getTarObjectInfo(readStream, location); TarInfo info = getTarObjectInfo(is);
if (!info.success || info.realContentSize == 0) if (!info.success || info.realContentSize == 0)
{ {
@@ -320,13 +258,13 @@ bool extractTzdata(CFURLRef homeUrl, CFURLRef archiveUrl, std::string destPath)
case '0': // file case '0': // file
case '\0': // case '\0': //
{ {
std::string obj = getTarObject(readStream, info.blocksContentSize); std::string obj = getTarObject(is, info.blocksContentSize);
#if TAR_DEBUG #if TAR_DEBUG
size += info.realContentSize; size += info.realContentSize;
printf("#%i %s file size %lld written total %ld from %lld\n", ++count, printf("#%i %s file size %lld written total %ld from %lld\n", ++count,
info.objName.c_str(), info.realContentSize, size, tarSize); info.objName.c_str(), info.realContentSize, size, tarSize);
#endif #endif
writeFile(tzdataPathUrl, info.objName, obj, info.realContentSize); writeFile(tzdataPath, info.objName, obj, info.realContentSize);
location += info.blocksContentSize; location += info.blocksContentSize;
break; break;
@@ -334,32 +272,21 @@ bool extractTzdata(CFURLRef homeUrl, CFURLRef archiveUrl, std::string destPath)
} }
} }
CFRelease(tzdataPathUrl); remove(tarPath.c_str());
CFReadStreamClose(readStream);
CFRelease(readStream);
return true; return true;
} }
TarInfo TarInfo
getTarObjectInfo(CFReadStreamRef readStream, int64_t location) getTarObjectInfo(std::ifstream &readStream)
{ {
int64_t length = TAR_BLOCK_SIZE; int64_t length = TAR_BLOCK_SIZE;
uint8_t buffer[length]; char buffer[length];
char type; char type;
char name[TAR_NAME_SIZE + 1]; char name[TAR_NAME_SIZE + 1];
char sizeBuf[TAR_SIZE_SIZE + 1]; char sizeBuf[TAR_SIZE_SIZE + 1];
CFIndex bytesRead;
bytesRead = CFReadStreamRead(readStream, buffer, length); readStream.read(buffer, length);
if (bytesRead < 0)
{
CFStreamError err = CFReadStreamGetError(readStream);
printf("error reading tar object info %i", err.error);
return {false};
}
memcpy(&type, &buffer[TAR_TYPE_POSITION], 1); memcpy(&type, &buffer[TAR_TYPE_POSITION], 1);
@@ -368,77 +295,38 @@ getTarObjectInfo(CFReadStreamRef readStream, int64_t location)
memset(&sizeBuf, '\0', TAR_SIZE_SIZE + 1); memset(&sizeBuf, '\0', TAR_SIZE_SIZE + 1);
memcpy(&sizeBuf, &buffer[TAR_SIZE_POSITION], TAR_SIZE_SIZE); memcpy(&sizeBuf, &buffer[TAR_SIZE_POSITION], TAR_SIZE_SIZE);
int64_t realSize = strtol(sizeBuf, NULL, 8); size_t realSize = strtol(sizeBuf, NULL, 8);
int64_t blocksSize = realSize + (TAR_BLOCK_SIZE - (realSize % TAR_BLOCK_SIZE)); size_t blocksSize = realSize + (TAR_BLOCK_SIZE - (realSize % TAR_BLOCK_SIZE));
return {type, std::string(name), realSize, blocksSize, true}; return {type, std::string(name), realSize, blocksSize, true};
} }
std::string std::string
getTarObject(CFReadStreamRef readStream, int64_t size) getTarObject(std::ifstream &readStream, int64_t size)
{ {
uint8_t buffer[size]; char buffer[size];
readStream.read(buffer, size);
CFIndex bytesRead = CFReadStreamRead(readStream, buffer, size); return std::string(buffer);
if (bytesRead < 0)
{
CFStreamError err = CFReadStreamGetError(readStream);
printf("error reading tar object info %i", err.error);
}
return std::string((char *)buffer);
} }
bool bool
writeFile(CFURLRef tzdataUrl, std::string fileName, std::string data, writeFile(const std::string &tzdataPath, const std::string &fileName, const std::string &data,
int64_t realContentSize) size_t realContentSize)
{ {
// create stream std::ofstream os(tzdataPath + "/" + fileName, std::ofstream::out | std::ofstream::binary);
CFStringRef fileNameRef = CFStringCreateWithCString(NULL, fileName.c_str(),
CFStringGetSystemEncoding());
CFURLRef url = CFURLCreateCopyAppendingPathComponent(NULL, tzdataUrl, fileNameRef,
false);
CFWriteStreamRef writeStream = CFWriteStreamCreateWithFile(NULL, url);
CFRelease(fileNameRef); if (!os) {
CFRelease(url);
// open stream
if (!CFWriteStreamOpen(writeStream))
{
CFStreamError err = CFWriteStreamGetError(writeStream);
if (err.domain == kCFStreamErrorDomainPOSIX)
{
printf("kCFStreamErrorDomainPOSIX %i\n", err.error);
}
else if(err.domain == kCFStreamErrorDomainMacOSStatus)
{
printf("kCFStreamErrorDomainMacOSStatus %i\n", err.error);
}
CFRelease(writeStream);
return false; return false;
} }
// trim empty space // trim empty space
uint8_t trimmedData[realContentSize + 1]; char trimmedData[realContentSize + 1];
memset(&trimmedData, '\0', realContentSize); memset(&trimmedData, '\0', realContentSize);
memcpy(&trimmedData, data.c_str(), realContentSize); memcpy(&trimmedData, data.c_str(), realContentSize);
// write // write
CFIndex writtenBytes = CFWriteStreamWrite(writeStream, trimmedData, realContentSize); os.write(trimmedData, realContentSize);
os.close();
if (writtenBytes < 0)
{
CFStreamError err = CFWriteStreamGetError(writeStream);
printf("write stream error %i\n", err.error);
}
CFWriteStreamClose(writeStream);
CFRelease(writeStream);
writeStream = NULL;
return true; return true;
} }