From ea74bfca7283c65f04931bfda6ad0e4d186d505d Mon Sep 17 00:00:00 2001 From: Fabian Groffen Date: Fri, 12 Oct 2007 22:44:38 +0000 Subject: [PATCH] Intermediate commit. Finished stage1 of chpathtool pimp-up. The idea is that chpathtool copies a directory into another, doing its job, retaining the files' properties, like cp -a (ok, cp -pPR) would do. The implementation is now up to copying, setting the permission bits and owner stuff. TODO: the *times, and then it should be done. svn path=/main/branches/prefix/; revision=8095 --- configure.in | 8 +- src/chpathtool.c | 245 ++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 206 insertions(+), 47 deletions(-) diff --git a/configure.in b/configure.in index 22b3defc8..2b5bb6c58 100644 --- a/configure.in +++ b/configure.in @@ -48,7 +48,13 @@ GENTOO_PATH_GNUPROG(GREP, [grep]) dnl Checks for header files. AC_HEADER_STDC -AC_CHECK_HEADERS([string.h errno.h unistd.h stdio.h stdlib.h sys/stat.h sys/types.h]) +AC_CHECK_HEADERS([string.h errno.h unistd.h stdio.h stdlib.h]) +AC_CHECK_HEADERS([sys/stat.h sys/types.h dirent.h]) + +AC_CHECK_LIBS([readdir], [c]) +AC_CHECK_LIBS([strcpy], [c]) +AC_CHECK_LIBS([strstr], [c]) +AC_CHECK_LIBS([memcpy], [c]) AC_ARG_ENABLE(tbz2tool, AC_HELP_STRING([--enable-tbz2tool],[build tbz2tool, tool for creating binpkgs (default yes)]), diff --git a/src/chpathtool.c b/src/chpathtool.c index e36a843fe..99c568339 100644 --- a/src/chpathtool.c +++ b/src/chpathtool.c @@ -16,10 +16,24 @@ #include #include #include +#include +#include +#include +#include +#include /* Don't allocate too much, or you'll be paying for waiting on IO, * size -1 to align in memory. */ #define BUFSIZE 8095 +/* POSIX says 256 on this one, but I can hardly believe that really is + * the limit of most popular systems. XOPEN says 1024, taking that + * value, hoping it is enough */ +#define MAX_PATH 1024 + +static char *magic; +static char *value; +static size_t magiclen; +static size_t valuelen; /** * Writes padding zero-bytes after the first encountered zero-byte. @@ -71,64 +85,30 @@ static char *memstr(const char *buf, const char *needle, size_t len) { return(NULL); } -int main(int argc, char **argv) { +static int chpath(const char *fi, const char *fo) { FILE *fin; FILE *fout; - char *magic; - char *value; - char buf[BUFSIZE + 1]; - char *tmp; size_t len; size_t pos; size_t padding; - size_t magiclen; - size_t valuelen; - - if (argc != 5) { - fprintf(stderr, "usage: in-file out-file magic value\n"); - return(-1); - } - - magic = argv[3]; - value = argv[4]; - magiclen = strlen(magic); - valuelen = strlen(value); + char *tmp; + char buf[BUFSIZE + 1]; - if (magiclen < valuelen) { - fprintf(stderr, "value length (%zd) is bigger than " - "the magic length (%zd)\n", valuelen, magiclen); - return(-1); - } - if (magiclen > BUFSIZE) { - fprintf(stderr, "magic length (%zd) is bigger than " - "BUFSIZE (%d), unable to process\n", magiclen, BUFSIZE); - return(-1); - } + /* make sure there is a trailing zero-byte, such that strstr and + * strchr won't go out of bounds causing segfaults. */ + buf[BUFSIZE] = '\0'; - if (strcmp(argv[1], "-") == 0) { - fin = stdin; - } else { - fin = fopen(argv[1], "r"); - } + fin = fopen(fi, "r"); if (fin == NULL) { - fprintf(stderr, "unable to open %s: %s\n", argv[1], strerror(errno)); + fprintf(stderr, "unable to open %s: %s\n", fi, strerror(errno)); return(-1); } - - if (strcmp(argv[2], "-") == 0) { - fout = stdout; - } else { - fout = fopen(argv[2], "w"); - } - if (fin == NULL) { - fprintf(stderr, "unable to open %s: %s\n", argv[2], strerror(errno)); + fout = fopen(fo, "w"); + if (fout == NULL) { + fprintf(stderr, "unable to open %s: %s\n", fo, strerror(errno)); return(-1); } - /* make sure there is a trailing zero-byte, such that strstr and - * strchr won't go out of bounds causing segfaults. */ - buf[BUFSIZE] = '\0'; - pos = 0; padding = 0; while ((len = fread(buf + pos, 1, BUFSIZE - pos, fin)) != 0 || pos > 0) { @@ -170,8 +150,181 @@ int main(int argc, char **argv) { if (padding != 0) { fprintf(stdout, "warning: couldn't find a location to write " - "%zd padding bytes\n", padding); + "%zd padding bytes for %s\n", padding, fi); } return(0); } + +int dirwalk(char *src, char *srcp, char *trg, char *trgp) { + DIR *d; + struct dirent *de; + struct stat s; + char *st; + char *tt; + + if (stat(trg, &s) != 0) { + /* try to create the target directory, retaining attributes */ + if (stat(src, &s) != 0) { + fprintf(stderr, "cannot stat %s: %s\n", src, strerror(errno)); + return(-1); + } + if (mkdir(trg, s.st_mode) != 0) { + fprintf(stderr, "failed to create directory %s: %s\n", + trg, strerror(errno)); + return(-1); + } + if (lchown(trg, s.st_uid, s.st_gid) != 0) { + fprintf(stderr, "failed to set ownership of %s: %s\n", + trg, strerror(errno)); + return(-1); + } + } + + if ((d = opendir(src)) == NULL) { + fprintf(stderr, "cannot read directory %s: %s\n", src, strerror(errno)); + return(-1); + } + /* store the end of the string pointer */ + st = srcp; + tt = trgp; + while ((de = readdir(d)) != NULL) { + if (strcmp(de->d_name, "..") == 0 || strcmp(de->d_name, ".") == 0) + continue; + + *st = '/'; + strcpy(st + 1, de->d_name); + *tt = '/'; + strcpy(tt + 1, de->d_name); + st += 1 + strlen(de->d_name); + tt += 1 + strlen(de->d_name); + + if (stat(src, &s) != 0) { + fprintf(stderr, "cannot stat %s: %s\n", src, strerror(errno)); + closedir(d); + return(-1); + } + if ( + S_ISBLK(s.st_mode) || + S_ISCHR(s.st_mode) || + S_ISFIFO(s.st_mode) || +#ifndef _POSIX_C_SOURCE + S_ISWHT(s.st_mode) || +#endif + S_ISSOCK(s.st_mode) + ) + { + fprintf(stderr, "missing implementation for copying " + "object %s\n", src); + closedir(d); + return(-1); + } else if ( + S_ISDIR(s.st_mode) + ) + { + /* recurse */ + if (dirwalk(src, st, trg, tt) != 0) + return(-1); + } else if ( + S_ISREG(s.st_mode) + ) + { + /* FIXME: handle hard links! */ + /* copy */ + if (chpath(src, trg) != 0) { + closedir(d); + return(-1); + } + /* fix permissions */ + if (stat(src, &s) != 0) { + fprintf(stderr, "cannot stat %s: %s\n", + src, strerror(errno)); + return(-1); + } + if (chmod(trg, s.st_mode) != 0) { + fprintf(stderr, "failed to set permissions of %s: %s\n", + trg, strerror(errno)); + return(-1); + } + if (lchown(trg, s.st_uid, s.st_gid) != 0) { + fprintf(stderr, "failed to set ownership of %s: %s\n", + trg, strerror(errno)); + return(-1); + } + } else if ( + S_ISLNK(s.st_mode) + ) + { + char buf[MAX_PATH]; + char rep[MAX_PATH]; + char *pb = buf; + char *pr = rep; + char *p = NULL; + int len = readlink(trg, buf, MAX_PATH - 1); + buf[len] = '\0'; + /* replace occurences of magic by value in the string */ + while ((p = strstr(pb, magic)) != NULL) { + memcpy(pr, pb, p - pb); + pr += p - pb; + memcpy(pr, value, valuelen); + pr += valuelen; + pb += magiclen; + } + memcpy(pr, pb, (&buf[0] + len) - pb); + + symlink(trg, rep); + } + + /* restore modified path */ + st = srcp; + tt = trgp; + *st = *tt = '\0'; + } + closedir(d); + + return(0); +} + +int main(int argc, char **argv) { + struct stat file; + + if (argc != 5) { + fprintf(stderr, "usage: in-file out-file magic value\n"); + fprintf(stderr, " if in-file is a directory, out-file is " + "treated as one too\n"); + return(-1); + } + + magic = argv[3]; + value = argv[4]; + magiclen = strlen(magic); + valuelen = strlen(value); + + if (magiclen < valuelen) { + fprintf(stderr, "value length (%zd) is bigger than " + "the magic length (%zd)\n", valuelen, magiclen); + return(-1); + } + if (magiclen > BUFSIZE) { + fprintf(stderr, "magic length (%zd) is bigger than " + "BUFSIZE (%d), unable to process\n", magiclen, BUFSIZE); + return(-1); + } + + if (stat(argv[1], &file) != 0) { + fprintf(stderr, "unable to stat %s: %s\n", argv[1], strerror(errno)); + return(-1); + } + if (S_ISDIR(file.st_mode)) { + char *src = alloca(sizeof(char) * MAX_PATH); + char *trg = alloca(sizeof(char) * MAX_PATH); + strcpy(src, argv[1]); + strcpy(trg, argv[2]); + /* walk this directory and process recursively */ + return(dirwalk(src, src + strlen(argv[1]), trg, trg + strlen(argv[2]))); + } else { + /* process as normal file */ + return(chpath(argv[1], argv[2])); + } +} + -- 2.26.2