I like to use System.IO.File.WriteAllBytes()
to keep things simple. But it seems, that this method can not be used everywhere. To write on my local system it works fine.
But when I use System.IO.File.WriteAllBytes()
to write on a Windows share it produces an empty file and fails with an Exception:
System.UnauthorizedAccessException: Access to the path '/var/windowsshare/file.bin' is denied.
---> System.IO.IOException: Permission denied
If I look at the source at https://github.com/dotnet/runtime/blob/c72b54243ade2e1118ab24476220a2eba6057466/src/libraries/System.IO.FileSystem/src/System/IO/File.cs#L421 I found the following code working under the hood:
using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read))
{
fs.Write(bytes, 0, bytes.Length);
}
If I change the code and use FileShare.None
instead of FileShare.Read
it works. So I have a workaround and I have to keep in mind that System.IO.File.WriteAllBytes()
is not waterproof (is it correct?).
Unfortunately, my analysis ended up with a few related questions:
So what is the best practice if the target path is configurable? Does the developer have to avoid System.IO.File.WriteAllBytes() or does the system administrator have to find another way to mount the share? What is wrong with FileShare.Read? Does the Windows share change permissions/locking while System.IO.File.WriteAllBytes() is writing? Are there some tips to mount the Windows share?
Update 1
WriteAllBytes():
// WriteAllBytes() Throws System.UnauthorizedAccessException
System.IO.File.WriteAllBytes("/var/windowsshare/file.bin", bytes);
Create and move with C#
// Create local and move + optional overwrite works!
var tmp = Path.GetTempFileName(); // local file
System.IO.File.WriteAllBytes(tmp, bytes); // write local
System.IO.File.Move(tmp, "/var/windowsshare/file.bin", true); // optional overwrite
ls:
# ls -l /var/windowsshare/file.bin
-rw-rw-rw-. 1 apache apache 20 Feb 9 11:43 /var/windowsshare/file.bin
# ls -Z /var/windowsshare/file.bin
system_u:object_r:cifs_t:s0 /var/windowsshare/file.bin
mount ...
# mount -l
//1.2.3.4/windowsshare on /var/windowsshare type cifs (rw,relatime,vers=3.1.1,cache=strict,username=luke,domain=dom,uid=48,forceuid,gid=48,forcegid,addr=1.2.3.4,file_mode=0666,dir_mode=0777,soft,nounix,nodfs,nouser_xattr,mapposix,noperm,rsize=4194304,wsize=4194304,bsize=1048576,echo_interval=60,actimeo=1,_netdev)
# stat -f -c %T /var/windowsshare/file.bin
smb2