OSDN Git Service

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