136 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			136 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include <errno.h>
 | |
| #include <sys/stat.h>
 | |
| 
 | |
| int
 | |
| normalizepath(const char *path, char **normal)
 | |
| {
 | |
|   size_t len = strlen(path);
 | |
|   *normal = (char *)malloc((len + 1) * sizeof(char));
 | |
|   const char *walk = path;
 | |
|   const char *match;
 | |
|   size_t newlen = 0;
 | |
| 
 | |
|   while ((match = strchr(walk, '/'))) {
 | |
|     // Copy everything between match and walk
 | |
|     strncpy(*normal + newlen, walk, match - walk);
 | |
|     newlen += match - walk;
 | |
|     walk += match - walk;
 | |
| 
 | |
|     // Skip all repeating slashes
 | |
|     while (*walk == '/')
 | |
|       walk++;
 | |
| 
 | |
|     // If not last character in path
 | |
|     if (walk != path + len)
 | |
|       (*normal)[newlen++] = '/';
 | |
|   }
 | |
| 
 | |
|   (*normal)[newlen++] = '\0';
 | |
| 
 | |
|   // Copy remaining path
 | |
|   strcat(*normal, walk);
 | |
|   newlen += strlen(walk);
 | |
| 
 | |
|   *normal = (char *)realloc(*normal, newlen * sizeof(char));
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| int
 | |
| parentdir(const char *path, char **parent)
 | |
| {
 | |
|   char *normal;
 | |
|   char *walk;
 | |
| 
 | |
|   normalizepath(path, &normal);
 | |
| 
 | |
|   // Pointer to last '/'
 | |
|   if (!(walk = strrchr(normal, '/'))) {
 | |
|     free(normal);
 | |
|     return -1;
 | |
|   }
 | |
| 
 | |
|   // Get path up to last '/'
 | |
|   size_t len = walk - normal;
 | |
|   *parent = (char *)malloc((len + 1) * sizeof(char));
 | |
| 
 | |
|   // Copy path up to last '/'
 | |
|   strncpy(*parent, normal, len);
 | |
|   // Add null char
 | |
|   (*parent)[len] = '\0';
 | |
| 
 | |
|   free(normal);
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| int
 | |
| mkdirp(const char *path)
 | |
| {
 | |
|   char *normal;
 | |
|   char *walk;
 | |
|   size_t normallen;
 | |
| 
 | |
|   normalizepath(path, &normal);
 | |
|   normallen = strlen(normal);
 | |
|   walk = normal;
 | |
| 
 | |
|   while (walk < normal + normallen + 1) {
 | |
|     // Get length from walk to next /
 | |
|     size_t n = strcspn(walk, "/");
 | |
| 
 | |
|     // Skip path /
 | |
|     if (n == 0) {
 | |
|       walk++;
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     // Length of current path segment
 | |
|     size_t curpathlen = walk - normal + n;
 | |
|     char curpath[curpathlen + 1];
 | |
|     struct stat s;
 | |
| 
 | |
|     // Copy path segment to stat
 | |
|     strncpy(curpath, normal, curpathlen);
 | |
|     strcpy(curpath + curpathlen, "");
 | |
|     int res = stat(curpath, &s);
 | |
| 
 | |
|     if (res < 0) {
 | |
|       if (errno == ENOENT) {
 | |
|         DEBUG("Making directory %s\n", curpath);
 | |
|         if (mkdir(curpath, 0700) < 0) {
 | |
|           fprintf(stderr, "Failed to make directory %s\n", curpath);
 | |
|           perror("");
 | |
|           free(normal);
 | |
|           return -1;
 | |
|         }
 | |
|       } else {
 | |
|         fprintf(stderr, "Error statting directory %s\n", curpath);
 | |
|         perror("");
 | |
|         free(normal);
 | |
|         return -1;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     // Continue to next path segment
 | |
|     walk += n;
 | |
|   }
 | |
| 
 | |
|   free(normal);
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| int
 | |
| nullterminate(char **str, size_t *len)
 | |
| {
 | |
|   if ((*str)[*len - 1] == '\0')
 | |
|     return 0;
 | |
| 
 | |
|   (*len)++;
 | |
|   *str = (char*)realloc(*str, *len * sizeof(char));
 | |
|   (*str)[*len - 1] = '\0';
 | |
| 
 | |
|   return 0;
 | |
| }
 |