Skip to content

When creating 20 files in FatFileSystem using new FatFileSystem per file created then "An item with the same key has already been added" exception is thrown #57

@henrikstengaard

Description

@henrikstengaard

I stumbled upon an exception while creating a lot of single files using FatFileSystem where I create a new FatFileSystem instance for each file and managed to create following test to reproduce the issue:

    [Fact]
    public async Task CreateFilesInSubdirectoryUsingFatFileSystemPerFile()
    {
        using var diskStream = new SparseMemoryStream();

        diskStream.Position = 0;
        using (var fsFormat = FatFileSystem.FormatFloppy(diskStream, FloppyDiskType.HighDensity, "FLOPPY_IMG "))
        {
            fsFormat.CreateDirectory("dir");            
        }

        for (var i = 0; i < 20; i++)
        {
            using (var fsCreate = new FatFileSystem(diskStream))
            {
                using (var fileStream = fsCreate.OpenFile($"dir{Path.DirectorySeparatorChar}file{i}.txt", FileMode.Create))
                {
                    await fileStream.WriteAsync(new byte[10]);
                }
            }            
        }

        using var fsAssert = new FatFileSystem(diskStream);
        {
            var entries = fsAssert.GetFileSystemEntries("").ToList();
            Assert.Single(entries);
            Assert.Equal("dir", entries[0]);

            entries = fsAssert.GetFileSystemEntries("dir").ToList();
            Assert.Equal(20, entries.Count);
            Assert.Equal(Enumerable.Range(0, 20).Select(i => $"dir\\file{i}.txt"), entries);
        }
    }

From what I have managed to investigate so far, the issue seems related to ClusterStream.cs switching from one cluster to another when the cluster for dir is full (512 bytes) causing the position (pos) going from 512 to 0. The exception is then thrown by AddEntryRaw method adding the entry to _entries dictionary in Directory.cs and 0 already exists from an entry in previous cluster.

I would like to help with a fix for the issue, but I would also ask some advise. The _entries dictionary uses cluster position as key to index entries and must be changed to something else than ClusterStream position. I initially thought about using Guid's instead of long's as dictionary key, but then I realised the long key fromthe dictionary is also used to seek to entry positions when deleting entries. Here I'm not sure how seeking to position of entry to delete works when the cluster have changed within the ClusterStream. More investigation needed

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions