static gboolean mk_dir(struct rdup *e, GHashTable * uidhash, GHashTable * gidhash) { struct stat *s; struct stat st; gchar *parent; if (opt_dry) return TRUE; if (lstat(e->f_name, &st) == 0) { if (S_ISDIR(st.st_mode)) { #if 0 msgd(__func__, __LINE__, _("Updating current dir `%s\'"), e->f_name); #endif /* DEBUG */ /* some dir is here - update the perms and ownership */ mk_meta(e, uidhash, gidhash); return TRUE; } } /* nothing there */ if (mkdir(e->f_name, e->f_mode) == -1) { if (errno == EACCES) { /* make parent dir writable, and try again */ parent = dir_parent(e->f_name); #ifdef DEBUG msgd(__func__, __LINE__, _("EACCES for `%s\'"), parent); #endif /* DEBUG */ s = dir_write(parent); if (!s) msgd(__func__, __LINE__, _("Failed to make parent writable")); if (mkdir(e->f_name, e->f_mode) == -1) { msgd(__func__, __LINE__, _("Failed to create directory `%s\': %s"), e->f_name, strerror(errno)); dir_restore(parent, s); g_free(parent); return FALSE; } dir_restore(parent, s); g_free(parent); } else { msgd(__func__, __LINE__, _("Failed to create directory `%s\': %s"), e->f_name, strerror(errno)); return FALSE; } } mk_meta(e, uidhash, gidhash); return TRUE; }
static gboolean mk_link(struct rdup *e, char *p, GHashTable * uidhash, GHashTable * gidhash) { struct stat *st; gchar *t; gchar *parent; if (opt_dry) return TRUE; if (!rm(e->f_name)) return FALSE; /* symlink */ if (S_ISLNK(e->f_mode)) { if (symlink(e->f_target, e->f_name) == -1) { if (errno == EACCES) { parent = dir_parent(e->f_name); st = dir_write(parent); if (symlink(e->f_target, e->f_name) == -1) { msgd(__func__, __LINE__, _ ("Failed to make symlink `%s -> %s\': %s"), e->f_name, e->f_target, strerror(errno)); dir_restore(parent, st); g_free(parent); return FALSE; } dir_restore(parent, st); g_free(parent); } else { msgd(__func__, __LINE__, _ ("Failed to make symlink `%s -> %s\': %s"), e->f_name, e->f_target, strerror(errno)); return FALSE; } } mk_chown(e, uidhash, gidhash); return TRUE; } /* hardlink */ /* target must also fall in backup dir */ t = g_strdup_printf("%s%s", p, e->f_target); e->f_target = t; hlink_list = g_slist_append(hlink_list, entry_dup(e)); return TRUE; }
/* Create the remaining hardlinks in the target directory */ gboolean mk_hlink(GSList * h) { struct rdup *e; GSList *p; struct stat *st; gchar *parent; if (opt_dry) return TRUE; for (p = g_slist_nth(h, 0); p; p = p->next) { e = (struct rdup *)p->data; if (link(e->f_target, e->f_name) == -1) { if (errno == EACCES) { parent = dir_parent(e->f_name); st = dir_write(parent); if (link(e->f_target, e->f_name) == -1) { msgd(__func__, __LINE__, _ ("Failed to create hardlink `%s -> %s\': %s"), e->f_name, e->f_target, strerror(errno)); dir_restore(parent, st); g_free(parent); return FALSE; } dir_restore(parent, st); g_free(parent); return TRUE; } else { msgd(__func__, __LINE__, _ ("Failed to create hardlink `%s -> %s\': %s"), e->f_name, e->f_target, strerror(errno)); return FALSE; } } entry_free(e); } return TRUE; }
static gboolean mk_dev(struct rdup *e, GHashTable * uidhash, GHashTable * gidhash) { gchar *parent; struct stat *st; if (opt_dry) return TRUE; if (!rm(e->f_name)) return FALSE; if (mknod(e->f_name, e->f_mode, e->f_rdev) == -1) { if (errno == EACCES) { parent = dir_parent(e->f_name); st = dir_write(parent); if (mknod(e->f_name, e->f_mode, e->f_rdev) == -1) { msgd(__func__, __LINE__, _("Failed to make device `%s\': %s"), e->f_name, strerror(errno)); dir_restore(parent, st); g_free(parent); return FALSE; } dir_restore(parent, st); g_free(parent); } else { msgd(__func__, __LINE__, _("Failed to make device `%s\': %s"), e->f_name, strerror(errno)); return FALSE; } } mk_meta(e, uidhash, gidhash); return TRUE; }
static gboolean mk_reg(FILE * in, struct rdup *e, GHashTable * uidhash, GHashTable * gidhash) { FILE *out = NULL; char *buf; gchar *parent; size_t bytes; gboolean ok = TRUE; gboolean old_dry = opt_dry; struct stat *st; /* with opt_dry we can't just return TRUE; as we may * need to suck in the file's content - which is thrown * away in that case */ if (!e->f_name) { /* fake an opt_dry */ opt_dry = TRUE; } if (!opt_dry) { if (!rm(e->f_name)) { opt_dry = old_dry; return FALSE; } } if (!opt_dry && !(out = fopen(e->f_name, "w"))) { if (errno == EACCES) { parent = dir_parent(e->f_name); st = dir_write(parent); if (!(out = fopen(e->f_name, "w"))) { msgd(__func__, __LINE__, _("Failed to open file `%s\': %s"), e->f_name, strerror(errno)); g_free(parent); ok = FALSE; } dir_restore(parent, st); g_free(parent); } else { msgd(__func__, __LINE__, _("Failed to open file `%s\': %s"), e->f_name, strerror(errno)); ok = FALSE; } } /* we need to read the input to not upset * the flow into rdup-up, but we are not * creating anything when opt_dry is active */ buf = g_malloc(BUFSIZE + 1); while ((bytes = block_in_header(in)) > 0) { if (block_in(in, bytes, buf) == -1) { if (out) fclose(out); opt_dry = old_dry; g_free(buf); return FALSE; } if (ok && !opt_dry) { if (fwrite(buf, sizeof(char), bytes, out) != bytes) { msgd(__func__, __LINE__, _("Write failure `%s\': %s"), e->f_name, strerror(errno)); if (out) fclose(out); opt_dry = old_dry; g_free(buf); return FALSE; } } } g_free(buf); if (ok && out) fclose(out); if (ok && !opt_dry) mk_meta(e, uidhash, gidhash); #ifdef DEBUG msgd(__func__, __LINE__, "Wrote file `%s\'", e->f_name); #endif /* DEBUG */ opt_dry = old_dry; return TRUE; }
gboolean rm(gchar *p) { int ret; gchar *dirp, *q; gchar *parent; GDir *d; struct stat st; struct stat *st2; if (opt_dry || !p) return TRUE; /* noop */ if (lstat(p, &st) == -1) { if (opt_verbose > 0 && errno != ENOENT) msgd(__func__, __LINE__,_("Failed to remove `%s\': %s"), p, strerror(errno)); return TRUE; /* noop */ } if (S_ISDIR(st.st_mode)) { ret = remove(p); if (ret == -1) { switch(errno) { case ENOTEMPTY: /* recursive into this dir and do our bidding */ if (!(d = g_dir_open(p, 0, NULL))) { msgd(__func__, __LINE__,_("Failed to open directory `%s\': %s"), p, strerror(errno)); return FALSE; } while ( (dirp = (gchar*)g_dir_read_name(d))) { dirp = g_strdup_printf("%s/%s", p, dirp); rm(dirp); g_free(dirp); } g_dir_close(d); /* dir should be empty by now */ if ((ret = remove(p)) == -1) msgd(__func__, __LINE__,_("Failed to remove directory `%s\': %s"), p, strerror(errno)); return TRUE; case EACCES: /* no write to dir, make writable */ parent = dir_parent(p); st2 = dir_write(parent); if (remove(p) == -1) { msgd(__func__, __LINE__,_("Failed to remove `%s\': %s"), p, strerror(errno)); dir_restore(parent, st2); g_free(parent); return FALSE; } dir_restore(parent, st2); g_free(parent); return TRUE; default: /* not ENOEMPTY */ msgd(__func__, __LINE__,_("Failed to remove directory `%s\': %s"), p, strerror(errno)); return FALSE; } } return TRUE; } /* dirs are now handled */ if (remove(p) == -1) { switch(errno) { case EACCES: /* we have no access, ok ... */ q = g_strdup(p); parent = dirname(q); st2 = dir_write(parent); if (remove(p) == -1) { msgd(__func__, __LINE__,_("Failed to remove `%s\': %s"), p, strerror(errno)); dir_restore(parent, st2); g_free(q); return FALSE; } dir_restore(parent, st2); g_free(q); return TRUE; case EPERM: /* no write on file, reuse st - and why is this needed again? */ /* this is dead code ... */ stat(p, &st); chmod(p, st.st_mode | S_IWUSR); if (remove(p) == -1) { msgd(__func__, __LINE__,_("Failed to remove `%s\': %s"), p, strerror(errno)); chmod(p, st.st_mode); /* is this usefull then? */ return FALSE; } return TRUE; } msgd(__func__, __LINE__,_("Failed to remove `%s\': %s"), p, strerror(errno)); return FALSE; } return TRUE; }