fluentd 1.15.1-x64-mingw-ucrt → 1.15.3-x64-mingw-ucrt

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,6 +5,7 @@ require 'fileutils'
5
5
  require 'time'
6
6
  require 'timecop'
7
7
  require 'zlib'
8
+ require 'fluent/file_wrapper'
8
9
 
9
10
  class FileOutputTest < Test::Unit::TestCase
10
11
  def setup
@@ -1016,7 +1017,7 @@ class FileOutputTest < Test::Unit::TestCase
1016
1017
 
1017
1018
  test 'returns filepath with index which does not exist yet' do
1018
1019
  5.times do |i|
1019
- File.open(File.join(@tmp, "exist_#{i}.log"), 'a'){|f| } # open(create) and close
1020
+ Fluent::FileWrapper.open(File.join(@tmp, "exist_#{i}.log"), 'a'){|f| } # open(create) and close
1020
1021
  end
1021
1022
  @i.find_filepath_available(File.join(@tmp, "exist_**.log")) do |path|
1022
1023
  assert_equal File.join(@tmp, "exist_5.log"), path
@@ -1025,7 +1026,7 @@ class FileOutputTest < Test::Unit::TestCase
1025
1026
 
1026
1027
  test 'creates lock directory when with_lock is true to exclude operations of other worker process' do
1027
1028
  5.times do |i|
1028
- File.open(File.join(@tmp, "exist_#{i}.log"), 'a')
1029
+ Fluent::FileWrapper.open(File.join(@tmp, "exist_#{i}.log"), 'a')
1029
1030
  end
1030
1031
  Dir.mkdir(File.join(@tmp, "exist_5.log.lock"))
1031
1032
  @i.find_filepath_available(File.join(@tmp, "exist_**.log"), with_lock: true) do |path|
data/test/test_config.rb CHANGED
@@ -237,6 +237,63 @@ class ConfigTest < Test::Unit::TestCase
237
237
  ])
238
238
  end
239
239
 
240
+ def test_included_glob
241
+ write_config "#{TMP_DIR}/config.yaml", <<-EOS
242
+ config:
243
+ - !include "include/*.yaml"
244
+ EOS
245
+ write_config "#{TMP_DIR}/include/02_source2.yaml", <<-EOS
246
+ - source:
247
+ $type: dummy
248
+ tag: tag.dummy
249
+ EOS
250
+ write_config "#{TMP_DIR}/include/01_source1.yaml", <<-EOS
251
+ - source:
252
+ $type: tcp
253
+ tag: tag.tcp
254
+ parse:
255
+ $arg:
256
+ - why.parse.section.doesnot.have.arg
257
+ - huh
258
+ $type: none
259
+ EOS
260
+ write_config "#{TMP_DIR}/include/03_match1.yaml", <<-EOS
261
+ - match:
262
+ $tag: tag.*
263
+ $type: stdout
264
+ buffer:
265
+ $type: memory
266
+ flush_interval: 1s
267
+ EOS
268
+ root_conf = read_config("#{TMP_DIR}/config.yaml", use_yaml: true)
269
+ tcp_source_conf = root_conf.elements.first
270
+ dummy_source_conf = root_conf.elements[1]
271
+ parse_tcp_conf = tcp_source_conf.elements.first
272
+ match_conf = root_conf.elements[2]
273
+
274
+ assert_equal(
275
+ [
276
+ 'tcp',
277
+ 'tag.tcp',
278
+ 'none',
279
+ 'why.parse.section.doesnot.have.arg,huh',
280
+ 'dummy',
281
+ 'tag.dummy',
282
+ 'stdout',
283
+ 'tag.*',
284
+ ],
285
+ [
286
+ tcp_source_conf['@type'],
287
+ tcp_source_conf['tag'],
288
+ parse_tcp_conf['@type'],
289
+ parse_tcp_conf.arg,
290
+ dummy_source_conf['@type'],
291
+ dummy_source_conf['tag'],
292
+ match_conf['@type'],
293
+ match_conf.arg,
294
+ ])
295
+ end
296
+
240
297
  def test_check_not_fetchd
