Changeset 1709 for branches/eraser6/CodeReview/Eraser.Util/FileSize.cs
- Timestamp:
- 1/28/2010 3:37:54 AM (3 years ago)
- File:
-
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
branches/eraser6/CodeReview/Eraser.Util/FileSize.cs
r1705 r1709 1 /*1 /* 2 2 * $Id$ 3 3 * Copyright 2008-2010 The Eraser Project 4 4 * Original Author: Joel Low <lowjoel@users.sourceforge.net> 5 * Modified By: Kasra Nassiri <cjax@users.sourceforge.net> @10/7/20085 * Modified By: 6 6 * 7 7 * This file is part of Eraser. … … 24 24 using System.Text; 25 25 26 using System.Runtime.InteropServices;27 using System.ComponentModel;28 using System.Windows.Forms;29 using System.Drawing;30 using System.IO;31 using Microsoft.Win32.SafeHandles;32 26 using System.Globalization; 33 27 34 28 namespace Eraser.Util 35 29 { 36 public static class File 30 /// <summary> 31 /// Gets the human-readable representation of a file size from the byte-wise 32 /// length of a file. This returns a KB = 1024 bytes (Windows convention.) 33 /// </summary> 34 public struct FileSize : IConvertible 37 35 { 38 36 /// <summary> 39 /// Gets the list of ADSes of the given file.37 /// Constructor. 40 38 /// </summary> 41 /// <param name="info">The FileInfo object with the file path etc.</param> 42 /// <returns>A list containing the names of the ADSes of each file. The 43 /// list will be empty if no ADSes exist.</returns> 44 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] 45 public static IList<string> GetADSes(FileInfo info) 39 /// <param name="filesize">The size of the file, in bytes.</param> 40 public FileSize(long filesize) 41 : this() 46 42 { 47 List<string> result = new List<string>(); 48 using (FileStream stream = new StreamInfo(info.FullName).Open(FileMode.Open, 49 FileAccess.Read, FileShare.ReadWrite)) 50 using (SafeFileHandle streamHandle = stream.SafeFileHandle) 51 { 52 //Allocate the structures 53 NativeMethods.FILE_STREAM_INFORMATION[] streams = GetADSes(streamHandle); 54 55 foreach (NativeMethods.FILE_STREAM_INFORMATION streamInfo in streams) 56 { 57 //Get the name of the stream. The raw value is :NAME:$DATA 58 string streamName = streamInfo.StreamName.Substring(1, 59 streamInfo.StreamName.LastIndexOf(':') - 1); 60 61 if (streamName.Length != 0) 62 result.Add(streamName); 63 } 64 } 65 66 return result.AsReadOnly(); 43 Size = filesize; 67 44 } 68 45 69 private static NativeMethods.FILE_STREAM_INFORMATION[] GetADSes(SafeFileHandle FileHandle) 46 #region IConvertible Members 47 48 public TypeCode GetTypeCode() 70 49 { 71 NativeMethods.IO_STATUS_BLOCK status = new NativeMethods.IO_STATUS_BLOCK();72 IntPtr fileInfoPtr = IntPtr.Zero;50 return TypeCode.Int64; 51 } 73 52 74 try 75 { 76 NativeMethods.FILE_STREAM_INFORMATION streamInfo = 77 new NativeMethods.FILE_STREAM_INFORMATION(); 78 int fileInfoPtrLength = (Marshal.SizeOf(streamInfo) + 32768) / 2; 79 uint ntStatus = 0; 53 public bool ToBoolean(IFormatProvider provider) 54 { 55 throw new InvalidCastException(); 56 } 80 57 81 do 82 { 83 fileInfoPtrLength *= 2; 84 if (fileInfoPtr != IntPtr.Zero) 85 Marshal.FreeHGlobal(fileInfoPtr); 86 fileInfoPtr = Marshal.AllocHGlobal(fileInfoPtrLength); 58 public byte ToByte(IFormatProvider provider) 59 { 60 return Convert.ToByte(Size); 61 } 87 62 88 ntStatus = NativeMethods.NtQueryInformationFile(FileHandle, ref status, 89 fileInfoPtr, (uint)fileInfoPtrLength, 90 NativeMethods.FILE_INFORMATION_CLASS.FileStreamInformation); 91 } 92 while (ntStatus != 0 /*STATUS_SUCCESS*/ && ntStatus == 0x80000005 /*STATUS_BUFFER_OVERFLOW*/); 63 public char ToChar(IFormatProvider provider) 64 { 65 throw new InvalidCastException(); 66 } 93 67 94 //Marshal the structure manually (argh!) 95 List<NativeMethods.FILE_STREAM_INFORMATION> result = 96 new List<NativeMethods.FILE_STREAM_INFORMATION>(); 97 unsafe 98 { 99 for (byte* i = (byte*)fileInfoPtr; streamInfo.NextEntryOffset != 0; 100 i += streamInfo.NextEntryOffset) 101 { 102 byte* currStreamPtr = i; 103 streamInfo.NextEntryOffset = *(uint*)currStreamPtr; 104 currStreamPtr += sizeof(uint); 68 public DateTime ToDateTime(IFormatProvider provider) 69 { 70 throw new InvalidCastException(); 71 } 105 72 106 streamInfo.StreamNameLength = *(uint*)currStreamPtr; 107 currStreamPtr += sizeof(uint); 73 public decimal ToDecimal(IFormatProvider provider) 74 { 75 return Convert.ToDecimal(Size); 76 } 108 77 109 streamInfo.StreamSize = *(long*)currStreamPtr; 110 currStreamPtr += sizeof(long); 78 public double ToDouble(IFormatProvider provider) 79 { 80 return Convert.ToDouble(Size); 81 } 111 82 112 streamInfo.StreamAllocationSize = *(long*)currStreamPtr; 113 currStreamPtr += sizeof(long); 83 public short ToInt16(IFormatProvider provider) 84 { 85 return Convert.ToInt16(Size); 86 } 114 87 115 streamInfo.StreamName = Marshal.PtrToStringUni((IntPtr)currStreamPtr, 116 (int)streamInfo.StreamNameLength / 2); 117 result.Add(streamInfo); 118 } 119 } 88 public int ToInt32(IFormatProvider provider) 89 { 90 return Convert.ToInt32(Size); 91 } 120 92 121 return result.ToArray(); 122 } 123 finally 124 { 125 Marshal.FreeHGlobal(fileInfoPtr); 126 } 93 public long ToInt64(IFormatProvider provider) 94 { 95 return Size; 96 } 97 98 public sbyte ToSByte(IFormatProvider provider) 99 { 100 return Convert.ToSByte(Size); 101 } 102 103 public float ToSingle(IFormatProvider provider) 104 { 105 return Convert.ToSingle(Size); 106 } 107 108 public string ToString(IFormatProvider provider) 109 { 110 return ToString(Size); 111 } 112 113 public object ToType(Type conversionType, IFormatProvider provider) 114 { 115 return Convert.ChangeType(Size, conversionType, provider); 116 } 117 118 public ushort ToUInt16(IFormatProvider provider) 119 { 120 return Convert.ToUInt16(Size); 121 } 122 123 public uint ToUInt32(IFormatProvider provider) 124 { 125 return Convert.ToUInt32(Size); 126 } 127 128 public ulong ToUInt64(IFormatProvider provider) 129 { 130 return Convert.ToUInt64(Size); 131 } 132 133 #endregion 134 135 /// <summary> 136 /// The size of the file, in bytes. 137 /// </summary> 138 public long Size 139 { 140 get; 141 private set; 127 142 } 128 143 129 144 /// <summary> 130 /// Uses SHGetFileInfo to retrieve the description for the given file, 131 /// folder or drive. 145 /// Converts this file size to the concise equivalent. 132 146 /// </summary> 133 /// <param name="path">A string that contains the path and file name for 134 /// the file in question. Both absolute and relative paths are valid. 135 /// Directories and volumes must contain the trailing \</param> 136 /// <returns>A string containing the description</returns> 137 public static string GetFileDescription(string path) 147 /// <returns>A string containing the file size and the associated unit. 148 /// Files larger than 1MB will be accurate to 2 decimal places.</returns> 149 public override string ToString() 138 150 { 139 NativeMethods.SHFILEINFO shfi = new NativeMethods.SHFILEINFO(); 140 NativeMethods.SHGetFileInfo(path, 0, ref shfi, Marshal.SizeOf(shfi), 141 NativeMethods.SHGetFileInfoFlags.SHGFI_DISPLAYNAME); 142 return shfi.szDisplayName; 151 return ToString(CultureInfo.CurrentCulture); 143 152 } 144 153 145 154 /// <summary> 146 /// Uses SHGetFileInfo to retrieve the icon for the given file, folder or 147 /// drive. 155 /// Converts a file size to the concise equivalent. 148 156 /// </summary> 149 /// <param name="path">A string that contains the path and file name for 150 /// the file in question. Both absolute and relative paths are valid. 151 /// Directories and volumes must contain the trailing \</param> 152 /// <returns>An Icon object containing the bitmap</returns> 153 public static Icon GetFileIcon(string path) 154 { 155 NativeMethods.SHFILEINFO shfi = new NativeMethods.SHFILEINFO(); 156 NativeMethods.SHGetFileInfo(path, 0, ref shfi, Marshal.SizeOf(shfi), 157 NativeMethods.SHGetFileInfoFlags.SHGFI_SMALLICON | 158 NativeMethods.SHGetFileInfoFlags.SHGFI_ICON); 159 160 if (shfi.hIcon != IntPtr.Zero) 161 return Icon.FromHandle(shfi.hIcon); 162 else 163 throw new IOException(string.Format(CultureInfo.CurrentCulture, 164 "Could not load file icon from {0}", path), 165 Win32ErrorCode.GetExceptionForWin32Error(Marshal.GetLastWin32Error())); 166 } 167 168 /// <summary> 169 /// Compacts the file path, fitting in the given width. 170 /// </summary> 171 /// <param name="longPath">The long file path.</param> 172 /// <param name="newWidth">The target width of the text.</param> 173 /// <param name="drawFont">The font used for drawing the text.</param> 174 /// <returns>The compacted file path.</returns> 175 public static string GetCompactPath(string longPath, int newWidth, Font drawFont) 176 { 177 using (Control ctrl = new Control()) 178 { 179 //First check if the source string is too long. 180 Graphics g = ctrl.CreateGraphics(); 181 int width = g.MeasureString(longPath, drawFont).ToSize().Width; 182 if (width <= newWidth) 183 return longPath; 184 185 //It is, shorten it. 186 int aveCharWidth = width / longPath.Length; 187 int charCount = newWidth / aveCharWidth; 188 StringBuilder builder = new StringBuilder(); 189 builder.Append(longPath); 190 builder.EnsureCapacity(charCount); 191 192 while (g.MeasureString(builder.ToString(), drawFont).Width > newWidth) 193 { 194 if (!NativeMethods.PathCompactPathEx(builder, longPath, 195 (uint)charCount--, 0)) 196 { 197 return string.Empty; 198 } 199 } 200 201 return builder.ToString(); 202 } 203 } 204 205 /// <summary> 206 /// Determines if a given file is protected by SFC. 207 /// </summary> 208 /// <param name="filePath">The path to check</param> 209 /// <returns>True if the file is protected.</returns> 210 public static bool IsProtectedSystemFile(string filePath) 211 { 212 return NativeMethods.SfcIsFileProtected(IntPtr.Zero, filePath); 213 } 214 215 /// <summary> 216 /// Checks whether the path given is compressed. 217 /// </summary> 218 /// <param name="path">The path to the file or folder</param> 219 /// <returns>True if the file or folder is compressed.</returns> 220 public static bool IsCompressed(string path) 221 { 222 ushort compressionStatus = 0; 223 uint bytesReturned = 0; 224 225 using (SafeFileHandle handle = NativeMethods.CreateFile(path, 226 NativeMethods.GENERIC_READ | NativeMethods.GENERIC_WRITE, 227 0, IntPtr.Zero, NativeMethods.OPEN_EXISTING, 228 NativeMethods.FILE_FLAG_BACKUP_SEMANTICS, IntPtr.Zero)) 229 { 230 if (NativeMethods.DeviceIoControl(handle, NativeMethods.FSCTL_GET_COMPRESSION, 231 IntPtr.Zero, 0, out compressionStatus, sizeof(ushort), out bytesReturned, 232 IntPtr.Zero)) 233 { 234 return compressionStatus != NativeMethods.COMPRESSION_FORMAT_NONE; 235 } 236 } 237 238 return false; 239 } 240 241 /// <summary> 242 /// Sets whether the file system object pointed to by path is compressed. 243 /// </summary> 244 /// <param name="path">The path to the file or folder.</param> 245 /// <returns>True if the file or folder has its compression value set.</returns> 246 public static bool SetCompression(string path, bool compressed) 247 { 248 ushort compressionStatus = compressed ? 249 NativeMethods.COMPRESSION_FORMAT_DEFAULT : 250 NativeMethods.COMPRESSION_FORMAT_NONE; 251 uint bytesReturned = 0; 252 253 using (SafeFileHandle handle = NativeMethods.CreateFile(path, 254 NativeMethods.GENERIC_READ | NativeMethods.GENERIC_WRITE, 255 0, IntPtr.Zero, NativeMethods.OPEN_EXISTING, 256 NativeMethods.FILE_FLAG_BACKUP_SEMANTICS, IntPtr.Zero)) 257 { 258 return NativeMethods.DeviceIoControl(handle, NativeMethods.FSCTL_SET_COMPRESSION, 259 ref compressionStatus, sizeof(ushort), IntPtr.Zero, 0, out bytesReturned, 260 IntPtr.Zero); 261 } 262 } 263 264 /// <summary> 265 /// Gets the human-readable representation of a file size from the byte-wise 266 /// length of a file. This returns a KB = 1024 bytes (Windows convention.) 267 /// </summary> 268 /// <param name="bytes">The file size to scale.</param> 157 /// <param name="size">The size of the file to convert.</param> 269 158 /// <returns>A string containing the file size and the associated unit. 270 159 /// Files larger than 1MB will be accurate to 2 decimal places.</returns> 271 public static string GetHumanReadableFileSize(long bytes)160 public static string ToString(long size) 272 161 { 273 162 //List of units, in ascending scale … … 282 171 }; 283 172 284 double d Bytes = (double)bytes;173 double dSize = (double)size; 285 174 for (int i = 0; i != units.Length; ++i) 286 175 { 287 if (d Bytes< 1000.0)176 if (dSize < 1000.0) 288 177 if (i <= 1) 289 178 return string.Format(CultureInfo.CurrentCulture, 290 "{0} {1}", (int)d Bytes, units[i]);179 "{0} {1}", (int)dSize, units[i]); 291 180 else 292 181 return string.Format(CultureInfo.CurrentCulture, 293 "{0:0.00} {1}", d Bytes, units[i]);294 d Bytes/= 1024.0;182 "{0:0.00} {1}", dSize, units[i]); 183 dSize /= 1024.0; 295 184 } 296 185 297 186 return string.Format(CultureInfo.CurrentCulture, "{0, 2} {1}", 298 dBytes, units[units.Length - 1]); 299 } 300 301 private static DateTime FileTimeToDateTime(System.Runtime.InteropServices.ComTypes.FILETIME value) 302 { 303 long time = (long)((((ulong)value.dwHighDateTime) << sizeof(int) * 8) | 304 (uint)value.dwLowDateTime); 305 return DateTime.FromFileTime(time); 306 } 307 308 private static System.Runtime.InteropServices.ComTypes.FILETIME DateTimeToFileTime(DateTime value) 309 { 310 long time = value.ToFileTime(); 311 312 System.Runtime.InteropServices.ComTypes.FILETIME result = 313 new System.Runtime.InteropServices.ComTypes.FILETIME(); 314 result.dwLowDateTime = (int)(time & 0xFFFFFFFFL); 315 result.dwHighDateTime = (int)(time >> 32); 316 317 return result; 318 } 319 320 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "1#")] 321 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "2#")] 322 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "3#")] 323 public static void GetFileTime(SafeFileHandle file, out DateTime creationTime, 324 out DateTime accessedTime, out DateTime modifiedTime) 325 { 326 System.Runtime.InteropServices.ComTypes.FILETIME accessedTimeNative = 327 new System.Runtime.InteropServices.ComTypes.FILETIME(); 328 System.Runtime.InteropServices.ComTypes.FILETIME modifiedTimeNative = 329 new System.Runtime.InteropServices.ComTypes.FILETIME(); 330 System.Runtime.InteropServices.ComTypes.FILETIME createdTimeNative = 331 new System.Runtime.InteropServices.ComTypes.FILETIME(); 332 333 if (!NativeMethods.GetFileTime(file, out createdTimeNative, out accessedTimeNative, 334 out modifiedTimeNative)) 335 { 336 throw Win32ErrorCode.GetExceptionForWin32Error(Marshal.GetLastWin32Error()); 337 } 338 339 creationTime = FileTimeToDateTime(createdTimeNative); 340 accessedTime = FileTimeToDateTime(accessedTimeNative); 341 modifiedTime = FileTimeToDateTime(modifiedTimeNative); 342 } 343 344 public static void SetFileTime(SafeFileHandle file, DateTime creationTime, 345 DateTime accessedTime, DateTime modifiedTime) 346 { 347 System.Runtime.InteropServices.ComTypes.FILETIME accessedTimeNative = 348 new System.Runtime.InteropServices.ComTypes.FILETIME(); 349 System.Runtime.InteropServices.ComTypes.FILETIME modifiedTimeNative = 350 new System.Runtime.InteropServices.ComTypes.FILETIME(); 351 System.Runtime.InteropServices.ComTypes.FILETIME createdTimeNative = 352 new System.Runtime.InteropServices.ComTypes.FILETIME(); 353 354 if (!NativeMethods.GetFileTime(file, out createdTimeNative, 355 out accessedTimeNative, out modifiedTimeNative)) 356 { 357 throw Win32ErrorCode.GetExceptionForWin32Error(Marshal.GetLastWin32Error()); 358 } 359 360 if (creationTime != DateTime.MinValue) 361 createdTimeNative = DateTimeToFileTime(creationTime); 362 if (accessedTime != DateTime.MinValue) 363 accessedTimeNative = DateTimeToFileTime(accessedTime); 364 if (modifiedTime != DateTime.MinValue) 365 modifiedTimeNative = DateTimeToFileTime(modifiedTime); 366 367 if (!NativeMethods.SetFileTime(file, ref createdTimeNative, 368 ref accessedTimeNative, ref modifiedTimeNative)) 369 { 370 throw Win32ErrorCode.GetExceptionForWin32Error(Marshal.GetLastWin32Error()); 371 } 187 dSize, units[units.Length - 1]); 372 188 } 373 189 }
Note: See TracChangeset
for help on using the changeset viewer.
