Class: Archive

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
ext/archive.cpp,
ext/entry.cpp,
ext/archive.cpp

Overview

This class represents an archive file. The file may or may not exist, depending on wheather you want to create a new archive or read from an existing one. When instanciating this class, libarchive-ruby will automatically detect the correct file format for you using libarchive’s own detection mechanism if the archive file is already present, otherwise by looking at the archive file’s file extension.

Defined Under Namespace

Classes: Entry, Error

Constant Summary collapse

EXTRACT_TIME =

extract the atime and mtime

INT2NUM(ARCHIVE_EXTRACT_TIME)
EXTRACT_OWNER =

extract the owner

INT2NUM(ARCHIVE_EXTRACT_OWNER)
EXTRACT_PERM =

extract the permission

INT2NUM(ARCHIVE_EXTRACT_PERM)
EXTRACT_NO_OVERWRITE =
INT2NUM(ARCHIVE_EXTRACT_NO_OVERWRITE)
EXTRACT_ACL =

extract the access control list

INT2NUM(ARCHIVE_EXTRACT_ACL)
EXTRACT_FFLAGS =

extract the fflags

INT2NUM(ARCHIVE_EXTRACT_FFLAGS)
EXTRACT_XATTR =

extract the extended information

INT2NUM(ARCHIVE_EXTRACT_XATTR)

Instance Method Summary collapse

Constructor Details

#new(path[, format [, compression ] ]) ⇒ Object

Makes a new Archive object. If format is given, a new archive is created or

an existing archive will be converted into the given format.
===Parameters
[path]   The path to the archive. May or may not exist.
[format] The archive's format as a symbol. If you ommit this, the format will
         be guessed from the file extension. Possible formats are:
         * :ar
         * :tar
         * :pax
         * :xar
         * :zip
[compression] Symbol inidicating the compression you want to use. If
              ommited, it will be guessed from the file extension.
              Possible formats are:
              * :bzip2
              * :compress
              * :gzip
              * :lzma
              * :xz
===Raises
[FormatError]      Unknown archive format or writing not supported.
[CompressionError] Unknown compression format.
===Examples
See the README for some examples.


248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
# File 'ext/archive.cpp', line 248

VALUE Archive_initialize(int argc, VALUE *argv,VALUE self)
{
	VALUE path,r_format,r_compression;
	rb_scan_args(argc, argv, "12", &path,&r_format,&r_compression);
	if(rb_obj_is_kind_of(path,rb_cIO)){
		_self->fd = NUM2INT(rb_funcall(path,rb_intern("fileno"),0));
		_self->type = archive_fd;
		rb_scan_args(argc, argv, "21", &path,&r_format,&r_compression);
	}else if(rb_obj_is_kind_of(path,rb_cInteger)){
		_self->fd = NUM2INT(path);
		_self->type = archive_fd;
		rb_scan_args(argc, argv, "21", &path,&r_format,&r_compression);
	}else if(rb_respond_to(path,rb_intern("read"))){
		_self->ruby = path;
		_self->type = archive_ruby;
		rb_scan_args(argc, argv, "21", &path,&r_format,&r_compression);
	}else{
		path = rb_file_s_expand_path(1,&path);
		_self->path = std::string(rb_string_value_cstr(&path));
		_self->type =archive_path;
	}
	
	//to set the format the file must convert
	if(!NIL_P(r_format)){
	
		char buff[8192];
		//std::string selfpath =_self->path;
		size_t bytes_read;
		struct archive *a = archive_read_new(),*b=archive_write_new();
		struct archive_entry *entry;
		int format,compression,error=0;
		std::vector<struct archive_entry *> entries;
		std::vector<std::string> allbuff;
		if(rb_obj_is_kind_of(r_format,rb_cSymbol)!=Qtrue)
			rb_raise(rb_eTypeError,"exepted Symbol");
		if(SYM2ID(r_format) == rb_intern("tar"))
			format = ARCHIVE_FORMAT_TAR_GNUTAR;
		else if(SYM2ID(r_format) == rb_intern("pax"))
			format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE;
		else if(SYM2ID(r_format) == rb_intern("zip"))
			format = ARCHIVE_FORMAT_ZIP;
		else if(SYM2ID(r_format) == rb_intern("ar"))
			format = ARCHIVE_FORMAT_AR_GNU;
		else if(SYM2ID(r_format) == rb_intern("xar"))
			format = ARCHIVE_FORMAT_XAR;
		else
			rb_raise(rb_eTypeError,"wrong format");
		
		if(NIL_P(r_compression)){
			compression = ARCHIVE_COMPRESSION_NONE;
			error = archive_write_set_compression_none(b);
		}else if(SYM2ID(r_compression) == rb_intern("gzip")){
			compression =ARCHIVE_COMPRESSION_GZIP;
			error = archive_write_set_compression_gzip(b);
		}else if(SYM2ID(r_compression) == rb_intern("bzip2")){
			compression =ARCHIVE_COMPRESSION_BZIP2;
			error = archive_write_set_compression_bzip2(b);
		}else if(SYM2ID(r_compression) == rb_intern("compress")){
			compression =ARCHIVE_COMPRESSION_BZIP2;
			error = archive_write_set_compression_compress(b);
		}else if(SYM2ID(r_compression) == rb_intern("lzma")){
			compression =ARCHIVE_COMPRESSION_LZMA;
			error = archive_write_set_compression_lzma(b);
		}else if(SYM2ID(r_compression) == rb_intern("xz")){
			compression =ARCHIVE_COMPRESSION_XZ;
			error = archive_write_set_compression_xz(b);
		}else
			rb_raise(rb_eTypeError,"unsupported compression");
		
		if(error)
			rb_raise(rb_eArchiveError,"error (%d): %s ",archive_errno(b),archive_error_string(b));
			
		archive_read_support_compression_all(a);
		archive_read_support_format_all(a);
		archive_read_support_format_raw(a);
		//autodetect format and compression
		error=Archive_read_ruby(self,a);
		_self->format = format;
		_self->compression = compression;
		if(error==ARCHIVE_OK){
			while(archive_read_next_header(a, &entry)==ARCHIVE_OK){
				if(format==archive_format(a) && compression==archive_compression(a)){
					archive_read_finish(a);
					return self;
				}
				entries.push_back(archive_entry_clone(entry));
				allbuff.push_back(std::string(""));
				while ((bytes_read=archive_read_data(a,&buff,sizeof(buff)))>0)
					allbuff.back().append(buff,bytes_read);
			}
			archive_read_finish(a);
		}
		//format fix
		if(format==ARCHIVE_FORMAT_TAR_GNUTAR)
			format=ARCHIVE_FORMAT_TAR_USTAR;
		
		if((error = archive_write_set_format(b,format)) != ARCHIVE_OK)
			rb_raise(rb_eArchiveErrorFormat,"error (%d): %s ",error,archive_error_string(b));
		error=Archive_write_ruby(self,b);
		if(error==ARCHIVE_OK){
			//write old data back
			for(unsigned int i=0; i<entries.size(); i++){
				archive_write_header(b,entries[i]);
				archive_write_data(b,allbuff[i].c_str(),allbuff[i].length());
				archive_write_finish_entry(b);
			}
			archive_write_finish(b);
		}
	}
	return self;
}

