Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset 4e6a610 in mainline


Ignore:
Timestamp:
2018-06-25T09:54:28Z (2 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
master
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.

Location:
uspace
Files:
5 added
1 deleted
13 edited

Legend:

Unmodified
Added
Removed
  • uspace/Makefile.common

    rfb0ec570 r4e6a610  
    165165ifneq ($(TEST_SOURCES),)
    166166        TEST_OUTPUTS = $(TEST_BINARY) $(TEST_BINARY).disasm
    167         TEST_CFLAGS = -I$(LIB_PREFIX)/pcut/include -D__helenos__
     167        TEST_CFLAGS = -I$(LIB_PREFIX)/pcut/include -D__helenos__ $(EXTRA_TEST_CFLAGS)
    168168        TEST_BINARY_LIBS = $(LIB_PREFIX)/pcut/libpcut.a
    169169        EXTRA_CLEAN += $(TEST_OUTPUTS) $(TEST_BINARY).map
  • uspace/lib/c/Makefile

    rfb0ec570 r4e6a610  
    4141EXTRA_OUTPUT = $(LINKER_SCRIPTS)
    4242EXTRA_CLEAN = $(LINKER_SCRIPTS)
     43EXTRA_TEST_CFLAGS = -Wno-deprecated-declarations
    4344LIBRARY = libc
    4445SOVERSION = 0.0
     
    151152        generic/adt/prodcons.c \
    152153        generic/time.c \
     154        generic/tmpfile.c \
    153155        generic/stdio.c \
    154156        generic/stdlib.c \
  • uspace/lib/c/generic/stdio.c

    rfb0ec570 r4e6a610  
    3434
    3535#include <errno.h>
     36#include <stdbool.h>
    3637#include <stdio.h>
     38#include <str.h>
    3739#include <str_error.h>
     40#include <tmpfile.h>
    3841#include <vfs/vfs.h>
     42
     43/** Static buffer for tmpnam function */
     44static char tmpnam_buf[L_tmpnam];
    3945
    4046/** Get stream position.
     
    8288        rc = vfs_rename_path(old_path, new_path);
    8389        if (rc != EOK) {
     90                /*
     91                 * Note that ISO C leaves the value of errno undefined,
     92                 * whereas according to UN*X standards, it is set.
     93                 */
    8494                errno = rc;
    8595                return -1;
     
    96106        rc = vfs_unlink_path(path);
    97107        if (rc != EOK) {
     108                /*
     109                 * Note that ISO C leaves the value of errno undefined,
     110                 * whereas according to UN*X standards, it is set.
     111                 */
    98112                errno = rc;
    99113                return -1;
     
    101115
    102116        return 0;
     117}
     118
     119/** Create a temporary file.
     120 *
     121 * @return Open stream descriptor or @c NULL on error. In that case
     122 *         errno is set (UN*X). Note that ISO C leaves the value of errno
     123 *         undefined.
     124 */
     125FILE *tmpfile(void)
     126{
     127        int file;
     128        FILE *stream;
     129
     130        file = __tmpfile();
     131        if (file < 0) {
     132                printf("file is < 0\n");
     133                errno = EEXIST;
     134                return NULL;
     135        }
     136
     137        stream = fdopen(file, "w+");
     138        if (stream == NULL) {
     139                printf("stream = NULL\n");
     140                vfs_put(file);
     141                errno = EACCES;
     142                return NULL;
     143        }
     144
     145        printf("returning stream\n");
     146        return stream;
     147}
     148
     149/** Create name for a temporary file.
     150 *
     151 * @param s Pointer to array of at least L_tmpnam bytes or @c NULL.
     152 * @return The pointer @a s or pointer to internal static buffer on success,
     153 *         @c NULL on error.
     154 */
     155char *tmpnam(char *s)
     156{
     157        char *p;
     158
     159        p = (s != NULL) ? s : tmpnam_buf;
     160        return __tmpnam(p);
    103161}
    104162
     
    115173}
    116174
     175
    117176/** @}
    118177 */
  • uspace/lib/c/include/stdio.h

    rfb0ec570 r4e6a610  
    4040#include <stdarg.h>
    4141#include <io/verify.h>
     42#include <_bits/NULL.h>
    4243#include <_bits/size_t.h>
    4344#include <_bits/wchar_t.h>
    4445#include <_bits/wint_t.h>
    45 
    46 #define EOF  (-1)
    47 
    48 #ifndef SEEK_SET
    49 #define SEEK_SET  0
    50 #endif
    51 
    52 #ifndef SEEK_CUR
    53 #define SEEK_CUR  1
    54 #endif
    55 
    56 #ifndef SEEK_END
    57 #define SEEK_END  2
    58 #endif
    59 
    60 /** Default size for stream I/O buffers */
    61 #define BUFSIZ  4096
    62 
    63 /** Max number of files that is guaranteed to be able to open at the same time */
    64 #define FOPEN_MAX VFS_MAX_OPEN_FILES
    65 
    66 /** Recommended size of fixed-size array for holding file names. */
    67 #define FILENAME_MAX 4096
    6846
    6947/** Forward declaration */
     
    7553        off64_t pos;
    7654} fpos_t;
     55
     56#ifndef _HELENOS_SOURCE
     57#define _IONBF 0
     58#define _IOLBF 1
     59#define _IOFBF 2
     60#endif
     61
     62/** Default size for stream I/O buffers */
     63#define BUFSIZ  4096
     64
     65#define EOF  (-1)
     66
     67/** Max number of files that is guaranteed to be able to open at the same time */
     68#define FOPEN_MAX VFS_MAX_OPEN_FILES
     69
     70/** Recommended size of fixed-size array for holding file names. */
     71#define FILENAME_MAX 4096
     72
     73/** Length of "/tmp/tmp.XXXXXX" + 1 */
     74#define L_tmpnam 16
     75
     76#ifndef SEEK_SET
     77#define SEEK_SET  0
     78#endif
     79
     80#ifndef SEEK_CUR
     81#define SEEK_CUR  1
     82#endif
     83
     84#ifndef SEEK_END
     85#define SEEK_END  2
     86#endif
     87
     88/** Minimum number of unique temporary file names */
     89#define TMP_MAX 1000000
    7790
    7891extern FILE *stdin;
     
    157170
    158171/* Misc file functions */
     172extern int remove(const char *);
    159173extern int rename(const char *, const char *);
    160 extern int remove(const char *);
    161 
    162 #ifndef _HELENOS_SOURCE
    163 #define _IONBF 0
    164 #define _IOLBF 1
    165 #define _IOFBF 2
    166 
    167 #endif
     174
     175extern FILE *tmpfile(void);
     176extern char *tmpnam(char *s) __attribute__((deprecated));
    168177
    169178#ifdef _HELENOS_SOURCE
  • uspace/lib/c/test/main.c

    rfb0ec570 r4e6a610  
    3838PCUT_IMPORT(scanf);
    3939PCUT_IMPORT(sprintf);
     40PCUT_IMPORT(stdio);
    4041PCUT_IMPORT(stdlib);
    4142PCUT_IMPORT(str);
  • uspace/lib/c/test/stdio.c

    rfb0ec570 r4e6a610  
    3838#include <pcut/pcut.h>
    3939#include <stdio.h>
     40#include <str.h>
     41#include <tmpfile.h>
     42#include <vfs/vfs.h>
    4043
    4144PCUT_INIT;
    4245
    4346PCUT_TEST_SUITE(stdio);
     47
     48/** remove function */
     49PCUT_TEST(remove)
     50{
     51        char buf[L_tmpnam];
     52        char *p;
     53        FILE *f;
     54        int rc;
     55
     56        /* Generate unique file name */
     57        p = tmpnam(buf);
     58        PCUT_ASSERT_NOT_NULL(p);
     59
     60        /* Removing it should fail */
     61        rc = remove(buf);
     62        PCUT_ASSERT_TRUE(rc != 0);
     63
     64        f = fopen(buf, "w");
     65        PCUT_ASSERT_NOT_NULL(f);
     66        fclose(f);
     67
     68        /* Remove for the first time */
     69        rc = remove(buf);
     70        PCUT_ASSERT_INT_EQUALS(0, rc);
     71
     72        /* Should fail the second time */
     73        rc = remove(buf);
     74        PCUT_ASSERT_TRUE(rc != 0);
     75}
     76
     77/** rename function */
     78PCUT_TEST(rename)
     79{
     80        char buf1[L_tmpnam];
     81        char buf2[L_tmpnam];
     82        char *p;
     83        FILE *f;
     84        int rc;
     85
     86        /* Generate first unique file name */
     87        p = tmpnam(buf1);
     88        PCUT_ASSERT_NOT_NULL(p);
     89
     90        /* Generate second unique file name */
     91        p = tmpnam(buf2);
     92        PCUT_ASSERT_NOT_NULL(p);
     93
     94        f = fopen(buf1, "w");
     95        PCUT_ASSERT_NOT_NULL(f);
     96        fclose(f);
     97
     98        /* Rename to the second name */
     99        rc = rename(buf1, buf2);
     100        PCUT_ASSERT_INT_EQUALS(0, rc);
     101
     102        /* First name should no longer exist */
     103        rc = remove(buf1);
     104        PCUT_ASSERT_TRUE(rc != 0);
     105
     106        /* Second can be removed */
     107        rc = remove(buf2);
     108        PCUT_ASSERT_INT_EQUALS(0, rc);
     109}
     110
     111/** tmpfile function */
     112PCUT_TEST(tmpfile)
     113{
     114        FILE *f;
     115        char c;
     116        size_t n;
     117
     118        f = tmpfile();
     119        PCUT_ASSERT_NOT_NULL(f);
     120
     121        c = 'x';
     122        n = fwrite(&c, sizeof(c), 1, f);
     123        PCUT_ASSERT_INT_EQUALS(1, n);
     124
     125        rewind(f);
     126        c = '\0';
     127        n = fread(&c, sizeof(c), 1, f);
     128        PCUT_ASSERT_INT_EQUALS(1, n);
     129        PCUT_ASSERT_INT_EQUALS('x', c);
     130
     131        fclose(f);
     132}
     133
     134/** tmpnam function with buffer argument */
     135PCUT_TEST(tmpnam_buf)
     136{
     137        char buf[L_tmpnam];
     138        char *p;
     139        FILE *f;
     140
     141        p = tmpnam(buf);
     142        PCUT_ASSERT_NOT_NULL(p);
     143
     144        f = fopen(p, "w+");
     145        PCUT_ASSERT_NOT_NULL(f);
     146        (void) remove(p);
     147        fclose(f);
     148}
     149
     150/** tmpnam function called twice */
     151PCUT_TEST(tmpnam_twice)
     152{
     153        char buf1[L_tmpnam];
     154        char buf2[L_tmpnam];
     155        char *p;
     156
     157        p = tmpnam(buf1);
     158        PCUT_ASSERT_NOT_NULL(p);
     159
     160        p = tmpnam(buf2);
     161        PCUT_ASSERT_NOT_NULL(p);
     162
     163        /* We must get two distinct names */
     164        PCUT_ASSERT_TRUE(str_cmp(buf1, buf2) != 0);
     165}
     166
     167/** tmpnam function with NULL argument */
     168PCUT_TEST(tmpnam_null)
     169{
     170        char *p;
     171        FILE *f;
     172
     173        p = tmpnam(NULL);
     174        PCUT_ASSERT_NOT_NULL(p);
     175
     176        f = fopen(p, "w+");
     177        PCUT_ASSERT_NOT_NULL(f);
     178        (void) remove(p);
     179        fclose(f);
     180}
    44181
    45182/** fgetpos and fsetpos functions */
     
    50187        FILE *f;
    51188
    52         // XXX Use tmpfile() when it is available
    53         f = fopen("/tmp/fgpsp.tmp", "w+");
    54         PCUT_ASSERT_NOT_NULL(f);
    55         rc = remove("/tmp/fgpsp.tmp");
    56         PCUT_ASSERT_INT_EQUALS(0, rc);
     189        f = tmpfile();
     190        PCUT_ASSERT_NOT_NULL(f);
    57191
    58192        rc = fputs("abc", f);
  • uspace/lib/posix/Makefile

    rfb0ec570 r4e6a610  
    8282TEST_SOURCES = \
    8383        test/main.c \
    84         test/scanf.c
     84        test/stdio.c \
     85        test/stdlib.c \
     86        test/unistd.c
     87
     88EXTRA_TEST_CFLAGS = -Wno-deprecated-declarations
    8589
    8690EXPORT_CPPFLAGS = \
  • uspace/lib/posix/include/posix/stdio.h

    rfb0ec570 r4e6a610  
    4848extern int fileno(FILE *);
    4949
     50#define P_tmpdir "/tmp"
     51
    5052/* Identifying the Terminal */
    5153#undef L_ctermid
     
    7779
    7880/* Temporary Files */
    79 #undef L_tmpnam
    80 #define L_tmpnam PATH_MAX
    81 extern char *tmpnam(char *s);
    8281extern char *tempnam(const char *dir, const char *pfx);
    83 extern FILE *tmpfile(void);
    8482
    8583#endif /* POSIX_STDIO_H_ */
  • uspace/lib/posix/include/posix/stdlib.h

    rfb0ec570 r4e6a610  
    5858
    5959/* Legacy Declarations */
    60 extern char *mktemp(char *tmpl);
     60extern char *mktemp(char *tmpl) __attribute__((deprecated));
    6161extern int bsd_getloadavg(double loadavg[], int nelem);
    6262
  • 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
  • uspace/lib/posix/src/stdlib.c

    rfb0ec570 r4e6a610  
    3838
    3939#include <errno.h>
     40#include <tmpfile.h>
    4041
    4142#include "posix/fcntl.h"
     
    163164int mkstemp(char *tmpl)
    164165{
    165         int fd = -1;
    166 
    167         char *tptr = tmpl + strlen(tmpl) - 6;
    168 
    169         while (fd < 0) {
    170                 if (*mktemp(tmpl) == '\0') {
    171                         /* Errno set by mktemp(). */
    172                         return -1;
    173                 }
    174 
    175                 fd = open(tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
    176 
    177                 if (fd == -1) {
    178                         /* Restore template to it's original state. */
    179                         snprintf(tptr, 7, "XXXXXX");
    180                 }
    181         }
    182 
    183         return fd;
     166        int tmpl_len;
     167        int file;
     168
     169        tmpl_len = strlen(tmpl);
     170        if (tmpl_len < 6) {
     171                errno = EINVAL;
     172                return -1;
     173        }
     174
     175        char *tptr = tmpl + tmpl_len - 6;
     176        if (strcmp(tptr, "XXXXXX") != 0) {
     177                errno = EINVAL;
     178                return -1;
     179        }
     180
     181        file = __tmpfile_templ(tmpl, true);
     182        if (file < 0) {
     183                errno = EIO; // XXX could be more specific
     184                return -1;
     185        }
     186
     187        return file;
    184188}
    185189
     
    194198char *mktemp(char *tmpl)
    195199{
    196         int tmpl_len = strlen(tmpl);
     200        int tmpl_len;
     201        int rc;
     202
     203        tmpl_len = strlen(tmpl);
    197204        if (tmpl_len < 6) {
    198205                errno = EINVAL;
     
    208215        }
    209216
    210         static int seq = 0;
    211 
    212         for (; seq < 1000000; ++seq) {
    213                 snprintf(tptr, 7, "%06d", seq);
    214 
    215                 int orig_errno = errno;
    216                 errno = 0;
    217                 /* Check if the file exists. */
    218                 if (access(tmpl, F_OK) == -1) {
    219                         if (errno == ENOENT) {
    220                                 errno = orig_errno;
    221                                 break;
    222                         } else {
    223                                 /* errno set by access() */
    224                                 *tmpl = '\0';
    225                                 return tmpl;
    226                         }
    227                 }
    228         }
    229 
    230         if (seq == 10000000) {
    231                 errno = EEXIST;
     217        rc = __tmpfile_templ(tmpl, false);
     218        if (rc != 0) {
     219                errno = EIO; // XXX could be more specific
    232220                *tmpl = '\0';
    233221                return tmpl;
  • uspace/lib/posix/src/unistd.c

    rfb0ec570 r4e6a610  
    3939#include <errno.h>
    4040
     41#include "posix/dirent.h"
    4142#include "posix/string.h"
     43#include "posix/sys/types.h"
    4244#include "posix/fcntl.h"
    4345
     
    368370                 */
    369371                int fd = open(path, O_RDONLY);
    370                 if (fd < 0)
    371                         return -1;
    372                 close(fd);
    373                 return 0;
     372                if (fd >= 0) {
     373                        close(fd);
     374                        return 0;
     375                }
     376                DIR *dir = opendir(path);
     377                if (dir != NULL) {
     378                        closedir(dir);
     379                        return 0;
     380                }
     381                return -1;
    374382        } else {
    375383                /* Invalid amode argument. */
  • uspace/lib/posix/test/main.c

    rfb0ec570 r4e6a610  
    11/*
    2  * Copyright (c) 2014 Vojtech Horky
     2 * Copyright (c) 2018 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    3131PCUT_INIT;
    3232
    33 PCUT_IMPORT(scanf);
     33PCUT_IMPORT(stdio);
     34PCUT_IMPORT(stdlib);
     35PCUT_IMPORT(unistd);
    3436
    3537PCUT_MAIN();
Note: See TracChangeset for help on using the changeset viewer.