/// <summary> /// Updates the <paramref name="path"/> timestamps with the values given. /// </summary> /// <param name="path">Symbolic link to be updated.</param> /// <param name="creationTime">Creation time.</param> /// <param name="lastAccessTime">Last access time.</param> /// <param name="lastWriteTime">Last write time.</param> /// <exception cref="UnauthorizedAccessException">The caller does not have the required permission.</exception> /// <exception cref="ArgumentException"> /// <paramref name="path"/> is a zero-length string, contains only white space, or contains one or more invalid characters as defined by <see cref="Path.GetInvalidPathChars"/>. /// <para>-or-</para> /// <paramref name="path"/> is prefixed with, or contains only a colon character (<c>:</c>). /// </exception> /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception> /// <exception cref="PathTooLongException">The specified path, file name, or both exceed the system-defined maximum length.</exception> /// <exception cref="DirectoryNotFoundException">The specified path is invalid (for example, it is on an unmapped drive).</exception> /// <exception cref="NotSupportedException"><paramref name="path"/> contains a colon character (<c>:</c>) that is not part of a drive label (<c>"C:\"</c>).</exception> /// <remarks> /// The major difference between this method and the <see cref="File.SetAttributes"/> is that this method supports /// setting attributes for symbolic links (both files and directories), while the <see cref="File.SetAttributes"/> /// will set them for a target file, not the link itself. /// </remarks> public static void SetTimestamps(string path, DateTime creationTime, DateTime lastAccessTime, DateTime lastWriteTime) { string normalizedPath = LongPathCommon.NormalizePath(path); using (SafeFileHandle handle = NativeMethods.CreateFile( normalizedPath, EFileAccess.FileWriteAttributes, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, EFileAttributes.OpenReparsePoint | EFileAttributes.BackupSemantics, IntPtr.Zero)) { if (handle.IsInvalid) { throw LongPathCommon.GetExceptionForHr(Marshal.GetHRForLastWin32Error(), path); } long creationFileTime = creationTime.ToLocalTime().ToFileTime(); long lastAccessFileTime = lastAccessTime.ToLocalTime().ToFileTime(); long lastWriteFileTime = lastWriteTime.ToLocalTime().ToFileTime(); if (!NativeMethods.SetFileTime(handle, ref creationFileTime, ref lastAccessFileTime, ref lastWriteFileTime)) { throw LongPathCommon.GetExceptionForHr(Marshal.GetHRForLastWin32Error(), path); } } }
/// <summary> /// Normalizes path (can be longer than <c>MAX_PATH</c>) and adds <c>\\?\</c> long path prefix, if needed. /// UNC paths are also supported. /// </summary> /// <param name="path">Path to be normalized.</param> /// <returns>Normalized path.</returns> /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception> public static string NormalizePath(string path) { // This will also validate the path. path = LongPathCommon.AddLongPathPrefix(path); // Don't forget about the null terminator. StringBuilder buffer = new StringBuilder(path.Length + 1); uint normalizedPathLength = NativeMethods.GetFullPathName(path, (uint)buffer.Capacity, buffer, IntPtr.Zero); // Length returned does not include null terminator. if (normalizedPathLength > buffer.Capacity - 1) { // Resulting path longer than our buffer, so increase it. buffer.Capacity = unchecked ((int)normalizedPathLength) + 1; normalizedPathLength = NativeMethods.GetFullPathName(path, normalizedPathLength, buffer, IntPtr.Zero); } if (normalizedPathLength == 0) { throw LongPathCommon.GetExceptionForHr(Marshal.GetHRForLastWin32Error(), path); } if (normalizedPathLength > NativeMethods.MaxLongPath - 1) { throw LongPathCommon.GetExceptionForHr(NativeMethods.ErrorFilenameExcedRange, path); } return(buffer.ToString()); }
/// <summary> /// Sets the attributes for a file or directory. /// </summary> /// <param name="path">The name of the file whose attributes are to be set.</param> /// <param name="attributes">The file attributes to set for the file.</param> /// <exception cref="UnauthorizedAccessException">The caller does not have the required permission.</exception> /// <exception cref="ArgumentException"> /// <paramref name="path"/> is a zero-length string, contains only white space, or contains one or more invalid characters as defined by <see cref="Path.GetInvalidPathChars"/>. /// <para>-or-</para> /// <paramref name="path"/> is prefixed with, or contains only a colon character (<c>:</c>). /// </exception> /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception> /// <exception cref="PathTooLongException">The specified path, file name, or both exceed the system-defined maximum length.</exception> /// <exception cref="DirectoryNotFoundException">The specified path is invalid (for example, it is on an unmapped drive).</exception> /// <exception cref="NotSupportedException"><paramref name="path"/> contains a colon character (<c>:</c>) that is not part of a drive label (<c>"C:\"</c>).</exception> public static void SetAttributes(string path, FileAttributes attributes) { string normalizedPath = LongPathCommon.NormalizePath(path); if (!NativeMethods.SetFileAttributes(normalizedPath, (EFileAttributes)attributes)) { throw LongPathCommon.GetExceptionForHr(Marshal.GetHRForLastWin32Error(), path); } }