#include #include #include #include #include "directory.h" #define TRUE 1 #define FALSE 0 /*Definitions for entryNode attribute bits*/ #define READ 0x1 #define WRITE 0x2 #define LINK 0x4000 #define DIR 0x8000 /*Constant String imports from dirmain.c*/ extern const char * create; extern const char * append; extern const char * mk_dir; extern const char * ln; extern const char * cd; extern const char * rm; extern const char * rm_dir; extern const char * mv; extern const char * pwd; extern const char * ls; extern const char * cat; extern const char * setread; extern const char * setwrite; /*The following define error strings your program must use on error conditions*/ /*Do not redefine these or use any additional error messages*/ const char * file_exists = "File already exists"; const char * no_such_file = "No such file or directory."; const char * not_a_directory = "Not a directory."; const char * is_a_directory = "Is a directory."; const char * directory_not_empty = "Directory not empty."; const char * operation_not_permitted = "Operation not permitted."; const char * links_must_be_absolute = "Soft link targets must be absolute"; /*message for running out of memory*/ const char * out_of_memory = "61C FS has run out of memory. Program aborting\n"; struct entryNode { char * name; struct entryNode * next; /* sibling */ uint16_t attributes; /* attribute definitions: bit 0 set - READABLE bit 1 set - WRITABLE bit 14 set - Soft link (if set, ignore other bits) bit 15 set - Directory */ union { char * contents; /*for files*/ struct entryNode * entryList; /*for directories*/ char * shortcutReference; /*for softlinks*/ } entry; }; struct entryNode * root; /* Helper functions */ struct entryNode * locateItem (char *,struct entryNode *, uint8_t); struct entryNode * resolvePath(char **); char * copyString(char * str); void * safeMalloc(size_t cnt); /* Generate an initialized file system (an empty directory named "/") and store it in the root variable. */ void initialFileSystem ( ) { /* YOU SUPPLY THE BODY FOR THIS FUNCTION; */ } /* implements the "create" command (one argument; not in standard UNIX) */ void createFile (char * fileName) { char * oldFileName = copyString(fileName); /*Create a file inside directory*/ struct entryNode * directory = resolvePath(&fileName); if (directory == NULL){ printf("%s: %s: %s\n", create, oldFileName, no_such_file); } else if (locateItem (fileName,directory,FALSE) != NULL) { printf ("%s: %s: %s\n", create, oldFileName, file_exists); } else { /* YOU SUPPLY THIS CODE. */ } free (oldFileName); } /* implements the "append" command (one argument; not in standard UNIX) */ void appendFile (char * fileName) { char * oldFileName = copyString(fileName); /*Create a file inside directory*/ struct entryNode * directory = resolvePath(&fileName); if (directory == NULL){ printf("%s: %s: %s\n", append, oldFileName, no_such_file); } else{ struct entryNode * file = locateItem (fileName,directory,TRUE); if (file == NULL) { printf ("%s: %s: %s\n", append, oldFileName, no_such_file); } else { /* YOU SUPPLY THIS CODE. ERROR CHECKING IS NEEDED*/ } } free (oldFileName); } /* implements the "mkdir" command (one argument; no options) */ void createDir (char * dirName) { char * oldDirName = copyString(dirName); struct entryNode * directory = resolvePath(&dirName); if (directory == NULL){ printf("%s: %s: %s\n", mk_dir, oldDirName, no_such_file); } else if (locateItem (dirName,directory,FALSE) != NULL) { printf ("%s: %s: %s\n", mk_dir, oldDirName, file_exists); } else { /* YOU SUPPLY THIS CODE. */ } free (oldDirName); } /* implements the "cd" command (one argument, which includes ".." or "/" (or combinations of .., /, files, etc.); no options) See Project Description for more details about cd. Remember that if there is any error in the PATH specified by dirName, the working directory MUST remain the same */ void newWorkingDir (char * dirName) { /* YOU SUPPLY THIS CODE. It should be rather similar to your resolvePath code */ } /* implements the "ln" command (two arguments, no options) */ void createSoftLink (char * targetName, char * linkName){ char * oldLinkName = copyString(linkName); struct entryNode * linkDirectory = resolvePath(&linkName); if (linkDirectory == NULL) { printf("%s: %s: %s\n", ln, oldLinkName, no_such_file); } else if (*linkName == '\0' || strcmp(linkName,".") == 0 || strcmp(linkName,"..") == 0){ printf ("%s: %s: %s\n", ln, oldLinkName, file_exists); } else if (locateItem (linkName,linkDirectory,FALSE) != NULL){ printf ("%s: %s: %s\n", ln, oldLinkName, file_exists); } else if (*targetName != '/'){ /*prevent relative links*/ printf ("%s: %s: %s\n", ln, targetName, links_must_be_absolute); } else{ struct entryNode * file = safeMalloc(sizeof(struct entryNode)); file->name = copyString(linkName); file->attributes = LINK | READ | WRITE; file->entry.shortcutReference = copyString(targetName); file->next = NULL; /* YOU SUPPLY THIS CODE. You just need to insert file into the entryList of linkDirectory */ } free (oldLinkName); } /* implements the "rm" command (one argument, unlike standard UNIX; no options) */ void removeFile (char * fileName) { char * oldFileName = copyString(fileName); struct entryNode * file; struct entryNode * directory = resolvePath(&fileName); if (directory == NULL){ printf("%s: %s: %s\n", rm, oldFileName, no_such_file); } else { file = locateItem (fileName,directory,FALSE); if (file == NULL) { printf ("%s: %s: %s\n", rm, fileName, no_such_file); } else{ /* YOU SUPPLY THIS CODE. THIS CAN ONLY REMOVE FILES AND SOFTLINKS */ } } free (oldFileName); } /* implements the "rmdir" command (one argument, unlike standard UNIX; no options) */ void removeDir (char * dirName) { char * oldDirName = copyString(dirName); struct entryNode * dirParent =resolvePath(&dirName); if (dirParent == NULL){ printf("%s: %s: %s\n", rm_dir, oldDirName, no_such_file); } else { struct entryNode *dir = locateItem (dirName,dirParent,FALSE); if (dir == NULL) { printf ("%s: %s: %s\n", rm_dir, dirName, no_such_file); } else { /* YOU SUPPLY THIS CODE. DIR MUST BE A DIRECTORY AND IT MUST BE EMPTY */ } } free (oldDirName); } /* implements the "mv" command (two arguments, no options) */ void moveEntry (char * from, char * to) { char * oldFrom = copyString(from); char * oldTo = copyString(to); struct entryNode * entryToMove; struct entryNode * newParent; struct entryNode * fromDirectory = resolvePath(&from); struct entryNode * toDirectory = resolvePath(&to); if (fromDirectory == NULL){ printf("%s: %s: %s\n", mv, oldFrom, no_such_file); } else if (toDirectory == NULL){ printf("%s: %s: %s\n", mv, oldTo, no_such_file); } else if (strcmp(to,".") == 0 || strcmp(to,"..") == 0){ printf ("%s: %s: %s\n", mv, oldTo, file_exists); } else { entryToMove = locateItem (from,fromDirectory,FALSE); if (entryToMove == NULL) { printf ("%s: %s: %s\n", mv, oldFrom, no_such_file); } else if ((entryToMove->attributes & DIR) != 0) { printf ("%s: %s: %s\n", mv, oldFrom, is_a_directory); } else { if (*to == '\0'){ /*directory reference*/ newParent = toDirectory; } else { /*file name*/ newParent = locateItem (to,toDirectory,FALSE); if (newParent != NULL){ printf ("%s: %s: %s\n", mv, oldTo, file_exists); free(oldFrom); free(oldTo); return; } else { newParent = toDirectory; free(entryToMove->name); entryToMove->name = copyString(to); } } /* YOU SUPPLY THIS CODE. You must do two things here: First, remove entryToMove from the entryList of 'fromDirectory' Then add it into the entryList of 'newParent' Be sure you understand why this is the appropriate behavior */ } } free (oldFrom); free (oldTo); } /* implements the "pwd" command (no arguments; no options) Remember, that softlink's, NOT the target directory's, name must be printed See the Project Spec for more information */ void printWorkingDir () { /* YOU SUPPLY THIS CODE.*/ } /* implements the "ls" command (0 or 1 argument, unlike standard UNIX; no options) */ /* Behavior is as follows: if no arguments, list the names of the files in wd; Otherwise echo all files in wd that match (see description about use of '?') print ls: ___: No such file or directory if no files do match */ void listWorkingDir () { /* YOU SUPPLY THIS CODE.*/ } void listWithinWorkingDir (char * name) { /* YOU SUPPLY THIS CODE.*/ } /* implements the "cat" command (arbitrary number of arguments, which all must name text files; no options) */ /* This function prints the contents of a single file. */ void listFileContents (char * name) { char * oldName = copyString(name); struct entryNode * file; struct entryNode * directory = resolvePath(&name); if (directory == NULL){ printf("%s: %s: %s\n", cat, oldName, no_such_file); } else { file = locateItem (name,directory,TRUE); if (file == NULL) { printf ("%s: %s: %s\n", cat, oldName, no_such_file); } else { if ((file->attributes & DIR) != 0){ printf ("%s: %s: %s\n", cat, oldName, is_a_directory); } else if ((file->attributes & READ) == 0){ printf ("%s: %s: %s\n", cat, oldName, operation_not_permitted); } else{ printf("%s",file->entry.contents); } } } free (oldName); } /* implements the "setRead" command (two arguments; not in standard UNIX)*/ /* This function modifies the READABLE attribute of a file or directory */ void modifyReadable (int readable, char * name) { char * oldName = copyString(name); struct entryNode * file; struct entryNode * directory = resolvePath(&name); if (directory == NULL){ printf("%s: %s: %s\n", setread, oldName, no_such_file); } else { file = locateItem (name,directory,TRUE); if (file == NULL) { printf ("%s: %s: %s\n", setread, oldName, no_such_file); } else { /* YOU SUPPLY THIS CODE.*/ } } free (oldName); } /* implements the "setWrite" command (two arguments; not in standard UNIX)*/ /* This function modifies the WRITABLE attribute of a file or directory */ void modifyWritable (int writable, char * name) { char * oldName = copyString(name); struct entryNode * file; struct entryNode * directory = resolvePath(&name); if (directory == NULL){ printf("%s: %s: %s\n", setwrite, oldName, no_such_file); } else { file = locateItem (name,directory,TRUE); if (file == NULL) { printf ("%s: %s: %s\n", setwrite, oldName, no_such_file); } else { /* YOU SUPPLY THIS CODE.*/ } } free (oldName); } /* Helper functions that you should implement and use*/ /* copyString: Takes in a string and returns a copy of it that has been allocated into dynamic storage */ char * copyString(char * str){ int len = strlen(str) + 1; char * newString = safeMalloc(len*sizeof(char)); strcpy(newString,str); return newString; } /* safeMalloc: Simply calls malloc. If malloc returns NULL, program prints out error message and exits*/ void * safeMalloc(size_t cnt){ void * retVal = malloc(cnt); if (retVal == NULL){ printf(out_of_memory); exit(1); } return retVal; } /* Return a pointer to the entry with the given name in directory, or NULL if no such entry exists. The name cannot contain the '/' character If name refers to a softlink and resolveLink is TRUE - this function will return the target of the softlink (recursively, as the target itself may also be a softlink); Otherwise, if resolveLink is FALSE, the softlink entryNode itself will be returned */ struct entryNode * locateItem (char * name, struct entryNode * directory, uint8_t resolveLink) { /* YOU SUPPLY THIS CODE.*/ return NULL; } /* Resolve a collection of directory names delimited by the '/' character relative to the current working directory *PathName is an relative path (a/..../y/z) or an absolute path (/a/.../y/z). When done, a pointer to the directory specified by "a/.../y" is returned and *pathName is advanced to just be z. To "resolve" this path, each item seperated by the "/" is interpretted as its own directory name This function effectively walks through the directories specified by each successive item from left to right to arrive at directory "y". NOTE: The working directory MUST remain the same after this function ends. Note2: Softlink directories MUST be resolved here, as a, y, etc. may be softlinks. If the path cannot be resolved, NULL is returned and *pathName is undefined If a path comes in with a "/" at the end, **pathName will be '\0' when done You may determine the behavior for the pathName that ends with ".." and ".". It may be a good idea to resolve those completely here. */ struct entryNode * resolvePath(char ** pathName){ /* YOU SUPPLY THIS CODE.*/ return NULL; }