Skip to content

Commit

Permalink
WindowsFile: Fix incorrect error message
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
ashie committed Apr 12, 2021
1 parent 4b1ee63 commit 55af3e8
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 1 deletion.
29 changes: 28 additions & 1 deletion lib/fluent/plugin/file_wrapper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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

Expand Down
77 changes: 77 additions & 0 deletions test/plugin/test_file_wrapper.rb
Original file line number Diff line number Diff line change
@@ -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?

0 comments on commit 55af3e8

Please sign in to comment.