appleadditions.diff   [plain text]


diff -urN xar.hash/include/xar.h.in xar.final/include/xar.h.in
--- xar.hash/include/xar.h.in	2006-03-17 13:36:32.000000000 -0800
+++ xar.final/include/xar.h.in	2006-03-17 10:35:14.000000000 -0800
@@ -101,8 +101,20 @@
 xar_t xar_open(const char *file, int32_t flags);
 int xar_close(xar_t x);
 xar_file_t xar_add(xar_t x, const char *path);
+
+xar_file_t xar_add_frombuffer(xar_t x, xar_file_t parent, const char *name, char *buffer, size_t length);
+xar_file_t xar_add_folder(xar_t x, xar_file_t f, const char *name, struct stat *info);
+xar_file_t xar_add_frompath(xar_t x, xar_file_t parent, const char *name, const char *realpath);
+
+xar_file_t xar_add_from_archive(xar_t x, xar_file_t parent, const char *name, xar_t sourcearchive, xar_file_t sourcefile);
+
 int32_t xar_extract(xar_t x, xar_file_t f);
 int32_t xar_extract_tofile(xar_t x, xar_file_t f, const char *path);
+int32_t xar_extract_tobuffer(xar_t x, xar_file_t f, char **buffer);
+
+int32_t xar_verify(xar_t x, xar_file_t f);
+
+
 const char *xar_opt_get(xar_t x, const char *option);
 int32_t xar_opt_set(xar_t x, const char *option, const char *value);
 
@@ -148,6 +160,7 @@
 int32_t xar_err_callback(xar_t x, int32_t sev, int32_t err);
 
 char *xar_get_path(xar_file_t f);
+off_t	xar_get_heap_offset(xar_t x);
 uint64_t xar_ntoh64(uint64_t num);
 
 #endif /* _XAR_H_ */
diff -urN xar.hash/lib/archive.c xar.final/lib/archive.c
--- xar.hash/lib/archive.c	2006-03-17 11:25:05.000000000 -0800
+++ xar.final/lib/archive.c	2006-03-17 10:35:14.000000000 -0800
@@ -217,6 +217,7 @@
 		XAR(ret)->heap_len += 20;
 		
 		xar_opt_set(ret, XAR_OPT_COMPRESSION, XAR_OPT_VAL_GZIP);
