コード例 #1
0
ファイル: ftsfind.c プロジェクト: fishilico/findutils-xattr
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;
    }
}
コード例 #2
0
ファイル: print.c プロジェクト: hnw/iOS-FindCmd
static void
do_fprintf (struct format_val *dest,
            struct segment *segment,
            const char *pathname,
            const struct stat *stat_buf)
{
  char hbuf[LONGEST_HUMAN_READABLE + 1];
  const char *cp;

  switch (segment->segkind)
    {
    case KIND_PLAIN:    /* Plain text string (no % conversion). */
      /* trusted */
      checked_fwrite(segment->text, 1, segment->text_len, dest);
      break;

    case KIND_STOP:             /* Terminate argument and flush output. */
      /* trusted */
      checked_fwrite (segment->text, 1, segment->text_len, dest);
      checked_fflush (dest);
      break;

    case KIND_FORMAT:
      switch (segment->format_char[0])
        {
        case 'a':               /* atime in `ctime' format. */
          /* UNTRUSTED, probably unexploitable */
          checked_fprintf (dest, segment->text, ctime_format (get_stat_atime (stat_buf)));
          break;
        case 'b':               /* size in 512-byte blocks */
          /* UNTRUSTED, probably unexploitable */
          checked_fprintf (dest, segment->text,
                           human_readable ((uintmax_t) ST_NBLOCKS (*stat_buf),
                                           hbuf, human_ceiling,
                                           ST_NBLOCKSIZE, 512));
          break;
        case 'c':               /* ctime in `ctime' format */
          /* UNTRUSTED, probably unexploitable */
          checked_fprintf (dest, segment->text, ctime_format (get_stat_ctime (stat_buf)));
          break;
        case 'd':               /* depth in search tree */
          /* UNTRUSTED, probably unexploitable */
          checked_fprintf (dest, segment->text, state.curdepth);
          break;
        case 'D':               /* Device on which file exists (stat.st_dev) */
          /* trusted */
          checked_fprintf (dest, segment->text,
                           human_readable ((uintmax_t) stat_buf->st_dev, hbuf,
                                           human_ceiling, 1, 1));
          break;
        case 'f':               /* base name of path */
          /* sanitised */
          {
            char *base = base_name (pathname);
            checked_print_quoted (dest, segment->text, base);
            free (base);
          }
          break;
        case 'F':               /* file system type */
          /* trusted */
          checked_print_quoted (dest, segment->text, filesystem_type (stat_buf, pathname));
          break;
        case 'g':               /* group name */
          /* trusted */
          /* (well, the actual group is selected by the user but
           * its name was selected by the system administrator)
           */
          {
            struct group *g;

            g = getgrgid (stat_buf->st_gid);
            if (g)
              {
                segment->text[segment->text_len] = 's';
                checked_fprintf (dest, segment->text, g->gr_name);
                break;
              }
            else
              {
                /* Do nothing. */
                /*FALLTHROUGH*/
              }
          }
          /*FALLTHROUGH*/ /*...sometimes, so 'G' case.*/

        case 'G':               /* GID number */
          /* UNTRUSTED, probably unexploitable */
          checked_fprintf (dest, segment->text,
                           human_readable ((uintmax_t) stat_buf->st_gid, hbuf,
                                           human_ceiling, 1, 1));
          break;
        case 'h':               /* leading directories part of path */
          /* sanitised */
          {
            cp = strrchr (pathname, '/');
            if (cp == NULL)     /* No leading directories. */
              {
                /* If there is no slash in the pathname, we still
                 * print the string because it contains characters
                 * other than just '%s'.  The %h expands to ".".
                 */
                checked_print_quoted (dest, segment->text, ".");
              }
            else
              {
                char *s = strdup (pathname);
                s[cp - pathname] = 0;
                checked_print_quoted (dest, segment->text, s);
                free (s);
              }
          }
          break;

        case 'H':               /* ARGV element file was found under */
          /* trusted */
          {
            char *s = xmalloc (state.starting_path_length+1);
            memcpy (s, pathname, state.starting_path_length);
            s[state.starting_path_length] = 0;
            checked_fprintf (dest, segment->text, s);
            free (s);
          }
          break;

        case 'i':               /* inode number */
          /* UNTRUSTED, but not exploitable I think */
          /* POSIX does not guarantee that ino_t is unsigned or even
           * integral (except as an XSI extension), but we'll work on
           * fixing that if we ever get a report of a system where
           * ino_t is indeed a signed integral type or a non-integral
           * arithmetic type. */
          checked_fprintf (dest, segment->text,
                           human_readable ((uintmax_t) stat_buf->st_ino, hbuf,
                                           human_ceiling,
                                           1, 1));
          break;
        case 'k':               /* size in 1K blocks */
          /* UNTRUSTED, but not exploitable I think */
          checked_fprintf (dest, segment->text,
                           human_readable ((uintmax_t) ST_NBLOCKS (*stat_buf),
                                           hbuf, human_ceiling,
                                           ST_NBLOCKSIZE, 1024));
          break;
        case 'l':               /* object of symlink */
          /* sanitised */
#ifdef S_ISLNK
          {
            char *linkname = 0;

            if (S_ISLNK (stat_buf->st_mode))
              {
                linkname = areadlinkat (state.cwd_dir_fd, state.rel_pathname);
                if (linkname == NULL)
                  {
                    nonfatal_target_file_error (errno, pathname);
                    state.exit_status = 1;
                  }
              }
            if (linkname)
              {
                checked_print_quoted (dest, segment->text, linkname);
              }
            else
              {
                /* We still need to honour the field width etc., so this is
                 * not a no-op.
                 */
                checked_print_quoted (dest, segment->text, "");
              }
            free (linkname);
          }
#endif                          /* S_ISLNK */
          break;

        case 'M':               /* mode as 10 chars (eg., "-rwxr-x--x" */
          /* UNTRUSTED, probably unexploitable */
          {
            char modestring[16] ;
            filemodestring (stat_buf, modestring);
            modestring[10] = '\0';
            checked_fprintf (dest, segment->text, modestring);
          }
          break;

        case 'm':               /* mode as octal number (perms only) */
          /* UNTRUSTED, probably unexploitable */
          {
            /* Output the mode portably using the traditional numbers,
               even if the host unwisely uses some other numbering
               scheme.  But help the compiler in the common case where
               the host uses the traditional numbering scheme.  */
            mode_t m = stat_buf->st_mode;
            bool traditional_numbering_scheme =
              (S_ISUID == 04000 && S_ISGID == 02000 && S_ISVTX == 01000
               && S_IRUSR == 00400 && S_IWUSR == 00200 && S_IXUSR == 00100
               && S_IRGRP == 00040 && S_IWGRP == 00020 && S_IXGRP == 00010
               && S_IROTH == 00004 && S_IWOTH == 00002 && S_IXOTH == 00001);
            checked_fprintf (dest, segment->text,
                     (traditional_numbering_scheme
                      ? m & MODE_ALL
                      : ((m & S_ISUID ? 04000 : 0)
                         | (m & S_ISGID ? 02000 : 0)
                         | (m & S_ISVTX ? 01000 : 0)
                         | (m & S_IRUSR ? 00400 : 0)
                         | (m & S_IWUSR ? 00200 : 0)
                         | (m & S_IXUSR ? 00100 : 0)
                         | (m & S_IRGRP ? 00040 : 0)
                         | (m & S_IWGRP ? 00020 : 0)
                         | (m & S_IXGRP ? 00010 : 0)
                         | (m & S_IROTH ? 00004 : 0)
                         | (m & S_IWOTH ? 00002 : 0)
                         | (m & S_IXOTH ? 00001 : 0))));
          }
          break;

        case 'n':               /* number of links */
          /* UNTRUSTED, probably unexploitable */
          checked_fprintf (dest, segment->text,
                   human_readable ((uintmax_t) stat_buf->st_nlink,
                                   hbuf,
                                   human_ceiling,
                                   1, 1));
          break;

        case 'p':               /* pathname */
          /* sanitised */
          checked_print_quoted (dest, segment->text, pathname);
          break;

        case 'P':               /* pathname with ARGV element stripped */
          /* sanitised */
          if (state.curdepth > 0)
            {
              cp = pathname + state.starting_path_length;
              if (*cp == '/')
                /* Move past the slash between the ARGV element
                   and the rest of the pathname.  But if the ARGV element
                   ends in a slash, we didn't add another, so we've
                   already skipped past it.  */
                cp++;
            }
          else
            {
              cp = "";
            }
          checked_print_quoted (dest, segment->text, cp);
          break;

        case 's':               /* size in bytes */
          /* UNTRUSTED, probably unexploitable */
          checked_fprintf (dest, segment->text,
                   human_readable ((uintmax_t) stat_buf->st_size,
                                   hbuf, human_ceiling, 1, 1));
          break;

        case 'S':               /* sparseness */
          /* UNTRUSTED, probably unexploitable */
          checked_fprintf (dest, segment->text, file_sparseness (stat_buf));
          break;

        case 't':               /* mtime in `ctime' format */
          /* UNTRUSTED, probably unexploitable */
          checked_fprintf (dest, segment->text,
                           ctime_format (get_stat_mtime (stat_buf)));
          break;

        case 'u':               /* user name */
          /* trusted */
          /* (well, the actual user is selected by the user on systems
           * where chown is not restricted, but the user name was
           * selected by the system administrator)
           */
          {
            struct passwd *p;

            p = getpwuid (stat_buf->st_uid);
            if (p)
              {
                segment->text[segment->text_len] = 's';
                checked_fprintf (dest, segment->text, p->pw_name);
                break;
              }
            /* else fallthru */
          }
          /* FALLTHROUGH*/ /* .. to case U */

        case 'U':               /* UID number */
          /* UNTRUSTED, probably unexploitable */
          checked_fprintf (dest, segment->text,
                           human_readable ((uintmax_t) stat_buf->st_uid, hbuf,
                                           human_ceiling, 1, 1));
          break;

          /* %Y: type of file system entry like `ls -l`:
           *     (d,-,l,s,p,b,c,n) n=nonexistent (symlink)
           */
        case 'Y':               /* in case of symlink */
          /* trusted */
          {
#ifdef S_ISLNK
            if (S_ISLNK (stat_buf->st_mode))
              {
                struct stat sbuf;
                /* If we would normally follow links, do not do so.
                 * If we would normally not follow links, do so.
                 */
                if ((following_links () ? optionp_stat : optionl_stat)
                    (state.rel_pathname, &sbuf) != 0)
                  {
                    if ( errno == ENOENT )
                      {
                        checked_fprintf (dest, segment->text, "N");
                        break;
                      }
                    else if ( errno == ELOOP )
                      {
                        checked_fprintf (dest, segment->text, "L");
                        break;
                      }
                    else
                      {
                        checked_fprintf (dest, segment->text, "?");
                        error (0, errno, "%s",
                               safely_quote_err_filename (0, pathname));
                        /* exit_status = 1;
                           return ; */
                        break;
                      }
                  }
                checked_fprintf (dest, segment->text,
                                 mode_to_filetype (sbuf.st_mode & S_IFMT));
              }
#endif /* S_ISLNK */
            else
              {
                checked_fprintf (dest, segment->text,
                                 mode_to_filetype (stat_buf->st_mode & S_IFMT));
              }
          }
          break;

        case 'y':
          /* trusted */
          {
            checked_fprintf (dest, segment->text,
                             mode_to_filetype (stat_buf->st_mode & S_IFMT));
          }
          break;

        case 'Z':               /* SELinux security context */
          {
            security_context_t scontext;
            int rv = (*options.x_getfilecon) (state.cwd_dir_fd, state.rel_pathname,
                                              &scontext);
            if (rv < 0)
              {
                /* If getfilecon fails, there will in the general case
                   still be some text to print.   We just make %Z expand
                   to an empty string. */
                checked_fprintf (dest, segment->text, "");

                error (0, errno, _("getfilecon failed: %s"),
                    safely_quote_err_filename (0, pathname));
                state.exit_status = 1;
              }
            else
              {
                checked_fprintf (dest, segment->text, scontext);
                freecon (scontext);
              }
          }
          break;

        case 0:
        case '%':
          checked_fprintf (dest, segment->text);
          break;
        }
      /* end of KIND_FORMAT case */
      break;
    }
}