qdumpfs 1.9.1 → 1.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.idea/qdumpfs.iml +51 -19
- data/Gemfile.lock +2 -2
- data/lib/qdumpfs/option.rb +1 -5
- data/lib/qdumpfs/version.rb +1 -1
- data/lib/qdumpfs.rb +104 -66
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4ace57748311474078255f93323c921f04c1d63ce40f04bb12ec15d0e48a38e8
|
4
|
+
data.tar.gz: 7c214b8b293a6f5feee3573d3d87d09be7fb18f43d1db6376b2c521081025bd5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 10107064217f62fb81170d3d6a01d8de7e18ec2953aed30c3d6fe0d68d0f0a8b157745b7277b9b92e8a61aa6bf49d7c8f9b42144cc3724f6279d7719caf316ee
|
7
|
+
data.tar.gz: d82bc50988880296280b4cf7c6fd47669288ffefa72049829ea9e3219ea2ab2769e33b6dda41f8f847c620f5d1b6e053f9aeb47bb2bbe07b105d21f12945d3a0
|
data/.idea/qdumpfs.iml
CHANGED
@@ -10,50 +10,82 @@
|
|
10
10
|
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
|
11
11
|
<excludeFolder url="file://$MODULE_DIR$/.idea/copilot/chatSessions" />
|
12
12
|
</content>
|
13
|
-
<orderEntry type="
|
13
|
+
<orderEntry type="jdk" jdkName="rbenv: 3.1.6" jdkType="RUBY_SDK" />
|
14
14
|
<orderEntry type="sourceFolder" forTests="false" />
|
15
15
|
<orderEntry type="module-library">
|
16
|
-
<library name="minitest (v5.
|
16
|
+
<library name="minitest (v5.25.1) [path][gem]" type="rubylib">
|
17
17
|
<properties>
|
18
|
-
<option name="
|
18
|
+
<option name="additionalInfo">
|
19
|
+
<AdditionalInfo>
|
20
|
+
<option name="authors" value="該当なし" />
|
21
|
+
<option name="email" value="該当なし" />
|
22
|
+
<option name="homepage" value="該当なし" />
|
23
|
+
<option name="summary" value="該当なし" />
|
24
|
+
</AdditionalInfo>
|
25
|
+
</option>
|
26
|
+
<option name="fromPath" value="true" />
|
27
|
+
<option name="name" value="minitest" />
|
28
|
+
<option name="requirePaths">
|
29
|
+
<list>
|
30
|
+
<option value="lib" />
|
31
|
+
</list>
|
32
|
+
</option>
|
33
|
+
<option name="url" value="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/minitest-5.25.1" />
|
34
|
+
<option name="version" value="5.25.1" />
|
19
35
|
</properties>
|
20
36
|
<CLASSES>
|
21
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/minitest-5.
|
22
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/minitest-5.
|
37
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/minitest-5.25.1/lib" />
|
38
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/minitest-5.25.1/test" />
|
23
39
|
</CLASSES>
|
24
40
|
<JAVADOC />
|
25
41
|
<SOURCES>
|
26
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/minitest-5.
|
27
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/minitest-5.
|
42
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/minitest-5.25.1/lib" />
|
43
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/minitest-5.25.1/test" />
|
28
44
|
</SOURCES>
|
29
45
|
<excluded>
|
30
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/minitest-5.
|
46
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/minitest-5.25.1/test" />
|
31
47
|
</excluded>
|
32
48
|
</library>
|
33
49
|
</orderEntry>
|
34
50
|
<orderEntry type="module-library">
|
35
|
-
<library name="rake (v13.2.
|
51
|
+
<library name="rake (v13.2.1) [path][gem]" type="rubylib">
|
36
52
|
<properties>
|
37
|
-
<option name="
|
53
|
+
<option name="additionalInfo">
|
54
|
+
<AdditionalInfo>
|
55
|
+
<option name="authors" value="該当なし" />
|
56
|
+
<option name="email" value="該当なし" />
|
57
|
+
<option name="homepage" value="該当なし" />
|
58
|
+
<option name="summary" value="該当なし" />
|
59
|
+
</AdditionalInfo>
|
60
|
+
</option>
|
61
|
+
<option name="fromPath" value="true" />
|
62
|
+
<option name="name" value="rake" />
|
63
|
+
<option name="requirePaths">
|
64
|
+
<list>
|
65
|
+
<option value="lib" />
|
66
|
+
</list>
|
67
|
+
</option>
|
68
|
+
<option name="url" value="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/rake-13.2.1" />
|
69
|
+
<option name="version" value="13.2.1" />
|
38
70
|
</properties>
|
39
71
|
<CLASSES>
|
40
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/rake-13.2.
|
41
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/rake-13.2.
|
42
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/rake-13.2.
|
72
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/rake-13.2.1/doc" />
|
73
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/rake-13.2.1/exe" />
|
74
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/rake-13.2.1/lib" />
|
43
75
|
</CLASSES>
|
44
76
|
<JAVADOC />
|
45
77
|
<SOURCES>
|
46
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/rake-13.2.
|
47
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/rake-13.2.
|
48
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/rake-13.2.
|
78
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/rake-13.2.1/doc" />
|
79
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/rake-13.2.1/exe" />
|
80
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/rake-13.2.1/lib" />
|
49
81
|
</SOURCES>
|
50
82
|
<excluded>
|
51
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/rake-13.2.
|
52
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/rake-13.2.
|
83
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/rake-13.2.1/doc" />
|
84
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/rake-13.2.1/exe" />
|
53
85
|
</excluded>
|
54
86
|
</library>
|
55
87
|
</orderEntry>
|
56
|
-
<orderEntry type="library" scope="PROVIDED" name="bundler (v2.
|
88
|
+
<orderEntry type="library" scope="PROVIDED" name="bundler (v2.3.27, rbenv: 3.1.6) [gem]" level="application" />
|
57
89
|
</component>
|
58
90
|
<component name="RakeTasksCache-v2">
|
59
91
|
<option name="myRootTask">
|
data/Gemfile.lock
CHANGED
data/lib/qdumpfs/option.rb
CHANGED
data/lib/qdumpfs/version.rb
CHANGED
data/lib/qdumpfs.rb
CHANGED
@@ -198,6 +198,8 @@ module Qdumpfs
|
|
198
198
|
# ファイルのアップデート
|
199
199
|
update_file(s, l, t)
|
200
200
|
dirs[t] = File.stat(s) if File.ftype(s) == "directory"
|
201
|
+
rescue Errno::ENOSPC
|
202
|
+
raise
|
201
203
|
rescue => e
|
202
204
|
report_error(s, e)
|
203
205
|
@error_files << [s, e.message]
|
@@ -235,6 +237,8 @@ module Qdumpfs
|
|
235
237
|
end
|
236
238
|
chown_if_root(type, s, t)
|
237
239
|
dirs[t] = File.stat(s) if File.ftype(s) == "directory"
|
240
|
+
rescue Errno::ENOSPC
|
241
|
+
raise
|
238
242
|
rescue => e
|
239
243
|
report_error(s, e)
|
240
244
|
@error_files << [s, e.message]
|
@@ -309,7 +313,29 @@ module Qdumpfs
|
|
309
313
|
}
|
310
314
|
return nil
|
311
315
|
end
|
312
|
-
|
316
|
+
|
317
|
+
def incomplete_backup(today)
|
318
|
+
# puts "incomplete_backup #{today}"
|
319
|
+
# バックアップが途中で終了した場合、そのディレクトリをリネームする
|
320
|
+
dirname = File.dirname(today)
|
321
|
+
prefix = "_"
|
322
|
+
incomplete = dirname.sub(/(\d+)$/, prefix + '\1')
|
323
|
+
return unless FileTest.directory?(dirname) # バックアップが途中で途中で終了。ただしまだ日付ディレクトリが存在しない場合はなにもしない。
|
324
|
+
|
325
|
+
# すでにincompleteが存在する場合はユニークな名前を探す
|
326
|
+
0.upto(10) do |i|
|
327
|
+
break unless FileTest.exist?(incomplete)
|
328
|
+
prefix += "_"
|
329
|
+
incomplete = dirname.sub(/(\d+)$/, prefix + '\1')
|
330
|
+
end
|
331
|
+
if FileTest.directory?(incomplete)
|
332
|
+
log("cannot rename incomplete backup: #{incomplete}")
|
333
|
+
else
|
334
|
+
FileUtils.mv(dirname, incomplete)
|
335
|
+
log("rename incomplete backup: #{dirname} -> #{incomplete}")
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
313
339
|
def backup
|
314
340
|
##### オリジナルのバックアップルーチン
|
315
341
|
@opt.validate_directories(2)
|
@@ -336,31 +362,37 @@ module Qdumpfs
|
|
336
362
|
base = File.basename(src)
|
337
363
|
dirname = File.dirname(src)
|
338
364
|
raise RuntimeError unless FileTest.exist?(dirname + '/' + base)
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
365
|
+
|
366
|
+
begin
|
367
|
+
# 存在するバックアップの最新を取得
|
368
|
+
latest = latest_snapshot(start_time, src, dst, base)
|
369
|
+
# 現在の日付フォルダを取得j:/to/backup1/2019/05/10/home
|
370
|
+
today = File.join(dst, datedir(start_time), base)
|
371
|
+
File.umask(0077)
|
372
|
+
FileUtils.mkpath(today) unless @opt.dry_run
|
373
|
+
if windows?
|
374
|
+
src = src.sub( /^[A-Za-z]:$/, src + "/" )
|
375
|
+
end
|
376
|
+
if latest
|
377
|
+
# バックアップがすでに存在する場合差分コピー
|
378
|
+
log("## update_snapshot #{src} #{latest}=>#{today} ##")
|
379
|
+
update_snapshot(src, latest, today)
|
380
|
+
else
|
381
|
+
# 初回は単純に再帰コピー
|
382
|
+
log("## recursive_copy #{src}=>#{today} ##")
|
383
|
+
recursive_copy(src, today)
|
384
|
+
end
|
385
|
+
unless @opt.dry_run
|
386
|
+
create_latest_symlink(dst, today)
|
387
|
+
elapsed = Time.now - start_time
|
388
|
+
log_result(src, today, elapsed)
|
389
|
+
end
|
390
|
+
log("##### backup end #####")
|
391
|
+
rescue Errno::ENOSPC
|
392
|
+
# 直前のmkpathでエラーが発生した場合 Errno::ENOSPCが発生する。内部ではIncompleteErrorに変換している
|
393
|
+
incomplete_backup(today)
|
394
|
+
log("##### backup incomplete(No space left on device) #####")
|
362
395
|
end
|
363
|
-
log("##### backup end #####")
|
364
396
|
end
|
365
397
|
|
366
398
|
def sync
|
@@ -379,49 +411,55 @@ module Qdumpfs
|
|
379
411
|
log("##### sync start #{fmt(start_time)} => limit_time=#{fmt(limit_time)} #####")
|
380
412
|
count = 0
|
381
413
|
last_sync_complete = false
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
414
|
+
|
415
|
+
begin
|
416
|
+
while true
|
417
|
+
count += 1
|
418
|
+
log("## sync_latest count=#{count} ##")
|
419
|
+
latest_start = Time.now
|
420
|
+
sync_result, from, to = sync_latest(src, dst)
|
421
|
+
latest_end = Time.now
|
422
|
+
|
423
|
+
log("## sync_latest result=#{sync_result} from=#{from} to=#{to} ##")
|
424
|
+
unless sync_result
|
425
|
+
# 同期結果がtrueでない場合ここで終了。ただしsync_result=falseになるのはコピー元フォルダが存在しない場合なので、
|
426
|
+
# 中途半端な結果にはならない
|
427
|
+
last_sync_complete = true
|
428
|
+
break
|
429
|
+
end
|
430
|
+
|
431
|
+
from_count, to_count = do_verify(from, to)
|
432
|
+
log("## from_count=#{from_count} to_count=#{to_count} equals=#{from_count == to_count} ##")
|
433
|
+
unless from_count == to_count
|
434
|
+
# ファイル数が同じでない場合ここで終了
|
435
|
+
last_sync_complete = false
|
436
|
+
break
|
437
|
+
end
|
438
|
+
|
439
|
+
# 次回同期にかかる時間を最終同期時間の半分と予想
|
440
|
+
next_sync = (latest_end - latest_start) / 2
|
441
|
+
|
442
|
+
cur_time = Time.now
|
443
|
+
in_limit = (cur_time + next_sync) < limit_time
|
444
|
+
log("## cur_time=#{fmt(cur_time)} + next_sync=#{next_sync} < limit_time=#{fmt(limit_time)} in_limit=#{in_limit} ## ")
|
445
|
+
unless in_limit
|
446
|
+
# 指定時間内ではない場合ここで終了(ただし最終同期は成功)
|
447
|
+
last_sync_complete = true
|
448
|
+
break
|
449
|
+
end
|
415
450
|
end
|
416
|
-
end
|
417
|
-
|
418
|
-
end_time = Time.now
|
419
|
-
diff = time_diff(start_time, end_time)
|
420
451
|
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
452
|
+
end_time = Time.now
|
453
|
+
diff = time_diff(start_time, end_time)
|
454
|
+
|
455
|
+
elapsed = Time.now - start_time
|
456
|
+
log_result(src, dst, elapsed)
|
457
|
+
|
458
|
+
log("##### sync end #{fmt(end_time)} diff=#{diff} last_sync_complete=#{last_sync_complete} #####")
|
459
|
+
rescue Errno::ENOSPC
|
460
|
+
incomplete_backup(today)
|
461
|
+
log("##### backup incomplete(No space left on device) #####")
|
462
|
+
end
|
425
463
|
end
|
426
464
|
|
427
465
|
def verify
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: qdumpfs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- src
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-12-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|