Logo Search packages:      
Sourcecode: libjsw version File versions  Download package

disk.cpp

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>

#include "../include/os.h"

#ifdef __MSW__
# include <io.h>  /* Needed by _findfirst(), _findnext(), etc */
#else
# include <unistd.h>
# include <sys/time.h>
#endif

#include <sys/types.h>
#include <sys/stat.h>

#ifndef USE_GETDENTS
# ifndef __MSW__
# include <dirent.h>
# endif
#endif /* not USE_GETDENTS */

#if defined(__linux__)
# include <linux/limits.h>

# ifdef USE_GETDENTS
#  include <linux/dirent.h>   
# endif
#endif

#include "../include/fio.h"
#include "../include/string.h"
#include "../include/disk.h"

#ifdef MEMWATCH
# include "memwatch.h"
#endif


int FILEHASEXTENSION(const char *filename);
int ISPATHABSOLUTE(const char *path);
int NUMDIRCONTENTS(const char *path);

int COMPARE_PARENT_PATHS(const char *path, const char *parent);

int ISPATHDIR(const char *path);
int ISLPATHDIR(const char *path);
int ISPATHEXECUTABLE(const char *path);

int rmkdir(const char *path, mode_t mode);

char *PathSubHome(const char *path);
char **GetDirEntNames2(const char *parent, int *total);
char **GetDirEntNames(const char *parent);
char *ChangeDirRel(const char *cpath, const char *npath);
void StripAbsolutePath(char *path);
void StripParentPath(char *path, const char *parent);
char *PrefixPaths(const char *parent, const char *child);
char *GetAllocLinkDest(const char *link);
char *GetParentDir(const char *path);
void StripPath(char *path);
void SimplifyPath(char *path);

char *CompletePath(char *path, int *status);

int FileCountLines(const char *filename);
int DirHasSubDirs(const char *path);

int CopyObject(
      char *target, char *source,
      int (*comferm_func)(const char *, const char *)
);


#define MAX(a,b)        (((a) > (b)) ? (a) : (b))
#define MIN(a,b)        (((a) < (b)) ? (a) : (b))
#define CLIP(a,l,h)     (MIN(MAX((a),(l)),(h)))
#define STRISEMPTY(s)   (((s) != NULL) ? (*(s) == '\0') : 1)
#define STRLEN(s) (((s) != NULL) ? (int)strlen(s) : 0)
#define STRDUP(s)       (((s) != NULL) ? strdup(s) : NULL)


/*
 *    Checks if there is a '.' character in the file name.
 *
 *    Skips the very first '.' character if any.
 */
int FILEHASEXTENSION(const char *filename)
{
      if(STRISEMPTY(filename))
          return(0);

      filename++; /* Skip first char */
      if(strchr(filename, '.') == NULL)
          return(0);
      else
          return(1);
}

int ISPATHABSOLUTE(const char *path)
{
#ifdef __MSW__
      char *strptr;

      if(STRISEMPTY(path))
          return(0);

      /* Has drive notation? */
      strptr = strchr(path, ':');
      if(strptr == NULL)
      {
          /* No drive notation, check if first char is a '\\' */
#if defined(__cplusplus) || defined(c_plusplus)
          while(ISBLANK(*path))
#else
          while(ISBLANK((int)(*path)))
#endif
            path++;

          return(*path == '\\');
      }
      else
      {
          /* Has drive notation, check if first char past : is a '\\' */
          return((*(strptr + 1)) == '\\');
      }
#else
      if(path == NULL)
          return(0);

      // Dan S: typecast is due to const.
#if defined(__cplusplus) || defined(c_plusplus)
      while(ISBLANK(reinterpret_cast<char>(*path)))
#else
      while(ISBLANK(*path))
#endif
          path++;

      return(*path == DIR_DELIMINATOR);
#endif
}

/*
 *    Returns the number of entries in a dir.
 */
int NUMDIRCONTENTS(const char *path)
{
#ifdef __MSW__
      int i, total = 0;
      char **strv;
      const char *s;


      strv = GetDirEntNames(path);
      if(strv == NULL)
          return(total);

      for(i = 0; strv[i] != NULL; i++)
      {
          s = strv[i];

          /* Skip special notations */
          if(!strcmp(s, ".") || !strcmp(s, ".."))
          {
            free(strv[i]);
            continue;
          }

          total++;            /* Count this directory entry */

          free(strv[i]);
      }

      free(strv);

      return(total);
#else
      DIR *dir;
      int total = 0;
      const char *s;
      struct dirent *de;


      if(path == NULL)
          return(total);

      /* Open directory for obtaining list of entries */
      dir = opendir(path);
      if(dir == NULL)
          return(total);

      /* Begin iterating through each directory entry */
      while(1)
      {
          /* Get next directory entry */
          de = (struct dirent *)readdir(dir);
          if(de == NULL)
            break;

          /* Get pointer to directory entry name */
          s = de->d_name;

          /* Skip special notations */
          if(!strcmp(s, ".") || !strcmp(s, ".."))
            continue;

          total++;      /* Count this directory entry */
      }

      /* Close directory */
      closedir(dir);

      return(total);
#endif
}

