예제 #1
0
 internal DirectoryEntry(DirectoryEntry toCopy)
 {
     _options = toCopy._options;
     _name = toCopy._name;
     _attr = toCopy._attr;
     _creationTimeTenth = toCopy._creationTimeTenth;
     _creationTime = toCopy._creationTime;
     _creationDate = toCopy._creationDate;
     _lastAccessDate = toCopy._lastAccessDate;
     _firstClusterHi = toCopy._firstClusterHi;
     _lastWriteTime = toCopy._lastWriteTime;
     _firstClusterLo = toCopy._firstClusterLo;
     _fileSize = toCopy._fileSize;
 }
예제 #2
0
 internal void ForgetDirectory(DirectoryEntry entry)
 {
     uint index = entry.FirstCluster;
     if (index != 0 && _dirCache.ContainsKey(index))
     {
         Directory dir = _dirCache[index];
         _dirCache.Remove(index);
         dir.Dispose();
     }
 }
예제 #3
0
        /// <summary>
        /// Moves a file, allowing an existing file to be overwritten.
        /// </summary>
        /// <param name="sourceName">The file to move.</param>
        /// <param name="destinationName">The target file name.</param>
        /// <param name="overwrite">Whether to permit a destination file to be overwritten</param>
        public override void MoveFile(string sourceName, string destinationName, bool overwrite)
        {
            Directory sourceDir;
            long sourceEntryId = GetDirectoryEntry(sourceName, out sourceDir);

            if (sourceDir == null || sourceEntryId < 0)
            {
                throw new FileNotFoundException(string.Format(CultureInfo.InvariantCulture, "The source file '{0}' was not found", sourceName));
            }

            DirectoryEntry sourceEntry = sourceDir.GetEntry(sourceEntryId);

            if ((sourceEntry.Attributes & FatAttributes.Directory) != 0)
            {
                throw new IOException("The source file is a directory");
            }

            DirectoryEntry newEntry = new DirectoryEntry(sourceEntry);
            newEntry.Name = FileName.FromPath(destinationName, FatOptions.FileNameEncoding);

            Directory destDir;
            long destEntryId = GetDirectoryEntry(destinationName, out destDir);

            if (destDir == null)
            {
                throw new DirectoryNotFoundException(string.Format(CultureInfo.InvariantCulture, "The destination directory for '{0}' was not found", destinationName));
            }

            // If the destination is a directory, use the old file name to construct a full path.
            if (destEntryId >= 0)
            {
                DirectoryEntry destEntry = destDir.GetEntry(destEntryId);
                if ((destEntry.Attributes & FatAttributes.Directory) != 0)
                {
                    newEntry.Name = FileName.FromPath(sourceName, FatOptions.FileNameEncoding);
                    destinationName = Utilities.CombinePaths(destinationName, Utilities.GetFileFromPath(sourceName));

                    destEntryId = GetDirectoryEntry(destinationName, out destDir);
                }
            }

            // If there's an existing entry...
            if (destEntryId >= 0)
            {
                DirectoryEntry destEntry = destDir.GetEntry(destEntryId);

                if ((destEntry.Attributes & FatAttributes.Directory) != 0)
                {
                    throw new IOException("Destination file is an existing directory");
                }

                if (!overwrite)
                {
                    throw new IOException("Destination file already exists");
                }

                // Remove the old file
                destDir.DeleteEntry(destEntryId, true);
            }

            // Add the new file's entry and remove the old link to the file's contents
            destDir.AddEntry(newEntry);
            sourceDir.DeleteEntry(sourceEntryId, false);
        }
