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_set_perm(xar_t x, xar_file_t f, const char *file, char *buffer, size_t len) { const char *opt; int32_t m=0, mset=0; uid_t u; gid_t g; const char *timestr; struct tm t; enum {ATIME=0, MTIME}; struct timeval tv[2]; /* when writing to a buffer, there are no permissions to set */ if ( len ) return 0; /* in case we don't find anything useful in the archive */ u = geteuid(); g = getegid(); opt = xar_opt_get(x, XAR_OPT_OWNERSHIP); if( opt && (strcmp(opt, XAR_OPT_VAL_SYMBOLIC) == 0) ) { struct passwd *pw; struct group *gr; xar_prop_get(f, "user", &opt); if( opt ) { pw = getpwnam(opt); if( pw ) { u = pw->pw_uid; } } xar_prop_get(f, "group", &opt); if( opt ) { gr = getgrnam(opt); if( gr ) { g = gr->gr_gid; } } } if( opt && (strcmp(opt, XAR_OPT_VAL_NUMERIC) == 0) ) { xar_prop_get(f, "uid", &opt); if( opt ) { long long tmp; tmp = strtol(opt, NULL, 10); if( ( (tmp == LLONG_MIN) || (tmp == LLONG_MAX) ) && (errno == ERANGE) ) { return -1; } u = (uid_t)tmp; } xar_prop_get(f, "gid", &opt); if( opt ) { long long tmp; tmp = strtol(opt, NULL, 10); if( ( (tmp == LLONG_MIN) || (tmp == LLONG_MAX) ) && (errno == ERANGE) ) { return -1; } g = (gid_t)tmp; } } xar_prop_get(f, "mode", &opt); if( opt ) { long long tmp; tmp = strtoll(opt, NULL, 8); if( ( (tmp == LLONG_MIN) || (tmp == LLONG_MAX) ) && (errno == ERANGE) ) { return -1; } m = (mode_t)tmp; mset = 1; } xar_prop_get(f, "type", &opt); if( opt && !mset ) { mode_t u = umask(0); umask(u); if( strcmp(opt, "directory") == 0 ) { m = (mode_t)(0777 & ~u); } else { m = (mode_t)(0666 & ~u); } mset = 1; } if( opt && (strcmp(opt, "symlink") == 0) ) { #ifdef HAVE_LCHOWN if( lchown(file, u, g) ) { xar_err_new(x); xar_err_set_file(x, f); xar_err_set_string(x, "perm: could not lchown symlink"); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); } #ifdef HAVE_LCHMOD if( mset ) if( lchmod(file, m) ) { xar_err_new(x); xar_err_set_file(x, f); xar_err_set_string(x, "perm: could not lchmod symlink"); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); } #endif #endif } else { if( chown(file, u, g) ) { xar_err_new(x); xar_err_set_file(x, f); xar_err_set_string(x, "perm: could not chown file"); xar_err_set_errno(x, errno); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); } if( mset ) if( chmod(file, m) ) { xar_err_new(x); xar_err_set_file(x, f); xar_err_set_string(x, "perm: could not chmod file"); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); } } eacls(x, f, file); memset(tv, 0, sizeof(struct timeval) * 2); xar_prop_get(f, "atime", ×tr); if( timestr ) { memset(&t, 0, sizeof(t)); strptime(timestr, "%FT%T", &t); tv[ATIME].tv_sec = timegm(&t); } else { tv[ATIME].tv_sec = time(NULL); } xar_prop_get(f, "mtime", ×tr); if( timestr ) { memset(&t, 0, sizeof(t)); strptime(timestr, "%FT%T", &t); tv[MTIME].tv_sec = timegm(&t); } else { tv[MTIME].tv_sec = time(NULL); } utimes(file, tv); return 0; }
int32_t xar_gzip_toheap_in(xar_t x, xar_file_t f, xar_prop_t p, void **in, size_t *inlen, void **context) { void *out = NULL; size_t outlen, offset = 0; int r; const char *opt; /* on first run, we init the context and check the compression type */ if( !GZIP_CONTEXT(context) ) { int level = Z_BEST_COMPRESSION; *context = calloc(1,sizeof(struct _gzip_context)); opt = xar_opt_get(x, XAR_OPT_COMPRESSION); if( !opt ) return 0; if( strcmp(opt, XAR_OPT_VAL_GZIP) != 0 ) return 0; opt = xar_opt_get(x, XAR_OPT_COMPRESSIONARG); if( opt ) { int tmp; errno = 0; tmp = strtol(opt, NULL, 10); if( errno == 0 ) { if( (level >= 0) && (level <= 9) ) level = tmp; } } deflateInit(&GZIP_CONTEXT(context)->z, level); GZIP_CONTEXT(context)->gzipcompressed = 1; if( *inlen == 0 ) return 0; }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/2; if(outlen == 0) outlen = 1024; 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; if( *inlen != 0 ) { do { 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 = deflate(&GZIP_CONTEXT(context)->z, Z_NO_FLUSH); offset = outlen - GZIP_CONTEXT(context)->z.avail_out; } while( r == Z_OK && GZIP_CONTEXT(context)->z.avail_in != 0 ); } else { do { 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 = deflate(&GZIP_CONTEXT(context)->z, Z_FINISH); offset = outlen - GZIP_CONTEXT(context)->z.avail_out; } while( r == Z_OK && r != Z_STREAM_END /* no-op */); } if( (r != Z_OK && r != Z_STREAM_END) ) { xar_err_new(x); xar_err_set_file(x, f); xar_err_set_string(x, "Error compressing file"); xar_err_set_errno(x, r); xar_err_callback(x, XAR_SEVERITY_FATAL, XAR_ERR_ARCHIVE_CREATION); return -1; } free(*in); *in = out; GZIP_CONTEXT(context)->count += *inlen; *inlen = offset; return 0; }
static int32_t eacls(xar_t x, xar_file_t f, const char *file) { #ifdef HAVE_SYS_ACL_H #if !defined(__APPLE__) const char *t; acl_t a; const char *type; xar_prop_get(f, "type", &type); if( !type || (strcmp(type, "symlink") == 0) ) return 0; xar_prop_get(f, "acl/default", &t); if( t ) { a = acl_from_text(t); if( !a ) { xar_err_new(x); xar_err_set_errno(x, errno); xar_err_set_string(x, "Error extracting default acl from toc"); xar_err_set_file(x, f); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); } else { if( acl_set_file(file, ACL_TYPE_DEFAULT, a) != 0 ) { xar_err_new(x); xar_err_set_errno(x, errno); xar_err_set_string(x, "Error setting default acl"); xar_err_set_file(x, f); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); } } } xar_prop_get(f, "acl/access", &t); if( t ) { a = acl_from_text(t); if( !a ) { xar_err_new(x); xar_err_set_errno(x, errno); xar_err_set_string(x, "Error extracting access acl from toc"); xar_err_set_file(x, f); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); } else { if( acl_set_file(file, ACL_TYPE_ACCESS, a) != 0 ) { xar_err_new(x); xar_err_set_errno(x, errno); xar_err_set_string(x, "Error setting access acl"); xar_err_set_file(x, f); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); } acl_free(a); } } #else /* !__APPLE__ */ const char *t; acl_t a; xar_prop_get(f, "acl/appleextended", &t); if( t ) { a = acl_from_text(t); if( !a ) { xar_err_new(x); xar_err_set_errno(x, errno); xar_err_set_string(x, "Error extracting access acl from toc"); xar_err_set_file(x, f); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); } else { if( acl_set_file(file, ACL_TYPE_ACCESS, a) != 0 ) { xar_err_new(x); xar_err_set_errno(x, errno); xar_err_set_string(x, "Error setting access acl"); xar_err_set_file(x, f); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); } acl_free(a); } } #endif /* !__APPLE__ */ #endif return 0; }