/** Callback given to process the dataset. */ static void walk_stat_process(CIRCLE_handle* handle) { /* get path from queue */ char path[CIRCLE_MAX_STRING_LEN]; handle->dequeue(path); /* stat item */ struct stat st; int status = mfu_lstat(path, &st); if (status != 0) { /* print error */ return; } /* increment our item count */ reduce_items++; /* TODO: filter items by stat info */ if (REMOVE_FILES && !S_ISDIR(st.st_mode)) { mfu_unlink(path); } else { /* record info for item in list */ mfu_flist_insert_stat(CURRENT_LIST, path, st.st_mode, &st); } /* recurse into directory */ if (S_ISDIR(st.st_mode)) { /* before more processing check if SET_DIR_PERMS is set, * and set usr read and execute bits if need be */ if (SET_DIR_PERMS) { /* use masks to check if usr_r and usr_x are already on */ long usr_r_mask = 1 << 8; long usr_x_mask = 1 << 6; /* turn on the usr read & execute bits if they are not already on*/ if (!((usr_r_mask & st.st_mode) && (usr_x_mask & st.st_mode))) { st.st_mode |= S_IRUSR; st.st_mode |= S_IXUSR; mfu_chmod(path, st.st_mode); } } /* TODO: check that we can recurse into directory */ walk_stat_process_dir(path, handle); } return; }
/* removes name by calling rmdir, unlink, or remove depending * on item type */ static void remove_type(char type, const char* name) { /* TODO: don't print message if errno == ENOENT (file already gone) */ if (type == 'd') { int rc = mfu_rmdir(name); if (rc != 0) { MFU_LOG(MFU_LOG_ERR, "Failed to rmdir `%s' (errno=%d %s)", name, errno, strerror(errno) ); } } else if (type == 'f') { int rc = mfu_unlink(name); if (rc != 0) { MFU_LOG(MFU_LOG_ERR, "Failed to unlink `%s' (errno=%d %s)", name, errno, strerror(errno) ); } } else if (type == 'u') { int rc = remove(name); if (rc != 0) { MFU_LOG(MFU_LOG_ERR, "Failed to remove `%s' (errno=%d %s)", name, errno, strerror(errno) ); } } else { /* print error */ MFU_LOG(MFU_LOG_ERR, "Unknown type=%c name=%s", type, name ); } return; }
static void walk_readdir_process_dir(const char* dir, CIRCLE_handle* handle) { /* TODO: may need to try these functions multiple times */ DIR* dirp = mfu_opendir(dir); /* if there is a permissions error and the usr read & execute are being turned * on when walk_stat=0 then catch the permissions error and turn the bits on */ if (dirp == NULL) { if (errno == EACCES && SET_DIR_PERMS) { struct stat st; mfu_lstat(dir, &st); // turn on the usr read & execute bits st.st_mode |= S_IRUSR; st.st_mode |= S_IXUSR; mfu_chmod(dir, st.st_mode); dirp = mfu_opendir(dir); if (dirp == NULL) { if (errno == EACCES) { MFU_LOG(MFU_LOG_ERR, "Failed to open directory with opendir: `%s' (errno=%d %s)", dir, errno, strerror(errno)); } } } } if (! dirp) { /* TODO: print error */ } else { /* Read all directory entries */ while (1) { /* read next directory entry */ struct dirent* entry = mfu_readdir(dirp); if (entry == NULL) { break; } /* process component, unless it's "." or ".." */ char* name = entry->d_name; if ((strncmp(name, ".", 2)) && (strncmp(name, "..", 3))) { /* <dir> + '/' + <name> + '/0' */ char newpath[CIRCLE_MAX_STRING_LEN]; size_t len = strlen(dir) + 1 + strlen(name) + 1; if (len < sizeof(newpath)) { /* build full path to item */ strcpy(newpath, dir); strcat(newpath, "/"); strcat(newpath, name); #ifdef _DIRENT_HAVE_D_TYPE /* record info for item */ mode_t mode; int have_mode = 0; if (entry->d_type != DT_UNKNOWN) { /* unlink files here if remove option is on, * and dtype is known without a stat */ if (REMOVE_FILES && (entry->d_type != DT_DIR)) { mfu_unlink(newpath); } else { /* we can read object type from directory entry */ have_mode = 1; mode = DTTOIF(entry->d_type); mfu_flist_insert_stat(CURRENT_LIST, newpath, mode, NULL); } } else { /* type is unknown, we need to stat it */ struct stat st; int status = mfu_lstat(newpath, &st); if (status == 0) { have_mode = 1; mode = st.st_mode; /* unlink files here if remove option is on, * and stat was necessary to get type */ if (REMOVE_FILES && !S_ISDIR(st.st_mode)) { mfu_unlink(newpath); } else { mfu_flist_insert_stat(CURRENT_LIST, newpath, mode, &st); } } else { /* error */ } } /* increment our item count */ reduce_items++; /* recurse into directories */ if (have_mode && S_ISDIR(mode)) { handle->enqueue(newpath); } #endif } else { /* TODO: print error in correct format */ /* name is too long */ MFU_LOG(MFU_LOG_ERR, "Path name is too long: %lu chars exceeds limit %lu", len, sizeof(newpath)); } } } } mfu_closedir(dirp); return; }