-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
Samba file share - File.Move not working #54966
Comments
I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label. |
Tagging subscribers to this area: @dotnet/area-system-io Issue DetailsAfter upgrading from 3.1 to 5 a program stopped working on ubuntu (both 18 and 20.04) that relies heavily on File.Move to move files across two different CIFS shares (with Windows as the host). I upgraded cifs-utils but to no avail: the file seems to have been copied all right but then it throws the following error: I assume this happens when the API call tries to delete the original file. I can delete that file manually with File.Delete - so it doesn't seem to be a permission issue. I now changed the code which seems to work:
But the original way should work too and seems much faster if the two files are on the same drive.
|
Could you please provide a full stack trace? |
@markusmobius I currently don't have an access to a CIFS and I can't properly test a fix that I've been working on. Is there any chance that you could run the following app with a path to a writeable folder as an argument and share the output with me? The app creates a file and tries to acquire few different type of locks before writing to it. dotnet run -- $pathToFolder <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Tmds.LibC" Version="0.5.0" />
</ItemGroup>
</Project> using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Win32.SafeHandles;
using Tmds.Linux;
using static Tmds.Linux.LibC;
namespace FileSystemRepro
{
class Program
{
static void Main(string[] args)
{
string directoryPath = args[0];
string fileName = Guid.NewGuid().ToString();
string filePath = Path.Combine(directoryPath, fileName);
try
{
CreateNoLocks(filePath);
File.Delete(filePath);
CreateFLock(filePath, LockOperations.LOCK_EX);
File.Delete(filePath);
CreateFLock(filePath, LockOperations.LOCK_SH);
File.Delete(filePath);
CreateFcntl(filePath, LockOperations.LOCK_EX);
File.Delete(filePath);
CreateFcntl(filePath, LockOperations.LOCK_SH);
File.Delete(filePath);
}
finally
{
if (File.Exists(filePath))
{
File.Delete(filePath);
}
}
}
private static void CreateNoLocks(string filePath)
{
using (SafeFileHandle sfh = CreateNewFile(filePath))
using (FileStream fs = new FileStream(sfh, FileAccess.ReadWrite, bufferSize: 1, isAsync: false))
{
WriteAndReadSimple(fs);
}
}
private static void CreateFLock(string filePath, LockOperations lockOperations)
{
using (SafeFileHandle sfh = CreateNewFile(filePath))
using (FileStream fs = new FileStream(sfh, FileAccess.ReadWrite, bufferSize: 1, isAsync: false))
{
Console.WriteLine($"Using {lockOperations} flock to lock the file");
int lockResult = flock(sfh.DangerousGetHandle().ToInt32(), lockOperations);
if (lockResult == -1)
{
int errorCode = errno;
Console.WriteLine($"Locking {filePath} failed with error code {errorCode} and message: {GetErrorMessage(errorCode)}");
}
try
{
WriteAndReadSimple(fs);
}
finally
{
flock(sfh.DangerousGetHandle().ToInt32(), LockOperations.LOCK_UN);
}
}
}
private static unsafe void CreateFcntl(string filePath, LockOperations lockOperations)
{
using (SafeFileHandle sfh = CreateNewFile(filePath))
using (FileStream fs = new FileStream(sfh, FileAccess.ReadWrite, bufferSize: 1, isAsync: false))
{
Console.WriteLine($"Using {lockOperations} fcntl to lock the file");
flock flock = default;
flock.l_whence = (short)SEEK_SET;
flock.l_start = 0;
flock.l_len = 0; // lock entire file
flock.l_type = (short) lockOperations;
int lockResult = fcntl(sfh.DangerousGetHandle().ToInt32(), F_SETLK, &flock);
if (lockResult == -1)
{
int errorCode = errno;
Console.WriteLine($"Locking {filePath} failed with error code {errorCode} and message: {GetErrorMessage(errorCode)}");
}
try
{
WriteAndReadSimple(fs);
}
finally
{
flock.l_type = (short) LockOperations.LOCK_UN;
fcntl(sfh.DangerousGetHandle().ToInt32(), F_SETLK, &flock);
}
}
}
private static void WriteAndReadSimple(FileStream fs)
{
Console.WriteLine($"Length: {fs.Length}, position: {fs.Position}");
fs.WriteByte(123);
Console.WriteLine($"After writing one byte: length: {fs.Length}, position: {fs.Position}");
fs.Position -= 1;
int read = fs.ReadByte();
if (read != 123)
{
Console.WriteLine($"Invalid content {read}");
}
}
private static unsafe SafeFileHandle CreateNewFile(string filePath)
{
byte[] utf8Path = Encoding.UTF8.GetBytes(filePath);
fixed (byte* pinnedPath = utf8Path)
{
int createNewFileFlags = O_CREAT | O_RDWR | O_EXCL;
mode_t openPermissions = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; // read and write for all
int result = open(pinnedPath, createNewFileFlags, openPermissions);
if (result == -1)
{
int errorCode = errno;
throw new Exception($"Creating {filePath} failed with error code {errorCode} and message: {GetErrorMessage(errorCode)}");
}
return new SafeFileHandle(new IntPtr(result), true);
}
}
private static unsafe string GetErrorMessage(int errno)
{
int bufferLength = 1024;
byte* buffer = stackalloc byte[bufferLength];
int rv = strerror_r(errno, buffer, bufferLength);
return rv == 0 ? Marshal.PtrToStringAnsi((IntPtr)buffer) : $"errno {errno}";
}
private enum LockOperations : int
{
LOCK_SH = 1, /* shared lock */
LOCK_EX = 2, /* exclusive lock */
LOCK_NB = 4, /* don't block when locking*/
LOCK_UN = 8, /* unlock */
}
[DllImport("libc", SetLastError = true, ExactSpelling = true)]
private static extern int flock(int fd, LockOperations operation);
}
} |
I am sorry about the delay. Thank you so much for responding so quickly. I ran the program and here is the output: Length: 0, position: 0 This was on runtime 5.0.300. |
After upgrading from 3.1 to 5 a program stopped working on ubuntu (both 18 and 20.04) that relies heavily on File.Move to move files across two different CIFS shares (with Windows as the host).
I upgraded cifs-utils but to no avail: the file seems to have been copied all right but then it throws the following error:
System.UnauthorizedAccessException exception - Access to the path is denied.
I assume this happens when the API call tries to delete the original file. I can delete that file manually with File.Delete - so it doesn't seem to be a permission issue.
I now changed the code which seems to work:
But the original way should work too and seems much faster if the two files are on the same drive.
The text was updated successfully, but these errors were encountered: