ProjectArcade

Форк
0
/
DokanOperationProxy.cs 
1378 строк · 59.9 Кб
1
#if !(NET10 || NET11 || NET20 || NET30 || NET35 || NET40 ) 
2
#define NET45_OR_GREATER   
3
#endif
4

5
#if NET45_OR_GREATER && !(NET45 ) 
6
#define NET451_OR_GREATER   
7
#endif
8

9
using System;
10
using System.Collections.Generic;
11
using System.Diagnostics;
12
using System.Diagnostics.Contracts;
13
using System.IO;
14
using System.Linq;
15
using System.Runtime.InteropServices;
16
using System.Security.AccessControl;
17
using System.Text;
18

19
using DokanNet.Logging;
20
using DokanNet.Native;
21

22
using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;
23

24
namespace DokanNet
25
{
26
    /// <summary>
27
    /// The dokan operation proxy.
28
    /// </summary>
29
    internal sealed class DokanOperationProxy
30
    {
31
        #region Delegates
32

33
        public delegate NtStatus ZwCreateFileDelegate(
34
            [MarshalAs(UnmanagedType.LPWStr)] string rawFileName,
35
            IntPtr securityContext,
36
            uint rawDesiredAccess,
37
            uint rawFileAttributes,
38
            uint rawShareAccess,
39
            uint rawCreateDisposition,
40
            uint rawCreateOptions,
41
            [MarshalAs(UnmanagedType.LPStruct), In, Out] DokanFileInfo dokanFileInfo);
42

43
        public delegate void CleanupDelegate(
44
            [MarshalAs(UnmanagedType.LPWStr)] string rawFileName,
45
            [MarshalAs(UnmanagedType.LPStruct), In, Out] DokanFileInfo rawFileInfo);
46

47
        public delegate void CloseFileDelegate(
48
            [MarshalAs(UnmanagedType.LPWStr)] string rawFileName,
49
            [MarshalAs(UnmanagedType.LPStruct), In, Out] DokanFileInfo rawFileInfo);
50

51
        public delegate NtStatus ReadFileDelegate(
52
            [MarshalAs(UnmanagedType.LPWStr)] string rawFileName,
53
            IntPtr rawBuffer,
54
            uint rawBufferLength,
55
            ref int rawReadLength,
56
            long rawOffset,
57
            [MarshalAs(UnmanagedType.LPStruct), In /*, Out*/] DokanFileInfo rawFileInfo);
58

59
        public delegate NtStatus WriteFileDelegate(
60
            [MarshalAs(UnmanagedType.LPWStr)] string rawFileName,
61
            IntPtr rawBuffer,
62
            uint rawNumberOfBytesToWrite,
63
            ref int rawNumberOfBytesWritten,
64
            long rawOffset,
65
            [MarshalAs(UnmanagedType.LPStruct), In /*, Out*/] DokanFileInfo rawFileInfo);
66

67
        public delegate NtStatus FlushFileBuffersDelegate(
68
            [MarshalAs(UnmanagedType.LPWStr)] string rawFileName,
69
            [MarshalAs(UnmanagedType.LPStruct), In /*, Out*/] DokanFileInfo rawFileInfo);
70

71
        public delegate NtStatus GetFileInformationDelegate(
72
            [MarshalAs(UnmanagedType.LPWStr)] string fileName,
73
            ref BY_HANDLE_FILE_INFORMATION handleFileInfo,
74
            [MarshalAs(UnmanagedType.LPStruct), In /*, Out*/] DokanFileInfo fileInfo);
75

76
        public delegate NtStatus FindFilesDelegate(
77
            [MarshalAs(UnmanagedType.LPWStr)] string rawFileName,
78
            IntPtr rawFillFindData,
79
            [MarshalAs(UnmanagedType.LPStruct), In /*, Out*/] DokanFileInfo rawFileInfo);
80

81
        public delegate NtStatus FindFilesWithPatternDelegate(
82
            [MarshalAs(UnmanagedType.LPWStr)] string rawFileName,
83
            [MarshalAs(UnmanagedType.LPWStr)] string rawSearchPattern,
84
            IntPtr rawFillFindData, 
85
            [MarshalAs(UnmanagedType.LPStruct), In, Out] DokanFileInfo rawFileInfo);
86

87
        public delegate NtStatus SetFileAttributesDelegate(
88
            [MarshalAs(UnmanagedType.LPWStr)] string rawFileName,
89
            uint rawAttributes,
90
            [MarshalAs(UnmanagedType.LPStruct), In /*, Out*/] DokanFileInfo rawFileInfo);
91

92
        public delegate NtStatus SetFileTimeDelegate(
93
            [MarshalAs(UnmanagedType.LPWStr)] string rawFileName,
94
            ref FILETIME rawCreationTime,
95
            ref FILETIME rawLastAccessTime,
96
            ref FILETIME rawLastWriteTime,
97
            [MarshalAs(UnmanagedType.LPStruct), In /*, Out*/] DokanFileInfo rawFileInfo);
98

99
        public delegate NtStatus DeleteFileDelegate(
100
            [MarshalAs(UnmanagedType.LPWStr)] string rawFileName,
101
            [MarshalAs(UnmanagedType.LPStruct), In /*, Out*/] DokanFileInfo rawFileInfo);
102

103
        public delegate NtStatus DeleteDirectoryDelegate(
104
            [MarshalAs(UnmanagedType.LPWStr)] string rawFileName,
105
            [MarshalAs(UnmanagedType.LPStruct), In /*, Out*/] DokanFileInfo rawFileInfo);
106

107
        public delegate NtStatus MoveFileDelegate(
108
            [MarshalAs(UnmanagedType.LPWStr)] string rawFileName,
109
            [MarshalAs(UnmanagedType.LPWStr)] string rawNewFileName,
110
            [MarshalAs(UnmanagedType.Bool)] bool rawReplaceIfExisting,
111
            [MarshalAs(UnmanagedType.LPStruct), In, Out] DokanFileInfo rawFileInfo);
112

113
        public delegate NtStatus SetEndOfFileDelegate(
114
            [MarshalAs(UnmanagedType.LPWStr)] string rawFileName, long rawByteOffset,
115
            [MarshalAs(UnmanagedType.LPStruct), In /*, Out*/] DokanFileInfo rawFileInfo);
116

117
        public delegate NtStatus SetAllocationSizeDelegate(
118
            [MarshalAs(UnmanagedType.LPWStr)] string rawFileName, long rawLength,
119
            [MarshalAs(UnmanagedType.LPStruct), In /*, Out*/] DokanFileInfo rawFileInfo);
120

121
        public delegate NtStatus LockFileDelegate(
122
            [MarshalAs(UnmanagedType.LPWStr)] string rawFileName, long rawByteOffset, long rawLength,
123
            [MarshalAs(UnmanagedType.LPStruct), In /*, Out*/] DokanFileInfo rawFileInfo);
124

125
        public delegate NtStatus UnlockFileDelegate(
126
            [MarshalAs(UnmanagedType.LPWStr)] string rawFileName, long rawByteOffset, long rawLength,
127
            [MarshalAs(UnmanagedType.LPStruct), In /*, Out*/] DokanFileInfo rawFileInfo);
128

129
        public delegate NtStatus GetDiskFreeSpaceDelegate(
130
            ref long rawFreeBytesAvailable, ref long rawTotalNumberOfBytes, ref long rawTotalNumberOfFreeBytes,
131
            [MarshalAs(UnmanagedType.LPStruct), In] DokanFileInfo rawFileInfo);
132

133
        public delegate NtStatus GetVolumeInformationDelegate(
134
            [MarshalAs(UnmanagedType.LPWStr)] StringBuilder rawVolumeNameBuffer,
135
            uint rawVolumeNameSize,
136
            ref uint rawVolumeSerialNumber,
137
            ref uint rawMaximumComponentLength,
138
            ref FileSystemFeatures rawFileSystemFlags,
139
            [MarshalAs(UnmanagedType.LPWStr)] StringBuilder rawFileSystemNameBuffer,
140
            uint rawFileSystemNameSize,
141
            [MarshalAs(UnmanagedType.LPStruct), In] DokanFileInfo rawFileInfo);
142

143
        public delegate NtStatus GetFileSecurityDelegate(
144
            [MarshalAs(UnmanagedType.LPWStr)] string rawFileName,
145
            [In] ref SECURITY_INFORMATION rawRequestedInformation,
146
            IntPtr rawSecurityDescriptor,
147
            uint rawSecurityDescriptorLength,
148
            ref uint rawSecurityDescriptorLengthNeeded,
149
            [MarshalAs(UnmanagedType.LPStruct), In /*, Out*/] DokanFileInfo rawFileInfo);
150

151
        public delegate NtStatus SetFileSecurityDelegate(
152
            [MarshalAs(UnmanagedType.LPWStr)] string rawFileName,
153
            [In] ref SECURITY_INFORMATION rawSecurityInformation,
154
            IntPtr rawSecurityDescriptor,
155
            uint rawSecurityDescriptorLength,
156
            [MarshalAs(UnmanagedType.LPStruct), In /*, Out*/] DokanFileInfo rawFileInfo);
157

158
        /// <summary>
159
        /// Retrieve all FileStreams informations on the file.
160
        /// This is only called if <see cref="DokanOptions.AltStream"/> is enabled.
161
        /// </summary>
162
        /// <remarks>Supported since 0.8.0. 
163
        /// You must specify the version at <see cref="DOKAN_OPTIONS.Version"/>.</remarks>
164
        /// <param name="rawFileName">Filename</param>
165
        /// <param name="rawFillFindData">A <see cref="IntPtr"/> to a <see cref="FILL_FIND_STREAM_DATA"/>.</param>
166
        /// <param name="rawFileInfo">A <see cref="DokanFileInfo"/>.</param>
167
        /// <returns></returns>
168
        public delegate NtStatus FindStreamsDelegate(
169
            [MarshalAs(UnmanagedType.LPWStr)] string rawFileName,
170
            IntPtr rawFillFindData,
171
            IntPtr findStreamContext,
172
            [MarshalAs(UnmanagedType.LPStruct), In /*, Out*/] DokanFileInfo rawFileInfo);
173

174
        public delegate NtStatus MountedDelegate(
175
            [MarshalAs(UnmanagedType.LPWStr)] string rawFileName,
176
            [MarshalAs(UnmanagedType.LPStruct), In] DokanFileInfo rawFileInfo);
177

178
        public delegate NtStatus UnmountedDelegate(
179
            [MarshalAs(UnmanagedType.LPStruct), In] DokanFileInfo rawFileInfo);
180

181
        #endregion Delegates
182

183
        private readonly IDokanOperations operations;
184

185
        private readonly ILogger logger;
186

187
        private readonly uint serialNumber;
188

189
        #region Enum masks
190
        /// <summary>
191
        /// To be used to mask out the <see cref="FileOptions"/> flags from what is returned 
192
        /// from <see cref="Native.NativeMethods.DokanMapKernelToUserCreateFileFlags"/>.
193
        /// </summary>
194
        private const int FileOptionsMask =
195
            (int)
196
            ( FileOptions.Asynchronous          | FileOptions.DeleteOnClose          | FileOptions.Encrypted 
197
            | FileOptions.None                  | FileOptions.RandomAccess           | FileOptions.SequentialScan 
198
            | FileOptions.WriteThrough);
199

200
        /// <summary>
201
        /// To be used to mask out the <see cref="FileAttributes"/> flags from what is returned 
202
        /// from <see cref="Native.NativeMethods.DokanMapKernelToUserCreateFileFlags"/>.
203
        /// Note that some flags where introduces in .NET Framework 4.5, and is not supported 
204
        /// in .NET Framework 4. 
205
        /// </summary>
206
        private const int FileAttributeMask =
207
            (int)
208
             ( FileAttributes.ReadOnly          | FileAttributes.Hidden              | FileAttributes.System
209
             | FileAttributes.Directory         | FileAttributes.Archive             | FileAttributes.Device
210
             | FileAttributes.Normal            | FileAttributes.Temporary           | FileAttributes.SparseFile
211
             | FileAttributes.ReparsePoint      | FileAttributes.Compressed          | FileAttributes.Offline
212
             | FileAttributes.NotContentIndexed | FileAttributes.Encrypted
213
#if NET45_OR_GREATER
214
          //   | FileAttributes.IntegrityStream   | FileAttributes.NoScrubData
215
#endif
216
            );
217

218
        /// <summary>
219
        /// To be used to mask out the <see cref="FileAccess"/> flags.
220
        /// </summary>
221
        private const long FileAccessMask =
222
            (uint)
223
            ( FileAccess.ReadData               | FileAccess.WriteData               | FileAccess.AppendData 
224
            | FileAccess.ReadExtendedAttributes | FileAccess.WriteExtendedAttributes | FileAccess.Execute 
225
            | FileAccess.DeleteChild            | FileAccess.ReadAttributes          | FileAccess.WriteAttributes
226
            | FileAccess.Delete                 | FileAccess.ReadPermissions         | FileAccess.ChangePermissions
227
            | FileAccess.SetOwnership           | FileAccess.Synchronize             | FileAccess.AccessSystemSecurity
228
            | FileAccess.MaximumAllowed         | FileAccess.GenericAll              | FileAccess.GenericExecute
229
            | FileAccess.GenericWrite           | FileAccess.GenericRead);
230

231
        /// <summary>
232
        /// To be used to mask out the <see cref="FileShare"/> flags.
233
        /// </summary>
234
        private const int FileShareMask =
235
            (int)
236
            ( FileShare.ReadWrite | FileShare.Delete | FileShare.Inheritable);
237
        #endregion
238

239
        /// <summary>
240
        /// Initializes a new instance of the <see cref="DokanOperationProxy"/> class.
241
        /// </summary>
242
        /// <param name="operations">
243
        /// A <see cref="IDokanOperations"/> that contains the custom implementation of the driver.
244
        /// </param>
245
        /// <param name="logger">
246
        /// A <see cref="ILogger"/> that handle all logging.
247
        /// </param>
248
        public DokanOperationProxy(ILogger logger, IDokanOperations operations)
249
        {
250
            this.logger = logger;
251
            this.operations = operations;
252
            serialNumber = (uint)operations.GetHashCode();
253
        }
254

255
        /// <summary>
256
        /// CreateFile is called each time a request is made on a file system object.
257
        /// 
258
        /// In case <see cref="FileMode.OpenOrCreate"/> and
259
        /// <see cref="FileMode.Create"/> are opening successfully a already
260
        /// existing file, you have to return <see cref="DokanResult.AlreadyExists"/> instead of <see cref="NtStatus.Success"/>.
261
        /// 
262
        /// If the file is a directory, CreateFile is also called.
263
        /// In this case, CreateFile should return <see cref="NtStatus.Success"/> when that directory
264
        /// can be opened and <see cref="DokanFileInfo.IsDirectory"/> has to be set to <c>true</c>.
265
        /// 
266
        /// <see cref="DokanFileInfo.Context"/> can be used to store data (like <see cref="FileStream"/>)
267
        /// that can be retrieved in all other request related to the context.
268
        /// </summary>
269
        /// <param name="rawFileName">File path requested by the Kernel on the FileSystem.</param>
270
        /// <param name="securityContext">SecurityContext, see <a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff550613(v=vs.85).aspx">IO_SECURITY_CONTEXT structure (MSDN)</a>.</param>
271
        /// <param name="rawDesiredAccess">Specifies an <a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff540466(v=vs.85).aspx">ACCESS_MASK (MSDN)</a> value that determines the requested access to the object.</param>
272
        /// <param name="rawFileAttributes">Specifies one or more FILE_ATTRIBUTE_XXX flags, which represent the file attributes to set if you create or overwrite a file.</param>
273
        /// <param name="rawShareAccess">Type of share access, which is specified as zero or any combination of <see cref="FileShare"/>.</param>
274
        /// <param name="rawCreateDisposition">Specifies the action to perform if the file does or does not exist.</param>
275
        /// <param name="rawCreateOptions">Specifies the options to apply when the driver creates or opens the file.</param>
276
        /// <param name="rawFileInfo">>An <see cref="DokanFileInfo"/> with information about the file or directory.</param>
277
        /// <returns>The <see cref="NtStatus"/>.</returns>
278
        /// \see <a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff566424(v=vs.85).aspx">ZwCreateFile routine (MSDN)</a>
279
        /// <see cref="DokanNet.IDokanOperations.CreateFile"/>
280
        public NtStatus ZwCreateFileProxy(
281
            string rawFileName,
282
            IntPtr securityContext,
283
            uint rawDesiredAccess,
284
            uint rawFileAttributes,
285
            uint rawShareAccess,
286
            uint rawCreateDisposition,
287
            uint rawCreateOptions,
288
            DokanFileInfo rawFileInfo)
289
        {
290
            try
291
            {
292
                var fileAttributesAndFlags = 0;
293
                var creationDisposition = 0;
294
                var outDesiredAccess = 0u;
295
                NativeMethods.DokanMapKernelToUserCreateFileFlags(
296
                    rawDesiredAccess,
297
                    rawFileAttributes,
298
                    rawCreateOptions,
299
                    rawCreateDisposition,
300
                    ref outDesiredAccess,
301
                    ref fileAttributesAndFlags,
302
                    ref creationDisposition);
303

304
                var fileAttributes = (FileAttributes)(fileAttributesAndFlags & FileAttributeMask);
305
                var fileOptions    = (FileOptions   )(fileAttributesAndFlags & FileOptionsMask);
306
                var desiredAccess  = (FileAccess    )(outDesiredAccess       & FileAccessMask);
307
                var shareAccess    = (FileShare     )(rawShareAccess         & FileShareMask);
308

309
                if (logger.DebugEnabled)
310
                {
311
                    logger.Debug("CreateFileProxy : {0}", rawFileName);
312
                    logger.Debug("\tCreationDisposition\t{0}", (FileMode)creationDisposition);
313
                    logger.Debug("\tFileAccess\t{0}", (FileAccess)rawDesiredAccess);
314
                    logger.Debug("\tFileShare\t{0}", (FileShare)rawShareAccess);
315
                    logger.Debug("\tFileOptions\t{0}", fileOptions);
316
                    logger.Debug("\tFileAttributes\t{0}", fileAttributes);
317
                    logger.Debug("\tContext\t{0}", rawFileInfo);
318
                }
319

320
                var result = operations.CreateFile(
321
                    rawFileName,
322
                    desiredAccess,
323
                    shareAccess,
324
                    (FileMode)creationDisposition,
325
                    fileOptions,
326
                    fileAttributes,
327
                    rawFileInfo);
328

329
                if (logger.DebugEnabled) logger.Debug("CreateFileProxy : {0} Return : {1}", rawFileName, result);
330
                return result;
331
            }
332
            catch (Exception ex)
333
            {
334
                logger.Error("CreateFileProxy : {0} Throw : {1}", rawFileName, ex.Message);
335
                return DokanResult.Unsuccessful;
336
            }
337
        }
338

339
        ////
340

341
        public void CleanupProxy(string rawFileName, DokanFileInfo rawFileInfo)
342
        {
343
            try
344
            {
345
                if (logger.DebugEnabled)
346
                {
347
                    logger.Debug("CleanupProxy : {0}", rawFileName);
348
                    logger.Debug("\tContext\t{0}", rawFileInfo);
349
                }
350

351
                operations.Cleanup(rawFileName, rawFileInfo);
352

353
                if (logger.DebugEnabled) logger.Debug("CleanupProxy : {0}", rawFileName);
354
            }
355
            catch (Exception ex)
356
            {
357
                logger.Error("CleanupProxy : {0} Throw : {1}", rawFileName, ex.Message);
358
            }
359
        }
360

361
        ////
362

363
        public void CloseFileProxy(string rawFileName, DokanFileInfo rawFileInfo)
364
        {
365
            try
366
            {
367
                if (logger.DebugEnabled)
368
                {
369
                    logger.Debug("CloseFileProxy : {0}", rawFileName);
370
                    logger.Debug("\tContext\t{0}", rawFileInfo);
371
                }
372

373
                operations.CloseFile(rawFileName, rawFileInfo);
374

375
                if (logger.DebugEnabled) logger.Debug("CloseFileProxy : {0}", rawFileName);
376
            }
377
            catch (Exception ex)
378
            {
379
                logger.Error("CloseFileProxy : {0} Throw : {1}", rawFileName, ex.Message);
380
            }
381
            finally
382
            {
383
                rawFileInfo.Context = null;
384
            }
385
        }
386

387
        ////
388

389
        public NtStatus ReadFileProxy(
390
            string rawFileName,
391
            IntPtr rawBuffer,
392
            uint rawBufferLength,
393
            ref int rawReadLength,
394
            long rawOffset,
395
            DokanFileInfo rawFileInfo)
396
        {
397
            try
398
            {
399
                if (logger.DebugEnabled)
400
                {
401
                    logger.Debug("ReadFileProxy : " + rawFileName);
402
                    logger.Debug("\tBufferLength\t" + rawBufferLength);
403
                    logger.Debug("\tOffset\t" + rawOffset);
404
                    logger.Debug("\tContext\t" + rawFileInfo);
405
                }
406

407
                // Check if the file system has implemented the unsafe Dokan interface.
408
                // If so, pass the raw IntPtr through instead of marshalling.
409
                NtStatus result;
410
                if (operations is IDokanOperationsUnsafe)
411
                {
412
                    IDokanOperationsUnsafe unsafeOperations = operations as IDokanOperationsUnsafe;
413
                    result = unsafeOperations.ReadFile(rawFileName, rawBuffer, rawBufferLength, out rawReadLength, rawOffset, rawFileInfo);
414
                }
415
                else
416
                {
417
                    // Pool the read buffer and return it to the pool when we're done with it.
418
                    byte[] buffer = BufferPool.Default.RentBuffer(rawBufferLength, logger);
419
                    try
420
                    {
421
                        result = operations.ReadFile(rawFileName, buffer, out rawReadLength, rawOffset, rawFileInfo);
422
                        Marshal.Copy(buffer, 0, rawBuffer, (int)rawBufferLength);
423
                    }
424
                    finally
425
                    {
426
                        BufferPool.Default.ReturnBuffer(buffer, logger);
427
                    }
428
                }
429

430
                if (logger.DebugEnabled) logger.Debug("ReadFileProxy : " + rawFileName + " Return : " + result + " ReadLength : " + rawReadLength);
431
                return result;
432
            }
433
            catch (Exception ex)
434
            {
435
                logger.Error("ReadFileProxy : {0} Throw : {1}", rawFileName, ex.Message);
436
                return DokanResult.InvalidParameter;
437
            }
438
        }
439

440
        ////
441

442
        public NtStatus WriteFileProxy(
443
            string rawFileName,
444
            IntPtr rawBuffer,
445
            uint rawNumberOfBytesToWrite,
446
            ref int rawNumberOfBytesWritten,
447
            long rawOffset,
448
            DokanFileInfo rawFileInfo)
449
        {
450
            try
451
            {
452
                if (logger.DebugEnabled)
453
                {
454
                    logger.Debug("WriteFileProxy : {0}", rawFileName);
455
                    logger.Debug("\tNumberOfBytesToWrite\t{0}", rawNumberOfBytesToWrite);
456
                    logger.Debug("\tOffset\t{0}", rawOffset);
457
                    logger.Debug("\tContext\t{0}", rawFileInfo);
458
                }
459

460
                // Check if the file system has implemented the unsafe Dokan interface.
461
                // If so, pass the raw IntPtr through instead of marshalling.
462
                NtStatus result;
463
                if (operations is IDokanOperationsUnsafe)
464
                {
465
                    IDokanOperationsUnsafe unsafeOperations = operations as IDokanOperationsUnsafe;
466
                    result = unsafeOperations.WriteFile(rawFileName, rawBuffer, rawNumberOfBytesToWrite, out rawNumberOfBytesWritten, rawOffset, rawFileInfo);
467
                }
468
                else
469
                {
470
                    // Pool the write buffer and return it to the pool when we're done with it.
471
                    byte[] buffer = BufferPool.Default.RentBuffer(rawNumberOfBytesToWrite, logger);
472
                    try
473
                    {
474
                        Marshal.Copy(rawBuffer, buffer, 0, (int)rawNumberOfBytesToWrite);
475
                        result = operations.WriteFile(
476
                            rawFileName,
477
                            buffer,
478
                            out rawNumberOfBytesWritten,
479
                            rawOffset,
480
                            rawFileInfo);
481
                    }
482
                    finally
483
                    {
484
                        BufferPool.Default.ReturnBuffer(buffer, logger);
485
                    }
486
                }
487

488
                if (logger.DebugEnabled)
489
                {
490
                    logger.Debug(
491
                        "WriteFileProxy : {0} Return : {1} NumberOfBytesWritten : {2}",
492
                        rawFileName,
493
                        result,
494
                        rawNumberOfBytesWritten);
495
                }
496

497
                return result;
498
            }
499
            catch (Exception ex)
500
            {
501
                logger.Error("WriteFileProxy : {0} Throw : {1}", rawFileName, ex.Message);
502
                return DokanResult.InvalidParameter;
503
            }
504
        }
505

506
        ////
507

508
        public NtStatus FlushFileBuffersProxy(string rawFileName, DokanFileInfo rawFileInfo)
509
        {
510
            try
511
            {
512
                if (logger.DebugEnabled)
513
                {
514
                    logger.Debug("FlushFileBuffersProxy : {0}", rawFileName);
515
                    logger.Debug("\tContext\t{0}", rawFileInfo);
516
                }
517

518
                var result = operations.FlushFileBuffers(rawFileName, rawFileInfo);
519

520
                if (logger.DebugEnabled) logger.Debug("FlushFileBuffersProxy : {0} Return : {1}", rawFileName, result);
521
                return result;
522
            }
523
            catch (Exception ex)
524
            {
525
                logger.Error("FlushFileBuffersProxy : {0} Throw : {1}", rawFileName, ex.Message);
526
                return DokanResult.InvalidParameter;
527
            }
528
        }
529

530
        ////
531

532
        public NtStatus GetFileInformationProxy(
533
            string rawFileName,
534
            ref BY_HANDLE_FILE_INFORMATION rawHandleFileInformation,
535
            DokanFileInfo rawFileInfo)
536
        {
537
            try
538
            {
539
                if (logger.DebugEnabled)
540
                {
541
                    logger.Debug("GetFileInformationProxy : {0}", rawFileName);
542
                    logger.Debug("\tContext\t{0}", rawFileInfo);
543
                }
544

545
                FileInformation fi;
546
                var result = operations.GetFileInformation(rawFileName, out fi, rawFileInfo);
547

548
                if (result == DokanResult.Success)
549
                {
550
                    Debug.Assert(fi.FileName != null, "FileName must not be null");
551
                    if (logger.DebugEnabled)
552
                    {
553
                        logger.Debug("\tFileName\t{0}", fi.FileName);
554
                        logger.Debug("\tAttributes\t{0}", fi.Attributes);
555
                        logger.Debug("\tCreationTime\t{0}", fi.CreationTime);
556
                        logger.Debug("\tLastAccessTime\t{0}", fi.LastAccessTime);
557
                        logger.Debug("\tLastWriteTime\t{0}", fi.LastWriteTime);
558
                        logger.Debug("\tLength\t{0}", fi.Length);
559
                    }
560

561
                    rawHandleFileInformation.dwFileAttributes = (uint)fi.Attributes /* + FILE_ATTRIBUTE_VIRTUAL*/;
562

563
                    var ctime = ToFileTime(fi.CreationTime);
564
                    var atime = ToFileTime(fi.LastAccessTime);
565
                    var mtime = ToFileTime(fi.LastWriteTime);
566
                    rawHandleFileInformation.ftCreationTime.dwHighDateTime = (int)(ctime >> 32);
567
                    rawHandleFileInformation.ftCreationTime.dwLowDateTime = (int)(ctime & 0xffffffff);
568

569
                    rawHandleFileInformation.ftLastAccessTime.dwHighDateTime = (int)(atime >> 32);
570
                    rawHandleFileInformation.ftLastAccessTime.dwLowDateTime = (int)(atime & 0xffffffff);
571

572
                    rawHandleFileInformation.ftLastWriteTime.dwHighDateTime = (int)(mtime >> 32);
573
                    rawHandleFileInformation.ftLastWriteTime.dwLowDateTime = (int)(mtime & 0xffffffff);
574

575
                    rawHandleFileInformation.dwVolumeSerialNumber = serialNumber;
576

577
                    rawHandleFileInformation.nFileSizeLow = (uint)(fi.Length & 0xffffffff);
578
                    rawHandleFileInformation.nFileSizeHigh = (uint)(fi.Length >> 32);
579
                    rawHandleFileInformation.dwNumberOfLinks = 1;
580
                    rawHandleFileInformation.nFileIndexHigh = 0;
581
                    rawHandleFileInformation.nFileIndexLow = (uint)(fi.FileName != null ? fi.FileName.GetHashCode() : 0);
582
                }
583

584
                if (logger.DebugEnabled) logger.Debug("GetFileInformationProxy : {0} Return : {1}", rawFileName, result);
585
                return result;
586
            }
587
            catch (Exception ex)
588
            {
589
                logger.Error("GetFileInformationProxy : {0} Throw : {1}", rawFileName, ex.Message);
590
                return DokanResult.InvalidParameter;
591
            }
592
        }
593

594
        ////
595

596
        public NtStatus FindFilesProxy(string rawFileName, IntPtr rawFillFindData, DokanFileInfo rawFileInfo)
597
        {
598
            try
599
            {
600
                if (logger.DebugEnabled)
601
                {
602
                    logger.Debug("FindFilesProxy : {0}", rawFileName);
603
                    logger.Debug("\tContext\t{0}", rawFileInfo);
604
                }
605

606
                IList<FileInformation> files;
607
                var result = operations.FindFiles(rawFileName, out files, rawFileInfo);
608

609
                Debug.Assert(files != null, "Files must not be null");
610
                if (result == DokanResult.Success && files.Count != 0)
611
                {
612
                    if (logger.DebugEnabled)
613
                    {
614
                        foreach (var fi in files)
615
                        {
616
                            logger.Debug("\tFileName\t{0}", fi.FileName);
617
                            logger.Debug("\t\tAttributes\t{0}", fi.Attributes);
618
                            logger.Debug("\t\tCreationTime\t{0}", fi.CreationTime);
619
                            logger.Debug("\t\tLastAccessTime\t{0}", fi.LastAccessTime);
620
                            logger.Debug("\t\tLastWriteTime\t{0}", fi.LastWriteTime);
621
                            logger.Debug("\t\tLength\t{0}", fi.Length);
622
                        }
623
                    }
624

625
                    var fill = GetDataFromPointer<FILL_FIND_FILE_DATA>(rawFillFindData);
626

627
                    // used a single entry call to speed up the "enumeration" of the list
628
                    foreach (var t in files)
629
                    {
630
                        AddTo(fill, rawFileInfo, t);
631
                    }
632
                }
633

634
                if (logger.DebugEnabled) logger.Debug("FindFilesProxy : {0} Return : {1}", rawFileName, result);
635
                return result;
636
            }
637
            catch (Exception ex)
638
            {
639
                logger.Error("FindFilesProxy : {0} Throw : {1}", rawFileName, ex.Message);
640
                return DokanResult.InvalidParameter;
641
            }
642
        }
643

644
        public NtStatus FindFilesWithPatternProxy(
645
            string rawFileName,
646
            string rawSearchPattern,
647
            IntPtr rawFillFindData,
648
            DokanFileInfo rawFileInfo)
649
        {
650
            try
651
            {
652
                if (logger.DebugEnabled)
653
                {
654
                    logger.Debug("FindFilesWithPatternProxy : {0}", rawFileName);
655
                    logger.Debug("\trawSearchPattern\t{0}", rawSearchPattern);
656
                    logger.Debug("\tContext\t{0}", rawFileInfo);
657
                }
658

659
                IList<FileInformation> files;
660
                var result = operations.FindFilesWithPattern(rawFileName, rawSearchPattern, out files, rawFileInfo);
661

662
                Debug.Assert(files != null, "Files must not be null");
663
                if (result == DokanResult.Success && files.Any())
664
                {
665
                    if (logger.DebugEnabled)
666
                    {
667
                        foreach (var fi in files)
668
                        {
669
                            logger.Debug("\tFileName\t{0}", fi.FileName);
670
                            logger.Debug("\t\tAttributes\t{0}", fi.Attributes);
671
                            logger.Debug("\t\tCreationTime\t{0}", fi.CreationTime);
672
                            logger.Debug("\t\tLastAccessTime\t{0}", fi.LastAccessTime);
673
                            logger.Debug("\t\tLastWriteTime\t{0}", fi.LastWriteTime);
674
                            logger.Debug("\t\tLength\t{0}", fi.Length);
675
                        }
676
                    }
677

678
                    var fill = GetDataFromPointer<FILL_FIND_FILE_DATA>(rawFillFindData);
679

680
                    // used a single entry call to speed up the "enumeration" of the list
681
                    foreach (var t in files)
682
                    {
683
                        AddTo(fill, rawFileInfo, t);
684
                    }
685
                }
686

687
                if (logger.DebugEnabled) logger.Debug("FindFilesWithPatternProxy : {0} Return : {1}", rawFileName, result);
688
                return result;
689
            }
690
            catch (Exception ex)
691
            {
692
                logger.Error("FindFilesWithPatternProxy : {0} Throw : {1}", rawFileName, ex.Message);
693
                return DokanResult.InvalidParameter;
694
            }
695
        }
696

697
        /// <summary>
698
        /// Call the delegate <paramref name="fill"/> using data in <paramref name="rawFileInfo"/> and <paramref name="fi"/>.
699
        /// </summary>
700
        /// <param name="fill">The delegate of type <see cref="FILL_FIND_FILE_DATA"/> to be called.</param>
701
        /// <param name="rawFileInfo">A <see cref="DokanFileInfo"/> to be used when calling <paramref name="fill"/>.</param>
702
        /// <param name="fi">A <see cref="FileInformation"/> with information to be used when calling <paramref name="fill"/>.</param>
703
        private static void AddTo(FILL_FIND_FILE_DATA fill, DokanFileInfo rawFileInfo, FileInformation fi)
704
        {
705
            Debug.Assert(!string.IsNullOrEmpty(fi.FileName), "FileName must not be empty or null");
706
            var ctime = ToFileTime(fi.CreationTime);
707
            var atime = ToFileTime(fi.LastAccessTime);
708
            var mtime = ToFileTime(fi.LastWriteTime);
709
            var data = new WIN32_FIND_DATA
710
            {
711
                dwFileAttributes = fi.Attributes,
712
                ftCreationTime =
713
                {
714
                    dwHighDateTime = (int) (ctime >> 32),
715
                    dwLowDateTime = (int) (ctime & 0xffffffff)
716
                },
717
                ftLastAccessTime =
718
                {
719
                    dwHighDateTime = (int) (atime >> 32),
720
                    dwLowDateTime = (int) (atime & 0xffffffff)
721
                },
722
                ftLastWriteTime =
723
                {
724
                    dwHighDateTime = (int) (mtime >> 32),
725
                    dwLowDateTime = (int) (mtime & 0xffffffff)
726
                },
727
                nFileSizeLow = (uint)(fi.Length & 0xffffffff),
728
                nFileSizeHigh = (uint)(fi.Length >> 32),
729
                cFileName = fi.FileName
730
            };
731
            //ZeroMemory(&data, sizeof(WIN32_FIND_DATAW));
732

733
            fill(ref data, rawFileInfo);
734
        }
735

736
        public NtStatus FindStreamsProxy(string rawFileName, IntPtr rawFillFindData, IntPtr findStreamContext, DokanFileInfo rawFileInfo)
737
        {
738
            try
739
            {
740
                if (logger.DebugEnabled)
741
                {
742
                    logger.Debug("FindStreamsProxy: {0}", rawFileName);
743
                    logger.Debug("\tContext\t{0}", rawFileInfo);
744
                }
745

746
                IList<FileInformation> files;
747
                var result = operations.FindStreams(rawFileName, out files, rawFileInfo);
748

749
                Debug.Assert(!(result == DokanResult.NotImplemented && files == null));
750
                if (result == DokanResult.Success && files.Count != 0)
751
                {
752
                    if (logger.DebugEnabled)
753
                    {
754
                        foreach (var fi in files)
755
                        {
756
                            logger.Debug("\tFileName\t{0}", fi.FileName);
757
                            logger.Debug("\t\tLength\t{0}", fi.Length);
758
                        }
759
                    }
760

761
                    var fill = GetDataFromPointer<FILL_FIND_STREAM_DATA>(rawFillFindData);
762

763
                    // used a single entry call to speed up the "enumeration" of the list
764
                    bool bufferFull = false;
765
                    foreach (var t in files)
766
                    {
767
                        if (bufferFull)
768
                        {
769
                            result = NtStatus.BufferOverflow;
770
                            break;
771
                        }
772
                        bufferFull = !AddTo(fill, findStreamContext, t);
773
                    }
774
                }
775

776
                if (logger.DebugEnabled) logger.Debug("FindStreamsProxy : {0} Return : {1}", rawFileName, result);
777
                return result;
778
            }
779
            catch (Exception ex)
780
            {
781
                logger.Error("FindStreamsProxy : {0} Throw : {1}", rawFileName, ex.Message);
782
                return DokanResult.InvalidParameter;
783
            }
784
        }
785

786
        /// <summary>Converts an unmanaged function pointer to a delegate of a specified type. </summary>
787
        /// <returns>A instance of the specified delegate type.</returns>
788
        /// <param name="rawDelegate">The unmanaged function pointer to convert. </param>
789
        /// <typeparam name="TDelegate">The type of the delegate to return. </typeparam>
790
        /// <exception cref="T:System.ArgumentException">The <typeparam name="TDelegate" /> generic parameter is not a delegate, or it is an open generic type.</exception>
791
        /// <exception cref="T:System.ArgumentNullException">The <paramref name="rawDelegate" /> parameter is null.</exception>
792
        private static TDelegate GetDataFromPointer<TDelegate>(IntPtr rawDelegate) where TDelegate : class 
793
        {
794
            /*
795
#if NET451_OR_GREATER
796
            return Marshal.GetDelegateForFunctionPointer<TDelegate>(rawDelegate);
797
#else*/
798
            return Marshal.GetDelegateForFunctionPointer(rawDelegate, typeof(TDelegate)) as TDelegate;
799
//#endif
800
        }
801

802
        /// <summary>
803
        /// Call the delegate <paramref name="fill"/> using data in <paramref name="rawFileInfo"/> and <paramref name="fi"/>.
804
        /// </summary>
805
        /// <param name="fill">The delegate of type <see cref="FILL_FIND_STREAM_DATA"/> to be called.</param>
806
        /// <param name="rawFileInfo">A <see cref="DokanFileInfo"/> to be used when calling <paramref name="fill"/>.</param>
807
        /// <param name="fi">A <see cref="FileInformation"/> with information to be used when calling <paramref name="fill"/>.</param>
808
        /// <returns>Whether the buffer is full or not.</returns>
809
        private static bool AddTo(FILL_FIND_STREAM_DATA fill, IntPtr findStreamContext, FileInformation fi)
810
        {
811
            Debug.Assert(!string.IsNullOrEmpty(fi.FileName), "FileName must not be empty or null");
812
            var data = new WIN32_FIND_STREAM_DATA
813
            {
814
                StreamSize = fi.Length,
815
                cStreamName = fi.FileName
816
            };
817
            //ZeroMemory(&data, sizeof(WIN32_FIND_DATAW));
818

819
            return fill(ref data, findStreamContext);
820
        }
821

822
        ////
823

824
        public NtStatus SetEndOfFileProxy(string rawFileName, long rawByteOffset, DokanFileInfo rawFileInfo)
825
        {
826
            try
827
            {
828
                if (logger.DebugEnabled)
829
                {
830
                    logger.Debug("SetEndOfFileProxy : {0}", rawFileName);
831
                    logger.Debug("\tByteOffset\t{0}", rawByteOffset);
832
                    logger.Debug("\tContext\t{0}", rawFileInfo);
833
                }
834

835
                var result = operations.SetEndOfFile(rawFileName, rawByteOffset, rawFileInfo);
836

837
                if (logger.DebugEnabled) logger.Debug("SetEndOfFileProxy : {0} Return : {1}", rawFileName, result);
838
                return result;
839
            }
840
            catch (Exception ex)
841
            {
842
                logger.Error("SetEndOfFileProxy : {0} Throw : {1}", rawFileName, ex.Message);
843
                return DokanResult.InvalidParameter;
844
            }
845
        }
846

847
        public NtStatus SetAllocationSizeProxy(string rawFileName, long rawLength, DokanFileInfo rawFileInfo)
848
        {
849
            try
850
            {
851
                if (logger.DebugEnabled)
852
                {
853
                    logger.Debug("SetAllocationSizeProxy : {0}", rawFileName);
854
                    logger.Debug("\tLength\t{0}", rawLength);
855
                    logger.Debug("\tContext\t{0}", rawFileInfo);
856
                }
857

858
                var result = operations.SetAllocationSize(rawFileName, rawLength, rawFileInfo);
859

860
                if (logger.DebugEnabled) logger.Debug("SetAllocationSizeProxy : {0} Return : {1}", rawFileName, result);
861
                return result;
862
            }
863
            catch (Exception ex)
864
            {
865
                logger.Error("SetAllocationSizeProxy : {0} Throw : {1}", rawFileName, ex.Message);
866
                return DokanResult.InvalidParameter;
867
            }
868
        }
869

870
        ////
871

872
        public NtStatus SetFileAttributesProxy(string rawFileName, uint rawAttributes, DokanFileInfo rawFileInfo)
873
        {
874
            try
875
            {
876
                if (logger.DebugEnabled)
877
                {
878
                    logger.Debug("SetFileAttributesProxy : {0}", rawFileName);
879
                    logger.Debug("\tAttributes\t{0}", (FileAttributes)rawAttributes);
880
                    logger.Debug("\tContext\t{0}", rawFileInfo);
881
                }
882

883
                var result = operations.SetFileAttributes(rawFileName, (FileAttributes)rawAttributes, rawFileInfo);
884

885
                if (logger.DebugEnabled) logger.Debug("SetFileAttributesProxy : {0} Return : {1}", rawFileName, result);
886
                return result;
887
            }
888
            catch (Exception ex)
889
            {
890
                logger.Error("SetFileAttributesProxy : {0} Throw : {1}", rawFileName, ex.Message);
891
                return DokanResult.InvalidParameter;
892
            }
893
        }
894

895
        ////
896

897
        public NtStatus SetFileTimeProxy(
898
            string rawFileName,
899
            ref FILETIME rawCreationTime,
900
            ref FILETIME rawLastAccessTime,
901
            ref FILETIME rawLastWriteTime,
902
            DokanFileInfo rawFileInfo)
903
        {
904
            try
905
            {
906
                var ctime = (rawCreationTime.dwLowDateTime != 0 || rawCreationTime.dwHighDateTime != 0) &&
907
                            (rawCreationTime.dwLowDateTime != -1 || rawCreationTime.dwHighDateTime != -1)
908
                    ? DateTime.FromFileTime(((long) rawCreationTime.dwHighDateTime << 32) |
909
                                            (uint) rawCreationTime.dwLowDateTime)
910
                    : (DateTime?) null;
911
                var atime = (rawLastAccessTime.dwLowDateTime != 0 || rawLastAccessTime.dwHighDateTime != 0) &&
912
                            (rawLastAccessTime.dwLowDateTime != -1 || rawLastAccessTime.dwHighDateTime != -1)
913
                    ? DateTime.FromFileTime(((long) rawLastAccessTime.dwHighDateTime << 32) |
914
                                            (uint) rawLastAccessTime.dwLowDateTime)
915
                    : (DateTime?) null;
916
                var mtime = (rawLastWriteTime.dwLowDateTime != 0 || rawLastWriteTime.dwHighDateTime != 0) &&
917
                            (rawLastWriteTime.dwLowDateTime != -1 || rawLastWriteTime.dwHighDateTime != -1)
918
                    ? DateTime.FromFileTime(((long) rawLastWriteTime.dwHighDateTime << 32) |
919
                                            (uint) rawLastWriteTime.dwLowDateTime)
920
                    : (DateTime?) null;
921

922
                if (logger.DebugEnabled)
923
                {
924
                    logger.Debug("SetFileTimeProxy : {0}", rawFileName);
925
                    logger.Debug("\tCreateTime\t{0}", ctime);
926
                    logger.Debug("\tAccessTime\t{0}", atime);
927
                    logger.Debug("\tWriteTime\t{0}", mtime);
928
                    logger.Debug("\tContext\t{0}", rawFileInfo);
929
                }
930

931
                var result = operations.SetFileTime(rawFileName, ctime, atime, mtime, rawFileInfo);
932

933
                if (logger.DebugEnabled) logger.Debug("SetFileTimeProxy : {0} Return : {1}", rawFileName, result);
934
                return result;
935
            }
936
            catch (Exception ex)
937
            {
938
                logger.Error("SetFileTimeProxy : {0} Throw : {1}", rawFileName, ex.Message);
939
                return DokanResult.InvalidParameter;
940
            }
941
        }
942

943
        ////
944

945
        public NtStatus DeleteFileProxy(string rawFileName, DokanFileInfo rawFileInfo)
946
        {
947
            try
948
            {
949
                if (logger.DebugEnabled)
950
                {
951
                    logger.Debug("DeleteFileProxy : {0}", rawFileName);
952
                    logger.Debug("\tContext\t{0}", rawFileInfo);
953
                }
954

955
                var result = operations.DeleteFile(rawFileName, rawFileInfo);
956

957
                if (logger.DebugEnabled) logger.Debug("DeleteFileProxy : {0} Return : {1}", rawFileName, result);
958
                return result;
959
            }
960
            catch (Exception ex)
961
            {
962
                logger.Error("DeleteFileProxy : {0} Throw : {1}", rawFileName, ex.Message);
963
                return DokanResult.InvalidParameter;
964
            }
965
        }
966

967
        ////
968

969
        public NtStatus DeleteDirectoryProxy(string rawFileName, DokanFileInfo rawFileInfo)
970
        {
971
            try
972
            {
973
                if (logger.DebugEnabled)
974
                {
975
                    logger.Debug("DeleteDirectoryProxy : {0}", rawFileName);
976
                    logger.Debug("\tContext\t{0}", rawFileInfo);
977
                }
978

979
                var result = operations.DeleteDirectory(rawFileName, rawFileInfo);
980

981
                if (logger.DebugEnabled) logger.Debug("DeleteDirectoryProxy : {0} Return : {1}", rawFileName, result);
982
                return result;
983
            }
984
            catch (Exception ex)
985
            {
986
                logger.Error("DeleteDirectoryProxy : {0} Throw : {1}", rawFileName, ex.Message);
987
                return DokanResult.InvalidParameter;
988
            }
989
        }
990

991
        ////
992

993
        public NtStatus MoveFileProxy(
994
            string rawFileName,
995
            string rawNewFileName,
996
            bool rawReplaceIfExisting,
997
            DokanFileInfo rawFileInfo)
998
        {
999
            try
1000
            {
1001
                if (logger.DebugEnabled)
1002
                {
1003
                    logger.Debug("MoveFileProxy : {0}", rawFileName);
1004
                    logger.Debug("\tNewFileName\t{0}", rawNewFileName);
1005
                    logger.Debug("\tReplaceIfExisting\t{0}", rawReplaceIfExisting);
1006
                    logger.Debug("\tContext\t{0}", rawFileInfo);
1007
                }
1008

1009
                var result = operations.MoveFile(rawFileName, rawNewFileName, rawReplaceIfExisting, rawFileInfo);
1010

1011
                if (logger.DebugEnabled) logger.Debug("MoveFileProxy : {0} Return : {1}", rawFileName, result);
1012
                return result;
1013
            }
1014
            catch (Exception ex)
1015
            {
1016
                logger.Error("MoveFileProxy : {0} Throw : {1}", rawFileName, ex.Message);
1017
                return DokanResult.InvalidParameter;
1018
            }
1019
        }
1020

1021
        ////
1022

1023
        public NtStatus LockFileProxy(string rawFileName, long rawByteOffset, long rawLength, DokanFileInfo rawFileInfo)
1024
        {
1025
            try
1026
            {
1027
                if (logger.DebugEnabled)
1028
                {
1029
                    logger.Debug("LockFileProxy : {0}", rawFileName);
1030
                    logger.Debug("\tByteOffset\t{0}", rawByteOffset);
1031
                    logger.Debug("\tLength\t{0}", rawLength);
1032
                    logger.Debug("\tContext\t{0}", rawFileInfo);
1033
                }
1034

1035
                var result = operations.LockFile(rawFileName, rawByteOffset, rawLength, rawFileInfo);
1036

1037
                if (logger.DebugEnabled) logger.Debug("LockFileProxy : {0} Return : {1}", rawFileName, result);
1038
                return result;
1039
            }
1040
            catch (Exception ex)
1041
            {
1042
                logger.Error("LockFileProxy : {0} Throw : {1}", rawFileName, ex.Message);
1043
                return DokanResult.InvalidParameter;
1044
            }
1045
        }
1046

1047
        ////
1048

1049
        public NtStatus UnlockFileProxy(
1050
            string rawFileName,
1051
            long rawByteOffset,
1052
            long rawLength,
1053
            DokanFileInfo rawFileInfo)
1054
        {
1055
            try
1056
            {
1057
                if (logger.DebugEnabled)
1058
                {
1059
                    logger.Debug("UnlockFileProxy : {0}", rawFileName);
1060
                    logger.Debug("\tByteOffset\t{0}", rawByteOffset);
1061
                    logger.Debug("\tLength\t{0}", rawLength);
1062
                    logger.Debug("\tContext\t{0}", rawFileInfo);
1063
                }
1064

1065
                var result = operations.UnlockFile(rawFileName, rawByteOffset, rawLength, rawFileInfo);
1066

1067
                if (logger.DebugEnabled) logger.Debug("UnlockFileProxy : {0} Return : {1}", rawFileName, result);
1068
                return result;
1069
            }
1070
            catch (Exception ex)
1071
            {
1072
                logger.Error("UnlockFileProxy : {0} Throw : {1}", rawFileName, ex.Message);
1073
                return DokanResult.InvalidParameter;
1074
            }
1075
        }
1076

1077
        ////
1078

1079
        public NtStatus GetDiskFreeSpaceProxy(
1080
            ref long rawFreeBytesAvailable,
1081
            ref long rawTotalNumberOfBytes,
1082
            ref long rawTotalNumberOfFreeBytes,
1083
            DokanFileInfo rawFileInfo)
1084
        {
1085
            try
1086
            {
1087
                if (logger.DebugEnabled)
1088
                {
1089
                    logger.Debug("GetDiskFreeSpaceProxy:");
1090
                    logger.Debug("\tContext\t{0}", rawFileInfo);
1091
                }
1092

1093
                var result = operations.GetDiskFreeSpace(
1094
                    out rawFreeBytesAvailable,
1095
                    out rawTotalNumberOfBytes,
1096
                    out rawTotalNumberOfFreeBytes,
1097
                    rawFileInfo);
1098

1099
                if (logger.DebugEnabled)
1100
                {
1101
                    logger.Debug("\tFreeBytesAvailable\t{0}", rawFreeBytesAvailable);
1102
                    logger.Debug("\tTotalNumberOfBytes\t{0}", rawTotalNumberOfBytes);
1103
                    logger.Debug("\tTotalNumberOfFreeBytes\t{0}", rawTotalNumberOfFreeBytes);
1104
                    logger.Debug("GetDiskFreeSpaceProxy Return : {0}", result);
1105
                }
1106

1107
                return result;
1108
            }
1109
            catch (Exception ex)
1110
            {
1111
                logger.Error("GetDiskFreeSpaceProxy Throw : {0}", ex.Message);
1112
                return DokanResult.InvalidParameter;
1113
            }
1114
        }
1115

1116
        public NtStatus GetVolumeInformationProxy(
1117
            StringBuilder rawVolumeNameBuffer,
1118
            uint rawVolumeNameSize,
1119
            ref uint rawVolumeSerialNumber,
1120
            ref uint rawMaximumComponentLength,
1121
            ref FileSystemFeatures rawFileSystemFlags,
1122
            StringBuilder rawFileSystemNameBuffer,
1123
            uint rawFileSystemNameSize,
1124
            DokanFileInfo rawFileInfo)
1125
        {
1126
            rawVolumeSerialNumber = serialNumber;
1127
            try
1128
            {
1129
                if (logger.DebugEnabled)
1130
                {
1131
                    logger.Debug("GetVolumeInformationProxy:");
1132
                    logger.Debug("\tContext\t{0}", rawFileInfo);
1133
                }
1134

1135
                string volumeName;
1136
                string name;
1137
                uint maximumComponentLength;
1138
                var result = operations.GetVolumeInformation(out volumeName, out rawFileSystemFlags, out name, out maximumComponentLength, rawFileInfo);
1139

1140
                if (result == DokanResult.Success)
1141
                {
1142
                    Debug.Assert(!string.IsNullOrEmpty(name), "name must not be null");
1143
                    Debug.Assert(!string.IsNullOrEmpty(volumeName), "Label must not be null");
1144
                    rawVolumeNameBuffer.Append(volumeName);
1145
                    rawFileSystemNameBuffer.Append(name);
1146
                    rawMaximumComponentLength = maximumComponentLength;
1147

1148
                    if (logger.DebugEnabled)
1149
                    {
1150
                        logger.Debug("\tVolumeNameBuffer\t{0}", rawVolumeNameBuffer);
1151
                        logger.Debug("\tFileSystemNameBuffer\t{0}", rawFileSystemNameBuffer);
1152
                        logger.Debug("\tVolumeSerialNumber\t{0}", rawVolumeSerialNumber);
1153
                        logger.Debug("\tFileSystemFlags\t{0}", rawFileSystemFlags);
1154
                        logger.Debug("\tMaximumComponentLength\t{0}", rawMaximumComponentLength);
1155
                    }
1156
                }
1157

1158
                if (logger.DebugEnabled) logger.Debug("GetVolumeInformationProxy Return : {0}", result);
1159
                return result;
1160
            }
1161
            catch (Exception ex)
1162
            {
1163
                logger.Error("GetVolumeInformationProxy Throw : {0}", ex.Message);
1164
                return DokanResult.InvalidParameter;
1165
            }
1166
        }
1167

1168
        public NtStatus MountedProxy(string mountPoint, DokanFileInfo rawFileInfo)
1169
        {
1170
            try
1171
            {
1172
                if (logger.DebugEnabled)
1173
                {
1174
                    logger.Debug("MountedProxy:");
1175
                    logger.Debug("\tMountPoint\t{0}", mountPoint);
1176
                    logger.Debug("\tContext\t{0}", rawFileInfo);
1177
                }
1178

1179
                var result = operations.Mounted(mountPoint, rawFileInfo);
1180

1181
                if (logger.DebugEnabled) logger.Debug("MountedProxy Return : {0}", result);
1182
                return result;
1183
            }
1184
            catch (Exception ex)
1185
            {
1186
                logger.Error("MountedProxy Throw : {0}", ex.Message);
1187
                return DokanResult.InvalidParameter;
1188
            }
1189
        }
1190

1191
        public NtStatus UnmountedProxy(DokanFileInfo rawFileInfo)
1192
        {
1193
            try
1194
            {
1195
                if (logger.DebugEnabled)
1196
                {
1197
                    logger.Debug("UnmountedProxy:");
1198
                    logger.Debug("\tContext\t{0}", rawFileInfo);
1199
                }
1200

1201
                var result = operations.Unmounted(rawFileInfo);
1202

1203
                if (logger.DebugEnabled) logger.Debug("UnmountedProxy Return : {0}", result);
1204
                return result;
1205
            }
1206
            catch (Exception ex)
1207
            {
1208
                logger.Error("UnmountedProxy Throw : {0}", ex.Message);
1209
                return DokanResult.InvalidParameter;
1210
            }
1211
        }
1212

1213
        public NtStatus GetFileSecurityProxy(
1214
            string rawFileName,
1215
            ref SECURITY_INFORMATION rawRequestedInformation,
1216
            IntPtr rawSecurityDescriptor,
1217
            uint rawSecurityDescriptorLength,
1218
            ref uint rawSecurityDescriptorLengthNeeded,
1219
            DokanFileInfo rawFileInfo)
1220
        {
1221
            var sect = AccessControlSections.None;
1222
            if (rawRequestedInformation.HasFlag(SECURITY_INFORMATION.OWNER_SECURITY_INFORMATION))
1223
            {
1224
                sect |= AccessControlSections.Owner;
1225
            }
1226
            if (rawRequestedInformation.HasFlag(SECURITY_INFORMATION.GROUP_SECURITY_INFORMATION))
1227
            {
1228
                sect |= AccessControlSections.Group;
1229
            }
1230
            if (rawRequestedInformation.HasFlag(SECURITY_INFORMATION.DACL_SECURITY_INFORMATION) ||
1231
                rawRequestedInformation.HasFlag(SECURITY_INFORMATION.PROTECTED_DACL_SECURITY_INFORMATION) ||
1232
                rawRequestedInformation.HasFlag(SECURITY_INFORMATION.UNPROTECTED_DACL_SECURITY_INFORMATION))
1233
            {
1234
                sect |= AccessControlSections.Access;
1235
            }
1236
            if (rawRequestedInformation.HasFlag(SECURITY_INFORMATION.SACL_SECURITY_INFORMATION) ||
1237
                rawRequestedInformation.HasFlag(SECURITY_INFORMATION.PROTECTED_SACL_SECURITY_INFORMATION) ||
1238
                rawRequestedInformation.HasFlag(SECURITY_INFORMATION.UNPROTECTED_SACL_SECURITY_INFORMATION))
1239
            {
1240
                sect |= AccessControlSections.Audit;
1241
            }
1242
            try
1243
            {
1244
                if (logger.DebugEnabled)
1245
                {
1246
                    logger.Debug("GetFileSecurityProxy : {0}", rawFileName);
1247
                    logger.Debug("\tFileSystemSecurity\t{0}", sect);
1248
                    logger.Debug("\tContext\t{0}", rawFileInfo);
1249
                }
1250

1251
                FileSystemSecurity sec;
1252
                var result = operations.GetFileSecurity(rawFileName, out sec, sect, rawFileInfo);
1253
                if (result == DokanResult.Success /*&& sec != null*/)
1254
                {
1255
                    Debug.Assert(sec != null, "sec must not be null");
1256
                    if (logger.DebugEnabled) logger.Debug("\tFileSystemSecurity Result : {0}", sec);
1257
                    var buffer = sec.GetSecurityDescriptorBinaryForm();
1258
                    rawSecurityDescriptorLengthNeeded = (uint)buffer.Length;
1259
                    if (buffer.Length > rawSecurityDescriptorLength)
1260
                        return DokanResult.BufferOverflow;
1261

1262
                    Marshal.Copy(buffer, 0, rawSecurityDescriptor, buffer.Length);
1263
                }
1264

1265
                if (logger.DebugEnabled) logger.Debug("GetFileSecurityProxy : {0} Return : {1}", rawFileName, result);
1266
                return result;
1267
            }
1268
            catch (Exception ex)
1269
            {
1270
                logger.Error("GetFileSecurityProxy : {0} Throw : {1}", rawFileName, ex.Message);
1271
                return DokanResult.InvalidParameter;
1272
            }
1273
        }
1274

1275
        public NtStatus SetFileSecurityProxy(
1276
            string rawFileName,
1277
            ref SECURITY_INFORMATION rawSecurityInformation,
1278
            IntPtr rawSecurityDescriptor,
1279
            uint rawSecurityDescriptorLength,
1280
            DokanFileInfo rawFileInfo)
1281
        {
1282
            var sect = AccessControlSections.None;
1283
            if (rawSecurityInformation.HasFlag(SECURITY_INFORMATION.OWNER_SECURITY_INFORMATION))
1284
            {
1285
                sect |= AccessControlSections.Owner;
1286
            }
1287
            if (rawSecurityInformation.HasFlag(SECURITY_INFORMATION.GROUP_SECURITY_INFORMATION))
1288
            {
1289
                sect |= AccessControlSections.Group;
1290
            }
1291
            if (rawSecurityInformation.HasFlag(SECURITY_INFORMATION.DACL_SECURITY_INFORMATION) ||
1292
                rawSecurityInformation.HasFlag(SECURITY_INFORMATION.PROTECTED_DACL_SECURITY_INFORMATION) ||
1293
                rawSecurityInformation.HasFlag(SECURITY_INFORMATION.UNPROTECTED_DACL_SECURITY_INFORMATION))
1294
            {
1295
                sect |= AccessControlSections.Access;
1296
            }
1297
            if (rawSecurityInformation.HasFlag(SECURITY_INFORMATION.SACL_SECURITY_INFORMATION) ||
1298
                rawSecurityInformation.HasFlag(SECURITY_INFORMATION.PROTECTED_SACL_SECURITY_INFORMATION) ||
1299
                rawSecurityInformation.HasFlag(SECURITY_INFORMATION.UNPROTECTED_SACL_SECURITY_INFORMATION))
1300
            {
1301
                sect |= AccessControlSections.Audit;
1302
            }
1303
            var buffer = new byte[rawSecurityDescriptorLength];
1304
            try
1305
            {
1306
                Marshal.Copy(rawSecurityDescriptor, buffer, 0, (int)rawSecurityDescriptorLength);
1307
                var sec = rawFileInfo.IsDirectory ? (FileSystemSecurity)new DirectorySecurity() : new FileSecurity();
1308
                sec.SetSecurityDescriptorBinaryForm(buffer);
1309

1310
                if (logger.DebugEnabled)
1311
                {
1312
                    logger.Debug("SetFileSecurityProxy : {0}", rawFileName);
1313
                    logger.Debug("\tAccessControlSections\t{0}", sect);
1314
                    logger.Debug("\tFileSystemSecurity\t{0}", sec);
1315
                    logger.Debug("\tContext\t{0}", rawFileInfo);
1316
                }
1317

1318
                var result = operations.SetFileSecurity(rawFileName, sec, sect, rawFileInfo);
1319

1320
                if (logger.DebugEnabled) logger.Debug("SetFileSecurityProxy : {0} Return : {1}", rawFileName, result);
1321
                return result;
1322
            }
1323
            catch (Exception ex)
1324
            {
1325
                logger.Error("SetFileSecurityProxy : {0} Throw : {1}", rawFileName, ex.Message);
1326
                return DokanResult.InvalidParameter;
1327
            }
1328
        }
1329

1330
        /// <summary>
1331
        /// Converts the value of <paramref name="dateTime"/> to a Windows file time.
1332
        /// If <paramref name="dateTime"/> is <c>null</c> or before 12:00 midnight January 1, 1601 C.E. UTC, it returns <c>0</c>.
1333
        /// </summary>
1334
        /// <param name="dateTime">
1335
        /// The date Time.
1336
        /// </param>
1337
        /// <returns>
1338
        /// The value of <paramref name="dateTime"/> expressed as a Windows file time
1339
        /// -or- it returns <c>0</c> if <paramref name="dateTime"/> is before 12:00 midnight January 1, 1601 C.E. UTC or <c>null</c>.
1340
        /// </returns>
1341
        /// \see <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa365739(v=vs.85).aspx">WIN32_FILE_ATTRIBUTE_DATA structure (MSDN)</a>
1342
        [Pure]
1343
        private static long ToFileTime(DateTime? dateTime)
1344
        {
1345
            return dateTime.HasValue && (dateTime.Value >= DateTime.FromFileTime(0))
1346
                ? dateTime.Value.ToFileTime()
1347
                : 0;
1348
        }
1349

1350
#region Nested type: FILL_FIND_FILE_DATA
1351

1352
        /// <summary>
1353
        /// Used to add an entry in <see cref="DokanOperationProxy.FindFilesProxy"/> and <see cref="DokanOperationProxy.FindFilesWithPatternProxy"/>.
1354
        /// </summary>
1355
        /// <param name="rawFindData">A <see cref="WIN32_FIND_DATA"/>.</param>
1356
        /// <param name="rawFileInfo">A <see cref="DokanFileInfo"/>.</param>
1357
        /// <returns><c>1</c> if buffer is full, otherwise <c>0</c> (currently it never returns <c>1</c>)</returns>
1358
        /// <remarks>This is the same delegate as <c>PFillFindData</c> (dokan.h) in the C version of Dokan.</remarks>
1359
        private delegate long FILL_FIND_FILE_DATA(
1360
            ref WIN32_FIND_DATA rawFindData, [MarshalAs(UnmanagedType.LPStruct), In] DokanFileInfo rawFileInfo);
1361

1362
#endregion Nested type: FILL_FIND_FILE_DATA
1363

1364
#region Nested type: FILL_FIND_STREAM_DATA
1365

1366
        /// <summary>
1367
        /// Used to add an entry in <see cref="DokanOperationProxy.FindStreamsProxy"/>.
1368
        /// </summary>
1369
        /// <param name="rawFindData">A <see cref="WIN32_FIND_STREAM_DATA"/>.</param>
1370
        /// <param name="findStreamContext">The context received by <see cref="DOKAN_OPERATIONS.FindStreams"/>.</param>
1371
        /// <returns><c>FALSE</c> if the buffer is full, otherwise <c>TRUE</c></returns>
1372
        /// <remarks>This is the same delegate as <c>PFillFindStreamData</c> (dokan.h) in the C version of Dokan.</remarks>
1373
        private delegate bool FILL_FIND_STREAM_DATA(
1374
            ref WIN32_FIND_STREAM_DATA rawFindData, IntPtr findStreamContext);
1375

1376
#endregion Nested type: FILL_FIND_STREAM_DATA
1377
    }
1378
}

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

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

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

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