// * do not move an xlink
        // * do not move between xlinks
        // * do not move a controlled item to a private path
        //   or add the private parents
        // * etc.
        int DokanOperations.MoveFile(
            string srcPath,
            string dstPath,
            bool replace,
            DokanFileInfo info)
        {
            mLog.InfoFormat(
                "*MoveFile* - [{0}] to [{1}] - replace [{2}]",
                srcPath, dstPath, replace);

            Node tree = GetRoot();

            Node parentSrc = WalkTree.Find(tree, Path.GetDirectoryName(srcPath));

            if (parentSrc == null)
            {
                return(-DokanNet.ERROR_PATH_NOT_FOUND);
            }

            Node node = WalkTree.GetChildByName(parentSrc.GetChildren(), Path.GetFileName(srcPath));

            if (node == null)
            {
                return(-DokanNet.ERROR_FILE_NOT_FOUND);
            }

            IVirtualFile virtualNode = mVirtualFiles.Get(node.GetNodeId());

            if (virtualNode != null)
            {
                mLog.ErrorFormat("We don't allow moving virtual files. [{0}]",
                                 node.GetName());

                return(-DokanNet.ERROR_ACCESS_DENIED);
            }

            Node parentDst = WalkTree.Find(tree, Path.GetDirectoryName(dstPath));

            if (parentDst == null)
            {
                return(-DokanNet.ERROR_PATH_NOT_FOUND);
            }

            if (WalkTree.GetChildByName(parentDst.GetChildren(), Path.GetFileName(dstPath)) != null)
            {
                return(-DokanNet.ERROR_ALREADY_EXISTS);
            }

            if (node.IsControlled())
            {
                mChangesTreeOperations.Move(
                    CmPath.FromWindows(srcPath), CmPath.FromWindows(dstPath));
            }

            parentSrc.DeleteChild(node);

            parentDst.AddChild(node, Path.GetFileName(dstPath));

            return(0);
        }
        int DokanOperations.WriteFile(
            string filename,
            byte[] buffer,
            ref uint writtenBytes,
            long offset,
            DokanFileInfo info)
        {
            mLog.DebugFormat(
                "WriteFile - offset: {0, 5} - bytes: {1, 5} - {2}",
                offset, buffer.Length, filename);

            Node node = WalkTree.Find(GetRoot(), filename);

            if (node == null)
            {
                return(-DokanNet.ERROR_PATH_NOT_FOUND);
            }

            if (node.IsControlledAndReadOnly())
            {
                return(-DokanNet.ERROR_ACCESS_DENIED);
            }

            return(mLocalFiles.WriteFile(
                       node.GetNodeId(),
                       filename,
                       buffer,
                       ref writtenBytes,
                       offset,
                       FileContext.Get(info)));
        }
        int DokanOperations.GetFileInformation(
            string filename,
            FileInformation fileinfo,
            DokanFileInfo info)
        {
            mLog.DebugFormat(
                "GetFileInformation - {0}",
                filename);

            Node node = WalkTree.Find(GetRoot(), filename);

            if (node != null)
            {
                node.FillFileInformation(fileinfo);
                return(0);
            }

            int result = Dynamic.SpecNode.GetFileInformation(
                filename, fileinfo, GetRoot(), mPlasticApi);

            if (result == 0)
            {
                return(0);
            }

            result = Dynamic.HistoryDirectory.GetFileInformation(
                filename, fileinfo, GetRoot(), mPlasticApi);

            if (result == 0)
            {
                return(0);
            }

            return(-DokanNet.ERROR_PATH_NOT_FOUND);
        }
        int DokanOperations.Cleanup(string filename, DokanFileInfo info)
        {
            if (info == null)
            {
                mLog.DebugFormat("Cleanup - {0} - INFO IS NULL", filename);
                return(0);
            }

            long size = 0;

            if (!info.IsDirectory)
            {
                Stream st = mHandles.GetStream(FileContext.Get(info));
                if (st != null)
                {
                    size = st.Length;
                }
            }

            Node node = WalkTree.Find(GetRoot(), filename);

            if (node != null)
            {
                mLog.DebugFormat("Cleanup - [{0}] - new size {1}", filename, size);

                node.UpdateSize(size);
            }
            else
            {
                mLog.DebugFormat("Cleanup - {0}", filename);
            }

            return(0);
        }
        int DokanOperations.CreateDirectory(string filename, DokanFileInfo info)
        {
            mLog.DebugFormat(
                "CreateDirectory - {0}",
                filename);

            Node tree = GetRoot();

            Node node = WalkTree.Find(tree, filename);

            if (node != null)
            {
                return(-DokanNet.ERROR_ALREADY_EXISTS);
            }

            // create the private directory in the tree
            Node parent = WalkTree.Find(tree, Path.GetDirectoryName(filename));

            if (parent == null)
            {
                return(-DokanNet.ERROR_PATH_NOT_FOUND);
            }

            Node child = parent.CreateChild();

            child.InitPrivate(DateTime.Now, Path.GetFileName(filename), FileAttributes.Directory);

            return(0);
        }
        int DokanOperations.SetEndOfFile(string filename, long length, DokanFileInfo info)
        {
            mLog.DebugFormat("SetEndOfFile - [{0}] {1}", filename, length);

            Node node = WalkTree.Find(GetRoot(), filename);

            if (node == null)
            {
                return(-DokanNet.ERROR_PATH_NOT_FOUND);
            }

            return(0);
        }
        int DokanOperations.OpenDirectory(string filename, DokanFileInfo info)
        {
            mLog.DebugFormat("OpenDirectory - [{0}]", filename);

            if (mHistoryDirectories.CreateNewDir(filename, FileAccess.Read, GetRoot(), mPlasticApi))
            {
                DirectoryContext.Set(info);
                return(0);
            }

            DirectoryContext.Set(info);

            Node node = WalkTree.Find(GetRoot(), filename);

            return(node != null ? 0 : -DokanNet.ERROR_PATH_NOT_FOUND);
        }
            internal static int CreateNew(
                string filename,
                FileAccess access,
                FileShare share,
                FileMode mode,
                FileOptions options,
                Node tree,
                WorkspaceLocalFiles localFiles,
                out int error)
            {
                // it is a private file, just create it
                Node parent = WalkTree.Find(tree, Path.GetDirectoryName(filename));

                if (parent == null || !parent.IsDirectory())
                {
                    error = -DokanNet.ERROR_PATH_NOT_FOUND;
                    return(0);
                }

                if (!IsCreateMode(mode))
                {
                    error = -DokanNet.ERROR_FILE_NOT_FOUND;
                    return(0);
                }

                Node newNode = parent.CreateChild();

                newNode.InitPrivate(
                    DateTime.Now,
                    Path.GetFileName(filename),
                    FileAttributes.Normal);

                error = 0;

                return(localFiles.CreateNewFile(
                           newNode.GetNodeId(),
                           filename,
                           access,
                           share,
                           mode,
                           options));
            }
        static int Delete(
            Node root,
            string path,
            VirtualFiles virtualFiles,
            ChangesTreeOperations changesTreeOperations)
        {
            Node parent = WalkTree.Find(root, Path.GetDirectoryName(path));

            if (parent == null)
            {
                return(-DokanNet.ERROR_PATH_NOT_FOUND);
            }

            Node node = WalkTree.GetChildByName(parent.GetChildren(), Path.GetFileName(path));

            if (node == null)
            {
                return(-DokanNet.ERROR_FILE_NOT_FOUND);
            }

            IVirtualFile virtualFile = virtualFiles.Get(node.GetNodeId());

            if (virtualFile != null)
            {
                mLog.ErrorFormat("We don't allow deleting virtual files. [{0}]",
                                 node.GetName());

                return(-DokanNet.ERROR_ACCESS_DENIED);
            }

            if (node.IsControlled())
            {
                changesTreeOperations.Delete(CmPath.FromWindows(path));
            }

            if (parent.DeleteChild(node))
            {
                return(0);
            }

            return(-DokanNet.ERROR_FILE_NOT_FOUND);
        }
        int DokanOperations.CloseFile(string filename, DokanFileInfo info)
        {
            mLog.DebugFormat("CloseFile - {0}", filename);

            Node node = WalkTree.Find(GetRoot(), filename);

            if (node == null)
            {
                return(-DokanNet.ERROR_FILE_NOT_FOUND);
            }

            if (mHistoryDirectories.Close(node))
            {
                return(0);
            }

            IVirtualFile virtualFile;

            if ((virtualFile = mVirtualFiles.Get(node.GetNodeId())) != null)
            {
                int handle = FileContext.Get(info);

                if (handle == -1)
                {
                    return(0);
                }

                virtualFile.CloseFile(handle);

                return(0);
            }

            if (info.IsDirectory)
            {
                return(0);
            }

            mHandles.Close(FileContext.Get(info));

            return(0);
        }
        int DokanOperations.FindFiles(
            string filename,
            ArrayList files,
            DokanFileInfo info)
        {
            mLog.DebugFormat("FindFiles - [{0}]", filename);

            List <FileInformation> result = new List <FileInformation>();

            if (Dynamic.HistoryDirectory.FindFiles(filename, GetRoot(), mPlasticApi, result))
            {
            }
            else
            {
                Node node = WalkTree.Find(GetRoot(), filename);

                if (node == null)
                {
                    return(-DokanNet.ERROR_PATH_NOT_FOUND);
                }

                if (!node.IsDirectory())
                {
                    return(0);
                }

                result = ListTree(node);

                if (node != GetRoot())
                {
                    AddCurrentAndPreviousDirectories(result, node);
                }
            }

            result.Sort((f1, f2) => f1.FileName.CompareTo(f2.FileName));

            files.AddRange(result);

            return(0);
        }
        int DokanOperations.CreateFile(
            string path,
            FileAccess access,
            FileShare share,
            FileMode mode,
            FileOptions options,
            DokanFileInfo info)
        {
            mLog.DebugFormat(
                "CreateFile - mode: {0, 5} - options: {1, 5} - {2}",
                mode, options, path);

            Node tree = GetRoot();

            Node node = WalkTree.Find(tree, path);

            if (node == null)
            {
                int  error;
                bool bIsDirectory;

                int handle = CreateNew.Create(
                    path,
                    access,
                    share,
                    mode,
                    options,
                    tree,
                    mFileCache,
                    mHandles,
                    mPlasticApi,
                    mLocalFiles,
                    mHistoryDirectories,
                    out bIsDirectory,
                    out error);

                if (error != 0)
                {
                    return(error);
                }

                if (bIsDirectory)
                {
                    DirectoryContext.Set(info);
                }
                else
                {
                    FileContext.Set(info, handle);
                }

                return(0);
            }

            if (mHistoryDirectories.OpenExisting(node))
            {
                DirectoryContext.Set(info);
                return(0);
            }

            if (node.IsDirectory())
            {
                DirectoryContext.Set(info);
                return(0);
            }

            IVirtualFile virtualFile;

            if ((virtualFile = mVirtualFiles.Get(node.GetNodeId())) != null)
            {
                int handle = virtualFile.CreateFile(access, share, mode, options);

                FileContext.Set(info, handle);

                return(0);
            }

#warning here me must handle CreateNew which I think should delete the existing file or fail

            if (node.IsControlledAndReadOnly())
            {
                string fileToOpen = mFileCache.GetFile(
                    node.GetRepSpec(),
                    node.CloneRevisionInfo(),
                    path,
                    mPlasticApi);

                if (OpenForRead(access))
                {
                    int handle = mHandles.OpenFile(
                        fileToOpen,
                        path,
                        access, share, mode, options);

                    if (handle == -1)
                    {
                        return(-1);
                    }

                    FileContext.Set(info, handle);

                    return(0);
                }

                // then we need to check it out and copy the content
                // of the file to the writable storage

                mLog.DebugFormat("**Doing CHECKOUT**");

                string writablePath = mLocalFiles.GetPathForFile(node.GetNodeId());

                File.Copy(fileToOpen, writablePath);

                Checkout(node, path, mChangesTreeOperations);
            }

            // return the existing private file
            int fhandle = LocalFile.OpenExisting(
                node.GetNodeId(),
                path,
                access,
                share,
                mode,
                options,
                mLocalFiles);

            if (fhandle == -1)
            {
                return(-DokanNet.ERROR_FILE_NOT_FOUND);
            }

            FileContext.Set(info, fhandle);

            return(fhandle);
        }