Instance Method Details

#<<(obj) ⇒ Object

Adds a file to an archive. Basicly the same as #add, but you can’t set the path inside the archive.

Parameters

obj

String or File

Return value

self

Raises

FormatError

The archive format is not supported for writing.



1291
1292
1293
1294
# File 'ext/archive.cpp', line 1291

VALUE Archive_add_shift(VALUE self,VALUE name)
{
	return Archive_add(1,&name,self);
}

#[](name) ⇒ Object

Returns an archive entry for the given name.

Parameters

name

could be a String or a Regex.

Return value

If a matching entry is found, it’s returned as an Archive::Entry object. If not, nil is returned.

Example

#Assuming your archive contains file.txt and ruby.txt

a["file.txt"] #=> Archive::Entry
a[/txt/] #=> Archive::Entry


690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
# File 'ext/archive.cpp', line 690

VALUE Archive_get(VALUE self,VALUE val)
{
	struct archive *a = archive_read_new();
	struct archive_entry *entry;
	archive_read_support_compression_all(a);
	archive_read_support_format_all(a);
	archive_read_support_format_raw(a);
	int error=Archive_read_ruby(self,a);
	if(error==ARCHIVE_OK){
		while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
			bool find = false;
			if(rb_obj_is_kind_of(val,rb_cRegexp)==Qtrue){
				find = rb_reg_match(val,rb_str_new2(archive_entry_pathname(entry)))!=Qnil;
			}else{
				val = rb_funcall(val,rb_intern("to_s"),0);
				std::string str1(rb_string_value_cstr(&val)),str2(str1);
				str2 += '/'; // dir ends of '/'
				const char *cstr = archive_entry_pathname(entry);
				find = (str1.compare(cstr)==0 || str2.compare(cstr)==0);
			}
			if(find){
				VALUE result = wrap(entry);
				archive_read_finish(a);
				return result;
			}
		}
		archive_read_finish(a);
	}
	return Qnil;
}

#addObject

(VALUE self,VALUE obj,VALUE name)



1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
# File 'ext/archive.cpp', line 1191

