diff options
Diffstat (limited to 'sysdeps/posix/tempname.c')
-rw-r--r-- | sysdeps/posix/tempname.c | 287 |
1 files changed, 98 insertions, 189 deletions
diff --git a/sysdeps/posix/tempname.c b/sysdeps/posix/tempname.c index 82e0243132..6dd893e613 100644 --- a/sysdeps/posix/tempname.c +++ b/sysdeps/posix/tempname.c @@ -28,119 +28,99 @@ #include <unistd.h> #include <sys/time.h> -#ifdef USE_IN_LIBIO -# include "libioP.h" -# include <libio.h> -#endif - /* Return nonzero if DIR is an existent directory. */ static int -diraccess (const char *dir) +direxists (const char *dir) { struct stat buf; return __stat (dir, &buf) == 0 && S_ISDIR (buf.st_mode); } -/* Return nonzero if FILE exists. */ -static int -exists (const char *file) +/* Path search algorithm, for tmpnam, tmpfile, etc. If DIR is + non-null and exists, uses it; otherwise uses the first of $TMPDIR, + P_tmpdir, /tmp that exists. Copies into TMPL a template suitable + for use with mk[s]temp. Will fail (-1) if DIR is non-null and + doesn't exist, none of the searched dirs exists, or there's not + enough space in TMPL. */ +int +__path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx) { - /* We can stat the file even if we can't read its data. */ - struct stat st; - int save = errno; - if (__stat (file, &st) == 0) - return 1; + const char *d; + size_t dlen, plen; + + if (!pfx || !pfx[0]) + { + pfx = "file"; + plen = 4; + } else { - /* We report that the file exists if stat failed for a reason other - than nonexistence. In this case, it may or may not exist, and we - don't know; but reporting that it does exist will never cause any - trouble, while reporting that it doesn't exist when it does would - violate the interface of __stdio_gen_tempname. */ - int exists = errno != ENOENT; - __set_errno (save); - return exists; + plen = strlen (pfx); + if (plen > 5) + plen = 5; } -} - -/* These are the characters used in temporary filenames. */ -static const char letters[] = - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - -/* Generate a temporary filename and return it (in a static buffer). If - STREAMPTR is not NULL, open a stream "w+b" on the file and set - *STREAMPTR to it. If DIR_SEARCH is nonzero, DIR and PFX are used as - described for tempnam. If not, a temporary filename in P_tmpdir with no - special prefix is generated. If LENPTR is not NULL, *LENPTR is set the - to length (including the terminating '\0') of the resultant filename, - which is returned. This goes through a cyclic pattern of all possible - filenames consisting of five decimal digits of the current pid and three - of the characters in `letters'. Data for tempnam and tmpnam is kept - separate, but when tempnam is using P_tmpdir and no prefix (i.e, it is - identical to tmpnam), the same data is used. Each potential filename is - tested for an already-existing file of the same name, and no name of an - existing file will be returned. When the cycle reaches its end - (12345ZZZ), NULL is returned. */ -char * -__stdio_gen_tempname (char *buf, size_t bufsize, const char *dir, - const char *pfx, int dir_search, size_t *lenptr, - FILE **streamptr, int large_file) -{ - int saverrno = errno; - static const char tmpdir[] = P_tmpdir; - size_t plen, dlen, len; - char *XXXXXX; - static uint64_t value; - struct timeval tv; - int count; - - if (dir_search) + d = __secure_getenv ("TMPDIR"); + if (d != NULL && direxists (d)) + dir = d; + else if (dir != NULL && direxists (dir)) + /* nothing */ ; + else if (direxists (P_tmpdir)) + dir = P_tmpdir; + else if (direxists ("/tmp")) + dir = "/tmp"; + else { - register const char *d = __secure_getenv ("TMPDIR"); - if (d != NULL && !diraccess (d)) - d = NULL; - if (d == NULL && dir != NULL && diraccess (dir)) - d = dir; - if (d == NULL && diraccess (tmpdir)) - d = tmpdir; - if (d == NULL && diraccess ("/tmp")) - d = "/tmp"; - if (d == NULL) - { - __set_errno (ENOENT); - return NULL; - } - dir = d; + __set_errno (ENOENT); + return -1; } - else - dir = tmpdir; dlen = strlen (dir); - - /* Remove trailing slashes from the directory name. */ while (dlen > 1 && dir[dlen - 1] == '/') - --dlen; + dlen--; /* remove trailing slashes */ - if (pfx != NULL && *pfx != '\0') + /* check we have room for "${dir}/${pfx}XXXXXX\0" */ + if (tmpl_len < dlen + 1 + plen + 6 + 1) { - plen = strlen (pfx); - if (plen > 5) - plen = 5; + __set_errno (EINVAL); + return -1; } - else - plen = 0; - len = __snprintf (buf, bufsize, "%.*s/%.*sXXXXXX", - (int) dlen, dir, (int) plen, pfx); + sprintf (tmpl, "%*s/%*sXXXXXX", dlen, dir, plen, pfx); + return 0; +} + +/* These are the characters used in temporary filenames. */ +static const char letters[] = +"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + +/* Generate a temporary file name based on TMPL. TMPL must match the + rules for mk[s]temp (i.e. end in "XXXXXX"). The name constructed + does not exist at the time of the call to __gen_tempname. TMPL is + overwritten with the result. If OPENIT is nonzero, creates the + file and returns a read-write fd; the file is mode 0600 modulo + umask. If LARGEFILE is nonzero, uses open64() instead of open(). + + We use a clever algorithm to get hard-to-predict names. */ +int +__gen_tempname (char *tmpl, int openit, int largefile) +{ + int len; + char *XXXXXX; + static uint64_t value; + struct timeval tv; + int count, fd; + int save_errno = errno; - if (len < dlen + plen + 7) - { + len = strlen (tmpl); + if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX")) + { __set_errno (EINVAL); - return NULL; - } + return -1; + } - XXXXXX = &buf[dlen + plen + 1]; + /* This is where the Xs start. */ + XXXXXX = &tmpl[len - 6]; /* Get some more or less random data. */ __gettimeofday (&tv, NULL); @@ -163,116 +143,45 @@ __stdio_gen_tempname (char *buf, size_t bufsize, const char *dir, v /= 62; XXXXXX[5] = letters[v % 62]; - if (streamptr != NULL) + if (openit) { - /* Try to create the file atomically. */ -#ifdef _G_OPEN64 - int fd = (large_file - ? __open (buf, O_RDWR|O_CREAT|O_EXCL, 0666) - : _G_OPEN64 (buf, O_RDWR|O_CREAT|O_EXCL, 0666)); + /* XXX Do we want to fail on largefile if 64 bit fileops + are not implemented, or just fall back to the old stuff? */ +#ifndef __stub_open64 + fd = (largefile + ? __open (tmpl, O_RDWR | O_CREAT | O_EXCL, 0666) + : __open64 (tmpl, O_RDWR | O_CREAT | O_EXCL, 0666)); #else - int fd = __open (buf, O_RDWR|O_CREAT|O_EXCL, 0666); + fd = __open (tmpl, O_RDWR | O_CREAT | O_EXCL, 0666); #endif if (fd >= 0) { - /* We got a new file that did not previously exist. - Create a stream for it. */ -#ifdef USE_IN_LIBIO - int save; - struct locked_FILE - { - struct _IO_FILE_plus fp; -#ifdef _IO_MTSAFE_IO - _IO_lock_t lock; -#endif - } *new_f; - struct _IO_FILE_plus *fp; - - new_f = (struct locked_FILE *) - malloc (sizeof (struct locked_FILE)); - if (new_f == NULL) - { - /* We lost trying to create a stream (out of memory?). - Nothing to do but remove the file, close the descriptor, - and return failure. */ - save = errno; - lose: - (void) remove (buf); - (void) __close (fd); - __set_errno (save); - return NULL; - } - fp = &new_f->fp; -#ifdef _IO_MTSAFE_IO - fp->file._lock = &new_f->lock; -#endif - _IO_init (&fp->file, 0); - _IO_JUMPS (&fp->file) = &_IO_file_jumps; - _IO_file_init (&fp->file); -# if !_IO_UNIFIED_JUMPTABLES - fp->vtable = NULL; -# endif - if (_IO_file_attach (&fp->file, fd) == NULL) - { - save = errno; - free (fp); - goto lose; - } - fp->file._flags &= ~_IO_DELETE_DONT_CLOSE; - - *streamptr = (FILE *) fp; -#else - *streamptr = __newstream (); - if (*streamptr == NULL) + __set_errno (save_errno); + return fd; + } + else if (errno != EEXIST) + /* Any other error will apply also to other names we might + try, and there are 2^32 or so of them, so give up now. */ + return -1; + } + else + { + struct stat st; + if (__stat (tmpl, &st) < 0) + { + if (errno == ENOENT) { - /* We lost trying to create a stream (out of memory?). - Nothing to do but remove the file, close the descriptor, - and return failure. */ - const int save = errno; - (void) remove (buf); - (void) __close (fd); - __set_errno (save); - return NULL; + __set_errno (save_errno); + return 0; } - (*streamptr)->__cookie = (__ptr_t) (long int) fd; - (*streamptr)->__mode.__write = 1; - (*streamptr)->__mode.__read = 1; - (*streamptr)->__mode.__binary = 1; -#endif + else + /* Give up now. */ + return -1; } -#if defined EMFILE || defined ENFILE || defined EINTR - else if (0 -# ifdef EMFILE - || errno == EMFILE -# endif -# ifdef ENFILE - || errno == ENFILE -# endif -# ifdef EINTR - || errno == EINTR -# endif - ) - /* We cannot open anymore files since all descriptors are - used or because we got a signal. */ - return NULL; -#endif - else - continue; } - else if (exists (buf)) - continue; - - /* If the file already existed we have continued the loop above, - so we only get here when we have a winning name to return. */ - - __set_errno (saverrno); - - if (lenptr != NULL) - *lenptr = len + 1; - return buf; } /* We got out of the loop because we ran out of combinations to try. */ - __set_errno (EEXIST); /* ? */ - return NULL; + __set_errno (EEXIST); + return -1; } |