libarchive-ruby-gvalmon 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +15 -0
- data/COPYING.txt +339 -0
- data/README.rdoc +147 -0
- data/ext/archive.cpp +1801 -0
- data/ext/entry.cpp +369 -0
- data/ext/extconf.rb +49 -0
- data/ext/main.cpp +68 -0
- data/ext/main.hpp +79 -0
- metadata +62 -0
data/ext/archive.cpp
ADDED
@@ -0,0 +1,1801 @@
|
|
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 <map>
|
26
|
+
#include <exception>
|
27
|
+
#include <stdexcept>
|
28
|
+
#define _self wrap<rarchive*>(self)
|
29
|
+
#define RB_ENSURE(func1,obj1,func2,obj2)\
|
30
|
+
rb_ensure(RUBY_METHOD_FUNC(func1),(VALUE)obj1,RUBY_METHOD_FUNC(func2),(VALUE)obj2)
|
31
|
+
|
32
|
+
//TODO: handle string IO as archive Archive.new(stringio)
|
33
|
+
|
34
|
+
#ifndef rb_proc_arity
|
35
|
+
#define rb_proc_arity(obj) 2
|
36
|
+
#endif
|
37
|
+
|
38
|
+
|
39
|
+
typedef std::vector<struct archive_entry *> EntryVector;
|
40
|
+
typedef std::vector<std::string> BuffVector;
|
41
|
+
typedef std::vector<int> IntVector;
|
42
|
+
|
43
|
+
typedef std::vector<std::pair<struct archive_entry *,std::string> > DataVector;
|
44
|
+
|
45
|
+
typedef std::map<ID,int> SymToIntType;
|
46
|
+
SymToIntType SymToFormat;
|
47
|
+
SymToIntType SymToFilter;
|
48
|
+
|
49
|
+
typedef std::map<std::string,std::pair<int,int> > FileExtType;
|
50
|
+
|
51
|
+
FileExtType fileExt;
|
52
|
+
|
53
|
+
VALUE rb_cArchive,rb_eArchiveError,rb_eArchiveErrorFormat,rb_eArchiveErrorCompression;
|
54
|
+
|
55
|
+
VALUE Archive_alloc(VALUE self)
|
56
|
+
{
|
57
|
+
rarchive *result = new rarchive;
|
58
|
+
return wrap(result);
|
59
|
+
}
|
60
|
+
|
61
|
+
VALUE Archive_initialize_copy(VALUE self, VALUE other)
|
62
|
+
{
|
63
|
+
VALUE result = rb_call_super(1,&other);
|
64
|
+
_self->path = std::string(wrap<rarchive*>(other)->path.c_str());
|
65
|
+
_self->type = wrap<rarchive*>(other)->type;
|
66
|
+
return result;
|
67
|
+
}
|
68
|
+
|
69
|
+
struct extract_obj {
|
70
|
+
struct archive* archive;
|
71
|
+
int extract_opt;
|
72
|
+
};
|
73
|
+
|
74
|
+
struct write_obj {
|
75
|
+
struct archive* archive;
|
76
|
+
DataVector *data;
|
77
|
+
};
|
78
|
+
|
79
|
+
struct add_obj {
|
80
|
+
struct archive* archive;
|
81
|
+
DataVector *data;
|
82
|
+
VALUE obj;
|
83
|
+
VALUE name;
|
84
|
+
};
|
85
|
+
|
86
|
+
|
87
|
+
VALUE wrap_data(const std::string &str)
|
88
|
+
{
|
89
|
+
#if HAVE_RUBY_ENCODING_H
|
90
|
+
return rb_external_str_new_with_enc(&str[0],str.length(),rb_filesystem_encoding());
|
91
|
+
#else
|
92
|
+
return rb_str_new(&str[0],str.length());
|
93
|
+
#endif
|
94
|
+
}
|
95
|
+
|
96
|
+
|
97
|
+
|
98
|
+
VALUE Archive_read_block_ensure(struct archive * data)
|
99
|
+
{
|
100
|
+
archive_read_close(data);
|
101
|
+
return Qnil;
|
102
|
+
}
|
103
|
+
|
104
|
+
VALUE Archive_write_block_ensure(struct archive * data)
|
105
|
+
{
|
106
|
+
archive_write_close(data);
|
107
|
+
return Qnil;
|
108
|
+
}
|
109
|
+
|
110
|
+
int rubymyopen(struct archive *a, void *client_data)
|
111
|
+
{
|
112
|
+
rb_funcall((VALUE)client_data,rb_intern("rewind"),0);
|
113
|
+
return ARCHIVE_OK;
|
114
|
+
}
|
115
|
+
ssize_t rubymyread(struct archive *a, void *client_data, const void **buff)
|
116
|
+
{
|
117
|
+
VALUE result = rb_funcall((VALUE)client_data,rb_intern("read"),0);
|
118
|
+
if(result == Qnil){
|
119
|
+
*buff = NULL;
|
120
|
+
return 0;
|
121
|
+
}else{
|
122
|
+
if (RSTRING_LEN(result))
|
123
|
+
*buff = RSTRING_PTR(result);
|
124
|
+
else
|
125
|
+
*buff = NULL;
|
126
|
+
return RSTRING_LEN(result);
|
127
|
+
}
|
128
|
+
}
|
129
|
+
|
130
|
+
ssize_t rubymywrite(struct archive *a,void *client_data,const void *buffer, size_t length){
|
131
|
+
VALUE string = rb_str_new((char*)buffer,length);
|
132
|
+
// rb_funcall(string,rb_intern("rstrip!"),0);
|
133
|
+
return NUM2INT(rb_funcall((VALUE)client_data,rb_intern("write"),1,string));
|
134
|
+
}
|
135
|
+
|
136
|
+
int rubymyclose(struct archive *a, void *client_data)
|
137
|
+
{
|
138
|
+
rb_funcall((VALUE)client_data,rb_intern("rewind"),0);
|
139
|
+
return ARCHIVE_OK;
|
140
|
+
}
|
141
|
+
|
142
|
+
namespace RubyArchive {
|
143
|
+
|
144
|
+
void read_get_filters(struct archive *a,IntVector &filters)
|
145
|
+
{
|
146
|
+
size_t filtercount = archive_filter_count(a);
|
147
|
+
for(size_t i = 0; i < filtercount; ++i)
|
148
|
+
filters.push_back(archive_filter_code(a,i));
|
149
|
+
}
|
150
|
+
|
151
|
+
void read_data(struct archive *a,std::string &str)
|
152
|
+
{
|
153
|
+
char buff[8192];
|
154
|
+
size_t bytes_read;
|
155
|
+
try{
|
156
|
+
while ((bytes_read=archive_read_data(a,&buff,sizeof(buff)))>0)
|
157
|
+
str.append(buff,bytes_read);
|
158
|
+
} catch (...){
|
159
|
+
rb_raise(rb_eArchiveError,"error:%d:%s",archive_errno(a),archive_error_string(a));
|
160
|
+
}
|
161
|
+
|
162
|
+
}
|
163
|
+
|
164
|
+
void read_old_data(struct archive *a,DataVector &entries, int &format, IntVector &filters)
|
165
|
+
{
|
166
|
+
struct archive_entry *entry;
|
167
|
+
|
168
|
+
while(archive_read_next_header(a, &entry)==ARCHIVE_OK){
|
169
|
+
format = archive_format(a);
|
170
|
+
if(filters.empty())
|
171
|
+
read_get_filters(a,filters);
|
172
|
+
std::string buff;
|
173
|
+
read_data(a,buff);
|
174
|
+
|
175
|
+
entries.push_back(std::make_pair(archive_entry_clone(entry),buff));
|
176
|
+
|
177
|
+
}
|
178
|
+
archive_read_close(a);
|
179
|
+
}
|
180
|
+
|
181
|
+
struct archive* create_match_object(VALUE opts)
|
182
|
+
{
|
183
|
+
VALUE temp;
|
184
|
+
struct archive* result = archive_match_new();
|
185
|
+
if(rb_obj_is_kind_of(opts,rb_cHash))
|
186
|
+
{
|
187
|
+
if(RTEST(temp=rb_hash_aref(opts,ID2SYM(rb_intern("uid")))))
|
188
|
+
archive_match_include_uid(result,NUM2INT(temp));
|
189
|
+
if(RTEST(temp=rb_hash_aref(opts,ID2SYM(rb_intern("gid")))))
|
190
|
+
archive_match_include_gid(result,NUM2INT(temp));
|
191
|
+
|
192
|
+
}
|
193
|
+
return result;
|
194
|
+
}
|
195
|
+
|
196
|
+
|
197
|
+
bool match_entry(struct archive_entry *entry,VALUE name)
|
198
|
+
{
|
199
|
+
const char *cstr = archive_entry_pathname(entry);
|
200
|
+
if(rb_obj_is_kind_of(name,rb_cArchiveEntry)){
|
201
|
+
return std::string(cstr).compare(archive_entry_pathname(wrap<archive_entry*>(name)))==0;
|
202
|
+
}else if(rb_obj_is_kind_of(name,rb_cRegexp)){
|
203
|
+
VALUE str = rb_str_new2(cstr);
|
204
|
+
return rb_reg_match(name,str)!=Qnil;
|
205
|
+
}else
|
206
|
+
name = rb_funcall(name,rb_intern("to_s"),0);
|
207
|
+
std::string str1(StringValueCStr(name)),str2(str1);
|
208
|
+
str2 += '/'; // dir ends of '/'
|
209
|
+
return str1.compare(cstr)==0 || str2.compare(cstr)==0;
|
210
|
+
|
211
|
+
return false;
|
212
|
+
}
|
213
|
+
|
214
|
+
|
215
|
+
int write_set_filters(struct archive *data,const IntVector &filter)
|
216
|
+
{
|
217
|
+
int error = 0;
|
218
|
+
|
219
|
+
for (IntVector::const_reverse_iterator it = filter.rbegin(); it != filter.rend();++it)
|
220
|
+
if(*it != ARCHIVE_FILTER_NONE)
|
221
|
+
archive_write_add_filter(data,*it);
|
222
|
+
|
223
|
+
return error;
|
224
|
+
}
|
225
|
+
|
226
|
+
void read_data_from_fd(struct archive *file,VALUE name,int fd,DataVector &data)
|
227
|
+
{
|
228
|
+
char buff[8192];
|
229
|
+
size_t bytes_read;
|
230
|
+
std::string strbuff;
|
231
|
+
|
232
|
+
struct archive_entry *entry = archive_entry_new();
|
233
|
+
|
234
|
+
archive_read_disk_entry_from_file(file, entry, fd, NULL);
|
235
|
+
archive_entry_copy_pathname(entry, StringValueCStr(name));
|
236
|
+
|
237
|
+
|
238
|
+
while ((bytes_read = read(fd, buff, sizeof(buff))) > 0)
|
239
|
+
strbuff.append(buff, bytes_read);
|
240
|
+
|
241
|
+
data.push_back(std::make_pair(entry,strbuff));
|
242
|
+
}
|
243
|
+
|
244
|
+
void read_data_from_ruby(struct archive *file,VALUE name,VALUE obj,DataVector &data)
|
245
|
+
{
|
246
|
+
std::string strbuff;
|
247
|
+
|
248
|
+
struct archive_entry *entry = archive_entry_new();
|
249
|
+
|
250
|
+
archive_entry_copy_pathname(entry, StringValueCStr(name));
|
251
|
+
|
252
|
+
//TODO should i read in chunks?
|
253
|
+
VALUE result = rb_funcall(obj,rb_intern("read"),0);
|
254
|
+
strbuff.append(StringValueCStr(result), RSTRING_LEN(result));
|
255
|
+
|
256
|
+
data.push_back(std::make_pair(entry,strbuff));
|
257
|
+
}
|
258
|
+
|
259
|
+
struct read_data_path_obj
|
260
|
+
{
|
261
|
+
struct archive* archive;
|
262
|
+
struct archive* match;
|
263
|
+
DataVector *data;
|
264
|
+
VALUE path;
|
265
|
+
};
|
266
|
+
|
267
|
+
|
268
|
+
void read_data_match_callback(struct archive * arch, void *, struct archive_entry *entry)
|
269
|
+
{
|
270
|
+
// entry = archive_entry_clone(entry);
|
271
|
+
// if(AE_IFDIR != archive_entry_filetype(entry))
|
272
|
+
// {
|
273
|
+
// rb_warn("%i ",);
|
274
|
+
//rb_warn("%i inclusions",archive_match_path_unmatched_inclusions(arch));
|
275
|
+
rb_warn("%s is excluded",archive_entry_pathname(entry));
|
276
|
+
// rb_warn("%d fflags",archive_entry_filetype(entry));
|
277
|
+
// rb_warn("%d uid",archive_entry_uid(entry));
|
278
|
+
|
279
|
+
// }else
|
280
|
+
// rb_warn("%s is a DIR!",archive_entry_pathname(entry));
|
281
|
+
// archive_read_disk_descend(arch);
|
282
|
+
|
283
|
+
|
284
|
+
}
|
285
|
+
|
286
|
+
int read_data_meta_callback(struct archive *arch, void *, struct archive_entry *entry)
|
287
|
+
{
|
288
|
+
if(archive_read_disk_can_descend(arch))
|
289
|
+
archive_read_disk_descend(arch);
|
290
|
+
return 1;
|
291
|
+
}
|
292
|
+
|
293
|
+
VALUE read_data_from_path_block(struct read_data_path_obj *obj)
|
294
|
+
{
|
295
|
+
struct archive_entry *entry = archive_entry_new();
|
296
|
+
|
297
|
+
while(archive_read_next_header2(obj->archive,entry) == ARCHIVE_OK)
|
298
|
+
{
|
299
|
+
const char *cstr = archive_entry_pathname(entry);
|
300
|
+
|
301
|
+
//allways add subdirs
|
302
|
+
//if(archive_read_disk_can_descend(obj->archive))
|
303
|
+
// archive_read_disk_descend(obj->archive);
|
304
|
+
|
305
|
+
// ignore the "." base dir
|
306
|
+
if(strcmp(cstr,".") == 0){
|
307
|
+
continue;
|
308
|
+
}
|
309
|
+
// fist look at the match object
|
310
|
+
if(archive_match_excluded(obj->match,entry))
|
311
|
+
continue;
|
312
|
+
|
313
|
+
// then if path is Regexp try to match against it
|
314
|
+
if(rb_obj_is_kind_of(obj->path,rb_cRegexp))
|
315
|
+
if(!RTEST(rb_reg_match(obj->path,rb_str_new2(cstr))))
|
316
|
+
continue;
|
317
|
+
|
318
|
+
// then use the block if given
|
319
|
+
if((!rb_block_given_p()) || RTEST(rb_yield(wrap(entry))))
|
320
|
+
{
|
321
|
+
//TODO: react to the change of the entry object
|
322
|
+
std::string strbuff;
|
323
|
+
const void *p;
|
324
|
+
size_t size;
|
325
|
+
int64_t offset;
|
326
|
+
|
327
|
+
while(archive_read_data_block(obj->archive, &p, &size, &offset) == ARCHIVE_OK)
|
328
|
+
strbuff.append((const char*)p,size);
|
329
|
+
|
330
|
+
struct archive_entry *entry2 = archive_entry_clone(entry);
|
331
|
+
|
332
|
+
|
333
|
+
//Drop the ./ from a filename when using pattern
|
334
|
+
std::string path(archive_entry_pathname(entry2));
|
335
|
+
if(path.compare(0,2,"./") == 0) {
|
336
|
+
path.erase(0,2);
|
337
|
+
archive_entry_copy_pathname(entry2,path.c_str());
|
338
|
+
}
|
339
|
+
|
340
|
+
obj->data->push_back(std::make_pair(entry2,strbuff));
|
341
|
+
|
342
|
+
}
|
343
|
+
|
344
|
+
}
|
345
|
+
return Qnil;
|
346
|
+
}
|
347
|
+
|
348
|
+
VALUE Archive_read_block_close(struct archive * data)
|
349
|
+
{
|
350
|
+
archive_read_close(data);
|
351
|
+
return Qnil;
|
352
|
+
}
|
353
|
+
|
354
|
+
void read_data_from_path(struct archive * file,struct archive * match,VALUE rpath,const char* path,DataVector &data)
|
355
|
+
{
|
356
|
+
|
357
|
+
archive_read_disk_open(file,path);
|
358
|
+
archive_read_disk_set_matching(file,match,read_data_match_callback,NULL);
|
359
|
+
archive_read_disk_set_metadata_filter_callback(file, read_data_meta_callback, NULL);
|
360
|
+
read_data_path_obj obj;
|
361
|
+
obj.archive = file;
|
362
|
+
obj.path = rpath;
|
363
|
+
obj.match = match;
|
364
|
+
obj.data = &data;
|
365
|
+
|
366
|
+
//struct archive_entry *entry = archive_entry_new();
|
367
|
+
|
368
|
+
//archive_read_next_header2(file,entry);
|
369
|
+
//archive_read_disk_descend(file);
|
370
|
+
|
371
|
+
RB_ENSURE(read_data_from_path_block,&obj,Archive_read_block_close,file);
|
372
|
+
}
|
373
|
+
|
374
|
+
|
375
|
+
void read_data_from_path2(VALUE path,VALUE opts,DataVector &data)
|
376
|
+
{
|
377
|
+
struct archive * file = archive_read_disk_new();
|
378
|
+
struct archive * match = create_match_object(opts);
|
379
|
+
|
380
|
+
archive_read_disk_set_standard_lookup(file);
|
381
|
+
const char * str = ".";
|
382
|
+
archive_match_include_pattern(match,".");
|
383
|
+
//archive_match_exclude_pattern(match,"*/*/*.cpp");
|
384
|
+
//archive_match_exclude_pattern(match,"*.cpp");
|
385
|
+
//archive_match_include_pattern(match,"*/");
|
386
|
+
|
387
|
+
if(!rb_obj_is_kind_of(path,rb_cRegexp))
|
388
|
+
{
|
389
|
+
path = rb_funcall(path,rb_intern("to_s"),0);
|
390
|
+
if(!RTEST(rb_funcall(rb_cFile,rb_intern("exist?"),1,path))){
|
391
|
+
archive_match_include_pattern(match,StringValueCStr(path));
|
392
|
+
}else
|
393
|
+
str = StringValueCStr(path);
|
394
|
+
}
|
395
|
+
read_data_from_path(file,match,path,str,data);
|
396
|
+
}
|
397
|
+
|
398
|
+
}
|
399
|
+
|
400
|
+
void Archive_format_from_path(VALUE self,int &format,IntVector &filters)
|
401
|
+
{
|
402
|
+
if(_self->type == archive_path){
|
403
|
+
std::string selfpath = _self->path;
|
404
|
+
size_t selfpathlength = selfpath.length();
|
405
|
+
for(FileExtType::iterator it = fileExt.begin(); it != fileExt.end(); ++it) {
|
406
|
+
if(selfpath.rfind(it->first) + it->first.length() == selfpathlength) {
|
407
|
+
format = it->second.first;
|
408
|
+
filters.push_back(it->second.second);
|
409
|
+
return;
|
410
|
+
}
|
411
|
+
}
|
412
|
+
}
|
413
|
+
|
414
|
+
format = _self->format;
|
415
|
+
filters.push_back(_self->filter);
|
416
|
+
|
417
|
+
}
|
418
|
+
|
419
|
+
int Archive_read_ruby(VALUE self,struct archive *data)
|
420
|
+
{
|
421
|
+
|
422
|
+
archive_read_support_filter_all(data);
|
423
|
+
archive_read_support_format_all(data);
|
424
|
+
#if HAVE_ARCHIVE_READ_SUPPORT_FORMAT_RAW
|
425
|
+
archive_read_support_format_raw(data);
|
426
|
+
#endif
|
427
|
+
int error =0;
|
428
|
+
switch(_self->type){
|
429
|
+
case archive_path:
|
430
|
+
error = archive_read_open_filename(data,_self->path.c_str(),10240);
|
431
|
+
break;
|
432
|
+
case archive_fd:
|
433
|
+
error = archive_read_open_fd(data,_self->fd,10240);
|
434
|
+
break;
|
435
|
+
case archive_buffer:
|
436
|
+
break;
|
437
|
+
case archive_ruby:
|
438
|
+
error = archive_read_open(data, (void*)_self->ruby,rubymyopen,rubymyread,rubymyclose);
|
439
|
+
break;
|
440
|
+
}
|
441
|
+
return error;
|
442
|
+
}
|
443
|
+
|
444
|
+
|
445
|
+
|
446
|
+
int Archive_write_ruby(VALUE self,struct archive *data,int format, const IntVector &filters)
|
447
|
+
{
|
448
|
+
int error =0;
|
449
|
+
|
450
|
+
if((error = archive_write_set_format(data,format)) != ARCHIVE_OK)
|
451
|
+
rb_raise(rb_eArchiveErrorFormat,"error (%d): %s ",error,archive_error_string(data));
|
452
|
+
|
453
|
+
RubyArchive::write_set_filters(data,filters);
|
454
|
+
|
455
|
+
switch(_self->type){
|
456
|
+
case archive_path:
|
457
|
+
error = archive_write_open_filename(data,_self->path.c_str());
|
458
|
+
break;
|
459
|
+
case archive_fd:
|
460
|
+
error = archive_write_open_fd(data,_self->fd);
|
461
|
+
break;
|
462
|
+
case archive_buffer:
|
463
|
+
break;
|
464
|
+
case archive_ruby:
|
465
|
+
error = archive_write_open(data,(void*)_self->ruby,rubymyopen,rubymywrite,rubymyclose);
|
466
|
+
break;
|
467
|
+
}
|
468
|
+
return error;
|
469
|
+
}
|
470
|
+
|
471
|
+
/*
|
472
|
+
*call-seq:
|
473
|
+
* new( path [, format [, compression ] ] ) → an_archive
|
474
|
+
*
|
475
|
+
* Makes a new Archive object. If format is given, a new archive is created or
|
476
|
+
* an existing archive will be converted into the given format.
|
477
|
+
* ===Parameters
|
478
|
+
* [path] The path to the archive. May or may not exist.
|
479
|
+
* [format] The archive's format as a symbol. If you ommit this, the format will
|
480
|
+
* be guessed from the file extension. Possible formats are:
|
481
|
+
* * :ar
|
482
|
+
* * :tar
|
483
|
+
* * :pax
|
484
|
+
* * :xar
|
485
|
+
* * :zip
|
486
|
+
* [compression] Symbol inidicating the compression you want to use. If
|
487
|
+
* ommited, it will be guessed from the file extension.
|
488
|
+
* Possible formats are:
|
489
|
+
* * :bzip2
|
490
|
+
* * :compress
|
491
|
+
* * :gzip
|
492
|
+
* * :lzma
|
493
|
+
* * :xz
|
494
|
+
* ===Raises
|
495
|
+
* [FormatError] Unknown archive format or writing not supported.
|
496
|
+
* [CompressionError] Unknown compression format.
|
497
|
+
* ===Examples
|
498
|
+
* See the README for some examples.
|
499
|
+
*/
|
500
|
+
|
501
|
+
VALUE Archive_initialize(int argc, VALUE *argv,VALUE self)
|
502
|
+
{
|
503
|
+
VALUE path,r_format,r_filter;
|
504
|
+
rb_scan_args(argc, argv, "12", &path,&r_format,&r_filter);
|
505
|
+
if(rb_obj_is_kind_of(path,rb_cIO)){
|
506
|
+
_self->fd = NUM2INT(rb_funcall(path,rb_intern("fileno"),0));
|
507
|
+
_self->type = archive_fd;
|
508
|
+
rb_scan_args(argc, argv, "21", &path,&r_format,&r_filter);
|
509
|
+
}else if(rb_obj_is_kind_of(path,rb_cInteger)){
|
510
|
+
_self->fd = NUM2INT(path);
|
511
|
+
_self->type = archive_fd;
|
512
|
+
rb_scan_args(argc, argv, "21", &path,&r_format,&r_filter);
|
513
|
+
}else if(rb_respond_to(path,rb_intern("read"))){
|
514
|
+
_self->type = archive_ruby;
|
515
|
+
rb_scan_args(argc, argv, "21", &path,&r_format,&r_filter);
|
516
|
+
}else{
|
517
|
+
path = rb_file_s_expand_path(1,&path);
|
518
|
+
_self->path = std::string(StringValueCStr(path));
|
519
|
+
_self->type =archive_path;
|
520
|
+
}
|
521
|
+
_self->ruby = path;
|
522
|
+
//to set the format the file must convert
|
523
|
+
if(!NIL_P(r_format)){
|
524
|
+
|
525
|
+
//struct archive *a = archive_read_new(),*b=archive_write_new();
|
526
|
+
//struct archive_entry *entry;
|
527
|
+
int format,filter;
|
528
|
+
|
529
|
+
if(SYMBOL_P(r_format)){
|
530
|
+
SymToIntType::iterator it = SymToFormat.find(SYM2ID(r_format));
|
531
|
+
if(it != SymToFormat.end()) {
|
532
|
+
format = it->second;
|
533
|
+
}else
|
534
|
+
rb_raise(rb_eTypeError,"wrong format");
|
535
|
+
}else
|
536
|
+
rb_raise(rb_eTypeError,"exepted Symbol");
|
537
|
+
|
538
|
+
if(NIL_P(r_filter)){
|
539
|
+
filter = ARCHIVE_FILTER_NONE;
|
540
|
+
}else if(SYMBOL_P(r_filter)){
|
541
|
+
SymToIntType::iterator it = SymToFilter.find(SYM2ID(r_filter));
|
542
|
+
if(it != SymToFilter.end()) {
|
543
|
+
filter = it->second;
|
544
|
+
} else
|
545
|
+
rb_raise(rb_eTypeError,"unsupported filter");
|
546
|
+
}else
|
547
|
+
rb_raise(rb_eTypeError,"exepted Symbol");
|
548
|
+
|
549
|
+
//autodetect format and compression
|
550
|
+
|
551
|
+
_self->format = format;
|
552
|
+
_self->filter = filter;
|
553
|
+
|
554
|
+
// if(Archive_read_ruby(self,a)==ARCHIVE_OK){
|
555
|
+
// while(archive_read_next_header(a, &entry)==ARCHIVE_OK){
|
556
|
+
// if(format==archive_format(a) && filter==archive_filter_code(a,0)){
|
557
|
+
// archive_read_close(a);
|
558
|
+
// return self;
|
559
|
+
// }
|
560
|
+
// entries.push_back(archive_entry_clone(entry));
|
561
|
+
// allbuff.push_back(std::string(""));
|
562
|
+
//
|
563
|
+
// RubyArchive::read_data(a,allbuff.back());
|
564
|
+
// }
|
565
|
+
// archive_read_close(a);
|
566
|
+
// if(Archive_write_ruby(self,b,format,IntVector(filter))==ARCHIVE_OK){
|
567
|
+
// //write old data back
|
568
|
+
// for(unsigned int i=0; i<entries.size(); i++){
|
569
|
+
// archive_write_header(b,entries[i]);
|
570
|
+
// archive_write_data(b,allbuff[i].c_str(),allbuff[i].length());
|
571
|
+
// archive_write_finish_entry(b);
|
572
|
+
// }
|
573
|
+
// archive_write_close(b);
|
574
|
+
// }
|
575
|
+
// }
|
576
|
+
}
|
577
|
+
return self;
|
578
|
+
}
|
579
|
+
|
580
|
+
/*
|
581
|
+
* call-seq:
|
582
|
+
* path() → a_string
|
583
|
+
*
|
584
|
+
* Returns the path (filename) of the archive.
|
585
|
+
* ===Return value
|
586
|
+
* Returns path of the archive. May or may not exist.
|
587
|
+
* ===Example
|
588
|
+
* a.path #=> /home/freak/myarchive.tar.gz
|
589
|
+
*/
|
590
|
+
|
591
|
+
VALUE Archive_path(VALUE self)
|
592
|
+
{
|
593
|
+
return (_self->type == archive_path) ? rb_str_new2(_self->path.c_str()) : Qnil;
|
594
|
+
}
|
595
|
+
|
596
|
+
VALUE Archive_each_block(struct archive *data)
|
597
|
+
{
|
598
|
+
struct archive_entry *entry;
|
599
|
+
while (archive_read_next_header(data, &entry) == ARCHIVE_OK) {
|
600
|
+
VALUE temp = wrap(entry);
|
601
|
+
if(rb_proc_arity(rb_block_proc())==1){
|
602
|
+
rb_yield(temp);
|
603
|
+
archive_read_data_skip(data);
|
604
|
+
}else{
|
605
|
+
std::string str;
|
606
|
+
RubyArchive::read_data(data,str);
|
607
|
+
rb_yield_values(2,temp,wrap_data(str));
|
608
|
+
}
|
609
|
+
}
|
610
|
+
return Qnil;
|
611
|
+
}
|
612
|
+
|
613
|
+
/*
|
614
|
+
* call-seq:
|
615
|
+
* each(){|entry [, data]| ... } → self
|
616
|
+
* each() → an_enumerator
|
617
|
+
*
|
618
|
+
* Iterates through the archive and yields each entry as an Archive::Entry object. The second parameter
|
619
|
+
* contains the data of that entry, so you don't have to extract it only to read what's in it.
|
620
|
+
* ===Return value
|
621
|
+
* If a block is given, returns self, otherwise an enumerator.
|
622
|
+
* ===Example
|
623
|
+
* a.each{|entry| p entry.path}
|
624
|
+
* a.each{|entry, data| puts "'#{entry.path}' contains '#{data}'"}
|
625
|
+
* Output:
|
626
|
+
* "file1.txt"
|
627
|
+
* "file2.txt"
|
628
|
+
* 'file1.txt' contains 'I am file1!'
|
629
|
+
* 'file2.txt' contains 'I am file2!'
|
630
|
+
*/
|
631
|
+
|
632
|
+
VALUE Archive_each(VALUE self)
|
633
|
+
{
|
634
|
+
RETURN_ENUMERATOR(self,0,NULL);
|
635
|
+
struct archive *a = archive_read_new();
|
636
|
+
|
637
|
+
|
638
|
+
int error=Archive_read_ruby(self,a);
|
639
|
+
if(error==ARCHIVE_OK){
|
640
|
+
RB_ENSURE(Archive_each_block,a,Archive_read_block_ensure,a);
|
641
|
+
return self;
|
642
|
+
}
|
643
|
+
return Qnil;
|
644
|
+
}
|
645
|
+
|
646
|
+
|
647
|
+
VALUE Archive_each_entry_block(struct archive *data)
|
648
|
+
{
|
649
|
+
VALUE result = rb_ary_new();
|
650
|
+
struct archive_entry *entry;
|
651
|
+
while (archive_read_next_header(data, &entry) == ARCHIVE_OK) {
|
652
|
+
VALUE temp = wrap(entry);
|
653
|
+
rb_yield(temp);
|
654
|
+
archive_read_data_skip(data);
|
655
|
+
rb_ary_push(result,temp);
|
656
|
+
}
|
657
|
+
return result;
|
658
|
+
}
|
659
|
+
|
660
|
+
/*
|
661
|
+
* call-seq:
|
662
|
+
* each_entry() {|entry| ... } → an_array
|
663
|
+
* each_entry() → an_enumerator
|
664
|
+
*
|
665
|
+
* Iterates through the archive and yields each entry as an Archive::Entry object.
|
666
|
+
* This is the same as #each, but doesn't allow for the second block parameter.
|
667
|
+
* ===Return value
|
668
|
+
* If a block is given, returns an array of Archive::Entry objects, otherwise an enumerator.
|
669
|
+
* ===Example
|
670
|
+
* a.each_entry{|entry| p entry.path}
|
671
|
+
* Output:
|
672
|
+
* "file1.txt"
|
673
|
+
* "file2.txt"
|
674
|
+
*/
|
675
|
+
|
676
|
+
VALUE Archive_each_entry(VALUE self)
|
677
|
+
{
|
678
|
+
RETURN_ENUMERATOR(self,0,NULL);
|
679
|
+
struct archive *a = archive_read_new();
|
680
|
+
|
681
|
+
if(Archive_read_ruby(self,a)==ARCHIVE_OK)
|
682
|
+
return RB_ENSURE(Archive_each_entry_block,a,Archive_read_block_ensure,a);
|
683
|
+
return Qnil;
|
684
|
+
}
|
685
|
+
|
686
|
+
|
687
|
+
VALUE Archive_each_data_block(struct archive *data)
|
688
|
+
{
|
689
|
+
struct archive_entry *entry;
|
690
|
+
while (archive_read_next_header(data, &entry) == ARCHIVE_OK) {
|
691
|
+
std::string str;
|
692
|
+
RubyArchive::read_data(data,str);
|
693
|
+
rb_yield(wrap_data(str));
|
694
|
+
}
|
695
|
+
return Qnil;
|
696
|
+
}
|
697
|
+
|
698
|
+
|
699
|
+
/*
|
700
|
+
* call-seq:
|
701
|
+
* each_data() {|data| } → self
|
702
|
+
* each_data() → an_enumerator
|
703
|
+
*
|
704
|
+
* Iterates through the archive and yields each entry's data as a string.
|
705
|
+
* This is the same as #each, but doesn't allow for the first block parameter.
|
706
|
+
* ===Return value
|
707
|
+
* If a block is given, returns self, otherwise an enumerator.
|
708
|
+
* ===Example
|
709
|
+
* a.each{|data| puts "This is: '#{data}'"}
|
710
|
+
* Output:
|
711
|
+
* This is: 'I am file1!'
|
712
|
+
* This is: 'I am file2!'
|
713
|
+
*/
|
714
|
+
|
715
|
+
VALUE Archive_each_data(VALUE self)
|
716
|
+
{
|
717
|
+
RETURN_ENUMERATOR(self,0,NULL);
|
718
|
+
struct archive *a = archive_read_new();
|
719
|
+
|
720
|
+
if(Archive_read_ruby(self,a)==ARCHIVE_OK)
|
721
|
+
RB_ENSURE(Archive_each_data_block,a,Archive_read_block_ensure,a);
|
722
|
+
return self;
|
723
|
+
}
|
724
|
+
|
725
|
+
VALUE Archive_each_filter_block(struct archive *data)
|
726
|
+
{
|
727
|
+
struct archive_entry *entry;
|
728
|
+
archive_read_next_header(data, &entry);
|
729
|
+
size_t count = archive_filter_count(data);
|
730
|
+
for(size_t i = 0; i < count; ++i)
|
731
|
+
rb_yield_values(2,INT2NUM(archive_filter_code(data,i)),rb_str_new2(archive_filter_name(data,i)));
|
732
|
+
|
733
|
+
return Qnil;
|
734
|
+
}
|
735
|
+
|
736
|
+
|
737
|
+
VALUE Archive_each_filter(VALUE self)
|
738
|
+
{
|
739
|
+
RETURN_ENUMERATOR(self,0,NULL);
|
740
|
+
struct archive *a = archive_read_new();
|
741
|
+
|
742
|
+
if(Archive_read_ruby(self,a)==ARCHIVE_OK)
|
743
|
+
RB_ENSURE(Archive_each_filter_block,a,Archive_read_block_ensure,a);
|
744
|
+
return self;
|
745
|
+
}
|
746
|
+
|
747
|
+
/*
|
748
|
+
* call-seq:
|
749
|
+
* archive.to_hash → Hash
|
750
|
+
*
|
751
|
+
* Iterates through the archive and yields each data of an entry as a string object.
|
752
|
+
* ===Return value
|
753
|
+
* returns Hash of Archive::Entry => String
|
754
|
+
*/
|
755
|
+
|
756
|
+
VALUE Archive_to_hash(VALUE self)
|
757
|
+
{
|
758
|
+
VALUE result = rb_hash_new();
|
759
|
+
struct archive *a = archive_read_new();
|
760
|
+
struct archive_entry *entry;
|
761
|
+
|
762
|
+
if(Archive_read_ruby(self,a)==ARCHIVE_OK){
|
763
|
+
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
|
764
|
+
std::string str;
|
765
|
+
RubyArchive::read_data(a,str);
|
766
|
+
rb_hash_aset(result,wrap(entry),wrap_data(str));
|
767
|
+
}
|
768
|
+
archive_read_close(a);
|
769
|
+
}
|
770
|
+
return result;
|
771
|
+
}
|
772
|
+
|
773
|
+
VALUE Archive_map_block(struct write_obj * data){
|
774
|
+
for(unsigned int i=0; i< data->data->size(); i++){
|
775
|
+
VALUE temp = wrap(data->data->at(i).first);
|
776
|
+
VALUE val;
|
777
|
+
if(rb_proc_arity(rb_block_proc())<2){
|
778
|
+
val = rb_yield(temp);
|
779
|
+
}else{
|
780
|
+
val = rb_yield_values(2,temp,wrap_data(data->data->at(i).second));
|
781
|
+
}
|
782
|
+
VALUE entry,rdata= Qnil;
|
783
|
+
if(rb_obj_is_kind_of(val,rb_cArray)){
|
784
|
+
entry=rb_ary_entry(val,0);
|
785
|
+
rdata=rb_ary_entry(val,1);
|
786
|
+
}else
|
787
|
+
entry = val;
|
788
|
+
if(rb_obj_is_kind_of(entry,rb_cArchiveEntry)){
|
789
|
+
archive_write_header(data->archive,wrap<struct archive_entry *>(val));
|
790
|
+
|
791
|
+
if(rdata == Qnil){
|
792
|
+
std::string &buff = data->data->at(i).second;
|
793
|
+
archive_write_data(data->archive,&buff[0],buff.length());
|
794
|
+
}else{
|
795
|
+
//char* buff = StringValueCStr(rdata);
|
796
|
+
archive_write_data(data->archive,RSTRING_PTR(rdata),RSTRING_LEN(rdata));
|
797
|
+
}
|
798
|
+
archive_write_finish_entry(data->archive);
|
799
|
+
}else if(entry==Qnil){
|
800
|
+
}else
|
801
|
+
rb_raise(rb_eTypeError,"exepted %s!",rb_class2name(rb_cArchiveEntry));
|
802
|
+
}
|
803
|
+
return Qnil;
|
804
|
+
}
|
805
|
+
|
806
|
+
/*
|
807
|
+
* call-seq:
|
808
|
+
* map!() {| entry [,data] | ... } → Array
|
809
|
+
* archive.map!() → Enumerator
|
810
|
+
*
|
811
|
+
* Iterates through the archive and changes it's data "on the fly", i.e.
|
812
|
+
* the value your block returns for each iteration is put for the data
|
813
|
+
* in the yielded entry. Your block is expected to return a 2-element
|
814
|
+
* array of form
|
815
|
+
* [archive_entry, "data"]
|
816
|
+
* where +archive_enty+ is the +entry+ yielded to the block (which you
|
817
|
+
* may modify via the Archive::Entry methods) and <tt>"data"</tt> is a
|
818
|
+
* string containing the data you want to set for this entry.
|
819
|
+
*
|
820
|
+
* The block parameters are the same as for #each.
|
821
|
+
* ===Return value
|
822
|
+
* The archive itself.
|
823
|
+
* ===Example
|
824
|
+
* #Double the contents in each file of the archive
|
825
|
+
* a.map!{|entry, data| [entry, data * 2]}
|
826
|
+
* #Clear all files in the archive
|
827
|
+
* a.map!{|entry| [entry, ""]}
|
828
|
+
*/
|
829
|
+
VALUE Archive_map_self(VALUE self)
|
830
|
+
{
|
831
|
+
RETURN_ENUMERATOR(self,0,NULL);
|
832
|
+
|
833
|
+
struct archive *a = archive_read_new(),*b=archive_write_new();
|
834
|
+
int format = ARCHIVE_FORMAT_EMPTY;
|
835
|
+
|
836
|
+
DataVector entries;
|
837
|
+
IntVector filters;
|
838
|
+
|
839
|
+
//autodetect format and filters
|
840
|
+
if(Archive_read_ruby(self,a)==ARCHIVE_OK){
|
841
|
+
|
842
|
+
RubyArchive::read_old_data(a,entries, format, filters);
|
843
|
+
|
844
|
+
if(Archive_write_ruby(self,b,format,filters)==ARCHIVE_OK){
|
845
|
+
write_obj obj;
|
846
|
+
obj.archive = b;
|
847
|
+
obj.data = &entries;
|
848
|
+
RB_ENSURE(Archive_map_block,&obj,Archive_write_block_ensure,b);
|
849
|
+
}
|
850
|
+
}
|
851
|
+
return self;
|
852
|
+
}
|
853
|
+
|
854
|
+
/*
|
855
|
+
* call-seq:
|
856
|
+
* [](name) → Archive::Entry or nil
|
857
|
+
*
|
858
|
+
* Returns an archive entry for the given name.
|
859
|
+
* ===Parameters
|
860
|
+
* [name] could be a String or a Regex.
|
861
|
+
* ===Return value
|
862
|
+
* If a matching entry is found, it's returned as an Archive::Entry object. If not,
|
863
|
+
* nil is returned.
|
864
|
+
* ===Example
|
865
|
+
* #Assuming your archive contains file.txt and ruby.txt
|
866
|
+
*
|
867
|
+
* a["file.txt"] #=> Archive::Entry
|
868
|
+
* a[/txt/] #=> Archive::Entry
|
869
|
+
*/
|
870
|
+
|
871
|
+
VALUE Archive_get(VALUE self,VALUE val)
|
872
|
+
{
|
873
|
+
struct archive *a = archive_read_new();
|
874
|
+
struct archive_entry *entry;
|
875
|
+
|
876
|
+
if(Archive_read_ruby(self,a)==ARCHIVE_OK){
|
877
|
+
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
|
878
|
+
if(RubyArchive::match_entry(entry,val)){
|
879
|
+
VALUE result = wrap(entry);
|
880
|
+
archive_read_close(a);
|
881
|
+
return result;
|
882
|
+
}
|
883
|
+
}
|
884
|
+
archive_read_close(a);
|
885
|
+
}
|
886
|
+
return Qnil;
|
887
|
+
}
|
888
|
+
|
889
|
+
|
890
|
+
void extract_extract(struct archive *a,struct archive_entry *entry,int extract_opt,VALUE io, int fd)
|
891
|
+
{
|
892
|
+
if(rb_obj_is_kind_of(io,rb_cIO)){
|
893
|
+
archive_read_data_into_fd(a,fd);
|
894
|
+
}else if(rb_respond_to(io,rb_intern("write"))){
|
895
|
+
char buff[8192];
|
896
|
+
size_t bytes_read;
|
897
|
+
while ((bytes_read=archive_read_data(a,&buff,sizeof(buff)))>0)
|
898
|
+
rb_funcall(io,rb_intern("write"),1,rb_str_new(buff,bytes_read));
|
899
|
+
}else
|
900
|
+
archive_read_extract(a,entry,extract_opt);
|
901
|
+
}
|
902
|
+
/*
|
903
|
+
* call-seq:
|
904
|
+
* extract( [name = nil [, io [ ,opt ] ] ] ) → an_array
|
905
|
+
*
|
906
|
+
* Extract files to current directory.
|
907
|
+
* ===Parameters
|
908
|
+
* [name] (nil) could be an Archive::Entry, a String or an Regex. If given,
|
909
|
+
* only this entry is extracted. Otherwise extracts the whole
|
910
|
+
* archive.
|
911
|
+
* [io] an instance of IO or something with a +write+ method like
|
912
|
+
* StringIO. If given, the entry specified via +name+ will be
|
913
|
+
* extracted into +io+ instead of a file.
|
914
|
+
* [opt] is an option hash. See below for possible options.
|
915
|
+
* ===Parameters for the option hash
|
916
|
+
* [:extract] flag, Integer combined of the Archive::Extract_* constants.
|
917
|
+
* This tells libarchive-ruby to only extract the file attributes
|
918
|
+
* you specify here. Exceptions is Archive::EXTRACT_NO_OVERWRITE
|
919
|
+
* which prevents this method from overwrtiting existing files.
|
920
|
+
* ===Return value
|
921
|
+
* The paths of the extracted entries as an array.
|
922
|
+
* ===Example
|
923
|
+
* #Simply extract everything into the current directory.
|
924
|
+
* a.extract
|
925
|
+
* #Extract only file1.txt
|
926
|
+
* a.extract("file1.txt")
|
927
|
+
* #Same as above, but extract it to a StringIO
|
928
|
+
* s = StringIO.new
|
929
|
+
* a.extract("file1.txt", s)
|
930
|
+
* #Same as the first example, but only extract information about the
|
931
|
+
* #modification time.
|
932
|
+
* a.extract(nil, nil, extract: Archive::EXTRACT_TIME)
|
933
|
+
*/
|
934
|
+
|
935
|
+
VALUE Archive_extract(int argc, VALUE *argv, VALUE self)
|
936
|
+
{
|
937
|
+
|
938
|
+
VALUE result = rb_ary_new(),name,io,opts,temp;
|
939
|
+
struct archive *a = archive_read_new();
|
940
|
+
struct archive_entry *entry;
|
941
|
+
//add raw, this is not by all
|
942
|
+
int extract_opt = 0,fd=-1;
|
943
|
+
rb_scan_args(argc, argv, "03", &name,&io,&opts);
|
944
|
+
if(rb_obj_is_kind_of(name,rb_cHash)){
|
945
|
+
opts = name;name = Qnil;
|
946
|
+
}
|
947
|
+
if(rb_obj_is_kind_of(io,rb_cHash)){
|
948
|
+
opts = io;io = Qnil;
|
949
|
+
}
|
950
|
+
if(rb_obj_is_kind_of(io,rb_cIO))
|
951
|
+
fd = NUM2INT(rb_funcall(io,rb_intern("fileno"),0));
|
952
|
+
|
953
|
+
|
954
|
+
if(rb_obj_is_kind_of(opts,rb_cHash))
|
955
|
+
if(RTEST(temp=rb_hash_aref(opts,ID2SYM(rb_intern("extract")))))
|
956
|
+
extract_opt = NUM2INT(temp);
|
957
|
+
|
958
|
+
if(Archive_read_ruby(self,a)==ARCHIVE_OK){
|
959
|
+
try{
|
960
|
+
if(NIL_P(name)){
|
961
|
+
if(!NIL_P(io)){
|
962
|
+
rb_raise(rb_eArgError,"You can't extract more than 1 entry into an IO-like object!");
|
963
|
+
}
|
964
|
+
while(archive_read_next_header(a, &entry) == ARCHIVE_OK){
|
965
|
+
archive_read_extract(a,entry,extract_opt);
|
966
|
+
rb_ary_push(result,rb_str_new2(archive_entry_pathname(entry)));
|
967
|
+
}
|
968
|
+
}else{
|
969
|
+
while(archive_read_next_header(a, &entry) == ARCHIVE_OK){
|
970
|
+
if(RubyArchive::match_entry(entry,name)){
|
971
|
+
extract_extract(a,entry,extract_opt,io,fd);
|
972
|
+
rb_ary_push(result,rb_str_new2(archive_entry_pathname(entry)));
|
973
|
+
}
|
974
|
+
}
|
975
|
+
}
|
976
|
+
}catch (...){
|
977
|
+
rb_raise(rb_eArchiveError,"error:%d:%s",archive_errno(a),archive_error_string(a));
|
978
|
+
}
|
979
|
+
archive_read_close(a);
|
980
|
+
}
|
981
|
+
return result;
|
982
|
+
}
|
983
|
+
|
984
|
+
VALUE Archive_extract_if_block(struct extract_obj * data)
|
985
|
+
{
|
986
|
+
VALUE result = rb_ary_new();
|
987
|
+
struct archive_entry *entry;
|
988
|
+
while(archive_read_next_header(data->archive, &entry) == ARCHIVE_OK){
|
989
|
+
VALUE str = rb_str_new2(archive_entry_pathname(entry));
|
990
|
+
if(RTEST(rb_yield(wrap(entry)))){
|
991
|
+
archive_read_extract(data->archive,entry,data->extract_opt);
|
992
|
+
rb_ary_push(result,str);
|
993
|
+
}
|
994
|
+
}
|
995
|
+
return result;
|
996
|
+
}
|
997
|
+
/*
|
998
|
+
* call-seq:
|
999
|
+
* extract_if( [ opt ] ) {|entry| } → an_array
|
1000
|
+
* extract_if( [ opt ] ) → an_enumerator
|
1001
|
+
*
|
1002
|
+
* Yields each entry in the archive to the block and extracts only those
|
1003
|
+
* entries (to the current directory) for which the block evaluates to a
|
1004
|
+
* truth value.
|
1005
|
+
* ===Parameters
|
1006
|
+
* [opt] is the same option hash that you can pass to #extract.
|
1007
|
+
* ====Parameters for the option hash
|
1008
|
+
* See the #extract method for explanation.
|
1009
|
+
* ===Return value
|
1010
|
+
* The paths of all extracted entries if a block was given, an Enumerator
|
1011
|
+
* otherwise.
|
1012
|
+
*/
|
1013
|
+
|
1014
|
+
VALUE Archive_extract_if(int argc, VALUE *argv, VALUE self)
|
1015
|
+
{
|
1016
|
+
RETURN_ENUMERATOR(self,argc,argv);
|
1017
|
+
VALUE opts,temp;
|
1018
|
+
struct archive *a = archive_read_new();
|
1019
|
+
|
1020
|
+
int extract_opt=0;
|
1021
|
+
|
1022
|
+
rb_scan_args(argc, argv, "01", &opts);
|
1023
|
+
if(rb_obj_is_kind_of(opts,rb_cHash))
|
1024
|
+
if(RTEST(temp=rb_hash_aref(opts,ID2SYM(rb_intern("extract")))))
|
1025
|
+
extract_opt = NUM2INT(temp);
|
1026
|
+
|
1027
|
+
if(Archive_read_ruby(self,a)==ARCHIVE_OK){
|
1028
|
+
extract_obj obj;
|
1029
|
+
obj.archive = a;
|
1030
|
+
obj.extract_opt = extract_opt;
|
1031
|
+
return RB_ENSURE(Archive_extract_if_block,&obj,Archive_read_block_ensure,a);
|
1032
|
+
}
|
1033
|
+
return Qnil;
|
1034
|
+
}
|
1035
|
+
|
1036
|
+
/*
|
1037
|
+
* call-seq:
|
1038
|
+
* format() → an_integer or nil
|
1039
|
+
*
|
1040
|
+
* Returns the archive format as an integer. You should use #format_name
|
1041
|
+
* instead.
|
1042
|
+
* ===Return value
|
1043
|
+
* An integer or nil if the format wasn't detectable.
|
1044
|
+
*/
|
1045
|
+
|
1046
|
+
VALUE Archive_format(VALUE self)
|
1047
|
+
{
|
1048
|
+
struct archive *a = archive_read_new();
|
1049
|
+
struct archive_entry *entry;
|
1050
|
+
VALUE result = Qnil;
|
1051
|
+
|
1052
|
+
if(Archive_read_ruby(self,a)==ARCHIVE_OK){
|
1053
|
+
archive_read_next_header(a, &entry);
|
1054
|
+
result = INT2NUM(archive_format(a));
|
1055
|
+
archive_read_close(a);
|
1056
|
+
}
|
1057
|
+
return result;
|
1058
|
+
}
|
1059
|
+
|
1060
|
+
/*
|
1061
|
+
* call-seq:
|
1062
|
+
* format_name() → a_string or nil
|
1063
|
+
*
|
1064
|
+
* Returns the archive format's name as a string.
|
1065
|
+
* ===Return value
|
1066
|
+
* A string or nil if the format wasn't detectable.
|
1067
|
+
* ===Example
|
1068
|
+
* a.format_name #=> "GNU tar format"
|
1069
|
+
*/
|
1070
|
+
|
1071
|
+
VALUE Archive_format_name(VALUE self)
|
1072
|
+
{
|
1073
|
+
struct archive *a = archive_read_new();
|
1074
|
+
struct archive_entry *entry;
|
1075
|
+
const char* name = NULL;
|
1076
|
+
|
1077
|
+
if(Archive_read_ruby(self,a)==ARCHIVE_OK){
|
1078
|
+
if(archive_read_next_header(a, &entry)==ARCHIVE_OK){
|
1079
|
+
name = archive_format_name(a);
|
1080
|
+
archive_read_close(a);
|
1081
|
+
}
|
1082
|
+
}
|
1083
|
+
return name ? rb_str_new2(name) : Qnil;
|
1084
|
+
}
|
1085
|
+
|
1086
|
+
|
1087
|
+
|
1088
|
+
|
1089
|
+
|
1090
|
+
|
1091
|
+
|
1092
|
+
|
1093
|
+
|
1094
|
+
|
1095
|
+
////key is the entry and val is
|
1096
|
+
|
1097
|
+
////TODO: hier nochmal ein ensure rein damit es das file wieder zu macht?
|
1098
|
+
//int Archive_add_hash_block(VALUE key,VALUE val,struct add_obj *obj){
|
1099
|
+
// char buff[8192];
|
1100
|
+
// size_t bytes_read;
|
1101
|
+
// int fd=-1;
|
1102
|
+
// obj->file = archive_read_disk_new();
|
1103
|
+
// archive_read_disk_set_standard_lookup(obj->file);
|
1104
|
+
// struct archive_entry *entry = archive_entry_new();
|
1105
|
+
// archive_entry_copy_pathname(entry, StringValueCStr(key));
|
1106
|
+
// if(rb_obj_is_kind_of(val,rb_cFile)){
|
1107
|
+
// VALUE pathname = rb_funcall(val,rb_intern("path"),0); //source path
|
1108
|
+
// VALUE obj2 = rb_file_s_expand_path(1,&pathname);
|
1109
|
+
// archive_entry_copy_sourcepath(entry, StringValueCStr(obj2));
|
1110
|
+
// fd = NUM2INT(rb_funcall(val,rb_intern("fileno"),0));
|
1111
|
+
// }else if(rb_obj_is_kind_of(val,rb_cIO)){
|
1112
|
+
// fd = NUM2INT(rb_funcall(val,rb_intern("fileno"),0));
|
1113
|
+
// }else if(rb_respond_to(val,rb_intern("read"))){
|
1114
|
+
// //stringio has neigther path or fileno, so do nothing
|
1115
|
+
// }else {
|
1116
|
+
// VALUE obj2 = rb_file_s_expand_path(1,&val);
|
1117
|
+
// archive_entry_copy_sourcepath(entry, StringValueCStr(obj2));
|
1118
|
+
// fd = open(StringValueCStr(obj2), O_RDONLY);
|
1119
|
+
// if (fd < 0) //TODO: add error
|
1120
|
+
// {
|
1121
|
+
// return 0;
|
1122
|
+
// }
|
1123
|
+
// }
|
1124
|
+
// if(fd > 0)
|
1125
|
+
// archive_read_disk_entry_from_file(obj->file, entry, fd, NULL);
|
1126
|
+
// if(rb_block_given_p()){
|
1127
|
+
// VALUE temp = wrap(entry);
|
1128
|
+
// VALUE result = rb_yield(temp);
|
1129
|
+
// if(rb_obj_is_kind_of(result,rb_cArchiveEntry))
|
1130
|
+
// entry = wrap<archive_entry*>(result);
|
1131
|
+
// else
|
1132
|
+
// entry = wrap<archive_entry*>(temp);
|
1133
|
+
// }
|
1134
|
+
// for(unsigned int i = 0;i < obj->entries->size();)
|
1135
|
+
// {
|
1136
|
+
// if(std::string(archive_entry_pathname(obj->entries->at(i))).compare(archive_entry_pathname(entry)) == 0){
|
1137
|
+
// obj->entries->erase(obj->entries->begin()+i);
|
1138
|
+
// obj->allbuff->erase(obj->allbuff->begin()+i);
|
1139
|
+
// }else
|
1140
|
+
// i++;
|
1141
|
+
// }
|
1142
|
+
// std::string strbuff;
|
1143
|
+
// if(fd < 0 and rb_respond_to(val,rb_intern("read"))){
|
1144
|
+
// VALUE result = rb_funcall(val,rb_intern("read"),0);
|
1145
|
+
// strbuff.append(StringValueCStr(result), RSTRING_LEN(result));
|
1146
|
+
// }else{
|
1147
|
+
// while ((bytes_read = read(fd, buff, sizeof(buff))) > 0)
|
1148
|
+
// strbuff.append(buff, bytes_read);
|
1149
|
+
// }
|
1150
|
+
// obj->entries->push_back(entry);
|
1151
|
+
// obj->allbuff->push_back(strbuff);
|
1152
|
+
// if(fd >= 0 and !rb_obj_is_kind_of(val,rb_cIO))
|
1153
|
+
// close(fd);
|
1154
|
+
// archive_read_close(obj->file);
|
1155
|
+
// return 0;
|
1156
|
+
//}
|
1157
|
+
|
1158
|
+
//VALUE Archive_add_block(struct add_obj *obj )
|
1159
|
+
//{
|
1160
|
+
// VALUE robj = obj->obj;
|
1161
|
+
// char buff[8192];
|
1162
|
+
// size_t bytes_read;
|
1163
|
+
// archive_read_disk_set_standard_lookup(obj->file);
|
1164
|
+
// if(rb_obj_is_kind_of(robj,rb_cArray)){
|
1165
|
+
// for(int i=0;i< RARRAY_LEN(robj);i++){
|
1166
|
+
// VALUE temp = RARRAY_PTR(robj)[i];
|
1167
|
+
// int fd = -1;
|
1168
|
+
// char *sourcepath,*pathname;
|
1169
|
+
// if(rb_obj_is_kind_of(temp,rb_cFile)){
|
1170
|
+
// VALUE rpath = rb_funcall(temp,rb_intern("path"),0); //source path
|
1171
|
+
// pathname = StringValueCStr(rpath);
|
1172
|
+
// VALUE obj2 = rb_file_s_expand_path(1,&rpath);
|
1173
|
+
// sourcepath = StringValueCStr(obj2);
|
1174
|
+
// fd = NUM2INT(rb_funcall(temp,rb_intern("fileno"),0));
|
1175
|
+
// }else{
|
1176
|
+
// VALUE obj2 = rb_file_s_expand_path(1,&temp);
|
1177
|
+
// sourcepath = pathname = StringValueCStr(obj2);
|
1178
|
+
// fd = open(pathname, O_RDONLY);
|
1179
|
+
// if (fd < 0) //TODO: add error
|
1180
|
+
// return Qnil;
|
1181
|
+
// }
|
1182
|
+
// struct archive_entry *entry = archive_entry_new();
|
1183
|
+
// archive_entry_copy_sourcepath(entry, sourcepath);
|
1184
|
+
// archive_entry_copy_pathname(entry, pathname);
|
1185
|
+
// archive_read_disk_entry_from_file(obj->file, entry, fd, NULL);
|
1186
|
+
// if(rb_block_given_p()){
|
1187
|
+
// VALUE temp = wrap(entry);
|
1188
|
+
// VALUE result = rb_yield(temp);
|
1189
|
+
// if(rb_obj_is_kind_of(result,rb_cArchiveEntry))
|
1190
|
+
// entry = wrap<archive_entry*>(result);
|
1191
|
+
// else
|
1192
|
+
// entry = wrap<archive_entry*>(temp);
|
1193
|
+
// }
|
1194
|
+
// std::string strbuff;
|
1195
|
+
// while ((bytes_read = read(fd, buff, sizeof(buff))) > 0)
|
1196
|
+
// strbuff.append(buff, bytes_read);
|
1197
|
+
// if(fd >= 0 and !rb_obj_is_kind_of(robj,rb_cIO))
|
1198
|
+
// close(fd);
|
1199
|
+
// obj->entries->push_back(entry);
|
1200
|
+
// obj->allbuff->push_back(strbuff);
|
1201
|
+
// }
|
1202
|
+
// }else if(rb_obj_is_kind_of(robj,rb_cHash)){
|
1203
|
+
// archive_read_close(obj->file);
|
1204
|
+
// rb_hash_foreach(robj,(int (*)(...))Archive_add_hash_block,(VALUE)obj);
|
1205
|
+
// }else
|
1206
|
+
// {
|
1207
|
+
// if(obj->fd > 0)
|
1208
|
+
// archive_read_disk_entry_from_file(obj->file, obj->entry, obj->fd, NULL);
|
1209
|
+
|
1210
|
+
// if(rb_block_given_p()){
|
1211
|
+
// VALUE temp = wrap(obj->entry);
|
1212
|
+
// VALUE result = rb_yield(temp);
|
1213
|
+
// if(rb_obj_is_kind_of(result,rb_cArchiveEntry))
|
1214
|
+
// obj->entry = wrap<archive_entry*>(result);
|
1215
|
+
// else
|
1216
|
+
// obj->entry = wrap<archive_entry*>(temp);
|
1217
|
+
// }
|
1218
|
+
// for(unsigned int i = 0;i < obj->entries->size();)
|
1219
|
+
// {
|
1220
|
+
// if(std::string(archive_entry_pathname(obj->entries->at(i))).compare(archive_entry_pathname(obj->entry)) == 0){
|
1221
|
+
// obj->entries->erase(obj->entries->begin()+i);
|
1222
|
+
// obj->allbuff->erase(obj->allbuff->begin()+i);
|
1223
|
+
// }else
|
1224
|
+
// i++;
|
1225
|
+
// }
|
1226
|
+
// std::string strbuff;
|
1227
|
+
// if(obj->fd < 0 and rb_respond_to(robj,rb_intern("read"))){
|
1228
|
+
// VALUE result = rb_funcall(robj,rb_intern("read"),0);
|
1229
|
+
// strbuff.append(StringValueCStr(result), RSTRING_LEN(result));
|
1230
|
+
// }else{
|
1231
|
+
// while ((bytes_read = read(obj->fd, buff, sizeof(buff))) > 0)
|
1232
|
+
// strbuff.append(buff, bytes_read);
|
1233
|
+
// }
|
1234
|
+
// obj->entries->push_back(obj->entry);
|
1235
|
+
// obj->allbuff->push_back(strbuff);
|
1236
|
+
// }
|
1237
|
+
// return Qnil;
|
1238
|
+
//}
|
1239
|
+
|
1240
|
+
VALUE Archive_add_block(struct add_obj *obj )
|
1241
|
+
{
|
1242
|
+
RubyArchive::read_data_from_path2(obj->obj,Qnil,*obj->data);
|
1243
|
+
return Qnil;
|
1244
|
+
}
|
1245
|
+
|
1246
|
+
VALUE Archive_add_block_ensure(struct add_obj *obj )
|
1247
|
+
{
|
1248
|
+
// if(!rb_obj_is_kind_of(obj->obj,rb_cHash))
|
1249
|
+
// archive_read_close(obj->file);
|
1250
|
+
|
1251
|
+
size_t size = obj->data->size();
|
1252
|
+
for(unsigned int i=0; i<size; i++){
|
1253
|
+
archive_write_header(obj->archive,obj->data->at(i).first);
|
1254
|
+
archive_write_data(obj->archive,&obj->data->at(i).second[0],obj->data->at(i).second.length());
|
1255
|
+
archive_write_finish_entry(obj->archive);
|
1256
|
+
}
|
1257
|
+
archive_write_close(obj->archive);
|
1258
|
+
return Qnil;
|
1259
|
+
}
|
1260
|
+
|
1261
|
+
/*
|
1262
|
+
* call-seq:
|
1263
|
+
* add( obj [, path] ) → self
|
1264
|
+
* add( obj [, path] ) {|entry| } → self
|
1265
|
+
* add( [obj, ... ] ) → self
|
1266
|
+
* add( [obj, ... ] ) {|entry| } → self
|
1267
|
+
* add( { path => obj} ) → self
|
1268
|
+
* add( { path => obj} ) {|entry| } → self
|
1269
|
+
*
|
1270
|
+
* Adds a file to an archive.
|
1271
|
+
* ===Parameters
|
1272
|
+
* [obj] String, IO, File or an object which responds to +read+.
|
1273
|
+
* [path] Sets the file name inside the archive.
|
1274
|
+
* ===Return value
|
1275
|
+
* self
|
1276
|
+
* ===Raises
|
1277
|
+
* [FormatError] Raised if the archive format is not supported for writing.
|
1278
|
+
*/
|
1279
|
+
|
1280
|
+
VALUE Archive_add(int argc, VALUE *argv, VALUE self)//(VALUE self,VALUE obj,VALUE name)
|
1281
|
+
{
|
1282
|
+
VALUE obj,name;
|
1283
|
+
rb_scan_args(argc, argv, "11", &obj,&name);
|
1284
|
+
if(NIL_P(name)){
|
1285
|
+
if(rb_obj_is_kind_of(obj,rb_cFile))
|
1286
|
+
name = rb_funcall(name,rb_intern("path"),0);
|
1287
|
+
else if(rb_obj_is_kind_of(obj,rb_cIO))
|
1288
|
+
rb_scan_args(argc, argv, "20", &obj,&name);
|
1289
|
+
else if(rb_respond_to(obj,rb_intern("read")))
|
1290
|
+
rb_scan_args(argc, argv, "20", &obj,&name);
|
1291
|
+
else if(rb_obj_is_kind_of(obj,rb_cArray) or rb_obj_is_kind_of(obj,rb_cHash))
|
1292
|
+
rb_scan_args(argc, argv, "10", &obj);
|
1293
|
+
else
|
1294
|
+
name = obj;
|
1295
|
+
}
|
1296
|
+
|
1297
|
+
struct archive *a = archive_read_new(),*b=archive_write_new();
|
1298
|
+
|
1299
|
+
DataVector entries;
|
1300
|
+
IntVector filters;
|
1301
|
+
|
1302
|
+
|
1303
|
+
int format= ARCHIVE_FORMAT_EMPTY;
|
1304
|
+
|
1305
|
+
|
1306
|
+
//autodetect format and compression
|
1307
|
+
if(Archive_read_ruby(self,a)==ARCHIVE_OK){
|
1308
|
+
RubyArchive::read_old_data(a, entries, format, filters);
|
1309
|
+
}
|
1310
|
+
|
1311
|
+
// if(rb_obj_is_kind_of(obj,rb_cFile)){
|
1312
|
+
// VALUE pathname = rb_funcall(obj,rb_intern("path"),0); //source path
|
1313
|
+
// VALUE obj2 = rb_file_s_expand_path(1,&pathname);
|
1314
|
+
// path = StringValueCStr(obj2);
|
1315
|
+
// fd = NUM2INT(rb_funcall(obj,rb_intern("fileno"),0));
|
1316
|
+
// }else if(rb_obj_is_kind_of(obj,rb_cIO)){
|
1317
|
+
// fd = NUM2INT(rb_funcall(obj,rb_intern("fileno"),0));
|
1318
|
+
// }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)){
|
1319
|
+
// //stringio has neigther path or fileno, so do nothing
|
1320
|
+
// }else {
|
1321
|
+
// if(RTEST(rb_funcall(rb_cFile,rb_intern("directory?"),1,obj)))
|
1322
|
+
// obj = rb_funcall(rb_cDir,rb_intern("glob"),1,rb_str_new2("**/**/*"));
|
1323
|
+
// else{
|
1324
|
+
// VALUE obj2 = rb_file_s_expand_path(1,&obj);
|
1325
|
+
// path = StringValueCStr(obj2);
|
1326
|
+
// fd = open(path, O_RDONLY);
|
1327
|
+
// if (fd < 0) //TODO: add error
|
1328
|
+
// return self;
|
1329
|
+
// }
|
1330
|
+
// }
|
1331
|
+
// Archive_format_from_path(self,format,compression);
|
1332
|
+
|
1333
|
+
if(format == ARCHIVE_FORMAT_EMPTY){
|
1334
|
+
Archive_format_from_path(self,format,filters);
|
1335
|
+
}
|
1336
|
+
|
1337
|
+
if(Archive_write_ruby(self,b,format,filters)==ARCHIVE_OK){
|
1338
|
+
|
1339
|
+
add_obj temp;
|
1340
|
+
temp.archive = b;
|
1341
|
+
temp.obj = obj;
|
1342
|
+
//temp.path = path;
|
1343
|
+
temp.name = name;
|
1344
|
+
temp.data = &entries;
|
1345
|
+
RB_ENSURE(Archive_add_block,&temp,Archive_add_block_ensure,&temp);
|
1346
|
+
}
|
1347
|
+
|
1348
|
+
return self;
|
1349
|
+
}
|
1350
|
+
|
1351
|
+
/*
|
1352
|
+
* call-seq:
|
1353
|
+
* << obj → self
|
1354
|
+
*
|
1355
|
+
* Adds a file to an archive. Basicly the same as #add, but you can't
|
1356
|
+
* set the path inside the archive.
|
1357
|
+
* ===Parameters
|
1358
|
+
* [obj] String or File
|
1359
|
+
* ===Return value
|
1360
|
+
* self
|
1361
|
+
* ===Raises
|
1362
|
+
* [FormatError] The archive format is not supported for writing.
|
1363
|
+
*/
|
1364
|
+
VALUE Archive_add_shift(VALUE self,VALUE name)
|
1365
|
+
{
|
1366
|
+
return Archive_add(1,&name,self);
|
1367
|
+
}
|
1368
|
+
|
1369
|
+
/*
|
1370
|
+
* call-seq:
|
1371
|
+
* delete( name ) → an_array
|
1372
|
+
*
|
1373
|
+
* Delete files from an archive.
|
1374
|
+
* ===Parameters
|
1375
|
+
* [name] An Archive::Entry, a String or a Regex.
|
1376
|
+
* ===Return value
|
1377
|
+
* A list of paths removed from the archive.
|
1378
|
+
* ===Raises
|
1379
|
+
* raise TypeError if the parameter is neigther String or File.
|
1380
|
+
* raise Error if the format has no write support
|
1381
|
+
*/
|
1382
|
+
|
1383
|
+
VALUE Archive_delete(VALUE self,VALUE val)
|
1384
|
+
{
|
1385
|
+
struct archive *a = archive_read_new(),*b=archive_write_new();
|
1386
|
+
int format = ARCHIVE_FORMAT_EMPTY;
|
1387
|
+
|
1388
|
+
DataVector entries;
|
1389
|
+
IntVector filters;
|
1390
|
+
|
1391
|
+
VALUE result = rb_ary_new();
|
1392
|
+
|
1393
|
+
//autodetect format and compression
|
1394
|
+
if(Archive_read_ruby(self,a)==ARCHIVE_OK){
|
1395
|
+
RubyArchive::read_old_data(a, entries, format, filters);
|
1396
|
+
|
1397
|
+
for(unsigned int i=0; i<entries.size();){
|
1398
|
+
if(RubyArchive::match_entry(entries[i].first,val)){
|
1399
|
+
rb_ary_push(result,rb_str_new2(archive_entry_pathname(entries[i].first)));
|
1400
|
+
entries.erase(entries.begin() + i);
|
1401
|
+
}else
|
1402
|
+
++i;
|
1403
|
+
}
|
1404
|
+
|
1405
|
+
if(Archive_write_ruby(self,b,format,filters)==ARCHIVE_OK){
|
1406
|
+
//write old data back
|
1407
|
+
for(unsigned int i=0; i<entries.size(); i++){
|
1408
|
+
archive_write_header(b,entries[i].first);
|
1409
|
+
archive_write_data(b,&entries[i].second[0],entries[i].second.length());
|
1410
|
+
archive_write_finish_entry(b);
|
1411
|
+
}
|
1412
|
+
archive_write_close(b);
|
1413
|
+
}
|
1414
|
+
|
1415
|
+
}
|
1416
|
+
return result;
|
1417
|
+
}
|
1418
|
+
|
1419
|
+
VALUE Archive_delete_if_block(struct write_obj * data)
|
1420
|
+
{
|
1421
|
+
VALUE result= rb_ary_new();
|
1422
|
+
for(unsigned int i=0; i< data->data->size(); i++){
|
1423
|
+
if(!RTEST(rb_yield(wrap(data->data->at(i).first)))){
|
1424
|
+
archive_write_header(data->archive,data->data->at(i).first);
|
1425
|
+
archive_write_data(data->archive,&data->data->at(i).second[0],data->data->at(i).second.length());
|
1426
|
+
archive_write_finish_entry(data->archive);
|
1427
|
+
}else
|
1428
|
+
rb_ary_push(result,wrap(data->data->at(i).first));
|
1429
|
+
}
|
1430
|
+
return result;
|
1431
|
+
}
|
1432
|
+
|
1433
|
+
/*
|
1434
|
+
* call-seq:
|
1435
|
+
* archive.delete_if {|entry| } -> self
|
1436
|
+
* archive.delete_if -> Enumerator
|
1437
|
+
*
|
1438
|
+
* Yields each entry in the archive to the block and deletes those for which
|
1439
|
+
* the block evaluates to a truth value.
|
1440
|
+
* ===Parameters
|
1441
|
+
* [name] An Archive::Entry, a String or a Regex.
|
1442
|
+
* ===Return value
|
1443
|
+
* If a block was given, returns self, otherwise an Enumerator.
|
1444
|
+
* ===Raises
|
1445
|
+
* raise Error if the format has no write support
|
1446
|
+
*/
|
1447
|
+
|
1448
|
+
VALUE Archive_delete_if(VALUE self)
|
1449
|
+
{
|
1450
|
+
RETURN_ENUMERATOR(self,0,NULL);
|
1451
|
+
|
1452
|
+
struct archive *a = archive_read_new(),*b=archive_write_new();
|
1453
|
+
int format = ARCHIVE_FORMAT_EMPTY;
|
1454
|
+
|
1455
|
+
DataVector entries;
|
1456
|
+
IntVector filters;
|
1457
|
+
|
1458
|
+
if(Archive_read_ruby(self,a)==ARCHIVE_OK){
|
1459
|
+
RubyArchive::read_old_data(a, entries, format, filters);
|
1460
|
+
|
1461
|
+
if(Archive_write_ruby(self,b,format,filters)==ARCHIVE_OK){
|
1462
|
+
write_obj obj;
|
1463
|
+
obj.archive = b;
|
1464
|
+
obj.data = &entries;
|
1465
|
+
return RB_ENSURE(Archive_delete_if_block,&obj,Archive_write_block_ensure,b);
|
1466
|
+
}
|
1467
|
+
}
|
1468
|
+
return Qnil;
|
1469
|
+
}
|
1470
|
+
|
1471
|
+
/*
|
1472
|
+
* call-seq:
|
1473
|
+
* archive.clear -> self
|
1474
|
+
*
|
1475
|
+
* Deletes all files from an archive.
|
1476
|
+
* ===Return value
|
1477
|
+
* returns self.
|
1478
|
+
* ===Raises
|
1479
|
+
* raise Error if the format has no write support
|
1480
|
+
*/
|
1481
|
+
|
1482
|
+
VALUE Archive_clear(VALUE self)
|
1483
|
+
{
|
1484
|
+
|
1485
|
+
struct archive *a = archive_read_new(),*b=archive_write_new();
|
1486
|
+
struct archive_entry *entry;
|
1487
|
+
int format = ARCHIVE_FORMAT_EMPTY;
|
1488
|
+
|
1489
|
+
if(Archive_read_ruby(self,a)==ARCHIVE_OK){
|
1490
|
+
archive_read_next_header(a, &entry);
|
1491
|
+
format = archive_format(a);
|
1492
|
+
IntVector filters;
|
1493
|
+
RubyArchive::read_get_filters(a,filters);
|
1494
|
+
archive_read_close(a);
|
1495
|
+
|
1496
|
+
if(Archive_write_ruby(self,b,format,filters)==ARCHIVE_OK)
|
1497
|
+
archive_write_close(b);
|
1498
|
+
}
|
1499
|
+
|
1500
|
+
return self;
|
1501
|
+
}
|
1502
|
+
|
1503
|
+
/*:nodoc:
|
1504
|
+
* call-seq:
|
1505
|
+
* archive.exist? -> true or false
|
1506
|
+
*
|
1507
|
+
* Same as
|
1508
|
+
* File.exist?(archive.path)
|
1509
|
+
* . Checks wheather or not the archive file is existant.
|
1510
|
+
* ===Return value
|
1511
|
+
* True or false.
|
1512
|
+
*/
|
1513
|
+
|
1514
|
+
VALUE Archive_exist(VALUE self)
|
1515
|
+
{
|
1516
|
+
return rb_funcall(rb_cFile,rb_intern("exist?"),1,Archive_path(self));
|
1517
|
+
}
|
1518
|
+
|
1519
|
+
/*:nodoc:
|
1520
|
+
* call-seq:
|
1521
|
+
* archive.unlink -> self
|
1522
|
+
*
|
1523
|
+
* call the File.unlink(path)
|
1524
|
+
*/
|
1525
|
+
|
1526
|
+
VALUE Archive_unlink(VALUE self)
|
1527
|
+
{
|
1528
|
+
return rb_funcall(rb_cFile,rb_intern("unlink"),1,Archive_path(self));
|
1529
|
+
return self;
|
1530
|
+
}
|
1531
|
+
|
1532
|
+
/*:nodoc:
|
1533
|
+
* call-seq:
|
1534
|
+
* archive.mtime -> Time
|
1535
|
+
*
|
1536
|
+
* call the File.mtime(path)
|
1537
|
+
*/
|
1538
|
+
|
1539
|
+
VALUE Archive_mtime(VALUE self)
|
1540
|
+
{
|
1541
|
+
return rb_funcall(rb_cFile,rb_intern("mtime"),1,Archive_path(self));
|
1542
|
+
}
|
1543
|
+
|
1544
|
+
/*:nodoc:
|
1545
|
+
* call-seq:
|
1546
|
+
* archive.atime -> Time
|
1547
|
+
*
|
1548
|
+
* call the File.atime(path)
|
1549
|
+
*/
|
1550
|
+
|
1551
|
+
VALUE Archive_atime(VALUE self)
|
1552
|
+
{
|
1553
|
+
return rb_funcall(rb_cFile,rb_intern("atime"),1,Archive_path(self));
|
1554
|
+
}
|
1555
|
+
|
1556
|
+
/*:nodoc:
|
1557
|
+
* call-seq:
|
1558
|
+
* archive.ctime -> Time
|
1559
|
+
*
|
1560
|
+
* call the File.ctime(path)
|
1561
|
+
*/
|
1562
|
+
|
1563
|
+
|
1564
|
+
VALUE Archive_ctime(VALUE self)
|
1565
|
+
{
|
1566
|
+
return rb_funcall(rb_cFile,rb_intern("ctime"),1,Archive_path(self));
|
1567
|
+
}
|
1568
|
+
|
1569
|
+
/*:nodoc:
|
1570
|
+
* call-seq:
|
1571
|
+
* archive.stat -> File::Stat
|
1572
|
+
*
|
1573
|
+
* call the File.stat(path)
|
1574
|
+
*/
|
1575
|
+
|
1576
|
+
VALUE Archive_stat(VALUE self)
|
1577
|
+
{
|
1578
|
+
return rb_funcall(rb_cFile,rb_intern("stat"),1,Archive_path(self));
|
1579
|
+
}
|
1580
|
+
|
1581
|
+
/*
|
1582
|
+
* call-seq:
|
1583
|
+
* archive.inspect -> String
|
1584
|
+
*
|
1585
|
+
* Human-readable description.
|
1586
|
+
* ===Return value
|
1587
|
+
* String
|
1588
|
+
*/
|
1589
|
+
|
1590
|
+
VALUE Archive_inspect(VALUE self)
|
1591
|
+
{
|
1592
|
+
VALUE array[3];
|
1593
|
+
switch(_self->type){
|
1594
|
+
case archive_path:
|
1595
|
+
array[0]=rb_str_new2("#<%s:%s>");
|
1596
|
+
array[1]=rb_class_of(self);
|
1597
|
+
array[2]=Archive_path(self);
|
1598
|
+
break;
|
1599
|
+
case archive_fd:
|
1600
|
+
array[0]=rb_str_new2("#<%s:%d>");
|
1601
|
+
array[1]=rb_class_of(self);
|
1602
|
+
array[2]=INT2NUM(_self->fd);
|
1603
|
+
break;
|
1604
|
+
case archive_buffer:
|
1605
|
+
break;
|
1606
|
+
case archive_ruby:
|
1607
|
+
array[0]=rb_str_new2("#<%s:%s>");
|
1608
|
+
array[1]=rb_class_of(self);
|
1609
|
+
array[2]=_self->ruby;
|
1610
|
+
break;
|
1611
|
+
}
|
1612
|
+
return rb_f_sprintf(3,array);
|
1613
|
+
}
|
1614
|
+
|
1615
|
+
/*
|
1616
|
+
* Document-class: Archive::Error
|
1617
|
+
* This is the superclass of all errors specific to this library.
|
1618
|
+
*/
|
1619
|
+
|
1620
|
+
/*
|
1621
|
+
* Document-class: Archive::Error::Compression
|
1622
|
+
* This exception is thrown if you try to use an unknown compression format.
|
1623
|
+
*/
|
1624
|
+
|
1625
|
+
/*
|
1626
|
+
* Document-class: Archive::Error::Format
|
1627
|
+
* This exception is thrown if you try to use an unknown archive format or libarchive doesn't
|
1628
|
+
* have write support for the format you wanted to write.
|
1629
|
+
*/
|
1630
|
+
|
1631
|
+
/*
|
1632
|
+
* Document-class: Archive
|
1633
|
+
*
|
1634
|
+
* This class represents an archive file. The file may or may not exist,
|
1635
|
+
* depending on wheather you want to create a new archive or read from
|
1636
|
+
* an existing one. When instanciating this class, libarchive-ruby will
|
1637
|
+
* automatically detect the correct file format for you using libarchive's
|
1638
|
+
* own detection mechanism if the archive file is already present, otherwise
|
1639
|
+
* by looking at the archive file's file extension.
|
1640
|
+
*/
|
1641
|
+
/*
|
1642
|
+
* Document-const: EXTRACT_TIME
|
1643
|
+
*
|
1644
|
+
* extract the atime and mtime
|
1645
|
+
*/
|
1646
|
+
/*
|
1647
|
+
* Document-const: EXTRACT_PERM
|
1648
|
+
*
|
1649
|
+
* extract the permission
|
1650
|
+
*/
|
1651
|
+
/*
|
1652
|
+
* Document-const: EXTRACT_OWNER
|
1653
|
+
*
|
1654
|
+
* extract the owner
|
1655
|
+
*/
|
1656
|
+
|
1657
|
+
/*
|
1658
|
+
* Document-const: EXTRACT_ACL
|
1659
|
+
*
|
1660
|
+
* extract the access control list
|
1661
|
+
*/
|
1662
|
+
/*
|
1663
|
+
* Document-const: EXTRACT_FFLAGS
|
1664
|
+
*
|
1665
|
+
* extract the fflags
|
1666
|
+
*/
|
1667
|
+
/*
|
1668
|
+
* Document-const: EXTRACT_XATTR
|
1669
|
+
*
|
1670
|
+
* extract the extended information
|
1671
|
+
*/
|
1672
|
+
extern "C" void Init_archive(void){
|
1673
|
+
rb_cArchive = rb_define_class("Archive",rb_cObject);
|
1674
|
+
rb_define_alloc_func(rb_cArchive,Archive_alloc);
|
1675
|
+
rb_define_method(rb_cArchive,"initialize",RUBY_METHOD_FUNC(Archive_initialize),-1);
|
1676
|
+
rb_define_private_method(rb_cArchive,"initialize_copy",RUBY_METHOD_FUNC(Archive_initialize_copy),1);
|
1677
|
+
rb_define_method(rb_cArchive,"path",RUBY_METHOD_FUNC(Archive_path),0);
|
1678
|
+
|
1679
|
+
rb_define_method(rb_cArchive,"each",RUBY_METHOD_FUNC(Archive_each),0);
|
1680
|
+
rb_define_method(rb_cArchive,"each_entry",RUBY_METHOD_FUNC(Archive_each_entry),0);
|
1681
|
+
rb_define_method(rb_cArchive,"each_data",RUBY_METHOD_FUNC(Archive_each_data),0);
|
1682
|
+
|
1683
|
+
rb_define_method(rb_cArchive,"each_filter",RUBY_METHOD_FUNC(Archive_each_filter),0);
|
1684
|
+
|
1685
|
+
rb_define_method(rb_cArchive,"map!",RUBY_METHOD_FUNC(Archive_map_self),0);
|
1686
|
+
rb_define_alias(rb_cArchive,"collect!","map!");
|
1687
|
+
rb_define_method(rb_cArchive,"[]",RUBY_METHOD_FUNC(Archive_get),1);
|
1688
|
+
|
1689
|
+
rb_define_method(rb_cArchive,"to_hash",RUBY_METHOD_FUNC(Archive_to_hash),0);
|
1690
|
+
|
1691
|
+
rb_define_method(rb_cArchive,"extract",RUBY_METHOD_FUNC(Archive_extract),-1);
|
1692
|
+
rb_define_method(rb_cArchive,"extract_if",RUBY_METHOD_FUNC(Archive_extract_if),-1);
|
1693
|
+
|
1694
|
+
rb_define_method(rb_cArchive,"delete",RUBY_METHOD_FUNC(Archive_delete),1);
|
1695
|
+
rb_define_method(rb_cArchive,"delete_if",RUBY_METHOD_FUNC(Archive_delete_if),0);
|
1696
|
+
rb_define_method(rb_cArchive,"clear",RUBY_METHOD_FUNC(Archive_clear),0);
|
1697
|
+
|
1698
|
+
//rb_define_method(rb_cArchive,"move_to",RUBY_METHOD_FUNC(Archive_move_to),1);
|
1699
|
+
|
1700
|
+
rb_define_method(rb_cArchive,"add",RUBY_METHOD_FUNC(Archive_add),-1);
|
1701
|
+
rb_define_method(rb_cArchive,"<<",RUBY_METHOD_FUNC(Archive_add_shift),1);
|
1702
|
+
|
1703
|
+
rb_define_method(rb_cArchive,"inspect",RUBY_METHOD_FUNC(Archive_inspect),0);
|
1704
|
+
|
1705
|
+
rb_define_method(rb_cArchive,"format",RUBY_METHOD_FUNC(Archive_format),0);
|
1706
|
+
//rb_define_method(rb_cArchive,"compression",RUBY_METHOD_FUNC(Archive_compression),0);
|
1707
|
+
rb_define_method(rb_cArchive,"format_name",RUBY_METHOD_FUNC(Archive_format_name),0);
|
1708
|
+
//rb_define_method(rb_cArchive,"compression_name",RUBY_METHOD_FUNC(Archive_compression_name),0);
|
1709
|
+
|
1710
|
+
rb_define_method(rb_cArchive,"unlink",RUBY_METHOD_FUNC(Archive_unlink),0);
|
1711
|
+
rb_define_method(rb_cArchive,"exist?",RUBY_METHOD_FUNC(Archive_exist),0);
|
1712
|
+
rb_define_method(rb_cArchive,"mtime",RUBY_METHOD_FUNC(Archive_mtime),0);
|
1713
|
+
rb_define_method(rb_cArchive,"atime",RUBY_METHOD_FUNC(Archive_atime),0);
|
1714
|
+
rb_define_method(rb_cArchive,"ctime",RUBY_METHOD_FUNC(Archive_ctime),0);
|
1715
|
+
rb_define_method(rb_cArchive,"stat",RUBY_METHOD_FUNC(Archive_stat),0);
|
1716
|
+
|
1717
|
+
rb_include_module(rb_cArchive,rb_mEnumerable);
|
1718
|
+
//rb_define_method(rb_cArchive,"size",RUBY_METHOD_FUNC(Archive_size),0);
|
1719
|
+
|
1720
|
+
Init_archive_entry(rb_cArchive);
|
1721
|
+
|
1722
|
+
rb_define_const(rb_cArchive,"EXTRACT_OWNER",INT2NUM(ARCHIVE_EXTRACT_OWNER));
|
1723
|
+
rb_define_const(rb_cArchive,"EXTRACT_PERM",INT2NUM(ARCHIVE_EXTRACT_PERM));
|
1724
|
+
rb_define_const(rb_cArchive,"EXTRACT_TIME",INT2NUM(ARCHIVE_EXTRACT_TIME));
|
1725
|
+
rb_define_const(rb_cArchive,"EXTRACT_NO_OVERWRITE",INT2NUM(ARCHIVE_EXTRACT_NO_OVERWRITE));
|
1726
|
+
rb_define_const(rb_cArchive,"EXTRACT_UNLINK",INT2NUM(ARCHIVE_EXTRACT_UNLINK));
|
1727
|
+
rb_define_const(rb_cArchive,"EXTRACT_ACL",INT2NUM(ARCHIVE_EXTRACT_ACL));
|
1728
|
+
rb_define_const(rb_cArchive,"EXTRACT_FFLAGS",INT2NUM(ARCHIVE_EXTRACT_FFLAGS));
|
1729
|
+
rb_define_const(rb_cArchive,"EXTRACT_XATTR",INT2NUM(ARCHIVE_EXTRACT_XATTR));
|
1730
|
+
rb_define_const(rb_cArchive,"EXTRACT_SECURE_SYMLINKS",INT2NUM(ARCHIVE_EXTRACT_SECURE_SYMLINKS));
|
1731
|
+
rb_define_const(rb_cArchive,"EXTRACT_SECURE_NODOTDOT",INT2NUM(ARCHIVE_EXTRACT_SECURE_NODOTDOT));
|
1732
|
+
rb_define_const(rb_cArchive,"EXTRACT_NO_AUTODIR",INT2NUM(ARCHIVE_EXTRACT_NO_AUTODIR));
|
1733
|
+
rb_define_const(rb_cArchive,"EXTRACT_NO_OVERWRITE_NEWER",INT2NUM(ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER));
|
1734
|
+
rb_define_const(rb_cArchive,"EXTRACT_SPARSE",INT2NUM(ARCHIVE_EXTRACT_SPARSE));
|
1735
|
+
rb_define_const(rb_cArchive,"EXTRACT_MAC_METADATA",INT2NUM(ARCHIVE_EXTRACT_MAC_METADATA));
|
1736
|
+
|
1737
|
+
|
1738
|
+
rb_eArchiveError = rb_define_class_under(rb_cArchive,"Error",rb_eStandardError);
|
1739
|
+
rb_eArchiveErrorFormat = rb_define_class_under(rb_eArchiveError,"Format",rb_eArchiveError);
|
1740
|
+
rb_eArchiveErrorCompression = rb_define_class_under(rb_eArchiveError,"Compression",rb_eArchiveError);
|
1741
|
+
|
1742
|
+
|
1743
|
+
SymToFormat[rb_intern("tar")]=ARCHIVE_FORMAT_TAR_GNUTAR;
|
1744
|
+
SymToFormat[rb_intern("pax")]=ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE;
|
1745
|
+
SymToFormat[rb_intern("zip")]=ARCHIVE_FORMAT_ZIP;
|
1746
|
+
SymToFormat[rb_intern("ar")]=ARCHIVE_FORMAT_AR_GNU;
|
1747
|
+
SymToFormat[rb_intern("xar")]=ARCHIVE_FORMAT_XAR;
|
1748
|
+
SymToFormat[rb_intern("lha")]=ARCHIVE_FORMAT_LHA;
|
1749
|
+
SymToFormat[rb_intern("cab")]=ARCHIVE_FORMAT_CAB;
|
1750
|
+
SymToFormat[rb_intern("rar")]=ARCHIVE_FORMAT_RAR;
|
1751
|
+
SymToFormat[rb_intern("7zip")]=ARCHIVE_FORMAT_7ZIP;
|
1752
|
+
|
1753
|
+
|
1754
|
+
SymToFilter[rb_intern("gzip")]=ARCHIVE_FILTER_GZIP;
|
1755
|
+
SymToFilter[rb_intern("bzip2")]=ARCHIVE_FILTER_BZIP2;
|
1756
|
+
SymToFilter[rb_intern("compress")]=ARCHIVE_FILTER_BZIP2;
|
1757
|
+
SymToFilter[rb_intern("lzma")]=ARCHIVE_FILTER_LZMA;
|
1758
|
+
SymToFilter[rb_intern("xz")]=ARCHIVE_FILTER_XZ;
|
1759
|
+
SymToFilter[rb_intern("uu")]=ARCHIVE_FILTER_UU;
|
1760
|
+
SymToFilter[rb_intern("rpm")]=ARCHIVE_FILTER_RPM;
|
1761
|
+
SymToFilter[rb_intern("lzip")]=ARCHIVE_FILTER_LZIP;
|
1762
|
+
|
1763
|
+
#ifdef ARCHIVE_FILTER_LZOP
|
1764
|
+
SymToFilter[rb_intern("lzop")]=ARCHIVE_FILTER_LZOP;
|
1765
|
+
#endif
|
1766
|
+
#ifdef ARCHIVE_FILTER_GRZIP
|
1767
|
+
SymToFilter[rb_intern("grzip")]=ARCHIVE_FILTER_GRZIP;
|
1768
|
+
#endif
|
1769
|
+
|
1770
|
+
|
1771
|
+
FileExtType::mapped_type pair;
|
1772
|
+
|
1773
|
+
pair = std::make_pair(ARCHIVE_FORMAT_TAR,ARCHIVE_FILTER_GZIP);
|
1774
|
+
fileExt[".tar.gz"]=pair;
|
1775
|
+
fileExt[".tgz"]=pair;
|
1776
|
+
|
1777
|
+
pair = std::make_pair(ARCHIVE_FORMAT_TAR,ARCHIVE_FILTER_BZIP2);
|
1778
|
+
fileExt[".tar.bz2"]=pair;
|
1779
|
+
fileExt[".tbz"]=pair;
|
1780
|
+
fileExt[".tb2"]=pair;
|
1781
|
+
|
1782
|
+
pair = std::make_pair(ARCHIVE_FORMAT_TAR,ARCHIVE_FILTER_XZ);
|
1783
|
+
fileExt[".tar.xz"]=pair;
|
1784
|
+
fileExt[".txz"]=pair;
|
1785
|
+
|
1786
|
+
fileExt[".tar.lzma"]=std::make_pair(ARCHIVE_FORMAT_TAR,ARCHIVE_FILTER_LZMA);
|
1787
|
+
|
1788
|
+
fileExt[".tar"]=std::make_pair(ARCHIVE_FORMAT_TAR,ARCHIVE_FILTER_NONE);
|
1789
|
+
|
1790
|
+
|
1791
|
+
DataVector data;
|
1792
|
+
// //RubyArchive::read_data_from_path2(rb_reg_new(".",8,0),Qnil,data);
|
1793
|
+
RubyArchive::read_data_from_path2(rb_str_new2("*/*.cpp"),Qnil,data);
|
1794
|
+
rb_warn("%lu",data.size());
|
1795
|
+
////
|
1796
|
+
for(size_t i = 0; i < data.size(); ++i)
|
1797
|
+
{
|
1798
|
+
rb_warn("%s",archive_entry_pathname(data[i].first));
|
1799
|
+
rb_warn("%lu",data[i].second.size());
|
1800
|
+
}
|
1801
|
+
}
|