/*
 *      Returns 1 if path has the parents of parent.
 *
 *      "/usr/X11/bin/xplay" "/usr/X11/bin"
 *      will return true. 
 *
 *      Spaces must be stripped from both!
 */
int COMPARE_PARENT_PATHS(const char *path, const char *parent)
{
      int   len_path = STRLEN(path),
            len_parent = STRLEN(parent);
      if((len_path <= 0) || (len_parent <= 0))
          return(0);

      /* Cannot compare if paths are not absolute */
      if(*path != DIR_DELIMINATOR)
          return(0);
      if(*parent != DIR_DELIMINATOR)
          return(0);

      /* Reduce length of parent for tailing DIR_DELIMINATOR chars */
      while(len_parent > 0)
      {   
          if(parent[len_parent - 1] == DIR_DELIMINATOR)
            len_parent--;
          else
            break;
      }

      /* Definately not if parent is longer then path */
      if(len_parent > len_path)
          return(0);

      /* Compare, but just to the length of the parent */
      if(strncmp(path, parent, len_parent))
          return(0);
      else
          return(1);
}

int ISPATHDIR(const char *path)
{
      struct stat stat_buf;


      if(STRISEMPTY(path))
          return(0);

      /* Check if path exists */
      if(stat(path, &stat_buf))
          return(0);

      return((S_ISDIR(stat_buf.st_mode)) ? 1 : 0);
}

int ISLPATHDIR(const char *path)
{
#ifdef __MSW__
      return(ISPATHDIR(path));
#else
      struct stat stat_buf;


      if(STRISEMPTY(path))
          return(0);

      /* Check if exists (do not follow links) */
      if(lstat(path, &stat_buf))
          return(0);

      return((S_ISDIR(stat_buf.st_mode)) ? 1 : 0);
#endif
}

int ISPATHEXECUTABLE(const char *path)
{
#ifdef __MSW__
      char *strptr;


      if(STRISEMPTY(path))
          return(0);

      strptr = strrchr(path, '.');
      if(strptr == NULL)
          return(0);
      else
          strptr++;

      /* Check known MSW extensions for being executeable */
      if(!strcasecmp(strptr, "exe"))
          return(1);
      else if(!strcasecmp(strptr, "bat"))
          return(1);
      else if(!strcasecmp(strptr, "com"))
          return(1);
      else
          return(0);
#else
      struct stat stat_buf;


      if(STRISEMPTY(path))
          return(0);

      /* Get stats */
      if(stat(path, &stat_buf))
          return(0);


      if((S_IXUSR & stat_buf.st_mode) |
         (S_IXGRP & stat_buf.st_mode) |
         (S_IXOTH & stat_buf.st_mode)
      )
          return(1);
      else
          return(0);
#endif
}

/*
 *    Creates the directory specified by path and any parent paths that
 *    do not exist.
 *
 *    Returns non-zero on error or 0 on success.
 */
int rmkdir(const char *path, mode_t m)
{
      char *s, *full_path;
      struct stat stat_buf;

      if(STRISEMPTY(path))
          return(-1);

      /* Need to get full absolute path */
      if(ISPATHABSOLUTE(path))
      {
          full_path = STRDUP(path);
      }
      else
      {
          char cwd[PATH_MAX];

          /* Not absolute path, so get current directory and prefix
           * it to the specified path
           */
          if(getcwd(cwd, sizeof(cwd)) != NULL)
            cwd[sizeof(cwd) - 1] = '\0';
          else
            return(-1);

          full_path = STRDUP(PrefixPaths(cwd, path));
      }
      if(full_path == NULL)
          return(-3);

      /* At this point, full_path is a copy of the completed path
       *
       * Next we will modify full_path by replacing each deliminator
       * with a null byte to check if the path compoent exists or not
       * so we know if we need to create it
       */

      /* Seek to start of full_path + 1 to skip the first deliminator */
      s = full_path + 1;
      while(s != NULL)
      {
          /* Seek to next deliminator and set it null temporarly to
           * check if the path compoent exists or not
           */
          s = strchr(s, DIR_DELIMINATOR);
          if(s != NULL)
            *s = '\0';

          if(stat(full_path, &stat_buf))
          {
#if defined(__MSW__)
            if(mkdir(full_path))
            {
                free(full_path);
                return(-1);
            }
#else
            if(mkdir(full_path, m))
            {
                free(full_path);
                return(-1);
            }
#endif
          }

          /* Set the pointer back to the deliminator and increment */
          if(s != NULL)
            *s++ = DIR_DELIMINATOR;
      }

      free(full_path);

      return(0);
}

/*
 *    Replaces any occurances of "~" in path with value of the
 *    HOME enviroment variable.
 *
 *    Returns a statically allocated string.
 */
