Example #1
0
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;
    }
}
Example #2
0
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;
    }
}