mirror of https://github.com/citusdata/citus.git
176 lines
4.3 KiB
C
176 lines
4.3 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* directory.c
|
|
*
|
|
* Utility functions for dealing with directories.
|
|
*
|
|
* Copyright (c) Citus Data, Inc.
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
|
|
#include "postgres.h"
|
|
|
|
#include "funcapi.h"
|
|
#include "miscadmin.h"
|
|
|
|
#include "distributed/utils/directory.h"
|
|
|
|
|
|
/* Local functions forward declarations */
|
|
static bool FileIsLink(const char *filename, struct stat filestat);
|
|
|
|
|
|
/*
|
|
* CitusCreateDirectory creates a new directory with the given directory name.
|
|
*/
|
|
void
|
|
CitusCreateDirectory(StringInfo directoryName)
|
|
{
|
|
int makeOK = MakePGDirectory(directoryName->data);
|
|
if (makeOK != 0)
|
|
{
|
|
ereport(ERROR, (errcode_for_file_access(),
|
|
errmsg("could not create directory \"%s\": %m",
|
|
directoryName->data)));
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* FileIsLink checks whether a file is a symbolic link.
|
|
*/
|
|
static bool
|
|
FileIsLink(const char *filename, struct stat filestat)
|
|
{
|
|
return S_ISLNK(filestat.st_mode);
|
|
}
|
|
|
|
|
|
/*
|
|
* CitusRemoveDirectory first checks if the given directory exists. If it does, the
|
|
* function recursively deletes the contents of the given directory, and then
|
|
* deletes the directory itself. This function is modeled on the Boost file
|
|
* system library's remove_all() method.
|
|
*/
|
|
void
|
|
CitusRemoveDirectory(const char *filename)
|
|
{
|
|
/* files may be added during execution, loop when that occurs */
|
|
while (true)
|
|
{
|
|
struct stat fileStat;
|
|
int removed = 0;
|
|
|
|
int statOK = stat(filename, &fileStat);
|
|
if (statOK < 0)
|
|
{
|
|
if (errno == ENOENT)
|
|
{
|
|
return; /* if file does not exist, return */
|
|
}
|
|
else
|
|
{
|
|
ereport(ERROR, (errcode_for_file_access(),
|
|
errmsg("could not stat file \"%s\": %m", filename)));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If this is a directory, iterate over all its contents and for each
|
|
* content, recurse into this function. Also, make sure that we do not
|
|
* recurse into symbolic links.
|
|
*/
|
|
if (S_ISDIR(fileStat.st_mode) && !FileIsLink(filename, fileStat))
|
|
{
|
|
const char *directoryName = filename;
|
|
|
|
DIR *directory = AllocateDir(directoryName);
|
|
if (directory == NULL)
|
|
{
|
|
ereport(ERROR, (errcode_for_file_access(),
|
|
errmsg("could not open directory \"%s\": %m",
|
|
directoryName)));
|
|
}
|
|
|
|
StringInfo fullFilename = makeStringInfo();
|
|
struct dirent *directoryEntry = ReadDir(directory, directoryName);
|
|
for (; directoryEntry != NULL; directoryEntry = ReadDir(directory,
|
|
directoryName))
|
|
{
|
|
const char *baseFilename = directoryEntry->d_name;
|
|
|
|
/* if system file, skip it */
|
|
if (strncmp(baseFilename, ".", MAXPGPATH) == 0 ||
|
|
strncmp(baseFilename, "..", MAXPGPATH) == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
resetStringInfo(fullFilename);
|
|
appendStringInfo(fullFilename, "%s/%s", directoryName, baseFilename);
|
|
|
|
CitusRemoveDirectory(fullFilename->data);
|
|
}
|
|
|
|
pfree(fullFilename->data);
|
|
pfree(fullFilename);
|
|
FreeDir(directory);
|
|
}
|
|
|
|
/* we now have an empty directory or a regular file, remove it */
|
|
if (S_ISDIR(fileStat.st_mode))
|
|
{
|
|
/*
|
|
* We ignore the TOCTUO race condition static analysis warning
|
|
* here, since we don't actually read the files or directories. We
|
|
* simply want to remove them.
|
|
*/
|
|
removed = rmdir(filename); /* lgtm[cpp/toctou-race-condition] */
|
|
|
|
if (errno == ENOTEMPTY || errno == EEXIST)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* We ignore the TOCTUO race condition static analysis warning
|
|
* here, since we don't actually read the files or directories. We
|
|
* simply want to remove them.
|
|
*/
|
|
removed = unlink(filename); /* lgtm[cpp/toctou-race-condition] */
|
|
}
|
|
|
|
if (removed != 0 && errno != ENOENT)
|
|
{
|
|
ereport(ERROR, (errcode_for_file_access(),
|
|
errmsg("could not remove file \"%s\": %m", filename)));
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* CleanupJobCacheDirectory cleans up all files in the job cache directory
|
|
* as part of this process's start-up logic.
|
|
*/
|
|
void
|
|
CleanupJobCacheDirectory(void)
|
|
{
|
|
/* use the default tablespace in {datadir}/base */
|
|
StringInfo jobCacheDirectory = makeStringInfo();
|
|
appendStringInfo(jobCacheDirectory, "base/%s", PG_JOB_CACHE_DIR);
|
|
|
|
CitusRemoveDirectory(jobCacheDirectory->data);
|
|
CitusCreateDirectory(jobCacheDirectory);
|
|
|
|
pfree(jobCacheDirectory->data);
|
|
pfree(jobCacheDirectory);
|
|
}
|