简体   繁体   English

更改符号链接的详细信息

[英]Changing a Details of Symbolic Link

Can't figure out what's the issue with CreateFilePrivate .无法弄清楚CreateFilePrivate有什么问题。

  • called from PowerShell, with:从 PowerShell 调用,带有:

     $path = "D:\temporal\t1.txt" $item = Get-Item -LiteralPath $path -Force [Win32]::setFileDetails($path, $item.CreationTimeUtc.ToFileTime(), $item.LastAccessTimeUtc.ToFileTime(), $item.LastWriteTimeUtc.AddDays(1).ToFileTime())
using System;       // required for some of it's content .
using System.Runtime.InteropServices;       // DllImport, Marshal
using Microsoft.Win32.SafeHandles;      // SafeFileHandle
using System.IO;        // FileShare, FileMode

public class Win32 {

    struct FILE_BASIC_INFO {
        internal long CreationTime;
        internal long LastAccessTime;
        internal long LastWriteTime;
        internal long ChangeTime;
        internal uint FileAttributes;       // binary
    };

    [Flags]
    enum AccessRights: uint {       // System.Messaging.GenericAccessRights doesn't work in Windows Powershell 's `Add-Type` .
        // # GenericAccessRights
        Read = 0x80000000,      // 2147483648 "-2147483648"
        Write = 0x40000000,     // 1073741824
        Execute = 0x20000000,   // 536870912
        All = 0x10000000,       // 268435456
        None = 0x00000000       // 0
    };

    [Flags]
    enum CreateFile_Options: uint {
        // # Flags
        ReparsePoint = 0x00200000,      // do not follow if a symbolic link . "OPEN_REPARSE_POINT"
        BACKUP_SEMANTICS = 0x02000000,
        DELETE_ON_CLOSE = 0x04000000,
        NO_BUFFERING = 0x20000000,
        OPEN_NO_RECALL = 0x00100000,
        OVERLAPPED = 0x40000000,
        POSIX_SEMANTICS = 0x01000000,
        RANDOM_ACCESS = 0x10000000,
        SESSION_AWARE = 0x00800000,
        SEQUENTIAL_SCAN = 0x08000000,
        WRITE_THROUGH = 0x80000000
    };

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool SetFileInformationByHandle(
        SafeFileHandle item,
        int Type_v,     // `enum FILE_INFO_BY_HANDLE_CLASS`
        ref FILE_BASIC_INFO sho_v,      // "Pointer"
        uint size_v
    );
    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool GetFileInformationByHandleEx(
        SafeFileHandle item,
        int Type_v,     // `enum FILE_INFO_BY_HANDLE_CLASS`
        ref FILE_BASIC_INFO sho_v,      // "Pointer"
        uint size_v
    );
    [DllImport("kernel32.dll", EntryPoint = "CreateFileW", SetLastError = true)]
    static extern SafeFileHandle CreateFilePrivate(
        string path,
        AccessRights v_Access,
        FileShare v_Share,
        IntPtr v_Security,      // `null` for default . `ref (SECURITY_ATTRIBUTES {})`
        FileMode a,
        CreateFile_Options v_Options,
        IntPtr Template     // `(SafeFileHandle) null` : "SafeHandle cannot be null" .
    );
    
    public static void setFileDetails (
        string path,
        long CreationEventTime,
        long ReadingEventTime,
        long WritingEventTime
        // System.IO.FileAttributes FileAttributes
    ) {
        SafeFileHandle item = CreateFilePrivate(path , AccessRights.Read | AccessRights.Write , FileShare.Read , IntPtr.Zero , FileMode.Open , CreateFile_Options.ReparsePoint , IntPtr.Zero);

        Console.WriteLine(path)     // the output path 100% targets a Symbolic Link
        Console.WriteLine(Marshal.GetLastWin32Error());     // "2"/"ERROR_FILE_NOT_FOUND"
        
        var BasicInfo = new FILE_BASIC_INFO() {};
        GetFileInformationByHandleEx(item, (int) 0, ref BasicInfo, (uint) Marshal.SizeOf(BasicInfo));
        
        BasicInfo = new FILE_BASIC_INFO() {
            CreationTime = CreationEventTime,
            LastAccessTime = ReadingEventTime,
            LastWriteTime = WritingEventTime,
            ChangeTime = BasicInfo.ChangeTime,
            FileAttributes = (uint) 0       // `(uint) 0` to not change any
        };
        SetFileInformationByHandle(item, (int) 0, ref BasicInfo, (uint) Marshal.SizeOf(BasicInfo));
    }
}

Edited with fixes for issues pointed out by @Dai.对@Dai 指出的问题进行了修复。

Dllimport by default converts parameters passed to the Method, to some specific encoding, so for Unicode <<name>>W Win32 commands it requires it's CharSet being set.默认情况下,Dllimport 将传递给方法的参数转换为某种特定的编码,因此对于 Unicode <<name>>W Win32 命令,它需要设置 CharSet。

[DllImport("kernel32.dll", EntryPoint = "CreateFileW", CharSet = CharSet.Unicode, SetLastError = true)]

IntPtr works as Pointer, so when: IntPtr 作为指针工作,所以当:

  • Pointer to null is required.需要指向 null 的指针。
  • and the needed Type doesn't support null.并且所需的类型不支持 null。

IntPtr Type and IntPtr.Zero can be used.可以使用 IntPtr Type 和 IntPtr.Zero。

thanks to everyone who tried to help, especially @SimonMourier @Dai.感谢所有试图提供帮助的人,尤其是@SimonMourier @Dai。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM