X-Git-Url: https://pd.if.org/git/?a=blobdiff_plain;f=zpm-syncfs.c;h=ecc66c84f8bec7df14a66bd2ad21a50e8fe81431;hb=fc0e2fbaf7051e42be1a6449a5a004fb3e665d45;hp=935e71509f2591ae20cc3a9801c22548c0a53ae1;hpb=7b9350d9ec18a9ab5bbcf92a6523b856839f8f5b;p=zpackage diff --git a/zpm-syncfs.c b/zpm-syncfs.c index 935e715..ecc66c8 100644 --- a/zpm-syncfs.c +++ b/zpm-syncfs.c @@ -40,11 +40,14 @@ struct nitem { gid_t gid; char *dest; char *path; - char *hash; + char *hash, *ohash; + char *mds, *omds; char *target; + char *pkglist; /* space separated */ time_t mtime; mode_t mode; int ftype; + int configuration; struct timespec times[2]; }; @@ -285,6 +288,7 @@ static int remove_files(void *f, int ncols, char **vals, char **cols) { struct config *conf = f; char *dest; struct stat st; + int flags = 0; dest = COL("dest"); if (!dest) return seterror(conf,"no file dest"); @@ -306,21 +310,22 @@ static int remove_files(void *f, int ncols, char **vals, char **cols) { } if (S_ISDIR(st.st_mode)) { - if (conf->verbose) { - fprintf(stderr, "rmdir(%s)\n", dest); - } - rmdir(dest); - } else if (S_ISREG(st.st_mode)) { - /* TODO conf to import before removal */ - if (conf->verbose) { - fprintf(stderr, "unlink(%s)\n", dest); - } - if (unlink(dest) == -1) { - return seterror(conf, "can't unlink"); - } - } else { - if (unlink(dest) == -1) { - return seterror(conf, "can't unlink"); + flags = AT_REMOVEDIR; + } + /* TODO check that expected filetype matches actual filetype */ + + if (conf->verbose) { + fprintf(stderr, "%s(%s)\n", flags ? "rmdir" : "unlink", dest); + } + + errno = 0; + + if (unlinkat(AT_FDCWD, dest, flags) == -1) { + switch (errno) { + case ENOENT: + break; + default: + return seterror(conf, "can't unlink"); } } @@ -339,6 +344,7 @@ static int remove_files(void *f, int ncols, char **vals, char **cols) { #define D_GID 0x80 #define D_MODE 0x100 #define D_MTIME 0x200 +#define D_OHASH 0x400 #define D_ERROR 0x1000 #define D_STATERROR 0x2000 #define D_RLERROR 0x4000 @@ -376,6 +382,9 @@ static unsigned int file_compare(struct nitem *n, struct stat *st) { if (strcmp(n->hash, ehash) != 0) { diff |= D_HASH; } + if (n->ohash && strcmp(n->ohash, ehash) != 0) { + diff |= D_OHASH; + } } if (n->hash && etype == S_IFLNK && stat_type == S_IFLNK) { lsize = readlink(n->dest, link, sizeof link); @@ -460,6 +469,13 @@ static int read_item(struct config *conf, int ncols, char **vals, char **cols, n->mode = strtoul(val, NULL, 8); + val = COL("configuration"); + if (!val) { + seterror(conf, "can't determine config status"); + return 0; + } + n->configuration = strtoul(val, NULL, 10); + val = COL("filetype"); if (!val || strlen(val) == 0) { seterror(conf, "can't determine file type"); @@ -467,6 +483,12 @@ static int read_item(struct config *conf, int ncols, char **vals, char **cols, } n->ftype = *val; + /* these can be null */ + n->ohash = COL("ohash"); + n->mds = COL("mds"); + n->omds = COL("omds"); + n->pkglist = COL("pkglist"); + if (n->ftype == 'r') { n->hash = COL("hash"); if (!n->hash) { @@ -601,6 +623,12 @@ static int set_md(struct config *conf, struct nitem *item) { /* flags: 1 = set md, 2 = create leading dirs, 4 = unlink existing file, * 8 = rmdir existing dir, 16 = return true/false */ +#define INS_MD 0x1 +#define INS_CLD 0x2 +#define INS_UNLINK 0x4 +#define INS_RMDIR 0x8 +#define INS_RTF 0x10 +#define INS_ZPMNEW 0x20 static int install(struct config *conf, struct nitem *item, unsigned int flags) { int rv = 1; struct zpm *source; @@ -681,6 +709,89 @@ static int install(struct config *conf, struct nitem *item, unsigned int flags) return success; } +/* + * + */ +static int adjust_for_config(struct config *conf, struct nitem *n, unsigned int + diffs) { +#if 0 + if (!n->oldwasconf) { + return 0; + } +#endif + /* TODO what if old was a directory? */ + if (!n->configuration) { + /* replacing conf with non-conf */ + /* absorb file, mark todo */ + char hash[ZPM_HASH_STRLEN+1]; + if (zpm_import(conf->log, n->dest, 0, hash)) { + zpm_note_add(conf->log, n->pkglist, n->dest, hash, + "replaced config file with non-config. zpm-cat %.8s", hash); + } else { + fprintf(stderr, "unable to import existing config file %s\n", n->dest); + return 1; + } + return 0; + } + + int sametype = (!(diffs & D_TYPE)); + int isdir = (diffs & D_ISDIR); + int eisdir = (diffs & D_EISDIR); + + /* both old and new are config files */ + if (isdir && sametype) { + /* both config directories, can only be changing + * metadata, so no adjustment needed + */ + return 0; + } + + if (isdir) { + char hash[ZPM_HASH_STRLEN+1]; + + /* replacing old file with new directory */ + /* absorb, make note */ + if (zpm_import(conf->log, n->dest, 0, hash)) { + zpm_note_add(conf->log, n->pkglist, n->dest, hash, + "replaced config file with config directory. zpm-cat %.8s", hash); + } else { + fprintf(stderr, "unable to import existing config file %s\n", n->dest); + return -1; + } + return 0; + } + + if (eisdir) { + /* replacing old conf directory with a conf file. + * nothing needs to be done, if the directory + * is empty, it's ok to remove. if it's not empty, + * the install will fail + */ + return 0; + } + + /* replacing old file with new file */ + /* new is same as on disk */ + if (!(diffs & D_HASH)) { + return 0; + } + + /* new is different than on disk, but on disk is same as old */ + if (!(diffs & D_OHASH)) { + /* ok to do the update, since same as default */ + fprintf(stderr, "updating default config %s\n", n->dest); + return 0; + } + + /* new is different than on disk, and disk different than old */ + /* log */ + zpm_note_add(conf->log, n->pkglist, n->dest, n->hash, + "default config file update. zpm-cat %.8s", n->hash); + /* TODO check for note error */ + return 1; + +} + static int install_files(void *f, int ncols, char **vals, char **cols) { struct config *conf = f; struct nitem nitem; @@ -747,15 +858,39 @@ static int install_files(void *f, int ncols, char **vals, char **cols) { return install(conf, &nitem, 3); } + switch (adjust_for_config(conf, &nitem, diffs)) { + case -1: return conf->errabort; break; + case 1: + fprintf(stderr, "skipping changed default config file: %s\n", nitem.dest); + return 0; break; + default: break; + } + /* file exists in filesystem */ if (sametype) { if (mdsame && hashsame) { - fprintf(stderr, "%s should not be an update", nitem.dest); - /* warn, bug in logic. This shouldn't - * occur, because if there is nothing - * to do, it shouldn't be listed - * as an update + /* warn, bug in logic. This shouldn't occur, + * because if there is nothing to do, it + * shouldn't be listed as an update + */ + /* could be an update. We're checking against + * what's actually on disk, not what was + * expected to have been on disk. So, if + * the admin has modified the file, or if + * it had been installed ignoring the user + * and group, it might be correct on disk + * but not as in the local database */ + /* TODO detect whether this a logic bug or + * an on-disk difference + */ +#if 0 + fprintf(stderr, "%s should not be an update\n", nitem.dest); + fprintf(stderr, "old hash: %s\n", nitem.ohash); + fprintf(stderr, "new hash: %s\n", nitem.hash); + fprintf(stderr, "old mds: %s\n", nitem.omds); + fprintf(stderr, "new mds: %s\n", nitem.mds); +#endif /* do nothing */ return 0; } @@ -792,6 +927,7 @@ static int install_files(void *f, int ncols, char **vals, char **cols) { return install(conf, &nitem, 7); } /* error, should not be possible, assert(0)? */ + fprintf(stderr,"impossible state: %s:%d\n", __func__, __LINE__); } if (installing) {