ProjectArcade

Форк
0
/
DokanOperations.cs 
765 строк · 26.6 Кб
1
using System;
2
using System.Collections.Generic;
3
using System.IO;
4
using System.Linq;
5
using System.Text;
6
using System.Threading.Tasks;
7
using DokanNet;
8
using System.Text.RegularExpressions;
9
using System.Diagnostics;
10
using System.Threading;
11
using EmulatorLauncher.Common;
12
using EmulatorLauncher.Common.Compression;
13

14
namespace Mount
15
{
16
    public class DokanOperations : IDokanOperations
17
    {
18
        public string FileName { get; private set; }
19
        public string OverlayPath { get; private set; }
20
        public string ExtractionDirectory { get; private set; }
21

22
        private Dictionary<string, FileEntry> _entries;
23
        private OverlayDeletionRepository _overlay;
24

25
        public DokanOperations(string filepath, string extractionDirectory = null, string overlayPath = null)
26
        {
27
            FileName = filepath;
28
            ExtractionDirectory = string.IsNullOrEmpty(extractionDirectory) ? Path.Combine(Path.GetTempPath(), ".mountfs", Path.GetFileName(filepath)) : extractionDirectory;
29

30
            if (overlayPath != null && (overlayPath.StartsWith("./") || overlayPath.StartsWith(".\\")))
31
                overlayPath = Path.GetFullPath(Path.Combine(ExtractionDirectory, overlayPath));
32
            else if (overlayPath == ".")                   
33
                overlayPath = Path.GetFullPath(Path.Combine(ExtractionDirectory, ".overlay"));
34

35
            OverlayPath = overlayPath;
36

37
            _entries = new Dictionary<string, FileEntry>(StringComparer.OrdinalIgnoreCase);
38
            _entries["\\"] = new MountedFileEntry(new ZipEntry() { Filename = "\\", Length = 0, IsDirectory = true }, this);
39

40
            var entries = Zip.ListEntries(FileName);
41
            foreach (var z in entries)
42
            {
43
                var entryName = "\\" + z.Filename.Replace("/", "\\");
44
                if (IsEntryNameValid(entryName))
45
                    _entries[entryName] = new MountedFileEntry(z, this);
46
            }
47

48
            LoadOverlay();
49
            RebuildTreeChildren();
50
        }
51

52
        HashSet<string> hiddenEntries = new HashSet<string>
53
        {
54
            "\\.update-timestamp",
55
            "\\dosdevices",
56
            "\\drive_c\\windows",
57
            "\\drive_c\\.windows-serial",
58
            "\\drive_c\\program files\\common files",
59
            "\\drive_c\\program files\\internet explorer",
60
            "\\drive_c\\program files\\windows media player",
61
            "\\drive_c\\program files\\windows nt",
62
            "\\drive_c\\program files (x86)\\common files",
63
            "\\drive_c\\program files (x86)\\internet explorer",
64
            "\\drive_c\\program files (x86)\\windows media player",
65
            "\\drive_c\\program files (x86)\\windows nt",
66
            "\\drive_c\\programdata",
67
            "\\system.reg",
68
            "\\user.reg",
69
            "\\userdef.reg"
70
        };
71

72
        private bool IsEntryNameValid(string fileName)
73
        {
74
            return !hiddenEntries.Contains(fileName.ToLowerInvariant());
75
        }
76

77
        public static bool DebugOutput { get; set; }
78
        
79
        #region IDokanOperations
80
        public NtStatus GetVolumeInformation(out string volumeLabel, out FileSystemFeatures features, out string fileSystemName, out uint maximumComponentLength, IDokanFileInfo info)
81
        {
82
            maximumComponentLength = 1024;
83
            fileSystemName = Path.GetExtension(FileName).Substring(1).ToUpperInvariant();
84
            volumeLabel = Path.GetFileNameWithoutExtension(FileName);
85
            features = FileSystemFeatures.CasePreservedNames | FileSystemFeatures.UnicodeOnDisk;
86

87
            if (string.IsNullOrEmpty(OverlayPath))
88
                features |= FileSystemFeatures.ReadOnlyVolume; // | FileSystemFeatures.VolumeIsCompressed
89

90
            return NtStatus.Success;
91
        }
92

93
        public NtStatus CreateFile(string fileName, DokanNet.FileAccess access, FileShare share, FileMode mode, FileOptions options, FileAttributes attributes, IDokanFileInfo info)
94
        {            
95
            bool isWrite = access.HasFlag(DokanNet.FileAccess.WriteData) || access.HasFlag(DokanNet.FileAccess.GenericWrite);
96
            bool isRead = access.HasFlag(DokanNet.FileAccess.ReadData) || access.HasFlag(DokanNet.FileAccess.GenericRead);
97

98
            if (fileName == "\\")
99
            {
100
                info.IsDirectory = true;
101
                return DokanResult.Success;
102
            }
103

104
            if (DebugOutput)
105
                Console.WriteLine("Open: " + fileName + " : " + mode.ToString() + " ( " + access.ToString() + " ) ");
106

107
            var item = GetFile(fileName);
108

109
            if (mode == FileMode.CreateNew || (mode == FileMode.Create && item == null))
110
                item = CreateToOverlay(fileName, null, info.IsDirectory);
111

112
            if (item == null)
113
                return DokanResult.FileNotFound;
114

115
            info.IsDirectory = item.IsDirectory;
116

117
            if (access == DokanNet.FileAccess.Delete)
118
            {
119
                if (string.IsNullOrEmpty(OverlayPath))
120
                    return NtStatus.AccessDenied;
121

122
                return NtStatus.Success;
123
            }
124

125
            if (access == DokanNet.FileAccess.Synchronize || access == DokanNet.FileAccess.ReadAttributes)
126
                return NtStatus.Success;          
127

128
            if (isWrite && string.IsNullOrEmpty(OverlayPath))
129
                return NtStatus.AccessDenied;            
130

131
            if (!info.IsDirectory && info.Context == null)
132
            {            
133
                if (isRead)
134
                {
135
                    System.IO.FileAccess fileAccess = System.IO.FileAccess.Read;
136
                    if (isWrite)
137
                        fileAccess |= System.IO.FileAccess.Write;
138

139
                    var m = item as MountedFileEntry;
140
                    if (m != null && !m.Queryed)
141
                    {
142
                        m.Queryed = true;
143
                        PreloadParentFolderEntries(fileName);
144
                    }
145
                
146
                    info.Context = item.GetPhysicalFileStream(fileAccess);
147

148
                    if (DebugOutput)
149
                        Console.WriteLine("CreateFile (" + fileAccess.ToString() + "): " + fileName);
150
                }
151
                else if (isWrite)
152
                {
153
                    if (DebugOutput)
154
                        Console.WriteLine("CreateFile (FileAccess.Write): " + fileName);
155
                }
156
            }
157
                        
158
            return NtStatus.Success;            
159
        }
160

161
        private string Extension(string fileName)
162
        {
163
            return Path.GetExtension(fileName).ToLowerInvariant(); 
164
        }
165

166
        private bool IsPreloadable(string fileName)
167
        {
168
            if (string.IsNullOrEmpty(fileName))
169
                return false;
170

171
            var ext = Extension(fileName);
172
            return ext == ".dll" || ext == ".exe";
173
        }
174

175
        private void PreloadParentFolderEntries(string fileName)
176
        {
177
            var parent = GetFile(Path.GetDirectoryName(fileName)) as MountedFileEntry;
178
            if (parent == null || !parent.IsDirectory)
179
                return;
180

181
            Task.Factory.StartNew(() =>
182
            {
183
                int take = Environment.ProcessorCount;
184

185
                string ext = Extension(fileName);
186
                if (ext == ".exe" || ext == ".dll")
187
                    take = 2 * Environment.ProcessorCount;
188

189
                var children = parent.Children.OfType<MountedFileEntry>()
190
                    .Where(p => !p.Queryed && !p.IsDirectory && !File.Exists(p.PhysicalPath))  // (Extension(p.Filename) == ext || IsPreloadable(p.Filename)) && 
191
                    .OrderByDescending(p => Extension(p.Filename) == ext)
192
                    .ThenByDescending(p => IsPreloadable(p.Filename))
193
                    .Take(take)
194
                    .ToArray();
195

196
                foreach (var child in children)
197
                    child.Queryed = true;
198

199
                Parallel.ForEach(children, new ParallelOptions { MaxDegreeOfParallelism = take }, child =>
200
                {
201
                    if (DebugOutput)
202
                        Console.WriteLine("Preloading: " + child.Filename);
203

204
                    child.GetPhysicalFileStream((System.IO.FileAccess)0);
205

206
                    if (DebugOutput)
207
                        Console.WriteLine("Preloaded: " + child.Filename);
208
                });
209
            });
210
        }
211

212
        public void Cleanup(string fileName, IDokanFileInfo info)
213
        {          
214
            if (info.IsDirectory)
215
                return;
216

217
            if (DebugOutput)
218
                Console.WriteLine("Cleanup: " + fileName);
219

220
            Stream stream = info.Context as Stream;
221
            if (stream != null)
222
            {
223
                info.Context = null;
224

225
                ThreadPool.QueueUserWorkItem((a) =>
226
                    {
227
                        stream.Close();
228
                        stream.Dispose();
229
                    });
230
            }
231

232
            if (info.DeleteOnClose)
233
            {
234
                if (info.IsDirectory)
235
                    DeleteDirectory(fileName, info);
236
                else
237
                    DeleteFile(fileName, info);
238
            }
239
        }
240

241
        public void CloseFile(string fileName, IDokanFileInfo info)
242
        {
243
            if (info.IsDirectory)
244
                return;
245

246
            if (DebugOutput)
247
                Console.WriteLine("CloseFile: " + fileName);
248

249
            Stream stream = info.Context as Stream;
250
            if (stream != null)
251
            {
252
                info.Context = null;
253

254
                ThreadPool.QueueUserWorkItem((a) =>
255
                    {
256
                        stream.Close();
257
                        stream.Dispose();
258
                    });
259
            }
260
        }
261

262
        public NtStatus ReadFile(string fileName, byte[] buffer, out int bytesRead, long offset, IDokanFileInfo info)
263
        {
264
            if (DebugOutput)
265
                Console.WriteLine("ReadFile: " + fileName + " @ " + offset + " => " + buffer.Length);
266
            
267
            Stream stream = info.Context as Stream;
268

269
            if (stream == null)
270
            {
271
                if (DebugOutput)
272
                    Console.WriteLine("ReadFile: NULL CONTEXT");
273

274
                //called when file is read as memory memory mapeded file usualy notepad and stuff
275
                var item = GetFile(fileName);
276
                if (item == null)
277
                {
278
                    bytesRead = 0;
279
                    return NtStatus.FileInvalid;
280
                }
281

282
                using (var tempStream = item.GetPhysicalFileStream())
283
                {
284
                    tempStream.Position = offset;
285
                    bytesRead = tempStream.Read(buffer, 0, buffer.Length);
286
                    tempStream.Close();                  
287
                }
288

289
                return NtStatus.Success;
290
            }
291
            
292
            lock (stream)
293
            {
294
                if (stream.Position != offset)
295
                    stream.Position = offset;
296

297
                bytesRead = stream.Read(buffer, 0, buffer.Length);
298
            }
299

300
            return NtStatus.Success;
301
        }
302
        
303
        public NtStatus MoveFile(string oldName, string newName, bool replace, IDokanFileInfo info)
304
        {
305
            var item = GetFile(oldName);
306
            if (item == null)
307
                return DokanResult.FileNotFound;
308

309
            string fullPath = Path.Combine(OverlayPath, newName.Substring(1));
310

311
            if (!replace)
312
            {
313
                var destItem = GetFile(newName);
314
                if (destItem != null)
315
                    return NtStatus.CannotDelete;
316
            }
317

318
            var dir = Path.GetDirectoryName(fullPath);
319
            if (!Directory.Exists(dir))
320
                Directory.CreateDirectory(dir);
321

322
            if (item is OverlayFileEntry)
323
            {
324
                if (item.IsDirectory)
325
                    Directory.Move(item.PhysicalPath, fullPath);
326
                else
327
                    File.Move(item.PhysicalPath, fullPath);
328

329
                item.Filename = newName.Substring(1);
330
                ((OverlayFileEntry)item).SetPhysicalPath(fullPath);
331

332
                _entries.Remove(oldName.Replace("/", "\\"));
333
                _entries[newName.Replace("/", "\\")] = item;
334
                _overlay.RestoreFile(item.Filename);
335
            }
336
            else
337
            {
338
                if (item.IsDirectory)
339
                {
340
                    FileTools.CopyDirectory(item.PhysicalPath, fullPath, true);
341

342
                    var childItems = item.Traverse(c => c.Children).Skip(1).ToList();
343
                    var keysToRemove = _entries.Where(e => childItems.Contains(e.Value)).Select(e => e.Key).ToList();
344
                    foreach (var keyToRemove in keysToRemove)
345
                        _entries.Remove(keyToRemove);
346

347
                    AddPathToOverlay(fullPath);
348
                }
349
                else
350
                {
351
                    using (var fs = new FileStream(fullPath, FileMode.CreateNew, System.IO.FileAccess.Write, FileShare.ReadWrite))
352
                    using (var stream = item.GetPhysicalFileStream())
353
                        stream.CopyTo(fs);
354
                }
355

356
                DeleteFile(oldName, info);
357

358
                var ret = new OverlayFileEntry(newName, fullPath);
359
                _entries[newName.Replace("/", "\\")] = ret;
360
                _overlay.RestoreFile(ret.Filename);
361
            }
362

363
            RebuildTreeChildren();
364

365
            return NtStatus.Success;
366
        }
367

368
        public NtStatus WriteFile(string fileName, byte[] buffer, out int bytesWritten, long offset, IDokanFileInfo info)
369
        {
370
            bytesWritten = 0;
371

372
            Stream stream = info.Context as Stream;
373

374
            var item = GetFile(fileName);            
375
            if (item == null || !(item is OverlayFileEntry))
376
            {
377
                item = CreateToOverlay(fileName, item);
378

379
                if (stream != null)
380
                {
381
                    stream.Dispose();
382
                    stream = item.GetPhysicalFileStream(System.IO.FileAccess.ReadWrite);
383
                    info.Context = stream;
384
                }
385
            }
386

387
            if (stream == null && item is OverlayFileEntry)
388
            {
389
                if (DebugOutput)
390
                    Console.WriteLine("WriteFile: NULL CONTEXT");
391

392
                if (offset == 0)
393
                {
394
                    _overlay.RestoreFile(item.Filename);
395
                    File.WriteAllText(item.PhysicalPath, "");
396
                }
397

398
                using (var tempStream = item.GetPhysicalFileStream(System.IO.FileAccess.Write))
399
                {
400
                    tempStream.Position = offset;
401
                    tempStream.Write(buffer, 0, buffer.Length);
402
                    bytesWritten = (int)(tempStream.Position - offset);
403
                    tempStream.Seek(0, SeekOrigin.End);
404
                    ((OverlayFileEntry)item).SetLength(tempStream.Length);
405
                    tempStream.Close();                    
406
                }
407

408
                return NtStatus.Success;
409
            }
410

411
            lock (stream)
412
            {
413
                stream.Position = offset;
414
                stream.Write(buffer, 0, buffer.Length);
415
                bytesWritten = (int)(stream.Position - offset);
416
              
417
                return NtStatus.Success;
418
            }
419
        }
420

421
        public NtStatus FlushFileBuffers(string fileName, IDokanFileInfo info)
422
        {
423
            Stream stream = info.Context as Stream;
424
            if (stream != null)
425
                stream.Flush();
426

427
            return NtStatus.Success;
428
        }
429

430
        public NtStatus GetFileInformation(string fileName, out FileInformation fileInfo, IDokanFileInfo info)
431
        {
432
            var item = GetFile(fileName);
433
            if (item == null)
434
            {
435
                fileInfo = default(FileInformation);
436
                return DokanResult.FileNotFound;
437
            }
438

439
            fileInfo = GetFileInformation(item);
440

441
            return NtStatus.Success;
442
        }
443

444
        public NtStatus FindFiles(string fileName, out IList<FileInformation> files, IDokanFileInfo info)
445
        {
446
            files = FindFilesHelper(fileName, "*");
447
            return DokanResult.Success;
448
        }
449

450
        public NtStatus FindFilesWithPattern(string fileName, string searchPattern, out IList<FileInformation> files, IDokanFileInfo info)
451
        {
452
            files = FindFilesHelper(fileName, searchPattern);
453
            return DokanResult.Success;
454
        }
455

456
        public NtStatus SetFileAttributes(string fileName, FileAttributes attributes, IDokanFileInfo info)
457
        {
458
            return NtStatus.DiskFull;
459
        }
460

461
        public NtStatus SetFileTime(string fileName, DateTime? creationTime, DateTime? lastAccessTime, DateTime? lastWriteTime, IDokanFileInfo info)
462
        {
463
            return NtStatus.DiskFull;
464
        }
465

466
        public NtStatus DeleteFile(string fileName, IDokanFileInfo info)
467
        {
468
            var item = GetFile(fileName);
469
            if (item == null)
470
                return DokanResult.Success;
471
           
472
            _entries.Remove(fileName);
473

474
            foreach (var entry in _entries)
475
                entry.Value.Children.Remove(item);
476

477
            if (item is OverlayFileEntry)
478
            {
479
                if (item.IsDirectory)
480
                {
481
                    try { Directory.Delete(item.PhysicalPath, true); }
482
                    catch { return NtStatus.DirectoryNotEmpty; }
483
                }
484
                else
485
                    File.Delete(item.PhysicalPath);
486
            }
487
            else
488
                _overlay.DeleteFile(item.Filename);
489
            
490
            return NtStatus.Success;
491
        }
492

493
        public NtStatus DeleteDirectory(string fileName, IDokanFileInfo info)
494
        {
495
            return DeleteFile(fileName, info);            
496
        }
497

498
        public NtStatus SetEndOfFile(string fileName, long length, IDokanFileInfo info)
499
        {
500
            FileStream stream = info.Context as FileStream;
501
            if (stream != null)
502
                stream.SetLength(length);
503

504
            var item = GetFile(fileName) as OverlayFileEntry;
505
            if (item != null)
506
                item.SetLength(length);             
507

508
            return NtStatus.Success;
509
        }
510

511
        public NtStatus SetAllocationSize(string fileName, long length, IDokanFileInfo info)
512
        {
513
            FileStream stream = info.Context as FileStream;
514
            if (stream != null)
515
                stream.SetLength(length);
516

517
            var item = GetFile(fileName) as OverlayFileEntry;
518
            if (item != null)
519
                item.SetLength(length);             
520

521
            return NtStatus.Success;
522
        }
523

524
        public NtStatus LockFile(string fileName, long offset, long length, IDokanFileInfo info)
525
        {
526
            return DokanResult.Success;
527
        }
528

529
        public NtStatus UnlockFile(string fileName, long offset, long length, IDokanFileInfo info)
530
        {
531
            return DokanResult.Success;
532
        }
533

534
        public NtStatus GetDiskFreeSpace(out long freeBytesAvailable, out long totalNumberOfBytes, out long totalNumberOfFreeBytes, IDokanFileInfo info)
535
        {
536
            if (string.IsNullOrEmpty(OverlayPath))
537
            {
538
                totalNumberOfBytes = new FileInfo(FileName).Length;
539
                totalNumberOfFreeBytes = 0;
540
                freeBytesAvailable = 0;
541
            }
542
            else
543
            {
544
                try
545
                {
546
                    var driveInfo = new DriveInfo(Path.GetPathRoot(OverlayPath));
547
                    freeBytesAvailable = driveInfo.AvailableFreeSpace;
548
                    totalNumberOfBytes = driveInfo.TotalSize;
549
                    totalNumberOfFreeBytes = driveInfo.TotalFreeSpace;
550
                }
551
                catch
552
                {
553
                    totalNumberOfBytes = new FileInfo(FileName).Length;
554
                    totalNumberOfFreeBytes = 0;
555
                    freeBytesAvailable = 0;
556
                }
557
            }
558

559
            return NtStatus.Success;
560
        }
561

562
        public NtStatus GetFileSecurity(string fileName, out System.Security.AccessControl.FileSystemSecurity security, System.Security.AccessControl.AccessControlSections sections, IDokanFileInfo info)
563
        {
564
            security = null;
565
            return NtStatus.NotImplemented;
566
        }
567

568
        public NtStatus SetFileSecurity(string fileName, System.Security.AccessControl.FileSystemSecurity security, System.Security.AccessControl.AccessControlSections sections, IDokanFileInfo info)
569
        {
570
            return NtStatus.DiskFull;
571
        }
572

573
        public NtStatus Mounted(IDokanFileInfo info)
574
        {
575
            return NtStatus.Success;
576
        }
577

578
        public NtStatus Unmounted(IDokanFileInfo info)
579
        {
580
            return NtStatus.Success;
581
        }
582

583
        public NtStatus FindStreams(string fileName, out IList<FileInformation> streams, IDokanFileInfo info)
584
        {
585
            streams = new FileInformation[0];
586
            return DokanResult.NotImplemented;
587
        }
588
        #endregion
589

590
        #region Helpers
591

592
        private void RebuildTreeChildren()
593
        {
594
            foreach (var file in _entries.Values)
595
                file.Children.Clear();
596

597
            foreach (var file in _entries.Values)
598
            {
599
                if (file.Filename == "\\")
600
                    continue;
601

602
                var dir = "\\" + Path.GetDirectoryName(file.Filename);
603

604
                FileEntry entry;
605
                if (_entries.TryGetValue(dir, out entry))
606
                    entry.Children.Add(file);
607
            }
608
        }
609

610
        private void LoadOverlay()
611
        {
612
            if (string.IsNullOrEmpty(OverlayPath))
613
                return;
614

615
            // Add local files & directories
616
            if (!Directory.Exists(OverlayPath))
617
                Directory.CreateDirectory(OverlayPath);
618

619
            AddPathToOverlay(OverlayPath);
620

621
            // Overlay of deleted files
622
            _overlay = new OverlayDeletionRepository(Path.Combine(OverlayPath, ".deletions"));
623
            foreach (var removed in _overlay.DeletedFiles)
624
                _entries.Remove(removed.Replace("/", "\\"));
625
        }
626

627
        private void AddPathToOverlay(string path)
628
        {
629
            var allLocalFiles = Directory.GetDirectories(path, "*.*", SearchOption.AllDirectories).Concat(
630
                                Directory.GetFiles(path, "*.*", SearchOption.AllDirectories));
631

632
            foreach (var file in allLocalFiles)
633
            {
634
                if (file.IndexOf(OverlayPath) != 0)
635
                    continue;
636

637
                var relative = file.Substring(OverlayPath.Length);
638
                var relativeLower = relative;
639

640
                if (relativeLower == "\\.deletions")
641
                    continue;
642

643
                FileEntry entry = new OverlayFileEntry(relative, file);
644
                _entries[relativeLower] = entry;
645
            }
646
        }
647

648
        private FileEntry GetFile(string fileName)
649
        {
650
            FileEntry value;
651
            if (_entries.TryGetValue(fileName, out value))
652
                return value;
653

654
            return null;
655
        }
656

657
        IList<FileInformation> FindFilesHelper(string fileName, string searchPattern)
658
        {
659
            var item = GetFile(fileName);
660
            if (item == null)
661
                return null;
662

663
            if (item.IsDirectory)
664
            {
665
                if (item.Children == null)
666
                    return new FileInformation[] { };
667

668
                var matcher = GetMatcher(searchPattern);
669
                return item.Children.Where(x => matcher(Path.GetFileName(x.Filename))).Select(x => GetFileInformation(x)).ToList();
670
            }
671
            return null;
672
        }
673

674
        static Func<string, bool> GetMatcher(string searchPattern)
675
        {
676
            // Strange : dokan replaces * with < -> Restore * back
677
            searchPattern = searchPattern.Replace("<", "*");
678

679
            if (searchPattern == "*") 
680
                return (k) => true;
681

682
            if (searchPattern.IndexOf('?') == -1 && searchPattern.IndexOf('*') == -1) 
683
                return key => key.Equals(searchPattern, StringComparison.OrdinalIgnoreCase);
684

685
            var regex = "^" + Regex.Escape(searchPattern).Replace(@"\*", ".*").Replace(@"\?", ".") + "$";
686
            return key => Regex.IsMatch(key, regex, RegexOptions.IgnoreCase);
687
        }
688
        
689
        FileEntry CreateToOverlay(string fileName, FileEntry item, bool directory = false)
690
        {
691
            if (string.IsNullOrEmpty(fileName) || fileName == "\\")
692
                return item;
693

694
            string fullPath = Path.Combine(OverlayPath, fileName.Substring(1));
695

696
            if (item == null)
697
            {
698
                if (directory)
699
                    Directory.CreateDirectory(fullPath);
700
                else
701
                    File.WriteAllText(fullPath, "");
702

703
                var ret = new OverlayFileEntry(fileName, fullPath);
704
                ret.IsDirectory = directory;
705
                _entries[fileName.Replace("/", "\\")] = ret;
706
                _overlay.RestoreFile(ret.Filename);
707
                RebuildTreeChildren();
708

709
                return ret;
710
            }
711

712
            if (item != null && !(item is OverlayFileEntry))
713
            {
714
                if (directory)
715
                {
716
                    FileTools.CopyDirectory(item.PhysicalPath, fullPath, true);
717

718
                    var childItems = item.Traverse(c => c.Children).Skip(1).ToList();
719
                    var keysToRemove = _entries.Where(e => childItems.Contains(e.Value)).Select(e => e.Key).ToList();
720
                    foreach (var keyToRemove in keysToRemove)
721
                        _entries.Remove(keyToRemove);
722

723
                    AddPathToOverlay(fullPath);
724
                }
725
                else
726
                {
727
                    using (var fs = new FileStream(fullPath, FileMode.CreateNew, System.IO.FileAccess.Write, FileShare.ReadWrite))
728
                    using (var stream = item.GetPhysicalFileStream())
729
                        stream.CopyTo(fs);
730
                }
731

732
                var ret = new OverlayFileEntry(fileName, fullPath);
733
                ret.IsDirectory = directory;
734
                _entries[fileName.Replace("/", "\\")] = ret;
735
                _overlay.RestoreFile(ret.Filename);
736
                RebuildTreeChildren();
737

738
                return ret;
739
            }
740

741
            return item;
742
        }
743

744
        private FileInformation GetFileInformation(FileEntry item)
745
        {
746
            return new FileInformation()
747
            {
748
                Attributes = item.IsDirectory ? FileAttributes.Directory : FileAttributes.NotContentIndexed, //(FileAttributes)item.Attributes,
749
                Length = item.Length,
750
                CreationTime = item.CreationTime,
751
                FileName = Path.GetFileName(item.Filename),
752
                LastAccessTime = item.LastAccessTime,
753
                LastWriteTime = item.LastWriteTime
754
            };
755
        }
756

757
        #endregion
758

759

760
        public NtStatus Mounted(string mountPoint, IDokanFileInfo info)
761
        {
762
            return NtStatus.Success;
763
        }
764
    }
765
}
766

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

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

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

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