char *PathSubHome(const char *path)
{
#ifdef __MSW__
      static char rtn_path[PATH_MAX];

      if(STRISEMPTY(path))
          return(NULL);

      strncpy(rtn_path, path, PATH_MAX);
      rtn_path[PATH_MAX - 1] = '\0';

      return(rtn_path);
#else
      static char rtn_path[PATH_MAX];


      if(STRISEMPTY(path))
          return(NULL);

      /* If the first character of the path is a '~' character then
       * we need to substitute it with the user's home directory.
       */
      if(*path == '~')
      {
          int m = PATH_MAX;
          const char *src = path + 1;
          const char *home = getenv("HOME");

          /* If no home dir defined then assume toplevel */
          if(home == NULL)
            home = "/";

          /* Reset return path */
          *rtn_path = '\0';

          /* Append home directory to return path */
          if(m > 0)
            strncat(rtn_path, home, m);

          /* Append source path to return path */
          m -= STRLEN(rtn_path);
          if(m > 0)
            strncat(rtn_path, src, m);

          rtn_path[PATH_MAX - 1] = '\0';
      }
      else
      {
          strncpy(rtn_path, path, PATH_MAX);
          rtn_path[PATH_MAX - 1] = '\0';
      }

      return(rtn_path);
#endif
}


/*
 *    Returns a pointer to an array of pointers to strings.
 *    Last pointer points to NULL.
 *
 *    Returns NULL on error.   All contents are dynamically
 *    allocated and MUST BE FREED by calling program.
 */
#ifdef USE_GETDENTS
char **GetDirEntNames2(const char *parent, int *total)
{
      int x, bytes_read, fd;

      struct dirent *dirp_origin;
      struct dirent *dirp_pos;
      char *dirp_raw;
      long dirp_memsize;
      long next_dirent;

      int total_dnames;
      char **dname;


      if(total != NULL)
          *total = 0;

      if(parent == NULL)
          return(NULL);

      /* Check if parent is a directory */
      if(!ISPATHDIR(parent))
          return(NULL);


      /* Open parent */
      fd = open(parent, O_RDONLY);
      if(fd < 0)
          return(NULL);


      /* Begin reading dirs */
      next_dirent = 0;
      total_dnames = 0;
      dname = NULL;
      dirp_origin = NULL;
      dirp_memsize = sizeof(struct dirent);
      while(1)
      {
          /* Reopen file descriptor */
          close(fd); fd = -1;
          fd = open(parent, O_RDONLY);
          if(fd < 0)
            break;

          /* Increment number of directory entry names gotten */
          total_dnames++;

          /* Allocate more directory entry name pointers */
          dname = (char **)realloc(dname, total_dnames * sizeof(char *));

          /* Allocate more dent pointers */
          dirp_origin = (struct dirent *)realloc(dirp_origin,
            dirp_memsize);
          /* Reset to prevent segfault */
          memset(dirp_origin, 0, dirp_memsize);

          /* Get more directory entries */
          bytes_read = getdents((unsigned int)fd, dirp_origin,
            dirp_memsize);
          if(bytes_read <= 0)
            break;

          /* Get raw FAT position pointer */
          dirp_raw = (char *)dirp_origin;
          dirp_pos = (struct dirent *)(&dirp_raw[next_dirent]);
          if(dirp_pos->d_reclen == 0)
            break;

          /* Get next dir entry position */
          next_dirent += dirp_pos->d_reclen;
          dirp_memsize += dirp_pos->d_reclen;   /* More memory needed */

          /* Allocate memory for new directory entry name */
          dname[total_dnames - 1] = (char *)calloc(
            1,
            (STRLEN(dirp_pos->d_name) + 1) * sizeof(char)
          );
          strcpy(dname[total_dnames - 1], dirp_pos->d_name);
      }

      /* Free dents pointer */
      free(dirp_origin); dirp_origin = NULL;

      /* Close the directory */
      if(fd > -1)
      {
          close(fd);
          fd = -1;
      }

      /* Last entry for directory entry names must be NULL */
      if(total_dnames > 0)
          dname[total_dnames - 1] = NULL;
      else
          dname[0] = NULL;

      /* Update total return */
      if(total != NULL)
          *total = total_dnames;

      return(dname);
}

#else /* USE_GETDENTS */