예제 #4
0
        /// <summary>
        /// Copies an existing file to a new file, allowing overwriting of an existing file.
        /// </summary>
        /// <param name="sourceFile">The source file</param>
        /// <param name="destinationFile">The destination file</param>
        /// <param name="overwrite">Whether to permit over-writing of an existing file.</param>
        public override void CopyFile(string sourceFile, string destinationFile, bool overwrite)
        {
            Directory sourceDir;
            long sourceEntryId = GetDirectoryEntry(sourceFile, out sourceDir);

            if (sourceDir == null || sourceEntryId < 0)
            {
                throw new FileNotFoundException(string.Format(CultureInfo.InvariantCulture, "The source file '{0}' was not found", sourceFile));
            }

            DirectoryEntry sourceEntry = sourceDir.GetEntry(sourceEntryId);

            if ((sourceEntry.Attributes & FatAttributes.Directory) != 0)
            {
                throw new IOException("The source file is a directory");
            }

            DirectoryEntry newEntry = new DirectoryEntry(sourceEntry);
            newEntry.Name = FileName.FromPath(destinationFile, FatOptions.FileNameEncoding);
            newEntry.FirstCluster = 0;

            Directory destDir;
            long destEntryId = GetDirectoryEntry(destinationFile, out destDir);

            if (destDir == null)
            {
                throw new DirectoryNotFoundException(string.Format(CultureInfo.InvariantCulture, "The destination directory for '{0}' was not found", destinationFile));
            }

            // If the destination is a directory, use the old file name to construct a full path.
            if (destEntryId >= 0)
            {
                DirectoryEntry destEntry = destDir.GetEntry(destEntryId);
                if ((destEntry.Attributes & FatAttributes.Directory) != 0)
                {
                    newEntry.Name = FileName.FromPath(sourceFile, FatOptions.FileNameEncoding);
                    destinationFile = Utilities.CombinePaths(destinationFile, Utilities.GetFileFromPath(sourceFile));

                    destEntryId = GetDirectoryEntry(destinationFile, out destDir);
                }
            }

            // If there's an existing entry...
            if (destEntryId >= 0)
            {
                DirectoryEntry destEntry = destDir.GetEntry(destEntryId);

                if ((destEntry.Attributes & FatAttributes.Directory) != 0)
                {
                    throw new IOException("Destination file is an existing directory");
                }

                if (!overwrite)
                {
                    throw new IOException("Destination file already exists");
                }

                // Remove the old file
                destDir.DeleteEntry(destEntryId, true);
            }

            // Add the new file's entry
            destEntryId = destDir.AddEntry(newEntry);

            // Copy the contents...
            using (Stream sourceStream = new FatFileStream(this, sourceDir, sourceEntryId, FileAccess.Read),
                destStream = new FatFileStream(this, destDir, destEntryId, FileAccess.Write))
            {
                Utilities.PumpStreams(sourceStream, destStream);
            }
        }
예제 #5
0
        private void PopulateNewChildDirectory(DirectoryEntry newEntry)
        {
            // Populate new directory with initial (special) entries.  First one is easy, just change the name!
            using (ClusterStream stream = new ClusterStream(_fileSystem, FileAccess.Write, newEntry.FirstCluster, uint.MaxValue))
            {
                // First is the self-referencing entry...
                DirectoryEntry selfEntry = new DirectoryEntry(newEntry);
                selfEntry.Name = FileName.SelfEntryName;
                selfEntry.WriteTo(stream);

                // Second is a clone of our self entry (i.e. parent) - though dates are odd...
                DirectoryEntry parentEntry = new DirectoryEntry(SelfEntry);
                parentEntry.Name = FileName.ParentEntryName;
                parentEntry.CreationTime = newEntry.CreationTime;
                parentEntry.LastWriteTime = newEntry.LastWriteTime;
                parentEntry.WriteTo(stream);
            }
        }
예제 #6
0
        internal void UpdateEntry(long id, DirectoryEntry entry)
        {
            if (id < 0)
            {
                throw new IOException("Attempt to update unknown directory entry");
            }

            _dirStream.Position = id;
            entry.WriteTo(_dirStream);
            _entries[id] = entry;
        }
예제 #7
0
        private void LoadEntries()
        {
            _entries = new Dictionary<long, DirectoryEntry>();
            _freeEntries = new List<long>();

            _selfEntryLocation = -1;
            _parentEntryLocation = -1;

            while (_dirStream.Position < _dirStream.Length)
            {
                long streamPos = _dirStream.Position;
                DirectoryEntry entry = new DirectoryEntry(_fileSystem.FatOptions, _dirStream);

                if (entry.Attributes == (FatAttributes.ReadOnly | FatAttributes.Hidden | FatAttributes.System | FatAttributes.VolumeId))
                {
                    // Long File Name entry
                }
                else if (entry.Name.IsDeleted())
                {
                    // E5 = Free Entry
                    _freeEntries.Add(streamPos);
                }
                else if (entry.Name == FileName.SelfEntryName)
                {
                    _selfEntry = entry;
                    _selfEntryLocation = streamPos;
                }
                else if (entry.Name == FileName.ParentEntryName)
                {
                    _parentEntry = entry;
                    _parentEntryLocation = streamPos;
                }
                else if (entry.Name == FileName.Null)
                {
                    // Free Entry, no more entries available
                    _endOfEntries = streamPos;
                    break;
                }
                else
                {
                    _entries.Add(streamPos, entry);
                }
            }
        }
예제 #8
0
        internal void DeleteEntry(long id, bool releaseContents)
        {
            if (id < 0)
            {
                throw new IOException("Attempt to delete unknown directory entry");
            }

            try
            {
                DirectoryEntry entry = _entries[id];

                DirectoryEntry copy = new DirectoryEntry(entry);
                copy.Name = entry.Name.Deleted();
                _dirStream.Position = id;
                copy.WriteTo(_dirStream);

                if (releaseContents)
                {
                    _fileSystem.Fat.FreeChain(entry.FirstCluster);
                }

                _entries.Remove(id);
                _freeEntries.Add(id);

                HandleAccessed(true);
            }
            finally
            {
                _fileSystem.Fat.Flush();
            }
        }
