1

我正在使用这个库来创建或获取我的连接点。一旦我得到这样的JunctionPoint实例,我就可以DirectoryInfoLink's (*)路径创建一个并读取LastWriteTimeUtc属性。现在我想将此时间戳设置为另一个日期,但它不起作用:值保持不变并且不会引发异常。

(*):这是您找到交汇点的位置的路径。

我怀疑,您需要使用一些 PInvoke 才能完成这项工作。通过在创建时或之后使用第二种方法指定所需的时间戳。所以我查找了用于创建连接点的文档,希望能找到一些有用的东西CreateFile()dwFlagsAndAttributes参数似乎接受一些标志/数值,并且 该方法的文档SetFileAttributes()看起来并不好。

我在使用 PInvoke 方面没有太多经验,非常感谢一些好的建议。

编辑

“我不想下载代码。我想在问题中看到足够多的代码以便能够回答”

这是用于创建联结的相关代码。它与codeproject的代码略有不同,因为我需要进行一些修改才能将其嵌入到我自己的库中。Link是类型DirectoryInfo

public void Create(bool overwrite = true)
    {
        Link.Refresh();
        if (Link.Exists)
        {
            if (!overwrite) throw new IOException("Directory already exists and overwrite parameter is false.");
        }
        else Link.Create();

        using (var handle = OpenReparsePoint(Link.FullName, EFileAccess.GenericWrite))
        {
            var targetDirBytes = Encoding.Unicode.GetBytes(NonInterpretedPathPrefix + Target.FullName);

            var reparseDataBuffer = new REPARSE_DATA_BUFFER();

            reparseDataBuffer.ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
            reparseDataBuffer.ReparseDataLength = (ushort) (targetDirBytes.Length + 12);
            reparseDataBuffer.SubstituteNameOffset = 0;
            reparseDataBuffer.SubstituteNameLength = (ushort) targetDirBytes.Length;
            reparseDataBuffer.PrintNameOffset = (ushort) (targetDirBytes.Length + 2);
            reparseDataBuffer.PrintNameLength = 0;
            reparseDataBuffer.PathBuffer = new byte[0x3ff0];
            Array.Copy(targetDirBytes, reparseDataBuffer.PathBuffer, targetDirBytes.Length);

            var inBufferSize = Marshal.SizeOf(reparseDataBuffer);
            var inBuffer = Marshal.AllocHGlobal(inBufferSize);

            try
            {
                Marshal.StructureToPtr(reparseDataBuffer, inBuffer, false);

                int bytesReturned;
                var result = DeviceIoControl(handle.DangerousGetHandle(), FSCTL_SET_REPARSE_POINT,
                                             inBuffer, targetDirBytes.Length + 20, IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero);

                if (!result) ThrowLastWin32Error("Unable to create junction point.");
            }
            finally
            {
                Marshal.FreeHGlobal(inBuffer);
            }
        }
    }

private static SafeFileHandle OpenReparsePoint(string reparsePoint, EFileAccess accessMode)
    {
        var reparsePointHandle = new SafeFileHandle(CreateFile(reparsePoint, accessMode,
                                                               EFileShare.Read | EFileShare.Write | EFileShare.Delete,
                                                               IntPtr.Zero, ECreationDisposition.OpenExisting,
                                                               EFileAttributes.BackupSemantics |
                                                               EFileAttributes.OpenReparsePoint, IntPtr.Zero), true);

        if (Marshal.GetLastWin32Error() != 0) ThrowLastWin32Error("Unable to open reparse point.");
        return reparsePointHandle;
    }

[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    private static extern IntPtr CreateFile(
        string lpFileName,
        EFileAccess dwDesiredAccess,
        EFileShare dwShareMode,
        IntPtr lpSecurityAttributes,
        ECreationDisposition dwCreationDisposition,
        EFileAttributes dwFlagsAndAttributes,
        IntPtr hTemplateFile);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool DeviceIoControl(IntPtr hDevice, uint dwIoControlCode,
                                               IntPtr InBuffer, int nInBufferSize,
                                               IntPtr OutBuffer, int nOutBufferSize,
                                               out int pBytesReturned, IntPtr lpOverlapped);
4

1 回答 1

1

最近我不得不回到这个老问题,并通过使用 Win32 API 找到了以下解决方案:

为此,您需要SafeFileHandle创建的 junction。所以我修改了Create()方法以返回结果OpenReparsePoint()而不处理它(这将在之后完成)。为了访问 Win32 API,您需要声明一个方法,该方法与要调用extern的 API 的方法相匹配。

[DllImport("kernel32.dll", SetLastError = true)]
[ResourceExposure(ResourceScope.None)]
private static extern bool SetFileTime(SafeFileHandle hFile,
                                       ref long lpCreationTime,
                                       ref long lpLastAccessTime,
                                       ref long lpLastWriteTime);

现在您可以像这样设置文件时间

string link;
string target;
var junctionPoint = new JunctionPoint(ling, target);

long creationTime; // ticks in FileTime format
long accessTime;
long lastWriteTime
using(SafeFileHandle hFile = junctionPoint.Create()) 
{ 
     SetFileTime(SafeFileHandle hFile, 
                     ref creationTime,
                   ref lastAccessTime,
                    ref lastWriteTime);
}
于 2015-05-16T11:12:48.527 回答