/* * Write size bytes from buf into file starting from offset * */ static int cs1550_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { (void) fi; meta_entry attribute = find_correct_directory(path); int index = attribute.file_index; cs1550_directory_entry directory_entry = get_directory_entry( attribute.index_of_directory ); if( index == -1) //check to make sure path exists { size = -1; //error } else if( && offset <= directory_entry.files[index].fsize ) //check that offset is <= to the file size and file size is greater than 0 { //write data FILE *disk; cs1550_disk_block block; //block to be written disk = fopen(".disk", "r+b"); fseek(disk, directory_entry.files[ index ].nStartBlock + offset, SEEK_SET); //seek from start to where the first block is plus offset strcpy(block.data, buf); fwrite(&block.data, sizeof(char), sizeof(buf), disk); //write data size = strlen(buf); //return the length of data fclose(disk); directory_entry.files[index].fsize = size; write_directory_entry( directory_entry, attribute.index_of_directory); } else if( offset <= directory_entry.files[index].fsize ) //append the file
/* * syscall_stat * * Implementation of the stat system call, which obtains information about a * particular file or directory. You should use this as a guideline for how to * implement the other system calls in assignment 3. */ int syscall_stat(const char *path, struct stat *buf) { /* * Ensure the supplied path name and buffer are valid pointers */ if (!valid_string(path)) return -EFAULT; if (!valid_pointer(buf, sizeof(struct stat))) return -EFAULT; /* * Get the directory_entry object for this path from the filesystem */ directory_entry *entry; int r; char abs[PATH_MAX]; relative_to_absolute(abs, current_process->cwd, path, PATH_MAX); if (0 != (r = get_directory_entry(filesystem, abs, &entry))) return r; /* * Set all fields of the stat buffer */ buf->st_mode = entry->mode; buf->st_uid = 0; buf->st_gid = 0; buf->st_size = entry->size; buf->st_mtime = entry->mtime; return 0; }
/* * Called whenever the contents of a directory are desired. Could be from an 'ls' * or could even be when a user hits TAB to do autocompletion */ static int cs1550_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) { //Since we're building with -Wall (all warnings reported) we need //to "use" every parameter, so let's just cast them to void to //satisfy the compiler (void) offset; (void) fi; int res = -ENOENT; //the filler function allows us to add entries to the listing //read the fuse.h file for a description (in the ../include dir) filler(buf, ".", NULL, 0); filler(buf, "..", NULL, 0); if ( strcmp(path, "/") == 0 ) //means that the path is root, so filler() all subdirectories { FILE *directory_list; cs1550_directory_entry current_directory; //current directory to be printed out directory_list = fopen(".directories", "rb"); //open .directories if(directory_list != NULL) { while( fread(¤t_directory, sizeof(current_directory), 1, directory_list) == 1 ) { filler(buf, current_directory.dname + 1, NULL, 0); } fclose(directory_list); } res = 0; } else { //add the user stuff (subdirs or files) //the +1 skips the leading '/' on the filenames meta_entry attribute = find_correct_directory(path); if(attribute.index_of_directory > -1) //means that parameter path is a directory(aka subdirectory of root) { cs1550_directory_entry directory_entry = get_directory_entry( attribute.index_of_directory ); int count; for(count = 0; count < directory_entry.nFiles; count++) //go through filler() the files { char fullname[12] = ""; sprintf(fullname, "%s.%s", directory_entry.files[count].fname, directory_entry.files[count].fext); filler(buf, fullname, NULL, 0); } res = 0; } } return res; }
int syscall_chdir(const char *path) { if (!valid_string(path)) return -EFAULT; char newcwd[PATH_MAX]; relative_to_absolute(newcwd, current_process->cwd, path, PATH_MAX); int r; directory_entry *entry; if (0 != (r = get_directory_entry(filesystem, newcwd, &entry))) return r; if (TYPE_DIR != entry->type) return -ENOTDIR; memmove(current_process->cwd, newcwd, PATH_MAX); return 0; }
/* * Does the actual creation of a file. Mode and dev can be ignored. * */ static int cs1550_mknod(const char *path, mode_t mode, dev_t dev) { (void) mode; (void) dev; char directory[MAX_FILENAME + 1]; //name of directory we are looking for char filename[MAX_FILENAME + 1]; //name of file we are looking for char extension[MAX_EXTENSION + 1]; //file extension we are looking for int res = 0; meta_entry attribute = find_correct_directory(path); sscanf(path, "/%[^/]/%[^.].%s", directory, filename, extension); //tokenizes and stores the strings for the directory we are looking for if( attribute.slash_count == 1 ) //under root, do not give permission { res = -EPERM; } else if( strlen(filename) > 8 || strlen(extension) > 3 ) //name length is too long { res = -ENAMETOOLONG; } else if( attribute.file_index > -1) //is already a file { res = -EEXIST; } else //create file { cs1550_directory_entry directory_entry = get_directory_entry( attribute.index_of_directory ); strcpy(directory_entry.files[ directory_entry.nFiles ].fname, filename); //put filename in array index strcpy(directory_entry.files[ directory_entry.nFiles ].fext, extension); //put extension in array index // directory_entry.files[ directory_entry.nFiles ].fsize = 512; //size of block directory_entry.files[ directory_entry.nFiles ].fsize = 0; //size of block directory_entry.files[ directory_entry.nFiles ].nStartBlock = get_first_free_block(); //gets the first free block directory_entry.nFiles = directory_entry.nFiles++; //increment the amount of files write_directory_entry( directory_entry, attribute.index_of_directory ); //write the directory entry } return res; }
int locate_file(char *directory, char *filename, char *extension) //locates and returns index of file in directory, -1 means not located { int index_of_file = -1; int count; //count of file indexes int index_of_directory = locate_directory( directory ); //locates the directory that holds supposive file if(index_of_directory > -1) //means the directory is actually there { cs1550_directory_entry current_directory = get_directory_entry( index_of_directory ); //get directory for(count = 0; count < current_directory.nFiles; count++) { //checks if filename and extension match if( strcmp(filename, current_directory.files[ count ].fname) == 0 && strcmp(extension, current_directory.files[ count ].fext) == 0 ) { index_of_file = count; break; } } } return index_of_file; }
int syscall_open(const char *pathname, int flags) { if (!valid_string(pathname)) return -EFAULT; int fd = -1; for (fd = 0; fd < MAX_FDS; fd++) { if (NULL == current_process->filedesc[fd]) break; } if (MAX_FDS == fd) return -EMFILE; char abspath[PATH_MAX]; relative_to_absolute(abspath, current_process->cwd, pathname, PATH_MAX); directory_entry *entry; int r; if (0 != (r = get_directory_entry(filesystem, abspath, &entry))) return r; if ((flags == OPEN_DIRECTORY) && (entry->type != TYPE_DIR)) return -ENOTDIR; else if ((flags != OPEN_DIRECTORY) && (entry->type == TYPE_DIR)) return -EISDIR; filehandle *fh; if (TYPE_DIR == entry->type) fh = new_file(FH_DIR); else fh = new_file(FH_FILE); fh->entry = entry; fh->pos = 0; fh->entryno = 0; current_process->filedesc[fd] = fh; return fd; }
/* * Read size bytes from file into buf starting from offset * */ static int cs1550_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { (void) fi; meta_entry attribute = find_correct_directory(path); //check to make sure path exists if(attribute.index_of_directory > -1 && attribute.slash_count == 1) //means that paramter path is a directory { size = -EISDIR; } else { int index = attribute.file_index; cs1550_directory_entry directory_entry = get_directory_entry( attribute.index_of_directory ); if( size > 0 && offset <= directory_entry.files[index].fsize ) //check that size is > 0 and offset is <= to the file size { //read in data FILE *disk; disk = fopen(".disk", "rb"); fseek(disk, directory_entry.files[ index ].nStartBlock + offset, SEEK_SET); //seek from start to where the first block is plus offset fread(buf, sizeof(char), sizeof(buf), disk); //read in the amount of bytes needed size = strlen(buf); //set size and return, or error fclose(disk); } else { size = -1; //error } } return size; }
/* * Called whenever the system wants to know the file attributes, including * simply whether the file exists or not. * * man -s 2 stat will show the fields of a stat structure */ static int cs1550_getattr(const char *path, struct stat *stbuf) { int res = -ENOENT; //sets res to error first, if the directory or file is found then res is set to 0 because there is no error memset(stbuf, 0, sizeof(struct stat)); //is path the root dir? if (strcmp(path, "/") == 0) { stbuf->st_mode = S_IFDIR | 0755; stbuf->st_nlink = 2; res = 0; } else //is directly under root directory { meta_entry attribute = find_correct_directory(path); if(attribute.index_of_directory > -1 && attribute.slash_count == 1) //means that paramter path is a directory { //Might want to return a structure with these fields stbuf->st_mode = S_IFDIR | 0755; stbuf->st_nlink = 2; res = 0; } else if(attribute.index_of_directory > -1 && attribute.file_index > -1)//means that parameter path is a file { //regular file, probably want to be read and write cs1550_directory_entry directory_entry = get_directory_entry( attribute.index_of_directory ); stbuf->st_mode = S_IFREG | 0666; stbuf->st_nlink = 1; //file link stbuf->st_size = directory_entry.files[ attribute.file_index ].fsize; //file size - make sure you replace with real size! res = 0; // no error } } return res; }
/* * Deletes a file */ static int cs1550_unlink(const char *path) { int res = 0; meta_entry attribute = find_correct_directory(path); if( attribute.slash_count == 1 ) //the path is a directory, overwrite res { res = -EISDIR; } else if( attribute.index_of_directory > 1 && attribute.file_index == -1 ) //file not found(or wrong path but goes under same error) { res = -ENOENT; } else //remove file { int index = attribute.file_index; cs1550_directory_entry directory_entry = get_directory_entry( attribute.index_of_directory ); //collasce the array for( ; index < directory_entry.nFiles-1; index++) { strcpy( directory_entry.files[ index ].fname, directory_entry.files[ index + 1 ].fname ); strcpy( directory_entry.files[ index ].fext, directory_entry.files[ index + 1 ].fext ); directory_entry.files[ index ].fsize = directory_entry.files[ index + 1 ].fsize; directory_entry.files[ index ].nStartBlock = directory_entry.files[ index + 1 ].nStartBlock; } directory_entry.nFiles = directory_entry.nFiles--; //remove the file from count write_directory_entry( directory_entry, attribute.index_of_directory ); //write the directory entry } return res; }
fclose(disk); directory_entry.files[index].fsize = size; write_directory_entry( directory_entry, attribute.index_of_directory); } else if( offset <= directory_entry.files[index].fsize ) //append the file { //hopefully how many writes is only 1 becuase it will be poor performance otherwise int how_many_writes = (offset - directory_entry.files[index].fsize) / 512 + 1; //how many times to copy int count = 0; FILE *disk; cs1550_disk_block block; FILE *directory_list; //to edit and sent directory cs1550_directory_entry directory = get_directory_entry( attribute.index_of_directory ); //get directory while(count < how_many_writes) { move_file( directory, index); disk = fopen(".disk", "r+b"); strncpy(block.data, buf + count * 512, 512); //copies up to \0 or 512 bytes fwrite(&block.data, sizeof(char), sizeof(block.data), disk); //write the new data count++; directory.files[index].fsize = directory_entry.files[index].fsize + 512; //update size fclose(disk); } directory_list = fopen(".directories", "r+b"); fseek(directory_list, index * sizeof(directory_entry), SEEK_SET ); //seek to correct direcotry entry fwrite(&directory_entry, sizeof(directory_entry), 1, directory_list); //rewrite the struct fclose(directory_list);
/* * syscall_execve * * Implements the execve system call. This effectively does a "brain transplant" * on a process by arranging for it to run a different program to what it was * previously. This is achieved by loading the new program from the file system, * placing a copy in the process's text segment, and changing the instruction * pointer of the process to point to the first instruction of the loaded * executable file. * * In addition to loading a new program, this call is also responsible for passing * command line arguments to the new program. This is done by using the memory * at the bottom of the stack (actually the highest address, since the stack grows * downwards), in which the array of strings corresponding to argv is placed. The * argv and argc values are placed at the top of the stack, so that the main * function will be able to access them as arguments. */ int syscall_execve(const char *filename, char *const argv[], char *const envp[], regs * r) { process *proc = current_process; /* * Verify that the filename and all of the pointers within argc arg valid * (i.e. completely reside in the process's address space) */ if (!valid_string(filename)) return -EFAULT; unsigned int argno = 0; if (NULL != argv) { while (1) { if (!valid_pointer(argv, (argno + 1) * sizeof(char *))) return -EFAULT; if (NULL == argv[argno]) break; if (!valid_string(argv[argno])) return -EFAULT; argno++; } } /* * Check that the specified executable file actually exists, and find out its * location within the file system */ directory_entry *entry; int res; if (0 > (res = get_directory_entry(filesystem, filename, &entry))) return res; if (TYPE_DIR == entry->type) return -EISDIR; /* * Calculate number of arguments and amount of space needed to store them */ unsigned int argc = 0; unsigned int argslen = 0; for (argc = 0; argv && argv[argc]; argc++) argslen += strlen(argv[argc]) + 1; /* * Allocate a temporary buffer in which to store the argument data. This will * later be copied to the process's stack. The reason we can't do this * in-place is that doing so would risk overwriting some of the data we are * copying from. */ unsigned int argdata_size = argslen + argc * sizeof(char *) + 2 * sizeof(int); char *argdata = kmalloc(argdata_size); char **newargv = (char **)(argdata + 8); /* * Work backwards through the allocated buffer, copying in the strings one- * by-one */ unsigned int pos = argdata_size; for (argno = 0; argno < argc; argno++) { unsigned int nbytes = strlen(argv[argno]) + 1; pos -= nbytes; memmove(&argdata[pos], argv[argno], nbytes); newargv[argno] = (char *)(PROCESS_STACK_BASE - argdata_size + pos); } /* * Set argc and argv as the top two words on the stack. These are the values * that main will see passed in as its parameters. */ *(unsigned int *)(argdata + 0) = argc; *(unsigned int *)(argdata + 4) = PROCESS_STACK_BASE - argdata_size + 8; /* * Unmap the existing text segment */ disable_paging(); unsigned int addr; for (addr = proc->text_start; addr < proc->text_end; addr += PAGE_SIZE) unmap_and_free_page(proc->pdir, addr); for (addr = proc->data_start; addr < proc->data_end; addr += PAGE_SIZE) unmap_and_free_page(proc->pdir, addr); /* * Resize text and data segments to 0 bytes each */ proc->text_start = PROCESS_TEXT_BASE; proc->text_end = PROCESS_TEXT_BASE; proc->data_start = PROCESS_DATA_BASE; proc->data_end = PROCESS_DATA_BASE; /* * Load in the text segment from the executable file */ char *data = filesystem + entry->location; for (pos = 0; pos < entry->size; pos += PAGE_SIZE) { proc->text_end = proc->text_start + pos; void *page = alloc_page(); if (PAGE_SIZE <= entry->size - pos) memmove(page, &data[pos], PAGE_SIZE); else memmove(page, &data[pos], entry->size - pos); map_page(proc->pdir, proc->text_end, (unsigned int)page, PAGE_USER, PAGE_READ_WRITE); } proc->text_end = proc->text_start + pos; enable_paging(current_process->pdir); /* * Copy the command line argument data we set up above to the process's * stack */ memmove((void *)(PROCESS_STACK_BASE - argdata_size), argdata, argdata_size); kfree(argdata); /* * Set up the process's saved register state so that when it resumes * execution, it will start from the beginning of the loaded code. */ init_regs(r, PROCESS_STACK_BASE - argdata_size, (void *)current_process->text_start); return 0; }