VALUE Archive_add(int argc, VALUE *argv, VALUE self)//(VALUE self,VALUE obj,VALUE name)
{	
	VALUE obj,name;
	rb_scan_args(argc, argv, "11", &obj,&name);
	if(NIL_P(name)){
		if(rb_obj_is_kind_of(obj,rb_cFile))
			name = rb_funcall(name,rb_intern("path"),0);
		else if(rb_obj_is_kind_of(obj,rb_cIO))
			rb_scan_args(argc, argv, "20", &obj,&name);
		else if(rb_respond_to(obj,rb_intern("read")))
			rb_scan_args(argc, argv, "20", &obj,&name);
		else if(rb_obj_is_kind_of(obj,rb_cArray) or rb_obj_is_kind_of(obj,rb_cHash))
			rb_scan_args(argc, argv, "10", &obj);
		else
			name = obj;
	}
	char buff[8192];
	char *path = NULL;

	size_t bytes_read;
	struct archive *a = archive_read_new(),*b=archive_write_new();
	struct archive_entry *entry;
	std::vector<struct archive_entry *> entries;
	std::vector<std::string> allbuff;
	int format= ARCHIVE_FORMAT_EMPTY,compression=ARCHIVE_COMPRESSION_NONE,fd=-1,error=0;
	archive_read_support_compression_all(a);
	archive_read_support_format_all(a);
	archive_read_support_format_raw(a);
	//autodetect format and compression
	if(Archive_read_ruby(self,a)==ARCHIVE_OK){
		while(archive_read_next_header(a, &entry)==ARCHIVE_OK){
			entries.push_back(archive_entry_clone(entry));
			allbuff.push_back(std::string(""));
			try{
				while ((bytes_read=archive_read_data(a,&buff,sizeof(buff)))>0)
					allbuff.back().append(buff,bytes_read);
			}catch(...){
				rb_raise(rb_eArchiveError,"error:%d:%s",archive_errno(a),archive_error_string(a));	
			}
		}
		format = archive_format(a);
		compression = archive_compression(a);
		archive_read_finish(a);
	}
	if(rb_obj_is_kind_of(obj,rb_cFile)){
		VALUE pathname = rb_funcall(obj,rb_intern("path"),0); //source path
		VALUE obj2 = rb_file_s_expand_path(1,&pathname);
		path = rb_string_value_cstr(&obj2);
		fd = NUM2INT(rb_funcall(obj,rb_intern("fileno"),0));
	}else if(rb_obj_is_kind_of(obj,rb_cIO)){
		fd = NUM2INT(rb_funcall(obj,rb_intern("fileno"),0));
	}else if(rb_respond_to(obj,rb_intern("read")) or rb_obj_is_kind_of(obj,rb_cArray) or rb_obj_is_kind_of(obj,rb_cHash)){
		//stringio has neigther path or fileno, so do nothing
	}else {
		VALUE obj2 = rb_file_s_expand_path(1,&obj);
		path = rb_string_value_cstr(&obj2);
		fd = open(path, O_RDONLY);
		if (fd < 0) //TODO: add error
			return self;
	}
	Archive_format_from_path(self,format,compression);
	if((error = archive_write_set_format(b,format)) != ARCHIVE_OK)
		rb_raise(rb_eArchiveErrorFormat,"error:%d:%s",archive_errno(b),archive_error_string(b));
	Archive_write_set_compression(b,compression);
	
	if(Archive_write_ruby(self,b)==ARCHIVE_OK){
		entry = archive_entry_new();
		if (path)
			archive_entry_copy_sourcepath(entry, path);
		if(!NIL_P(name))
			archive_entry_copy_pathname(entry, rb_string_value_cstr(&name));
		add_obj temp;
		temp.archive = b;
		temp.file = archive_read_disk_new();
		temp.entry = entry;
		temp.fd = fd;
		temp.obj = obj;
		temp.entries = &entries;
		temp.allbuff = &allbuff;
		RB_ENSURE(Archive_add_block,&temp,Archive_add_block_ensure,&temp);
	}
	
	if(fd >= 0 and !rb_obj_is_kind_of(name,rb_cIO))
		close(fd);
	return self;
}

#atimeObject

:nodoc:

call-seq:
archive.atime -> Time

call the File.atime(path)


1548
1549
1550
1551
# File 'ext/archive.cpp', line 1548

VALUE Archive_atime(VALUE self)
{
	return rb_funcall(rb_cFile,rb_intern("atime"),1,Archive_path(self));
}

#clearself

Deletes all files from an archive.

Return value

returns self.

Raises

raise Error if the format has no write support

Returns:

  • (self)


1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
# File 'ext/archive.cpp', line 1466

VALUE Archive_clear(VALUE self)
{

	std::string selfpath =_self->path;

	struct archive *a = archive_read_new(),*b=archive_write_new();
	struct archive_entry *entry;
	int format = ARCHIVE_FORMAT_EMPTY,compression = ARCHIVE_COMPRESSION_NONE,error=0;
	
	archive_read_support_compression_all(a);
	archive_read_support_format_all(a);
	archive_read_support_format_raw(a);
	error=Archive_read_ruby(self,a);
	if(error==ARCHIVE_OK){
		archive_read_next_header(a, &entry);
		format = archive_format(a);
		compression = archive_compression(a);
		archive_read_finish(a);
	
		//format fix
		if(format==ARCHIVE_FORMAT_TAR_GNUTAR)
			format=ARCHIVE_FORMAT_TAR_USTAR;
	
		if((error = archive_write_set_format(b,format)) != ARCHIVE_OK)
			rb_raise(rb_eArchiveErrorFormat,"error (%d): %s ",error,archive_error_string(b));
		Archive_write_set_compression(b,compression);
		error=Archive_write_ruby(self,b);
		if(error==ARCHIVE_OK)
			archive_write_finish(b);
	}
	
	return self;
}

#compressionObject

Returns the archive compression as an integer. You should use #compression_name instead.

Return value

An integer or nil if the compression wasn’t detectable. 0 means no compression.



941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
# File 'ext/archive.cpp', line 941

