Changeset 2155


Ignore:
Timestamp:
6/13/2010 12:29:44 AM (4 years ago)
Author:
lowjoel
Message:

Implements #273: Use NtSetInformationFile? to deeply set file times.

Location:
trunk/eraser
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/eraser/Eraser.DefaultPlugins/FileSystems/Ntfs.cs

    r2149 r2155  
    208208            get 
    209209            { 
    210                 return new DateTime(1601, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); 
     210                return new DateTime(1601, 1, 1, 0, 0, 0, 1, DateTimeKind.Utc); 
    211211            } 
    212212        } 
  • trunk/eraser/Eraser.DefaultPlugins/FileSystems/Windows.cs

    r2150 r2155  
    101101                { 
    102102                    //Reset the file access times: after every rename the file times may change. 
    103                     info.CreationTime = info.LastWriteTime = info.LastAccessTime = MinTimestamp; 
     103                    info.SetTimes(MinTimestamp, MinTimestamp, MinTimestamp, MinTimestamp); 
    104104 
    105105                    //Try to rename the file. If it fails, it is probably due to another 
     
    371371            { 
    372372                //Reset the file times 
    373                 streamInfo.LastAccessTime = lastAccess; 
    374                 streamInfo.LastWriteTime = lastWrite; 
    375                 streamInfo.CreationTime = created; 
     373                streamInfo.SetTimes(MinTimestamp, created, lastWrite, lastAccess); 
    376374            } 
    377375        } 
  • trunk/eraser/Eraser.Util/ExtensionMethods/IO.cs

    r2151 r2155  
    5050 
    5151        /// <summary> 
     52        /// Deeply sets the file times associated with the current 
     53        /// <see cref="FileInfo"/> object. 
     54        /// </summary> 
     55        /// <param name="updateTime">The time the basic information was last set.</param> 
     56        /// <param name="createdTime">The time the file was created.</param> 
     57        /// <param name="lastModifiedTime">The time the file was last modified.</param> 
     58        /// <param name="lastAccessedTime">The time the file was last accessed.</param> 
     59        public static void SetTimes(this FileSystemInfo info, DateTime updateTime, 
     60            DateTime createdTime, DateTime lastModifiedTime, DateTime lastAccessedTime) 
     61        { 
     62            FileInfo file = info as FileInfo; 
     63            DirectoryInfo directory = info as DirectoryInfo; 
     64 
     65            if (file != null) 
     66                file.SetTimes(updateTime, createdTime, lastModifiedTime, lastAccessedTime); 
     67            else if (directory != null) 
     68                directory.SetTimes(updateTime, createdTime, lastModifiedTime, lastAccessedTime); 
     69            else 
     70                throw new NotImplementedException(); 
     71        } 
     72 
     73        /// <summary> 
     74        /// Deeply sets the file times associated with the current 
     75        /// <see cref="FileInfo"/> object. 
     76        /// </summary> 
     77        /// <param name="updateTime">The time the basic information was last set.</param> 
     78        /// <param name="createdTime">The time the file was created.</param> 
     79        /// <param name="lastModifiedTime">The time the file was last modified.</param> 
     80        /// <param name="lastAccessedTime">The time the file was last accessed.</param> 
     81        public static void SetTimes(this FileInfo info, DateTime updateTime, 
     82            DateTime createdTime, DateTime lastModifiedTime, DateTime lastAccessedTime) 
     83        { 
     84            using (SafeFileHandle streamHandle = new StreamInfo(info.FullName). 
     85                OpenHandle(FileMode.Open, NativeMethods.FILE_WRITE_ATTRIBUTES, 
     86                    FileShare.ReadWrite, FileOptions.None)) 
     87            { 
     88                SetTimes(streamHandle, updateTime, createdTime, lastModifiedTime, lastAccessedTime); 
     89            } 
     90        } 
     91 
     92        /// <summary> 
     93        /// Deeply sets the file times associated with the current 
     94        /// <see cref="DirectoryInfo"/> object. 
     95        /// </summary> 
     96        /// <param name="updateTime">The time the basic information was last set.</param> 
     97        /// <param name="createdTime">The time the file was created.</param> 
     98        /// <param name="lastModifiedTime">The time the file was last modified.</param> 
     99        /// <param name="lastAccessedTime">The time the file was last accessed.</param> 
     100        public static void SetTimes(this DirectoryInfo info, DateTime updateTime, 
     101            DateTime createdTime, DateTime lastModifiedTime, DateTime lastAccessedTime) 
     102        { 
     103            using (SafeFileHandle streamHandle = new StreamInfo(info.FullName). 
     104                OpenHandle(FileMode.Open, NativeMethods.FILE_WRITE_ATTRIBUTES, 
     105                    FileShare.ReadWrite, (FileOptions)NativeMethods.FILE_FLAG_BACKUP_SEMANTICS)) 
     106            { 
     107                SetTimes(streamHandle, updateTime, createdTime, lastModifiedTime, lastAccessedTime); 
     108            } 
     109        } 
     110 
     111        internal static void SetTimes(SafeFileHandle handle, DateTime updateTime, 
     112            DateTime createdTime, DateTime lastModifiedTime, DateTime lastAccessedTime) 
     113        { 
     114            NativeMethods.FILE_BASIC_INFORMATION fileInfo = 
     115                new NativeMethods.FILE_BASIC_INFORMATION(); 
     116            fileInfo.ChangeTime = updateTime.ToFileTime(); 
     117            fileInfo.CreationTime = createdTime.ToFileTime(); 
     118            fileInfo.LastAccessTime = lastAccessedTime.ToFileTime(); 
     119            fileInfo.LastWriteTime = lastModifiedTime.ToFileTime(); 
     120 
     121            if (fileInfo.ChangeTime == 0) 
     122                throw new ArgumentOutOfRangeException("updateTime"); 
     123            if (fileInfo.CreationTime == 0) 
     124                throw new ArgumentOutOfRangeException("createdTime"); 
     125            if (fileInfo.LastAccessTime == 0) 
     126                throw new ArgumentOutOfRangeException("lastAccessedTime"); 
     127            if (fileInfo.LastWriteTime == 0) 
     128                throw new ArgumentOutOfRangeException("lastModifiedTime"); 
     129 
     130            IntPtr fileInfoPtr = Marshal.AllocHGlobal(Marshal.SizeOf(fileInfo)); 
     131            try 
     132            { 
     133                Marshal.StructureToPtr(fileInfo, fileInfoPtr, true); 
     134                NativeMethods.IO_STATUS_BLOCK status; 
     135                uint result = NativeMethods.NtSetInformationFile(handle, 
     136                    out status, fileInfoPtr, (uint)Marshal.SizeOf(fileInfo), 
     137                    NativeMethods.FILE_INFORMATION_CLASS.FileBasicInformation); 
     138 
     139                if (result != 0) 
     140                    throw new IOException(); 
     141            } 
     142            finally 
     143            { 
     144                Marshal.FreeHGlobal(fileInfoPtr); 
     145            } 
     146        } 
     147 
     148        /// <summary> 
    52149        /// Gets the parent directory of the current <see cref="System.IO.FileSystemInfo"/> 
    53150        /// object. 
  • trunk/eraser/Eraser.Util/NativeMethods/Kernel.cs

    r2076 r2155  
    456456 
    457457        public const uint FILE_READ_ATTRIBUTES = 0x0080; 
     458        public const uint FILE_WRITE_ATTRIBUTES = 0x0100; 
    458459        public const uint GENERIC_READ = 0x80000000; 
    459460        public const uint GENERIC_WRITE = 0x40000000; 
  • trunk/eraser/Eraser.Util/NativeMethods/NtDll.cs

    r1802 r2155  
    5858            FILE_INFORMATION_CLASS FileInformationClass); 
    5959 
     60        /// <summary> 
     61        /// The ZwSetInformationFile routine changes various kinds of information 
     62        /// about a file object. 
     63        /// </summary> 
     64        /// <param name="FileHandle">Handle to the file object. This handle is 
     65        /// created by a successful call to ZwCreateFile or ZwOpenFile.</param> 
     66        /// <param name="IoStatusBlock">Pointer to an IO_STATUS_BLOCK structure 
     67        /// that receives the final completion status and information about the 
     68        /// requested operation. The Information member receives the number of 
     69        /// bytes set on the file.</param> 
     70        /// <param name="FileInformation">Pointer to a buffer that contains the 
     71        /// information to set for the file. The particular structure in this 
     72        /// buffer is determined by the FileInformationClass parameter. Setting 
     73        /// any member of the structure to zero tells ZwSetInformationFile to 
     74        /// leave the current information about the file for that member 
     75        /// unchanged.</param> 
     76        /// <param name="Length">The size, in bytes, of the FileInformation 
     77        /// buffer.</param> 
     78        /// <param name="FileInformationClass">The type of information, supplied in 
     79        /// the buffer pointed to by FileInformation, to set for the file. Device 
     80        /// and intermediate drivers can specify any of the 
     81        /// <see cref="FILE_INFORMATION_CLASS"/> values.</param> 
     82        /// <returns>ZwSetInformationFile returns STATUS_SUCCESS or an appropriate 
     83        /// error status.</returns> 
     84        /// <remarks>ZwSetInformationFile changes information about a file. It 
     85        /// ignores any member of a FILE_XXX_INFORMATION structure that is not 
     86        /// supported by a particular device or file system. 
     87        ///  
     88        /// If you set FileInformationClass to FileDispositionInformation, you 
     89        /// can subsequently pass FileHandle to ZwClose but not to any other 
     90        /// ZwXxxFile routine. Because FileDispositionInformation causes the file 
     91        /// to be marked for deletion, it is a programming error to attempt any 
     92        /// subsequent operation on the handle other than closing it. 
     93        ///  
     94        /// If you set FileInformationClass to FilePositionInformation, and the 
     95        /// preceding call to ZwCreateFile included the FILE_NO_INTERMEDIATE_BUFFERING 
     96        /// flag in the CreateOptions parameter, certain restrictions on the 
     97        /// CurrentByteOffset member of the FILE_POSITION_INFORMATION structure 
     98        /// are enforced. For more information, see ZwCreateFile. 
     99        ///  
     100        /// If you set FileInformationClass to FileEndOfFileInformation, and the 
     101        /// EndOfFile member of FILE_END_OF_FILE_INFORMATION specifies an offset 
     102        /// beyond the current end-of-file mark, ZwSetInformationFile extends 
     103        /// the file and pads the extension with zeros.</remarks> 
     104        [DllImport("NtDll.dll")] 
     105        public static extern uint NtSetInformationFile(SafeFileHandle FileHandle, 
     106            out IO_STATUS_BLOCK IoStatusBlock, IntPtr FileInformation, uint Length, 
     107            FILE_INFORMATION_CLASS FileInformationClass); 
     108 
    60109        public struct IO_STATUS_BLOCK 
    61110        { 
     
    94143            public string StreamName; 
    95144        } 
     145 
     146        #pragma warning disable 0649 
     147        /// <summary> 
     148        /// The FILE_BASIC_INFORMATION structure is used as an argument to routines 
     149        /// that query or set file information. 
     150        /// </summary> 
     151        public struct FILE_BASIC_INFORMATION 
     152        { 
     153            /// <summary> 
     154            /// Specifies the time that the file was created. 
     155            /// </summary> 
     156            public long CreationTime; 
     157 
     158            /// <summary> 
     159            /// Specifies the time that the file was last accessed. 
     160            /// </summary> 
     161            public long LastAccessTime; 
     162             
     163            /// <summary> 
     164            /// Specifies the time that the file was last written to. 
     165            /// </summary> 
     166            public long LastWriteTime; 
     167 
     168            /// <summary> 
     169            /// Specifies the last time the file was changed. 
     170            /// </summary> 
     171            public long ChangeTime; 
     172 
     173            /// <summary> 
     174            /// Specifies one or more FILE_ATTRIBUTE_XXX flags. 
     175            /// </summary> 
     176            public uint FileAttributes; 
     177        } 
     178        #pragma warning restore 0649 
    96179 
    97180        public enum FILE_INFORMATION_CLASS 
  • trunk/eraser/Eraser.Util/StreamInfo.cs

    r2134 r2155  
    310310            } 
    311311 
     312            return OpenHandle(mode, iAccess, share, options); 
     313        } 
     314 
     315        internal SafeFileHandle OpenHandle(FileMode mode, uint access, FileShare share, 
     316            FileOptions options) 
     317        { 
    312318            //Sharing mode 
    313319            if ((share & FileShare.Inheritable) != 0) 
     
    319325 
    320326            //Create the handle 
    321             SafeFileHandle result = NativeMethods.CreateFile(FullName, iAccess, 
     327            SafeFileHandle result = NativeMethods.CreateFile(FullName, access, 
    322328                (uint)share, IntPtr.Zero, (uint)mode, (uint)options, IntPtr.Zero); 
    323329            if (result.IsInvalid) 
     
    331337        } 
    332338 
     339        public void SetTimes(DateTime updateTime, DateTime createdTime, DateTime lastModifiedTime, 
     340            DateTime lastAccessedTime) 
     341        { 
     342            using (SafeFileHandle streamHandle = OpenHandle(FileMode.Open, 
     343                    NativeMethods.FILE_WRITE_ATTRIBUTES, FileShare.ReadWrite, 
     344                    FileOptions.None)) 
     345            { 
     346                ExtensionMethods.IO.SetTimes(streamHandle, updateTime, createdTime, 
     347                    lastModifiedTime, lastAccessedTime); 
     348            } 
     349        } 
     350 
    333351        /// <summary> 
    334352        /// Returns the path as a string. 
Note: See TracChangeset for help on using the changeset viewer.