Logo Search packages:      
Sourcecode: yiff 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);

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 IS_STRING_EMPTY(s)      (((s) != NULL) ? ((s) == '\0') : 1)

#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(IS_STRING_EMPTY(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(IS_STRING_EMPTY(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 *cstrptr;


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

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

          /* Skip this entry if it is a special notation. */
          if(!strcmp(cstrptr, ".") ||
             !strcmp(cstrptr, "..")
          )
          {
            free(strv[i]);
            continue;
          }

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

          free(strv[i]);
      }

      free(strv);

      return(total);
#else
      DIR *dir;
      int total = 0;
      const char *cstrptr;
      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. */
          cstrptr = de->d_name;
          if(cstrptr != NULL)
          {
            /* Not a special directory notation? */
            if(strcmp(cstrptr, ".") && strcmp(cstrptr, ".."))
                total++;
          }
      }

      /* 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, len_parent;


      if(IS_STRING_EMPTY(path) || IS_STRING_EMPTY(parent))
          return(0);
  
      len_path = strlen(path);
      len_parent = strlen(parent);
          
      /* Cannot compare if path is 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_path < len_parent)
          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(IS_STRING_EMPTY(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(IS_STRING_EMPTY(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(IS_STRING_EMPTY(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(IS_STRING_EMPTY(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 -1 on error, or 0 on success.
 */
int rmkdir(const char *path, mode_t m)
{
      char *strptr;
      struct stat stat_buf;
      char fullpath[PATH_MAX + NAME_MAX];


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


      /* Need to get full absolute path. */
      if(ISPATHABSOLUTE(path))
      {
          strncpy(fullpath, path, PATH_MAX + NAME_MAX);
      }
      else
      {
          char cwd[PATH_MAX];

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

          strptr = PrefixPaths(cwd, path);
          strncpy(
            fullpath,
            ((strptr == NULL) ? path : strptr),
            PATH_MAX + NAME_MAX
          );
      }
      fullpath[PATH_MAX + NAME_MAX - 1] = '\0';

      /* Full path has now been coppied to our local variable fullpath.
       * Next we will modify the fullpath variable by replacing each
       * encountered DIR_DELIMINATOR to check if the path exists
       * and if not, create it.
       */


      /* Get pointer to beginning of fullpath but skip
       * first character since it's a DIR_DELIMINATOR.
       */
      strptr = fullpath + 1;
      while(strptr != NULL)
      {
          /* Seek to next deliminator, updating strptr. If there
           * are no more deliminators then strptr will be NULL.
           */
          strptr = strchr(strptr, DIR_DELIMINATOR);
          if(strptr != NULL)
            *strptr = '\0';

          if(stat(fullpath, &stat_buf))
          {
#ifdef __MSW__
            if(mkdir(fullpath))
                return(-1);
#else
            if(mkdir(fullpath, m))
                return(-1);
#endif
          }

          /* If pointer to next deliminator is valid then reset it
           * back to DIR_DELIMINATOR and increment strptr.
           */
          if(strptr != NULL)
            *strptr++ = DIR_DELIMINATOR;
      }

      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(IS_STRING_EMPTY(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(IS_STRING_EMPTY(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. */
      getcwd(prev_cwd, PATH_MAX);
      prev_cwd[PATH_MAX - 1] = '\0';

      /* Change to parent dir. */
      chdir(parent);

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


          if(rtn_names == NULL)
          {
            _findclose(ffh);
            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);
                return(NULL);
            }

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

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

          /* 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__ */
}


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


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


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

          i = fgetc(fp);
      }

      /* Close file. */
      FClose(fp);


      return(lines);
}


/*
 *    Returns 1 if path is a dir and contains sub dirs.
 *
 *    The given path must be an absolute path.
 */
int DirHasSubDirs(const char *path)
{
#ifdef __MSW__
      return(0);
#else
      const char *cstrptr, *ent_name;
      DIR *dir;
      struct dirent *dent;
      char tmp_path[PATH_MAX + NAME_MAX];
      int status = 0;


      /* Error checks. */
      if(path == NULL)
          return(status);

      /* Open dir. */
      dir = opendir(path);
      if(dir == NULL)
          return(status);

      /* Get first directory entry then itterate through rest (if any). */
      dent = readdir(dir);
      while(dent != NULL)
      {
          /* Get pointer to name of this directory entry. */
          ent_name = dent->d_name;

          /* Skip special dir notations. */
          if(!strcmp(ent_name, ".") ||
             !strcmp(ent_name, "..")
          )
          {
            dent = readdir(dir);    /* Get next dir entry. */
            continue;
          }

          /* Generate full path from current directory entry name. */
          cstrptr = PrefixPaths(path, ent_name);
          if(cstrptr == NULL)
          {
            dent = readdir(dir);    /* Get next dir entry. */
            continue;
          }
          else
          {
            strncpy(tmp_path, cstrptr, PATH_MAX + NAME_MAX);
            tmp_path[PATH_MAX + NAME_MAX - 1] = '\0';
          }

          /* stat() this object to see if its destination goes to a
           * directory.
           */
          if(ISPATHDIR(tmp_path))
          {
            status = 1;
            break;
          }

          dent = readdir(dir);      /* Get next dir entry. */
      }

      /* Close dir. */
      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);

      /* Copy given path to return parent path */
      strncpy(parent, path, PATH_MAX);
      parent[PATH_MAX - 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 *strptr1, *strptr2, *strptr3;


      if(path == NULL)
          return;

      /* Look for a "/..". */
      strptr1 = strstr(path, "/..");
      while(strptr1 != NULL)
      {
          /* Seek next DIR_DELIMINATOR char or end. */
          strptr2 = strptr1 + 1;
          while((*strptr2 != '\0') &&
              (*strptr2 != DIR_DELIMINATOR)
          )
            strptr2++;

          /* Seek prev DIR_DELIMINATOR char or start. */
          strptr3 = strptr1 - 1;
          while((strptr3 > path) &&
              (*strptr3 != DIR_DELIMINATOR)
          )
            strptr3--;

          if(strptr3 < path)
            strptr3 = path;

          /* Copy segment. */
          while(*strptr2 != '\0')
          {
            *strptr3 = *strptr2;

            strptr2++;   
            strptr3++;
          }
          *strptr3 = '\0';

          /* Look for another "/.." if any. */
          strptr1 = strstr(path, "/..");
      }

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


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