LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/krb5 - store_stdio.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 94 130 72.3 %
Date: 2024-04-21 15:09:00 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2017 Kungliga Tekniska Högskolan
       3             :  * (Royal Institute of Technology, Stockholm, Sweden).
       4             :  * All rights reserved.
       5             :  *
       6             :  * Redistribution and use in source and binary forms, with or without
       7             :  * modification, are permitted provided that the following conditions
       8             :  * are met:
       9             :  *
      10             :  * 1. Redistributions of source code must retain the above copyright
      11             :  *    notice, this list of conditions and the following disclaimer.
      12             :  *
      13             :  * 2. Redistributions in binary form must reproduce the above copyright
      14             :  *    notice, this list of conditions and the following disclaimer in the
      15             :  *    documentation and/or other materials provided with the distribution.
      16             :  *
      17             :  * 3. Neither the name of the Institute nor the names of its contributors
      18             :  *    may be used to endorse or promote products derived from this software
      19             :  *    without specific prior written permission.
      20             :  *
      21             :  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
      22             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      23             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      24             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
      25             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      26             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      27             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      28             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      29             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      30             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      31             :  * SUCH DAMAGE.
      32             :  */
      33             : 
      34             : #include "krb5_locl.h"
      35             : #include "store-int.h"
      36             : 
      37             : #ifndef HAVE_FSEEKO
      38             : #define fseeko fseek
      39             : #define ftello ftell
      40             : #endif
      41             : 
      42             : typedef struct stdio_storage {
      43             :     FILE *f;
      44             :     off_t pos;
      45             : } stdio_storage;
      46             : 
      47             : #define F(S) (((stdio_storage*)(S)->data)->f)
      48             : #define POS(S) (((stdio_storage*)(S)->data)->pos)
      49             : 
      50             : static ssize_t
      51     3654058 : stdio_fetch(krb5_storage * sp, void *data, size_t size)
      52             : {
      53     3654058 :     char *cbuf = (char *)data;
      54       72298 :     ssize_t count;
      55     3654058 :     size_t rem = size;
      56             : 
      57             :     /* similar pattern to net_read() to support pipes */
      58     7301629 :     while (rem > 0) {
      59     3654058 :         count = fread(cbuf, 1, rem, F(sp));
      60     3654058 :         if (count < 0) {
      61           0 :             POS(sp) = -1;
      62           0 :             if (errno == EINTR)
      63           0 :                 continue;
      64             :             else
      65           0 :                 return count;
      66     3654058 :         } else if (count == 0) {
      67        6487 :             if (POS(sp) >= 0)
      68        6487 :                 POS(sp) += size - rem;
      69        6487 :             return size - rem;
      70             :         }
      71     3647571 :         cbuf += count;
      72     3647571 :         rem -= count;
      73             :     }
      74     3647571 :     if (POS(sp) >= 0)
      75     3647571 :         POS(sp) += size;
      76     3647571 :     return size;
      77             : }
      78             : 
      79             : static ssize_t
      80        5972 : stdio_store(krb5_storage * sp, const void *data, size_t size)
      81             : {
      82        5972 :     const char *cbuf = (const char *)data;
      83         560 :     ssize_t count;
      84        5972 :     size_t rem = size;
      85             : 
      86             :     /*
      87             :      * It's possible we just went from reading to writing if the file was open
      88             :      * for both.  Per C99 (N869 final draft) section 7.18.5.3, point 6, when
      89             :      * going from reading to writing [a file opened for both] one must seek.
      90             :      */
      91        5972 :     (void) fseeko(F(sp), 0, SEEK_CUR);
      92             : 
      93             :     /* similar pattern to net_write() to support pipes */
      94       11944 :     while (rem > 0) {
      95        5972 :         count = fwrite(cbuf, 1, rem, F(sp));
      96        5972 :         if (count < 0) {
      97           0 :             if (errno == EINTR)
      98           0 :                 continue;
      99             :             /*
     100             :              * What does it mean to have a short write when using stdio?
     101             :              *
     102             :              * It can't mean much.  After all stdio is buffering, so
     103             :              * earlier writes that appeared complete may have failed,
     104             :              * and so we don't know how much we really failed to write.
     105             :              */
     106           0 :             POS(sp) = -1;
     107           0 :             return -1;
     108             :         }
     109        5972 :         if (count == 0) {
     110           0 :             POS(sp) = -1;
     111           0 :             return -1;
     112             :         }
     113        5972 :         cbuf += count;
     114        5972 :         rem -= count;
     115             :     }
     116        5972 :     if (POS(sp) >= 0)
     117        5972 :         POS(sp) += size;
     118        5972 :     return size;
     119             : }
     120             : 
     121             : static off_t
     122      695873 : stdio_seek(krb5_storage * sp, off_t offset, int whence)
     123             : {
     124      695873 :     int save_errno = errno;
     125             : 
     126      695873 :     if (whence == SEEK_SET && POS(sp) == offset)
     127      207482 :         return POS(sp);
     128             : 
     129      483987 :     if (whence == SEEK_CUR && POS(sp) >= 0 && offset == 0)
     130      451648 :         return POS(sp);
     131             : 
     132       21983 :     if (fseeko(F(sp), offset, whence) != 0)
     133           0 :         return -1;
     134       21983 :     errno = save_errno;
     135       21983 :     return POS(sp) = ftello(F(sp));
     136             : }
     137             : 
     138             : static int
     139        1816 : stdio_trunc(krb5_storage * sp, off_t offset)
     140             : {
     141         204 :     off_t tmpoff;
     142        1816 :     int save_errno = errno;
     143             : 
     144        1816 :     if (fflush(F(sp)) == EOF)
     145           0 :         return errno;
     146        1816 :     tmpoff = ftello(F(sp));
     147        1816 :     if (tmpoff < 0)
     148           0 :         return errno;
     149        1816 :     if (tmpoff > offset)
     150           0 :         tmpoff = offset;
     151        1816 :     if (ftruncate(fileno(F(sp)), offset) == -1)
     152           0 :         return errno;
     153        1816 :     if (fseeko(F(sp), 0, SEEK_END) == -1)
     154           0 :         return errno;
     155        1816 :     if (fseeko(F(sp), tmpoff, SEEK_SET) == -1)
     156           0 :         return errno;
     157        1816 :     errno = save_errno;
     158        1816 :     POS(sp) = tmpoff;
     159        1816 :     return 0;
     160             : }
     161             : 
     162             : static int
     163        2282 : stdio_sync(krb5_storage * sp)
     164             : {
     165        2282 :     if (fflush(F(sp)) == EOF)
     166           0 :         return errno;
     167        2282 :     if (fsync(fileno(F(sp))) == -1)
     168           0 :         return errno;
     169        2051 :     return 0;
     170             : }
     171             : 
     172             : static void
     173       64954 : stdio_free(krb5_storage * sp)
     174             : {
     175       64954 :     int save_errno = errno;
     176             : 
     177       64954 :     if (F(sp) != NULL && fclose(F(sp)) == 0)
     178       64954 :         errno = save_errno;
     179       64954 :     F(sp) = NULL;
     180       64954 : }
     181             : 
     182             : /**
     183             :  * Open a krb5_storage using stdio for buffering.
     184             :  *
     185             :  * @return A krb5_storage on success, or NULL on out of memory error.
     186             :  *
     187             :  * @ingroup krb5_storage
     188             :  *
     189             :  * @sa krb5_storage_emem()
     190             :  * @sa krb5_storage_from_fd()
     191             :  * @sa krb5_storage_from_mem()
     192             :  * @sa krb5_storage_from_readonly_mem()
     193             :  * @sa krb5_storage_from_data()
     194             :  * @sa krb5_storage_from_socket()
     195             :  */
     196             : 
     197             : KRB5_LIB_FUNCTION krb5_storage * KRB5_LIB_CALL
     198       64954 : krb5_storage_stdio_from_fd(int fd_in, const char *mode)
     199             : {
     200        1379 :     krb5_storage *sp;
     201        1379 :     off_t off;
     202        1379 :     FILE *f;
     203       64954 :     int saved_errno = errno;
     204        1379 :     int fd;
     205             : 
     206       64954 :     off = lseek(fd_in, 0, SEEK_CUR);
     207       64954 :     if (off == -1)
     208           0 :         return NULL;
     209             : 
     210             : #ifdef _MSC_VER
     211             :     /*
     212             :      * This function used to try to pass the input to
     213             :      * _get_osfhandle() to test if the value is a HANDLE
     214             :      * but this doesn't work because doing so throws an
     215             :      * exception that will result in Watson being triggered
     216             :      * to file a Windows Error Report.
     217             :      */
     218             :     fd = _dup(fd_in);
     219             : #else
     220       64954 :     fd = dup(fd_in);
     221             : #endif
     222             : 
     223       64954 :     if (fd < 0)
     224           0 :         return NULL;
     225             : 
     226       64954 :     f = fdopen(fd, mode);
     227       64954 :     if (f == NULL) {
     228           0 :         (void) close(fd);
     229           0 :         return NULL;
     230             :     }
     231             : 
     232       64954 :     errno = saved_errno;
     233             : 
     234       64954 :     if (fseeko(f, off, SEEK_SET) == -1) {
     235           0 :         saved_errno = errno;
     236           0 :         (void) fclose(f);
     237           0 :         errno = saved_errno;
     238           0 :         return NULL;
     239             :     }
     240             : 
     241       64954 :     errno = ENOMEM;
     242       64954 :     sp = malloc(sizeof(krb5_storage));
     243       64954 :     if (sp == NULL) {
     244           0 :         saved_errno = errno;
     245           0 :         (void) fclose(f);
     246           0 :         errno = saved_errno;
     247           0 :         return NULL;
     248             :     }
     249             : 
     250       64954 :     errno = ENOMEM;
     251       64954 :     sp->data = malloc(sizeof(stdio_storage));
     252       64954 :     if (sp->data == NULL) {
     253           0 :         saved_errno = errno;
     254           0 :         (void) fclose(f);
     255           0 :         free(sp);
     256           0 :         errno = saved_errno;
     257           0 :         return NULL;
     258             :     }
     259       64954 :     sp->flags = 0;
     260       64954 :     sp->eof_code = HEIM_ERR_EOF;
     261       64954 :     F(sp) = f;
     262       64954 :     POS(sp) = off;
     263       64954 :     sp->fetch = stdio_fetch;
     264       64954 :     sp->store = stdio_store;
     265       64954 :     sp->seek = stdio_seek;
     266       64954 :     sp->trunc = stdio_trunc;
     267       64954 :     sp->fsync = stdio_sync;
     268       64954 :     sp->free = stdio_free;
     269       64954 :     sp->max_alloc = UINT32_MAX/64;
     270       64954 :     return sp;
     271             : }

Generated by: LCOV version 1.14