Exemple #1
0
    public override async ValueTask <FileHandle> CreateDirectory(FileHandle parentFileHandle, string name)
    {
        var parentLocalFileHandle = new LocalFileHandle(parentFileHandle);
        var stats = StatRealPath(GetRealPath(parentLocalFileHandle.Path));

        if (!parentLocalFileHandle.IsSameFile(stats))
        {
            throw new FileNotFoundException(parentFileHandle);
        }

        if (!stats.Type.HasFlag(FileType.Directory))
        {
            throw new FileNotADirectoryException(parentFileHandle);
        }

        var targetPath     = PathLib.Join(parentLocalFileHandle.Path, name);
        var targetRealPath = GetRealPath(targetPath);
        var fileType       = GetFileType(targetRealPath);

        if (fileType != null)
        {
            throw new FileExistsException($"The file '{targetPath}' existed.");
        }

        Directory.CreateDirectory(targetRealPath);

        var targetStat       = StatRealPath(targetRealPath);
        var targetFileHandle = new LocalFileHandle(targetPath, targetStat).FileHandle;

        await IndexFile(targetPath, targetFileHandle, targetStat);

        return(targetFileHandle);
    }
Exemple #2
0
    public void JoinTest()
    {
        var joinTests = new Dictionary <string[], string>
        {
            { new[] { ".", "x/b", "..", "/b/c.js" }, "x/b/c.js" },
            { Array.Empty <string>(), "." },
            { new[] { "/.", "x/b", "..", "/b/c.js" }, "/x/b/c.js" },
            { new[] { "/foo", "../../../bar" }, "/bar" },
            { new[] { "foo", "../../../bar" }, "../../bar" },
            { new[] { "foo/", "../../../bar" }, "../../bar" },
            { new[] { "foo/x", "../../../bar" }, "../bar" },
            { new[] { "foo/x", "./bar" }, "foo/x/bar" },
            { new[] { "foo/x/", "./bar" }, "foo/x/bar" },
            { new[] { "foo/x/", ".", "bar" }, "foo/x/bar" },
            { new[] { "./" }, "./" },
            { new[] { ".", "./" }, "./" },
            { new[] { ".", ".", "." }, "." },
            { new[] { ".", "./", "." }, "." },
            { new[] { ".", "/./", "." }, "." },
            { new[] { ".", "/////./", "." }, "." },
            { new[] { "." }, "." },
            { new[] { "", "." }, "." },
            { new[] { "", "foo" }, "foo" },
            { new[] { "foo", "/bar" }, "foo/bar" },
            { new[] { "", "/foo" }, "/foo" },
            { new[] { "", "", "/foo" }, "/foo" },
            { new[] { "", "", "foo" }, "foo" },
            { new[] { "foo", "" }, "foo" },
            { new[] { "foo/", "" }, "foo/" },
            { new[] { "foo", "", "/bar" }, "foo/bar" },
            { new[] { "./", "..", "/foo" }, "../foo" },
            { new[] { "./", "..", "..", "/foo" }, "../../foo" },
            { new[] { ".", "..", "..", "/foo" }, "../../foo" },
            { new[] { "", "..", "..", "/foo" }, "../../foo" },
            { new[] { "/" }, "/" },
            { new[] { "/", "." }, "/" },
            { new[] { "/", ".." }, "/" },
            { new[] { "/", "..", ".." }, "/" },
            { new[] { "" }, "." },
            { new[] { "", "" }, "." },
            { new[] { " /foo" }, " /foo" },
            { new[] { " ", "foo" }, " /foo" },
            { new[] { " ", "." }, " " },
            { new[] { " ", "/" }, " /" },
            { new[] { " ", "" }, " " },
            { new[] { "/", "foo" }, "/foo" },
            { new[] { "/", "/foo" }, "/foo" },
            { new[] { "/", "//foo" }, "/foo" },
            { new[] { "/", "", "/foo" }, "/foo" },
            { new[] { "", "/", "foo" }, "/foo" },
            { new[] { "", "/", "/foo" }, "/foo" }
        };

        foreach (var(test, expected) in joinTests)
        {
            Assert.AreEqual(expected, PathLib.Join(test));
        }
    }
Exemple #3
0
    public override async ValueTask Delete(FileHandle fileHandle, FileHandle parentFileHandle, string name, bool recursive)
    {
        var localFileHandle       = new LocalFileHandle(fileHandle);
        var parentLocalFileHandle = new LocalFileHandle(parentFileHandle);

        // check
        if (localFileHandle.Path != PathLib.Join(parentLocalFileHandle.Path, name))
        {
            throw new FileNotFoundException("File handles are inconsistent.");
        }

        var stats       = StatRealPath(GetRealPath(localFileHandle.Path));
        var parentStats = StatRealPath(GetRealPath(parentLocalFileHandle.Path));

        if (!localFileHandle.IsSameFile(stats))
        {
            throw new FileNotFoundException(fileHandle);
        }

        if (!parentLocalFileHandle.IsSameFile(parentStats))
        {
            throw new FileNotFoundException(parentFileHandle);
        }

        var realPath = GetRealPath(localFileHandle.Path);

        if (stats.Type.HasFlag(FileType.Directory))
        {
            if (recursive)
            {
                Directory.Delete(realPath, true);
            }
            else
            {
                throw new FileIsADirectoryException(fileHandle);
            }
        }
        else
        {
            File.Delete(realPath);
        }

        await IndexDeletedFile(localFileHandle.Path, fileHandle);
    }
