Skip to content
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

FileStream.Lock(Int64, Int64) failure on Linux - always uses 'F_WRLCK'. #29173

Closed
ConcreteHatstand opened this issue Apr 5, 2019 · 7 comments · Fixed by #44185
Closed

FileStream.Lock(Int64, Int64) failure on Linux - always uses 'F_WRLCK'. #29173

ConcreteHatstand opened this issue Apr 5, 2019 · 7 comments · Fixed by #44185
Assignees
Labels
area-System.IO enhancement Product code improvement that does NOT require public API changes/additions os-linux Linux OS (any supported distro)
Milestone

Comments

@ConcreteHatstand
Copy link

I am unable to create a shared lock (F_RDLCK) on a region within a file opened read-only on Linux.

FileStream.Lock always seems to use 'fcntl(fd, F_SETLK, {type=F_WRLCK...'.

For a file opened read-only, setting a 'F_WRLCK' (exclusive lock) is not a valid operation and triggers an EBADF (Bad file descriptor) error from fcntl, which triggers an Unhandled Exception from dotnet.

I can see this using 'strace', e.g. strace -o st_output.txt -f dotnet myprogram.

What is needed here is some way (property or method I guess) to specify the lock type, either F_RDLCK (a shared lock) or F_WRLCK (an exclusive lock).

To clarify those options and fcntl's behaviour - any number of concurrent shared locks can be made on the same part of a file unless there is an exclusive lock on it.

And ONE exclusive lock can be made on a specific region within a file unless there is already a lock - shared or exclusive - already present.

Note that the test program attached (a dotnet console app) expects a file 'testfile' to exist in its directory which can contain any random text.

This is my first issue, I do hope I have done this correctly! Regards.

Program_output.txt

Program.txt

@danmoseley
Copy link
Member

@tmds

@tmds
Copy link
Member

tmds commented Apr 5, 2019

What these operations do is based on how they work on Windows.
For FileStream.Lock that is:

Prevents other processes from reading from or writing to the FileStream.

So using an exclusive lock to implement this seems appropriate.

What is needed here is some way (property or method I guess) to specify the lock type, either F_RDLCK (a shared lock) or F_WRLCK (an exclusive lock).

You can make an API request.

@ConcreteHatstand
Copy link
Author

ConcreteHatstand commented Apr 8, 2019

@tmds - perhaps I should clarify the problem. This simple program throws an exception when run on Linux - (again a file, 'testfile' must be present).

using System;
using System.IO;

class Test
{
    public static void Main()
    {
        using (FileStream fs = File.OpenRead("testfile"))
        {
            fs.Lock((long) 3, (long) 1);
        }
    }
}

No exception is thrown on Windows.
The exception thrown on Linux does not immediately make any sense (Unauthorized access?)...

Unhandled Exception: System.UnauthorizedAccessException: Access to the path '/home/nicp/FileStream_simple/testfile' is denied. ---> System.IO.IOException: Bad file descriptor
   --- End of inner exception stack trace ---
   at System.IO.FileStream.CheckFileCall(Int64 result, Boolean ignoreNotSupported)
   at System.IO.FileStream.Lock(Int64 position, Int64 length)
   at Test.Main() in /home/nicp/FileStream_simple/Program.cs:line 10

... but is ultimately due to the attempt by .NET Core to set an exclusive lock on a read-only file - this gives the 'Bad file descriptor' error above.

@tmds
Copy link
Member

tmds commented Apr 8, 2019

... but is ultimately due to the attempt by .NET Core to set an exclusive lock on a read-only file - this gives the 'Bad file descriptor' error above.

Yes, if you open with ReadWrite, no exception is thrown. It seems write permission is needed on Linux to be able to take the lock, while it is not required on Windows.

@ConcreteHatstand
Copy link
Author

So the behaviour documented by Microsoft...

Prevents other processes from reading from or writing to the FileStream.

.. is not actually possible for read only files on Linux because setting an exclusive lock on a read only file stream is going to throw an exception.

But it is possible to create a shared lock on a read only file which when in place will block any attempt by another process to get an exclusive lock. This, of course will not prevent other processes from reading the locked region (or indeed getting another shared lock) - but that has got to be better than throwing an exception.
Currently I have ...

if( isWindows || theFileStream.CanWrite ) theFileStream.Lock(pos, len);

... just to avoid the exception on Linux. I don't see that as a good solution because now some other process (that has the file open for read/write) can wade in, get an exclusive lock and modify content in the file that the first process is using.

Could .NET Core be changed to allow use of F_RDLCK (a shared lock) for read only files on Linux? This could either be implicit based on whether the file is opened read-only, or perhaps some other (API change?) mod could be made.

@tmds
Copy link
Member

tmds commented Apr 14, 2019

Could .NET Core be changed to allow use of F_RDLCK (a shared lock) for read only files on Linux?

@JeremyKuhne wdyt about changing Lock to be a shared lock on Linux for files opened without write access? That means others will be able to read it. I don't see issues with that. Currently the operation is throwing, because read access is not sufficient to take an exclusive lock.

@JeremyKuhne
Copy link
Member

wdyt about changing Lock to be a shared lock on Linux for files opened without write access?

Sorry about the delayed response. I'm ok with moving to a shared lock.

@msftgits msftgits transferred this issue from dotnet/corefx Feb 1, 2020
@msftgits msftgits added this to the Future milestone Feb 1, 2020
@maryamariyan maryamariyan added the untriaged New issue has not been triaged by the area owner label Feb 23, 2020
@carlossanlop carlossanlop removed the untriaged New issue has not been triaged by the area owner label Feb 24, 2020
@carlossanlop carlossanlop added this to To do in System.IO - FileStream via automation Mar 6, 2020
System.IO - FileStream automation moved this from To do to Done Nov 5, 2020
@Jozkee Jozkee modified the milestones: Future, 6.0.0 Nov 5, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 13, 2020
@carlossanlop carlossanlop removed the help wanted [up-for-grabs] Good issue for external contributors label Oct 15, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.IO enhancement Product code improvement that does NOT require public API changes/additions os-linux Linux OS (any supported distro)
Projects
Development

Successfully merging a pull request may close this issue.

8 participants