/* Disk and Directory Handling int FILEHASEXTENSION(char *filename) int ISPATHABSOLUTE(char *path) int NUMDIRCONTENTS(char *path) int COMPARE_PARENT_PATHS(char *path, char *parent) int ISPATHDIR(char *path) int ISLPATHDIR(char *path) int ISPATHEXECUTABLE(char *path) char *PathSubHome(char *path) char **GetDirEntNames(char *parent) char *ChangeDirRel(char *cpath, char *npath) void StripAbsolutePath(char *path) char *PrefixPaths(char *parent, char *child) char *GetAllocLinkDest(char *link) char *GetParentDir(char *path) void SimplifyPath(char *path) int FileCountLines(char *filename) int DirHasSubDirs(char *path) int CopyObject( char *target, char *source, int (*comferm_func)(char *, char *) ) */ #include #include #include #include #include #include #include extern int errno; #include #include #include #include #ifndef USE_GETDENTS # include #endif /* not USE_GETDENTS */ #if defined(__linux__) # include # ifdef USE_GETDENTS # include # endif #endif #include "../include/os.h" #include "../include/string.h" #include "../include/disk.h" int FILEHASEXTENSION(char *filename) { char *strptr; if(filename == NULL) return(0); strptr = filename; strptr += 1; /* Skip first char. */ if(strchr(strptr, '.') == NULL) return(0); else return(1); } int ISPATHABSOLUTE(char *path) { if(path == NULL) return(0); while(isblank(*path)) path++; /* First non space character a '/' character? */ return(*path == '/'); } /* * Returns the number of entries in a dir. */ int NUMDIRCONTENTS(char *path) { int i, items; char **dname; if(path == NULL) return(0); if(!ISPATHDIR(path)) return(0); dname = GetDirEntNames(path); if(dname == NULL) return(0); items = 0; for(i = 0; dname[i] != NULL; i++) { if(dname[i] == NULL) continue; /* Skip this and parent notation entries. */ if(!strcmp(dname[i], ".") || !strcmp(dname[i], "..") ) { /* Free the name. */ free(dname[i]); dname[i] = NULL; continue; } /* Increment count. */ items++; /* Free the name. */ free(dname[i]); dname[i] = NULL; } free(dname); dname = NULL; return(items); } /* * 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(char *path, char *parent) { int len_path, len_parent; if((path == NULL) || (parent == NULL) ) return(0); len_path = strlen(path); len_parent = strlen(parent); /* Cannot compare if path is not absolute. */ if(path[0] != '/') return(0); if(parent[0] != '/') return(0); /* Reduce length of parent for tailing /'s. */ while(len_parent > 0) { if(parent[len_parent - 1] == '/') 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(char *path) { struct stat stat_buf; /* Input error checks. */ if(path == NULL) return(0); /* Check if exists. */ if(stat(path, &stat_buf)) return(0); return((S_ISDIR(stat_buf.st_mode)) ? 1 : 0); } int ISLPATHDIR(char *path) { struct stat stat_buf; if(path == NULL) return(0); /* Check if exists. */ if(lstat(path, &stat_buf)) return(0); return((S_ISDIR(stat_buf.st_mode)) ? 1 : 0); } int ISPATHEXECUTABLE(char *path) { struct stat stat_buf; if(path == NULL) 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); } /* * Replaces any occurances of "~" in path with user's home * dir. * * Returns statically allocated string. */ char *PathSubHome(char *path) { int i, n, p, len; char home_dir[PATH_MAX]; char *strptr; static char rtn_path[PATH_MAX]; if(path == NULL) return(NULL); /* Get home dir. */ strptr = getenv("HOME"); if(strptr == NULL) return(NULL); strncpy(home_dir, strptr, PATH_MAX); home_dir[PATH_MAX - 1] = '\0'; len = strlen(home_dir); /* Seek ~. */ for(p = 0, n = 1; path[p] != '\0'; p++) { if(path[p] == '~') { n = 0; break; } } /* No match? */ if(n) { strncpy(rtn_path, path, PATH_MAX); rtn_path[PATH_MAX - 1] = '\0'; return(rtn_path); } /* Copy over first few chars. */ for(i = 0; (i < p) && (i < PATH_MAX); i++) { rtn_path[i] = path[i]; } /* Sub. */ for(i = p, n = 0; (i < PATH_MAX) && (n < len); n++, i++) { rtn_path[i] = home_dir[n]; } /* Ending chars. */ for(i = p + len, n = p + 1; (path[n] != '\0') && (i < PATH_MAX); i++, n++ ) { rtn_path[i] = path[n]; } if(i < PATH_MAX) rtn_path[i] = '\0'; else rtn_path[PATH_MAX - 1] = '\0'; return(rtn_path); } /* * 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 **GetDirEntNames(char *parent) { int x, bytes_read, fd; struct dirent *dirp_origin; struct dirent *dirp_pos; char *dirp_raw; long dirp_memsize; long next_dirent; long total_dnames; char **dname; /* Error checks. */ if(parent == NULL) return(NULL); /* Must be absolute parent. */ x = 0; while((parent[x] == ' ') || (parent[x] == '\t') ) x++; if(parent[x] != '/') 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; return(dname); } #else /* USE_GETDENTS */ char **GetDirEntNames(char *parent) { int i, len; DIR *dir; struct dirent *de; char **rtn_names; /* Error checks. */ if(parent == NULL) return(NULL); /* Open dir. */ dir = opendir(parent); if(dir == NULL) return(NULL); /* Allocate rtn_names pointers. */ rtn_names = NULL; for(i = 0; 1; i++) { /* Reallocate rtn_names pointers. */ rtn_names = (char **)realloc( rtn_names, (i + 1) * sizeof(char *) ); if(rtn_names == NULL) { closedir(dir); dir = NULL; return(NULL); } /* Get next dir entry. */ de = (struct dirent *)readdir(dir); if(de == NULL) break; len = strlen(de->d_name); rtn_names[i] = (char *)calloc(1, (len + 1) * sizeof(char)); if(rtn_names[i] == NULL) break; strcpy(rtn_names[i], de->d_name); } closedir(dir); dir = NULL; /* Set last entry to NULL. */ rtn_names[i] = NULL; return(rtn_names); } #endif /* USE_GETDENTS */ /* * 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. Examples * * * Returns NULL on error or an allocated NULL terminated string on * success. The calling function must free the returned pointer. */ char *ChangeDirRel(char *cpath, 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); rtn_str = NULL; return(NULL); } 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); rtn_str = NULL; return(NULL); } 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); rtn_str = NULL; return(NULL); } 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 != '/') return; strptr1 = path; /* Seek to end. */ while(*strptr1 != '\0') strptr1++; /* Seek back, skipping tailing '/' chars. */ strptr1--; if(strptr1 < path) strptr1 = path; while((strptr1 > path) && (*strptr1 == '/') ) strptr1--; /* Seek back untill a '/' char. */ if(strptr1 < path) strptr1 = path; while((strptr1 > path) && (*strptr1 != '/') ) 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 "/". */ if(*path == '\0') { path[0] = '/'; path[1] = '\0'; } 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(char *parent, char *child) { char *strptr1, *strptr2, *strend; static char rtn_path[PATH_MAX]; if((parent == NULL) || (child == NULL) || (parent == child) ) return("/"); /* If child is absolute, copy child and return. */ if(*child == '/') { 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 '/' char. */ if(strptr1 > rtn_path) { if(*(strptr1 - 1) != '/') { *strptr1 = '/'; 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] = '/'; 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(char *link) { 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); } /* * Returns the number of lines in the file filename. */ int FileCountLines(char *filename) { FILE *fp; int i, lines = 0; fp = fopen(filename, "r"); 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(char *path) { char *strptr; DIR *dir; struct dirent *dent; char tmp_path[PATH_MAX + NAME_MAX]; int status = 0; /* Error checks. */ if(path == NULL) return(status); if(!ISPATHDIR(path)) return(status); /* Open dir. */ dir = opendir(path); if(dir == NULL) return(status); /* Scan through dirs. */ dent = (struct dirent *)readdir(dir); while(dent != NULL) { /* Skip special dir notations. */ if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..") ) { dent = (struct dirent *)readdir(dir); continue; } strptr = PrefixPaths(path, dent->d_name); if(strptr == NULL) continue; strncpy(tmp_path, strptr, PATH_MAX + NAME_MAX); tmp_path[PATH_MAX + NAME_MAX - 1] = '\0'; if(ISPATHDIR(tmp_path)) { status = 1; break; } dent = (struct dirent *)readdir(dir); } /* Close dir. */ closedir(dir); return(status); } /* * Returns a statically allocated string containing the parent * of the given absolute path. */ char *GetParentDir(char *path) { int i; char *strptr1, *strptr2; static char rtn_path[PATH_MAX]; if(path == NULL) return("/"); i = 0; strptr1 = path; strptr2 = rtn_path; while((*strptr1 != '\0') && (i < PATH_MAX)) { *strptr2 = *strptr1; strptr1++; strptr2++; i++; } if(i < PATH_MAX) *strptr2 = '\0'; else rtn_path[PATH_MAX - 1] = '\0'; strptr2--; if(strptr2 < rtn_path) strptr2 = rtn_path; while(*strptr2 == '/') { *strptr2 = '\0'; strptr2--; } /* Removing the child. */ while((strptr2 > rtn_path) && (*strptr2 != '/') ) strptr2--; if(strptr2 < rtn_path) strptr2 = rtn_path; *strptr2 = '\0'; /* Make sure rtn_path contains atleast "/". */ if(*rtn_path == '\0') { rtn_path[0] = '/'; rtn_path[1] = '\0'; } return(rtn_path); } /* * Simplifies path statement path by removing: * * 1. Any embedded "whatever/.." in it. * * Path must be absolute. */ void SimplifyPath(char *path) { char *strptr1, *strptr2, *strptr3; if(path == NULL) return; /* Look for a "/..". */ strptr1 = strstr(path, "/.."); while(strptr1 != NULL) { /* Seek next '/' char or end. */ strptr2 = strptr1 + 1; while((*strptr2 != '\0') && (*strptr2 != '/') ) strptr2++; /* Seek prev '/' char or start. */ strptr3 = strptr1 - 1; while((strptr3 > path) && (*strptr3 != '/') ) 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] = '/'; path[1] = '\0'; } return; } /* * 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( char *target, char *source, int (*comferm_func)(char *, char *) ) { int i; FILE *tar_fp, *src_fp; struct stat stat_buf; if((target == NULL) || (source == NULL) ) return(-1); /* Check if target exists. */ if(!stat(target, &stat_buf)) { if(comferm_func != NULL) { /* Overwrite? */ if(!comferm_func(target, source)) return(-3); /* Don't! */ } } /* Truncate target and open source. */ tar_fp = fopen(target, "wb"); if(tar_fp == NULL) return(-1); src_fp = fopen(source, "rb"); if(src_fp == NULL) return(-1); i = fgetc(src_fp); while(i != EOF) { if(fputc(i, tar_fp) == EOF) break; i = fgetc(src_fp); } fclose(tar_fp); fclose(src_fp); return(0); }