/* ** OSSP path - Filesystem Path Manipulation ** Copyright (c) 2002-2003 Ralf S. Engelschall ** Copyright (c) 2002-2003 The OSSP Project ** Copyright (c) 2002-2003 Cable & Wireless Deutschland ** ** 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 #include #include #include #include #include #include #include #include #include #include #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; }