async-ruby-zip 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +31 -0
- data/README.md +30 -0
- data/async-ruby-zip.gemspec +77 -0
- data/ext/LICENSE +20 -0
- data/ext/archive.c +106 -0
- data/ext/archive.h +8 -0
- data/ext/archive_data.c +61 -0
- data/ext/archive_data.h +25 -0
- data/ext/archive_data_fwd.h +6 -0
- data/ext/async_zip.c +18 -0
- data/ext/async_zip.h +8 -0
- data/ext/callback.c +121 -0
- data/ext/callback.h +9 -0
- data/ext/carchive.c +219 -0
- data/ext/carchive.h +10 -0
- data/ext/carray.c +80 -0
- data/ext/carray.h +28 -0
- data/ext/cerror.c +74 -0
- data/ext/cerror.h +35 -0
- data/ext/cfilesystem.c +107 -0
- data/ext/cfilesystem.h +11 -0
- data/ext/extconf.rb +10 -0
- data/ext/task.c +62 -0
- data/ext/task.h +13 -0
- data/ext/writer.c +96 -0
- data/ext/writer.h +7 -0
- data/lib/async_zip.rb +5 -0
- data/lib/async_zip/version.rb +3 -0
- metadata +140 -0
data/ext/cfilesystem.c
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
#include "cfilesystem.h"
|
2
|
+
#include <stdio.h>
|
3
|
+
#include <stdlib.h>
|
4
|
+
#include <string.h>
|
5
|
+
#include <unistd.h>
|
6
|
+
#include <sys/stat.h>
|
7
|
+
#include <sys/types.h>
|
8
|
+
|
9
|
+
|
10
|
+
// Recursive directory creation
|
11
|
+
static void _mkdir(const char *dir, mode_t mode) {
|
12
|
+
|
13
|
+
char tmp[512];
|
14
|
+
char *p = NULL;
|
15
|
+
size_t len;
|
16
|
+
|
17
|
+
snprintf(tmp, sizeof(tmp),"%s",dir);
|
18
|
+
len = strlen(tmp);
|
19
|
+
if(tmp[len - 1] == '/')
|
20
|
+
tmp[len - 1] = 0;
|
21
|
+
for(p = tmp + 1; *p; p++)
|
22
|
+
if(*p == '/') {
|
23
|
+
*p = 0;
|
24
|
+
mkdir(tmp, mode);
|
25
|
+
*p = '/';
|
26
|
+
}
|
27
|
+
mkdir(tmp, S_IRWXU);
|
28
|
+
}
|
29
|
+
|
30
|
+
|
31
|
+
// Remove file or directory
|
32
|
+
void cfilesystem_remove(const char* filepath)
|
33
|
+
{
|
34
|
+
remove(filepath);
|
35
|
+
}
|
36
|
+
|
37
|
+
// Returns a positive value if path is found, otherwise 0
|
38
|
+
int cfilesystem_exists(const char* filepath)
|
39
|
+
{
|
40
|
+
return (access(filepath, F_OK) == 0 ? 1 : 0);
|
41
|
+
}
|
42
|
+
|
43
|
+
// Get the filename for the given file path
|
44
|
+
char* cfilesystem_filename(const char* filepath)
|
45
|
+
{
|
46
|
+
char* result = NULL;
|
47
|
+
char* last = strrchr(filepath, '/');
|
48
|
+
if(last)
|
49
|
+
{
|
50
|
+
result = strdup(last);
|
51
|
+
}
|
52
|
+
|
53
|
+
return result;
|
54
|
+
}
|
55
|
+
|
56
|
+
// Create directories
|
57
|
+
void cfilesystem_create_directories(const char* filepath)
|
58
|
+
{
|
59
|
+
_mkdir(filepath, S_IRWXU | S_IRWXG | S_IRWXO);
|
60
|
+
}
|
61
|
+
|
62
|
+
// Get a temporary filename.
|
63
|
+
char* cfilesystem_tempfilename()
|
64
|
+
{
|
65
|
+
char buffer[L_tmpnam];
|
66
|
+
tmpnam(buffer);
|
67
|
+
return strdup(buffer);
|
68
|
+
}
|
69
|
+
|
70
|
+
// Append one path to the other.
|
71
|
+
// Returns the combined path
|
72
|
+
char* cfilesystem_combine(const char* path1, const char* path2)
|
73
|
+
{
|
74
|
+
char* result = NULL;
|
75
|
+
|
76
|
+
if(!path1 && !path2) {
|
77
|
+
// no-op
|
78
|
+
}
|
79
|
+
else if(!path2 || !path2[0]) {
|
80
|
+
result = strdup(path1);
|
81
|
+
}
|
82
|
+
else if(!path1 || !path1[0]) {
|
83
|
+
result = strdup(path2);
|
84
|
+
}
|
85
|
+
else {
|
86
|
+
char* ptr;
|
87
|
+
size_t len1 = strlen(path1);
|
88
|
+
size_t len2 = strlen(path2);
|
89
|
+
|
90
|
+
size_t newlen = len1 + len2 + 1 + ((path1[len1 - 1] != '/' && path2[0] != '/') ? 1 : 0);
|
91
|
+
result = (char*)malloc(newlen);
|
92
|
+
ptr = result;
|
93
|
+
|
94
|
+
strcpy(ptr, path1);
|
95
|
+
ptr += len1;
|
96
|
+
|
97
|
+
if((ptr[-1] != '/') && (path2[0] != '/'))
|
98
|
+
{
|
99
|
+
ptr[0] = '/';
|
100
|
+
++ptr;
|
101
|
+
}
|
102
|
+
|
103
|
+
strcpy(ptr, path2);
|
104
|
+
}
|
105
|
+
|
106
|
+
return result;
|
107
|
+
}
|
data/ext/cfilesystem.h
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#ifndef EXTRA_CFILESYSTEM_H
|
2
|
+
#define EXTRA_CFILESYSTEM_H
|
3
|
+
|
4
|
+
void cfilesystem_remove(const char* filepath);
|
5
|
+
int cfilesystem_exists(const char* filepath);
|
6
|
+
char* cfilesystem_filename(const char* filepath);
|
7
|
+
void cfilesystem_create_directories(const char* filepath);
|
8
|
+
char* cfilesystem_tempfilename();
|
9
|
+
char* cfilesystem_combine(const char* path1, const char* path2);
|
10
|
+
|
11
|
+
#endif
|
data/ext/extconf.rb
ADDED
data/ext/task.c
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
#include "task.h"
|
2
|
+
#include "carray.h"
|
3
|
+
|
4
|
+
VALUE cTask;
|
5
|
+
|
6
|
+
/* Get the source parameter */
|
7
|
+
static VALUE az_task_src(VALUE self)
|
8
|
+
{
|
9
|
+
return rb_iv_get(self, "@src");
|
10
|
+
}
|
11
|
+
|
12
|
+
/* Get the destination parameter */
|
13
|
+
static VALUE az_task_dst(VALUE self)
|
14
|
+
{
|
15
|
+
return rb_iv_get(self, "@dst");
|
16
|
+
}
|
17
|
+
|
18
|
+
/* Get the error parameter */
|
19
|
+
static VALUE az_task_error(VALUE self)
|
20
|
+
{
|
21
|
+
return rb_iv_get(self, "@error");
|
22
|
+
}
|
23
|
+
|
24
|
+
/* Get the files */
|
25
|
+
static VALUE az_task_files(VALUE self)
|
26
|
+
{
|
27
|
+
return rb_iv_get(self, "@files");
|
28
|
+
}
|
29
|
+
|
30
|
+
|
31
|
+
/* Initialize the object, called before the callback is invoked */
|
32
|
+
void az_task_init(VALUE self, const char* src_path, const char* dst_path, const char* err_str, const carray_str_t* files_arr)
|
33
|
+
{
|
34
|
+
rb_iv_set(self, "@src", (src_path ? rb_str_new2(src_path) : Qnil));
|
35
|
+
rb_iv_set(self, "@dst", (dst_path ? rb_str_new2(dst_path) : Qnil));
|
36
|
+
rb_iv_set(self, "@error", (err_str ? rb_str_new2(err_str) : Qnil));
|
37
|
+
|
38
|
+
// create an array
|
39
|
+
VALUE arr = rb_ary_new();
|
40
|
+
size_t len = carray_str_size(files_arr);
|
41
|
+
if(len > 0)
|
42
|
+
{
|
43
|
+
size_t i;
|
44
|
+
for(i = 0; i != len; ++i)
|
45
|
+
{
|
46
|
+
const char* s = carray_str_get(files_arr, i);
|
47
|
+
rb_ary_push(arr, rb_str_new2(s));
|
48
|
+
}
|
49
|
+
}
|
50
|
+
rb_iv_set(self, "@files", arr);
|
51
|
+
}
|
52
|
+
|
53
|
+
|
54
|
+
void init_async_zip_task()
|
55
|
+
{
|
56
|
+
cTask = rb_define_class_under(mAsyncZip, "Task", rb_cObject);
|
57
|
+
|
58
|
+
rb_define_method(cTask, "src", az_task_src, 0);
|
59
|
+
rb_define_method(cTask, "dst", az_task_dst, 0);
|
60
|
+
rb_define_method(cTask, "error", az_task_error, 0);
|
61
|
+
rb_define_method(cTask, "files", az_task_files, 0);
|
62
|
+
}
|
data/ext/task.h
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#ifndef ASYNC_ZIP_TASK_H
|
2
|
+
#define ASYNC_ZIP_TASK_H
|
3
|
+
|
4
|
+
#include "async_zip.h"
|
5
|
+
#include "carray.h"
|
6
|
+
|
7
|
+
extern VALUE cTask;
|
8
|
+
|
9
|
+
void az_task_init(VALUE self, const char* src_path, const char* dst_path, const char* err_str, const carray_str_t* files_arr);
|
10
|
+
|
11
|
+
void init_async_zip_task();
|
12
|
+
|
13
|
+
#endif
|
data/ext/writer.c
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
#include "writer.h"
|
2
|
+
#include "archive_data.h"
|
3
|
+
#include <memory.h>
|
4
|
+
#include <stdlib.h>
|
5
|
+
#include <pthread.h>
|
6
|
+
|
7
|
+
pthread_t az_writer_thread;
|
8
|
+
pthread_once_t qt_once = PTHREAD_ONCE_INIT;
|
9
|
+
|
10
|
+
typedef struct _az_write_task_t
|
11
|
+
{
|
12
|
+
archive_func_t func;
|
13
|
+
void* data;
|
14
|
+
struct _az_write_task_t* next;
|
15
|
+
} az_write_task_t;
|
16
|
+
|
17
|
+
|
18
|
+
/* Queue of tasks for processing. */
|
19
|
+
pthread_mutex_t az_writer_mutex = PTHREAD_MUTEX_INITIALIZER;
|
20
|
+
pthread_cond_t az_writer_cond = PTHREAD_COND_INITIALIZER;
|
21
|
+
az_write_task_t* az_writer_queue = NULL;
|
22
|
+
|
23
|
+
|
24
|
+
/* Push new task to front of the queue */
|
25
|
+
static void az_write_task_queue_push(az_write_task_t* wtask)
|
26
|
+
{
|
27
|
+
wtask->next = az_writer_queue;
|
28
|
+
az_writer_queue = wtask;
|
29
|
+
}
|
30
|
+
|
31
|
+
/* Pop next task from the queue; Returns NULL, when the queue is empty */
|
32
|
+
static az_write_task_t* az_write_task_queue_pop(void)
|
33
|
+
{
|
34
|
+
az_write_task_t* wtask = az_writer_queue;
|
35
|
+
if(wtask)
|
36
|
+
{
|
37
|
+
az_writer_queue = wtask->next;
|
38
|
+
}
|
39
|
+
|
40
|
+
return wtask;
|
41
|
+
}
|
42
|
+
|
43
|
+
|
44
|
+
/* Task processing queue */
|
45
|
+
static void* az_writer_thread_func(void* data)
|
46
|
+
{
|
47
|
+
int is_running = 1;
|
48
|
+
az_write_task_t* wtask = NULL;
|
49
|
+
|
50
|
+
while(is_running)
|
51
|
+
{
|
52
|
+
pthread_mutex_lock(&az_writer_mutex);
|
53
|
+
while (is_running && (wtask = az_write_task_queue_pop()) == NULL)
|
54
|
+
{
|
55
|
+
pthread_cond_wait(&az_writer_cond, &az_writer_mutex);
|
56
|
+
}
|
57
|
+
pthread_mutex_unlock(&az_writer_mutex);
|
58
|
+
|
59
|
+
if(wtask)
|
60
|
+
{
|
61
|
+
if(wtask->func)
|
62
|
+
{
|
63
|
+
wtask->func(wtask->data);
|
64
|
+
}
|
65
|
+
|
66
|
+
free(wtask);
|
67
|
+
}
|
68
|
+
}
|
69
|
+
|
70
|
+
return NULL;
|
71
|
+
}
|
72
|
+
|
73
|
+
|
74
|
+
/* Initialize the writer thread. The thread will wait for tasks to process */
|
75
|
+
static void az_init_writer_thread(void)
|
76
|
+
{
|
77
|
+
pthread_create(&az_writer_thread, NULL, az_writer_thread_func, NULL);
|
78
|
+
pthread_detach(az_writer_thread);
|
79
|
+
}
|
80
|
+
|
81
|
+
/* asynchronously invoke the func with the provided data */
|
82
|
+
void az_enqueue_task(archive_func_t func, void* data)
|
83
|
+
{
|
84
|
+
pthread_once(&qt_once, az_init_writer_thread);
|
85
|
+
|
86
|
+
pthread_mutex_lock(&az_writer_mutex);
|
87
|
+
|
88
|
+
az_write_task_t* wtask = (az_write_task_t*)malloc(sizeof(az_write_task_t));
|
89
|
+
memset(wtask, 0, sizeof(az_write_task_t));
|
90
|
+
wtask->func = func;
|
91
|
+
wtask->data = data;
|
92
|
+
az_write_task_queue_push(wtask);
|
93
|
+
|
94
|
+
pthread_mutex_unlock(&az_writer_mutex);
|
95
|
+
pthread_cond_signal(&az_writer_cond);
|
96
|
+
}
|
data/ext/writer.h
ADDED
data/lib/async_zip.rb
ADDED
metadata
ADDED
@@ -0,0 +1,140 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: async-ruby-zip
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Grigoriy Chudnov
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-08-04 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rdoc
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '3.12'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '3.12'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: bundler
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: jeweler
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.8.3
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.8.3
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rspec
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
description: Non-blocking zip reading and writing for Ruby.
|
79
|
+
email: g.chudnov@gmail.com
|
80
|
+
executables: []
|
81
|
+
extensions:
|
82
|
+
- ext/extconf.rb
|
83
|
+
extra_rdoc_files:
|
84
|
+
- README.md
|
85
|
+
files:
|
86
|
+
- Gemfile.lock
|
87
|
+
- README.md
|
88
|
+
- async-ruby-zip-1.0.0.gem
|
89
|
+
- async-ruby-zip.gemspec
|
90
|
+
- ext/LICENSE
|
91
|
+
- ext/archive.c
|
92
|
+
- ext/archive.h
|
93
|
+
- ext/archive_data.c
|
94
|
+
- ext/archive_data.h
|
95
|
+
- ext/archive_data_fwd.h
|
96
|
+
- ext/async_zip.c
|
97
|
+
- ext/async_zip.h
|
98
|
+
- ext/callback.c
|
99
|
+
- ext/callback.h
|
100
|
+
- ext/carchive.c
|
101
|
+
- ext/carchive.h
|
102
|
+
- ext/carray.c
|
103
|
+
- ext/carray.h
|
104
|
+
- ext/cerror.c
|
105
|
+
- ext/cerror.h
|
106
|
+
- ext/cfilesystem.c
|
107
|
+
- ext/cfilesystem.h
|
108
|
+
- ext/extconf.rb
|
109
|
+
- ext/task.c
|
110
|
+
- ext/task.h
|
111
|
+
- ext/writer.c
|
112
|
+
- ext/writer.h
|
113
|
+
- lib/async_zip.rb
|
114
|
+
- lib/async_zip/version.rb
|
115
|
+
homepage: https://github.com/gchudnov/async-ruby-zip
|
116
|
+
licenses:
|
117
|
+
- MIT
|
118
|
+
post_install_message:
|
119
|
+
rdoc_options: []
|
120
|
+
require_paths:
|
121
|
+
- lib
|
122
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
123
|
+
none: false
|
124
|
+
requirements:
|
125
|
+
- - ! '>='
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
version: '0'
|
128
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ! '>='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
requirements: []
|
135
|
+
rubyforge_project:
|
136
|
+
rubygems_version: 1.8.24
|
137
|
+
signing_key:
|
138
|
+
specification_version: 3
|
139
|
+
summary: async-ruby-zip is a ruby extension that zip files asynchronously.
|
140
|
+
test_files: []
|