X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=common-src%2Ffile.c;h=b9e9788b8e097889495e85f795a44b9ac4ed1551;hb=HEAD;hp=62cf171bab4da3dc2c53ce53c4a3dece1ddabc62;hpb=310f09c0f55a2fb6f3f3746d6ded20099792b773;p=debian%2Famanda diff --git a/common-src/file.c b/common-src/file.c index 62cf171..b9e9788 100644 --- a/common-src/file.c +++ b/common-src/file.c @@ -1,6 +1,7 @@ /* * Amanda, The Advanced Maryland Automatic Network Disk Archiver * Copyright (c) 1997-1998 University of Maryland at College Park + * Copyright (c) 2007-2012 Zmanda, Inc. All Rights Reserved. * All Rights Reserved. * * Permission to use, copy, modify, distribute, and sell this software and its @@ -23,52 +24,19 @@ * Author: AMANDA core development group. */ /* - * $Id: file.c,v 1.40.2.1 2006/11/24 18:05:05 martinea Exp $ + * $Id: file.c,v 1.40 2006/07/19 17:41:15 martinea Exp $ * * file and directory bashing routines */ #include "amanda.h" #include "util.h" +#include "timestamp.h" +#include "arglist.h" +#include "file.h" -void amanda_setup(int argc, char **argv, int setup_flags); -static int mk1dir(const char *, mode_t, uid_t, gid_t); static void areads_getbuf(const char *s, int l, int fd); - -uid_t client_uid = (uid_t) -1; -gid_t client_gid = (gid_t) -1; - -/* Make a directory (internal function). -** If the directory already exists then we pretend we created it. -** XXX - I'm not sure about the use of the chown() stuff. On most systems -** it will do nothing - only root is permitted to change the owner -** of a file. -*/ -static int -mk1dir( - const char *dir, /* directory to create */ - mode_t mode, /* mode for new directory */ - uid_t uid, /* uid for new directory */ - gid_t gid) /* gid for new directory */ -{ - int rc; /* return code */ - - if((rc = mkdir(dir, mode)) == 0) { - if ((rc = chmod(dir, mode)) == 0) { /* mkdir() affected by the umask */ - rc = chown(dir, uid, gid); - } - } else { /* maybe someone beat us to it */ - int serrno; - - serrno = errno; - if(access(dir, F_OK) != 0) - rc = -1; - errno = serrno; /* pass back the real error */ - } - - return rc; -} - +static char *original_cwd = NULL; /* * Make a directory hierarchy given an entry to be created (by the caller) @@ -89,14 +57,32 @@ mkpdir( rc = 0; - dir = stralloc(file); /* make a copy we can play with */ + /* Remove last member of file, put the result in dir */ + dir = stralloc(file); /* make a copy we can play with */ p = strrchr(dir, '/'); - if(p != dir && p != NULL) { /* got a '/' or a simple name */ - *p = '\0'; + *p = '\0'; - if(access(dir, F_OK) != 0) { /* doesn't exist */ - if(mkpdir(dir, mode, uid, gid) != 0 || - mk1dir(dir, mode, uid, gid) != 0) rc = -1; /* create failed */ + rc = mkdir(dir, mode); + if (rc != 0) { + if (errno == ENOENT) { /* create parent directory */ + rc = mkpdir(dir, mode, uid, gid); + if (rc != 0) + return rc; + rc = mkdir(dir, mode); + } + if (rc != 0 && errno == EEXIST) { + amfree(dir); + return 0; + } + } + + /* mkdir succeded, set permission and ownership */ + if (rc == 0) { + /* mkdir is affected by umask, so set the mode bits manually */ + rc = chmod(dir, mode); + + if (rc == 0 && geteuid() == 0) { + rc = chown(dir, uid, gid); } } @@ -156,37 +142,12 @@ rmpdir( } -/* - *===================================================================== - * Do Amanda setup for all programs. - * - * void amanda_setup (int argc, char **argv, int setup_flags) - * - * entry: setup_flags (see AMANDA_SETUP_FLAG_xxx) - * exit: none - *===================================================================== - */ - -void -amanda_setup ( - int argc, - char ** argv, - int setup_flags) -{ - (void)argc; /* Quiet unused parameter warning */ - (void)argv; /* Quiet unused parameter warning */ - (void)setup_flags; /* Quiet unused parameter warning */ -} - /* *===================================================================== * Change directory to a "safe" location and set some base environment. * * void safe_cd (void) * - * entry: client_uid and client_gid set to CLIENT_LOGIN information - * exit: none - * * Set a default umask of 0077. * * Create the Amada debug directory (if defined) and the Amanda temp @@ -209,25 +170,25 @@ safe_cd(void) { int cd_ok = 0; struct stat sbuf; - struct passwd *pwent; char *d; - - if(client_uid == (uid_t) -1 && (pwent = getpwnam(CLIENT_LOGIN)) != NULL) { - client_uid = pwent->pw_uid; - client_gid = pwent->pw_gid; - endpwent(); - } + uid_t client_uid = get_client_uid(); + gid_t client_gid = get_client_gid(); (void) umask(0077); + /* stash away the current directory for later reference */ + if (original_cwd == NULL) { + original_cwd = g_get_current_dir(); + } + if (client_uid != (uid_t) -1) { #if defined(AMANDA_DBGDIR) d = stralloc2(AMANDA_DBGDIR, "/."); - (void) mkpdir(d, (mode_t)02700, client_uid, client_gid); + (void) mkpdir(d, (mode_t)0700, client_uid, client_gid); amfree(d); #endif d = stralloc2(AMANDA_TMPDIR, "/."); - (void) mkpdir(d, (mode_t)02700, client_uid, client_gid); + (void) mkpdir(d, (mode_t)0700, client_uid, client_gid); amfree(d); } @@ -279,7 +240,7 @@ safe_fd( { int fd; - for(fd = 0; fd < FD_SETSIZE; fd++) { + for(fd = 0; fd < (int)FD_SETSIZE; fd++) { if (fd < 3) { /* * Open three file descriptors. If one of the standard @@ -292,7 +253,7 @@ safe_fd( */ if (fcntl(fd, F_GETFD) == -1) { if (open("/dev/null", O_RDWR) == -1) { - fprintf(stderr, "/dev/null is inaccessable: %s\n", + g_fprintf(stderr, _("/dev/null is inaccessable: %s\n"), strerror(errno)); exit(1); } @@ -342,7 +303,7 @@ save_core(void) char suffix[2]; char *old, *new; - ts = construct_datestamp((time_t *)&sbuf.st_mtime); + ts = get_datestamp_from_time(sbuf.st_mtime); suffix[0] = 'z'; suffix[1] = '\0'; old = vstralloc("core", ts, suffix, NULL); @@ -369,11 +330,13 @@ save_core(void) /* ** Sanitise a file name. ** -** Convert all '/' characters to '_' so that we can use, +** Convert all '/', ':', and '\' characters to '_' so that we can use, ** for example, disk names as part of file names. ** Notes: ** - there is a many-to-one mapping between input and output -** - Only / and '\0' are disallowed in filenames by POSIX... +** - Only / and '\0' are disallowed in filenames by POSIX, but Windows +** disallows ':' and '\' as well. Furthermore, we use ':' as a +** delimiter at other points in Amanda. */ char * sanitise_filename( @@ -389,7 +352,7 @@ sanitise_filename( d = buf; s = inp; while((ch = *s++) != '\0') { - if(ch == '/') { + if((ch == '/') || (ch == ':') || (ch == '\\')) { ch = '_'; /* convert "bad" to "_" */ } *d++ = (char)ch; @@ -429,6 +392,17 @@ old_sanitise_filename( return buf; } +void +canonicalize_pathname(char *pathname, char *result_buf) +{ +#ifdef __CYGWIN__ + cygwin_conv_to_full_posix_path(pathname, result_buf); +#else + strncpy(result_buf, pathname, PATH_MAX-1); + result_buf[PATH_MAX-1] = '\0'; +#endif +} + /* *===================================================================== * Get the next line of input from a stdio file. @@ -480,7 +454,7 @@ debug_agets( } if (ch == '\\') { - escape = 1; + escape = !escape; } else { if (ch == '"') { if (!escape) @@ -646,8 +620,6 @@ debug_areads ( size_t size; ssize_t r; - malloc_enter(dbmalloc_caller_loc(s, l)); - if(fd < 0) { errno = EBADF; return NULL; @@ -680,7 +652,6 @@ debug_areads ( if(r == 0) { errno = 0; /* flag EOF instead of error */ } - malloc_leave(dbmalloc_caller_loc(s, l)); return NULL; } endptr[r] = '\0'; /* we always leave room for this */ @@ -693,10 +664,135 @@ debug_areads ( memmove(buffer, nl, size); areads_buffer[fd].endptr = buffer + size; areads_buffer[fd].endptr[0] = '\0'; - malloc_leave(dbmalloc_caller_loc(s, l)); return line; } +int robust_open(const char * pathname, int flags, mode_t mode) { + int result = -1; + int e_busy_count = 0; + + for (;;) { + if (flags & O_CREAT) { + result = open(pathname, flags, mode); + } else { + result = open(pathname, flags); + } + + if (result < 0) { +#ifdef EBUSY + /* EBUSY is a tricky one; sometimes it is synonymous with + EINTR, but sometimes it means the device is open + elsewhere (e.g., with a tape drive on Linux). We take + the middle path and retry, but with limited + patience. */ + if (errno == EBUSY && e_busy_count < 10) { + e_busy_count ++; + continue; + } else +#endif + if (0 + /* Always retry on EINTR; if the caller did + not specify non-blocking mode, then also retry on + EAGAIN or EWOULDBLOCK. */ +#ifdef EINTR + || errno == EINTR +#endif + || ( 1 +#ifdef O_NONBLOCK + && !(flags & O_NONBLOCK) +#endif + && ( 0 +#ifdef EAGAIN + || errno == EAGAIN +#endif +#ifdef EWOULDBLOCK + || errno == EWOULDBLOCK +#endif + ) ) ) { + /* Try again */ + continue; + } else { + /* Failure. */ + return result; + } + } else { + break; + } + } + +#ifdef F_SETFD + if (result >= 0) { + fcntl(result, F_SETFD, 1); /* Throw away result. */ + } +#endif + + return result; +} + +int robust_close(int fd) { + for (;;) { + int result; + + result = close(fd); + if (result != 0 && (0 +#ifdef EINTR + || errno == EINTR +#endif +#ifdef EBUSY + || errno == EBUSY +#endif +#ifdef EAGAIN + || errno == EAGAIN +#endif +#ifdef EWOULDBLOCK + || errno == EWOULDBLOCK +#endif + )) { + continue; + } else { + return result; + } + } +} + +uid_t +get_client_uid(void) +{ + static uid_t client_uid = (uid_t) -1; + struct passwd *pwent; + + if(client_uid == (uid_t) -1 && (pwent = getpwnam(CLIENT_LOGIN)) != NULL) { + client_uid = pwent->pw_uid; + endpwent(); + } + + return client_uid; +} + +gid_t +get_client_gid(void) +{ + static gid_t client_gid = (gid_t) -1; + struct passwd *pwent; + + if(client_gid == (gid_t) -1 && (pwent = getpwnam(CLIENT_LOGIN)) != NULL) { + client_gid = pwent->pw_gid; + endpwent(); + } + + return client_gid; +} + +char * +get_original_cwd(void) +{ + if (original_cwd == NULL) { + original_cwd = g_get_current_dir(); + } + + return original_cwd; +} + #ifdef TEST int @@ -711,6 +807,15 @@ main( char *file; char *line; + /* + * Configure program for internationalization: + * 1) Only set the message locale for now. + * 2) Set textdomain for all amanda related programs to "amanda" + * We don't want to be forced to support dozens of message catalogs + */ + setlocale(LC_MESSAGES, "C"); + textdomain("amanda"); + safe_fd(-1, 0); set_pname("file test"); @@ -733,25 +838,25 @@ main( name = argv[3]; } - fprintf(stderr, "Create parent directories of %s ...", name); + g_fprintf(stderr, _("Create parent directories of %s ..."), name); rc = mkpdir(name, (mode_t)02777, (uid_t)-1, (gid_t)-1); if (rc == 0) - fprintf(stderr, " done\n"); + g_fprintf(stderr, " done\n"); else { - perror("failed"); + perror(_("failed")); return rc; } - fprintf(stderr, "Delete %s back to %s ...", name, top); + g_fprintf(stderr, _("Delete %s back to %s ..."), name, top); rc = rmpdir(name, top); if (rc == 0) - fprintf(stderr, " done\n"); + g_fprintf(stderr, _(" done\n")); else { - perror("failed"); + perror(_("failed")); return rc; } - fprintf(stderr, "areads dump of %s ...", file); + g_fprintf(stderr, _("areads dump of %s ..."), file); if ((fd = open (file, 0)) < 0) { perror(file); return 1; @@ -762,10 +867,13 @@ main( amfree(line); } aclose(fd); - fprintf(stderr, " done.\n"); + g_fprintf(stderr, _(" done.\n")); + + g_fprintf(stderr, _("Finished.\n")); - fprintf(stderr, "Finished.\n"); + dbclose(); return 0; } #endif +