public NtStatus CreateFile(
            string filename,
            FileAccess access,
            FileShare share,
            FileMode mode,
            FileOptions options,
            FileAttributes attributes,
            IDokanFileInfo info)
        {
            // don't allow user to create new files or directories - this fake volume is read only
            if (mode != FileMode.Open && mode != FileMode.OpenOrCreate)
            {
                return(DokanResult.AccessDenied);
            }

            // check if the file/directory exists
            try
            {
                var fi = VirtualFileSystemProvider.QueryItem(filename);
                if (info.IsDirectory && !fi.Attributes.HasFlag(FileAttributes.Directory))
                {
                    return(DokanResult.NotADirectory);
                }
                if (!info.IsDirectory && access.HasFlag(FileAccess.GenericRead))
                {
                    // set the memory stream on the context
                    info.Context = VirtualFileSystemProvider.GetFileStream(filename);
                }
            }
            catch (FileNotFoundException)
            {
                return(info.IsDirectory ? DokanResult.PathNotFound : DokanResult.FileNotFound);
            }
            catch (Exception e)
            {
                log.Error(e.Message);
                return(DokanResult.Error);
            }

            return(DokanResult.Success);
        }
Пример #2
0
        public NtStatus CreateFile(string fileName, FileAccess access, FileShare share, FileMode mode, FileOptions options, FileAttributes attributes, DokanFileInfo info)
        {
            if (info == null)
            {
                throw new ArgumentNullException(nameof(info));
            }

            // HACK: Fix for Bug in Dokany related to a missing trailing slash for directory names
            if (string.IsNullOrEmpty(fileName))
            {
                fileName = @"\";
            }
            // HACK: Fix for Bug in Dokany related to a call to CreateFile with a fileName of '\*'
            else if (fileName == @"\*" && access == FileAccess.ReadAttributes)
            {
                return(AsTrace(nameof(CreateFile), fileName, info, access, share, mode, options, attributes, DokanResult.Success));
            }

            if (fileName == @"\")
            {
                info.IsDirectory = true;
                return(AsTrace(nameof(CreateFile), fileName, info, access, share, mode, options, attributes, DokanResult.Success));
            }

            fileName = fileName.TrimEnd(Path.DirectorySeparatorChar);

            var parent = GetItem(Path.GetDirectoryName(fileName)) as CloudDirectoryNode;

            if (parent == null)
            {
                return(AsDebug(nameof(CreateFile), fileName, info, access, share, mode, options, attributes, DokanResult.PathNotFound));
            }

            var           itemName = Path.GetFileName(fileName);
            var           item     = parent.GetChildItemByName(_drive, itemName);
            CloudFileNode fileItem;

            switch (mode)
            {
            case FileMode.Create:
                fileItem = item as CloudFileNode;
                if (fileItem != null)
                {
                    fileItem.Truncate(_drive);
                }
                else
                {
                    fileItem = parent.NewFileItem(_drive, itemName);
                }

                info.Context = new StreamContext(fileItem, FileAccess.WriteData);

                return(AsTrace(nameof(CreateFile), fileName, info, access, share, mode, options, attributes, DokanResult.Success));

            case FileMode.Open:
                fileItem = item as CloudFileNode;
                if (fileItem != null)
                {
                    if (access.HasFlag(FileAccess.ReadData) || access.HasFlag(FileAccess.GenericRead) || access.HasFlag(FileAccess.ReadAttributes))
                    {
                        info.Context = new StreamContext(fileItem, FileAccess.ReadData);
                    }
                    else if (access.HasFlag(FileAccess.WriteData))
                    {
                        info.Context = new StreamContext(fileItem, FileAccess.WriteData);
                    }
                    else if (access.HasFlag(FileAccess.Delete))
                    {
                        info.Context = new StreamContext(fileItem, FileAccess.Delete);
                    }
                    //                        else if (!access.HasFlag(FileAccess.ReadAttributes))
                    else if (!access.HasFlag(FileAccess.ReadAttributes) && !access.HasFlag(FileAccess.ReadPermissions))
                    {
                        return(AsDebug(nameof(CreateFile), fileName, info, access, share, mode, options, attributes, DokanResult.NotImplemented));
                    }
                }
                else
                {
                    info.IsDirectory = item != null;
                }

                if (item != null)
                {
                    return(AsTrace(nameof(CreateFile), fileName, info, access, share, mode, options, attributes, DokanResult.Success));
                }
                else
                {
                    return(AsError(nameof(CreateFile), fileName, info, access, share, mode, options, attributes, DokanResult.FileNotFound));
                }

            case FileMode.OpenOrCreate:
                fileItem = item as CloudFileNode ?? parent.NewFileItem(_drive, itemName);

                if (access.HasFlag(FileAccess.ReadData) && !access.HasFlag(FileAccess.WriteData))
                {
                    info.Context = new StreamContext(fileItem, FileAccess.ReadData);
                }
                else
                {
                    info.Context = new StreamContext(fileItem, FileAccess.WriteData);
                }

                return(AsTrace(nameof(CreateFile), fileName, info, access, share, mode, options, attributes, DokanResult.Success));

            case FileMode.CreateNew:
                if (item != null)
                {
                    return(AsDebug(nameof(CreateFile), fileName, info, access, share, mode, options, attributes, info.IsDirectory ? DokanResult.AlreadyExists : DokanResult.FileExists));
                }

                if (info.IsDirectory)
                {
                    parent.NewDirectoryItem(_drive, itemName);
                }
                else
                {
                    fileItem     = parent.NewFileItem(_drive, itemName);
                    info.Context = new StreamContext(fileItem, FileAccess.WriteData);
                }
                return(AsTrace(nameof(CreateFile), fileName, info, access, share, mode, options, attributes, DokanResult.Success));

            case FileMode.Append:
                return(AsError(nameof(CreateFile), fileName, info, access, share, mode, options, attributes, DokanResult.NotImplemented));

            case FileMode.Truncate:
                fileItem = item as CloudFileNode;
                if (fileItem == null)
                {
                    return(AsDebug(nameof(CreateFile), fileName, info, access, share, mode, options, attributes, DokanResult.FileNotFound));
                }

                fileItem.Truncate(_drive);
                info.Context = new StreamContext(fileItem, FileAccess.WriteData);

                return(AsTrace(nameof(CreateFile), fileName, info, access, share, mode, options, attributes, DokanResult.Success));

            //return AsError(nameof(CreateFile), fileName, info, access, share, mode, options, attributes, DokanResult.NotImplemented);
            default:
                return(AsError(nameof(CreateFile), fileName, info, access, share, mode, options, attributes, DokanResult.NotImplemented));
            }
        }
Пример #3
0
        public NtStatus CreateFile([NotNull] string fileName, FileAccess access, FileShare share, FileMode mode, FileOptions options, FileAttributes attributes, [NotNull] IDokanFileInfo info)
        {
            NtStatus result   = DokanResult.Success;
            string   filePath = GetMinePath(fileName);

            if (info.IsDirectory)
            {
                try {
                    switch (mode)
                    {
                    case FileMode.Open: {
                        if (!Directory.Exists(filePath))
                        {
                            try {
                                if (!File.GetAttributes(filePath).HasFlag(FileAttributes.Directory))
                                {
                                    return(DokanResult.NotADirectory);
                                }
                            } catch (Exception) {
                                return(DokanResult.FileNotFound);
                            }

                            return(DokanResult.PathNotFound);
                        }

                        // ReSharper disable once ReturnValueOfPureMethodIsNotUsed
                        new DirectoryInfo(filePath).EnumerateFileSystemInfos().Any();
                        // you can't list the directory
                        break;
                    }

                    case FileMode.CreateNew: {
                        if (Directory.Exists(filePath))
                        {
                            return(DokanResult.FileExists);
                        }

                        try {
                            // ReSharper disable once ReturnValueOfPureMethodIsNotUsed
                            File.GetAttributes(filePath).HasFlag(FileAttributes.Directory);
                            return(DokanResult.AlreadyExists);
                        } catch (IOException) {
                        }

                        Directory.CreateDirectory(GetMinePath(fileName));
                        break;
                    }
                    }
                } catch (UnauthorizedAccessException) {
                    return(DokanResult.AccessDenied);
                }
            }
            else
            {
                bool pathExists      = true;
                bool pathIsDirectory = false;

                bool readWriteAttributes = (access & DataAccess) == 0;
                bool readAccess          = (access & DataWriteAccess) == 0;

                try {
                    pathExists      = Directory.Exists(filePath) || File.Exists(filePath);
                    pathIsDirectory = pathExists && File.GetAttributes(filePath).HasFlag(FileAttributes.Directory);
                } catch (IOException) {
                }

                switch (mode)
                {
                case FileMode.Open: {
                    if (pathExists)
                    {
                        // check if driver only wants to read attributes, security info, or open directory
                        if (readWriteAttributes || pathIsDirectory)
                        {
                            if (pathIsDirectory && access.HasFlag(FileAccess.Delete) && !access.HasFlag(FileAccess.Synchronize))
                            {
                                // It is a DeleteFile request on a directory
                                return(DokanResult.AccessDenied);
                            }

                            info.IsDirectory = pathIsDirectory;
                            info.Context     = new object();
                            // must set it to someting if you return DokanError.Success

                            OnBeforeReadFile(fileName);

                            return(DokanResult.Success);
                        }
                    }
                    else
                    {
                        return(DokanResult.FileNotFound);
                    }

                    break;
                }

                case FileMode.CreateNew: {
                    if (pathExists)
                    {
                        return(DokanResult.FileExists);
                    }

                    break;
                }

                case FileMode.Truncate: {
                    if (!pathExists)
                    {
                        return(DokanResult.FileNotFound);
                    }

                    break;
                }
                }

                try {
                    _WriteFile.Add(fileName);
                    OnBeforeWriteFile(fileName);

                    if (pathExists && (mode == FileMode.OpenOrCreate || mode == FileMode.Create))
                    {
                        result = DokanResult.AlreadyExists;
                    }

                    info.Context = new FileStream(filePath, mode, readAccess ? System.IO.FileAccess.Read : System.IO.FileAccess.ReadWrite, share, 4096, options);

                    bool fileCreated = mode == FileMode.CreateNew || mode == FileMode.Create || !pathExists && mode == FileMode.OpenOrCreate;
                    if (fileCreated)
                    {
                        FileAttributes newAttributes = attributes;
                        newAttributes |= FileAttributes.Archive; // Files are always created as Archive
                        // FILE_ATTRIBUTE_NORMAL is override if any other attribute is set.
                        newAttributes &= ~FileAttributes.Normal;
                        File.SetAttributes(filePath, newAttributes);
                    }
                } catch (UnauthorizedAccessException) {
                    // don't have access rights
                    if (info.Context is FileStream fileStream)
                    {
                        // returning AccessDenied cleanup and close won't be called,
                        // so we have to take care of the stream now
                        fileStream.Dispose();
                        info.Context = null;
                    }

                    return(DokanResult.AccessDenied);
                } catch (DirectoryNotFoundException) {
                    return(DokanResult.PathNotFound);
                } catch (Exception ex) {
                    uint hr = (uint)Marshal.GetHRForException(ex);
                    switch (hr)
                    {
                    case 0x80070020:
                        return(DokanResult.SharingViolation);

                    default:
                        throw;
                    }
                }
            }

            return(result);
        }
Пример #4
0
        /// <inheritdoc/>
        public override NtStatus CreateFileHandle(string path, DokanNet.FileAccess access, FileShare share, FileMode mode, FileOptions options, FileAttributes attributes, LVFSContextInfo info)
        {
            var controlsFile = ControlsFile(path);

            if (!controlsFile && PredecessorHasFile(path))
            {
                return(PredecessorCreateFileHandle(path, access, share, mode, options, attributes, info));
            }

            var convertedPath   = ConvertPath(path);
            var directoryExists = Directory.Exists(convertedPath);
            var fileExists      = File.Exists(convertedPath);

            if (info.IsDirectory)
            {
                try
                {
                    switch (mode)
                    {
                    case FileMode.Open:
                    {
                        if (directoryExists)
                        {
                            return(DokanResult.Success);
                        }
                        else if (fileExists)
                        {
                            return(NtStatus.NotADirectory);
                        }
                        else
                        {
                            return(PredecessorCreateFileHandle(path, access, share, mode, options, attributes, info));
                        }
                    }

                    case FileMode.CreateNew:
                    {
                        if (directoryExists)
                        {
                            return(DokanResult.AlreadyExists);
                        }
                        else if (fileExists)
                        {
                            return(DokanResult.FileExists);
                        }
                        else if (PredecessorHasFile(path))
                        {
                            return(DokanResult.AlreadyExists);
                        }
                        else
                        {
                            Directory.CreateDirectory(convertedPath);
                            return(DokanResult.Success);
                        }
                    }

                    case FileMode.OpenOrCreate:
                    {
                        if (directoryExists)
                        {
                            return(DokanResult.Success);
                        }
                        else if (fileExists)
                        {
                            return(NtStatus.NotADirectory);
                        }
                        else if (PredecessorHasFile(path))
                        {
                            return(PredecessorCreateFileHandle(path, access, share, mode, options, attributes, info));
                        }
                        else
                        {
                            Directory.CreateDirectory(convertedPath);
                            return(DokanResult.Success);
                        }
                    }

                    default:
                    {
                        // I don't think any other file modes can actually used with directories, so we should be free to die in any arbitrary way here. In fact, I don't think OpenOrCreate can actually be used with directories either, but the associated behaviour was simple enough, so I implemented it anyway.
                        return(DokanResult.NotImplemented);
                    }
                    }
                }
                catch (UnauthorizedAccessException)
                {
                    return(DokanResult.AccessDenied);
                }
            }
            else
            {
                switch (mode)
                {
                case FileMode.Open:
                {
                    if (fileExists || directoryExists)
                    {
                        var dataAccess = DokanNet.FileAccess.ReadData | DokanNet.FileAccess.WriteData | DokanNet.FileAccess.AppendData | DokanNet.FileAccess.Execute | DokanNet.FileAccess.GenericExecute | DokanNet.FileAccess.GenericWrite | DokanNet.FileAccess.GenericRead;
                        var readWriteOnlyAttributes = (access & dataAccess) == 0;

                        if (directoryExists || readWriteOnlyAttributes)
                        {
                            if (directoryExists && access.HasFlag(DokanNet.FileAccess.Delete) && !access.HasFlag(DokanNet.FileAccess.Synchronize))
                            {
                                // Delete request on (potentially) non-empty directory
                                return(DokanResult.AccessDenied);
                            }

                            info.IsDirectory = directoryExists;

                            return(DokanResult.Success);
                        }
                        else
                        {
                            // Go to the regular handler
                            break;
                        }
                    }
                    else
                    {
                        return(PredecessorCreateFileHandle(path, access, share, mode, options, attributes, info));
                    }
                }

                case FileMode.OpenOrCreate:
                case FileMode.Create:
                case FileMode.Append:
                {
                    if (fileExists || directoryExists)
                    {
                        // Go to the regular handler
                        break;
                    }
                    else if (PredecessorHasFile(path))
                    {
                        return(PredecessorCreateFileHandle(path, access, share, mode, options, attributes, info));
                    }
                    else
                    {
                        // Go to the regular handler
                        break;
                    }
                }

                case FileMode.CreateNew:
                {
                    if (fileExists || directoryExists || PredecessorHasFile(path))
                    {
                        return(DokanResult.AlreadyExists);
                    }
                    else
                    {
                        // Go to the regular handler
                        break;
                    }
                }

                case FileMode.Truncate:
                {
                    if (fileExists || directoryExists)
                    {
                        // Go to the regular handler
                        break;
                    }
                    else if (PredecessorHasFile(path))
                    {
                        return(PredecessorCreateFileHandle(path, access, share, mode, options, attributes, info));
                    }
                    else
                    {
                        return(DokanResult.FileNotFound);
                    }
                }

                default:
                    // This code should never be reached
                    throw new ArgumentException("Unknown file mode: " + mode, nameof(mode));
                }

                var dataWriteAccess = DokanNet.FileAccess.WriteData | DokanNet.FileAccess.AppendData | DokanNet.FileAccess.Delete | DokanNet.FileAccess.GenericWrite;
                var readAccessOnly  = (access & dataWriteAccess) == 0;

                try
                {
                    var result = DokanResult.Success;

                    if (!Directory.Exists(Path.GetDirectoryName(convertedPath)))
                    {
                        if (PredecessorHasDirectory(Path.GetDirectoryName(path)))
                        {
                            Directory.CreateDirectory(Path.GetDirectoryName(convertedPath));
                        }
                        else
                        {
                            return(DokanResult.PathNotFound);
                        }
                    }
                    info.Context[this] = new FileStream(convertedPath, mode, readAccessOnly ? System.IO.FileAccess.Read : System.IO.FileAccess.ReadWrite, share, 4096, options);

                    if ((fileExists || directoryExists) && (mode == FileMode.OpenOrCreate || mode == FileMode.Create))
                    {
                        result = DokanResult.AlreadyExists;
                    }

                    if (mode == FileMode.CreateNew || mode == FileMode.Create)
                    {
                        attributes |= FileAttributes.Archive;
                    }

                    File.SetAttributes(convertedPath, attributes);

                    return(result);
                }
                catch (UnauthorizedAccessException)
                {
                    return(DokanResult.AccessDenied);
                }
                catch (DirectoryNotFoundException)
                {
                    return(DokanResult.PathNotFound);
                }
                catch (Exception ex)
                {
                    var hr = (uint)System.Runtime.InteropServices.Marshal.GetHRForException(ex);
                    switch (hr)
                    {
                    case 0x80070020:                             //Sharing violation
                        return(DokanResult.SharingViolation);

                    default:
                        throw;
                    }
                }
            }
        }
Пример #5
0
        public NtStatus CreateFile(string fileName, FileAccess access, FileShare share, FileMode mode, FileOptions options, FileAttributes attributes, DokanFileInfo info)
        {
            // HACK: Fix for Bug in Dokany related to a missing trailing slash for directory names
            if (string.IsNullOrEmpty(fileName))
                fileName = @"\";

            if (fileName == @"\") {
                info.IsDirectory = true;
                return Trace(nameof(CreateFile), fileName, info, access, share, mode, options, attributes, DokanResult.Success);
            }

            fileName = fileName.TrimEnd(Path.DirectorySeparatorChar);

            var parent = GetItem(Path.GetDirectoryName(fileName)) as CloudDirectoryNode;
            if (parent == null)
                return Trace(nameof(CreateFile), fileName, info, access, share, mode, options, attributes, DokanResult.PathNotFound);

            var itemName = Path.GetFileName(fileName);
            var item = parent.GetChildItemByName(drive, itemName);
            var fileItem = default(CloudFileNode);
            switch (mode) {
                case FileMode.Create:
                    fileItem = item as CloudFileNode;
                    if (fileItem != null)
                        fileItem.Truncate(drive);
                    else
                        fileItem = parent.NewFileItem(drive, itemName);

                    info.Context = new StreamContext(fileItem, FileAccess.WriteData);

                    return Trace(nameof(CreateFile), fileName, info, access, share, mode, options, attributes, DokanResult.Success);
                case FileMode.Open:
                    fileItem = item as CloudFileNode;
                    if (fileItem != null) {
                        if (access.HasFlag(FileAccess.ReadData))
                            info.Context = new StreamContext(fileItem, FileAccess.ReadData) { Stream = Stream.Synchronized(fileItem.GetContent(drive)) };
                        else if (access.HasFlag(FileAccess.WriteData))
                            info.Context = new StreamContext(fileItem, FileAccess.WriteData);
                        else if (access.HasFlag(FileAccess.Delete))
                            info.Context = new StreamContext(fileItem, FileAccess.Delete);
                    } else {
                        info.IsDirectory = item != null;
                    }

                    return Trace(nameof(CreateFile), fileName, info, access, share, mode, options, attributes, item != null ? DokanResult.Success : DokanResult.FileNotFound);
                case FileMode.OpenOrCreate:
                    fileItem = item as CloudFileNode ?? parent.NewFileItem(drive, itemName);

                    if (access.HasFlag(FileAccess.ReadData) && !access.HasFlag(FileAccess.WriteData))
                        info.Context = new StreamContext(fileItem, FileAccess.ReadData) { Stream = Stream.Synchronized(fileItem.GetContent(drive)) };
                    else
                        info.Context = new StreamContext(fileItem, FileAccess.WriteData);

                    return Trace(nameof(CreateFile), fileName, info, access, share, mode, options, attributes, DokanResult.Success);
                case FileMode.CreateNew:
                    if (item != null)
                        return Trace(nameof(CreateFile), fileName, info, access, share, mode, options, attributes, info.IsDirectory ? DokanResult.AlreadyExists : DokanResult.FileExists);

                    if (info.IsDirectory) {
                        parent.NewDirectoryItem(drive, itemName);
                    } else {
                        fileItem = parent.NewFileItem(drive, itemName);

                        info.Context = new StreamContext(fileItem, FileAccess.WriteData);
                    }
                    return Trace(nameof(CreateFile), fileName, info, access, share, mode, options, attributes, DokanResult.Success);
                case FileMode.Append:
                    return Trace(nameof(CreateFile), fileName, info, access, share, mode, options, attributes, DokanResult.NotImplemented);
                case FileMode.Truncate:
                    fileItem = item as CloudFileNode;
                    if (fileItem == null)
                        return Trace(nameof(CreateFile), fileName, info, access, share, mode, options, attributes, DokanResult.FileNotFound);

                    fileItem.Truncate(drive);

                    info.Context = new StreamContext(fileItem, FileAccess.WriteData);

                    return Trace(nameof(CreateFile), fileName, info, access, share, mode, options, attributes, DokanResult.Success);
                default:
                    return Trace(nameof(CreateFile), fileName, info, access, share, mode, options, attributes, DokanResult.NotImplemented);
            }
        }
Пример #6
0
        public NtStatus CreateFile(string fileName, FileAccess access, FileShare share, FileMode mode, FileOptions options,
                                   FileAttributes attributes, IDokanFileInfo info)
        {
            var result   = NtStatus.Success;
            var filePath = GetPath(fileName);

            if (info.IsDirectory)
            {
                try
                {
                    switch (mode)
                    {
                    case FileMode.Open:
                        if (!Directory.Exists(filePath))
                        {
                            try
                            {
                                if (!File.GetAttributes(filePath).HasFlag(FileAttributes.Directory))
                                {
                                    return(NtStatus.NotADirectory);
                                }
                            }
                            catch (Exception)
                            {
                                return(DokanResult.FileNotFound);
                            }
                            return(DokanResult.PathNotFound);
                        }

                        new DirectoryInfo(filePath).EnumerateFileSystemInfos().Any();
                        // you can't list the directory
                        break;

                    case FileMode.CreateNew:
                        if (Directory.Exists(filePath))
                        {
                            return(DokanResult.FileExists);
                        }

                        try
                        {
                            File.GetAttributes(filePath).HasFlag(FileAttributes.Directory);
                            return(DokanResult.AlreadyExists);
                        }
                        catch (IOException)
                        {
                        }

                        Directory.CreateDirectory(GetPath(fileName));
                        break;
                    }
                }
                catch (UnauthorizedAccessException)
                {
                    return(DokanResult.AccessDenied);
                }
            }
            else
            {
                var pathExists      = true;
                var pathIsDirectory = false;

                var readWriteAttributes = (access & DataAccess) == 0;
                var readAccess          = (access & DataWriteAccess) == 0;

                try
                {
                    pathExists      = (Directory.Exists(filePath) || File.Exists(filePath));
                    pathIsDirectory = File.GetAttributes(filePath).HasFlag(FileAttributes.Directory);
                }
                catch (IOException)
                {
                }

                switch (mode)
                {
                case FileMode.Open:
                {
                    // Scan file before open
                    if ((access != FileAccess.Delete) && (access != FileAccess.ReadAttributes))
                    {
                        if (File.Exists(filePath))
                        {
                            try
                            {
                                bool executing = access.HasFlag(FileAccess.ReadData) &&
                                                 access.HasFlag(FileAccess.Execute) &&
                                                 access.HasFlag(FileAccess.ReadAttributes) &&
                                                 access.HasFlag(FileAccess.Synchronize) &&
                                                 share.HasFlag(FileShare.Read) &&
                                                 share.HasFlag(FileShare.Delete) &&
                                                 attributes.HasFlag(FileAttributes.Normal);

                                if (executing)
                                {
                                    return(OnRequestFileOpen?.Invoke(filePath) ?? DokanResult.Success);
                                }
                            }
                            catch (Exception ex)
                            {
                                //ex.Log();
                            }
                        }
                    }

                    if (pathExists)
                    {
                        // check if driver only wants to read attributes, security info, or open directory
                        if (readWriteAttributes || pathIsDirectory)
                        {
                            if (pathIsDirectory && (access & FileAccess.Delete) == FileAccess.Delete &&
                                (access & FileAccess.Synchronize) != FileAccess.Synchronize)
                            {
                                //It is a DeleteFile request on a directory
                                return(DokanResult.AccessDenied);
                            }

                            info.IsDirectory = pathIsDirectory;
                            info.Context     = new object();
                            // must set it to someting if you return DokanError.Success

                            return(DokanResult.Success);
                        }
                    }
                    else
                    {
                        return(DokanResult.FileNotFound);
                    }
                }
                break;

                case FileMode.CreateNew:
                    if (pathExists)
                    {
                        return(DokanResult.FileExists);
                    }
                    break;

                case FileMode.Truncate:
                    if (!pathExists)
                    {
                        return(DokanResult.FileNotFound);
                    }
                    break;
                }

                try
                {
                    info.Context = new FileStream(filePath, mode,
                                                  readAccess ? System.IO.FileAccess.Read : System.IO.FileAccess.ReadWrite, share, 4096, options);

                    if (pathExists && (mode == FileMode.OpenOrCreate ||
                                       mode == FileMode.Create))
                    {
                        result = DokanResult.AlreadyExists;
                    }

                    if (mode == FileMode.CreateNew || mode == FileMode.Create) //Files are always created as Archive
                    {
                        attributes |= FileAttributes.Archive;
                    }
                    File.SetAttributes(filePath, attributes);
                }
                catch (UnauthorizedAccessException) // don't have access rights
                {
                    return(DokanResult.AccessDenied);
                }
                catch (DirectoryNotFoundException)
                {
                    return(DokanResult.PathNotFound);
                }
                catch (Exception ex)
                {
                    var hr = (uint)Marshal.GetHRForException(ex);
                    switch (hr)
                    {
                    case 0x80070020:     //Sharing violation
                        return(DokanResult.SharingViolation);

                    default:
                        throw;
                    }
                }
            }
            return(result);
        }
Пример #7
0
        /// <inheritdoc/>
        public override NtStatus CreateFileHandle(string path, DokanNet.FileAccess access, FileShare share, FileMode mode, FileOptions options, FileAttributes attributes, LVFSContextInfo info)
        {
            var filePath = ConvertPath(path);

            var isDirectory = Directory.Exists(filePath);
            var pathExists  = isDirectory || File.Exists(filePath);

            // Check this first for performance reasons. Keep checking it later in case anything's been meddled with
            if (!pathExists)
            {
                return(PredecessorCreateFileHandle(path, access, share, mode, options, attributes, info));
            }

            if (info.IsDirectory)
            {
                try
                {
                    switch (mode)
                    {
                    case FileMode.Open:
                        if (Directory.Exists(filePath))
                        {
                            // The original Dokan mirror this is based on called new DirectoryInfo(filePath).EnumerateFileSystemInfos().Any();, but did nothing with its result at this point
                            return(DokanResult.Success);
                        }
                        else if (File.Exists(filePath))
                        {
                            return(NtStatus.NotADirectory);
                        }
                        else
                        {
                            return(PredecessorCreateFileHandle(path, access, share, mode, options, attributes, info));
                        }

                    case FileMode.OpenOrCreate:
                        if (Directory.Exists(filePath))
                        {
                            return(DokanResult.Success);
                        }
                        else if (File.Exists(filePath))
                        {
                            return(DokanResult.FileExists);
                        }
                        else
                        {
                            return(PredecessorCreateFileHandle(path, access, share, mode, options, attributes, info));
                        }

                    case FileMode.CreateNew:
                        if (Directory.Exists(filePath))
                        {
                            return(DokanResult.AlreadyExists);
                        }
                        else if (File.Exists(filePath))
                        {
                            return(DokanResult.FileExists);
                        }
                        else
                        {
                            return(PredecessorCreateFileHandle(path, access, share, mode, options, attributes, info));
                        }

                    default:
                        if (Directory.Exists(filePath) || File.Exists(filePath))
                        {
                            return(DokanResult.AccessDenied);
                        }
                        else
                        {
                            return(PredecessorCreateFileHandle(path, access, share, mode, options, attributes, info));
                        }
                    }
                }
                catch (UnauthorizedAccessException)
                {
                    return(DokanResult.AccessDenied);
                }
            }
            else
            {
                switch (mode)
                {
                case FileMode.Open:
                    if (pathExists)
                    {
                        var dataAccess = DokanNet.FileAccess.ReadData | DokanNet.FileAccess.WriteData | DokanNet.FileAccess.AppendData | DokanNet.FileAccess.Execute | DokanNet.FileAccess.GenericExecute | DokanNet.FileAccess.GenericWrite | DokanNet.FileAccess.GenericRead;
                        var readWriteOnlyAttributes = (access & dataAccess) == 0;
                        if (isDirectory || readWriteOnlyAttributes)
                        {
                            if (isDirectory && access.HasFlag(DokanNet.FileAccess.Delete) && !access.HasFlag(DokanNet.FileAccess.Synchronize))
                            {
                                // It's a delete request on a directory.
                                return(DokanResult.AccessDenied);
                            }

                            info.IsDirectory = isDirectory;

                            return(DokanResult.Success);
                        }
                        else
                        {
                            // Go to the regular handler
                            break;
                        }
                    }
                    else
                    {
                        return(PredecessorCreateFileHandle(path, access, share, mode, options, attributes, info));
                    }

                case FileMode.OpenOrCreate:
                    if (pathExists)
                    {
                        // Go to the regular handler
                        break;
                    }
                    else
                    {
                        return(PredecessorCreateFileHandle(path, access, share, mode, options, attributes, info));
                    }

                case FileMode.CreateNew:
                    if (pathExists)
                    {
                        return(DokanResult.FileExists);
                    }
                    else
                    {
                        return(PredecessorCreateFileHandle(path, access, share, mode, options, attributes, info));
                    }

                case FileMode.Truncate:
                    if (pathExists)
                    {
                        return(DokanResult.AccessDenied);
                    }
                    else
                    {
                        return(PredecessorCreateFileHandle(path, access, share, mode, options, attributes, info));
                    }

                case FileMode.Create:
                    if (pathExists)
                    {
                        return(DokanResult.AccessDenied);
                    }
                    else
                    {
                        return(PredecessorCreateFileHandle(path, access, share, mode, options, attributes, info));
                    }

                case FileMode.Append:
                    if (pathExists)
                    {
                        return(DokanResult.AccessDenied);
                    }
                    else
                    {
                        return(PredecessorCreateFileHandle(path, access, share, mode, options, attributes, info));
                    }

                default:
                    // This code should never be reached
                    throw new ArgumentException("Unknown file mode: " + mode, nameof(mode));
                }

                try
                {
                    info.Context[this] = new FileStream(filePath, mode, System.IO.FileAccess.Read, share, 4096, options);

                    if (mode == FileMode.Open)
                    {
                        return(DokanResult.Success);
                    }
                    else
                    {
                        return(DokanResult.AlreadyExists);
                    }
                }
                catch (UnauthorizedAccessException)
                {
                    return(DokanResult.AccessDenied);
                }
                catch (DirectoryNotFoundException)
                {
                    return(DokanResult.PathNotFound);
                }
                catch (Exception ex)
                {
                    var hr = (uint)System.Runtime.InteropServices.Marshal.GetHRForException(ex);
                    switch (hr)
                    {
                    case 0x80070020:                             //Sharing violation
                        return(DokanResult.SharingViolation);

                    default:
                        throw;
                    }
                }
            }
        }