Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@steveisok
Copy link
Contributor

Fixes #16032

When we switched to corefx File.Copy on unix, the behavior changed where it opened a source and destination stream in order to pass the safe handles to Interop.Sys.CopyFile. This exposed a flaw in our sharing validation rules in MonoIO.Open, which threw an exception in this scenario:

new FileStream("source.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite, 2048, FileOptions.DeleteOnClose);
new FileStream("source.txt", FileMode.Open, FileAccess.Read, FileShare.Read, 2048, FileOptions.None);

This should now correctly line up w/ https://docs.microsoft.com/en-us/dotnet/api/system.io.fileshare?view=netframework-4.8#fields

Switching to corefx File.Copy on unix changed the behavior where it opened a source and destination stream in order to pass
the safe handles to Interop.Sys.CopyFile.  This exposed a flaw in our sharing validation rules in MonoIO.Open, which
threw an exception in this scenario:

new FileStream("source.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite, 2048, FileOptions.DeleteOnClose);
new FileStream("source.txt", FileMode.Open, FileAccess.Read, FileShare.Read, 2048, FileOptions.None);

The change is intended to take into account all sharing scenarios.
Copy link
Member

@lambdageek lambdageek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test looks good. fix makes sense. there's a line in the if that seems suspicious to me, but overall looks ok.

/* New share mode doesn't match up */
mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Access mode prevents open: requested share: 0x%" PRIx32 ", file has access: 0x%" PRIx32, __func__, sharemode, file_existing_access);
if (file_existing_share != sharemode &&
((sharemode | FILE_SHARE_READ) != sharemode) &&
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need this? It's checking that the new requested sharing mode sharemode doesn't include FileShare.Read. Why?

Isn't it enough to just check that file_existing_share != sharemode (new is different from existing) and (file_existing_share | sharemode) == file_existing_share (new it at most as lax as existing - it doesn't include). That together means that new sharemode is a strict subset of the existing file_existing_share. And therefore we take the branch and return FALSE.

Copy link
Contributor

@jaykrell jaykrell Aug 15, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change/code confuses me.
Why do the share modes have to line up, as long as they grant each other access?
Don't sharemodes get anded upon successful open, to weigh against later opens?
I might try it myself if that not too rude.

like:

  • open read, share readwrite
  • open read, share read; success, resulting share is read
  • open readwrite; fail

or:
- open read, share read
- open read, share readwrite; success, resulting share is read
- open readwrite; fail

Note this cannot really work without underlying kernel support.
We end up presumably only enforcing it within the process, amongst mono users, which is a lot less than the original intent.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lambdageek From our conversation, the ((sharemode | FILE_SHARE_READ) != sharemode) && line is to close the gap w/ ReadWrite. Without it, FIle.Copy would fail (ReadWrite to Read).

The more I look at this and the corefx version, the more I think we should just follow in kind.
Which is, FileShare.None locks exclusively and that's about it.

https://github.com/dotnet/corefx/blob/b990ece3f8cd7999ad62483f1bd814ec586895de/src/Common/src/CoreLib/System/IO/FileStream.Unix.cs#L76-L88

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, since it requires kernel/filesystem to really support, i.e. to play "correctly" with non-mono callers.
A coworker of mine years ago suggested this sharing stuff, while it seems like a good idea, isn't really all that great even on Windows and perhaps is pointless. Unix might have its flaws, but this missing feature you don't hear about much.

My simple attempt broke tests.
#16271

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The check is pretty simple now.

Copy link
Contributor

@jaykrell jaykrell Aug 15, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to "subscribe" to that file/line and get a notification if they decide to work on it.
Maybe the AI will notice the copied code or this comment and notify us, or update ours.

@tobiasschulz
Copy link

How soon can we get this into xamarin.android stable? It is broken since VS release 16.2 on production.

Steve Pfister added 2 commits August 15, 2019 16:09
1. If the caller specifies FileShare.None, then it's an exclusive lock and no
   sharing is allowed.

2. If the caller specifies some other FileShare option, then FileShare.None
   cannot be specified.
Copy link
Member

@lambdageek lambdageek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, now we match what CoreFX does (FileShare.None is exclusive locking which is incompatible with any other open request for the same file; everything else is ok to share)

@lambdageek
Copy link
Member

@monojenkins backport to 2019-08
@monojenkins backport to 2019-06

@lambdageek
Copy link
Member

@monojenkins backport to 2019-02

#define GENERIC_EXECUTE 0x20000000
#define GENERIC_ALL 0x10000000

#define FILE_SHARE_NONE 0x00000000
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not actually a symbol in Windows, but ok.

@steveisok
Copy link
Contributor Author

@monojenkins build failed

@steveisok steveisok merged commit da2c015 into mono:master Aug 16, 2019
ManickaP pushed a commit to ManickaP/runtime that referenced this pull request Jan 20, 2020
Fixes mono/mono#16032

When we switched to corefx File.Copy on unix, the behavior changed where it opened a source and destination stream in order to pass the safe handles to Interop.Sys.CopyFile. This exposed a flaw in our sharing validation rules in MonoIO.Open, which threw an exception in this scenario:

new FileStream("source.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite, 2048, FileOptions.DeleteOnClose);
new FileStream("source.txt", FileMode.Open, FileAccess.Read, FileShare.Read, 2048, FileOptions.None);

Simplified the FileShare check down to:

1. If the caller specifies FileShare.None, then it's an exclusive lock and no
   sharing is allowed.

2. If the caller specifies some other FileShare option, then FileShare.None
    cannot be specified.


Commit migrated from mono/mono@da2c015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

IOException: Sharing violation on path ...

4 participants