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