Comments (3)
It seems CRT does not actually use FILE_APPEND_DATA
to implement _O_APPEND
, as those file descriptors always contain FILE_WRITE_DATA | FILE_APPEND_DATA
in their access masks:
@[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 #lock
probably has the same issue. We might have to keep track of the append flag in Crystal ourselves.
from crystal.
This is odd. The handle should be created with GENERIC_WRITE
access right from File.open(filename, "a")
.
Apparently that's not the case. The actual access mode value used is 0x120114
. This seems wrong.
I'm also confused about both LibC::GENERIC_WRITE
and LibC::FILE_GENERIC_WRITE
(with different values; neither is in the actual access mode), and similar.
The documentation for CreateFileW
mentions GENERIC_WRITE
etc. should be used for access rights. But the Crystal implementation (posix_to_open_opts
) uses FILE_GENERIC_WRITE
etc. 🤔
from crystal.
https://learn.microsoft.com/en-us/windows/win32/fileio/file-access-rights-constants
FILE_APPEND_DATA
(4
): For a file object, the right to append data to the file. (For local files, write operations will not overwrite existing data if this flag is specified withoutFILE_WRITE_DATA
.)
So FILE_WRITE_DATA
is removed in order to prevent overwriting existing data. This is necessary to ensure the same behaviour as POSIX a
mode (and makes a lot of sense anyway).
However, that also prevents truncate
from working. I suppose it's not wrong to consider that overwriting existing data.
But in POSIX, truncate works with a file descriptor opened in append mode.
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 FILE_WRITE_DATA
unset for the first one to succeed, and set for the second one to succeed.
from crystal.
Related Issues (20)
- Nilable `Proc` types inside libs
- Cannot return `Proc`s from top-level funs
- `ReferenceStorage(T)` is always atomic even when `T` isn't HOT 1
- Add `crystal tool method_types` for listing method parameter types HOT 4
- Passing nil to Addrinfo.getaddrinfo gives unexpected error message HOT 1
- Package installation fails on Windows due to missing SQLite3 .lib files HOT 2
- Cache compiler results for tools
- Include more types in `crystal tool hierarchy` HOT 9
- `close_on_exec` on Windows HOT 2
- Pointer equality for `Slice` HOT 4
- Forbid variable assignment in function call HOT 4
- Captured block parameter not recognised when used inside macro HOT 2
- Internal error when using `sizeof` as generic type argument in inferred ivar type
- ECR escape sequences do not work with `-`
- Customizing or hiding `Benchmark.ips`'s output format HOT 3
- Adding a Difference method to the Math module HOT 3
- Visit the Time.local in the macro. HOT 3
- Add Makefile support `--mcpu=native` as override FLAGS to permit build crystal compiler can enable this option optional for a better performance. HOT 4
- Compiler should Emit Warning/Notes when Deduced Type Differs from Annotated Type. HOT 5
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from crystal.