Изменение атрибутов точки соединения 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);
}