char *GetParentDirectoryCopy(const char *path) /** * WARNING: Remember to free return value. **/ { assert(path); assert(strlen(path) > 0); char *path_copy = xstrdup(path); if(strcmp(path_copy, "/") == 0) { return path_copy; } char *sp = (char *)LastFileSeparator(path_copy); if(!sp) { Log(LOG_LEVEL_ERR, "Path %s does not contain file separators (GetParentDirectory())", path_copy); free(path_copy); return NULL; } if(sp == FirstFileSeparator(path_copy)) // don't chop off first path separator { *(sp + 1) = '\0'; } else { *sp = '\0'; } return path_copy; }
int ChopLastNode(char *str) /* Chop off trailing node name (possible blank) starting from last character and removing up to the first / encountered e.g. /a/b/c -> /a/b /a/b/ -> /a/b */ { char *sp; int ret; if ((sp = LastFileSeparator(str)) == NULL) { ret = false; } else { *sp = '\0'; ret = true; } if (strlen(str) == 0) { AddSlash(str); } return ret; }
bool ChopLastNode(char *str) /* Chop off trailing node name (possible blank) starting from last character and removing up to the first / encountered e.g. /a/b/c -> /a/b /a/b/ -> /a/b */ { char *sp; int ret; /* Here cast is necessary and harmless, str is modifiable */ if ((sp = (char *) LastFileSeparator(str)) == NULL) { ret = false; } else { *sp = '\0'; ret = true; } if (strlen(str) == 0) { AddSlash(str); } return ret; }
const char *ReadLastNode(const char *str) /* Return the last node of a pathname string */ { const char *sp; if ((sp = LastFileSeparator(str)) == NULL) { return str; } else { return sp + 1; } }
bool ChopLastNode(char *str) /* Chop off trailing node name (possible blank) starting from last character and removing up to the first / encountered e.g. /a/b/c -> /a/b /a/b/ -> /a/b Will also collapse redundant/repeating path separators. */ { char *sp; int ret; DeleteRedundantSlashes(str); /* Here cast is necessary and harmless, str is modifiable */ if ((sp = (char *) LastFileSeparator(str)) == NULL) { int pos = RootDirLength(str); if (str[pos] == '\0') { ret = false; } else { str[pos] = '.'; str[pos + 1] = '\0'; ret = true; } } else { // Don't chop the root slash in an absolute path. if (IsAbsoluteFileName(str) && FirstFileSeparator(str) == sp) { *(++sp) = '\0'; } else { *sp = '\0'; } ret = true; } return ret; }
bool MakeParentDirectory(const char *parentandchild, bool force) { char *spc, *sp; char currentpath[CF_BUFSIZE]; char pathbuf[CF_BUFSIZE]; struct stat statbuf; mode_t mask; int rootlen; char Path_File_Separator; #ifdef __APPLE__ /* Keeps track of if dealing w. resource fork */ int rsrcfork; rsrcfork = 0; char *tmpstr; #endif Log(LOG_LEVEL_DEBUG, "Trying to create a parent directory for '%s%s'", parentandchild, force ? " (force applied)" : ""); if (!IsAbsoluteFileName(parentandchild)) { Log(LOG_LEVEL_ERR, "Will not create directories for a relative filename '%s'. Has no invariant meaning", parentandchild); return false; } strncpy(pathbuf, parentandchild, CF_BUFSIZE - 1); /* local copy */ #ifdef __APPLE__ if (strstr(pathbuf, _PATH_RSRCFORKSPEC) != NULL) { rsrcfork = 1; } #endif /* skip link name */ /* This cast is necessary, as you can't have (char* -> char*) and (const char* -> const char*) functions in C */ sp = (char *) LastFileSeparator(pathbuf); if (sp == NULL) { sp = pathbuf; } *sp = '\0'; DeleteSlash(pathbuf); if (lstat(pathbuf, &statbuf) != -1) { if (S_ISLNK(statbuf.st_mode)) { Log(LOG_LEVEL_VERBOSE, "INFO: %s is a symbolic link, not a true directory!", pathbuf); } if (force) /* force in-the-way directories aside */ { struct stat dir; stat(pathbuf, &dir); if (!S_ISDIR(dir.st_mode)) /* if the dir exists - no problem */ { struct stat sbuf; if (DONTDO) { return true; } strcpy(currentpath, pathbuf); DeleteSlash(currentpath); strcat(currentpath, ".cf-moved"); Log(LOG_LEVEL_INFO, "Moving obstructing file/link %s to %s to make directory", pathbuf, currentpath); /* If cfagent, remove an obstructing backup object */ if (lstat(currentpath, &sbuf) != -1) { if (S_ISDIR(sbuf.st_mode)) { DeleteDirectoryTree(currentpath); } else { if (unlink(currentpath) == -1) { Log(LOG_LEVEL_INFO, "Couldn't remove file/link '%s' while trying to remove a backup. (unlink: %s)", currentpath, GetErrorStr()); } } } /* And then move the current object out of the way... */ if (rename(pathbuf, currentpath) == -1) { Log(LOG_LEVEL_INFO, "Warning: The object '%s' is not a directory. (rename: %s)", pathbuf, GetErrorStr()); return false; } } } else { if (!S_ISLNK(statbuf.st_mode) && !S_ISDIR(statbuf.st_mode)) { Log(LOG_LEVEL_INFO, "The object %s is not a directory. Cannot make a new directory without deleting it.", pathbuf); return false; } } } /* Now we can make a new directory .. */ currentpath[0] = '\0'; rootlen = RootDirLength(parentandchild); strncpy(currentpath, parentandchild, rootlen); for (sp = (char*) parentandchild + rootlen, spc = currentpath + rootlen; *sp != '\0'; sp++) { if (!IsFileSep(*sp) && *sp != '\0') { *spc = *sp; spc++; } else { Path_File_Separator = *sp; *spc = '\0'; if (strlen(currentpath) == 0) { } else if (stat(currentpath, &statbuf) == -1) { if (!DONTDO) { mask = umask(0); if (mkdir(currentpath, DEFAULTMODE) == -1) { Log(LOG_LEVEL_ERR, "Unable to make directories to '%s'. (mkdir: %s)", parentandchild, GetErrorStr()); umask(mask); return false; } umask(mask); } } else { if (!S_ISDIR(statbuf.st_mode)) { #ifdef __APPLE__ /* Ck if rsrc fork */ if (rsrcfork) { tmpstr = xmalloc(CF_BUFSIZE); strncpy(tmpstr, currentpath, CF_BUFSIZE); strncat(tmpstr, _PATH_FORKSPECIFIER, CF_BUFSIZE); /* CFEngine removed terminating slashes */ DeleteSlash(tmpstr); if (strncmp(tmpstr, pathbuf, CF_BUFSIZE) == 0) { free(tmpstr); return true; } free(tmpstr); } #endif Log(LOG_LEVEL_ERR, "Cannot make %s - %s is not a directory! (use forcedirs=true)", pathbuf, currentpath); return false; } } /* *spc = FILE_SEPARATOR; */ *spc = Path_File_Separator; spc++; } } Log(LOG_LEVEL_DEBUG, "Directory for '%s' exists. Okay", parentandchild); return true; }
int MakeDirectoriesFor(char *file,char force) /* Make all directories which underpin file */ { char *sp,*spc; char currentpath[CF_BUFSIZE]; char pathbuf[CF_BUFSIZE]; struct stat statbuf; mode_t mask; int rootlen; char Path_File_Separator; #ifdef DARWIN /* Keeps track of if dealing w. resource fork */ int rsrcfork; rsrcfork = 0; char * tmpstr; #endif if (!IsAbsoluteFileName(file)) { snprintf(OUTPUT,CF_BUFSIZE*2,"Will not create directories for a relative filename (%s). Has no invariant meaning\n",file); CfLog(cferror,OUTPUT,""); return false; } strncpy(pathbuf,file,CF_BUFSIZE-1); /* local copy */ #ifdef DARWIN /* Dealing w. a rsrc fork? */ if (strstr(pathbuf, _PATH_RSRCFORKSPEC) != NULL) { rsrcfork = 1; } #endif /* skip link name */ sp = LastFileSeparator(pathbuf); if (sp == NULL) { sp = pathbuf; } *sp = '\0'; DeleteSlash(pathbuf); if (lstat(pathbuf,&statbuf) != -1) { if (S_ISLNK(statbuf.st_mode)) { Verbose("%s: INFO: %s is a symbolic link, not a true directory!\n",VPREFIX,pathbuf); } if (force == 'y') /* force in-the-way directories aside */ { if (!S_ISDIR(statbuf.st_mode)) /* if the dir exists - no problem */ { if (ISCFENGINE) { struct Tidy tp; struct TidyPattern tpat; struct stat sbuf; if (DONTDO) { return true; } strcpy(currentpath,pathbuf); DeleteSlash(currentpath); strcat(currentpath,".cf-moved"); snprintf(OUTPUT,CF_BUFSIZE,"Moving obstructing file/link %s to %s to make directory",pathbuf,currentpath); CfLog(cferror,OUTPUT,""); /* If cfagent, remove an obstructing backup object */ if (lstat(currentpath,&sbuf) != -1) { if (S_ISDIR(sbuf.st_mode)) { tp.maxrecurse = 2; tp.tidylist = &tpat; tp.next = NULL; tp.path = currentpath; tpat.recurse = CF_INF_RECURSE; tpat.age = 0; tpat.size = 0; tpat.pattern = strdup("*"); tpat.classes = strdup("any"); tpat.defines = NULL; tpat.elsedef = NULL; tpat.dirlinks = 'y'; tpat.travlinks = 'n'; tpat.rmdirs = 'y'; tpat.searchtype = 'a'; tpat.log = 'd'; tpat.inform = 'd'; tpat.next = NULL; // RecursiveTidySpecialArea(currentpath,&tp,CF_INF_RECURSE,&sbuf); free(tpat.pattern); free(tpat.classes); if (rmdir(currentpath) == -1) { snprintf(OUTPUT,CF_BUFSIZE*2,"Couldn't remove directory %s while trying to remove a backup\n",currentpath); CfLog(cfinform,OUTPUT,"rmdir"); } } else { if (unlink(currentpath) == -1) { snprintf(OUTPUT,CF_BUFSIZE*2,"Couldn't remove file/link %s while trying to remove a backup\n",currentpath); CfLog(cfinform,OUTPUT,"rmdir"); } } } /* And then move the current object out of the way...*/ if (rename(pathbuf,currentpath) == -1) { snprintf(OUTPUT,CF_BUFSIZE*2,"Warning. The object %s is not a directory.\n",pathbuf); CfLog(cfinform,OUTPUT,""); CfLog(cfinform,"Could not make a new directory or move the block","rename"); return(false); } } } else { if (! S_ISLNK(statbuf.st_mode) && ! S_ISDIR(statbuf.st_mode)) { snprintf(OUTPUT,CF_BUFSIZE*2,"Warning. The object %s is not a directory.\n",pathbuf); CfLog(cfinform,OUTPUT,""); CfLog(cfinform,"Cannot make a new directory without deleting it!\n\n",""); return(false); } } } } /* Now we can make a new directory .. */ currentpath[0] = '\0'; rootlen = RootDirLength(sp); strncpy(currentpath, file, rootlen); for (sp = file+rootlen, spc = currentpath+rootlen; *sp != '\0'; sp++) { if (!IsFileSep(*sp) && *sp != '\0') { *spc = *sp; spc++; } else { Path_File_Separator = *sp; *spc = '\0'; if (strlen(currentpath) == 0) { } else if (stat(currentpath,&statbuf) == -1) { Debug2("cfengine: Making directory %s, mode %o\n",currentpath,DEFAULTMODE); if (! DONTDO) { mask = umask(0); if (mkdir(currentpath,DEFAULTMODE) == -1) { snprintf(OUTPUT,CF_BUFSIZE*2,"Unable to make directories to %s\n",file); CfLog(cferror,OUTPUT,"mkdir"); umask(mask); return(false); } umask(mask); } } else { if (! S_ISDIR(statbuf.st_mode)) { #ifdef DARWIN /* Ck if rsrc fork */ if (rsrcfork) { tmpstr = malloc(CF_BUFSIZE); strncpy(tmpstr, currentpath, CF_BUFSIZE); strncat(tmpstr, _PATH_FORKSPECIFIER, CF_BUFSIZE); /* Cfengine removed terminating slashes */ DeleteSlash(tmpstr); if (strncmp(tmpstr, pathbuf, CF_BUFSIZE) == 0) { free(tmpstr); return(true); } free(tmpstr); } #endif snprintf(OUTPUT,CF_BUFSIZE*2,"Cannot make %s - %s is not a directory! (use forcedirs=true)\n",pathbuf,currentpath); CfLog(cferror,OUTPUT,""); return(false); } } /* *spc = FILE_SEPARATOR; */ *spc = Path_File_Separator; spc++; } } Debug("Directory for %s exists. Okay\n",file); return(true); }
bool MakeParentDirectory(const char *parentandchild, bool force) { char *sp; char currentpath[CF_BUFSIZE]; char pathbuf[CF_BUFSIZE]; struct stat statbuf; mode_t mask; int rootlen; #ifdef __APPLE__ /* Keeps track of if dealing w. resource fork */ int rsrcfork; rsrcfork = 0; char *tmpstr; #endif Log(LOG_LEVEL_DEBUG, "Trying to create a parent directory%s for: %s", force ? " (force applied)" : "", parentandchild); if (!IsAbsoluteFileName(parentandchild)) { Log(LOG_LEVEL_ERR, "Will not create directories for a relative filename: %s", parentandchild); return false; } strlcpy(pathbuf, parentandchild, CF_BUFSIZE); /* local copy */ #ifdef __APPLE__ if (strstr(pathbuf, _PATH_RSRCFORKSPEC) != NULL) { rsrcfork = 1; } #endif /* skip link name */ sp = (char *) LastFileSeparator(pathbuf); /* de-constify */ if (sp == NULL) { sp = pathbuf; } *sp = '\0'; DeleteSlash(pathbuf); if (lstat(pathbuf, &statbuf) != -1) { if (S_ISLNK(statbuf.st_mode)) { Log(LOG_LEVEL_VERBOSE, "'%s' is a symbolic link, not a directory", pathbuf); } if (force) /* force in-the-way directories aside */ { struct stat dir; stat(pathbuf, &dir); /* If the target directory exists as a directory, no problem. */ /* If the target directory exists but is not a directory, then * rename it to ".cf-moved": */ if (!S_ISDIR(dir.st_mode)) { struct stat sbuf; if (DONTDO) { return true; } strcpy(currentpath, pathbuf); DeleteSlash(currentpath); /* TODO overflow check! */ strlcat(currentpath, ".cf-moved", sizeof(currentpath)); Log(LOG_LEVEL_INFO, "Moving obstructing file/link %s to %s to make directory", pathbuf, currentpath); /* Remove possibly pre-existing ".cf-moved" backup object. */ if (lstat(currentpath, &sbuf) != -1) { if (S_ISDIR(sbuf.st_mode)) /* directory */ { DeleteDirectoryTree(currentpath); } else /* not a directory */ { if (unlink(currentpath) == -1) { Log(LOG_LEVEL_INFO, "Couldn't remove file/link" " '%s' while trying to remove a backup" " (unlink: %s)", currentpath, GetErrorStr()); } } } /* And then rename the current object to ".cf-moved". */ if (rename(pathbuf, currentpath) == -1) { Log(LOG_LEVEL_INFO, "Couldn't rename '%s' to .cf-moved" " (rename: %s)", pathbuf, GetErrorStr()); return false; } } } else { if (!S_ISLNK(statbuf.st_mode) && !S_ISDIR(statbuf.st_mode)) { Log(LOG_LEVEL_INFO, "The object '%s' is not a directory." " Cannot make a new directory without deleting it.", pathbuf); return false; } } } /* Now we make directories descending from the root folder down to the leaf */ currentpath[0] = '\0'; rootlen = RootDirLength(parentandchild); /* currentpath is not NULL terminated on purpose! */ strncpy(currentpath, parentandchild, rootlen); for (size_t z = rootlen; parentandchild[z] != '\0'; z++) { const char c = parentandchild[z]; /* Copy up to the next separator. */ if (!IsFileSep(c)) { currentpath[z] = c; continue; } const char path_file_separator = c; currentpath[z] = '\0'; /* currentpath is complete path for each of the parent directories. */ if (currentpath[0] == '\0') { /* We are at dir "/" of an absolute path, no need to create. */ } /* WARNING: on Windows stat() fails if path has a trailing slash! */ else if (stat(currentpath, &statbuf) == -1) { if (!DONTDO) { mask = umask(0); if (mkdir(currentpath, DEFAULTMODE) == -1) { Log(LOG_LEVEL_ERR, "Unable to make directory: %s (mkdir: %s)", currentpath, GetErrorStr()); umask(mask); return false; } umask(mask); } } else { if (!S_ISDIR(statbuf.st_mode)) { #ifdef __APPLE__ /* Ck if rsrc fork */ if (rsrcfork) { tmpstr = xmalloc(CF_BUFSIZE); strlcpy(tmpstr, currentpath, CF_BUFSIZE); strncat(tmpstr, _PATH_FORKSPECIFIER, CF_BUFSIZE); /* CFEngine removed terminating slashes */ DeleteSlash(tmpstr); if (strncmp(tmpstr, pathbuf, CF_BUFSIZE) == 0) { free(tmpstr); return true; } free(tmpstr); } #endif Log(LOG_LEVEL_ERR, "Cannot make %s - %s is not a directory!" " (use forcedirs=true)", pathbuf, currentpath); return false; } } currentpath[z] = path_file_separator; } Log(LOG_LEVEL_DEBUG, "Directory for '%s' exists. Okay", parentandchild); return true; }