/*
* Copyright 2001-2004 Brandon Long
* All Rights Reserved.
*
* ClearSilver Templating System
*
* This code is made available under the terms of the ClearSilver License.
* http://www.clearsilver.net/license.hdf
*
*/
#include "cs_config.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include <dirent.h>
#include <sys/stat.h>
#include "neo_misc.h"
#include "neo_err.h"
#include "neo_files.h"
#include "wildmat.h"
NEOERR *ne_mkdirs (const char *path, mode_t mode)
{
char mypath[_POSIX_PATH_MAX];
int x;
int r;
strncpy (mypath, path, sizeof(mypath));
x = strlen(mypath);
if ((x < sizeof(mypath)) && (mypath[x-1] != '/'))
{
mypath[x] = '/';
mypath[x+1] = '\0';
}
for (x = 1; mypath[x]; x++)
{
if (mypath[x] == '/')
{
mypath[x] = '\0';
#ifdef __MINGW32__
/* Braindead MINGW32 doesn't just have a dummy argument for mode */
r = mkdir (mypath);
#else
r = mkdir (mypath, mode);
#endif
if (r == -1 && errno != EEXIST)
{
return nerr_raise_errno(NERR_SYSTEM, "ne_mkdirs: mkdir(%s, %x) failed", mypath, mode);
}
mypath[x] = '/';
}
}
return STATUS_OK;
}
NEOERR *ne_load_file_len (const char *path, char **str, int *out_len)
{
struct stat s;
int fd;
int len;
int bytes_read;
*str = NULL;
if (out_len) *out_len = 0;
if (stat(path, &s) == -1)
{
if (errno == ENOENT)
return nerr_raise (NERR_NOT_FOUND, "File %s not found", path);
return nerr_raise_errno (NERR_SYSTEM, "Unable to stat file %s", path);
}
fd = open (path, O_RDONLY);
if (fd == -1)
{
return nerr_raise_errno (NERR_SYSTEM, "Unable to open file %s", path);
}
len = s.st_size;
*str = (char *) malloc (len + 1);
if (*str == NULL)
{
close(fd);
return nerr_raise (NERR_NOMEM,
"Unable to allocate memory (%d) to load file %s", len + 1, path);
}
if ((bytes_read = read (fd, *str, len)) == -1)
{
close(fd);
free(*str);
return nerr_raise_errno (NERR_SYSTEM, "Unable to read file %s", path);
}
(*str)[bytes_read] = '\0';
close(fd);
if (out_len) *out_len = bytes_read;
return STATUS_OK;
}
NEOERR *ne_load_file (const char *path, char **str) {
return ne_load_file_len (path, str, NULL);
}
NEOERR *ne_save_file (const char *path, char *str)
{
NEOERR *err;
int fd;
int w, l;
fd = open (path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP );
if (fd == -1)
{
return nerr_raise_errno (NERR_IO, "Unable to create file %s", path);
}
l = strlen(str);
w = write (fd, str, l);
if (w != l)
{
err = nerr_raise_errno (NERR_IO, "Unable to write file %s", path);
close (fd);
return err;
}
close (fd);
return STATUS_OK;
}
NEOERR *ne_remove_dir (const char *path)
{
NEOERR *err;
DIR *dp;
struct stat s;
struct dirent *de;
char npath[_POSIX_PATH_MAX];
if (stat(path, &s) == -1)
{
if (errno == ENOENT) return STATUS_OK;
return nerr_raise_errno (NERR_SYSTEM, "Unable to stat file %s", path);
}
if (!S_ISDIR(s.st_mode))
{
return nerr_raise (NERR_ASSERT, "Path %s is not a directory", path);
}
dp = opendir(path);
if (dp == NULL)
return nerr_raise_errno (NERR_IO, "Unable to open directory %s", path);
while ((de = readdir (dp)) != NULL)
{
if (strcmp(de->d_name, ".") && strcmp(de->d_name, ".."))
{
snprintf (npath, sizeof(npath), "%s/%s", path, de->d_name);
if (stat(npath, &s) == -1)
{
if (errno == ENOENT) continue;
closedir(dp);
return nerr_raise_errno (NERR_SYSTEM, "Unable to stat file %s", npath);
}
if (S_ISDIR(s.st_mode))
{
err = ne_remove_dir(npath);
if (err) break;
}
else
{
if (unlink(npath) == -1)
{
if (errno == ENOENT) continue;
closedir(dp);
return nerr_raise_errno (NERR_SYSTEM, "Unable to unlink file %s",
npath);
}
}
}
}
closedir(dp);
if (rmdir(path) == -1)
{
return nerr_raise_errno (NERR_SYSTEM, "Unable to rmdir %s", path);
}
return STATUS_OK;
}
NEOERR *ne_listdir(const char *path, ULIST **files)
{
return nerr_pass(ne_listdir_fmatch(path, files, NULL, NULL));
}
static int _glob_match(void *rock, const char *filename)
{
return wildmat(filename, rock);
}
NEOERR *ne_listdir_match(const char *path, ULIST **files, const char *match)
{
return nerr_pass(ne_listdir_fmatch(path, files, _glob_match, (void *)match));
}
NEOERR *ne_listdir_fmatch(const char *path, ULIST **files, MATCH_FUNC fmatch,
void *rock)
{
DIR *dp;
struct dirent *de;
ULIST *myfiles = NULL;
NEOERR *err = STATUS_OK;
if (files == NULL)
return nerr_raise(NERR_ASSERT, "Invalid call to ne_listdir_fmatch");
if (*files == NULL)
{
err = uListInit(&myfiles, 10, 0);
if (err) return nerr_pass(err);
}
else
{
myfiles = *files;
}
if ((dp = opendir (path)) == NULL)
{
return nerr_raise_errno(NERR_IO, "Unable to opendir %s", path);
}
while ((de = readdir (dp)) != NULL)
{
if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
continue;
if (fmatch != NULL && !fmatch(rock, de->d_name))
continue;
err = uListAppend(myfiles, strdup(de->d_name));
if (err) break;
}
closedir(dp);
if (err && *files == NULL)
{
uListDestroy(&myfiles, ULIST_FREE);
}
else if (*files == NULL)
{
*files = myfiles;
}
return nerr_pass(err);
}