241
298
  write_config "#{TMP_DIR}/config_test_not_fetched.yaml", <<-EOS
242
299
  config:
@@ -1,12 +1,7 @@
1
- require_relative '../helper'
2
- require 'fluent/plugin/file_wrapper'
1
+ require_relative 'helper'
2
+ require 'fluent/file_wrapper'
3
3
 
4
4
  class FileWrapperTest < Test::Unit::TestCase
5
- require 'windows/file'
6
- require 'windows/error'
7
- include Windows::File
8
- include Windows::Error
9
-
10
5
  TMP_DIR = File.dirname(__FILE__) + "/../tmp/file_wrapper#{ENV['TEST_ENV_NUMBER']}"
11
6
 
12
7
  def setup
data/test/test_log.rb CHANGED
@@ -4,13 +4,16 @@ require 'fluent/engine'
4
4
  require 'fluent/log'
5
5
  require 'timecop'
6
6
  require 'logger'
7
+ require 'securerandom'
7
8
 
8
9
  class LogTest < Test::Unit::TestCase
9
- TMP_DIR = File.expand_path(File.dirname(__FILE__) + "/tmp/log/#{ENV['TEST_ENV_NUMBER']}")
10
+ def tmp_dir
11
+ File.join(File.dirname(__FILE__), "tmp", "log", "#{ENV['TEST_ENV_NUMBER']}", SecureRandom.hex(10))
12
+ end
10
13
 
11
14
  def setup
12
- FileUtils.rm_rf(TMP_DIR)
13
- FileUtils.mkdir_p(TMP_DIR)
15
+ @tmp_dir = tmp_dir
16
+ FileUtils.mkdir_p(@tmp_dir)
14
17
  @log_device = Fluent::Test::DummyLogDevice.new
15
18
  @timestamp = Time.parse("2016-04-21 02:58:41 +0000")
16
19
  @timestamp_str = @timestamp.strftime("%Y-%m-%d %H:%M:%S %z")
@@ -21,6 +24,13 @@ class LogTest < Test::Unit::TestCase
21
24
  @log_device.reset
22
25
  Timecop.return
23
26
  Thread.current[:last_repeated_stacktrace] = nil
27
+ begin
28
+ FileUtils.rm_rf(@tmp_dir)
29
+ rescue Errno::EACCES
30
+ # It may occur on Windows because of delete pending state due to delayed GC.
31
+ # Ruby 3.2 or later doesn't ignore Errno::EACCES:
32
+ # https://github.com/ruby/ruby/commit/983115cf3c8f75b1afbe3274f02c1529e1ce3a81
33
+ end
24
34
  end
25
35
 
26
36
  sub_test_case "log level" do
@@ -560,7 +570,7 @@ class LogTest < Test::Unit::TestCase
560
570
  Timecop.freeze(@timestamp)
561
571
 
562
572
  rotate_age, rotate_size, travel_term = expected
563
- path = "#{TMP_DIR}/log-dev-io-#{rotate_size}-#{rotate_age}"
573
+ path = "#{@tmp_dir}/log-dev-io-#{rotate_size}-#{rotate_age}"
564
574
 
565
575
  logdev = Fluent::LogDeviceIO.new(path, shift_age: rotate_age, shift_size: rotate_size)
566
576
  logger = ServerEngine::DaemonLogger.new(logdev)
@@ -585,7 +595,7 @@ class LogTest < Test::Unit::TestCase
585
595
  with_timezone('utc') do
586
596
  rotate_age = 2
587
597
  rotate_size = 100
588
- path = "#{TMP_DIR}/log-dev-io-#{rotate_size}-#{rotate_age}"
598
+ path = "#{@tmp_dir}/log-dev-io-#{rotate_size}-#{rotate_age}"
589
599
  path0 = path + '.0'
590
600
  path1 = path + '.1'
591
601
 
@@ -2,12 +2,14 @@ require_relative 'helper'
2
2
  require 'fluent/event_router'
3
3
  require 'fluent/system_config'
4
4
  require 'fluent/supervisor'
5
+ require 'fluent/file_wrapper'
5
6
  require_relative 'test_plugin_classes'
