Ignore:
File:
1 edited

Legend:

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

    r5a6c28d1 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"
     
    169173
    170174/**
    171  * Write error messages to standard error.
    172  *
    173  * @param s Error message.
    174  */
    175 void perror(const char *s)
    176 {
    177         if (s == NULL || s[0] == '\0') {
    178                 fprintf(stderr, "%s\n", strerror(errno));
    179         } else {
    180                 fprintf(stderr, "%s: %s\n", s, strerror(errno));
    181         }
    182 }
    183 
    184 /** Restores stream a to position previously saved with fgetpos().
    185  *
    186  * @param stream Stream to restore
    187  * @param pos Position to restore
    188  * @return Zero on success, non-zero (with errno set) on failure
    189  */
    190 int fsetpos(FILE *stream, const fpos_t *pos)
    191 {
    192         return fseek64(stream, pos->offset, SEEK_SET);
    193 }
    194 
    195 /** Saves the stream's position for later use by fsetpos().
    196  *
    197  * @param stream Stream to save
    198  * @param pos Place to store the position
    199  * @return Zero on success, non-zero (with errno set) on failure
    200  */
    201 int fgetpos(FILE *restrict stream, fpos_t *restrict pos)
    202 {
    203         off64_t ret = ftell64(stream);
    204         if (ret != -1) {
    205                 pos->offset = ret;
    206                 return 0;
    207         } else {
    208                 return -1;
    209         }
    210 }
    211 
    212 /**
    213175 * Reposition a file-position indicator in a stream.
    214176 *
     
    320282
    321283/**
    322  * Print formatted output to the string.
    323  *
    324  * @param s Output string.
    325  * @param format Format description.
    326  * @return Either the number of printed characters (excluding null byte) or
    327  *     negative value on error.
    328  */
    329 int sprintf(char *s, const char *restrict format, ...)
    330 {
    331         va_list list;
    332         va_start(list, format);
    333         int result = vsprintf(s, format, list);
    334         va_end(list);
    335         return result;
    336 }
    337 
    338 /**
    339  * Print formatted output to the string.
    340  *
    341  * @param s Output string.
    342  * @param format Format description.
    343  * @param ap Print arguments.
    344  * @return Either the number of printed characters (excluding null byte) or
    345  *     negative value on error.
    346  */
    347 int vsprintf(char *s, const char *restrict format, va_list ap)
    348 {
    349         return vsnprintf(s, INT_MAX, format, ap);
    350 }
    351 
    352 /**
    353284 * Acquire file stream for the thread.
    354285 *
     
    426357}
    427358
    428 /**
    429  * Get a unique temporary file name (obsolete).
    430  *
    431  * @param s Buffer for the file name. Must be at least L_tmpnam bytes long.
    432  * @return The value of s on success, NULL on failure.
    433  */
    434 char *tmpnam(char *s)
    435 {
    436         assert(L_tmpnam >= strlen("/tmp/tnXXXXXX"));
    437 
    438         static char buffer[L_tmpnam + 1];
    439         if (s == NULL) {
    440                 s = buffer;
    441         }
    442 
    443         strcpy(s, "/tmp/tnXXXXXX");
    444         mktemp(s);
    445 
    446         if (*s == '\0') {
    447                 /* Errno set by mktemp(). */
    448                 return NULL;
    449         }
    450 
    451         return s;
    452 }
    453 
    454 /**
    455  * 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.
    456393 *
    457394 * @param dir Path to directory, where the file should be created.
     
    461398char *tempnam(const char *dir, const char *pfx)
    462399{
    463         /* Sequence number of the filename. */
    464         static int seq = 0;
    465 
    466         size_t dir_len = strlen(dir);
    467         if (dir[dir_len - 1] == '/') {
    468                 dir_len--;
    469         }
    470 
    471         size_t pfx_len = strlen(pfx);
    472         if (pfx_len > 5) {
    473                 pfx_len = 5;
    474         }
    475 
    476         char *result = malloc(dir_len + /* slash*/ 1 +
    477             pfx_len + /* three-digit seq */ 3 + /* .tmp */ 4 + /* nul */ 1);
    478 
    479         if (result == NULL) {
    480                 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);
    481426                return NULL;
    482427        }
    483428
    484         char *res_ptr = result;
    485         strncpy(res_ptr, dir, dir_len);
    486         res_ptr += dir_len;
    487         strncpy(res_ptr, pfx, pfx_len);
    488         res_ptr += pfx_len;
    489 
    490         for (; seq < 1000; ++seq) {
    491                 snprintf(res_ptr, 8, "%03d.tmp", seq);
    492 
    493                 int orig_errno = errno;
    494                 errno = EOK;
    495                 /* Check if the file exists. */
    496                 if (access(result, F_OK) == -1) {
    497                         if (errno == ENOENT) {
    498                                 errno = orig_errno;
    499                                 break;
    500                         } else {
    501                                 /* errno set by access() */
    502                                 return NULL;
    503                         }
    504                 }
    505         }
    506 
    507         if (seq == 1000) {
    508                 free(result);
    509                 errno = EINVAL;
    510                 return NULL;
    511         }
    512 
    513         return result;
    514 }
    515 
    516 /**
    517  * Create and open an unique temporary file.
    518  * The file is automatically removed when the stream is closed.
    519  *
    520  * @param dir Path to directory, where the file should be created.
    521  * @param pfx Optional prefix up to 5 characters long.
    522  * @return Newly allocated unique path for temporary file. NULL on failure.
    523  */
    524 FILE *tmpfile(void)
    525 {
    526         char filename[] = "/tmp/tfXXXXXX";
    527         int fd = mkstemp(filename);
    528         if (fd == -1) {
    529                 /* errno set by mkstemp(). */
    530                 return NULL;
    531         }
    532 
    533         /* Unlink the created file, so that it's removed on close(). */
    534         unlink(filename);
    535         return fdopen(fd, "w+");
     429        return buf;
    536430}
    537431
Note: See TracChangeset for help on using the changeset viewer.