source: trunk/eraser6/Eraser.Util/File.cs @ 1675

Revision 1675, 9.0 KB checked in by lowjoel, 4 years ago (diff)

Updated copyright information: since Eraser is still under development we should update our copyright status.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1/*
2 * $Id$
3 * Copyright 2008-2010 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 ICollection<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                NTApi.NativeMethods.FILE_STREAM_INFORMATION[] streams =
53                    NTApi.NativeMethods.NtQueryInformationFile(streamHandle);
54
55                foreach (NTApi.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;
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            ShellApi.NativeMethods.SHFILEINFO shfi = new ShellApi.NativeMethods.SHFILEINFO();
80            ShellApi.NativeMethods.SHGetFileInfo(path, 0, ref shfi, Marshal.SizeOf(shfi),
81                ShellApi.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            ShellApi.NativeMethods.SHFILEINFO shfi = new ShellApi.NativeMethods.SHFILEINFO();
96            ShellApi.NativeMethods.SHGetFileInfo(path, 0, ref shfi, Marshal.SizeOf(shfi),
97                ShellApi.NativeMethods.SHGetFileInfoFlags.SHGFI_SMALLICON |
98                ShellApi.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 (!ShellApi.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 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(
166                KernelApi.NativeMethods.CreateFile(path,
167                KernelApi.NativeMethods.GENERIC_READ | KernelApi.NativeMethods.GENERIC_WRITE,
168                0, IntPtr.Zero, KernelApi.NativeMethods.OPEN_EXISTING,
169                KernelApi.NativeMethods.FILE_FLAG_BACKUP_SEMANTICS, IntPtr.Zero), FileAccess.Read))
170            {
171                if (KernelApi.NativeMethods.DeviceIoControl(strm.SafeFileHandle,
172                    KernelApi.NativeMethods.FSCTL_GET_COMPRESSION, IntPtr.Zero, 0,
173                    out compressionStatus, sizeof(ushort), out bytesReturned, IntPtr.Zero))
174                {
175                    return compressionStatus != KernelApi.NativeMethods.COMPRESSION_FORMAT_NONE;
176                }
177            }
178
179            return false;
180        }
181
182        /// <summary>
183        /// Sets whether the file system object pointed to by path is compressed.
184        /// </summary>
185        /// <param name="path">The path to the file or folder.</param>
186        /// <returns>True if the file or folder has its compression value set.</returns>
187        public static bool SetCompression(string path, bool compressed)
188        {
189            ushort compressionStatus = compressed ?
190                KernelApi.NativeMethods.COMPRESSION_FORMAT_DEFAULT :
191                KernelApi.NativeMethods.COMPRESSION_FORMAT_NONE;
192            uint bytesReturned = 0;
193
194            using (FileStream strm = new FileStream(
195                KernelApi.NativeMethods.CreateFile(path,
196                KernelApi.NativeMethods.GENERIC_READ | KernelApi.NativeMethods.GENERIC_WRITE,
197                0, IntPtr.Zero, KernelApi.NativeMethods.OPEN_EXISTING,
198                KernelApi.NativeMethods.FILE_FLAG_BACKUP_SEMANTICS, IntPtr.Zero), FileAccess.ReadWrite))
199            {
200                return KernelApi.NativeMethods.DeviceIoControl(strm.SafeFileHandle,
201                    KernelApi.NativeMethods.FSCTL_SET_COMPRESSION, ref compressionStatus,
202                    sizeof(ushort), IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero);
203            }
204        }
205
206        /// <summary>
207        /// Determines whether the specified file is protected. Applications
208        /// should avoid replacing protected system files.
209        /// </summary>
210        /// <param name="RpcHandle">This parameter must be NULL.</param>
211        /// <param name="ProtFileName">The name of the file.</param>
212        /// <returns>If the file is protected, the return value is true.</returns>
213        [DllImport("Sfc.dll", CharSet = CharSet.Unicode)]
214        [return: MarshalAs(UnmanagedType.Bool)]
215        private static extern bool SfcIsFileProtected(IntPtr RpcHandle,
216            string ProtFileName);
217
218        /// <summary>
219        /// Gets the human-readable representation of a file size from the byte-wise
220        /// length of a file. This returns a KB = 1024 bytes (Windows convention.)
221        /// </summary>
222        /// <param name="bytes">The file size to scale.</param>
223        /// <returns>A string containing the file size and the associated unit.
224        /// Files larger than 1MB will be accurate to 2 decimal places.</returns>
225        public static string GetHumanReadableFilesize(long bytes)
226        {
227            //List of units, in ascending scale
228            string[] units = new string[] {
229                "bytes",
230                "KB",
231                "MB",
232                "GB",
233                "TB",
234                "PB",
235                "EB"
236            };
237
238            double dBytes = (double)bytes;
239            for (int i = 0; i != units.Length; ++i)
240            {
241                if (dBytes < 1020.0)
242                    if (i <= 1)
243                        return string.Format(CultureInfo.CurrentCulture,
244                            "{0} {1}", (int)dBytes, units[i]);
245                    else
246                        return string.Format(CultureInfo.CurrentCulture,
247                            "{0:0.00} {1}", dBytes, units[i]);
248                dBytes /= 1024.0;
249            }
250
251            return string.Format(CultureInfo.CurrentCulture, "{0, 2} {1}",
252                dBytes, units[units.Length - 1]);
253        }
254    }
255}
Note: See TracBrowser for help on using the repository browser.