Изменение атрибутов точки соединения NTFS

Я использую этот libray, чтобы создать или получить мои точки соединения. Однажды я получил такой JunctionPoint Например, я могу создать DirectoryInfo от Link(*) и прочитайте 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);

1 ответ

Решение

Недавно мне пришлось вернуться к этому старому вопросу и найти следующее решение, используя Win32 API:

Для этого вам нужен SafeFileHandle созданного соединения. Поэтому я изменил 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);
}
Другие вопросы по тегам