// FUNCTION DEPTHSEARCH // SEARCH AN ELEMENT IN THE WHOLE TREE AND RETURNS HIS PATH char* DepthSearch(Tree* tree, char symbol, Tree* previous, int n, int count) { char path[30]; int i; path[30] = '\0'; tree->visited = 1; if((tree->symbol == symbol) && ((tree->left == NULL) && (tree->right == NULL))) { return path; } else { if(((tree->left->visited == 1) && (tree->right->visited == 1)) || ((tree->left == NULL) && (tree->right == NULL))) { n++; //removendo da string count--; DepthSearch(tree->previous, symbol, tree->previous->previous, n, count); } else { if((tree->left == NULL) || (tree->left->visited == 1)) { if(tree->right->visited == 1) { n++; //removendo da string count--; DepthSearch(tree->previous, symbol, tree->previous->previous, n, count); } else { // add 1 na string for(i = n - 1; i >= 0; i--) { path[i] = 1; n--; count++; } DepthSearch(tree->right, symbol, tree, n, count); } } else if((tree->right == NULL) || (tree->right->visited == 1)) { n++; count--; DepthSearch(tree->previous, symbol, tree->previous->previous, n, count); } else { //add 0 na string for(i = n - 1; i >= 0; i--){ path[i] = 0; n--; count++; } DepthSearch(tree->left, symbol, tree, n, count); } } } for(i = n; i < n + count; i++) { printf("%c", path[i]); } }
int DepthSearch(char *name, struct stat *sb, int rlevel, Attributes attr, Promise *pp) { Dir *dirh; int goback; const struct dirent *dirp; char path[CF_BUFSIZE]; struct stat lsb; if (!attr.havedepthsearch) /* if the search is trivial, make sure that we are in the parent dir of the leaf */ { char basedir[CF_BUFSIZE]; CfDebug(" -> Direct file reference %s, no search implied\n", name); snprintf(basedir, sizeof(basedir), "%s", name); ChopLastNode(basedir); chdir(basedir); return VerifyFileLeaf(name, sb, attr, pp); } if (rlevel > CF_RECURSION_LIMIT) { CfOut(cf_error, "", "WARNING: Very deep nesting of directories (>%d deep): %s (Aborting files)", rlevel, name); return false; } if (rlevel > CF_RECURSION_LIMIT) { CfOut(cf_error, "", "WARNING: Very deep nesting of directories (>%d deep): %s (Aborting files)", rlevel, name); return false; } memset(path, 0, CF_BUFSIZE); CfDebug("To iterate is Human, to recurse is Divine...(%s)\n", name); if (!PushDirState(name, sb)) { return false; } if ((dirh = OpenDirLocal(".")) == NULL) { CfOut(cf_inform, "opendir", "Could not open existing directory %s\n", name); return false; } for (dirp = ReadDir(dirh); dirp != NULL; dirp = ReadDir(dirh)) { if (!ConsiderFile(dirp->d_name, name, attr, pp)) { continue; } strcpy(path, name); AddSlash(path); if (!JoinPath(path, dirp->d_name)) { CloseDir(dirh); return true; } if (lstat(dirp->d_name, &lsb) == -1) { CfOut(cf_verbose, "lstat", "Recurse was looking at %s when an error occurred:\n", path); continue; } if (S_ISLNK(lsb.st_mode)) /* should we ignore links? */ { if (!KillGhostLink(path, attr, pp)) { VerifyFileLeaf(path, &lsb, attr, pp); } else { continue; } } /* See if we are supposed to treat links to dirs as dirs and descend */ if (attr.recursion.travlinks && S_ISLNK(lsb.st_mode)) { if (lsb.st_uid != 0 && lsb.st_uid != getuid()) { CfOut(cf_inform, "", "File %s is an untrusted link: cfengine will not follow it with a destructive operation", path); continue; } /* if so, hide the difference by replacing with actual object */ if (cfstat(dirp->d_name, &lsb) == -1) { CfOut(cf_error, "stat", "Recurse was working on %s when this failed:\n", path); continue; } } if (attr.recursion.xdev && DeviceBoundary(&lsb, pp)) { CfOut(cf_verbose, "", "Skipping %s on different device - use xdev option to change this\n", path); continue; } if (S_ISDIR(lsb.st_mode)) { if (SkipDirLinks(path, dirp->d_name, attr.recursion)) { continue; } if (attr.recursion.depth > 1 && rlevel <= attr.recursion.depth) { CfOut(cf_verbose, "", " ->> Entering %s (%d)\n", path, rlevel); goback = DepthSearch(path, &lsb, rlevel + 1, attr, pp); PopDirState(goback, name, sb, attr.recursion); VerifyFileLeaf(path, &lsb, attr, pp); } else { VerifyFileLeaf(path, &lsb, attr, pp); } } else { VerifyFileLeaf(path, &lsb, attr, pp); } } CloseDir(dirh); return true; }
static PromiseResult VerifyFilePromise(EvalContext *ctx, char *path, Promise *pp) { struct stat osb, oslb, dsb; Attributes a = { {0} }; CfLock thislock; int exists; a = GetFilesAttributes(ctx, pp); if (!FileSanityChecks(ctx, path, a, pp)) { return PROMISE_RESULT_NOOP; } EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_THIS, "promiser", path, DATA_TYPE_STRING); thislock = AcquireLock(ctx, path, VUQNAME, CFSTARTTIME, a.transaction, pp, false); if (thislock.lock == NULL) { return PROMISE_RESULT_NOOP; } LoadSetuid(a); PromiseResult result = PROMISE_RESULT_NOOP; if (lstat(path, &oslb) == -1) /* Careful if the object is a link */ { if ((a.create) || (a.touch)) { if (!CfCreateFile(ctx, path, pp, a, &result)) { goto exit; } else { exists = (lstat(path, &oslb) != -1); } } exists = false; } else { if ((a.create) || (a.touch)) { cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_NOOP, pp, a, "File '%s' exists as promised", path); } exists = true; } if ((a.havedelete) && (!exists)) { cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_NOOP, pp, a, "File '%s' does not exist as promised", path); goto exit; } if (!a.havedepthsearch) /* if the search is trivial, make sure that we are in the parent dir of the leaf */ { char basedir[CF_BUFSIZE]; Log(LOG_LEVEL_DEBUG, "Direct file reference '%s', no search implied", path); snprintf(basedir, sizeof(basedir), "%s", path); if (strcmp(ReadLastNode(basedir), ".") == 0) { // Handle /. notation for deletion of directories ChopLastNode(basedir); ChopLastNode(path); } ChopLastNode(basedir); if (chdir(basedir)) { Log(LOG_LEVEL_ERR, "Failed to chdir into '%s'", basedir); } } if (exists && (!VerifyFileLeaf(ctx, path, &oslb, a, pp, &result))) { if (!S_ISDIR(oslb.st_mode)) { goto exit; } } if (stat(path, &osb) == -1) { if ((a.create) || (a.touch)) { if (!CfCreateFile(ctx, path, pp, a, &result)) { goto exit; } else { exists = true; } } else { exists = false; } } else { if (!S_ISDIR(osb.st_mode)) { if (a.havedepthsearch) { Log(LOG_LEVEL_WARNING, "depth_search (recursion) is promised for a base object '%s' that is not a directory", path); goto exit; } } exists = true; } if (a.link.link_children) { if (stat(a.link.source, &dsb) != -1) { if (!S_ISDIR(dsb.st_mode)) { Log(LOG_LEVEL_ERR, "Cannot promise to link the children of '%s' as it is not a directory!", a.link.source); goto exit; } } } /* Phase 1 - */ if (exists && ((a.havedelete) || (a.haverename) || (a.haveperms) || (a.havechange) || (a.transformer))) { lstat(path, &oslb); /* if doesn't exist have to stat again anyway */ DepthSearch(ctx, path, &oslb, 0, a, pp, oslb.st_dev, &result); /* normally searches do not include the base directory */ if (a.recursion.include_basedir) { int save_search = a.havedepthsearch; /* Handle this node specially */ a.havedepthsearch = false; DepthSearch(ctx, path, &oslb, 0, a, pp, oslb.st_dev, &result); a.havedepthsearch = save_search; } else { /* unless child nodes were repaired, set a promise kept class */ if (!IsDefinedClass(ctx, "repaired" , PromiseGetNamespace(pp))) { cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_NOOP, pp, a, "Basedir '%s' not promising anything", path); } } if (((a.change.report_changes) == FILE_CHANGE_REPORT_CONTENT_CHANGE) || ((a.change.report_changes) == FILE_CHANGE_REPORT_ALL)) { if (a.havedepthsearch) { PurgeHashes(ctx, NULL, a, pp); } else { PurgeHashes(ctx, path, a, pp); } } } /* Phase 2a - copying is potentially threadable if no followup actions */ if (a.havecopy) { result = PromiseResultUpdate(result, ScheduleCopyOperation(ctx, path, a, pp)); } /* Phase 2b link after copy in case need file first */ if ((a.havelink) && (a.link.link_children)) { result = PromiseResultUpdate(result, ScheduleLinkChildrenOperation(ctx, path, a.link.source, 1, a, pp)); } else if (a.havelink) { result = PromiseResultUpdate(result, ScheduleLinkOperation(ctx, path, a.link.source, a, pp)); } /* Phase 3 - content editing */ if (a.haveedit) { result = PromiseResultUpdate(result, ScheduleEditOperation(ctx, path, a, pp)); } // Once more in case a file has been created as a result of editing or copying exists = (stat(path, &osb) != -1); if (exists && (S_ISREG(osb.st_mode))) { VerifyFileLeaf(ctx, path, &osb, a, pp, &result); } if (!exists && a.havechange) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Promised to monitor '%s' for changes, but file does not exist", path); result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL); } exit: result = PromiseResultUpdate(result, SaveSetuid(ctx, a, pp)); YieldCurrentLock(thislock); return result; }