int IsAbsoluteFileName(const char *f) { int off = 0; // Check for quoted strings for (off = 0; f[off] == '\"'; off++) { } #ifdef _WIN32 if (IsFileSep(f[off]) && IsFileSep(f[off + 1])) { return true; } if (isalpha(f[off]) && f[off + 1] == ':' && IsFileSep(f[off + 2])) { return true; } #endif if (f[off] == '/') { return true; } return false; }
int CompressPath(char *dest, const char *src) { char node[CF_BUFSIZE]; int nodelen; int rootlen; memset(dest, 0, CF_BUFSIZE); rootlen = RootDirLength(src); strncpy(dest, src, rootlen); for (const char *sp = src + rootlen; *sp != '\0'; sp++) { if (IsFileSep(*sp)) { continue; } for (nodelen = 0; (sp[nodelen] != '\0') && (!IsFileSep(sp[nodelen])); nodelen++) { if (nodelen > CF_MAXLINKSIZE) { Log(LOG_LEVEL_ERR, "Link in path suspiciously large"); return false; } } strncpy(node, sp, nodelen); node[nodelen] = '\0'; sp += nodelen - 1; if (strcmp(node, ".") == 0) { continue; } if (strcmp(node, "..") == 0) { if (!ChopLastNode(dest)) { Log(LOG_LEVEL_DEBUG, "used .. beyond top of filesystem!"); return false; } continue; } else { AddSlash(dest); } if (!JoinPath(dest, node)) { return false; } } return true; }
char *MapNameCopy(const char *s) { Writer *w = StringWriter(); /* c:\a\b -> /cygdrive/c\a\b */ if (s[0] && isalpha(s[0]) && s[1] == ':') { WriterWriteF(w, "/cygdrive/%c", s[0]); s += 2; } for (; *s; s++) { /* a//b//c -> a/b/c */ /* a\\b\\c -> a\b\c */ if (IsFileSep(*s) && IsFileSep(*(s + 1))) { continue; } /* a\b\c -> a/b/c */ WriterWriteChar(w, *s == '\\' ? '/' : *s); } return StringWriterClose(w); }
void DeleteRedundantSlashes(char *str) { int move_from; // Invariant: newpos <= oldpos int oldpos = RootDirLength(str); int newpos = oldpos; while (str[oldpos] != '\0') { // Skip over subsequent separators. while (IsFileSep(str[oldpos])) { oldpos++; } move_from = oldpos; // And then skip over the next path component. while (str[oldpos] != '\0' && !IsFileSep(str[oldpos])) { oldpos++; } // If next character is file separator, move past it, since we want to keep one. if (IsFileSep(str[oldpos])) { oldpos++; } int move_len = oldpos - move_from; memmove(&str[newpos], &str[move_from], move_len); newpos += move_len; } str[newpos] = '\0'; }
int RootDirLength(char *f) /* Return length of Initial directory in path - */ { #ifdef NT int len; if (IsFileSep(f[0]) && IsFileSep(f[1])) { /* UNC style path */ /* Skip over host name */ for (len=2; !IsFileSep(f[len]); len++) { if (f[len] == '\0') { return len; } } /* Skip over share name */ for (len++; !IsFileSep(f[len]); len++) { if (f[len] == '\0') { return len; } } /* Skip over file separator */ len++; return len; } if ( isalpha(f[0]) && f[1] == ':' && IsFileSep(f[2]) ) { return 3; } #endif if (*f == '/') { return 1; } return 0; }
static int NTRootDirLength(const char *f) { int len; if (IsFileSep(f[0]) && IsFileSep(f[1])) { /* UNC style path */ /* Skip over host name */ for (len = 2; !IsFileSep(f[len]); len++) { if (f[len] == '\0') { return len; } } /* Skip over share name */ for (len++; !IsFileSep(f[len]); len++) { if (f[len] == '\0') { return len; } } /* Skip over file separator */ len++; return len; } if (isalpha(f[0]) && f[1] == ':') { if (IsFileSep(f[2])) { return 3; } return 2; } return UnixRootDirLength(f); }
static int UnixRootDirLength(const char *f) { if (IsFileSep(*f)) { return 1; } return 0; }
int IsAbsPath(const char *path) { if (IsFileSep(*path)) { return true; } else { return false; } }
int IsAbsoluteFileName(char *f) { #ifdef NT if (IsFileSep(f[0]) && IsFileSep(f[1])) { return true; } if ( isalpha(f[0]) && f[1] == ':' && IsFileSep(f[2]) ) { return true; } #endif if (*f == '/') { return true; } return false; }
void AddSlash(char *str) { char *sp, *sep = FILE_SEPARATOR_STR; int f = false, b = false; if (str == NULL) { return; } // add root slash on Unix systems if (strlen(str) == 0) { #if !defined(_WIN32) strcpy(str, "/"); #endif return; } /* Try to see what convention is being used for filenames in case this is a cross-system copy from Win/Unix */ for (sp = str; *sp != '\0'; sp++) { switch (*sp) { case '/': f = true; break; case '\\': b = true; break; default: break; } } if (f && (!b)) { sep = "/"; } else if (b && (!f)) { sep = "\\"; } if (!IsFileSep(str[strlen(str) - 1])) { strcat(str, sep); } }
// Can remove several slashes if they are redundant. void DeleteSlash(char *str) { int size = strlen(str); if ((size == 0) || (str == NULL)) { return; } int root = RootDirLength(str); while (IsFileSep(str[size - 1]) && size - 1 > root) { size--; } str[size] = '\0'; /* no-op if we didn't change size */ }
void DeleteSlash(char *str) { if ((strlen(str) == 0) || (str == NULL)) { return; } if (strcmp(str, "/") == 0) { return; } if (IsFileSep(str[strlen(str) - 1])) { str[strlen(str) - 1] = '\0'; } }
const char *FirstFileSeparator(const char *str) { assert(str); assert(strlen(str) > 0); if(strncmp(str, "\\\\", 2) == 0) // windows share { return str + 1; } for(const char *pos = str; *pos != '\0'; pos++) { if(IsFileSep(*pos)) { return pos; } } return NULL; }
const char *LastFileSeparator(const char *str) /* Return pointer to last file separator in string, or NULL if string does not contains any file separtors */ { const char *sp; /* Walk through string backwards */ sp = str + strlen(str) - 1; while (sp >= str) { if (IsFileSep(*sp)) { return sp; } sp--; } return NULL; }
int CompressPath(char *dest,char *src) { char *sp; char node[CF_BUFSIZE]; int nodelen; int rootlen; Debug2("CompressPath(%s,%s)\n",dest,src); memset(dest,0,CF_BUFSIZE); rootlen = RootDirLength(src); strncpy(dest,src,rootlen); for (sp = src+rootlen; *sp != '\0'; sp++) { if (IsFileSep(*sp)) { continue; } for (nodelen = 0; sp[nodelen] != '\0' && !IsFileSep(sp[nodelen]); nodelen++) { if (nodelen > CF_MAXLINKSIZE) { CfLog(cferror,"Link in path suspiciously large",""); return false; } } strncpy(node, sp, nodelen); node[nodelen] = '\0'; sp += nodelen - 1; if (strcmp(node,".") == 0) { continue; } if (strcmp(node,"..") == 0) { if (!ChopLastNode(dest)) { Debug("cfengine: used .. beyond top of filesystem!\n"); return false; } continue; } else { AddSlash(dest); } if (BufferOverflow(dest,node)) { return false; } strcat(dest,node); } return true; }
/** * @TODO fix the dangerous path lengths */ int CompressPath(char *dest, const char *src) { char node[CF_BUFSIZE]; int nodelen; int rootlen; memset(dest, 0, CF_BUFSIZE); rootlen = RootDirLength(src); memcpy(dest, src, rootlen); for (const char *sp = src + rootlen; *sp != '\0'; sp++) { if (IsFileSep(*sp)) { continue; } for (nodelen = 0; (sp[nodelen] != '\0') && (!IsFileSep(sp[nodelen])); nodelen++) { if (nodelen > CF_MAXLINKSIZE) { Log(LOG_LEVEL_ERR, "Link in path suspiciously large"); return false; } } strncpy(node, sp, nodelen); node[nodelen] = '\0'; sp += nodelen - 1; if (strcmp(node, ".") == 0) { continue; } if (strcmp(node, "..") == 0) { if (!ChopLastNode(dest)) { Log(LOG_LEVEL_DEBUG, "used .. beyond top of filesystem!"); return false; } continue; } AddSlash(dest); /* TODO use dest_size parameter instead of CF_BUFSIZE. */ size_t ret = strlcat(dest, node, CF_BUFSIZE); if (ret >= CF_BUFSIZE) { Log(LOG_LEVEL_ERR, "Internal limit reached in CompressPath()," " path too long: '%s' + '%s'", dest, node); return false; } } return true; }
PromiseResult VerifyRelativeLink(EvalContext *ctx, char *destination, const char *source, Attributes attr, const Promise *pp) { char *sp, *commonto, *commonfrom; char buff[CF_BUFSIZE], linkto[CF_BUFSIZE]; int levels = 0; if (*source == '.') { return VerifyLink(ctx, destination, source, attr, pp); } if (!CompressPath(linkto, sizeof(linkto), source)) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_INTERRUPTED, pp, attr, "Failed to link '%s' to '%s'", destination, source); return PROMISE_RESULT_INTERRUPTED; } commonto = linkto; commonfrom = destination; if (strcmp(commonto, commonfrom) == 0) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_INTERRUPTED, pp, attr, "Failed to link '%s' to '%s', can't link file '%s' to itself", destination, source, commonto); return PROMISE_RESULT_INTERRUPTED; } while (*commonto == *commonfrom) { commonto++; commonfrom++; } while (!((IsAbsoluteFileName(commonto)) && (IsAbsoluteFileName(commonfrom)))) { commonto--; commonfrom--; } commonto++; for (sp = commonfrom; *sp != '\0'; sp++) { if (IsFileSep(*sp)) { levels++; } } memset(buff, 0, CF_BUFSIZE); strcat(buff, "."); strcat(buff, FILE_SEPARATOR_STR); while (--levels > 0) { const char add[] = ".." FILE_SEPARATOR_STR; if (!PathAppend(buff, sizeof(buff), add, FILE_SEPARATOR)) { Log(LOG_LEVEL_ERR, "Internal limit reached in VerifyRelativeLink()," " path too long: '%s' + '%s'", buff, add); return PROMISE_RESULT_FAIL; } } if (!PathAppend(buff, sizeof(buff), commonto, FILE_SEPARATOR)) { Log(LOG_LEVEL_ERR, "Internal limit reached in VerifyRelativeLink() end," " path too long: '%s' + '%s'", buff, commonto); return PROMISE_RESULT_FAIL; } return VerifyLink(ctx, destination, buff, attr, pp); }
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); }
PromiseResult VerifyRelativeLink(EvalContext *ctx, char *destination, const char *source, Attributes attr, const Promise *pp) { char *sp, *commonto, *commonfrom; char buff[CF_BUFSIZE], linkto[CF_BUFSIZE], add[CF_BUFSIZE]; int levels = 0; if (*source == '.') { return VerifyLink(ctx, destination, source, attr, pp); } if (!CompressPath(linkto, source)) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_INTERRUPTED, pp, attr, "Failed to link %s to %s\n", destination, source); return PROMISE_RESULT_FAIL; } commonto = linkto; commonfrom = destination; if (strcmp(commonto, commonfrom) == 0) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_INTERRUPTED, pp, attr, "Failed to link %s to %s - can't link file %s to itself\n", destination, source, commonto); return PROMISE_RESULT_FAIL; } while (*commonto == *commonfrom) { commonto++; commonfrom++; } while (!((IsAbsoluteFileName(commonto)) && (IsAbsoluteFileName(commonfrom)))) { commonto--; commonfrom--; } commonto++; for (sp = commonfrom; *sp != '\0'; sp++) { if (IsFileSep(*sp)) { levels++; } } memset(buff, 0, CF_BUFSIZE); strcat(buff, "."); strcat(buff, FILE_SEPARATOR_STR); while (--levels > 0) { snprintf(add, CF_BUFSIZE - 1, "..%c", FILE_SEPARATOR); if (!JoinPath(buff, add)) { return PROMISE_RESULT_FAIL; } } if (!JoinPath(buff, commonto)) { return PROMISE_RESULT_FAIL; } return VerifyLink(ctx, destination, buff, attr, pp); }
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; }