Skip to content

Commit

Permalink
Add IO::Error#target (crystal-lang#13865)
Browse files Browse the repository at this point in the history
  • Loading branch information
straight-shoota authored Nov 28, 2023
1 parent a59b5ab commit 9082692
Show file tree
Hide file tree
Showing 9 changed files with 54 additions and 32 deletions.
4 changes: 2 additions & 2 deletions spec/std/file_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -941,7 +941,7 @@ describe "File" do
pending! "Spec cannot run as superuser"
end
{% end %}
expect_raises(File::AccessDeniedError) { File.read(path) }
expect_raises(File::AccessDeniedError, path) { File.read(path) }
end
end
{% end %}
Expand All @@ -958,7 +958,7 @@ describe "File" do
pending! "Spec cannot run as superuser"
end
{% end %}
expect_raises(File::AccessDeniedError) { File.write(path, "foo") }
expect_raises(File::AccessDeniedError, path) { File.write(path, "foo") }
end
end

Expand Down
6 changes: 3 additions & 3 deletions src/crystal/system/unix/file.cr
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ module Crystal::System::File
sleep 0.1
end
else
flock(op) || raise IO::Error.from_errno("Error applying file lock: file is already locked")
flock(op) || raise IO::Error.from_errno("Error applying file lock: file is already locked", target: self)
end
end

Expand All @@ -251,7 +251,7 @@ module Crystal::System::File
if errno.in?(Errno::EAGAIN, Errno::EWOULDBLOCK)
false
else
raise IO::Error.from_os_error("Error applying or removing file lock", errno)
raise IO::Error.from_os_error("Error applying or removing file lock", errno, target: self)
end
end
end
Expand All @@ -269,7 +269,7 @@ module Crystal::System::File
end

if ret != 0
raise IO::Error.from_errno("Error syncing file")
raise IO::Error.from_errno("Error syncing file", target: self)
end
end
end
10 changes: 5 additions & 5 deletions src/crystal/system/unix/file_descriptor.cr
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ module Crystal::System::FileDescriptor
evented_read(slice, "Error reading file") do
LibC.read(fd, slice, slice.size).tap do |return_code|
if return_code == -1 && Errno.value == Errno::EBADF
raise IO::Error.new "File not open for reading"
raise IO::Error.new "File not open for reading", target: self
end
end
end
Expand All @@ -25,7 +25,7 @@ module Crystal::System::FileDescriptor
evented_write(slice, "Error writing file") do |slice|
LibC.write(fd, slice, slice.size).tap do |return_code|
if return_code == -1 && Errno.value == Errno::EBADF
raise IO::Error.new "File not open for writing"
raise IO::Error.new "File not open for writing", target: self
end
end
end
Expand Down Expand Up @@ -90,13 +90,13 @@ module Crystal::System::FileDescriptor
seek_value = LibC.lseek(fd, offset, whence)

if seek_value == -1
raise IO::Error.from_errno "Unable to seek"
raise IO::Error.from_errno "Unable to seek", target: self
end
end

private def system_pos
pos = LibC.lseek(fd, 0, IO::Seek::Current).to_i64
raise IO::Error.from_errno "Unable to tell" if pos == -1
raise IO::Error.from_errno("Unable to tell", target: self) if pos == -1
pos
end

Expand Down Expand Up @@ -147,7 +147,7 @@ module Crystal::System::FileDescriptor
when Errno::EINTR, Errno::EINPROGRESS
# ignore
else
raise IO::Error.from_errno("Error closing file")
raise IO::Error.from_errno("Error closing file", target: self)
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions src/crystal/system/win32/file.cr
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ module Crystal::System::File
if winerror == WinError::ERROR_LOCK_VIOLATION
false
else
raise IO::Error.from_os_error("LockFileEx", winerror)
raise IO::Error.from_os_error("LockFileEx", winerror, target: self)
end
end
end
Expand All @@ -509,7 +509,7 @@ module Crystal::System::File

private def system_fsync(flush_metadata = true) : Nil
if LibC._commit(fd) != 0
raise IO::Error.from_errno("Error syncing file")
raise IO::Error.from_errno("Error syncing file", target: self)
end
end
end
18 changes: 9 additions & 9 deletions src/crystal/system/win32/file_descriptor.cr
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ module Crystal::System::FileDescriptor
bytes_read = LibC._read(fd, slice, slice.size)
if bytes_read == -1
if Errno.value == Errno::EBADF
raise IO::Error.new "File not open for reading"
raise IO::Error.new "File not open for reading", target: self
else
raise IO::Error.from_errno("Error reading file")
raise IO::Error.from_errno("Error reading file", target: self)
end
end
bytes_read
Expand All @@ -36,9 +36,9 @@ module Crystal::System::FileDescriptor
bytes_written = LibC._write(fd, slice, slice.size)
if bytes_written == -1
if Errno.value == Errno::EBADF
raise IO::Error.new "File not open for writing"
raise IO::Error.new "File not open for writing", target: self
else
raise IO::Error.from_errno("Error writing file")
raise IO::Error.from_errno("Error writing file", target: self)
end
end
else
Expand Down Expand Up @@ -106,7 +106,7 @@ module Crystal::System::FileDescriptor