예제 #9
0
        internal long AddEntry(DirectoryEntry newEntry)
        {
            // Unlink an entry from the free list (or add to the end of the existing directory)
            long pos;
            if (_freeEntries.Count > 0)
            {
                pos = _freeEntries[0];
                _freeEntries.RemoveAt(0);
            }
            else
            {
                pos = _endOfEntries;
                _endOfEntries += 32;
            }

            // Put the new entry into it's slot
            _dirStream.Position = pos;
            newEntry.WriteTo(_dirStream);

            // Update internal structures to reflect new entry (as if read from disk)
            _entries.Add(pos, newEntry);

            HandleAccessed(true);

            return pos;
        }
예제 #10
0
        internal SparseStream OpenFile(FileName name, FileMode mode, FileAccess fileAccess)
        {
            if (mode == FileMode.Append || mode == FileMode.Truncate)
            {
                throw new NotImplementedException();
            }

            long fileId = FindEntry(name);
            bool exists = fileId != -1;

            if (mode == FileMode.CreateNew && exists)
            {
                throw new IOException("File already exists");
            }
            else if (mode == FileMode.Open && !exists)
            {
                throw new FileNotFoundException("File not found", name.GetDisplayName(_fileSystem.FatOptions.FileNameEncoding));
            }
            else if ((mode == FileMode.Open || mode == FileMode.OpenOrCreate || mode == FileMode.Create) && exists)
            {
                SparseStream stream = new FatFileStream(_fileSystem, this, fileId, fileAccess);
                if (mode == FileMode.Create)
                {
                    stream.SetLength(0);
                }

                HandleAccessed(false);

                return stream;
            }
            else if ((mode == FileMode.OpenOrCreate || mode == FileMode.CreateNew || mode == FileMode.Create) && !exists)
            {
                // Create new file
                DirectoryEntry newEntry = new DirectoryEntry(_fileSystem.FatOptions, name, FatAttributes.Archive);
                newEntry.FirstCluster = 0; // i.e. Zero-length
                newEntry.CreationTime = _fileSystem.ConvertFromUtc(DateTime.UtcNow);
                newEntry.LastWriteTime = newEntry.CreationTime;

                fileId = AddEntry(newEntry);

                return new FatFileStream(_fileSystem, this, fileId, fileAccess);
            }
            else
            {
                // Should never get here...
                throw new NotImplementedException();
            }
        }
예제 #11
0
        internal void AttachChildDirectory(FileName name, Directory newChild)
        {
            long id = FindEntry(name);
            if (id >= 0)
            {
                throw new IOException("Directory entry already exists");
            }

            DirectoryEntry newEntry = new DirectoryEntry(newChild.ParentsChildEntry);
            newEntry.Name = name;
            AddEntry(newEntry);

            DirectoryEntry newParentEntry = new DirectoryEntry(SelfEntry);
            newParentEntry.Name = FileName.ParentEntryName;
            newChild.ParentEntry = newParentEntry;
        }
예제 #12
0
        internal Directory CreateChildDirectory(FileName name)
        {
            long id = FindEntry(name);
            if (id >= 0)
            {
                if ((_entries[id].Attributes & FatAttributes.Directory) == 0)
                {
                    throw new IOException("A file exists with the same name");
                }
                else
                {
                    return _fileSystem.GetDirectory(this, id);
                }
            }
            else
            {
                try
                {
                    uint firstCluster;
                    if (!_fileSystem.Fat.TryGetFreeCluster(out firstCluster))
                    {
                        throw new IOException("Failed to allocate first cluster for new directory");
                    }

                    _fileSystem.Fat.SetEndOfChain(firstCluster);

                    DirectoryEntry newEntry = new DirectoryEntry(_fileSystem.FatOptions, name, FatAttributes.Directory);
                    newEntry.FirstCluster = firstCluster;
                    newEntry.CreationTime = _fileSystem.ConvertFromUtc(DateTime.UtcNow);
                    newEntry.LastWriteTime = newEntry.CreationTime;

                    id = AddEntry(newEntry);

                    PopulateNewChildDirectory(newEntry);

                    // Rather than just creating a new instance, pull it through the fileSystem cache
                    // to ensure the cache model is preserved.
                    return _fileSystem.GetDirectory(this, id);
                }
                finally
                {
                    _fileSystem.Fat.Flush();
                }
            }
        }