|
/***************************************************************************
|
|
begin : Wed Jun 22 2011
|
|
copyright : (C) 2011 by Martin Preuss
|
|
email : martin@libchipcard.de
|
|
|
|
***************************************************************************
|
|
* *
|
|
* This library is free software; you can redistribute it and/or *
|
|
* modify it under the terms of the GNU Lesser General Public *
|
|
* License as published by the Free Software Foundation; either *
|
|
* version 2.1 of the License, or (at your option) any later version. *
|
|
* *
|
|
* This library is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
|
* Lesser General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU Lesser General Public *
|
|
* License along with this library; if not, write to the Free Software *
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
|
|
* MA 02111-1307 USA *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
|
|
#include "sar_p.h"
|
|
#include "gwen_sar_fileheader_l.h"
|
|
#include "i18n_l.h"
|
|
|
|
#include <gwenhywfar/misc.h>
|
|
#include <gwenhywfar/debug.h>
|
|
#include <gwenhywfar/tlv.h>
|
|
#include <gwenhywfar/gui.h>
|
|
#include <gwenhywfar/text.h>
|
|
#include <gwenhywfar/cryptmgrkeys.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
|
|
|
|
|
|
GWEN_SAR *GWEN_Sar_new(void) {
|
|
GWEN_SAR *sr;
|
|
|
|
GWEN_NEW_OBJECT(GWEN_SAR, sr);
|
|
sr->refCount=1;
|
|
|
|
sr->headers=GWEN_SarFileHeader_List_new();
|
|
|
|
return sr;
|
|
}
|
|
|
|
|
|
|
|
void GWEN_Sar_Attach(GWEN_SAR *sr) {
|
|
assert(sr);
|
|
assert(sr->refCount);
|
|
sr->refCount++;
|
|
}
|
|
|
|
|
|
|
|
void GWEN_Sar_free(GWEN_SAR *sr) {
|
|
if (sr) {
|
|
assert(sr->refCount);
|
|
if (sr->refCount==1) {
|
|
free(sr->archiveName);
|
|
GWEN_SarFileHeader_List_free(sr->headers);
|
|
GWEN_SyncIo_free(sr->archiveSio);
|
|
sr->refCount=0;
|
|
GWEN_FREE_OBJECT(sr);
|
|
}
|
|
else {
|
|
sr->refCount--;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int GWEN_Sar_CreateArchive(GWEN_SAR *sr, const char *aname) {
|
|
GWEN_SYNCIO *sio;
|
|
int rv;
|
|
|
|
assert(sr);
|
|
assert(sr->refCount);
|
|
|
|
assert(aname);
|
|
if (sr->openMode!=GWEN_Sar_OpenMode_Closed) {
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "Archive already open");
|
|
return GWEN_ERROR_OPEN;
|
|
}
|
|
|
|
free(sr->archiveName);
|
|
sr->archiveName=strdup(aname);
|
|
sio=GWEN_SyncIo_File_new(aname, GWEN_SyncIo_File_CreationMode_CreateAlways);
|
|
GWEN_SyncIo_AddFlags(sio,
|
|
GWEN_SYNCIO_FILE_FLAGS_READ |
|
|
GWEN_SYNCIO_FILE_FLAGS_WRITE |
|
|
GWEN_SYNCIO_FILE_FLAGS_UREAD |
|
|
GWEN_SYNCIO_FILE_FLAGS_UWRITE |
|
|
GWEN_SYNCIO_FILE_FLAGS_GREAD |
|
|
GWEN_SYNCIO_FILE_FLAGS_GWRITE);
|
|
rv=GWEN_SyncIo_Connect(sio);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_SyncIo_free(sio);
|
|
return rv;
|
|
}
|
|
|
|
sr->archiveSio=sio;
|
|
sr->openMode=GWEN_Sar_OpenMode_Created;
|
|
|
|
sr->signaturePos=0;
|
|
sr->signatureSize=0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_Sar_OpenArchive(GWEN_SAR *sr, const char *aname,
|
|
GWEN_SYNCIO_FILE_CREATIONMODE cm,
|
|
uint32_t acc) {
|
|
GWEN_SYNCIO *sio;
|
|
int rv;
|
|
|
|
assert(sr);
|
|
assert(sr->refCount);
|
|
|
|
assert(aname);
|
|
if (sr->openMode!=GWEN_Sar_OpenMode_Closed) {
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "Archive already open");
|
|
return GWEN_ERROR_OPEN;
|
|
}
|
|
|
|
free(sr->archiveName);
|
|
sr->archiveName=strdup(aname);
|
|
sio=GWEN_SyncIo_File_new(aname, cm);
|
|
GWEN_SyncIo_AddFlags(sio, acc);
|
|
rv=GWEN_SyncIo_Connect(sio);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_SyncIo_free(sio);
|
|
return rv;
|
|
}
|
|
|
|
sr->archiveSio=sio;
|
|
sr->openMode=GWEN_Sar_OpenMode_Opened;
|
|
|
|
sr->signaturePos=0;
|
|
sr->signatureSize=0;
|
|
|
|
rv=GWEN_Sar_ScanFile(sr);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
sr->archiveSio=NULL;
|
|
sr->openMode=GWEN_Sar_OpenMode_Closed;
|
|
GWEN_SyncIo_free(sio);
|
|
return rv;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_Sar_CloseArchive(GWEN_SAR *sr, int abandon) {
|
|
int rv;
|
|
|
|
assert(sr);
|
|
assert(sr->refCount);
|
|
|
|
if (sr->openMode!=GWEN_Sar_OpenMode_Opened &&
|
|
sr->openMode!=GWEN_Sar_OpenMode_Created) {
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "Archive not open");
|
|
return GWEN_ERROR_NOT_OPEN;
|
|
}
|
|
|
|
if (!abandon) {
|
|
/* flush */
|
|
rv=GWEN_SyncIo_Flush(sr->archiveSio);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_SyncIo_Disconnect(sr->archiveSio);
|
|
GWEN_SyncIo_free(sr->archiveSio);
|
|
sr->archiveSio=NULL;
|
|
free(sr->archiveName);
|
|
sr->archiveName=NULL;
|
|
sr->openMode=GWEN_Sar_OpenMode_Closed;
|
|
return rv;
|
|
}
|
|
}
|
|
|
|
/* disconnect */
|
|
rv=GWEN_SyncIo_Disconnect(sr->archiveSio);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_SyncIo_free(sr->archiveSio);
|
|
sr->archiveSio=NULL;
|
|
free(sr->archiveName);
|
|
sr->archiveName=NULL;
|
|
sr->openMode=GWEN_Sar_OpenMode_Closed;
|
|
return rv;
|
|
}
|
|
|
|
GWEN_SyncIo_free(sr->archiveSio);
|
|
sr->archiveSio=NULL;
|
|
free(sr->archiveName);
|
|
sr->archiveName=NULL;
|
|
sr->openMode=GWEN_Sar_OpenMode_Closed;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_Sar_FileHeaderToTlv(const GWEN_SAR_FILEHEADER *fh, GWEN_BUFFER *tbuf) {
|
|
const char *s;
|
|
uint16_t v8;
|
|
uint32_t v32;
|
|
uint64_t v64;
|
|
uint8_t hbuf[8];
|
|
const GWEN_TIME *ti;
|
|
int rv;
|
|
|
|
/* header version */
|
|
v32=GWEN_SAR_HEADER_VERSION;
|
|
hbuf[0]=(v32>>24) & 0xff;
|
|
hbuf[1]=(v32>>16) & 0xff;
|
|
hbuf[2]=(v32>>8) & 0xff;
|
|
hbuf[3]=v32 & 0xff;
|
|
GWEN_TLV_DirectlyToBuffer(GWEN_SAR_TAG_HEADER_VERSION, 0x00, hbuf, 4, 1, tbuf);
|
|
|
|
/* status */
|
|
v8=GWEN_SarFileHeader_GetStatus(fh) & 0xff;
|
|
hbuf[0]=v8;
|
|
GWEN_TLV_DirectlyToBuffer(GWEN_SAR_TAG_HEADER_STATUS, 0x00, hbuf, 1, 1, tbuf);
|
|
|
|
/* flags */
|
|
v32=GWEN_SarFileHeader_GetFlags(fh);
|
|
hbuf[0]=(v32>>24) & 0xff;
|
|
hbuf[1]=(v32>>16) & 0xff;
|
|
hbuf[2]=(v32>>8) & 0xff;
|
|
hbuf[3]=v32 & 0xff;
|
|
GWEN_TLV_DirectlyToBuffer(GWEN_SAR_TAG_HEADER_FLAGS, 0x00, hbuf, 4, 1, tbuf);
|
|
|
|
/* path */
|
|
s=GWEN_SarFileHeader_GetPath(fh);
|
|
if (s && *s)
|
|
GWEN_TLV_DirectlyToBuffer(GWEN_SAR_TAG_HEADER_PATH, 0x00, s, strlen(s)+1, 1, tbuf);
|
|
|
|
/* file type */
|
|
v8=GWEN_SarFileHeader_GetFileType(fh) & 0xff;
|
|
hbuf[0]=v8;
|
|
GWEN_TLV_DirectlyToBuffer(GWEN_SAR_TAG_HEADER_TYPE, 0x00, hbuf, 1, 1, tbuf);
|
|
|
|
/* permissions */
|
|
v32=GWEN_SarFileHeader_GetPermissions(fh);
|
|
hbuf[0]=(v32>>24) & 0xff;
|
|
hbuf[1]=(v32>>16) & 0xff;
|
|
hbuf[2]=(v32>>8) & 0xff;
|
|
hbuf[3]=v32 & 0xff;
|
|
GWEN_TLV_DirectlyToBuffer(GWEN_SAR_TAG_HEADER_PERM, 0x00, hbuf, 4, 1, tbuf);
|
|
|
|
/* atime */
|
|
ti=GWEN_SarFileHeader_GetAtime(fh);
|
|
if (ti) {
|
|
GWEN_BUFFER *xbuf;
|
|
|
|
xbuf=GWEN_Buffer_new(0, 32, 0, 1);
|
|
rv=GWEN_Time_toUtcString(ti, "YYYYMMDDhhmmss", xbuf);
|
|
if (rv>=0)
|
|
GWEN_TLV_DirectlyToBuffer(GWEN_SAR_TAG_HEADER_ATIME, 0x00,
|
|
GWEN_Buffer_GetStart(xbuf),
|
|
GWEN_Buffer_GetUsedBytes(xbuf),
|
|
1,
|
|
tbuf);
|
|
GWEN_Buffer_free(xbuf);
|
|
}
|
|
|
|
/* mtime */
|
|
ti=GWEN_SarFileHeader_GetMtime(fh);
|
|
if (ti) {
|
|
GWEN_BUFFER *xbuf;
|
|
|
|
xbuf=GWEN_Buffer_new(0, 32, 0, 1);
|
|
rv=GWEN_Time_toUtcString(ti, "YYYYMMDDhhmmss", xbuf);
|
|
if (rv>=0)
|
|
GWEN_TLV_DirectlyToBuffer(GWEN_SAR_TAG_HEADER_MTIME, 0x00,
|
|
GWEN_Buffer_GetStart(xbuf),
|
|
GWEN_Buffer_GetUsedBytes(xbuf),
|
|
1,
|
|
tbuf);
|
|
GWEN_Buffer_free(xbuf);
|
|
}
|
|
|
|
/* ctime */
|
|
ti=GWEN_SarFileHeader_GetCtime(fh);
|
|
if (ti) {
|
|
GWEN_BUFFER *xbuf;
|
|
|
|
xbuf=GWEN_Buffer_new(0, 32, 0, 1);
|
|
rv=GWEN_Time_toUtcString(ti, "YYYYMMDDhhmmss", xbuf);
|
|
if (rv>=0)
|
|
GWEN_TLV_DirectlyToBuffer(GWEN_SAR_TAG_HEADER_CTIME, 0x00,
|
|
GWEN_Buffer_GetStart(xbuf),
|
|
GWEN_Buffer_GetUsedBytes(xbuf),
|
|
1,
|
|
tbuf);
|
|
GWEN_Buffer_free(xbuf);
|
|
}
|
|
|
|
/* file size */
|
|
v64=GWEN_SarFileHeader_GetFileSize(fh);
|
|
hbuf[0]=(v64>>56) & 0xff;
|
|
hbuf[1]=(v64>>48) & 0xff;
|
|
hbuf[2]=(v64>>40) & 0xff;
|
|
hbuf[3]=(v64>>32) & 0xff;
|
|
hbuf[4]=(v64>>24) & 0xff;
|
|
hbuf[5]=(v64>>16) & 0xff;
|
|
hbuf[6]=(v64>>8) & 0xff;
|
|
hbuf[7]=v64 & 0xff;
|
|
GWEN_TLV_DirectlyToBuffer(GWEN_SAR_TAG_HEADER_SIZE, 0x00, hbuf, 8, 1, tbuf);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
uint64_t GWEN_Sar_ReadUint64(const uint8_t *p, uint32_t bs) {
|
|
uint64_t v=0;
|
|
|
|
switch(bs) {
|
|
case 8:
|
|
v=(((uint64_t)(p[0]))<<56)+
|
|
(((uint64_t)(p[1]))<<48)+
|
|
(((uint64_t)(p[2]))<<40)+
|
|
(((uint64_t)(p[3]))<<32)+
|
|
(((uint64_t)(p[4]))<<24)+
|
|
(((uint64_t)(p[5]))<<16)+
|
|
(((uint64_t)(p[6]))<<8)+
|
|
((uint64_t)(p[7]));
|
|
break;
|
|
case 7:
|
|
v=(((uint64_t)(p[0]))<<48)+
|
|
(((uint64_t)(p[1]))<<40)+
|
|
(((uint64_t)(p[2]))<<32)+
|
|
(((uint64_t)(p[3]))<<24)+
|
|
(((uint64_t)(p[4]))<<16)+
|
|
(((uint64_t)(p[5]))<<8)+
|
|
((uint64_t)(p[6]));
|
|
break;
|
|
case 6:
|
|
v=(((uint64_t)(p[0]))<<40)+
|
|
(((uint64_t)(p[1]))<<32)+
|
|
(((uint64_t)(p[2]))<<24)+
|
|
(((uint64_t)(p[3]))<<16)+
|
|
(((uint64_t)(p[4]))<<8)+
|
|
((uint64_t)(p[5]));
|
|
break;
|
|
case 5:
|
|
v=(((uint64_t)(p[0]))<<32)+
|
|
(((uint64_t)(p[1]))<<24)+
|
|
(((uint64_t)(p[2]))<<16)+
|
|
(((uint64_t)(p[3]))<<8)+
|
|
((uint64_t)(p[4]));
|
|
break;
|
|
case 4:
|
|
v=(((uint64_t)(p[0]))<<24)+
|
|
(((uint64_t)(p[1]))<<16)+
|
|
(((uint64_t)(p[2]))<<8)+
|
|
((uint64_t)(p[3]));
|
|
break;
|
|
case 3:
|
|
v=(((uint64_t)(p[0]))<<16)+
|
|
(((uint64_t)(p[1]))<<8)+
|
|
((uint64_t)(p[2]));
|
|
break;
|
|
case 2:
|
|
v=(((uint64_t)(p[0]))<<8)+
|
|
((uint64_t)(p[1]));
|
|
break;
|
|
case 1:
|
|
v=((uint64_t)(p[0]));
|
|
break;
|
|
|
|
default:
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "Unsupported size of %d for uint32", bs);
|
|
break;
|
|
}
|
|
|
|
return v;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_Sar_TlvToFileHeader(GWEN_BUFFER *mbuf, GWEN_SAR_FILEHEADER *fh) {
|
|
while(GWEN_Buffer_GetBytesLeft(mbuf)) {
|
|
GWEN_TLV *tlv;
|
|
|
|
tlv=GWEN_TLV_fromBuffer(mbuf, 1);
|
|
if (tlv) {
|
|
const uint8_t *p;
|
|
uint32_t bs;
|
|
uint64_t v;
|
|
GWEN_TIME *ti;
|
|
|
|
p=GWEN_TLV_GetTagData(tlv);
|
|
bs=GWEN_TLV_GetTagLength(tlv);
|
|
switch(GWEN_TLV_GetTagType(tlv)) {
|
|
case GWEN_SAR_TAG_HEADER_VERSION:
|
|
v=GWEN_Sar_ReadUint64(p, bs);
|
|
DBG_DEBUG(GWEN_LOGDOMAIN, "File Header Version: %08x", (unsigned int) (v & 0xffffffff));
|
|
break;
|
|
|
|
case GWEN_SAR_TAG_HEADER_STATUS:
|
|
v=GWEN_Sar_ReadUint64(p, bs);
|
|
GWEN_SarFileHeader_SetStatus(fh, v & 0xffffffff);
|
|
break;
|
|
|
|
case GWEN_SAR_TAG_HEADER_FLAGS:
|
|
v=GWEN_Sar_ReadUint64(p, bs);
|
|
GWEN_SarFileHeader_SetFlags(fh, v & 0xffffffff);
|
|
break;
|
|
|
|
case GWEN_SAR_TAG_HEADER_PATH:
|
|
GWEN_SarFileHeader_SetPath(fh, (const char*)p);
|
|
break;
|
|
|
|
case GWEN_SAR_TAG_HEADER_TYPE:
|
|
v=GWEN_Sar_ReadUint64(p, bs);
|
|
GWEN_SarFileHeader_SetFileType(fh, v & 0xffffffff);
|
|
break;
|
|
|
|
case GWEN_SAR_TAG_HEADER_PERM:
|
|
v=GWEN_Sar_ReadUint64(p, bs);
|
|
GWEN_SarFileHeader_SetPermissions(fh, v & 0xffffffff);
|
|
break;
|
|
|
|
case GWEN_SAR_TAG_HEADER_ATIME:
|
|
ti=GWEN_Time_fromUtcString((const char*) p, "YYYYMMDDhhmmss");
|
|
GWEN_SarFileHeader_SetAtime(fh, ti);
|
|
break;
|
|
|
|
case GWEN_SAR_TAG_HEADER_MTIME:
|
|
ti=GWEN_Time_fromUtcString((const char*) p, "YYYYMMDDhhmmss");
|
|
GWEN_SarFileHeader_SetMtime(fh, ti);
|
|
break;
|
|
|
|
case GWEN_SAR_TAG_HEADER_CTIME:
|
|
ti=GWEN_Time_fromUtcString((const char*) p, "YYYYMMDDhhmmss");
|
|
GWEN_SarFileHeader_SetCtime(fh, ti);
|
|
break;
|
|
|
|
case GWEN_SAR_TAG_HEADER_SIZE:
|
|
v=GWEN_Sar_ReadUint64(p, bs);
|
|
GWEN_SarFileHeader_SetFileSize(fh, v);
|
|
break;
|
|
default:
|
|
DBG_WARN(GWEN_LOGDOMAIN, "Ignoring unknown tag %d", GWEN_TLV_GetTagType(tlv));
|
|
break;
|
|
}
|
|
|
|
}
|
|
else {
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "No TLV in buffer");
|
|
return GWEN_ERROR_BAD_DATA;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_Sar_AddAndDigestFileReg(GWEN_SAR *sr, const GWEN_SAR_FILEHEADER *fh, GWEN_MDIGEST *md) {
|
|
int rv;
|
|
const char *fname;
|
|
uint64_t fsize;
|
|
uint64_t bytesDone;
|
|
GWEN_BUFFER *hbuf;
|
|
|
|
assert(sr);
|
|
assert(sr->refCount);
|
|
|
|
fname=GWEN_SarFileHeader_GetPath(fh);
|
|
assert(fname);
|
|
fsize=GWEN_SarFileHeader_GetFileSize(fh);
|
|
|
|
/* create TLV header */
|
|
hbuf=GWEN_Buffer_new(0, 32, 0, 1);
|
|
rv=GWEN_TLV_WriteHeader(GWEN_SAR_TAG_FILE, 0x00, fsize, 1, hbuf);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Buffer_free(hbuf);
|
|
return rv;
|
|
}
|
|
|
|
/* write TLV header */
|
|
rv=GWEN_SyncIo_WriteForced(sr->archiveSio,
|
|
(const uint8_t*) GWEN_Buffer_GetStart(hbuf),
|
|
GWEN_Buffer_GetUsedBytes(hbuf));
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Buffer_free(hbuf);
|
|
return rv;
|
|
}
|
|
|
|
GWEN_Buffer_free(hbuf);
|
|
|
|
/* copy file if fsize>0 */
|
|
if (fsize>0) {
|
|
GWEN_SYNCIO *sio;
|
|
uint32_t pid;
|
|
|
|
/* open input file */
|
|
sio=GWEN_SyncIo_File_new(fname, GWEN_SyncIo_File_CreationMode_OpenExisting);
|
|
GWEN_SyncIo_AddFlags(sio, GWEN_SYNCIO_FILE_FLAGS_READ);
|
|
rv=GWEN_SyncIo_Connect(sio);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_SyncIo_free(sio);
|
|
return rv;
|
|
}
|
|
|
|
pid=GWEN_Gui_ProgressStart(GWEN_GUI_PROGRESS_DELAY |
|
|
GWEN_GUI_PROGRESS_SHOW_ABORT |
|
|
GWEN_GUI_PROGRESS_ALLOW_EMBED |
|
|
GWEN_GUI_PROGRESS_SHOW_PROGRESS,
|
|
I18N("File Operation"),
|
|
I18N("Copying file into archive"),
|
|
fsize,
|
|
0);
|
|
bytesDone=0;
|
|
while(fsize) {
|
|
uint8_t fbuf[10240];
|
|
uint64_t bs;
|
|
|
|
bs=fsize;
|
|
if (bs>sizeof(fbuf))
|
|
bs=sizeof(fbuf);
|
|
|
|
/* read from input */
|
|
rv=GWEN_SyncIo_Read(sio, fbuf, bs);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
GWEN_SyncIo_Disconnect(sio);
|
|
GWEN_SyncIo_free(sio);
|
|
return rv;
|
|
}
|
|
bs=rv;
|
|
|
|
/* digest data */
|
|
rv=GWEN_MDigest_Update(md, fbuf, bs);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
GWEN_SyncIo_Disconnect(sio);
|
|
GWEN_SyncIo_free(sio);
|
|
return rv;
|
|
}
|
|
|
|
/* write to archive */
|
|
rv=GWEN_SyncIo_WriteForced(sr->archiveSio, fbuf, bs);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
GWEN_SyncIo_Disconnect(sio);
|
|
GWEN_SyncIo_free(sio);
|
|
return rv;
|
|
}
|
|
|
|
if (bs>fsize) {
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "Internal error: bs>fsize (%lu>%lu)",
|
|
(unsigned long int)bs, (unsigned long int) fsize);
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
GWEN_SyncIo_Disconnect(sio);
|
|
GWEN_SyncIo_free(sio);
|
|
return rv;
|
|
}
|
|
|
|
bytesDone+=bs;
|
|
fsize-=bs;
|
|
|
|
/* advance progress bar */
|
|
rv=GWEN_Gui_ProgressAdvance(pid, bytesDone);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
GWEN_SyncIo_Disconnect(sio);
|
|
GWEN_SyncIo_free(sio);
|
|
return rv;
|
|
}
|
|
|
|
} /* while */
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
|
|
/* close input file */
|
|
GWEN_SyncIo_Disconnect(sio);
|
|
GWEN_SyncIo_free(sio);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_Sar_AddAndDigestFileLink(GWEN_SAR *sr, const GWEN_SAR_FILEHEADER *fh, GWEN_MDIGEST *md) {
|
|
#if _BSD_SOURCE || _XOPEN_SOURCE >= 500 || (_XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED) || _POSIX_C_SOURCE >= 200112L || defined(OS_DARWIN)
|
|
int rv;
|
|
const char *fname;
|
|
GWEN_BUFFER *hbuf;
|
|
char lbuf[300];
|
|
int len;
|
|
|
|
assert(sr);
|
|
assert(sr->refCount);
|
|
|
|
fname=GWEN_SarFileHeader_GetPath(fh);
|
|
assert(fname);
|
|
|
|
/* read link content */
|
|
rv=readlink(fname, lbuf, sizeof(lbuf)-1);
|
|
if (rv<0) {
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "readlink(%s): %d (%s)",
|
|
fname, errno, strerror(errno));
|
|
return GWEN_ERROR_IO;
|
|
}
|
|
len=rv;
|
|
lbuf[len]=0;
|
|
|
|
/* create TLV header */
|
|
hbuf=GWEN_Buffer_new(0, rv+8, 0, 1);
|
|
GWEN_TLV_DirectlyToBuffer(GWEN_SAR_TAG_FILE, 0x00,
|
|
lbuf, len+1,
|
|
1, hbuf);
|
|
|
|
|
|
/* write TLV */
|
|
rv=GWEN_SyncIo_WriteForced(sr->archiveSio,
|
|
(const uint8_t*) GWEN_Buffer_GetStart(hbuf),
|
|
GWEN_Buffer_GetUsedBytes(hbuf));
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Buffer_free(hbuf);
|
|
return rv;
|
|
}
|
|
GWEN_Buffer_free(hbuf);
|
|
|
|
/* digest data */
|
|
rv=GWEN_MDigest_Update(md, (const uint8_t*) lbuf, len+1);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
return rv;
|
|
}
|
|
|
|
return 0;
|
|
#else
|
|
# warning "Function readlink() is not available"
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "Function readlink() is not available");
|
|
return GWEN_ERROR_IO;
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
int GWEN_Sar_AddAndDigestFile(GWEN_SAR *sr, const GWEN_SAR_FILEHEADER *fh, GWEN_MDIGEST *md) {
|
|
int rv;
|
|
|
|
switch(GWEN_SarFileHeader_GetFileType(fh)) {
|
|
case GWEN_SarFileHeader_FType_File:
|
|
rv=GWEN_Sar_AddAndDigestFileReg(sr, fh, md);
|
|
break;
|
|
case GWEN_SarFileHeader_FType_Dir:
|
|
rv=0;
|
|
break;
|
|
case GWEN_SarFileHeader_FType_SymLink:
|
|
rv=GWEN_Sar_AddAndDigestFileLink(sr, fh, md);
|
|
break;
|
|
default:
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "File type %d not supported", GWEN_SarFileHeader_GetFileType(fh));
|
|
return GWEN_ERROR_INVALID;
|
|
}
|
|
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
return rv;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_Sar_AddFile(GWEN_SAR *sr, const char *fname) {
|
|
struct stat st;
|
|
int rv;
|
|
GWEN_SAR_FILEHEADER *fh;
|
|
GWEN_TIME *ti;
|
|
GWEN_BUFFER *hbuf;
|
|
GWEN_BUFFER *xbuf;
|
|
GWEN_MDIGEST *md;
|
|
uint64_t pos;
|
|
|
|
assert(sr);
|
|
assert(sr->refCount);
|
|
|
|
/* stat file to be added */
|
|
#if _BSD_SOURCE || _XOPEN_SOURCE >= 500 || _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED
|
|
rv=lstat(fname, &st);
|
|
#else
|
|
rv=stat(fname, &st);
|
|
#endif
|
|
if (rv) {
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "stat(%s): %d (%s)",
|
|
fname, errno, strerror(errno));
|
|
return GWEN_ERROR_IO;
|
|
}
|
|
|
|
/* create and setup file header */
|
|
fh=GWEN_SarFileHeader_new();
|
|
|
|
/* path */
|
|
GWEN_SarFileHeader_SetPath(fh, fname);
|
|
|
|
/* file type */
|
|
switch(st.st_mode & S_IFMT) {
|
|
#ifdef S_IFLNK
|
|
case S_IFLNK:
|
|
GWEN_SarFileHeader_SetFileType(fh, GWEN_SarFileHeader_FType_SymLink);
|
|
break;
|
|
#endif
|
|
case S_IFREG:
|
|
GWEN_SarFileHeader_SetFileType(fh, GWEN_SarFileHeader_FType_File);
|
|
break;
|
|
case S_IFDIR:
|
|
GWEN_SarFileHeader_SetFileType(fh, GWEN_SarFileHeader_FType_Dir);
|
|
break;
|
|
default:
|
|
GWEN_SarFileHeader_free(fh);
|
|
return GWEN_ERROR_INVALID;
|
|
}
|
|
|
|
/* permissions */
|
|
if (st.st_mode & S_IRUSR) GWEN_SarFileHeader_AddPermissions(fh, GWEN_SYNCIO_FILE_FLAGS_UREAD);
|
|
if (st.st_mode & S_IWUSR) GWEN_SarFileHeader_AddPermissions(fh, GWEN_SYNCIO_FILE_FLAGS_UWRITE);
|
|
if (st.st_mode & S_IXUSR) GWEN_SarFileHeader_AddPermissions(fh, GWEN_SYNCIO_FILE_FLAGS_UEXEC);
|
|
|
|
#ifdef S_IRGRP
|
|
if (st.st_mode & S_IRGRP) GWEN_SarFileHeader_AddPermissions(fh, GWEN_SYNCIO_FILE_FLAGS_GREAD);
|
|
#endif
|
|
#ifdef S_IWGRP
|
|
if (st.st_mode & S_IWGRP) GWEN_SarFileHeader_AddPermissions(fh, GWEN_SYNCIO_FILE_FLAGS_GWRITE);
|
|
#endif
|
|
#ifdef S_IXGRP
|
|
if (st.st_mode & S_IXGRP) GWEN_SarFileHeader_AddPermissions(fh, GWEN_SYNCIO_FILE_FLAGS_GEXEC);
|
|
#endif
|
|
|
|
#ifdef S_IROTH
|
|
if (st.st_mode & S_IROTH) GWEN_SarFileHeader_AddPermissions(fh, GWEN_SYNCIO_FILE_FLAGS_OREAD);
|
|
#endif
|
|
#ifdef S_IWOTH
|
|
if (st.st_mode & S_IWOTH) GWEN_SarFileHeader_AddPermissions(fh, GWEN_SYNCIO_FILE_FLAGS_OWRITE);
|
|
#endif
|
|
#ifdef S_IXOTH
|
|
if (st.st_mode & S_IXOTH) GWEN_SarFileHeader_AddPermissions(fh, GWEN_SYNCIO_FILE_FLAGS_OEXEC);
|
|
#endif
|
|
|
|
/* atime */
|
|
ti=GWEN_Time_fromSeconds(st.st_atime);
|
|
GWEN_SarFileHeader_SetAtime(fh, ti);
|
|
|
|
/* mtime */
|
|
ti=GWEN_Time_fromSeconds(st.st_mtime);
|
|
GWEN_SarFileHeader_SetMtime(fh, ti);
|
|
|
|
/* ctime */
|
|
ti=GWEN_Time_fromSeconds(st.st_ctime);
|
|
GWEN_SarFileHeader_SetCtime(fh, ti);
|
|
|
|
/* file size */
|
|
GWEN_SarFileHeader_SetFileSize(fh, st.st_size);
|
|
|
|
|
|
/* prepare header */
|
|
hbuf=GWEN_Buffer_new(0, 256, 0, 1);
|
|
GWEN_Buffer_ReserveBytes(hbuf, 16);
|
|
rv=GWEN_Sar_FileHeaderToTlv(fh, hbuf);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Buffer_free(hbuf);
|
|
GWEN_SarFileHeader_free(fh);
|
|
return rv;
|
|
}
|
|
|
|
/* create TLV header for file header */
|
|
xbuf=GWEN_Buffer_new(0, 16, 0, 1);
|
|
rv=GWEN_TLV_WriteHeader(GWEN_SAR_TAG_HEADER, 0xe0,
|
|
GWEN_Buffer_GetUsedBytes(hbuf), 1, xbuf);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Buffer_free(xbuf);
|
|
GWEN_Buffer_free(hbuf);
|
|
GWEN_SarFileHeader_free(fh);
|
|
return rv;
|
|
}
|
|
|
|
/* insert TLV header into file header buffer */
|
|
GWEN_Buffer_SetPos(hbuf, 0);
|
|
GWEN_Buffer_InsertBytes(hbuf,
|
|
GWEN_Buffer_GetStart(xbuf),
|
|
GWEN_Buffer_GetUsedBytes(xbuf));
|
|
GWEN_Buffer_SetPos(hbuf, GWEN_Buffer_GetUsedBytes(hbuf));
|
|
GWEN_Buffer_free(xbuf);
|
|
|
|
/* seek to end of file */
|
|
pos=GWEN_SyncIo_File_Seek(sr->archiveSio, 0, GWEN_SyncIo_File_Whence_End);
|
|
if (pos<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", (int) pos);
|
|
GWEN_Buffer_free(hbuf);
|
|
GWEN_SarFileHeader_free(fh);
|
|
return (int) pos;
|
|
}
|
|
|
|
/* write header into archive file */
|
|
rv=GWEN_SyncIo_WriteForced(sr->archiveSio,
|
|
(const uint8_t*) GWEN_Buffer_GetStart(hbuf),
|
|
GWEN_Buffer_GetUsedBytes(hbuf));
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Buffer_free(hbuf);
|
|
GWEN_SarFileHeader_free(fh);
|
|
return rv;
|
|
}
|
|
|
|
/* prepare digest */
|
|
md=GWEN_MDigest_Rmd160_new();
|
|
rv=GWEN_MDigest_Begin(md);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_MDigest_free(md);
|
|
GWEN_Buffer_free(hbuf);
|
|
GWEN_SarFileHeader_free(fh);
|
|
return rv;
|
|
}
|
|
|
|
/* digest header */
|
|
rv=GWEN_MDigest_Update(md, (const uint8_t*) GWEN_Buffer_GetStart(hbuf), GWEN_Buffer_GetUsedBytes(hbuf));
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_MDigest_free(md);
|
|
GWEN_Buffer_free(hbuf);
|
|
GWEN_SarFileHeader_free(fh);
|
|
return rv;
|
|
}
|
|
|
|
GWEN_Buffer_Reset(hbuf);
|
|
|
|
/* copy file into archive */
|
|
rv=GWEN_Sar_AddAndDigestFile(sr, fh, md);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_MDigest_free(md);
|
|
GWEN_Buffer_free(hbuf);
|
|
GWEN_SarFileHeader_free(fh);
|
|
return rv;
|
|
}
|
|
|
|
/* finish hash */
|
|
rv=GWEN_MDigest_End(md);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_MDigest_free(md);
|
|
GWEN_Buffer_free(hbuf);
|
|
GWEN_SarFileHeader_free(fh);
|
|
return rv;
|
|
}
|
|
|
|
/* create hash TLV */
|
|
GWEN_TLV_DirectlyToBuffer(GWEN_SAR_TAG_HASH, 0x00,
|
|
GWEN_MDigest_GetDigestPtr(md),
|
|
GWEN_MDigest_GetDigestSize(md),
|
|
1, hbuf);
|
|
GWEN_MDigest_free(md);
|
|
|
|
/* write hash into archive file */
|
|
rv=GWEN_SyncIo_WriteForced(sr->archiveSio,
|
|
(const uint8_t*) GWEN_Buffer_GetStart(hbuf),
|
|
GWEN_Buffer_GetUsedBytes(hbuf));
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Buffer_free(hbuf);
|
|
GWEN_SarFileHeader_free(fh);
|
|
return rv;
|
|
}
|
|
|
|
/* done */
|
|
GWEN_Buffer_free(hbuf);
|
|
GWEN_SarFileHeader_free(fh);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
int GWEN_Sar_ScanFile(GWEN_SAR *sr) {
|
|
int rv;
|
|
int64_t pos;
|
|
GWEN_BUFFER *mbuf;
|
|
GWEN_SAR_FILEHEADER *lastHeader=NULL;
|
|
|
|
assert(sr);
|
|
assert(sr->refCount);
|
|
|
|
sr->signaturePos=0;
|
|
sr->signatureSize=0;
|
|
|
|
/* scan all TLV elements */
|
|
pos=0;
|
|
mbuf=GWEN_Buffer_new(0, 1024, 0, 1);
|
|
for (;;) {
|
|
int64_t startOfTagHeader;
|
|
int64_t startOfTagData;
|
|
unsigned int tagType;
|
|
uint32_t tagLength;
|
|
uint32_t fullTagSize;
|
|
uint32_t bs;
|
|
GWEN_TLV *tlv;
|
|
uint8_t buffer[32];
|
|
|
|
startOfTagHeader=pos;
|
|
rv=GWEN_SyncIo_Read(sr->archiveSio, buffer, sizeof(buffer));
|
|
if (rv<0) {
|
|
if (rv==GWEN_ERROR_EOF)
|
|
break;
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Buffer_free(mbuf);
|
|
return rv;
|
|
}
|
|
else if (rv==0) {
|
|
DBG_VERBOUS(GWEN_LOGDOMAIN, "EOF met");
|
|
break;
|
|
}
|
|
bs=rv;
|
|
|
|
/* read start of fileheader TLV */
|
|
tlv=GWEN_TLV_new();
|
|
rv=GWEN_TLV_ReadHeader(tlv, buffer, bs, 1);
|
|
if (rv<2) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_TLV_free(tlv);
|
|
GWEN_Buffer_free(mbuf);
|
|
return rv;
|
|
}
|
|
/* got it, now calculate start of tag data */
|
|
startOfTagData=pos+rv;
|
|
tagLength=GWEN_TLV_GetTagLength(tlv);
|
|
tagType=GWEN_TLV_GetTagType(tlv);
|
|
fullTagSize=GWEN_TLV_GetTagSize(tlv);
|
|
GWEN_TLV_free(tlv);
|
|
|
|
/* seek to start of header data */
|
|
pos=GWEN_SyncIo_File_Seek(sr->archiveSio, startOfTagData, GWEN_SyncIo_File_Whence_Set);
|
|
if (pos<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", (int) pos);
|
|
GWEN_Buffer_free(mbuf);
|
|
return (int) pos;
|
|
}
|
|
|
|
/* now read or skip info */
|
|
if (tagType==GWEN_SAR_TAG_HEADER) {
|
|
GWEN_SAR_FILEHEADER *fh;
|
|
const char *s;
|
|
|
|
/* alloc memory for data */
|
|
GWEN_Buffer_AllocRoom(mbuf, tagLength);
|
|
|
|
/* read header data */
|
|
rv=GWEN_SyncIo_ReadForced(sr->archiveSio, (uint8_t*) GWEN_Buffer_GetStart(mbuf), tagLength);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Buffer_free(mbuf);
|
|
return rv;
|
|
}
|
|
GWEN_Buffer_IncrementPos(mbuf, tagLength);
|
|
GWEN_Buffer_AdjustUsedBytes(mbuf);
|
|
GWEN_Buffer_Rewind(mbuf);
|
|
|
|
/* now parse header */
|
|
fh=GWEN_SarFileHeader_new();
|
|
rv=GWEN_Sar_TlvToFileHeader(mbuf, fh);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_SarFileHeader_free(fh);
|
|
GWEN_Buffer_free(mbuf);
|
|
return rv;
|
|
}
|
|
|
|
GWEN_SarFileHeader_SetHeaderStartPos(fh, startOfTagHeader);
|
|
GWEN_SarFileHeader_SetHeaderSize(fh, fullTagSize);
|
|
|
|
s=GWEN_SarFileHeader_GetPath(fh);
|
|
DBG_DEBUG(GWEN_LOGDOMAIN, "Got entry [%s]", s?s:"(empty)");
|
|
|
|
GWEN_SarFileHeader_List_Add(fh, sr->headers);
|
|
lastHeader=fh;
|
|
}
|
|
else if (tagType==GWEN_SAR_TAG_FILE) {
|
|
if (lastHeader==NULL) {
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "Bad file structure: No file header before data");
|
|
GWEN_Buffer_free(mbuf);
|
|
return GWEN_ERROR_BAD_DATA;
|
|
}
|
|
if (GWEN_SarFileHeader_GetFileType(lastHeader)!=GWEN_SarFileHeader_FType_SymLink &&
|
|
GWEN_SarFileHeader_GetFileSize(lastHeader)!=tagLength) {
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "File size in header and in archive differ (%s: hs=%lu, ts=%lu)",
|
|
GWEN_SarFileHeader_GetPath(lastHeader),
|
|
(unsigned long int) GWEN_SarFileHeader_GetFileSize(lastHeader),
|
|
(unsigned long int) tagLength);
|
|
GWEN_Buffer_free(mbuf);
|
|
return GWEN_ERROR_BAD_DATA;
|
|
}
|
|
/* only store position of file data */
|
|
GWEN_SarFileHeader_SetDataPos(lastHeader, startOfTagData);
|
|
GWEN_SarFileHeader_SetDataSize(lastHeader, tagLength);
|
|
|
|
/* skip data */
|
|
pos=GWEN_SyncIo_File_Seek(sr->archiveSio, tagLength, GWEN_SyncIo_File_Whence_Current);
|
|
if (pos<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", (int) pos);
|
|
GWEN_Buffer_free(mbuf);
|
|
return (int) pos;
|
|
}
|
|
}
|
|
else if (tagType==GWEN_SAR_TAG_HASH) {
|
|
if (lastHeader==NULL) {
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "Bad file structure: No file header before data");
|
|
GWEN_Buffer_free(mbuf);
|
|
return GWEN_ERROR_BAD_DATA;
|
|
}
|
|
/* only store position of file data */
|
|
GWEN_SarFileHeader_SetHashPos(lastHeader, startOfTagData);
|
|
|
|
/* skip data */
|
|
pos=GWEN_SyncIo_File_Seek(sr->archiveSio, tagLength, GWEN_SyncIo_File_Whence_Current);
|
|
if (pos<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", (int) pos);
|
|
GWEN_Buffer_free(mbuf);
|
|
return (int) pos;
|
|
}
|
|
}
|
|
else if (tagType==GWEN_SAR_TAG_SIGNATURE) {
|
|
/* only store position of file data */
|
|
DBG_INFO(GWEN_LOGDOMAIN, "Signature found");
|
|
sr->signaturePos=startOfTagData;
|
|
sr->signatureSize=tagLength;
|
|
|
|
/* skip data */
|
|
pos=GWEN_SyncIo_File_Seek(sr->archiveSio, tagLength, GWEN_SyncIo_File_Whence_Current);
|
|
if (pos<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", (int) pos);
|
|
GWEN_Buffer_free(mbuf);
|
|
return (int) pos;
|
|
}
|
|
}
|
|
else {
|
|
DBG_WARN(GWEN_LOGDOMAIN, "Unknown TAG %d, ignoring", (int) tagType);
|
|
/* just skip data */
|
|
pos=GWEN_SyncIo_File_Seek(sr->archiveSio, tagLength, GWEN_SyncIo_File_Whence_Current);
|
|
if (pos<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", (int) pos);
|
|
GWEN_Buffer_free(mbuf);
|
|
return (int) pos;
|
|
}
|
|
}
|
|
|
|
GWEN_Buffer_Reset(mbuf);
|
|
pos=startOfTagData+tagLength;
|
|
} /* for */
|
|
|
|
/* done */
|
|
GWEN_Buffer_free(mbuf);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_Sar_ExtractAndDigestFileReg(GWEN_SAR *sr, const GWEN_SAR_FILEHEADER *fh, int checkOnly) {
|
|
int rv;
|
|
const char *fname;
|
|
uint32_t perms;
|
|
uint64_t dpos;
|
|
uint64_t fsize;
|
|
uint64_t bytesDone;
|
|
uint64_t hsize;
|
|
uint64_t hpos;
|
|
uint64_t mpos;
|
|
uint64_t pos;
|
|
GWEN_MDIGEST *md;
|
|
|
|
assert(sr);
|
|
assert(sr->refCount);
|
|
|
|
md=GWEN_MDigest_Rmd160_new();
|
|
rv=GWEN_MDigest_Begin(md);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
|
|
fname=GWEN_SarFileHeader_GetPath(fh);
|
|
assert(fname);
|
|
perms=GWEN_SarFileHeader_GetPermissions(fh);
|
|
fsize=GWEN_SarFileHeader_GetFileSize(fh);
|
|
dpos=GWEN_SarFileHeader_GetDataPos(fh);
|
|
|
|
hpos=GWEN_SarFileHeader_GetHeaderStartPos(fh);
|
|
hsize=GWEN_SarFileHeader_GetHeaderSize(fh);
|
|
if (hsize>0) {
|
|
GWEN_BUFFER *mbuf;
|
|
|
|
/* seek to start of header */
|
|
pos=GWEN_SyncIo_File_Seek(sr->archiveSio, hpos, GWEN_SyncIo_File_Whence_Set);
|
|
if (pos<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", (int) pos);
|
|
GWEN_MDigest_free(md);
|
|
return (int) pos;
|
|
}
|
|
|
|
mbuf=GWEN_Buffer_new(0, hsize, 0, 1);
|
|
rv=GWEN_SyncIo_ReadForced(sr->archiveSio,
|
|
(uint8_t*) GWEN_Buffer_GetStart(mbuf),
|
|
hsize);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Buffer_free(mbuf);
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
GWEN_Buffer_IncrementPos(mbuf, hsize);
|
|
GWEN_Buffer_AdjustUsedBytes(mbuf);
|
|
|
|
/* digest TLV */
|
|
rv=GWEN_MDigest_Update(md, (const uint8_t*) GWEN_Buffer_GetStart(mbuf), GWEN_Buffer_GetUsedBytes(mbuf));
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Buffer_free(mbuf);
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
GWEN_Buffer_free(mbuf);
|
|
}
|
|
|
|
/* copy file if fsize>0 */
|
|
if (1) {
|
|
GWEN_SYNCIO *sio=NULL;
|
|
uint32_t pid;
|
|
|
|
/* open input file */
|
|
if (!checkOnly) {
|
|
sio=GWEN_SyncIo_File_new(fname, GWEN_SyncIo_File_CreationMode_CreateNew);
|
|
GWEN_SyncIo_AddFlags(sio, GWEN_SYNCIO_FILE_FLAGS_READ | GWEN_SYNCIO_FILE_FLAGS_WRITE);
|
|
GWEN_SyncIo_AddFlags(sio, perms);
|
|
rv=GWEN_SyncIo_Connect(sio);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_SyncIo_free(sio);
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
}
|
|
|
|
if (fsize>0) {
|
|
/* seek to start of data */
|
|
pos=GWEN_SyncIo_File_Seek(sr->archiveSio, dpos, GWEN_SyncIo_File_Whence_Set);
|
|
if (pos<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", (int) pos);
|
|
if (!checkOnly) {
|
|
GWEN_SyncIo_Disconnect(sio);
|
|
GWEN_SyncIo_free(sio);
|
|
}
|
|
GWEN_MDigest_free(md);
|
|
return (int) pos;
|
|
}
|
|
|
|
/* start extracting */
|
|
pid=GWEN_Gui_ProgressStart(GWEN_GUI_PROGRESS_DELAY |
|
|
GWEN_GUI_PROGRESS_SHOW_ABORT |
|
|
GWEN_GUI_PROGRESS_ALLOW_EMBED |
|
|
GWEN_GUI_PROGRESS_SHOW_PROGRESS,
|
|
I18N("File Operation"),
|
|
I18N("Extracting file from archive"),
|
|
fsize,
|
|
0);
|
|
bytesDone=0;
|
|
while(fsize) {
|
|
uint8_t fbuf[10240];
|
|
uint64_t bs;
|
|
|
|
bs=fsize;
|
|
if (bs>sizeof(fbuf))
|
|
bs=sizeof(fbuf);
|
|
|
|
/* read from input */
|
|
rv=GWEN_SyncIo_Read(sr->archiveSio, fbuf, bs);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
if (!checkOnly) {
|
|
GWEN_SyncIo_Disconnect(sio);
|
|
GWEN_SyncIo_free(sio);
|
|
}
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
bs=rv;
|
|
|
|
/* digest data */
|
|
rv=GWEN_MDigest_Update(md, fbuf, bs);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
if (!checkOnly) {
|
|
GWEN_SyncIo_Disconnect(sio);
|
|
GWEN_SyncIo_free(sio);
|
|
}
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
|
|
if (!checkOnly) {
|
|
/* write to archive */
|
|
rv=GWEN_SyncIo_WriteForced(sio, fbuf, bs);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
if (!checkOnly) {
|
|
GWEN_SyncIo_Disconnect(sio);
|
|
GWEN_SyncIo_free(sio);
|
|
}
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
}
|
|
|
|
if (bs>fsize) {
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "Internal error: bs>fsize (%lu>%lu)",
|
|
(unsigned long int)bs, (unsigned long int) fsize);
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
if (!checkOnly) {
|
|
GWEN_SyncIo_Disconnect(sio);
|
|
GWEN_SyncIo_free(sio);
|
|
}
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
|
|
bytesDone+=bs;
|
|
fsize-=bs;
|
|
|
|
/* advance progress bar */
|
|
rv=GWEN_Gui_ProgressAdvance(pid, bytesDone);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
if (!checkOnly) {
|
|
GWEN_SyncIo_Disconnect(sio);
|
|
GWEN_SyncIo_free(sio);
|
|
}
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
|
|
} /* while */
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
}
|
|
|
|
if (!checkOnly) {
|
|
/* close output file */
|
|
GWEN_SyncIo_Disconnect(sio);
|
|
GWEN_SyncIo_free(sio);
|
|
}
|
|
|
|
/* finish hash */
|
|
rv=GWEN_MDigest_End(md);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
|
|
/* read and check hash */
|
|
mpos=GWEN_SarFileHeader_GetHashPos(fh);
|
|
if (mpos) {
|
|
GWEN_BUFFER *mbuf;
|
|
|
|
/* seek to end of file */
|
|
pos=GWEN_SyncIo_File_Seek(sr->archiveSio, mpos, GWEN_SyncIo_File_Whence_Set);
|
|
if (pos<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", (int) pos);
|
|
GWEN_MDigest_free(md);
|
|
return (int) pos;
|
|
}
|
|
|
|
/* read 20 bytes of hash */
|
|
mbuf=GWEN_Buffer_new(0, 20, 0, 1);
|
|
rv=GWEN_SyncIo_ReadForced(sr->archiveSio,
|
|
(uint8_t*) GWEN_Buffer_GetStart(mbuf),
|
|
20);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Buffer_free(mbuf);
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
GWEN_Buffer_IncrementPos(mbuf, 20);
|
|
GWEN_Buffer_AdjustUsedBytes(mbuf);
|
|
|
|
if (memcmp(GWEN_MDigest_GetDigestPtr(md),
|
|
GWEN_Buffer_GetStart(mbuf),
|
|
20)!=0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
DBG_ERROR(0, "Hash don't match:");
|
|
GWEN_Text_LogString((const char*) GWEN_MDigest_GetDigestPtr(md), 20,
|
|
GWEN_LOGDOMAIN, GWEN_LoggerLevel_Error);
|
|
|
|
GWEN_Text_LogString(GWEN_Buffer_GetStart(mbuf), 20,
|
|
GWEN_LOGDOMAIN, GWEN_LoggerLevel_Error);
|
|
GWEN_Buffer_free(mbuf);
|
|
GWEN_MDigest_free(md);
|
|
return GWEN_ERROR_BAD_DATA;
|
|
}
|
|
|
|
GWEN_Buffer_free(mbuf);
|
|
}
|
|
|
|
GWEN_MDigest_free(md);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_Sar_ExtractAndDigestFileLink(GWEN_SAR *sr, const GWEN_SAR_FILEHEADER *fh, int checkOnly) {
|
|
#if _BSD_SOURCE || _XOPEN_SOURCE >= 500 || (_XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED) || _POSIX_C_SOURCE >= 200112L || defined(OS_DARWIN)
|
|
int rv;
|
|
const char *fname;
|
|
uint32_t perms;
|
|
uint64_t dpos;
|
|
uint64_t fsize;
|
|
uint64_t hsize;
|
|
uint64_t hpos;
|
|
uint64_t mpos;
|
|
uint64_t pos;
|
|
GWEN_MDIGEST *md;
|
|
|
|
assert(sr);
|
|
assert(sr->refCount);
|
|
|
|
md=GWEN_MDigest_Rmd160_new();
|
|
rv=GWEN_MDigest_Begin(md);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
|
|
fname=GWEN_SarFileHeader_GetPath(fh);
|
|
perms=GWEN_SarFileHeader_GetPermissions(fh);
|
|
assert(fname);
|
|
fsize=GWEN_SarFileHeader_GetDataSize(fh); /* not FileSize!! */
|
|
dpos=GWEN_SarFileHeader_GetDataPos(fh);
|
|
|
|
hpos=GWEN_SarFileHeader_GetHeaderStartPos(fh);
|
|
hsize=GWEN_SarFileHeader_GetHeaderSize(fh);
|
|
if (hsize>0) {
|
|
GWEN_BUFFER *mbuf;
|
|
|
|
/* seek to header pos */
|
|
pos=GWEN_SyncIo_File_Seek(sr->archiveSio, hpos, GWEN_SyncIo_File_Whence_Set);
|
|
if (pos<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", (int) pos);
|
|
GWEN_MDigest_free(md);
|
|
return (int) pos;
|
|
}
|
|
|
|
mbuf=GWEN_Buffer_new(0, hsize, 0, 1);
|
|
rv=GWEN_SyncIo_ReadForced(sr->archiveSio,
|
|
(uint8_t*) GWEN_Buffer_GetStart(mbuf),
|
|
hsize);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Buffer_free(mbuf);
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
GWEN_Buffer_IncrementPos(mbuf, hsize);
|
|
GWEN_Buffer_AdjustUsedBytes(mbuf);
|
|
|
|
/* digest header TLV */
|
|
rv=GWEN_MDigest_Update(md, (const uint8_t*) GWEN_Buffer_GetStart(mbuf), GWEN_Buffer_GetUsedBytes(mbuf));
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Buffer_free(mbuf);
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
GWEN_Buffer_free(mbuf);
|
|
}
|
|
|
|
/* seek to data pos */
|
|
pos=GWEN_SyncIo_File_Seek(sr->archiveSio, dpos, GWEN_SyncIo_File_Whence_Set);
|
|
if (pos<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", (int) pos);
|
|
GWEN_MDigest_free(md);
|
|
return (int) pos;
|
|
}
|
|
|
|
/* copy file if fsize>0 */
|
|
if (fsize>0) { /* fsize is the size of the file tag data */
|
|
GWEN_BUFFER *mbuf;
|
|
|
|
mbuf=GWEN_Buffer_new(0, fsize, 0, 1);
|
|
rv=GWEN_SyncIo_ReadForced(sr->archiveSio,
|
|
(uint8_t*) GWEN_Buffer_GetStart(mbuf),
|
|
fsize);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Buffer_free(mbuf);
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
GWEN_Buffer_IncrementPos(mbuf, fsize);
|
|
GWEN_Buffer_AdjustUsedBytes(mbuf);
|
|
|
|
/* digest TLV */
|
|
rv=GWEN_MDigest_Update(md, (const uint8_t*) GWEN_Buffer_GetStart(mbuf), GWEN_Buffer_GetUsedBytes(mbuf));
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Buffer_free(mbuf);
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
|
|
if (!checkOnly) {
|
|
mode_t mode=0;
|
|
|
|
if (symlink(GWEN_Buffer_GetStart(mbuf), fname)) {
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "symlink(%s, %s): %d (%s)",
|
|
GWEN_Buffer_GetStart(mbuf),
|
|
fname, errno, strerror(errno));
|
|
GWEN_Buffer_free(mbuf);
|
|
GWEN_MDigest_free(md);
|
|
return GWEN_ERROR_IO;
|
|
}
|
|
/* owner perms */
|
|
if (perms & GWEN_SYNCIO_FILE_FLAGS_UREAD)
|
|
mode|=S_IRUSR;
|
|
if (perms & GWEN_SYNCIO_FILE_FLAGS_UWRITE)
|
|
mode|=S_IWUSR;
|
|
if (perms & GWEN_SYNCIO_FILE_FLAGS_UEXEC)
|
|
mode|=S_IXUSR;
|
|
|
|
#if 0 /* CHMOD on symlinks doesn't work */
|
|
|
|
/* group perms */
|
|
#ifdef S_IRGRP
|
|
if (perms & GWEN_SYNCIO_FILE_FLAGS_GREAD) mode|=S_IRGRP;
|
|
#endif
|
|
#ifdef S_IWGRP
|
|
if (perms & GWEN_SYNCIO_FILE_FLAGS_GWRITE) mode|=S_IWGRP;
|
|
#endif
|
|
#ifdef S_IXGRP
|
|
if (perms & GWEN_SYNCIO_FILE_FLAGS_GEXEC) mode|=S_IXGRP;
|
|
#endif
|
|
|
|
/* other perms */
|
|
#ifdef S_IROTH
|
|
if (perms & GWEN_SYNCIO_FILE_FLAGS_OREAD) mode|=S_IROTH;
|
|
#endif
|
|
#ifdef S_IWOTH
|
|
if (perms & GWEN_SYNCIO_FILE_FLAGS_OWRITE) mode|=S_IWOTH;
|
|
#endif
|
|
#ifdef S_IXOTH
|
|
if (perms & GWEN_SYNCIO_FILE_FLAGS_OEXEC) mode|=S_IXOTH;
|
|
#endif
|
|
|
|
rv=chmod(fname, mode);
|
|
if (rv<0) {
|
|
DBG_WARN(GWEN_LOGDOMAIN, "chmod(%s): %d (%s), ignoring",
|
|
fname, errno, strerror(errno));
|
|
}
|
|
|
|
#endif
|
|
}
|
|
GWEN_Buffer_free(mbuf);
|
|
}
|
|
|
|
/* finish hash */
|
|
rv=GWEN_MDigest_End(md);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
|
|
/* read and check hash */
|
|
mpos=GWEN_SarFileHeader_GetHashPos(fh);
|
|
if (mpos) {
|
|
GWEN_BUFFER *mbuf;
|
|
|
|
/* seek to end of file */
|
|
pos=GWEN_SyncIo_File_Seek(sr->archiveSio, mpos, GWEN_SyncIo_File_Whence_Set);
|
|
if (pos<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", (int) pos);
|
|
GWEN_MDigest_free(md);
|
|
return (int) pos;
|
|
}
|
|
|
|
/* read 20 bytes of hash */
|
|
mbuf=GWEN_Buffer_new(0, 20, 0, 1);
|
|
rv=GWEN_SyncIo_ReadForced(sr->archiveSio,
|
|
(uint8_t*) GWEN_Buffer_GetStart(mbuf),
|
|
20);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Buffer_free(mbuf);
|
|
GWEN_MDigest_free(md);
|
|
if (!checkOnly)
|
|
unlink(fname);
|
|
return rv;
|
|
}
|
|
GWEN_Buffer_IncrementPos(mbuf, 20);
|
|
GWEN_Buffer_AdjustUsedBytes(mbuf);
|
|
|
|
if (memcmp(GWEN_MDigest_GetDigestPtr(md),
|
|
GWEN_Buffer_GetStart(mbuf),
|
|
20)!=0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Buffer_free(mbuf);
|
|
GWEN_MDigest_free(md);
|
|
if (!checkOnly)
|
|
unlink(fname);
|
|
return GWEN_ERROR_BAD_DATA;
|
|
}
|
|
|
|
GWEN_Buffer_free(mbuf);
|
|
}
|
|
|
|
GWEN_MDigest_free(md);
|
|
|
|
return 0;
|
|
#else
|
|
# warning "Function symlink() is not available"
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "Function symlink() is not available");
|
|
return GWEN_ERROR_IO;
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
int GWEN_Sar_ExtractAndDigestFileDir(GWEN_SAR *sr, const GWEN_SAR_FILEHEADER *fh, int checkOnly) {
|
|
int rv;
|
|
const char *fname;
|
|
uint64_t dpos;
|
|
uint64_t fsize;
|
|
uint64_t hsize;
|
|
uint64_t hpos;
|
|
uint64_t mpos;
|
|
uint64_t pos;
|
|
GWEN_MDIGEST *md;
|
|
GWEN_BUFFER *mbuf;
|
|
uint32_t perms;
|
|
|
|
assert(sr);
|
|
assert(sr->refCount);
|
|
|
|
md=GWEN_MDigest_Rmd160_new();
|
|
rv=GWEN_MDigest_Begin(md);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
|
|
fname=GWEN_SarFileHeader_GetPath(fh);
|
|
assert(fname);
|
|
perms=GWEN_SarFileHeader_GetPermissions(fh);
|
|
fsize=GWEN_SarFileHeader_GetDataSize(fh); /* not FileSize!! */
|
|
dpos=GWEN_SarFileHeader_GetDataPos(fh);
|
|
|
|
hpos=GWEN_SarFileHeader_GetHeaderStartPos(fh);
|
|
hsize=GWEN_SarFileHeader_GetHeaderSize(fh);
|
|
assert(hsize);
|
|
|
|
/* seek to end of file */
|
|
pos=GWEN_SyncIo_File_Seek(sr->archiveSio, hpos, GWEN_SyncIo_File_Whence_Set);
|
|
if (pos<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", (int) pos);
|
|
GWEN_MDigest_free(md);
|
|
return (int) pos;
|
|
}
|
|
|
|
mbuf=GWEN_Buffer_new(0, hsize, 0, 1);
|
|
rv=GWEN_SyncIo_ReadForced(sr->archiveSio,
|
|
(uint8_t*) GWEN_Buffer_GetStart(mbuf),
|
|
hsize);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Buffer_free(mbuf);
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
GWEN_Buffer_IncrementPos(mbuf, hsize);
|
|
GWEN_Buffer_AdjustUsedBytes(mbuf);
|
|
|
|
/* digest TLV */
|
|
rv=GWEN_MDigest_Update(md, (const uint8_t*) GWEN_Buffer_GetStart(mbuf), GWEN_Buffer_GetUsedBytes(mbuf));
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Buffer_free(mbuf);
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
GWEN_Buffer_free(mbuf);
|
|
|
|
/* finish hash */
|
|
rv=GWEN_MDigest_End(md);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
|
|
/* read and check hash */
|
|
mpos=GWEN_SarFileHeader_GetHashPos(fh);
|
|
if (mpos) {
|
|
GWEN_BUFFER *mbuf;
|
|
|
|
/* seek to end of file */
|
|
pos=GWEN_SyncIo_File_Seek(sr->archiveSio, mpos, GWEN_SyncIo_File_Whence_Set);
|
|
if (pos<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", (int) pos);
|
|
GWEN_MDigest_free(md);
|
|
return (int) pos;
|
|
}
|
|
|
|
/* read 20 bytes of hash */
|
|
mbuf=GWEN_Buffer_new(0, 20, 0, 1);
|
|
rv=GWEN_SyncIo_ReadForced(sr->archiveSio,
|
|
(uint8_t*) GWEN_Buffer_GetStart(mbuf),
|
|
20);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Buffer_free(mbuf);
|
|
GWEN_MDigest_free(md);
|
|
unlink(fname);
|
|
return rv;
|
|
}
|
|
GWEN_Buffer_IncrementPos(mbuf, 20);
|
|
GWEN_Buffer_AdjustUsedBytes(mbuf);
|
|
|
|
if (memcmp(GWEN_MDigest_GetDigestPtr(md),
|
|
GWEN_Buffer_GetStart(mbuf),
|
|
20)!=0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Buffer_free(mbuf);
|
|
GWEN_MDigest_free(md);
|
|
unlink(fname);
|
|
return GWEN_ERROR_BAD_DATA;
|
|
}
|
|
|
|
GWEN_Buffer_free(mbuf);
|
|
}
|
|
|
|
GWEN_MDigest_free(md);
|
|
|
|
if (!checkOnly) {
|
|
mode_t mode=0;
|
|
|
|
/* owner perms */
|
|
if (perms & GWEN_SYNCIO_FILE_FLAGS_UREAD)
|
|
mode|=S_IRUSR;
|
|
if (perms & GWEN_SYNCIO_FILE_FLAGS_UWRITE)
|
|
mode|=S_IWUSR;
|
|
if (perms & GWEN_SYNCIO_FILE_FLAGS_UEXEC)
|
|
mode|=S_IXUSR;
|
|
|
|
/* group perms */
|
|
#ifdef S_IRGRP
|
|
if (perms & GWEN_SYNCIO_FILE_FLAGS_GREAD) mode|=S_IRGRP;
|
|
#endif
|
|
#ifdef S_IWGRP
|
|
if (perms & GWEN_SYNCIO_FILE_FLAGS_GWRITE) mode|=S_IWGRP;
|
|
#endif
|
|
#ifdef S_IXGRP
|
|
if (perms & GWEN_SYNCIO_FILE_FLAGS_GEXEC) mode|=S_IXGRP;
|
|
#endif
|
|
|
|
/* other perms */
|
|
#ifdef S_IROTH
|
|
if (perms & GWEN_SYNCIO_FILE_FLAGS_OREAD) mode|=S_IROTH;
|
|
#endif
|
|
#ifdef S_IWOTH
|
|
if (perms & GWEN_SYNCIO_FILE_FLAGS_OWRITE) mode|=S_IWOTH;
|
|
#endif
|
|
#ifdef S_IXOTH
|
|
if (perms & GWEN_SYNCIO_FILE_FLAGS_OEXEC) mode|=S_IXOTH;
|
|
#endif
|
|
|
|
/* create folder */
|
|
#ifndef OS_WIN32
|
|
rv=mkdir(fname, mode);
|
|
#else
|
|
rv=mkdir(fname);
|
|
#endif
|
|
if (rv) {
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "mkdir(%s): %d (%s)",
|
|
fname, errno, strerror(errno));
|
|
return GWEN_ERROR_IO;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_Sar_ExtractAndDigestFile(GWEN_SAR *sr, const GWEN_SAR_FILEHEADER *fh, int checkOnly) {
|
|
int rv;
|
|
|
|
switch(GWEN_SarFileHeader_GetFileType(fh)) {
|
|
case GWEN_SarFileHeader_FType_File:
|
|
rv=GWEN_Sar_ExtractAndDigestFileReg(sr, fh, checkOnly);
|
|
break;
|
|
case GWEN_SarFileHeader_FType_Dir:
|
|
rv=GWEN_Sar_ExtractAndDigestFileDir(sr, fh, checkOnly);
|
|
break;
|
|
case GWEN_SarFileHeader_FType_SymLink:
|
|
rv=GWEN_Sar_ExtractAndDigestFileLink(sr, fh, checkOnly);
|
|
break;
|
|
default:
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "File type %d not supported", GWEN_SarFileHeader_GetFileType(fh));
|
|
return GWEN_ERROR_INVALID;
|
|
}
|
|
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
return rv;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_Sar_ExtractFile(GWEN_SAR *sr, const GWEN_SAR_FILEHEADER *fh) {
|
|
int rv;
|
|
|
|
rv=GWEN_Sar_ExtractAndDigestFile(sr, fh, 0);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
return rv;
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_Sar_CheckFile(GWEN_SAR *sr, const GWEN_SAR_FILEHEADER *fh) {
|
|
int rv;
|
|
|
|
rv=GWEN_Sar_ExtractAndDigestFile(sr, fh, 1);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
return rv;
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
|
|
const GWEN_SAR_FILEHEADER_LIST *GWEN_Sar_GetHeaders(GWEN_SAR *sr) {
|
|
assert(sr);
|
|
assert(sr->refCount);
|
|
return sr->headers;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_Sar__UnpackArchive(const char *inFile, const char *where) {
|
|
GWEN_SAR *sr;
|
|
int rv;
|
|
const GWEN_SAR_FILEHEADER_LIST *fhl;
|
|
|
|
/* open archive file */
|
|
sr=GWEN_Sar_new();
|
|
rv=GWEN_Sar_OpenArchive(sr, inFile,
|
|
GWEN_SyncIo_File_CreationMode_OpenExisting,
|
|
GWEN_SYNCIO_FILE_FLAGS_READ);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
return rv;
|
|
}
|
|
|
|
/* change to "where" */
|
|
if (chdir(where)) {
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "chdir(%s): %s", where, strerror(errno));
|
|
GWEN_Sar_CloseArchive(sr, 1);
|
|
GWEN_Sar_free(sr);
|
|
return GWEN_ERROR_IO;
|
|
}
|
|
|
|
fhl=GWEN_Sar_GetHeaders(sr);
|
|
if (fhl) {
|
|
const GWEN_SAR_FILEHEADER *fh;
|
|
uint32_t pid;
|
|
|
|
pid=GWEN_Gui_ProgressStart(GWEN_GUI_PROGRESS_DELAY |
|
|
GWEN_GUI_PROGRESS_SHOW_ABORT |
|
|
GWEN_GUI_PROGRESS_ALLOW_EMBED |
|
|
GWEN_GUI_PROGRESS_SHOW_PROGRESS,
|
|
I18N("File Operation"),
|
|
I18N("Unpacking archive file"),
|
|
GWEN_SarFileHeader_List_GetCount(fhl),
|
|
0);
|
|
|
|
fh=GWEN_SarFileHeader_List_First(fhl);
|
|
while(fh) {
|
|
const char *s;
|
|
|
|
s=GWEN_SarFileHeader_GetPath(fh);
|
|
rv=GWEN_Sar_ExtractFile(sr, fh);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
GWEN_Sar_CloseArchive(sr, 1);
|
|
GWEN_Sar_free(sr);
|
|
}
|
|
|
|
rv=GWEN_Gui_ProgressAdvance(pid, GWEN_GUI_PROGRESS_ONE);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
GWEN_Sar_CloseArchive(sr, 1);
|
|
GWEN_Sar_free(sr);
|
|
return rv;
|
|
}
|
|
|
|
fh=GWEN_SarFileHeader_List_Next(fh);
|
|
}
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
}
|
|
|
|
rv=GWEN_Sar_CloseArchive(sr, 0);
|
|
if (rv<0) {
|
|
fprintf(stderr, "Error closing archive (%d)\n", rv);
|
|
return 2;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_Sar_UnpackArchive(const char *inFile, const char *where) {
|
|
char savedPwd[300];
|
|
int rv;
|
|
|
|
/* get current working dir */
|
|
if (getcwd(savedPwd, sizeof(savedPwd)-1)==NULL) {
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "getcwd(): %s", strerror(errno));
|
|
return GWEN_ERROR_IO;
|
|
}
|
|
savedPwd[sizeof(savedPwd)-1]=0;
|
|
|
|
rv=GWEN_Sar__UnpackArchive(inFile, where);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
}
|
|
|
|
/* change back to previous pwd */
|
|
if (chdir(savedPwd)) {
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "chdir(%s): %s", savedPwd, strerror(errno));
|
|
return GWEN_ERROR_IO;
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_Sar_Sign(GWEN_SAR *sr, GWEN_CRYPTMGR *cm) {
|
|
int rv;
|
|
GWEN_SAR_FILEHEADER_LIST *fhl;
|
|
|
|
assert(sr);
|
|
assert(sr->refCount);
|
|
|
|
if (sr->openMode!=GWEN_Sar_OpenMode_Opened &&
|
|
sr->openMode!=GWEN_Sar_OpenMode_Created) {
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "Archive not open");
|
|
return GWEN_ERROR_NOT_OPEN;
|
|
}
|
|
|
|
if (sr->signaturePos!=0 || sr->signatureSize!=0) {
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "There already is a signature in the archive file");
|
|
return GWEN_ERROR_INVALID;
|
|
}
|
|
|
|
fhl=sr->headers;
|
|
if (fhl) {
|
|
GWEN_SAR_FILEHEADER *fh;
|
|
uint32_t pid;
|
|
GWEN_MDIGEST *md;
|
|
uint8_t hashBuf[21];
|
|
GWEN_BUFFER *sbuf;
|
|
GWEN_BUFFER *tbuf;
|
|
int64_t pos;
|
|
|
|
md=GWEN_MDigest_Rmd160_new();
|
|
rv=GWEN_MDigest_Begin(md);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
|
|
/* clear SIGNED flags */
|
|
fh=GWEN_SarFileHeader_List_First(fhl);
|
|
while(fh) {
|
|
GWEN_SarFileHeader_SubFlags(fh, GWEN_SAR_FILEHEADER_FLAGS_SIGNED);
|
|
fh=GWEN_SarFileHeader_List_Next(fh);
|
|
}
|
|
|
|
/* calculate hash over all file hashes */
|
|
pid=GWEN_Gui_ProgressStart(GWEN_GUI_PROGRESS_DELAY |
|
|
GWEN_GUI_PROGRESS_SHOW_ABORT |
|
|
GWEN_GUI_PROGRESS_ALLOW_EMBED |
|
|
GWEN_GUI_PROGRESS_SHOW_PROGRESS,
|
|
I18N("File Operation"),
|
|
I18N("Signing archive file"),
|
|
GWEN_SarFileHeader_List_GetCount(fhl),
|
|
0);
|
|
fh=GWEN_SarFileHeader_List_First(fhl);
|
|
while(fh) {
|
|
const char *s;
|
|
uint64_t hpos;
|
|
|
|
s=GWEN_SarFileHeader_GetPath(fh);
|
|
hpos=GWEN_SarFileHeader_GetHashPos(fh);
|
|
if (hpos==0) {
|
|
DBG_WARN(GWEN_LOGDOMAIN, "File %s has no valid hash", s?s:"(unnamed)");
|
|
}
|
|
else {
|
|
/* seek to start of hash */
|
|
pos=GWEN_SyncIo_File_Seek(sr->archiveSio, hpos, GWEN_SyncIo_File_Whence_Set);
|
|
if (pos<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", (int) pos);
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
GWEN_MDigest_free(md);
|
|
return (int) pos;
|
|
}
|
|
|
|
/* read hash */
|
|
rv=GWEN_SyncIo_ReadForced(sr->archiveSio, hashBuf, 20);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
|
|
/* digest hash */
|
|
rv=GWEN_MDigest_Update(md, hashBuf, 20);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
|
|
|
|
GWEN_SarFileHeader_AddFlags(fh, GWEN_SAR_FILEHEADER_FLAGS_SIGNED);
|
|
}
|
|
|
|
rv=GWEN_Gui_ProgressAdvance(pid, GWEN_GUI_PROGRESS_ONE);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
|
|
fh=GWEN_SarFileHeader_List_Next(fh);
|
|
}
|
|
|
|
/* finish hash */
|
|
rv=GWEN_MDigest_End(md);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
|
|
/* sign hash */
|
|
sbuf=GWEN_Buffer_new(0, 256, 0, 1);
|
|
rv=GWEN_CryptMgr_Sign(cm,
|
|
GWEN_MDigest_GetDigestPtr(md),
|
|
GWEN_MDigest_GetDigestSize(md),
|
|
sbuf);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Buffer_free(sbuf);
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
GWEN_MDigest_free(md);
|
|
|
|
/* create signature TLV */
|
|
tbuf=GWEN_Buffer_new(0, 256, 0, 1);
|
|
rv=GWEN_TLV_DirectlyToBuffer(GWEN_SAR_TAG_SIGNATURE, 0x00,
|
|
GWEN_Buffer_GetStart(sbuf),
|
|
GWEN_Buffer_GetUsedBytes(sbuf),
|
|
1, tbuf);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Buffer_free(tbuf);
|
|
GWEN_Buffer_free(sbuf);
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
return rv;
|
|
}
|
|
|
|
/* seek to end of file */
|
|
pos=GWEN_SyncIo_File_Seek(sr->archiveSio, 0, GWEN_SyncIo_File_Whence_End);
|
|
if (pos<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", (int) pos);
|
|
GWEN_Buffer_free(tbuf);
|
|
GWEN_Buffer_free(sbuf);
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
return (int) pos;
|
|
}
|
|
|
|
/* write TLV into archive file */
|
|
rv=GWEN_SyncIo_WriteForced(sr->archiveSio,
|
|
(const uint8_t*) GWEN_Buffer_GetStart(tbuf),
|
|
GWEN_Buffer_GetUsedBytes(tbuf));
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Buffer_free(tbuf);
|
|
GWEN_Buffer_free(sbuf);
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
return rv;
|
|
}
|
|
|
|
|
|
GWEN_Buffer_free(tbuf);
|
|
GWEN_Buffer_free(sbuf);
|
|
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_Sar_Verify(GWEN_SAR *sr, GWEN_CRYPTMGR *cm) {
|
|
int rv;
|
|
GWEN_SAR_FILEHEADER_LIST *fhl;
|
|
|
|
assert(sr);
|
|
assert(sr->refCount);
|
|
|
|
if (sr->openMode!=GWEN_Sar_OpenMode_Opened &&
|
|
sr->openMode!=GWEN_Sar_OpenMode_Created) {
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "Archive not open");
|
|
return GWEN_ERROR_NOT_OPEN;
|
|
}
|
|
|
|
if (sr->signaturePos==0 || sr->signatureSize==0) {
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "No valid signature data in the archive file");
|
|
return GWEN_ERROR_INVALID;
|
|
}
|
|
|
|
fhl=sr->headers;
|
|
if (fhl) {
|
|
GWEN_SAR_FILEHEADER *fh;
|
|
uint32_t pid;
|
|
GWEN_MDIGEST *md;
|
|
uint8_t hashBuf[21];
|
|
GWEN_BUFFER *sbuf;
|
|
GWEN_BUFFER *hbuf;
|
|
int64_t pos;
|
|
|
|
md=GWEN_MDigest_Rmd160_new();
|
|
rv=GWEN_MDigest_Begin(md);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
|
|
/* clear SIGNED flags */
|
|
fh=GWEN_SarFileHeader_List_First(fhl);
|
|
while(fh) {
|
|
GWEN_SarFileHeader_SubFlags(fh, GWEN_SAR_FILEHEADER_FLAGS_SIGNED);
|
|
fh=GWEN_SarFileHeader_List_Next(fh);
|
|
}
|
|
|
|
/* calculate hash over all file hashes */
|
|
pid=GWEN_Gui_ProgressStart(GWEN_GUI_PROGRESS_DELAY |
|
|
GWEN_GUI_PROGRESS_SHOW_ABORT |
|
|
GWEN_GUI_PROGRESS_ALLOW_EMBED |
|
|
GWEN_GUI_PROGRESS_SHOW_PROGRESS,
|
|
I18N("File Operation"),
|
|
I18N("Signing archive file"),
|
|
GWEN_SarFileHeader_List_GetCount(fhl),
|
|
0);
|
|
fh=GWEN_SarFileHeader_List_First(fhl);
|
|
while(fh) {
|
|
const char *s;
|
|
uint64_t hpos;
|
|
|
|
s=GWEN_SarFileHeader_GetPath(fh);
|
|
hpos=GWEN_SarFileHeader_GetHashPos(fh);
|
|
if (hpos==0) {
|
|
DBG_WARN(GWEN_LOGDOMAIN, "File %s has no valid hash", s?s:"(unnamed)");
|
|
}
|
|
else {
|
|
/* seek to start of hash */
|
|
pos=GWEN_SyncIo_File_Seek(sr->archiveSio, hpos, GWEN_SyncIo_File_Whence_Set);
|
|
if (pos<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", (int) pos);
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
GWEN_MDigest_free(md);
|
|
return (int) pos;
|
|
}
|
|
|
|
/* read hash */
|
|
rv=GWEN_SyncIo_ReadForced(sr->archiveSio, hashBuf, 20);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
|
|
/* digest hash */
|
|
rv=GWEN_MDigest_Update(md, hashBuf, 20);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
|
|
|
|
GWEN_SarFileHeader_AddFlags(fh, GWEN_SAR_FILEHEADER_FLAGS_SIGNED);
|
|
}
|
|
|
|
rv=GWEN_Gui_ProgressAdvance(pid, GWEN_GUI_PROGRESS_ONE);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
|
|
fh=GWEN_SarFileHeader_List_Next(fh);
|
|
}
|
|
|
|
/* finish hash */
|
|
rv=GWEN_MDigest_End(md);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
|
|
/* seek to start of signature data */
|
|
pos=GWEN_SyncIo_File_Seek(sr->archiveSio, sr->signaturePos, GWEN_SyncIo_File_Whence_Set);
|
|
if (pos<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", (int) pos);
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
GWEN_MDigest_free(md);
|
|
return (int) pos;
|
|
}
|
|
|
|
/* read signature data */
|
|
sbuf=GWEN_Buffer_new(0, sr->signatureSize, 0, 1);
|
|
rv=GWEN_SyncIo_ReadForced(sr->archiveSio,
|
|
(uint8_t*) GWEN_Buffer_GetStart(sbuf),
|
|
sr->signatureSize);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Buffer_free(sbuf);
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
GWEN_Buffer_IncrementPos(sbuf, sr->signatureSize);
|
|
GWEN_Buffer_AdjustUsedBytes(sbuf);
|
|
|
|
/* verify signature */
|
|
hbuf=GWEN_Buffer_new(0, 256, 0, 1);
|
|
rv=GWEN_CryptMgr_Verify(cm,
|
|
(const uint8_t*) GWEN_Buffer_GetStart(sbuf),
|
|
GWEN_Buffer_GetUsedBytes(sbuf),
|
|
hbuf);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Buffer_free(hbuf);
|
|
GWEN_Buffer_free(sbuf);
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
GWEN_MDigest_free(md);
|
|
return rv;
|
|
}
|
|
GWEN_Buffer_free(sbuf);
|
|
|
|
/* verify hash */
|
|
if (GWEN_Buffer_GetUsedBytes(hbuf)!=20) {
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "Invalid size of signed hash (%d)", GWEN_Buffer_GetUsedBytes(hbuf));
|
|
GWEN_Buffer_free(hbuf);
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
GWEN_MDigest_free(md);
|
|
return GWEN_ERROR_BAD_DATA;
|
|
}
|
|
if (memcmp(GWEN_Buffer_GetStart(hbuf), GWEN_MDigest_GetDigestPtr(md), 20)!=0) {
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "Invalid hash, data is invalid!");
|
|
GWEN_Buffer_free(hbuf);
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
GWEN_MDigest_free(md);
|
|
return GWEN_ERROR_VERIFY;
|
|
}
|
|
DBG_INFO(GWEN_LOGDOMAIN, "Signature is valid");
|
|
|
|
GWEN_MDigest_free(md);
|
|
GWEN_Buffer_free(hbuf);
|
|
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_Sar_VerifyArchive(const char *inFile, const char *signer, GWEN_CRYPT_KEY *key) {
|
|
GWEN_SAR *sr;
|
|
int rv;
|
|
|
|
/* open archive file */
|
|
sr=GWEN_Sar_new();
|
|
rv=GWEN_Sar_OpenArchive(sr, inFile,
|
|
GWEN_SyncIo_File_CreationMode_OpenExisting,
|
|
GWEN_SYNCIO_FILE_FLAGS_READ);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Sar_free(sr);
|
|
return rv;
|
|
}
|
|
else {
|
|
GWEN_CRYPTMGR *cm;
|
|
|
|
cm=GWEN_CryptMgrKeys_new(NULL, NULL, signer, key, 1);
|
|
|
|
/* verify */
|
|
rv=GWEN_Sar_Verify(sr, cm);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_CryptMgr_free(cm);
|
|
GWEN_Sar_CloseArchive(sr, 1);
|
|
GWEN_Sar_free(sr);
|
|
return rv;
|
|
}
|
|
GWEN_CryptMgr_free(cm);
|
|
|
|
/* close archive */
|
|
rv=GWEN_Sar_CloseArchive(sr, 0);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Sar_CloseArchive(sr, 1);
|
|
GWEN_Sar_free(sr);
|
|
return rv;
|
|
}
|
|
GWEN_Sar_free(sr);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int GWEN_Sar_SignArchive(const char *inFile, const char *signer, GWEN_CRYPT_KEY *key) {
|
|
GWEN_SAR *sr;
|
|
int rv;
|
|
|
|
/* open archive file */
|
|
sr=GWEN_Sar_new();
|
|
rv=GWEN_Sar_OpenArchive(sr, inFile,
|
|
GWEN_SyncIo_File_CreationMode_OpenExisting,
|
|
GWEN_SYNCIO_FILE_FLAGS_READ);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Sar_free(sr);
|
|
return rv;
|
|
}
|
|
else {
|
|
GWEN_CRYPTMGR *cm;
|
|
|
|
cm=GWEN_CryptMgrKeys_new(NULL, NULL, signer, key, 1);
|
|
|
|
/* verify */
|
|
rv=GWEN_Sar_Sign(sr, cm);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_CryptMgr_free(cm);
|
|
GWEN_Sar_CloseArchive(sr, 1);
|
|
GWEN_Sar_free(sr);
|
|
return rv;
|
|
}
|
|
GWEN_CryptMgr_free(cm);
|
|
|
|
/* close archive */
|
|
rv=GWEN_Sar_CloseArchive(sr, 0);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Sar_CloseArchive(sr, 1);
|
|
GWEN_Sar_free(sr);
|
|
return rv;
|
|
}
|
|
GWEN_Sar_free(sr);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int GWEN_Sar_CheckArchive(const char *inFile) {
|
|
GWEN_SAR *sr;
|
|
int rv;
|
|
const GWEN_SAR_FILEHEADER_LIST *fhl;
|
|
|
|
/* open archive file */
|
|
sr=GWEN_Sar_new();
|
|
rv=GWEN_Sar_OpenArchive(sr, inFile,
|
|
GWEN_SyncIo_File_CreationMode_OpenExisting,
|
|
GWEN_SYNCIO_FILE_FLAGS_READ);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
return rv;
|
|
}
|
|
|
|
fhl=GWEN_Sar_GetHeaders(sr);
|
|
if (fhl) {
|
|
const GWEN_SAR_FILEHEADER *fh;
|
|
uint32_t pid;
|
|
|
|
pid=GWEN_Gui_ProgressStart(GWEN_GUI_PROGRESS_DELAY |
|
|
GWEN_GUI_PROGRESS_SHOW_ABORT |
|
|
GWEN_GUI_PROGRESS_ALLOW_EMBED |
|
|
GWEN_GUI_PROGRESS_SHOW_PROGRESS,
|
|
I18N("File Operation"),
|
|
I18N("Checking archive file"),
|
|
GWEN_SarFileHeader_List_GetCount(fhl),
|
|
0);
|
|
|
|
fh=GWEN_SarFileHeader_List_First(fhl);
|
|
while(fh) {
|
|
const char *s;
|
|
|
|
s=GWEN_SarFileHeader_GetPath(fh);
|
|
rv=GWEN_Sar_CheckFile(sr, fh);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
GWEN_Sar_CloseArchive(sr, 1);
|
|
GWEN_Sar_free(sr);
|
|
}
|
|
|
|
rv=GWEN_Gui_ProgressAdvance(pid, GWEN_GUI_PROGRESS_ONE);
|
|
if (rv<0) {
|
|
DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
GWEN_Sar_CloseArchive(sr, 1);
|
|
GWEN_Sar_free(sr);
|
|
return rv;
|
|
}
|
|
|
|
fh=GWEN_SarFileHeader_List_Next(fh);
|
|
}
|
|
GWEN_Gui_ProgressEnd(pid);
|
|
}
|
|
|
|
rv=GWEN_Sar_CloseArchive(sr, 0);
|
|
if (rv<0) {
|
|
fprintf(stderr, "Error closing archive (%d)\n", rv);
|
|
return 2;
|
|
}
|
|
GWEN_Sar_free(sr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|