+		xar_opt_set(ret, XAR_OPT_FILECKSUM, XAR_OPT_VAL_SHA1);
 	} else {
 		unsigned char toccksum[EVP_MAX_MD_SIZE];
 		unsigned char cval[EVP_MAX_MD_SIZE];
@@ -455,6 +456,7 @@
 
 		if( XAR(x)->docksum ) {
 			unsigned int l = r;
+			
 			memset(chkstr, 0, sizeof(chkstr));
 			EVP_DigestFinal(&XAR(x)->toc_ctx, chkstr, &l);
 			r = l;
@@ -588,19 +590,25 @@
  * x: archive the file should belong to
  * f: parent node, possibly NULL
  * name: name of the node to add
+ * realpath: real path to item, this is used if the item being archived is to be located at a different location in the tree
+ * then it is on the real filesystem.
  * Returns: newly allocated and populated node
  * Summary: helper function which adds a child of f and populates
  * its properties.  If f is NULL, the node will be added as a top
  * level node of the archive, x.
  */
-static xar_file_t xar_add_node(xar_t x, xar_file_t f, const char *name, const char *prefix, int srcpath) {
+static xar_file_t xar_add_node(xar_t x, xar_file_t f, const char *name, const char *prefix, const char *realpath, int srcpath) {
 	xar_file_t ret;
 	const char *path; 
 	char *tmp;
 	char idstr[32];
 
 	if( !f ) {
-		asprintf(&tmp, "%s%s%s", XAR(x)->path_prefix, prefix, name);
+		if( realpath )
+			asprintf(&tmp, "%s", realpath);
+		else
+			asprintf(&tmp, "%s%s%s", XAR(x)->path_prefix, prefix, name);
+
 		if( lstat(tmp, &XAR(x)->sbcache) != 0 ) {
 			free(tmp);
 			return NULL;
@@ -631,7 +639,12 @@
 			}
 			
 		}
-		asprintf(&tmp, "%s/%s%s", path, prefix, name);
+
+		if( realpath ){
+			asprintf(&tmp, "%s", realpath);
+		}else
+			asprintf(&tmp, "%s/%s%s", path, prefix, name);
+		
 		if( lstat(tmp, &XAR(x)->sbcache) != 0 ) {
 			free(tmp);
 			return NULL;
@@ -648,7 +661,7 @@
 
 	xar_prop_set(ret, "name", name);
 
-	if( xar_arcmod_archive(x, ret, XAR_FILE(ret)->fspath) < 0 ) {
+	if( xar_arcmod_archive(x, ret, XAR_FILE(ret)->fspath, NULL, 0) < 0 ) {
 		xar_file_t i;
 		if( f ) {
 			for( i = XAR_FILE(f)->children; i && (XAR_FILE(i)->next != ret); i = XAR_FILE(i)->next );
@@ -736,9 +749,9 @@
 
 	/* tmp3 was not found in children of start, so we add it */
 	if( tmp2 ) {
-		ret = xar_add_node(x, f, tmp3, prefix, 1);
+		ret = xar_add_node(x, f, tmp3, prefix, NULL,  1);
 	} else {
-		ret = xar_add_node(x, f, tmp3, prefix, 0);
+		ret = xar_add_node(x, f, tmp3, prefix, NULL,  0);
 	}
 
 	if( !ret ) {
@@ -783,18 +796,209 @@
 	return xar_add_r(x, NULL, path, "");
 }
 
+/* xar_add_frombuffer
+* x: archive to add the file to
+* parent: parent node, possibly NULL
+* name: name of file
+* buffer: buffer for file contents
+* length: length of buffer
+* Returns: allocated an populated xar_file_t representing the 
+* specified file.
+* Summary: Use this to add chunks of named data to a xar without
+* using the filesystem.
+*/
+
+xar_file_t xar_add_frombuffer(xar_t x, xar_file_t parent, const char *name, char *buffer, size_t length) {
+	xar_file_t ret;
+	char *tmp;
+	char idstr[32];
+	
+	if( !parent ) {
+		ret = xar_file_new(NULL);
+		if( !ret )
+			return NULL;
+		memset(idstr, 0, sizeof(idstr));
+		snprintf(idstr, sizeof(idstr)-1, "%"PRIu64, ++XAR(x)->last_fileid);
+		xar_attr_set(ret, NULL, "id", idstr);
+		XAR_FILE(ret)->parent = NULL;
+		if( XAR(x)->files == NULL )
+			XAR(x)->files = ret;
+		else {
+			XAR_FILE(ret)->next = XAR(x)->files;
+			XAR(x)->files = ret;
+		}
+	} else {
+		ret = xar_file_new(parent);
+		if( !ret )
+			return NULL;
+		memset(idstr, 0, sizeof(idstr));
+		snprintf(idstr, sizeof(idstr)-1, "%"PRIu64, ++XAR(x)->last_fileid);
+		xar_attr_set(ret, NULL, "id", idstr);
+		XAR_FILE(ret)->fspath = tmp;
+	}
+	
+	xar_prop_set(ret, "name", name);
+		
+	//int32_t xar_arcmod_archive(xar_t x, xar_file_t f, const char *file, const char *buffer, size_t len) 
+	if( xar_arcmod_archive(x, ret, NULL , buffer , length) < 0 ) {
+		xar_file_t i;
+		if( parent ) {
+			for( i = XAR_FILE(parent)->children; i && (XAR_FILE(i)->next != ret); i = XAR_FILE(i)->next );
+		} else {
+			for( i = XAR(x)->files; i && (XAR_FILE(i)->next != ret); i = XAR_FILE(i)->next );
+		}
+		if( i )
+			XAR_FILE(i)->next = XAR_FILE(ret)->next;
+		xar_file_free(ret);
+		return NULL;
+	}
+	
+	return ret;
+}
+
+xar_file_t xar_add_folder(xar_t x, xar_file_t f, const char *name, struct stat *info)
+{
+	xar_file_t ret;
+	char idstr[32];
+
+	if( info )
+		memcpy(&XAR(x)->sbcache,info,sizeof(struct stat));
+	
+	ret = xar_file_new(f);
+	if( !ret )
+		return NULL;
+	
+	memset(idstr, 0, sizeof(idstr));
+	snprintf(idstr, sizeof(idstr)-1, "%"PRIu64, ++XAR(x)->last_fileid);
+	xar_attr_set(ret, NULL, "id", idstr);
+	XAR_FILE(ret)->fspath = NULL;
+	
+	if( !f ) {
+		XAR_FILE(ret)->parent = NULL;
+		
+		if( XAR(x)->files == NULL )
+			XAR(x)->files = ret;
+		else {
+			XAR_FILE(ret)->next = XAR(x)->files;
+			XAR(x)->files = ret;
+		}
+	}
+	
+	xar_prop_set(ret, "name", name);
+
+	if( xar_arcmod_archive(x, ret, XAR_FILE(ret)->fspath, NULL, 0) < 0 ) {
+		xar_file_t i;
+		if( f ) {
+			for( i = XAR_FILE(f)->children; i && (XAR_FILE(i)->next != ret); i = XAR_FILE(i)->next );
+		} else {
+			for( i = XAR(x)->files; i && (XAR_FILE(i)->next != ret); i = XAR_FILE(i)->next );
+		}
+		if( i )
+			XAR_FILE(i)->next = XAR_FILE(ret)->next;
+		xar_file_free(ret);
+		return NULL;
+	}
+	
+	return ret;	
+}
+
+xar_file_t xar_add_frompath(xar_t x, xar_file_t parent, const char *name, const char *realpath)
+{
+	return xar_add_node(x, parent, name , "" , realpath,  1);
+}
+
+xar_file_t xar_add_from_archive(xar_t x, xar_file_t parent, const char *name, xar_t sourcearchive, xar_file_t sourcefile)
+{
+	xar_file_t ret;
+	char idstr[32];
+		
+	ret = xar_file_replicate(sourcefile, parent);
+	
+	if( !ret )
+		return NULL;
+	
+	memset(idstr, 0, sizeof(idstr));
+	snprintf(idstr, sizeof(idstr)-1, "%"PRIu64, ++XAR(x)->last_fileid);
+	xar_attr_set(ret, NULL, "id", idstr);
+	XAR_FILE(ret)->fspath = NULL;
+	
+	if( !parent ) {
+		XAR_FILE(ret)->parent = NULL;
+		
+		if( XAR(x)->files == NULL )
+			XAR(x)->files = ret;
+		else {
+			XAR_FILE(ret)->next = XAR(x)->files;
+			XAR(x)->files = ret;
+		}
+	}
+		
+	xar_prop_set(ret, "name", name);
+		
+	/* iterate through all the properties, see if any of them have an offset */
+	xar_iter_t iter = xar_iter_new();
+	const char *attr = xar_prop_first(ret , iter);
+	char *tmpstr = NULL;
+
+	do{
+		asprintf(&tmpstr, "%s/offset", attr);
+		if(0 == xar_prop_get(ret, tmpstr, NULL) ){
+			if( 0 != xar_attrcopy_from_heap_to_heap(sourcearchive, sourcefile, attr, x, ret)){			
+				xar_file_free(ret);
+				ret = NULL;
+				break;
+			}
+		}
+		free(tmpstr);
+		
+	}while( (attr = xar_prop_next(iter)) );
+	
+	xar_iter_free(iter);
+	
+	return ret;	
+}
+
 /* xar_extract_tofile
- * x: archive to extract from
- * f: file associated with x
- * Returns 0 on success, -1 on failure
- * Summary: This actually does the file extraction.
- * No traversal is performed, it is assumed all directory paths
- * leading up to f already exist.
- */
+* x: archive to extract from
+* f: file associated with x
+* Returns 0 on success, -1 on failure
+* Summary: This actually does the file extraction.
+* No traversal is performed, it is assumed all directory paths
+* leading up to f already exist.
+*/
 int32_t xar_extract_tofile(xar_t x, xar_file_t f, const char *path) {
-	return xar_arcmod_extract(x, f, path);
+	return xar_arcmod_extract(x, f, path,NULL, 0);
 }
 
+
+/* xar_extract_tobuffer
+* x: archive to extract from
+* buffer: buffer to extract to
+* Returns 0 on success, -1 on failure.
+* Summary: This is the entry point for extraction to a buffer.
+* On success, a buffer is allocated with the contents of the file
+* specified.  The caller is responsible for freeing the returend buffer.
+* Example: xar_extract_tobuffer(x, "foo/bar/blah",&buffer)
+*/
+int32_t xar_extract_tobuffer(xar_t x, xar_file_t f, char **buffer) {
+	size_t	size;
+	const char *sizestring = NULL;
+	
+	if(0 != xar_prop_get(f,"data/size",&sizestring)){
+		return -1;
+	}
+
+	size = strtoull(sizestring, (char **)NULL, 10);
+	*buffer = malloc(size);
+	
+	if(!(*buffer)){
+		return -1;
+	}
+	
+	return xar_arcmod_extract(x,f,NULL,*buffer,size);
+}
+
+
 /* xar_extract
  * x: archive to extract from
  * path: path to file to extract
@@ -828,6 +1032,18 @@
 	return xar_extract_tofile(x, f, XAR_FILE(f)->fspath);
 }
 
+/* xar_extract
+* x: archive to extract from
+* f: file to verify
+* Returns 0 on success, -1 on failure.
+* Summary: This function allows for verification of
+* an entry without extraction.  If there is no checksum
+* the verification will pass.
+*/
+int32_t xar_verify(xar_t x, xar_file_t f) {
+	return xar_arcmod_verify(x,f);
+}
+
 /* read_callback
  * context: context passed through from the reader
  * buffer: buffer to read into
diff -urN xar.hash/lib/archive.h xar.final/lib/archive.h
--- xar.hash/lib/archive.h	2006-03-17 11:19:16.000000000 -0800
+++ xar.final/lib/archive.h	2006-03-17 10:35:14.000000000 -0800
@@ -55,28 +55,28 @@
 	const char *ns;
 	const char *filler1;
 	const char *filler2;
-	xar_file_t files;      /* file forest */
-	const char *filename;  /* name of the archive we are operating on */
-	char *dirname;         /* directory of the archive, used in creation */
-	int fd;                /* open file descriptor for the archive */
-	int heap_fd;           /* fd for tmp heap archive, used in creation */
-	off_t heap_offset;     /* current offset within the heap */
-	off_t heap_len;        /* current length of the heap */
-	xar_header_t header;   /* header of the xar archive */
-	void *readbuf;         /* buffer for reading/writing compressed toc */
-	size_t readbuf_len;    /* length of readbuf */
-	size_t offset;         /* offset into readbuf for keeping track
-	                        * between callbacks. */
-	size_t toc_count;      /* current bytes read of the toc */
-	z_stream zs;           /* gz state for compressing/decompressing toc */
-	char *path_prefix;     /* used for distinguishing absolute paths */
-	err_handler ercallback; /* callback for errors/warnings */
-	struct errctx errctx;   /* error callback context */
-	xar_subdoc_t subdocs;   /* linked list of subdocs */
-	uint64_t last_fileid;   /* unique fileid's in the archive */
-	xmlHashTablePtr ino_hash;/* Hash for looking up hardlinked files (add)*/
-	xmlHashTablePtr link_hash;/* Hash for looking up hardlinked files (extract)*/
-	xmlHashTablePtr csum_hash;/* Hash for looking up checksums of files */
+	xar_file_t files;			/* file forest */
+	const char *filename;		/* name of the archive we are operating on */
+	char *dirname;				/* directory of the archive, used in creation */
+	int fd;						/* open file descriptor for the archive */
+	int heap_fd;				/* fd for tmp heap archive, used in creation */
+	off_t heap_offset;			/* current offset within the heap */
+	off_t heap_len;				/* current length of the heap */
+	xar_header_t header;		/* header of the xar archive */
+	void *readbuf;				/* buffer for reading/writing compressed toc */
+	size_t readbuf_len;			/* length of readbuf */
+	size_t offset;				/* offset into readbuf for keeping track
+								* between callbacks. */
+	size_t toc_count;			/* current bytes read of the toc */
+	z_stream zs;				/* gz state for compressing/decompressing toc */
+	char *path_prefix;			/* used for distinguishing absolute paths */
+	err_handler ercallback;		/* callback for errors/warnings */
+	struct errctx errctx;		/* error callback context */
+	xar_subdoc_t subdocs;		/* linked list of subdocs */
+	uint64_t last_fileid;		/* unique fileid's in the archive */
+	xmlHashTablePtr ino_hash;	/* Hash for looking up hardlinked files (add)*/
+	xmlHashTablePtr link_hash;	/* Hash for looking up hardlinked files (extract)*/
+	xmlHashTablePtr csum_hash;	/* Hash for looking up checksums of files */
 	EVP_MD_CTX toc_ctx;
 	int docksum;
 	int skipwarn;
diff -urN xar.hash/lib/arcmod.c xar.final/lib/arcmod.c
--- xar.hash/lib/arcmod.c	2006-03-17 11:19:16.000000000 -0800
+++ xar.final/lib/arcmod.c	2006-03-17 10:35:14.000000000 -0800
@@ -57,12 +57,12 @@
  * Returns: 0 on success
  * Summary: This is the entry point to actual file archival.
  */
-int32_t xar_arcmod_archive(xar_t x, xar_file_t f, const char *file) {
+int32_t xar_arcmod_archive(xar_t x, xar_file_t f, const char *file, const char *buffer, size_t len) {
 	int i;
 	int32_t ret;
 	for(i = 0; i < (sizeof(xar_arcmods)/sizeof(struct arcmod)); i++) {
 		if( xar_arcmods[i].archive ) {
-			ret = xar_arcmods[i].archive(x, f, file);
+			ret = xar_arcmods[i].archive(x, f, file, buffer, len);
 			if( ret < 0 ) {
 				return ret;
 			}
@@ -81,12 +81,12 @@
  * Returns: 0 on success
  * Summary: This is the entry point to actual file archival.
  */
-int32_t xar_arcmod_extract(xar_t x, xar_file_t f, const char *file) {
+int32_t xar_arcmod_extract(xar_t x, xar_file_t f, const char *file, char *buffer, size_t len) {
 	int i;
 	int32_t ret;
 	for(i = 0; i < (sizeof(xar_arcmods)/sizeof(struct arcmod)); i++) {
 		if( xar_arcmods[i].extract ) {
-			ret = xar_arcmods[i].extract(x, f, file);
+			ret = xar_arcmods[i].extract(x, f, file, buffer, len);
 			if( ret < 0 ) {
 				return ret;
 			}
@@ -97,3 +97,8 @@
 	}
 	return 0;
 }
+
+
+int32_t xar_arcmod_verify(xar_t x, xar_file_t f){
+	return xar_data_verify(x,f);
+}
diff -urN xar.hash/lib/arcmod.h xar.final/lib/arcmod.h
--- xar.hash/lib/arcmod.h	2006-03-17 11:19:16.000000000 -0800
+++ xar.final/lib/arcmod.h	2006-03-17 10:35:14.000000000 -0800
@@ -37,15 +37,17 @@
 #include "filetree.h"
 
 
-typedef int32_t (*arcmod_archive)(xar_t x, xar_file_t f, const char* file);
-typedef int32_t (*arcmod_extract)(xar_t x, xar_file_t f, const char* file);
+typedef int32_t (*arcmod_archive)(xar_t x, xar_file_t f, const char* file, const char *buffer, size_t len);
+typedef int32_t (*arcmod_extract)(xar_t x, xar_file_t f, const char* file, char *buffer, size_t len);
 
 struct arcmod {
 	arcmod_archive archive;
 	arcmod_extract extract;
 };
 
-int32_t xar_arcmod_archive(xar_t x, xar_file_t f, const char *file);
-int32_t xar_arcmod_extract(xar_t x, xar_file_t f, const char *file);
+int32_t xar_arcmod_archive(xar_t x, xar_file_t f, const char *file, const char *buffer, size_t len);
+int32_t xar_arcmod_extract(xar_t x, xar_file_t f, const char *file, char *buffer, size_t len);
+
+int32_t xar_arcmod_verify(xar_t x, xar_file_t f);
 
 #endif /* _XAR_ARCMOD_H_ */
diff -urN xar.hash/lib/darwinattr.c xar.final/lib/darwinattr.c
--- xar.hash/lib/darwinattr.c	2006-03-17 11:26:55.000000000 -0800
+++ xar.final/lib/darwinattr.c	2006-03-17 10:35:14.000000000 -0800
@@ -554,19 +554,21 @@
 
 	DARWINATTR_CONTEXT(context)->fd = 0;
 
-	xar_set_perm(x, f, underbarname );
+	xar_set_perm(x, f, underbarname, NULL, 0 );
 	
 	return 0;
 }
 
 
-int32_t xar_darwinattr_archive(xar_t x, xar_file_t f, const char* file)
+int32_t xar_darwinattr_archive(xar_t x, xar_file_t f, const char* file, const char *buffer, size_t len)
 {
 	struct _darwinattr_context context;
 	
 	memset(&context,0,sizeof(struct _darwinattr_context));
 	
 #if defined(__APPLE__)
+	if( len )
+		return 0;
 #if defined(HAVE_GETXATTR)
 	if( ea_archive(x, f, file, (void *)&context) == 0 )
 		return 0;
@@ -578,13 +580,15 @@
 	return 0;
 }
 
-int32_t xar_darwinattr_extract(xar_t x, xar_file_t f, const char* file)
+int32_t xar_darwinattr_extract(xar_t x, xar_file_t f, const char* file, char *buffer, size_t len)
 {
 	struct _darwinattr_context context;
 	
 	memset(&context,0,sizeof(struct _darwinattr_context));
 	
 #if defined(__APPLE__)
+	if( len )
+		return 0;
 #if defined(HAVE_GETXATTR)
 	if( ea_extract(x, f, file, (void *)&context) == 0 )
 		return 0;
diff -urN xar.hash/lib/darwinattr.h xar.final/lib/darwinattr.h
--- xar.hash/lib/darwinattr.h	2006-03-17 11:19:16.000000000 -0800
+++ xar.final/lib/darwinattr.h	2006-03-17 10:35:14.000000000 -0800
@@ -6,6 +6,6 @@
 #ifndef _XAR_DARWINATTR_H_
 #define _XAR_DARWINATTR_H_
 int32_t xar_underbar_check(xar_t x, xar_file_t f, const char* file);
-int32_t xar_darwinattr_archive(xar_t x, xar_file_t f, const char* file);
-int32_t xar_darwinattr_extract(xar_t x, xar_file_t f, const char* file);
+int32_t xar_darwinattr_archive(xar_t x, xar_file_t f, const char* file, const char *buffer, size_t len);
+int32_t xar_darwinattr_extract(xar_t x, xar_file_t f, const char* file,	char *buffer, size_t len);
 #endif /* _XAR_DARWINATTR_H_ */
diff -urN xar.hash/lib/data.c xar.final/lib/data.c
--- xar.hash/lib/data.c	2006-03-17 11:19:16.000000000 -0800
+++ xar.final/lib/data.c	2006-03-17 10:35:14.000000000 -0800
@@ -99,7 +99,7 @@
  * 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) {
+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;
@@ -120,14 +120,20 @@
 			return 0;
 	}
 
-	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;
-	}		
+	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;
+	}
 
 	retval = xar_attrcopy_to_heap(x, f, "data", xar_data_read,(void *)(&context));
 
@@ -137,7 +143,7 @@
 	return retval;
 }
 
-int32_t xar_data_extract(xar_t x, xar_file_t f, const char *file) {
+int32_t xar_data_extract(xar_t x, xar_file_t f, const char *file, char *buffer, size_t len) {
 	const char *opt;
 	struct _data_context context;
 	
@@ -158,25 +164,32 @@
 			return 0;
 	}
 	
-	/* mode 600 since other modules may need to operate on the file
-	* prior to the real permissions being set.
-	*/
+	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.
+		*/
 TRYAGAIN:
-	context.fd = open(file, O_RDWR|O_TRUNC|O_EXLOCK, 0600);
-	if( context.fd < 0 ) {
-		if( errno == ENOENT ) {
-			xar_file_t parent = XAR_FILE(f)->parent;
-			if( parent && (xar_extract(x, parent) == 0) )
-				goto TRYAGAIN;
+		context.fd = open(file, O_RDWR|O_TRUNC|O_EXLOCK, 0600);
+		if( context.fd < 0 ) {
+			if( errno == ENOENT ) {
+				xar_file_t parent = XAR_FILE(f)->parent;
+				if( parent && (xar_extract(x, parent) == 0) )
+					goto TRYAGAIN;
+			}
+			
+			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;
 		}
 		
-		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;
 	}
-			
+	
 	xar_attrcopy_from_heap(x, f, "data", xar_data_write, (void *)(&context));
 	
 	if( context.fd > 0 )		
@@ -185,3 +198,19 @@
 	return 0;
 }
 
+int32_t xar_data_verify(xar_t x, xar_file_t f)
+{
+	const char *opt;
+	struct _data_context context;
+	
+	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, "directory") == 0 ) {
+		return 0;
+	}
+	
+	return xar_attrcopy_from_heap(x, f, "data", NULL , (void *)(&context));
+}
diff -urN xar.hash/lib/data.h xar.final/lib/data.h
--- xar.hash/lib/data.h	2006-03-17 11:19:16.000000000 -0800
+++ xar.final/lib/data.h	2006-03-17 10:35:14.000000000 -0800
@@ -5,6 +5,8 @@
  */
 #ifndef _XAR_DATA_H_
 #define _XAR_DATA_H_
-int32_t xar_data_archive(xar_t x, xar_file_t f, const char* file);
-int32_t xar_data_extract(xar_t x, xar_file_t f, const char* file);
+int32_t xar_data_archive(xar_t x, xar_file_t f, const char* file, const char *buffer, size_t len);
+int32_t xar_data_extract(xar_t x, xar_file_t f, const char* file, char *buffer, size_t len);
+
+int32_t xar_data_verify(xar_t x, xar_file_t f);
 #endif /* _XAR_DATA_H_ */
diff -urN xar.hash/lib/ext2.c xar.final/lib/ext2.c
--- xar.hash/lib/ext2.c	2006-03-17 11:19:16.000000000 -0800
+++ xar.final/lib/ext2.c	2006-03-17 10:35:14.000000000 -0800
@@ -70,9 +70,14 @@
 }
 #endif
 
-int xar_ext2attr_archive(xar_t x, xar_file_t f, const char* file)
+int xar_ext2attr_archive(xar_t x, xar_file_t f, const char* file, const char *buffer, size_t len)
 {
 	int ret = 0;
+	
+	/* if archiving from a buffer, then there is no place to get extattr */
+	if ( len )
+		return 0;
+		
 #if defined(HAVE_EXT2FS_EXT2_FS_H) || defined(HAVE_LINUX_EXT2_FS_H)
 	int fd, flags=0, version;
 	char *vstr;
@@ -158,8 +163,12 @@
 }
 #endif
 
-int xar_ext2attr_extract(xar_t x, xar_file_t f, const char* file)
+int xar_ext2attr_extract(xar_t x, xar_file_t f, const char* file, char *buffer, size_t len)
 {
+	/* if extracting to a buffer, then there is no place to write extattr */
+	if ( len )
+		return 0;
+	
 #if defined(HAVE_EXT2FS_EXT2_FS_H) || defined(HAVE_LINUX_EXT2_FS_H)
 	int fd = -1, version, flags = 0;
 	char *tmp;
diff -urN xar.hash/lib/ext2.h xar.final/lib/ext2.h
--- xar.hash/lib/ext2.h	2006-03-17 11:19:16.000000000 -0800
+++ xar.final/lib/ext2.h	2006-03-17 10:35:14.000000000 -0800
@@ -6,6 +6,6 @@
 #ifndef _XAR_EXT2_H_
 #define _XAR_EXT2_H_
 #define XAR_ATTR_FORK "attribute"
-int xar_ext2attr_archive(xar_t x, xar_file_t f, const char* file);
-int xar_ext2attr_extract(xar_t x, xar_file_t f, const char* file);
+int xar_ext2attr_archive(xar_t x, xar_file_t f, const char* file, const char *buffer, size_t len);
+int xar_ext2attr_extract(xar_t x, xar_file_t f, const char* file, char *buffer, size_t len);
 #endif /* _XAR_EXT2_H_ */
diff -urN xar.hash/lib/fbsdattr.c xar.final/lib/fbsdattr.c
--- xar.hash/lib/fbsdattr.c	2006-03-17 11:19:16.000000000 -0800
+++ xar.final/lib/fbsdattr.c	2006-03-17 10:54:53.000000000 -0800
@@ -99,7 +99,7 @@
 }
 #endif
 
-int32_t xar_fbsdattr_archive(xar_t x, xar_file_t f, const char* file)
+int32_t xar_fbsdattr_archive(xar_t x, xar_file_t f, const char* file, const char *buffer, size_t len)
 {
 #ifdef HAVE_SYS_EXTATTR_H
 	char *buf = NULL;
@@ -110,6 +110,11 @@
 	struct _fbsdattr_context context;
 	
 	memset(&context,0,sizeof(struct _fbsdattr_context));
+
+	/* no fbsdattr attributes for data to a buffer */
+	if(len){
+		return 0;
+	}
 	
 TRYAGAIN:
 	/* extattr_list_link()'s man page does not define the return
@@ -218,7 +223,12 @@
 	struct _fbsdattr_context context;
 	
 	memset(&context,0,sizeof(struct _fbsdattr_context));
-		
+	
+	/* no fbsdattr attributes for data to a buffer */
+	if(len){
+		return 0;
+	}
+	
 	statfs(file, &sfs);
 	fsname = sfs.f_fstypename;
 
diff -urN xar.hash/lib/fbsdattr.h xar.final/lib/fbsdattr.h
--- xar.hash/lib/fbsdattr.h	2006-03-17 11:19:16.000000000 -0800
+++ xar.final/lib/fbsdattr.h	2006-03-17 10:35:14.000000000 -0800
@@ -5,6 +5,6 @@
  */
 #ifndef _XAR_FBSDATTR_H_
 #define _XAR_FBSDATTR_H_
-int32_t xar_fbsdattr_archive(xar_t x, xar_file_t f, const char* file);
-int32_t xar_fbsdattr_extract(xar_t x, xar_file_t f, const char* file);
+int32_t xar_fbsdattr_archive(xar_t x, xar_file_t f, const char* file, const char *buffer, size_t len);
+int32_t xar_fbsdattr_extract(xar_t x, xar_file_t f, const char* file, char *buffer, size_t len);
 #endif /* _XAR_FBSDATTR_H_ */
diff -urN xar.hash/lib/filetree.c xar.final/lib/filetree.c
--- xar.hash/lib/filetree.c	2006-03-17 11:19:16.000000000 -0800
+++ xar.final/lib/filetree.c	2006-03-17 10:35:14.000000000 -0800
@@ -545,6 +545,51 @@
 	return 0;
 }
 
+/* xar_prop_replicate_r
+* f: file to attach property
+* p: property (list) to iterate and add
+* parent: parent property
+* Summary: Recursivley adds property list (p) to file (f) and parent (parent).
+*/
+
+void xar_prop_replicate_r(xar_file_t f, xar_prop_t p, xar_prop_t parent )
+{
+	xar_prop_t property = p;
+	
+	/* look through properties */
+	for( property = p; property; property = property->next ){
+		xar_prop_t	newprop = xar_prop_new( f, parent );
+		
+		/* copy the key value for the property */
+		XAR_PROP(newprop)->key = strdup(property->key);
+		if(property->value)
+			XAR_PROP(newprop)->value = strdup(property->value);
+		
+		/* loop through the attributes and copy them */
+		xar_attr_t a = NULL;
+		xar_attr_t last = NULL;
+		
+		/* copy attributes for file */
+		for(a = property->attrs; a; a = a->next) {			
+			if( NULL == newprop->attrs ){
+				last = xar_attr_new();
+				XAR_PROP(newprop)->attrs = last;				
+			}else{
+				XAR_ATTR(last)->next = xar_attr_new();
+				last = XAR_ATTR(last)->next;
+			}
+			
+			XAR_ATTR(last)->key = strdup(a->key);
+			if(a->value)
+				XAR_ATTR(last)->value = strdup(a->value);
+		}
+		
+		/* loop through the children properties and recursively add them */
+		xar_prop_replicate_r(f, property->children, newprop );		
+	}
+	
+}
+
 /* xar_prop_free
  * p: property to free
  * Summary: frees the specified property and all its children.
@@ -621,6 +666,26 @@
 	return ret;
 }
 
+xar_file_t xar_file_replicate(xar_file_t original, xar_file_t newparent)
+{
+	xar_file_t ret = xar_file_new(newparent);	
+	xar_attr_t a;
+	
+	/* copy attributes for file */
+	for(a = XAR_FILE(original)->attrs; a; a = XAR_ATTR(a)->next) {
+		/* skip the id attribute */
+		if( 0 == strcmp(a->key, "id" ) )
+			continue;
+		
+		xar_attr_set(ret, NULL , a->key, a->value );
+	}
+		
+	/* recursively copy properties */
+	xar_prop_replicate_r(ret, XAR_FILE(original)->props, NULL);
+
+	return ret;
+}
+
 /* xar_file_free
  * f: file to free
  * Summary: frees the specified file and all children,
diff -urN xar.hash/lib/filetree.h xar.final/lib/filetree.h
--- xar.hash/lib/filetree.h	2006-03-17 11:19:16.000000000 -0800
+++ xar.final/lib/filetree.h	2006-03-17 10:35:14.000000000 -0800
@@ -82,6 +82,7 @@
 xar_file_t xar_file_unserialize(xar_t x, xar_file_t parent, xmlTextReaderPtr reader);
 xar_file_t xar_file_find(xar_file_t f, const char *path);
 xar_file_t xar_file_new(xar_file_t f);
+xar_file_t xar_file_replicate(xar_file_t original, xar_file_t newparent);
 void xar_file_free(xar_file_t f);
 
 void xar_prop_serialize(xar_prop_t p, xmlTextWriterPtr writer);
diff -urN xar.hash/lib/io.c xar.final/lib/io.c
--- xar.hash/lib/io.c	2006-03-17 11:20:06.000000000 -0800
+++ xar.final/lib/io.c	2006-03-17 10:35:14.000000000 -0800
@@ -415,6 +415,140 @@
 	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, const char *attr, 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, *tmpstr2 = NULL;
+	
+	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;
+		}
+	}
+	
+	asprintf(&tmpstr, "%s/offset", attr);
+	xar_prop_get(fsource, tmpstr, &opt);
+	free(tmpstr);
+	
+	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);
+			}
+		}
+	}
+	
+	asprintf(&tmpstr, "%s/length", attr);
+	xar_prop_get(fsource, tmpstr, &opt);
+	free(tmpstr);
+	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);
+	asprintf(&tmpstr2, "%s/offset", attr);
+	xar_prop_set(fdest, tmpstr2, tmpstr);
+	free(tmpstr);
+	free(tmpstr2);
+	
+	
+	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_heap_to_archive
  * x: archive to operate on
  * Returns 0 on success, -1 on error
diff -urN xar.hash/lib/io.h xar.final/lib/io.h
--- xar.hash/lib/io.h	2006-03-17 11:19:16.000000000 -0800
+++ xar.final/lib/io.h	2006-03-17 10:35:14.000000000 -0800
@@ -56,6 +56,7 @@
 
 int32_t xar_attrcopy_to_heap(xar_t x, xar_file_t f, const char *attr, read_callback rcb, void *context);
 int32_t xar_attrcopy_from_heap(xar_t x, xar_file_t f, const char *attr, write_callback wcb, void *context);
+int32_t xar_attrcopy_from_heap_to_heap(xar_t xsource, xar_file_t fsource, const char *attr, xar_t xdest, xar_file_t fdest);
 int32_t xar_heap_to_archive(xar_t x);
 
 #endif /* _XAR_IO_H_ */
diff -urN xar.hash/lib/linuxattr.c xar.final/lib/linuxattr.c
--- xar.hash/lib/linuxattr.c	2006-03-17 11:19:16.000000000 -0800
+++ xar.final/lib/linuxattr.c	2006-03-17 13:38:53.000000000 -0800
@@ -128,7 +128,7 @@
 }
 #endif
 
-int32_t xar_linuxattr_archive(xar_t x, xar_file_t f, const char* file)
+int32_t xar_linuxattr_archive(xar_t x, xar_file_t f, const char* file, const char *buffer, size_t len)
 {
 #if defined(HAVE_SYS_XATTR_H) && defined(HAVE_LGETXATTR) && !defined(__APPLE__)
 	char *i, *buf = NULL;
@@ -139,6 +139,11 @@
 	
 	memset(&context,0,sizeof(struct _linuxattr_context));
 	
+	/* data from buffers don't have linuxattr */
+	if(len){
+		return 0;
+	}
+	
 TRYAGAIN:
 	buf = malloc(bufsz);
 	if(!buf)
@@ -188,7 +193,7 @@
 	return 0;
 }
 
-int32_t xar_linuxattr_extract(xar_t x, xar_file_t f, const char* file)
+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";
@@ -200,6 +205,11 @@
 	
 	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));
diff -urN xar.hash/lib/linuxattr.h xar.final/lib/linuxattr.h
--- xar.hash/lib/linuxattr.h	2006-03-17 11:19:16.000000000 -0800
+++ xar.final/lib/linuxattr.h	2006-03-17 13:38:55.000000000 -0800
@@ -5,6 +5,6 @@
  */
 #ifndef _XAR_LINUXATTR_H_
 #define _XAR_LINUXATTR_H_
-int32_t xar_linuxattr_archive(xar_t x, xar_file_t f, const char* file);
-int32_t xar_linuxattr_extract(xar_t x, xar_file_t f, const char* file);
+int32_t xar_linuxattr_archive(xar_t x, xar_file_t f, const char* file, const char *buffer, size_t len);
+int32_t xar_linuxattr_extract(xar_t x, xar_file_t f, const char* file, char *buffer, size_t len);
 #endif /* _XAR_LINUXATTR_H_ */
diff -urN xar.hash/lib/stat.c xar.final/lib/stat.c
--- xar.hash/lib/stat.c	2006-03-17 11:19:16.000000000 -0800
+++ xar.final/lib/stat.c	2006-03-17 10:35:14.000000000 -0800
@@ -214,7 +214,7 @@
 	return 0;
 }
 
-int32_t xar_stat_archive(xar_t x, xar_file_t f, const char *file) {
+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;
@@ -222,6 +222,12 @@
 	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");
@@ -304,7 +310,7 @@
 	return 0;
 }
 
-int32_t xar_set_perm(xar_t x, xar_file_t f, const char *file) {
+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;
@@ -314,6 +320,10 @@
 	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();
@@ -433,7 +443,7 @@
 	return 0;
 }
 
-int32_t xar_stat_extract(xar_t x, xar_file_t f, const char *file) {
+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;
 
diff -urN xar.hash/lib/stat.h xar.final/lib/stat.h
--- xar.hash/lib/stat.h	2006-03-17 11:19:16.000000000 -0800
+++ xar.final/lib/stat.h	2006-03-17 10:35:14.000000000 -0800
@@ -36,8 +36,8 @@
 
 #include "xar.h"
 
-int32_t xar_stat_archive(xar_t x, xar_file_t f, const char *file);
-int32_t xar_stat_extract(xar_t x, xar_file_t f, const char *file);
-int32_t xar_set_perm(xar_t x, xar_file_t f, const char *file);
+int32_t xar_stat_archive(xar_t x, xar_file_t f, const char *file, const char *buffer, size_t len);
+int32_t xar_stat_extract(xar_t x, xar_file_t f, const char *file, char *buffer, size_t len);
+int32_t xar_set_perm(xar_t x, xar_file_t f, const char *file, char *buffer, size_t len);
 
 #endif /* _XAR_STAT_H_ */
diff -urN xar.hash/lib/util.c xar.final/lib/util.c
--- xar.hash/lib/util.c	2006-03-17 11:19:16.000000000 -0800
+++ xar.final/lib/util.c	2006-03-17 10:35:14.000000000 -0800
@@ -30,6 +30,7 @@
  * 03-Apr-2005
  * DRI: Rob Braun <bbraun@opendarwin.org>
  */
+
 #include <stdio.h>
 #include <stdint.h>
 #include <sys/types.h>
@@ -42,6 +43,7 @@
 #include "asprintf.h"
 #endif
 #include "xar.h"
+#include "archive.h"
 #include "filetree.h"
 
 uint64_t xar_ntoh64(uint64_t num) {
@@ -97,6 +99,10 @@
 	return ret;
 }
 
+off_t	xar_get_heap_offset(xar_t x) {
+	return XAR(x)->toc_count + sizeof(xar_header_t);
+}
+
 /* xar_read_fd
  * Summary: Reads from a file descriptor a certain number of bytes to a specific
  * buffer.  This simple wrapper just handles certain retryable error situations.
diff -urN xar.hash/lib/util.h xar.final/lib/util.h
--- xar.hash/lib/util.h	2006-03-17 11:19:16.000000000 -0800
+++ xar.final/lib/util.h	2006-03-17 10:35:14.000000000 -0800
@@ -41,6 +41,7 @@
 uint64_t xar_ntoh64(uint64_t num);
 uint32_t xar_swap32(uint32_t num);
 char *xar_get_path(xar_file_t f);
+off_t	xar_get_heap_offset(xar_t x);
 ssize_t xar_read_fd(int fd, void * buffer, size_t nbytes);
 ssize_t xar_write_fd(int fd, void * buffer, size_t nbytes);