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