How to specify to createfilew function get uncached result?

3

I need to check whether a file (on a remote server via UNC path) exists or not (permission is not a problem here; I make a required impersonation etc.).

I use CreateFileW function for creating file handle. I've also tried GetFileAttributesEx but the behavior is the same.

HANDLE CreateFileW(
  LPCWSTR               lpFileName,
  DWORD                 dwDesiredAccess,
  DWORD                 dwShareMode,
  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  DWORD                 dwCreationDisposition,
  DWORD                 dwFlagsAndAttributes,
  HANDLE                hTemplateFile
);

If I deal with UNC paths I might get wrong result because of UNC cache (different process copies or removes a file that I need to check). It depends on FileNotFoundCacheLifetime registry key value (by default the value is 10 seconds).

// lets say I would like to check a file
// in the beginning the file exists
// than another process delete this file
// (e.g. executing drop database command by sql server)
// than another process copies this file back
// and all steps above takes less then FileNotFoundCacheLifetime value

// path = @"\\server\C$\Tmp\Folder\database\myDb.mdf"
private static void Test(string path)
{
    File.Exists(path);                              //exists
    Directory.Exists(Path.GetDirectoryName(path));  //exists

    using (var handle = CreateFile(path, EFileAccess.GenericRead, EFileShare.Read, IntPtr.Zero,
        ECreationDisposition.OpenExisting, EFileAttributes.Normal, IntPtr.Zero))
    {
        if (handle == null || handle.IsInvalid)
        {
            //FileNotFoundCacheLifetime = 0  => exists
            //FileNotFoundCacheLifetime = 10 => Win32Exception - The system cannot find the file specified
            Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
        }
    }
}

[DllImport("kernel32.dll", EntryPoint = "CreateFileW", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)]
public static extern SafeFileHandle CreateFile(
    string lpFileName,
    EFileAccess dwDesiredAccess,
    EFileShare dwShareMode,
    IntPtr lpSecurityAttributes,
    ECreationDisposition dwCreationDisposition,
    EFileAttributes dwFlagsAndAttributes,
    IntPtr hTemplateFile);

#region CreateFile
[Flags]
public enum EFileAccess : uint
{
    GenericRead = 0x80000000,
    GenericWrite = 0x40000000,
    GenericExecute = 0x20000000,
    GenericAll = 0x10000000,
}

[Flags]
public enum EFileShare : uint
{
    None = 0x00000000,
    Read = 0x00000001,
    Write = 0x00000002,
    Delete = 0x00000004,
}

public enum ECreationDisposition : uint
{
    New = 1,
    CreateAlways = 2,
    OpenExisting = 3,
    OpenAlways = 4,
    TruncateExisting = 5,
}

[Flags]
public enum EFileAttributes : uint
{
    Readonly = 0x00000001,
    Hidden = 0x00000002,
    System = 0x00000004,
    Directory = 0x00000010,
    Archive = 0x00000020,
    Device = 0x00000040,
    Normal = 0x00000080,
    Temporary = 0x00000100,
    SparseFile = 0x00000200,
    ReparsePoint = 0x00000400,
    Compressed = 0x00000800,
    Offline = 0x00001000,
    NotContentIndexed = 0x00002000,
    Encrypted = 0x00004000,
    Write_Through = 0x80000000,
    Overlapped = 0x40000000,
    NoBuffering = 0x20000000,
    RandomAccess = 0x10000000,
    SequentialScan = 0x08000000,
    DeleteOnClose = 0x04000000,
    BackupSemantics = 0x02000000,
    PosixSemantics = 0x01000000,
    OpenReparsePoint = 0x00200000,
    OpenNoRecall = 0x00100000,
    FirstPipeInstance = 0x00080000
}
#endregion CreateFile

Do you know how to get uncached result ? Basically I can disable UNC cache I know about it. Here I need a different approach - how to get uncached result precisely for a specific method call.

I know about the following approach - $NOCSC$ (@"\\server$NOCSC$\C$\folder\file") modifier but unfortunately it does not work on all operating systems.

File.Exists() and Folder.Exists() works but I need fileapi because it supports long paths (basically it's only one working solution).

Another good solution for me is cleaning UNC file system cache programmatically (again precisely before a specific method call).

c#
c++
.net
filesystems
asked on Stack Overflow Jul 13, 2019 by isxaker • edited Jul 16, 2019 by 1201ProgramAlarm

1 Answer

1

There is a fix for long paths (as per your comment to this post), at blogs mdsn and it is applicant for .net 4.6.2 and above.

You will have to add the application manifest file item to your project, there is a detailed guide in the blog for the process but all to all, it seems like a good solution to your issue without any necessary headache.

In the example they do test it on Console Application, so you will have to figure how to make proper adjustments to your solution.

answered on Stack Overflow Jul 21, 2019 by Barr J

User contributions licensed under CC BY-SA 3.0