/* * clean up any files we created on failure * if we created the data directory remove it too */ static void exit_nicely(void) { if (!noclean) { if (made_new_pgdata) { fprintf(stderr, _("%s: removing data directory \"%s\"\n"), progname, pg_data); if (!rmtree(pg_data, true)) fprintf(stderr, _("%s: failed to remove data directory\n"), progname); } else if (found_existing_pgdata) { fprintf(stderr, _("%s: removing contents of data directory \"%s\"\n"), progname, pg_data); if (!rmtree(pg_data, false)) fprintf(stderr, _("%s: failed to remove contents of data directory\n"), progname); } /* otherwise died during startup, do nothing! */ } else { if (made_new_pgdata || found_existing_pgdata) fprintf(stderr, _("%s: data directory \"%s\" not removed at user's request\n"), progname, pg_data); } exit(1); }
int main(int argc, char ** argv) { int n = 1; real m = 1.0; check_help(); extern char *poptarg; int c; const char *param_string = "m:n:"; while ((c = pgetopt(argc, argv, param_string, "$Revision: 1.9 $", _SRC_)) != -1) switch(c) { case 'm': m = atof(poptarg); break; case 'n': n = atoi(poptarg); break; case '?': params_to_usage(cerr, argv[0], param_string); get_help(); exit(1); } if (m <= 0) err_exit("mknodes: M > 0 required!"); if (n <= 0) err_exit("mknodes: N > 0 required!"); node * root = mknode_mass(n, m); root->log_history(argc, argv); put_node(root); rmtree(root); return 0; }
// Recursively deletes the file named path. If path is a file, it will be // removed. If it is a directory, everything in it will also be deleted. // Returns 0 on success, -1 on error, and sets errno appropriately. static int rmtree(const char* path) { // TODO: Handle errors in a more intelligent fashion? DIR* dir = opendir(path); if (dir == NULL) { if (errno == ENOTDIR) { // Not a directory: unlink it instead return unlink(path); } return -1; } assert(dir != NULL); for (struct dirent* entry = readdir(dir); entry != NULL; entry = readdir(dir)) { // Skip special directories if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { continue; } // Recursively delete the directory entry. This handles regular files // and directories. string fullpath(path); fullpath += "/"; fullpath += entry->d_name; rmtree(fullpath.c_str()); } int error = closedir(dir); assert(error == 0); return rmdir(path); }
/* * Delete the given subdirectory contents from the new cluster, and copy the * files from the old cluster into it. */ static void copy_subdir_files(char *subdir) { char old_path[MAXPGPATH]; char new_path[MAXPGPATH]; prep_status("Deleting files from new %s", subdir); snprintf(old_path, sizeof(old_path), "%s/%s", old_cluster.pgdata, subdir); snprintf(new_path, sizeof(new_path), "%s/%s", new_cluster.pgdata, subdir); if (!rmtree(new_path, true)) pg_log(PG_FATAL, "could not delete directory \"%s\"\n", new_path); check_ok(); prep_status("Copying old %s to new server", subdir); exec_prog(UTILITY_LOG_FILE, NULL, true, #ifndef WIN32 "cp -Rf \"%s\" \"%s\"", #else /* flags: everything, no confirm, quiet, overwrite read-only */ "xcopy /e /y /q /r \"%s\" \"%s\\\"", #endif old_path, new_path); check_ok(); }
bool FileSystem::rmtree(const Path& path) { Directory* test_dir = opendir(path); if (test_dir != NULL) { auto_Object<Directory> dir(test_dir); Directory::Entry* test_dentry = dir->read(); if (test_dentry != NULL) { auto_Object<Directory::Entry> dentry(*test_dentry); do { if (dentry->is_special()) { continue; } Path dentry_path(path / dentry->get_name()); if (dentry->ISDIR()) { if (rmtree(dentry_path)) { continue; } else { return false; } } else if (unlink(dentry_path)) { continue; } else { return false; } } while (dir->read(*dentry)); return rmdir(path); } } return false; }
static BOOL move_program() { if (MoveFileEx(L"Calibre Portable\\calibre-portable.exe", L"..\\calibre-portable.exe", MOVEFILE_REPLACE_EXISTING) == 0) { show_last_error(L"Failed to move calibre-portable.exe, make sure calibre is not running"); return false; } if (directory_exists(L"..\\Calibre")) { if (!rmtree(L"..\\Calibre")) { show_error(L"Failed to delete the Calibre program folder. Make sure calibre is not running."); return false; } } if (MoveFileEx(L"Calibre Portable\\Calibre", L"..\\Calibre", 0) == 0) { Sleep(4000); // Sleep and try again if (MoveFileEx(L"Calibre Portable\\Calibre", L"..\\Calibre", 0) == 0) { show_last_error(L"Failed to move calibre program folder. This is usually caused by an antivirus program or a file sync program like DropBox. Turn them off temporarily and try again. Underlying error: "); return false; } } if (!directory_exists(L"..\\Calibre Library")) { MoveFileEx(L"Calibre Portable\\Calibre Library", L"..\\Calibre Library", 0); } if (!directory_exists(L"..\\Calibre Settings")) { MoveFileEx(L"Calibre Portable\\Calibre Settings", L"..\\Calibre Settings", 0); } return true; }
main(int argc, char ** argv) { check_help(); extern char *poptarg; extern char *poparr[]; int c; const char *param_string = ""; while ((c = pgetopt(argc, argv, param_string, "$Revision: 1.5 $", _SRC_)) != -1) switch(c) { case '?': params_to_usage(cerr, argv[0], param_string); get_help(); exit(1); } dyn *b; real prev_time = -VERY_LARGE_NUMBER; cerr.precision(HIGH_PRECISION); while (b = get_dyn()) { real time = b->get_system_time(); if (prev_time > -VERY_LARGE_NUMBER) { real dt = time - prev_time; PRC(time); PRL(dt); } else PRL(time); prev_time = time; rmtree(b); } }
void testutil_cleanup(void) { test_call_ok(chdir(orig_wd), strerror(errno), "cd into original working directory"); rmtree("test_tmp"); }
/* ---- * Manipulation of ondisk state of replication slots * * NB: none of the routines below should take any notice whether a slot is the * current one or not, that's all handled a layer above. * ---- */ static void CreateSlotOnDisk(ReplicationSlot *slot) { char tmppath[MAXPGPATH]; char path[MAXPGPATH]; struct stat st; /* * No need to take out the io_in_progress_lock, nobody else can see this * slot yet, so nobody else will write. We're reusing SaveSlotToPath which * takes out the lock, if we'd take the lock here, we'd deadlock. */ sprintf(path, "pg_replslot/%s", NameStr(slot->data.name)); sprintf(tmppath, "pg_replslot/%s.tmp", NameStr(slot->data.name)); /* * It's just barely possible that some previous effort to create or * drop a slot with this name left a temp directory lying around. * If that seems to be the case, try to remove it. If the rmtree() * fails, we'll error out at the mkdir() below, so we don't bother * checking success. */ if (stat(tmppath, &st) == 0 && S_ISDIR(st.st_mode)) rmtree(tmppath, true); /* Create and fsync the temporary slot directory. */ if (mkdir(tmppath, S_IRWXU) < 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not create directory \"%s\": %m", tmppath))); fsync_fname(tmppath, true); /* Write the actual state file. */ slot->dirty = true; /* signal that we really need to write */ SaveSlotToPath(slot, tmppath, ERROR); /* Rename the directory into place. */ if (rename(tmppath, path) != 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not rename file \"%s\" to \"%s\": %m", tmppath, path))); /* * If we'd now fail - really unlikely - we wouldn't know whether this slot * would persist after an OS crash or not - so, force a restart. The * restart would try to fysnc this again till it works. */ START_CRIT_SECTION(); fsync_fname(path, true); fsync_fname("pg_replslot", true); END_CRIT_SECTION(); }
ChTempDir::~ChTempDir() { // TODO: chdir back to the original directory? int status = chdir("/"); assert(status == 0); // Recursively delete everything in the temporary directory. status = rmtree(name_.c_str()); assert(status == 0); }
static void runbenchn(Benchmark *b, int n) { int outfd = tmpfd(); int durfd = tmpfd(); strcpy(b->dir, TmpDirPat); mktemp(b->dir); int pid = fork(); if (pid < 0) { die(1, errno, "fork"); } else if (!pid) { setpgid(0, 0); if (dup2(outfd, 1) == -1) { die(3, errno, "dup2"); } if (close(outfd) == -1) { die(3, errno, "fclose"); } if (dup2(1, 2) == -1) { die(3, errno, "dup2"); } curdir = b->dir; ctstarttimer(); b->f(n); ctstoptimer(); write(durfd, &bdur, sizeof bdur); write(durfd, &bbytes, sizeof bbytes); _exit(0); } setpgid(pid, pid); pid = waitpid(pid, &b->status, 0); if (pid == -1) { die(3, errno, "wait"); } killpg(pid, 9); rmtree(b->dir); if (b->status != 0) { putchar('\n'); lseek(outfd, 0, SEEK_SET); copyfd(stdout, outfd); return; } lseek(durfd, 0, SEEK_SET); int r = read(durfd, &b->dur, sizeof b->dur); if (r != sizeof b->dur) { perror("read"); b->status = 1; } r = read(durfd, &b->bytes, sizeof b->bytes); if (r != sizeof b->bytes) { perror("read"); b->status = 1; } }
void rmtree(node* b, bool delete_b) // default = true { node* d = b->get_oldest_daughter(); while (d) { node* tmp = d->get_younger_sister(); rmtree(d); d = tmp; } if (delete_b) delete b; // optionally leave node itself untouched }
main(int argc, char *argv[]) { // Read and sort the list of masses. vector<real> mass; bool percent = false; mass.push_back(0); for (int i = 1; i < argc; i++) { real m = atof(argv[i]); mass.push_back(m); if (m > 1) percent = true; // default interpretation is fraction, // >1 ==> switch to percentile } if (percent) for (int i = 0; i < mass.size(); i++) mass[i] = 0.01*mass[i]; sort(mass.begin(), mass.end()); mass.push_back(1.0); dyn *b; // root node while (b = get_dyn()) { // Compute the quartiles (not actually printed, but stored // in the root dyn story) for each mass range. cerr << b->get_system_time() << " "; for (int i = 1; i < mass.size(); i++) { if (i == 1) set_lagr_cutoff_mass(b, mass[i-1], mass[i]); // sort masses else reset_lagr_cutoff_mass(b, mass[i-1], mass[i]); // no sort real rhalf = compute_lagrangian_radii(b, 0.5, false, // not verbose 4); // mass filter // Alternatively, if several Lagrangian radii are needed: // // real lagr_array[3] = {0.1, 0.5, 0.9}; // compute_lagrangian_radii(b, // lagr_array, 3, // false, // not verbose // 4); // mass filter // rhalf = lagr_array[1]; cerr << rhalf<< " "; } cerr << endl; rmtree(b); } }
/* * Load all replication slots from disk into memory at server startup. This * needs to be run before we start crash recovery. */ void StartupReplicationSlots(XLogRecPtr checkPointRedo) { DIR *replication_dir; struct dirent *replication_de; ereport(DEBUG1, (errmsg("starting up replication slots"))); /* restore all slots by iterating over all on-disk entries */ replication_dir = AllocateDir("pg_replslot"); while ((replication_de = ReadDir(replication_dir, "pg_replslot")) != NULL) { struct stat statbuf; char path[MAXPGPATH]; if (strcmp(replication_de->d_name, ".") == 0 || strcmp(replication_de->d_name, "..") == 0) continue; snprintf(path, MAXPGPATH, "pg_replslot/%s", replication_de->d_name); /* we're only creating directories here, skip if it's not our's */ if (lstat(path, &statbuf) == 0 && !S_ISDIR(statbuf.st_mode)) continue; /* we crashed while a slot was being setup or deleted, clean up */ if (string_endswith(replication_de->d_name, ".tmp")) { if (!rmtree(path, true)) { ereport(WARNING, (errcode_for_file_access(), errmsg("could not remove directory \"%s\"", path))); continue; } fsync_fname("pg_replslot", true); continue; } /* looks like a slot in a normal state, restore */ RestoreSlotFromDisk(replication_de->d_name); } FreeDir(replication_dir); /* currently no slots exist, we're done. */ if (max_replication_slots <= 0) return; /* Now that we have recovered all the data, compute replication xmin */ ReplicationSlotsComputeRequiredXmin(); ReplicationSlotsComputeRequiredLSN(); }
int queue_message_incoming_delete(uint32_t msgid) { char rootdir[MAXPATHLEN]; if (! queue_message_incoming_path(msgid, rootdir, sizeof(rootdir))) fatal("queue_message_incoming_delete: snprintf"); if (rmtree(rootdir, 0) == -1) fatal("queue_message_incoming_delete: rmtree"); return 1; }
/* * Delete the given subdirectory contents from the new cluster */ static void remove_new_subdir(const char *subdir, bool rmtopdir) { char new_path[MAXPGPATH]; prep_status("Deleting files from new %s", subdir); snprintf(new_path, sizeof(new_path), "%s/%s", new_cluster.pgdata, subdir); if (!rmtree(new_path, rmtopdir)) pg_fatal("could not delete directory \"%s\"\n", new_path); check_ok(); }
void testutil_init(void) { test_is_not_null(getcwd(orig_wd, PATH_MAX), "get startup working dir"); rmtree("test_tmp"); test_call_ok(mkdir("test_tmp", 0777), strerror(errno), "make test_tmp directory"); test_call_ok(chdir("test_tmp"), strerror(errno), "cd into test_tmp directory"); }
static void copy_clog_xlog_xid(void) { char old_clog_path[MAXPGPATH]; char new_clog_path[MAXPGPATH]; /* copy old commit logs to new data dir */ prep_status("Deleting new commit clogs"); snprintf(old_clog_path, sizeof(old_clog_path), "%s/pg_clog", old_cluster.pgdata); snprintf(new_clog_path, sizeof(new_clog_path), "%s/pg_clog", new_cluster.pgdata); if (!rmtree(new_clog_path, true)) pg_log(PG_FATAL, "could not delete directory \"%s\"\n", new_clog_path); check_ok(); prep_status("Copying old commit clogs to new server"); exec_prog(true, false, UTILITY_LOG_FILE, #ifndef WIN32 SYSTEMQUOTE "%s \"%s\" \"%s\" >> \"%s\" 2>&1" SYSTEMQUOTE, "cp -Rf", #else /* flags: everything, no confirm, quiet, overwrite read-only */ SYSTEMQUOTE "%s \"%s\" \"%s\\\" >> \"%s\" 2>&1" SYSTEMQUOTE, "xcopy /e /y /q /r", #endif old_clog_path, new_clog_path, UTILITY_LOG_FILE); check_ok(); /* set the next transaction id of the new cluster */ prep_status("Setting next transaction ID for new cluster"); exec_prog(true, true, UTILITY_LOG_FILE, SYSTEMQUOTE "\"%s/pg_resetxlog\" -f -x %u \"%s\" >> \"%s\" 2>&1" SYSTEMQUOTE, new_cluster.bindir, old_cluster.controldata.chkpnt_nxtxid, new_cluster.pgdata, UTILITY_LOG_FILE); check_ok(); /* now reset the wal archives in the new cluster */ prep_status("Resetting WAL archives"); exec_prog(true, true, UTILITY_LOG_FILE, SYSTEMQUOTE "\"%s/pg_resetxlog\" -l %u,%u,%u \"%s\" >> \"%s\" 2>&1" SYSTEMQUOTE, new_cluster.bindir, old_cluster.controldata.chkpnt_tli, old_cluster.controldata.logid, old_cluster.controldata.nxtlogseg, new_cluster.pgdata, UTILITY_LOG_FILE); check_ok(); }
/* * Terminate */ void timeshift_filemgr_term ( void ) { char path[512]; /* Wait for thread */ pthread_mutex_lock(×hift_reaper_lock); timeshift_reaper_run = 0; pthread_cond_signal(×hift_reaper_cond); pthread_mutex_unlock(×hift_reaper_lock); pthread_join(timeshift_reaper_thread, NULL); /* Remove the lot */ timeshift_filemgr_get_root(path, sizeof(path)); rmtree(path); }
/* * Physically delete a spill file set. Path is assumed to be database relative. */ static void workfile_mgr_unlink_directory(const char *dirpath) { elog(gp_workfile_caching_loglevel, "deleting spill file set directory %s", dirpath); int res = rmtree(dirpath,true); if (!res) { ereport(ERROR, (errcode(ERRCODE_IO_ERROR), errmsg("could not remove spill file directory"))); } }
/* * Initialise global structures */ void timeshift_filemgr_init ( void ) { char path[512]; /* Try to remove any rubbish left from last run */ timeshift_filemgr_get_root(path, sizeof(path)); rmtree(path); /* Start the reaper thread */ timeshift_reaper_run = 1; pthread_mutex_init(×hift_reaper_lock, NULL); pthread_cond_init(×hift_reaper_cond, NULL); TAILQ_INIT(×hift_reaper_list); pthread_create(×hift_reaper_thread, NULL, timeshift_reaper_callback, NULL); }
/* Process one pgsql_tmp directory for RemovePgTempFiles */ static void RemovePgTempFilesInDir(const char *tmpdirname) { DIR *temp_dir; struct dirent *temp_de; char rm_path[MAXPGPATH]; temp_dir = AllocateDir(tmpdirname); if (temp_dir == NULL) { /* anything except ENOENT is fishy */ if (errno != ENOENT) elog(LOG, "could not open temporary-files directory \"%s\": %m", tmpdirname); return; } while ((temp_de = ReadDir(temp_dir, tmpdirname)) != NULL) { if (strcmp(temp_de->d_name, ".") == 0 || strcmp(temp_de->d_name, "..") == 0) continue; snprintf(rm_path, sizeof(rm_path), "%s/%s", tmpdirname, temp_de->d_name); if (HasTempFilePrefix(temp_de->d_name)) { /* * It can be a file or a directory, so try to delete both ways * We ignore errors. */ unlink(rm_path); rmtree(rm_path,true); } else { elog(LOG, "unexpected file found in temporary-files directory: \"%s\"", rm_path); } } FreeDir(temp_dir); }
void hts_settings_remove(const char *pathfmt, ...) { char fullpath[256]; va_list ap; struct stat st; va_start(ap, pathfmt); _hts_settings_buildpath(fullpath, sizeof(fullpath), pathfmt, ap, settingspath); va_end(ap); if (stat(fullpath, &st) == 0) { if (S_ISDIR(st.st_mode)) rmtree(fullpath); else unlink(fullpath); } }
/*----------------------------------------------------------------------------- * main -- driver to create directly a single node *----------------------------------------------------------------------------- */ main(int argc, char ** argv) { bool c_flag = FALSE; bool i_flag = FALSE; real m = 1; // default mass: unity char *comment; check_help(); extern char *poptarg; int c; const char *param_string = "c:im:"; while ((c = pgetopt(argc, argv, param_string, "$Revision: 1.7 $", _SRC_)) != -1) switch(c) { case 'c': c_flag = TRUE; comment = poptarg; break; case 'i': i_flag = TRUE; break; case 'm': m = atof(poptarg); break; case '?': params_to_usage(cerr, argv[0], param_string); get_help(); exit(1); } node * root; root = new node(); root->set_root(root); root->set_mass(m); if (c_flag == TRUE) root->log_comment(comment); root->log_history(argc, argv); if (i_flag) root->set_label(1); put_node(root); rmtree(root); }
static LPWSTR make_unpack_dir() { WCHAR buf[4*MAX_PATH] = {0}; LPWSTR ans = NULL; if (directory_exists(L"_unpack_calibre_portable")) rmtree(L"_unpack_calibre_portable"); if (!CreateDirectory(L"_unpack_calibre_portable", NULL) && GetLastError() != ERROR_ALREADY_EXISTS) { show_last_error(L"Failed to create temporary folder to unpack into"); return ans; } if (!GetFullPathName(L"_unpack_calibre_portable", 4*MAX_PATH, buf, NULL)) { show_last_error(L"Failed to resolve path"); return NULL; } ans = _wcsdup(buf); if (ans == NULL) show_error(L"Out of memory"); return ans; }
static int report(Test *t) { int nfail = 0, nerr = 0; putchar('\n'); for (; t->f; t++) { rmtree(t->dir); if (!t->status) { continue; } printf("\n%s: ", t->name); if (failed(t->status)) { nfail++; printf("failure"); } else { nerr++; printf("error"); if (WIFEXITED(t->status)) { printf(" (exit status %d)", WEXITSTATUS(t->status)); } if (WIFSIGNALED(t->status)) { printf(" (signal %d)", WTERMSIG(t->status)); } } putchar('\n'); lseek(t->fd, 0, SEEK_SET); copyfd(stdout, t->fd); } if (nfail || nerr) { printf("\n%d failures; %d errors.\n", nfail, nerr); } else { printf("\nPASS\n"); } return nfail || nerr; }
bool rmforest(Forest* f) { // ensure source is not NULL if (f == NULL) { return false; } // clear forest's trees while (f->first != NULL) { Plot* plot = f->first; f->first = f->first->next; rmtree(plot->tree); free(plot); } // free forest free(f); // success! return true; }
/* Removes path and all of its children. Writes errors to stderr and keeps going. If path doesn't exist, rmtree returns silently. */ static void rmtree(char *path) { int r = unlink(path); if (r == 0 || errno == ENOENT) { return; /* success */ } int unlinkerr = errno; DIR *d = opendir(path); if (!d) { if (errno == ENOTDIR) { fprintf(stderr, "ct: unlink: %s\n", strerror(unlinkerr)); } else { perror("ct: opendir"); } fprintf(stderr, "ct: path %s\n", path); return; } struct dirent *ent; while ((ent = readdir(d))) { if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) { continue; } int n = strlen(path) + 1 + strlen(ent->d_name); char s[n+1]; sprintf(s, "%s/%s", path, ent->d_name); rmtree(s); } closedir(d); r = rmdir(path); if (r == -1) { perror("ct: rmdir"); fprintf(stderr, "ct: path %s\n", path); } }
/* * rmtree * * Delete a directory tree recursively. * Assumes path points to a valid directory. * Deletes everything under path. * If rmtopdir is true deletes the directory too. * Returns true if successful, false if there was any problem. * (The details of the problem are reported already, so caller * doesn't really have to say anything more, but most do.) */ bool rmtree(const char *path, bool rmtopdir) { bool result = true; char pathbuf[MAXPGPATH]; char **filenames; char **filename; struct stat statbuf; /* * we copy all the names out of the directory before we start modifying * it. */ filenames = pgfnames(path); if (filenames == NULL) return false; /* now we have the names we can start removing things */ for (filename = filenames; *filename; filename++) { snprintf(pathbuf, MAXPGPATH, "%s/%s", path, *filename); /* * It's ok if the file is not there anymore; we were just about to * delete it anyway. * * This is not an academic possibility. One scenario where this * happens is when bgwriter has a pending unlink request for a file in * a database that's being dropped. In dropdb(), we call * ForgetDatabaseFsyncRequests() to flush out any such pending unlink * requests, but because that's asynchronous, it's not guaranteed that * the bgwriter receives the message in time. */ if (lstat(pathbuf, &statbuf) != 0) { if (errno != ENOENT) { #ifndef FRONTEND elog(WARNING, "could not stat file or directory \"%s\": %m", pathbuf); #else fprintf(stderr, _("could not stat file or directory \"%s\": %s\n"), pathbuf, strerror(errno)); #endif result = false; } continue; } if (S_ISDIR(statbuf.st_mode)) { /* call ourselves recursively for a directory */ if (!rmtree(pathbuf, true)) { /* we already reported the error */ result = false; } } else { if (unlink(pathbuf) != 0) { if (errno != ENOENT) { #ifndef FRONTEND elog(WARNING, "could not remove file or directory \"%s\": %m", pathbuf); #else fprintf(stderr, _("could not remove file or directory \"%s\": %s\n"), pathbuf, strerror(errno)); #endif result = false; } } } } if (rmtopdir) { if (rmdir(path) != 0) { #ifndef FRONTEND elog(WARNING, "could not remove file or directory \"%s\": %m", path); #else fprintf(stderr, _("could not remove file or directory \"%s\": %s\n"), path, strerror(errno)); #endif result = false; } } pgfnames_cleanup(filenames); return result; }
int main(int argc, char* argv[]) { // ensure proper usage if (argc != 3) { printf("Usage: %s input output\n", argv[0]); return 1; } // open input Huffile* input = hfopen(argv[1], "r"); if (input == NULL) { printf("Could not open %s for reading.\n", argv[1]); return 1; } // open outfile FILE* outfile = fopen(argv[2], "w"); // read in header Huffeader header; if (hread(&header, input) == false) { hfclose(input); printf("Could not read header.\n"); return 1; } // check for magic number if (header.magic != MAGIC) { hfclose(input); printf("File was not huffed.\n"); return 1; } // check checksum int checksum = header.checksum; for (int i = 0; i < SYMBOLS; i++) { checksum -= header.frequencies[i]; } if (checksum != 0) { hfclose(input); printf("File was not huffed.\n"); return 1; } // make forest Forest* forest = mkforest(); // search for symbols that are non-zero frequency for (int i = 0; i < SYMBOLS; i++) { // make and plant the trees in the forest if (header.frequencies[i] >= 1) { Tree* newTree = mktree(); newTree->frequency = header.frequencies[i]; newTree->symbol = i; newTree->left = NULL; newTree->right = NULL; plant(forest, newTree); } } // run loop until there is only one tree left bool done = false; while (!done) { // pick smallest tree Tree* a = pick(forest); // pick second smallest tree Tree* b = pick(forest); // if there is only one tree left in the forest, a is the huffman tree if (b == NULL) { done = true; root = a; } // if two trees were succesfully picked else { // combine the two trees by calling the combine function Tree* combinedTree = combine(a, b); // plant combined tree back in forest plant(forest, combinedTree); } } // write message to file int bit; Tree* cursor = root; while ((bit = bread(input)) != EOF) { // if bit == 0 -> go left if (bit == 0) { cursor = cursor->left; } // if bit == 1 -> go right else if (bit == 1) { cursor = cursor->right; } // when you find a leaf if ((cursor->right == NULL) && (cursor->left == NULL)) { // print the leaf fprintf(outfile, "%c", cursor->symbol); // reset the cursor to root for the next iteration cursor = root; } } // free root rmtree(root); // close forest rmforest(forest); // close input hfclose(input); // close outfile fclose(outfile); // that's all folks! return 0; }