char **GetDirEntNames2(const char *parent, int *total)
{
#ifdef __MSW__
      long ffh;         /* Find file handle */
      struct _finddata_t d;   /* Find data return structure */
      char prev_cwd[PATH_MAX];


      if(total != NULL)
          *total = 0;

      /* Record previous current working dir */
      if(getcwd(prev_cwd, sizeof(prev_cwd)) != NULL)
          prev_cwd[sizeof(prev_cwd) - 1] = '\0';
      else
          *prev_cwd = '\0';

      /* Change to parent dir */
      if(parent != NULL)
          chdir(parent);

      /* Find first file in specified directory */
      ffh = _findfirst("*", &d);
      if(ffh == -1L)
      {
          chdir(prev_cwd);
          return(NULL);
      }
      else
      {
          /* Found first file in directory */
          int i = 0;
          char **rtn_names = (char **)malloc(sizeof(char *));


          if(rtn_names == NULL)
          {
            _findclose(ffh);
            chdir(prev_cwd);
            return(NULL);
          }

          rtn_names[i] = strdup(d.name);
          i++;

          /* Find additional (if any) files in directory */
          while(_findnext(ffh, &d) == 0)
          {
            rtn_names = (char **)realloc(rtn_names, (i + 1) * sizeof(char *));
            if(rtn_names == NULL)
            {
                _findclose(ffh);
                chdir(prev_cwd);
                return(NULL);
            }

            rtn_names[i] = strdup(d.name);
            i++;
          }

          /* Close find file handle and its resources */
          _findclose(ffh);
          chdir(prev_cwd);

          /* Allocate last pointer to be NULL */
          rtn_names = (char **)realloc(rtn_names, (i + 1) * sizeof(char *));
          if(rtn_names != NULL)
          {
            rtn_names[i] = NULL;
            if(total != NULL)
                *total = i;
          }

          return(rtn_names);
      }
#else
      int i;
      DIR *dir;
      struct dirent *de;
      char **rtn_names;


      if(total != NULL)
          *total = 0;

      if(parent == NULL)  
          return(NULL);

      /* Open directory for obtaining list of entries */
      dir = opendir(parent);
      if(dir == NULL)
          return(NULL);

      /* Begin iterating through each directory entry */
      rtn_names = NULL;
      for(i = 0; 1; i++)
      {
          /* Allocate more pointers in directory entry names array */
          rtn_names = (char **)realloc(
            rtn_names,
            (i + 1) * sizeof(char *)
          );
          if(rtn_names == NULL)
          {
            closedir(dir);
            return(NULL);
          }

          /* Get next directory entry */
          de = (struct dirent *)readdir(dir);

          /* End of directory entries? If so then break, leaving the
           * newly allocated pointer index undefined where it will be
           * set to NULL just outside the loop.
          */
          if(de == NULL)
            break;

          /* Copy directory entry name to directory names array */
          rtn_names[i] = strdup(de->d_name);
      }

      /* Close directory */
      closedir(dir);

      /* Set last entry to NULL */
      rtn_names[i] = NULL;

      /* Update total */
      if(total != NULL)
          *total = i;

      return(rtn_names);
#endif      /* NOT __MSW__ */
}
#endif /* USE_GETDENTS */


char **GetDirEntNames(const char *parent)
{
      return(GetDirEntNames2(parent, NULL));
}


/*
 *    Performs a `change directory' operation on the given path
 *    statements cpath and npath.
 *
 *    cpath is treated as your current directory and npath is
 *    treated as the operation.
 *
 *    Returns NULL on error or an allocated NULL terminated string on
 *    success.  The calling function must free the returned pointer.
 */
char *ChangeDirRel(const char *cpath, const char *npath)
{
      int len;
      char *rtn_str, *strptr;


      /* If both cpath and npath are NULL, return allocated cwd */
      if((cpath == NULL) &&
         (npath == NULL)
      )
      {           
          len = PATH_MAX;
          rtn_str = (char *)malloc((len + 1) * sizeof(char));
          if(rtn_str == NULL)
            return(NULL);

          if(getcwd(rtn_str, len) == NULL)
          {
            free(rtn_str);
            return(NULL);
          }
          else
          {
            rtn_str[len] = '\0';
            return(rtn_str);
          }
      }
      /* If only npath is NULL, return allocated cpath */
      if((cpath != NULL) && (npath == NULL))
      {
          len = STRLEN(cpath);
          rtn_str = (char *)malloc((len + 1) * sizeof(char));
          if(rtn_str == NULL)
            return(NULL);

          strncpy(rtn_str, cpath, len);
          rtn_str[len] = '\0';

          return(rtn_str);
      }
      /* If only cpath is NULL, return allocated cwd */
      if((npath != NULL) && (cpath == NULL))
      {
          len = PATH_MAX;
          rtn_str = (char *)malloc((len + 1) * sizeof(char));
          if(rtn_str == NULL)
            return(NULL);

          if(getcwd(rtn_str, len) == NULL)
          {
            free(rtn_str); 
            return(NULL);
          }
          else
          {
            rtn_str[len] = '\0';
            return(rtn_str);
          }
      }


      /* If cpath is not absolute, then return cwd */
      if(!ISPATHABSOLUTE(cpath))
      {
          len = PATH_MAX;
          rtn_str = (char *)malloc((len + 1) * sizeof(char));
          if(rtn_str == NULL)
            return(NULL);

          if(getcwd(rtn_str, len) == NULL)
          {
            free(rtn_str);
            return(NULL);
          }
          else
          {
            rtn_str[len] = '\0';
            return(rtn_str);
          }
      }

      /* If npath is ".", then just return cpath */
      if(!strcmp(npath, "."))
      {
          len = STRLEN(cpath);
          rtn_str = (char *)malloc((len + 1) * sizeof(char));
          if(rtn_str == NULL)
            return(NULL);

          strncpy(rtn_str, cpath, len);
          rtn_str[len] = '\0';

          return(rtn_str);
      }

      /* If npath is an absolute directory, then change to it */
      if(ISPATHABSOLUTE(npath))
      {
          len = STRLEN(npath);
          rtn_str = (char *)malloc((len + 1) * sizeof(char));
          if(rtn_str == NULL)
            return(NULL);

          strncpy(rtn_str, npath, len);
          rtn_str[len] = '\0';

          return(rtn_str);
      }


      /* npath is a relative notation */

      /* Prefix paths */
      strptr = PrefixPaths(cpath, npath);
      if(strptr == NULL)
          return(NULL);

      /* Allocate return string */
      len = STRLEN(strptr);
      rtn_str = (char *)malloc((len + 1) * sizeof(char));
      if(rtn_str == NULL)
          return(NULL);

      strncpy(rtn_str, strptr, len);
      rtn_str[len] = '\0';


      /* Simplify return path, this removes any "whatever/.."s */
      SimplifyPath(rtn_str);


      return(rtn_str);
}

