Changeset 4e6a610 in mainline for uspace/lib/posix/src/stdio.c


Ignore:
Timestamp:
2018-06-25T09:54:28Z (6 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
bfe90b6
Parents:
fb0ec570
git-author:
Jiri Svoboda <jiri@…> (2018-06-24 17:51:54)
git-committer:
Jiri Svoboda <jiri@…> (2018-06-25 09:54:28)
Message:

Temporary file functions rework. Fix libposix access() not working on directories.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/posix/src/stdio.c

    rfb0ec570 r4e6a610  
    22 * Copyright (c) 2011 Jiri Zarevucky
    33 * Copyright (c) 2011 Petr Koupy
     4 * Copyright (c) 2018 Jiri Svoboda
    45 * All rights reserved.
    56 *
     
    3839
    3940#include <assert.h>
    40 
    4141#include <errno.h>
    42 
     42#include <stdbool.h>
     43#include <tmpfile.h>
     44
     45#include "posix/fcntl.h"
    4346#include "posix/stdlib.h"
    4447#include "posix/string.h"
     48#include "posix/sys/stat.h"
    4549#include "posix/sys/types.h"
    4650#include "posix/unistd.h"
     
    353357}
    354358
    355 /**
    356  * Get a unique temporary file name (obsolete).
    357  *
    358  * @param s Buffer for the file name. Must be at least L_tmpnam bytes long.
    359  * @return The value of s on success, NULL on failure.
    360  */
    361 char *tmpnam(char *s)
    362 {
    363         assert(L_tmpnam >= strlen("/tmp/tnXXXXXX"));
    364 
    365         static char buffer[L_tmpnam + 1];
    366         if (s == NULL) {
    367                 s = buffer;
    368         }
    369 
    370         strcpy(s, "/tmp/tnXXXXXX");
    371         mktemp(s);
    372 
    373         if (*s == '\0') {
    374                 /* Errno set by mktemp(). */
    375                 return NULL;
    376         }
    377 
    378         return s;
    379 }
    380 
    381 /**
    382  * Get an unique temporary file name with additional constraints (obsolete).
     359/** Determine if directory is an 'appropriate' temporary directory.
     360 *
     361 * @param dir Directory path
     362 * @return @c true iff directory is appropriate.
     363 */
     364static bool is_appropriate_tmpdir(const char *dir)
     365{
     366        struct stat sbuf;
     367
     368        /* Must not be NULL */
     369        if (dir == NULL)
     370                return false;
     371
     372        /* Must not be empty */
     373        if (dir[0] == '\0')
     374                return false;
     375
     376        if (stat(dir, &sbuf) != 0)
     377                return false;
     378
     379        /* Must be a directory */
     380        if ((sbuf.st_mode & S_IFMT) != S_IFDIR)
     381                return false;
     382
     383        /* Must be writable */
     384        if (access(dir, W_OK) != 0)
     385                return false;
     386
     387        return true;
     388}
     389
     390/** Construct unique file name.
     391 *
     392 * Never use this function.
    383393 *
    384394 * @param dir Path to directory, where the file should be created.
     
    388398char *tempnam(const char *dir, const char *pfx)
    389399{
    390         /* Sequence number of the filename. */
    391         static int seq = 0;
    392 
    393         size_t dir_len = strlen(dir);
    394         if (dir[dir_len - 1] == '/') {
    395                 dir_len--;
    396         }
    397 
    398         size_t pfx_len = strlen(pfx);
    399         if (pfx_len > 5) {
    400                 pfx_len = 5;
    401         }
    402 
    403         char *result = malloc(dir_len + /* slash*/ 1 +
    404             pfx_len + /* three-digit seq */ 3 + /* .tmp */ 4 + /* nul */ 1);
    405 
    406         if (result == NULL) {
    407                 errno = ENOMEM;
     400        const char *dpref;
     401        char *d;
     402        char *buf;
     403        int rc;
     404
     405        d = getenv("TMPDIR");
     406        if (is_appropriate_tmpdir(d))
     407                dpref = d;
     408        else if (is_appropriate_tmpdir(dir))
     409                dpref = dir;
     410        else if (is_appropriate_tmpdir(P_tmpdir))
     411                dpref = P_tmpdir;
     412        else
     413                dpref = "/";
     414
     415        if (dpref[strlen(dpref) - 1] != '/')
     416                rc = asprintf(&buf, "%s/%sXXXXXX", dpref, pfx);
     417        else
     418                rc = asprintf(&buf, "%s%sXXXXXX", dpref, pfx);
     419
     420        if (rc < 0)
     421                return NULL;
     422
     423        rc = __tmpfile_templ(buf, false);
     424        if (rc != 0) {
     425                free(buf);
    408426                return NULL;
    409427        }
    410428
    411         char *res_ptr = result;
    412         strncpy(res_ptr, dir, dir_len);
    413         res_ptr += dir_len;
    414         strncpy(res_ptr, pfx, pfx_len);
    415         res_ptr += pfx_len;
    416 
    417         for (; seq < 1000; ++seq) {
    418                 snprintf(res_ptr, 8, "%03d.tmp", seq);
    419 
    420                 int orig_errno = errno;
    421                 errno = EOK;
    422                 /* Check if the file exists. */
    423                 if (access(result, F_OK) == -1) {
    424                         if (errno == ENOENT) {
    425                                 errno = orig_errno;
    426                                 break;
    427                         } else {
    428                                 /* errno set by access() */
    429                                 return NULL;
    430                         }
    431                 }
    432         }
    433 
    434         if (seq == 1000) {
    435                 free(result);
    436                 errno = EINVAL;
    437                 return NULL;
    438         }
    439 
    440         return result;
    441 }
    442 
    443 /**
    444  * Create and open an unique temporary file.
    445  * The file is automatically removed when the stream is closed.
    446  *
    447  * @param dir Path to directory, where the file should be created.
    448  * @param pfx Optional prefix up to 5 characters long.
    449  * @return Newly allocated unique path for temporary file. NULL on failure.
    450  */
    451 FILE *tmpfile(void)
    452 {
    453         char filename[] = "/tmp/tfXXXXXX";
    454         int fd = mkstemp(filename);
    455         if (fd == -1) {
    456                 /* errno set by mkstemp(). */
    457                 return NULL;
    458         }
    459 
    460         /* Unlink the created file, so that it's removed on close(). */
    461         unlink(filename);
    462         return fdopen(fd, "w+");
     429        return buf;
    463430}
    464431
Note: See TracChangeset for help on using the changeset viewer.