Example #1
0
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;
}
Example #2
0
int32_t xar_data_extract(xar_t x, xar_file_t f, const char *file, char *buffer, size_t len) {
	const char *opt;
	int32_t retval = 0;
	struct _data_context context;
	xar_prop_t tmpp;
	
	memset(&context,0,sizeof(struct _data_context));
	
	/* Only regular files are copied in and out of the heap here */
	xar_prop_get(f, "type", &opt);
	if( !opt ) return 0;
	if( strcmp(opt, "file") != 0 ) {
		if( strcmp(opt, "hardlink") == 0 ) {
			opt = xar_attr_get(f, "type", "link");
			if( !opt )
				return 0;
			if( strcmp(opt, "original") != 0 )
				return 0; 
			/* else, we're an original hardlink, so keep going */
		} else
			return 0;
	}
	
	if ( len ){
		context.length = len;
		context.buffer = buffer;
		context.offset = 0;
	}else{
		/* mode 600 since other modules may need to operate on the file
		* prior to the real permissions being set.
		*/
		context.fd = open(file, O_RDWR|O_TRUNC|O_EXLOCK, 0600);
		if( context.fd < 0 ) {
			xar_err_new(x);
			xar_err_set_file(x, f);
			xar_err_set_string(x, "io: Could not create file");
			xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION);
			return -1;
		}
		
	}
	
	tmpp = xar_prop_pfirst(f);
	if( tmpp )
		tmpp = xar_prop_find(tmpp, "data");
	if( !tmpp ) {
		close(context.fd);
		return 0;
	}
	retval = xar_attrcopy_from_heap(x, f, tmpp, xar_data_write, (void *)(&context));
	
	if( context.fd > 0 ){		
		close(context.fd);
		context.fd = -1;
	}
	
	return retval;
}
Example #3
0
/* xar_data_archive
 * This is the arcmod archival entry point for archiving the file's
 * data into the heap file.
 */
int32_t xar_data_archive(xar_t x, xar_file_t f, const char *file, const char *buffer, size_t len) {
	const char *opt;
	int32_t retval = 0;
	struct _data_context context;
	xar_prop_t tmpp;
	
	memset(&context,0,sizeof(struct _data_context));

	if( !xar_check_prop(x, "data") )
		return 0;

	xar_prop_get(f, "type", &opt);
	if(!opt) return 0;
	if( strcmp(opt, "file") != 0 ) {
		if( strcmp(opt, "hardlink") == 0 ) {
			opt = xar_attr_get(f, "type", "link");
			if( !opt )
				return 0;
			if( strcmp(opt, "original") != 0 )
				return 0;
			/* else, we're an original hardlink, so keep going */
		} else
			return 0;
	}

	if( 0 == len ){
		context.fd = open(file, O_RDONLY);
		if( context.fd < 0 ) {
			xar_err_new(x);
			xar_err_set_file(x, f);
			xar_err_set_string(x, "io: Could not open file");
			xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_CREATION);
			return -1;
		}		
	}else{
		context.buffer = (void *)buffer;
		context.length = len;
		context.offset = 0;
	}

#ifdef F_NOCACHE
	fcntl(context.fd, F_NOCACHE, 1);
#endif

	tmpp = xar_prop_pset(f, NULL, "data", NULL);
	retval = xar_attrcopy_to_heap(x, f, tmpp, xar_data_read,(void *)(&context));
	if( context.total == 0 )
		xar_prop_unset(f, "data");

	if(context.fd > 0){
		close(context.fd);
		context.fd = -1;
	}
	
	return retval;
}
Example #4
0
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;
}
Example #5
0
File: hash.c Project: aosm/xar
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;
}
Example #6
0
int32_t xar_flags_extract(xar_t x, xar_file_t f, const char *file, char *buffer, size_t len) {
#ifdef HAVE_CHFLAGS
	char *tmp;
	u_int flags = 0;

	if( xar_prop_get(f, XAR_FLAG_FORK, NULL) )
		return 0;

#ifdef UF_NODUMP
	if( x_getprop(f, "UserNoDump", (char **)&tmp) == 0 )
		flags |= UF_NODUMP;
#endif
#ifdef UF_IMMUTABLE
	if( x_getprop(f, "UserImmutable", (char **)&tmp) == 0 )
		flags |= UF_IMMUTABLE;
#endif
#ifdef UF_APPEND
	if( x_getprop(f, "UserAppend", (char **)&tmp) == 0 )
		flags |= UF_APPEND;
#endif
#ifdef UF_OPAQUE
	if( x_getprop(f, "UserOpaque", (char **)&tmp) == 0 )
		flags |= UF_OPAQUE;
#endif
#ifdef SF_ARCHIVED
	if( x_getprop(f, "SystemArchived", (char **)&tmp) == 0 )
		flags |= SF_ARCHIVED;
#endif
#ifdef SF_IMMUTABLE
	if( x_getprop(f, "SystemImmutable", (char **)&tmp) == 0 )
		flags |= SF_IMMUTABLE;
#endif
#ifdef SF_APPEND
	if( x_getprop(f, "SystemAppend", (char **)&tmp) == 0 )
		flags |= SF_APPEND;
#endif

	if( !flags )
		return 0;

	if( chflags(file, flags) != 0 ) {
		char e[1024];
		memset(e, 0, sizeof(e));
		snprintf(e, sizeof(e)-1, "chflags: %s", strerror(errno));
		xar_err_new(x);
		xar_err_set_file(x, f);
		xar_err_set_string(x, e);
		xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION);
		return -1;
	}
