The File folio, in cooperation with the various file systems, provides the services needed to access filesystem-oriented external storage; for example, reading files from a CD-ROM, or writing files to the 3DO NVRAM (non-volatile RAM).
When you open a file using the File folio OpenDiskFile()
function, the item that is returned serves as a handle to the file. The Item
is of type Device. This enables communication to the filesystem that controls this file using the standard Portfolio I/O model.
When you send a command to a file device, the file system responsible for the file wakes up and executes the command. Therefore, the file device is only a pseudo-device, serving as a gateway to the underlying filesystem.
The File folio provides many high-level functions to control file systems. For example, you can create files using the CreateFile()
function, or you can delete files using the DeleteFile()
function. These File folio functions are merely wrappers for file system commands. The functions internally create file devices and send commands to the device to perform work.
This section explains the various commands you can send to a file device. It is often much easier to use the higher-level File folio functions to interact with the file system. However, there are some operations that can only be performed by interfacing to the file device directly.
Once you open a file, you can obtain information about the filesystem the file resides on. This is done by using the FILECMD_FSSTAT
command.
IOInfo ioInfo; FileSystemStat fsStat; memset(&ioInfo,0,sizeof(ioInfo)); ioInfo.ioi_Command = FILECMD_FSSTAT; ioInfo.ioi_Recv.iob_Buffer = &fsStat; ioInfo.ioi_Recv.iob_Len = sizeof(FileSystemStat);
Once the command returns successfully, you can look at the fields in the fsStat structure for the status information. The fst_BitMap
field of the FileSystemStat structure indicates which fields in the rest of the structure are valid and can be examined. Different file systems cannot always provide all the information in a FileSystemStat structure. For example, if the FSSTAT_SIZE
bit is set in fst_BitMap
, it means the fst_Size
field of the FileSystemStat structure is valid.
The fields in the FileSystemStat structure are:
Once you open a file, you can obtain information about the file by using the CMD_STATUS
command.
IOInfo ioInfo; FileStatus fStat; memset(&ioInfo,0,sizeof(ioInfo)); ioInfo.ioi_Command = CMD_STATUS; ioInfo.ioi_Recv.iob_Buffer = &fStat; ioInfo.ioi_Recv.iob_Len = sizeof(FileStatus);
Once the command completes successfully, you can look at the fields in the fStat structure for the status information. Fields of interest are:
To create a file, use the File folio's CreateFile()
function. You supply the path name of the file to create, and the function does the necessary work to create a new file entry on the filesystem.
To delete an existing file, use the File folio's DeleteFile()
function. You supply it the path name of the file to delete, and the function does the necessary work to remove the file's entry from the filesystem.
Before you can write data to a file, you must allocate enough free blocks in the file to hold the data to be written. This is done by using the FILECMD_ALLOCBLOCKS
command.
IOInfo ioInfo; memset(&ioInfo,0,sizeof(ioInfo)); ioInfo.ioi_Command = FILECMD_ALLOCBLOCKS; ioInfo.ioi_Offset = numBlocks;
The numBlocks
variable contains the number of blocks by which to extend the file. If this value is negative, the size of the file is reduced by the specified number of blocks.
You must use the CMD_WRITE
command to write data to a file. All write operations must be performed in full blocks. The size of the blocks can be obtained by sending a CMD_STATUS
command to the file device. The write operation must also be aligned on a block boundary within the file.
IOInfo ioInfo; memset(&ioInfo,0,sizeof(ioInfo)); ioInfo.ioi_Command = CMD_WRITE; ioInfo.ioi_Offset = blockOffset; ioInfo.ioi_Send.iob_Buffer = dataAddress; ioInfo.ioi_Send.iob_Len = numBytes;
The blockOffset
field indicates the offset in blocks from the beginning of the file where the data is to be written. The dataAddress
value points to the data that is to be written. Finally, the numBytes
value indicates the number of bytes to write out. This value must be an even multiple of the block size for the file.
Once you are done writing data to a file, you must mark the end of the file using the FILECMD_SETEOF
command. This command tells the filesystem how many useful bytes of data are in the file. Because you can only transfer data in terms of blocks, sending this command tells the filesystem how many bytes of the last written block are useful bytes.
IOInfo ioInfo; memset(&ioInfo,0,sizeof(ioInfo)); ioInfo.ioi_Command = FILECMD_SETEOF; ioInfo.ioi_Offset = numBytesInFile;
Reading information from a file is done much the same way you write information to a file. You must supply the offset in blocks where to start reading data, and the number of bytes of data to read.
IOInfo ioInfo; memset(&ioInfo,0,sizeof(ioInfo)); ioInfo.ioi_Command = CMD_READ; ioInfo.ioi_Offset = blockOffset; ioInfo.ioi_Recv.iob_Buffer = dataAddress; ioInfo.ioi_Recv.iob_Len = numBytes;
The blockOffset
value indicates the offset in blocks from the beginning of the file from which data is read. dataAddress
indicates an address in memory where the data will be copied once read from the filesystem. Finally, numBytes
contains the number of bytes to read. This number must be an even multiple of the block size of the file.
The OpenDiskFile()
function
opens a directories. You can then use the FILECMD_READDIR
command to scan the directory and obtain information about files in the directory.
IOInfo ioInfo; DirectoryEntry dirEntry; memset(&ioInfo,0,sizeof(ioInfo)); ioInfo.ioi_Command = FILECMD_READDIR; ioInfo.ioi_Offset = fileNum; ioInfo.ioi_Recv.iob_Buffer = &dirEntry; ioInfo.ioi_Recv.iob_Len = sizeof(DirectoryEntry);
The fileNum
value indicates the number of the file within the directory to read. You start with file 0, and keep going until the I/O cannot be completed because there are no more files. The dirEntry structure will be filled out with information about the specified file.
Once you have an open file, you may need to determine the exact path to reach this file. The FILECMD_GETPATH
command determines the exact path to an open file.
IOInfo ioInfo; char path[FILESYSTEM_MAX_PATH_LEN]; memset(&ioInfo,0,sizeof(ioInfo)); ioInfo.ioi_Command = FILECMD_GETPATH; ioInfo.ioi_Recv.iob_Buffer = path; ioInfo.ioi_Recv.iob_Len = sizeof(path);
Once the command completes successfully, the path variable contains a complete unambiguous path to reach the file. You can then use this path to issue another OpenDiskFile()
command or a DeleteFile()
command.