libarchive-ruby 0.0.1.dev

Sign up to get free protection for your applications and to get access to all the features.
Files changed (7) hide show
  1. data/COPYING.txt +339 -0
  2. data/README.rdoc +135 -0
  3. data/ext/archive.cpp +1547 -0
  4. data/ext/entry.cpp +592 -0
  5. data/ext/extconf.rb +38 -0
  6. data/ext/main.hpp +86 -0
  7. metadata +80 -0
data/ext/archive.cpp ADDED
@@ -0,0 +1,1547 @@
1
+ /****************************************************************************
2
+ This file is part of libarchive-ruby.
3
+
4
+ libarchive-ruby is a Ruby binding for the C library libarchive.
5
+
6
+ Copyright (C) 2011 Hans Mackowiak
7
+
8
+ libarchive-ruby is free software; you can redistribute it and/or modify
9
+ it under the terms of the GNU General Public License as published by
10
+ the Free Software Foundation; either version 2 of the License, or
11
+ (at your option) any later version.
12
+
13
+ libarchive-ruby is distributed in the hope that it will be useful,
14
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ GNU General Public License for more details.
17
+
18
+ You should have received a copy of the GNU General Public License along
19
+ with libarchive-ruby; if not, write to the Free Software Foundation, Inc.,
20
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21
+ ****************************************************************************/
22
+
23
+ #include "main.hpp"
24
+ #include <vector>
25
+ #include <exception>
26
+ #include <stdexcept>
27
+ #define _self wrap<rarchive*>(self)
28
+ #define RB_ENSURE(func1,obj1,func2,obj2)\
29
+ rb_ensure(RUBY_METHOD_FUNC(func1),(VALUE)obj1,RUBY_METHOD_FUNC(func2),(VALUE)obj2)
30
+
31
+ //TODO: handle string IO as archive Archive.new(stringio)
32
+
33
+
34
+ VALUE rb_cArchive,rb_eArchiveError,rb_eArchiveErrorFormat,rb_eArchiveErrorCompression;
35
+
36
+ VALUE Archive_alloc(VALUE self)
37
+ {
38
+ rarchive *result = new rarchive;
39
+ return wrap(result);
40
+ }
41
+
42
+ VALUE Archive_initialize_copy(VALUE self, VALUE other)
43
+ {
44
+ VALUE result = rb_call_super(1,&other);
45
+ _self->path = std::string(wrap<rarchive*>(other)->path.c_str());
46
+ _self->type = wrap<rarchive*>(other)->type;
47
+ return result;
48
+ }
49
+
50
+ struct extract_obj {
51
+ struct archive* archive;
52
+ int extract_opt;
53
+ };
54
+
55
+ struct write_obj {
56
+ struct archive* archive;
57
+ std::vector<struct archive_entry *> *entries;
58
+ std::vector<std::string> *allbuff;
59
+ };
60
+
61
+
62
+ VALUE Archive_read_block_ensure(struct archive * data)
63
+ {
64
+ archive_read_finish(data);
65
+ return Qnil;
66
+ }
67
+
68
+ VALUE Archive_write_block_ensure(struct archive * data)
69
+ {
70
+ archive_write_finish(data);
71
+ return Qnil;
72
+ }
73
+
74
+ int rubymyopen(struct archive *a, void *client_data)
75
+ {
76
+ rb_funcall((VALUE)client_data,rb_intern("rewind"),0);
77
+ return ARCHIVE_OK;
78
+ }
79
+ ssize_t
80
+ rubymyread(struct archive *a, void *client_data, const void **buff)
81
+ {
82
+ VALUE result = rb_funcall((VALUE)client_data,rb_intern("read"),0);
83
+ if(result == Qnil){
84
+ *buff = NULL;
85
+ return 0;
86
+ }else{
87
+ if (RSTRING_LEN(result))
88
+ *buff = RSTRING_PTR(result);
89
+ else
90
+ *buff = NULL;
91
+ return RSTRING_LEN(result);
92
+ }
93
+ }
94
+
95
+ ssize_t rubymywrite(struct archive *a,void *client_data,const void *buffer, size_t length){
96
+ VALUE string = rb_str_new((char*)buffer,length);
97
+ // rb_funcall(string,rb_intern("rstrip!"),0);
98
+ return NUM2INT(rb_funcall((VALUE)client_data,rb_intern("write"),1,string));
99
+ }
100
+
101
+ int rubymyclose(struct archive *a, void *client_data)
102
+ {
103
+ rb_funcall((VALUE)client_data,rb_intern("rewind"),0);
104
+ return ARCHIVE_OK;
105
+ }
106
+
107
+
108
+ void Archive_format_from_path(VALUE self,int &format,int &compression)
109
+ {
110
+ if(format == ARCHIVE_FORMAT_EMPTY){
111
+ if(_self->type == archive_path){
112
+ std::string selfpath = _self->path;
113
+ if(selfpath.substr(selfpath.length()-7).compare(".tar.xz")==0 || selfpath.substr(selfpath.length()-4).compare(".txz")==0 ){
114
+ format=ARCHIVE_FORMAT_TAR_USTAR;
115
+ compression=ARCHIVE_COMPRESSION_XZ;
116
+ }else if(selfpath.substr(selfpath.length()-9).compare(".tar.lzma")==0 ){
117
+ format=ARCHIVE_FORMAT_TAR_USTAR;
118
+ compression=ARCHIVE_COMPRESSION_LZMA;
119
+ }else if(selfpath.substr(selfpath.length()-7).compare(".tar.gz")==0 || selfpath.substr(selfpath.length()-4).compare(".tgz")==0){
120
+ format=ARCHIVE_FORMAT_TAR_USTAR;
121
+ compression=ARCHIVE_COMPRESSION_GZIP;
122
+ }else if(selfpath.substr(selfpath.length()-8).compare(".tar.bz2")==0 || selfpath.substr(selfpath.length()-4).compare(".tbz")==0 || selfpath.substr(selfpath.length()-4).compare(".tb2")==0){
123
+ format=ARCHIVE_FORMAT_TAR_USTAR;
124
+ compression=ARCHIVE_COMPRESSION_BZIP2;
125
+ }else if(selfpath.substr(selfpath.length()-4).compare(".tar")==0)
126
+ format=ARCHIVE_FORMAT_TAR_USTAR;
127
+ }
128
+ }
129
+ if(format==ARCHIVE_FORMAT_TAR_GNUTAR)
130
+ format=ARCHIVE_FORMAT_TAR_USTAR;
131
+ }
132
+
133
+ int Archive_read_ruby(VALUE self,struct archive *data)
134
+ {
135
+ int error =0;
136
+ switch(_self->type){
137
+ case archive_path:
138
+ error = archive_read_open_filename(data,_self->path.c_str(),10240);
139
+ break;
140
+ case archive_fd:
141
+ error = archive_read_open_fd(data,_self->fd,10240);
142
+ break;
143
+ case archive_buffer:
144
+ break;
145
+ case archive_ruby:
146
+ error = archive_read_open(data, (void*)_self->ruby,rubymyopen,rubymyread,rubymyclose);
147
+ break;
148
+ }
149
+ return error;
150
+ }
151
+
152
+
153
+
154
+ int Archive_write_ruby(VALUE self,struct archive *data)
155
+ {
156
+ int error =0;
157
+ switch(_self->type){
158
+ case archive_path:
159
+ error = archive_write_open_filename(data,_self->path.c_str());
160
+ break;
161
+ case archive_fd:
162
+ error = archive_write_open_fd(data,_self->fd);
163
+ break;
164
+ case archive_buffer:
165
+ break;
166
+ case archive_ruby:
167
+ error = archive_write_open(data,(void*)_self->ruby,rubymyopen,rubymywrite,rubymyclose);
168
+ break;
169
+ }
170
+ return error;
171
+ }
172
+
173
+ int Archive_write_set_compression(struct archive *data,int compression)
174
+ {
175
+ int error = 0;
176
+ switch(compression){
177
+ case ARCHIVE_COMPRESSION_NONE:
178
+ error = archive_write_set_compression_none(data);
179
+ break;
180
+ case ARCHIVE_COMPRESSION_GZIP:
181
+ error = archive_write_set_compression_gzip(data);
182
+ break;
183
+ case ARCHIVE_COMPRESSION_BZIP2:
184
+ error = archive_write_set_compression_bzip2(data);
185
+ break;
186
+ case ARCHIVE_COMPRESSION_COMPRESS:
187
+ error = archive_write_set_compression_compress(data);
188
+ break;
189
+ case ARCHIVE_COMPRESSION_LZMA:
190
+ error = archive_write_set_compression_lzma(data);
191
+ break;
192
+ case ARCHIVE_COMPRESSION_XZ:
193
+ error = archive_write_set_compression_xz(data);
194
+ break;
195
+ default:
196
+ rb_raise(rb_eArchiveErrorCompression,"unsupported compresstype");
197
+ break;
198
+ }
199
+ return error;
200
+ }
201
+ /*
202
+ *call-seq:
203
+ * new( path [, format [, compression ] ] ) → an_archive
204
+ *
205
+ * Makes a new Archive object. If format is given, a new archive is created or
206
+ * an existing archive will be converted into the given format.
207
+ * ===Parameters
208
+ * [path] The path to the archive. May or may not exist.
209
+ * [format] The archive's format as a symbol. If you ommit this, the format will
210
+ * be guessed from the file extension. Possible formats are:
211
+ * * :ar
212
+ * * :tar
213
+ * * :xar
214
+ * * :zip
215
+ * [compression] Symbol inidicating the compression you want to use. If
216
+ * ommited, it will be guessed from the file extension.
217
+ * Possible formats are:
218
+ * * :bzip2
219
+ * * :compress
220
+ * * :gzip
221
+ * * :lzma
222
+ * * :xz
223
+ * ===Raises
224
+ * [FormatError] Unknown archive format or writing not supported.
225
+ * [CompressionError] Unknown compression format.
226
+ * ===Examples
227
+ * See the README for some examples.
228
+ */
229
+
230
+ VALUE Archive_initialize(int argc, VALUE *argv,VALUE self)
231
+ {
232
+ VALUE path,r_format,r_compression;
233
+ rb_scan_args(argc, argv, "12", &path,&r_format,&r_compression);
234
+ if(rb_obj_is_kind_of(path,rb_cIO)){
235
+ _self->fd = NUM2INT(rb_funcall(path,rb_intern("fileno"),0));
236
+ _self->type = archive_fd;
237
+ rb_scan_args(argc, argv, "21", &path,&r_format,&r_compression);
238
+ }else if(rb_respond_to(path,rb_intern("read"))){
239
+ _self->ruby = path;
240
+ _self->type = archive_ruby;
241
+ rb_scan_args(argc, argv, "21", &path,&r_format,&r_compression);
242
+ }else{
243
+ path = rb_file_s_expand_path(1,&path);
244
+ _self->path = std::string(rb_string_value_cstr(&path));
245
+ _self->type =archive_path;
246
+ }
247
+
248
+ //to set the format the file must convert
249
+ if(!NIL_P(r_format)){
250
+
251
+ char buff[8192];
252
+ //std::string selfpath =_self->path;
253
+ size_t bytes_read;
254
+ struct archive *a = archive_read_new(),*b=archive_write_new();
255
+ struct archive_entry *entry;
256
+ int format,compression,error=0;
257
+ std::vector<struct archive_entry *> entries;
258
+ std::vector<std::string> allbuff;
259
+ if(rb_obj_is_kind_of(r_format,rb_cSymbol)!=Qtrue)
260
+ rb_raise(rb_eTypeError,"exepted Symbol");
261
+ if(SYM2ID(r_format) == rb_intern("tar"))
262
+ format = ARCHIVE_FORMAT_TAR_GNUTAR;
263
+ else if(SYM2ID(r_format) == rb_intern("zip"))
264
+ format = ARCHIVE_FORMAT_ZIP;
265
+ else if(SYM2ID(r_format) == rb_intern("ar"))
266
+ format = ARCHIVE_FORMAT_AR_GNU;
267
+ else if(SYM2ID(r_format) == rb_intern("xar"))
268
+ format = ARCHIVE_FORMAT_XAR;
269
+ else
270
+ rb_raise(rb_eTypeError,"wrong format");
271
+
272
+ if(NIL_P(r_compression)){
273
+ compression = ARCHIVE_COMPRESSION_NONE;
274
+ error = archive_write_set_compression_none(b);
275
+ }else if(SYM2ID(r_compression) == rb_intern("gzip")){
276
+ compression =ARCHIVE_COMPRESSION_GZIP;
277
+ error = archive_write_set_compression_gzip(b);
278
+ }else if(SYM2ID(r_compression) == rb_intern("bzip2")){
279
+ compression =ARCHIVE_COMPRESSION_BZIP2;
280
+ error = archive_write_set_compression_bzip2(b);
281
+ }else if(SYM2ID(r_compression) == rb_intern("compress")){
282
+ compression =ARCHIVE_COMPRESSION_BZIP2;
283
+ error = archive_write_set_compression_compress(b);
284
+ }else if(SYM2ID(r_compression) == rb_intern("lzma")){
285
+ compression =ARCHIVE_COMPRESSION_LZMA;
286
+ error = archive_write_set_compression_lzma(b);
287
+ }else if(SYM2ID(r_compression) == rb_intern("xz")){
288
+ compression =ARCHIVE_COMPRESSION_XZ;
289
+ error = archive_write_set_compression_xz(b);
290
+ }else
291
+ rb_raise(rb_eTypeError,"unsupported compression");
292
+
293
+ if(error)
294
+ rb_raise(rb_eArchiveError,"error (%d): %s ",archive_errno(b),archive_error_string(b));
295
+
296
+ archive_read_support_compression_all(a);
297
+ archive_read_support_format_all(a);
298
+ archive_read_support_format_raw(a);
299
+ //autodetect format and compression
300
+ error=Archive_read_ruby(self,a);
301
+ _self->format = format;
302
+ _self->compression = compression;
303
+ if(error==ARCHIVE_OK){
304
+ while(archive_read_next_header(a, &entry)==ARCHIVE_OK){
305
+ if(format==archive_format(a) && compression==archive_compression(a)){
306
+ archive_read_finish(a);
307
+ return self;
308
+ }
309
+ entries.push_back(archive_entry_clone(entry));
310
+ allbuff.push_back(std::string(""));
311
+ while ((bytes_read=archive_read_data(a,&buff,sizeof(buff)))>0)
312
+ allbuff.back().append(buff,bytes_read);
313
+ }
314
+ archive_read_finish(a);
315
+ }
316
+ //format fix
317
+ if(format==ARCHIVE_FORMAT_TAR_GNUTAR)
318
+ format=ARCHIVE_FORMAT_TAR_USTAR;
319
+
320
+ if((error = archive_write_set_format(b,format)) != ARCHIVE_OK)
321
+ rb_raise(rb_eArchiveErrorFormat,"error (%d): %s ",error,archive_error_string(b));
322
+ error=Archive_write_ruby(self,b);
323
+ if(error==ARCHIVE_OK){
324
+ //write old data back
325
+ for(unsigned int i=0; i<entries.size(); i++){
326
+ archive_write_header(b,entries[i]);
327
+ archive_write_data(b,allbuff[i].c_str(),allbuff[i].length());
328
+ archive_write_finish_entry(b);
329
+ }
330
+ archive_write_finish(b);
331
+ }
332
+ }
333
+ return self;
334
+ }
335
+
336
+ /*
337
+ * call-seq:
338
+ * path() → a_string
339
+ *
340
+ * Returns the path (filename) of the archive.
341
+ * ===Return value
342
+ * Returns path of the archive. May or may not exist.
343
+ * ===Example
344
+ * a.path #=> /home/freak/myarchive.tar.gz
345
+ */
346
+
347
+ VALUE Archive_path(VALUE self)
348
+ {
349
+ return (_self->type == archive_path) ? rb_str_new2(_self->path.c_str()) : Qnil;
350
+ }
351
+
352
+ VALUE Archive_each_block(struct archive *data)
353
+ {
354
+ VALUE result = rb_ary_new();
355
+ struct archive_entry *entry;
356
+ while (archive_read_next_header(data, &entry) == ARCHIVE_OK) {
357
+ VALUE temp = wrap(entry);
358
+ if(rb_proc_arity(rb_block_proc())==1){
359
+ rb_yield(temp);
360
+ archive_read_data_skip(data);
361
+ }else{
362
+ char buff[8192];
363
+ std::string str;
364
+ size_t bytes_read;
365
+ try {
366
+ while ((bytes_read=archive_read_data(data,&buff,sizeof(buff)))>0)
367
+ str.append(buff,bytes_read);
368
+ }catch(...){
369
+ rb_raise(rb_eArchiveError,"error:%d:%s",archive_errno(data),archive_error_string(data));
370
+ }
371
+ rb_yield_values(2,temp,rb_str_new2(str.c_str()));
372
+ }
373
+ rb_ary_push(result,temp);
374
+ }
375
+ return result;
376
+ }
377
+
378
+ /*
379
+ * call-seq:
380
+ * each(){|entry [, data]| ... } → an_array
381
+ * each() → an_enumerator
382
+ *
383
+ * Iterates through the archive and yields each entry as an Archive::Entry object. The second parameter
384
+ * contains the data of that entry, so you don't have to extract it only to read what's in it.
385
+ * ===Return value
386
+ * If a block is given, returns an array of Archive::Entry objects, otherwise an enumerator.
387
+ * ===Example
388
+ * a.each{|entry| p entry.path}
389
+ * a.each{|entry, data| puts "'#{entry.path}' contains '#{data}'"}
390
+ * Output:
391
+ * "file1.txt"
392
+ * "file2.txt"
393
+ * 'file1.txt' contains 'I am file1!'
394
+ * 'file2.txt' contains 'I am file2!'
395
+ */
396
+
397
+ VALUE Archive_each(VALUE self)
398
+ {
399
+ RETURN_ENUMERATOR(self,0,NULL);
400
+ struct archive *a = archive_read_new();
401
+
402
+ archive_read_support_compression_all(a);
403
+ archive_read_support_format_all(a);
404
+ archive_read_support_format_raw(a);
405
+ int error=Archive_read_ruby(self,a);
406
+ if(error==ARCHIVE_OK)
407
+ return RB_ENSURE(Archive_each_block,a,Archive_read_block_ensure,a);
408
+ return Qnil;
409
+ }
410
+
411
+
412
+ VALUE Archive_each_entry_block(struct archive *data)
413
+ {
414
+ VALUE result = rb_ary_new();
415
+ struct archive_entry *entry;
416
+ while (archive_read_next_header(data, &entry) == ARCHIVE_OK) {
417
+ VALUE temp = wrap(entry);
418
+ rb_yield(temp);
419
+ archive_read_data_skip(data);
420
+ rb_ary_push(result,temp);
421
+ }
422
+ return result;
423
+ }
424
+
425
+ /*
426
+ * call-seq:
427
+ * each_entry() {|entry| ... } → an_array
428
+ * each_entry() → an_enumerator
429
+ *
430
+ * Iterates through the archive and yields each entry as an Archive::Entry object.
431
+ * This is the same as #each, but doesn't allow for the second block parameter.
432
+ * ===Return value
433
+ * If a block is given, returns an array of Archive::Entry objects, otherwise an enumerator.
434
+ * ===Example
435
+ * a.each_entry{|entry| p entry.path}
436
+ * Output:
437
+ * "file1.txt"
438
+ * "file2.txt"
439
+ */
440
+
441
+ VALUE Archive_each_entry(VALUE self)
442
+ {
443
+ RETURN_ENUMERATOR(self,0,NULL);
444
+ struct archive *a = archive_read_new();
445
+
446
+ archive_read_support_compression_all(a);
447
+ archive_read_support_format_all(a);
448
+ archive_read_support_format_raw(a);
449
+ int error=Archive_read_ruby(self,a);
450
+ if(error==ARCHIVE_OK)
451
+ return RB_ENSURE(Archive_each_entry_block,a,Archive_read_block_ensure,a);
452
+ return Qnil;
453
+ }
454
+
455
+
456
+ VALUE Archive_each_data_block(struct archive *data)
457
+ {
458
+ VALUE result = rb_ary_new();
459
+ struct archive_entry *entry;
460
+ while (archive_read_next_header(data, &entry) == ARCHIVE_OK) {
461
+ char buff[8192];
462
+ std::string str;
463
+ size_t bytes_read;
464
+ try{
465
+ while ((bytes_read=archive_read_data(data,&buff,sizeof(buff)))>0)
466
+ str.append(buff,bytes_read);
467
+ } catch (...){
468
+ rb_raise(rb_eArchiveError,"error:%d:%s",archive_errno(data),archive_error_string(data));
469
+ }
470
+ rb_yield(rb_str_new2(str.c_str()));
471
+ rb_ary_push(result,rb_str_new2(str.c_str()));
472
+ }
473
+ return result;
474
+ }
475
+
476
+
477
+ /*
478
+ * call-seq:
479
+ * each_data() {|data| } → an_array
480
+ * each_data() → an_enumerator
481
+ *
482
+ * Iterates through the archive and yields each entry's data as a string.
483
+ * This is the same as #each, but doesn't allow for the first block parameter.
484
+ * ===Return value
485
+ * If a block is given, returns an array of String objects, otherwise an enumerator.
486
+ * ===Example
487
+ * a.each{|data| puts "This is: '#{data}'"}
488
+ * Output:
489
+ * This is: 'I am file1!'
490
+ * This is: 'I am file2!'
491
+ */
492
+
493
+ VALUE Archive_each_data(VALUE self)
494
+ {
495
+ RETURN_ENUMERATOR(self,0,NULL);
496
+ struct archive *a = archive_read_new();
497
+
498
+ archive_read_support_compression_all(a);
499
+ archive_read_support_format_all(a);
500
+ archive_read_support_format_raw(a);
501
+ int error=Archive_read_ruby(self,a);
502
+ if(error==ARCHIVE_OK)
503
+ return RB_ENSURE(Archive_each_data_block,a,Archive_read_block_ensure,a);
504
+ return Qnil;
505
+ }
506
+
507
+
508
+ /*
509
+ * call-seq:
510
+ * archive.to_hash → Hash
511
+ *
512
+ * Iterates through the archive and yields each data of an entry as a string object.
513
+ * ===Return value
514
+ * returns Hash of Archive::Entry => Sring
515
+ */
516
+
517
+ VALUE Archive_to_hash(VALUE self)
518
+ {
519
+ VALUE result = rb_hash_new();
520
+ struct archive *a = archive_read_new();
521
+ struct archive_entry *entry;
522
+ archive_read_support_compression_all(a);
523
+ archive_read_support_format_all(a);
524
+ archive_read_support_format_raw(a);
525
+ int error=Archive_read_ruby(self,a);
526
+ if(error==ARCHIVE_OK){
527
+ while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
528
+ char buff[8192];
529
+ std::string str;
530
+ size_t bytes_read;
531
+ try{
532
+ while ((bytes_read=archive_read_data(a,&buff,sizeof(buff)))>0)
533
+ str.append(buff,bytes_read);
534
+ } catch (...){
535
+ rb_raise(rb_eArchiveError,"error:%d:%s",archive_errno(a),archive_error_string(a));
536
+ }
537
+ rb_hash_aset(result,wrap(entry),rb_str_new2(str.c_str()));
538
+ }
539
+ archive_read_finish(a);
540
+ }
541
+ return result;
542
+ }
543
+
544
+ VALUE Archive_map_block(struct write_obj * data){
545
+ for(unsigned int i=0; i< data->entries->size(); i++){
546
+ VALUE temp = wrap(data->entries->at(i));
547
+ VALUE val;
548
+ if(rb_proc_arity(rb_block_proc())<2){
549
+ val = rb_yield(temp);
550
+ }else{
551
+ val = rb_yield_values(2,temp,rb_str_new2(data->allbuff->at(i).c_str()));
552
+ }
553
+ VALUE entry,rdata= Qnil;
554
+ if(rb_obj_is_kind_of(val,rb_cArray)==Qtrue){
555
+ entry=rb_ary_entry(val,0);
556
+ rdata=rb_ary_entry(val,1);
557
+ }else
558
+ entry = val;
559
+ if(rb_obj_is_kind_of(entry,rb_cArchiveEntry)==Qtrue){
560
+ archive_write_header(data->archive,wrap<struct archive_entry *>(val));
561
+
562
+ if(rdata == Qnil)
563
+ archive_write_data(data->archive,data->allbuff->at(i).c_str(),data->allbuff->at(i).length());
564
+ else{
565
+ char* buff = StringValueCStr(rdata);
566
+ archive_write_data(data->archive,buff,strlen(buff));
567
+ }
568
+ archive_write_finish_entry(data->archive);
569
+ }else if(entry==Qnil){
570
+ }else
571
+ rb_raise(rb_eTypeError,"exepted %s!",rb_class2name(rb_cArchiveEntry));
572
+ }
573
+ return Qnil;
574
+ }
575
+
576
+ /*
577
+ * call-seq:
578
+ * map!() {| entry [,data] | ... } → Array
579
+ * archive.map!() → Enumerator
580
+ *
581
+ * Iterates through the archive and changes it's data "on the fly", i.e.
582
+ * the value your block returns for each iteration is put for the data
583
+ * in the yielded entry. Your block is expected to return a 2-element
584
+ * array of form
585
+ * [archive_entry, "data"]
586
+ * where +archive_enty+ is the +entry+ yielded to the block (which you
587
+ * may modify via the Archive::Entry methods) and <tt>"data"</tt> is a
588
+ * string containing the data you want to set for this entry.
589
+ *
590
+ * The block parameters are the same as for #each.
591
+ * ===Return value
592
+ * The archive itself.
593
+ * ===Example
594
+ * #Double the contents in each file of the archive
595
+ * a.map!{|entry, data| [entry, data * 2]}
596
+ * #Clear all files in the archive
597
+ * a.map!{|entry| [entry, ""]}
598
+ */
599
+ VALUE Archive_map_self(VALUE self)
600
+ {
601
+ RETURN_ENUMERATOR(self,0,NULL);
602
+ char buff[8192];
603
+ std::string selfpath =_self->path;
604
+ size_t bytes_read;
605
+ struct archive *a = archive_read_new(),*b=archive_write_new();
606
+ struct archive_entry *entry;
607
+ int format = ARCHIVE_FORMAT_EMPTY,compression = ARCHIVE_COMPRESSION_NONE,error=0;
608
+ std::vector<struct archive_entry *> entries;
609
+ std::vector<std::string> allbuff;
610
+
611
+ archive_read_support_compression_all(a);
612
+ archive_read_support_format_all(a);
613
+ archive_read_support_format_raw(a);
614
+ //autodetect format and compression
615
+ error=Archive_read_ruby(self,a);
616
+ if(error==ARCHIVE_OK){
617
+ while(archive_read_next_header(a, &entry)==ARCHIVE_OK){
618
+ format = archive_format(a);
619
+ compression = archive_compression(a);
620
+ entries.push_back(archive_entry_clone(entry));
621
+ allbuff.push_back(std::string(""));
622
+ try{
623
+ while ((bytes_read=archive_read_data(a,&buff,sizeof(buff)))>0)
624
+ allbuff.back().append(buff,bytes_read);
625
+ } catch (...){
626
+ rb_raise(rb_eArchiveError,"error:%d:%s",archive_errno(a),archive_error_string(a));
627
+ }
628
+ }
629
+ archive_read_finish(a);
630
+ //format fix
631
+ if(format==ARCHIVE_FORMAT_TAR_GNUTAR)
632
+ format=ARCHIVE_FORMAT_TAR_USTAR;
633
+ if((error = archive_write_set_format(b,format)) != ARCHIVE_OK)
634
+ rb_raise(rb_eArchiveErrorFormat,"error (%d): %s ",error,archive_error_string(b));
635
+ Archive_write_set_compression(b,compression);
636
+
637
+ error=Archive_write_ruby(self,b);
638
+ if(error==ARCHIVE_OK){
639
+ write_obj obj;
640
+ obj.archive = b;
641
+ obj.entries = &entries;
642
+ obj.allbuff = &allbuff;
643
+ RB_ENSURE(Archive_map_block,&obj,Archive_write_block_ensure,b);
644
+ }
645
+ }
646
+ return self;
647
+ }
648
+
649
+ /*
650
+ * call-seq:
651
+ * [](name) → Archive::Entry or nil
652
+ *
653
+ * Returns an archive entry for the given name.
654
+ * ===Parameters
655
+ * [name] could be a String or a Regex.
656
+ * ===Return value
657
+ * If a matching entry is found, it's returned as an Archive::Entry object. If not,
658
+ * nil is returned.
659
+ * ===Example
660
+ * #Assuming your archive contains file.txt and ruby.txt
661
+ *
662
+ * a["file.txt"] #=> Archive::Entry
663
+ * a[/txt/] #=> Archive::Entry
664
+ */
665
+
666
+ VALUE Archive_get(VALUE self,VALUE val)
667
+ {
668
+ struct archive *a = archive_read_new();
669
+ struct archive_entry *entry;
670
+ archive_read_support_compression_all(a);
671
+ archive_read_support_format_all(a);
672
+ archive_read_support_format_raw(a);
673
+ int error=Archive_read_ruby(self,a);
674
+ if(error==ARCHIVE_OK){
675
+ while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
676
+ bool find = false;
677
+ if(rb_obj_is_kind_of(val,rb_cRegexp)==Qtrue){
678
+ find = rb_reg_match(val,rb_str_new2(archive_entry_pathname(entry)))!=Qnil;
679
+ }else{
680
+ val = rb_funcall(val,rb_intern("to_s"),0);
681
+ std::string str1(rb_string_value_cstr(&val)),str2(str1);
682
+ str2 += '/'; // dir ends of '/'
683
+ const char *cstr = archive_entry_pathname(entry);
684
+ find = (str1.compare(cstr)==0 || str2.compare(cstr)==0);
685
+ }
686
+ if(find){
687
+ VALUE result = wrap(entry);
688
+ archive_read_finish(a);
689
+ return result;
690
+ }
691
+ }
692
+ archive_read_finish(a);
693
+ }
694
+ return Qnil;
695
+ }
696
+ /*
697
+ * call-seq:
698
+ * extract( [name = nil [, io [ ,opt ] ] ] ) → an_array
699
+ *
700
+ * Extract files to current directory.
701
+ * ===Parameters
702
+ * [name] (nil) could be an Archive::Entry, a String or an Regex. If given,
703
+ * only this entry is extracted. Otherwise extracts the whole
704
+ * archive.
705
+ * [io] an instance of IO or something with a +write+ method like
706
+ * StringIO. If given, the entry specified via +name+ will be
707
+ * extracted into +io+ instead of a file.
708
+ * [opt] is an option hash. See below for possible options.
709
+ * ===Parameters for the option hash
710
+ * [:extract] flag, Integer combined of the Archive::Extract_* constants.
711
+ * This tells libarchive-ruby to only extract the file attributes
712
+ * you specify here. Exceptions is Archive::EXTRACT_NO_OVERWRITE
713
+ * which prevents this method from overwrtiting existing files.
714
+ * ===Return value
715
+ * The paths of the extracted entries as an array.
716
+ * ===Example
717
+ * #Simply extract everything into the current directory.
718
+ * a.extract
719
+ * #Extract only file1.txt
720
+ * a.extract("file1.txt")
721
+ * #Same as above, but extract it to a StringIO
722
+ * s = StringIO.new
723
+ * a.extract("file1.txt", s)
724
+ * #Same as the first example, but only extract information about the
725
+ * #modification time.
726
+ * a.extract(nil, nil, extract: Archive::EXTRACT_TIME)
727
+ */
728
+
729
+ VALUE Archive_extract(int argc, VALUE *argv, VALUE self)
730
+ {
731
+ char buff[8192];
732
+ size_t bytes_read;
733
+
734
+ VALUE result = rb_ary_new(),name,io,opts,temp;
735
+ struct archive *a = archive_read_new();
736
+ struct archive_entry *entry;
737
+ archive_read_support_compression_all(a);
738
+ archive_read_support_format_all(a);
739
+ archive_read_support_format_raw(a);//add raw, this is not by all
740
+ int extract_opt = 0,fd=-1,error=0;
741
+ rb_scan_args(argc, argv, "03", &name,&io,&opts);
742
+ if(rb_obj_is_kind_of(name,rb_cHash)){
743
+ opts = name;name = Qnil;
744
+ }
745
+ if(rb_obj_is_kind_of(io,rb_cHash)){
746
+ opts = io;io = Qnil;
747
+ }
748
+ if(rb_obj_is_kind_of(io,rb_cIO))
749
+ fd = NUM2INT(rb_funcall(io,rb_intern("fileno"),0));
750
+
751
+
752
+ if(rb_obj_is_kind_of(opts,rb_cHash))
753
+ if(RTEST(temp=rb_hash_aref(opts,ID2SYM(rb_intern("extract")))))
754
+ extract_opt = NUM2INT(temp);
755
+
756
+ error=Archive_read_ruby(self,a);
757
+ if(error==ARCHIVE_OK){
758
+ try{
759
+ if(NIL_P(name)){
760
+ if(!NIL_P(io)){
761
+ rb_raise(rb_eArgError,"You can't extract more than 1 entry into an IO-like object!");
762
+ }
763
+ while(archive_read_next_header(a, &entry) == ARCHIVE_OK){
764
+ archive_read_extract(a,entry,extract_opt);
765
+ rb_ary_push(result,rb_str_new2(archive_entry_pathname(entry)));
766
+ }
767
+ }else{
768
+ if(rb_obj_is_kind_of(name,rb_cArchiveEntry)==Qtrue){
769
+ if(rb_obj_is_kind_of(io,rb_cIO)==Qtrue){
770
+ while(archive_read_next_header(a, &entry) == ARCHIVE_OK){
771
+ if(std::string(archive_entry_pathname(entry)).compare(archive_entry_pathname(wrap<archive_entry*>(name)))==0)
772
+ archive_read_data_into_fd(a,fd);
773
+ }
774
+ }else if(rb_respond_to(io,rb_intern("write"))){
775
+ while(archive_read_next_header(a, &entry) == ARCHIVE_OK){
776
+ if(std::string(archive_entry_pathname(entry)).compare(archive_entry_pathname(wrap<archive_entry*>(name)))==0)
777
+ while ((bytes_read=archive_read_data(a,&buff,sizeof(buff)))>0)
778
+ rb_funcall(io,rb_intern("write"),1,rb_str_new(buff,bytes_read));
779
+
780
+ }
781
+ }else
782
+ archive_read_extract(a,wrap<archive_entry*>(name),extract_opt);
783
+ rb_ary_push(result,rb_str_new2(archive_entry_pathname(wrap<archive_entry*>(name))));
784
+ }else if(rb_obj_is_kind_of(name,rb_cRegexp)==Qtrue){
785
+ while(archive_read_next_header(a, &entry) == ARCHIVE_OK){
786
+ VALUE str = rb_str_new2(archive_entry_pathname(entry));
787
+ if(rb_reg_match(name,str)!=Qnil){
788
+ if(rb_obj_is_kind_of(io,rb_cIO)==Qtrue){
789
+ archive_read_data_into_fd(a,fd);
790
+ }else if(rb_respond_to(io,rb_intern("write"))){
791
+ while ((bytes_read=archive_read_data(a,&buff,sizeof(buff)))>0)
792
+ rb_funcall(io,rb_intern("write"),1,rb_str_new(buff,bytes_read));
793
+ }else
794
+ archive_read_extract(a,entry,extract_opt);
795
+ rb_ary_push(result,str);
796
+ }
797
+ }
798
+ }else{
799
+ name = rb_funcall(name,rb_intern("to_s"),0);
800
+ std::string str1(rb_string_value_cstr(&name)),str2(str1);
801
+ str2 += '/'; // dir ends of '/'
802
+ while(archive_read_next_header(a, &entry) == ARCHIVE_OK){
803
+ const char *cstr = archive_entry_pathname(entry);
804
+ if(str1.compare(cstr)==0 || str2.compare(cstr)==0){
805
+ if(rb_obj_is_kind_of(io,rb_cIO)==Qtrue){
806
+ archive_read_data_into_fd(a,fd);
807
+ }else if(rb_respond_to(io,rb_intern("write"))){
808
+ while ((bytes_read=archive_read_data(a,&buff,sizeof(buff)))>0)
809
+ rb_funcall(io,rb_intern("write"),1,rb_str_new(buff,bytes_read));
810
+ }else
811
+ archive_read_extract(a,entry,extract_opt);
812
+ rb_ary_push(result,rb_str_new2(cstr));
813
+ }
814
+ }
815
+ }
816
+ }
817
+ }catch (...){
818
+ rb_raise(rb_eArchiveError,"error:%d:%s",archive_errno(a),archive_error_string(a));
819
+ }
820
+ archive_read_finish(a);
821
+ }
822
+ return result;
823
+ }
824
+
825
+ VALUE Archive_extract_if_block(struct extract_obj * data)
826
+ {
827
+ VALUE result = rb_ary_new();
828
+ struct archive_entry *entry;
829
+ while(archive_read_next_header(data->archive, &entry) == ARCHIVE_OK){
830
+ VALUE str = rb_str_new2(archive_entry_pathname(entry));
831
+ if(RTEST(rb_yield(wrap(entry)))){
832
+ archive_read_extract(data->archive,entry,data->extract_opt);
833
+ rb_ary_push(result,str);
834
+ }
835
+ }
836
+ return result;
837
+ }
838
+ /*
839
+ * call-seq:
840
+ * extract_if( [ opt ] ) {|entry| } → an_array
841
+ * extract_if( [ opt ] ) → an_enumerator
842
+ *
843
+ * Yields each entry in the archive to the block and extracts only those
844
+ * entries (to the current directory) for which the block evaluates to a
845
+ * truth value.
846
+ * ===Parameters
847
+ * [opt] is the same option hash that you can pass to #extract.
848
+ * ====Parameters for the option hash
849
+ * See the #extract method for explanation.
850
+ * ===Return value
851
+ * The paths of all extracted entries if a block was given, an Enumerator
852
+ * otherwise.
853
+ */
854
+
855
+ VALUE Archive_extract_if(int argc, VALUE *argv, VALUE self)
856
+ {
857
+ RETURN_ENUMERATOR(self,argc,argv);
858
+ VALUE opts,temp;
859
+ struct archive *a = archive_read_new();
860
+ archive_read_support_compression_all(a);
861
+ archive_read_support_format_all(a);
862
+ archive_read_support_format_raw(a);
863
+ int extract_opt=0,error=0;
864
+
865
+ rb_scan_args(argc, argv, "01", &opts);
866
+ if(rb_obj_is_kind_of(opts,rb_cHash))
867
+ if(RTEST(temp=rb_hash_aref(opts,ID2SYM(rb_intern("extract")))))
868
+ extract_opt = NUM2INT(temp);
869
+ error=Archive_read_ruby(self,a);
870
+ if(error==ARCHIVE_OK){
871
+ extract_obj obj;
872
+ obj.archive = a;
873
+ obj.extract_opt = extract_opt;
874
+ return RB_ENSURE(Archive_extract_if_block,&obj,Archive_read_block_ensure,a);
875
+ }
876
+ return Qnil;
877
+ }
878
+
879
+ /*
880
+ * call-seq:
881
+ * format() → an_integer or nil
882
+ *
883
+ * Returns the archive format as an integer. You should use #format_name
884
+ * instead.
885
+ * ===Return value
886
+ * An integer or nil if the format wasn't detectable.
887
+ */
888
+
889
+ VALUE Archive_format(VALUE self)
890
+ {
891
+ struct archive *a = archive_read_new();
892
+ struct archive_entry *entry;
893
+ VALUE result = Qnil;
894
+ archive_read_support_compression_all(a);
895
+ archive_read_support_format_all(a);
896
+ archive_read_support_format_raw(a);
897
+ int error=Archive_read_ruby(self,a);
898
+ if(error==ARCHIVE_OK){
899
+ archive_read_next_header(a, &entry);
900
+ result = INT2NUM(archive_format(a));
901
+ archive_read_finish(a);
902
+ }
903
+ return result;
904
+ }
905
+
906
+ /*
907
+ * call-seq:
908
+ * compression() → an_integer or nil
909
+ *
910
+ * Returns the archive compression as an integer. You should use
911
+ * #compression_name instead.
912
+ * ===Return value
913
+ * An integer or nil if the compression wasn't detectable. 0 means
914
+ * no compression.
915
+ */
916
+
917
+ VALUE Archive_compression(VALUE self)
918
+ {
919
+ struct archive *a = archive_read_new();
920
+ struct archive_entry *entry;
921
+ VALUE result = Qnil;
922
+ archive_read_support_compression_all(a);
923
+ archive_read_support_format_all(a);
924
+ archive_read_support_format_raw(a);
925
+ int error=Archive_read_ruby(self,a);
926
+ if(error==ARCHIVE_OK){
927
+ archive_read_next_header(a, &entry);
928
+ result = INT2NUM(archive_compression(a));
929
+ archive_read_finish(a);
930
+ }
931
+ return result;
932
+ }
933
+
934
+ /*
935
+ * call-seq:
936
+ * format_name() → a_string or nil
937
+ *
938
+ * Returns the archive format's name as a string.
939
+ * ===Return value
940
+ * A string or nil if the format wasn't detectable.
941
+ * ===Example
942
+ * a.format_name #=> "GNU tar format"
943
+ */
944
+
945
+ VALUE Archive_format_name(VALUE self)
946
+ {
947
+ struct archive *a = archive_read_new();
948
+ struct archive_entry *entry;
949
+ const char* name = NULL;
950
+ archive_read_support_compression_all(a);
951
+ archive_read_support_format_all(a);
952
+ archive_read_support_format_raw(a);
953
+ int error=Archive_read_ruby(self,a);
954
+ if(error==ARCHIVE_OK){
955
+ if(archive_read_next_header(a, &entry)==ARCHIVE_OK){
956
+ name = archive_format_name(a);
957
+ archive_read_finish(a);
958
+ }
959
+ }
960
+ return name ? rb_str_new2(name) : Qnil ;
961
+ }
962
+
963
+ /*
964
+ * call-seq:
965
+ * compression_name() → a_string or nil
966
+ *
967
+ * Returns the archive compression's name as a string.
968
+ * ===Return value
969
+ * A string or nil if the compression format wasn't detectable. If there
970
+ * is no compression, <tt>"none"</tt> is returned.
971
+ * ===Example
972
+ * a.compression_name #=> "gzip"
973
+ *
974
+ * a.compression_name #=> "none"
975
+ */
976
+
977
+ VALUE Archive_compression_name(VALUE self)
978
+ {
979
+ struct archive *a = archive_read_new();
980
+ struct archive_entry *entry;
981
+ const char* name = NULL;
982
+ archive_read_support_compression_all(a);
983
+ archive_read_support_format_all(a);
984
+ archive_read_support_format_raw(a);
985
+ int error=Archive_read_ruby(self,a);
986
+ if(error==ARCHIVE_OK){
987
+ archive_read_next_header(a, &entry);
988
+ name = archive_compression_name(a);
989
+ archive_read_finish(a);
990
+ }
991
+ return name ? rb_str_new2(name) : Qnil ;
992
+ }
993
+
994
+ /*
995
+ * call-seq:
996
+ * add( obj , path ) → self
997
+ *
998
+ * Adds a file to an archive.
999
+ * ===Parameters
1000
+ * [obj] String, IO, File or an object which responds to +read+.
1001
+ * [path] Sets the file name inside the archive.
1002
+ * ===Return value
1003
+ * self
1004
+ * ===Raises
1005
+ * [FormatError] Raised if the archive format is not supported for writing.
1006
+ */
1007
+
1008
+ VALUE Archive_add(VALUE self,VALUE obj,VALUE name)
1009
+ {
1010
+ char buff[8192];
1011
+ char *path = NULL;
1012
+
1013
+ size_t bytes_read;
1014
+ struct archive *a = archive_read_new(),*b=archive_write_new(),*c=archive_read_disk_new();
1015
+ struct archive_entry *entry;
1016
+ std::vector<struct archive_entry *> entries;
1017
+ std::vector<std::string> allbuff;
1018
+ int format= ARCHIVE_FORMAT_EMPTY,compression=ARCHIVE_COMPRESSION_NONE,fd=-1,error=0;
1019
+ archive_read_support_compression_all(a);
1020
+ archive_read_support_format_all(a);
1021
+ archive_read_support_format_raw(a);
1022
+ //autodetect format and compression
1023
+ error=Archive_read_ruby(self,a);
1024
+ if(error==ARCHIVE_OK){
1025
+ while(archive_read_next_header(a, &entry)==ARCHIVE_OK){
1026
+ entries.push_back(archive_entry_clone(entry));
1027
+ allbuff.push_back(std::string(""));
1028
+ try{
1029
+ while ((bytes_read=archive_read_data(a,&buff,sizeof(buff)))>0)
1030
+ allbuff.back().append(buff,bytes_read);
1031
+ }catch(...){
1032
+ rb_raise(rb_eArchiveError,"error:%d:%s",archive_errno(a),archive_error_string(a));
1033
+ }
1034
+ }
1035
+ format = archive_format(a);
1036
+ compression = archive_compression(a);
1037
+ archive_read_finish(a);
1038
+ }
1039
+ if(rb_obj_is_kind_of(obj,rb_cIO)){
1040
+ fd = NUM2INT(rb_funcall(obj,rb_intern("fileno"),0));
1041
+ }else if(rb_obj_is_kind_of(obj,rb_cFile)){
1042
+ VALUE pathname = rb_funcall(obj,rb_intern("path"),0); //source path
1043
+ VALUE obj2 = rb_file_s_expand_path(1,&pathname);
1044
+ path = rb_string_value_cstr(&obj2);
1045
+ fd = NUM2INT(rb_funcall(obj,rb_intern("fileno"),0));
1046
+ }else if(rb_respond_to(obj,rb_intern("read"))){
1047
+ //stringio has neigther path or fileno, so do nothing
1048
+ }else {
1049
+ VALUE obj2 = rb_file_s_expand_path(1,&obj);
1050
+ path = rb_string_value_cstr(&obj2);
1051
+ fd = open(path, O_RDONLY);
1052
+ if (fd < 0) //TODO: add error
1053
+ return self;
1054
+ }
1055
+ Archive_format_from_path(self,format,compression);
1056
+ if((error = archive_write_set_format(b,format)) != ARCHIVE_OK)
1057
+ rb_raise(rb_eArchiveErrorFormat,"error:%d:%s",archive_errno(b),archive_error_string(b));
1058
+ Archive_write_set_compression(b,compression);
1059
+
1060
+ error=Archive_write_ruby(self,b);
1061
+ if(error==ARCHIVE_OK){
1062
+ for(unsigned int i=0; i<entries.size(); i++){
1063
+ if(std::string(rb_string_value_cstr(&name)).compare(archive_entry_pathname(entries[i]))!=0){
1064
+ archive_write_header(b,entries[i]);
1065
+ archive_write_data(b,allbuff[i].c_str(),allbuff[i].length());
1066
+ archive_write_finish_entry(b);
1067
+ }
1068
+ }
1069
+ archive_read_disk_set_standard_lookup(c);
1070
+ entry = archive_entry_new();
1071
+ if (path)
1072
+ archive_entry_copy_sourcepath(entry, path);
1073
+ archive_entry_copy_pathname(entry, rb_string_value_cstr(&name));
1074
+ if(fd < 0 and rb_respond_to(obj,rb_intern("read"))){
1075
+ archive_write_header(b, entry);
1076
+ VALUE result;
1077
+ result = rb_funcall(obj,rb_intern("read"),0);
1078
+ archive_write_data(b, rb_string_value_cstr(&result), RSTRING_LEN(result));
1079
+ }else{
1080
+ archive_read_disk_entry_from_file(c, entry, fd, NULL);
1081
+ archive_write_header(b, entry);
1082
+ while ((bytes_read = read(fd, buff, sizeof(buff))) > 0)
1083
+ archive_write_data(b, buff, bytes_read);
1084
+ }
1085
+ archive_write_finish_entry(b);
1086
+ archive_read_finish(c);
1087
+ archive_write_finish(b);
1088
+ }
1089
+
1090
+ if(fd >= 0 and !rb_obj_is_kind_of(name,rb_cIO))
1091
+ close(fd);
1092
+ return self;
1093
+ }
1094
+
1095
+ /*
1096
+ * call-seq:
1097
+ * << obj → self
1098
+ *
1099
+ * Adds a file to an archive. Basicly the same as #add, but you can't
1100
+ * set the path inside the archive.
1101
+ * ===Parameters
1102
+ * [obj] String or File
1103
+ * ===Return value
1104
+ * self
1105
+ * ===Raises
1106
+ * [FormatError] The archive format is not supported for writing.
1107
+ */
1108
+ VALUE Archive_add_shift(VALUE self,VALUE name)
1109
+ {
1110
+ if(rb_obj_is_kind_of(name,rb_cFile))
1111
+ return Archive_add(self,name,rb_funcall(name,rb_intern("path"),0));
1112
+ else
1113
+ return Archive_add(self,name,name);
1114
+ }
1115
+
1116
+ /*
1117
+ * call-seq:
1118
+ * delete( name ) → an_array
1119
+ *
1120
+ * Delete files from an archive.
1121
+ * ===Parameters
1122
+ * [name] An Archive::Entry, a String or a Regex.
1123
+ * ===Return value
1124
+ * A list of paths removed from the archive.
1125
+ * ===Raises
1126
+ * raise TypeError if the parameter is neigther String or File.
1127
+ * raise Error if the format has no write support
1128
+ */
1129
+
1130
+ VALUE Archive_delete(VALUE self,VALUE val)
1131
+ {
1132
+ char buff[8192];
1133
+ size_t bytes_read;
1134
+ struct archive *a = archive_read_new(),*b=archive_write_new();
1135
+ struct archive_entry *entry;
1136
+ int format = ARCHIVE_FORMAT_EMPTY,compression = ARCHIVE_COMPRESSION_NONE,error=0;
1137
+ std::vector<struct archive_entry *> entries;
1138
+ std::vector<std::string> allbuff;
1139
+ VALUE result = rb_ary_new();
1140
+ archive_read_support_compression_all(a);
1141
+ archive_read_support_format_all(a);
1142
+ archive_read_support_format_raw(a);
1143
+ //autodetect format and compression
1144
+ error=Archive_read_ruby(self,a);
1145
+ if(error==ARCHIVE_OK){
1146
+ while(archive_read_next_header(a, &entry)==ARCHIVE_OK){
1147
+ format = archive_format(a);
1148
+ compression = archive_compression(a);
1149
+ bool del = false;
1150
+ if(rb_obj_is_kind_of(val,rb_cArchiveEntry)==Qtrue){
1151
+ del = std::string(archive_entry_pathname(wrap<archive_entry*>(val))).compare(archive_entry_pathname(entry)) == 0;
1152
+ }else if(rb_obj_is_kind_of(val,rb_cRegexp)==Qtrue){
1153
+ VALUE str = rb_str_new2(archive_entry_pathname(entry));
1154
+ del = rb_reg_match(val,str)!=Qnil;
1155
+ }else {
1156
+ std::string str1(rb_string_value_cstr(&val)),str2(str1);
1157
+ str2 += '/'; // dir ends of '/'
1158
+ const char *cstr = archive_entry_pathname(entry);
1159
+ del = (str1.compare(cstr)==0 || str2.compare(cstr)==0);
1160
+ }
1161
+ if(!del){
1162
+ entries.push_back(archive_entry_clone(entry));
1163
+ allbuff.push_back(std::string(""));
1164
+ try{
1165
+ while ((bytes_read=archive_read_data(a,&buff,sizeof(buff)))>0)
1166
+ allbuff.back().append(buff,bytes_read);
1167
+ }catch(...){
1168
+ rb_raise(rb_eArchiveError,"error:%d:%s",archive_errno(a),archive_error_string(a));
1169
+ }
1170
+ }else
1171
+ rb_ary_push(result,wrap(archive_entry_clone(entry)));
1172
+ }
1173
+ archive_read_finish(a);
1174
+
1175
+ //format fix
1176
+ if(format==ARCHIVE_FORMAT_TAR_GNUTAR)
1177
+ format=ARCHIVE_FORMAT_TAR_USTAR;
1178
+
1179
+ //TODO add archive-error
1180
+ if((error = archive_write_set_format(b,format)) != ARCHIVE_OK)
1181
+ rb_raise(rb_eArchiveErrorFormat,"error (%d): %s ",error,archive_error_string(b));
1182
+ Archive_write_set_compression(b,compression);
1183
+ error=Archive_write_ruby(self,b);
1184
+ if(error==ARCHIVE_OK){
1185
+ //write old data back
1186
+ for(unsigned int i=0; i<entries.size(); i++){
1187
+ archive_write_header(b,entries[i]);
1188
+ archive_write_data(b,allbuff[i].c_str(),allbuff[i].length());
1189
+ archive_write_finish_entry(b);
1190
+ }
1191
+ archive_write_finish(b);
1192
+ }
1193
+
1194
+ }
1195
+ return result;
1196
+ }
1197
+
1198
+ VALUE Archive_delete_if_block(struct write_obj * data)
1199
+ {
1200
+ VALUE result= rb_ary_new();
1201
+ for(unsigned int i=0; i< data->entries->size(); i++){
1202
+ if(!RTEST(rb_yield(wrap(data->entries->at(i))))){
1203
+ archive_write_header(data->archive,data->entries->at(i));
1204
+ archive_write_data(data->archive,data->allbuff->at(i).c_str(),data->allbuff->at(i).length());
1205
+ archive_write_finish_entry(data->archive);
1206
+ }else
1207
+ rb_ary_push(result,wrap(data->entries->at(i)));
1208
+ }
1209
+ return result;
1210
+ }
1211
+
1212
+ /*
1213
+ * call-seq:
1214
+ * archive.delete_if {|entry| } -> self
1215
+ * archive.delete_if -> Enumerator
1216
+ *
1217
+ * Yields each entry in the archive to the block and deletes those for which
1218
+ * the block evaluates to a truth value.
1219
+ * ===Parameters
1220
+ * [name] An Archive::Entry, a String or a Regex.
1221
+ * ===Return value
1222
+ * If a block was given, returns self, otherwise an Enumerator.
1223
+ * ===Raises
1224
+ * raise Error if the format has no write support
1225
+ */
1226
+
1227
+ VALUE Archive_delete_if(VALUE self)
1228
+ {
1229
+ RETURN_ENUMERATOR(self,0,NULL);
1230
+ char buff[8192];
1231
+ std::string selfpath =_self->path;
1232
+ size_t bytes_read;
1233
+ struct archive *a = archive_read_new(),*b=archive_write_new();
1234
+ struct archive_entry *entry;
1235
+ int format = ARCHIVE_FORMAT_EMPTY,compression = ARCHIVE_COMPRESSION_NONE,error=0;
1236
+ std::vector<struct archive_entry *> entries;
1237
+ std::vector<std::string> allbuff;
1238
+
1239
+ archive_read_support_compression_all(a);
1240
+ archive_read_support_format_all(a);
1241
+ archive_read_support_format_raw(a);
1242
+ error=Archive_read_ruby(self,a);
1243
+ if(error==ARCHIVE_OK){
1244
+ while(archive_read_next_header(a, &entry)==ARCHIVE_OK){
1245
+ format = archive_format(a);
1246
+ compression = archive_compression(a);
1247
+ entries.push_back(archive_entry_clone(entry));
1248
+ allbuff.push_back(std::string(""));
1249
+ try{
1250
+ while ((bytes_read=archive_read_data(a,&buff,sizeof(buff)))>0)
1251
+ allbuff.back().append(buff,bytes_read);
1252
+ }catch(...){
1253
+ rb_raise(rb_eArchiveError,"error:%d:%s",archive_errno(a),archive_error_string(a));
1254
+ }
1255
+ }
1256
+ archive_read_finish(a);
1257
+ //format fix
1258
+ if(format==ARCHIVE_FORMAT_TAR_GNUTAR)
1259
+ format=ARCHIVE_FORMAT_TAR_USTAR;
1260
+ if((error = archive_write_set_format(b,format)) != ARCHIVE_OK)
1261
+ rb_raise(rb_eArchiveErrorFormat,"error (%d): %s ",error,archive_error_string(b));
1262
+ Archive_write_set_compression(b,compression);
1263
+ error=Archive_write_ruby(self,b);
1264
+ if(error==ARCHIVE_OK){
1265
+ write_obj obj;
1266
+ obj.archive = b;
1267
+ obj.entries = &entries;
1268
+ obj.allbuff = &allbuff;
1269
+ return RB_ENSURE(Archive_delete_if_block,&obj,Archive_write_block_ensure,b);
1270
+ }
1271
+ }
1272
+ return Qnil;
1273
+ }
1274
+
1275
+ /*
1276
+ * call-seq:
1277
+ * archive.clear -> self
1278
+ *
1279
+ * Deletes all files from an archive.
1280
+ * ===Return value
1281
+ * returns self.
1282
+ * ===Raises
1283
+ * raise Error if the format has no write support
1284
+ */
1285
+
1286
+ VALUE Archive_clear(VALUE self)
1287
+ {
1288
+
1289
+ std::string selfpath =_self->path;
1290
+
1291
+ struct archive *a = archive_read_new(),*b=archive_write_new();
1292
+ struct archive_entry *entry;
1293
+ int format = ARCHIVE_FORMAT_EMPTY,compression = ARCHIVE_COMPRESSION_NONE,error=0;
1294
+
1295
+ archive_read_support_compression_all(a);
1296
+ archive_read_support_format_all(a);
1297
+ archive_read_support_format_raw(a);
1298
+ error=Archive_read_ruby(self,a);
1299
+ if(error==ARCHIVE_OK){
1300
+ archive_read_next_header(a, &entry);
1301
+ format = archive_format(a);
1302
+ compression = archive_compression(a);
1303
+ archive_read_finish(a);
1304
+
1305
+ //format fix
1306
+ if(format==ARCHIVE_FORMAT_TAR_GNUTAR)
1307
+ format=ARCHIVE_FORMAT_TAR_USTAR;
1308
+
1309
+ if((error = archive_write_set_format(b,format)) != ARCHIVE_OK)
1310
+ rb_raise(rb_eArchiveErrorFormat,"error (%d): %s ",error,archive_error_string(b));
1311
+ Archive_write_set_compression(b,compression);
1312
+ error=Archive_write_ruby(self,b);
1313
+ if(error==ARCHIVE_OK)
1314
+ archive_write_finish(b);
1315
+ }
1316
+
1317
+ return self;
1318
+ }
1319
+
1320
+ /*:nodoc:
1321
+ * call-seq:
1322
+ * archive.exist? -> true or false
1323
+ *
1324
+ * Same as
1325
+ * File.exist?(archive.path)
1326
+ * . Checks wheather or not the archive file is existant.
1327
+ * ===Return value
1328
+ * True or false.
1329
+ */
1330
+
1331
+ VALUE Archive_exist(VALUE self)
1332
+ {
1333
+ return rb_funcall(rb_cFile,rb_intern("exist?"),1,Archive_path(self));
1334
+ }
1335
+
1336
+ /*:nodoc:
1337
+ * call-seq:
1338
+ * archive.unlink -> self
1339
+ *
1340
+ * call the File.unlink(path)
1341
+ */
1342
+
1343
+ VALUE Archive_unlink(VALUE self)
1344
+ {
1345
+ return rb_funcall(rb_cFile,rb_intern("unlink"),1,Archive_path(self));
1346
+ return self;
1347
+ }
1348
+
1349
+ /*:nodoc:
1350
+ * call-seq:
1351
+ * archive.mtime -> Time
1352
+ *
1353
+ * call the File.mtime(path)
1354
+ */
1355
+
1356
+ VALUE Archive_mtime(VALUE self)
1357
+ {
1358
+ return rb_funcall(rb_cFile,rb_intern("mtime"),1,Archive_path(self));
1359
+ }
1360
+
1361
+ /*:nodoc:
1362
+ * call-seq:
1363
+ * archive.atime -> Time
1364
+ *
1365
+ * call the File.atime(path)
1366
+ */
1367
+
1368
+ VALUE Archive_atime(VALUE self)
1369
+ {
1370
+ return rb_funcall(rb_cFile,rb_intern("atime"),1,Archive_path(self));
1371
+ }
1372
+
1373
+ /*:nodoc:
1374
+ * call-seq:
1375
+ * archive.ctime -> Time
1376
+ *
1377
+ * call the File.ctime(path)
1378
+ */
1379
+
1380
+
1381
+ VALUE Archive_ctime(VALUE self)
1382
+ {
1383
+ return rb_funcall(rb_cFile,rb_intern("ctime"),1,Archive_path(self));
1384
+ }
1385
+
1386
+ /*:nodoc:
1387
+ * call-seq:
1388
+ * archive.stat -> File::Stat
1389
+ *
1390
+ * call the File.stat(path)
1391
+ */
1392
+
1393
+ VALUE Archive_stat(VALUE self)
1394
+ {
1395
+ return rb_funcall(rb_cFile,rb_intern("stat"),1,Archive_path(self));
1396
+ }
1397
+
1398
+ /*
1399
+ * call-seq:
1400
+ * archive.inspect -> String
1401
+ *
1402
+ * Human-readable description.
1403
+ * ===Return value
1404
+ * String
1405
+ */
1406
+
1407
+ VALUE Archive_inspect(VALUE self)
1408
+ {
1409
+ VALUE array[3];
1410
+ switch(_self->type){
1411
+ case archive_path:
1412
+ array[0]=rb_str_new2("#<%s:%s>");
1413
+ array[1]=rb_class_of(self);
1414
+ array[2]=Archive_path(self);
1415
+ break;
1416
+ case archive_fd:
1417
+ array[0]=rb_str_new2("#<%s:%d>");
1418
+ array[1]=rb_class_of(self);
1419
+ array[2]=INT2NUM(_self->fd);
1420
+ break;
1421
+ case archive_buffer:
1422
+ break;
1423
+ case archive_ruby:
1424
+ array[0]=rb_str_new2("#<%s:%s>");
1425
+ array[1]=rb_class_of(self);
1426
+ array[2]=_self->ruby;
1427
+ break;
1428
+ }
1429
+ return rb_f_sprintf(3,array);
1430
+ }
1431
+
1432
+ /*
1433
+ * Document-class: Archive::Error
1434
+ * This is the superclass of all errors specific to this library.
1435
+ */
1436
+
1437
+ /*
1438
+ * Document-class: Archive::Error::Compression
1439
+ * This exception is thrown if you try to use an unknown compression format.
1440
+ */
1441
+
1442
+ /*
1443
+ * Document-class: Archive::Error::Format
1444
+ * This exception is thrown if you try to use an unknown archive format or libarchive doesn't
1445
+ * have write support for the format you wanted to write.
1446
+ */
1447
+
1448
+ /*
1449
+ * Document-class: Archive
1450
+ *
1451
+ * This class represents an archive file. The file may or may not exist,
1452
+ * depending on wheather you want to create a new archive or read from
1453
+ * an existing one. When instanciating this class, libarchive-ruby will
1454
+ * automatically detect the correct file format for you using libarchive's
1455
+ * own detection mechanism if the archive file is already present, otherwise
1456
+ * by looking at the archive file's file extension.
1457
+ */
1458
+ /*
1459
+ * Document-const: EXTRACT_TIME
1460
+ *
1461
+ * extract the atime and mtime
1462
+ */
1463
+ /*
1464
+ * Document-const: EXTRACT_PERM
1465
+ *
1466
+ * extract the permission
1467
+ */
1468
+ /*
1469
+ * Document-const: EXTRACT_OWNER
1470
+ *
1471
+ * extract the owner
1472
+ */
1473
+
1474
+ /*
1475
+ * Document-const: EXTRACT_ACL
1476
+ *
1477
+ * extract the access control list
1478
+ */
1479
+ /*
1480
+ * Document-const: EXTRACT_FFLAGS
1481
+ *
1482
+ * extract the fflags
1483
+ */
1484
+ /*
1485
+ * Document-const: EXTRACT_XATTR
1486
+ *
1487
+ * extract the extended information
1488
+ */
1489
+ extern "C" void Init_archive(void){
1490
+ rb_cArchive = rb_define_class("Archive",rb_cObject);
1491
+ rb_define_alloc_func(rb_cArchive,Archive_alloc);
1492
+ rb_define_method(rb_cArchive,"initialize",RUBY_METHOD_FUNC(Archive_initialize),-1);
1493
+ rb_define_private_method(rb_cArchive,"initialize_copy",RUBY_METHOD_FUNC(Archive_initialize_copy),1);
1494
+ rb_define_method(rb_cArchive,"path",RUBY_METHOD_FUNC(Archive_path),0);
1495
+
1496
+ rb_define_method(rb_cArchive,"each",RUBY_METHOD_FUNC(Archive_each),0);
1497
+ rb_define_method(rb_cArchive,"each_entry",RUBY_METHOD_FUNC(Archive_each_entry),0);
1498
+ rb_define_method(rb_cArchive,"each_data",RUBY_METHOD_FUNC(Archive_each_data),0);
1499
+ rb_define_method(rb_cArchive,"map!",RUBY_METHOD_FUNC(Archive_map_self),0);
1500
+ rb_define_alias(rb_cArchive,"collect!","map!");
1501
+ rb_define_method(rb_cArchive,"[]",RUBY_METHOD_FUNC(Archive_get),1);
1502
+
1503
+ rb_define_method(rb_cArchive,"to_hash",RUBY_METHOD_FUNC(Archive_to_hash),0);
1504
+
1505
+ rb_define_method(rb_cArchive,"extract",RUBY_METHOD_FUNC(Archive_extract),-1);
1506
+ rb_define_method(rb_cArchive,"extract_if",RUBY_METHOD_FUNC(Archive_extract_if),-1);
1507
+
1508
+ rb_define_method(rb_cArchive,"delete",RUBY_METHOD_FUNC(Archive_delete),1);
1509
+ rb_define_method(rb_cArchive,"delete_if",RUBY_METHOD_FUNC(Archive_delete_if),0);
1510
+ rb_define_method(rb_cArchive,"clear",RUBY_METHOD_FUNC(Archive_clear),0);
1511
+
1512
+ //rb_define_method(rb_cArchive,"move_to",RUBY_METHOD_FUNC(Archive_move_to),1);
1513
+
1514
+ rb_define_method(rb_cArchive,"add",RUBY_METHOD_FUNC(Archive_add),2);
1515
+ rb_define_method(rb_cArchive,"<<",RUBY_METHOD_FUNC(Archive_add_shift),1);
1516
+
1517
+ rb_define_method(rb_cArchive,"inspect",RUBY_METHOD_FUNC(Archive_inspect),0);
1518
+
1519
+ rb_define_method(rb_cArchive,"format",RUBY_METHOD_FUNC(Archive_format),0);
1520
+ rb_define_method(rb_cArchive,"compression",RUBY_METHOD_FUNC(Archive_compression),0);
1521
+ rb_define_method(rb_cArchive,"format_name",RUBY_METHOD_FUNC(Archive_format_name),0);
1522
+ rb_define_method(rb_cArchive,"compression_name",RUBY_METHOD_FUNC(Archive_compression_name),0);
1523
+
1524
+ rb_define_method(rb_cArchive,"unlink",RUBY_METHOD_FUNC(Archive_unlink),0);
1525
+ rb_define_method(rb_cArchive,"exist?",RUBY_METHOD_FUNC(Archive_exist),0);
1526
+ rb_define_method(rb_cArchive,"mtime",RUBY_METHOD_FUNC(Archive_mtime),0);
1527
+ rb_define_method(rb_cArchive,"atime",RUBY_METHOD_FUNC(Archive_atime),0);
1528
+ rb_define_method(rb_cArchive,"ctime",RUBY_METHOD_FUNC(Archive_ctime),0);
1529
+ rb_define_method(rb_cArchive,"stat",RUBY_METHOD_FUNC(Archive_stat),0);
1530
+
1531
+ rb_include_module(rb_cArchive,rb_mEnumerable);
1532
+ //rb_define_method(rb_cArchive,"size",RUBY_METHOD_FUNC(Archive_size),0);
1533
+
1534
+ Init_archive_entry(rb_cArchive);
1535
+
1536
+ rb_define_const(rb_cArchive,"EXTRACT_TIME",INT2NUM(ARCHIVE_EXTRACT_TIME));
1537
+ rb_define_const(rb_cArchive,"EXTRACT_OWNER",INT2NUM(ARCHIVE_EXTRACT_OWNER));
1538
+ rb_define_const(rb_cArchive,"EXTRACT_PERM",INT2NUM(ARCHIVE_EXTRACT_PERM));
1539
+ rb_define_const(rb_cArchive,"EXTRACT_NO_OVERWRITE",INT2NUM(ARCHIVE_EXTRACT_NO_OVERWRITE));
1540
+ rb_define_const(rb_cArchive,"EXTRACT_ACL",INT2NUM(ARCHIVE_EXTRACT_ACL));
1541
+ rb_define_const(rb_cArchive,"EXTRACT_FFLAGS",INT2NUM(ARCHIVE_EXTRACT_FFLAGS));
1542
+ rb_define_const(rb_cArchive,"EXTRACT_XATTR",INT2NUM(ARCHIVE_EXTRACT_XATTR));
1543
+
1544
+ rb_eArchiveError = rb_define_class_under(rb_cArchive,"Error",rb_eStandardError);
1545
+ rb_eArchiveErrorFormat = rb_define_class_under(rb_eArchiveError,"Format",rb_eArchiveError);
1546
+ rb_eArchiveErrorCompression = rb_define_class_under(rb_eArchiveError,"Compression",rb_eArchiveError);
1547
+ }