source: branches/eraser6/CodeReview/Eraser.Util/File.cs @ 1561

Revision 1561, 10.9 KB checked in by lowjoel, 5 years ago (diff)

Compilo.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1/*
2 * $Id$
3 * Copyright 2008-2009 The Eraser Project
4 * Original Author: Joel Low <lowjoel@users.sourceforge.net>
5 * Modified By: Kasra Nassiri <cjax@users.sourceforge.net> @10/7/2008
6 *
7 * This file is part of Eraser.
8 *
9 * Eraser is free software: you can redistribute it and/or modify it under the
10 * terms of the GNU General Public License as published by the Free Software
11 * Foundation, either version 3 of the License, or (at your option) any later
12 * version.
13 *
14 * Eraser is distributed in the hope that it will be useful, but WITHOUT ANY
15 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17 *
18 * A copy of the GNU General Public License can be found at
19 * <http://www.gnu.org/licenses/>.
20 */
21
22using System;
23using System.Collections.Generic;
24using System.Text;
25
26using System.Runtime.InteropServices;
27using System.ComponentModel;
28using System.Windows.Forms;
29using System.Drawing;
30using System.IO;
31using Microsoft.Win32.SafeHandles;
32using System.Globalization;
33
34namespace Eraser.Util
35{
36    public static class File
37    {
38        /// <summary>
39        /// Gets the list of ADSes of the given file.
40        /// </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        public static IList<string> GetADSes(FileInfo info)
45        {
46            List<string> result = new List<string>();
47            using (FileStream stream = new StreamInfo(info.FullName).Open(FileMode.Open,
48                FileAccess.Read, FileShare.ReadWrite))
49            using (SafeFileHandle streamHandle = stream.SafeFileHandle)
50            {
51                //Allocate the structures
52                NativeMethods.FILE_STREAM_INFORMATION[] streams =
53                    NTApi.NtQueryInformationFile(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();
67        }
68
69        /// <summary>
70        /// Uses SHGetFileInfo to retrieve the description for the given file,
71        /// folder or drive.
72        /// </summary>
73        /// <param name="path">A string that contains the path and file name for
74        /// the file in question. Both absolute and relative paths are valid.
75        /// Directories and volumes must contain the trailing \</param>
76        /// <returns>A string containing the description</returns>
77        public static string GetFileDescription(string path)
78        {
79            NativeMethods.SHFILEINFO shfi = new NativeMethods.SHFILEINFO();
80            NativeMethods.SHGetFileInfo(path, 0, ref shfi, Marshal.SizeOf(shfi),
81                NativeMethods.SHGetFileInfoFlags.SHGFI_DISPLAYNAME);
82            return shfi.szDisplayName;
83        }
84
85        /// <summary>
86        /// Uses SHGetFileInfo to retrieve the icon for the given file, folder or
87        /// drive.
88        /// </summary>
89        /// <param name="path">A string that contains the path and file name for
90        /// the file in question. Both absolute and relative paths are valid.
91        /// Directories and volumes must contain the trailing \</param>
92        /// <returns>An Icon object containing the bitmap</returns>
93        public static Icon GetFileIcon(string path)
94        {
95            NativeMethods.SHFILEINFO shfi = new NativeMethods.SHFILEINFO();
96            NativeMethods.SHGetFileInfo(path, 0, ref shfi, Marshal.SizeOf(shfi),
97                NativeMethods.SHGetFileInfoFlags.SHGFI_SMALLICON |
98                NativeMethods.SHGetFileInfoFlags.SHGFI_ICON);
99
100            if (shfi.hIcon != IntPtr.Zero)
101                return Icon.FromHandle(shfi.hIcon);
102            else
103                throw new IOException(string.Format(CultureInfo.CurrentCulture,
104                    "Could not load file icon from {0}", path),
105                    Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error()));
106        }
107
108        /// <summary>
109        /// Compacts the file path, fitting in the given width.
110        /// </summary>
111        /// <param name="longPath">The long file path.</param>
112        /// <param name="newWidth">The target width of the text.</param>
113        /// <param name="drawFont">The font used for drawing the text.</param>
114        /// <returns>The compacted file path.</returns>
115        public static string GetCompactPath(string longPath, int newWidth, Font drawFont)
116        {
117            using (Control ctrl = new Control())
118            {
119                //First check if the source string is too long.
120                Graphics g = ctrl.CreateGraphics();
121                int width = g.MeasureString(longPath, drawFont).ToSize().Width;
122                if (width <= newWidth)
123                    return longPath;
124
125                //It is, shorten it.
126                int aveCharWidth = width / longPath.Length;
127                int charCount = newWidth / aveCharWidth;
128                StringBuilder builder = new StringBuilder();
129                builder.Append(longPath);
130                builder.EnsureCapacity(charCount);
131
132                while (g.MeasureString(builder.ToString(), drawFont).Width > newWidth)
133                {
134                    if (!NativeMethods.PathCompactPathEx(builder, longPath,
135                        (uint)charCount--, 0))
136                    {
137                        return string.Empty;
138                    }
139                }
140
141                return builder.ToString();
142            }
143        }
144
145        /// <summary>
146        /// Determines if a given file is protected by SFC.
147        /// </summary>
148        /// <param name="filePath">The path to check</param>
149        /// <returns>True if the file is protected.</returns>
150        public static bool IsProtectedSystemFile(string filePath)
151        {
152            return NativeMethods.SfcIsFileProtected(IntPtr.Zero, filePath);
153        }
154
155        /// <summary>
156        /// Checks whether the path given is compressed.
157        /// </summary>
158        /// <param name="path">The path to the file or folder</param>
159        /// <returns>True if the file or folder is compressed.</returns>
160        public static bool IsCompressed(string path)
161        {
162            ushort compressionStatus = 0;
163            uint bytesReturned = 0;
164
165            using (FileStream strm = new FileStream(NativeMethods.CreateFile(path,
166                NativeMethods.GENERIC_READ | NativeMethods.GENERIC_WRITE,
167                0, IntPtr.Zero, NativeMethods.OPEN_EXISTING,
168                NativeMethods.FILE_FLAG_BACKUP_SEMANTICS, IntPtr.Zero), FileAccess.Read))
169            {
170                if (NativeMethods.DeviceIoControl(strm.SafeFileHandle,
171                    NativeMethods.FSCTL_GET_COMPRESSION, IntPtr.Zero, 0,
172                    out compressionStatus, sizeof(ushort), out bytesReturned, IntPtr.Zero))
173                {
174                    return compressionStatus != NativeMethods.COMPRESSION_FORMAT_NONE;
175                }
176            }
177
178            return false;
179        }
180
181        /// <summary>
182        /// Sets whether the file system object pointed to by path is compressed.
183        /// </summary>
184        /// <param name="path">The path to the file or folder.</param>
185        /// <returns>True if the file or folder has its compression value set.</returns>
186        public static bool SetCompression(string path, bool compressed)
187        {
188            ushort compressionStatus = compressed ?
189                NativeMethods.COMPRESSION_FORMAT_DEFAULT :
190                NativeMethods.COMPRESSION_FORMAT_NONE;
191            uint bytesReturned = 0;
192
193            using (FileStream strm = new FileStream(NativeMethods.CreateFile(path,
194                NativeMethods.GENERIC_READ | NativeMethods.GENERIC_WRITE,
195                0, IntPtr.Zero, NativeMethods.OPEN_EXISTING,
196                NativeMethods.FILE_FLAG_BACKUP_SEMANTICS, IntPtr.Zero), FileAccess.ReadWrite))
197            {
198                return NativeMethods.DeviceIoControl(strm.SafeFileHandle,
199                    NativeMethods.FSCTL_SET_COMPRESSION, ref compressionStatus,
200                    sizeof(ushort), IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero);
201            }
202        }
203
204        /// <summary>
205        /// Gets the human-readable representation of a file size from the byte-wise
206        /// length of a file. This returns a KB = 1024 bytes (Windows convention.)
207        /// </summary>
208        /// <param name="bytes">The file size to scale.</param>
209        /// <returns>A string containing the file size and the associated unit.
210        /// Files larger than 1MB will be accurate to 2 decimal places.</returns>
211        public static string GetHumanReadableFilesize(long bytes)
212        {
213            //List of units, in ascending scale
214            string[] units = new string[] {
215                "bytes",
216                "KB",
217                "MB",
218                "GB",
219                "TB",
220                "PB",
221                "EB"
222            };
223
224            double dBytes = (double)bytes;
225            for (int i = 0; i != units.Length; ++i)
226            {
227                if (dBytes < 1020.0)
228                    if (i <= 1)
229                        return string.Format(CultureInfo.CurrentCulture,
230                            "{0} {1}", (int)dBytes, units[i]);
231                    else
232                        return string.Format(CultureInfo.CurrentCulture,
233                            "{0:0.00} {1}", dBytes, units[i]);
234                dBytes /= 1024.0;
235            }
236
237            return string.Format(CultureInfo.CurrentCulture, "{0, 2} {1}",
238                dBytes, units[units.Length - 1]);
239        }
240
241        private static DateTime FileTimeToDateTime(System.Runtime.InteropServices.ComTypes.FILETIME value)
242        {
243            long time = (long)((((ulong)value.dwHighDateTime) << sizeof(int) * 8) |
244                (uint)value.dwLowDateTime);
245            return DateTime.FromFileTime(time);
246        }
247
248        private static System.Runtime.InteropServices.ComTypes.FILETIME DateTimeToFileTime(DateTime value)
249        {
250            long time = value.ToFileTime();
251
252            System.Runtime.InteropServices.ComTypes.FILETIME result =
253                new System.Runtime.InteropServices.ComTypes.FILETIME();
254            result.dwLowDateTime = (int)(time & 0xFFFFFFFFL);
255            result.dwHighDateTime = (int)(time >> 32);
256
257            return result;
258        }
259
260        public static void GetFileTime(SafeFileHandle file, out DateTime creationTime,
261            out DateTime accessedTime, out DateTime modifiedTime)
262        {
263            System.Runtime.InteropServices.ComTypes.FILETIME accessedTimeNative =
264                new System.Runtime.InteropServices.ComTypes.FILETIME();
265            System.Runtime.InteropServices.ComTypes.FILETIME modifiedTimeNative =
266                new System.Runtime.InteropServices.ComTypes.FILETIME();
267            System.Runtime.InteropServices.ComTypes.FILETIME createdTimeNative =
268                new System.Runtime.InteropServices.ComTypes.FILETIME();
269
270            if (!NativeMethods.GetFileTime(file, out createdTimeNative, out accessedTimeNative,
271                out modifiedTimeNative))
272            {
273                throw KernelApi.GetExceptionForWin32Error(Marshal.GetLastWin32Error());
274            }
275
276            creationTime = FileTimeToDateTime(createdTimeNative);
277            accessedTime = FileTimeToDateTime(accessedTimeNative);
278            modifiedTime = FileTimeToDateTime(modifiedTimeNative);
279        }
280
281        public static void SetFileTime(SafeFileHandle file, DateTime creationTime,
282            DateTime accessedTime, DateTime modifiedTime)
283        {
284            System.Runtime.InteropServices.ComTypes.FILETIME accessedTimeNative =
285                new System.Runtime.InteropServices.ComTypes.FILETIME();
286            System.Runtime.InteropServices.ComTypes.FILETIME modifiedTimeNative =
287                new System.Runtime.InteropServices.ComTypes.FILETIME();
288            System.Runtime.InteropServices.ComTypes.FILETIME createdTimeNative =
289                new System.Runtime.InteropServices.ComTypes.FILETIME();
290
291            if (!NativeMethods.GetFileTime(file, out createdTimeNative,
292                out accessedTimeNative, out modifiedTimeNative))
293            {
294                throw KernelApi.GetExceptionForWin32Error(Marshal.GetLastWin32Error());
295            }
296
297            if (creationTime != DateTime.MinValue)
298                createdTimeNative = DateTimeToFileTime(creationTime);
299            if (accessedTime != DateTime.MinValue)
300                accessedTimeNative = DateTimeToFileTime(accessedTime);
301            if (modifiedTime != DateTime.MinValue)
302                modifiedTimeNative = DateTimeToFileTime(modifiedTime);
303
304            if (!NativeMethods.SetFileTime(file, ref createdTimeNative,
305                ref accessedTimeNative, ref modifiedTimeNative))
306            {
307                throw KernelApi.GetExceptionForWin32Error(Marshal.GetLastWin32Error());
308            }
309        }
310    }
311}
Note: See TracBrowser for help on using the repository browser.