static int recover_finishing(struct async *as, struct sdirs *sdirs, struct conf **cconfs) { int r; char msg[128]=""; struct asfd *asfd=as->asfd; logp("Found finishing symlink - attempting to complete prior backup!\n"); snprintf(msg, sizeof(msg), "Now finalising previous backup of client. " "Please try again later."); asfd->write_str(asfd, CMD_ERROR, msg); // Do not need the client connected any more. // Disconnect. logp("Disconnect from client.\n"); as->asfd_remove(as, asfd); asfd_close(asfd); switch(get_protocol(cconfs)) { case PROTO_1: r=backup_phase4_server_protocol1(sdirs, cconfs); break; case PROTO_2: default: r=backup_phase4_server_protocol2(sdirs, cconfs); break; } if(r) { logp("Problem with prior backup. Please check the client log on the server."); return -1; } logp("Prior backup completed OK.\n"); // Move the symlink to indicate that we are now in the end // phase. // FIX THIS: Check whether the rename race condition is recoverable // here. if(do_rename(sdirs->finishing, sdirs->current)) return -1; return 0; }
static int do_rename_w(const char *a, const char *b, const char *cname, struct bu *bu) { int ret=-1; char *target=NULL; char new_name[256]=""; snprintf(new_name, sizeof(new_name), "%s-%s", cname, bu->basename); if(!(target=prepend_s(b, new_name)) || build_path_w(target)) goto end; if(do_rename(a, target)) { logp("Error when trying to rename for delete %s\n", a); goto end; } ret=0; end: free_w(&target); return ret; }
int make_backup(char *fname) { char fnamebak[MAXPATHLEN]; if (strlen(fname) + strlen(backup_suffix) > (MAXPATHLEN-1)) { rprintf(FERROR,"backup filename too long\n"); return 0; } slprintf(fnamebak,sizeof(fnamebak),"%s%s",fname,backup_suffix); if (do_rename(fname,fnamebak) != 0) { /* cygwin (at least version b19) reports EINVAL */ if (errno != ENOENT && errno != EINVAL) { rprintf(FERROR,"rename %s %s : %s\n",fname,fnamebak,strerror(errno)); return 0; } } else if (verbose > 1) { rprintf(FINFO,"backed up %s to %s\n",fname,fnamebak); } return 1; }
int main(int argc, char *argv[]) { char *init_cwd; pid_t pid; int status; int ret = 1; if (argc != 2) { printf("Usage: %s <dir>\n", argv[0]); exit(1); } init_cwd = argv[1]; ret = chdir(init_cwd); if (ret < 0) { perror("chdir failed"); exit(1); } if (signal(SIGALRM, sigproc) == SIG_ERR) { perror("signal failed"); exit(1); } alarm(TIMEOUT); pid = fork(); if (pid < 0) { perror("fork failed"); exit(1); } else if (pid == 0) { do_rename("t_getcwd_testfile"); } else { ret = test_getcwd(init_cwd); kill(pid, SIGTERM); waitpid(pid, &status, 0); } exit(ret); }
/* Make it atomic by linking to a temporary file, then moving it into place. */ static int do_hardlink(struct file *o, struct file *n, const char *ext) { int ret=-1; char *tmppath=NULL; if(!(tmppath=prepend(o->path, ext, ""))) { log_out_of_memory(__func__); goto end; } if(link(n->path, tmppath)) { logp("Could not hardlink %s to %s: %s\n", tmppath, n->path, strerror(errno)); goto end; } if((ret=do_rename(tmppath, o->path))) goto end; ret=0; end: free_w(&tmppath); return ret; }
/* Make it atomic by linking to a temporary file, then moving it into place. */ static int do_hardlink(struct file *o, struct file *n, const char *ext) { char *tmppath=NULL; if(!(tmppath=prepend(o->path, ext, ""))) { logp("out of memory\n"); return -1; } if(link(n->path, tmppath)) { logp("Could not hardlink %s to %s: %s\n", tmppath, n->path, strerror(errno)); free(tmppath); return -1; } if(do_rename(tmppath, o->path)) { free(tmppath); return -1; } free(tmppath); return 0; }
static int merge_into_global_sparse(const char *sparse, const char *global, struct conf **confs) { int ret=-1; char *tmpfile=NULL; struct stat statp; char *lockfile=NULL; struct lock *lock=NULL; const char *globalsrc=NULL; if(!(tmpfile=prepend_n(global, "tmp", strlen("tmp"), "."))) goto end; // Get a lock before messing with the global sparse index. if(!(lockfile=prepend_n(global, "lock", strlen("lock"), ".")) || !(lock=lock_alloc_and_init(lockfile))) goto end; if(try_to_get_lock(lock)) goto end; if(!lstat(global, &statp)) globalsrc=global; if(merge_sparse_indexes(sparse, globalsrc, tmpfile, confs)) goto end; // FIX THIS: nasty race condition needs to be recoverable. if(do_rename(tmpfile, global)) goto end; ret=0; end: lock_release(lock); lock_free(&lock); if(lockfile) free(lockfile); if(tmpfile) free(tmpfile); return ret; }
int compress_file(const char *src, const char *dst, struct config *cconf) { char *dsttmp=NULL; pid_t pid=getpid(); char p[12]=""; snprintf(p, sizeof(p), "%d", (int)pid); if(!(dsttmp=prepend(dst, p, strlen(p), 0 /* no slash */))) return -1; // Need to compress the log. logp("Compressing %s to %s...\n", src, dst); if(compress(src, dsttmp, cconf) || do_rename(dsttmp, dst)) { unlink(dsttmp); free(dsttmp); return -1; } // succeeded - get rid of the uncompressed version unlink(src); free(dsttmp); return 0; }
int main(int argc, char **argv) { int a; if (argc == 1) { printf("usage: %s file [file ...]\n", argv[0]); exit(1); } for (a = 1;a < argc;a++) { if (strcmp("-v", argv[a]) == 0) { _verbose++; continue; } do_rename(argv[a]); } return 0; }
int main(void) { char dir_src[PATH_MAX]; char dir_dst[PATH_MAX]; EXPECT_ZERO(get_tempdir(dir_src, PATH_MAX, 0755)); EXPECT_ZERO(register_tempdir_for_cleanup(dir_src)); EXPECT_ZERO(get_tempdir(dir_dst, PATH_MAX, 0755)); EXPECT_ZERO(register_tempdir_for_cleanup(dir_dst)); /* test rename /src/a -> /dst/m, a as file, m as file */ EXPECT_ZERO(do_touch2(dir_src, "a")); EXPECT_ZERO(do_touch2(dir_dst, "m")); EXPECT_ZERO(do_rename(dir_src, "a", dir_dst, "m")); /* test rename /src/b -> /dst/n, b as file, n as dir */ EXPECT_ZERO(do_touch2(dir_src, "b")); EXPECT_ZERO(do_test_mkdir(dir_dst, "n")); EXPECT_EQ(do_rename(dir_src, "b", dir_dst, "n"), -EISDIR); /* test rename /src/c -> /dst/o, c as dir, o as file */ EXPECT_ZERO(do_test_mkdir(dir_src, "c")); EXPECT_ZERO(do_touch2(dir_dst, "o")); EXPECT_EQ(do_rename(dir_src, "c", dir_dst, "o"), -ENOTDIR); /* test rename /src/d -> /dst/p, d as dir, p as dir */ EXPECT_ZERO(do_test_mkdir(dir_src, "d")); EXPECT_ZERO(do_test_mkdir(dir_dst, "p")); EXPECT_ZERO(do_rename(dir_src, "d", dir_dst, "p")); /* test rename /src/e -> /dst/q, e as file, q as nonexistent */ EXPECT_ZERO(do_touch2(dir_src, "e")); EXPECT_ZERO(do_rename(dir_src, "e", dir_dst, "q")); /* test rename /src/f -> /dst/r, f as dir, r as nonexistent */ EXPECT_ZERO(do_test_mkdir(dir_src, "f")); EXPECT_ZERO(do_rename(dir_src, "f", dir_dst, "r")); return 0; }
/* Return 1 for everything OK, signed and returned, -1 for error, 0 for nothing done. */ int ca_client_setup(struct config *conf, struct cntr *p1cntr) { char cmd; int ret=-1; size_t len=0; char *buf=NULL; char csr_path[256]=""; char ssl_cert_tmp[512]=""; char ssl_cert_ca_tmp[512]=""; struct stat statp; // Do not continue if we have none of the following things set. if( !conf->ca_burp_ca || !conf->ca_csr_dir || !conf->ssl_cert_ca || !conf->ssl_cert || !conf->ssl_key // Do not try to get a new certificate if we already have a // key. || !lstat(conf->ssl_key, &statp)) { if(async_write_str(CMD_GEN, "nocsr") || async_read_expect(CMD_GEN, "nocsr ok")) { logp("problem reading from server nocsr\n"); return -1; } logp("nocsr ok\n"); return 0; } // Tell the server we want to do a signing request. if(async_write_str(CMD_GEN, "csr")) return -1; if(async_rw_ensure_read(&cmd, &buf, &len, '\0', NULL, 0)) { logp("problem reading from server csr\n"); goto end; } if(cmd!=CMD_GEN || strncmp(buf, "csr ok:", strlen("csr ok:"))) { logp("unexpected command from server: %c:%s\n", cmd, buf); goto end; } // The server appends its name after 'csr ok:' if(conf->ssl_peer_cn) free(conf->ssl_peer_cn); if(!(conf->ssl_peer_cn=strdup(buf+strlen("csr ok:")))) { logp("out of memory\n"); goto end; } logp("Server will sign a certificate request\n"); // First need to generate a client key and a certificate signing // request. snprintf(csr_path, sizeof(csr_path), "%s/%s.csr", conf->ca_csr_dir, conf->cname); if(generate_key_and_csr(conf, csr_path)) goto end; // Then copy the csr to the server. if(send_a_file(csr_path, p1cntr)) goto end; snprintf(ssl_cert_tmp, sizeof(ssl_cert_tmp), "%s.%d", conf->ssl_cert, getpid()); snprintf(ssl_cert_ca_tmp, sizeof(ssl_cert_ca_tmp), "%s.%d", conf->ssl_cert_ca, getpid()); // The server will then sign it, and give it back. if(receive_a_file(ssl_cert_tmp, p1cntr)) goto end; // The server will also send the CA certificate. if(receive_a_file(ssl_cert_ca_tmp, p1cntr)) goto end; if(do_rename(ssl_cert_tmp, conf->ssl_cert) || do_rename(ssl_cert_ca_tmp, conf->ssl_cert_ca)) goto end; // Need to rewrite our configuration file to contain the server // name (ssl_peer_cn) if(rewrite_client_conf(conf)) goto end; // My goodness, everything seems to have gone OK. Stand back! ret=1; end: if(buf) free(buf); if(ret<0) { // On error, remove any possibly newly created files, so that // this function might run again on another go. unlink(csr_path); unlink(conf->ssl_key); unlink(conf->ssl_cert); unlink(conf->ssl_cert_ca); unlink(ssl_cert_tmp); unlink(ssl_cert_ca_tmp); } return ret; }
/* * Try to revert everything we have done in __rename_all and __rename_all_unlink */ static int __rename_all_revert(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry, fd_set * success_mask, struct rename_info *info) { int bindex; int err; int eio = 0; print_entry_location(); for (bindex = info->old_bstart; bindex <= info->old_bend; bindex++) { if (!FD_ISSET(bindex, success_mask)) continue; err = unionfs_refresh_hidden_dentry(new_dentry, bindex); if (err) { printk(KERN_WARNING "Revert failed in rename: " "the new refresh failed.\n"); eio = -EIO; } err = unionfs_refresh_hidden_dentry(old_dentry, bindex); if (err) { printk(KERN_WARNING "Revert failed in rename: " "the old refresh failed.\n"); eio = -EIO; continue; } if (!dtohd_index(new_dentry, bindex) || !dtohd_index(new_dentry, bindex)->d_inode) { printk(KERN_WARNING "Revert failed in rename: " "the object disappeared from under us!\n"); eio = -EIO; continue; } if (dtohd_index(old_dentry, bindex) && dtohd_index(old_dentry, bindex)->d_inode) { printk(KERN_WARNING "Revert failed in rename: " "the object was created underneath us!\n"); eio = -EIO; continue; } err = do_rename(new_dir, new_dentry, old_dir, old_dentry, bindex, NULL); /* If we can't fix it, then we cop-out with -EIO. */ if (err) { printk(KERN_WARNING "Revert failed in rename!\n"); eio = -EIO; } err = unionfs_refresh_hidden_dentry(new_dentry, bindex); if (err) eio = -EIO; err = unionfs_refresh_hidden_dentry(old_dentry, bindex); if (err) eio = -EIO; } print_exit_status(eio); return eio; }
// Combine the phase1 and phase2 files into a new manifest. int backup_phase3_server_all(struct sdirs *sdirs, struct conf **confs) { int ret=-1; int pcmp=0; struct blk *blk=NULL; struct sbuf *usb=NULL; struct sbuf *csb=NULL; char *manifesttmp=NULL; struct manio *newmanio=NULL; struct manio *chmanio=NULL; struct manio *unmanio=NULL; enum protocol protocol=get_protocol(confs); struct cntr *cntr=get_cntr(confs); const char *rmanifest_relative=NULL; logp("Begin phase3 (merge manifests)\n"); if(protocol==PROTO_2) rmanifest_relative=get_rmanifest_relative(sdirs, confs); if(!(manifesttmp=get_tmp_filename(sdirs->manifest)) || !(newmanio=manio_open_phase3(manifesttmp, comp_level(get_int(confs[OPT_COMPRESSION])), protocol, rmanifest_relative)) || !(chmanio=manio_open_phase2(sdirs->changed, "rb", protocol)) || !(unmanio=manio_open_phase2(sdirs->unchanged, "rb", protocol)) || !(usb=sbuf_alloc(protocol)) || !(csb=sbuf_alloc(protocol))) goto end; while(chmanio || unmanio) { if(!blk && !(blk=blk_alloc())) goto end; if(unmanio && !usb->path.buf) { switch(manio_read(unmanio, usb)) { case -1: goto end; case 1: manio_close(&unmanio); } } if(chmanio && !csb->path.buf) { switch(manio_read(chmanio, csb)) { case -1: goto end; case 1: manio_close(&chmanio); } } if(usb->path.buf && !csb->path.buf) { if(write_status(CNTR_STATUS_MERGING, usb->path.buf, cntr)) goto end; switch(manio_copy_entry( usb, usb, &blk, unmanio, newmanio)) { case -1: goto end; case 1: manio_close(&unmanio); } } else if(!usb->path.buf && csb->path.buf) { if(write_status(CNTR_STATUS_MERGING, csb->path.buf, cntr)) goto end; switch(manio_copy_entry( csb, csb, &blk, chmanio, newmanio)) { case -1: goto end; case 1: manio_close(&chmanio); } } else if(!usb->path.buf && !csb->path.buf) { continue; } else if(!(pcmp=sbuf_pathcmp(usb, csb))) { // They were the same - write one. if(write_status(CNTR_STATUS_MERGING, csb->path.buf, cntr)) goto end; switch(manio_copy_entry( csb, csb, &blk, chmanio, newmanio)) { case -1: goto end; case 1: manio_close(&chmanio); } } else if(pcmp<0) { if(write_status(CNTR_STATUS_MERGING, usb->path.buf, cntr)) goto end; switch(manio_copy_entry( usb, usb, &blk, unmanio, newmanio)) { case -1: goto end; case 1: manio_close(&unmanio); } } else { if(write_status(CNTR_STATUS_MERGING, csb->path.buf, cntr)) goto end; switch(manio_copy_entry( csb, csb, &blk, chmanio, newmanio)) { case -1: goto end; case 1: manio_close(&chmanio); } } } // Flush to disk. if(manio_close(&newmanio)) { logp("error gzclosing %s in backup_phase3_server\n", manifesttmp); goto end; } // Rename race condition should be of no consequence here, as the // manifest should just get recreated automatically. if(do_rename(manifesttmp, sdirs->manifest)) goto end; else { recursive_delete(sdirs->changed); recursive_delete(sdirs->unchanged); } logp("End phase3 (merge manifests)\n"); ret=0; end: manio_close(&newmanio); manio_close(&chmanio); manio_close(&unmanio); sbuf_free(&csb); sbuf_free(&usb); blk_free(&blk); free_w(&manifesttmp); return ret; }
// This is basically backup_phase3_server() from protocol1. It used to merge the // unchanged and changed data into a single file. Now it splits the manifests // into several files. int backup_phase3_server_protocol2(struct sdirs *sdirs, struct conf **confs) { int ret=1; int pcmp=0; char *hooksdir=NULL; char *dindexdir=NULL; char *manifesttmp=NULL; struct sbuf *usb=NULL; struct sbuf *csb=NULL; struct blk *blk=NULL; int finished_ch=0; int finished_un=0; struct manio *newmanio=NULL; struct manio *chmanio=NULL; struct manio *unmanio=NULL; uint64_t fcount=0; logp("Start phase3\n"); if(!(manifesttmp=get_tmp_filename(sdirs->rmanifest)) || !(newmanio=manio_alloc()) || !(chmanio=manio_alloc()) || !(unmanio=manio_alloc()) || !(hooksdir=prepend_s(manifesttmp, "hooks")) || !(dindexdir=prepend_s(manifesttmp, "dindex")) || manio_init_write(newmanio, manifesttmp) || manio_init_write_hooks(newmanio, get_string(confs[OPT_DIRECTORY]), hooksdir, sdirs->rmanifest) || manio_init_write_dindex(newmanio, dindexdir) || manio_init_read(chmanio, sdirs->changed) || manio_init_read(unmanio, sdirs->unchanged) || !(usb=sbuf_alloc(confs)) || !(csb=sbuf_alloc(confs))) goto end; while(!finished_ch || !finished_un) { if(!blk && !(blk=blk_alloc())) goto end; if(!finished_un && usb && !usb->path.buf) { switch(manio_sbuf_fill(unmanio, NULL /* no async */, usb, NULL, NULL, confs)) { case -1: goto end; case 1: finished_un++; } } if(!finished_ch && csb && !csb->path.buf) { switch(manio_sbuf_fill(chmanio, NULL /* no async */, csb, NULL, NULL, confs)) { case -1: goto end; case 1: finished_ch++; } } if((usb && usb->path.buf) && (!csb || !csb->path.buf)) { switch(manio_copy_entry(NULL /* no async */, &usb, usb, &blk, unmanio, newmanio, confs)) { case -1: goto end; case 1: finished_un++; } } else if((!usb || !usb->path.buf) && (csb && csb->path.buf)) { switch(manio_copy_entry(NULL /* no async */, &csb, csb, &blk, chmanio, newmanio, confs)) { case -1: goto end; case 1: finished_ch++; } } else if((!usb || !usb->path.buf) && (!csb || !(csb->path.buf))) { continue; } else if(!(pcmp=sbuf_pathcmp(usb, csb))) { // They were the same - write one. switch(manio_copy_entry(NULL /* no async */, &csb, csb, &blk, chmanio, newmanio, confs)) { case -1: goto end; case 1: finished_ch++; } } else if(pcmp<0) { switch(manio_copy_entry(NULL /* no async */, &usb, usb, &blk, unmanio, newmanio, confs)) { case -1: goto end; case 1: finished_un++; } } else { switch(manio_copy_entry(NULL /* no async */, &csb, csb, &blk, chmanio, newmanio, confs)) { case -1: goto end; case 1: finished_ch++; } } } fcount=newmanio->fcount; // Flush to disk and set up for reading. if(manio_free(&newmanio) || !(newmanio=manio_alloc()) || manio_init_read(newmanio, sdirs->rmanifest)) goto end; // Rename race condition should be of no consequence here, as the // manifest should just get recreated automatically. if(do_rename(manifesttmp, sdirs->rmanifest)) goto end; else { recursive_delete(sdirs->changed, NULL, 1); recursive_delete(sdirs->unchanged, NULL, 1); } if(sparse_generation(newmanio, fcount, sdirs, confs)) goto end; ret=0; logp("End phase3\n"); end: manio_free(&newmanio); manio_free(&chmanio); manio_free(&unmanio); sbuf_free(&csb); sbuf_free(&usb); blk_free(&blk); free_w(&hooksdir); free_w(&dindexdir); free_w(&manifesttmp); return ret; }
/** * Creates a veh_interact window based on the given parameters. * @param v The vehicle the player is interacting with. * @param x The x-coordinate of the square the player is 'e'xamining. * @param y The y-coordinate of the square the player is 'e'xamining. */ void veh_interact::exec (game *gm, vehicle *v, int x, int y) { g = gm; veh = v; // x1 x2 // y1 ----+------+-- // | | // y2 ----+------+ // | // | winw1 = 12; winw2 = 35; winh1 = 3; winh2 = 12; winw12 = winw1 + winw2 + 1; winw3 = FULL_SCREEN_WIDTH - winw1 - winw2 - 2; winh3 = FULL_SCREEN_HEIGHT - winh1 - winh2 - 2; winh23 = winh2 + winh3 + 1; winx1 = winw1; winx2 = winw1 + winw2 + 1; winy1 = winh1; winy2 = winh1 + winh2 + 1; // changed FALSE value to 1, to keep w_border from starting at a negative x,y const int iOffsetX = (TERMX > FULL_SCREEN_WIDTH) ? (TERMX-FULL_SCREEN_WIDTH)/2 : 1; const int iOffsetY = (TERMY > FULL_SCREEN_HEIGHT) ? (TERMY-FULL_SCREEN_HEIGHT)/2 : 1; page_size = winh23; // h w y x WINDOW *w_border= newwin(FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, -1 + iOffsetY, -1 + iOffsetX); w_grid = newwin(FULL_SCREEN_HEIGHT -2, FULL_SCREEN_WIDTH-2, iOffsetY, iOffsetX); w_mode = newwin(1, FULL_SCREEN_WIDTH-2, iOffsetY, iOffsetX); w_msg = newwin(winh1 - 1, FULL_SCREEN_WIDTH-2, 1 + iOffsetY, iOffsetX); w_disp = newwin(winh2-1, winw1, winy1 + 1 + iOffsetY, iOffsetX); w_parts = newwin(winh2-1, winw2, winy1 + 1 + iOffsetY, winx1 + 1 + iOffsetX); w_stats = newwin(winh3-1, winw12, winy2 + iOffsetY, iOffsetX); w_list = newwin(winh23, winw3, winy1 + 1 + iOffsetY, winx2 + 1 + iOffsetX); wborder(w_border, LINE_XOXO, LINE_XOXO, LINE_OXOX, LINE_OXOX, LINE_OXXO, LINE_OOXX, LINE_XXOO, LINE_XOOX ); mvwputch(w_border, 16, 0, c_ltgray, LINE_XXXO); // |- mvwputch(w_border, 4, 0, c_ltgray, LINE_XXXO); // |- mvwputch(w_border, 4, FULL_SCREEN_WIDTH-1, c_ltgray, LINE_XOXX); // -| mvwputch(w_border, 24, 49, c_ltgray, LINE_XXOX); wrefresh(w_border); for (int i = 0; i < FULL_SCREEN_HEIGHT; i++) { mvwputch(w_grid, i, winx2, c_ltgray, i == winy1 || i == winy2-1? LINE_XOXX : LINE_XOXO); if (i >= winy1 && i < winy2) { mvwputch(w_grid, i, winx1, c_ltgray, LINE_XOXO); } } for (int i = 0; i < FULL_SCREEN_WIDTH; i++) { mvwputch(w_grid, winy1, i, c_ltgray, i == winx1? LINE_OXXX : (i == winx2? LINE_OXXX : LINE_OXOX)); if (i < winx2) { mvwputch(w_grid, winy2-1, i, c_ltgray, i == winx1? LINE_XXOX : LINE_OXOX); } } wrefresh(w_grid); crafting_inv = gm->crafting_inventory(&gm->u); int charges = static_cast<it_tool *>(g->itypes["welder"])->charges_per_use; int charges_crude = static_cast<it_tool *>(g->itypes["welder_crude"])->charges_per_use; has_wrench = crafting_inv.has_amount("wrench", 1) || crafting_inv.has_amount("toolset", 1); has_hacksaw = crafting_inv.has_amount("hacksaw", 1) || crafting_inv.has_amount("toolset", 1); has_welder = (crafting_inv.has_amount("welder", 1) && crafting_inv.has_charges("welder", charges)) || (crafting_inv.has_amount("welder_crude", 1) && crafting_inv.has_charges("welder_crude", charges_crude)) || (crafting_inv.has_amount("toolset", 1) && crafting_inv.has_charges("toolset", charges/20)); has_jack = crafting_inv.has_amount("jack", 1); has_siphon = crafting_inv.has_amount("hose", 1); has_wheel = crafting_inv.has_amount( "wheel", 1 ) || crafting_inv.has_amount( "wheel_wide", 1 ) || crafting_inv.has_amount( "wheel_bicycle", 1 ) || crafting_inv.has_amount( "wheel_motorbike", 1 ) || crafting_inv.has_amount( "wheel_small", 1 ); display_stats (); display_veh (); move_cursor (0, 0); bool finish = false; while (!finish) { char ch = input(); // See keypress.h int dx, dy; get_direction (dx, dy, ch); if (ch == KEY_ESCAPE || ch == 'q' ) { finish = true; } else { if (dx != -2 && (dx || dy) && cursor_x + dx >= -6 && cursor_x + dx < 6 && cursor_y + dy >= -6 && cursor_y + dy < 6) { move_cursor(dx, dy); } else { int mval = cant_do(ch); display_mode (ch); switch (ch) { case 'i': do_install(mval); break; case 'r': do_repair(mval); break; case 'f': do_refill(mval); break; case 'o': do_remove(mval); break; case 'e': do_rename(mval); break; case 's': do_siphon(mval); break; case 'c': do_tirechange(mval); break; case 'd': do_drain(mval); break; } if (sel_cmd != ' ') { finish = true; } display_mode (' '); } } } werase(w_grid); werase(w_mode); werase(w_msg); werase(w_disp); werase(w_parts); werase(w_stats); werase(w_list); delwin(w_grid); delwin(w_mode); delwin(w_msg); delwin(w_disp); delwin(w_parts); delwin(w_stats); delwin(w_list); erase(); }
/* * Finish off the rename, by either over writing the last destination or * unlinking the last destination to the left of us */ static int __rename_all_clobber(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry, struct rename_info *info) { int err = 0; print_entry_location(); if (dtohd_index(old_dentry, info->new_bstart)) { /* rename the last source, knowing we're overwriting something */ DPUT(info->wh_old); info->bwh_old = info->new_bstart; err = do_rename(old_dir, old_dentry, new_dir, new_dentry, info->new_bstart, &info->wh_old); if (IS_COPYUP_ERR(err)) { if (info->isdir) { err = -EXDEV; goto out; } if (info->rename_ok > info->new_bstart) { if ((info->do_copyup == -1) || (info->new_bstart - 1 < info->do_copyup)) info->do_copyup = info->new_bstart - 1; } if ((info->do_whiteout == -1) || (info->new_bstart - 1 < info->do_whiteout)) { info->do_whiteout = info->new_bstart - 1; } err = 0; // reset error } } else if (info->new_bstart < info->old_bstart) { /* the newly renamed file would get hidden, let's unlink the * file to the left of it */ struct dentry *unlink_dentry; struct dentry *unlink_dir_dentry; unlink_dentry = dtohd_index(new_dentry, info->new_bstart); unlink_dir_dentry = lock_parent(unlink_dentry); if (!(err = is_robranch_super(old_dir->i_sb, info->new_bstart))) err = vfs_unlink(unlink_dir_dentry->d_inode, unlink_dentry); fist_copy_attr_times(new_dentry->d_parent->d_inode, unlink_dir_dentry->d_inode); new_dentry->d_parent->d_inode->i_nlink = get_nlinks(new_dentry->d_parent->d_inode); unlock_dir(unlink_dir_dentry); if (IS_COPYUP_ERR(err)) { if (info->isdir) { err = -EXDEV; goto out; } if ((info->do_copyup == -1) || (info->new_bstart - 1 < info->do_copyup)) info->do_copyup = info->new_bstart - 1; err = 0; // reset error } } out: print_exit_status(err); return err; }
int backup_phase4_server_protocol2(struct sdirs *sdirs, struct conf **confs) { int ret=-1; uint64_t i=0; uint64_t pass=0; char *sparse=NULL; char *global_sparse=NULL; char *h1dir=NULL; char *h2dir=NULL; char *hooksdir=NULL; char *srca=NULL; char *srcb=NULL; char *dst=NULL; char compa[32]=""; char compb[32]=""; char compd[32]=""; struct manio *newmanio=NULL; char *logpath=NULL; char *fmanifest=NULL; // FIX THIS: should be part of sdirs. if(!(logpath=prepend_s(sdirs->finishing, "log"))) goto end; if(set_logfp(logpath, confs)) goto end; logp("Begin phase4 (sparse generation)\n"); if(!(newmanio=manio_alloc()) || !(fmanifest=prepend_s(sdirs->finishing, "manifest")) || manio_init_read(newmanio, fmanifest) || manio_read_fcount(newmanio) || !(hooksdir=prepend_s(fmanifest, "hooks")) || !(h1dir=prepend_s(fmanifest, "h1")) || !(h2dir=prepend_s(fmanifest, "h2"))) goto end; while(1) { char *srcdir=NULL; char *dstdir=NULL; if(!pass) { srcdir=hooksdir; dstdir=h1dir; } else if(pass%2) { srcdir=h1dir; dstdir=h2dir; } else { srcdir=h2dir; dstdir=h1dir; } pass++; for(i=0; i<newmanio->offset.fcount; i+=2) { free_w(&srca); free_w(&srcb); free_w(&dst); snprintf(compa, sizeof(compa), "%08"PRIX64, i); snprintf(compb, sizeof(compb), "%08"PRIX64, i+1); snprintf(compd, sizeof(compd), "%08"PRIX64, i/2); if(!(srca=prepend_s(srcdir, compa)) || !(dst=prepend_s(dstdir, compd))) goto end; if(i+1<newmanio->offset.fcount && !(srcb=prepend_s(srcdir, compb))) goto end; if(merge_sparse_indexes(srca, srcb, dst, confs)) goto end; } if((newmanio->offset.fcount=i/2)<2) break; } if(!(sparse=prepend_s(fmanifest, "sparse")) || !(global_sparse=prepend_s(sdirs->data, "sparse"))) goto end; // FIX THIS: nasty race condition here needs to be automatically // recoverable. if(do_rename(dst, sparse)) goto end; if(merge_into_global_sparse(sparse, global_sparse, confs)) goto end; logp("End phase4 (sparse generation)\n"); ret=0; end: manio_free(&newmanio); free_w(&sparse); free_w(&global_sparse); free_w(&srca); free_w(&srcb); recursive_delete(h1dir, NULL, 1); recursive_delete(h2dir, NULL, 1); free_w(&h1dir); free_w(&h2dir); free_w(&logpath); free_w(&fmanifest); return ret; }
/* Need to make all the stuff that this does atomic so that existing backups never get broken, even if somebody turns the power off on the server. */ static int atomic_data_jiggle(struct sdirs *sdirs, struct fdirs *fdirs, int hardlinked_current, struct conf *cconf, unsigned long bno) { int ars=0; int ret=-1; char *datapth=NULL; char *tmpman=NULL; struct stat statp; char *deltabdir=NULL; char *deltafdir=NULL; char *sigpath=NULL; gzFile zp=NULL; struct sbuf *sb=NULL; FILE *delfp=NULL; logp("Doing the atomic data jiggle...\n"); if(!(tmpman=get_tmp_filename(fdirs->manifest))) goto end; if(lstat(fdirs->manifest, &statp)) { // Manifest does not exist - maybe the server was killed before // it could be renamed. logp("%s did not exist - trying %s\n", fdirs->manifest, tmpman); // Rename race condition is of no consequence, because manifest // already does not exist. do_rename(tmpman, fdirs->manifest); } if(!(zp=gzopen_file(fdirs->manifest, "rb"))) goto end; if(!(deltabdir=prepend_s(fdirs->currentdup, "deltas.reverse")) || !(deltafdir=prepend_s(sdirs->finishing, "deltas.forward")) || !(sigpath=prepend_s(fdirs->currentdup, "sig.tmp")) || !(sb=sbuf_alloc(cconf))) { log_out_of_memory(__func__); goto end; } mkdir(fdirs->datadir, 0777); while(!(ars=sbufl_fill(sb, NULL, NULL, zp, cconf->cntr))) { if(sb->burp1->datapth.buf) { if(write_status(STATUS_SHUFFLING, sb->burp1->datapth.buf, cconf)) goto end; if((ret=jiggle(sdirs, fdirs, sb, hardlinked_current, deltabdir, deltafdir, sigpath, &delfp, cconf))) goto end; } sbuf_free_content(sb); } if(ars<0) goto end; if(close_fp(&delfp)) { logp("error closing %s in atomic_data_jiggle\n", fdirs->deletionsfile); goto end; } if(maybe_delete_files_from_manifest(tmpman, fdirs, cconf)) goto end; // Remove the temporary data directory, we have probably removed // useful files from it. sync(); // try to help CIFS recursive_delete(deltafdir, NULL, 0 /* do not del files */); end: gzclose_fp(&zp); close_fp(&delfp); sbuf_free(&sb); free_w(&deltabdir); free_w(&deltafdir); free_w(&sigpath); free_w(&datapth); free_w(&tmpman); return ret; }
int backup_phase4_server_burp1(struct sdirs *sdirs, struct conf *cconf) { int ret=-1; struct stat statp; ssize_t len=0; char realcurrent[256]=""; unsigned long bno=0; int hardlinked_current=0; char tstmp[64]=""; int previous_backup=0; struct fdirs *fdirs=NULL; if((len=readlink(sdirs->current, realcurrent, sizeof(realcurrent)-1))<0) len=0; realcurrent[len]='\0'; if(!(fdirs=fdirs_alloc()) || fdirs_init(fdirs, sdirs, realcurrent)) goto end; if(set_logfp(fdirs->logpath, cconf)) goto end; logp("Begin phase4 (shuffle files)\n"); if(write_status(STATUS_SHUFFLING, NULL, cconf)) goto end; if(!lstat(sdirs->current, &statp)) // Had a previous backup. { previous_backup++; if(lstat(fdirs->hlinkedcurrent, &statp)) { hardlinked_current=0; logp("Previous backup is not a hardlinked_archive\n"); logp(" will generate reverse deltas\n"); } else { hardlinked_current=1; logp("Previous backup is a hardlinked_archive\n"); logp(" will not generate reverse deltas\n"); } // If current was not a hardlinked_archive, need to duplicate // it. if(!hardlinked_current && lstat(fdirs->currentdup, &statp)) { // Have not duplicated the current backup yet. if(!lstat(fdirs->currentduptmp, &statp)) { logp("Removing previous directory: %s\n", fdirs->currentduptmp); if(recursive_delete(fdirs->currentduptmp, NULL, 1 /* del files */)) { logp("Could not delete %s\n", fdirs->currentduptmp); goto end; } } logp("Duplicating current backup.\n"); if(recursive_hardlink(sdirs->current, fdirs->currentduptmp, cconf) // The rename race condition is of no consequence here // because currentdup does not exist. || do_rename(fdirs->currentduptmp, fdirs->currentdup)) goto end; } } if(timestamp_read(fdirs->timestamp, tstmp, sizeof(tstmp))) { logp("could not read timestamp file: %s\n", fdirs->timestamp); goto end; } // Get the backup number. bno=strtoul(tstmp, NULL, 10); // Determine whether the new backup should be a hardlinked // archive or not, from the conf and the backup number... if(need_hardlinked_archive(cconf, bno)) { // Create a file to indicate that the previous backup // does not have others depending on it. FILE *hfp=NULL; if(!(hfp=open_file(fdirs->hlinked, "wb"))) goto end; // Stick the next backup timestamp in it. It might // be useful one day when wondering when the next // backup, now deleted, was made. fprintf(hfp, "%s\n", tstmp); if(close_fp(&hfp)) { logp("error closing hardlinked indication\n"); goto end; } } else unlink(fdirs->hlinked); if(atomic_data_jiggle(sdirs, fdirs, hardlinked_current, cconf, bno)) { logp("could not finish up backup.\n"); goto end; } if(write_status(STATUS_SHUFFLING, "deleting temporary files", cconf)) goto end; // Remove the temporary data directory, we have now removed // everything useful from it. recursive_delete(fdirs->datadirtmp, NULL, 1 /* del files */); // Clean up the currentdata directory - this is now the 'old' // currentdata directory. Any files that were deleted from // the client will be left in there, so call recursive_delete // with the option that makes it not delete files. // This will have the effect of getting rid of unnecessary // directories. sync(); // try to help CIFS recursive_delete(fdirs->currentdupdata, NULL, 0 /* do not del files */); // Rename the old current to something that we know to delete. if(previous_backup && !hardlinked_current) { if(deleteme_move(sdirs->client, fdirs->fullrealcurrent, realcurrent, cconf) // I have tested that potential race conditions on the // rename() are automatically recoverable here. || do_rename(fdirs->currentdup, fdirs->fullrealcurrent)) goto end; } if(deleteme_maybe_delete(cconf, sdirs->client)) goto end; cntr_stats_to_file(cconf->cntr, sdirs->finishing, ACTION_BACKUP); logp("End phase4 (shuffle files)\n"); ret=0; end: fdirs_free(fdirs); return ret; }
/* * The function is nasty, nasty, nasty, but so is rename. :( */ static int unionfs_rename_all(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { struct dentry *parent_dentry = NULL; int err = 0; int eio; /* These variables control error handling. */ fd_set success_mask; char *name = NULL; /* unfortunately, we have to resort to this, because dbstart/dbend would return different things in different place of the rename code */ struct rename_info info; info.rename_ok = FD_SETSIZE; /* The last rename that is ok. */ info.do_copyup = -1; /* Where we should start copyup. */ info.do_whiteout = -1; /* Where we should start whiteouts of the source. */ info.wh_old = NULL; info.bwh_old = -1; print_entry_location(); parent_dentry = old_dentry->d_parent; name = KMALLOC(old_dentry->d_name.len + 1, GFP_KERNEL); if (!name) { err = -ENOMEM; goto out; } strncpy(name, old_dentry->d_name.name, old_dentry->d_name.len + 1); info.new_bstart = dbstart(new_dentry); info.new_bend = dbend(new_dentry); info.old_bstart = dbstart(old_dentry); info.old_bend = dbend(old_dentry); BUG_ON(info.new_bstart < 0); BUG_ON(info.old_bstart < 0); /* The failure mask only can deal with FD_SETSIZE entries. */ BUG_ON(info.old_bend > FD_SETSIZE); BUG_ON(info.new_bend > FD_SETSIZE); FD_ZERO(&success_mask); /* Life is simpler if the dentry doesn't exist. */ info.clobber = (dtohd_index(new_dentry, info.new_bstart)->d_inode) ? 1 : 0; info.isdir = S_ISDIR(old_dentry->d_inode->i_mode); /* rename everything we can */ err = __rename_all(old_dir, old_dentry, new_dir, new_dentry, &success_mask, &info); if (err) goto revert; /* unlink destinations even further left */ err = __rename_all_unlink(old_dir, old_dentry, new_dir, new_dentry, &info); if (err) goto revert; if (info.clobber) { /* Now we need to handle the leftmost of the destination. */ err = __rename_all_clobber(old_dir, old_dentry, new_dir, new_dentry, &info); if (err) goto revert; } /* Copy up if necessary */ if (info.do_copyup != -1) { int bindex; for (bindex = info.do_copyup; bindex >= 0; bindex--) { err = copyup_dentry(old_dentry->d_parent->d_inode, old_dentry, info.old_bstart, bindex, NULL, old_dentry->d_inode->i_size); if (!err) { DPUT(info.wh_old); info.bwh_old = bindex; err = do_rename(old_dir, old_dentry, new_dir, new_dentry, bindex, &info.wh_old); break; } } } /* Create a whiteout for the source. */ if (info.do_whiteout != -1) { struct dentry *hidden_parent; BUG_ON(info.do_whiteout < 0 || !info.wh_old || IS_ERR(info.wh_old) || info.wh_old->d_inode || info.bwh_old < 0); hidden_parent = lock_parent(info.wh_old); err = vfs_create(hidden_parent->d_inode, info.wh_old, S_IRUGO, NULL); unlock_dir(hidden_parent); if (!err) set_dbopaque(old_dentry, info.bwh_old); else { /* We can't fix anything now, so we -EIO. */ printk(KERN_WARNING "We can't create a whiteout for the" "source in rename!\n"); err = -EIO; goto out; } } /* We are at the point where reverting doesn't happen. */ goto out; revert: /* something bad happened, try to revert */ eio = __rename_all_revert(old_dir, old_dentry, new_dir, new_dentry, &success_mask, &info); if (eio) err = eio; out: DPUT(info.wh_old); KFREE(name); print_exit_status(err); return err; }
static int maybe_delete_files_from_manifest(const char *manifesttmp, struct fdirs *fdirs, struct conf *cconf) { int ars=0; int ret=-1; int pcmp=0; FILE *dfp=NULL; gzFile nmzp=NULL; gzFile omzp=NULL; struct sbuf *db=NULL; struct sbuf *mb=NULL; struct stat statp; if(lstat(fdirs->deletionsfile, &statp)) // No deletions, no problem. return 0; logp("Performing deletions on manifest\n"); if(!(manifesttmp=get_tmp_filename(fdirs->manifest))) goto end; if(!(dfp=open_file(fdirs->deletionsfile, "rb")) || !(omzp=gzopen_file(fdirs->manifest, "rb")) || !(nmzp=gzopen_file(manifesttmp, comp_level(cconf))) || !(db=sbuf_alloc(cconf)) || !(mb=sbuf_alloc(cconf))) goto end; while(omzp || dfp) { if(dfp && !db->path.buf && (ars=sbufl_fill(db, NULL, dfp, NULL, cconf->cntr))) { if(ars<0) goto end; // ars==1 means it ended ok. close_fp(&dfp); } if(omzp && !mb->path.buf && (ars=sbufl_fill(mb, NULL, NULL, omzp, cconf->cntr))) { if(ars<0) goto end; // ars==1 means it ended ok. gzclose_fp(&omzp); } if(mb->path.buf && !db->path.buf) { if(sbufl_to_manifest(mb, NULL, nmzp)) goto end; sbuf_free_content(mb); } else if(!mb->path.buf && db->path.buf) { sbuf_free_content(db); } else if(!mb->path.buf && !db->path.buf) { continue; } else if(!(pcmp=sbuf_pathcmp(mb, db))) { // They were the same - do not write. sbuf_free_content(mb); sbuf_free_content(db); } else if(pcmp<0) { // Behind in manifest. Write. if(sbufl_to_manifest(mb, NULL, nmzp)) goto end; sbuf_free_content(mb); } else { // Behind in deletions file. Do not write. sbuf_free_content(db); } } ret=0; end: if(gzclose_fp(&nmzp)) { logp("error closing %s in %s\n", manifesttmp, __func__); ret=-1; } close_fp(&dfp); gzclose_fp(&omzp); sbuf_free(&db); sbuf_free(&mb); if(!ret) { unlink(fdirs->deletionsfile); // The rename race condition is not a problem here, as long // as manifesttmp is the same path as that generated in the // atomic data jiggle. if(do_rename(manifesttmp, fdirs->manifest)) return -1; } if(manifesttmp) unlink(manifesttmp); return ret; }
void *extra_self_tests(int arg1, void *arg2) { /* creating /test1/test2/ directories */ dbg(DBG_ERROR | DBG_VFS,"TEST: Creating directories\n"); do_mkdir("dir"); do_mkdir("dir/dir1"); do_mkdir("dir/dir2"); do_mkdir("dir/dir3"); do_mkdir("dir/dir4"); dbg(DBG_ERROR | DBG_VFS,"TEST: Directories are created\n"); int fd; char *file2buf="File 2 write only test case"; char *file1buf="Testing file_1 for write operation"; char readbuf[150]; dbg(DBG_ERROR | DBG_VFS,"TEST: Change directory to dir/dir1\n"); do_chdir("dir/dir1"); /* file1.txt creation with O_CREAT|O_WRONLY flag*/ dbg(DBG_ERROR | DBG_VFS,"TEST: Create file1.txt with O_CREAT|O_WRONLY flag in directory dir/dir1\n"); fd = do_open("file1.txt", O_CREAT|O_WRONLY); do_write(fd, file1buf, strlen(file1buf)); do_close(fd); /* file2.txt creation with O_CREAT|O_RDONLY flag*/ dbg(DBG_ERROR | DBG_VFS,"TEST: Change directory to dir/dir2\n"); do_chdir("/dir/dir2"); dbg(DBG_ERROR | DBG_VFS,"TEST: Create file2.txt with O_CREAT | O_RDONLY flag in directory dir/dir2\n"); fd = do_open("file2.txt", O_CREAT | O_RDONLY); do_close(fd); /* Write into file2.txt using O_WRONLY flag*/ dbg(DBG_ERROR | DBG_VFS,"TEST: Write into file2.txt with O_WRONLY flag in directory dir/dir2\n"); fd = do_open("file2.txt", O_WRONLY); do_write(fd, file2buf, strlen(file2buf)); do_close(fd); dbg(DBG_ERROR | DBG_VFS,"TEST: written chars: \"%s\" in file2.txt\n",file2buf); char *appendbuf=" Appending for O_WRONLY|O_APPEND mode"; /* Append into file2.txt using O_WRONLY|O_APPEND flag*/ dbg(DBG_ERROR | DBG_VFS,"TEST: Append into file2.txt with O_WRONLY|O_APPEND flag in directory dir/dir2\n"); fd = do_open("file2.txt", O_WRONLY|O_APPEND); do_write(fd, appendbuf, strlen(appendbuf)); do_close(fd); dbg(DBG_ERROR | DBG_VFS,"TEST: Appending chars: \"%s\" in file2.txt\n",appendbuf); fd = do_open("file2.txt", O_RDONLY); memset(readbuf,0,sizeof(char)*150); do_read(fd,readbuf,strlen(file2buf)+strlen(appendbuf)); dbg(DBG_ERROR | DBG_VFS,"TEST: After Appending text in file2.txt is: \"%s\" \n",readbuf); char *append2buf=" Appending for O_RDWR|O_APPEND mode in file2"; /* Append into file2.txt using O_RDWR|O_APPEND flag*/ dbg(DBG_ERROR | DBG_VFS,"TEST: Append into file2.txt with O_RDWR|O_APPEND flag in directory dir/dir2\n"); fd = do_open("file2.txt", O_RDWR|O_APPEND); do_write(fd, append2buf, strlen(append2buf)); do_close(fd); dbg(DBG_ERROR | DBG_VFS,"TEST: Appending chars: \"%s\" in file2.txt\n",append2buf); fd = do_open("file2.txt", O_RDONLY); memset(readbuf,0,sizeof(char)*150); do_read(fd,readbuf,strlen(file2buf)+strlen(append2buf)+strlen(appendbuf)); dbg(DBG_ERROR | DBG_VFS,"TEST: After Appending text in file2.txt is: \"%s\" \n",readbuf); dbg(DBG_ERROR | DBG_VFS,"TEST:Linking Source directory => /dir/dir2, Destination directory => /dir/linkofdir2 \n"); do_chdir("/"); do_link("dir/dir2","dir/linkofdir2"); dbg(DBG_ERROR | DBG_VFS,"TEST:Linking Source file => /dir/dir1/file1.txt, to the Destination => /dir/linkoffile1 \n"); do_link("dir/dir1/file1.txt","dir/linkoffile1"); dbg(DBG_ERROR | DBG_VFS,"TEST: Renaming directory from dir/dir3 to dir/renamed \n"); do_rename("dir/dir3","dir/renameddir3"); dbg(DBG_ERROR | DBG_VFS,"TEST: Renaming file from dir/dir1/file1.txt to dir/dir1/renamedfile1.txt \n"); do_rename("dir/dir1/file1.txt","dir/dir1/renamedfile1.txt"); dbg(DBG_ERROR | DBG_VFS,"TEST: Removing directory dir/dir4 \n"); do_rmdir("dir/dir4"); dbg(DBG_ERROR | DBG_VFS,"TEST: reading 18 chars from file: /dir/linkoffile2 which is hard link of /dir/dir2/file2.txt \n"); fd = do_open("dir/linkoffile2", O_RDONLY); memset(readbuf,0,sizeof(char)*150); do_close(fd); dbg(DBG_ERROR | DBG_VFS,"TEST: read 18 chars: \"%s\" from file: /dir/linkoffile1\n",readbuf); dbg(DBG_ERROR | DBG_VFS,"TEST: reading file using lseek function on /dir/linkoffile2 which is hard link of /dir/dir2/file2.txt \n"); memset(readbuf,0,sizeof(char)*150); fd = do_open("dir/linkoffile2", O_RDONLY); do_lseek(fd,-19,2); do_read(fd,readbuf,19); do_close(fd); dbg(DBG_ERROR | DBG_VFS,"TEST: read chars: \"%s\" using lseek from file: /dir/linkoffile1\n",readbuf); dbg(DBG_ERROR | DBG_VFS,"TEST: creating a duplicate file descriptor of file: /dir/dir2/file2.txt using do_dup()\n"); fd = do_open("/dir/dir2/file2.txt", O_RDONLY); int fd2= do_dup(fd); dbg(DBG_ERROR | DBG_VFS,"TEST: duplicate file descriptor is :\"%d\" of file: /dir/dir2/file2.txt \n",fd2); do_close(fd); do_close(fd2); dbg(DBG_ERROR | DBG_VFS,"TEST: creating a duplicate file descriptor of file: /dir/dir2/file2.txt using do_dup2()\n"); fd = do_open("/dir/dir2/file2.txt", O_RDONLY); fd2= do_dup2(fd,20); dbg(DBG_ERROR | DBG_VFS,"TEST: custom file descriptor is :\"%d\" of file: /dir/dir2/file2.txt \n",fd2); do_close(fd); do_close(fd2); /* Testing stat struct *statbuf; dbg(DBG_ERROR | DBG_VFS,"TEST: Testing the stat system call for directory dir\n"); do_stat("dir",statbuf); dbg(DBG_ERROR | DBG_VFS,"TEST: Output of stat for directory dir is :\"%s\" \n",statbuf);*/ shellTest(); return NULL; }
int aufs_rename(struct inode *_src_dir, struct dentry *_src_dentry, struct inode *_dst_dir, struct dentry *_dst_dentry) { int err, flags; /* reduce stack space */ struct au_ren_args *a; AuDbg("%.*s, %.*s\n", AuDLNPair(_src_dentry), AuDLNPair(_dst_dentry)); IMustLock(_src_dir); IMustLock(_dst_dir); err = -ENOMEM; BUILD_BUG_ON(sizeof(*a) > PAGE_SIZE); a = kzalloc(sizeof(*a), GFP_NOFS); if (unlikely(!a)) goto out; a->src_dir = _src_dir; a->src_dentry = _src_dentry; a->src_inode = a->src_dentry->d_inode; a->src_parent = a->src_dentry->d_parent; /* dir inode is locked */ a->dst_dir = _dst_dir; a->dst_dentry = _dst_dentry; a->dst_inode = a->dst_dentry->d_inode; a->dst_parent = a->dst_dentry->d_parent; /* dir inode is locked */ if (a->dst_inode) { IMustLock(a->dst_inode); au_igrab(a->dst_inode); } err = -ENOTDIR; flags = AuLock_FLUSH | AuLock_NOPLM | AuLock_GEN; if (S_ISDIR(a->src_inode->i_mode)) { au_fset_ren(a->flags, ISDIR); if (unlikely(a->dst_inode && !S_ISDIR(a->dst_inode->i_mode))) goto out_free; err = aufs_read_and_write_lock2(a->dst_dentry, a->src_dentry, AuLock_DIR | flags); } else err = aufs_read_and_write_lock2(a->dst_dentry, a->src_dentry, flags); if (unlikely(err)) goto out_free; err = au_d_hashed_positive(a->src_dentry); if (unlikely(err)) goto out_unlock; err = -ENOENT; if (a->dst_inode) { /* * If it is a dir, VFS unhash dst_dentry before this * function. It means we cannot rely upon d_unhashed(). */ if (unlikely(!a->dst_inode->i_nlink)) goto out_unlock; if (!S_ISDIR(a->dst_inode->i_mode)) { err = au_d_hashed_positive(a->dst_dentry); if (unlikely(err)) goto out_unlock; } else if (unlikely(IS_DEADDIR(a->dst_inode))) goto out_unlock; } else if (unlikely(d_unhashed(a->dst_dentry))) goto out_unlock; au_fset_ren(a->flags, ISSAMEDIR); /* temporary */ di_write_lock_parent(a->dst_parent); /* which branch we process */ err = au_ren_wbr(a); if (unlikely(err < 0)) goto out_parent; a->br = au_sbr(a->dst_dentry->d_sb, a->btgt); a->h_path.mnt = a->br->br_mnt; /* are they available to be renamed */ err = au_ren_may_dir(a); if (unlikely(err)) goto out_children; /* prepare the writable parent dir on the same branch */ if (a->dst_bstart == a->btgt) { au_fset_ren(a->flags, WHDST); } else { err = au_cpup_dirs(a->dst_dentry, a->btgt); if (unlikely(err)) goto out_children; } if (a->src_dir != a->dst_dir) { /* * this temporary unlock is safe, * because both dir->i_mutex are locked. */ di_write_unlock(a->dst_parent); di_write_lock_parent(a->src_parent); err = au_wr_dir_need_wh(a->src_dentry, au_ftest_ren(a->flags, ISDIR), &a->btgt); di_write_unlock(a->src_parent); di_write_lock2_parent(a->src_parent, a->dst_parent, /*isdir*/1); au_fclr_ren(a->flags, ISSAMEDIR); } else err = au_wr_dir_need_wh(a->src_dentry, au_ftest_ren(a->flags, ISDIR), &a->btgt); if (unlikely(err < 0)) goto out_children; if (err) au_fset_ren(a->flags, WHSRC); /* lock them all */ err = au_ren_lock(a); if (unlikely(err)) goto out_children; if (!au_opt_test(au_mntflags(a->dst_dir->i_sb), UDBA_NONE)) err = au_may_ren(a); else if (unlikely(a->dst_dentry->d_name.len > AUFS_MAX_NAMELEN)) err = -ENAMETOOLONG; if (unlikely(err)) goto out_hdir; /* store timestamps to be revertible */ au_ren_dt(a); /* here we go */ err = do_rename(a); if (unlikely(err)) goto out_dt; /* update dir attributes */ au_ren_refresh_dir(a); /* dput/iput all lower dentries */ au_ren_refresh(a); goto out_hdir; /* success */ out_dt: au_ren_rev_dt(err, a); out_hdir: au_ren_unlock(a); out_children: au_nhash_wh_free(&a->whlist); if (err && a->dst_inode && a->dst_bstart != a->btgt) { AuDbg("bstart %d, btgt %d\n", a->dst_bstart, a->btgt); au_set_h_dptr(a->dst_dentry, a->btgt, NULL); au_set_dbstart(a->dst_dentry, a->dst_bstart); } out_parent: if (!err) d_move(a->src_dentry, a->dst_dentry); else { au_update_dbstart(a->dst_dentry); if (!a->dst_inode) d_drop(a->dst_dentry); } if (au_ftest_ren(a->flags, ISSAMEDIR)) di_write_unlock(a->dst_parent); else di_write_unlock2(a->src_parent, a->dst_parent); out_unlock: aufs_read_and_write_unlock2(a->dst_dentry, a->src_dentry); out_free: iput(a->dst_inode); if (a->thargs) au_whtmp_rmdir_free(a->thargs); kfree(a); out: AuTraceErr(err); return err; }
void veh_interact::exec (game *gm, vehicle *v, int x, int y) { g = gm; veh = v; ex = x; ey = y; // x1 x2 // y1 ----+------+-- // | | // y2 ----+------+ // | // | winw1 = 12; winw2 = 35; winh1 = 3; winh2 = 12; winw12 = winw1 + winw2 + 1; winw3 = 80 - winw1 - winw2 - 2; winh3 = 25 - winh1 - winh2 - 2; winh23 = winh2 + winh3 + 1; winx1 = winw1; winx2 = winw1 + winw2 + 1; winy1 = winh1; winy2 = winh1 + winh2 + 1; page_size = winh23; // h w y x w_grid = newwin(25, 80, 0, 0); w_mode = newwin(1, 80, 0, 0); w_msg = newwin(winh1 - 1, 80, 1, 0); w_disp = newwin(winh2, winw1, winy1 + 1, 0); w_parts = newwin(winh2, winw2, winy1 + 1, winx1 + 1); w_stats = newwin(winh3, winw12, winy2 + 1, 0); w_list = newwin(winh23, winw3, winy1 + 1, winx2 + 1); for (int i = 0; i < 25; i++) { mvwputch(w_grid, i, winx2, c_ltgray, i == winy1 || i == winy2? LINE_XOXX : LINE_XOXO); if (i >= winy1 && i < winy2) mvwputch(w_grid, i, winx1, c_ltgray, LINE_XOXO); } for (int i = 0; i < 80; i++) { mvwputch(w_grid, winy1, i, c_ltgray, i == winx1? LINE_OXXX : (i == winx2? LINE_OXXX : LINE_OXOX)); if (i < winx2) mvwputch(w_grid, winy2, i, c_ltgray, i == winx1? LINE_XXOX : LINE_OXOX); } wrefresh(w_grid); crafting_inv = gm->crafting_inventory(); int charges = ((it_tool *) g->itypes["welder"])->charges_per_use; has_wrench = crafting_inv.has_amount("wrench", 1) || crafting_inv.has_amount("toolset", 1); has_hacksaw = crafting_inv.has_amount("hacksaw", 1) || crafting_inv.has_amount("toolset", 1); has_welder = (crafting_inv.has_amount("welder", 1) && crafting_inv.has_charges("welder", charges)) || (crafting_inv.has_amount("toolset", 1) && crafting_inv.has_charges("toolset", charges/5)); display_stats (); display_veh (); move_cursor (0, 0); bool finish = false; while (!finish) { char ch = input(); // See keypress.h int dx, dy; get_direction (gm, dx, dy, ch); if (ch == KEY_ESCAPE) finish = true; else if (dx != -2 && (dx || dy) && cx + dx >= -6 && cx + dx < 6 && cy + dy >= -6 && cy + dy < 6) move_cursor(dx, dy); else { int mval = cant_do(ch); display_mode (ch); switch (ch) { case 'i': do_install(mval); break; case 'r': do_repair(mval); break; case 'f': do_refill(mval); break; case 'o': do_remove(mval); break; case 'e': do_rename(mval); break; default:; } if (sel_cmd != ' ') finish = true; display_mode (' '); } } werase(w_grid); werase(w_mode); werase(w_msg); werase(w_disp); werase(w_parts); werase(w_stats); werase(w_list); delwin(w_grid); delwin(w_mode); delwin(w_msg); delwin(w_disp); delwin(w_parts); delwin(w_stats); delwin(w_list); erase(); }
// The failure conditions here are dealt with by the rubble cleaning code. static int delete_backup(struct sdirs *sdirs, const char *cname, struct bu *bu, const char *manual_delete) { logp("deleting %s backup %"PRId64"\n", cname, bu->bno); if(sdirs->global_sparse) { const char *candidate_str=bu->path+strlen(sdirs->base)+1; if(remove_from_global_sparse( sdirs->global_sparse, candidate_str)) return -1; } if(!bu->next && !bu->prev) { // The current, and only, backup. if(do_rename_w(bu->path, sdirs->deleteme, cname, bu)) return -1; // If interrupted here, there will be a dangling 'current' // symlink. if(unlink(sdirs->current)) { logp("unlink %s: %s\n", sdirs->current, strerror(errno)); return -1; } return recursive_delete_w(sdirs, bu, manual_delete); } if(!bu->next && bu->prev) { // The current backup. There are other backups left. // Need to point the symlink at the previous backup. const char *target=NULL; target=bu->prev->basename; unlink(sdirs->currenttmp); if(symlink(target, sdirs->currenttmp)) { logp("could not symlink '%s' to '%s': %s\n", sdirs->currenttmp, target, strerror(errno)); return -1; } // If interrupted here, there is a currenttmp and a current // symlink, and they both point to valid directories. if(do_rename_w(bu->path, sdirs->deleteme, cname, bu)) return -1; // If interrupted here, there is a currenttmp and a current // symlink, and the current link is dangling. if(do_rename(sdirs->currenttmp, sdirs->current)) return -1; // If interrupted here, moving the symlink could have failed // after current was deleted but before currenttmp was renamed. if(recursive_delete_w(sdirs, bu, manual_delete)) return -1; return 0; } // It is not the current backup. if(do_rename_w(bu->path, sdirs->deleteme, cname, bu) || recursive_delete_w(sdirs, bu, manual_delete)) return -1; return 0; }
static char *convert_name(char *name, struct stat *st, cnid_t cur_did) { static char buffer[MAXPATHLEN +2]; /* for convert_charset dest_len parameter +2 */ size_t outlen = 0; unsigned char *p,*q; int require_conversion = 0; u_int16_t flags = conv_flags; cnid_t id; p = (unsigned char *)name; q = (unsigned char *)buffer; /* optimize for ascii case */ while (*p != 0) { if ( *p >= 0x80 || *p == ':') { require_conversion = 1; break; } p++; } if (!require_conversion) { if (verbose > 1) fprintf(stdout, "no conversion required\n"); return name; } /* convert charsets */ q=(unsigned char *)buffer; p=(unsigned char *)name; outlen = convert_charset(ch_from, ch_to, ch_mac, (char *)p, strlen((char *)p), (char *)q, sizeof(buffer) -2, &flags); if ((size_t)-1 == outlen) { if ( ch_to == CH_UTF8) { /* maybe name is already in UTF8? */ flags = conv_flags; q = (unsigned char *)buffer; p = (unsigned char *)name; outlen = convert_charset(ch_to, ch_to, ch_mac, (char *)p, strlen((char *)p), (char *)q, sizeof(buffer) -2, &flags); if ((size_t)-1 == outlen) { /* it's not UTF8... */ fprintf(stderr, "ERROR: conversion from '%s' to '%s' for '%s' in DID %u failed!!!\n", from_charset, to_charset, name, ntohl(cur_did)); return name; } if (!strcmp(buffer, name)) { return name; } } fprintf(stderr, "ERROR: conversion from '%s' to '%s' for '%s' in DID %u failed. Please check this!\n", from_charset, to_charset, name, ntohl(cur_did)); return name; } if (strcmp (name, buffer)) { if (dry_run) { fprintf(stdout, "dry_run: would rename %s to %s.\n", name, buffer); } else if (!do_rename(name, buffer, st)) { if (CNID_INVALID != (id = cnid_add(cdb, st, cur_did, buffer, strlen(buffer), 0))) fprintf(stdout, "converted '%s' to '%s' (ID %u, DID %u).\n", name, buffer, ntohl(id), ntohl(cur_did)); } } else if (verbose > 1) fprintf(stdout, "no conversion required\n"); return (buffer); }
static int do_backup_server(struct async *as, struct sdirs *sdirs, struct conf **cconfs, const char *incexc, int resume) { int ret=0; int do_phase2=1; struct asfd *asfd=as->asfd; enum protocol protocol=get_protocol(cconfs); struct cntr *cntr=get_cntr(cconfs); logp("in do_backup_server\n"); log_rshash(cconfs); if(resume) { if(sdirs_get_real_working_from_symlink(sdirs) || sdirs_get_real_manifest(sdirs, protocol) || open_log(asfd, sdirs, cconfs)) goto error; } else { // Not resuming - need to set everything up fresh. if(sdirs_create_real_working(sdirs, get_string(cconfs[OPT_TIMESTAMP_FORMAT])) || sdirs_get_real_manifest(sdirs, protocol) || open_log(asfd, sdirs, cconfs)) goto error; if(write_incexc(sdirs->rworking, incexc)) { logp("unable to write incexc\n"); goto error; } if(backup_phase1_server(as, sdirs, cconfs)) { logp("error in phase 1\n"); goto error; } } if(resume) { struct stat statp; if(lstat(sdirs->phase1data, &statp) && !lstat(sdirs->changed, &statp) && !lstat(sdirs->unchanged, &statp)) { // In this condition, it looks like there was an // interruption during phase3. Skip phase2. do_phase2=0; } } if(do_phase2) { if(backup_phase2_server(as, sdirs, incexc, resume, cconfs)) { logp("error in backup phase 2\n"); goto error; } asfd->write_str(asfd, CMD_GEN, "okbackupend"); } // Close the connection with the client, the rest of the job we can do // by ourselves. logp("Backup ending - disconnect from client.\n"); if(asfd_flush_asio(asfd)) goto end; as->asfd_remove(as, asfd); asfd_close(asfd); if(backup_phase3_server(sdirs, cconfs)) { logp("error in backup phase 3\n"); goto error; } if(do_rename(sdirs->working, sdirs->finishing)) goto error; if(backup_phase4_server(sdirs, cconfs)) { logp("error in backup phase 4\n"); goto error; } cntr_print(cntr, ACTION_BACKUP, asfd); cntr_stats_to_file(cntr, sdirs->rworking, ACTION_BACKUP); if(protocol==PROTO_2) { // Regenerate dindex before the symlink is renamed, so that the // champ chooser cleanup does not try to remove data files // whilst the dindex regeneration is happening. if(regenerate_client_dindex(sdirs)) goto error; } // Move the symlink to indicate that we are now in the end phase. The // rename() race condition is automatically recoverable here. if(do_rename(sdirs->finishing, sdirs->current)) goto error; logp("Backup completed.\n"); log_fzp_set(NULL, cconfs); compress_filename(sdirs->rworking, "log", "log.gz", get_int(cconfs[OPT_COMPRESSION])); goto end; error: ret=-1; end: log_fzp_set(NULL, cconfs); return ret; }
/* Rewrite the config file with the ssl_peer_cn value changed to what the server told us it should be. */ static int rewrite_client_conf(struct config *conf) { int ret=-1; char p[32]=""; FILE *dp=NULL; FILE *sp=NULL; char *tmp=NULL; char buf[4096]=""; logp("Rewriting config file: %s\n", conf->configfile); snprintf(p, sizeof(p), ".%d", getpid()); if(!(tmp=prepend(conf->configfile, p, strlen(p), ""))) goto end; if(!(sp=open_file(conf->configfile, "rb")) || !(dp=open_file(tmp, "wb"))) goto end; while(fgets(buf, sizeof(buf), sp)) { char *copy=NULL; char *field=NULL; char *value=NULL; if(!(copy=strdup(buf))) { logp("out of memory\n"); goto end; } if(config_get_pair(buf, &field, &value) || !field || !value || strcmp(field, "ssl_peer_cn")) { fprintf(dp, "%s", copy); free(copy); continue; } free(copy); fprintf(dp, "ssl_peer_cn = %s\n", conf->ssl_peer_cn); } close_fp(&sp); if(close_fp(&dp)) { logp("error closing %s in rewrite_client_conf\n", tmp); ret=-1; goto end; } #ifdef HAVE_WIN32 // Need to delete the destination, or Windows gets upset. unlink(conf->configfile); #endif if(do_rename(tmp, conf->configfile)) goto end; ret=0; end: close_fp(&sp); close_fp(&dp); if(ret) { logp("Rewrite failed\n"); unlink(tmp); } if(tmp) free(tmp); return ret; }
int vfs_selftest(kshell_t *kshell, int argc, char **argv) { int fd1,fd2; char *y="/ab/fil"; char x[2]; int err; do_mkdir("/ab"); do_mknod("/ab/new", S_IFCHR,MKDEVID(1,1)); fd1=do_open("/ab/new",2); fd2=do_dup2(fd1,NFILES+1); if(fd2<0) { dbg(DBG_PRINT,"File not created\n"); } do_mknod("/ab/notmade",4096,MKDEVID(1,1)); do_mknod("/ab/new/not",S_IFCHR,MKDEVID(1,1)); do_mknod("/ab/new", S_IFCHR,MKDEVID(1,1)); do_mknod("", S_IFCHR,MKDEVID(1,1)); /*do_close(fd1);*/ for(fd2=1;fd2<35;fd2++) { sprintf(x,"%d",fd2); strcat(y,x); do_mknod(y,S_IFCHR,MKDEVID(1,0)); err=do_open(y,2); if(err<0) { break; } if(fd2<10) { y[strlen(y)-1]='\0'; } else { y[strlen(y)-2]='\0'; } } do_mknod("/ab/new1", S_IFCHR,MKDEVID(1,1)); err=do_dup(fd1); do_unlink("/ab/new/ab"); do_unlink("/ab/new"); do_close(fd1); for(fd2=NFILES-1;fd2>0;fd2--) { err=do_close(fd2); sprintf(x,"%d",fd2); strcat(y,x); do_unlink(y); if(err<0) { break; } if(fd2<10) { y[strlen(y)-1]='\0'; } else { y[strlen(y)-2]='\0'; } } do_link("/a","/dev"); do_link("/dev","/a"); do_link("/dev","/a"); do_rmdir("/a"); /* mkdir("/k"); do_link("/ab","/k");*/ do_rmdir("/ab"); /*do_rmdir("/k");*/ /*GS: SELF TESTS*/ dbg(DBG_PRINT,"\n*************************************************************\n"); dbg(DBG_PRINT,"\n\n\n\n(GRADING2C)(kmain.c)(selftest_proc_run) selftests begin\n"); int retVal = 0; int i = 0; /* 1. dbg(DBG_PRINT, "(GRADING2C) (vfs_syscall.c) (do_stat) strlen too long, return -ENAMETOOLONG\n");*/ char longPath[1024 + 1] = {0}; for(i = 0; i < 1025; i++) longPath[i] = 'a'; struct stat buf; retVal = do_stat(longPath, &buf); retVal=do_chdir(longPath); /*2. dbg(DBG_PRINT, "(GRADING2B) ENOTDIR or ENOENT\n");*/ retVal = do_stat("", &buf); /*3. dbg(DBG_PRINT, "(GRADING2C) (vfs_syscall.c) (do_getdent) Invalid file descriptor fd, return -EBADF\n");*/ struct dirent dirp; retVal = do_getdent(-1, &dirp); /*4. dbg(DBG_PRINT, "(GRADING2C) (vfs_syscall.c) (do_getdent) Invalid file descriptor fd, return -EBADF\n");*/ retVal = do_getdent(1, &dirp); /*5. dbg(DBG_PRINT, "(GRADING2C) (vfs_syscall.c) (do_getdent) File descriptor does not refer to a directory, return -ENOTDIR\n");*/ do_mknod("/./file", S_IFCHR,MKDEVID(1,1)); fd1 = do_open("/./file",2); retVal = do_getdent(fd1, &dirp); do_unlink("/./file"); do_close(fd1); /*6. dbg(DBG_PRINT, "(GRADING2C) (vfs_syscall.c) (do_rename) Both are valid names \n");*/ /* and */ /*7. dbg(DBG_PRINT, "(GRADING2C) (vfs_syscall.c) (do_rename) error do_link, return error\n"); \n");*/ retVal = do_rename("/./aaa", "/./bbb"); dbg(DBG_PRINT,"\n\nretVal=%d",retVal); dbg(DBG_PRINT,"\n*************************************************************\n"); return 0; }
static int jiggle(struct sdirs *sdirs, struct fdirs *fdirs, struct sbuf *sb, int hardlinked_current, const char *deltabdir, const char *deltafdir, const char *sigpath, FILE **delfp, struct conf *cconf) { int ret=-1; struct stat statp; char *oldpath=NULL; char *newpath=NULL; char *finpath=NULL; char *deltafpath=NULL; const char *datapth=sb->burp1->datapth.buf; // If the previous backup was a hardlinked_archive, there will not be // a currentdup directory - just directly use the file in the previous // backup. if(!(oldpath=prepend_s(hardlinked_current? sdirs->currentdata:fdirs->currentdupdata, datapth)) || !(newpath=prepend_s(fdirs->datadirtmp, datapth)) || !(finpath=prepend_s(fdirs->datadir, datapth)) || !(deltafpath=prepend_s(deltafdir, datapth))) goto end; if(!lstat(finpath, &statp) && S_ISREG(statp.st_mode)) { // Looks like an interrupted jiggle // did this file already. static int donemsg=0; if(!lstat(deltafpath, &statp) && S_ISREG(statp.st_mode)) { logp("deleting unneeded forward delta: %s\n", deltafpath); unlink(deltafpath); } if(!donemsg) { logp("skipping already present file: %s\n", finpath); logp("to save log space, skips of other already present files will not be logged\n"); donemsg++; } } else if(mkpath(&finpath, fdirs->datadir)) { logp("could not create path for: %s\n", finpath); goto end; } else if(mkpath(&newpath, fdirs->datadirtmp)) { logp("could not create path for: %s\n", newpath); goto end; } else if(!lstat(deltafpath, &statp) && S_ISREG(statp.st_mode)) { int lrs; char *infpath=NULL; // Got a forward patch to do. // First, need to gunzip the old file, // otherwise the librsync patch will take // forever, because it will be doing seeks // all over the place, and gzseeks are slow. if(!(infpath=prepend_s(deltafdir, "inflate"))) { log_out_of_memory(__func__); goto end; } //logp("Fixing up: %s\n", datapth); if(inflate_or_link_oldfile(oldpath, infpath, sb->compression, cconf)) { logp("error when inflating old file: %s\n", oldpath); free(infpath); goto end; } if((lrs=do_patch(NULL, infpath, deltafpath, newpath, cconf->compression, sb->compression /* from the manifest */, cconf))) { logp("WARNING: librsync error when patching %s: %d\n", oldpath, lrs); cntr_add(cconf->cntr, CMD_WARNING, 1); // Try to carry on with the rest of the backup // regardless. //ret=-1; // Remove anything that got written. unlink(newpath); unlink(infpath); free(infpath); // First, note that we want to remove this entry from // the manifest. if(!*delfp && !(*delfp=open_file(fdirs->deletionsfile, "ab"))) { // Could not mark this file as deleted. Fatal. goto end; } if(sbufl_to_manifest(sb, *delfp, NULL)) goto end; if(fflush(*delfp)) { logp("error fflushing deletions file in %s: %s\n", __func__, strerror(errno)); goto end; } ret=0; goto end; } // Get rid of the inflated old file. unlink(infpath); free(infpath); // Need to generate a reverse diff, unless we are keeping a // hardlinked archive. if(!hardlinked_current) { if(gen_rev_delta(sigpath, deltabdir, oldpath, newpath, datapth, sb, cconf)) goto end; } // Power interruptions should be recoverable. If it happens // before this point, the data jiggle for this file has to be // done again. // Once finpath is in place, no more jiggle is required. // Use the fresh new file. // Rename race condition is of no consequence, because finpath // will just get recreated automatically. if(do_rename(newpath, finpath)) goto end; // Remove the forward delta, as it is no longer needed. There // is a reverse diff and the finished finished file is in place. //logp("Deleting delta.forward...\n"); unlink(deltafpath); // Remove the old file. If a power cut happens just before // this, the old file will hang around forever. // FIX THIS: maybe put in something to detect this. // ie, both a reverse delta and the old file exist. if(!hardlinked_current) { //logp("Deleting oldpath...\n"); unlink(oldpath); } } else if(!lstat(newpath, &statp) && S_ISREG(statp.st_mode)) { // Use the fresh new file. // This needs to happen after checking // for the forward delta, because the // patching stuff writes to newpath. // Rename race condition is of no consequence, because finpath // will just get recreated automatically. //logp("Using newly received file\n"); if(do_rename(newpath, finpath)) goto end; } else if(!lstat(oldpath, &statp) && S_ISREG(statp.st_mode)) { // Use the old unchanged file. // Hard link it first. //logp("Hard linking to old file: %s\n", datapth); if(do_link(oldpath, finpath, &statp, cconf, 0 /* do not overwrite finpath (should never need to) */)) goto end; else { // If we are not keeping a hardlinked // archive, delete the old link. if(!hardlinked_current) { //logp("Unlinking old file: %s\n", oldpath); unlink(oldpath); } } } else { logp("could not find: %s\n", oldpath); goto end; } ret=0; end: free_w(&oldpath); free_w(&newpath); free_w(&finpath); free_w(&deltafpath); return ret; }