Exemple #1
0
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;
    }
}
Exemple #2
0
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;
}
Exemple #3
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;
    }
}
Exemple #4
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;
    }
}