public void CreateFileTest()
        {
            var fileinfo = new OS9FileInfo("list", 0x4f, OS9FileAttributes.Execute|OS9FileAttributes.Read, null, null, 0, 0, null);
            byte[] data = {
                              0x87, 0xcd, 0x00, 0x4f, 0x00, 0x0d, 0x11, 0x81,
                              0x67, 0x00, 0x12, 0x02, 0x8d, 0x4c, 0x69, 0x73,
                              0xf4, 0x05, 0x9f, 0x01, 0x86, 0x01, 0x10, 0x3f,
                              0x84, 0x25, 0x2e, 0x97, 0x00, 0x9f, 0x01, 0x96,
                              0x00, 0x30, 0x43, 0x10, 0x8e, 0x00, 0xc8, 0x10,
                              0x3f, 0x8b, 0x25, 0x09, 0x86, 0x01, 0x10, 0x3f,
                              0x8c, 0x24, 0xec, 0x20, 0x14, 0xc1, 0xd3, 0x26,
                              0x10, 0x96, 0x00, 0x10, 0x3f, 0x8f, 0x25, 0x09,
                              0x9e, 0x01, 0xa6, 0x84, 0x81, 0x0d, 0x26, 0xca,
                              0x5f, 0x10, 0x3f, 0x06, 0x58, 0xbc, 0x12
                          };

            var file = (OS9File) OS9File.CreateFile(fileinfo, data);
            Assert.IsTrue(file is OS9ModuleFile);

            var module = (OS9ModuleFile) file;
            Assert.AreEqual("List", module.ModuleName);
            Assert.AreEqual(OS9ModuleType.Program, module.ModuleType);
            Assert.AreEqual(1, module.ModuleLanguage);
            Assert.AreEqual(8, module.ModuleAttributes);
            Assert.AreEqual(1, module.ModuleRevision);
            Assert.AreEqual(0x67, module.HeaderParity);
            Assert.AreEqual(0x58bc12, module.ModuleCRC);
        }
Beispiel #2
0
        /// <summary>
        /// Reads a file from the system and returns it, without parsing or removing any file headers or other file meta-infromation.
        /// The file is identified by passing the information from the file description sector.
        /// </summary>
        /// <param name="fileinfo">File description sector.</param>
        /// <returns>The raw data associated with this file.</returns>
        byte[] ReadFile(OS9FileInfo fileinfo)
        {
            var data = new byte[fileinfo.Size];

            if (fileinfo.Size == 0)
            {
                return(data);
            }

            int offset = 0;

            foreach (var segment in fileinfo.Segments)
            {
                int sector = segment.Lsn;
                for (int i = 0; i < segment.Size; i++)
                {
                    var sectordata = ReadSector(sector++);
                    int sectorsize = Math.Min(sectordata.Length, data.Length - offset);
                    Array.Copy(sectordata, 0, data, offset, sectorsize);
                    offset += sectorsize;
                    if (offset == fileinfo.Size)
                    {
                        return(data);
                    }
                }
            }

            return(data);
        }
Beispiel #3
0
        /// <summary>
        /// Reads the file descriptor sector for a given file and verified that all sectors in the file segment list (and the file descriptor sector itself)
        /// are marked as free in the passed cluster allocation map.  It then marks the clusters as marked.
        /// </summary>
        /// <param name="map">Cluster allocation map.</param>
        /// <param name="filedesc">Logical sector number of the file descriptor sector for the file.</param>
        /// <param name="clustersize">Cluster size for this filesystem.</param>
        /// <exception cref="FilesystemConsistencyException">Thrown if any cluster used for this file is already allocated.</exception>
        private void VerifyAndUpdateAllocationMap(OS9AllocationMap map, int filedesc, int clustersize)
        {
            var fileinfo = OS9FileInfo.Parse(ReadSector(filedesc), null);

            /* Verify that all sectors used by this file are marked as free in the cluster allocation map. */
            if (map.IsAllocated(filedesc / clustersize))
            {
                throw new FilesystemConsistencyException(String.Format("Sector {0} is in use by multiple files", filedesc));
            }
            foreach (var segment in fileinfo.Segments)
            {
                int sector = segment.Lsn;
                for (int i = 0; i < segment.Size; i++)
                {
                    if (map.IsAllocated(sector / clustersize))
                    {
                        throw new FilesystemConsistencyException(String.Format("Sector {0} is in use by multiple files", sector));
                    }
                    sector++;
                }
            }

            /* Mark all sectors as allocated. */
            map.SetAllocated(filedesc / clustersize, true);
            foreach (var segment in fileinfo.Segments)
            {
                int sector = segment.Lsn;
                for (int i = 0; i < segment.Size; i++)
                {
                    map.SetAllocated(sector / clustersize, true);
                    sector++;
                }
            }
        }
