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"


#if defined(WIN32)
      #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>

#if !defined(USE_GETDENTS) && !defined(WIN32)
      #include <dirent.h>
#endif

#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(
      const char *target, const char *source,
      int (*confirm_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);
}

/*
 *    Checks if the specified path is an absolute path.
 */
int ISPATHABSOLUTE(const char *path)
{
#if defined(WIN32)
      if( path == NULL )
            return(0);

      /* Has "X:" drive notation? */
      if( (path[0] != '\0') ? (path[1] == ':') : 0 )
      {
            /* Has drive notation, check if first char past the drive
             * notation is a DIR_DELIMINATOR
             */
            return(path[2] == DIR_DELIMINATOR);
      } else
      {
            /* No drive notation, check if first char is a '\\' */
            while( ISBLANK(*path) )
                  path++;
            return(*path == DIR_DELIMINATOR);
      }
#else
      if( path == NULL )
            return(0);

      while( ISBLANK(*path) )
            path++;

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

/*
 *    Returns the number of entries in a dir.
 */
int NUMDIRCONTENTS(const char *path)
{
#if defined(WIN32)
      int i, total = 0;
      const char *s;
      char **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 = 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)
{
#if defined(WIN32)
      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)
{
#if defined(WIN32)
      char *s;

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

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

      /* Check known MSW extensions for being executeable */
      if( !strcasecmp(s, "exe") )
            return(1);
      else if( !strcasecmp(s, "bat") )
            return(1);
      else if( !strcasecmp(s, "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) )
            {
#ifdef WIN32
                  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)
{
#if defined(WIN32)
      static char rtn_path[PATH_MAX];

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

      strncpy(rtn_path, path, sizeof(rtn_path));
      rtn_path[sizeof(rtn_path) - 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 == '~' )
      {
            size_t m = sizeof(rtn_path);
            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[sizeof(rtn_path) - 1] = '\0';
      } else
      {
            strncpy(rtn_path, path, sizeof(rtn_path));
            rtn_path[sizeof(rtn_path) - 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)
{
#if defined(WIN32)
      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 WIN32 */
}
#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, *s;


      /* 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 */
      s = PrefixPaths(cpath, npath);
      if( s == NULL )
            return(NULL);

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

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


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


      return(rtn_str);
}

/*
 *    Strips the specified absolute path of its absolute path,
 *    leaving it with just the final destination name.
 */
void StripAbsolutePath(char *path)
{
      char *s1, *s2;

      if( path == NULL )
            return;

      if( *path != DIR_DELIMINATOR )
            return;

      s1 = path;

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

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

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

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

      if( s1 < path )
            s1 = path;

      /* Copy child to beginning */
      s2 = path;
      while( *s1 != '\0' )
            *s2++ = *s1++;
      *s2 = '\0';

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

/*
 *    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 *s;

      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 )
      {
            s = path;
            while(*s != '\0')
            {
                  *s = *(s + 1);
                  ++s;
            }
      }

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

/*
 *    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 *s, *s_end;
      const char *s2;
      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, sizeof(rtn_path));
            rtn_path[sizeof(rtn_path) - 1] = '\0';
            return(rtn_path);
      }

      /* Get the end of rtn_path */
      s_end = rtn_path + sizeof(rtn_path);

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

      /* Seek s to end of parent path in rtn_path */
      s = rtn_path;
      while( *s != '\0' )
            s++;

      /* Insert deliminator to rtn_path */
      if( s > rtn_path )
      {
            /* Does the parent portion of rtn_path does not already
             * have a tailing deliminator?
             */
            if( *(s - 1) != DIR_DELIMINATOR )
            {
                  *s++ = DIR_DELIMINATOR;
            }
      } else
      {
            s = rtn_path;
      }

      /* Copy child */
      s2 = child;
      while( (s < s_end) && (*s2 != '\0') )
            *s++ = *s2++;
      if( s < s_end )
            *s = '\0';
      else
            rtn_path[sizeof(rtn_path) - 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)
{
#if defined(WIN32)
      return(NULL);
#else
      int bytes_read;
      char *dest;
      struct stat lstat_buf;

      if( link == NULL )
            return(NULL);
      if( lstat(link, &lstat_buf) )
            return(NULL);
#ifdef S_ISLNK
      if( !S_ISLNK(lstat_buf.st_mode) )
            return(NULL);
#endif

      /* Allocate link destination 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;

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

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


/*
 *    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, **matches_list = 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;
                        matches_list = (char **)realloc(
                              matches_list,
                              matches * sizeof(char *)
                        );
                        matches_list[n] = STRDUP(name);
                  }

                  free(name);
            }
            free(strv);

            /* Got exactly one match? */
            if( matches == 1 )
            {
                  char *new_path = STRDUP(PrefixPaths(
                        GetParentDir(path),
                        matches_list[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 = matches_list[i];
                        if( ss == NULL )
                              continue;

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

                              st = matches_list[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(matches_list[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 the matched names list */
            for( i = 0; i < matches; i++ )
                  free(matches_list[i]);
            free(matches_list);
      } 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 exactly 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 the 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)
{
#if defined(WIN32)
      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 WIN32 */
}


/*
 *    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 WIN32
      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 WIN32
      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 *s;


      if( path == NULL )
            return;

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

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


/*
 *    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 s to first path compoent */
      for( s = path; *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 confirm_func is not NULL, then
 *    confirm_func will be called, given the target and
 *    source (respectivly) and return is checked.
 *
 *    Return of any true value from confirm_func will mean overwrite,
 *    and return of 0 from confirm_func will mean do not overwrite.
 */
int CopyObject(
      const char *target, const char *source,
      int (*confirm_func)(const char *, const char *)
)
{
      size_t blksize;
      FILE *tar_fp, *src_fp;
      struct stat stat_buf;

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

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

      /* 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);
      }

      /* Get block size of the source */
      if(fstat(fileno(src_fp), &stat_buf))
          blksize = 0l;
      else
          blksize = stat_buf.st_blksize;
      if(blksize > 0l)
      {
          /* Copy block by block */
          void *buf = malloc(blksize * sizeof(char));
          if(buf != NULL)
          {
            size_t len = fread(buf, sizeof(char), blksize, src_fp);
            while(len > 0)
            {
                if(fwrite(buf, sizeof(char), len, tar_fp) < len)
                  break;

                len = fread(buf, sizeof(char), blksize, src_fp);
            }
            free(buf);
          }
      }
      else
      {
          /* Block size not specified, copy byte by byte instead */
          int 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