# Examples

This section provides code listings of programs that use the File folio and the file system.

## Using NVRAM

Example 1 is a program listing that demonstrates how to save data to a file in NVRAM or to any other writable device.

The `SaveDataFile()` function takes a name, a data pointer, and a size indicator, and creates a file with that name and size, containing the supplied data.

Writing data to a file requires a bit of finesse. Data can only be written in blocks, not bytes. So if the data being written out is not a multiple of the target device's block size, the last chunk of data must be copied to a buffer which is the size of a block, and the block can then be written out.

Example 1: Saving data to a file in NVRAM (nvram.c).

``

    #include "types.h"
    #include "filesystem.h"
    #include "filefunctions.h"
    #include "io.h"
    #include "string.h"
    #include "mem.h"
    #include "stdio.h"
    #include "operror.h"

    /*****************************************************************************/

    Err SaveDataFile(const char *name, void *data, uint32 dataSize)
    {
    Item       fileItem;
    Item       ioReqItem;
    IOInfo     ioInfo;
    void      *temp;
    Err        result;
    uint32     numBlocks;
    uint32     blockSize;
    uint32     roundedSize;
    FileStatus status;

        /* get rid of the file if it was already there */
        DeleteFile((char *)name);

        /* create the file again... */
        result = CreateFile((char *)name);
        if (result >= 0)
        {
            /* open the file for access */
            fileItem = OpenDiskFile((char *)name);
            if (fileItem >= 0)
            {
                /* create an IOReq to communicate with the file */
                ioReqItem = CreateIOReq(NULL, 0, fileItem, 0);
                if (ioReqItem >= 0)
                {
                    /* get the block size of the file */
                    memset(&ioInfo, 0, sizeof(IOInfo));
                    ioInfo.ioi_Command         = CMD_STATUS;
                    ioInfo.ioi_Recv.iob_Buffer = &status;
                    ioInfo.ioi_Recv.iob_Len    = sizeof(FileStatus);
                    result = DoIO(ioReqItem, &ioInfo);
                    if (result >= 0)
                    {
                        blockSize = status.fs.ds_DeviceBlockSize;
                        numBlocks = (dataSize + blockSize - 1) / blockSize;

                        /* allocate the blocks we need for this file */
                        ioInfo.ioi_Command         = FILECMD_ALLOCBLOCKS;
                        ioInfo.ioi_Recv.iob_Buffer = NULL;
                        ioInfo.ioi_Recv.iob_Len    = 0;
                        ioInfo.ioi_Offset          = numBlocks;
                        result = DoIO(ioReqItem, &ioInfo);
                        if (result >= 0)
                        {
                            /* tell the system how many bytes for this file */
                            memset(&ioInfo,0,sizeof(IOInfo));
                            ioInfo.ioi_Command         = FILECMD_SETEOF;
                            ioInfo.ioi_Offset          = dataSize;
                            result = DoIO(ioReqItem, &ioInfo);
                            if (result >= 0)
                            {
                                roundedSize = 0;
                                if (dataSize >= blockSize)
                                {
                                    /* If we have more than one block's worth of
                                     * data, write as much of it as possible.
                                     */

                                    roundedSize = (dataSize / blockSize) * blockSize;
                                    ioInfo.ioi_Command         = CMD_WRITE;
                                    ioInfo.ioi_Send.iob_Buffer = (void *)data;
                                    ioInfo.ioi_Send.iob_Len    = roundedSize;
                                    ioInfo.ioi_Offset          = 0;
                                    result = DoIO(ioReqItem, &ioInfo);

                                    data      = (void *)((uint32)data + roundedSize);
                                    dataSize -= roundedSize;
                                }

                                if ((result >= 0) && dataSize)
                                {
                                    /* If the amount of data left isn't as large
                                     * as a whole block, we must allocate a memory
                                     * buffer of the size of the block, copy the
                                     * rest of the data into it, and write the
                                     * buffer to disk.
                                     */

                                    temp = AllocMem(blockSize,MEMTYPE_DMA |

                                                  MEMTYPE_FILL);
                                    if (temp)
                                    {
                                        memcpy(temp,data,dataSize);
                                        ioInfo.ioi_Command         = CMD_WRITE;
                                        ioInfo.ioi_Send.iob_Buffer = temp;
                                        ioInfo.ioi_Send.iob_Len    = blockSize;
                                        ioInfo.ioi_Offset          = roundedSize;
                                        result = DoIO(ioReqItem, &ioInfo);

                                        FreeMem(temp,blockSize);
                                    }
                                    else
                                    {
                                        result = NOMEM;
                                    }
                                }
                            }
                        }
                    }
                    DeleteIOReq(ioReqItem);
                }
                else
                {
                    result = ioReqItem;
                }
                CloseDiskFile(fileItem);
            }
            else
            {
                result = fileItem;
            }

            /* don't leave a potentially corrupt file around... */
            if (result < 0)
                DeleteFile((char *)name);
        }

        return (result);
    }

    /*****************************************************************************/

    static char testData[] = "This is some test data to save out";

    int main(int32 argc, char **argv)
    {
    Err err;

        err = SaveDataFile("/NVRAM/test",testData,sizeof(testData));
        if (err < 0)
        {
            printf("Could not save data: ");
            PrintfSysErr(err);
        }
    }

