OSDN Git Service

SDKを更新した
[completeeraser/CompleteEraser.git] / CompleteEraser / FileBreaker.cs
1 using System;\r
2 using System.Text;\r
3 using System.Collections.Generic;\r
4 using System.IO;\r
5 using System.Security.AccessControl;\r
6 using System.Security.Principal;\r
7 using System.Linq;\r
8 using Trinet.Core.IO.Ntfs;\r
9 using CompleteEraser.Properties;\r
10 \r
11 namespace CompleteEraser\r
12 {\r
13     class FileBreaker\r
14     {\r
15         const long ShirnkLength = 1;\r
16 \r
17         public static void BreakFileOrFolder(string path)\r
18         {\r
19             if (Directory.Exists(path))\r
20                 BreakFolder(path);\r
21             else if (File.Exists(path))\r
22                 BreakFile(path);\r
23         }\r
24 \r
25         public static void BreakFile(string file)\r
26         {\r
27             FileAttributes attr = File.GetAttributes(file);\r
28 \r
29             if ((attr & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)\r
30                 File.SetAttributes(file, attr & ~FileAttributes.ReadOnly);\r
31 \r
32             if ((attr & FileAttributes.ReparsePoint) != FileAttributes.ReparsePoint &&\r
33                 (attr & FileAttributes.SparseFile) != FileAttributes.SparseFile)\r
34                 FillFileContent(file);\r
35             \r
36             string newFile = GenerateRandoName(Path.GetDirectoryName(file), Path.GetFileName(file).Length);\r
37             if(File.Exists(newFile) == false)\r
38                 File.Move(file, newFile);\r
39             \r
40             File.Delete(newFile);\r
41         }\r
42 \r
43         private static void FillFileContent(string file)\r
44         {\r
45             FileStream fs;\r
46             FileInfo info = new FileInfo(file);\r
47 \r
48             foreach (AlternateDataStreamInfo alt in info.ListAlternateDataStreams())\r
49             {\r
50                 fs = alt.Open(FileMode.Open);\r
51                 BreakFileSlowSpeed(fs);\r
52                 fs.Close();\r
53             }\r
54 \r
55             string ext = Path.GetExtension(file);\r
56 \r
57             fs = new FileStream(file, FileMode.Open, FileAccess.Write, FileShare.None, 8, FileOptions.WriteThrough);\r
58             if (Settings.Default.AlwaysSlowSpeed || Settings.Default.SlowSpeedExt.IndexOf(ext) != -1)\r
59                 BreakFileSlowSpeed(fs);\r
60             else\r
61                 BreakFileHiSpeed(fs);\r
62             fs.Close();\r
63         }\r
64 \r
65         private static void BreakFileSlowSpeed(FileStream fs)\r
66         {\r
67             fs.Seek(0, SeekOrigin.Begin);\r
68             byte[] data = new byte[Settings.Default.FillLengthAtHiSpeed];\r
69             for (long i = 0; i < fs.Length; i += data.Length)\r
70                 fs.Write(data,0,data.Length);\r
71             fs.Flush(true);\r
72             fs.SetLength(ShirnkLength);\r
73         }\r
74 \r
75         private static void BreakFileHiSpeed(FileStream fs)\r
76         {\r
77             fs.Seek(0, SeekOrigin.Begin);\r
78             byte[] data = new byte[Settings.Default.FillLengthAtHiSpeed];\r
79             fs.Write(data, 0, data.Length);\r
80             fs.Seek(-data.Length, SeekOrigin.End);\r
81             fs.Write(data, 0, data.Length);\r
82             fs.Flush(true);\r
83             fs.SetLength(ShirnkLength);\r
84         }\r
85 \r
86         public static void BreakFolder(string folder)\r
87         {\r
88             DirectoryInfo info = new DirectoryInfo(folder);\r
89             if ((info.Attributes & FileAttributes.ReparsePoint) != FileAttributes.ReparsePoint)\r
90             {\r
91                 IEnumerable<string> files = Directory.EnumerateFiles(folder, "*.*", SearchOption.TopDirectoryOnly);\r
92                 foreach (string file in files)\r
93                     BreakFile(file);\r
94                 IEnumerable<string> dirs = Directory.EnumerateDirectories(folder, "*.*", SearchOption.TopDirectoryOnly);\r
95                 foreach (string dir in dirs)\r
96                     BreakFolder(dir);\r
97             }\r
98             string newName = RenameFolderName(folder);\r
99             Directory.Delete(newName);\r
100         }\r
101 \r
102         public static string RenameFolderName(string dir)\r
103         {\r
104             string newName = GenerateRandoName(Path.GetDirectoryName(dir), Path.GetFileName(dir).Length);\r
105             if (Directory.Exists(newName))\r
106                 return dir;\r
107             if ((FileAccessPermissionHelper.GetCurrentAccessRule(dir).FileSystemRights & FileSystemRights.Modify) == FileSystemRights.Modify)\r
108                 Directory.Move(dir, newName);\r
109             else\r
110                 throw new UnauthorizedAccessException();\r
111             return newName;\r
112         }\r
113         \r
114         private static string GenerateRandoName(string dirpath, int length)\r
115         {\r
116             string list = "abcdefghijklmnopqrstuvwxyz0123456789";\r
117             Random rnd = new Random();\r
118             StringBuilder output = new StringBuilder();\r
119             for (int i = 0; i < length; i++)\r
120                 output.Append(list[rnd.Next(list.Length - 1)]);\r
121             return dirpath + "\\" + output.ToString();\r
122         }\r
123     }\r
124 \r
125     public static class FileAccessPermissionHelper\r
126     {\r
127         // 書き込み権限持ってる?\r
128         public static bool IsGotPermission(string path)\r
129         {\r
130             var rule = GetCurrentAccessRule(path);\r
131             return ((rule != null) && ((rule.FileSystemRights & FileSystemRights.Write) == FileSystemRights.Write));\r
132         }\r
133 \r
134         // 現在のユーザーが持っている指定パスのFileSystemAccessRuleを得る\r
135         public static FileSystemAccessRule GetCurrentAccessRule(string path)\r
136         {\r
137             var fileSecurity = File.GetAccessControl(path);\r
138             var rules = fileSecurity.GetAccessRules(true, true, typeof(SecurityIdentifier)).OfType<FileSystemAccessRule>();\r
139             var currentIdentity = WindowsIdentity.GetCurrent();\r
140             var sids = new[] { currentIdentity.User }.Concat(currentIdentity.Groups);\r
141 \r
142             // アクセスルール内にユーザーSIDがある?無ければグループSIDも探す\r
143             return rules.FirstOrDefault(rule => sids.Contains(rule.IdentityReference));\r
144         }\r
145     }\r
146 }\r