Exemple #4
0
    public override async ValueTask <IEnumerable <Dirent> > ReadDirectory(FileHandle fileHandle)
    {
        var localFileHandle = new LocalFileHandle(fileHandle);
        var realPath        = GetRealPath(localFileHandle.Path);
        var directoryInfo   = new DirectoryInfo(realPath);

        if (!directoryInfo.Exists)
        {
            var fileType = GetFileType(realPath);

            if (fileType != null && !fileType.Value.HasFlag(FileType.Directory))
            {
                throw new FileNotADirectoryException(fileHandle);
            }

            throw new FileNotFoundException(fileHandle);
        }

        var stats = GetFileStatFromFileSystemInfo(directoryInfo);

        if (!localFileHandle.IsSameFile(stats))
        {
            throw new FileNotFoundException(fileHandle);
        }

        var result = directoryInfo.EnumerateFileSystemInfos().Select(info =>
        {
            var entryLocalFileHandle = new LocalFileHandle(
                PathLib.Join(localFileHandle.Path, info.Name),
                GetFileStatFromFileSystemInfo(info));
            return(new Dirent(
                       info.Name,
                       entryLocalFileHandle.FileHandle,
                       GetFileStatFromFileSystemInfo(info)));
        }).ToImmutableArray();

        await IndexDirectory(localFileHandle.Path, fileHandle, result);

        return(result);
    }
Exemple #5
0
    public override async ValueTask <FileHandle> CreateFile(FileHandle parentFileHandle, string name, ReadOnlyMemory <byte> content)
    {
        var parentLocalFileHandle = new LocalFileHandle(parentFileHandle);
        var parentFilePath        = parentLocalFileHandle.Path;
        var filePath    = PathLib.Join(parentFilePath, name);
        var parentStats = StatRealPath(GetRealPath(parentFilePath));

        if (!parentLocalFileHandle.IsSameFile(parentStats))
        {
            throw new FileNotFoundException(parentFileHandle);
        }

        if (!parentStats.Type.HasFlag(FileType.Directory))
        {
            throw new FileNotADirectoryException(parentFileHandle);
        }

        var realPath = GetRealPath(filePath);

        if (GetFileType(realPath) != null)
        {
            throw new FileExistsException($"The file '{filePath}' existed.");
        }

        await using var fileStream = File.OpenWrite(realPath);
        await fileStream.WriteAsync(content);

        await fileStream.FlushAsync();

        var newStats      = StatRealPath(realPath);
        var newFileHandle = new LocalFileHandle(filePath, newStats).FileHandle;

        await IndexFile(parentFilePath, newFileHandle, newStats);

        return(newFileHandle);
    }
