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