void integck(void) { pid_t pid; int64_t rpt; uint64_t z; char dir_name[256]; /* Make our top directory */ pid = getpid(); printf("pid is %u\n", (unsigned) pid); tests_cat_pid(dir_name, "integck_test_dir_", pid); if (chdir(dir_name) != -1) { /* Remove it if it is already there */ tests_clear_dir("."); CHECK(chdir("..") != -1); CHECK(rmdir(dir_name) != -1); } initial_free_space = tests_get_free_space(); log10_initial_free_space = 0; for (z = initial_free_space; z >= 10; z /= 10) ++log10_initial_free_space; top_dir = dir_new(NULL, dir_name); if (!top_dir) return; srand(pid); create_test_data(); if (!tests_fs_is_rootfs()) { close_open_files(); tests_remount(); /* Requires root access */ } /* Check everything */ dir_check(top_dir); check_deleted_files(); for (rpt = 0; tests_repeat_parameter == 0 || rpt < tests_repeat_parameter; ++rpt) { update_test_data(); if (!tests_fs_is_rootfs()) { close_open_files(); tests_remount(); /* Requires root access */ } /* Check everything */ dir_check(top_dir); check_deleted_files(); } /* Tidy up by removing everything */ close_open_files(); tests_clear_dir(dir_name); CHECK(rmdir(dir_name) != -1); }
/** * @brief fatfs_cp copy a file * @param fc the current FAT session * @param from_name original filename * @param to_name the name of the copy filename * @return 0 on success */ int fatfs_cp(struct block_cache *output, off_t block_offset, const char *from_name, const char *to_name) { close_open_files(); MAYBE_MOUNT(output, block_offset); FIL fromfil; FIL tofil; CHECK("fatfs_cp can't open file", from_name, f_open(&fromfil, from_name, FA_READ)); CHECK("fatfs_cp can't open file", to_name, f_open(&tofil, to_name, FA_CREATE_ALWAYS | FA_WRITE)); for (;;) { char buffer[4096]; UINT bw, br; CHECK("fatfs_cp can't read", from_name, f_read(&fromfil, buffer, sizeof(buffer), &br)); if (br == 0) break; CHECK("fatfs_cp can't write", to_name, f_write(&tofil, buffer, br, &bw)); if (br != bw) ERR_RETURN("Error copying file to FAT"); } f_close(&fromfil); f_close(&tofil); return 0; }
/** * @brief fatfs_setlabel Set the volume label * @param fc the current FAT session * @param label the name of the filesystem * @return 0 on success */ int fatfs_setlabel(struct block_cache *output, off_t block_offset, const char *label) { close_open_files(); MAYBE_MOUNT(output, block_offset); CHECK("fat_setlabel", label, f_setlabel(label)); return 0; }
void fatfs_closefs() { if (output_) { close_open_files(); // This unmounts. Don't check error. f_mount(NULL, "", 0); output_ = NULL; } }
/** * @brief fatfs_exists check if the specified file exists * @param fc the current FAT session * @param filename the filename * @return 0 if it exists */ int fatfs_exists(struct block_cache *output, off_t block_offset, const char *filename) { close_open_files(); MAYBE_MOUNT(output, block_offset); FIL fil; CHECK("fatfs_exists", filename, f_open(&fil, filename, FA_OPEN_EXISTING)); f_close(&fil); return 0; }
/** * @brief fatfs_touch create an empty file if the file doesn't exist * @param fc the current FAT session * @param filename the file to touch * @return 0 on success */ int fatfs_touch(struct block_cache *output, off_t block_offset, const char *filename) { close_open_files(); MAYBE_MOUNT(output, block_offset); FIL fil; CHECK("fat_touch", filename, f_open(&fil, filename, FA_OPEN_ALWAYS)); f_close(&fil); return 0; }
void repl_driver(void) { int k; k = setjmp(errjmp); if (k == 2) return; signal(SIGFPE,handle_sigfpe); signal(SIGINT,handle_sigint); close_open_files(); errjmp_ok = 1; nointerrupt = 0; if (init_file && (k == 0)) vload(init_file); repl(); }
/** * @brief fatfs_mv rename a file * @param fc the current FAT session * @param cmd the command name for error messages * @param from_name original filename * @param to_name new filename * @param force set to true to rename the file even if to_name exists * @return 0 on success */ int fatfs_mv(struct block_cache *output, off_t block_offset, const char *cmd, const char *from_name, const char *to_name, bool force) { close_open_files(); MAYBE_MOUNT(output, block_offset); // If forcing, remove the file first. if (force && fatfs_rm(output, block_offset, cmd, to_name, false)) return -1; CHECK(cmd, from_name, f_rename(from_name, to_name)); return 0; }
/** * @brief fatfs_file_matches check if the pattern can be found in filename * @param fc the current FAT session * @param filename the file to search through * @param pattern the pattern to patch * @return 0 if the file exists and the pattern is inside of it */ int fatfs_file_matches(struct block_cache *output, off_t block_offset, const char *filename, const char *pattern) { close_open_files(); MAYBE_MOUNT(output, block_offset); FIL fil; CHECK("fatfs_file_matches can't open file", filename, f_open(&fil, filename, FA_READ)); char buffer[4096]; int rc = -1; size_t pattern_len = strlen(pattern); if (pattern_len >= sizeof(buffer)) goto cleanup; if (pattern_len == 0) { // 0-length patterns always match if the file exists. rc = 0; goto cleanup; } size_t offset = 0; for (;;) { UINT br; CHECK_CLEANUP("fatfs_file_matches", filename, f_read(&fil, buffer + offset, sizeof(buffer) - offset, &br)); if (br == 0) break; if (memmem(buffer, br, pattern, pattern_len) != 0) { // Found it. rc = 0; break; } // Handle pattern matches between this buffer and the next one. if (br >= pattern_len) { // Copy the last (pattern_len - 1) bytes to the beginning and read // from there next time. offset = pattern_len - 1; memcpy(buffer, buffer + br - offset, offset); } else { // Read less than pattern_len, so read more from there next time // assuming that there is a next time. offset = br; } } cleanup: f_close(&fil); return rc; }
/** * @brief fatfs_mkdir Make a directory * @param fc the current FAT session * @param dir the name of the directory * @return 0 on success */ int fatfs_mkdir(struct block_cache *output, off_t block_offset, const char *dir) { close_open_files(); MAYBE_MOUNT(output, block_offset); // Check if the directory already exists and is a directory. FILINFO info; FRESULT rc = f_stat(dir, &info); if (rc == FR_OK && info.fattrib & AM_DIR) return 0; // Try to make it if not. CHECK("fat_mkdir", dir, f_mkdir(dir)); return 0; }
int fatfs_pwrite(struct block_cache *output, off_t block_offset, const char *filename, int offset, const char *buffer, off_t size) { // Check if this is the same file as a previous pwrite call if (current_file_ && strcmp(current_file_, filename) != 0) close_open_files(); MAYBE_MOUNT(output, block_offset); if (!current_file_) { CHECK("fat_write can't open file", filename, f_open(&fil_, filename, FA_OPEN_ALWAYS | FA_WRITE)); // Assuming it opens ok, cache the filename for future writes. current_file_ = strdup(filename); } // Check if this pwrite requires a seek. DWORD desired_offset = offset; if (desired_offset != f_tell(&fil_)) { // Need to seek, but if we're seeking past the end, be sure to fill in with zeros. if (desired_offset > f_size(&fil_)) { // Seek to the end CHECK("fat_write can't seek to end of file", filename, f_lseek(&fil_, f_size(&fil_))); // Write zeros. DWORD zero_count = desired_offset - f_tell(&fil_); char zero_buffer[FWUP_BLOCK_SIZE]; memset(zero_buffer, 0, sizeof(zero_buffer)); while (zero_count) { DWORD btw = (zero_count < sizeof(zero_buffer) ? zero_count : sizeof(zero_buffer)); UINT bw; CHECK("fat_write can't write", filename, f_write(&fil_, zero_buffer, btw, &bw)); if (btw != bw) ERR_RETURN("Error writing file to FAT: %s, expected %ld bytes written, got %d (maybe the disk is full?)", filename, size, bw); zero_count -= bw; } } else { CHECK("fat_write can't seek in file", filename, f_lseek(&fil_, desired_offset)); } } UINT bw; CHECK("fat_write can't write", filename, f_write(&fil_, buffer, size, &bw)); if (size != bw) ERR_RETURN("Error writing file to FAT: %s, expected %ld bytes written, got %d (maybe the disk is full?)", filename, size, bw); return 0; }
/** * @brief fatfs_rm Delete a file * @param fc the current FAT session * @param cmd the command name for error messages * @param filename the name of the file * @param file_must_exist true if the file must exist * @return 0 on success */ int fatfs_rm(struct block_cache *output, off_t block_offset, const char *cmd, const char *filename, bool file_must_exist) { close_open_files(); MAYBE_MOUNT(output, block_offset); FRESULT rc = f_unlink(filename); switch (rc) { case FR_OK: return 0; case FR_NO_FILE: if (!file_must_exist) return 0; // fall through default: fatfs_error(cmd, filename, rc); return -1; } }
int fatfs_truncate(struct block_cache *output, off_t block_offset, const char *filename) { // Check if this is the same file as a previous pwrite call if (current_file_ && strcmp(current_file_, filename) != 0) close_open_files(); MAYBE_MOUNT(output, block_offset); if (!current_file_) { // FA_CREATE_ALWAYS truncates if the file exists CHECK("Can't open file on FAT partition", filename, f_open(&fil_, filename, FA_CREATE_ALWAYS | FA_WRITE)); // Assuming it opens ok, cache the filename for future writes. current_file_ = strdup(filename); } else { // Truncate an already open file CHECK("Can't seek to the beginning", filename, f_lseek(&fil_, 0)); CHECK("Can't truncate file on FAT partition", filename, f_truncate(&fil_)); } // Leave the file open since the main use case is to start writing to it afterwards. return 0; }
/* Select an open file at random */ static void operate_on_an_open_file(void) { size_t r; struct open_file_info *ofi; /* When shrinking, close all open files 1 time in 128 */ if (shrink) { static int x = 0; x += 1; x &= 127; if (x == 0) { close_open_files(); return; } } /* Close any open files that have errored */ if (!check_nospc_files) { ofi = open_files; while (ofi) { if (ofi->fdi->file->no_space_error) { struct fd_info *fdi; fdi = ofi->fdi; ofi = ofi->next; file_close(fdi); } else ofi = ofi->next; } } r = tests_random_no(open_files_count); for (ofi = open_files; ofi; ofi = ofi->next, --r) if (!r) { operate_on_open_file(ofi->fdi); return; } }