Exemple #6
0
    /// <summary>
    ///     Create indexes of the contents in the directory.
    /// </summary>
    /// <param name="path">The path of the directory.</param>
    /// <param name="contents">The contents in the directory.</param>
    private async ValueTask IndexDirectory(
        IDbTransaction transaction,
        string path,
        IEnumerable <Dirent> contents,
        FileChangeEventBuilder eventBuilder)
    {
        var directoryId = await CreateDirectory(transaction, path, eventBuilder);

        var oldContents =
            (await _databaseTable.SelectByParentAsync(transaction, directoryId)).ToDictionary(content => content.Path);

        var newContents =
            contents.Select(
                content => new
        {
            Path          = PathLib.Join(path, content.Name),
            Parent        = directoryId,
            IsDirectory   = content.Stats.Type.HasFlag(FileType.Directory),
            IdentifierTag = content.FileHandle.Identifier,
            content.FileHandle,
            FileStats = content.Stats
        })
            .ToDictionary(content => content.Path);

        var addedContents =
            newContents.Keys.Except(oldContents.Keys).Select(key => newContents[key]).ToList();
        var removedContents =
            oldContents.Keys.Except(newContents.Keys).Select(key => oldContents[key]).ToList();
        var reservedContents =
            oldContents.Keys.Intersect(newContents.Keys).Select(
                key =>
                new { oldContents[key].Path, oldFile = oldContents[key], newFile = newContents[key] });

        var updatedTagContents = new List <(long Id, string Path, FileHandle FileHandle, FileStats FileStats, bool IsNew)>();

        foreach (var reservedContent in reservedContents)
        {
            var oldFile = reservedContent.oldFile;
            var newFile = reservedContent.newFile;
            if (oldFile.IsDirectory != newFile.IsDirectory)
            {
                removedContents.Add(oldFile);
                addedContents.Add(newFile);
            }
            else if (oldFile.IdentifierTag == null)
            {
                updatedTagContents.Add(
                    (oldFile.Id, newFile.Path, newFile.FileHandle, newFile.FileStats, true));
            }
            else if (oldFile.IdentifierTag != newFile.IdentifierTag)
            {
                removedContents.Add(oldFile);
                addedContents.Add(newFile);
            }
            else if (oldFile.ContentTag != newFile.FileStats.Hash.ContentTag)
            {
                updatedTagContents.Add((oldFile.Id, newFile.Path, newFile.FileHandle, newFile.FileStats, false));
            }
        }

        foreach (var removed in removedContents)
        {
            await Delete(transaction, removed, eventBuilder);
        }

        foreach (var added in addedContents)
        {
            await _databaseTable.InsertAsync(
                transaction,
                added.Path,
                directoryId,
                added.IsDirectory,
                added.FileHandle.Identifier,
                added.FileStats.Hash.ContentTag);

            eventBuilder.Created(added.FileHandle);
        }

        foreach (var updatedTagContent in updatedTagContents)
        {
            if (updatedTagContent.IsNew)
            {
                await _databaseTable.UpdateIdentifierTagByIdAsync(
                    transaction,
                    updatedTagContent.Id,
                    updatedTagContent.FileHandle.Identifier,
                    updatedTagContent.FileStats.Hash.ContentTag);

                eventBuilder.Created(updatedTagContent.FileHandle);
            }
            else
            {
                await _databaseTable.UpdateStatsByIdAsync(
                    transaction,
                    updatedTagContent.Id,
                    updatedTagContent.FileStats.Hash.ContentTag);

                await _databaseTable.DeletePropertyOnFileUpdated(transaction, updatedTagContent.Id);

                eventBuilder.Changed(updatedTagContent.FileHandle);
            }
        }
    }
Exemple #7
0
    private static async IAsyncEnumerable <FileSystemWalkerEntry> EnumerateAllFiles(
        ISingletonFileSystem singletonFileSystem,
        FileHandle rootFileHandle)
    {
        var directoryWalker = new FileSystemDirectoryWalker(singletonFileSystem, rootFileHandle);

        await foreach (var directory in directoryWalker)
        {
            foreach (var entries in directory.Entries)
            {
                yield return(new FileSystemWalkerEntry(entries.FileHandle, entries.Stats, PathLib.Join(directory.Path, entries.Name)));
            }
        }
    }
Exemple #8
0
    public override async ValueTask <FileHandle> Rename(
        FileHandle fileHandle,
        FileHandle oldParentFileHandle,
        string oldName,
        FileHandle newParentFileHandle,
        string newName)
    {
        var localFileHandle          = new LocalFileHandle(fileHandle);
        var oldParentLocalFileHandle = new LocalFileHandle(oldParentFileHandle);
        var newParentLocalFileHandle = new LocalFileHandle(newParentFileHandle);

        // check
        if (localFileHandle.Path != PathLib.Join(oldParentLocalFileHandle.Path, oldName))
        {
            throw new FileNotFoundException("File handles are inconsistent.");
        }

        var oldRealPath    = GetRealPath(localFileHandle.Path);
        var oldFileStats   = StatRealPath(oldRealPath);
        var oldParentStats = StatRealPath(GetRealPath(oldParentLocalFileHandle.Path));
        var newParentStats = StatRealPath(GetRealPath(newParentLocalFileHandle.Path));

        if (!localFileHandle.IsSameFile(oldFileStats))
        {
            throw new FileNotFoundException(fileHandle);
        }

        if (!oldParentLocalFileHandle.IsSameFile(oldParentStats))
        {
            throw new FileNotFoundException(oldParentFileHandle);
        }

        if (!newParentLocalFileHandle.IsSameFile(newParentStats))
        {
            throw new FileNotFoundException(newParentFileHandle);
        }

        if (!newParentStats.Type.HasFlag(FileType.Directory))
        {
            throw new FileNotADirectoryException(newParentFileHandle);
        }

        var newPath     = PathLib.Join(newParentLocalFileHandle.Path, newName);
        var newRealPath = GetRealPath(newPath);

        if (GetFileType(newRealPath) != null)
        {
            throw new FileExistsException($"The file '{newPath}' existed.");
        }

        if (oldFileStats.Type.HasFlag(FileType.Directory))
        {
            Directory.Move(oldRealPath, newRealPath);
        }
        else
        {
            File.Move(oldRealPath, newRealPath, false);
        }

        var newFileStats = StatRealPath(newRealPath);

        await IndexDeletedFile(localFileHandle.Path, fileHandle);

        var newFileHandle = new LocalFileHandle(newPath, newFileStats).FileHandle;

        await IndexFile(newPath, new LocalFileHandle(newPath, newFileStats).FileHandle, newFileStats);

        return(newFileHandle);
    }