/*
 *    Strips the pointed storage path of its absolute path,
 *    leaving it with just the final destination name.
 */
void StripAbsolutePath(char *path)
{
      char *strptr1, *strptr2;


      if(path == NULL)
          return;

      if((*path) != DIR_DELIMINATOR)
          return;

      strptr1 = path;

      /* Seek to end */
      while((*strptr1) != '\0')
          strptr1++;

      /* Seek back, skipping tailing DIR_DELIMINATOR chars */
      strptr1--;
      if(strptr1 < path)
          strptr1 = path;
      while((strptr1 > path) &&
            (*strptr1 == DIR_DELIMINATOR)
      )
          strptr1--;

      /* Seek back untill a DIR_DELIMINATOR char */
      if(strptr1 < path)
          strptr1 = path;
      while((strptr1 > path) &&
            ((*strptr1) != DIR_DELIMINATOR)
      )
          strptr1--;

      strptr1++;      /* Go forward one char */

      if(strptr1 < path)
          strptr1 = path;

      /* Copy child to beginning */
      strptr2 = path;
      while((*strptr1) != '\0')
      {
          (*strptr2) = (*strptr1);

          strptr1++;
          strptr2++;
      }
      (*strptr2) = '\0';

      /* Make sure path contains atleast DIR_DELIMINATOR */
      if((*path) == '\0')
      {
          path[0] = DIR_DELIMINATOR;
          path[1] = '\0';
      }

      return;
}

/*
 *    Checks if parent is under the specified path, if it
 *    is then it will be removed. Example:
 *
 *    path = "/var/spool/mail"
 *    parent = "/var"
 *
 *    Then path becomes "spool/mail"
 */
void StripParentPath(char *path, const char *parent)
{
      char *strptr;


      if((path == NULL) ||
         (parent == NULL)
      )
          return;

      /* Both given paths must be absolute */
      if(!ISPATHABSOLUTE(path) ||
         !ISPATHABSOLUTE(parent)
      )
          return;

      if(!COMPARE_PARENT_PATHS(path, parent))
          return;

      /* Remove parent from path */
      substr(path, parent, "");

      /* Need to remove any prefixing DIR_DELIMINATOR characters */
      while((*path) == DIR_DELIMINATOR)
      {
          strptr = path;
          while(*strptr != '\0')
            *strptr++ = *(strptr + 1);
      }

      /* If path is empty, it implies the parent and path were
       * the same.
       */
      if(*path == '\0')
          strcpy(path, parent);

      return;
}

/*
 *    Returns a statically allocated string containing the
 *    prefixed paths of the parent and child.
 *
 *    If child is absolute, then the statically allocated string
 *    will contain the child path.
 *
 *    The parent path must be absolute.
 */