VALUE Archive_compression(VALUE self)
{
	struct archive *a = archive_read_new();
	struct archive_entry *entry;
	VALUE result = Qnil;
	archive_read_support_compression_all(a);
	archive_read_support_format_all(a);
	archive_read_support_format_raw(a);
	int error=Archive_read_ruby(self,a);
	if(error==ARCHIVE_OK){
		archive_read_next_header(a, &entry);
		result = INT2NUM(archive_compression(a));
		archive_read_finish(a);
	}
	return result;
}

#compression_nameObject

Returns the archive compression’s name as a string.

Return value

A string or nil if the compression format wasn’t detectable. If there is no compression, "none" is returned.

Example

a.compression_name #=> "gzip"

a.compression_name #=> "none"


1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
# File 'ext/archive.cpp', line 1001

VALUE Archive_compression_name(VALUE self)
{
	struct archive *a = archive_read_new();
	struct archive_entry *entry;
	const char* name = NULL;
	archive_read_support_compression_all(a);
	archive_read_support_format_all(a);
	archive_read_support_format_raw(a);
	int error=Archive_read_ruby(self,a);
	if(error==ARCHIVE_OK){
		archive_read_next_header(a, &entry);
		name = archive_compression_name(a);
		archive_read_finish(a);
	}
	return name ? rb_str_new2(name) : Qnil	;
}

#ctimeObject

:nodoc:

call-seq:
archive.ctime -> Time

call the File.ctime(path)


1561
1562
1563
1564
# File 'ext/archive.cpp', line 1561

VALUE Archive_ctime(VALUE self)
{
	return rb_funcall(rb_cFile,rb_intern("ctime"),1,Archive_path(self));
}

#delete(name) ⇒ Object

Delete files from an archive.

Parameters

name

An Archive::Entry, a String or a Regex.

Return value

A list of paths removed from the archive.

Raises

raise TypeError if the parameter is neigther String or File. raise Error if the format has no write support



1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
# File 'ext/archive.cpp', line 1310

VALUE Archive_delete(VALUE self,VALUE val)
{
	char buff[8192];
	size_t bytes_read;
	struct archive *a = archive_read_new(),*b=archive_write_new();
	struct archive_entry *entry;
	int format = ARCHIVE_FORMAT_EMPTY,compression = ARCHIVE_COMPRESSION_NONE,error=0;
	std::vector<struct archive_entry *> entries;
	std::vector<std::string> allbuff;
	VALUE result = rb_ary_new();
	archive_read_support_compression_all(a);
	archive_read_support_format_all(a);
	archive_read_support_format_raw(a);
	//autodetect format and compression
	error=Archive_read_ruby(self,a);
	if(error==ARCHIVE_OK){
		while(archive_read_next_header(a, &entry)==ARCHIVE_OK){
			format = archive_format(a);
			compression = archive_compression(a);
			bool del = false;
			if(rb_obj_is_kind_of(val,rb_cArchiveEntry)==Qtrue){
				del = std::string(archive_entry_pathname(wrap<archive_entry*>(val))).compare(archive_entry_pathname(entry)) == 0;
			}else if(rb_obj_is_kind_of(val,rb_cRegexp)==Qtrue){
				VALUE str = rb_str_new2(archive_entry_pathname(entry));
				del = rb_reg_match(val,str)!=Qnil;
			}else {
				std::string str1(rb_string_value_cstr(&val)),str2(str1);
				str2 += '/'; // dir ends of '/'
				const char *cstr = archive_entry_pathname(entry);
				del = (str1.compare(cstr)==0 || str2.compare(cstr)==0);
			}
			if(!del){
				entries.push_back(archive_entry_clone(entry));
				allbuff.push_back(std::string(""));
				try{
					while ((bytes_read=archive_read_data(a,&buff,sizeof(buff)))>0)
						allbuff.back().append(buff,bytes_read);
				}catch(...){
					rb_raise(rb_eArchiveError,"error:%d:%s",archive_errno(a),archive_error_string(a));	
				}
			}else
				rb_ary_push(result,wrap(archive_entry_clone(entry)));
		}
		archive_read_finish(a);
	
		//format fix
		if(format==ARCHIVE_FORMAT_TAR_GNUTAR)
			format=ARCHIVE_FORMAT_TAR_USTAR;
	
		//TODO add archive-error
		if((error = archive_write_set_format(b,format)) != ARCHIVE_OK)
			rb_raise(rb_eArchiveErrorFormat,"error (%d): %s ",error,archive_error_string(b));
		Archive_write_set_compression(b,compression);
		error=Archive_write_ruby(self,b);
		if(error==ARCHIVE_OK){
			//write old data back
			for(unsigned int i=0; i<entries.size(); i++){
				archive_write_header(b,entries[i]);
				archive_write_data(b,allbuff[i].c_str(),allbuff[i].length());
				archive_write_finish_entry(b);
			}
			archive_write_finish(b);
		}
		
	}
	return result;
}

#delete_if {|entry| ... } ⇒ self #delete_ifEnumerator

Yields each entry in the archive to the block and deletes those for which the block evaluates to a truth value.

Parameters

name

An Archive::Entry, a String or a Regex.

Return value

