667 lines
14 KiB
C
667 lines
14 KiB
C
|
/*
|
||
|
* unmunge.c -- Program to convert a munged file to original form
|
||
|
*
|
||
|
* Copyright (C) 1997 Pretty Good Privacy, Inc.
|
||
|
*
|
||
|
* Designed by Colin Plumb, Mark H. Weaver, and Philip R. Zimmermann
|
||
|
* Written by Mark H. Weaver
|
||
|
*
|
||
|
* $Id: unmunge.c,v 1.13 1997/11/13 23:27:08 mhw Exp $
|
||
|
*/
|
||
|
|
||
|
#include <sys/stat.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <unistd.h>
|
||
|
|
||
|
/*#include <direct.h> teun: MS VC wants direct.h for mkdir */
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <errno.h>
|
||
|
#include <string.h>
|
||
|
#include <ctype.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <assert.h>
|
||
|
|
||
|
#include "util.h"
|
||
|
|
||
|
typedef struct UnMungeState
|
||
|
{
|
||
|
char const * mungedFileName;
|
||
|
char dirName[128];
|
||
|
char fileName[128];
|
||
|
char * fileNameTail;
|
||
|
int binaryMode, tabWidth;
|
||
|
long productNumber, fileNumber, pageNumber, lineNumber;
|
||
|
long manifestLineNumber;
|
||
|
word16 hdrFlags;
|
||
|
CRC pageCRC, seenPageCRC;
|
||
|
FILE * manifest;
|
||
|
FILE * file;
|
||
|
FILE * out;
|
||
|
} UnMungeState;
|
||
|
|
||
|
|
||
|
/* Returns number of characters decoded, or -1 on error */
|
||
|
static int
|
||
|
Decode4(char const src[4], byte dest[3])
|
||
|
{
|
||
|
int i, length;
|
||
|
byte srcVal[4];
|
||
|
|
||
|
for (i = 0; i < 4 && src[i] != RADIX64_END_CHAR; i++)
|
||
|
if ((srcVal[i] = Radix64DigitValue(src[i])) == (byte) -1)
|
||
|
return 1;
|
||
|
|
||
|
length = i - 1;
|
||
|
if (length < 1)
|
||
|
return -1;
|
||
|
|
||
|
for (; i < 4; i++)
|
||
|
srcVal[0] = 0;
|
||
|
|
||
|
dest[0] = (srcVal[0] << 2) | (srcVal[1] >> 4);
|
||
|
dest[1] = (srcVal[1] << 4) | (srcVal[2] >> 2);
|
||
|
dest[2] = (srcVal[2] << 6) | (srcVal[3]);
|
||
|
|
||
|
return length;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Return number of characters decoded, or -1 on error
|
||
|
*/
|
||
|
static int
|
||
|
DecodeLine(char const *src, char *dest, int srclength)
|
||
|
{
|
||
|
int destlength = 0;
|
||
|
int result;
|
||
|
|
||
|
if (srclength % 4 || !srclength)
|
||
|
return -1; /* Must be a multiple of 4 */
|
||
|
|
||
|
while (srclength -= 4) {
|
||
|
if (Decode4(src, dest + destlength) != 3)
|
||
|
return -1;
|
||
|
src += 4;
|
||
|
destlength += 3;
|
||
|
}
|
||
|
result = Decode4(src, dest + destlength);
|
||
|
if (result < 1)
|
||
|
return -1;
|
||
|
return destlength + result;
|
||
|
}
|
||
|
|
||
|
int PrintFileError(UnMungeState *state, char const *message)
|
||
|
{
|
||
|
fprintf(stderr, "%s, %s line %ld\n", message,
|
||
|
state->mungedFileName, state->lineNumber);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
int ReadManifest(UnMungeState *state, long fileNumberWanted,
|
||
|
char const *fileTailPrefix, long prefixLen)
|
||
|
{
|
||
|
long fileNumber = 0;
|
||
|
long firstMissingFileNum = 0, lastMissingFileNum = 0;
|
||
|
char buffer[512];
|
||
|
char * p;
|
||
|
|
||
|
if (state->manifest == NULL)
|
||
|
{
|
||
|
if (fileNumberWanted != 0)
|
||
|
{
|
||
|
assert(fileTailPrefix != NULL);
|
||
|
strncpy(state->fileName, fileTailPrefix, sizeof(state->fileName));
|
||
|
state->fileName[sizeof(state->fileName) - 1] = '\0';
|
||
|
state->fileNameTail = state->fileName;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
while (fgets(buffer, sizeof(buffer), state->manifest))
|
||
|
{
|
||
|
if ((p = strchr(buffer, '\n')) != NULL)
|
||
|
*p = '\0';
|
||
|
state->manifestLineNumber++;
|
||
|
if (buffer[0] == 'D')
|
||
|
{
|
||
|
if (buffer[1] != ' ')
|
||
|
goto invalidManifest;
|
||
|
strncpy(state->dirName, buffer + 2, sizeof(state->dirName));
|
||
|
if (state->dirName[sizeof(state->dirName) - 1] != '\0')
|
||
|
goto invalidManifest;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fileNumber = strtol(buffer, &p, 10);
|
||
|
if (p == buffer || *p != ' ')
|
||
|
goto invalidManifest;
|
||
|
p++;
|
||
|
|
||
|
if (fileNumberWanted == 0 || fileNumber < fileNumberWanted)
|
||
|
{
|
||
|
if (firstMissingFileNum == 0)
|
||
|
firstMissingFileNum = fileNumber;
|
||
|
lastMissingFileNum = fileNumber;
|
||
|
continue;
|
||
|
}
|
||
|
else if (fileNumber > fileNumberWanted)
|
||
|
break;
|
||
|
else
|
||
|
{
|
||
|
size_t len;
|
||
|
|
||
|
len = strlen(state->dirName);
|
||
|
assert(sizeof(state->fileName) >= sizeof(state->dirName));
|
||
|
memcpy(state->fileName, state->dirName, len);
|
||
|
strncpy(state->fileName + len, p,
|
||
|
sizeof(state->fileName) - len);
|
||
|
if (strncmp(p, fileTailPrefix, prefixLen) != 0)
|
||
|
{
|
||
|
fprintf(stderr, "Mismatched filename, headers say '%s',\n"
|
||
|
" manifest says '%s'\n",
|
||
|
fileTailPrefix, p);
|
||
|
return 1;
|
||
|
}
|
||
|
p = state->dirName;
|
||
|
while ((p = strchr(p, '/')) != NULL)
|
||
|
{
|
||
|
*p = '\0';
|
||
|
mkdir(state->dirName, 0777);
|
||
|
*p++ = '/';
|
||
|
}
|
||
|
state->fileNameTail = state->fileName + len;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (firstMissingFileNum != 0)
|
||
|
{
|
||
|
fprintf(stderr, "Missing files %ld-%ld\n",
|
||
|
firstMissingFileNum, lastMissingFileNum);
|
||
|
}
|
||
|
if (fileNumberWanted != 0 && fileNumber != fileNumberWanted)
|
||
|
{
|
||
|
fprintf(stderr, "Can't find file %ld in manifest file\n",
|
||
|
fileNumberWanted);
|
||
|
return 1;
|
||
|
}
|
||
|
return 0;
|
||
|
|
||
|
invalidManifest:
|
||
|
fprintf(stderr, "Error parsing manifest file, line %ld\n",
|
||
|
state->manifestLineNumber);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
int UnMungeFile(char const *mungedFileName, char const *manifestFileName,
|
||
|
int forceOverwrite, int forcePartialFiles)
|
||
|
{
|
||
|
UnMungeState * state;
|
||
|
EncodeFormat const * fmt = NULL;
|
||
|
char buffer[512];
|
||
|
char outbuf[BYTES_PER_LINE+1];
|
||
|
char * line;
|
||
|
char * lineData;
|
||
|
char * p;
|
||
|
int length;
|
||
|
int result = 0;
|
||
|
int skipPage = 0;
|
||
|
CRC lineCRC;
|
||
|
word32 num;
|
||
|
|
||
|
state = (UnMungeState *)calloc(1, sizeof(*state));
|
||
|
state->mungedFileName = mungedFileName;
|
||
|
|
||
|
if (manifestFileName != NULL)
|
||
|
{
|
||
|
if ((state->manifest = fopen(manifestFileName, "r")) == NULL)
|
||
|
goto errnoError;
|
||
|
}
|
||
|
|
||
|
if ((state->file = fopen(state->mungedFileName, "r")) == NULL)
|
||
|
goto errnoError;
|
||
|
|
||
|
while (!feof(state->file))
|
||
|
{
|
||
|
if (fgets(buffer, sizeof(buffer), state->file) == NULL)
|
||
|
{
|
||
|
if (feof(state->file))
|
||
|
break;
|
||
|
goto fileError;
|
||
|
}
|
||
|
|
||
|
state->lineNumber++;
|
||
|
|
||
|
line = buffer;
|
||
|
/* Strip leading whitespace */
|
||
|
while (isspace(*line))
|
||
|
line++;
|
||
|
if (*line == '\0')
|
||
|
continue;
|
||
|
|
||
|
/* Strip trailing whitespace */
|
||
|
p = line + strlen(line);
|
||
|
while (p > line && (byte)p[-1] < 128 && isspace(p[-1]))
|
||
|
p--;
|
||
|
|
||
|
lineData = line + PREFIX_LENGTH;
|
||
|
|
||
|
/* Pad up to at least PREFIX_LENGTH */
|
||
|
while (p < lineData)
|
||
|
*p++ = ' ';
|
||
|
*p++ = '\n';
|
||
|
*p = '\0';
|
||
|
length = p - lineData;
|
||
|
|
||
|
if (line[0] == HDR_PREFIX_CHAR)
|
||
|
{
|
||
|
fmt = FindFormat(line[1]);
|
||
|
if (!fmt)
|
||
|
{
|
||
|
result = PrintFileError(state, "ERROR: Invalid header type");
|
||
|
goto error;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
lineCRC = CalculateCRC(fmt->lineCRC, 0, (byte const *)lineData, length);
|
||
|
|
||
|
p = line + EncodedLength(fmt, fmt->runningCRCBits);
|
||
|
if (DecodeCheckDigits(fmt, p, NULL, fmt->lineCRC->bits, &num)
|
||
|
|| lineCRC != num)
|
||
|
{
|
||
|
result = PrintFileError(state, "ERROR: Line CRC failed");
|
||
|
goto error;
|
||
|
}
|
||
|
|
||
|
if (line[0] == HDR_PREFIX_CHAR)
|
||
|
{
|
||
|
int formatVersion;
|
||
|
int flags;
|
||
|
CRC seenPageCRC;
|
||
|
int tabWidth;
|
||
|
long productNumber;
|
||
|
long fileNumber;
|
||
|
long pageNumber;
|
||
|
char * fileNameTail;
|
||
|
int skipNextPage = 0;
|
||
|
char * p;
|
||
|
EncodeFormat const * hFmt = &hexFormat;
|
||
|
|
||
|
/* Parse header line */
|
||
|
p = lineData;
|
||
|
|
||
|
if (DecodeCheckDigits(hFmt, p, &p, HDR_VERSION_BITS, &num))
|
||
|
{
|
||
|
invalidHeader:
|
||
|
result = PrintFileError(state, "ERROR: Invalid header");
|
||
|
goto error;
|
||
|
}
|
||
|
formatVersion = num;
|
||
|
|
||
|
if (DecodeCheckDigits(hFmt, p, &p, HDR_FLAG_BITS, &num))
|
||
|
goto invalidHeader;
|
||
|
flags = num;
|
||
|
|
||
|
if (DecodeCheckDigits(hFmt, p, &p, fmt->pageCRC->bits, &num))
|
||
|
goto invalidHeader;
|
||
|
seenPageCRC = num;
|
||
|
|
||
|
if (DecodeCheckDigits(hFmt, p, &p, HDR_TABWIDTH_BITS, &num))
|
||
|
goto invalidHeader;
|
||
|
tabWidth = num;
|
||
|
|
||
|
if (DecodeCheckDigits(hFmt, p, &p, HDR_PRODNUM_BITS, &num))
|
||
|
goto invalidHeader;
|
||
|
productNumber = num;
|
||
|
|
||
|
if (DecodeCheckDigits(hFmt, p, &p, HDR_FILENUM_BITS, &num))
|
||
|
goto invalidHeader;
|
||
|
fileNumber = num;
|
||
|
|
||
|
if (sscanf(p, " Page %ld of ", &pageNumber) < 1)
|
||
|
goto invalidHeader;
|
||
|
|
||
|
if (formatVersion > 0)
|
||
|
{
|
||
|
result = PrintFileError(state,
|
||
|
"ERROR: Format too new for "
|
||
|
"this version of unmunge");
|
||
|
goto error;
|
||
|
}
|
||
|
|
||
|
p = strstr(p, " of ");
|
||
|
if (p == NULL)
|
||
|
goto invalidHeader;
|
||
|
|
||
|
fileNameTail = p + 4;
|
||
|
p = fileNameTail + strlen(fileNameTail);
|
||
|
if (p < fileNameTail + 3 || p[-1] != '\n')
|
||
|
goto invalidHeader;
|
||
|
else
|
||
|
p[-1] = '\0';
|
||
|
|
||
|
if (state->out != NULL && state->pageCRC != state->seenPageCRC)
|
||
|
{
|
||
|
result = PrintFileError(state,
|
||
|
"ERROR: Page CRC mismatch on page before");
|
||
|
goto error;
|
||
|
}
|
||
|
|
||
|
if ((state->hdrFlags & HDR_FLAG_LASTPAGE) && state->out != NULL)
|
||
|
{
|
||
|
fclose(state->out);
|
||
|
state->out = NULL;
|
||
|
}
|
||
|
|
||
|
if (state->out != NULL)
|
||
|
{
|
||
|
if (pageNumber != state->pageNumber + 1 ||
|
||
|
fileNumber != state->fileNumber ||
|
||
|
productNumber != state->productNumber ||
|
||
|
tabWidth != state->tabWidth ||
|
||
|
strcmp(fileNameTail, state->fileNameTail) != 0)
|
||
|
{
|
||
|
if (fileNumber == state->fileNumber &&
|
||
|
pageNumber > state->pageNumber + 1)
|
||
|
{
|
||
|
(void)PrintFileError(state,
|
||
|
"ERROR: Missing pages of this file");
|
||
|
if (forcePartialFiles && !state->binaryMode)
|
||
|
{
|
||
|
fputs("\n\n@@@@@@ Missing pages here! @@@@@@\n\n",
|
||
|
state->out);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
skipNextPage = 1;
|
||
|
fclose(state->out);
|
||
|
state->out = NULL;
|
||
|
remove(state->fileName);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
(void)PrintFileError(state,
|
||
|
"ERROR: Missing pages of previous file");
|
||
|
if (forcePartialFiles && !state->binaryMode)
|
||
|
{
|
||
|
fputs("\n\n@@@@@@ Missing pages here! @@@@@@\n\n",
|
||
|
state->out);
|
||
|
/* Make it non-fatal, though... */
|
||
|
fclose(state->out);
|
||
|
state->out = NULL;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fclose(state->out);
|
||
|
state->out = NULL;
|
||
|
remove(state->fileName);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (state->out == NULL)
|
||
|
{
|
||
|
if (pageNumber != 1 && !skipPage)
|
||
|
(void)PrintFileError(state,
|
||
|
"ERROR: File doesn't begin with page 1");
|
||
|
|
||
|
state->binaryMode = (tabWidth == 0);
|
||
|
|
||
|
if (pageNumber != 1 && (state->binaryMode
|
||
|
|| !forcePartialFiles))
|
||
|
{
|
||
|
skipNextPage = 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* TODO: Use global filelist to get pathname */
|
||
|
result = ReadManifest(state, fileNumber, fileNameTail,
|
||
|
strlen(fileNameTail));
|
||
|
if (result != 0)
|
||
|
goto error;
|
||
|
|
||
|
if (!forceOverwrite)
|
||
|
{
|
||
|
FILE * file;
|
||
|
|
||
|
/* Make sure file doesn't already exist */
|
||
|
file = fopen(state->fileName, "r");
|
||
|
if (file != NULL)
|
||
|
{
|
||
|
fclose(file);
|
||
|
fprintf(stderr, "ERROR: %s already exists\n",
|
||
|
state->fileName);
|
||
|
result = 1;
|
||
|
goto error;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
state->out = fopen(state->fileName,
|
||
|
state->binaryMode ? "wb" : "w");
|
||
|
if (state->out == NULL)
|
||
|
goto errnoError;
|
||
|
|
||
|
if (pageNumber != 1)
|
||
|
fputs("\n\n@@@@@@ Missing pages here! @@@@@@\n\n",
|
||
|
state->out);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
state->pageCRC = 0;
|
||
|
state->seenPageCRC = seenPageCRC;
|
||
|
state->hdrFlags = (word16)flags;
|
||
|
state->pageNumber = pageNumber;
|
||
|
state->fileNumber = fileNumber;
|
||
|
state->productNumber = productNumber;
|
||
|
state->tabWidth = tabWidth;
|
||
|
skipPage = skipNextPage;
|
||
|
}
|
||
|
else if (!skipPage)
|
||
|
{
|
||
|
if (state->out == NULL)
|
||
|
{
|
||
|
result = PrintFileError(state, "ERROR: Missing header line");
|
||
|
goto error;
|
||
|
}
|
||
|
|
||
|
/* Normal data line */
|
||
|
state->pageCRC = CalculateCRC(fmt->pageCRC, state->pageCRC,
|
||
|
(byte const *)lineData,
|
||
|
length);
|
||
|
line[2] = '\0';
|
||
|
if (DecodeCheckDigits(fmt, line, NULL, fmt->runningCRCBits, &num)
|
||
|
|| RunningCRCFromPageCRC(fmt, state->pageCRC) != num)
|
||
|
{
|
||
|
result = PrintFileError(state, "ERROR: Running CRC failed");
|
||
|
goto error;
|
||
|
}
|
||
|
|
||
|
if (state->binaryMode)
|
||
|
{
|
||
|
length = DecodeLine(lineData, outbuf, length-1);
|
||
|
if (length < 0 || length > BYTES_PER_LINE) {
|
||
|
result = PrintFileError(state,
|
||
|
"ERROR: Corrupt radix-64 data");
|
||
|
goto error;
|
||
|
}
|
||
|
fwrite(outbuf, 1, length, state->out);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
p = lineData;
|
||
|
while (*p != '\0')
|
||
|
{
|
||
|
if (*p == TAB_CHAR)
|
||
|
{
|
||
|
p++;
|
||
|
putc('\t', state->out);
|
||
|
while ((p - lineData) % state->tabWidth)
|
||
|
{
|
||
|
if (*p == '\n')
|
||
|
break;
|
||
|
else if (*p == ' ')
|
||
|
p++;
|
||
|
else
|
||
|
{
|
||
|
result = PrintFileError(state,
|
||
|
"ERROR: Not enough spaces "
|
||
|
"after a tab character");
|
||
|
goto error;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (*p == FORMFEED_CHAR)
|
||
|
{
|
||
|
p++;
|
||
|
if (*p != '\n')
|
||
|
{
|
||
|
result = PrintFileError(state,
|
||
|
"ERROR: Formfeed character "
|
||
|
"not at end of line");
|
||
|
goto error;
|
||
|
}
|
||
|
p++; /* Skip newline */
|
||
|
putc('\f', state->out);
|
||
|
}
|
||
|
else if (*p == CONTIN_CHAR)
|
||
|
{
|
||
|
p++;
|
||
|
if (*p != '\n')
|
||
|
{
|
||
|
result = PrintFileError(state,
|
||
|
"ERROR: Continuation character "
|
||
|
"not at end of line");
|
||
|
goto error;
|
||
|
}
|
||
|
p++; /* Skip newline */
|
||
|
}
|
||
|
else if (*p == SPACE_CHAR)
|
||
|
{
|
||
|
putc(' ', state->out);
|
||
|
p++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
putc(*p, state->out);
|
||
|
p++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (state->out != NULL)
|
||
|
{
|
||
|
if (!(state->hdrFlags & HDR_FLAG_LASTPAGE))
|
||
|
{
|
||
|
result = PrintFileError(state, "ERROR: Missing pages");
|
||
|
goto error;
|
||
|
}
|
||
|
if (state->pageCRC != state->seenPageCRC)
|
||
|
{
|
||
|
result = PrintFileError(state,
|
||
|
"ERROR: Page CRC failed on previous page");
|
||
|
goto error;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Check for missing files at the end */
|
||
|
result = ReadManifest(state, 0, NULL, 0);
|
||
|
goto done;
|
||
|
|
||
|
errnoError:
|
||
|
result = errno;
|
||
|
goto printError;
|
||
|
|
||
|
fileError:
|
||
|
result = ferror(state->file);
|
||
|
|
||
|
printError:
|
||
|
fprintf(stderr, "ERROR: %s\n", strerror(result));
|
||
|
|
||
|
error:
|
||
|
done:
|
||
|
if (state != NULL)
|
||
|
{
|
||
|
if (state->out != NULL)
|
||
|
fclose(state->out);
|
||
|
if (state->file != NULL)
|
||
|
fclose(state->file);
|
||
|
if (state->manifest != NULL)
|
||
|
fclose(state->manifest);
|
||
|
free(state);
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
void UsageAndExit(int result)
|
||
|
{
|
||
|
fprintf(stderr,
|
||
|
"Usage: unmunge [-fp] <file> [<manifest>]\n"
|
||
|
" -f Force overwrites of existing files\n"
|
||
|
" -p Force unmunge of partial files\n");
|
||
|
exit(result);
|
||
|
}
|
||
|
|
||
|
int main(int argc, char *argv[])
|
||
|
{
|
||
|
int result = 0;
|
||
|
int forceOverwrite = 0;
|
||
|
int forcePartialFiles = 0;
|
||
|
char * fileName = NULL;
|
||
|
char * manifestFileName = NULL;
|
||
|
int i, j;
|
||
|
|
||
|
InitUtil();
|
||
|
|
||
|
for (i = 1; i < argc && argv[i][0] == '-'; i++)
|
||
|
{
|
||
|
if (0 == strcmp(argv[i], "--"))
|
||
|
{
|
||
|
i++;
|
||
|
break;
|
||
|
}
|
||
|
for (j = 1; argv[i][j] != '\0'; j++)
|
||
|
{
|
||
|
if (argv[i][j] == 'h')
|
||
|
UsageAndExit(0);
|
||
|
else if (argv[i][j] == 'f')
|
||
|
forceOverwrite = 1;
|
||
|
else if (argv[i][j] == 'p')
|
||
|
forcePartialFiles = 1;
|
||
|
else
|
||
|
{
|
||
|
fprintf(stderr, "ERROR: Unrecognized option -%c\n", argv[i][j]);
|
||
|
UsageAndExit(1);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (i < argc)
|
||
|
fileName = argv[i++];
|
||
|
if (i < argc)
|
||
|
manifestFileName = argv[i++];
|
||
|
if (fileName == NULL || i < argc)
|
||
|
UsageAndExit(1);
|
||
|
|
||
|
if ((result = UnMungeFile(fileName, manifestFileName,
|
||
|
forceOverwrite, forcePartialFiles)) != 0)
|
||
|
{
|
||
|
/* If result > 0, message should have already been printed */
|
||
|
if (result < 0)
|
||
|
fprintf(stderr, "ERROR: %s\n", strerror(result));
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Local Variables:
|
||
|
* tab-width: 4
|
||
|
* End:
|
||
|
* vi: ts=4 sw=4
|
||
|
* vim: si
|
||
|
*/
|
||
|
|