Skip to content

Commit 9082692

Browse files
Add IO::Error#target (#13865)
1 parent a59b5ab commit 9082692

File tree

9 files changed

+54
-32
lines changed

9 files changed

+54
-32
lines changed

spec/std/file_spec.cr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -941,7 +941,7 @@ describe "File" do
941941
pending! "Spec cannot run as superuser"
942942
end
943943
{% end %}
944-
expect_raises(File::AccessDeniedError) { File.read(path) }
944+
expect_raises(File::AccessDeniedError, path) { File.read(path) }
945945
end
946946
end
947947
{% end %}
@@ -958,7 +958,7 @@ describe "File" do
958958
pending! "Spec cannot run as superuser"
959959
end
960960
{% end %}
961-
expect_raises(File::AccessDeniedError) { File.write(path, "foo") }
961+
expect_raises(File::AccessDeniedError, path) { File.write(path, "foo") }
962962
end
963963
end
964964

src/crystal/system/unix/file.cr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ module Crystal::System::File
239239
sleep 0.1
240240
end
241241
else
242-
flock(op) || raise IO::Error.from_errno("Error applying file lock: file is already locked")
242+
flock(op) || raise IO::Error.from_errno("Error applying file lock: file is already locked", target: self)
243243
end
244244
end
245245

@@ -251,7 +251,7 @@ module Crystal::System::File
251251
if errno.in?(Errno::EAGAIN, Errno::EWOULDBLOCK)
252252
false
253253
else
254-
raise IO::Error.from_os_error("Error applying or removing file lock", errno)
254+
raise IO::Error.from_os_error("Error applying or removing file lock", errno, target: self)
255255
end
256256
end
257257
end
@@ -269,7 +269,7 @@ module Crystal::System::File
269269
end
270270

271271
if ret != 0
272-
raise IO::Error.from_errno("Error syncing file")
272+
raise IO::Error.from_errno("Error syncing file", target: self)
273273
end
274274
end
275275
end

src/crystal/system/unix/file_descriptor.cr

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ module Crystal::System::FileDescriptor
1515
evented_read(slice, "Error reading file") do
1616
LibC.read(fd, slice, slice.size).tap do |return_code|
1717
if return_code == -1 && Errno.value == Errno::EBADF
18-
raise IO::Error.new "File not open for reading"
18+
raise IO::Error.new "File not open for reading", target: self
1919
end
2020
end
2121
end
@@ -25,7 +25,7 @@ module Crystal::System::FileDescriptor
2525
evented_write(slice, "Error writing file") do |slice|
2626
LibC.write(fd, slice, slice.size).tap do |return_code|
2727
if return_code == -1 && Errno.value == Errno::EBADF
28-
raise IO::Error.new "File not open for writing"
28+
raise IO::Error.new "File not open for writing", target: self
2929
end
3030
end
3131
end
@@ -90,13 +90,13 @@ module Crystal::System::FileDescriptor
9090
seek_value = LibC.lseek(fd, offset, whence)
9191

9292
if seek_value == -1
93-
raise IO::Error.from_errno "Unable to seek"
93+
raise IO::Error.from_errno "Unable to seek", target: self
9494
end
9595
end
9696

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

@@ -147,7 +147,7 @@ module Crystal::System::FileDescriptor
147147
when Errno::EINTR, Errno::EINPROGRESS
148148
# ignore
149149
else
150-
raise IO::Error.from_errno("Error closing file")
150+
raise IO::Error.from_errno("Error closing file", target: self)
151151
end
152152
end
153153
end

src/crystal/system/win32/file.cr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,7 @@ module Crystal::System::File
493493
if winerror == WinError::ERROR_LOCK_VIOLATION
494494
false
495495
else
496-
raise IO::Error.from_os_error("LockFileEx", winerror)
496+
raise IO::Error.from_os_error("LockFileEx", winerror, target: self)
497497
end
498498
end
499499
end
@@ -509,7 +509,7 @@ module Crystal::System::File
509509

510510
private def system_fsync(flush_metadata = true) : Nil
511511
if LibC._commit(fd) != 0
512-
raise IO::Error.from_errno("Error syncing file")
512+
raise IO::Error.from_errno("Error syncing file", target: self)
513513
end
514514
end
515515
end

src/crystal/system/win32/file_descriptor.cr

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ module Crystal::System::FileDescriptor
1515
bytes_read = LibC._read(fd, slice, slice.size)
1616
if bytes_read == -1
1717
if Errno.value == Errno::EBADF
18-
raise IO::Error.new "File not open for reading"
18+
raise IO::Error.new "File not open for reading", target: self
1919
else
20-
raise IO::Error.from_errno("Error reading file")
20+
raise IO::Error.from_errno("Error reading file", target: self)
2121
end
2222
end
2323
bytes_read
@@ -36,9 +36,9 @@ module Crystal::System::FileDescriptor
3636
bytes_written = LibC._write(fd, slice, slice.size)
3737
if bytes_written == -1
3838
if Errno.value == Errno::EBADF
39-
raise IO::Error.new "File not open for writing"
39+
raise IO::Error.new "File not open for writing", target: self
4040
else
41-
raise IO::Error.from_errno("Error writing file")
41+
raise IO::Error.from_errno("Error writing file", target: self)
4242
end
4343
end
4444
else
@@ -106,7 +106,7 @@ module Crystal::System::FileDescriptor
106106