if file_type == LibC::FILE_TYPE_UNKNOWN
error = WinError.value
raise IO::Error.from_os_error("Unable to get info", error) unless error == WinError::ERROR_SUCCESS
raise IO::Error.from_os_error("Unable to get info", error, target: self) unless error == WinError::ERROR_SUCCESS
end
end

Expand All @@ -129,13 +129,13 @@ module Crystal::System::FileDescriptor
seek_value = LibC._lseeki64(fd, offset, whence)

if seek_value == -1
raise IO::Error.from_errno "Unable to seek"
raise IO::Error.from_errno "Unable to seek", target: self
end
end

private def system_pos
pos = LibC._lseeki64(fd, 0, IO::Seek::Current)
raise IO::Error.from_errno "Unable to tell" if pos == -1
raise IO::Error.from_errno("Unable to tell", target: self) if pos == -1
pos
end

Expand Down Expand Up @@ -165,7 +165,7 @@ module Crystal::System::FileDescriptor
when Errno::EINTR
# ignore
else
raise IO::Error.from_errno("Error closing file")
raise IO::Error.from_errno("Error closing file", target: self)
end
end
end
Expand Down Expand Up @@ -204,7 +204,7 @@ module Crystal::System::FileDescriptor
if LibC.ReadFile(handle, buffer, buffer.size, out bytes_read, pointerof(overlapped)) == 0
error = WinError.value
return 0_i64 if error == WinError::ERROR_HANDLE_EOF
raise IO::Error.from_os_error "Error reading file", error
raise IO::Error.from_os_error "Error reading file", error, target: self
end

bytes_read.to_i64
Expand Down
14 changes: 8 additions & 6 deletions src/file/error.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ class File < IO::FileDescriptor
end

class File::Error < IO::Error
getter file : String
getter other : String?

def file : String
target.not_nil!
end

private def self.new_from_os_error(message, os_error, **opts)
case os_error
when Errno::ENOENT, WinError::ERROR_FILE_NOT_FOUND, WinError::ERROR_PATH_NOT_FOUND
Expand All @@ -20,6 +23,10 @@ class File::Error < IO::Error
end
end

def initialize(message, *, file : String | Path, @other : String? = nil)
super message, target: file
end

protected def self.build_message(message, *, file : String) : String
"#{message}: '#{file.inspect_unquoted}'"
end
Expand All @@ -38,11 +45,6 @@ class File::Error < IO::Error
end
end
{% end %}

def initialize(message, *, file : String | Path, @other : String? = nil)
@file = file.to_s
super message
end
end

class File::NotFoundError < File::Error
Expand Down
20 changes: 20 additions & 0 deletions src/io/error.cr
Original file line number Diff line number Diff line change
@@ -1,6 +1,26 @@
class IO
class Error < Exception
include SystemError

getter target : String?

protected def self.build_message(message, *, target : File) : String
build_message(message, target: target.path)
end

protected def self.build_message(message, *, target : Nil) : String
message
end

protected def self.build_message(message, *, target) : String
"#{message} (#{target})"
end

def initialize(message : String? = nil, *, target = nil)
@target = target.try(&.to_s)

super message
end
end

# Raised when an `IO` operation times out.
Expand Down
4 changes: 2 additions & 2 deletions src/io/evented.cr
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ module IO::Evented
if Errno.value == Errno::EAGAIN
wait_readable
else
raise IO::Error.from_errno(errno_msg)
raise IO::Error.from_errno(errno_msg, target: self)
end
end
ensure
Expand All @@ -79,7 +79,7 @@ module IO::Evented
if Errno.value == Errno::EAGAIN
wait_writable
else
raise IO::Error.from_errno(errno_msg)
raise IO::Error.from_errno(errno_msg, target: self)
end
end
end
Expand Down
6 changes: 3 additions & 3 deletions src/io/overlapped.cr
Original file line number Diff line number Diff line change
Expand Up @@ -211,9 +211,9 @@ module IO::Overlapped
when .error_io_pending?
# the operation is running asynchronously; do nothing
when .error_access_denied?
raise IO::Error.new "File not open for #{writing ? "writing" : "reading"}"
raise IO::Error.new "File not open for #{writing ? "writing" : "reading"}", target: self
else
raise IO::Error.from_os_error(method, error)
raise IO::Error.from_os_error(method, error, target: self)
end
else
operation.synchronous = true
Expand Down Expand Up @@ -245,7 +245,7 @@ module IO::Overlapped
when .wsa_io_pending?
# the operation is running asynchronously; do nothing
else
raise IO::Error.from_os_error(method, error)
raise IO::Error.from_os_error(method, error, target: self)
end
else
operation.synchronous = true
Expand Down

0 comments on commit 9082692

Please sign in to comment.