Beispiel #4
0
        /// <summary>
        /// Create an OS-9 file by parsing raw file data.
        /// </summary>
        /// <param name="fileinfo">File directory information.</param>
        /// <param name="data">Raw file data.</param>
        /// <returns></returns>
        public static OS9File CreateFile(OS9FileInfo fileinfo, byte[] data)
        {
            if (OS9ModuleFile.IsModuleFile(data))
            {
                return(new OS9ModuleFile(fileinfo, data));
            }

            return(new OS9DataFile(fileinfo, data));
        }
Beispiel #5
0
        /// <summary>
        /// Create an OS-9 file by parsing raw file data.
        /// </summary>
        /// <param name="fileinfo">File directory information.</param>
        /// <param name="data">Raw file data.</param>
        /// <returns></returns>
        internal static OS9File CreateFile(OS9FileInfo fileinfo, byte[] data)
        {
            if (OS9ModuleFile.IsModuleFile(data))
            {
                return new OS9ModuleFile(fileinfo, data);
            }

            return new OS9DataFile(fileinfo, data);
        }
Beispiel #6
0
        /// <summary>
        /// Checks the filesystem consistency.
        /// </summary>
        /// <exception cref="FilesystemConsistencyException">Thrown if the filesystem is not consistent in a manner that makes write operations unsafe.</exception>
        public void Check()
        {
            if (IsDisposed)
            {
                throw new ObjectDisposedException(GetType().FullName);
            }

            ReadDiskHeader();

            var allocmap = new OS9AllocationMap(DiskInfo.AllocationMapSize);            // mirror the allocation map

            allocmap.SetAllocated(IdentificationSector / DiskInfo.ClusterSize, true);
            allocmap.SetAllocated(AllocationMapSector / DiskInfo.ClusterSize, true);

            var dirs = new Queue <int>();                        // LSN of all directories found while traversing the file structure

            dirs.Enqueue(DiskInfo.RootDirectory);
            VerifyAndUpdateAllocationMap(allocmap, DiskInfo.RootDirectory, DiskInfo.ClusterSize);

            /* Traverse the directory hierarchy and update the cluster allocation map for all files encountered. */
            while (dirs.Count > 0)
            {
                int lsn   = dirs.Dequeue();
                var files = ReadDirectory(lsn);
                foreach (var file in files)
                {
                    if (file.IsValid && !String.Equals(file.Filename, ".") && !String.Equals(file.Filename, ".."))
                    {
                        VerifyAndUpdateAllocationMap(allocmap, file.Sector, DiskInfo.ClusterSize);
                        var fileinfo = OS9FileInfo.Parse(ReadSector(file.Sector), file.Filename);
                        if (fileinfo.IsDirectory)
                        {
                            dirs.Enqueue(file.Sector);
                        }
                    }
                }
            }

            /* Finally, verify that all clusters used by files found are actually marked as allocated in the disk cluster allocation map. */
            for (int i = 0; i < AllocationMap.AllocationMapSize; i++)
            {
                if (allocmap.IsAllocated(i) && !AllocationMap.IsAllocated(i))
                {
                    throw new FilesystemConsistencyException(String.Format("Cluster {0} is in use by a file but not marked as allocated", i));
                }
            }
        }
        /// <summary>
        /// Create a OS9 module file object.
        /// </summary>
        /// <param name="fileinfo">Directory information for this file, or <value>null</value> if no directory information is available.</param>
        /// <param name="filedata">Raw file data, including headers and payload.</param>
        /// <param name="validate">If cleared, an invalid module file can be created, i.e. header and file checksum values are not validated.</param>
        internal OS9ModuleFile(OS9FileInfo fileinfo, byte[] filedata, bool validate = true) : base(fileinfo)
        {
            if (filedata == null)
            {
                throw new ArgumentNullException("filedata");
            }
            var filename = fileinfo == null ? null : fileinfo.Name;

            if (filedata.Length < StandardModuleHeaderSize)
            {
                throw new InvalidFileException(filename, String.Format("A module file must contain a {0} byte header.  This file is only {1} bytes long.", StandardModuleHeaderSize, filedata.Length));
            }
            if (filedata[0] != 0x87 || filedata[1] != 0xcd)
            {
                throw new InvalidFileException(filename, "Module file header does not contain valid sync sequence.");
            }

            data = (byte[])filedata.Clone();

            if (ModuleSize > data.Length)
            {
                throw new InvalidFileException(filename, String.Format("The module header specifies a module size of {0} bytes but the file is only {1} bytes.", ModuleSize, data.Length));
            }

            int nameoffset = (data[4] << 8) | data[5];

            if (nameoffset > data.Length)
            {
                throw new InvalidFileException(filename, "Module filename offset is outside the file data.");
            }
            ModuleName = OS9Utils.ParseString(data, nameoffset);

            if (validate)
            {
                if (HeaderParity != CalculateHeaderParity(data, StandardModuleHeaderSize - 1))
                {
                    throw new InvalidFileException(filename, "Header parity error");
                }
                if (ModuleCRC != CalculateModuleCRC(data, ModuleSize - 3))
                {
                    throw new InvalidFileException(filename, "Invalid module CRC");
                }
            }
        }