char *PrefixPaths(const char *parent, const char *child)
{
      char *strptr1, *strend;
      const char *strptr2;
      static char rtn_path[PATH_MAX];


      if((parent == NULL) ||
         (child == NULL) ||
         (parent == child)
      )
          return("/");

      /* If child is absolute, copy child and return */
      if((*child) == DIR_DELIMINATOR)
      {
          strncpy(rtn_path, child, PATH_MAX);
          rtn_path[PATH_MAX - 1] = '\0';

          return(rtn_path);
      }

      /* Calculate strend */
      strend = rtn_path + PATH_MAX;


      /* Copy parent */
      strncpy(rtn_path, parent, PATH_MAX);
      rtn_path[PATH_MAX - 1] = '\0';

      /* Seek to end of rtn_path */
      strptr1 = rtn_path;
      while((*strptr1) != '\0')
          strptr1++;

      /* Insert deliminating DIR_DELIMINATOR char */
      if(strptr1 > rtn_path)
      {
          if(*(strptr1 - 1) != DIR_DELIMINATOR)
          {
            (*strptr1) = DIR_DELIMINATOR;
            strptr1++;
          }
      }
      else
      {
          strptr1 = rtn_path;
      }

      /* Copy child */
      strptr2 = child;
      while((strptr1 < strend) &&
            (*strptr2 != '\0')
      )
      {
          *strptr1 = *strptr2;

          strptr1++;
          strptr2++;
      }
      if(strptr1 < strend)
          *strptr1 = '\0';
      else
          rtn_path[PATH_MAX - 1] = '\0';

      /* Make sure rtn_path contains atleast "/" */
      if(*rtn_path == '\0')
      {
          rtn_path[0] = DIR_DELIMINATOR;
          rtn_path[1] = '\0';
      }

      return(rtn_path);
}


/*
 *    Returns an allocated string containing the link's destination
 *    or NULL on error or if link is not really a link.
 *
 *    The pointer returned must be free()ed at by the
 *    calling function.
 */
char *GetAllocLinkDest(const char *link)
{
#ifdef __MSW__
      return(NULL);
#else
      int bytes_read;
      char *dest;
      struct stat stat_buf;


      if(link == NULL)
          return(NULL);
      if(lstat(link, &stat_buf))
          return(NULL);
      if(!S_ISLNK(stat_buf.st_mode))
          return(NULL);

      /* Allocate dest buffer */
      dest = (char *)calloc(1, (PATH_MAX + NAME_MAX + 1) * sizeof(char));
      if(dest == NULL)
          return(NULL);

      /* Read link's destination */
      bytes_read = readlink(link, dest, PATH_MAX + NAME_MAX);
      if(bytes_read <= 0)
      {
          /* Empty dest buffer, return an allocated but empty string */
          dest[0] = '\0';
          return(dest);
      }

      if(bytes_read > PATH_MAX + NAME_MAX)
          bytes_read = PATH_MAX + NAME_MAX;
      if(bytes_read < 0)
          bytes_read = 0;

      /* Must NULL terminate */
      dest[bytes_read] = '\0';


      return(dest);
#endif      /* NOT __MSW__ */
}


/*
 *    Completes the path, reallocating it as needed.
 */
char *CompletePath(char *path, int *status)
{
      const char *cur_child;

      if(!ISPATHABSOLUTE(path))
      {
          if(status != NULL)
            *status = COMPLETE_PATH_NONE;
          return(NULL);
      }

      cur_child = strrchr(path, DIR_DELIMINATOR);
      if(cur_child != NULL)
          cur_child++;

      if(!STRISEMPTY(cur_child))
      {
          /* Get parent directory and listing of all child objects
           * to complete the path
           */
          int i, strc, matches = 0;
          char *name, **match = NULL;
          char **strv = GetDirEntNames2(GetParentDir(path), &strc);

          /* Get match list containing all object names that have
           * cur_child as their prefix and then delete the object
           * names list
           */
          for(i = 0; i < strc; i++)
          {
            name = strv[i];
            if(name == NULL)
                continue;

            if(!strcmp(name, ".") ||
               !strcmp(name, "..")
            )
            {
                free(name);
                continue;
            }

            if(strpfx(name, cur_child))
            {
                /* Append this name to the matches list */
                int n = matches;
                matches = n + 1;
                match = (char **)realloc(
                  match, matches * sizeof(char *)
                );
                match[n] = STRDUP(name);
            }

            free(name);
          }
          free(strv);

          /* Got one match? */
          if(matches == 1)
          {
            char *new_path = STRDUP(
                PrefixPaths(GetParentDir(path), match[0])
            );
            free(path);
            path = new_path;
            if(ISPATHDIR(path))
                path = strcatalloc(path, "/");
            if(status != NULL)
                *status = COMPLETE_PATH_SUCCESS;
          }
          /* Got multiple matches? */
          else if(matches > 1)
          {
            /* Iterate through multiple matches and get len to be
             * the number of the most common characters in all of
             * the matches
             */
            int n, k, len = 0;
            const char *ss, *st;
            for(i = 0; i < matches; i++)
            {
                ss = match[i];
                if(ss == NULL)
                  continue;

                for(n = 0; n < matches; n++)
                {
                  if(n == i)
                      continue;

                  st = match[n];
                  if(st == NULL)
                      continue;

                  /* Calculate the number of common characters
                   * k in both name strings
                   */
                  for(k = 0; ss[k] != '\0'; k++)
                  {
                      if(ss[k] != st[k])
                        break;
                  }

                  /* Record length if it is longer than the
                   * previous length
                   */
                  if((len > 0) ? (k < len) : 1)
                      len = k;
                }
            }

            /* Is the length of the common characters shorter than
             * or equal to the child's name?
             */
            if(len <= STRLEN(cur_child))
            {
                if(status != NULL)
                  *status = COMPLETE_PATH_AMBIGUOUS;
            }
            else
            {
                char    *new_path,
                        *new_child = STRDUP(match[0]);
                new_child[len] = '\0';
                new_path = STRDUP(
                  PrefixPaths(GetParentDir(path), new_child)
                );
                free(path);
                path = new_path;
                free(new_child);
                if(status != NULL)
                  *status = COMPLETE_PATH_PARTIAL;
            }
          }
          /* No matches */
          else
          {
            if(status != NULL) 
                *status = COMPLETE_PATH_NONE;
          }

          /* Delete matched names list */
          for(i = 0; i < matches; i++)
            free(match[i]);
          free(match);
      }
      else
      {
          /* Child name is empty so get listing of object names and
           * only set match if there is exactly one object
           */
          int i, strc, matches = 0;
          char *name, *match = NULL;
          char **strv = GetDirEntNames2(path, &strc);

          for(i = 0; i < strc; i++)
          {
            name = strv[i];
            if(name == NULL)
                continue;

            if(!strcmp(name, ".") ||  
               !strcmp(name, "..")
            )
            {
                free(name);
                continue;
            }

            if(match == NULL)
                match = STRDUP(name);
            matches++;

            free(name);
          }
          free(strv);

          /* Got one match? */
          if(matches == 1)
          {
            char *new_path = STRDUP(
                PrefixPaths(path, match)
            );
            free(path);
            path = new_path;
            if(ISPATHDIR(path))
                path = strcatalloc(path, "/");
            if(status != NULL)
                *status = COMPLETE_PATH_SUCCESS;
          }
          else
          {
            if(status != NULL)
                *status = COMPLETE_PATH_AMBIGUOUS;
          }

          /* Delete matched name */
          free(match);
      }

      return(path);
}


