file_pool 0.5.1 → 0.6.2
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 +7 -0
- data/lib/file_pool/version.rb +1 -1
- data/lib/file_pool.rb +174 -57
- metadata +49 -76
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 133469293b9b495e160951b1abd81d5716aa06b1e9abb18a0f1b98b6904f3ad8
|
4
|
+
data.tar.gz: 1b4befbb63377f359174c7e77caf5e95a831412d709efa688dc1cdfb6b2daf5b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 28b215968194546b52830604ac034616a2a78d55db738a83d91ac8e2a5ffaf703e658e4535e1865dc37b102026725a3119770c0ac8f4f346d0aed43387be78ad
|
7
|
+
data.tar.gz: f3345fd4c4a9e71dc4a3f02e499ae1b85c2bc4dd4ad9a5c65a573f85f5c99cbe17ac850123cf5bad7dab79f167e2da0e5bc81536be583da9057371f9015c0fb4
|
data/lib/file_pool/version.rb
CHANGED
data/lib/file_pool.rb
CHANGED
@@ -27,20 +27,20 @@ module FilePool
|
|
27
27
|
# encryption/decryption in bytes. Larger blocks need more memory and less time (less IO).
|
28
28
|
# Defaults to 1'048'576 (1 MiB).
|
29
29
|
# * :copy_source (true,false)
|
30
|
-
# if +false+ files added to the pool are hard-linked with the source if source and file pool
|
30
|
+
# if +false+ files added to the pool are hard-linked with the source if source and file pool
|
31
31
|
# are on the same file system (default). If set to +true+ files are always copied into the pool.
|
32
32
|
# * :mode (Integer)
|
33
33
|
# File mode to set on all files added to the pool. E.g. +mode:+ +0640+ for +rw-r-----+ or symbolic "u=wrx,go=rx"
|
34
34
|
# (see Ruby stdlib FileUtils#chmod).
|
35
|
-
# Note that the desired mode is not set if the file is hard-linked with the source.
|
35
|
+
# Note that the desired mode is not set if the file is hard-linked with the source.
|
36
36
|
# Use +copy_source:true+ when to ensure.
|
37
37
|
# * :owner
|
38
|
-
# Owner of the files added to the pool.
|
39
|
-
# Note that the desired owner is not set if the file is hard-linked with the source.
|
38
|
+
# Owner of the files added to the pool.
|
39
|
+
# Note that the desired owner is not set if the file is hard-linked with the source.
|
40
40
|
# Use +copy_source:true+ when to ensure.
|
41
41
|
# * :group
|
42
|
-
# Group of the files added to the pool.
|
43
|
-
# Note that the desired group is not set if the file is hard-linked with the source.
|
42
|
+
# Group of the files added to the pool.
|
43
|
+
# Note that the desired group is not set if the file is hard-linked with the source.
|
44
44
|
# Use +copy_source:true+ when to ensure.
|
45
45
|
def self.setup root, options={}
|
46
46
|
unless(unknown = options.keys - [:encryption_block_size, :secrets_file, :copy_source, :mode, :owner, :group]).empty?
|
@@ -70,32 +70,50 @@ module FilePool
|
|
70
70
|
#
|
71
71
|
# path (String)::
|
72
72
|
# path of the file to add.
|
73
|
+
# options (Hash)::
|
74
|
+
# :background (true,false) adding large files can take long (esp. with encryption), +true+ won't block, default is +false+
|
73
75
|
#
|
74
76
|
# === Return Value:
|
75
77
|
#
|
76
78
|
# :: *String* containing a new unique ID for the file added.
|
77
|
-
def self.add! orig_path
|
79
|
+
def self.add! orig_path, options = {}
|
78
80
|
newid = uuid
|
79
|
-
target = path newid
|
80
81
|
|
81
|
-
|
82
|
-
FileUtils.mkpath(id2dir_secured newid)
|
83
|
-
path = crypt(orig_path)
|
84
|
-
else
|
85
|
-
path = orig_path
|
86
|
-
FileUtils.mkpath(id2dir newid)
|
87
|
-
end
|
82
|
+
raise Errno::ENOENT unless File.exist?(orig_path)
|
88
83
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
84
|
+
child = fork do
|
85
|
+
target = path newid
|
86
|
+
|
87
|
+
if @@crypted_mode
|
88
|
+
FileUtils.mkpath(id2dir_secured newid)
|
89
|
+
path = encrypt_to_tempfile(orig_path)
|
90
|
+
else
|
91
|
+
path = orig_path
|
92
|
+
FileUtils.mkpath(id2dir newid)
|
93
|
+
end
|
94
|
+
|
95
|
+
# try quick hard-linking, copy if forced or hard-linking impossible
|
96
|
+
begin
|
97
|
+
raise Errno::EXDEV if @@copy_source
|
98
|
+
FileUtils.link(path, target)
|
99
|
+
rescue Errno::EXDEV
|
100
|
+
FileUtils.copy(path, target)
|
101
|
+
end
|
102
|
+
|
103
|
+
# don't chmod if orginal file is same as target (hard-linked)
|
104
|
+
if File.stat(orig_path).ino != File.stat(File.dirname(target)).ino
|
105
|
+
FileUtils.chmod(@@mode, target) if @@mode
|
106
|
+
FileUtils.chown(@@owner, @@group, target)
|
107
|
+
end
|
93
108
|
end
|
94
109
|
|
95
|
-
|
96
|
-
if
|
97
|
-
|
98
|
-
|
110
|
+
|
111
|
+
if options[:background]
|
112
|
+
# don't wait, avoid zombies
|
113
|
+
Process.detach(child)
|
114
|
+
else
|
115
|
+
# block until done
|
116
|
+
Process.waitpid(child)
|
99
117
|
end
|
100
118
|
|
101
119
|
newid
|
@@ -110,18 +128,49 @@ module FilePool
|
|
110
128
|
#
|
111
129
|
# source (String)::
|
112
130
|
# path of the file to add.
|
131
|
+
# options (Hash)::
|
132
|
+
# :background (true,false) adding large files can take long (esp. with encryption), +true+ won't block, default is +false+
|
113
133
|
#
|
114
134
|
# === Return Value:
|
115
135
|
#
|
116
136
|
# :: *String* containing a new unique ID for the file added.
|
117
137
|
# :: +false+ when the file could not be stored.
|
118
|
-
def self.add path
|
119
|
-
self.add!(path)
|
138
|
+
def self.add path, options = {}
|
139
|
+
self.add!(path, options)
|
120
140
|
|
121
141
|
rescue Exception
|
122
142
|
return false
|
123
143
|
end
|
124
144
|
|
145
|
+
#
|
146
|
+
# Add a new file from a stream to the file pool
|
147
|
+
#
|
148
|
+
def self.add_stream in_stream
|
149
|
+
newid = uuid
|
150
|
+
|
151
|
+
# ensure target path exists
|
152
|
+
if @@crypted_mode
|
153
|
+
FileUtils.mkpath(id2dir_secured newid)
|
154
|
+
else
|
155
|
+
FileUtils.mkpath(id2dir newid)
|
156
|
+
end
|
157
|
+
|
158
|
+
child = fork do
|
159
|
+
target = path(newid)
|
160
|
+
# create the target file to write
|
161
|
+
open(target,'w') do |out_stream|
|
162
|
+
encrypt in_stream, out_stream
|
163
|
+
end
|
164
|
+
|
165
|
+
FileUtils.chmod(@@mode, target) if @@mode
|
166
|
+
FileUtils.chown(@@owner, @@group, target)
|
167
|
+
end
|
168
|
+
|
169
|
+
Process.detach(child)
|
170
|
+
|
171
|
+
newid
|
172
|
+
end
|
173
|
+
|
125
174
|
#
|
126
175
|
# Return the file's path corresponding to the passed file ID, no matter if it
|
127
176
|
# exists or not. In encrypting mode the file is first decrypted and the
|
@@ -141,7 +190,7 @@ module FilePool
|
|
141
190
|
#
|
142
191
|
# :: *String*, absolute path of the file in the pool or to temporary location if it was decrypted.
|
143
192
|
def self.path fid, options={}
|
144
|
-
options[:decrypt] =
|
193
|
+
options[:decrypt] = options.fetch(:decrypt, true)
|
145
194
|
|
146
195
|
raise InvalidFileId unless valid?(fid)
|
147
196
|
|
@@ -151,7 +200,7 @@ module FilePool
|
|
151
200
|
if @@crypted_mode
|
152
201
|
if options[:decrypt]
|
153
202
|
# return path of decrypted file (tmp path)
|
154
|
-
|
203
|
+
decrypt_to_tempfile id2dir_secured(fid) + "/#{fid}"
|
155
204
|
else
|
156
205
|
id2dir_secured(fid) + "/#{fid}"
|
157
206
|
end
|
@@ -171,6 +220,33 @@ module FilePool
|
|
171
220
|
end
|
172
221
|
end
|
173
222
|
|
223
|
+
# Returns an IO object providing an (unencrypted) stream of data of the given file ID
|
224
|
+
# To get the stream of the encrypted data pass :decrypt => false, as an option.
|
225
|
+
#
|
226
|
+
# === Parameters:
|
227
|
+
#
|
228
|
+
# fid (String)::
|
229
|
+
# File ID which was generated by a previous #add operation.
|
230
|
+
#
|
231
|
+
# options (Hash)::
|
232
|
+
# :decrypt (true,false) In encryption mode don't decrypt, but prioved the encrypted data. Defaults to +true+.
|
233
|
+
#
|
234
|
+
# === Return Value:
|
235
|
+
#
|
236
|
+
# :: *IO*, IO stream open for reading
|
237
|
+
#
|
238
|
+
def self.stream fid, options={}
|
239
|
+
options[:decrypt] = options.fetch(:decrypt, true)
|
240
|
+
|
241
|
+
if path = path(fid, :decrypt => false)
|
242
|
+
if @@crypted_mode and options[:decrypt]
|
243
|
+
decrypt_to_stream path
|
244
|
+
else
|
245
|
+
open(path)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
174
250
|
#
|
175
251
|
# Remove a previously added file by its ID. Same as FilePool.remove,
|
176
252
|
# but throws exceptions on failure.
|
@@ -271,7 +347,7 @@ module FilePool
|
|
271
347
|
end
|
272
348
|
|
273
349
|
#
|
274
|
-
# Crypt a file and store the result
|
350
|
+
# Crypt a file and store the result a Tempfile
|
275
351
|
#
|
276
352
|
# Returns the path to the crypted file.
|
277
353
|
#
|
@@ -282,28 +358,19 @@ module FilePool
|
|
282
358
|
#
|
283
359
|
# === Return Value:
|
284
360
|
#
|
285
|
-
# :: *String*Path and name of the crypted file.
|
286
|
-
def self.
|
361
|
+
# :: *String* Path and name of the crypted file.
|
362
|
+
def self.encrypt_to_tempfile path
|
287
363
|
# Crypt the file in the temp folder and copy after
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
result.set_encoding Encoding::BINARY,Encoding::BINARY
|
292
|
-
buf = ''.encode(Encoding::BINARY)
|
364
|
+
tempfile = Tempfile.new 'FilePool-encrypt'
|
365
|
+
tempfile.sync = true
|
293
366
|
|
294
|
-
|
295
|
-
while inf.read(@@block_size, buf)
|
296
|
-
result << cipher.update(buf)
|
297
|
-
end
|
298
|
-
result << cipher.final
|
299
|
-
end
|
367
|
+
encrypt open(path), tempfile
|
300
368
|
|
301
|
-
|
302
|
-
result.path
|
369
|
+
tempfile.path
|
303
370
|
end
|
304
371
|
|
305
372
|
#
|
306
|
-
# Decrypt
|
373
|
+
# Decrypt file to a file in /tmp
|
307
374
|
#
|
308
375
|
# Returns the path to the decrypted file.
|
309
376
|
#
|
@@ -314,26 +381,76 @@ module FilePool
|
|
314
381
|
#
|
315
382
|
# === Return Value:
|
316
383
|
#
|
317
|
-
# :: *String*Path and name of the
|
318
|
-
def self.
|
319
|
-
|
320
|
-
|
321
|
-
output = Tempfile.new 'FilePool-decrypt'
|
384
|
+
# :: *String* Path and name of the decrypted file.
|
385
|
+
def self.decrypt_to_tempfile path
|
386
|
+
tmpfile = Tempfile.new 'FilePool-decrypt'
|
387
|
+
tmpfile.sync = true
|
322
388
|
|
323
|
-
|
324
|
-
|
389
|
+
File.open(path) do |encrypted_file|
|
390
|
+
decrypt encrypted_file, tmpfile
|
391
|
+
end
|
392
|
+
|
393
|
+
tmpfile.path
|
394
|
+
end
|
325
395
|
|
326
|
-
|
327
|
-
|
328
|
-
|
396
|
+
#
|
397
|
+
# Decrypt file to a stream (IO) non-blocking by forking a child process.
|
398
|
+
#
|
399
|
+
# === Parameters:
|
400
|
+
#
|
401
|
+
# path (String)::
|
402
|
+
# path of the file to decrypt.
|
403
|
+
#
|
404
|
+
# === Return Value:
|
405
|
+
#
|
406
|
+
# :: *IO* decrypted data as stream
|
407
|
+
def self.decrypt_to_stream path
|
408
|
+
|
409
|
+
pipe_read, pipe_write = IO.pipe
|
410
|
+
|
411
|
+
child = fork do
|
412
|
+
# in child process: decrypting
|
413
|
+
pipe_read.close
|
414
|
+
|
415
|
+
# open encrypted file
|
416
|
+
File.open(path) do |encrypted_file|
|
417
|
+
decrypt encrypted_file, pipe_write
|
329
418
|
end
|
330
|
-
|
419
|
+
|
420
|
+
pipe_write.close
|
331
421
|
end
|
332
422
|
|
333
|
-
|
334
|
-
|
423
|
+
# in parent
|
424
|
+
Process.detach(child) # not waiting for it
|
425
|
+
pipe_write.close
|
426
|
+
pipe_read
|
335
427
|
end
|
336
428
|
|
429
|
+
|
430
|
+
# decrypts data stream +in_stream+ (IO: readable) to +out+ (IO: writeable), blocking
|
431
|
+
def self.decrypt in_stream, out_stream
|
432
|
+
crypt(in_stream, out_stream, :decrypt)
|
433
|
+
end
|
434
|
+
|
435
|
+
# encrypts data stream +in+ (IO: readable) to +out+ (IO: writeable), blocking
|
436
|
+
def self.encrypt in_stream, out_stream
|
437
|
+
crypt(in_stream, out_stream, :encrypt)
|
438
|
+
end
|
439
|
+
|
440
|
+
def self.crypt in_stream, out_stream, direction
|
441
|
+
cipher = (direction == :encrypt) ? create_cipher : create_decipher
|
442
|
+
|
443
|
+
buf = ''.encode(Encoding::BINARY)
|
444
|
+
out_stream.set_encoding Encoding::BINARY,Encoding::BINARY
|
445
|
+
in_stream.set_encoding Encoding::BINARY,Encoding::BINARY
|
446
|
+
|
447
|
+
while in_stream.read(@@block_size, buf)
|
448
|
+
out_stream << cipher.update(buf)
|
449
|
+
end
|
450
|
+
out_stream << cipher.final
|
451
|
+
|
452
|
+
nil
|
453
|
+
end
|
337
454
|
#
|
338
455
|
# Creates a cipher to encrypt data.
|
339
456
|
#
|
metadata
CHANGED
@@ -1,104 +1,77 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: file_pool
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 5
|
9
|
-
- 1
|
10
|
-
version: 0.5.1
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.6.2
|
11
5
|
platform: ruby
|
12
|
-
authors:
|
13
|
-
-
|
14
|
-
autorequire:
|
6
|
+
authors:
|
7
|
+
- robokopp (Robert Anniés)
|
8
|
+
autorequire:
|
15
9
|
bindir: bin
|
16
10
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
dependencies:
|
21
|
-
- !ruby/object:Gem::Dependency
|
11
|
+
date: 2022-01-14 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
22
14
|
name: uuidtools
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
- - ~>
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
hash: 15
|
30
|
-
segments:
|
31
|
-
- 2
|
32
|
-
- 1
|
33
|
-
- 2
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
34
19
|
version: 2.1.2
|
35
20
|
type: :runtime
|
36
|
-
version_requirements: *id001
|
37
|
-
- !ruby/object:Gem::Dependency
|
38
|
-
name: pry
|
39
21
|
prerelease: false
|
40
|
-
|
41
|
-
|
42
|
-
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 2.1.2
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: pry
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
43
31
|
- - ">="
|
44
|
-
- !ruby/object:Gem::Version
|
45
|
-
|
46
|
-
segments:
|
47
|
-
- 0
|
48
|
-
version: "0"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
49
34
|
type: :development
|
50
|
-
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
51
41
|
description: |
|
52
42
|
FilePool helps to manage a large number of files in a Ruby
|
53
43
|
project. It takes care of the storage of files in a balanced directory
|
54
44
|
tree and generates unique identifiers for all files.
|
55
|
-
|
56
|
-
email:
|
45
|
+
email:
|
57
46
|
- robokopp@fernwerk.net
|
58
47
|
executables: []
|
59
|
-
|
60
48
|
extensions: []
|
61
|
-
|
62
|
-
|
49
|
+
extra_rdoc_files:
|
50
|
+
- README.md
|
51
|
+
files:
|
63
52
|
- README.md
|
64
|
-
files:
|
65
53
|
- lib/file_pool.rb
|
66
54
|
- lib/file_pool/version.rb
|
67
|
-
- README.md
|
68
|
-
has_rdoc: true
|
69
55
|
homepage: https://github.com/robokopp/file_pool
|
70
56
|
licenses: []
|
71
|
-
|
72
|
-
post_install_message:
|
57
|
+
metadata: {}
|
58
|
+
post_install_message:
|
73
59
|
rdoc_options: []
|
74
|
-
|
75
|
-
require_paths:
|
60
|
+
require_paths:
|
76
61
|
- lib
|
77
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
- 2
|
85
|
-
- 0
|
86
|
-
version: "2.0"
|
87
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
88
|
-
none: false
|
89
|
-
requirements:
|
62
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">"
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '2.0'
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
90
69
|
- - ">="
|
91
|
-
- !ruby/object:Gem::Version
|
92
|
-
|
93
|
-
segments:
|
94
|
-
- 0
|
95
|
-
version: "0"
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
96
72
|
requirements: []
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
signing_key:
|
101
|
-
specification_version: 3
|
73
|
+
rubygems_version: 3.2.22
|
74
|
+
signing_key:
|
75
|
+
specification_version: 4
|
102
76
|
summary: Manage a large number files in a pool
|
103
77
|
test_files: []
|
104
|
-
|