Coverage Report

Created: 2024-11-04 06:16

/src/libcups/cups/dir.c
Line
Count
Source (jump to first uncovered line)
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
#include "string-private.h"
15
#include "debug-internal.h"
16
#include "cups-private.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
  // Convert file time (1/10 microseconds since Jan 1, 1601) to UNIX
89
  // time (seconds since Jan 1, 1970).  There are 11,644,732,800 seconds
90
  // between them...
91
  val = ft.dwLowDateTime + ((ULONGLONG)ft.dwHighDateTime << 32);
92
  return ((time_t)(val / 10000000 - 11644732800));
93
}
94
95
96
//
97
// 'cupsDirClose()' - Close a directory.
98
//
99
100
void
101
cupsDirClose(cups_dir_t *dp)    // I - Directory pointer
102
{
103
  // Range check input...
104
  if (!dp)
105
    return;
106
107
  // Close an open directory handle...
108
  if (dp->dir != INVALID_HANDLE_VALUE)
109
    FindClose(dp->dir);
110
111
  // Free memory used...
112
  free(dp);
113
}
114
115
116
//
117
// 'cupsDirOpen()' - Open a directory.
118
//
119
120
cups_dir_t *        // O - Directory pointer or @code NULL@ if the directory could not be opened.
121
cupsDirOpen(const char *directory)  // I - Directory name
122
{
123
  cups_dir_t  *dp;      // Directory
124
125
126
  // Range check input...
127
  if (!directory)
128
    return (NULL);
129
130
  // Allocate memory for the directory structure...
131
  dp = (cups_dir_t *)calloc(1, sizeof(cups_dir_t));
132
  if (!dp)
133
    return (NULL);
134
135
  // Copy the directory name for later use...
136
  dp->dir = INVALID_HANDLE_VALUE;
137
138
  snprintf(dp->directory, sizeof(dp->directory), "%s\\*",  directory);
139
140
  // Return the new directory structure...
141
  return (dp);
142
}
143
144
145
//
146
// 'cupsDirRead()' - Read the next directory entry.
147
//
148
149
cups_dentry_t *       // O - Directory entry or @code NULL@ if there are no more
150
cupsDirRead(cups_dir_t *dp)   // I - Directory pointer
151
{
152
  WIN32_FIND_DATAA  entry;    // Directory entry data
153
154
155
  // Range check input...
156
  if (!dp)
157
    return (NULL);
158
159
  // See if we have already started finding files...
160
  if (dp->dir == INVALID_HANDLE_VALUE)
161
  {
162
    // No, find the first file...
163
    dp->dir = FindFirstFileA(dp->directory, &entry);
164
    if (dp->dir == INVALID_HANDLE_VALUE)
165
      return (NULL);
166
  }
167
  else if (!FindNextFileA(dp->dir, &entry))
168
  {
169
    return (NULL);
170
  }
171
172
  // Loop until we have something other than "." or ".."...
173
  while (!strcmp(entry.cFileName, ".") || !strcmp(entry.cFileName, ".."))
174
  {
175
    if (!FindNextFileA(dp->dir, &entry))
176
      return (NULL);
177
  }
178
179
  // Copy the name over and convert the file information...
180
  cupsCopyString(dp->entry.filename, entry.cFileName, sizeof(dp->entry.filename));
181
182
  if (entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
183
    dp->entry.fileinfo.st_mode = 0755 | S_IFDIR;
184
  else
185
    dp->entry.fileinfo.st_mode = 0644 | S_IFREG;
186
187
  dp->entry.fileinfo.st_atime = _cups_dir_time(entry.ftLastAccessTime);
188
  dp->entry.fileinfo.st_ctime = _cups_dir_time(entry.ftCreationTime);
189
  dp->entry.fileinfo.st_mtime = _cups_dir_time(entry.ftLastWriteTime);
190
  dp->entry.fileinfo.st_size  = entry.nFileSizeLow + ((unsigned long long)entry.nFileSizeHigh << 32);
191
192
  // Return the entry...
193
  return (&(dp->entry));
194
}
195
196
197
//
198
// 'cupsDirRewind()' - Rewind to the start of the directory.
199
//
200
201
void
202
cupsDirRewind(cups_dir_t *dp)   // I - Directory pointer
203
{
204
  // Range check input...
205
  if (!dp)
206
    return;
207
208
  // Close an open directory handle...
209
  if (dp->dir != INVALID_HANDLE_VALUE)
210
  {
211
    FindClose(dp->dir);
212
    dp->dir = INVALID_HANDLE_VALUE;
213
  }
214
}
215
216
217
#else
218
219
//
220
// POSIX implementation...
221
//
222
223
#  include <sys/types.h>
224
#  include <dirent.h>
225
226
227
//
228
// Types and structures...
229
//
230
231
struct _cups_dir_s      // Directory data structure
232
{
233
  char    directory[1024];  // Directory filename
234
  DIR   *dir;     // Directory file
235
  cups_dentry_t entry;      // Directory entry
236
};
237
238
239
//
240
// 'cupsDirClose()' - Close a directory.
241
//
242
243
void
244
cupsDirClose(cups_dir_t *dp)    // I - Directory pointer
245
0
{
246
0
  DEBUG_printf("cupsDirClose(dp=%p)", (void *)dp);
247
248
  // Range check input...
249
0
  if (!dp)
250
0
    return;
251
252
  // Close the directory and free memory...
253
0
  closedir(dp->dir);
254
0
  free(dp);
255
0
}
256
257
258
//
259
// 'cupsDirOpen()' - Open a directory.
260
//
261
262
cups_dir_t *        // O - Directory pointer or @code NULL@ if the directory could not be opened.
263
cupsDirOpen(const char *directory)  // I - Directory name
264
0
{
265
0
  cups_dir_t  *dp;      // Directory
266
267
268
0
  DEBUG_printf("cupsDirOpen(directory=\"%s\")", directory);
269
270
  // Range check input...
271
0
  if (!directory)
272
0
    return (NULL);
273
274
  // Allocate memory for the directory structure...
275
0
  dp = (cups_dir_t *)calloc(1, sizeof(cups_dir_t));
276
0
  if (!dp)
277
0
    return (NULL);
278
279
  // Open the directory...
280
0
  dp->dir = opendir(directory);
281
0
  if (!dp->dir)
282
0
  {
283
0
    free(dp);
284
0
    return (NULL);
285
0
  }
286
287
  // Copy the directory name for later use...
288
0
  cupsCopyString(dp->directory, directory, sizeof(dp->directory));
289
290
  // Return the new directory structure...
291
0
  return (dp);
292
0
}
293
294
295
//
296
// 'cupsDirRead()' - Read the next directory entry.
297
//
298
299
cups_dentry_t *       // O - Directory entry or @code NULL@ when there are no more
300
cupsDirRead(cups_dir_t *dp)   // I - Directory pointer
301
0
{
302
0
  struct dirent *entry;     // Pointer to entry
303
0
  char    filename[1024];   // Full filename
304
305
306
0
  DEBUG_printf("2cupsDirRead(dp=%p)", (void *)dp);
307
308
  // Range check input...
309
0
  if (!dp)
310
0
    return (NULL);
311
312
  // Try reading an entry that is not "." or ".."...
313
0
  for (;;)
314
0
  {
315
    // Read the next entry...
316
0
    if ((entry = readdir(dp->dir)) == NULL)
317
0
    {
318
0
      DEBUG_puts("3cupsDirRead: readdir() returned a NULL pointer!");
319
0
      return (NULL);
320
0
    }
321
322
0
    DEBUG_printf("4cupsDirRead: readdir() returned \"%s\"...", entry->d_name);
323
324
    // Skip "." and ".."...
325
0
    if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
326
0
      continue;
327
328
    // Copy the name over and get the file information...
329
0
    cupsCopyString(dp->entry.filename, entry->d_name, sizeof(dp->entry.filename));
330
331
0
    snprintf(filename, sizeof(filename), "%s/%s", dp->directory, entry->d_name);
332
333
0
    if (stat(filename, &(dp->entry.fileinfo)))
334
0
    {
335
0
      DEBUG_printf("3cupsDirRead: stat() failed for \"%s\" - %s...", filename, strerror(errno));
336
0
      continue;
337
0
    }
338
339
    // Return the entry...
340
0
    return (&(dp->entry));
341
0
  }
342
0
}
343
344
345
//
346
// 'cupsDirRewind()' - Rewind to the start of the directory.
347
//
348
349
void
350
cupsDirRewind(cups_dir_t *dp)   // I - Directory pointer
351
0
{
352
0
  DEBUG_printf("cupsDirRewind(dp=%p)", (void *)dp);
353
354
  // Range check input...
355
0
  if (!dp)
356
0
    return;
357
358
  // Rewind the directory...
359
0
  rewinddir(dp->dir);
360
0
}
361
#endif // _WIN32