## Displaying Contents of a File

Example 2 is a program listing that demonstrates how to read a file using the byte stream calls, and output its contents to the debugging terminal.

Example 2: Displaying the contents of a 3DO file (type.c)

``

    #include "types.h"
    #include "stdio.h"
    #include "filestream.h"
    #include "filestreamfunctions.h"

    /*****************************************************************************/

    #define MAXLINE 1024

    static void Type(const char *path)
    {
    Stream *stream;
    char    c;
    char    line[MAXLINE];
    int32   linelen;
    int32   lines;
    int32   endOfLine, endOfFile;

        /* Open the file as a byte-stream. A buffer size of zero is
         * specified, which permits the File folio to choose an appropriate
         * amount of buffer space based on the file's actual block size.
         */

        stream = OpenDiskStream((char *)path, 0);
        if (!stream)
        {
            printf("File '%s' could not be opened\n", path);
            return;
        }

        lines     = 0;
        linelen   = 0;
        endOfLine = FALSE;
        endOfFile = FALSE;

        /* Spin through a loop, grabbing one byte each time.
         *
         * A more efficient implementation would grab bytes
         * in larger batches (e.g. 128 bytes at a time) and parse them in a
         * more reasonable fashion.
         */

        while (!endOfFile)
        {
            if (ReadDiskStream(stream, &c, 1) < 1)
            {
                endOfFile = TRUE;
                endOfLine = TRUE;
                line[linelen] = '\0';
            }
            else if (c == '\r' || c == '\n')
            {
                endOfLine = TRUE;
                line[linelen] = '\0';
            }
            else if (linelen < MAXLINE-1)
            {
                line[linelen++] = c;
            }

            if (endOfLine)
            {
                printf("%s\n", line);
                linelen = 0;
                lines++;
                endOfLine = FALSE;
            }
        }

        printf("\n%d lines processed\n\n", lines);

        /* close the file */
        CloseDiskStream(stream);
    }

    /*****************************************************************************/

    int main(int32 argc, char **argv)
    {
    int32 i;

        if (argc < 2)
        {
            printf("Usage: type file1 [file2] [file3] [...]\n");
        }
        else
        {
            /* go through all the arguments */
            for (i = 1; i < argc; i++)
                Type(argv[i]);
        }

        return 0;
    }

## Scanning the File System

Example 3 is a program listing of an application that scans the file system.

Example 3: Scanning the file system (Walker.c).

``

    #include "types.h"
    #include "io.h"
    #include "stdio.h"
    #include "operror.h"
    #include "filesystem.h"
    #include "directory.h"
    #include "directoryfunctions.h"
    #include "filefunctions.h"

    /*****************************************************************************/

    static void TraverseDirectory(Item dirItem)
    {
    Directory      *dir;
    DirectoryEntry  de;
    Item            subDirItem;
    int32           entry;

        dir = OpenDirectoryItem(dirItem);
        if (dir)
        {
            entry = 1;
            while (ReadDirectory(dir, &de) >= 0)
            {
                printf("Entry #%d:\n", entry);
                printf("  file '%s', type 0x%lx, ID 0x%lx",
                        de.de_FileName, de.de_Type,
                        de.de_UniqueIdentifier);
                printf(", flags 0x%lx\n", de.de_Flags);
                printf("  %d bytes, %d block(s) of %d byte(s) each\n",
                        de.de_ByteCount,
                        de.de_BlockCount, de.de_BlockSize);
                printf("  %d avatar(s)", de.de_AvatarCount);
                printf("\n\n");

                if (de.de_Flags & FILE_IS_DIRECTORY)
                {
                    subDirItem = OpenDiskFileInDir(dirItem, de.de_FileName);
                    if (subDirItem >= 0)
                    {
                        printf("********** RECURSE **********\n\n");
                        TraverseDirectory(subDirItem);
                        printf("******* END RECURSION *******\n\n");
                    }
                    else
                    {
                        printf("***  RECURSION FAILED  ***\n\n");
                    }
                }
                entry++;
            }
            CloseDirectory(dir);
        }
        else
        {
            printf("OpenDirectoryItem() failed\n");
            CloseDiskFile(dirItem);
        }
    }

    /*****************************************************************************/

    static Err Walk(const char *path)
    {
    Item startItem;

        startItem = OpenDiskFile((char *)path);
        if (startItem >= 0)
        {
            printf("\nRecursive directory scan from %s\n\n", path);
            TraverseDirectory(startItem);
            printf("End of %s has been reached\n\n", path);
            return 0;
        }
        else
        {
            printf("OpenDiskFile(\"%s\") failed: ",path);
            PrintfSysErr(startItem);
            return startItem;
        }
    }

    /*****************************************************************************/

    int main(int32 argc, char **argv)
    {
    int i;

        if (argc <= 1)
        {
            /* if no directory name was given, scan the current directory */
            Walk(".");
        }
        else
        {
            for (i = 1; i < argc; i++)
                Walk(argv[i]);
        }

        return 0;
    }

