Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright 2001-2004 Brandon Long
      3  * All Rights Reserved.
      4  *
      5  * ClearSilver Templating System
      6  *
      7  * This code is made available under the terms of the ClearSilver License.
      8  * http://www.clearsilver.net/license.hdf
      9  *
     10  */
     11 
     12 #include "cs_config.h"
     13 
     14 #include <stdio.h>
     15 #include <stdlib.h>
     16 #include <sys/types.h>
     17 #include <fcntl.h>
     18 #include <string.h>
     19 #include <unistd.h>
     20 #include <errno.h>
     21 #include <limits.h>
     22 #include <dirent.h>
     23 #include <sys/stat.h>
     24 
     25 #include "neo_misc.h"
     26 #include "neo_err.h"
     27 #include "neo_files.h"
     28 #include "wildmat.h"
     29 
     30 NEOERR *ne_mkdirs (const char *path, mode_t mode)
     31 {
     32   char mypath[_POSIX_PATH_MAX];
     33   int x;
     34   int r;
     35 
     36   strncpy (mypath, path, sizeof(mypath));
     37   x = strlen(mypath);
     38   if ((x < sizeof(mypath)) && (mypath[x-1] != '/'))
     39   {
     40     mypath[x] = '/';
     41     mypath[x+1] = '\0';
     42   }
     43 
     44   for (x = 1; mypath[x]; x++)
     45   {
     46     if (mypath[x] == '/')
     47     {
     48       mypath[x] = '\0';
     49 #ifdef __MINGW32__
     50       /* Braindead MINGW32 doesn't just have a dummy argument for mode */
     51       r = mkdir (mypath);
     52 #else
     53       r = mkdir (mypath, mode);
     54 #endif
     55 
     56       if (r == -1 && errno != EEXIST)
     57       {
     58 	return nerr_raise_errno(NERR_SYSTEM, "ne_mkdirs: mkdir(%s, %x) failed", mypath, mode);
     59       }
     60       mypath[x] = '/';
     61     }
     62   }
     63   return STATUS_OK;
     64 }
     65 
     66 NEOERR *ne_load_file_len (const char *path, char **str, int *out_len)
     67 {
     68   struct stat s;
     69   int fd;
     70   int len;
     71   int bytes_read;
     72 
     73   *str = NULL;
     74   if (out_len) *out_len = 0;
     75 
     76   if (stat(path, &s) == -1)
     77   {
     78     if (errno == ENOENT)
     79       return nerr_raise (NERR_NOT_FOUND, "File %s not found", path);
     80     return nerr_raise_errno (NERR_SYSTEM, "Unable to stat file %s", path);
     81   }
     82 
     83   fd = open (path, O_RDONLY);
     84   if (fd == -1)
     85   {
     86     return nerr_raise_errno (NERR_SYSTEM, "Unable to open file %s", path);
     87   }
     88   len = s.st_size;
     89   *str = (char *) malloc (len + 1);
     90 
     91   if (*str == NULL)
     92   {
     93     close(fd);
     94     return nerr_raise (NERR_NOMEM,
     95 	"Unable to allocate memory (%d) to load file %s", len + 1, path);
     96   }
     97   if ((bytes_read = read (fd, *str, len)) == -1)
     98   {
     99     close(fd);
    100     free(*str);
    101     return nerr_raise_errno (NERR_SYSTEM, "Unable to read file %s", path);
    102   }
    103 
    104   (*str)[bytes_read] = '\0';
    105   close(fd);
    106   if (out_len) *out_len = bytes_read;
    107 
    108   return STATUS_OK;
    109 }
    110 
    111 NEOERR *ne_load_file (const char *path, char **str) {
    112   return ne_load_file_len (path, str, NULL);
    113 }
    114 
    115 NEOERR *ne_save_file (const char *path, char *str)
    116 {
    117   NEOERR *err;
    118   int fd;
    119   int w, l;
    120 
    121   fd = open (path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP );
    122   if (fd == -1)
    123   {
    124     return nerr_raise_errno (NERR_IO, "Unable to create file %s", path);
    125   }
    126   l = strlen(str);
    127   w = write (fd, str, l);
    128   if (w != l)
    129   {
    130     err = nerr_raise_errno (NERR_IO, "Unable to write file %s", path);
    131     close (fd);
    132     return err;
    133   }
    134   close (fd);
    135 
    136   return STATUS_OK;
    137 }
    138 
    139 NEOERR *ne_remove_dir (const char *path)
    140 {
    141   NEOERR *err;
    142   DIR *dp;
    143   struct stat s;
    144   struct dirent *de;
    145   char npath[_POSIX_PATH_MAX];
    146 
    147   if (stat(path, &s) == -1)
    148   {
    149     if (errno == ENOENT) return STATUS_OK;
    150     return nerr_raise_errno (NERR_SYSTEM, "Unable to stat file %s", path);
    151   }
    152   if (!S_ISDIR(s.st_mode))
    153   {
    154     return nerr_raise (NERR_ASSERT, "Path %s is not a directory", path);
    155   }
    156   dp = opendir(path);
    157   if (dp == NULL)
    158     return nerr_raise_errno (NERR_IO, "Unable to open directory %s", path);
    159   while ((de = readdir (dp)) != NULL)
    160   {
    161     if (strcmp(de->d_name, ".") && strcmp(de->d_name, ".."))
    162     {
    163       snprintf (npath, sizeof(npath), "%s/%s", path, de->d_name);
    164       if (stat(npath, &s) == -1)
    165       {
    166 	if (errno == ENOENT) continue;
    167 	closedir(dp);
    168 	return nerr_raise_errno (NERR_SYSTEM, "Unable to stat file %s", npath);
    169       }
    170       if (S_ISDIR(s.st_mode))
    171       {
    172 	err = ne_remove_dir(npath);
    173 	if (err) break;
    174       }
    175       else
    176       {
    177 	if (unlink(npath) == -1)
    178 	{
    179 	  if (errno == ENOENT) continue;
    180 	  closedir(dp);
    181 	  return nerr_raise_errno (NERR_SYSTEM, "Unable to unlink file %s",
    182 	      npath);
    183 	}
    184       }
    185     }
    186   }
    187   closedir(dp);
    188   if (rmdir(path) == -1)
    189   {
    190     return nerr_raise_errno (NERR_SYSTEM, "Unable to rmdir %s", path);
    191   }
    192   return STATUS_OK;
    193 }
    194 
    195 NEOERR *ne_listdir(const char *path, ULIST **files)
    196 {
    197   return nerr_pass(ne_listdir_fmatch(path, files, NULL, NULL));
    198 }
    199 
    200 static int _glob_match(void *rock, const char *filename)
    201 {
    202   return wildmat(filename, rock);
    203 }
    204 
    205 NEOERR *ne_listdir_match(const char *path, ULIST **files, const char *match)
    206 {
    207   return nerr_pass(ne_listdir_fmatch(path, files, _glob_match, (void *)match));
    208 }
    209 
    210 NEOERR *ne_listdir_fmatch(const char *path, ULIST **files, MATCH_FUNC fmatch,
    211                           void *rock)
    212 {
    213   DIR *dp;
    214   struct dirent *de;
    215   ULIST *myfiles = NULL;
    216   NEOERR *err = STATUS_OK;
    217 
    218   if (files == NULL)
    219     return nerr_raise(NERR_ASSERT, "Invalid call to ne_listdir_fmatch");
    220 
    221   if (*files == NULL)
    222   {
    223     err = uListInit(&myfiles, 10, 0);
    224     if (err) return nerr_pass(err);
    225   }
    226   else
    227   {
    228     myfiles = *files;
    229   }
    230 
    231   if ((dp = opendir (path)) == NULL)
    232   {
    233     return nerr_raise_errno(NERR_IO, "Unable to opendir %s", path);
    234   }
    235   while ((de = readdir (dp)) != NULL)
    236   {
    237     if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
    238       continue;
    239 
    240     if (fmatch != NULL && !fmatch(rock, de->d_name))
    241       continue;
    242 
    243     err = uListAppend(myfiles, strdup(de->d_name));
    244     if (err) break;
    245   }
    246   closedir(dp);
    247   if (err && *files == NULL)
    248   {
    249     uListDestroy(&myfiles, ULIST_FREE);
    250   }
    251   else if (*files == NULL)
    252   {
    253     *files = myfiles;
    254   }
    255   return nerr_pass(err);
    256 }
    257