Beispiel #8
0
        /// <summary>
        /// Reads a directory starting at a given disk sector.
        /// </summary>
        /// <param name="sector">First sector of the directory file.</param>
        /// <returns>A list of (filename, sector) tuples for the entries in the directory.</returns>
        internal List <OS9DirectoryEntry> ReadDirectory(int sector)
        {
            var header = OS9FileInfo.Parse(ReadSector(sector), null);

            if (!header.IsDirectory)
            {
                throw new InvalidFileException();
            }

            var dir        = new List <OS9DirectoryEntry>();
            var raw        = ReadFile(header);
            int direntries = raw.Length / OS9DirectoryEntry.RawEntrySize;

            for (int i = 0; i < direntries; i++)
            {
                dir.Add(new OS9DirectoryEntry(raw, i));
            }

            return(dir);
        }
Beispiel #9
0
        /// <summary>
        /// Returns meta-information for a named file.
        /// </summary>
        /// <param name="filename">Name of file</param>
        /// <returns>File meta-information object.</returns>
        public IFileInfo GetFileInfo(string filename)
        {
            if (IsDisposed)
            {
                throw new ObjectDisposedException(GetType().FullName);
            }
            if (filename == null)
            {
                throw new ArgumentNullException();
            }

            int sector = FindPath(filename);

            if (sector == -1)
            {
                throw new FileNotFoundException(filename);
            }

            var raw = ReadSector(sector);

            return(OS9FileInfo.Parse(raw, filename));
        }
Beispiel #10
0
 internal OS9File(OS9FileInfo fileinfo)
 {
     FileInfo = fileinfo;
 }
Beispiel #11
0
        /// <summary>
        /// Reads a file from the system and returns it, without parsing or removing any file headers or other file meta-infromation.
        /// The file is identified by passing the information from the file description sector.
        /// </summary>
        /// <param name="fileinfo">File description sector.</param>
        /// <returns>The raw data associated with this file.</returns>
        byte[] ReadFile(OS9FileInfo fileinfo)
        {
            var data = new byte[fileinfo.Size];
            if (fileinfo.Size == 0)
                return data;

            int offset = 0;
            foreach (var segment in fileinfo.Segments)
            {
                int sector = segment.Lsn;
                for (int i=0; i<segment.Size; i++)
                {
                    var sectordata = ReadSector(sector++);
                    int sectorsize = Math.Min(sectordata.Length, data.Length - offset);
                    Array.Copy(sectordata, 0, data, offset, sectorsize);
                    offset += sectorsize;
                    if (offset == fileinfo.Size)
                        return data;
                }
            }

            return data;
        }
 internal OS9DataFile(OS9FileInfo fileinfo, byte[] data)
     : base(fileinfo)
 {
     this.data = data;
 }
        /// <summary>
        /// Create a OS9 module file object.
        /// </summary>
        /// <param name="fileinfo">Directory information for this file, or <value>null</value> if no directory information is available.</param>
        /// <param name="filedata">Raw file data, including headers and payload.</param>
        /// <param name="validate">If cleared, an invalid module file can be created, i.e. header and file checksum values are not validated.</param>
        internal OS9ModuleFile(OS9FileInfo fileinfo, byte[] filedata, bool validate=true)
            : base(fileinfo)
        {
            if (filedata == null) throw new ArgumentNullException("filedata");
            var filename = fileinfo == null ? null : fileinfo.Name;
            if (filedata.Length < StandardModuleHeaderSize) throw new InvalidFileException(filename, String.Format("A module file must contain a {0} byte header.  This file is only {1} bytes long.", StandardModuleHeaderSize, filedata.Length));
            if (filedata[0] != 0x87 || filedata[1] != 0xcd) throw new InvalidFileException(filename, "Module file header does not contain valid sync sequence.");

            data = (byte[]) filedata.Clone();

            if (ModuleSize > data.Length) throw new InvalidFileException(filename, String.Format("The module header specifies a module size of {0} bytes but the file is only {1} bytes.", ModuleSize, data.Length));

            int nameoffset = (data[4] << 8) | data[5];
            if (nameoffset > data.Length) throw new InvalidFileException(filename, "Module filename offset is outside the file data.");
            ModuleName = OS9Utils.ParseString(data, nameoffset);

            if (validate)
            {
                if (HeaderParity != CalculateHeaderParity(data, StandardModuleHeaderSize-1)) throw new InvalidFileException(filename, "Header parity error");
                if (ModuleCRC != CalculateModuleCRC(data, ModuleSize-3)) throw new InvalidFileException(filename, "Invalid module CRC");
            }
        }
Beispiel #14
0
 internal OS9File(OS9FileInfo fileinfo)
 {
     FileInfo = fileinfo;
 }
Beispiel #15
0
 internal OS9DataFile(OS9FileInfo fileinfo, byte[] data) : base(fileinfo)
 {
     this.data = data;
 }