-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
File#truncate
raises File::AccessDeniedError
on Windows when file was opened in append mode
#14702
Comments
This is odd. The handle should be created with Apparently that's not the case. The actual access mode value used is I'm also confused about both The documentation for |
https://learn.microsoft.com/en-us/windows/win32/fileio/file-access-rights-constants
So We're missing specs for both behaviours, this is how they could look like: it "does not overwrite existing content in append mode" do
with_tempfile("append-override.txt") do |filename|
File.write(filename, "0123456789")
File.open(filename, "a") do |file|
file.seek(5)
file.write "abcd".to_slice
end
File.read(filename).should eq "0123456789abcd"
end
end
it "truncates file opened in append mode (#14702)" do
with_tempfile("truncate-append.txt") do |path|
File.write(path, "0123456789")
File.open(path, "a") do |file|
file.truncate(4)
end
File.read(path).should eq "0123"
end
end On Windows, we need |
It seems CRT does not actually use @[Link("ntdll")]
lib LibC
alias NTSTATUS = Long
alias ACCESS_MASK = DWORD
enum OBJECT_INFORMATION_CLASS
ObjectBasicInformation = 0
end
struct PUBLIC_OBJECT_BASIC_INFORMATION
attributes : ULong
grantedAccess : ACCESS_MASK
handleCount : ULong
pointerCount : ULong
reserved : ULong[10]
end
fun NtQueryObject(
handle : HANDLE, objectInformationClass : OBJECT_INFORMATION_CLASS,
objectInformation : Void*, objectInformationLength : ULong, returnLength : ULong*
) : NTSTATUS
end
# same with or without `LibC::O_APPEND`
fd = LibC._wopen("README.md".to_utf16, LibC::O_WRONLY | LibC::O_APPEND | LibC::O_BINARY)
handle = LibC::HANDLE.new(LibC._get_osfhandle(fd))
pobi = uninitialized LibC::PUBLIC_OBJECT_BASIC_INFORMATION
LibC.NtQueryObject(handle, LibC::OBJECT_INFORMATION_CLASS::ObjectBasicInformation,
pointerof(pobi), sizeof(typeof(pobi)), out _)
pobi.grantedAccess.to_s(16) # => "120196" Every write simply seeks to the end of the file first. Wine does the same. Also |
Opening a file in append mode on Windows and then calling
File#truncate
on the opened file used to work prior to Crystal version 1.12.0.Pull request 14316 changed the Windows implementation of
File#truncate
to use SetEndOfFile, whose docs, if I'm reading it right, say the file handle must be opened in write mode, which would explain why truncate no longer works in append mode:The following code:
Throws a
File::AccessDeniedError
exception, rather than truncating the file, on Windows and Crystal 1.12.2:The text was updated successfully, but these errors were encountered: