Home | History | Annotate | Download | only in cups
      1 /*
      2  * Directory routines for CUPS.
      3  *
      4  * This set of APIs abstracts enumeration of directory entries.
      5  *
      6  * Copyright 2007-2012 by Apple Inc.
      7  * Copyright 1997-2005 by Easy Software Products, all rights reserved.
      8  *
      9  * These coded instructions, statements, and computer programs are the
     10  * property of Apple Inc. and are protected by Federal copyright
     11  * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
     12  * which should have been included with this file.  If this file is
     13  * missing or damaged, see the license at "http://www.cups.org/".
     14  */
     15 
     16 /*
     17  * Include necessary headers...
     18  */
     19 
     20 #include "string-private.h"
     21 #include "debug-private.h"
     22 #include "dir.h"
     23 
     24 
     25 /*
     26  * Windows implementation...
     27  */
     28 
     29 #ifdef WIN32
     30 #  include <windows.h>
     31 
     32 /*
     33  * Types and structures...
     34  */
     35 
     36 struct _cups_dir_s			/**** Directory data structure ****/
     37 {
     38   char		directory[1024];	/* Directory filename */
     39   HANDLE	dir;			/* Directory handle */
     40   cups_dentry_t	entry;			/* Directory entry */
     41 };
     42 
     43 
     44 /*
     45  * '_cups_dir_time()' - Convert a FILETIME value to a UNIX time value.
     46  */
     47 
     48 time_t					/* O - UNIX time */
     49 _cups_dir_time(FILETIME ft)		/* I - File time */
     50 {
     51   ULONGLONG	val;			/* File time in 0.1 usecs */
     52 
     53 
     54  /*
     55   * Convert file time (1/10 microseconds since Jan 1, 1601) to UNIX
     56   * time (seconds since Jan 1, 1970).  There are 11,644,732,800 seconds
     57   * between them...
     58   */
     59 
     60   val = ft.dwLowDateTime + ((ULONGLONG)ft.dwHighDateTime << 32);
     61   return ((time_t)(val / 10000000 - 11644732800));
     62 }
     63 
     64 
     65 /*
     66  * 'cupsDirClose()' - Close a directory.
     67  *
     68  * @since CUPS 1.2/macOS 10.5@
     69  */
     70 
     71 void
     72 cupsDirClose(cups_dir_t *dp)		/* I - Directory pointer */
     73 {
     74  /*
     75   * Range check input...
     76   */
     77 
     78   if (!dp)
     79     return;
     80 
     81  /*
     82   * Close an open directory handle...
     83   */
     84 
     85   if (dp->dir != INVALID_HANDLE_VALUE)
     86     FindClose(dp->dir);
     87 
     88  /*
     89   * Free memory used...
     90   */
     91 
     92   free(dp);
     93 }
     94 
     95 
     96 /*
     97  * 'cupsDirOpen()' - Open a directory.
     98  *
     99  * @since CUPS 1.2/macOS 10.5@
    100  */
    101 
    102 cups_dir_t *				/* O - Directory pointer or @code NULL@ if the directory could not be opened. */
    103 cupsDirOpen(const char *directory)	/* I - Directory name */
    104 {
    105   cups_dir_t	*dp;			/* Directory */
    106 
    107 
    108  /*
    109   * Range check input...
    110   */
    111 
    112   if (!directory)
    113     return (NULL);
    114 
    115  /*
    116   * Allocate memory for the directory structure...
    117   */
    118 
    119   dp = (cups_dir_t *)calloc(1, sizeof(cups_dir_t));
    120   if (!dp)
    121     return (NULL);
    122 
    123  /*
    124   * Copy the directory name for later use...
    125   */
    126 
    127   dp->dir = INVALID_HANDLE_VALUE;
    128 
    129   strlcpy(dp->directory, directory, sizeof(dp->directory));
    130 
    131  /*
    132   * Return the new directory structure...
    133   */
    134 
    135   return (dp);
    136 }
    137 
    138 
    139 /*
    140  * 'cupsDirRead()' - Read the next directory entry.
    141  *
    142  * @since CUPS 1.2/macOS 10.5@
    143  */
    144 
    145 cups_dentry_t *				/* O - Directory entry or @code NULL@ if there are no more */
    146 cupsDirRead(cups_dir_t *dp)		/* I - Directory pointer */
    147 {
    148   WIN32_FIND_DATA	entry;		/* Directory entry data */
    149 
    150 
    151  /*
    152   * Range check input...
    153   */
    154 
    155   if (!dp)
    156     return (NULL);
    157 
    158  /*
    159   * See if we have already started finding files...
    160   */
    161 
    162   if (dp->dir == INVALID_HANDLE_VALUE)
    163   {
    164    /*
    165     * No, find the first file...
    166     */
    167 
    168     dp->dir = FindFirstFile(dp->directory, &entry);
    169     if (dp->dir == INVALID_HANDLE_VALUE)
    170       return (NULL);
    171   }
    172   else if (!FindNextFile(dp->dir, &entry))
    173     return (NULL);
    174 
    175  /*
    176   * Copy the name over and convert the file information...
    177   */
    178 
    179   strlcpy(dp->entry.filename, entry.cFileName, sizeof(dp->entry.filename));
    180 
    181   if (entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
    182     dp->entry.fileinfo.st_mode = 0755 | S_IFDIR;
    183   else
    184     dp->entry.fileinfo.st_mode = 0644;
    185 
    186   dp->entry.fileinfo.st_atime = _cups_dir_time(entry.ftLastAccessTime);
    187   dp->entry.fileinfo.st_ctime = _cups_dir_time(entry.ftCreationTime);
    188   dp->entry.fileinfo.st_mtime = _cups_dir_time(entry.ftLastWriteTime);
    189   dp->entry.fileinfo.st_size  = entry.nFileSizeLow + ((unsigned long long)entry.nFileSizeHigh << 32);
    190 
    191  /*
    192   * Return the entry...
    193   */
    194 
    195   return (&(dp->entry));
    196 }
    197 
    198 
    199 /*
    200  * 'cupsDirRewind()' - Rewind to the start of the directory.
    201  *
    202  * @since CUPS 1.2/macOS 10.5@
    203  */
    204 
    205 void
    206 cupsDirRewind(cups_dir_t *dp)		/* I - Directory pointer */
    207 {
    208  /*
    209   * Range check input...
    210   */
    211 
    212   if (!dp)
    213     return;
    214 
    215  /*
    216   * Close an open directory handle...
    217   */
    218 
    219   if (dp->dir != INVALID_HANDLE_VALUE)
    220   {
    221     FindClose(dp->dir);
    222     dp->dir = INVALID_HANDLE_VALUE;
    223   }
    224 }
    225 
    226 
    227 #else
    228 
    229 /*
    230  * POSIX implementation...
    231  */
    232 
    233 #  include <sys/types.h>
    234 #  include <dirent.h>
    235 
    236 
    237 /*
    238  * Types and structures...
    239  */
    240 
    241 struct _cups_dir_s			/**** Directory data structure ****/
    242 {
    243   char		directory[1024];	/* Directory filename */
    244   DIR		*dir;			/* Directory file */
    245   cups_dentry_t	entry;			/* Directory entry */
    246 };
    247 
    248 
    249 /*
    250  * 'cupsDirClose()' - Close a directory.
    251  *
    252  * @since CUPS 1.2/macOS 10.5@
    253  */
    254 
    255 void
    256 cupsDirClose(cups_dir_t *dp)		/* I - Directory pointer */
    257 {
    258   DEBUG_printf(("cupsDirClose(dp=%p)", (void *)dp));
    259 
    260  /*
    261   * Range check input...
    262   */
    263 
    264   if (!dp)
    265     return;
    266 
    267  /*
    268   * Close the directory and free memory...
    269   */
    270 
    271   closedir(dp->dir);
    272   free(dp);
    273 }
    274 
    275 
    276 /*
    277  * 'cupsDirOpen()' - Open a directory.
    278  *
    279  * @since CUPS 1.2/macOS 10.5@
    280  */
    281 
    282 cups_dir_t *				/* O - Directory pointer or @code NULL@ if the directory could not be opened. */
    283 cupsDirOpen(const char *directory)	/* I - Directory name */
    284 {
    285   cups_dir_t	*dp;			/* Directory */
    286 
    287 
    288   DEBUG_printf(("cupsDirOpen(directory=\"%s\")", directory));
    289 
    290  /*
    291   * Range check input...
    292   */
    293 
    294   if (!directory)
    295     return (NULL);
    296 
    297  /*
    298   * Allocate memory for the directory structure...
    299   */
    300 
    301   dp = (cups_dir_t *)calloc(1, sizeof(cups_dir_t));
    302   if (!dp)
    303     return (NULL);
    304 
    305  /*
    306   * Open the directory...
    307   */
    308 
    309   dp->dir = opendir(directory);
    310   if (!dp->dir)
    311   {
    312     free(dp);
    313     return (NULL);
    314   }
    315 
    316  /*
    317   * Copy the directory name for later use...
    318   */
    319 
    320   strlcpy(dp->directory, directory, sizeof(dp->directory));
    321 
    322  /*
    323   * Return the new directory structure...
    324   */
    325 
    326   return (dp);
    327 }
    328 
    329 
    330 /*
    331  * 'cupsDirRead()' - Read the next directory entry.
    332  *
    333  * @since CUPS 1.2/macOS 10.5@
    334  */
    335 
    336 cups_dentry_t *				/* O - Directory entry or @code NULL@ when there are no more */
    337 cupsDirRead(cups_dir_t *dp)		/* I - Directory pointer */
    338 {
    339   struct dirent	*entry;			/* Pointer to entry */
    340   char		filename[1024];		/* Full filename */
    341 #  ifdef HAVE_PTHREAD_H
    342   char		buffer[sizeof(struct dirent) + 1024];
    343 					/* Directory entry buffer */
    344 #  endif /* HAVE_PTHREAD_H */
    345 
    346 
    347   DEBUG_printf(("2cupsDirRead(dp=%p)", (void *)dp));
    348 
    349  /*
    350   * Range check input...
    351   */
    352 
    353   if (!dp)
    354     return (NULL);
    355 
    356  /*
    357   * Try reading an entry that is not "." or ".."...
    358   */
    359 
    360   for (;;)
    361   {
    362 #  ifdef HAVE_PTHREAD_H
    363    /*
    364     * Read the next entry using the reentrant version of readdir...
    365     */
    366 
    367     if (readdir_r(dp->dir, (struct dirent *)buffer, &entry))
    368     {
    369       DEBUG_printf(("3cupsDirRead: readdir_r() failed - %s\n", strerror(errno)));
    370       return (NULL);
    371     }
    372 
    373     if (!entry)
    374     {
    375       DEBUG_puts("3cupsDirRead: readdir_r() returned a NULL pointer!");
    376       return (NULL);
    377     }
    378 
    379     DEBUG_printf(("4cupsDirRead: readdir_r() returned \"%s\"...",
    380                   entry->d_name));
    381 
    382 #  else
    383    /*
    384     * Read the next entry using the original version of readdir...
    385     */
    386 
    387     if ((entry = readdir(dp->dir)) == NULL)
    388     {
    389       DEBUG_puts("3cupsDirRead: readdir() returned a NULL pointer!");
    390       return (NULL);
    391     }
    392 
    393     DEBUG_printf(("4cupsDirRead: readdir() returned \"%s\"...", entry->d_name));
    394 
    395 #  endif /* HAVE_PTHREAD_H */
    396 
    397    /*
    398     * Skip "." and ".."...
    399     */
    400 
    401     if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
    402       continue;
    403 
    404    /*
    405     * Copy the name over and get the file information...
    406     */
    407 
    408     strlcpy(dp->entry.filename, entry->d_name, sizeof(dp->entry.filename));
    409 
    410     snprintf(filename, sizeof(filename), "%s/%s", dp->directory, entry->d_name);
    411 
    412     if (stat(filename, &(dp->entry.fileinfo)))
    413     {
    414       DEBUG_printf(("3cupsDirRead: stat() failed for \"%s\" - %s...", filename,
    415                     strerror(errno)));
    416       continue;
    417     }
    418 
    419    /*
    420     * Return the entry...
    421     */
    422 
    423     return (&(dp->entry));
    424   }
    425 }
    426 
    427 
    428 /*
    429  * 'cupsDirRewind()' - Rewind to the start of the directory.
    430  *
    431  * @since CUPS 1.2/macOS 10.5@
    432  */
    433 
    434 void
    435 cupsDirRewind(cups_dir_t *dp)		/* I - Directory pointer */
    436 {
    437   DEBUG_printf(("cupsDirRewind(dp=%p)", (void *)dp));
    438 
    439  /*
    440   * Range check input...
    441   */
    442 
    443   if (!dp)
    444     return;
    445 
    446  /*
    447   * Rewind the directory...
    448   */
    449 
    450   rewinddir(dp->dir);
    451 }
    452 #endif /* WIN32 */
    453