LCOV - code coverage report
Current view: top level - src/base - pdf-fsys-disk.c (source / functions) Hit Total Coverage
Test: libgnupdf.info Lines: 230 529 43.5 %
Date: 2011-12-09 Functions: 23 42 54.8 %
Branches: 126 325 38.8 %

           Branch data     Line data    Source code
       1                 :            : /* -*- mode: C -*-
       2                 :            :  *
       3                 :            :  *       File:         pdf-fsys-disk.c
       4                 :            :  *       Date:         Thu May 22 18:27:35 2008
       5                 :            :  *
       6                 :            :  *       GNU PDF Library - Disk Filesystem Implementation
       7                 :            :  *
       8                 :            :  */
       9                 :            : 
      10                 :            : /* Copyright (C) 2008-2011 Free Software Foundation, Inc. */
      11                 :            : 
      12                 :            : /* This program is free software: you can redistribute it and/or modify
      13                 :            :  * it under the terms of the GNU General Public License as published by
      14                 :            :  * the Free Software Foundation, either version 3 of the License, or
      15                 :            :  * (at your option) any later version.
      16                 :            :  *
      17                 :            :  * This program is distributed in the hope that it will be useful,
      18                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      19                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      20                 :            :  * GNU General Public License for more details.
      21                 :            :  *
      22                 :            :  * You should have received a copy of the GNU General Public License
      23                 :            :  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
      24                 :            :  */
      25                 :            : 
      26                 :            : #include <config.h>
      27                 :            : 
      28                 :            : #include <errno.h>
      29                 :            : #include <stdio.h>
      30                 :            : #include <stdio-safer.h>
      31                 :            : #include <string.h>
      32                 :            : #include <sys/stat.h>
      33                 :            : 
      34                 :            : #if defined PDF_HOST_WIN32 || defined PDF_HOST_BSD
      35                 :            : #   include <sys/param.h>
      36                 :            : #   if defined PDF_HOST_BSD
      37                 :            : #      include <sys/mount.h>
      38                 :            : #   endif /* PDF_HOST_BSD */
      39                 :            : #else
      40                 :            : #   include <sys/statfs.h>
      41                 :            : #endif /* PDF_HOST_WIN32 | PDF_HOST_BSD */
      42                 :            : 
      43                 :            : #if defined PDF_HOST_WIN32
      44                 :            : #   include <windows.h>
      45                 :            : #   include <wchar.h>
      46                 :            : #endif /* !PDF_HOST_WIN32 */
      47                 :            : 
      48                 :            : #include <dirent.h>
      49                 :            : #include <unistd.h>
      50                 :            : 
      51                 :            : #include <pdf-types.h>
      52                 :            : #include <pdf-error.h>
      53                 :            : #include <pdf-fsys-disk.h>
      54                 :            : 
      55                 :            : #if FILE_SYSTEM_BACKSLASH_IS_FILE_NAME_SEPARATOR
      56                 :            : #   define DIR_SEPARATOR_C '\\'
      57                 :            : #   define DIR_SEPARATOR_S "\\"
      58                 :            : #   define IS_DIR_SEPARATOR(c) (((c) == '/') || ((c) == '\\'))
      59                 :            : #else
      60                 :            : #   define DIR_SEPARATOR_C '/'
      61                 :            : #   define DIR_SEPARATOR_S "/"
      62                 :            : #   define IS_DIR_SEPARATOR(c) ((c) == '/')
      63                 :            : #endif /* FILE_SYSTEM_BACKSLASH_IS_FILE_NAME_SEPARATOR */
      64                 :            : 
      65                 :            : /* Filesystem-specific implementation */
      66                 :            : struct pdf_fsys_disk_s
      67                 :            : {
      68                 :            :   /* The common parent struct */
      69                 :            :   struct pdf_fsys_s common;
      70                 :            : 
      71                 :            :   /* Precomputed filename separator */
      72                 :            :   pdf_text_t *filename_separator;
      73                 :            : };
      74                 :            : 
      75                 :            : /* Filesystem-specific implementation of open files */
      76                 :            : struct pdf_fsys_disk_file_s
      77                 :            : {
      78                 :            :   /* The common parent struct */
      79                 :            :   struct pdf_fsys_file_s common;
      80                 :            : 
      81                 :            :   /* Host-encoded path */
      82                 :            :   pdf_char_t *host_path;
      83                 :            :   pdf_size_t host_path_length;
      84                 :            : 
      85                 :            :   /* The descriptor of the open file */
      86                 :            :   FILE *file_descriptor;
      87                 :            : };
      88                 :            : 
      89                 :            : /* Private function declarations */
      90                 :            : 
      91                 :            : static pdf_status_t get_status_from_errno (int _errno);
      92                 :            : 
      93                 :            : static pdf_char_t *get_host_path (const pdf_text_t  *path,
      94                 :            :                                   pdf_size_t        *host_path_size,
      95                 :            :                                   pdf_error_t      **error);
      96                 :            : 
      97                 :            : static pdf_text_t *set_host_path (const pdf_char_t  *host_path,
      98                 :            :                                   const pdf_size_t   host_path_size,
      99                 :            :                                   pdf_error_t      **error);
     100                 :            : 
     101                 :            : static const pdf_char_t *get_mode_string (const enum pdf_fsys_file_mode_e mode);
     102                 :            : 
     103                 :            : #ifdef PDF_HOST_WIN32
     104                 :            : static pdf_bool_t win32_device_p (const pdf_text_t  *path,
     105                 :            :                                   pdf_error_t      **error);
     106                 :            : #endif
     107                 :            : 
     108                 :            : /*
     109                 :            :  * Filesystem Interface Implementation
     110                 :            :  */
     111                 :            : 
     112                 :            : /* Private function to de-initialize and de-allocate base file data */
     113                 :            : static void
     114                 :         26 : deinit_base_file_data (struct pdf_fsys_disk_file_s *file)
     115                 :            : {
     116                 :         26 :   pdf_fsys_impl_helper_file_deinit (&(file->common));
     117                 :            : 
     118         [ +  + ]:         26 :   if (file->host_path)
     119                 :         25 :     pdf_dealloc (file->host_path);
     120                 :         26 : }
     121                 :            : 
     122                 :            : /* Private function to allocate and initialize base file data */
     123                 :            : static pdf_bool_t
     124                 :         26 : init_base_file_data (struct pdf_fsys_disk_file_s  *file,
     125                 :            :                      const struct pdf_fsys_s      *fsys,
     126                 :            :                      const pdf_text_t             *path,
     127                 :            :                      enum pdf_fsys_file_mode_e     mode,
     128                 :            :                      pdf_error_t                 **error)
     129                 :            : {
     130                 :         26 :   memset (file, 0, sizeof (struct pdf_fsys_disk_file_s));
     131                 :            : 
     132                 :            :   /* Initialize common data */
     133         [ -  + ]:         26 :   if (!pdf_fsys_impl_helper_file_init (&(file->common),
     134                 :            :                                        fsys,
     135                 :            :                                        path,
     136                 :            :                                        mode,
     137                 :            :                                        error))
     138                 :            :     {
     139                 :          0 :       deinit_base_file_data (file);
     140                 :          0 :       return PDF_FALSE;
     141                 :            :     }
     142                 :            : 
     143                 :            :   /* Get the host encoded path */
     144         [ +  + ]:         26 :   if (file->common.unicode_path)
     145                 :            :     {
     146                 :         25 :       file->host_path = get_host_path (file->common.unicode_path,
     147                 :            :                                        &(file->host_path_length),
     148                 :            :                                        error);
     149         [ -  + ]:         25 :       if (!file->host_path)
     150                 :            :         {
     151                 :          0 :           deinit_base_file_data (file);
     152                 :          0 :           return PDF_FALSE;
     153                 :            :         }
     154                 :            :     }
     155                 :            : 
     156                 :         26 :   return PDF_TRUE;
     157                 :            : }
     158                 :            : 
     159                 :            : static pdf_bool_t
     160                 :            : is_absolute_path (const pdf_text_t  *path,
     161                 :            :                   pdf_error_t      **error)
     162                 :            : {
     163                 :            :   pdf_char_t *utf8;
     164                 :            :   pdf_size_t utf8_size;
     165                 :            : 
     166                 :         16 :   utf8 = pdf_text_get_unicode (path,
     167                 :            :                                PDF_TEXT_UTF8,
     168                 :            :                                PDF_TEXT_UNICODE_WITH_NUL_SUFFIX,
     169                 :            :                                &utf8_size,
     170                 :            :                                error);
     171         [ -  + ]:         16 :   if (!utf8)
     172                 :          0 :     return PDF_FALSE;
     173                 :            : 
     174         [ -  + ]:         16 :   if (utf8_size == 0)
     175                 :            :     {
     176                 :          0 :       pdf_dealloc (utf8);
     177                 :          0 :       return PDF_FALSE;
     178                 :            :     }
     179                 :            : 
     180         [ +  - ]:         16 :   if (IS_DIR_SEPARATOR (utf8[0]))
     181                 :            :     {
     182                 :         16 :       pdf_dealloc (utf8);
     183                 :         16 :       return PDF_TRUE;
     184                 :            :     }
     185                 :            : 
     186                 :            : #ifdef PDF_HOST_WIN32
     187                 :            :   /* Recognize drive letter in native windows */
     188                 :            :   if (utf8_size >= 3 &&
     189                 :            :       ((utf8[0] >= 'a' && utf8[0] <= 'z') ||
     190                 :            :        (utf8[0] >= 'A' && utf8[0] <= 'Z')) &&
     191                 :            :       utf8[1] == ':' &&
     192                 :            :       IS_DIR_SEPARATOR (utf8[2]))
     193                 :            :     {
     194                 :            :       pdf_dealloc (utf8);
     195                 :            :       return PDF_TRUE;
     196                 :            :     }
     197                 :            : #endif /* PDF_HOST_WIN32 */
     198                 :            : 
     199                 :          0 :   pdf_dealloc (utf8);
     200                 :          0 :   return PDF_FALSE;
     201                 :            : }
     202                 :            : 
     203                 :            : static pdf_text_t *
     204                 :            : get_current_path (pdf_error_t **error)
     205                 :            : {
     206                 :            : #ifdef PDF_HOST_WIN32
     207                 :            :   wchar_t dummy[2];
     208                 :            :   wchar_t *current;
     209                 :            :   pdf_size_t current_len;
     210                 :            :   pdf_text_t *current_text;
     211                 :            : 
     212                 :            :   /* Get number of wchar_t items that may get written when getting current
     213                 :            :    * directory (includes last NIL wchar_t).
     214                 :            :    * Note len here is given in wchar_ts not in bytes */
     215                 :            :   current_len = GetCurrentDirectoryW (2, dummy);
     216                 :            : 
     217                 :            :   /* Allocate buffer to store the current dir */
     218                 :            :   current = pdf_alloc (sizeof (wchar_t) * current_len);
     219                 :            :   if (!current)
     220                 :            :     {
     221                 :            :       pdf_set_error (error,
     222                 :            :                      PDF_EDOMAIN_BASE_FSYS,
     223                 :            :                      PDF_ENOMEM,
     224                 :            :                      "cannot get current path: "
     225                 :            :                      "couldn't allocate %lu bytes",
     226                 :            :                      sizeof (wchar_t) * current_len);
     227                 :            :       return NULL;
     228                 :            :     }
     229                 :            : 
     230                 :            :   /* Fill the buffer with the current directory */
     231                 :            :   if (GetCurrentDirectoryW (current_len, current) != (current_len - 1))
     232                 :            :     {
     233                 :            :       pdf_dealloc (current);
     234                 :            :       pdf_set_error (error,
     235                 :            :                      PDF_EDOMAIN_BASE_FSYS,
     236                 :            :                      PDF_ENOMEM,
     237                 :            :                      "cannot get current path: "
     238                 :            :                      "couldn't query current directory");
     239                 :            :       return NULL;
     240                 :            :     }
     241                 :            : 
     242                 :            :   current_text = set_host_path ((const pdf_char_t *)current,
     243                 :            :                                 (current_len - 1) * sizeof (wchar_t),
     244                 :            :                                 error);
     245                 :            : 
     246                 :            :   pdf_dealloc (current);
     247                 :            :   return current_text;
     248                 :            : 
     249                 :            : #else
     250                 :            :   pdf_char_t *current;
     251                 :            :   pdf_text_t *current_text;
     252                 :            : 
     253                 :            :   /* Rely on gnulib's getcwd module for portability issues */
     254                 :          0 :   current = getcwd (NULL, 0);
     255         [ #  # ]:          0 :   if (!current)
     256                 :            :     {
     257                 :          0 :       pdf_set_error (error,
     258                 :            :                      PDF_EDOMAIN_BASE_FSYS,
     259                 :            :                      PDF_ENOMEM,
     260                 :            :                      "cannot build absolute path: "
     261                 :            :                      "couldn't get current directory");
     262                 :          0 :       return NULL;
     263                 :            :     }
     264                 :            : 
     265                 :          0 :   current_text = set_host_path (current,
     266                 :            :                                 strlen (current),
     267                 :            :                                 error);
     268                 :            : 
     269                 :          0 :   pdf_dealloc (current);
     270                 :          0 :   return current_text;
     271                 :            : 
     272                 :            : #endif /* !PDF_HOST_WIN32 */
     273                 :            : }
     274                 :            : 
     275                 :            : static pdf_char_t *
     276                 :            : skip_root_utf8 (const pdf_char_t *path_utf8)
     277                 :            : {
     278                 :         16 :   pdf_char_t *p = (pdf_char_t *)path_utf8;
     279                 :            : 
     280                 :            : #ifdef PDF_HOST_WIN32
     281                 :            :   /* On windows, skip leading X:\ */
     282                 :            :   if (((p[0] >= 'a' && p[0] <= 'z') ||
     283                 :            :        (p[0] >= 'A' && p[0] <= 'Z')) &&
     284                 :            :       p[1] == ':' &&
     285                 :            :       IS_DIR_SEPARATOR (p[2]))
     286                 :            :     p = &p[3];
     287                 :            : #else
     288                 :            :   /* Skip initial slash */
     289         [ +  - ]:         16 :   if (IS_DIR_SEPARATOR (p[0]))
     290                 :         16 :     p++;
     291                 :            : #endif /* PDF_HOST_WIN32 */
     292                 :            : 
     293                 :         16 :   return p;
     294                 :            : }
     295                 :            : 
     296                 :            : /* Returns UTF-8 encoded path */
     297                 :            : static pdf_char_t *
     298                 :         16 : ensure_absolute_path (const pdf_fsys_t  *fsys,
     299                 :            :                       const pdf_text_t  *path,
     300                 :            :                       pdf_error_t      **error)
     301                 :            : {
     302                 :         16 :   pdf_error_t *inner_error = NULL;
     303                 :            :   pdf_char_t *path_utf8;
     304                 :            :   pdf_size_t path_utf8_size;
     305                 :            : 
     306         [ -  + ]:         16 :   if (!is_absolute_path (path, &inner_error))
     307                 :            :     {
     308                 :            :       pdf_text_t *current;
     309                 :            :       pdf_text_t *absolute;
     310                 :            : 
     311         [ #  # ]:          0 :       if (inner_error)
     312                 :            :         {
     313                 :          0 :           pdf_propagate_error (error, inner_error);
     314                 :          0 :           return NULL;
     315                 :            :         }
     316                 :            : 
     317                 :            :       /* Get current path */
     318                 :          0 :       current = get_current_path (error);
     319         [ #  # ]:          0 :       if (!current)
     320                 :          0 :         return NULL;
     321                 :            : 
     322                 :            :       /* Build path with current absolute plus relative */
     323                 :          0 :       absolute = pdf_fsys_build_path (fsys,
     324                 :            :                                       error,
     325                 :            :                                       current,
     326                 :            :                                       path,
     327                 :            :                                       NULL);
     328                 :          0 :       pdf_text_destroy (current);
     329                 :            : 
     330         [ #  # ]:          0 :       if (!absolute)
     331                 :          0 :         return NULL;
     332                 :            : 
     333                 :            :       /* Get UTF-8 of the resulting absolute path */
     334                 :          0 :       path_utf8 = pdf_text_get_unicode (absolute,
     335                 :            :                                         PDF_TEXT_UTF8,
     336                 :            :                                         PDF_TEXT_UNICODE_WITH_NUL_SUFFIX,
     337                 :            :                                         &path_utf8_size,
     338                 :            :                                         error);
     339                 :          0 :       pdf_text_destroy (absolute);
     340                 :            :     }
     341                 :            :   else
     342                 :            :     {
     343                 :            :       /* Get UTF-8 of the original absolute path */
     344                 :         16 :       path_utf8 = pdf_text_get_unicode (path,
     345                 :            :                                         PDF_TEXT_UTF8,
     346                 :            :                                         PDF_TEXT_UNICODE_WITH_NUL_SUFFIX,
     347                 :            :                                         &path_utf8_size,
     348                 :            :                                         error);
     349                 :            :     }
     350                 :            : 
     351                 :         16 :   return path_utf8;
     352                 :            : }
     353                 :            : 
     354                 :            : /* Based on GLib's canonicalize_filename(), in gio/glocalfile.c
     355                 :            :  *  Copyright (C) 2006-2007 Red Hat, Inc.
     356                 :            :  *  Author: Alexander Larsson <alexl@redhat.com>
     357                 :            :  *
     358                 :            :  * Returns either UTF-8 encoded path or pdf_text_t, or both
     359                 :            :  */
     360                 :            : static pdf_bool_t
     361                 :         16 : canonicalize_path (const pdf_fsys_t  *fsys,
     362                 :            :                    const pdf_text_t  *path,
     363                 :            :                    pdf_text_t       **canonicalized_path,
     364                 :            :                    pdf_char_t       **canonicalized_path_utf8,
     365                 :            :                    pdf_error_t      **error)
     366                 :            : {
     367                 :            :   pdf_char_t *canon;
     368                 :            :   pdf_char_t *start;
     369                 :            :   pdf_char_t *p;
     370                 :            :   pdf_char_t *q;
     371                 :            :   int i;
     372                 :            : 
     373                 :            :   /* Get UTF-8 encoded path */
     374                 :         16 :   canon = ensure_absolute_path (fsys, path, error);
     375         [ -  + ]:         16 :   if (!canon)
     376                 :          0 :     return PDF_FALSE;
     377                 :            : 
     378                 :            :   /* Skip root */
     379                 :         16 :   start = skip_root_utf8 (canon);
     380                 :            : 
     381                 :            :   /* POSIX allows double slashes at the start to
     382                 :            :    * mean something special (as does windows too).
     383                 :            :    * So, "//" != "/", but more than two slashes
     384                 :            :    * is treated as "/".
     385                 :            :    */
     386                 :         16 :   i = 0;
     387 [ +  + ][ +  - ]:         32 :   for (p = start - 1;
     388                 :            :        (p >= canon) &&
     389                 :         16 :          IS_DIR_SEPARATOR (*p);
     390                 :         16 :        p--)
     391                 :         16 :     i++;
     392         [ -  + ]:         16 :   if (i > 2)
     393                 :            :     {
     394                 :          0 :       i -= 1;
     395                 :          0 :       start -= i;
     396                 :          0 :       memmove (start, start + i, strlen (start + i) + 1);
     397                 :            :     }
     398                 :            : 
     399                 :         16 :   p = start;
     400         [ +  + ]:         72 :   while (*p != 0)
     401                 :            :     {
     402 [ +  + ][ +  + ]:         56 :       if (p[0] == '.' && (p[1] == 0 || IS_DIR_SEPARATOR (p[1])))
     403                 :            :         {
     404                 :          2 :           memmove (p, p + 1, strlen (p + 1) + 1);
     405                 :            :         }
     406 [ +  + ][ +  - ]:         68 :       else if (p[0] == '.' && p[1] == '.' && (p[2] == 0 || IS_DIR_SEPARATOR (p[2])))
                 [ +  - ]
     407                 :            :         {
     408                 :         14 :           q = p + 2;
     409                 :            :           /* Skip previous separator */
     410                 :         14 :           p = p - 2;
     411         [ -  + ]:         14 :           if (p < start)
     412                 :          0 :             p = start;
     413 [ +  - ][ +  + ]:         78 :           while (p > start && !IS_DIR_SEPARATOR (*p))
     414                 :         64 :             p--;
     415         [ +  - ]:         14 :           if (IS_DIR_SEPARATOR (*p))
     416                 :         14 :             *p++ = DIR_SEPARATOR_C;
     417                 :         14 :           memmove (p, q, strlen (q)+1);
     418                 :            :         }
     419                 :            :       else
     420                 :            :         {
     421                 :            :           /* Skip until next separator */
     422         [ +  + ]:        212 :           while (*p != 0 && !IS_DIR_SEPARATOR (*p))
     423                 :        172 :             p++;
     424                 :            : 
     425         [ +  + ]:         40 :           if (*p != 0)
     426                 :            :             {
     427                 :            :               /* Canonicalize one separator */
     428                 :         32 :               *p++ = DIR_SEPARATOR_C;
     429                 :            :             }
     430                 :            :         }
     431                 :            : 
     432                 :            :       /* Remove additional separators */
     433                 :         56 :       q = p;
     434         [ +  + ]:        110 :       while (*q && IS_DIR_SEPARATOR (*q))
     435                 :         54 :         q++;
     436                 :            : 
     437         [ +  + ]:         56 :       if (p != q)
     438                 :         24 :         memmove (p, q, strlen (q)+1);
     439                 :            :     }
     440                 :            : 
     441                 :            :   /* Remove trailing slashes */
     442 [ +  + ][ +  + ]:         16 :   if (p > start && IS_DIR_SEPARATOR (*(p-1)))
     443                 :          6 :     *(p-1) = 0;
     444                 :            : 
     445                 :            : 
     446                 :            :   /* If length of the canonicalized path is zero, report error */
     447         [ -  + ]:         16 :   if (canon [0] == '\0')
     448                 :            :     {
     449                 :          0 :       pdf_set_error (error,
     450                 :            :                      PDF_EDOMAIN_BASE_FSYS,
     451                 :            :                      PDF_EBADDATA,
     452                 :            :                      "empty canonicalized path built");
     453                 :          0 :       pdf_dealloc (canon);
     454                 :          0 :       return PDF_FALSE;
     455                 :            :     }
     456                 :            : 
     457                 :            :   /* Set output(s) */
     458                 :            : 
     459         [ -  + ]:         16 :   if (canonicalized_path)
     460                 :          0 :     *canonicalized_path = pdf_text_new_from_unicode (canon,
     461                 :            :                                                      strlen (canon),
     462                 :            :                                                      PDF_TEXT_UTF8,
     463                 :            :                                                      error);
     464                 :            : 
     465         [ +  - ]:         16 :   if (canonicalized_path_utf8)
     466                 :         16 :     *canonicalized_path_utf8 = canon;
     467                 :            :   else
     468                 :          0 :     pdf_dealloc (canon);
     469                 :            : 
     470                 :         16 :   return PDF_TRUE;
     471                 :            : }
     472                 :            : 
     473                 :            : /* Host-dependent fopen() */
     474                 :            : #ifdef PDF_HOST_WIN32
     475                 :            : #define PDF_FOPEN(f,m) _wfopen((wchar_t *)f,(wchar_t *)m)
     476                 :            : #else
     477                 :            : #define PDF_FOPEN(f,m) fopen_safer(f,m)
     478                 :            : #endif
     479                 :            : 
     480                 :            : static pdf_fsys_file_t *
     481                 :         25 : file_open (const pdf_fsys_t           *fsys,
     482                 :            :            const pdf_text_t           *path,
     483                 :            :            enum pdf_fsys_file_mode_e   mode,
     484                 :            :            pdf_error_t               **error)
     485                 :            : {
     486                 :            :   struct pdf_fsys_disk_file_s *file;
     487                 :            : 
     488         [ -  + ]:         25 :   PDF_ASSERT_POINTER_RETURN_VAL (path, NULL);
     489                 :            :   PDF_ASSERT_RETURN_VAL (mode >= PDF_FSYS_OPEN_MODE_FIRST, NULL);
     490         [ -  + ]:         25 :   PDF_ASSERT_RETURN_VAL (mode <= PDF_FSYS_OPEN_MODE_LAST, NULL);
     491                 :            : 
     492                 :            :   /* Allocate private data storage for the file */
     493                 :         25 :   file = (struct pdf_fsys_disk_file_s *) pdf_alloc (sizeof (struct pdf_fsys_disk_file_s));
     494         [ -  + ]:         25 :   if (!file)
     495                 :            :     {
     496                 :          0 :       pdf_set_error (error,
     497                 :            :                      PDF_EDOMAIN_BASE_FSYS,
     498                 :            :                      PDF_ENOMEM,
     499                 :            :                      "cannot create disk file object: "
     500                 :            :                      "couldn't allocate %lu bytes",
     501                 :            :                      (unsigned long) sizeof (struct pdf_fsys_disk_file_s));
     502                 :          0 :       return NULL;
     503                 :            :     }
     504                 :            : 
     505                 :            :   /* Init base data */
     506         [ -  + ]:         25 :   if (!init_base_file_data (file,
     507                 :            :                             fsys,
     508                 :            :                             path,
     509                 :            :                             mode,
     510                 :            :                             error))
     511                 :            :     {
     512                 :          0 :       deinit_base_file_data (file);
     513                 :          0 :       pdf_dealloc (file);
     514                 :          0 :       return NULL;
     515                 :            :     }
     516                 :            : 
     517                 :            :   /* Open the file */
     518                 :         25 :   file->file_descriptor = PDF_FOPEN (file->host_path,
     519                 :            :                                      get_mode_string (mode));
     520         [ +  + ]:         25 :   if (!file->file_descriptor)
     521                 :            :     {
     522                 :          2 :       pdf_set_error (error,
     523                 :            :                      PDF_EDOMAIN_BASE_FSYS,
     524                 :            :                      get_status_from_errno (errno),
     525                 :            :                      "cannot open file: '%s'",
     526                 :            :                      strerror (errno));
     527                 :          2 :       deinit_base_file_data (file);
     528                 :          2 :       pdf_dealloc (file);
     529                 :          2 :       return NULL;
     530                 :            :     }
     531                 :            : 
     532                 :         25 :   return (struct pdf_fsys_file_s *)file;
     533                 :            : }
     534                 :            : 
     535                 :            : static pdf_fsys_file_t *
     536                 :          1 : file_open_tmp (const pdf_fsys_t  *fsys,
     537                 :            :                pdf_error_t      **error)
     538                 :            : {
     539                 :            :   struct pdf_fsys_disk_file_s *file;
     540                 :            : 
     541                 :            :   /* Allocate private data storage for the file */
     542                 :          1 :   file = (struct pdf_fsys_disk_file_s *) pdf_alloc (sizeof (struct pdf_fsys_disk_file_s));
     543         [ -  + ]:          1 :   if (!file)
     544                 :            :     {
     545                 :          0 :       pdf_set_error (error,
     546                 :            :                      PDF_EDOMAIN_BASE_FSYS,
     547                 :            :                      PDF_ENOMEM,
     548                 :            :                      "cannot create disk file object: "
     549                 :            :                      "couldn't allocate %lu bytes",
     550                 :            :                      (unsigned long) sizeof (struct pdf_fsys_disk_file_s));
     551                 :          0 :       return NULL;
     552                 :            :     }
     553                 :            : 
     554                 :            :   /* Init base data */
     555         [ -  + ]:          1 :   if (!init_base_file_data (file,
     556                 :            :                             fsys,
     557                 :            :                             NULL,
     558                 :            :                             PDF_FSYS_OPEN_MODE_RW,
     559                 :            :                             error))
     560                 :            :     {
     561                 :          0 :       deinit_base_file_data (file);
     562                 :          0 :       pdf_dealloc (file);
     563                 :          0 :       return NULL;
     564                 :            :     }
     565                 :            : 
     566                 :            :   /* Open a temporary file.  */
     567                 :          1 :   file->file_descriptor = tmpfile_safer ();
     568         [ -  + ]:          1 :   if (!file->file_descriptor)
     569                 :            :     {
     570                 :          0 :       pdf_set_error (error,
     571                 :            :                      PDF_EDOMAIN_BASE_FSYS,
     572                 :            :                      get_status_from_errno (errno),
     573                 :            :                      "cannot open temporary file: '%s'",
     574                 :            :                      strerror (errno));
     575                 :          0 :       deinit_base_file_data (file);
     576                 :          0 :       pdf_dealloc (file);
     577                 :          0 :       return NULL;
     578                 :            :     }
     579                 :            : 
     580                 :          1 :   return (struct pdf_fsys_file_s *)file;
     581                 :            : }
     582                 :            : 
     583                 :            : static pdf_bool_t
     584                 :         24 : file_close (pdf_fsys_file_t  *file,
     585                 :            :             pdf_error_t     **error)
     586                 :            : {
     587                 :         24 :   struct pdf_fsys_disk_file_s *disk_file = (struct pdf_fsys_disk_file_s *)file;
     588                 :         24 :   pdf_bool_t ret = PDF_TRUE;
     589                 :            : 
     590         [ -  + ]:         24 :   PDF_ASSERT_POINTER_RETURN_VAL (file, PDF_FALSE);
     591         [ -  + ]:         24 :   PDF_ASSERT_RETURN_VAL (disk_file->file_descriptor > 0, PDF_FALSE);
     592                 :            : 
     593                 :            :   /* Host path is optional, not available in tmp files */
     594                 :            : 
     595                 :            :   /* Close the I/O stream only if still open */
     596   [ +  -  -  + ]:         48 :   if (disk_file->file_descriptor &&
     597                 :         24 :       fclose (disk_file->file_descriptor) == EOF)
     598                 :            :     {
     599                 :            :       /* Note that even if an error is set, the file is fully closed
     600                 :            :        * and the object disposed */
     601                 :          0 :       pdf_set_error (error,
     602                 :            :                      PDF_EDOMAIN_BASE_FSYS,
     603                 :            :                      get_status_from_errno (errno),
     604                 :            :                      "cannot close temporary file: '%s'",
     605                 :            :                      strerror (errno));
     606                 :          0 :       ret = PDF_FALSE;
     607                 :            :     }
     608                 :            : 
     609                 :         24 :   deinit_base_file_data (disk_file);
     610                 :         24 :   pdf_dealloc (disk_file);
     611                 :         24 :   return ret;
     612                 :            : }
     613                 :            : 
     614                 :            : /* Host-dependent mkdir() */
     615                 :            : #ifdef PDF_HOST_WIN32
     616                 :            : #define PDF_MKDIR(f,m) _wmkdir((const wchar_t *)f)
     617                 :            : #else
     618                 :            : #define PDF_MKDIR(f,m) mkdir(f,m)
     619                 :            : #endif
     620                 :            : 
     621                 :            : static pdf_bool_t
     622                 :          0 : create_folder (const pdf_fsys_t  *fsys,
     623                 :            :                const pdf_text_t  *path,
     624                 :            :                pdf_error_t      **error)
     625                 :            : {
     626                 :            :   pdf_char_t *host_path;
     627                 :            : 
     628         [ #  # ]:          0 :   PDF_ASSERT_POINTER_RETURN_VAL (path, PDF_FALSE);
     629                 :            : 
     630                 :            :   /* Get a host-encoded version of the path name */
     631                 :          0 :   host_path = get_host_path (path, NULL, error);
     632         [ #  # ]:          0 :   if (!host_path)
     633                 :          0 :     return PDF_FALSE;
     634                 :            : 
     635                 :            :   /* Set the permissions of the new directory (posix-only):
     636                 :            :    * rwxr_xr_x
     637                 :            :    */
     638                 :            : 
     639                 :            :   /* Create the directory */
     640         [ #  # ]:          0 :   if (PDF_MKDIR (host_path,                             \
     641                 :            :                  (S_IRUSR | S_IWUSR | S_IXUSR |         \
     642                 :            :                   S_IRGRP | S_IXGRP |                   \
     643                 :            :                   S_IROTH | S_IXOTH)) != 0)
     644                 :            :     {
     645                 :          0 :       pdf_set_error (error,
     646                 :            :                      PDF_EDOMAIN_BASE_FSYS,
     647                 :            :                      get_status_from_errno (errno),
     648                 :            :                      "cannot create directory: '%s'",
     649                 :            :                      strerror (errno));
     650                 :          0 :       pdf_dealloc (host_path);
     651                 :          0 :       return PDF_FALSE;
     652                 :            :     }
     653                 :            : 
     654                 :          0 :   pdf_dealloc (host_path);
     655                 :          0 :   return PDF_TRUE;
     656                 :            : }
     657                 :            : 
     658                 :            : /* Host-dependent opendir(), closedir() and friends */
     659                 :            : #ifdef PDF_HOST_WIN32
     660                 :            : #define PDF_DIR          _WDIR
     661                 :            : #define pdf_dirent_s     _wdirent
     662                 :            : #define PDF_OPENDIR(f)   _wopendir ((const wchar_t *)f)
     663                 :            : #define PDF_READDIR(ds)  _wreaddir ((PDF_DIR *)ds)
     664                 :            : #define PDF_CLOSEDIR(ds) _wclosedir ((PDF_DIR *)ds)
     665                 :            : /* In mingw dir_entry->d_namlen is an array of FILENAME_MAX
     666                 :            :  * octects long. The dir_entry->d_namlen contain the length of
     667                 :            :  * the name stored in d_name */
     668                 :            : #define PDF_NAMELEN(de)  (de->d_namlen)
     669                 :            : #else
     670                 :            : #define PDF_DIR          DIR
     671                 :            : #define pdf_dirent_s     dirent
     672                 :            : #define PDF_OPENDIR(f)   opendir ((const char *)f)
     673                 :            : #define PDF_READDIR(ds)  readdir ((PDF_DIR *)ds)
     674                 :            : #define PDF_CLOSEDIR(ds) closedir ((PDF_DIR *)ds)
     675                 :            : /* In POSIX systems dir_entry->d_name is a NULL-terminated
     676                 :            :  * string */
     677                 :            : #define PDF_NAMELEN(de)  (strlen (de->d_name))
     678                 :            : 
     679                 :            : #endif /* !PDF_HOST_WIN32 */
     680                 :            : 
     681                 :            : static pdf_list_t *
     682                 :          0 : get_folder_contents (const pdf_fsys_t  *fsys,
     683                 :            :                      const pdf_text_t  *path,
     684                 :            :                      pdf_error_t      **error)
     685                 :            : {
     686                 :            :   PDF_DIR *dir_stream;
     687                 :            :   pdf_char_t *host_path;
     688                 :            :   struct pdf_dirent_s *dir_entry;
     689                 :            :   pdf_list_t *list;
     690                 :            : 
     691         [ #  # ]:          0 :   PDF_ASSERT_POINTER_RETURN_VAL (path, NULL);
     692                 :            : 
     693                 :            :   /* Get a host-encoded version of the path name */
     694                 :          0 :   host_path = get_host_path (path, NULL, error);
     695         [ #  # ]:          0 :   if (!host_path)
     696                 :          0 :     return NULL;
     697                 :            : 
     698                 :            :   /* Open the directory stream */
     699                 :          0 :   dir_stream = PDF_OPENDIR (host_path);
     700         [ #  # ]:          0 :   if (!dir_stream)
     701                 :            :     {
     702                 :          0 :       pdf_set_error (error,
     703                 :            :                      PDF_EDOMAIN_BASE_FSYS,
     704                 :            :                      get_status_from_errno (errno),
     705                 :            :                      "cannot open directory: '%s'",
     706                 :            :                      strerror (errno));
     707                 :          0 :       pdf_dealloc (host_path);
     708                 :          0 :       return NULL;
     709                 :            :     }
     710                 :            : 
     711                 :            :   /* Create the list to be returned.
     712                 :            :    * Note that we don't expect duplicates when listing files in
     713                 :            :    * a single directory, so there's no point in comparing the
     714                 :            :    * entry names and disallowing duplicates. */
     715                 :          0 :   list = pdf_list_new (NULL,
     716                 :            :                        (pdf_list_element_dispose_fn_t)pdf_text_destroy,
     717                 :            :                        PDF_TRUE,
     718                 :            :                        error);
     719         [ #  # ]:          0 :   if (!list)
     720                 :            :     {
     721                 :          0 :       PDF_CLOSEDIR (dir_stream);
     722                 :          0 :       pdf_dealloc (host_path);
     723                 :          0 :       return NULL;
     724                 :            :     }
     725                 :            : 
     726                 :            :   /* Scan directory contents */
     727         [ #  # ]:          0 :   while ((dir_entry = PDF_READDIR (dir_stream)) != NULL)
     728                 :            :     {
     729                 :            :       pdf_text_t *entry_text;
     730                 :            :       pdf_u32_t name_length;
     731                 :            : 
     732                 :            :       /* Note that dir_entry is statically allocated and can be
     733                 :            :        * rewritten by a subsequent call. Also, there is not need to
     734                 :            :        * free that structure */
     735                 :            : 
     736                 :            :       /* Get the length of the entry name */
     737                 :          0 :       name_length = PDF_NAMELEN (dir_entry);
     738                 :            : 
     739                 :            :       /* Create the text object containing the entry name */
     740                 :          0 :       entry_text = set_host_path ((const pdf_char_t *)dir_entry->d_name,
     741                 :            :                                   name_length,
     742                 :            :                                   error);
     743         [ #  # ]:          0 :       if (!entry_text)
     744                 :            :         {
     745                 :          0 :           PDF_CLOSEDIR (dir_stream);
     746                 :          0 :           pdf_dealloc (host_path);
     747         [ #  # ]:          0 :           if (list)
     748                 :          0 :             pdf_list_destroy (list);
     749                 :          0 :           return NULL;
     750                 :            :         }
     751                 :            : 
     752         [ #  # ]:          0 :       if (!pdf_list_add_last (list,
     753                 :            :                               entry_text,
     754                 :            :                               error))
     755                 :            :         {
     756                 :          0 :           PDF_CLOSEDIR (dir_stream);
     757                 :          0 :           PDF_CLOSEDIR (dir_stream);
     758                 :          0 :           pdf_dealloc (host_path);
     759                 :          0 :           return NULL;
     760                 :            :         }
     761                 :            : 
     762                 :            :       /* Go on to next item */
     763                 :            :     }
     764                 :            : 
     765                 :          0 :   PDF_CLOSEDIR (dir_stream);
     766                 :          0 :   return list;
     767                 :            : }
     768                 :            : 
     769                 :            : static pdf_bool_t
     770                 :         16 : get_directory_and_filename (const pdf_fsys_t  *fsys,
     771                 :            :                             const pdf_text_t  *path,
     772                 :            :                             pdf_text_t       **directory,
     773                 :            :                             pdf_text_t       **filename,
     774                 :            :                             pdf_char_t       **filename_utf8,
     775                 :            :                             pdf_error_t      **error)
     776                 :            : {
     777                 :            :   pdf_size_t utf8_size;
     778                 :            :   pdf_char_t *utf8;
     779                 :            :   pdf_char_t *p;
     780                 :            :   pdf_size_t filename_size;
     781                 :            : 
     782                 :            :   /* Canonicalize path and get output in UTF-8 */
     783         [ -  + ]:         16 :   if (!canonicalize_path (fsys, path, NULL, &utf8, error))
     784                 :          0 :     return PDF_FALSE;
     785                 :            : 
     786                 :            :   /* Move pointer to last character in the path */
     787                 :         16 :   utf8_size = strlen (utf8);
     788                 :         16 :   p = &utf8[utf8_size - 1];
     789                 :            : 
     790                 :            :   /* Skip possible separator at the end of the path */
     791         [ +  + ]:         16 :   if (IS_DIR_SEPARATOR (*p))
     792                 :          2 :     p--;
     793                 :            : 
     794                 :            :   /* Find previous directory separator */
     795 [ +  + ][ +  + ]:         74 :   while (p >= utf8 &&
     796                 :         72 :          !IS_DIR_SEPARATOR (*p))
     797                 :         58 :     p--;
     798                 :            : 
     799                 :            :   /* Directory separator found? */
     800         [ +  + ]:         16 :   if (p < utf8)
     801                 :            :     {
     802                 :            :       /* No parent */
     803                 :          2 :       pdf_dealloc (utf8);
     804                 :          2 :       return NULL;
     805                 :            :     }
     806                 :            : 
     807                 :            :   /* Filename starts always after the dir separator */
     808                 :         14 :   filename_size = strlen (&p[1]);
     809                 :            : 
     810                 :            :   /* Get filename if requested */
     811         [ +  + ]:         14 :   if (filename)
     812                 :            :     {
     813                 :          7 :       *filename = pdf_text_new_from_unicode (&p[1],
     814                 :            :                                              filename_size,
     815                 :            :                                              PDF_TEXT_UTF8,
     816                 :            :                                              error);
     817         [ -  + ]:          7 :       if (!*filename)
     818                 :            :         {
     819                 :          0 :           pdf_dealloc (utf8);
     820                 :          0 :           return PDF_FALSE;
     821                 :            :         }
     822                 :            :     }
     823                 :            : 
     824                 :            :   /* Get filename in UTF-8 if requested */
     825         [ -  + ]:         14 :   if (filename_utf8)
     826                 :            :     {
     827                 :          0 :       *filename_utf8 = pdf_alloc (filename_size + 1);
     828         [ #  # ]:          0 :       if (!*filename_utf8)
     829                 :            :         {
     830                 :          0 :           pdf_set_error (error,
     831                 :            :                          PDF_EDOMAIN_BASE_FSYS,
     832                 :            :                          PDF_ENOMEM,
     833                 :            :                          "cannot get filename: "
     834                 :            :                          "couldn't allocate %lu bytes",
     835                 :            :                          (unsigned long)(filename_size + 1));
     836         [ #  # ]:          0 :           if (filename)
     837                 :          0 :             pdf_text_destroy (*filename);
     838                 :          0 :           return PDF_FALSE;
     839                 :            :         }
     840                 :          0 :       memcpy (*filename_utf8, &p[1], filename_size);
     841                 :          0 :       (*filename_utf8)[filename_size] = '\0';
     842                 :            :     }
     843                 :            : 
     844         [ +  + ]:         14 :   if (directory)
     845                 :            :     {
     846                 :            :       /* Directory last (to be NUL-ed) depends on whether the directory is the root
     847                 :            :        * directory (we shouldn't remove the dir separator from the root directory)
     848                 :            :        */
     849         [ +  + ]:          7 :       if (p == utf8)
     850                 :          3 :         p[1] = '\0';
     851                 :            :       else
     852                 :          4 :         p[0] = '\0';
     853                 :            : 
     854                 :          7 :       *directory = pdf_text_new_from_unicode (utf8,
     855                 :            :                                               strlen (utf8),
     856                 :            :                                               PDF_TEXT_UTF8,
     857                 :            :                                               error);
     858         [ -  + ]:          7 :       if (!*directory)
     859                 :            :         {
     860         [ #  # ]:          0 :           if (filename)
     861                 :          0 :             pdf_text_destroy (*filename);
     862         [ #  # ]:          0 :           if (filename_utf8)
     863                 :          0 :             pdf_dealloc (*filename_utf8);
     864                 :          0 :           pdf_dealloc (utf8);
     865                 :          0 :           return PDF_FALSE;
     866                 :            :         }
     867                 :            :     }
     868                 :            : 
     869                 :         14 :   pdf_dealloc (utf8);
     870                 :         16 :   return PDF_TRUE;
     871                 :            : }
     872                 :            : 
     873                 :            : static pdf_text_t *
     874                 :          8 : get_basename (const pdf_fsys_t  *fsys,
     875                 :            :               const pdf_text_t  *path,
     876                 :            :               pdf_error_t      **error)
     877                 :            : {
     878                 :            :   pdf_text_t *basename;
     879                 :            : 
     880         [ -  + ]:          8 :   PDF_ASSERT_POINTER_RETURN_VAL (path, NULL);
     881                 :            : 
     882         [ +  + ]:          8 :   if (!get_directory_and_filename (fsys,
     883                 :            :                                    path,
     884                 :            :                                    NULL,
     885                 :            :                                    &basename,
     886                 :            :                                    NULL,
     887                 :            :                                    error))
     888                 :            :     {
     889                 :          1 :       pdf_prefix_error (error, "couldn't get basename: ");
     890                 :          1 :       return NULL;
     891                 :            :     }
     892                 :            : 
     893                 :          8 :   return basename;
     894                 :            : }
     895                 :            : 
     896                 :            : static pdf_text_t *
     897                 :          8 : get_parent (const pdf_fsys_t  *fsys,
     898                 :            :             const pdf_text_t  *path,
     899                 :            :             pdf_error_t      **error)
     900                 :            : {
     901                 :            :   pdf_text_t *parent;
     902                 :            : 
     903         [ -  + ]:          8 :   PDF_ASSERT_POINTER_RETURN_VAL (path, NULL);
     904                 :            : 
     905         [ +  + ]:          8 :   if (!get_directory_and_filename (fsys,
     906                 :            :                                    path,
     907                 :            :                                    &parent,
     908                 :            :                                    NULL,
     909                 :            :                                    NULL,
     910                 :            :                                    error))
     911                 :            :     {
     912                 :          1 :       pdf_prefix_error (error, "couldn't get parent: ");
     913                 :          1 :       return NULL;
     914                 :            :     }
     915                 :            : 
     916                 :          8 :   return parent;
     917                 :            : }
     918                 :            : 
     919                 :            : /* Host-dependent rmdir() */
     920                 :            : #ifdef PDF_HOST_WIN32
     921                 :            : #define PDF_RMDIR(f) _wrmdir((wchar_t *)f)
     922                 :            : #else
     923                 :            : #define PDF_RMDIR(f) rmdir(f)
     924                 :            : #endif
     925                 :            : 
     926                 :            : static pdf_bool_t
     927                 :          0 : remove_folder (const pdf_fsys_t  *fsys,
     928                 :            :                const pdf_text_t  *path,
     929                 :            :                pdf_error_t      **error)
     930                 :            : {
     931                 :            :   pdf_char_t *host_path;
     932                 :            : 
     933         [ #  # ]:          0 :   PDF_ASSERT_POINTER_RETURN_VAL (path, PDF_FALSE);
     934                 :            : 
     935                 :            :   /* Get a host-encoded version of the path name */
     936                 :          0 :   host_path = get_host_path (path, NULL, error);
     937         [ #  # ]:          0 :   if (!host_path)
     938                 :          0 :     return PDF_FALSE;
     939                 :            : 
     940                 :            :   /* Try to remove the directory */
     941         [ #  # ]:          0 :   if (PDF_RMDIR (host_path) < 0)
     942                 :            :     {
     943                 :          0 :       pdf_set_error (error,
     944                 :            :                      PDF_EDOMAIN_BASE_FSYS,
     945                 :            :                      get_status_from_errno (errno),
     946                 :            :                      "cannot create directory: '%s'",
     947                 :            :                      strerror (errno));
     948                 :          0 :       pdf_dealloc (host_path);
     949                 :          0 :       return PDF_FALSE;
     950                 :            :     }
     951                 :            : 
     952                 :          0 :   pdf_dealloc (host_path);
     953                 :          0 :   return PDF_TRUE;
     954                 :            : }
     955                 :            : 
     956                 :            : /* Host-dependent access() */
     957                 :            : #ifdef PDF_HOST_WIN32
     958                 :            : #define PDF_ACCESS(f,m) _waccess((wchar_t *)f,m)
     959                 :            : #else
     960                 :            : #define PDF_ACCESS(f,m) access(f,m)
     961                 :            : #endif
     962                 :            : 
     963                 :            : static pdf_bool_t
     964                 :          0 : is_readable_from_host_path (const pdf_char_t  *host_path,
     965                 :            :                             pdf_error_t      **error)
     966                 :            : {
     967         [ #  # ]:          0 :   if (PDF_ACCESS (host_path, R_OK) < 0)
     968                 :            :     {
     969                 :            :       /* Now, either is not readable, or another error happened */
     970         [ #  # ]:          0 :       if (errno != EACCES)
     971                 :          0 :         pdf_set_error (error,
     972                 :            :                        PDF_EDOMAIN_BASE_FSYS,
     973                 :            :                        get_status_from_errno (errno),
     974                 :            :                        "cannot check if file is readable: '%s'",
     975                 :            :                        strerror (errno));
     976                 :          0 :       return PDF_FALSE;
     977                 :            :     }
     978                 :          0 :   return PDF_TRUE;
     979                 :            : }
     980                 :            : 
     981                 :            : static pdf_bool_t
     982                 :          0 : is_writable_from_host_path (const pdf_char_t  *host_path,
     983                 :            :                             pdf_error_t      **error)
     984                 :            : {
     985         [ #  # ]:          0 :   if (PDF_ACCESS (host_path, W_OK) < 0)
     986                 :            :     {
     987                 :            :       /* Now, either is not readable, or another error happened */
     988         [ #  # ]:          0 :       if (errno != EACCES)
     989                 :          0 :         pdf_set_error (error,
     990                 :            :                        PDF_EDOMAIN_BASE_FSYS,
     991                 :            :                        get_status_from_errno (errno),
     992                 :            :                        "cannot check if file is writable: '%s'",
     993                 :            :                        strerror (errno));
     994                 :          0 :       return PDF_FALSE;
     995                 :            :     }
     996                 :          0 :   return PDF_TRUE;
     997                 :            : }
     998                 :            : 
     999                 :            : /* Host-dependent stat() */
    1000                 :            : #ifdef PDF_HOST_WIN32
    1001                 :            : #define PDF_STAT(f,s) _wstat((wchar_t *)f,s)
    1002                 :            : typedef struct _stat pdf_stat_s;
    1003                 :            : #else
    1004                 :            : #define PDF_STAT(f,s) stat64(f,s)
    1005                 :            : typedef struct stat64 pdf_stat_s;
    1006                 :            : #endif
    1007                 :            : 
    1008                 :            : static pdf_bool_t
    1009                 :         10 : get_stat_info_from_host_path (const pdf_char_t  *host_path,
    1010                 :            :                               pdf_off_t         *size,
    1011                 :            :                               pdf_time_t        *ctime,
    1012                 :            :                               pdf_time_t        *mtime,
    1013                 :            :                               pdf_error_t      **error)
    1014                 :            : {
    1015                 :            :   pdf_stat_s file_info;
    1016                 :            : 
    1017         [ -  + ]:         10 :   if (PDF_STAT (host_path, &file_info) < 0)
    1018                 :            :     {
    1019                 :          0 :       pdf_set_error (error,
    1020                 :            :                      PDF_EDOMAIN_BASE_FSYS,
    1021                 :            :                      get_status_from_errno (errno),
    1022                 :            :                      "cannot get stat info: '%s'",
    1023                 :            :                      strerror (errno));
    1024                 :          0 :       return PDF_FALSE;
    1025                 :            :     }
    1026                 :            : 
    1027         [ +  - ]:         10 :   if (size)
    1028                 :            :     {
    1029                 :         10 :       *size = (pdf_off_t)file_info.st_size;
    1030                 :            :     }
    1031                 :            : 
    1032         [ -  + ]:         10 :   if (ctime)
    1033                 :            :     {
    1034                 :          0 :       pdf_time_init (ctime);
    1035                 :          0 :       pdf_time_set_utc (ctime, file_info.st_ctime);
    1036                 :            :     }
    1037                 :            : 
    1038         [ -  + ]:         10 :   if (mtime)
    1039                 :            :     {
    1040                 :          0 :       pdf_time_init (mtime);
    1041                 :          0 :       pdf_time_set_utc (mtime, file_info.st_mtime);
    1042                 :            :     }
    1043                 :            : 
    1044                 :         10 :   return PDF_TRUE;
    1045                 :            : }
    1046                 :            : 
    1047                 :            : static pdf_bool_t
    1048                 :          0 : get_item_props (const pdf_fsys_t              *fsys,
    1049                 :            :                 const pdf_text_t              *path,
    1050                 :            :                 struct pdf_fsys_item_props_s  *props,
    1051                 :            :                 pdf_error_t                  **error)
    1052                 :            : {
    1053                 :            :   pdf_char_t* host_path;
    1054                 :          0 :   pdf_error_t *inner_error = NULL;
    1055                 :            : 
    1056         [ #  # ]:          0 :   PDF_ASSERT_POINTER_RETURN_VAL (path, PDF_FALSE);
    1057         [ #  # ]:          0 :   PDF_ASSERT_POINTER_RETURN_VAL (props, PDF_FALSE);
    1058                 :            : 
    1059                 :            :   /* Get a host-encoded version of the path name */
    1060                 :          0 :   host_path = get_host_path (path, NULL, error);
    1061         [ #  # ]:          0 :   if (!host_path)
    1062                 :          0 :     return PDF_FALSE;
    1063                 :            : 
    1064                 :            :   /* Initialize the output to all zeros */
    1065                 :          0 :   memset (props, 0, sizeof (struct pdf_fsys_item_props_s));
    1066                 :            : 
    1067                 :            :   /* Is readable? */
    1068                 :          0 :   props->is_readable = is_readable_from_host_path (host_path, &inner_error);
    1069         [ #  # ]:          0 :   if (inner_error)
    1070                 :            :     {
    1071                 :          0 :       pdf_dealloc (host_path);
    1072                 :          0 :       pdf_propagate_error (error, inner_error);
    1073                 :          0 :       return PDF_FALSE;
    1074                 :            :     }
    1075                 :            : 
    1076                 :            :   /* Is writable? */
    1077                 :          0 :   props->is_writable = is_writable_from_host_path (host_path, &inner_error);
    1078         [ #  # ]:          0 :   if (inner_error)
    1079                 :            :     {
    1080                 :          0 :       pdf_dealloc (host_path);
    1081                 :          0 :       pdf_propagate_error (error, inner_error);
    1082                 :          0 :       return PDF_FALSE;
    1083                 :            :     }
    1084                 :            : 
    1085                 :            :   /* Get file size, ctime and mtime */
    1086         [ #  # ]:          0 :   if (!get_stat_info_from_host_path (host_path,
    1087                 :            :                                      &props->file_size,
    1088                 :            :                                      &props->creation_date,
    1089                 :            :                                      &props->modification_date,
    1090                 :            :                                      error))
    1091                 :            :     {
    1092                 :          0 :       pdf_dealloc (host_path);
    1093                 :          0 :       return PDF_FALSE;
    1094                 :            :     }
    1095                 :            : 
    1096                 :            : #ifdef PDF_HOST_WIN32
    1097                 :            :   {
    1098                 :            :     DWORD attrs;
    1099                 :            : 
    1100                 :            :     attrs = GetFileAttributesW ((LPCWSTR) host_path);
    1101                 :            :     if (attrs == INVALID_FILE_ATTRIBUTES)
    1102                 :            :       {
    1103                 :            :         pdf_set_error (error,
    1104                 :            :                        PDF_EDOMAIN_BASE_FSYS,
    1105                 :            :                        PDF_ERROR,
    1106                 :            :                        "couldn't get item properties: got error code %d",
    1107                 :            :                        (pdf_i32_t)GetLastError ());
    1108                 :            :         pdf_dealloc (host_path);
    1109                 :            :         return PDF_FALSE;
    1110                 :            :       }
    1111                 :            : 
    1112                 :            :     props->is_hidden = (attrs & FILE_ATTRIBUTE_HIDDEN ? PDF_TRUE : PDF_FALSE);
    1113                 :            :   }
    1114                 :            : #else
    1115                 :            :   {
    1116                 :            :     pdf_char_t *filename_utf8;
    1117                 :            : 
    1118                 :            :     /* Get filename */
    1119                 :          0 :     filename_utf8 = NULL;
    1120         [ #  # ]:          0 :     if (!get_directory_and_filename (fsys,
    1121                 :            :                                      path,
    1122                 :            :                                      NULL,
    1123                 :            :                                      NULL,
    1124                 :            :                                      &filename_utf8,
    1125                 :            :                                      error))
    1126                 :            :       {
    1127                 :          0 :         pdf_dealloc (host_path);
    1128                 :          0 :         return PDF_FALSE;
    1129                 :            :       }
    1130                 :            : 
    1131                 :            :     /* Lets consider files starting with dot as hidden */
    1132                 :          0 :     props->is_hidden = (filename_utf8[0] == '.' ? PDF_TRUE : PDF_FALSE);
    1133                 :          0 :     pdf_dealloc (filename_utf8);
    1134                 :            :   }
    1135                 :            : #endif /* PDF_HOST_WIN32 */
    1136                 :            : 
    1137                 :          0 :   pdf_dealloc (host_path);
    1138                 :            : 
    1139                 :          0 :   return PDF_TRUE;
    1140                 :            : }
    1141                 :            : 
    1142                 :            : static pdf_bool_t
    1143                 :          0 : item_p (const pdf_fsys_t *fsys,
    1144                 :            :         const pdf_text_t *path)
    1145                 :            : {
    1146                 :            :   pdf_char_t *host_path;
    1147                 :            :   pdf_bool_t exists;
    1148                 :            : 
    1149         [ #  # ]:          0 :   PDF_ASSERT_POINTER_RETURN_VAL (path, PDF_FALSE);
    1150                 :            : 
    1151                 :            : #ifdef PDF_HOST_WIN32
    1152                 :            :   if (win32_device_p (path, NULL))
    1153                 :            :     return PDF_TRUE;
    1154                 :            : #endif
    1155                 :            : 
    1156                 :            :   /* We get the string in HOST-encoding (with NUL-suffix) */
    1157                 :          0 :   host_path = get_host_path (path, NULL, NULL);
    1158         [ #  # ]:          0 :   if (!host_path)
    1159                 :          0 :     return PDF_FALSE;
    1160                 :            : 
    1161                 :            :   /* Get file size, ctime and mtime, but don't return any.
    1162                 :            :    * We just want to know if file exists or not */
    1163                 :          0 :   exists = get_stat_info_from_host_path (host_path,
    1164                 :            :                                          NULL,
    1165                 :            :                                          NULL,
    1166                 :            :                                          NULL,
    1167                 :            :                                          NULL);
    1168                 :          0 :   pdf_dealloc (host_path);
    1169                 :          0 :   return exists;
    1170                 :            : }
    1171                 :            : 
    1172                 :            : static pdf_bool_t
    1173                 :          0 : item_readable_p (const pdf_fsys_t *fsys,
    1174                 :            :                  const pdf_text_t *path)
    1175                 :            : {
    1176                 :          0 :   pdf_error_t *inner_error = NULL;
    1177                 :            :   pdf_char_t* host_path;
    1178                 :            :   pdf_bool_t readable;
    1179                 :            : 
    1180         [ #  # ]:          0 :   PDF_ASSERT_POINTER_RETURN_VAL (path, PDF_FALSE);
    1181                 :            : 
    1182                 :            :   /* We get the string in HOST-encoding (with NUL-suffix) */
    1183                 :          0 :   host_path = get_host_path (path, NULL, NULL);
    1184         [ #  # ]:          0 :   if (!host_path)
    1185                 :          0 :     return PDF_FALSE;
    1186                 :            : 
    1187                 :          0 :   readable = is_readable_from_host_path (host_path, &inner_error);
    1188         [ #  # ]:          0 :   if (inner_error)
    1189                 :            :     {
    1190                 :          0 :       pdf_dealloc (host_path);
    1191                 :          0 :       pdf_error_destroy (inner_error);
    1192                 :          0 :       return PDF_FALSE;
    1193                 :            :     }
    1194                 :            : 
    1195                 :          0 :   pdf_dealloc (host_path);
    1196                 :          0 :   return readable;
    1197                 :            : }
    1198                 :            : 
    1199                 :            : static pdf_bool_t
    1200                 :          0 : item_writable_p (const pdf_fsys_t *fsys,
    1201                 :            :                  const pdf_text_t *path)
    1202                 :            : {
    1203                 :          0 :   pdf_error_t *inner_error = NULL;
    1204                 :            :   pdf_char_t* host_path;
    1205                 :            :   pdf_bool_t writable;
    1206                 :            : 
    1207         [ #  # ]:          0 :   PDF_ASSERT_POINTER_RETURN_VAL (path, PDF_FALSE);
    1208                 :            : 
    1209                 :            :   /* We get the string in HOST-encoding (with NUL-suffix) */
    1210                 :          0 :   host_path = get_host_path (path, NULL, NULL);
    1211         [ #  # ]:          0 :   if (!host_path)
    1212                 :          0 :     return PDF_FALSE;
    1213                 :            : 
    1214                 :          0 :   writable = is_writable_from_host_path (host_path, &inner_error);
    1215         [ #  # ]:          0 :   if (inner_error)
    1216                 :            :     {
    1217                 :          0 :       pdf_dealloc (host_path);
    1218                 :          0 :       pdf_error_destroy (inner_error);
    1219                 :          0 :       return PDF_FALSE;
    1220                 :            :     }
    1221                 :            : 
    1222                 :          0 :   pdf_dealloc (host_path);
    1223                 :          0 :   return writable;
    1224                 :            : }
    1225                 :            : 
    1226                 :            : #ifdef PDF_HOST_WIN32
    1227                 :            : 
    1228                 :            : static pdf_i64_t
    1229                 :            : get_free_space (const pdf_fsys_t  *fsys,
    1230                 :            :                 const pdf_text_t  *path,
    1231                 :            :                 pdf_error_t      **error)
    1232                 :            : {
    1233                 :            :   pdf_char_t *utf16le_path;
    1234                 :            :   pdf_u32_t utf16le_path_size = 0;
    1235                 :            :   ULARGE_INTEGER free_bytes;
    1236                 :            : 
    1237                 :            :   PDF_ASSERT_POINTER_RETURN_VAL (path, -1);
    1238                 :            : 
    1239                 :            :   /* Note that as we get the string as UTF-16LE with LAST NUL suffix,
    1240                 :            :    *  it's equivalent to a wchar_t in windows environments */
    1241                 :            :   utf16le_path = pdf_text_get_unicode (path,
    1242                 :            :                                        PDF_TEXT_UTF16_LE,
    1243                 :            :                                        PDF_TEXT_UNICODE_WITH_NUL_SUFFIX,
    1244                 :            :                                        &utf16le_path_size,
    1245                 :            :                                        error);
    1246                 :            :   if (!utf16le_path)
    1247                 :            :     return -1;
    1248                 :            : 
    1249                 :            :   /* No need to get the drive letter of the specified path:
    1250                 :            :    * This parameter does not have to specify the root directory on a disk.
    1251                 :            :    *  The function accepts any directory on a disk.
    1252                 :            :    **/
    1253                 :            : 
    1254                 :            :   /* Get the information from the filesystem
    1255                 :            :    *
    1256                 :            :    * BOOL WINAPI GetDiskFreeSpaceEx(
    1257                 :            :    *  __in_opt   LPCTSTR lpDirectoryName,
    1258                 :            :    *  __out_opt  PULARGE_INTEGER lpFreeBytesAvailable,
    1259                 :            :    *  __out_opt  PULARGE_INTEGER lpTotalNumberOfBytes,
    1260                 :            :    *  __out_opt  PULARGE_INTEGER lpTotalNumberOfFreeBytes
    1261                 :            :    * );
    1262                 :            :    *
    1263                 :            :    **/
    1264                 :            :   if (!GetDiskFreeSpaceExW ((LPCWSTR) utf16le_path,
    1265                 :            :                             NULL,
    1266                 :            :                             NULL,
    1267                 :            :                             &free_bytes))
    1268                 :            :     {
    1269                 :            :       /* Propagate error */
    1270                 :            :       pdf_set_error (error,
    1271                 :            :                      PDF_EDOMAIN_BASE_FSYS,
    1272                 :            :                      get_status_from_errno (errno),
    1273                 :            :                      "cannot get free disk space: got error code %d",
    1274                 :            :                      (pdf_i32_t)GetLastError ());
    1275                 :            :       pdf_dealloc (utf16le_path);
    1276                 :            :       return -1;
    1277                 :            :     }
    1278                 :            : 
    1279                 :            :   pdf_dealloc (utf16le_path);
    1280                 :            : 
    1281                 :            :   return (pdf_i64_t)free_bytes.QuadPart;
    1282                 :            : }
    1283                 :            : 
    1284                 :            : #else
    1285                 :            : 
    1286                 :            : static pdf_i64_t
    1287                 :          2 : get_free_space (const pdf_fsys_t  *fsys,
    1288                 :            :                 const pdf_text_t  *path,
    1289                 :            :                 pdf_error_t      **error)
    1290                 :            : {
    1291                 :            :   struct statfs fs_stats;
    1292                 :            :   pdf_char_t *host_path;
    1293                 :            : 
    1294         [ -  + ]:          2 :   PDF_ASSERT_POINTER_RETURN_VAL (path, -1);
    1295                 :            : 
    1296                 :            :   /* We get the string in HOST-encoding (with NUL-suffix) */
    1297                 :          2 :   host_path = get_host_path (path, NULL, error);
    1298         [ -  + ]:          2 :   if (!host_path)
    1299                 :          0 :     return -1;
    1300                 :            : 
    1301                 :            :   PDF_DEBUG_BASE ("Getting free bytes of FS at path '%s'...",
    1302                 :            :                   host_path);
    1303                 :            : 
    1304         [ +  + ]:          2 :   if (statfs (host_path, &fs_stats) < 0)
    1305                 :            :     {
    1306                 :          1 :       pdf_set_error (error,
    1307                 :            :                      PDF_EDOMAIN_BASE_FSYS,
    1308                 :            :                      get_status_from_errno (errno),
    1309                 :            :                      "cannot get free disk space: %s",
    1310                 :            :                      strerror (errno));
    1311                 :          1 :       pdf_dealloc (host_path);
    1312                 :          1 :       return -1;
    1313                 :            :     }
    1314                 :            : 
    1315                 :          1 :   pdf_dealloc (host_path);
    1316                 :            : 
    1317                 :            :   /* Return the free space in octects */
    1318                 :          2 :   return (pdf_i64_t)(fs_stats.f_bfree * fs_stats.f_bsize);
    1319                 :            : }
    1320                 :            : 
    1321                 :            : #endif /* !PDF_HOST_WIN32 */
    1322                 :            : 
    1323                 :            : static pdf_bool_t
    1324                 :          0 : compare_path_p (const pdf_fsys_t  *fsys,
    1325                 :            :                 const pdf_text_t  *first,
    1326                 :            :                 const pdf_text_t  *second,
    1327                 :            :                 pdf_error_t      **error)
    1328                 :            : {
    1329                 :          0 :   pdf_error_t *inner_error = NULL;
    1330                 :            :   pdf_i32_t ret;
    1331                 :            :   pdf_bool_t case_sensitive;
    1332                 :          0 :   pdf_text_t *canonicalized_first = NULL;
    1333                 :          0 :   pdf_text_t *canonicalized_second = NULL;
    1334                 :            : 
    1335         [ #  # ]:          0 :   PDF_ASSERT_POINTER_RETURN_VAL (first, PDF_FALSE);
    1336         [ #  # ]:          0 :   PDF_ASSERT_POINTER_RETURN_VAL (second, PDF_FALSE);
    1337                 :            : 
    1338                 :            :   /* TODO: Mac OS X should have a method in CoreFoundation libs to
    1339                 :            :    *  check if a the HFS+ filesystem is case-sensitive or not */
    1340                 :            : 
    1341                 :            :   /* Unix-like systems have case sensitive paths, Windows doesn't. */
    1342                 :            : #ifndef PDF_HOST_WIN32
    1343                 :          0 :   case_sensitive = PDF_TRUE;
    1344                 :            : #else
    1345                 :            :   case_sensitive = PDF_FALSE;
    1346                 :            : #endif
    1347                 :            : 
    1348                 :            :   /* Canonicalize paths before comparing */
    1349 [ #  # ][ #  # ]:          0 :   if (!canonicalize_path (fsys,
    1350                 :            :                           first,
    1351                 :            :                           &canonicalized_first,
    1352                 :            :                           NULL,
    1353                 :            :                           error) ||
    1354                 :            :       !canonicalize_path (fsys,
    1355                 :            :                           second,
    1356                 :            :                           &canonicalized_second,
    1357                 :            :                           NULL,
    1358                 :            :                           error))
    1359                 :            :     {
    1360                 :          0 :       pdf_prefix_error (error, "couldn't check if same files: ");
    1361                 :            : 
    1362         [ #  # ]:          0 :       if (canonicalized_first)
    1363                 :          0 :         pdf_text_destroy (canonicalized_first);
    1364                 :            : 
    1365         [ #  # ]:          0 :       if (canonicalized_second)
    1366                 :          0 :         pdf_text_destroy (canonicalized_second);
    1367                 :            : 
    1368                 :          0 :       return PDF_FALSE;
    1369                 :            :     }
    1370                 :            : 
    1371                 :            :   /* Compare canonicalized paths */
    1372                 :          0 :   ret = pdf_text_cmp (canonicalized_first,
    1373                 :            :                       canonicalized_second,
    1374                 :            :                       case_sensitive,
    1375                 :            :                       &inner_error);
    1376                 :            : 
    1377                 :          0 :   pdf_text_destroy (canonicalized_first);
    1378                 :          0 :   pdf_text_destroy (canonicalized_second);
    1379                 :            : 
    1380         [ #  # ]:          0 :   if (inner_error)
    1381                 :            :     {
    1382                 :          0 :       pdf_propagate_error (error, inner_error);
    1383                 :          0 :       pdf_prefix_error (error, "couldn't check if same files: ");
    1384                 :          0 :       return PDF_FALSE;
    1385                 :            :     }
    1386                 :            : 
    1387                 :          0 :   return (ret == 0 ? PDF_TRUE : PDF_FALSE);
    1388                 :            : }
    1389                 :            : 
    1390                 :            : static pdf_text_t *
    1391                 :          1 : build_path (const pdf_fsys_t  *fsys,
    1392                 :            :             pdf_error_t      **error,
    1393                 :            :             const pdf_text_t  *first_element,
    1394                 :            :             ...)
    1395                 :            : {
    1396                 :          1 :   const struct pdf_fsys_disk_s *disk_fsys = (const struct pdf_fsys_disk_s *)fsys;
    1397                 :            :   pdf_text_t *output;
    1398                 :            :   pdf_text_t *next;
    1399                 :            :   va_list args;
    1400                 :            : 
    1401         [ -  + ]:          1 :   PDF_ASSERT_POINTER_RETURN_VAL (first_element, NULL);
    1402                 :            : 
    1403                 :          1 :   output = pdf_text_dup (first_element, error);
    1404         [ -  + ]:          1 :   if (!output)
    1405                 :          0 :     return NULL;
    1406                 :            : 
    1407                 :          1 :   va_start (args, first_element);
    1408         [ +  - ]:          1 :   next = va_arg (args, pdf_text_t *);
    1409         [ +  + ]:          3 :   while (next != NULL)
    1410                 :            :     {
    1411 [ +  - ][ -  + ]:          2 :       if (!pdf_text_concat (output,
    1412                 :          2 :                             disk_fsys->filename_separator,
    1413                 :            :                             PDF_TRUE,
    1414                 :            :                             error) ||
    1415                 :            :           !pdf_text_concat (output,
    1416                 :            :                             next,
    1417                 :            :                             PDF_TRUE,
    1418                 :            :                             error))
    1419                 :            :         {
    1420                 :          0 :           pdf_text_destroy (output);
    1421                 :          0 :           va_end (args);
    1422                 :          0 :           return NULL;
    1423                 :            :         }
    1424         [ +  - ]:          2 :       next = va_arg (args, pdf_text_t *);
    1425                 :            :     }
    1426                 :          1 :   va_end (args);
    1427                 :            : 
    1428                 :          1 :   return output;
    1429                 :            : }
    1430                 :            : 
    1431                 :            : static pdf_char_t *
    1432                 :          0 : get_url_from_path (const pdf_fsys_t  *fsys,
    1433                 :            :                    const pdf_text_t  *path,
    1434                 :            :                    pdf_error_t      **error)
    1435                 :            : {
    1436         [ #  # ]:          0 :   PDF_ASSERT_POINTER_RETURN_VAL (path, NULL);
    1437                 :            : 
    1438                 :            :   /* TODO. See FS#126 */
    1439                 :            : 
    1440                 :          0 :   return NULL;
    1441                 :            : }
    1442                 :            : 
    1443                 :            : static pdf_text_t *
    1444                 :          0 : get_path_from_url (const pdf_fsys_t  *fsys,
    1445                 :            :                    const pdf_char_t  *url,
    1446                 :            :                    pdf_error_t      **error)
    1447                 :            : {
    1448         [ #  # ]:          0 :   PDF_ASSERT_POINTER_RETURN_VAL (url, NULL);
    1449                 :            : 
    1450                 :            :   /* TODO. See FS#126 */
    1451                 :            : 
    1452                 :          0 :   return NULL;
    1453                 :            : }
    1454                 :            : 
    1455                 :            : /*
    1456                 :            :  * File Interface Implementation
    1457                 :            :  */
    1458                 :            : 
    1459                 :            : static pdf_off_t
    1460                 :         46 : file_get_pos (const pdf_fsys_file_t  *file,
    1461                 :            :               pdf_error_t           **error)
    1462                 :            : {
    1463                 :            :   struct pdf_fsys_disk_file_s *disk_file;
    1464                 :            :   pdf_off_t cpos;
    1465                 :            : 
    1466         [ -  + ]:         46 :   PDF_ASSERT_POINTER_RETURN_VAL (file, (pdf_off_t)-1);
    1467                 :            : 
    1468                 :         46 :   disk_file = (struct pdf_fsys_disk_file_s *)file;
    1469                 :         46 :   cpos = ftello (disk_file->file_descriptor);
    1470         [ -  + ]:         46 :   if (cpos == (pdf_off_t)-1)
    1471                 :            :     {
    1472                 :          0 :       pdf_set_error (error,
    1473                 :            :                      PDF_EDOMAIN_BASE_FSYS,
    1474                 :            :                      get_status_from_errno (errno),
    1475                 :            :                      "cannot get position from file: '%s'",
    1476                 :            :                      strerror (errno));
    1477                 :          0 :       return (pdf_off_t)-1;
    1478                 :            :     }
    1479                 :            : 
    1480                 :         46 :   return cpos;
    1481                 :            : }
    1482                 :            : 
    1483                 :            : static pdf_bool_t
    1484                 :         22 : file_set_pos (pdf_fsys_file_t  *file,
    1485                 :            :               pdf_off_t         new_pos,
    1486                 :            :               pdf_error_t     **error)
    1487                 :            : {
    1488                 :            :   struct pdf_fsys_disk_file_s *disk_file;
    1489                 :            : 
    1490         [ -  + ]:         22 :   PDF_ASSERT_POINTER_RETURN_VAL (file, PDF_FALSE);
    1491         [ -  + ]:         22 :   PDF_ASSERT_RETURN_VAL (new_pos >= 0, PDF_FALSE);
    1492                 :            : 
    1493                 :         22 :   disk_file = (struct pdf_fsys_disk_file_s *)file;
    1494         [ -  + ]:         22 :   if (fseeko (disk_file->file_descriptor,
    1495                 :            :               new_pos,
    1496                 :            :               SEEK_SET) == (pdf_off_t)-1)
    1497                 :            :     {
    1498                 :          0 :       pdf_set_error (error,
    1499                 :            :                      PDF_EDOMAIN_BASE_FSYS,
    1500                 :            :                      get_status_from_errno (errno),
    1501                 :            :                      "cannot set position in file: '%s'",
    1502                 :            :                      strerror (errno));
    1503                 :          0 :       return PDF_FALSE;
    1504                 :            :     }
    1505                 :            : 
    1506                 :         22 :   return PDF_TRUE;
    1507                 :            : }
    1508                 :            : 
    1509                 :            : static pdf_bool_t
    1510                 :          0 : file_can_set_size_p (const pdf_fsys_file_t *file,
    1511                 :            :                      pdf_off_t              size)
    1512                 :            : {
    1513                 :            :   struct pdf_fsys_disk_file_s *disk_file;
    1514                 :            : 
    1515         [ #  # ]:          0 :   PDF_ASSERT_POINTER_RETURN_VAL (file, PDF_FALSE);
    1516                 :            : 
    1517                 :            :   /* We'll assume that we can set any new size of the file if it is writable */
    1518                 :          0 :   disk_file = (struct pdf_fsys_disk_file_s *)file;
    1519                 :          0 :   return is_writable_from_host_path (disk_file->host_path, NULL);
    1520                 :            : }
    1521                 :            : 
    1522                 :            : static pdf_off_t
    1523                 :         10 : file_get_size (const pdf_fsys_file_t  *file,
    1524                 :            :                pdf_error_t           **error)
    1525                 :            : {
    1526                 :            :   struct pdf_fsys_disk_file_s *disk_file;
    1527                 :            :   pdf_off_t size;
    1528                 :            : 
    1529         [ -  + ]:         10 :   PDF_ASSERT_POINTER_RETURN_VAL (file, (pdf_off_t)-1);
    1530                 :            : 
    1531                 :         10 :   disk_file = (struct pdf_fsys_disk_file_s *)file;
    1532         [ +  - ]:         10 :   return (get_stat_info_from_host_path (disk_file->host_path,
    1533                 :            :                                         &size,
    1534                 :            :                                         NULL,
    1535                 :            :                                         NULL,
    1536                 :            :                                         error) ?
    1537                 :            :           size :
    1538                 :            :           (pdf_off_t)-1);
    1539                 :            : }
    1540                 :            : 
    1541                 :            : static pdf_bool_t
    1542                 :          0 : file_set_size (pdf_fsys_file_t  *file,
    1543                 :            :                pdf_off_t         size,
    1544                 :            :                pdf_error_t     **error)
    1545                 :            : {
    1546                 :          0 :   struct pdf_fsys_disk_file_s *disk_file = (struct pdf_fsys_disk_file_s *)file;
    1547                 :            : 
    1548         [ #  # ]:          0 :   PDF_ASSERT_POINTER_RETURN_VAL (file, PDF_FALSE);
    1549         [ #  # ]:          0 :   PDF_ASSERT_RETURN_VAL (disk_file->file_descriptor > 0, PDF_FALSE);
    1550                 :            : 
    1551                 :            :   /* Setting size of the file is just seeking to the given size offset and
    1552                 :            :    * writing an EOF... isn't it? */
    1553 [ #  # ][ #  # ]:          0 :   if (!file_set_pos (file, (size > 0 ? size - 1 : 0), error))
    1554                 :            :     {
    1555                 :          0 :       pdf_prefix_error (error, "cannot set size: ");
    1556                 :          0 :       return PDF_FALSE;
    1557                 :            :     }
    1558                 :            : 
    1559                 :            :   /* putc() returns exactly the same character written, or EOF on error,
    1560                 :            :    * so if we try to write EOF we should indeed get EOF */
    1561                 :          0 :   putc (EOF, disk_file->file_descriptor);
    1562                 :            : 
    1563                 :          0 :   return PDF_TRUE;
    1564                 :            : }
    1565                 :            : 
    1566                 :            : static pdf_bool_t
    1567                 :         46 : file_read (pdf_fsys_file_t  *file,
    1568                 :            :            pdf_char_t       *buf,
    1569                 :            :            pdf_size_t        bytes,
    1570                 :            :            pdf_size_t       *read_bytes,
    1571                 :            :            pdf_error_t     **error)
    1572                 :            : {
    1573                 :         46 :   struct pdf_fsys_disk_file_s *disk_file = (struct pdf_fsys_disk_file_s *)file;
    1574                 :            : 
    1575         [ -  + ]:         46 :   PDF_ASSERT_POINTER_RETURN_VAL (file, PDF_FALSE);
    1576         [ -  + ]:         46 :   PDF_ASSERT_POINTER_RETURN_VAL (buf, PDF_FALSE);
    1577         [ -  + ]:         46 :   PDF_ASSERT_POINTER_RETURN_VAL (read_bytes, PDF_FALSE);
    1578         [ -  + ]:         46 :   PDF_ASSERT_RETURN_VAL (disk_file->file_descriptor > 0, PDF_FALSE);
    1579                 :            : 
    1580                 :         46 :   *read_bytes = fread (buf,
    1581                 :            :                        1,
    1582                 :            :                        bytes,
    1583                 :            :                        disk_file->file_descriptor);
    1584                 :            : 
    1585                 :            :   /* On EOF, PDF_FALSE without error */
    1586         [ +  + ]:         46 :   if (feof (disk_file->file_descriptor))
    1587                 :         44 :     return PDF_FALSE;
    1588                 :            : 
    1589         [ -  + ]:          2 :   if (ferror (disk_file->file_descriptor))
    1590                 :            :     {
    1591                 :          0 :       pdf_set_error (error,
    1592                 :            :                      PDF_EDOMAIN_BASE_FSYS,
    1593                 :            :                      get_status_from_errno (errno),
    1594                 :            :                      "cannot read from file: '%s'",
    1595                 :            :                      strerror (errno));
    1596                 :          0 :       return PDF_FALSE;
    1597                 :            :     }
    1598                 :            : 
    1599                 :         46 :   return PDF_TRUE;
    1600                 :            : }
    1601                 :            : 
    1602                 :            : static pdf_bool_t
    1603                 :         10 : file_write (pdf_fsys_file_t  *file,
    1604                 :            :             const pdf_char_t *buf,
    1605                 :            :             pdf_size_t        bytes,
    1606                 :            :             pdf_size_t       *written_bytes,
    1607                 :            :             pdf_error_t     **error)
    1608                 :            : {
    1609                 :         10 :   struct pdf_fsys_disk_file_s *disk_file = (struct pdf_fsys_disk_file_s *)file;
    1610                 :            : 
    1611         [ -  + ]:         10 :   PDF_ASSERT_POINTER_RETURN_VAL (file, PDF_FALSE);
    1612         [ -  + ]:         10 :   PDF_ASSERT_POINTER_RETURN_VAL (buf, PDF_FALSE);
    1613         [ -  + ]:         10 :   PDF_ASSERT_POINTER_RETURN_VAL (written_bytes, PDF_FALSE);
    1614         [ -  + ]:         10 :   PDF_ASSERT_RETURN_VAL (disk_file->file_descriptor > 0, PDF_FALSE);
    1615                 :            : 
    1616                 :         10 :   *written_bytes = fwrite (buf,
    1617                 :            :                            1,
    1618                 :            :                            bytes,
    1619                 :            :                            disk_file->file_descriptor);
    1620                 :            : 
    1621         [ -  + ]:         10 :   if (ferror (disk_file->file_descriptor))
    1622                 :            :     {
    1623                 :          0 :       pdf_set_error (error,
    1624                 :            :                      PDF_EDOMAIN_BASE_FSYS,
    1625                 :            :                      get_status_from_errno (errno),
    1626                 :            :                      "cannot write to file: '%s'",
    1627                 :            :                      strerror (errno));
    1628                 :          0 :       return PDF_FALSE;
    1629                 :            :     }
    1630                 :            : 
    1631                 :         10 :   return PDF_TRUE;
    1632                 :            : }
    1633                 :            : 
    1634                 :            : static pdf_bool_t
    1635                 :          0 : file_flush (pdf_fsys_file_t  *file,
    1636                 :            :             pdf_error_t     **error)
    1637                 :            : {
    1638                 :          0 :   struct pdf_fsys_disk_file_s *disk_file = (struct pdf_fsys_disk_file_s *)file;
    1639                 :            : 
    1640         [ #  # ]:          0 :   PDF_ASSERT_POINTER_RETURN_VAL (file, PDF_FALSE);
    1641         [ #  # ]:          0 :   PDF_ASSERT_RETURN_VAL (disk_file->file_descriptor > 0, PDF_FALSE);
    1642                 :            : 
    1643         [ #  # ]:          0 :   if (fflush (disk_file->file_descriptor) < 0)
    1644                 :            :     {
    1645                 :            :       /* On Windows platforms (excluding Cygwin), fflush does not
    1646                 :            :        * set errno upon failure. */
    1647                 :            : #ifndef PDF_HOST_WIN32
    1648                 :          0 :       pdf_set_error (error,
    1649                 :            :                      PDF_EDOMAIN_BASE_FSYS,
    1650                 :            :                      get_status_from_errno (errno),
    1651                 :            :                      "cannot flush to file: '%s'",
    1652                 :            :                      strerror (errno));
    1653                 :            : #else
    1654                 :            :       pdf_set_error (error,
    1655                 :            :                      PDF_EDOMAIN_BASE_FSYS,
    1656                 :            :                      PDF_ERROR,
    1657                 :            :                      "cannot flush to file: 'unknown error'",
    1658                 :            :                      strerror (errno));
    1659                 :            : #endif
    1660                 :          0 :       return PDF_FALSE;
    1661                 :            :     }
    1662                 :            : 
    1663                 :          0 :   return PDF_TRUE;
    1664                 :            : }
    1665                 :            : 
    1666                 :            : static pdf_u32_t
    1667                 :          0 : file_request_ria (pdf_fsys_file_t  *file,
    1668                 :            :                   pdf_off_t         offset,
    1669                 :            :                   pdf_size_t        count,
    1670                 :            :                   pdf_error_t     **error)
    1671                 :            : {
    1672                 :          0 :   pdf_set_error (error,
    1673                 :            :                  PDF_EDOMAIN_BASE_FSYS,
    1674                 :            :                  PDF_EBADDATA,
    1675                 :            :                  "can't request RIA: not provided by the disk filesystem");
    1676                 :          0 :   return 0;
    1677                 :            : }
    1678                 :            : 
    1679                 :            : static pdf_bool_t
    1680                 :          0 : file_has_ria (pdf_fsys_file_t  *file)
    1681                 :            : {
    1682                 :            :   /* We can just safely return FALSE here, without error:
    1683                 :            :    * the file has definitely not an ongoing RIA operation */
    1684                 :          0 :   return PDF_FALSE;
    1685                 :            : }
    1686                 :            : 
    1687                 :            : static pdf_bool_t
    1688                 :          0 : file_cancel_ria (pdf_fsys_file_t  *file,
    1689                 :            :                  pdf_u32_t         ria_id,
    1690                 :            :                  pdf_error_t     **error)
    1691                 :            : {
    1692                 :            :   /* We can just safely return FALSE here, without error:
    1693                 :            :    * the file has definitely not an ongoing RIA operation, so
    1694                 :            :    * canceling RIA always succeeds. */
    1695                 :          0 :   return PDF_TRUE;
    1696                 :            : }
    1697                 :            : 
    1698                 :            : 
    1699                 :            : /* Host-dependent freopen() */
    1700                 :            : #ifdef PDF_HOST_WIN32
    1701                 :            : #define PDF_FREOPEN(f,m,s) _wfreopen((wchar_t *)f,(wchar_t *)m,s)
    1702                 :            : #else
    1703                 :            : #define PDF_FREOPEN(f,m,s) freopen_safer (f,m,s)
    1704                 :            : #endif
    1705                 :            : 
    1706                 :            : static pdf_bool_t
    1707                 :          0 : file_reopen (pdf_fsys_file_t            *file,
    1708                 :            :              enum pdf_fsys_file_mode_e   mode,
    1709                 :            :              pdf_error_t               **error)
    1710                 :            : {
    1711                 :            :   struct pdf_fsys_disk_file_s *disk_file;
    1712                 :            :   FILE *reopened;
    1713                 :            : 
    1714                 :          0 :   disk_file = (struct pdf_fsys_disk_file_s *)file;
    1715                 :            : 
    1716         [ #  # ]:          0 :   PDF_ASSERT_POINTER_RETURN_VAL (file, PDF_FALSE);
    1717         [ #  # ]:          0 :   PDF_ASSERT_RETURN_VAL (disk_file->file_descriptor > 0, PDF_FALSE);
    1718         [ #  # ]:          0 :   PDF_ASSERT_POINTER_RETURN_VAL (disk_file->host_path, PDF_FALSE);
    1719                 :            : 
    1720                 :            :   /* re-open the file */
    1721                 :          0 :   reopened = PDF_FREOPEN (disk_file->host_path,
    1722                 :            :                           get_mode_string (mode),
    1723                 :            :                           disk_file->file_descriptor);
    1724         [ #  # ]:          0 :   if (!reopened)
    1725                 :            :     {
    1726                 :          0 :       pdf_set_error (error,
    1727                 :            :                      PDF_EDOMAIN_BASE_FSYS,
    1728                 :            :                      get_status_from_errno (errno),
    1729                 :            :                      "cannot reopen file: '%s'",
    1730                 :            :                      strerror (errno));
    1731                 :          0 :       return PDF_FALSE;
    1732                 :            :     }
    1733                 :            : 
    1734                 :          0 :   disk_file->file_descriptor = reopened;
    1735                 :          0 :   file->mode = mode;
    1736                 :            : 
    1737                 :          0 :   return PDF_TRUE;
    1738                 :            : }
    1739                 :            : 
    1740                 :            : /*
    1741                 :            :  * Private functions
    1742                 :            :  */
    1743                 :            : 
    1744                 :            : static pdf_char_t *
    1745                 :         27 : get_host_path (const pdf_text_t  *path,
    1746                 :            :                pdf_size_t        *host_path_size,
    1747                 :            :                pdf_error_t      **error)
    1748                 :            : {
    1749                 :            : #ifdef PDF_HOST_WIN32
    1750                 :            :   /* For W32, we will always use widechar functions, so Windows' wchar_t
    1751                 :            :    * implementation should be used (UTF-16LE) */
    1752                 :            :   return pdf_text_get_unicode (path,
    1753                 :            :                                PDF_TEXT_UTF16_LE,
    1754                 :            :                                PDF_TEXT_UNICODE_WITH_NUL_SUFFIX,
    1755                 :            :                                host_path_size,
    1756                 :            :                                error);
    1757                 :            : #else
    1758                 :            :   /* Call the pdf_text module to get a host-encoded version of the
    1759                 :            :    *  given path */
    1760                 :            :   pdf_char_t *str;
    1761                 :            :   pdf_char_t *nul_suffixed;
    1762                 :         27 :   pdf_size_t length = 0;
    1763                 :            : 
    1764                 :         27 :   str = pdf_text_get_host (path,
    1765                 :            :                            pdf_text_get_host_encoding (),
    1766                 :            :                            &length,
    1767                 :            :                            error);
    1768         [ -  + ]:         27 :   if (!str)
    1769                 :          0 :     return NULL;
    1770                 :            : 
    1771                 :            :   /* Realloc to append last NUL byte */
    1772                 :         27 :   length++;
    1773                 :         27 :   nul_suffixed = pdf_realloc (str, length);
    1774         [ -  + ]:         27 :   if (!nul_suffixed)
    1775                 :            :     {
    1776                 :          0 :       pdf_dealloc (str);
    1777                 :          0 :       pdf_set_error (error,
    1778                 :            :                      PDF_EDOMAIN_BASE_FSYS,
    1779                 :            :                      PDF_ENOMEM,
    1780                 :            :                      "cannot get text contents host encoded: "
    1781                 :            :                      "couldn't reallocate %lu bytes",
    1782                 :            :                      (unsigned long)length);
    1783                 :          0 :       return NULL;
    1784                 :            :     }
    1785                 :         27 :   nul_suffixed[length - 1] = '\0';
    1786                 :            : 
    1787         [ +  + ]:         27 :   if (host_path_size)
    1788                 :         25 :     *host_path_size = length;
    1789                 :            : 
    1790                 :         27 :   return nul_suffixed;
    1791                 :            : #endif
    1792                 :            : }
    1793                 :            : 
    1794                 :            : static pdf_text_t *
    1795                 :            : set_host_path (const pdf_char_t *host_path,
    1796                 :            :                const pdf_size_t  host_path_size,
    1797                 :            :                pdf_error_t      **error)
    1798                 :            : {
    1799                 :            : #ifdef PDF_HOST_WIN32
    1800                 :            :   /* For W32, we will always use widechar functions, so Windows' wchar_t
    1801                 :            :    * implementation should be used (UTF-16LE) */
    1802                 :            :   return pdf_text_new_from_unicode (host_path,
    1803                 :            :                                     host_path_size,
    1804                 :            :                                     PDF_TEXT_UTF16_LE,
    1805                 :            :                                     error);
    1806                 :            : #else
    1807                 :            :   /* Call the pdf_text module to get a host-encoded version of the
    1808                 :            :    *  given path */
    1809                 :          0 :   return pdf_text_new_from_host (host_path,
    1810                 :            :                                  host_path_size,
    1811                 :            :                                  pdf_text_get_host_encoding (),
    1812                 :            :                                  error);
    1813                 :            : #endif
    1814                 :            : }
    1815                 :            : 
    1816                 :            : #ifndef PDF_HOST_WIN32
    1817                 :            : /* Posix-based open mode */
    1818                 :            : static const pdf_char_t *open_mode_strings[PDF_FSYS_OPEN_MODE_MAX] = {
    1819                 :            :   /* PDF_FSYS_OPEN_MODE_INVALID  */ (pdf_char_t *)"",
    1820                 :            :   /* PDF_FSYS_OPEN_MODE_READ     */ (pdf_char_t *)"r",
    1821                 :            :   /* PDF_FSYS_OPEN_MODE_WRITE    */ (pdf_char_t *)"w",
    1822                 :            :   /* PDF_FSYS_OPEN_MODE_RW      */ (pdf_char_t *)"r+",
    1823                 :            : };
    1824                 :            : #else
    1825                 :            : /* Windows portability note:
    1826                 :            :  *
    1827                 :            :  * Files are opened in "text mode" (with crlf translation) by
    1828                 :            :  * default.
    1829                 :            :  *
    1830                 :            :  * Although the "b" fopen option is supported by POSIX some old Unix
    1831                 :            :  * systems may not implement it, so we should use that option to
    1832                 :            :  * open files only while running in Windows.
    1833                 :            :  *
    1834                 :            :  * Also, note that the open modes are in UTF-16 for w32
    1835                 :            :  */
    1836                 :            : static const pdf_char_t *open_mode_strings[PDF_FSYS_OPEN_MODE_MAX] = {
    1837                 :            :   /* PDF_FSYS_OPEN_MODE_INVALID  */ (pdf_char_t *)"\x00\x00",
    1838                 :            :   /* PDF_FSYS_OPEN_MODE_READ     */ (pdf_char_t *)"\x72\x00\x62\x00\x00\x00",
    1839                 :            :   /* PDF_FSYS_OPEN_MODE_WRITE    */ (pdf_char_t *)"\x77\x00\x62\x00\x00\x00",
    1840                 :            :   /* PDF_FSYS_OPEN_MODE_RW       */ (pdf_char_t *)"\x72\x00\x62\x00\x2B\x00\x00\x00",
    1841                 :            : };
    1842                 :            : #endif
    1843                 :            : 
    1844                 :            : static const pdf_char_t *
    1845                 :            : get_mode_string (const enum pdf_fsys_file_mode_e mode)
    1846                 :            : {
    1847                 :         25 :   return open_mode_strings[mode];
    1848                 :            : }
    1849                 :            : 
    1850                 :            : #ifdef PDF_HOST_WIN32
    1851                 :            : 
    1852                 :            : #define PDF_MAX_W32_DEVICE_NAMES  32
    1853                 :            : static const pdf_char_t *device_names[PDF_MAX_W32_DEVICE_NAMES] = {
    1854                 :            :   (pdf_char_t *)"NUL",
    1855                 :            :   (pdf_char_t *)"CON",
    1856                 :            :   (pdf_char_t *)"PRN",
    1857                 :            :   (pdf_char_t *)"AUX",
    1858                 :            :   (pdf_char_t *)"COM1",
    1859                 :            :   (pdf_char_t *)"COM2",
    1860                 :            :   (pdf_char_t *)"COM3",
    1861                 :            :   (pdf_char_t *)"COM4",
    1862                 :            :   (pdf_char_t *)"COM5",
    1863                 :            :   (pdf_char_t *)"COM6",
    1864                 :            :   (pdf_char_t *)"COM7",
    1865                 :            :   (pdf_char_t *)"COM8",
    1866                 :            :   (pdf_char_t *)"COM9",
    1867                 :            :   (pdf_char_t *)"LPT1",
    1868                 :            :   (pdf_char_t *)"LPT2",
    1869                 :            :   (pdf_char_t *)"LPT3",
    1870                 :            :   (pdf_char_t *)"LPT4",
    1871                 :            :   (pdf_char_t *)"LPT5",
    1872                 :            :   (pdf_char_t *)"LPT6",
    1873                 :            :   (pdf_char_t *)"LPT7",
    1874                 :            :   (pdf_char_t *)"LPT8",
    1875                 :            :   (pdf_char_t *)"LPT9"
    1876                 :            : };
    1877                 :            : 
    1878                 :            : static pdf_bool_t
    1879                 :            : win32_device_p (const pdf_text_t  *path,
    1880                 :            :                 pdf_error_t      **error)
    1881                 :            : {
    1882                 :            :   /* The following special "files", which access devices, exist in all
    1883                 :            :      directories, case-insensitively, and with all possible endings
    1884                 :            :      after a period or colon, excpets in pathnames that start with
    1885                 :            :      \\?\: */
    1886                 :            :   int i;
    1887                 :            :   pdf_text_t *device_name;
    1888                 :            : 
    1889                 :            :   for (i = 0; i < PDF_MAX_W32_DEVICE_NAMES; ++i)
    1890                 :            :     {
    1891                 :            :       pdf_error_t *inner_error = NULL;
    1892                 :            : 
    1893                 :            :       device_name = pdf_text_new_from_unicode (device_names[i],
    1894                 :            :                                                strlen (device_names[i]),
    1895                 :            :                                                PDF_TEXT_UTF8,
    1896                 :            :                                                error);
    1897                 :            :       if (!device_name)
    1898                 :            :         return PDF_FALSE;
    1899                 :            : 
    1900                 :            :       if (pdf_text_cmp (path,
    1901                 :            :                         device_name,
    1902                 :            :                         PDF_FALSE,
    1903                 :            :                         &inner_error) == 0)
    1904                 :            :         {
    1905                 :            :           pdf_text_destroy (device_name);
    1906                 :            :           return PDF_TRUE;
    1907                 :            :         }
    1908                 :            : 
    1909                 :            :       pdf_text_destroy (device_name);
    1910                 :            : 
    1911                 :            :       if (inner_error)
    1912                 :            :         {
    1913                 :            :           pdf_propagate_error (error, inner_error);
    1914                 :            :           return PDF_FALSE;
    1915                 :            :         }
    1916                 :            :     }
    1917                 :            : 
    1918                 :            :   return PDF_FALSE;
    1919                 :            : }
    1920                 :            : 
    1921                 :            : #endif /* !PDF_HOST_WIN32 */
    1922                 :            : 
    1923                 :            : static pdf_status_t
    1924                 :          3 : get_status_from_errno (int _errno)
    1925                 :            : {
    1926 [ -  +  +  -  - :          3 :   switch (_errno)
             -  -  -  - ]
    1927                 :            :     {
    1928                 :            :     case EINVAL:
    1929                 :            :     case ESPIPE:
    1930                 :            :     case EOVERFLOW:
    1931                 :            :     case EBADF:
    1932                 :            :     case EFAULT:
    1933                 :            :     case EFBIG:
    1934                 :            :       /* Bad data */
    1935                 :          0 :       return PDF_EBADDATA;
    1936                 :            :     case EACCES:
    1937                 :            :     case EPERM:
    1938                 :            :     case EROFS:
    1939                 :            :     case ETXTBSY:
    1940                 :            :       /* Not enough permissions */
    1941                 :          1 :       return PDF_EBADPERMS;
    1942                 :            :     case EISDIR:
    1943                 :            :     case ENAMETOOLONG:
    1944                 :            :     case ENOENT:
    1945                 :            :     case ENOTDIR:
    1946                 :            : #ifdef ELOOP
    1947                 :            :     case ELOOP:
    1948                 :            : #endif
    1949                 :            :       /* Invalid path name */
    1950                 :          2 :       return PDF_EBADNAME;
    1951                 :            :     case ENOMEM:
    1952                 :            :       /* No memory */
    1953                 :          0 :       return PDF_ENOMEM;
    1954                 :            :     case EEXIST:
    1955                 :            :       /* File Exists */
    1956                 :          0 :       return PDF_EEXIST;
    1957                 :            :     case ENOTEMPTY:
    1958                 :            :       /* Not empty */
    1959                 :          0 :       return PDF_ENOTEMPTY;
    1960                 :            :     case EAGAIN:
    1961                 :            :       /* non-blocking descriptor and blocking writing
    1962                 :            :          requested */
    1963                 :          0 :       return PDF_EAGAIN;
    1964                 :            :     case ENOSPC:
    1965                 :            :       /* Not enough room in disk */
    1966                 :          0 :       return PDF_ENOSPC;
    1967                 :            :     default:
    1968                 :            :       /* Other error */
    1969                 :          3 :       return PDF_ERROR;
    1970                 :            :     }
    1971                 :            : }
    1972                 :            : 
    1973                 :            : /* Setup the disk filesystem implementation, using named initializers */
    1974                 :            : static struct pdf_fsys_disk_s pdf_fsys_disk_implementation =
    1975                 :            :   {
    1976                 :            :     .common.get_free_space_fn      = get_free_space,
    1977                 :            :     .common.create_folder_fn       = create_folder,
    1978                 :            :     .common.get_folder_contents_fn = get_folder_contents,
    1979                 :            :     .common.remove_folder_fn       = remove_folder,
    1980                 :            :     .common.get_parent_fn          = get_parent,
    1981                 :            :     .common.get_basename_fn        = get_basename,
    1982                 :            :     .common.compare_path_p_fn      = compare_path_p,
    1983                 :            :     .common.build_path_fn          = build_path,
    1984                 :            :     .common.get_url_from_path_fn   = get_url_from_path,
    1985                 :            :     .common.get_path_from_url_fn   = get_path_from_url,
    1986                 :            :     .common.item_p_fn              = item_p,
    1987                 :            :     .common.get_item_props_fn      = get_item_props,
    1988                 :            :     .common.item_readable_p_fn     = item_readable_p,
    1989                 :            :     .common.item_writable_p_fn     = item_writable_p,
    1990                 :            :     .common.file_open_fn           = file_open,
    1991                 :            :     .common.file_open_tmp_fn       = file_open_tmp,
    1992                 :            :     .common.file_reopen_fn         = file_reopen,
    1993                 :            :     .common.file_close_fn          = file_close,
    1994                 :            :     .common.file_get_size_fn       = file_get_size,
    1995                 :            :     .common.file_can_set_size_p_fn = file_can_set_size_p,
    1996                 :            :     .common.file_set_size_fn       = file_set_size,
    1997                 :            :     .common.file_get_pos_fn        = file_get_pos,
    1998                 :            :     .common.file_set_pos_fn        = file_set_pos,
    1999                 :            :     .common.file_read_fn           = file_read,
    2000                 :            :     .common.file_write_fn          = file_write,
    2001                 :            :     .common.file_flush_fn          = file_flush,
    2002                 :            :     .common.file_request_ria_fn    = file_request_ria,
    2003                 :            :     .common.file_has_ria_fn        = file_has_ria,
    2004                 :            :     .common.file_cancel_ria_fn     = file_cancel_ria,
    2005                 :            :   };
    2006                 :            : 
    2007                 :            : static void
    2008                 :        745 : pdf_fsys_disk_deinit_cb (struct pdf_fsys_s *impl)
    2009                 :            : {
    2010                 :        745 :   struct pdf_fsys_disk_s *disk_fsys = (struct pdf_fsys_disk_s *)impl;
    2011                 :            : 
    2012         [ +  - ]:        745 :   if (disk_fsys->filename_separator)
    2013                 :            :     {
    2014                 :        745 :       pdf_text_destroy (disk_fsys->filename_separator);
    2015                 :        745 :       disk_fsys->filename_separator = NULL;
    2016                 :            :     }
    2017                 :        745 : }
    2018                 :            : 
    2019                 :            : pdf_bool_t
    2020                 :        745 : pdf_fsys_disk_init (pdf_error_t **error)
    2021                 :            : {
    2022                 :            :   /* Disk filesystem implementation specific stuff */
    2023                 :        745 :   pdf_fsys_disk_implementation.filename_separator =
    2024                 :        745 :     pdf_text_new_from_unicode ((pdf_char_t*)DIR_SEPARATOR_S,
    2025                 :            :                                1,
    2026                 :            :                                PDF_TEXT_UTF8,
    2027                 :            :                                error);
    2028         [ -  + ]:        745 :   if (!pdf_fsys_disk_implementation.filename_separator)
    2029                 :            :     {
    2030                 :          0 :       pdf_prefix_error (error, "couldn't initialize disk filesystem: ");
    2031                 :          0 :       return PDF_FALSE;
    2032                 :            :     }
    2033                 :            : 
    2034                 :        745 :   return pdf_fsys_add (PDF_FSYS_DISK_ID,
    2035                 :            :                        (struct pdf_fsys_s *)&pdf_fsys_disk_implementation,
    2036                 :            :                        pdf_fsys_disk_deinit_cb,
    2037                 :            :                        error);
    2038                 :            : }
    2039                 :            : 
    2040                 :            : void
    2041                 :        745 : pdf_fsys_disk_deinit (void)
    2042                 :            : {
    2043                 :        745 :   pdf_fsys_remove (PDF_FSYS_DISK_ID);
    2044                 :        745 : }
    2045                 :            : 
    2046                 :            : /* End of pdf-fsys-disk.c */

Generated by: LCOV version 1.8