Coder Social home page Coder Social logo

Comments (3)

HertzDevil avatar HertzDevil commented on July 4, 2024 1

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.

straight-shoota avatar straight-shoota commented on July 4, 2024

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.

straight-shoota avatar straight-shoota commented on July 4, 2024

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 without FILE_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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.