Coverage Report

Created: 2026-01-17 06:55

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