#endif
	
	return 0;
}
Example #7
0
File: io.c Project: Jean-Daniel/xar
static void xar_io_seek(xar_t x, xar_file_t f, off_t seekoff) {
	int r;

	if( XAR(x)->fd >= 0 ) {
		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 = xar_read_fd(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);
					}
					XAR(x)->heap_offset += rr;
					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);
			}
		}
	}
}
Example #8
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;
}
Example #9
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;
}
Example #10
0
File: io.c Project: Jean-Daniel/xar
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;
}
Example #11
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;
}
Example #12
0
int32_t xar_stat_extract(xar_t x, xar_file_t f, const char *file, char *buffer, size_t len) {
	const char *opt;
	int ret, fd;
	mode_t modet = 0;

	xar_prop_get(f, "type", &opt);
	if(opt && (strcmp(opt, "character special") == 0))
		modet = S_IFCHR;
	if(opt && (strcmp(opt, "block special") == 0))
		modet = S_IFBLK;

	if( modet ) {
		uint32_t major, minor;
		long long tmpll;
		dev_t devt;

		xar_prop_get(f, "device/major", &opt);
		tmpll = strtoll(opt, NULL, 10);
		if( ( (tmpll == LLONG_MIN) || (tmpll == LLONG_MAX) ) && (errno == ERANGE) )
			return -1;
		if( (tmpll < 0) || (tmpll > 255) )
			return -1;
		major = tmpll;

		xar_prop_get(f, "device/minor", &opt);
		tmpll = strtoll(opt, NULL, 10);
		if( ( (tmpll == LLONG_MIN) || (tmpll == LLONG_MAX) ) && (errno == ERANGE) )
			return -1;
		if( (tmpll < 0) || (tmpll > 255) )
			return -1;
		minor = tmpll;
		
		devt = xar_makedev(major, minor);
		unlink(file);
		if( mknod(file, modet, devt) ) {
			xar_err_new(x);
			xar_err_set_file(x, f);
			xar_err_set_string(x, "mknod: Could not create character device");
			xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION);
			return -1;
		}
		return 0;
	}
	if(opt && (strcmp(opt, "directory") == 0)) {
		ret = mkdir(file, 0700);
		if( (ret != 0) && (errno != EEXIST) ) {
			xar_err_new(x);
			xar_err_set_file(x, f);
			xar_err_set_string(x, "stat: Could not create directory");
			xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION);
			return ret;
		}
		return 0;
	}
	if(opt && (strcmp(opt, "symlink") == 0)) {
		xar_prop_get(f, "link", &opt);
		if( opt ) {
			unlink(file);
			ret = symlink(opt, file);
			if( ret != 0 ) {
				xar_err_new(x);
				xar_err_set_file(x, f);
				xar_err_set_string(x, "stat: Could not create symlink");
				xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION);
			}
			return ret;
		}
	}
	if(opt && (strcmp(opt, "hardlink") == 0)) {
		xar_file_t tmpf;
		opt = xar_attr_get(f, "type", "link");
		if( !opt )
			return 0;
		if( strcmp(opt, "original") == 0 )
			goto CREATEFILE;

		tmpf = xmlHashLookup(XAR(x)->link_hash, BAD_CAST(opt));
		if( !tmpf ) {
			xar_err_new(x);
			xar_err_set_file(x, f);
			xar_err_set_string(x, "stat: Encountered hardlink with no original");
			xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION);
			return -1;
		}

		unlink(file);
		if( link(XAR_FILE(tmpf)->fspath, file) != 0 ) {
			if( errno == ENOENT ) {
				xar_iter_t i;
				const char *ptr;
				i = xar_iter_new(x);
				for(ptr = xar_prop_first(tmpf, i); ptr; ptr = xar_prop_next(i)) {
					xar_iter_t a;
					const char *val = NULL;
					const char *akey, *aval;
					if( strncmp("data", ptr, 4) != 0 )
						continue;
	
					if( xar_prop_get(tmpf, ptr, &val) )
						continue;
	
					xar_prop_set(f, ptr, val);
					a = xar_iter_new(x);
					for(akey = xar_attr_first(tmpf, ptr, a); akey; akey = xar_attr_next(a)) {
						aval = xar_attr_get(tmpf, ptr, akey);
						xar_attr_set(f, ptr, akey, aval);
					}
					xar_iter_free(a);
				}
				xar_iter_free(i);
				xar_attr_set(f, "type", "link", "original");
				return 0;
			} else {
				xar_err_new(x);
				xar_err_set_file(x, f);
				xar_err_set_string(x, "stat: Could not link hardlink to original");
				xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION);
				return -1;
			}
		}
		return 0;
	}

	if(opt && (strcmp(opt, "fifo") == 0)) {
		unlink(file);
		if( mkfifo(file, 0) ) {
			xar_err_new(x);
			xar_err_set_file(x, f);
			xar_err_set_string(x, "mkfifo: Could not create fifo");
			xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION);
			return -1;
		}
		return 0;
	}

	/* skip sockets */
	if(opt && (strcmp(opt, "socket") == 0)) {
		return 0;
	}

