static void find(char *arg) { char * arglist[2]; FTS *p; FTSENT *ent; state.starting_path_length = strlen(arg); inside_dir(AT_FDCWD); arglist[0] = arg; arglist[1] = NULL; switch (options.symlink_handling) { case SYMLINK_ALWAYS_DEREF: ftsoptions |= FTS_COMFOLLOW|FTS_LOGICAL; break; case SYMLINK_DEREF_ARGSONLY: ftsoptions |= FTS_COMFOLLOW|FTS_PHYSICAL; break; case SYMLINK_NEVER_DEREF: ftsoptions |= FTS_PHYSICAL; break; } if (options.stay_on_filesystem) ftsoptions |= FTS_XDEV; p = fts_open(arglist, ftsoptions, NULL); if (NULL == p) { error (0, errno, _("cannot search %s"), safely_quote_err_filename(0, arg)); } else { while ( (ent=fts_read(p)) != NULL ) { state.have_stat = false; state.have_type = false; state.type = 0; consider_visiting(p, ent); } fts_close(p); p = NULL; } }
static bool find (char *arg) { char * arglist[2]; FTS *p; FTSENT *ent; state.starting_path_length = strlen (arg); inside_dir (AT_FDCWD); arglist[0] = arg; arglist[1] = NULL; switch (options.symlink_handling) { case SYMLINK_ALWAYS_DEREF: ftsoptions |= FTS_COMFOLLOW|FTS_LOGICAL; break; case SYMLINK_DEREF_ARGSONLY: ftsoptions |= FTS_COMFOLLOW|FTS_PHYSICAL; break; case SYMLINK_NEVER_DEREF: ftsoptions |= FTS_PHYSICAL; break; } if (options.stay_on_filesystem) ftsoptions |= FTS_XDEV; p = fts_open (arglist, ftsoptions, NULL); if (NULL == p) { error (0, errno, _("cannot search %s"), safely_quote_err_filename (0, arg)); error_severity (EXIT_FAILURE); } else { int level = INT_MIN; while ( (errno=0, ent=fts_read (p)) != NULL ) { if (state.execdirs_outstanding) { /* If we changed level, perform any outstanding * execdirs. If we see a sequence of directory entries * like this: fffdfffdfff, we could build a command line * of 9 files, but this simple-minded implementation * builds a command line for only 3 files at a time * (since fts descends into the directories). */ if ((int)ent->fts_level != level) { show_outstanding_execdirs (stderr); complete_pending_execdirs (); } } level = (int)ent->fts_level; state.already_issued_stat_error_msg = false; state.have_stat = false; state.have_type = !!ent->fts_statp->st_mode; state.type = state.have_type ? ent->fts_statp->st_mode : 0; consider_visiting (p, ent); } /* fts_read returned NULL; distinguish between "finished" and "error". */ if (errno) { error (0, errno, "failed to read file names from file system at or below %s", safely_quote_err_filename (0, arg)); error_severity (EXIT_FAILURE); return false; } if (0 != fts_close (p)) { /* Here we break the abstraction of fts_close a bit, because we * are going to skip the rest of the start points, and return with * nonzero exit status. Hence we need to issue a diagnostic on * stderr. */ error (0, errno, _("failed to restore working directory after searching %s"), arg); error_severity (EXIT_FAILURE); return false; } p = NULL; } return true; }
static void consider_visiting (FTS *p, FTSENT *ent) { struct stat statbuf; mode_t mode; int ignore, isdir; if (options.debug_options & DebugSearch) fprintf (stderr, "consider_visiting (early): %s: " "fts_info=%-6s, fts_level=%2d, prev_depth=%d " "fts_path=%s, fts_accpath=%s\n", quotearg_n_style (0, options.err_quoting_style, ent->fts_path), get_fts_info_name (ent->fts_info), (int)ent->fts_level, prev_depth, quotearg_n_style (1, options.err_quoting_style, ent->fts_path), quotearg_n_style (2, options.err_quoting_style, ent->fts_accpath)); if (ent->fts_info == FTS_DP) { left_dir (); } else if (ent->fts_level > prev_depth || ent->fts_level==0) { left_dir (); } inside_dir (p->fts_cwd_fd); prev_depth = ent->fts_level; statbuf.st_ino = ent->fts_statp->st_ino; /* Cope with various error conditions. */ if (ent->fts_info == FTS_ERR || ent->fts_info == FTS_DNR) { nonfatal_target_file_error (ent->fts_errno, ent->fts_path); return; } else if (ent->fts_info == FTS_DC) { issue_loop_warning (ent); error_severity (EXIT_FAILURE); return; } else if (ent->fts_info == FTS_SLNONE) { /* fts_read() claims that ent->fts_accpath is a broken symbolic * link. That would be fine, but if this is part of a symbolic * link loop, we diagnose the problem and also ensure that the * eventual return value is nonzero. Note that while the path * we stat is local (fts_accpath), we print the full path name * of the file (fts_path) in the error message. */ if (symlink_loop (ent->fts_accpath)) { nonfatal_target_file_error (ELOOP, ent->fts_path); return; } } else if (ent->fts_info == FTS_NS) { if (ent->fts_level == 0) { /* e.g., nonexistent starting point */ nonfatal_target_file_error (ent->fts_errno, ent->fts_path); return; } else { /* The following if statement fixes Savannah bug #19605 * (failure to diagnose a symbolic link loop) */ if (symlink_loop (ent->fts_accpath)) { nonfatal_target_file_error (ELOOP, ent->fts_path); return; } else { nonfatal_target_file_error (ent->fts_errno, ent->fts_path); /* Continue despite the error, as file name without stat info * might be better than not even processing the file name. This * can lead to repeated error messages later on, though, if a * predicate requires stat information. * * Not printing an error message here would be even more wrong, * though, as this could cause the contents of a directory to be * silently ignored, as the directory wouldn't be identified as * such. */ } } } /* Cope with the usual cases. */ if (ent->fts_info == FTS_NSOK || ent->fts_info == FTS_NS /* e.g. symlink loop */) { assert (!state.have_stat); assert (ent->fts_info == FTS_NSOK || state.type == 0); mode = state.type; } else { state.have_stat = true; state.have_type = true; statbuf = *(ent->fts_statp); state.type = mode = statbuf.st_mode; if (00000 == mode) { /* Savannah bug #16378. */ error (0, 0, _("WARNING: file %s appears to have mode 0000"), quotearg_n_style (0, options.err_quoting_style, ent->fts_path)); } } /* update state.curdepth before calling digest_mode(), because digest_mode * may call following_links(). */ state.curdepth = ent->fts_level; if (mode) { if (!digest_mode (&mode, ent->fts_path, ent->fts_name, &statbuf, 0)) return; } /* examine this item. */ ignore = 0; isdir = S_ISDIR(mode) || (FTS_D == ent->fts_info) || (FTS_DP == ent->fts_info) || (FTS_DC == ent->fts_info); if (isdir && (ent->fts_info == FTS_NSOK)) { /* This is a directory, but fts did not stat it, so * presumably would not be planning to search its * children. Force a stat of the file so that the * children can be checked. */ fts_set (p, ent, FTS_AGAIN); return; } if (options.maxdepth >= 0) { if (ent->fts_level >= options.maxdepth) { fts_set (p, ent, FTS_SKIP); /* descend no further */ if (ent->fts_level > options.maxdepth) ignore = 1; /* don't even look at this one */ } } if ( (ent->fts_info == FTS_D) && !options.do_dir_first ) { /* this is the preorder visit, but user said -depth */ ignore = 1; } else if ( (ent->fts_info == FTS_DP) && options.do_dir_first ) { /* this is the postorder visit, but user didn't say -depth */ ignore = 1; } else if (ent->fts_level < options.mindepth) { ignore = 1; } if (options.debug_options & DebugSearch) fprintf (stderr, "consider_visiting (late): %s: " "fts_info=%-6s, isdir=%d ignore=%d have_stat=%d have_type=%d \n", quotearg_n_style (0, options.err_quoting_style, ent->fts_path), get_fts_info_name (ent->fts_info), isdir, ignore, state.have_stat, state.have_type); if (!ignore) { visit (p, ent, &statbuf); } if (ent->fts_info == FTS_DP) { /* we're leaving a directory. */ state.stop_at_current_level = false; } }
static void consider_visiting(FTS *p, FTSENT *ent) { struct stat statbuf; mode_t mode; int ignore, isdir; if (options.debug_options & DebugSearch) fprintf(stderr, "consider_visiting: fts_info=%-6s, fts_level=%2d, prev_depth=%d " "fts_path=%s, fts_accpath=%s\n", get_fts_info_name(ent->fts_info), (int)ent->fts_level, prev_depth, quotearg_n_style(0, options.err_quoting_style, ent->fts_path), quotearg_n_style(1, options.err_quoting_style, ent->fts_accpath)); if (ent->fts_info == FTS_DP) { left_dir(); } else if (ent->fts_level > prev_depth || ent->fts_level==0) { left_dir(); } inside_dir(p->fts_cwd_fd); prev_depth = ent->fts_level; /* Cope with various error conditions. */ if (ent->fts_info == FTS_ERR || ent->fts_info == FTS_DNR) { error(0, ent->fts_errno, "%s", safely_quote_err_filename(0, ent->fts_path)); error_severity(1); return; } else if (ent->fts_info == FTS_DC) { issue_loop_warning(ent); error_severity(1); return; } else if (ent->fts_info == FTS_SLNONE) { /* fts_read() claims that ent->fts_accpath is a broken symbolic * link. That would be fine, but if this is part of a symbolic * link loop, we diagnose the problem and also ensure that the * eventual return value is nonzero. Note that while the path * we stat is local (fts_accpath), we print the full path name * of the file (fts_path) in the error message. */ if (symlink_loop(ent->fts_accpath)) { error(0, ELOOP, "%s", safely_quote_err_filename(0, ent->fts_path)); error_severity(1); return; } } else if (ent->fts_info == FTS_NS) { if (ent->fts_level == 0) { /* e.g., nonexistent starting point */ error(0, ent->fts_errno, "%s", safely_quote_err_filename(0, ent->fts_path)); error_severity(1); /* remember problem */ return; } else { /* The following if statement fixes Savannah bug #19605 * (failure to diagnose a symbolic link loop) */ if (symlink_loop(ent->fts_accpath)) { error(0, ELOOP, "%s", safely_quote_err_filename(0, ent->fts_path)); error_severity(1); return; } } } /* Cope with the usual cases. */ if (ent->fts_info == FTS_NSOK || ent->fts_info == FTS_NS /* e.g. symlink loop */) { assert (!state.have_stat); assert (!state.have_type); state.type = mode = 0; } else { state.have_stat = true; state.have_type = true; statbuf = *(ent->fts_statp); state.type = mode = statbuf.st_mode; if (00000 == mode) { /* Savannah bug #16378. */ error(0, 0, _("Warning: file %s appears to have mode 0000"), quotearg_n_style(0, options.err_quoting_style, ent->fts_path)); } } if (mode) { if (!digest_mode(mode, ent->fts_path, ent->fts_name, &statbuf, 0)) return; } /* examine this item. */ ignore = 0; isdir = S_ISDIR(mode) || (FTS_D == ent->fts_info) || (FTS_DP == ent->fts_info) || (FTS_DC == ent->fts_info); if (isdir && (ent->fts_info == FTS_NSOK)) { /* This is a directory, but fts did not stat it, so * presumably would not be planning to search its * children. Force a stat of the file so that the * children can be checked. */ fts_set(p, ent, FTS_AGAIN); return; } if (options.maxdepth >= 0) { if (ent->fts_level >= options.maxdepth) { fts_set(p, ent, FTS_SKIP); /* descend no further */ if (ent->fts_level > options.maxdepth) ignore = 1; /* don't even look at this one */ } } if ( (ent->fts_info == FTS_D) && !options.do_dir_first ) { /* this is the preorder visit, but user said -depth */ ignore = 1; } else if ( (ent->fts_info == FTS_DP) && options.do_dir_first ) { /* this is the postorder visit, but user didn't say -depth */ ignore = 1; } else if (ent->fts_level < options.mindepth) { ignore = 1; } if (!ignore) { visit(p, ent, &statbuf); } /* XXX: if we allow a build-up of pending arguments for "-execdir foo {} +" * we need to execute them in the same directory as we found the item. * If we are trying to do "find a -execdir echo {} +", we will need to * echo * a while in the original working directory * b while in a * c while in b (just before leaving b) * * These restrictions are hard to satisfy while using fts(). The reason is * that it doesn't tell us just before we leave a directory. For the moment, * we punt and don't allow the arguments to build up. */ if (state.execdirs_outstanding) { show_outstanding_execdirs(stderr); run_in_dir(p->fts_cwd_fd, complete_execdirs_cb, NULL); } if (ent->fts_info == FTS_DP) { /* we're leaving a directory. */ state.stop_at_current_level = false; } }