6
7
 
7
8
  require 'net/http'
8
9
  require 'uri'
9
10
  require 'fileutils'
10
11
  require 'tempfile'
12
+ require 'securerandom'
11
13
 
12
14
  if Fluent.windows?
13
15
  require 'win32/event'
@@ -22,17 +24,29 @@ class SupervisorTest < ::Test::Unit::TestCase
22
24
  end
23
25
  end
24
26
 
25
- TMP_DIR = File.expand_path(File.dirname(__FILE__) + "/tmp/supervisor#{ENV['TEST_ENV_NUMBER']}")
26
- TMP_ROOT_DIR = File.join(TMP_DIR, 'root')
27
+ def tmp_dir
28
+ File.join(File.dirname(__FILE__), "tmp", "supervisor#{ENV['TEST_ENV_NUMBER']}", SecureRandom.hex(10))
29
+ end
27
30
 
28
31
  def setup
29
- FileUtils.rm_rf(TMP_DIR)
30
- FileUtils.mkdir_p(TMP_DIR)
32
+ @tmp_dir = tmp_dir
33
+ @tmp_root_dir = File.join(@tmp_dir, 'root')
34
+ FileUtils.mkdir_p(@tmp_dir)
35
+ end
36
+
37
+ def teardown
38
+ begin
39
+ FileUtils.rm_rf(@tmp_dir)
40
+ rescue Errno::EACCES
41
+ # It may occur on Windows because of delete pending state due to delayed GC.
42
+ # Ruby 3.2 or later doesn't ignore Errno::EACCES:
43
+ # https://github.com/ruby/ruby/commit/983115cf3c8f75b1afbe3274f02c1529e1ce3a81
44
+ end
31
45
  end
32
46
 
33
47
  def write_config(path, data)
34
48
  FileUtils.mkdir_p(File.dirname(path))
35
- File.open(path, "w") {|f| f.write data }
49
+ Fluent::FileWrapper.open(path, "w") {|f| f.write data }
36
50
  end
37
51
 
38
52
 
@@ -48,7 +62,7 @@ class SupervisorTest < ::Test::Unit::TestCase
48
62
  enable_get_dump true
49
63
  process_name "process_name"
50
64
  log_level info
51
- root_dir #{TMP_ROOT_DIR}
65
+ root_dir #{@tmp_root_dir}
52
66
  <log>
53
67
  format json
54
68
  time_format %Y
@@ -76,7 +90,7 @@ class SupervisorTest < ::Test::Unit::TestCase
76
90
  assert_equal true, sys_conf.enable_get_dump
77
91
  assert_equal "process_name", sys_conf.process_name
78
92
  assert_equal 2, sys_conf.log_level
79
- assert_equal TMP_ROOT_DIR, sys_conf.root_dir
93
+ assert_equal @tmp_root_dir, sys_conf.root_dir
80
94
  assert_equal :json, sys_conf.log.format
81
95
  assert_equal '%Y', sys_conf.log.time_format
82
96
  counter_server = sys_conf.counter_server
@@ -116,7 +130,7 @@ class SupervisorTest < ::Test::Unit::TestCase
116
130
  enable_get_dump: true
117
131
  process_name: "process_name"
118
132
  log_level: info
119
- root_dir: !fluent/s "#{TMP_ROOT_DIR}"
133
+ root_dir: !fluent/s "#{@tmp_root_dir}"
120
134
  log:
121
135
  format: json
122
136
  time_format: "%Y"
@@ -144,7 +158,7 @@ class SupervisorTest < ::Test::Unit::TestCase
144
158
  true,
145
159
  "process_name",
146
160
  2,
147
- TMP_ROOT_DIR,
161
+ @tmp_root_dir,
148
162
  :json,
149
163
  '%Y',
150
164
  '127.0.0.1',
@@ -449,7 +463,7 @@ class SupervisorTest < ::Test::Unit::TestCase
449
463
  end
450
464
 
451
465
  def test_load_config
