In this assignment, you will be implementing a simple file

In this assignment, you will be implementing a simple file

In this assignment, you will be implementing a simple file system over a simulated disk.Copy the source code files from/home/fac/lillethd/cpsc3500/projects/filesys to get started. A Makefileis also provided.Since we do not have a raw physical disk for each of you, we will use a single (large) Unix file toemulate a disk. The file should be thought of as an array of blocks. In this assignment, there are1,024 blocks (numbered from 0 to 1023) and each block is 128 bytes.The provided code implements a layered architecture as follows:Shell(Shell.cpp and Shell.h)Processes commands from the command line.File System(FileSys.cpp and FileSys.h)Provides an interface for file system commands.(You will implement your solution here.)Basic File System(BasicFileSys.cpp and BasicFileSys.h)A low-level interface that interacts with the disk.Disk(Disk.cpp and Disk.h)Represents a “virtual” disk that is containedwithin a file.Each of the four layers is implemented using a class. The class contains (“has-a”) a singleinstance of the lower layer. For instance, the file system class has an instance of the basic filesystem.Your task is to implement the following file system commands in the File System layer.FileSys.cpp and FileSys.h are the only files you should modify to do this. It is recommended toimplement these functions in the order they appear:mkdir Creates an empty subdirectory in the current directory.ls List the contents of the current directory. Directories shouldhave a ‘/’ suffix such as ‘myDir/’. Files do not have a suffix.cd Change to specified directory. The directory must be asubdirectory in the current directory. (No paths or “..” areallowed.)home Switch to the home directory.rmdir Removes a subdirectory. The subdirectory must be empty.create Creates an empty file of the filename in the current directory.An empty file consists of an inode and no data blocks.append Appends the data to the file. Data should be appended in amanner to first fill the last data block as much as possible andthen allocating new block(s) ONLY if more space is needed.(i.e., Make sure you never have an empty last block in the file– that would be wasteful!) More information about theformat of data files is described later.stat Displays stats for the given file or directory. The preciseformat is described later in this document.cat Display the contents of the file to the screen. Print a newlinewhen completed.tail Display the last N bytes of the file to the screen. Print anewline when completed. (If N >= file size, print the whole filejust as with the cat command.)For example, if foo.txt contains “abcdef” then the command“tail foo.txt 3” would output “def”.rm Remove a file from the directory, reclaim all of its blocksincluding its inode. Cannot remove directories.The above list shows the shell commands. You will be implementing these commands in the filesystem (FileSys.cpp). Each command has a corresponding function with the same name.Commands that require a file name or directory name have a name parameter. The appendfunction also has a second parameter for the data, and tail has a second parameter for thenumber of bytes to print.The only files that requires modification are FileSys.cpp and FileSys.h. In FileSys.h, you are onlyallowed to modify the private section of the class. You can add extra data members and privatemember functions.Basic File System Interface RoutinesTo implement these commands, you will need to utilize routines provided by the basic filesystem. The file system class contains a basic file system interface, specifically private datamember bfs. Here is a description of the provided routines you will need to use:// Gets a free block from the disk.short get_free_block();// Reclaims block making it available for future use.void reclaim_block(short block_num);// Reads block from disk. Output parameter block points to new block.void read_block(short block_num, void *block);// Writes block to disk. Input block points to block to write.void write_block(short block_num, void *block);Note that basic file system also provides code for mounting (initializing) and unmounting(cleaning up) the basic file system. The basic file system is already mounted and unmounted inthe provided code so there is no need to use the mount and unmount functions in your code.File System BlocksThere are two types of files: data files (that store a sequence of characters) and directories.Data files consist of an inode and zero or more data blocks. Directories consist of a singledirectory block that stores the contents of the directory.There are four types of blocks used in the file system:• Superblock: There is only one superblock on the disk and that is always block 0. Itcontains a bitmap on what disk blocks are free. (The superblock is used by the Basic FileSystem to implement get_free_block() and reclaim_block() – you shouldn’t have totouch it, but be careful not to corrupt it by writing to it by mistake.)• Directories: Represents a directory. The first field is a magic number which is used todistinguish between directories and inodes. The second field stores the number of fileslocated in the directory. The remaining space is used to store the file entries. Each entryconsists of a name and a block number (the directory block for directories and the inodeblock for data files). Unused entries are indicated by having a block number of 0 (weknow that’s not a valid block because 0 is reserved for the superblock). Block 1 alwayscontains the directory for the “home” directory.• Inodes: Represents an index block for a data file. In this assignment, only direct indexpointers are used. The first field is a magic number which is used to distinguish betweendirectories and inodes. The second field is the size of the file (in bytes). The remainingspace consists of an array of indices to data blocks of the file. Use 0 to represent unusedpointer entries (note that files cannot access the superblock).• Data blocks: Blocks currently used to store data in files.The different blocks are defined using these structures defined in Blocks.h. These structures areall BLOCK_SIZE (128) bytes.// Superblock – keeps track of which blocks are used in the filesystem.// Block 0 is the only super block in the system.struct superblock_t { unsigned char bitmap[BLOCK_SIZE]; // bitmap of free blocks};// Directory block – represents a directorystruct dirblock_t { unsigned int magic; // magic number, must be DIR_MAGIC_NUM unsigned int num_entries; // number of files in directory struct { char name[MAX_FNAME_SIZE + 1]; // file name (extra space for null) short block_num; // block number of file (0 – unused) } dir_entries[MAX_DIR_ENTRIES]; // list of directory entries};// Inode – index node for a data filestruct inode_t { unsigned int magic; // magic number, must be INODE_MAGIC_NUM unsigned int size; // file size in bytes short blocks[MAX_DATA_BLOCKS]; // array of direct indices to data blocks};// Data block – stores data for a data filestruct datablock_t { char data[BLOCK_SIZE]; // data (BLOCK_SIZE bytes)};You will use the basic file system interface routines to read and write these blocks. For instance,to read the home directory (block 1):struct dirblock_t dirblock;bfs.read_block(1, (void *) &dirblock);In some cases, you will not know whether the block is a directory or an inode. To address thisissue, both the directory and inode contain a magic number located as the first field (same spotin memory). For an unknown block, read the block as a directory block (or an inode block – itdoesn’t matter). Then read the magic number. If the magic number is DIR_MAGIC_NUM, then itis a directory. If the magic number is INODE_MAGIC_NUM, then it is an inode.TIP: Create a private method is_directory than returns true if the block corresponds to adirectory and false otherwise.Since the blocks are a fixed size, there are limits on the size of files, size of file names, and thenumber of entries in a directory. These constants, along with other file system parameters, arealso defined in Blocks.h.Data File FormatHere are the rules concerning data files:• Data files consist of a single index block and zero or more data blocks. (An empty fileuses 0 data blocks.)• The command create creates an empty file. This creates an inode but no data blocks,since the file is empty.• The data string passed into append is null terminated, you can use strlen() todetermine its size.• When appending data using append, do not add a null termination character. Ifappending “ABC” to the file, exactly three characters are appended. Do not store nullcharacters in the file; instead, use the size data member to determine the end of thefile.• When appending data, you need to add characters where you left off. If there is room inthe last block, that block needs to be filled before adding a new block. If the data toappend does completely fit in the last block, completely fill in the last block first, thencreate a new data block for the remainder. (No file should ever use a data block that isempty – if the append fits exactly into the last block, then fill the last block and do notallocate a new block.)• There is no limit* on the size of the data to append so it may be necessary to create twoor more data blocks with a single call to append. (* You will have to check for situationswhere the append would exceed the maximum file size, however.)• Only create a new block when it is absolutely necessary to create one. For instance, afile consisting of exactly 128 bytes should have only one (completely full) data block.• Since the data is not null terminated, it is recommended that append copies charactersone at a time and that cat displays characters one at a time. You may be tempted touse C string functions (such as strcpy()) or using In both modes, the disk will be mounted at the beginning of the program. The disk is stored inthe filename “DISK”. If the disk file exists, it will use those disk contents. If the disk file doesnot exist, it will create a new disk file and properly initialize block 0 (superblock) and 1 (homedirectory). The current directory is always the home directory at the start of the program.The disk is persistent across different runs of the program. This can be helpful for testing, sinceyou don’t have to run all your commands in one go. However, in some cases, you may want tostart with a fresh disk; simply remove (delete) the file DISK. The Makefile will alsoautomatically remove the disk when you recompile.Implementation Notes• The size of the block data structures are 128 bytes on cs1 and should be 128 bytes onmany other systems. If you are concerned with portability problems, uncomment thesanity check code at the beginning of main to double check.• Unlike data files, the names of files and subdirectories stored in directories are nullterminated.• Neither get_free_block nor reclaim_block initializes or clears out thecorresponding block in any way. Your implementation should not rely on blocks being”empty”.• Be sure that rmdir and rm actually reclaim blocks that are part of the deleted file ordirectory. This can be tested for by removing a file, creating a new file, and running staton that new file to see if the block is indeed reused. This test is possible sinceget_free_block deterministically returns the free block with the lowest number.Error CheckingThe program must PRINT (output) the following error messages when appropriate:• File is not a directory (Applies to: cd, rmdir)• File is a directory (Applies to: cat, tail, append, rm)• File exists (Applies to: create, mkdir)• File does not exist (Applies to: cd, rmdir, cat, tail,append, rm, stat)• File name is too long (Applies to: create, mkdir)• Disk is full (Applies to: create, mkdir, append)• Directory is full (Applies to: create, mkdir)• Directory is not empty (Applies to: rmdir)• Append exceeds maximum file size (Applies to: append)After printing the error, return from the function. Do NOT exit the program. (Calling exit() orabort() in this assignment is not allowed! After all, you wouldn’t want your OS to blue screen /kernel panic just because of a file system error.) In addition, all errors should be detectedbefore any writes are made to the disk. In an error condition, the disk should not be modified -operations should either complete fully and