int32_t xar_hash_fromheap_out(xar_t x, xar_file_t f, xar_prop_t p, void *in, size_t inlen, void **context) { const char *opt; xar_prop_t tmpp; opt = NULL; tmpp = xar_prop_pget(p, "extracted-checksum"); if( tmpp ) { opt = xar_attr_pget(f, tmpp, "style"); } else { // The xar-1.7 release in OS X Yosemite accidentally wrote <unarchived-checksum> // instead of <extracted-checksum>. Since archives like this are now in the wild, // we check for both. tmpp = xar_prop_pget(p, "unarchived-checksum"); if( tmpp ) { opt = xar_attr_pget(f, tmpp, "style"); } } // If there's an <archived-checksum> and no <extracted-checksum> (or // <unarchived-checksum>), the archive is malformed. if ( !opt && xar_prop_pget(p, "archived-checksum") ) { xar_err_new(x); xar_err_set_string(x, "No extracted-checksum"); xar_err_callback(x, XAR_SEVERITY_FATAL, XAR_ERR_ARCHIVE_EXTRACTION); return -1; } if( !opt ) opt = xar_opt_get(x, XAR_OPT_FILECKSUM); if( !opt || (0 == strcmp(opt, XAR_OPT_VAL_NONE) ) ) return 0; if(!CONTEXT(context)) { *context = calloc(1, sizeof(struct _hash_context)); if( ! *context ) return -1; } if( ! CONTEXT(context)->unarchived ) { CONTEXT(context)->unarchived = xar_hash_new(opt, NULL); if( ! CONTEXT(context)->unarchived ) { free(*context); *context = NULL; return -1; } } if( inlen == 0 ) return 0; CONTEXT(context)->count += inlen; xar_hash_update(CONTEXT(context)->unarchived, in, inlen); return 0; }
xar_prop_t xar_ea_find(xar_file_t f, const char *name) { xar_prop_t p; for(p = xar_prop_pfirst(f); p; p = xar_prop_pnext(p)) { const char *tmp; xar_prop_t tmpp; tmp = xar_prop_getkey(p); if( strncmp(tmp, XAR_EA_FORK, strlen(XAR_EA_FORK)) != 0 ) continue; if( strlen(tmp) != strlen(XAR_EA_FORK) ) continue; tmpp = xar_prop_pget(p, "name"); if( !tmpp ) continue; tmp = xar_prop_getvalue(tmpp); if( !tmp ) continue; if( strcmp(tmp, name) == 0 ) return p; } return NULL; }
int xar_gzip_fromheap_in(xar_t x, xar_file_t f, xar_prop_t p, void **in, size_t *inlen, void **context) { const char *opt; void *out = NULL; size_t outlen, offset = 0; int r; xar_prop_t tmpp; /* on first run, we init the context and check the compression type */ if( !GZIP_CONTEXT(context) ) { *context = calloc(1,sizeof(struct _gzip_context)); opt = NULL; tmpp = xar_prop_pget(p, "encoding"); if( tmpp ) opt = xar_attr_pget(f, tmpp, "style"); if( !opt ) return 0; if( strcmp(opt, "application/x-gzip") != 0 ) return 0; inflateInit(&GZIP_CONTEXT(context)->z); GZIP_CONTEXT(context)->gzipcompressed = 1; }else if( !GZIP_CONTEXT(context)->gzipcompressed ){ /* once the context has been initialized, then we have already checked the compression type, so we need only check if we actually are compressed */ return 0; } outlen = *inlen; GZIP_CONTEXT(context)->z.next_in = *in; GZIP_CONTEXT(context)->z.avail_in = *inlen; GZIP_CONTEXT(context)->z.next_out = out; GZIP_CONTEXT(context)->z.avail_out = 0; while( GZIP_CONTEXT(context)->z.avail_in != 0 ) { outlen = outlen * 2; out = realloc(out, outlen); if( out == NULL ) abort(); GZIP_CONTEXT(context)->z.next_out = ((unsigned char *)out) + offset; GZIP_CONTEXT(context)->z.avail_out = outlen - offset; r = inflate(&(GZIP_CONTEXT(context)->z), Z_NO_FLUSH); if( (r != Z_OK) && (r != Z_STREAM_END) ) { xar_err_new(x); xar_err_set_file(x, f); xar_err_set_string(x, "Error decompressing file"); xar_err_callback(x, XAR_SEVERITY_FATAL, XAR_ERR_ARCHIVE_EXTRACTION); return -1; } offset += outlen - offset - GZIP_CONTEXT(context)->z.avail_out; if( (r == Z_STREAM_END) && (offset == 0) ) break; } free(*in); *in = out; *inlen = offset; return 0; }
off_t xar_io_get_file_offset(xar_t x, xar_file_t f, xar_prop_t p) { xar_prop_t tmpp; const char *opt = NULL; tmpp = xar_prop_pget(p, "offset"); if( tmpp ) { opt = xar_prop_getvalue(tmpp); return strtoll(opt, NULL, 0); } else { return -1; } }
int32_t xar_hash_fromheap_done(xar_t x, xar_file_t f, xar_prop_t p, void **context) { if(!CONTEXT(context)) return 0; int32_t result = 0; const char *archived_hash = NULL, *archived_style = NULL; // Fetch the existing hash from the archive if( CONTEXT(context)->archived ) { xar_prop_t tmpp = xar_prop_pget(p, "archived-checksum"); if( tmpp ) { archived_style = xar_attr_pget(f, tmpp, "style"); archived_hash = xar_prop_getvalue(tmpp); } // We have the fetched hash; now get the calculated hash if( archived_hash && archived_style ) { size_t calculated_length = -1; const char *calculated_style = strdup(xar_hash_get_digest_name(CONTEXT(context)->archived)); void *calculated_buffer = xar_hash_finish(CONTEXT(context)->archived, &calculated_length); char *calculated_hash = _xar_format_hash(calculated_buffer, calculated_length); free(calculated_buffer); // Compare int hash_match = ( strcmp(archived_hash, calculated_hash) == 0 ); int style_match = (strcmp(archived_style, calculated_style) == 0 ); if( ! hash_match || ! style_match ) { xar_err_new(x); xar_err_set_file(x, f); xar_err_set_formatted_string(x, "archived-checksum %s's do not match", archived_style); xar_err_callback(x, XAR_SEVERITY_FATAL, XAR_ERR_ARCHIVE_EXTRACTION); result = -1; } free((void *)calculated_style); free(calculated_hash); } } // Clean up the unarchived hash as well, if we have one if( CONTEXT(context)->unarchived ) { size_t length = -1; void *hash = xar_hash_finish(CONTEXT(context)->unarchived, &length); free(hash); } if(*context) { free(*context); *context = NULL; } return result; }
int64_t xar_io_get_length(xar_prop_t p) { const char *opt = NULL; int64_t fsize = 0; xar_prop_t tmpp; tmpp = xar_prop_pget(p, "length"); if( tmpp ) opt = xar_prop_getvalue(tmpp); if( !opt ) { return 0; } else { fsize = strtoll(opt, NULL, 10); if( ((fsize == LLONG_MAX) || (fsize == LLONG_MIN)) && (errno == ERANGE) ) { return -1; } } return fsize; }
int32_t xar_hash_toheap_out(xar_t x, xar_file_t f, xar_prop_t p, void *in, size_t inlen, void **context) { const char *opt; xar_prop_t tmpp; opt = NULL; tmpp = xar_prop_pget(p, "archived-checksum"); if( tmpp ) opt = xar_attr_pget(f, tmpp, "style"); if( !opt ) opt = xar_opt_get(x, XAR_OPT_FILECKSUM); if( !opt || (0 == strcmp(opt, XAR_OPT_VAL_NONE) ) ) return 0; if( ! CONTEXT(context) ) { *context = calloc(1, sizeof(struct _hash_context)); if( ! *context ) return -1; } if( ! CONTEXT(context)->archived ) { CONTEXT(context)->archived = xar_hash_new(opt, NULL); if( ! CONTEXT(context)->archived ) { free(*context); *context = NULL; return -1; } } if( inlen == 0 ) return 0; CONTEXT(context)->count += inlen; xar_hash_update(CONTEXT(context)->archived, in, inlen); return 0; }
/* xar_attrcopy_from_heap_to_heap * This does a simple copy of the heap data from one head (read-only) to another heap (write only). * This does not set any properties or attributes of the file, so this should not be used alone. */ int32_t xar_attrcopy_from_heap_to_heap(xar_t xsource, xar_file_t fsource, xar_prop_t p, xar_t xdest, xar_file_t fdest){ int r, off; size_t bsize; int64_t fsize, inc = 0, seekoff, writesize=0; off_t orig_heap_offset = XAR(xdest)->heap_offset; void *inbuf; const char *opt; char *tmpstr = NULL; xar_prop_t tmpp; opt = xar_opt_get(xsource, "rsize"); if( !opt ) { bsize = 4096; } else { bsize = strtol(opt, NULL, 0); if( ((bsize == LONG_MAX) || (bsize == LONG_MIN)) && (errno == ERANGE) ) { bsize = 4096; } } tmpp = xar_prop_pget(p, "offset"); if( tmpp ) opt = xar_prop_getvalue(tmpp); seekoff = strtoll(opt, NULL, 0); if( ((seekoff == LLONG_MAX) || (seekoff == LLONG_MIN)) && (errno == ERANGE) ) { return -1; } seekoff += XAR(xsource)->toc_count + sizeof(xar_header_t); if( XAR(xsource)->fd > 1 ) { r = lseek(XAR(xsource)->fd, seekoff, SEEK_SET); if( r == -1 ) { if( errno == ESPIPE ) { ssize_t rr; char *buf; unsigned int len; len = seekoff - XAR(xsource)->toc_count; len -= sizeof(xar_header_t); if( XAR(xsource)->heap_offset > len ) { xar_err_new(xsource); xar_err_set_file(xsource, fsource); xar_err_set_string(xsource, "Unable to seek"); xar_err_callback(xsource, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); } else { len -= XAR(xsource)->heap_offset; buf = malloc(len); assert(buf); rr = read(XAR(xsource)->fd, buf, len); if( rr < len ) { xar_err_new(xsource); xar_err_set_file(xsource, fsource); xar_err_set_string(xsource, "Unable to seek"); xar_err_callback(xsource, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); } free(buf); } } else { xar_err_new(xsource); xar_err_set_file(xsource, fsource); xar_err_set_string(xsource, "Unable to seek"); xar_err_callback(xsource, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); } } } opt = NULL; tmpp = xar_prop_pget(p, "length"); if( tmpp ) opt = xar_prop_getvalue(tmpp); if( !opt ) { return 0; } else { fsize = strtoll(opt, NULL, 10); if( ((fsize == LLONG_MAX) || (fsize == LLONG_MIN)) && (errno == ERANGE) ) { return -1; } } inbuf = malloc(bsize); if( !inbuf ) { return -1; } while(1) { /* Size has been reached */ if( fsize == inc ) break; if( (fsize - inc) < bsize ) bsize = fsize - inc; r = read(XAR(xsource)->fd, inbuf, bsize); if( r == 0 ) break; if( (r < 0) && (errno == EINTR) ) continue; if( r < 0 ) { free(inbuf); return -1; } XAR(xsource)->heap_offset += r; inc += r; bsize = r; off = 0; do { r = write(XAR(xdest)->heap_fd, inbuf+off, r-off ); off += r; writesize += r; } while( off < r ); XAR(xdest)->heap_offset += off; XAR(xdest)->heap_len += off; } asprintf(&tmpstr, "%"PRIu64, (uint64_t)orig_heap_offset); opt = xar_prop_getkey(p); tmpp = xar_prop_pfirst(fdest); if( tmpp ) tmpp = xar_prop_find(tmpp, opt); if( tmpp ) xar_prop_pset(fdest, tmpp, "offset", tmpstr); free(tmpstr); free(inbuf); /* It is the caller's responsibility to copy the attributes of the file, etc, this only copies the data in the heap */ return 0; }
/* xar_copy_from_heap * This is the arcmod extraction entry point for extracting the file's * data from the heap file. * It is assumed the heap_fd is already positioned appropriately. */ int32_t xar_attrcopy_from_heap(xar_t x, xar_file_t f, xar_prop_t p, write_callback wcb, void *context) { int modulecount = (sizeof(xar_datamods)/sizeof(struct datamod)); void *modulecontext[modulecount]; int r, i; size_t bsize, def_bsize; int64_t fsize, inc = 0, seekoff; void *inbuf; const char *opt; xar_prop_t tmpp; memset(modulecontext, 0, sizeof(void*)*modulecount); opt = xar_opt_get(x, "rsize"); if( !opt ) { def_bsize = 4096; } else { def_bsize = strtol(opt, NULL, 0); if( ((def_bsize == LONG_MAX) || (def_bsize == LONG_MIN)) && (errno == ERANGE) ) { def_bsize = 4096; } } opt = NULL; tmpp = xar_prop_pget(p, "offset"); if( tmpp ) opt = xar_prop_getvalue(tmpp); if( !opt ) { wcb(x, f, NULL, 0, context); return 0; } else { seekoff = strtoll(opt, NULL, 0); if( ((seekoff == LLONG_MAX) || (seekoff == LLONG_MIN)) && (errno == ERANGE) ) { return -1; } } seekoff += XAR(x)->toc_count + sizeof(xar_header_t); if( XAR(x)->fd > 1 ) { r = lseek(XAR(x)->fd, seekoff, SEEK_SET); if( r == -1 ) { if( errno == ESPIPE ) { ssize_t rr; char *buf; unsigned int len; len = seekoff - XAR(x)->toc_count; len -= sizeof(xar_header_t); if( XAR(x)->heap_offset > len ) { xar_err_new(x); xar_err_set_file(x, f); xar_err_set_string(x, "Unable to seek"); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); } else { len -= XAR(x)->heap_offset; buf = malloc(len); assert(buf); rr = read(XAR(x)->fd, buf, len); if( rr < len ) { xar_err_new(x); xar_err_set_file(x, f); xar_err_set_string(x, "Unable to seek"); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); } free(buf); } } else { xar_err_new(x); xar_err_set_file(x, f); xar_err_set_string(x, "Unable to seek"); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); } } } opt = NULL; tmpp = xar_prop_pget(p, "length"); if( tmpp ) opt = xar_prop_getvalue(tmpp); if( !opt ) { return 0; } else { fsize = strtoll(opt, NULL, 10); if( ((fsize == LLONG_MAX) || (fsize == LLONG_MIN)) && (errno == ERANGE) ) { return -1; } } bsize = def_bsize; inbuf = malloc(bsize); if( !inbuf ) { return -1; } while(1) { /* Size has been reached */ if( fsize == inc ) break; if( (fsize - inc) < bsize ) bsize = fsize - inc; r = read(XAR(x)->fd, inbuf, bsize); if( r == 0 ) break; if( (r < 0) && (errno == EINTR) ) continue; if( r < 0 ) { free(inbuf); return -1; } XAR(x)->heap_offset += r; inc += r; bsize = r; /* filter the data through the in modules */ for( i = 0; i < modulecount; i++) { if( xar_datamods[i].fh_in ) { int32_t ret; ret = xar_datamods[i].fh_in(x, f, p, &inbuf, &bsize, &(modulecontext[i])); if( ret < 0 ) return -1; } } /* Only due the write phase, if there is a write function to call */ if(wcb){ /* filter the data through the out modules */ for( i = 0; i < modulecount; i++) { if( xar_datamods[i].fh_out ) { int32_t ret; ret = xar_datamods[i].fh_out(x, f, p, inbuf, bsize, &(modulecontext[i])); if( ret < 0 ) return -1; } } wcb(x, f, inbuf, bsize, context); } free(inbuf); bsize = def_bsize; inbuf = malloc(bsize); } free(inbuf); /* finish up anything that still needs doing */ for( i = 0; i < modulecount; i++) { if( xar_datamods[i].fh_done ) { int32_t ret; ret = xar_datamods[i].fh_done(x, f, p, &(modulecontext[i])); if( ret < 0 ) return ret; } } return 0; }
int32_t xar_attrcopy_to_heap(xar_t x, xar_file_t f, xar_prop_t p, read_callback rcb, void *context) { int modulecount = (sizeof(xar_datamods)/sizeof(struct datamod)); void *modulecontext[modulecount]; int r, off, i; size_t bsize, rsize; int64_t readsize=0, writesize=0, inc = 0; void *inbuf; char *tmpstr = NULL; const char *opt, *csum; off_t orig_heap_offset = XAR(x)->heap_offset; xar_file_t tmpf = NULL; xar_prop_t tmpp = NULL; memset(modulecontext, 0, sizeof(void*)*modulecount); opt = xar_opt_get(x, XAR_OPT_RSIZE); if( !opt ) { bsize = 4096; } else { bsize = strtol(opt, NULL, 0); if( ((bsize == LONG_MAX) || (bsize == LONG_MIN)) && (errno == ERANGE) ) { bsize = 4096; } } r = 1; while(r != 0) { inbuf = malloc(bsize); if( !inbuf ) return -1; r = rcb(x, f, inbuf, bsize, context); if( r < 0 ) { free(inbuf); return -1; } readsize+=r; inc += r; rsize = r; /* filter the data through the in modules */ for( i = 0; i < modulecount; i++) { if( xar_datamods[i].th_in ) { xar_datamods[i].th_in(x, f, p, &inbuf, &rsize, &(modulecontext[i])); } } /* filter the data through the out modules */ for( i = 0; i < modulecount; i++) { if( xar_datamods[i].th_out ) xar_datamods[i].th_out(x, f, p, inbuf, rsize, &(modulecontext[i])); } off = 0; if( rsize != 0 ) { do { r = write(XAR(x)->heap_fd, inbuf+off, rsize-off); if( (r < 0) && (errno != EINTR) ) return -1; off += r; writesize += r; } while( off < rsize ); } XAR(x)->heap_offset += off; free(inbuf); } /* If size is 0, don't bother having anything in the heap */ if( readsize == 0 ) { XAR(x)->heap_offset = orig_heap_offset; lseek(XAR(x)->heap_fd, -writesize, SEEK_CUR); for( i = 0; i < modulecount; i++) { if( xar_datamods[i].th_done ) xar_datamods[i].th_done(x, f, p, &(modulecontext[i])); } return 0; } /* finish up anything that still needs doing */ for( i = 0; i < modulecount; i++) { if( xar_datamods[i].th_done ) xar_datamods[i].th_done(x, f, p, &(modulecontext[i])); } XAR(x)->heap_len += writesize; tmpp = xar_prop_pget(p, "archived-checksum"); if( tmpp ) csum = xar_prop_getvalue(tmpp); tmpf = xmlHashLookup(XAR(x)->csum_hash, BAD_CAST(csum)); if( tmpf ) { const char *attr = xar_prop_getkey(p); opt = xar_opt_get(x, XAR_OPT_LINKSAME); if( opt && (strcmp(attr, "data") == 0) ) { const char *id = xar_attr_pget(tmpf, NULL, "id"); xar_prop_pset(f, NULL, "type", "hardlink"); tmpp = xar_prop_pfirst(f); if( tmpp ) tmpp = xar_prop_find(tmpp, "type"); if( tmpp ) xar_attr_pset(f, tmpp, "link", id); xar_prop_pset(tmpf, NULL, "type", "hardlink"); tmpp = xar_prop_pfirst(tmpf); if( tmpp ) tmpp = xar_prop_find(tmpp, "type"); if( tmpp ) xar_attr_pset(tmpf, tmpp, "link", "original"); tmpp = xar_prop_pfirst(f); if( tmpp ) tmpp = xar_prop_find(tmpp, "data"); xar_prop_punset(f, tmpp); XAR(x)->heap_offset = orig_heap_offset; lseek(XAR(x)->heap_fd, -writesize, SEEK_CUR); XAR(x)->heap_len -= writesize; return 0; } opt = xar_opt_get(x, XAR_OPT_COALESCE); if( opt ) { long long tmpoff; const char *offstr = NULL; tmpp = xar_prop_pfirst(tmpf); if( tmpp ) { const char *key; key = xar_prop_getkey(p); tmpp = xar_prop_find(tmpp, key); } if( tmpp ) tmpp = xar_prop_pget(tmpp, "offset"); if( tmpp ) offstr = xar_prop_getvalue(tmpp); if( offstr ) { tmpoff = strtoll(offstr, NULL, 10); XAR(x)->heap_offset = orig_heap_offset; lseek(XAR(x)->heap_fd, -writesize, SEEK_CUR); orig_heap_offset = tmpoff; XAR(x)->heap_len -= writesize; } } } else { xmlHashAddEntry(XAR(x)->csum_hash, BAD_CAST(csum), XAR_FILE(f)); } asprintf(&tmpstr, "%"PRIu64, readsize); xar_prop_pset(f, p, "size", tmpstr); free(tmpstr); asprintf(&tmpstr, "%"PRIu64, (uint64_t)orig_heap_offset); xar_prop_pset(f, p, "offset", tmpstr); free(tmpstr); tmpstr = (char *)xar_opt_get(x, XAR_OPT_COMPRESSION); if( tmpstr && (strcmp(tmpstr, XAR_OPT_VAL_NONE) == 0) ) { xar_prop_pset(f, p, "encoding", NULL); tmpp = xar_prop_pget(p, "encoding"); if( tmpp ) xar_attr_pset(f, tmpp, "style", "application/octet-stream"); } asprintf(&tmpstr, "%"PRIu64, writesize); xar_prop_pset(f, p, "length", tmpstr); free(tmpstr); return 0; }
int32_t xar_attrcopy_to_heap(xar_t x, xar_file_t f, xar_prop_t p, read_callback rcb, void *context) { int modulecount = (sizeof(xar_datamods)/sizeof(struct datamod)); void *modulecontext[modulecount]; int r, i; size_t bsize, rsize; int64_t readsize=0, writesize=0, inc = 0, this_write=0; void *inbuf; char *tmpstr = NULL; const char *opt = NULL, *csum = NULL; off_t orig_heap_offset = XAR(x)->heap_offset; xar_file_t tmpf = NULL; xar_prop_t tmpp = NULL; memset(modulecontext, 0, sizeof(void*)*modulecount); bsize = xar_io_get_rsize(x); r = 1; // (Apple) allocate once inbuf = malloc(bsize); if( !inbuf ) return -1; while(r != 0) { r = rcb(x, f, inbuf, bsize, context); if( r < 0 ) { free(inbuf); return -1; } readsize+=r; inc += r; rsize = r; /* filter the data through the in modules */ for( i = 0; i < modulecount; i++) { if( xar_datamods[i].th_in ) { xar_datamods[i].th_in(x, f, p, &inbuf, &rsize, &(modulecontext[i])); } } /* filter the data through the out modules */ for( i = 0; i < modulecount; i++) { if( xar_datamods[i].th_out ) xar_datamods[i].th_out(x, f, p, inbuf, rsize, &(modulecontext[i])); } size_t written = 0; if( rsize != 0 ) { while(written < rsize) { this_write = xar_write_fd(XAR(x)->heap_fd, inbuf, rsize); if( this_write < 0 ) { xar_err_new(x); xar_err_set_string(x, "write(2) error when writing to heap"); xar_err_set_errno(x, errno); xar_err_callback(x, XAR_SEVERITY_FATAL, XAR_ERR_ARCHIVE_CREATION); free(inbuf); return -1; } written += this_write; } } XAR(x)->heap_offset += written; writesize += written; } free(inbuf); /* If size is 0, don't bother having anything in the heap */ if( readsize == 0 ) { XAR(x)->heap_offset = orig_heap_offset; lseek(XAR(x)->heap_fd, -writesize, SEEK_CUR); for( i = 0; i < modulecount; i++) { if( xar_datamods[i].th_done ) xar_datamods[i].th_done(x, f, p, &(modulecontext[i])); } return 0; } /* finish up anything that still needs doing */ for( i = 0; i < modulecount; i++) { if( xar_datamods[i].th_done ) xar_datamods[i].th_done(x, f, p, &(modulecontext[i])); } XAR(x)->heap_len += writesize; tmpp = xar_prop_pget(p, "archived-checksum"); if( tmpp ) csum = xar_prop_getvalue(tmpp); if( csum ) tmpf = xmlHashLookup(XAR(x)->csum_hash, BAD_CAST(csum)); if( tmpf ) { const char *attr = xar_prop_getkey(p); opt = xar_opt_get(x, XAR_OPT_LINKSAME); if( opt && (strcmp(attr, "data") == 0) ) { const char *id = xar_attr_pget(tmpf, NULL, "id"); xar_prop_pset(f, NULL, "type", "hardlink"); tmpp = xar_prop_pfirst(f); if( tmpp ) tmpp = xar_prop_find(tmpp, "type"); if( tmpp ) xar_attr_pset(f, tmpp, "link", id); xar_prop_pset(tmpf, NULL, "type", "hardlink"); tmpp = xar_prop_pfirst(tmpf); if( tmpp ) tmpp = xar_prop_find(tmpp, "type"); if( tmpp ) xar_attr_pset(tmpf, tmpp, "link", "original"); tmpp = xar_prop_pfirst(f); if( tmpp ) tmpp = xar_prop_find(tmpp, "data"); xar_prop_punset(f, tmpp); XAR(x)->heap_offset = orig_heap_offset; lseek(XAR(x)->heap_fd, -writesize, SEEK_CUR); XAR(x)->heap_len -= writesize; return 0; } opt = xar_opt_get(x, XAR_OPT_COALESCE); if( opt ) { long long tmpoff; const char *offstr = NULL; tmpp = xar_prop_pfirst(tmpf); if( tmpp ) { const char *key; key = xar_prop_getkey(p); tmpp = xar_prop_find(tmpp, key); } if( tmpp ) tmpp = xar_prop_pget(tmpp, "offset"); if( tmpp ) offstr = xar_prop_getvalue(tmpp); if( offstr ) { tmpoff = strtoll(offstr, NULL, 10); XAR(x)->heap_offset = orig_heap_offset; lseek(XAR(x)->heap_fd, -writesize, SEEK_CUR); orig_heap_offset = tmpoff; XAR(x)->heap_len -= writesize; } } } else if( csum ) { xmlHashAddEntry(XAR(x)->csum_hash, BAD_CAST(csum), XAR_FILE(f)); } else { xar_err_new(x); xar_err_set_file(x, f); xar_err_set_string(x, "No archived-checksum"); xar_err_callback(x, XAR_SEVERITY_WARNING, XAR_ERR_ARCHIVE_CREATION); } asprintf(&tmpstr, "%"PRIu64, readsize); xar_prop_pset(f, p, "size", tmpstr); free(tmpstr); asprintf(&tmpstr, "%"PRIu64, (uint64_t)orig_heap_offset); xar_prop_pset(f, p, "offset", tmpstr); free(tmpstr); tmpstr = (char *)xar_opt_get(x, XAR_OPT_COMPRESSION); if( tmpstr && (strcmp(tmpstr, XAR_OPT_VAL_NONE) == 0) ) { xar_prop_pset(f, p, "encoding", NULL); tmpp = xar_prop_pget(p, "encoding"); if( tmpp ) xar_attr_pset(f, tmpp, "style", "application/octet-stream"); } asprintf(&tmpstr, "%"PRIu64, writesize); xar_prop_pset(f, p, "length", tmpstr); free(tmpstr); return 0; }
int32_t xar_linuxattr_extract(xar_t x, xar_file_t f, const char* file, char *buffer, size_t len) { #if defined HAVE_SYS_XATTR_H && defined(HAVE_LSETXATTR) && !defined(__APPLE__) const char *fsname = "bogus"; struct statfs sfs; int eaopt = 0; struct _linuxattr_context context; xar_prop_t p; memset(&context,0,sizeof(struct _linuxattr_context)); /* data buffers, can't store linux attrs */ if(len){ return 0; } /* Check for EA extraction behavior */ memset(&sfs, 0, sizeof(sfs)); if( statfs(file, &sfs) != 0 ) { char *tmp, *bname; tmp = strdup(file); bname = dirname(tmp); statfs(bname, &sfs); free(tmp); } switch(sfs.f_type) { case EXT3_SUPER_MAGIC: fsname = "ext3"; break; /* assume ext3 */ case JFS_SUPER_MAGIC: fsname = "jfs" ; break; case REISERFS_SUPER_MAGIC:fsname = "reiser" ; break; case XFS_SUPER_MAGIC: fsname = "xfs" ; break; }; for(p = xar_prop_pfirst(f); p; p = xar_prop_pnext(p)) { const char *fs = NULL; const char *prop; const char *eaname = NULL; xar_prop_t tmpp; prop = xar_prop_getkey(p); if( strncmp(prop, XAR_EA_FORK, strlen(XAR_EA_FORK)) != 0 ) continue; if( strlen(prop) != strlen(XAR_EA_FORK) ) continue; tmpp = xar_prop_pget(p, "fstype"); if( tmpp ) fs = xar_prop_getvalue(tmpp); if( !eaopt && fs && strcmp(fs, fsname) != 0 ) { continue; } if( !fs ) continue; tmpp = xar_prop_pget(p, "name"); if( tmpp ) eaname = xar_prop_getvalue(tmpp); context.file = file; context.attrname = eaname; xar_attrcopy_from_heap(x, f, p, xar_linuxattr_write, &context); } #endif return 0; }