452
- tmp_dir = "#{TMP_DIR}/dir/test_load_config.conf"
466
+ tmp_dir = "#{@tmp_dir}/dir/test_load_config.conf"
453
467
  conf_info_str = %[
454
468
  <system>
455
469
  log_level info
@@ -520,7 +534,7 @@ class SupervisorTest < ::Test::Unit::TestCase
520
534
  end
521
535
 
522
536
  def test_load_config_for_logger
523
- tmp_dir = "#{TMP_DIR}/dir/test_load_config_log.conf"
537
+ tmp_dir = "#{@tmp_dir}/dir/test_load_config_log.conf"
524
538
  conf_info_str = %[
525
539
  <system>
526
540
  <log>
@@ -547,7 +561,7 @@ class SupervisorTest < ::Test::Unit::TestCase
547
561
  end
548
562
 
549
563
  def test_load_config_for_daemonize
550
- tmp_dir = "#{TMP_DIR}/dir/test_load_config.conf"
564
+ tmp_dir = "#{@tmp_dir}/dir/test_load_config.conf"
551
565
  conf_info_str = %[
552
566
  <system>
553
567
  log_level info
@@ -644,7 +658,7 @@ class SupervisorTest < ::Test::Unit::TestCase
644
658
  )
645
659
  def test_logger_with_rotate_age_and_rotate_size(rotate_age)
646
660
  opts = Fluent::Supervisor.default_options.merge(
647
- log_path: "#{TMP_DIR}/test", log_rotate_age: rotate_age, log_rotate_size: 10
661
+ log_path: "#{@tmp_dir}/test", log_rotate_age: rotate_age, log_rotate_size: 10
648
662
  )
649
663
  sv = Fluent::Supervisor.new(opts)
650
664
  log = sv.instance_variable_get(:@log)
@@ -674,7 +688,7 @@ class SupervisorTest < ::Test::Unit::TestCase
674
688
  file.puts(config)
675
689
  file.flush
676
690
  opts = Fluent::Supervisor.default_options.merge(
677
- log_path: "#{TMP_DIR}/test.log", config_path: file.path
691
+ log_path: "#{@tmp_dir}/test.log", config_path: file.path
678
692
  )
679
693
  sv = Fluent::Supervisor.new(opts)
680
694
 
@@ -699,7 +713,7 @@ class SupervisorTest < ::Test::Unit::TestCase
699
713
  file.puts(config)
700
714
  file.flush
701
715
  opts = Fluent::Supervisor.default_options.merge(
702
- log_path: "#{TMP_DIR}/test.log", config_path: file.path, config_file_type: :yaml,
716
+ log_path: "#{@tmp_dir}/test.log", config_path: file.path, config_file_type: :yaml,
703
717
  )
704
718
  sv = Fluent::Supervisor.new(opts)
705
719
 
@@ -773,6 +787,14 @@ class SupervisorTest < ::Test::Unit::TestCase
773
787
  end
774
788
  end
775
789
 
790
+ def test_per_process_path
791
+ path = Fluent::Supervisor::LoggerInitializer.per_process_path("C:/tmp/test.log", :supervisor, 0)
792
+ assert_equal(path, "C:/tmp/test-supervisor-0.log")
793
+
794
+ path = Fluent::Supervisor::LoggerInitializer.per_process_path("C:/tmp/test.log", :worker, 1)
795
+ assert_equal(path, "C:/tmp/test-1.log")
796
+ end
797
+
776
798
  def create_debug_dummy_logger
777
799
  dl_opts = {}
778
800
  dl_opts[:log_level] = ServerEngine::DaemonLogger::DEBUG
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluentd
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.15.1
4
+ version: 1.15.3
5
5
  platform: x64-mingw-ucrt
6
6
  authors:
7
7
  - Sadayuki Furuhashi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-07-27 00:00:00.000000000 Z
11
+ date: 2022-11-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -206,26 +206,6 @@ dependencies:
206
206
  - - "<"
207
207
  - !ruby/object:Gem::Version
208
208
  version: 1.8.0
209
- - !ruby/object:Gem::Dependency
210
- name: win32-api
211
- requirement: !ruby/object:Gem::Requirement
212
- requirements:
213
- - - ">="
214
- - !ruby/object:Gem::Version
215
- version: '1.10'
216
- - - "<"
217
- - !ruby/object:Gem::Version
218
- version: 2.0.0
219
- type: :runtime
220
- prerelease: false
221
- version_requirements: !ruby/object:Gem::Requirement
222
- requirements:
223
- - - ">="
224
- - !ruby/object:Gem::Version
225
- version: '1.10'
226
- - - "<"
227
- - !ruby/object:Gem::Version
228
- version: 2.0.0
229
209
  - !ruby/object:Gem::Dependency
230
210
  name: win32-service
231
211
  requirement: !ruby/object:Gem::Requirement
@@ -268,34 +248,6 @@ dependencies:
268
248
  - - "~>"
269
249
  - !ruby/object:Gem::Version
270
250
  version: 0.6.3
271
- - !ruby/object:Gem::Dependency
272
- name: windows-api
273
- requirement: !ruby/object:Gem::Requirement
274
- requirements:
275
- - - "~>"
276
- - !ruby/object:Gem::Version
277
- version: 0.4.5
278
- type: :runtime
279
- prerelease: false
280
- version_requirements: !ruby/object:Gem::Requirement
281
- requirements:
282
- - - "~>"
283
- - !ruby/object:Gem::Version
284
- version: 0.4.5
285
- - !ruby/object:Gem::Dependency
286
- name: windows-pr
287
- requirement: !ruby/object:Gem::Requirement
288
- requirements:
289
- - - "~>"
290
- - !ruby/object:Gem::Version
291
- version: 1.2.6
292
- type: :runtime
293
- prerelease: false
294
- version_requirements: !ruby/object:Gem::Requirement
295
- requirements:
296
- - - "~>"
297
- - !ruby/object:Gem::Version
298
- version: 1.2.6
299
251
  - !ruby/object:Gem::Dependency
300
252
  name: certstore_c
301
253
  requirement: !ruby/object:Gem::Requirement
@@ -495,10 +447,8 @@ files:
495
447
  - ".github/ISSUE_TEMPLATE/config.yml"
496
448
  - ".github/ISSUE_TEMPLATE/feature_request.yaml"
497
449
  - ".github/PULL_REQUEST_TEMPLATE.md"
498
- - ".github/workflows/issue-auto-closer.yml"
499
450
  - ".github/workflows/linux-test.yaml"
500
451
  - ".github/workflows/macos-test.yaml"
501
- - ".github/workflows/stale-actions.yml"
502
452
  - ".github/workflows/windows-test.yaml"
503
453
  - ".gitignore"
504
454
  - ".gitlab-ci.yml"
@@ -633,6 +583,7 @@ files:
633
583
  - lib/fluent/event.rb
634
584
  - lib/fluent/event_router.rb
635
585
  - lib/fluent/ext_monitor_require.rb
586
+ - lib/fluent/file_wrapper.rb
636
587
  - lib/fluent/filter.rb
637
588
  - lib/fluent/fluent_log_event_router.rb
638
589
  - lib/fluent/formatter.rb
@@ -661,7 +612,6 @@ files:
661
612
  - lib/fluent/plugin/compressable.rb
662
613
  - lib/fluent/plugin/exec_util.rb
663
614
  - lib/fluent/plugin/file_util.rb
664
- - lib/fluent/plugin/file_wrapper.rb
665
615
  - lib/fluent/plugin/filter.rb
666
616
  - lib/fluent/plugin/filter_grep.rb
667
617
  - lib/fluent/plugin/filter_parser.rb
@@ -809,6 +759,7 @@ files:
809
759
  - lib/fluent/unique_id.rb
810
760
  - lib/fluent/variable_store.rb
811
761
  - lib/fluent/version.rb
762
+ - lib/fluent/win32api.rb
812
763
  - lib/fluent/winsvc.rb
813
764
  - templates/new_gem/Gemfile
814
765
  - templates/new_gem/README.md.erb
@@ -893,7 +844,6 @@ files:
893
844
  - test/plugin/test_buffer_memory_chunk.rb
894
845
  - test/plugin/test_compressable.rb
895
846
  - test/plugin/test_file_util.rb
896
- - test/plugin/test_file_wrapper.rb
897
847
  - test/plugin/test_filter.rb
898
848
  - test/plugin/test_filter_grep.rb
899
849
  - test/plugin/test_filter_parser.rb
@@ -1025,6 +975,7 @@ files:
1025
975
  - test/test_event.rb
1026
976
  - test/test_event_router.rb
1027
977
  - test/test_event_time.rb
978
+ - test/test_file_wrapper.rb
1028
979
  - test/test_filter.rb
1029
980
  - test/test_fluent_log_event_router.rb
1030
981
  - test/test_formatter.rb
@@ -1069,7 +1020,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1069
1020
  - !ruby/object:Gem::Version
1070
1021
  version: '0'
1071
1022
  requirements: []
1072
- rubygems_version: 3.3.5
1023
+ rubygems_version: 3.3.17
1073
1024
  signing_key:
1074
1025
  specification_version: 4
1075
1026
  summary: Fluentd event collector
@@ -1136,7 +1087,6 @@ test_files:
1136
1087
  - test/plugin/test_buffer_memory_chunk.rb
1137
1088
  - test/plugin/test_compressable.rb
1138
1089
  - test/plugin/test_file_util.rb
1139
- - test/plugin/test_file_wrapper.rb
1140
1090
  - test/plugin/test_filter.rb
1141
1091
  - test/plugin/test_filter_grep.rb
1142
1092
  - test/plugin/test_filter_parser.rb
@@ -1268,6 +1218,7 @@ test_files:
1268
1218
  - test/test_event.rb
1269
1219
  - test/test_event_router.rb
1270
1220
  - test/test_event_time.rb
1221
+ - test/test_file_wrapper.rb
1271
1222
  - test/test_filter.rb
1272
1223
  - test/test_fluent_log_event_router.rb
1273
1224
  - test/test_formatter.rb
@@ -1,12 +0,0 @@
1
- name: Autocloser
2
- on: [issues]
3
- jobs:
4
- autoclose:
5
- runs-on: ubuntu-latest
6
- steps:
7
- - name: Autoclose issues that did not follow issue template
8
- uses: roots/issue-closer-action@v1.1
9
- with:
10
- repo-token: ${{ secrets.GITHUB_TOKEN }}
11
- issue-close-message: "@${issue.user.login} this issue was automatically closed because it did not follow the issue template"
12
- issue-pattern: "(.*Describe the bug.*)|(.*Is your feature request related to a problem.*)"
@@ -1,22 +0,0 @@
1
- name: "Mark or close stale issues and PRs"
2
- on:
3
- schedule:
4
- - cron: "00 10 * * *"
5
-
6
- jobs:
7
- stale:
8
- runs-on: ubuntu-latest
9
- steps:
10
- - uses: actions/stale@v3
11
- with:
12
- repo-token: ${{ secrets.GITHUB_TOKEN }}
13
- days-before-stale: 90
14
- days-before-close: 30
15
- stale-issue-message: "This issue has been automatically marked as stale because it has been open 90 days with no activity. Remove stale label or comment or this issue will be closed in 30 days"
16
- stale-pr-message: "This PR has been automatically marked as stale because it has been open 90 days with no activity. Remove stale label or comment or this PR will be closed in 30 days"
17
- close-issue-message: "This issue was automatically closed because of stale in 30 days"
18
- close-pr-message: "This PR was automatically closed because of stale in 30 days"
19
- stale-pr-label: "stale"
20
- stale-issue-label: "stale"
21
- exempt-issue-labels: "bug,enhancement,feature request,pending,work_in_progress,v1,v2"
22
- exempt-pr-labels: "bug,enhancement,feature request,pending,work_in_progress,v1,v2"
@@ -1,132 +0,0 @@
1
- #
2
- # Fluentd
3
- #
4
- # Licensed under the Apache License, Version 2.0 (the "License");
5
- # you may not use this file except in compliance with the License.
6
- # You may obtain a copy of the License at
7
- #
8
- # http://www.apache.org/licenses/LICENSE-2.0
9
- #
10
- # Unless required by applicable law or agreed to in writing, software
11
- # distributed under the License is distributed on an "AS IS" BASIS,
12
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- # See the License for the specific language governing permissions and
14
- # limitations under the License.
15
- #
16
-
17
- module Fluent
18
- module FileWrapper
19
- def self.open(path, mode='r')
20
- io = WindowsFile.new(path, mode).io
21
- if block_given?
22
- v = yield io
23
- io.close
24
- v
25
- else
26
- io
27
- end
28
- end
29
-
30
- def self.stat(path)
31
- f = WindowsFile.new(path)
32
- s = f.stat
33
- f.close
34
- s
35
- end
36
- end
37
-
38
- class WindowsFile
39
- require 'windows/file'
40
- require 'windows/handle'
41
-
42
- include File::Constants
43
- include Windows::File
44
- include Windows::Handle
45
-
46
- attr_reader :io
47
-
48
- def initialize(path, mode='r')
49
- @path = path
50
- @io = File.open(path, mode2flags(mode))
51
- @file_handle = _get_osfhandle(@io.to_i)
52
- @io.instance_variable_set(:@file_index, self.ino)
53
- def @io.ino
54
- @file_index
55
- end
56
- end
57
-
58
- def close
59
- @io.close
60
- @file_handle = INVALID_HANDLE_VALUE
61
- end
62
-
63
- # To keep backward compatibility, we continue to use GetFileInformationByHandle()
64
- # to get file id.
65
- # Note that Ruby's File.stat uses GetFileInformationByHandleEx() with FileIdInfo
66
- # and returned value is different with above one, former one is 64 bit while
67
- # later one is 128bit.
68
- def ino
69
- by_handle_file_information = '\0'*(4+8+8+8+4+4+4+4+4+4) #72bytes
70
-
71
- unless GetFileInformationByHandle.call(@file_handle, by_handle_file_information)
72
- return 0
73
- end
74
-
75
- by_handle_file_information.unpack("I11Q1")[11] # fileindex
76
- end
77
-
78
- def stat
79
- raise Errno::ENOENT if delete_pending
80
- s = File.stat(@path)
81
- s.instance_variable_set :@ino, self.ino
82
- def s.ino; @ino; end
83
- s
84
- end
85
-
86
- private
87
-
88
- def mode2flags(mode)
89
- # Always inject File::Constants::SHARE_DELETE
90
- # https://github.com/fluent/fluentd/pull/3585#issuecomment-1101502617
91
- # To enable SHARE_DELETE, BINARY is also required.
92
- # https://bugs.ruby-lang.org/issues/11218
93
- # https://github.com/ruby/ruby/blob/d6684f063bc53e3cab025bd39526eca3b480b5e7/win32/win32.c#L6332-L6345
94
- flags = BINARY | SHARE_DELETE
95
- case mode.delete("b")
96
- when "r"
97
- flags |= RDONLY
98
- when "r+"
99
- flags |= RDWR
100
- when "w"
101
- flags |= WRONLY | CREAT | TRUNC
102
- when "w+"
103
- flags |= RDWR | CREAT | TRUNC
104
- when "a"
105
- flags |= WRONLY | CREAT | APPEND
106
- when "a+"
107
- flags |= RDWR | CREAT | APPEND
108
- else
109
- raise Errno::EINVAL.new("Unsupported mode by Fluent::FileWrapper: #{mode}")
110
- end
111
- end
112
-
113
- # DeletePending is a Windows-specific file state that roughly means
114
- # "this file is queued for deletion, so close any open handlers"
115
- #
116
- # This flag can be retrieved via GetFileInformationByHandleEx().
117
- #
118
- # https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getfileinformationbyhandleex
119
- #
120
- def delete_pending
121
- file_standard_info = 0x01
122
- bufsize = 1024
123
- buf = '\0' * bufsize
124
-
125
- unless GetFileInformationByHandleEx.call(@file_handle, file_standard_info, buf, bufsize)
126
- return false
127
- end
128
-
129
- return buf.unpack("QQICC")[3] != 0
130
- end
131
- end
132
- end if Fluent.windows?