If a block was given, returns self, otherwise an Enumerator.

Raises

raise Error if the format has no write support

Overloads:

  • #delete_if {|entry| ... } ⇒ self

    Yields:

    • (entry)

    Returns:

    • (self)
  • #delete_ifEnumerator

    Returns:

    • (Enumerator)


1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
# File 'ext/archive.cpp', line 1407

VALUE Archive_delete_if(VALUE self)
{
	RETURN_ENUMERATOR(self,0,NULL);
	char buff[8192];
	std::string selfpath =_self->path;
	size_t bytes_read;
	struct archive *a = archive_read_new(),*b=archive_write_new();
	struct archive_entry *entry;
	int format = ARCHIVE_FORMAT_EMPTY,compression = ARCHIVE_COMPRESSION_NONE,error=0;
	std::vector<struct archive_entry *> entries;
	std::vector<std::string> allbuff;
	
	archive_read_support_compression_all(a);
	archive_read_support_format_all(a);
	archive_read_support_format_raw(a);
	error=Archive_read_ruby(self,a);
	if(error==ARCHIVE_OK){
		while(archive_read_next_header(a, &entry)==ARCHIVE_OK){
			format = archive_format(a);
			compression = archive_compression(a);
			entries.push_back(archive_entry_clone(entry));
			allbuff.push_back(std::string(""));
			try{
				while ((bytes_read=archive_read_data(a,&buff,sizeof(buff)))>0)
					allbuff.back().append(buff,bytes_read);
			}catch(...){
				rb_raise(rb_eArchiveError,"error:%d:%s",archive_errno(a),archive_error_string(a));	
			}
		}
		archive_read_finish(a);
		//format fix
		if(format==ARCHIVE_FORMAT_TAR_GNUTAR)
			format=ARCHIVE_FORMAT_TAR_USTAR;
		if((error = archive_write_set_format(b,format)) != ARCHIVE_OK)
			rb_raise(rb_eArchiveErrorFormat,"error (%d): %s ",error,archive_error_string(b));
		Archive_write_set_compression(b,compression);
		error=Archive_write_ruby(self,b);
		if(error==ARCHIVE_OK){
			write_obj obj;
			obj.archive = b;
			obj.entries = &entries;
			obj.allbuff = &allbuff;
			return RB_ENSURE(Archive_delete_if_block,&obj,Archive_write_block_ensure,b);
		}	
	}	
	return Qnil;
}

#eachObject #eachObject

Iterates through the archive and yields each entry as an Archive::Entry object. The second parameter contains the data of that entry, so you don’t have to extract it only to read what’s in it.

Return value

If a block is given, returns an array of Archive::Entry objects, otherwise an enumerator.

Example

a.each{|entry| p entry.path}
a.each{|entry, data| puts "'#{entry.path}' contains '#{data}'"}

Output:

"file1.txt"
"file2.txt"
'file1.txt' contains 'I am file1!'
'file2.txt' contains 'I am file2!'


421
422
423
424
425
426
427
428
429
430
431
432
433
# File 'ext/archive.cpp', line 421

VALUE Archive_each(VALUE self)
{
	RETURN_ENUMERATOR(self,0,NULL);
	struct archive *a = archive_read_new();

	archive_read_support_compression_all(a);
	archive_read_support_format_all(a);
	archive_read_support_format_raw(a);
	int error=Archive_read_ruby(self,a);
	if(error==ARCHIVE_OK)
		return RB_ENSURE(Archive_each_block,a,Archive_read_block_ensure,a);
	return Qnil;
}

#each_dataObject #each_dataObject

Iterates through the archive and yields each entry’s data as a string. This is the same as #each, but doesn’t allow for the first block parameter.

Return value

If a block is given, returns an array of String objects, otherwise an enumerator.

Example

a.each{|data| puts "This is: '#{data}'"}

Output:

This is: 'I am file1!'
This is: 'I am file2!'


517
518
519
520
521
522
523
524
525
526
527
528
529
# File 'ext/archive.cpp', line 517

VALUE Archive_each_data(VALUE self)
{
	RETURN_ENUMERATOR(self,0,NULL);
	struct archive *a = archive_read_new();

	archive_read_support_compression_all(a);
	archive_read_support_format_all(a);
	archive_read_support_format_raw(a);
	int error=Archive_read_ruby(self,a);
	if(error==ARCHIVE_OK)
		return RB_ENSURE(Archive_each_data_block,a,Archive_read_block_ensure,a);
	return Qnil;
}

#each_entryObject #each_entryObject

Iterates through the archive and yields each entry as an Archive::Entry object. This is the same as #each, but doesn’t allow for the second block parameter.

Return value

If a block is given, returns an array of Archive::Entry objects, otherwise an enumerator.

Example

a.each_entry{|entry| p entry.path}

Output:

"file1.txt"
"file2.txt"


465
466
467
468
469
470
471
472
473
474
475
476
477
# File 'ext/archive.cpp', line 465

