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