ACL2readonly

Форк
0
/
Program.cs 
551 строка · 18.4 Кб
1
#region License
2
//------------------------------------------------------------------------------
3
// Copyright (c) Dmitrii Evdokimov
4
// Source https://github.com/diev/
5
// 
6
// Licensed under the Apache License, Version 2.0 (the "License");
7
// you may not use this file except in compliance with the License.
8
// You may obtain a copy of the License at
9
// http://www.apache.org/licenses/LICENSE-2.0
10
// Unless required by applicable law or agreed to in writing, software
11
// distributed under the License is distributed on an "AS IS" BASIS,
12
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
// See the License for the specific language governing permissions and
14
// limitations under the License.
15
//------------------------------------------------------------------------------
16
#endregion
17

18
using System;
19
using System.Configuration;
20
using System.Diagnostics;
21
using System.IO;
22
using System.Linq;
23
using System.Reflection;
24
using System.Runtime.InteropServices;
25
using System.Security.AccessControl;
26
using System.Security.Cryptography;
27
using System.Security.Principal;
28
using System.Text;
29
using System.Xml.Linq;
30

31
namespace ACL2readonly
32
{
33
    //:: Установка прав на архив
34
    //icacls "path" /deny "principal":(DE) /t /c
35

36
    internal class Program
37
    {
38
        //counters
39
        private static int _totalDirs = 0;
40
        private static int _totalFiles = 0;
41
        private static int _newDirs = 0;
42
        private static int _newFiles = 0;
43
        private static int _renDirs = 0;
44
        private static int _renFiles = 0;
45
        private static int _renDirsE = 0;
46
        private static int _renFilesE = 0;
47
        private static int _level = 0;
48
        private static int _maxLevel = 0;
49
        private static int _errors = 0;
50

51
        //app.config
52
        private static readonly string _path = ConfigurationManager.AppSettings["Path"];
53
        private static readonly string _deny = ConfigurationManager.AppSettings["Deny"];
54
        private static string _log = ConfigurationManager.AppSettings["Log"];
55
        private static string _logE;
56

57
        //deny rights
58
        private static readonly FileSystemRights _dirDeny = FileSystemRights.Delete | FileSystemRights.DeleteSubdirectoriesAndFiles;
59
        private static readonly FileSystemRights _fileDeny = FileSystemRights.Delete | FileSystemRights.Write;
60

61
        //cut basepath
62
        private static readonly int _cut = _path.LastIndexOf(Path.DirectorySeparatorChar) + 1;
63

64
        //switch logic
65
        private static readonly bool _doRights = !string.IsNullOrEmpty(_deny);
66

67
        private static void Main(string[] args)
68
        {
69
            //try
70
            {
71
                Console.WriteLine(Banner());
72

73
                var logs = Directory.CreateDirectory(Path.Combine(_log, $"{DateTime.Now:yyyy}"));
74

75
                _log = Path.Combine(logs.FullName, $"{DateTime.Now:yyyyMMdd}.log");
76
                _logE = Path.Combine(logs.FullName, $"{DateTime.Now:yyyyMMdd}.err");
77

78
                if (!Directory.Exists(_path))
79
                {
80
                    Console.WriteLine($"Path \"{_path}\" not exists!");
81
                    Environment.Exit(2);
82
                }
83

84
                var watch = Stopwatch.StartNew();
85
                
86
                Console.WriteLine("Wait...");
87
                File.AppendAllText(_log, $"[{DateTime.Now:yyyy-MM-dd HH:mm}]\n");
88
                ProcessDir(_path);
89

90
                watch.Stop();
91

92
                StringBuilder report = new StringBuilder();
93
                report.AppendLine($"Execution Time: {watch.ElapsedMilliseconds} ms.");
94
                report.Append("Total: ");
95
                report.Append($"{_totalDirs} folders (+{_newDirs}, ren {_renDirs}/E{_renDirsE}), ");
96
                report.Append($"{_totalFiles} files (+{_newFiles}, ren {_renFiles}/E{_renFilesE}), ");
97
                report.Append($"{_maxLevel} levels, ");
98
                report.Append($"{_errors} errors");
99

100
                if (_errors > 0)
101
                {
102
                    report.Append($" (see \"{_logE}\")");
103
                }
104

105
                report.AppendLine(".");
106

107
                string s = report.ToString();
108
                Console.WriteLine($"\n{s}");
109
                File.AppendAllText(_log, $"{s}\n");
110

111
                Environment.Exit(0);
112
            }
113
            //catch (Exception e)
114
            //{
115
            //    Console.WriteLine(e.Message);
116
            //    File.AppendAllText(_logE, $"{e}\n\n");
117

118
            //    Environment.Exit(1);
119
            //}
120
        }
121

122
        /// <summary>
123
        /// Returns a banner text for this application.
124
        /// </summary>
125
        /// <returns>String of text.</returns>
126
        private static string Banner()
127
        {
128
            var assembly = Assembly.GetCallingAssembly();
129
            var assemblyName = assembly.GetName();
130
            var name = assemblyName.Name;
131
            var version = assemblyName.Version; // Major.Minor.Build.Revision
132
            string build = (version.Revision > 0) ? $" build {version.Revision}" : "";
133
            var ver = version.ToString(3);
134
            var d = Attribute.GetCustomAttribute(assembly, typeof(AssemblyDescriptionAttribute)) as AssemblyDescriptionAttribute;
135
            var c = Attribute.GetCustomAttribute(assembly, typeof(AssemblyCopyrightAttribute)) as AssemblyCopyrightAttribute;
136
            string C = c.Copyright.Replace("\u00a9", "(c)");
137

138
            return $"{name} v{ver}{build} - {d.Description}\n{C}\n";
139
        }
140

141
        /// <summary>
142
        /// Processes a specified directory.
143
        /// </summary>
144
        /// <param name="file">Directory name.</param>
145
        private static void ProcessDir(string dir)
146
        {
147
            _totalDirs++;
148

149
            if (_level > _maxLevel)
150
            {
151
                _maxLevel = _level;
152
            }
153

154
            string sdir = dir.Substring(_cut) + Path.DirectorySeparatorChar;
155

156
            string d1 = Path.GetFileName(dir);
157
            string d2 = d1.Trim();
158
            bool safe = true;
159

160
            while (d2.Contains(".."))
161
            {
162
                d2 = d2.Replace("..", ".");
163
            }
164

165
            while (d2.Contains(" ."))
166
            {
167
                d2 = d2.Replace(" .", ".");
168
            }
169

170
            while (d2.Contains(" ,"))
171
            {
172
                d2 = d2.Replace(" ,", ",");
173
            }
174

175
            while (d2.Contains("( "))
176
            {
177
                d2 = d2.Replace("( ", "(");
178
            }
179

180
            while (d2.Contains(" )"))
181
            {
182
                d2 = d2.Replace(" )", ")");
183
            }
184

185
            while (d2.Contains("  "))
186
            {
187
                d2 = d2.Replace("  ", " ");
188
            }
189

190
            while (d2.EndsWith("."))
191
            {
192
                d2 = d2.Substring(0, d2.Length - 1);
193
                safe = false;
194
            }
195

196
            if (!d2.Equals(d1))
197
            {
198
                string dir2 = Path.Combine(Path.GetDirectoryName(dir), d2);
199

200
                if (Directory.Exists(dir2))
201
                {
202
                    _renDirsE++;
203
                    File.AppendAllText(_logE, $"D2! \"{sdir}\"\n");
204

205
                    d2 = GetFreeDirname(d2);
206
                    dir2 = Path.Combine(Path.GetDirectoryName(dir), d2);
207
                }
208

209
                _renDirs++;
210
                File.AppendAllText(_log, $"ren \"{sdir}\" \"{d2}\"\n");
211

212
                if (safe)
213
                {
214
                    Directory.Move(dir, dir2);
215
                }
216
                else if (!RenameDirectoryWithSideWhiteSpaces(dir, dir2))
217
                {
218
                    _renDirsE++;
219
                    File.AppendAllText(_logE, $"DX! \"{sdir}\"\n");
220

221
                    return; //TODO bad dir!
222
                }
223

224
                dir = dir2;
225
                sdir = dir.Substring(_cut) + Path.DirectorySeparatorChar;
226

227
                //_renDirsE++;
228
                //File.AppendAllText(_logE, $"D1! \"{sdir}\"\n");
229
            }
230

231
            if (_doRights)
232
            {
233
                DirectorySecurity dirSecurity;
234

235
                try
236
                {
237
                    if (_doRights)
238
                    {
239
                        dirSecurity = Directory.GetAccessControl(dir);
240

241
                        if (NewEntry(dirSecurity))
242
                        {
243
                            _newDirs++;
244
                            dirSecurity.AddAccessRule(new FileSystemAccessRule(_deny, _dirDeny, AccessControlType.Deny));
245
                            Directory.SetAccessControl(dir, dirSecurity);
246

247
                            Console.WriteLine(sdir);
248
                            File.AppendAllText(_log, $"{sdir}\n");
249
                        }
250
                    }
251
                }
252
                catch (ArgumentException)
253
                {
254
                    _errors++;
255
                    Console.WriteLine("Error dirname! " + sdir);
256
                    File.AppendAllText(_logE, $"Error dirname! \"{sdir}\"\n");
257
                }
258
                catch (DirectoryNotFoundException)
259
                {
260
                    _errors++;
261
                    Console.WriteLine("Error dirname_! " + sdir);
262
                    File.AppendAllText(_logE, $"Error dirname_! \"{sdir}\"\n");
263
                }
264
                catch (Exception e)
265
                {
266
                    _errors++;
267
                    Console.WriteLine("Error dir! " + sdir);
268
                    File.AppendAllText(_logE, $"Error dir! \"{sdir}\"\n{e}\n\n");
269
                }
270
            }
271

272
            var files = Directory.EnumerateFiles(dir);
273

274
            foreach (string file in files)
275
            {
276
                ProcessFile(file);
277
            }
278

279
            _level++;
280
            var subdirs = Directory.EnumerateDirectories(dir);
281

282
            foreach (string subdir in subdirs)
283
            {
284
                ProcessDir(subdir);
285
            }
286

287
            _level--;
288
        }
289

290
        /// <summary>
291
        /// Processes a specified file.
292
        /// </summary>
293
        /// <param name="file">Filename.</param>
294
        private static void ProcessFile(string file)
295
        {
296
            _totalFiles++;
297

298
            string sfile = file.Substring(_cut);
299

300
            string f1 = Path.GetFileName(file);
301
            string f2 = f1.Trim();
302

303
            while (f2.Contains(".."))
304
            {
305
                f2 = f2.Replace("..", ".");
306
            }
307

308
            while (f2.Contains(" ."))
309
            {
310
                f2 = f2.Replace(" .", ".");
311
            }
312

313
            while (f2.Contains(" ,"))
314
            {
315
                f2 = f2.Replace(" ,", ",");
316
            }
317

318
            while (f2.Contains("( "))
319
            {
320
                f2 = f2.Replace("( ", "(");
321
            }
322

323
            while (f2.Contains(" )"))
324
            {
325
                f2 = f2.Replace(" )", ")");
326
            }
327

328
            while (f2.Contains("  "))
329
            {
330
                f2 = f2.Replace("  ", " ");
331
            }
332

333
            if (!f2.Equals(f1))
334
            {
335
                string file2 = Path.Combine(Path.GetDirectoryName(file), f2);
336
                try
337
                {
338
                    if (File.Exists(file2))
339
                    {
340
                        if (FileHashesEqual(file, file2))
341
                        {
342
                            _renFiles++;
343
                            File.AppendAllText(_log, $"ren(h) \"{sfile}\"\n");
344
                            File.Delete(file2);
345
                            File.Move(file, file2);
346
                            file = file2;
347
                            sfile = file.Substring(_cut);
348
                        }
349
                        else
350
                        {
351
                            //_renFilesE++;
352
                            //File.AppendAllText(_logE, $"F2! \"{sfile}\"\n");
353

354
                            _renFiles++;
355
                            File.AppendAllText(_log, $"ren(n) \"{sfile}\"\n");
356
                            file2 = GetFreeFilename(file2);
357
                            File.Move(file, file2);
358
                            file = file2;
359
                            sfile = file.Substring(_cut);
360

361
                        }
362
                    }
363
                    else
364
                    {
365
                        _renFiles++;
366
                        //File.AppendAllText(_log, $"ren \"{sfile}\"\n");
367
                        File.Move(file, file2);
368
                        file = file2;
369
                        sfile = file.Substring(_cut);
370
                    }
371
                }
372
                catch (Exception)
373
                {
374
                    File.AppendAllText(_log, $"use \"{sfile}\"\n");
375
                }
376
            }
377

378
            if (_doRights)
379
            {
380
                FileSecurity fileSecurity;
381

382
                try
383
                {
384
                    fileSecurity = File.GetAccessControl(file);
385

386
                    if (NewEntry(fileSecurity))
387
                    {
388
                        _newFiles++;
389
                        fileSecurity.AddAccessRule(new FileSystemAccessRule(_deny, _fileDeny, AccessControlType.Deny));
390
                        File.SetAccessControl(file, fileSecurity);
391

392
                        Console.WriteLine(sfile);
393
                        File.AppendAllText(_log, $"{sfile}\n");
394
                    }
395
                }
396
                catch (ArgumentException)
397
                {
398
                    _errors++;
399
                    Console.WriteLine("Error filename! " + sfile);
400
                    File.AppendAllText(_logE, $"Error filename! \"{sfile}\"\n");
401
                }
402
                catch (Exception e)
403
                {
404
                    _errors++;
405
                    Console.WriteLine("Error file! " + sfile);
406
                    File.AppendAllText(_logE, $"Error file! \"{sfile}\"\n{e}\n\n");
407
                }
408
            }
409
        }
410

411
        /// <summary>
412
        /// Check if a new directory requires to change rights.
413
        /// </summary>
414
        /// <param name="security"></param>
415
        /// <returns>True if this directory requires.</returns>
416
        private static bool NewEntry(in DirectorySecurity security)
417
        {
418
            var rules = security.GetAccessRules(true, true, typeof(NTAccount));
419

420
            foreach (FileSystemAccessRule rule in rules)
421
            {
422
                if (rule.AccessControlType.HasFlag(AccessControlType.Deny) &&
423
                    rule.IdentityReference.Value.Equals(_deny, StringComparison.OrdinalIgnoreCase) &&
424
                    rule.FileSystemRights.HasFlag(_dirDeny))
425
                {
426
                    return false;
427
                }
428
            }
429

430
            return true;
431
        }
432

433
        /// <summary>
434
        /// Check if a new file requires to change rights.
435
        /// </summary>
436
        /// <param name="security"></param>
437
        /// <returns>True if this file requires.</returns>
438
        private static bool NewEntry(in FileSecurity security)
439
        {
440
            var rules = security.GetAccessRules(true, true, typeof(NTAccount));
441

442
            foreach (FileSystemAccessRule rule in rules)
443
            {
444
                if (rule.AccessControlType.HasFlag(AccessControlType.Deny) &&
445
                    rule.IdentityReference.Value.Equals(_deny, StringComparison.OrdinalIgnoreCase) &&
446
                    rule.FileSystemRights.HasFlag(_fileDeny))
447
                {
448
                    return false;
449
                }
450
            }
451

452
            return true;
453
        }
454

455
        /// <summary>
456
        /// Compares contents of two files if they are equal.
457
        /// </summary>
458
        /// <param name="file1">Filename 1.</param>
459
        /// <param name="file2">Filename 2.</param>
460
        /// <returns>True if contents are equal.</returns>
461
        private static bool FileHashesEqual(string file1, string file2)
462
        {
463
            byte[] hash1, hash2;
464

465
            using (var hasher = MD5.Create())
466
            {
467
                using (var stream = File.OpenRead(file1))
468
                {
469
                    hash1 = hasher.ComputeHash(stream);
470
                }
471

472
                using (var stream = File.OpenRead(file2))
473
                {
474
                    hash2 = hasher.ComputeHash(stream);
475
                }
476
            }
477

478
            return hash1.Equals(hash2);
479
        }
480

481
        /// <summary>
482
        /// Looks for a free dirname with (++counter) if there is same used.
483
        /// </summary>
484
        /// <param name="file">Dirname to look.</param>
485
        /// <returns>New unused dirname.</returns>
486
        private static string GetFreeDirname(string dir)
487
        {
488
            string ext = Path.GetExtension(dir);
489
            string name = Path.ChangeExtension(dir, null);
490
            int n = 1;
491

492
            while (Directory.Exists($"{name} ({++n}){ext}"))
493
            {
494
            }
495

496
            return $"{name} ({n}){ext}";
497
        }
498

499
        /// <summary>
500
        /// Looks for a free filename with (++counter) if there is same used.
501
        /// </summary>
502
        /// <param name="file">Filename to look.</param>
503
        /// <returns>New unused filename.</returns>
504
        private static string GetFreeFilename(string file)
505
        {
506
            string ext = Path.GetExtension(file);
507
            string name = Path.ChangeExtension(file, null);
508
            int n = 1;
509

510
            while (File.Exists($"{name} ({++n}){ext}"))
511
            {
512
            }
513

514
            return $"{name} ({n}){ext}";
515
        }
516

517
        // https://social.msdn.microsoft.com/Forums/en-US/92f8813f-5dbf-4e67-b8eb-2c91de2a6696/directorynotfoundexception-when-directory-name-ends-with-white-space?forum=csharpgeneral
518

519
        [DllImport("kernel32.dll", EntryPoint = "MoveFileW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
520
        private static extern bool MoveFile(string lpExistingFileName, string lpNewFileName);
521

522
        private static bool RenameDirectoryWithSideWhiteSpaces(string path, string newPath)
523
        {
524
            var oldPath = path.StartsWith(@"\\?\") ? path : @"\\?\" + path;
525
            var result = MoveFile(oldPath, newPath);
526

527
            return result;
528
        }
529

530
        private static string RemoveSideWhiteSpaces(string path)
531
        {
532
            //var parent = Path.GetDirectoryName(path);
533
            //var name = Path.GetFileName(path);
534
            //var result = Path.Combine(parent ?? Path.GetPathRoot(path), name.Trim());
535

536
            var breadcrumbs = path.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar).Select(x => x.Trim()).ToArray();
537

538
            for (int i = 0; i < breadcrumbs.Length; i++)
539
            {
540
                while (breadcrumbs[i].EndsWith("."))
541
                {
542
                    breadcrumbs[i] = breadcrumbs[i].Substring(0, breadcrumbs[i].Length - 1);
543
                }
544
            }    
545

546
            var result = string.Join(@"\", breadcrumbs);
547

548
            return result;
549
        }
550
    }
551
}
552

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.