From 55af3e82e40f463ccef20444a314f6bdd1ef1265 Mon Sep 17 00:00:00 2001 From: Takuro Ashie Date: Mon, 12 Apr 2021 14:27:24 +0900 Subject: [PATCH] WindowsFile: Fix incorrect error message It passes win32 error codes to SystemCallError so that it doesn't show correct message for them. For example when ERROR_SHARING_VIOLATION(32) of win32 occurs, it shows Errno::EPIPE(32). Signed-off-by: Takuro Ashie --- lib/fluent/plugin/file_wrapper.rb | 29 +++++++++++- test/plugin/test_file_wrapper.rb | 77 +++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 test/plugin/test_file_wrapper.rb diff --git a/lib/fluent/plugin/file_wrapper.rb b/lib/fluent/plugin/file_wrapper.rb index 0970ecc931..f2f9faa89a 100644 --- a/lib/fluent/plugin/file_wrapper.rb +++ b/lib/fluent/plugin/file_wrapper.rb @@ -46,6 +46,33 @@ def s.ino; @ino; end end end + class Win32Error < StandardError + require 'windows/error' + include Windows::Error + + attr_reader :errcode + + def initialize(errcode) + @errcode = errcode + end + + def format_english_message(errcode) + buf = 0.chr * 260 + flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY + english_lang_id = 1033 # The result of MAKELANDID(LANG_ENGLISH, SUBLANG_ENGLISH_US) + FormatMessageA.call(flags, 0, errcode, english_lang_id, buf, buf.size, 0) + buf.force_encoding(Encoding.default_external).strip + end + + def message + "code: #{@errcode}, #{format_english_message(@errcode)}" + end + + def ==(other) + @errcode == other.errcode + end + end + # To open and get stat with setting FILE_SHARE_DELETE class WindowsFile require 'windows/file' @@ -81,7 +108,7 @@ def initialize(path, mode='r', sharemode=FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_S if err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND || err == ERROR_ACCESS_DENIED raise SystemCallError.new(2) end - raise SystemCallError.new(err) + raise Win32Error.new(err) end end diff --git a/test/plugin/test_file_wrapper.rb b/test/plugin/test_file_wrapper.rb new file mode 100644 index 0000000000..bcda1791ec --- /dev/null +++ b/test/plugin/test_file_wrapper.rb @@ -0,0 +1,77 @@ +require_relative '../helper' +require 'fluent/plugin/file_wrapper' + +class FileWrapperTest < Test::Unit::TestCase + require 'windows/file' + include Windows::File + + TMP_DIR = File.dirname(__FILE__) + "/../tmp/file_wrapper#{ENV['TEST_ENV_NUMBER']}" + + def setup + FileUtils.mkdir_p(TMP_DIR) + end + + def teardown + FileUtils.rm_rf(TMP_DIR) + end + + sub_test_case 'Win32Error' do + test 'equal' do + assert_equal(Fluent::Win32Error.new(32), + Fluent::Win32Error.new(32)) + end + + test 'not equal' do + assert_not_equal(Fluent::Win32Error.new(2), + Fluent::Win32Error.new(32)) + end + + test 'ERROR_SHARING_VIOLATION message' do + assert_equal(Fluent::Win32Error.new(32).message, + "code: 32, The process cannot access the file because it is being used by another process.") + end + end + + sub_test_case 'WindowsFile exceptions' do + test 'nothing raised' do + begin + path = "#{TMP_DIR}/test_windows_file.txt" + file1 = file2 = nil + file1 = File.open(path, "wb") do |f| + end + assert_nothing_raised do + file2 = Fluent::WindowsFile.new(path) + ensure + file2.close + end + ensure + file1.close if file1 + end + end + + test 'Errno::ENOENT raised' do + path = "#{TMP_DIR}/nofile.txt" + file = nil + assert_raise(SystemCallError.new(2)) do + file = Fluent::WindowsFile.new(path) + ensure + file.close if file + end + end + + test 'ERROR_SHARING_VIOLATION raised' do + begin + path = "#{TMP_DIR}/test_windows_file.txt" + file1 = file2 = nil + file1 = File.open(path, "wb") + assert_raise(Fluent::Win32Error.new(32)) do + file2 = Fluent::WindowsFile.new(path, 'r', FILE_SHARE_READ) + ensure + file2.close if file2 + end + ensure + file1.close if file1 + end + end + end +end if Fluent.windows?