VALUE Archive_each_entry(VALUE self)
{
	RETURN_ENUMERATOR(self,0,NULL);
	struct archive *a = archive_read_new();

	archive_read_support_compression_all(a);
	archive_read_support_format_all(a);
	archive_read_support_format_raw(a);
	int error=Archive_read_ruby(self,a);
	if(error==ARCHIVE_OK)
		return RB_ENSURE(Archive_each_entry_block,a,Archive_read_block_ensure,a);
	return Qnil;
}

#exist?Boolean

:nodoc:

call-seq:
  archive.exist? -> true or false

Same as
 File.exist?(archive.path)
. Checks wheather or not the archive file is existant.
===Return value
True or false.

Returns:

  • (Boolean)


1511
1512
1513
1514
# File 'ext/archive.cpp', line 1511

VALUE Archive_exist(VALUE self)
{
	return rb_funcall(rb_cFile,rb_intern("exist?"),1,Archive_path(self));
}

#extract([name = nil [, io [ ,opt ] ] ]) ⇒ Object

Extract files to current directory.

Parameters

name

(nil) could be an Archive::Entry, a String or an Regex. If given, only this entry is extracted. Otherwise extracts the whole archive.

io

an instance of IO or something with a write method like StringIO. If given, the entry specified via name will be extracted into io instead of a file.

opt

is an option hash. See below for possible options.

Parameters for the option hash

:extract

flag, Integer combined of the Archive::Extract_* constants. This tells libarchive-ruby to only extract the file attributes you specify here. Exceptions is Archive::EXTRACT_NO_OVERWRITE which prevents this method from overwrtiting existing files.

Return value

The paths of the extracted entries as an array.

Example

#Simply extract everything into the current directory.
a.extract
#Extract only file1.txt
a.extract("file1.txt")
#Same as above, but extract it to a StringIO
s = StringIO.new
a.extract("file1.txt", s)
#Same as the first example, but only extract information about the
#modification time.
a.extract(nil, nil, extract: Archive::EXTRACT_TIME)


753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
# File 'ext/archive.cpp', line 753

VALUE Archive_extract(int argc, VALUE *argv, VALUE self)
{
	char buff[8192];
	size_t bytes_read;

	VALUE result = rb_ary_new(),name,io,opts,temp;
	struct archive *a = archive_read_new();
	struct archive_entry *entry;
	archive_read_support_compression_all(a);
	archive_read_support_format_all(a);
	archive_read_support_format_raw(a);//add raw, this is not by all
	int extract_opt = 0,fd=-1,error=0;
	rb_scan_args(argc, argv, "03", &name,&io,&opts);
	if(rb_obj_is_kind_of(name,rb_cHash)){
		opts = name;name = Qnil;
	}
	if(rb_obj_is_kind_of(io,rb_cHash)){
		opts = io;io = Qnil;
	}
	if(rb_obj_is_kind_of(io,rb_cIO))
		fd = NUM2INT(rb_funcall(io,rb_intern("fileno"),0));
	
	
	if(rb_obj_is_kind_of(opts,rb_cHash))
		if(RTEST(temp=rb_hash_aref(opts,ID2SYM(rb_intern("extract")))))
			extract_opt = NUM2INT(temp);
			
	error=Archive_read_ruby(self,a);
	if(error==ARCHIVE_OK){
		try{
			if(NIL_P(name)){
				if(!NIL_P(io)){
					rb_raise(rb_eArgError,"You can't extract more than 1 entry into an IO-like object!");
				}
				while(archive_read_next_header(a, &entry) == ARCHIVE_OK){
					archive_read_extract(a,entry,extract_opt);
					rb_ary_push(result,rb_str_new2(archive_entry_pathname(entry)));
				}
			}else{
				if(rb_obj_is_kind_of(name,rb_cArchiveEntry)==Qtrue){
					if(rb_obj_is_kind_of(io,rb_cIO)==Qtrue){
						while(archive_read_next_header(a, &entry) == ARCHIVE_OK){
							if(std::string(archive_entry_pathname(entry)).compare(archive_entry_pathname(wrap<archive_entry*>(name)))==0)
								archive_read_data_into_fd(a,fd);
						}
					}else if(rb_respond_to(io,rb_intern("write"))){
						while(archive_read_next_header(a, &entry) == ARCHIVE_OK){
							if(std::string(archive_entry_pathname(entry)).compare(archive_entry_pathname(wrap<archive_entry*>(name)))==0)
								while ((bytes_read=archive_read_data(a,&buff,sizeof(buff)))>0)
									rb_funcall(io,rb_intern("write"),1,rb_str_new(buff,bytes_read));
							
						}
					}else
						archive_read_extract(a,wrap<archive_entry*>(name),extract_opt);
					rb_ary_push(result,rb_str_new2(archive_entry_pathname(wrap<archive_entry*>(name))));
				}else if(rb_obj_is_kind_of(name,rb_cRegexp)==Qtrue){
					while(archive_read_next_header(a, &entry) == ARCHIVE_OK){
						VALUE str = rb_str_new2(archive_entry_pathname(entry));
						if(rb_reg_match(name,str)!=Qnil){
							if(rb_obj_is_kind_of(io,rb_cIO)==Qtrue){
								archive_read_data_into_fd(a,fd);
							}else if(rb_respond_to(io,rb_intern("write"))){
								while ((bytes_read=archive_read_data(a,&buff,sizeof(buff)))>0)
										rb_funcall(io,rb_intern("write"),1,rb_str_new(buff,bytes_read));
							}else
								archive_read_extract(a,entry,extract_opt);
							rb_ary_push(result,str);
						}
					}
				}else{
					name = rb_funcall(name,rb_intern("to_s"),0);
					std::string str1(rb_string_value_cstr(&name)),str2(str1);
					str2 += '/'; // dir ends of '/'
					while(archive_read_next_header(a, &entry) == ARCHIVE_OK){
						const char *cstr = archive_entry_pathname(entry);
						if(str1.compare(cstr)==0 || str2.compare(cstr)==0){
							if(rb_obj_is_kind_of(io,rb_cIO)==Qtrue){
								archive_read_data_into_fd(a,fd);
							}else if(rb_respond_to(io,rb_intern("write"))){
								while ((bytes_read=archive_read_data(a,&buff,sizeof(buff)))>0)
										rb_funcall(io,rb_intern("write"),1,rb_str_new(buff,bytes_read));
							}else
								archive_read_extract(a,entry,extract_opt);
							rb_ary_push(result,rb_str_new2(cstr));
						}
					}
				}
			}
		}catch (...){
			rb_raise(rb_eArchiveError,"error:%d:%s",archive_errno(a),archive_error_string(a));
		}
		archive_read_finish(a);
	}
	return result;
}

