void DrawMenu(MenuInfo* currMenu, u32 index, bool fullDraw, bool subMenu) { u32 emunand_state = CheckEmuNand(); bool top_screen = true; u32 menublock_x0 = (top_screen) ? 76 : 36; u32 menublock_x1 = (top_screen) ? 52 : 12; u32 menublock_y0 = 40; u32 menublock_y1 = menublock_y0 + currMenu->n_entries * 10; if (fullDraw) { // draw full menu ClearScreenFull(true, !top_screen); DrawStringF(menublock_x0, menublock_y0 - 20, top_screen, "%s", currMenu->name); DrawStringF(menublock_x0, menublock_y0 - 10, top_screen, "=============================="); DrawStringF(menublock_x0, menublock_y1 + 0, top_screen, "=============================="); DrawStringF(menublock_x0, menublock_y1 + 10, top_screen, (subMenu) ? "A: Elegir B: Volver" : "A: Elegir"); DrawStringF(menublock_x0, menublock_y1 + 20, top_screen, "SELECT: Desmontar la tarjeta SD"); DrawStringF(menublock_x0, menublock_y1 + 30, top_screen, "START: Reiniciar / [+\x1B] Apagar"); DrawStringF(menublock_x1, SCREEN_HEIGHT - 20, top_screen, "Tarjeta SD: %lluMB/%lluMB & %s", RemainingStorageSpace() / 1024 / 1024, TotalStorageSpace() / 1024 / 1024, (emunand_state == EMUNAND_READY) ? "EmuNAND lista" : (emunand_state == EMUNAND_GATEWAY) ? "GW EmuNAND" : (emunand_state == EMUNAND_REDNAND) ? "RedNAND" : (emunand_state > 3) ? "MultiNAND" : "no EmuNAND"); DrawStringF(menublock_x1, SCREEN_HEIGHT - 30, top_screen, "Directorio de juego: %s", GAME_DIR); if (DirOpen(WORK_DIR)) { DrawStringF(menublock_x1, SCREEN_HEIGHT - 40, top_screen, "Directorio de trabajo: %s", WORK_DIR); DirClose(); } } if (!top_screen) DrawStringF(10, 10, true, "Selected: %-*.*s", 32, 32, currMenu->entries[index].name); for (u32 i = 0; i < currMenu->n_entries; i++) { // draw menu entries / selection [] char* name = currMenu->entries[i].name; DrawStringF(menublock_x0, menublock_y0 + (i*10), top_screen, (i == index) ? "[%s]" : " %s ", name); } }
void DrawMenu(MenuInfo* currMenu, u32 index, bool fullDraw, bool subMenu) { u32 emunand_state = CheckEmuNand(); bool top_screen = true; u32 menublock_x0 = (top_screen) ? 76 : 36; u32 menublock_x1 = (top_screen) ? 52 : 12; u32 menublock_y0 = 40; u32 menublock_y1 = menublock_y0 + currMenu->n_entries * 10; if (fullDraw) { // draw full menu ClearScreenFull(true, !top_screen); DrawStringF(menublock_x0, menublock_y0 - 20, top_screen, "%s", currMenu->name); DrawStringF(menublock_x0, menublock_y0 - 10, top_screen, "=============================="); DrawStringF(menublock_x0, menublock_y1 + 0, top_screen, "=============================="); DrawStringF(menublock_x0, menublock_y1 + 10, top_screen, (subMenu) ? "A: Choose B: Return" : "A: Choose"); DrawStringF(menublock_x0, menublock_y1 + 20, top_screen, "SELECT: Unmount SD"); DrawStringF(menublock_x0, menublock_y1 + 30, top_screen, "START: Reboot"); DrawStringF(menublock_x1, SCREEN_HEIGHT - 20, top_screen, "SD card: %lluMB/%lluMB & %s", RemainingStorageSpace() / 1024 / 1024, TotalStorageSpace() / 1024 / 1024, (emunand_state == EMUNAND_READY) ? "EmuNAND ready" : (emunand_state == EMUNAND_GATEWAY) ? "GW EmuNAND" : (emunand_state == EMUNAND_REDNAND) ? "RedNAND" : (emunand_state > 3) ? "MultiNAND" : "no EmuNAND"); DrawStringF(menublock_x1, SCREEN_HEIGHT - 30, top_screen, "Game directory: %s", GAME_DIR); if (DirOpen(WORK_DIR)) { DrawStringF(menublock_x1, SCREEN_HEIGHT - 40, top_screen, "Work directory: %s", WORK_DIR); DirClose(); } } if (!top_screen) DrawStringF(10, 10, true, "Selected: %-*.*s", 32, 32, currMenu->entries[index].name); for (u32 i = 0; i < currMenu->n_entries; i++) { // draw menu entries / selection [] char* name = currMenu->entries[i].name; DrawStringF(menublock_x0, menublock_y0 + (i*10), top_screen, (i == index) ? "[%s]" : " %s ", name); } }
void DrawMenu(MenuInfo* currMenu, u32 index, bool fullDraw, bool subMenu) { bool top_screen = true; u32 menublock_x0 = (top_screen) ? 76 : 36; u32 menublock_x1 = (top_screen) ? 50 : 10; u32 menublock_y0 = 40; u32 menublock_y1 = menublock_y0 + currMenu->n_entries * 10; if (fullDraw) { // draw full menu ClearScreenFull(true, !top_screen); DrawStringF(menublock_x0, menublock_y0 - 20, top_screen, "%s", currMenu->name); DrawStringF(menublock_x0, menublock_y0 - 10, top_screen, "=============================="); DrawStringF(menublock_x0, menublock_y1 + 0, top_screen, "=============================="); DrawStringF(menublock_x0, menublock_y1 + 10, top_screen, (subMenu) ? "A: Choose B: Return" : "A: Choose"); DrawStringF(menublock_x0, menublock_y1 + 20, top_screen, "SELECT: Unmount SD"); DrawStringF(menublock_x0, menublock_y1 + 30, top_screen, "START: Reboot"); DrawStringF(menublock_x1, SCREEN_HEIGHT - 20, top_screen, "Remaining SD storage space: %llu MiB", RemainingStorageSpace() / 1024 / 1024); DrawStringF(menublock_x1, SCREEN_HEIGHT - 30, top_screen, "Game directory: %s", GAME_DIR); if (DirOpen(WORK_DIR)) { DrawStringF(menublock_x1, SCREEN_HEIGHT - 40, top_screen, "Work directory: %s", WORK_DIR); DirClose(); } } if (!top_screen) DrawStringF(10, 10, true, "Selected: %-*.*s", 32, 32, currMenu->entries[index].name); for (u32 i = 0; i < currMenu->n_entries; i++) { // draw menu entries / selection [] char* name = currMenu->entries[i].name; DrawStringF(menublock_x0, menublock_y0 + (i*10), top_screen, (i == index) ? "[%s]" : " %s ", name); } }
int CfSecOpenDirectory(ServerConnectionState *conn, char *sendbuffer, char *dirname) { Dir *dirh; const struct dirent *dirp; int offset, cipherlen; char out[CF_BUFSIZE]; if (!IsAbsoluteFileName(dirname)) { sprintf(sendbuffer, "BAD: request to access a non-absolute filename\n"); cipherlen = EncryptString(conn->encryption_type, sendbuffer, out, conn->session_key, strlen(sendbuffer) + 1); SendTransaction(&conn->conn_info, out, cipherlen, CF_DONE); return -1; } if ((dirh = DirOpen(dirname)) == NULL) { Log(LOG_LEVEL_VERBOSE, "Couldn't open dir %s", dirname); snprintf(sendbuffer, CF_BUFSIZE, "BAD: cfengine, couldn't open dir %s\n", dirname); cipherlen = EncryptString(conn->encryption_type, sendbuffer, out, conn->session_key, strlen(sendbuffer) + 1); SendTransaction(&conn->conn_info, out, cipherlen, CF_DONE); return -1; } /* Pack names for transmission */ memset(sendbuffer, 0, CF_BUFSIZE); offset = 0; for (dirp = DirRead(dirh); dirp != NULL; dirp = DirRead(dirh)) { if (strlen(dirp->d_name) + 1 + offset >= CF_BUFSIZE - CF_MAXLINKSIZE) { cipherlen = EncryptString(conn->encryption_type, sendbuffer, out, conn->session_key, offset + 1); SendTransaction(&conn->conn_info, out, cipherlen, CF_MORE); offset = 0; memset(sendbuffer, 0, CF_BUFSIZE); memset(out, 0, CF_BUFSIZE); } strncpy(sendbuffer + offset, dirp->d_name, CF_MAXLINKSIZE); /* + zero byte separator */ offset += strlen(dirp->d_name) + 1; } strcpy(sendbuffer + offset, CFD_TERMINATOR); cipherlen = EncryptString(conn->encryption_type, sendbuffer, out, conn->session_key, offset + 2 + strlen(CFD_TERMINATOR)); SendTransaction(&conn->conn_info, out, cipherlen, CF_DONE); DirClose(dirh); return 0; }
int CfOpenDirectory(ServerConnectionState *conn, char *sendbuffer, char *oldDirname) { Dir *dirh; const struct dirent *dirp; int offset; char dirname[CF_BUFSIZE]; TranslatePath(dirname, oldDirname); if (!IsAbsoluteFileName(dirname)) { sprintf(sendbuffer, "BAD: request to access a non-absolute filename\n"); SendTransaction(&conn->conn_info, sendbuffer, 0, CF_DONE); return -1; } if ((dirh = DirOpen(dirname)) == NULL) { Log(LOG_LEVEL_DEBUG, "Couldn't open dir '%s'", dirname); snprintf(sendbuffer, CF_BUFSIZE, "BAD: cfengine, couldn't open dir %s\n", dirname); SendTransaction(&conn->conn_info, sendbuffer, 0, CF_DONE); return -1; } /* Pack names for transmission */ memset(sendbuffer, 0, CF_BUFSIZE); offset = 0; for (dirp = DirRead(dirh); dirp != NULL; dirp = DirRead(dirh)) { if (strlen(dirp->d_name) + 1 + offset >= CF_BUFSIZE - CF_MAXLINKSIZE) { SendTransaction(&conn->conn_info, sendbuffer, offset + 1, CF_MORE); offset = 0; memset(sendbuffer, 0, CF_BUFSIZE); } strncpy(sendbuffer + offset, dirp->d_name, CF_MAXLINKSIZE); offset += strlen(dirp->d_name) + 1; /* + zero byte separator */ } strcpy(sendbuffer + offset, CFD_TERMINATOR); SendTransaction(&conn->conn_info, sendbuffer, offset + 2 + strlen(CFD_TERMINATOR), CF_DONE); DirClose(dirh); return 0; }
static bool GetAcpi(double *cf_this) { Dir *dirh; FILE *fp; const struct dirent *dirp; int count = 0; char path[CF_BUFSIZE], buf[CF_BUFSIZE], index[4]; double temp = 0; if ((dirh = DirOpen("/proc/acpi/thermal_zone")) == NULL) { Log(LOG_LEVEL_VERBOSE, "Can't open directory '%s'. (opendir: %s)", path, GetErrorStr()); return false; } for (dirp = DirRead(dirh); dirp != NULL; dirp = DirRead(dirh)) { if (!strcmp(dirp->d_name, ".") || !strcmp(dirp->d_name, "..")) { continue; } snprintf(path, CF_BUFSIZE, "/proc/acpi/thermal_zone/%s/temperature", dirp->d_name); if ((fp = fopen(path, "r")) == NULL) { Log(LOG_LEVEL_ERR, "Couldn't open '%s'", path); continue; } if (fgets(buf, sizeof(buf), fp) == NULL) { Log(LOG_LEVEL_ERR, "Failed to read line from stream '%s'", path); fclose(fp); continue; } sscanf(buf, "%*s %lf", &temp); for (count = 0; count < 4; count++) { snprintf(index, 2, "%d", count); if (strstr(dirp->d_name, index)) { switch (count) { case 0: cf_this[ob_temp0] = temp; break; case 1: cf_this[ob_temp1] = temp; break; case 2: cf_this[ob_temp2] = temp; break; case 3: cf_this[ob_temp3] = temp; break; } Log(LOG_LEVEL_DEBUG, "Set temp%d to %lf", count, temp); } } fclose(fp); } DirClose(dirh); return true; }
void LocateFilePromiserGroup(EvalContext *ctx, char *wildpath, Promise *pp, void (*fnptr) (EvalContext *ctx, char *path, Promise *ptr)) { Item *path, *ip, *remainder = NULL; char pbuffer[CF_BUFSIZE]; struct stat statbuf; int count = 0, lastnode = false, expandregex = false; uid_t agentuid = getuid(); int create = PromiseGetConstraintAsBoolean(ctx, "create", pp); char *pathtype = ConstraintGetRvalValue(ctx, "pathtype", pp, RVAL_TYPE_SCALAR); /* Do a search for promiser objects matching wildpath */ if ((!IsPathRegex(wildpath)) || (pathtype && (strcmp(pathtype, "literal") == 0))) { Log(LOG_LEVEL_VERBOSE, "Using literal pathtype for '%s'", wildpath); (*fnptr) (ctx, wildpath, pp); return; } else { Log(LOG_LEVEL_VERBOSE, "Using regex pathtype for '%s' (see pathtype)", wildpath); } pbuffer[0] = '\0'; path = SplitString(wildpath, '/'); // require forward slash in regex on all platforms for (ip = path; ip != NULL; ip = ip->next) { if ((ip->name == NULL) || (strlen(ip->name) == 0)) { continue; } if (ip->next == NULL) { lastnode = true; } /* No need to chdir as in recursive descent, since we know about the path here */ if (IsRegex(ip->name)) { remainder = ip->next; expandregex = true; break; } else { expandregex = false; } if (!JoinPath(pbuffer, ip->name)) { Log(LOG_LEVEL_ERR, "Buffer has limited size in LocateFilePromiserGroup"); return; } if (stat(pbuffer, &statbuf) != -1) { if ((S_ISDIR(statbuf.st_mode)) && ((statbuf.st_uid) != agentuid) && ((statbuf.st_uid) != 0)) { Log(LOG_LEVEL_INFO, "Directory '%s' in search path '%s' is controlled by another user (uid %ju) - trusting its content is potentially risky (possible race condition)", pbuffer, wildpath, (uintmax_t)statbuf.st_uid); PromiseRef(LOG_LEVEL_INFO, pp); } } } if (expandregex) /* Expand one regex link and hand down */ { char nextbuffer[CF_BUFSIZE], nextbufferOrig[CF_BUFSIZE], regex[CF_BUFSIZE]; const struct dirent *dirp; Dir *dirh; memset(regex, 0, CF_BUFSIZE); strncpy(regex, ip->name, CF_BUFSIZE - 1); if ((dirh = DirOpen(pbuffer)) == NULL) { // Could be a dummy directory to be created so this is not an error. Log(LOG_LEVEL_VERBOSE, "Using best-effort expanded (but non-existent) file base path '%s'", wildpath); (*fnptr) (ctx, wildpath, pp); DeleteItemList(path); return; } else { count = 0; for (dirp = DirRead(dirh); dirp != NULL; dirp = DirRead(dirh)) { if (!ConsiderLocalFile(dirp->d_name, pbuffer)) { continue; } if ((!lastnode) && (!S_ISDIR(statbuf.st_mode))) { Log(LOG_LEVEL_DEBUG, "Skipping non-directory '%s'", dirp->d_name); continue; } if (FullTextMatch(regex, dirp->d_name)) { Log(LOG_LEVEL_DEBUG, "Link '%s' matched regex '%s'", dirp->d_name, regex); } else { continue; } count++; strncpy(nextbuffer, pbuffer, CF_BUFSIZE - 1); AddSlash(nextbuffer); strcat(nextbuffer, dirp->d_name); for (ip = remainder; ip != NULL; ip = ip->next) { AddSlash(nextbuffer); strcat(nextbuffer, ip->name); } /* The next level might still contain regexs, so go again as long as expansion is not nullpotent */ if ((!lastnode) && (strcmp(nextbuffer, wildpath) != 0)) { LocateFilePromiserGroup(ctx, nextbuffer, pp, fnptr); } else { Promise *pcopy; Log(LOG_LEVEL_VERBOSE, "Using expanded file base path '%s'", nextbuffer); /* Now need to recompute any back references to get the complete path */ snprintf(nextbufferOrig, sizeof(nextbufferOrig), "%s", nextbuffer); MapNameForward(nextbuffer); if (!FullTextMatch(pp->promiser, nextbuffer)) { Log(LOG_LEVEL_DEBUG, "Error recomputing references for '%s' in '%s'", pp->promiser, nextbuffer); } /* If there were back references there could still be match.x vars to expand */ pcopy = ExpandDeRefPromise(ctx, ScopeGetCurrent()->scope, pp); (*fnptr) (ctx, nextbufferOrig, pcopy); PromiseDestroy(pcopy); } } DirClose(dirh); } } else { Log(LOG_LEVEL_VERBOSE, "Using file base path '%s'", pbuffer); (*fnptr) (ctx, pbuffer, pp); } if (count == 0) { Log(LOG_LEVEL_VERBOSE, "No promiser file objects matched as regular expression '%s'", wildpath); if (create) { (*fnptr)(ctx, pp->promiser, pp); } } DeleteItemList(path); }
bool TraverseDirectoryTreeInternal(const char *base_path, const char *current_path, int (*callback)(const char *, const struct stat *, void *), void *user_data) { Dir *dirh = DirOpen(base_path); if (!dirh) { if (errno == ENOENT) { return true; } Log(LOG_LEVEL_INFO, "Unable to open directory '%s' during traversal of directory tree '%s' (opendir: %s)", current_path, base_path, GetErrorStr()); return false; } bool failed = false; for (const struct dirent *dirp = DirRead(dirh); dirp != NULL; dirp = DirRead(dirh)) { if (!strcmp(dirp->d_name, ".") || !strcmp(dirp->d_name, "..")) { continue; } char sub_path[CF_BUFSIZE]; snprintf(sub_path, CF_BUFSIZE, "%s" FILE_SEPARATOR_STR "%s", current_path, dirp->d_name); struct stat lsb; if (lstat(sub_path, &lsb) == -1) { if (errno == ENOENT) { /* File disappeared on its own */ continue; } Log(LOG_LEVEL_VERBOSE, "Unable to stat file '%s' during traversal of directory tree '%s' (lstat: %s)", current_path, base_path, GetErrorStr()); failed = true; } else { if (S_ISDIR(lsb.st_mode)) { if (!TraverseDirectoryTreeInternal(base_path, sub_path, callback, user_data)) { failed = true; } } else { if (callback(sub_path, &lsb, user_data) == -1) { failed = true; } } } } DirClose(dirh); return !failed; }
static bool DeleteDirectoryTreeInternal(const char *basepath, const char *path) { Dir *dirh = DirOpen(path); const struct dirent *dirp; bool failed = false; if (dirh == NULL) { if (errno == ENOENT) { /* Directory disappeared on its own */ return true; } Log(LOG_LEVEL_INFO, "Unable to open directory '%s' during purge of directory tree '%s' (opendir: %s)", path, basepath, GetErrorStr()); return false; } for (dirp = DirRead(dirh); dirp != NULL; dirp = DirRead(dirh)) { if (!strcmp(dirp->d_name, ".") || !strcmp(dirp->d_name, "..")) { continue; } char subpath[CF_BUFSIZE]; snprintf(subpath, CF_BUFSIZE, "%s" FILE_SEPARATOR_STR "%s", path, dirp->d_name); struct stat lsb; if (lstat(subpath, &lsb) == -1) { if (errno == ENOENT) { /* File disappeared on its own */ continue; } Log(LOG_LEVEL_VERBOSE, "Unable to stat file '%s' during purge of directory tree '%s' (lstat: %s)", path, basepath, GetErrorStr()); failed = true; } else { if (S_ISDIR(lsb.st_mode)) { if (!DeleteDirectoryTreeInternal(basepath, subpath)) { failed = true; } if (rmdir(subpath) == -1) { failed = true; } } else { if (unlink(subpath) == -1) { if (errno == ENOENT) { /* File disappeared on its own */ continue; } Log(LOG_LEVEL_VERBOSE, "Unable to remove file '%s' during purge of directory tree '%s'. (unlink: %s)", subpath, basepath, GetErrorStr()); failed = true; } } } } DirClose(dirh); return !failed; }
static PromiseResult VerifyFileSystem(EvalContext *ctx, char *name, Attributes a, Promise *pp) { struct stat statbuf, localstat; Dir *dirh; const struct dirent *dirp; off_t sizeinbytes = 0; long filecount = 0; char buff[CF_BUFSIZE]; Log(LOG_LEVEL_VERBOSE, "Checking required filesystem %s", name); if (stat(name, &statbuf) == -1) { return PROMISE_RESULT_NOOP; } if (S_ISLNK(statbuf.st_mode)) { KillGhostLink(ctx, name, a, pp); return PROMISE_RESULT_NOOP; } if (S_ISDIR(statbuf.st_mode)) { if ((dirh = DirOpen(name)) == NULL) { Log(LOG_LEVEL_ERR, "Can't open directory '%s' which checking required/disk. (opendir: %s)", name, GetErrorStr()); return PROMISE_RESULT_NOOP; } for (dirp = DirRead(dirh); dirp != NULL; dirp = DirRead(dirh)) { if (!ConsiderLocalFile(dirp->d_name, name)) { continue; } filecount++; strcpy(buff, name); if (buff[strlen(buff)] != FILE_SEPARATOR) { strcat(buff, FILE_SEPARATOR_STR); } strcat(buff, dirp->d_name); if (lstat(buff, &localstat) == -1) { if (S_ISLNK(localstat.st_mode)) { KillGhostLink(ctx, buff, a, pp); continue; } Log(LOG_LEVEL_ERR, "Can't stat volume '%s'. (lstat: %s)", buff, GetErrorStr()); continue; } sizeinbytes += localstat.st_size; } DirClose(dirh); if (sizeinbytes < 0) { Log(LOG_LEVEL_VERBOSE, "Internal error: count of byte size was less than zero!"); return PROMISE_RESULT_NOOP; } if (sizeinbytes < a.volume.sensible_size) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_INTERRUPTED, pp, a, "File system '%s' is suspiciously small! (%jd bytes)", name, (intmax_t) sizeinbytes); return PROMISE_RESULT_INTERRUPTED; } if (filecount < a.volume.sensible_count) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_INTERRUPTED, pp, a, "Filesystem '%s' has only %ld files/directories.", name, filecount); return PROMISE_RESULT_INTERRUPTED; } } cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_NOOP, pp, a, "Filesystem '%s' content seems to be sensible as promised", name); return PROMISE_RESULT_NOOP; }
int IsNewerFileTree(const char *dir, time_t reftime) { const struct dirent *dirp; Dir *dirh; struct stat sb; // Assumes that race conditions on the file path are unlikely and unimportant if (lstat(dir, &sb) == -1) { Log(LOG_LEVEL_ERR, "Unable to stat directory '%s' in IsNewerFileTree. (stat: %s)", dir, GetErrorStr()); // return true to provoke update return true; } if (S_ISDIR(sb.st_mode)) { if (sb.st_mtime > reftime) { Log(LOG_LEVEL_VERBOSE, " >> Detected change in %s", dir); return true; } } if ((dirh = DirOpen(dir)) == NULL) { Log(LOG_LEVEL_ERR, "Unable to open directory '%s' in IsNewerFileTree. (opendir: %s)", dir, GetErrorStr()); return false; } else { for (dirp = DirRead(dirh); dirp != NULL; dirp = DirRead(dirh)) { if (!strcmp(dirp->d_name, ".") || !strcmp(dirp->d_name, "..")) { continue; } char path[CF_BUFSIZE]; size_t ret = (size_t) snprintf(path, sizeof(path), "%s%c%s", dir, FILE_SEPARATOR, dirp->d_name); if (ret >= sizeof(path)) { Log(LOG_LEVEL_ERR, "Internal limit reached in IsNewerFileTree()," " path too long: '%s' + '%s'", dir, dirp->d_name); DirClose(dirh); return false; } if (lstat(path, &sb) == -1) { Log(LOG_LEVEL_ERR, "Unable to stat directory '%s' in IsNewerFileTree. (lstat: %s)", path, GetErrorStr()); DirClose(dirh); // return true to provoke update return true; } if (S_ISDIR(sb.st_mode)) { if (sb.st_mtime > reftime) { Log(LOG_LEVEL_VERBOSE, " >> Detected change in %s", path); DirClose(dirh); return true; } else { if (IsNewerFileTree(path, reftime)) { DirClose(dirh); return true; } } } } } DirClose(dirh); return false; }
static int VerifyFileSystem(EvalContext *ctx, char *name, Attributes a, Promise *pp) { struct stat statbuf, localstat; Dir *dirh; const struct dirent *dirp; off_t sizeinbytes = 0; long filecount = 0; char buff[CF_BUFSIZE]; CfOut(OUTPUT_LEVEL_VERBOSE, "", " -> Checking required filesystem %s\n", name); if (cfstat(name, &statbuf) == -1) { return (false); } if (S_ISLNK(statbuf.st_mode)) { KillGhostLink(ctx, name, a, pp); return (true); } if (S_ISDIR(statbuf.st_mode)) { if ((dirh = DirOpen(name)) == NULL) { CfOut(OUTPUT_LEVEL_ERROR, "opendir", "Can't open directory %s which checking required/disk\n", name); return false; } for (dirp = DirRead(dirh); dirp != NULL; dirp = DirRead(dirh)) { if (!ConsiderFile(ctx, dirp->d_name, name, a, pp)) { continue; } filecount++; strcpy(buff, name); if (buff[strlen(buff)] != FILE_SEPARATOR) { strcat(buff, FILE_SEPARATOR_STR); } strcat(buff, dirp->d_name); if (lstat(buff, &localstat) == -1) { if (S_ISLNK(localstat.st_mode)) { KillGhostLink(ctx, buff, a, pp); continue; } CfOut(OUTPUT_LEVEL_ERROR, "lstat", "Can't stat volume %s\n", buff); continue; } sizeinbytes += localstat.st_size; } DirClose(dirh); if (sizeinbytes < 0) { CfOut(OUTPUT_LEVEL_VERBOSE, "", "Internal error: count of byte size was less than zero!\n"); return true; } if (sizeinbytes < a.volume.sensible_size) { cfPS(ctx, OUTPUT_LEVEL_ERROR, PROMISE_RESULT_INTERRUPTED, "", pp, a, " !! File system %s is suspiciously small! (%jd bytes)\n", name, (intmax_t) sizeinbytes); return (false); } if (filecount < a.volume.sensible_count) { cfPS(ctx, OUTPUT_LEVEL_ERROR, PROMISE_RESULT_INTERRUPTED, "", pp, a, " !! Filesystem %s has only %ld files/directories.\n", name, filecount); return (false); } } cfPS(ctx, OUTPUT_LEVEL_INFORM, PROMISE_RESULT_NOOP, "", pp, a, " -> Filesystem %s's content seems to be sensible as promised\n", name); return (true); }
int IsNewerFileTree(char *dir, time_t reftime) { const struct dirent *dirp; char path[CF_BUFSIZE] = { 0 }; Dir *dirh; struct stat sb; // Assumes that race conditions on the file path are unlikely and unimportant if (lstat(dir, &sb) == -1) { Log(LOG_LEVEL_ERR, "Unable to stat directory '%s' in IsNewerFileTree. (stat: %s)", dir, GetErrorStr()); // return true to provoke update return true; } if (S_ISDIR(sb.st_mode)) { if (sb.st_mtime > reftime) { Log(LOG_LEVEL_VERBOSE, " >> Detected change in %s", dir); return true; } } if ((dirh = DirOpen(dir)) == NULL) { Log(LOG_LEVEL_ERR, "Unable to open directory '%s' in IsNewerFileTree. (opendir: %s)", dir, GetErrorStr()); return false; } else { for (dirp = DirRead(dirh); dirp != NULL; dirp = DirRead(dirh)) { if (!strcmp(dirp->d_name, ".") || !strcmp(dirp->d_name, "..")) { continue; } strncpy(path, dir, CF_BUFSIZE - 1); if (!JoinPath(path, dirp->d_name)) { Log(LOG_LEVEL_ERR, "Internal limit: Buffer ran out of space adding %s to %s in IsNewerFileTree", dir, path); DirClose(dirh); return false; } if (lstat(path, &sb) == -1) { Log(LOG_LEVEL_ERR, "Unable to stat directory '%s' in IsNewerFileTree. (lstat: %s)", path, GetErrorStr()); DirClose(dirh); // return true to provoke update return true; } if (S_ISDIR(sb.st_mode)) { if (sb.st_mtime > reftime) { Log(LOG_LEVEL_VERBOSE, " >> Detected change in %s", path); DirClose(dirh); return true; } else { if (IsNewerFileTree(path, reftime)) { DirClose(dirh); return true; } } } } } DirClose(dirh); return false; }