OSSP CVS Repository

ossp - ossp-pkg/path/path_temp.c
Not logged in
[Honeypot]  [Browse]  [Directory]  [Home]  [Login
[Reports]  [Search]  [Ticket]  [Timeline
  [Raw

ossp-pkg/path/path_temp.c
/*
**  OSSP path - Filesystem Path Manipulation
**  Copyright (c) 2002-2003 Ralf S. Engelschall <rse@engelschall.com>
**  Copyright (c) 2002-2003 The OSSP Project <http://www.ossp.org/>
**  Copyright (c) 2002-2003 Cable & Wireless Deutschland <http://www.cw.com/de/>
**
**  This file is part of OSSP path, a filesystem path manipulation library
**  which can be found at http://www.ossp.org/pkg/lib/path/.
**
**  Permission to use, copy, modify, and distribute this software for
**  any purpose with or without fee is hereby granted, provided that
**  the above copyright notice and this permission notice appear in all
**  copies.
**
**  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
**  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
**  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
**  IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
**  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
**  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
**  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
**  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
**  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
**  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
**  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
**  SUCH DAMAGE.
**
**  path_temp.c: temporary pathname creation
*/

#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <pwd.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/time.h>

#include "path.h"
#include "path_util.h"

static const char
path_temp_padchar[] =
    "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

path_rc_t
path_temp(
    path_temp_t id,
    const char *tmpl,
    char      **res_ptr,
    size_t     *res_size,
    int        *res_fd)
{
    char tmpl_def[MAXPATHLEN];
    char path[MAXPATHLEN];
    char *tmpdir;
    size_t n;
    char *user;
    char user_buf[4+((sizeof(long)*8)/3)+10];
    const char *cp;
    const char *cpT;
    char *cpP;
    struct passwd *pw;
    struct timeval tp;
    struct timezone tzp;
    pid_t pid;
    pid_t ppid;
    uid_t uid;
    int r;
    path_rc_t rc;
    int fd;

    /* argument sanity checks */
    if (res_ptr == NULL && res_fd == NULL)
        return PATH_ERR_ARG;
    if (id == PATH_TEMP_DIR && res_fd != NULL)
        return PATH_ERR_USE;

    /* determine temporary directory */
    if ((tmpdir = getenv("TMPDIR")) == NULL)
        tmpdir = getenv("TEMPDIR");
    if (tmpdir == NULL || tmpdir[0] == '\0')
        tmpdir = "/tmp";

    /* provide a reasonable fallback template */
    uid = getuid();
    if (tmpl == NULL || tmpl[0] == '\0') {
        /* none or empty template */
        if ((pw = getpwuid(uid)) != NULL)
            user = pw->pw_name;
        else {
            path_msnprintf(user_buf, sizeof(user_buf), "uid-%ld", (long)uid);
            user = user_buf;
        }
        n = strlen(tmpdir);
        path_msnprintf(tmpl_def, sizeof(tmpl_def), "%s%s%s.XXXXXXXX",
                       tmpdir, (tmpdir[n-1] != '/' ? "/" : ""), user_buf);
        tmpl = tmpl_def;
    }
    else if (tmpl[0] != '/') {
        /* non-absolute path template */
        n = strlen(tmpdir);
        path_msnprintf(tmpl_def, sizeof(tmpl_def), "%s%s%s",
                       tmpdir, (tmpdir[n-1] != '/' ? "/" : ""), tmpl);
        if (strchr(tmpl_def, 'X') == NULL) {
            n = strlen(tmpl_def);
            path_msnprintf(tmpl_def+n, sizeof(tmpl_def)-n, ".XXXXXXXX");
        }
        tmpl = tmpl_def;
    }

    /* seed PRNG as good as possible with POSIX features */
    gettimeofday(&tp, &tzp);
    pid = getpid();
    ppid = getppid();
    srand(  (unsigned int)tp.tv_sec
          + (unsigned int)tp.tv_usec
          + (unsigned int)uid
          + (unsigned int)pid
          + (unsigned int)ppid);

    /* create initial path */
    n = 0;
    for (cpT = tmpl, cpP = path; *cpT != '\0'; cpT++, cpP++) {
        if (*cpT == 'X') {
            r = rand() % (sizeof(path_temp_padchar)-1);
            *cpP = path_temp_padchar[r];
            n++;
        }
        else
            *cpP = *cpT;
    }
    *cpP = '\0';
    if (n < 2)
        return PATH_ERR_ARG;

    /* try to find a good temporary path */
    rc = PATH_ERR_INT;
    fd = -1;
    for (;;) {
        /* try to create path */
        if (id == PATH_TEMP_FILE) {
            if ((fd = open(path, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0) {
                rc = PATH_OK;
                break;
            }
            if (errno != EEXIST)
                return PATH_ERR_SYS;
        }
        else if (id == PATH_TEMP_DIR) {
            if (mkdir(path, 0711) == 0) {
                rc = PATH_OK;
                break;
            }
            if (errno != EEXIST)
                return PATH_ERR_SYS;
        }
        else
            return PATH_ERR_ARG;

        /* path collision found, so cycle through namespace */
        for (cpT = tmpl, cpP = path; *cpT != '\0'; cpT++, cpP++) {
            if (*cpT == 'X') {
                cp = strchr(path_temp_padchar, *cpP);
                if (cp == NULL || *++cp == '\0')
                    *cpP = path_temp_padchar[0];
                else {
                    *cpP = *cp;
                    break;
                }
            }
        }
        if (*cpT == '\0')
            return PATH_ERR_EXS;
    }

    /* provide results */
    if (rc == PATH_OK) {
        if (res_ptr != NULL)
            *res_ptr = strdup(path);
        else
            unlink(path);
        if (res_fd != NULL)
            *res_fd = fd;
        else
            close(fd);
    }

    return rc;
}


CVSTrac 2.0.1