#extract_if([ opt ]) ⇒ Object #extract_if([ opt ]) ⇒ Object

Yields each entry in the archive to the block and extracts only those entries (to the current directory) for which the block evaluates to a truth value.

Parameters

opt

is the same option hash that you can pass to #extract.

Parameters for the option hash

See the #extract method for explanation.

Return value

The paths of all extracted entries if a block was given, an Enumerator otherwise.



879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
# File 'ext/archive.cpp', line 879

VALUE Archive_extract_if(int argc, VALUE *argv, VALUE self)
{
	RETURN_ENUMERATOR(self,argc,argv);
	VALUE opts,temp;
	struct archive *a = archive_read_new();
	archive_read_support_compression_all(a);
	archive_read_support_format_all(a);
	archive_read_support_format_raw(a);
	int extract_opt=0,error=0;
	
	rb_scan_args(argc, argv, "01", &opts);
	if(rb_obj_is_kind_of(opts,rb_cHash))
		if(RTEST(temp=rb_hash_aref(opts,ID2SYM(rb_intern("extract")))))
			extract_opt = NUM2INT(temp);
	error=Archive_read_ruby(self,a);
	if(error==ARCHIVE_OK){
		extract_obj obj;
		obj.archive = a;
		obj.extract_opt = extract_opt;
		return RB_ENSURE(Archive_extract_if_block,&obj,Archive_read_block_ensure,a);
	}
	return Qnil;
}

#formatObject

Returns the archive format as an integer. You should use #format_name instead.

Return value

An integer or nil if the format wasn’t detectable.



913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
# File 'ext/archive.cpp', line 913

VALUE Archive_format(VALUE self)
{
	struct archive *a = archive_read_new();
	struct archive_entry *entry;
	VALUE result = Qnil;
	archive_read_support_compression_all(a);
	archive_read_support_format_all(a);
	archive_read_support_format_raw(a);
	int error=Archive_read_ruby(self,a);
	if(error==ARCHIVE_OK){
		archive_read_next_header(a, &entry);
		result = INT2NUM(archive_format(a));
		archive_read_finish(a);
	}
	return result;
}

#format_nameObject

Returns the archive format’s name as a string.

Return value

A string or nil if the format wasn’t detectable.

Example

a.format_name #=> "GNU tar format"


969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
# File 'ext/archive.cpp', line 969

VALUE Archive_format_name(VALUE self)
{
	struct archive *a = archive_read_new();
	struct archive_entry *entry;
	const char* name = NULL;
	archive_read_support_compression_all(a);
	archive_read_support_format_all(a);
	archive_read_support_format_raw(a);
	int error=Archive_read_ruby(self,a);
	if(error==ARCHIVE_OK){
		if(archive_read_next_header(a, &entry)==ARCHIVE_OK){
			name = archive_format_name(a);
			archive_read_finish(a);
		}
	}
	return name ? rb_str_new2(name) : Qnil	;
}

#inspectString

Human-readable description.

Return value

String

Returns:

  • (String)


1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
# File 'ext/archive.cpp', line 1587

VALUE Archive_inspect(VALUE self)
{
	VALUE array[3];
	switch(_self->type){
	case archive_path:
		array[0]=rb_str_new2("#<%s:%s>");
		array[1]=rb_class_of(self);	
		array[2]=Archive_path(self);
		break;
	case archive_fd:
		array[0]=rb_str_new2("#<%s:%d>");
		array[1]=rb_class_of(self);	
		array[2]=INT2NUM(_self->fd);
		break;
	case archive_buffer: 
		break;
	case archive_ruby:
		array[0]=rb_str_new2("#<%s:%s>");
		array[1]=rb_class_of(self);	
		array[2]=_self->ruby;
		break;
	}	
	return rb_f_sprintf(3,array);
}

