int regmulti_rest_getfile(cregmulti *m, int index, cdico **filehead, char *data, u64 *datsize, u32 bufsize) { u32 offset; u64 filesize; if (!m || !filehead) { errprintf("invalid param\n"); return -1; } if (index >= m->count) { errprintf("index=%d out of scope: the structure only contains %ld items\n", index, (long)m->count); return -1; } // ---- return the header to the calling function *filehead=m->objhead[index]; // ---- return the data to the calling function if (dico_get_u64(m->objhead[index], DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_SIZE, &filesize)!=0) { errprintf("Cannot read filesize DISKITEMKEY_SIZE from archive\n"); return -1; } if (dico_get_u32(m->objhead[index], DICO_OBJ_SECTION_STDATTR, DISKITEMKEY_MULTIFILESOFFSET, &offset)!=0) { errprintf("Cannot read filesize DISKITEMKEY_SIZE from archive\n"); return -1; } *datsize=filesize; memcpy(data, m->data+offset, filesize); return 0; }
void *thread_reader_fct(void *args) { char magic[FSA_SIZEOF_MAGIC]; struct s_blockinfo blkinfo; u32 endofarchive=false; carchreader *ai=NULL; cdico *dico=NULL; int skipblock; u16 fsid; int sumok; int status; u64 errors; s64 lres; int res; // init errors=0; inc_secthreads(); if ((ai=(carchreader *)args)==NULL) { errprintf("ai is NULL\n"); goto thread_reader_fct_error; } // open archive file if (archreader_volpath(ai)!=0) { errprintf("archreader_volpath() failed\n"); goto thread_reader_fct_error; } if (archreader_open(ai)!=0) { errprintf("archreader_open(%s) failed\n", ai->basepath); goto thread_reader_fct_error; } // read volume header if (archreader_read_volheader(ai)!=0) { errprintf("archio_read_volheader() failed\n"); goto thread_reader_fct_error; } // ---- read main archive header if ((res=archreader_read_header(ai, magic, &dico, false, &fsid))!=FSAERR_SUCCESS) { errprintf("archreader_read_header() failed to read the archive header\n"); goto thread_reader_fct_error; // this header is required to continue } if (dico_get_u32(dico, 0, MAINHEADKEY_ARCHIVEID, &ai->archid)!=0) { msgprintf(3, "cannot get archive-id from main header\n"); goto thread_reader_fct_error; } if ((lres=queue_add_header(&g_queue, dico, magic, fsid))!=FSAERR_SUCCESS) { errprintf("queue_add_header()=%ld=%s failed to add the archive header\n", (long)lres, error_int_to_string(lres)); goto thread_reader_fct_error; } // read all other data from file (filesys-header, normal objects headers, ...) while (endofarchive==false && get_stopfillqueue()==false) { if ((res=archreader_read_header(ai, magic, &dico, true, &fsid))!=FSAERR_SUCCESS) { dico_destroy(dico); msgprintf(MSG_STACK, "archreader_read_header() failed to read next header\n"); if (res==OLDERR_MINOR) // header is corrupt or not what we expected { errors++; msgprintf(MSG_DEBUG1, "OLDERR_MINOR\n"); continue; } else // fatal error (eg: cannot read archive from disk) { msgprintf(MSG_DEBUG1, "!OLDERR_MINOR\n"); goto thread_reader_fct_error; } } // read header and see if it's for archive management or higher level data if (strncmp(magic, FSA_MAGIC_VOLF, FSA_SIZEOF_MAGIC)==0) // header is "end of volume" { archreader_close(ai); // check the "end of archive" flag in header if (dico_get_u32(dico, 0, VOLUMEFOOTKEY_LASTVOL, &endofarchive)!=0) { errprintf("cannot get compr from block-header\n"); goto thread_reader_fct_error; } msgprintf(MSG_VERB2, "End of volume [%s]\n", ai->volpath); if (endofarchive!=true) { archreader_incvolume(ai, false); while (regfile_exists(ai->volpath)!=true) { // wait until the queue is empty so that the main thread does not pollute the screen while (queue_count(&g_queue)>0) usleep(5000); fflush(stdout); fflush(stderr); msgprintf(MSG_FORCE, "File [%s] is not found, please type the path to volume %ld:\n", ai->volpath, (long)ai->curvol); fprintf(stdout, "New path:> "); res=scanf("%256s", ai->volpath); } msgprintf(MSG_VERB2, "New volume is [%s]\n", ai->volpath); if (archreader_open(ai)!=0) { msgprintf(MSG_STACK, "archreader_open() failed\n"); goto thread_reader_fct_error; } if (archreader_read_volheader(ai)!=0) { msgprintf(MSG_STACK, "archio_read_volheader() failed\n"); goto thread_reader_fct_error; } } dico_destroy(dico); } else // high-level archive (not involved in volume management) { if (strncmp(magic, FSA_MAGIC_BLKH, FSA_SIZEOF_MAGIC)==0) // header starts a data block { skipblock=(g_fsbitmap[fsid]==0); //errprintf("DEBUG: skipblock=%d g_fsbitmap[fsid=%d]=%d\n", skipblock, (int)fsid, (int)g_fsbitmap[fsid]); if (archreader_read_block(ai, dico, skipblock, &sumok, &blkinfo)!=0) { msgprintf(MSG_STACK, "archreader_read_block() failed\n"); goto thread_reader_fct_error; } if (skipblock==false) { status=((sumok==true)?QITEM_STATUS_TODO:QITEM_STATUS_DONE); if ((lres=queue_add_block(&g_queue, &blkinfo, status))!=FSAERR_SUCCESS) { if (lres!=FSAERR_NOTOPEN) errprintf("queue_add_block()=%ld=%s failed\n", (long)lres, error_int_to_string(lres)); goto thread_reader_fct_error; } if (sumok==false) errors++; dico_destroy(dico); } } else // another higher level header { // if it's a global header or a if this local header belongs to a filesystem that the main thread needs if (fsid==FSA_FILESYSID_NULL || g_fsbitmap[fsid]==1) { if ((lres=queue_add_header(&g_queue, dico, magic, fsid))!=FSAERR_SUCCESS) { msgprintf(MSG_STACK, "queue_add_header()=%ld=%s failed\n", (long)lres, error_int_to_string(lres)); goto thread_reader_fct_error; } } else // header not used: remove data strucutre in dynamic memory { dico_destroy(dico); } } } } thread_reader_fct_error: msgprintf(MSG_DEBUG1, "THREAD-READER: queue_set_end_of_queue(&g_queue, true)\n"); queue_set_end_of_queue(&g_queue, true); // don't wait for more data from this thread dec_secthreads(); msgprintf(MSG_DEBUG1, "THREAD-READER: exit\n"); return NULL; }
int archreader_read_block(carchreader *ai, cdico *in_blkdico, int in_skipblock, int *out_sumok, struct s_blockinfo *out_blkinfo) { u32 arblockcsumorig; u32 arblockcsumcalc; u32 curblocksize; // data size u64 blockoffset; // offset of the block in the file u16 compalgo; // compression algo used u16 cryptalgo; // encryption algo used u32 finalsize; // compressed block size u32 compsize; u8 *buffer; bool corrupt; assert(ai); assert(out_sumok); assert(in_blkdico); assert(out_blkinfo); // init memset(out_blkinfo, 0, sizeof(struct s_blockinfo)); *out_sumok=-1; if (dico_get_u64(in_blkdico, 0, BLOCKHEADITEMKEY_BLOCKOFFSET, &blockoffset)!=0) { msgprintf(3, "cannot get blockoffset from block-header\n"); return -1; } if (dico_get_u32(in_blkdico, 0, BLOCKHEADITEMKEY_REALSIZE, &curblocksize)!=0 || curblocksize>FSA_MAX_BLKSIZE) { msgprintf(3, "cannot get blocksize from block-header\n"); return -1; } if (dico_get_u16(in_blkdico, 0, BLOCKHEADITEMKEY_COMPRESSALGO, &compalgo)!=0) { msgprintf(3, "cannot get BLOCKHEADITEMKEY_COMPRESSALGO from block-header\n"); return -1; } if (dico_get_u16(in_blkdico, 0, BLOCKHEADITEMKEY_ENCRYPTALGO, &cryptalgo)!=0) { msgprintf(3, "cannot get BLOCKHEADITEMKEY_ENCRYPTALGO from block-header\n"); return -1; } if (dico_get_u32(in_blkdico, 0, BLOCKHEADITEMKEY_ARSIZE, &finalsize)!=0) { msgprintf(3, "cannot get BLOCKHEADITEMKEY_ARSIZE from block-header\n"); return -1; } if (dico_get_u32(in_blkdico, 0, BLOCKHEADITEMKEY_COMPSIZE, &compsize)!=0) { msgprintf(3, "cannot get BLOCKHEADITEMKEY_COMPSIZE from block-header\n"); return -1; } if (dico_get_u32(in_blkdico, 0, BLOCKHEADITEMKEY_ARCSUM, &arblockcsumorig)!=0) { msgprintf(3, "cannot get BLOCKHEADITEMKEY_ARCSUM from block-header\n"); return -1; } if (in_skipblock==true) // the main thread does not need that block (block belongs to a filesys we want to skip) { if (lseek64(ai->archfd, (long)finalsize, SEEK_CUR)<0) { sysprintf("cannot skip block (finalsize=%ld) failed\n", (long)finalsize); return -1; } return 0; } // ---- allocate memory if ((buffer=malloc(finalsize))==NULL) { errprintf("cannot allocate block: malloc(%d) failed\n", finalsize); return FSAERR_ENOMEM; } if (read(ai->archfd, buffer, (long)finalsize)!=(long)finalsize) { sysprintf("cannot read block (finalsize=%ld) failed\n", (long)finalsize); free(buffer); return -1; } // prepare blkinfo out_blkinfo->blkdata=(char*)buffer; out_blkinfo->blkrealsize=curblocksize; out_blkinfo->blkoffset=blockoffset; out_blkinfo->blkarcsum=arblockcsumorig; out_blkinfo->blkcompalgo=compalgo; out_blkinfo->blkcryptalgo=cryptalgo; out_blkinfo->blkarsize=finalsize; out_blkinfo->blkcompsize=compsize; // ---- checksum arblockcsumcalc=fletcher32(buffer, finalsize); corrupt=false; if (arblockcsumcalc!=arblockcsumorig) // bad checksum { errprintf("block is corrupt at offset=%ld, blksize=%ld\n", (long)blockoffset, (long)curblocksize); corrupt=!g_options.keepcorrupt; } if (corrupt) { free(out_blkinfo->blkdata); if ((out_blkinfo->blkdata=malloc(curblocksize))==NULL) { errprintf("cannot allocate block: malloc(%d) failed\n", curblocksize); return FSAERR_ENOMEM; } memset(out_blkinfo->blkdata, 0, curblocksize); *out_sumok=false; // go to the beginning of the corrupted contents so that the next header is searched here if (lseek64(ai->archfd, -(long long)finalsize, SEEK_CUR)<0) { errprintf("lseek64() failed\n"); } } else // no corruption detected { *out_sumok=true; } return 0; }
int archreader_read_volheader(carchreader *ai) { char creatver[FSA_MAX_PROGVERLEN]; char filefmt[FSA_MAX_FILEFMTLEN]; char magic[FSA_SIZEOF_MAGIC]; cdico *d; u32 volnum; u32 readid; u16 fsid; int res; int ret=0; // init assert(ai); memset(magic, 0, sizeof(magic)); // ---- a. read header from archive file if ((res=archreader_read_header(ai, magic, &d, false, &fsid))!=FSAERR_SUCCESS) { errprintf("archreader_read_header() failed to read the archive header\n"); return -1; } // ---- b. check the magic is what we expected if (strncmp(magic, FSA_MAGIC_VOLH, FSA_SIZEOF_MAGIC)!=0) { errprintf("magic is not what we expected: found=[%s] and expected=[%s]\n", magic, FSA_MAGIC_VOLH); ret=-1; goto archio_read_volheader_error; } if (dico_get_u32(d, 0, VOLUMEHEADKEY_ARCHID, &readid)!=0) { errprintf("cannot get VOLUMEHEADKEY_ARCHID from the volume header\n"); ret=-1; goto archio_read_volheader_error; } // ---- c. check the archive id if (ai->archid==0) // archid not know: this is the first volume { ai->archid=readid; } else if (readid!=ai->archid) // archid known: not the first volume { errprintf("wrong header id: found=%.8x and expected=%.8x\n", readid, ai->archid); ret=-1; goto archio_read_volheader_error; } // ---- d. check the volnum if (dico_get_u32(d, 0, VOLUMEHEADKEY_VOLNUM, &volnum)!=0) { errprintf("cannot get VOLUMEHEADKEY_VOLNUM from the volume header\n"); ret=-1; goto archio_read_volheader_error; } if (volnum!=ai->curvol) // not the right volume number { errprintf("wrong volume number in [%s]: volnum is %d and we need volnum %d\n", ai->volpath, (int)volnum, (int)ai->curvol); ret=-1; goto archio_read_volheader_error; } // ---- d. check the the file format if (dico_get_data(d, 0, VOLUMEHEADKEY_FILEFORMATVER, filefmt, FSA_MAX_FILEFMTLEN, NULL)!=0) { errprintf("cannot find VOLUMEHEADKEY_FILEFORMATVER in main-header\n"); ret=-1; goto archio_read_volheader_error; } if (ai->filefmt[0]==0) // filefmt not know: this is the first volume { memcpy(ai->filefmt, filefmt, FSA_MAX_FILEFMTLEN); } else if (strncmp(filefmt, ai->filefmt, FSA_MAX_FILEFMTLEN)!=0) { errprintf("This archive is based on a different file format: [%s]. Cannot continue.\n", ai->filefmt); errprintf("It has been created with fsarchiver [%s], you should extrat the archive using that version.\n", ai->creatver); errprintf("The current version of the program is [%s], and it's based on format [%s]\n", FSA_VERSION, FSA_FILEFORMAT); ret=-1; goto archio_read_volheader_error; } if (dico_get_data(d, 0, VOLUMEHEADKEY_PROGVERCREAT, creatver, FSA_MAX_PROGVERLEN, NULL)!=0) { errprintf("cannot find VOLUMEHEADKEY_PROGVERCREAT in main-header\n"); ret=-1; goto archio_read_volheader_error; } if (ai->creatver[0]==0) memcpy(ai->creatver, creatver, FSA_MAX_PROGVERLEN); archio_read_volheader_error: dico_destroy(d); return ret; }