Imported Upstream version 2.2.2
[platform/upstream/cups.git] / cups / dir.c
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 */