/*
* Directory routines for CUPS.
*
* This set of APIs abstracts enumeration of directory entries.
*
* Copyright 2007-2017 by Apple Inc.
* Copyright 1997-2005 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
* property of Apple Inc. and are protected by Federal copyright
* law. Distribution and use rights are outlined in the file "LICENSE.txt"
* which should have been included with this file. If this file is
* missing or damaged, see the license at "http://www.cups.org/".
*/
/*
* Include necessary headers...
*/
#include "string-private.h"
#include "debug-private.h"
#include "dir.h"
/*
* Windows implementation...
*/
#ifdef WIN32
# include <windows.h>
/*
* Types and structures...
*/
struct _cups_dir_s /**** Directory data structure ****/
{
char directory[1024]; /* Directory filename */
HANDLE dir; /* Directory handle */
cups_dentry_t entry; /* Directory entry */
};
/*
* '_cups_dir_time()' - Convert a FILETIME value to a UNIX time value.
*/
time_t /* O - UNIX time */
_cups_dir_time(FILETIME ft) /* I - File time */
{
ULONGLONG val; /* File time in 0.1 usecs */
/*
* Convert file time (1/10 microseconds since Jan 1, 1601) to UNIX
* time (seconds since Jan 1, 1970). There are 11,644,732,800 seconds
* between them...
*/
val = ft.dwLowDateTime + ((ULONGLONG)ft.dwHighDateTime << 32);
return ((time_t)(val / 10000000 - 11644732800));
}
/*
* 'cupsDirClose()' - Close a directory.
*
* @since CUPS 1.2/macOS 10.5@
*/
void
cupsDirClose(cups_dir_t *dp) /* I - Directory pointer */
{
/*
* Range check input...
*/
if (!dp)
return;
/*
* Close an open directory handle...
*/
if (dp->dir != INVALID_HANDLE_VALUE)
FindClose(dp->dir);
/*
* Free memory used...
*/
free(dp);
}
/*
* 'cupsDirOpen()' - Open a directory.
*
* @since CUPS 1.2/macOS 10.5@
*/
cups_dir_t * /* O - Directory pointer or @code NULL@ if the directory could not be opened. */
cupsDirOpen(const char *directory) /* I - Directory name */
{
cups_dir_t *dp; /* Directory */
/*
* Range check input...
*/
if (!directory)
return (NULL);
/*
* Allocate memory for the directory structure...
*/
dp = (cups_dir_t *)calloc(1, sizeof(cups_dir_t));
if (!dp)
return (NULL);
/*
* Copy the directory name for later use...
*/
dp->dir = INVALID_HANDLE_VALUE;
strlcpy(dp->directory, directory, sizeof(dp->directory));
/*
* Return the new directory structure...
*/
return (dp);
}
/*
* 'cupsDirRead()' - Read the next directory entry.
*
* @since CUPS 1.2/macOS 10.5@
*/
cups_dentry_t * /* O - Directory entry or @code NULL@ if there are no more */
cupsDirRead(cups_dir_t *dp) /* I - Directory pointer */
{
WIN32_FIND_DATA entry; /* Directory entry data */
/*
* Range check input...
*/
if (!dp)
return (NULL);
/*
* See if we have already started finding files...
*/
if (dp->dir == INVALID_HANDLE_VALUE)
{
/*
* No, find the first file...
*/
dp->dir = FindFirstFile(dp->directory, &entry);
if (dp->dir == INVALID_HANDLE_VALUE)
return (NULL);
}
else if (!FindNextFile(dp->dir, &entry))
return (NULL);
/*
* Copy the name over and convert the file information...
*/
strlcpy(dp->entry.filename, entry.cFileName, sizeof(dp->entry.filename));
if (entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
dp->entry.fileinfo.st_mode = 0755 | S_IFDIR;
else
dp->entry.fileinfo.st_mode = 0644;
dp->entry.fileinfo.st_atime = _cups_dir_time(entry.ftLastAccessTime);
dp->entry.fileinfo.st_ctime = _cups_dir_time(entry.ftCreationTime);
dp->entry.fileinfo.st_mtime = _cups_dir_time(entry.ftLastWriteTime);
dp->entry.fileinfo.st_size = entry.nFileSizeLow + ((unsigned long long)entry.nFileSizeHigh << 32);
/*
* Return the entry...
*/
return (&(dp->entry));
}
/*
* 'cupsDirRewind()' - Rewind to the start of the directory.
*
* @since CUPS 1.2/macOS 10.5@
*/
void
cupsDirRewind(cups_dir_t *dp) /* I - Directory pointer */
{
/*
* Range check input...
*/
if (!dp)
return;
/*
* Close an open directory handle...
*/
if (dp->dir != INVALID_HANDLE_VALUE)
{
FindClose(dp->dir);
dp->dir = INVALID_HANDLE_VALUE;
}
}
#else
/*
* POSIX implementation...
*/
# include <sys/types.h>
# include <dirent.h>
/*
* Types and structures...
*/
struct _cups_dir_s /**** Directory data structure ****/
{
char directory[1024]; /* Directory filename */
DIR *dir; /* Directory file */
cups_dentry_t entry; /* Directory entry */
};
/*
* 'cupsDirClose()' - Close a directory.
*
* @since CUPS 1.2/macOS 10.5@
*/
void
cupsDirClose(cups_dir_t *dp) /* I - Directory pointer */
{
DEBUG_printf(("cupsDirClose(dp=%p)", (void *)dp));
/*
* Range check input...
*/
if (!dp)
return;
/*
* Close the directory and free memory...
*/
closedir(dp->dir);
free(dp);
}
/*
* 'cupsDirOpen()' - Open a directory.
*
* @since CUPS 1.2/macOS 10.5@
*/
cups_dir_t * /* O - Directory pointer or @code NULL@ if the directory could not be opened. */
cupsDirOpen(const char *directory) /* I - Directory name */
{
cups_dir_t *dp; /* Directory */
DEBUG_printf(("cupsDirOpen(directory=\"%s\")", directory));
/*
* Range check input...
*/
if (!directory)
return (NULL);
/*
* Allocate memory for the directory structure...
*/
dp = (cups_dir_t *)calloc(1, sizeof(cups_dir_t));
if (!dp)
return (NULL);
/*
* Open the directory...
*/
dp->dir = opendir(directory);
if (!dp->dir)
{
free(dp);
return (NULL);
}
/*
* Copy the directory name for later use...
*/
strlcpy(dp->directory, directory, sizeof(dp->directory));
/*
* Return the new directory structure...
*/
return (dp);
}
/*
* 'cupsDirRead()' - Read the next directory entry.
*
* @since CUPS 1.2/macOS 10.5@
*/
cups_dentry_t * /* O - Directory entry or @code NULL@ when there are no more */
cupsDirRead(cups_dir_t *dp) /* I - Directory pointer */
{
struct dirent *entry; /* Pointer to entry */
char filename[1024]; /* Full filename */
DEBUG_printf(("2cupsDirRead(dp=%p)", (void *)dp));
/*
* Range check input...
*/
if (!dp)
return (NULL);
/*
* Try reading an entry that is not "." or ".."...
*/
for (;;)
{
/*
* Read the next entry...
*/
if ((entry = readdir(dp->dir)) == NULL)
{
DEBUG_puts("3cupsDirRead: readdir() returned a NULL pointer!");
return (NULL);
}
DEBUG_printf(("4cupsDirRead: readdir() returned \"%s\"...", entry->d_name));
/*
* Skip "." and ".."...
*/
if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
continue;
/*
* Copy the name over and get the file information...
*/
strlcpy(dp->entry.filename, entry->d_name, sizeof(dp->entry.filename));
snprintf(filename, sizeof(filename), "%s/%s", dp->directory, entry->d_name);
if (stat(filename, &(dp->entry.fileinfo)))
{
DEBUG_printf(("3cupsDirRead: stat() failed for \"%s\" - %s...", filename,
strerror(errno)));
continue;
}
/*
* Return the entry...
*/
return (&(dp->entry));
}
}
/*
* 'cupsDirRewind()' - Rewind to the start of the directory.
*
* @since CUPS 1.2/macOS 10.5@
*/
void
cupsDirRewind(cups_dir_t *dp) /* I - Directory pointer */
{
DEBUG_printf(("cupsDirRewind(dp=%p)", (void *)dp));
/*
* Range check input...
*/
if (!dp)
return;
/*
* Rewind the directory...
*/
rewinddir(dp->dir);
}
#endif /* WIN32 */