/*
 *    Returns the number of lines in the text file.
 */
int FileCountLines(const char *filename)
{
      int c, lines = 0;

      FILE *fp = FOpen(filename, "rb");
      if(fp == NULL)
          return(lines);

      /* Start counting lines */
      c = fgetc(fp);
      while(c != EOF)
      {
          if((c == '\n') || (c == '\r'))
            lines++;

          c = fgetc(fp);
      }

      FClose(fp);

      return(lines);
}


/*
 *    Returns true if the path is a directory and contains
 *    subdirectories, otherwise it returns false.
 *
 *    The given path must be an absolute path.
 */
int DirHasSubDirs(const char *path)
{
#ifdef __MSW__
      return(0);
#else
      int status = 0;
      const char *s, *name;
      struct dirent *dent;
      struct stat stat_buf;
      char child_path[PATH_MAX + NAME_MAX];

      /* Open directory */
      DIR *dir = !STRISEMPTY(path) ? opendir(path) : NULL;
      if(dir == NULL)
          return(status);

      /* Get first directory entry then iterate through rest (if any) */
      dent = readdir(dir);
      while(dent != NULL)
      {
#define NEXT_ENT_CONTINUE     {     \
 dent = readdir(dir);               \
 continue;                    \
}
          /* Get pointer to name of this directory entry */
          name = dent->d_name;

          /* Skip special notations */
          if(!strcmp(name, ".") ||
             !strcmp(name, "..")
          )
          {
            NEXT_ENT_CONTINUE
          }

          /* Get full path from current entry name */
          s = PrefixPaths(path, name);
          if(STRISEMPTY(s))
          {
            NEXT_ENT_CONTINUE
          }

          strncpy(child_path, s, sizeof(child_path));
          child_path[sizeof(child_path) - 1] = '\0';

          /* Does this object lead to a directory? */
          if(!stat(child_path, &stat_buf))
          {
            if(S_ISDIR(stat_buf.st_mode))
            {
                status = 1;
                break;
            }
          }

          NEXT_ENT_CONTINUE
#undef NEXT_ENT_CONTINUE
      }

      closedir(dir);

      return(status);
#endif      /* NOT __MSW__ */
}


/*
 *    Returns a statically allocated string containing the parent
 *    of the given absolute path.
 */
char *GetParentDir(const char *path)
{
      char *s;
      static char parent[PATH_MAX];

      if(path == NULL)
          return(NULL);

      strncpy(parent, path, sizeof(parent));
      parent[sizeof(parent) - 1] = '\0';

      /* Seek to last deliminator character (which may be a tailing
       * deliminator)
       */
      s = strrchr(parent, DIR_DELIMINATOR);
      if(s == NULL)
          return(parent);

      /* Strip tailing deliminators */
#ifdef __MSW__
      while(s >= (parent + 3))
#else
      while(s >= (parent + 1))
#endif
      {
          if(*(s + 1) != '\0')
            break;

          *s = '\0';
          s = strrchr(parent, DIR_DELIMINATOR);
      }

      /* Get parent */
#ifdef __MSW__
      if(s >= (parent + 3))
          *s = '\0';
      else
          parent[3] = '\0';
#else
      if(s >= (parent + 1))
          *s = '\0';
      else
          parent[1] = '\0';
#endif
      return(parent);
}