## Listing the Contents of a Directory

Example 4 is a code listing that list the contents of a directory.

Example 4: Listing a directory (ls.c)

``

    **/

    #include "types.h"
    #include "stdio.h"
    #include "string.h"
    #include "io.h"
    #include "operror.h"
    #include "filesystem.h"
    #include "filefunctions.h"
    #include "directory.h"
    #include "directoryfunctions.h"

    /*****************************************************************************/

    static void ListDirectory(const char *path)
    {
    Directory      *dir;
    DirectoryEntry  de;
    Item            ioReqItem;
    int32           entry;
    int32           err;
    char            fullPath[FILESYSTEM_MAX_PATH_LEN];
    IOInfo          ioInfo;
    Item            dirItem;

        /* open the directory for access */
        dirItem = OpenDiskFile((char *)path);
        if (dirItem >= 0)
        {
            /* create an IOReq for the directory */
            ioReqItem = CreateIOReq(NULL, 0, dirItem, 0);
            if (ioReqItem >= 0)
            {
                /* Ask the directory its full name. This will expand any aliases
                 * given on the command-line into fully qualified pathnames.
                 */
                memset(&ioInfo, 0, sizeof(ioInfo));
                ioInfo.ioi_Command         = FILECMD_GETPATH;
                ioInfo.ioi_Recv.iob_Buffer = fullPath;
                ioInfo.ioi_Recv.iob_Len    = sizeof(fullPath);
                err = DoIO(ioReqItem, &ioInfo);
                if (err >= 0)
                {
                    /* now open the directory for scanning */
                    dir = OpenDirectoryPath((char *)path);
                    if (dir)
                    {
                        printf("\nContents of directory %s:\n\n", fullPath);
                        entry = 1;
                        while (ReadDirectory(dir, &de) >= 0)
                        {
                            printf("%5s", (char *) &de.de_Type);
                            printf(" %8d", de.de_ByteCount);
                            printf(" %4d*%4d", de.de_BlockCount, de.de_BlockSize);
                            printf(" %3d", de.de_AvatarCount);
                            printf(" %8x", de.de_Flags);
                            printf(" %s\n", de.de_FileName);
                            entry++;
                        }
                        CloseDirectory(dir);

                        printf("\nEnd of directory\n\n");
                    }
                    else
                    {
                        printf("OpenDirectory(\"%s\") failed\n",fullPath);
                    }
                }
                else
                {
                    printf("Unable to get full path name for '%s': ",path);
                    PrintfSysErr(err);
                }
                DeleteIOReq(ioReqItem);
            }
            else
            {
                printf("CreateIOReq() failed: ");
                PrintfSysErr(ioReqItem);
            }
            CloseDiskFile(dirItem);
        }
        else
        {
            printf("OpenDiskFile(\"%s\") failed: ",path);
            PrintfSysErr(dirItem);
        }
    }

    /*****************************************************************************/

    int main(int32 argc, char **argv)
    {
    int32 i;

        if (argc <= 1)
        {
            /* if no directory name was given, scan the current directory */
            ListDirectory(".");
        }
        else
        {
            /* go through all the arguments */
            for (i = 1; i < argc; i++)
                ListDirectory(argv[i]);
        }

        return 0;
    }