/* * Given an absolute path to a file (for example /a/b/myFile), vfs_create * will create a new file named myFile in the /a/b directory. * */ static int vfs_create(const char *path, mode_t mode, struct fuse_file_info *fi) { vcb vb = getvcb(); // Get our VCB, used to find start/end points of dirents. if(validate_path(path) != 0) // If the path is invalid, return an error. return -1; path++; // Increment path, getting rid of the leading /. int first_free = -1; // Index of first free dirent. // To create a file, we need to first read used dirents and search for a duplicate. for(int i = vb.de_start; i < vb.de_start+vb.de_length && first_free < 0; i++){ dirent de = getdirent(i); if(de.valid == 1){ if(strcmp(de.name, path) == 0) return -EEXIST; } else{ first_free = i; } } // File doesn't already exist. Next, check for free spaces. If free_flag != 0 first_free == idx of first free dirent. if(first_free >= 0){ // If free dirents exist... dirent new_file; // Creating a new dirent, and assign its fields. new_file.valid = 1; new_file.first_block = -1; // Used to indicate a file with no data. new_file.size = 0; new_file.userid = getuid(); new_file.groupid = getgid(); new_file.mode = mode; struct timespec newtime; clock_gettime(CLOCK_REALTIME, &newtime); new_file.access_time = newtime; new_file.modify_time = newtime; new_file.create_time = newtime; memset(new_file.name,0,sizeof(new_file.name)); //char file_name[27]; //memset(file_name,0,27); char file_name[512 - (3*sizeof(struct timespec)) - 24]; // Build the name string... memset(file_name,0,sizeof(file_name)); strcpy(file_name,path); // Save path in to filename. Note: path has already been incrimented, so we're good. strcpy(new_file.name, file_name); setdirent(first_free,new_file); // Finally, we write our new dirent to disk at the index of first_free. return 0; } return -1; // If we reached here, free_flag == 0, meaning no free dirents exist. }
/** Process command line arguements and decide how to proceed. * Includes explanatory text for inline help and self-documentation. */ int main( int argc, char *argv[] ) { int descend_flag = 0, hadoop_flag = 0, stats_flag = 0, verbose_flag = 0, json_flag = 0; int count = 0, ret_val = 0; g_dir_arg = "."; /// set the default directory argument to "here" poptContext pc; struct poptOption po[] = { {"descend", 'd', POPT_ARG_NONE, &descend_flag, 0, UNIMPL"Parallelise and descend into subdirectories.", NULL}, {"stats", 's', POPT_ARG_NONE, &stats_flag, 0, "Print detailed statistics.", NULL}, {"verbose", 'v', POPT_ARG_NONE, &verbose_flag, 0, UNIMPL"Expand statistics output for each subdirectory.", NULL}, {"json", 'j', POPT_ARG_NONE, &json_flag, 0, UNIMPL"Write output in JSON format.", NULL}, POPT_AUTOHELP POPT_TABLEEND }; pc = poptGetContext(NULL, argc, (const char **)argv, po, 0); poptSetOtherOptionHelp(pc, "[directory]"); while ( (count = poptGetNextOpt(pc) ) >= 0 ) { printf("poptGetNextOpt return val %d\n", count); } for ( count = 0 ; poptPeekArg(pc) != NULL ; ++count ) { asprintf(&g_dir_arg, (char*)poptGetArg(pc)); if ( count > 0 ) { poptPrintUsage(pc, stderr, 0); goto EXITNOW; } } if ( descend_flag + hadoop_flag + stats_flag + verbose_flag + json_flag > 5 ) { poptPrintUsage(pc, stderr, 0); goto EXITNOW; } else { if ( descend_flag != POPT_ARG_NONE ) printf("%s: %s %s\n", PROGNAME, UNIMPL, "descend"); else if ( stats_flag != POPT_ARG_NONE ) ret_val = getdirent(g_dir_arg); else if ( verbose_flag != POPT_ARG_NONE ) printf("%s: %s %s\n", PROGNAME, UNIMPL, "verbose"); else if ( json_flag != POPT_ARG_NONE ) printf("%s: %s %s\n", PROGNAME, UNIMPL, "json"); else ret_val = quickcount(g_dir_arg); } if ( ret_val == 0 ) { exit(EXIT_SUCCESS); } else { goto EXITNOW; } EXITNOW: exit(EXIT_FAILURE); }
/** Read directory * * Given an absolute path to a directory, vfs_readdir will return * all the files and directories in that directory. * * HINT: * Use the filler parameter to fill in, look at fusexmp.c to see an example * Prototype below * * Function to add an entry in a readdir() operation * * @param buf the buffer passed to the readdir() operation * @param name the file name of the directory entry * @param stat file attributes, can be NULL * @param off offset of the next entry or zero * @return 1 if buffer is full, zero otherwise * typedef int (*fuse_fill_dir_t) (void *buf, const char *name, * const struct stat *stbuf, off_t off); * * Your solution should not need to touch fi * */ static int vfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) { if(strcmp(path, "/") == 0){ vcb vb = getvcb(); for(int i = vb.de_start; i < vb.de_start+vb.de_length; i++){ dirent de = getdirent(i); if(filler(buf, de.name, NULL, 0) != 0){ return -ENOMEM; } } return 0; }else{ return -1; } }
/* * The function rename will rename a file or directory named by the * string 'oldpath' and rename it to the file name specified by 'newpath'. * * HINT: Renaming could also be moving in disguise * */ static int vfs_rename(const char *from, const char *to) { vcb vb = getvcb(); if(validate_path(from) != 0) return -1; from++; for(int i = vb.de_start; i < vb.de_start+vb.de_length;i++){ dirent de = getdirent(i); if(strcmp(de.name,from) == 0){ strcpy(de.name, to); return 0; } } return -1; }
/* * This function will change the permissions on the file * to be mode. This should only update the file's mode. * Only the permission bits of mode should be examined * (basically, the last 16 bits). You should do something like * * fcb->mode = (mode & 0x0000ffff); * */ static int vfs_chmod(const char *file, mode_t mode) { vcb vb = getvcb(); if(validate_path(file) != 0) return -1; // Invalid path. file++; for(int i = vb.de_start; i < vb.de_start+vb.de_length; i++){ dirent de = getdirent(i); if(strcmp(de.name,file)==0){ //de.mode = (mode & 0x0000ffff); de.mode = mode; setdirent(i,de); return 0; // Success } } return -1; // File not found. }
/* * This function will update the file's last accessed time to * be ts[0] and will update the file's last modified time to be ts[1]. */ static int vfs_utimens(const char *file, const struct timespec ts[2]) { vcb vb = getvcb(); if(validate_path(file) != 0) return -1; // Invalid path. file++; for(int i = vb.de_start; i < vb.de_start+vb.de_length; i++){ dirent de = getdirent(i); if(strcmp(de.name,file)==0){ de.access_time = ts[0]; de.modify_time = ts[1]; setdirent(i,de); return 0; // Success } } return -1; // File not found. }
/* * This function will change the user and group of the file * to be uid and gid. This should only update the file's owner * and group. */ static int vfs_chown(const char *file, uid_t uid, gid_t gid) { vcb vb = getvcb(); if(validate_path(file) != 0) return -1; // Invalid path. file++; for(int i = vb.de_start; i < vb.de_start+vb.de_length; i++){ dirent de = getdirent(i); if(strcmp(de.name,file)==0){ de.userid = uid; de.groupid = gid; setdirent(i,de); return 0; // Success } } return -1; // File not found. }
static int dir(int argc, char **argv) { int i = 0, r; char buf[BUF_SIZ]; if (argc > 2) { printf("usage: %s [file]\n", argv[0]); return 1; } if (argc == 2) { r = stat(argv[1], &sbuf); if (r < 0) { printf("stat(%s) failed: %d\n", buf, r); return 0; } prstat(argv[1]); return 0; } while (1) { r = getdirent(i, buf, BUF_SIZ); if (r < 0) { printf("dirent(%d) failed: %d\n", i, r); break; } else if (!r) { break; } #if 0 printf("dirent(%d): \"%s\"\n", i, buf); #endif r = stat(buf, &sbuf); if (r < 0) { printf("stat(%s) failed: %d\n", buf, r); break; } prstat(buf); i++; } return 0; }
/* * This function will truncate the file at the given offset * (essentially, it should shorten the file to only be offset * bytes long). */ static int vfs_truncate(const char *file, off_t offset) { // First, we ensure thepath is valid. if(validate_path(file) != 0) return -1; file++; vcb vb = getvcb(); dirent de; int dirent_index = -1; for(int i = vb.de_start; i < vb.de_start + vb.de_length && dirent_index == -1; i++){ // Get matching dirent. de = getdirent(i); if(strcmp(de.name,file) == 0) dirent_index = i; } /* 3600: NOTE THAT ANY BLOCKS FREED BY THIS OPERATION SHOULD BE AVAILABLE FOR OTHER FILES TO USE. */ return 0; }
/** * This function deletes the last component of the path (e.g., /a/b/c you * need to remove the file 'c' from the directory /a/b). */ static int vfs_delete(const char *path) { vcb vb = getvcb(); // Get our VCB, used to find start/end points of dirents. if(validate_path(path) != 0) // If the path is invalid, return an error. return -1; path++; // Increment path, getting rid of the leading /. // To create a file, we need to first read used dirents and search for a duplicate. for(int i = vb.de_start; i < vb.de_start+vb.de_length; i++){ dirent de = getdirent(i); if(strcmp(de.name, path) == 0){ de.valid = 0; setdirent(i,de); return 0; } } return -EEXIST; /* 3600: NOTE THAT THE BLOCKS CORRESPONDING TO THE FILE SHOULD BE MARKED AS FREE, AND YOU SHOULD MAKE THEM AVAILABLE TO BE USED WITH OTHER FILES */ // TODO: Mark blocks as free. }
DIR *opendir(char *name) { struct stat statb; DIR *dirp; char c; char *s; struct _dircontents *dp; char nbuf[MAXPATHLEN + 1]; int len; strcpy(nbuf, name); len = strlen (nbuf); s = nbuf + len; #if 1 if ( ((c = nbuf[strlen(nbuf) - 1]) == '\\' || c == '/') && (strlen(nbuf) > 1) ) { nbuf[strlen(nbuf) - 1] = 0; if ( nbuf[strlen(nbuf) - 1] == ':' ) strcat(nbuf, "\\."); } else if ( nbuf[strlen(nbuf) - 1] == ':' ) strcat(nbuf, "."); #else if ( len && ((c = nbuf[len-1]) == '\\' || c == '/' || c == ':') ) { nbuf[len++] = '.'; /* s now points to '.' */ nbuf[len] = 0; } #endif if (stat(nbuf, &statb) < 0 || (statb.st_mode & S_IFMT) != S_IFDIR) return NULL; if ( (dirp = malloc(sizeof(DIR))) == NULL ) return NULL; #if 1 if ( nbuf[strlen(nbuf) - 1] == '.' ) strcpy(nbuf + strlen(nbuf) - 1, "*.*"); else if ( ((c = nbuf[strlen(nbuf) - 1]) == '\\' || c == '/') && (strlen(nbuf) == 1) ) strcat(nbuf, "*.*"); else strcat(nbuf, "\\*.*"); #else if ( *s == 0 ) *s++ = '\\'; strcpy (s, "*.*"); #endif dirp -> dd_loc = 0; dirp -> dd_contents = dirp -> dd_cp = NULL; if ((s = getdirent(nbuf)) == NULL) return dirp; do { if (((dp = malloc(sizeof(struct _dircontents))) == NULL) || ((dp -> _d_entry = malloc(strlen(s) + 1)) == NULL) ) { if (dp) free(dp); free_dircontents(dirp -> dd_contents); return NULL; } if (dirp -> dd_contents) { dirp -> dd_cp -> _d_next = dp; dirp -> dd_cp = dirp -> dd_cp -> _d_next; } else dirp -> dd_contents = dirp -> dd_cp = dp; strcpy(dp -> _d_entry, s); dp -> _d_next = NULL; dp -> _d_size = find.cbFile; dp -> _d_mode = find.attrFile; dp -> _d_time = *(unsigned *) &(find.ftimeLastWrite); dp -> _d_date = *(unsigned *) &(find.fdateLastWrite); } while ((s = getdirent(NULL)) != NULL); dirp -> dd_cp = dirp -> dd_contents; return dirp; }
int main(int argc, char *argv[]) #endif { u8 sta = 0, cmd; int i; #ifndef __AVR__ if (argc > 3 || argc < 2) { printf("Usage: (sudo) testfat rawdevice e.g. fat32 /dev/sdb \r\n"); return 1; } // fcntl(0, F_SETFL, fcntl(0, F_GETFL) | O_NONBLOCK); if (initsec(argv[1])) return -1; #endif hwinit(); printf("\nFAT32 Test\n"); i = sdhcinit(); printf("init %d\n", i); if (!i) { printf( "%lu sects\n", sdnumsectors ); i = mount(0); printf("Mount: %d\n", i); if (!i) seekfile(0, 0); #if 1 // show what is read else for (i = 0; i < 1; i++) { readsec(i); dumpsect(); } #endif } if (i) printf("Not Ready\n"); for (;;) { cmd = tzgetchar(); if (cmd >= 'a') cmd -= 32; switch (cmd) { #ifdef __AVR__ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': // while (!tzkbhit()) { ADMUX = 0xe0 + cmd - '0'; ADCSRA = 0xc7; while (ADCSRA & 0x40); printf("%c %04x\n", cmd, ADC); // } break; #endif case 3: case 26: case 'Q': exit(0); case 'Y': { u16 u; u = getdirent((u8 *) ""); printf("%u entries in dir\n", u); } break; case 'I': sta = sdhcinit(); printf("init %d\n", sta); if (sta) continue; printf( "%lu sects\n", sdnumsectors ); sta = cardinfo(0); printf("inf %d\n", sta); if (sta) continue; for (sta = 0; sta < 18; sta++) printf("%02X", filesectbuf[sta]); printf(" "); for (sta = 0; sta < 18; sta++) printf("%c", dochar(filesectbuf[sta])); printf("\n"); sta = cardinfo(1); printf("inf %d\n", sta); if (sta) continue; for (sta = 0; sta < 18; sta++) printf("%02X", filesectbuf[sta]); printf(" "); for (sta = 0; sta < 18; sta++) printf("%c", dochar(filesectbuf[sta])); printf("\n"); break; case 'M': i = mount(0); if (!i) printf("Mounted\n"); else printf("Error\n"); break; case 'O': printf("Open:\n"); i = getfname(); if (i < 0) { printf("bad fname\n"); break; } i = getdirent(filename); if (i == 2) printf("Entered Dir\n"); else if (!i) printf("Opened\n"); else printf("Not Found\n"); break; case 'C': printf("Create:\n"); i = getfname(); if (i < 0) { printf("bad fname\n"); break; } if (i == 1) { printf("Directory:\n"); i = getfname(); if (i) { printf("bad fname\n"); break; } i = 0x10; // directory attribute } i = newdirent(filename, i); if (!i) printf("Created\n"); else if (i == 2) printf("Exists\n"); else printf("Error\n"); break; case 'N': i = newdirent(NULL, 0); if (!i) printf("Created Ser Log\n"); else printf("Error\n"); break; case 'L': resettodir(); seekfile(0, 0); for (i = 0; i < 16; i++) { if (!filesectbuf[i << 5]) break; if (0xe5 == filesectbuf[i << 5]) { printf("(del)\n"); continue; } if (0xf == filesectbuf[(i << 5) + 11]) { printf("(lfn)\n"); continue; } printf("%8.8s.%3.3s %c\n", &filesectbuf[i << 5], &filesectbuf[(i << 5) + 8], filesectbuf[(i << 5) + 11] & 0x10 ? '/' : ' '); if (i == 15) { i = readnextsect(); if (i != 512) break; i = -1; } } break; case 'W': printf("Write: ^c|^z to exit\n"); for (;;) { char cx; cx = tzgetchar(); if (cx == 3 || cx == 26) break; writebyte(cx); printf("%c", cx); } printf("\nWritten "); flushbuf(); printf("Flushed "); syncdirent(0); printf("DSynced\n"); break; case 'F': flushbuf(); printf("Flushed\n"); break; case 'E': syncdirent(0); printf("dirsynced\n"); break; case 'P': syncdirent(1); printf("size pushed\n"); break; case 'Z': zaphint(); printf("hint zapped\n"); break; case 'T': truncatefile(); printf("Trunc-ed\n"); break; case 'D': i = deletefile(); if (i == 1) printf("no rmdir\n"); else if (!i) printf("Deleted\n"); else printf("Error\n"); break; // will go away when seek is filled in case 'A': seekfile(0, 2); printf("At EOF\n"); break; case 'S': { u32 x = 0; u8 y = 1; seekfile(x, y); printf("Rewound\n"); } break; case 'R': case 'V': case 'X': sta = 0; while (!tzkbhit()) { i = readbyte(); if (i < 0) { printf("\n=EOF=\n"); break; } switch (cmd) { case 'R': printf("%c", i); break; case 'V': printf("%c", dochar(i)); break; case 'X': if (!(sta++ & 15)) printf("\n"); printf("%02X", i); break; } } break; case 'U': resetrootdir(); seekfile(0, 0); // for list printf("At rootdir\n"); break; case 'G': resettodir(); seekfile(0, 0); // for list printf("At curdir\n"); break; default: // help message { char *c = mainmenu; while (pgm_read_byte(c)) putchar(pgm_read_byte(c++)); } break; } } }
/* * Gets the pathname of the current working directory. */ char *getcwd(char *buf, size_t size) { ino_t cino; /* Current dir inode number. */ dev_t cdev; /* Current dir inode pointer. */ ino_t rino; /* Root dir inode number. */ dev_t rdev; /* Root dir device number. */ DIR *dirp; /* Working directory. */ struct stat st; /* Working directory stat. */ struct dirent *dp; /* Working directory entry. */ char curdir[PATH_MAX]; /* Current directory. */ /* Invalid size. */ if (size == 0) { errno = EINVAL; return (NULL); } buf[0] = '\0'; strcpy(curdir, "."); /* * Get root inode and device numbers * so we know where we should stop. */ if (stat("/", &st) < 0) goto error0; rino = st.st_ino; rdev = st.st_dev; /* Get current working directory pathname. */ while (1) { /* * Remember current directory inode * and device number to get it name later. */ if (stat(curdir, &st) < 0) goto error0; cino = st.st_ino; cdev = st.st_dev; /* Done. */ if ((cino == rino) && (cdev == rdev)) break; /* Open upper directory. */ strcat(curdir, "/.."); if ((dirp = opendir(curdir)) == NULL) goto error0; /* Get lower directory name. */ dp = getdirent(dirp, cino); if (prepend(buf, dp->d_name, size)) goto error1; closedir(dirp); } /* * Special case when current working directory * is the root directory. */ if (buf[0] == '\0') { /* Start from root*/ if (prepend(buf, "", size)) goto error0; } return (buf); error1: closedir(dirp); error0: return (NULL); }
DIR *opendirx(char *name, char *pattern) { struct stat statb; DIR *dirp; char c; char *s; struct _dircontents *dp; int len; int unc; char path[OFS_MAXPATHNAME]; register char *ip, *op; for (ip = name, op = path;; op++, ip++) { *op = *ip; if (*ip == '\0') { break; } } len = ip - name; if (len > 0) { unc = ((path[0] == '\\' || path[0] == '/') && (path[1] == '\\' || path[1] == '/')); c = path[len - 1]; if (unc) { if (c != '\\' && c != '/') { path[len] = '/'; len++; path[len] = '\0'; } } else { if ((c == '\\' || c == '/') && (len > 1)) { len--; path[len] = '\0'; if (path[len - 1] == ':') { path[len] = '/'; len++; path[len] = '.'; len++; path[len] = '\0'; } } else if (c == ':') { path[len] = '.'; len++; path[len] = '\0'; } } } else { unc = 0; path[0] = '.'; path[1] = '\0'; len = 1; } if (stat(path, &statb) < 0 || (statb.st_mode & S_IFMT) != S_IFDIR) { return NULL; } dirp = malloc(sizeof(DIR)); if (dirp == NULL) { return dirp; } c = path[len - 1]; if (c == '.') { if (len == 1) { len--; } else { c = path[len - 2]; if (c == '\\' || c == ':') { len--; } else { path[len] = '/'; len++; } } } else if (!unc && ((len != 1) || (c != '\\' && c != '/'))) { path[len] = '/'; len++; } strcpy(path + len, pattern); dirp->dd_loc = 0; dirp->dd_contents = dirp->dd_cp = NULL; if ((s = getdirent(path)) == NULL) { return dirp; } do { if (((dp = malloc(sizeof(struct _dircontents))) == NULL) || ((dp->_d_entry = malloc(strlen(s) + 1)) == NULL)) { if (dp) free(dp); free_dircontents(dirp->dd_contents); return NULL; } if (dirp->dd_contents) dirp->dd_cp = dirp->dd_cp->_d_next = dp; else dirp->dd_contents = dirp->dd_cp = dp; strcpy(dp->_d_entry, s); dp->_d_next = NULL; } while ((s = getdirent(NULL)) != NULL); dirp->dd_cp = dirp->dd_contents; return dirp; }
/* Description. * Read next consequitive directory entry, pointed by fnp. * If some error occures the other critical * fields aren't changed, except those used for caching. * The fnp->f_diroff always corresponds to the directory entry * which has been read. * Return value. * 1 - all OK, directory entry having been read is not empty. * 0 - Directory entry is empty. * DE_SEEK - Attempt to read beyound the end of the directory. * DE_BLKINVLD - Invalid block. * Note. Empty directory entries always resides at the end of the directory. */ COUNT dir_read(REG f_node_ptr fnp) { struct buffer FAR *bp; REG UWORD secsize = fnp->f_dpb->dpb_secsize; ULONG new_diroff = fnp->f_diroff; /* Directories need to point to their current offset, not for */ /* next op. Therefore, if it is anything other than the first */ /* directory entry, we will update the offset on entry rather */ /* than wait until exit. If it was new, clear the special new */ /* flag. */ if (!fnp->f_flags.f_dnew) new_diroff += DIRENT_SIZE; /* Determine if we hit the end of the directory. If we have, */ /* bump the offset back to the end and exit. If not, fill the */ /* dirent portion of the fnode, clear the f_dmod bit and leave, */ /* but only for root directories */ if (fnp->f_flags.f_droot) { if (new_diroff >= DIRENT_SIZE * (ULONG)fnp->f_dpb->dpb_dirents) return DE_SEEK; bp = getblock((ULONG) (new_diroff / secsize + fnp->f_dpb->dpb_dirstrt), fnp->f_dpb->dpb_unit); #ifdef DISPLAY_GETBLOCK printf("DIR (dir_read)\n"); #endif } else { /* Do a "seek" to the directory position */ fnp->f_offset = new_diroff; /* Search through the FAT to find the block */ /* that this entry is in. */ #ifdef DISPLAY_GETBLOCK printf("dir_read: "); #endif if (map_cluster(fnp, XFR_READ) != SUCCESS) return DE_SEEK; /* Compute the block within the cluster and the */ /* offset within the block. */ fnp->f_sector = (fnp->f_offset / secsize) & fnp->f_dpb->dpb_clsmask; fnp->f_boff = fnp->f_offset % secsize; /* Get the block we need from cache */ bp = getblock(clus2phys(fnp->f_cluster, fnp->f_dpb) + fnp->f_sector, fnp->f_dpb->dpb_unit); #ifdef DISPLAY_GETBLOCK printf("DIR (dir_read)\n"); #endif } /* Now that we have the block for our entry, get the */ /* directory entry. */ if (bp == NULL) return DE_BLKINVLD; bp->b_flag &= ~(BFR_DATA | BFR_FAT); bp->b_flag |= BFR_DIR | BFR_VALID; getdirent((BYTE FAR *) & bp->b_buffer[((UWORD)new_diroff) % fnp->f_dpb->dpb_secsize], (struct dirent FAR *)&fnp->f_dir); /* Update the fnode's directory info */ fnp->f_flags.f_dmod = FALSE; fnp->f_flags.f_dnew = FALSE; fnp->f_diroff = new_diroff; /* and for efficiency, stop when we hit the first */ /* unused entry. */ /* either returns 1 or 0 */ return (fnp->f_dir.dir_name[0] != '\0'); }
static int mygetdents(int fd, struct dirent *buf, int n) { return getdirent(fd, (void*)buf, n); }
/* Description. * Read next consequitive directory entry, pointed by fnp. * If some error occures the other critical * fields aren't changed, except those used for caching. * The fnp->f_diroff always corresponds to the directory entry * which has been read. * Return value. * 1 - all OK, directory entry having been read is not empty. * 0 - Directory entry is empty. * DE_SEEK - Attempt to read beyound the end of the directory. * DE_BLKINVLD - Invalid block. * Note. Empty directory entries always resides at the end of the directory. */ COUNT dir_read(REG f_node_ptr fnp) { struct buffer FAR *bp; REG UWORD secsize = fnp->f_dpb->dpb_secsize; /* can't have more than 65535 directory entries */ if (fnp->f_diroff >= 65535U) { FDirDbgPrintf(("dir_read: exceed dir entry count\n")); return DE_SEEK; } /* Determine if we hit the end of the directory. If we have, */ /* bump the offset back to the end and exit. If not, fill the */ /* dirent portion of the fnode, clear the f_dmod bit and leave, */ /* but only for root directories */ if (fnp->f_dirstart == 0) { if (fnp->f_diroff >= fnp->f_dpb->dpb_dirents) { FDirDbgPrintf(("dir_read: end of dir\n")); return DE_SEEK; } bp = getblock(fnp->f_diroff / (secsize / DIRENT_SIZE) + fnp->f_dpb->dpb_dirstrt, fnp->f_dpb->dpb_unit); #ifdef DISPLAY_GETBLOCK printf("DIR (dir_read)\n"); #endif } else { /* Do a "seek" to the directory position */ fnp->f_offset = fnp->f_diroff * (ULONG)DIRENT_SIZE; /* Search through the FAT to find the block */ /* that this entry is in. */ #ifdef DISPLAY_GETBLOCK printf("dir_read: "); #endif if (map_cluster(fnp, XFR_READ) != SUCCESS) { DebugPrintf(("dir_read: map_cluster failed\n")); return DE_SEEK; } bp = getblock_from_off(fnp, secsize); #ifdef DISPLAY_GETBLOCK printf("DIR (dir_read)\n"); #endif } /* Now that we have the block for our entry, get the */ /* directory entry. */ if (bp == NULL) { FDirDbgPrintf(("dir_read: invalid block\n")); return DE_BLKINVLD; } bp->b_flag &= ~(BFR_DATA | BFR_FAT); bp->b_flag |= BFR_DIR | BFR_VALID; getdirent((BYTE FAR *) & bp-> b_buffer[(fnp->f_diroff * DIRENT_SIZE) % fnp->f_dpb->dpb_secsize], &fnp->f_dir); swap_deleted(fnp->f_dir.dir_name); /* Update the fnode's directory info */ fnp->f_flags &= ~F_DMOD; /* and for efficiency, stop when we hit the first */ /* unused entry. */ /* either returns 1 or 0 */ FDirDbgPrintf(("dir_read: dir_name is %11s\n", fnp->f_dir.dir_name)); return (fnp->f_dir.dir_name[0] != '\0'); }
/* * * Given an absolute path to a file/directory (i.e., /foo ---all * paths will start with the root directory of the CS3600 file * system, "/"), you need to return the file attributes that is * similar stat system call. * * HINT: You must implement stbuf->stmode, stbuf->st_size, and * stbuf->st_blocks correctly. * */ static int vfs_getattr(const char *path, struct stat *stbuf) { fprintf(stderr, "vfs_getattr called\n"); // Do not mess with this code stbuf->st_nlink = 1; // hard links stbuf->st_rdev = 0; stbuf->st_blksize = BLOCKSIZE; /* 3600: YOU MUST UNCOMMENT BELOW AND IMPLEMENT THIS CORRECTLY */ /* if (The path represents the root directory) stbuf->st_mode = 0777 | S_IFDIR; else stbuf->st_mode = <<file mode>> | S_IFREG; stbuf->st_uid = // file uid stbuf->st_gid = // file gid stbuf->st_atime = // access time stbuf->st_mtime = // modify time stbuf->st_ctime = // create time stbuf->st_size = // file size stbuf->st_blocks = // file size in blocks */ if(strcmp(path, "/") == 0){ vcb vb = getvcb(); struct tm * tm1; struct tm * tm2; struct tm * tm3; tm1 = localtime(&((vb.access_time).tv_sec)); tm2 = localtime(&((vb.modify_time).tv_sec)); tm3 = localtime(&((vb.create_time).tv_sec)); stbuf->st_mode = 0777 | S_IFDIR; stbuf->st_uid = vb.userid; stbuf->st_gid = vb.groupid; stbuf->st_atime = mktime(tm1); stbuf->st_mtime = mktime(tm2); stbuf->st_ctime = mktime(tm3); stbuf->st_size = BLOCKSIZE; stbuf->st_blocks = 1; return 0; } else{ if(validate_path(path) != 0) // If the path is valid, we can proceed. return -1; path++; // char *filename = (char *) malloc(512 - (3 * sizeof(timespec)) - 24); for(int i = 1; i < 101; i++){ dirent de = getdirent(i); if(de.valid == 1){ if(strcmp(de.name, path) == 0){ struct tm * tm1; struct tm * tm2; struct tm * tm3; tm1 = localtime(&((de.access_time).tv_sec)); tm2 = localtime(&((de.modify_time).tv_sec)); tm3 = localtime(&((de.create_time).tv_sec)); stbuf->st_mode = de.mode | S_IFREG; stbuf->st_uid = de.userid; stbuf->st_gid = de.groupid; stbuf->st_atime = mktime(tm1); stbuf->st_mtime = mktime(tm2); stbuf->st_ctime = mktime(tm3); stbuf->st_size = de.size; stbuf->st_blocks = (de.size / BLOCKSIZE); return 0; }// End if }// End if }// End for loop return -ENOENT; } }
COUNT dir_read(REG struct f_node FAR * fnp) { REG i; REG j; struct buffer FAR *bp; /* Directories need to point to their current offset, not for */ /* next op. Therefore, if it is anything other than the first */ /* directory entry, we will update the offset on entry rather */ /* than wait until exit. If it was new, clear the special new */ /* flag. */ if (fnp->f_flags.f_dnew) fnp->f_flags.f_dnew = FALSE; else fnp->f_diroff += DIRENT_SIZE; /* Determine if we hit the end of the directory. If we have, */ /* bump the offset back to the end and exit. If not, fill the */ /* dirent portion of the fnode, clear the f_dmod bit and leave, */ /* but only for root directories */ if (fnp->f_flags.f_droot && fnp->f_diroff >= fnp->f_dsize) { fnp->f_diroff -= DIRENT_SIZE; return 0; } else { if (fnp->f_flags.f_droot) { if ((fnp->f_diroff / fnp->f_dpb->dpb_secsize + fnp->f_dpb->dpb_dirstrt) >= fnp->f_dpb->dpb_data) { fnp->f_flags.f_dfull = TRUE; return 0; } bp = getblock((ULONG) (fnp->f_diroff / fnp->f_dpb->dpb_secsize + fnp->f_dpb->dpb_dirstrt), fnp->f_dpb->dpb_unit); bp->b_flag &= ~(BFR_DATA | BFR_FAT); bp->b_flag |= BFR_DIR; #ifdef DISPLAY_GETBLOCK printf("DIR (dir_read)\n"); #endif } else { REG UWORD secsize = fnp->f_dpb->dpb_secsize; /* Do a "seek" to the directory position */ fnp->f_offset = fnp->f_diroff; /* Search through the FAT to find the block */ /* that this entry is in. */ #ifdef DISPLAY_GETBLOCK printf("dir_read: "); #endif if (map_cluster(fnp, XFR_READ) != SUCCESS) { fnp->f_flags.f_dfull = TRUE; return 0; } /* If the returned cluster is FREE, return zero */ /* bytes read. */ if (fnp->f_cluster == FREE) return 0; /* If the returned cluster is LAST_CLUSTER or */ /* LONG_LAST_CLUSTER, return zero bytes read */ /* and set the directory as full. */ if (last_link(fnp)) { fnp->f_diroff -= DIRENT_SIZE; fnp->f_flags.f_dfull = TRUE; return 0; } /* Compute the block within the cluster and the */ /* offset within the block. */ fnp->f_sector = (fnp->f_offset / secsize) & fnp->f_dpb->dpb_clsmask; fnp->f_boff = fnp->f_offset % secsize; /* Get the block we need from cache */ bp = getblock((ULONG) clus2phys(fnp->f_cluster, (fnp->f_dpb->dpb_clsmask + 1), fnp->f_dpb->dpb_data) + fnp->f_sector, fnp->f_dpb->dpb_unit); bp->b_flag &= ~(BFR_DATA | BFR_FAT); bp->b_flag |= BFR_DIR; #ifdef DISPLAY_GETBLOCK printf("DIR (dir_read)\n"); #endif } /* Now that we have the block for our entry, get the */ /* directory entry. */ if (bp != NULL) getdirent((BYTE FAR *) & bp->b_buffer[fnp->f_diroff % fnp->f_dpb->dpb_secsize], (struct dirent FAR *)&fnp->f_dir); else { fnp->f_flags.f_dfull = TRUE; return 0; } /* Update the fnode's directory info */ fnp->f_flags.f_dfull = FALSE; fnp->f_flags.f_dmod = FALSE; /* and for efficiency, stop when we hit the first */ /* unused entry. */ if (fnp->f_dir.dir_name[0] == '\0') return 0; else return DIRENT_SIZE; } }
/* * The function vfs_write will attempt to write 'size' bytes from * memory address 'buf' into a file specified by an absolute 'path'. * It should do so starting at the specified offset 'offset'. If * offset is beyond the current size of the file, you should pad the * file with 0s until you reach the appropriate length. * * You should return the number of bytes written. * * HINT: Ignore 'fi' */ static int vfs_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { // First, we ensure thepath is valid. if(validate_path(path) != 0) return -1; vcb vb = getvcb(); path++; // Get rid of leading slash in path int byteswritten = 0; // Amount of bytes we've written to disk from buffer int num_pad = 0; // Amount of 0s we need to pad between EOF and offset int write_offset = 0; // variable to hold an offset for vfs_write. dirent de; int found_dirent = 0; int dirent_index = -1; for(int i = vb.de_start; i < vb.de_start + vb.de_length, found_dirent == 0; i++){ de = getdirent(i); if(de.valid == 1) if(strcmp(path,de.name)==0){ found_dirent = 1; dirent_index = i; } } if(found_dirent){ // Begin writing to disk. if(offset > de.size){ // Check for padding. num_pad = (offset - de.size); // Number of 0's to add. } if((size + offset) > de.size){ de.size = (size + offset); // Set the new size of the file. } // Update access modify times of file struct timespec newtime; clock_gettime(CLOCK_REALTIME, &newtime); de.access_time = newtime; de.modify_time = newtime; /* Next, since we have our dirent to write to, we must: - Check to see if the dirent has a FAT entry allocated. - Attempt to allocate one if necessary. x If the dirent has at least one FAT entry, begin writing: x Begin traversing offset, decrementing it as necessary until offset == 0. x Attempt to create new FAT entries if necessary. x Begin padding the file with zeros, if necessary, decrementing num_pad until it == 0. x Attempt to create new FAT entries if necessary. x Begin appending buf to file, decrementing size while doing so. x Attempt to create new FAT entries if necessary. x If, in any of the above cases, creating a new FAT entry fails, return -ENOSPC. */ // Check if found dirent has allocated FAT. If not, attempt to allocate one. if((int) de.first_block == -1){ char block[BLOCKSIZE]; int found_free = 0; for(int i = vb.fat_start;(i < vb.fat_start + ((int) (vb.fat_length/128))) && found_free == 0; i++){ // For each fat block... int block_index = (i-vb.fat_start)*128; memset(block,0,BLOCKSIZE); // Reset block. dread(i, block); // Read FAT Block into block. for(int j = 0; j < 128 && found_free == 0; j++){ fatent fe = getfe( block_index + j); if(fe.used == 0){ de.first_block = block_index + j; fe.used = 1; fe.eof = 1; fe.next = 0; found_free = 1; } } } if(found_free != 1){ return -ENOSPC; } } fatent fe = getfe(de.first_block); char block[BLOCKSIZE]; memset(block,0,BLOCKSIZE); // Expand file and pad 0's, if necessary. if(num_pad > 0){ int eof_fat_idx = get_eof_fe(&fe) + vb.db_start;// find index of eof dread(eof_fat_idx,block); int eof_data_idx; for(int i = 0; block[i] != EOF; i++) eof_data_idx++; eof_data_idx++; // Increment counter so block[eof_data_idx] == EOF. while(num_pad > 0){ if(eof_data_idx < BLOCKSIZE){ memset(&block[eof_data_idx],0,1); eof_data_idx++; num_pad--; if(num_pad == 0){ dwrite(eof_data_idx,block); memset(block,0,BLOCKSIZE); } } else{ dwrite(eof_fat_idx,block); memset(block,0,BLOCKSIZE); if(allocate_fat(&fe) != 0){ return -ENOSPC; } eof_fat_idx = get_eof_fe(&fe) + vb.db_start; eof_data_idx = 0; } } } // Now, we need to start writing size chars from buf into the file, starting at offset // Start by finding where offset is in the datablock. int offset_block = (int)(offset/512); int offset_into_block = offset % 512; int buffer_offset = 0; // Read in offset block, write at offset into block memset(block,0,BLOCKSIZE); dread(offset_block + vb.db_start, block); // Memcpy the rest of the block, or size bytes, whichever bounds first while(offset_into_block < BLOCKSIZE && size > 0){ memcpy(&block[offset_into_block], buf, 1); size--; buf++; buffer_offset++; offset_into_block++; byteswritten++; } // Write block rest of block dwrite(offset_block + vb.db_start, block); // While there remains bytes to be written... while(size > 0){ if(offset_into_block == BLOCKSIZE){ // Write block dwrite(offset_block + vb.db_start, block); // Allocate new fat/data block if(allocate_fat(&fe) != 0){ return -ENOSPC; } // reset offset_into_block offset_into_block = 0; offset_block = get_eof_fe(&fe); memset(block,0,BLOCKSIZE); } memcpy(&block[offset_into_block], &buf[buffer_offset], 1); size--; buffer_offset++; offset_into_block++; byteswritten++; } // Write the rest of size bytes dwrite(offset_block + vb.db_start, block); setdirent(dirent_index,de); return byteswritten; } else{ // No free dirents found return -1; } }