#map!Object #map!Object Also known as: collect!

Iterates through the archive and changes it’s data “on the fly”, i.e. the value your block returns for each iteration is put for the data in the yielded entry. Your block is expected to return a 2-element array of form

archive_entry, “data”

where archive_enty is the entry yielded to the block (which you may modify via the Archive::Entry methods) and "data" is a string containing the data you want to set for this entry.

The block parameters are the same as for #each.

Return value

The archive itself.

Example

#Double the contents in each file of the archive
a.map!{|entry, data| [entry, data * 2]}
#Clear all files in the archive
a.map!{|entry| [entry, ""]}


623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
# File 'ext/archive.cpp', line 623

VALUE Archive_map_self(VALUE self)
{
	RETURN_ENUMERATOR(self,0,NULL);
	char buff[8192];
	std::string selfpath =_self->path;
	size_t bytes_read;
	struct archive *a = archive_read_new(),*b=archive_write_new();
	struct archive_entry *entry;
	int format = ARCHIVE_FORMAT_EMPTY,compression = ARCHIVE_COMPRESSION_NONE,error=0;
	std::vector<struct archive_entry *> entries;
	std::vector<std::string> allbuff;
	
	archive_read_support_compression_all(a);
	archive_read_support_format_all(a);
	archive_read_support_format_raw(a);
	//autodetect format and compression
	error=Archive_read_ruby(self,a);
	if(error==ARCHIVE_OK){
		while(archive_read_next_header(a, &entry)==ARCHIVE_OK){
			format = archive_format(a);
			compression = archive_compression(a);
			entries.push_back(archive_entry_clone(entry));
			allbuff.push_back(std::string(""));
			try{
				while ((bytes_read=archive_read_data(a,&buff,sizeof(buff)))>0)
					allbuff.back().append(buff,bytes_read);
			} catch (...){
				rb_raise(rb_eArchiveError,"error:%d:%s",archive_errno(a),archive_error_string(a));
			}
		}
		archive_read_finish(a);
		//format fix
		if(format==ARCHIVE_FORMAT_TAR_GNUTAR)
			format=ARCHIVE_FORMAT_TAR_USTAR;
		if((error = archive_write_set_format(b,format)) != ARCHIVE_OK)
			rb_raise(rb_eArchiveErrorFormat,"error (%d): %s ",error,archive_error_string(b));
		Archive_write_set_compression(b,compression);
	
		error=Archive_write_ruby(self,b);
		if(error==ARCHIVE_OK){
			write_obj obj;
			obj.archive = b;
			obj.entries = &entries;
			obj.allbuff = &allbuff;
			RB_ENSURE(Archive_map_block,&obj,Archive_write_block_ensure,b);
		}	
	}	
	return self;
}

#mtimeObject

:nodoc:

call-seq:
archive.mtime -> Time

call the File.mtime(path)


1536
1537
1538
1539
# File 'ext/archive.cpp', line 1536

VALUE Archive_mtime(VALUE self)
{
	return rb_funcall(rb_cFile,rb_intern("mtime"),1,Archive_path(self));
}

#pathObject

Returns the path (filename) of the archive.

Return value

Returns path of the archive. May or may not exist.

Example

a.path #=> /home/freak/myarchive.tar.gz


371
372
373
374
# File 'ext/archive.cpp', line 371

VALUE Archive_path(VALUE self)
{
	return (_self->type == archive_path) ? rb_str_new2(_self->path.c_str()) : Qnil;
}

#statObject

:nodoc:

call-seq:
archive.stat -> File::Stat

call the File.stat(path)


1573
1574
1575
1576
# File 'ext/archive.cpp', line 1573

VALUE Archive_stat(VALUE self)
{
	return rb_funcall(rb_cFile,rb_intern("stat"),1,Archive_path(self));
}

#to_hashObject

Iterates through the archive and yields each data of an entry as a string object.

Return value

returns Hash of Archive::Entry => Sring



541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
# File 'ext/archive.cpp', line 541

VALUE Archive_to_hash(VALUE self)
{
	VALUE result = rb_hash_new();
	struct archive *a = archive_read_new();
	struct archive_entry *entry;
	archive_read_support_compression_all(a);
	archive_read_support_format_all(a);
	archive_read_support_format_raw(a);
	int error=Archive_read_ruby(self,a);
	if(error==ARCHIVE_OK){
		while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
			char buff[8192];
			std::string str;
			size_t bytes_read;
			try{
				while ((bytes_read=archive_read_data(a,&buff,sizeof(buff)))>0)
					str.append(buff,bytes_read);
			} catch (...){
				rb_raise(rb_eArchiveError,"error:%d:%s",archive_errno(a),archive_error_string(a));
			}
			rb_hash_aset(result,wrap(entry),rb_str_new2(str.c_str()));
		}
		archive_read_finish(a);
	}
	return result;
}

:nodoc:

call-seq:
archive.unlink -> self

call the File.unlink(path)


1523
1524
1525
1526
1527
# File 'ext/archive.cpp', line 1523

VALUE Archive_unlink(VALUE self)
{
	return rb_funcall(rb_cFile,rb_intern("unlink"),1,Archive_path(self));
	return self;
}