CREATEFILE:
	unlink(file);
	fd = open(file, O_RDWR|O_CREAT|O_TRUNC, 0600);
	if( fd > 0 )
		close(fd);
	return 0;
}
Example #13
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", &timestr);
	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", &timestr);
	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;
}
Example #14
0
int32_t xar_stat_archive(xar_t x, xar_file_t f, const char *file, const char *buffer, size_t len) {
	char *tmpstr;
	struct passwd *pw;
	struct group *gr;
	char time[128];
	struct tm t;
	const char *type;

	/* no stat attributes for data from a buffer, it is just a file */
	if(len){
		xar_prop_set(f, "type", "file");
		return 0;
	}
	
	if( S_ISREG(XAR(x)->sbcache.st_mode) && (XAR(x)->sbcache.st_nlink > 1) ) {
		xar_file_t tmpf;
		const char *id = xar_attr_get(f, NULL, "id");
		if( !id ) {
			xar_err_new(x);
			xar_err_set_file(x, f);
			xar_err_set_string(x, "stat: No file id for file");
			xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_CREATION);
			return -1;
		}
		tmpf = xar_link_lookup(x, XAR(x)->sbcache.st_dev, XAR(x)->sbcache.st_ino, f);
		xar_prop_set(f, "type", "hardlink");
		if( tmpf ) {
			const char *id;
			id = xar_attr_get(tmpf, NULL, "id");
			xar_attr_set(f, "type", "link", id);
		} else {
			xar_attr_set(f, "type", "link", "original");
		}
	} else {
		type = filetype_name(XAR(x)->sbcache.st_mode & S_IFMT);
		xar_prop_set(f, "type", type);
	}

	/* Record major/minor device node numbers */
	if( S_ISBLK(XAR(x)->sbcache.st_mode) || S_ISCHR(XAR(x)->sbcache.st_mode)) {
		uint32_t major, minor;
		char tmpstr[12];
		xar_devmake(XAR(x)->sbcache.st_rdev, &major, &minor);
		memset(tmpstr, 0, sizeof(tmpstr));
		snprintf(tmpstr, sizeof(tmpstr)-1, "%u", major);
		xar_prop_set(f, "device/major", tmpstr);
		memset(tmpstr, 0, sizeof(tmpstr));
		snprintf(tmpstr, sizeof(tmpstr)-1, "%u", minor);
		xar_prop_set(f, "device/minor", tmpstr);
	}

	if( S_ISLNK(XAR(x)->sbcache.st_mode) ) {
		char link[4096];
		struct stat lsb;

		memset(link, 0, sizeof(link));
		readlink(file, link, sizeof(link)-1);
		xar_prop_set(f, "link", link);
		if( stat(file, &lsb) != 0 ) {
			xar_attr_set(f, "link", "type", "broken");
		} else {
			type = filetype_name(lsb.st_mode & S_IFMT);
			xar_attr_set(f, "link", "type", type);
		}
	}

	asprintf(&tmpstr, "%04o", XAR(x)->sbcache.st_mode & (~S_IFMT));
	xar_prop_set(f, "mode", tmpstr);
	free(tmpstr);

	asprintf(&tmpstr, "%"PRIu64, (uint64_t)XAR(x)->sbcache.st_uid);
	xar_prop_set(f, "uid", tmpstr);
	free(tmpstr);

	pw = getpwuid(XAR(x)->sbcache.st_uid);
	if( pw )
		xar_prop_set(f, "user", pw->pw_name);

	asprintf(&tmpstr, "%"PRIu64, (uint64_t)XAR(x)->sbcache.st_gid);
	xar_prop_set(f, "gid", tmpstr);
	free(tmpstr);

	gr = getgrgid(XAR(x)->sbcache.st_gid);
	if( gr )
		xar_prop_set(f, "group", gr->gr_name);

	gmtime_r(&XAR(x)->sbcache.st_atime, &t);
	memset(time, 0, sizeof(time));
	strftime(time, sizeof(time), "%FT%T", &t);
	strcat(time, "Z");
	xar_prop_set(f, "atime", time);

	gmtime_r(&XAR(x)->sbcache.st_mtime, &t);
	memset(time, 0, sizeof(time));
	strftime(time, sizeof(time), "%FT%T", &t);
	strcat(time, "Z");
	xar_prop_set(f, "mtime", time);

	gmtime_r(&XAR(x)->sbcache.st_ctime, &t);
	memset(time, 0, sizeof(time));
	strftime(time, sizeof(time), "%FT%T", &t);
	strcat(time, "Z");
	xar_prop_set(f, "ctime", time);

	flags_archive(f, &(XAR(x)->sbcache));

	aacls(f, file);

	return 0;
}
Example #15
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;
}