Пример #1
0
static bool
enter_dir (FTS *fts, FTSENT *ent)
{
  if (fts->fts_options & (FTS_TIGHT_CYCLE_CHECK | FTS_LOGICAL))
    {
      struct stat const *st = ent->fts_statp;
      struct Active_dir *ad = malloc (sizeof *ad);
      struct Active_dir *ad_from_table;

      if (!ad)
        return false;

      ad->dev = st->st_dev;
      ad->ino = st->st_ino;
      ad->fts_ent = ent;

      /* See if we've already encountered this directory.
         This can happen when following symlinks as well as
         with a corrupted directory hierarchy. */
      ad_from_table = hash_insert (fts->fts_cycle.ht, ad);

      if (ad_from_table != ad)
        {
          free (ad);
          if (!ad_from_table)
            return false;

          /* There was an entry with matching dev/inode already in the table.
             Record the fact that we've found a cycle.  */
          ent->fts_cycle = ad_from_table->fts_ent;
          ent->fts_info = FTS_DC;
        }
    }
  else
    {
      if (cycle_check (fts->fts_cycle.state, ent->fts_statp))
        {
          /* FIXME: setting fts_cycle like this isn't proper.
             To do what the documentation requires, we'd have to
             go around the cycle again and find the right entry.
             But no callers in coreutils use the fts_cycle member. */
          ent->fts_cycle = ent;
          ent->fts_info = FTS_DC;
        }
    }

  return true;
}
Пример #2
0
char *
canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode)
{
  char *rname, *dest, *extra_buf = NULL;
  char const *start;
  char const *end;
  char const *rname_limit;
  size_t extra_len = 0;
  struct cycle_check_state cycle_state;

  if (name == NULL)
    {
      __set_errno (EINVAL);
      return NULL;
    }

  if (name[0] == '\0')
    {
      __set_errno (ENOENT);
      return NULL;
    }

  if (name[0] != '/')
    {
      rname = xgetcwd ();
      if (!rname)
	return NULL;
      dest = strchr (rname, '\0');
      if (dest - rname < PATH_MAX)
	{
	  char *p = xrealloc (rname, PATH_MAX);
	  dest = p + (dest - rname);
	  rname = p;
	  rname_limit = rname + PATH_MAX;
	}
      else
	{
	  rname_limit = dest;
	}
    }
  else
    {
      rname = xmalloc (PATH_MAX);
      rname_limit = rname + PATH_MAX;
      rname[0] = '/';
      dest = rname + 1;
    }

  cycle_check_init (&cycle_state);
  for (start = end = name; *start; start = end)
    {
      /* Skip sequence of multiple file name separators.  */
      while (*start == '/')
	++start;

      /* Find end of component.  */
      for (end = start; *end && *end != '/'; ++end)
	/* Nothing.  */;

      if (end - start == 0)
	break;
      else if (end - start == 1 && start[0] == '.')
	/* nothing */;
      else if (end - start == 2 && start[0] == '.' && start[1] == '.')
	{
	  /* Back up to previous component, ignore if at root already.  */
	  if (dest > rname + 1)
	    while ((--dest)[-1] != '/');
	}
      else
	{
	  struct stat st;

	  if (dest[-1] != '/')
	    *dest++ = '/';

	  if (dest + (end - start) >= rname_limit)
	    {
	      ptrdiff_t dest_offset = dest - rname;
	      size_t new_size = rname_limit - rname;

	      if (end - start + 1 > PATH_MAX)
		new_size += end - start + 1;
	      else
		new_size += PATH_MAX;
	      rname = xrealloc (rname, new_size);
	      rname_limit = rname + new_size;

	      dest = rname + dest_offset;
	    }

	  dest = memcpy (dest, start, end - start);
	  dest += end - start;
	  *dest = '\0';

	  if (lstat (rname, &st) != 0)
	    {
	      if (can_mode == CAN_EXISTING)
		goto error;
	      if (can_mode == CAN_ALL_BUT_LAST && *end)
		goto error;
	      st.st_mode = 0;
	    }

	  if (S_ISLNK (st.st_mode))
	    {
	      char *buf;
	      size_t n, len;

	      if (cycle_check (&cycle_state, &st))
		{
		  __set_errno (ELOOP);
		  if (can_mode == CAN_MISSING)
		    continue;
		  else
		    goto error;
		}

	      buf = xreadlink (rname, st.st_size);
	      if (!buf)
		{
		  if (can_mode == CAN_MISSING)
		    continue;
		  else
		    goto error;
		}

	      n = strlen (buf);
	      len = strlen (end);

	      if (!extra_len)
		{
		  extra_len =
		    ((n + len + 1) > PATH_MAX) ? (n + len + 1) : PATH_MAX;
		  extra_buf = xmalloc (extra_len);
		}
	      else if ((n + len + 1) > extra_len)
		{
		  extra_len = n + len + 1;
		  extra_buf = xrealloc (extra_buf, extra_len);
		}

	      /* Careful here, end may be a pointer into extra_buf... */
	      memmove (&extra_buf[n], end, len + 1);
	      name = end = memcpy (extra_buf, buf, n);

	      if (buf[0] == '/')
		dest = rname + 1;	/* It's an absolute symlink */
	      else
		/* Back up to previous component, ignore if at root already: */
		if (dest > rname + 1)
		  while ((--dest)[-1] != '/');

	      free (buf);
	    }
	  else
	    {
	      if (!S_ISDIR (st.st_mode) && *end && (can_mode != CAN_MISSING))
		{
		  errno = ENOTDIR;
		  goto error;
		}
	    }
	}
    }
  if (dest > rname + 1 && dest[-1] == '/')
    --dest;
  *dest = '\0';

  free (extra_buf);
  return rname;

error:
  free (extra_buf);
  free (rname);
  return NULL;
}