107107
if file_type == LibC::FILE_TYPE_UNKNOWN
108108
error = WinError.value
109-
raise IO::Error.from_os_error("Unable to get info", error) unless error == WinError::ERROR_SUCCESS
109+
raise IO::Error.from_os_error("Unable to get info", error, target: self) unless error == WinError::ERROR_SUCCESS
110110
end
111111
end
112112

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

131131
if seek_value == -1
132-
raise IO::Error.from_errno "Unable to seek"
132+
raise IO::Error.from_errno "Unable to seek", target: self
133133
end
134134
end
135135

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

@@ -165,7 +165,7 @@ module Crystal::System::FileDescriptor
165165
when Errno::EINTR
166166
# ignore
167167
else
168-
raise IO::Error.from_errno("Error closing file")
168+
raise IO::Error.from_errno("Error closing file", target: self)
169169
end
170170
end
171171
end
@@ -204,7 +204,7 @@ module Crystal::System::FileDescriptor
204204
if LibC.ReadFile(handle, buffer, buffer.size, out bytes_read, pointerof(overlapped)) == 0
205205
error = WinError.value
206206
return 0_i64 if error == WinError::ERROR_HANDLE_EOF
207-
raise IO::Error.from_os_error "Error reading file", error
207+
raise IO::Error.from_os_error "Error reading file", error, target: self
208208
end
209209

210210
bytes_read.to_i64

src/file/error.cr

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ class File < IO::FileDescriptor
22
end
33

44
class File::Error < IO::Error
5-
getter file : String
65
getter other : String?
76

7+
def file : String
8+
target.not_nil!
9+
end
10+
811
private def self.new_from_os_error(message, os_error, **opts)
912
case os_error
1013
when Errno::ENOENT, WinError::ERROR_FILE_NOT_FOUND, WinError::ERROR_PATH_NOT_FOUND
@@ -20,6 +23,10 @@ class File::Error < IO::Error
2023
end
2124
end
2225

26+
def initialize(message, *, file : String | Path, @other : String? = nil)
27+
super message, target: file
28+
end
29+
2330
protected def self.build_message(message, *, file : String) : String
2431
"#{message}: '#{file.inspect_unquoted}'"
2532
end
@@ -38,11 +45,6 @@ class File::Error < IO::Error
3845
end
3946
end
4047
{% end %}
41-
42-
def initialize(message, *, file : String | Path, @other : String? = nil)
43-
@file = file.to_s
44-
super message
45-
end
4648
end
4749

4850
class File::NotFoundError < File::Error

src/io/error.cr

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,26 @@
11
class IO
22
class Error < Exception
33
include SystemError
4+
5+
getter target : String?
6+
7+
protected def self.build_message(message, *, target : File) : String
8+
build_message(message, target: target.path)
9+
end
10+
11+
protected def self.build_message(message, *, target : Nil) : String
12+
message
13+
end
14+
15+
protected def self.build_message(message, *, target) : String
16+
"#{message} (#{target})"
17+
end
18+
19+
def initialize(message : String? = nil, *, target = nil)
20+
@target = target.try(&.to_s)
21+
22+
super message
23+
end
424
end
525

626
# Raised when an `IO` operation times out.

src/io/evented.cr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ module IO::Evented
5858
if Errno.value == Errno::EAGAIN
5959
wait_readable
6060
else
61-
raise IO::Error.from_errno(errno_msg)
61+
raise IO::Error.from_errno(errno_msg, target: self)
6262
end
6363
end
6464
ensure
@@ -79,7 +79,7 @@ module IO::Evented
7979
if Errno.value == Errno::EAGAIN
8080
wait_writable
8181
else
82-
raise IO::Error.from_errno(errno_msg)
82+
raise IO::Error.from_errno(errno_msg, target: self)
8383
end
8484
end
8585
end

src/io/overlapped.cr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -211,9 +211,9 @@ module IO::Overlapped
211211
when .error_io_pending?
212212
# the operation is running asynchronously; do nothing
213213
when .error_access_denied?
214-
raise IO::Error.new "File not open for #{writing ? "writing" : "reading"}"
214+
raise IO::Error.new "File not open for #{writing ? "writing" : "reading"}", target: self
215215
else
216-
raise IO::Error.from_os_error(method, error)
216+
raise IO::Error.from_os_error(method, error, target: self)
217217
end
218218
else
219219
operation.synchronous = true
@@ -245,7 +245,7 @@ module IO::Overlapped
245245
when .wsa_io_pending?
246246
# the operation is running asynchronously; do nothing
247247
else
248-
raise IO::Error.from_os_error(method, error)
248+
raise IO::Error.from_os_error(method, error, target: self)
249249
end
250250
else
251251
operation.synchronous = true

0 commit comments

Comments
 (0)