/*
 *    Strips tailing deliminator characters found in the given path.
 */
void StripPath(char *path)
{
      char *strptr;


      if(path == NULL)
          return;

      strptr = strrchr(path, DIR_DELIMINATOR);
      if(strptr != NULL)
      {
          while((*(strptr + 1) == '\0') &&
              (strptr > path)
          )
          {
            if(*strptr != DIR_DELIMINATOR)
                break;

            *strptr = '\0';
            strptr--;
          }
      }
}


/*
 *    Simplifies the given path by reducing any/all occurances of
 *    "/..".
 *
 *    The given path must be an absolute path.
 */
void SimplifyPath(char *path)
{
      char was_absolute_path;
      char *s;

      if(STRISEMPTY(path))
          return;

      was_absolute_path = ISPATHABSOLUTE(path);

      /* Seek to first path compoent */
      s = path;
      while(*s == DIR_DELIMINATOR)
          s++;

      while(*s != '\0')
      {
          /* This compoent is a parent directory notation? */
          if(strpfx(s, "../") || !strcmp(s, ".."))
          {
            /* Seek s2 to start of previous path compoent (if any) */
            char *s2 = s - 1;
            while((s2 >= path) ? (*s2 == DIR_DELIMINATOR) : 0)
                s2--;
            while((s2 >= path) ? (*s2 != DIR_DELIMINATOR) : 0)
                s2--;
            s2++;

            /* Seek s to next compoent */
            while((*s != '\0') && (*s != DIR_DELIMINATOR))
                s++;
            while(*s == DIR_DELIMINATOR)
                s++;

            if(s2 < s)
            {
                /* Shift s position to s2 position */
                char *s3 = s;
                while(*s3 != '\0')
                  *s2++ = *s3++;
                *s2 = *s3;
            }

            s = path;         /* Reset s position */
            while(*s == DIR_DELIMINATOR)
                s++;
          }
          /* This compoent is a current directory notation? */
          else if(strpfx(s, "./") || !strcmp(s, "."))
          {
            char *s2 = s;

            /* Seek s to next compoent */
            while((*s != '\0') && (*s != DIR_DELIMINATOR))
                s++;
            while(*s == DIR_DELIMINATOR)
                s++;

            if(s2 < s)
            {
                /* Shift s position to s2 position */
                char *s3 = s;
                while(*s3 != '\0')
                  *s2++ = *s3++;
                *s2 = *s3;
            }

            s = path;               /* Reset s position */
            while(*s == DIR_DELIMINATOR)
                s++;
          }
          else
          {
            /* Seek s to next compoent */
            while((*s != '\0') && (*s != DIR_DELIMINATOR))
                s++;
            while(*s == DIR_DELIMINATOR)
                s++;
          }
      }

      /* Strip tailing deliminators (s should already be at the
       * end of path)
       */
      while(s > (path + 1))
      {
          s--;
          if(*s == DIR_DELIMINATOR)
            *s = '\0';
          else
            break;
      }

      /* Restore absolute path as needed */
      if(was_absolute_path)
      {
          /* Resulted in empty string? */
          if(*path == '\0')
            strcpy(path, "/");
      }
}


/*
 *    Coppies object source to target.
 *
 *    If target exists and comferm_func is not NULL, then
 *    comferm_func will be called, given the target and
 *    source (respectivly) and return is checked.
 *
 *    Return of any true value from comferm_func will mean overwrite,
 *    and return of 0 from comferm_func will mean do not overwrite.
 */
int CopyObject(
      const char *target, const char *source,
      int (*comferm_func)(const char *, const char *)
)
{
      int c;
      FILE *tar_fp, *src_fp;
      struct stat stat_buf;


      if((target == NULL) || (source == NULL))
          return(-1);

      /* Check if target exists */
#ifdef __MSW__
      if(!stat(target, &stat_buf))
#else
      if(!lstat(target, &stat_buf))
#endif
      {
          if(comferm_func != NULL)
          {
            /* Overwrite? */
            if(!comferm_func(target, source))
                return(-3);   /* Don't! */
          }
      }


      /* Open target for writing and source for reading */
      tar_fp = FOpen(target, "wb");
      if(tar_fp == NULL)
          return(-1);

      src_fp = FOpen(source, "rb");
      if(src_fp == NULL)
      {
          FClose(tar_fp);
          return(-1);
      }

      /* Begin copying */
      c = fgetc(src_fp);
      while(c != EOF)
      {
          if(fputc(c, tar_fp) == EOF)
            break;

          c = fgetc(src_fp);
      }

      /* Close target and source */
      FClose(tar_fp);
      FClose(src_fp);

      return(0);
}





Generated by  Doxygen 1.6.0   Back to index