Exemple #1
0
static char *
savedirstream (DIR *dirp)
{
  char *name_space;
  size_t allocated = NAME_SIZE_DEFAULT;
  size_t used = 0;
  int save_errno;

  if (dirp == NULL)
    return NULL;

  name_space = xmalloc (allocated);

  for (;;)
    {
      struct dirent const *dp;
      char const *entry;

      errno = 0;
      dp = readdir (dirp);
      if (! dp)
	break;

      /* Skip "", ".", and "..".  "" is returned by at least one buggy
         implementation: Solaris 2.4 readdir on NFS file systems.  */
      entry = dp->d_name;
      if (entry[entry[0] != '.' ? 0 : entry[1] != '.' ? 1 : 2] != '\0')
	{
	  size_t entry_size = _D_EXACT_NAMLEN (dp) + 1;
	  if (used + entry_size < used)
	    xalloc_die ();
	  if (allocated <= used + entry_size)
	    {
	      do
		{
		  if (2 * allocated < allocated)
		    xalloc_die ();
		  allocated *= 2;
		}
	      while (allocated <= used + entry_size);

	      name_space = xrealloc (name_space, allocated);
	    }
	  memcpy (name_space + used, entry, entry_size);
	  used += entry_size;
	}
    }
  name_space[used] = '\0';
  save_errno = errno;
  if (closedir (dirp) != 0)
    save_errno = errno;
  if (save_errno != 0)
    {
      free (name_space);
      errno = save_errno;
      return NULL;
    }
  return name_space;
}
Exemple #2
0
/* Return the number of bytes in DP's name.  */
static ptrdiff_t
dirent_namelen (struct dirent *dp)
{
#ifdef _D_EXACT_NAMLEN
  return _D_EXACT_NAMLEN (dp);
#else
  return strlen (dp->d_name);
#endif
}
Exemple #3
0
static int
internal_function attribute_compat_text_section
getttyname_r (char *buf, size_t buflen, dev_t mydev, ino64_t myino,
	      int save, int *dostat)
{
  struct stat64 st;
  DIR *dirstream;
  struct dirent64 *d;
  size_t devlen = strlen (buf);

  dirstream = __opendir (buf);
  if (dirstream == NULL)
    {
      *dostat = -1;
      return errno;
    }

  while ((d = __readdir64 (dirstream)) != NULL)
    if ((d->d_fileno == myino || *dostat)
	&& strcmp (d->d_name, "stdin")
	&& strcmp (d->d_name, "stdout")
	&& strcmp (d->d_name, "stderr"))
      {
	char *cp;
	size_t needed = _D_EXACT_NAMLEN (d) + 1;

	if (needed > buflen)
	  {
	    *dostat = -1;
	    (void) __closedir (dirstream);
	    __set_errno (ERANGE);
	    return ERANGE;
	  }

	cp = __stpncpy (buf + devlen, d->d_name, needed);
	cp[0] = '\0';

	if (__xstat64 (_STAT_VER, buf, &st) == 0
#ifdef _STATBUF_ST_RDEV
	    && S_ISCHR (st.st_mode) && st.st_rdev == mydev
#else
	    && d->d_fileno == myino && st.st_dev == mydev
#endif
	   )
	  {
	    (void) __closedir (dirstream);
	    __set_errno (save);
	    return 0;
	  }
      }

  (void) __closedir (dirstream);
  __set_errno (save);
  /* It is not clear what to return in this case.  `isatty' says FD
     refers to a TTY but no entry in /dev has this inode.  */
  return ENOTTY;
}
Exemple #4
0
internal_function
fts_build (FTSOBJ *sp, int type)
{
	struct dirent *dp;
	FTSENTRY *p, *head;
	int nitems;
	FTSENTRY *cur, *tail;
	DIR *dirp;
	void *oldaddr;
	int cderrno, descend, len, level, nlinks, saved_errno,
	    nostat, doadjust;
	size_t maxlen;
	char *cp;

	/* Set current node pointer. */
	cur = sp->fts_cur;

	/*
	 * Open the directory for reading.  If this fails, we're done.
	 * If being called from fts_read, set the fts_info field.
	 */
#if defined FTS_WHITEOUT && 0
	if (ISSET(FTS_WHITEOUT))
		oflag = DTF_NODUP|DTF_REWIND;
	else
		oflag = DTF_HIDEW|DTF_NODUP|DTF_REWIND;
#else
# define __opendir2(path, flag) __opendir(path)
#endif
       if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) {
		if (type == BREAD) {
			cur->fts_info = FTS_DNR;
			cur->fts_errno = errno;
		}
		return (NULL);
	}

	/*
	 * Nlinks is the number of possible entries of type directory in the
	 * directory if we're cheating on stat calls, 0 if we're not doing
	 * any stat calls at all, -1 if we're doing stats on everything.
	 */
	if (type == BNAMES) {
		nlinks = 0;
		/* Be quiet about nostat, GCC. */
		nostat = 0;
	} else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) {
		nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2);
		nostat = 1;
	} else {
		nlinks = -1;
		nostat = 0;
	}

#ifdef notdef
	(void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink);
	(void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n",
	    ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT));
#endif
	/*
	 * If we're going to need to stat anything or we want to descend
	 * and stay in the directory, chdir.  If this fails we keep going,
	 * but set a flag so we don't chdir after the post-order visit.
	 * We won't be able to stat anything, but we can still return the
	 * names themselves.  Note, that since fts_read won't be able to
	 * chdir into the directory, it will have to return different path
	 * names than before, i.e. "a/b" instead of "b".  Since the node
	 * has already been visited in pre-order, have to wait until the
	 * post-order visit to return the error.  There is a special case
	 * here, if there was nothing to stat then it's not an error to
	 * not be able to stat.  This is all fairly nasty.  If a program
	 * needed sorted entries or stat information, they had better be
	 * checking FTS_NS on the returned nodes.
	 */
	cderrno = 0;
	if (nlinks || type == BREAD) {
		if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) {
			if (nlinks && type == BREAD)
				cur->fts_errno = errno;
			cur->fts_flags |= FTS_DONTCHDIR;
			descend = 0;
			cderrno = errno;
			(void)__closedir(dirp);
			dirp = NULL;
		} else
			descend = 1;
	} else
		descend = 0;

	/*
	 * Figure out the max file name length that can be stored in the
	 * current path -- the inner loop allocates more path as necessary.
	 * We really wouldn't have to do the maxlen calculations here, we
	 * could do them in fts_read before returning the path, but it's a
	 * lot easier here since the length is part of the dirent structure.
	 *
	 * If not changing directories set a pointer so that can just append
	 * each new name into the path.
	 */
	len = NAPPEND(cur);
	if (ISSET(FTS_NOCHDIR)) {
		cp = sp->fts_path + len;
		*cp++ = '/';
	} else {
		/* GCC, you're too verbose. */
		cp = NULL;
	}
	len++;
	maxlen = sp->fts_pathlen - len;

	level = cur->fts_level + 1;

	/* Read the directory, attaching each entry to the `link' pointer. */
	doadjust = 0;
	for (head = tail = NULL, nitems = 0; dirp && (dp = __readdir(dirp));) {
		if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
			continue;

		if ((p = fts_alloc(sp, dp->d_name, _D_EXACT_NAMLEN (dp))) == NULL)
			goto mem1;
		if (_D_EXACT_NAMLEN (dp) >= maxlen) {/* include space for NUL */
			oldaddr = sp->fts_path;
			if (fts_palloc(sp, _D_EXACT_NAMLEN (dp) + len + 1)) {
				/*
				 * No more memory for path or structures.  Save
				 * errno, free up the current structure and the
				 * structures already allocated.
				 */
mem1:				saved_errno = errno;
				free(p);
				fts_lfree(head);
				(void)__closedir(dirp);
				cur->fts_info = FTS_ERR;
				SET(FTS_STOP);
				__set_errno (saved_errno);
				return (NULL);
			}
			/* Did realloc() change the pointer? */
			if (oldaddr != sp->fts_path) {
				doadjust = 1;
				if (ISSET(FTS_NOCHDIR))
					cp = sp->fts_path + len;
			}
			maxlen = sp->fts_pathlen - len;
		}

		if (len + _D_EXACT_NAMLEN (dp) >= USHRT_MAX) {
			/*
			 * In an FTSENT, fts_pathlen is a u_short so it is
			 * possible to wraparound here.  If we do, free up
			 * the current structure and the structures already
			 * allocated, then error out with ENAMETOOLONG.
			 */
			free(p);
			fts_lfree(head);
			(void)__closedir(dirp);
			cur->fts_info = FTS_ERR;
			SET(FTS_STOP);
			__set_errno (ENAMETOOLONG);
			return (NULL);
		}
		p->fts_level = level;
		p->fts_parent = sp->fts_cur;
		p->fts_pathlen = len + _D_EXACT_NAMLEN (dp);

#if defined FTS_WHITEOUT && 0
		if (dp->d_type == DT_WHT)
			p->fts_flags |= FTS_ISW;
#endif

		/* Unreachable code.  cderrno is only ever set to a nonnull
		   value if dirp is closed at the same time.  But then we
		   cannot enter this loop.  */
		if (0 && cderrno) {
			if (nlinks) {
				p->fts_info = FTS_NS;
				p->fts_errno = cderrno;
			} else
				p->fts_info = FTS_NSOK;
			p->fts_accpath = cur->fts_accpath;
		} else if (nlinks == 0
                           || (nostat && dirent_not_directory(dp))) {
			p->fts_accpath =
			    ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name;
			p->fts_info = FTS_NSOK;
		} else {
			/* Build a file name for fts_stat to stat. */
			if (ISSET(FTS_NOCHDIR)) {
				p->fts_accpath = p->fts_path;
				memmove(cp, p->fts_name, p->fts_namelen + 1);
			} else
				p->fts_accpath = p->fts_name;
			/* Stat it. */
			p->fts_info = fts_stat(sp, p, 0);

			/* Decrement link count if applicable. */
			if (nlinks > 0 && (p->fts_info == FTS_D ||
			    p->fts_info == FTS_DC || p->fts_info == FTS_DOT))
				--nlinks;
		}

		/* We walk in directory order so "ls -f" doesn't get upset. */
		p->fts_link = NULL;
		if (head == NULL)
			head = tail = p;
		else {
			tail->fts_link = p;
			tail = p;
		}
		++nitems;
	}
	if (dirp)
		(void)__closedir(dirp);

	/*
	 * If realloc() changed the address of the path, adjust the
	 * addresses for the rest of the tree and the dir list.
	 */
	if (doadjust)
		fts_padjust(sp, head);

	/*
	 * If not changing directories, reset the path back to original
	 * state.
	 */
	if (ISSET(FTS_NOCHDIR)) {
		if (len == sp->fts_pathlen || nitems == 0)
			--cp;
		*cp = '\0';
	}

	/*
	 * If descended after called from fts_children or after called from
	 * fts_read and nothing found, get back.  At the root level we use
	 * the saved fd; if one of fts_open()'s arguments is a relative path
	 * to an empty directory, we wind up here with no other way back.  If
	 * can't get back, we're done.
	 */
	if (descend && (type == BCHILD || !nitems) &&
	    (cur->fts_level == FTS_ROOTLEVEL ?
	     FCHDIR(sp, sp->fts_rfd) :
	     fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {
		cur->fts_info = FTS_ERR;
		SET(FTS_STOP);
		fts_lfree(head);
		return (NULL);
	}

	/* If didn't find anything, return NULL. */
	if (!nitems) {
		if (type == BREAD)
			cur->fts_info = FTS_DP;
		fts_lfree(head);
		return (NULL);
	}

	/* Sort the entries. */
	if (sp->fts_compar && nitems > 1)
		head = fts_sort(sp, head, nitems);
	return (head);
}
Exemple #5
0
static int WorldP (struct dirent* candidateWorld)
#endif
{
  World aWorld, **newWorlds;
  char candidatePathname[_POSIX_PATH_MAX+1];
  size_t nameLen;
  int newTotalWorlds, i;

#ifdef OS_LINUX
    nameLen = _D_EXACT_NAMLEN(candidateWorld);
#else
	nameLen = candidateWorld->d_namlen;
#endif

	if ((nameLen > strlen (VLMWorldSuffix) &&
		(0 == strncmp (candidateWorld->d_name + nameLen - strlen (VLMWorldSuffix),
					   (VLMWorldFormat == originalWorld->format) ? VLMWorldSuffix 
																 : IvoryWorldSuffix,
					   strlen (VLMWorldSuffix)))))
		  {
			sprintf (candidatePathname, "%s/%s", scanningDir, candidateWorld->d_name);
#if defined(OS_OSF) || defined(__FreeBSD__)
			aWorld.pathname = strdup (candidatePathname);
#else
			aWorld.pathname = strndup (candidatePathname, _POSIX_PATH_MAX+1);
#endif

			if (OpenWorldFile (&aWorld, FALSE))
			  {
				if (nWorlds == totalWorlds)
				  {
					newTotalWorlds = totalWorlds + 32;
					newWorlds = malloc (sizeof (World*) * newTotalWorlds);
					if (NULL == newWorlds)
					  {
						CloseExtraWorlds ();
						CloseWorldFile (&aWorld, TRUE);
						PuntWorld (originalWorld, 
								   "Unable to allocate space to search for parents of world file %s",
								   originalWorld->pathname);
					  }
					memcpy (newWorlds, worlds, (totalWorlds * sizeof (World*)));
					free (worlds);
					worlds = newWorlds;
					totalWorlds = newTotalWorlds;
				  }
				worlds[nWorlds] = malloc (sizeof (World));
				if (NULL == worlds[nWorlds])
				  {
					CloseExtraWorlds ();
					CloseWorldFile (&aWorld, TRUE);
					PuntWorld (originalWorld,
							   "Unable to allocate space to search for parents of world file %s",
							   originalWorld->pathname);
				  }
				memcpy (worlds[nWorlds], &aWorld, sizeof (World));
				for (i = 0; i < worlds[nWorlds]->nWiredMapEntries; i++)
					worlds[nWorlds]->wiredMapEntries[i].world = worlds[nWorlds];
				for (i = 0; i < worlds[nWorlds]->nUnwiredMapEntries; i++)
					worlds[nWorlds]->unwiredMapEntries[i].world = worlds[nWorlds];
				nWorlds++;
				return (TRUE);
			  }

			else
				return (FALSE);
		  }

	else
		return (FALSE);
}
Exemple #6
0
static bool
dir_read (struct file_data const *dir, struct dirdata *dirdata)
{
  register struct dirent *next;
  register size_t i;

  /* Address of block containing the files that are described.  */
  char const **names;

  /* Number of files in directory.  */
  size_t nnames;

  /* Allocated and used storage for file name data.  */
  char *data;
  size_t data_alloc, data_used;

  dirdata->names = 0;
  dirdata->data = 0;
  nnames = 0;
  data = 0;

  if (dir->desc != -1)
    {
      /* Open the directory and check for errors.  */
      register DIR *reading = opendir (dir->name);
      if (!reading)
	return false;

      /* Initialize the table of filenames.  */

      data_alloc = 512;
      data_used = 0;
      dirdata->data = data = xmalloc (data_alloc);

      /* Read the directory entries, and insert the subfiles
	 into the `data' table.  */

      while ((errno = 0, (next = readdir (reading)) != 0))
	{
	  char *d_name = next->d_name;
	  size_t d_size = _D_EXACT_NAMLEN (next) + 1;

	  /* Ignore "." and "..".  */
	  if (d_name[0] == '.'
	      && (d_name[1] == 0 || (d_name[1] == '.' && d_name[2] == 0)))
	    continue;

	  if (excluded_file_name (excluded, d_name))
	    continue;

	  while (data_alloc < data_used + d_size)
	    {
	      if (PTRDIFF_MAX / 2 <= data_alloc)
		xalloc_die ();
	      dirdata->data = data = xrealloc (data, data_alloc *= 2);
	    }

	  memcpy (data + data_used, d_name, d_size);
	  data_used += d_size;
	  nnames++;
	}
      if (errno)
	{
	  int e = errno;
	  closedir (reading);
	  errno = e;
	  return false;
	}
#if CLOSEDIR_VOID
      closedir (reading);
#else
      if (closedir (reading) != 0)
	return false;
#endif
    }

  /* Create the `names' table from the `data' table.  */
  if (PTRDIFF_MAX / sizeof *names - 1 <= nnames)
    xalloc_die ();
  dirdata->names = names = xmalloc ((nnames + 1) * sizeof *names);
  dirdata->nnames = nnames;
  for (i = 0;  i < nnames;  i++)
    {
      names[i] = data;
      data += strlen (data) + 1;
    }
  names[nnames] = 0;
  return true;
}
Exemple #7
0
int
create_tmpdir ( int tracing )
{
    int fixedname = ipa && ( option[OPT_KEEP_TEMPS].flag );

    if ( ipa ) {
	if ( fixedname ) {
	    tmpdir = concat_names ( outfilename, ".ipakeep" );
	} else {
	    char *tmpdir_env_var;
	    if ((tmpdir_env_var = getenv("TMPDIR")) != NULL) {
		char *filename;
	        tmpdir_env_var = concat_names ( tmpdir_env_var, DIR_SEP_CHAR);
		if ((filename = strrchr(outfilename, DIR_SEP_CHAR)) != NULL)
		    filename++;
		else
		    filename = outfilename;
		
	        tmpdir = concat_names ( tmpdir_env_var, filename);
	    }
	    else
	        tmpdir = outfilename;
	    tmpdir = concat_names ( tmpdir, ".ipaXXXXXX" );
	}
    } else {
	tmpdir = concat_names ( DEFAULT_TMPDIR, "XXXXXX" );
    }
    if ( ! fixedname ) {
	tmpdir = mktemp ( tmpdir );
    }
    tmpdir_length = strlen ( tmpdir );

    if ( cmask == 0 ) {
	cmask = umask (0);
	(void) umask (cmask);
    }

    if ( MKDIR (tmpdir, 0777 & ~cmask) != 0 ) {
	if ( errno == EEXIST && fixedname ) {
	    /* We have an old instance of this directory -- clear it out: */
	    DIR *dirp;
	    struct direct *entryp;
	    char *prefix;

	    dirp = opendir ( tmpdir );
	    if ( dirp != NULL ) {
		prefix = concat_names ( tmpdir, "/" );
		while ( ( entryp = readdir(dirp) ) != NULL ) {
		    /* Don't bother with names of one or two characters, e.g. '.'
		     * and '..', since we don't create temporary files with such
		     * names:
		     */
#if defined(_DIRENT_HAVE_D_NAMLEN)
		  if ( entryp->d_namlen > 2 )
#else
		  if (_D_EXACT_NAMLEN(entryp) > 2)
#endif
		    {
			string fname = concat_names ( prefix, entryp->d_name);
			unlink (fname);
			FREE (fname);
		    }
		}
		FREE (prefix);
		closedir ( dirp );
	    }
	} else {
    	    perror(""cannot create temporary directory for code generation");
	    return -1;
	}
    }

    add_to_tmp_file_list ( tmpdir );

    return 0;

} /* create_tmpdir */
static enum numbered_backup_result
numbered_backup (char **buffer, size_t buffer_size, size_t filelen)
{
  enum numbered_backup_result result = BACKUP_IS_NEW;
  DIR *dirp;
  struct dirent *dp;
  char *buf = *buffer;
  size_t versionlenmax = 1;
  char *base = last_component (buf);
  size_t base_offset = base - buf;
  size_t baselen = base_len (base);

  /* Temporarily modify the buffer into its parent directory name,
     open the directory, and then restore the buffer.  */
  char tmp[sizeof "."];
  memcpy (tmp, base, sizeof ".");
  strcpy (base, ".");
  dirp = opendir (buf);
  memcpy (base, tmp, sizeof ".");
  strcpy (base + baselen, ".~1~");

  if (!dirp)
    return result;

  while ((dp = readdir (dirp)) != NULL)
    {
      char const *p;
      char *q;
      bool all_9s;
      size_t versionlen;
      size_t new_buflen;

      if (! REAL_DIR_ENTRY (dp) || _D_EXACT_NAMLEN (dp) < baselen + 4)
        continue;

      if (memcmp (buf + base_offset, dp->d_name, baselen + 2) != 0)
        continue;

      p = dp->d_name + baselen + 2;

      /* Check whether this file has a version number and if so,
         whether it is larger.  Use string operations rather than
         integer arithmetic, to avoid problems with integer overflow.  */

      if (! ('1' <= *p && *p <= '9'))
        continue;
      all_9s = (*p == '9');
      for (versionlen = 1; ISDIGIT (p[versionlen]); versionlen++)
        all_9s &= (p[versionlen] == '9');

      if (! (p[versionlen] == '~' && !p[versionlen + 1]
             && (versionlenmax < versionlen
                 || (versionlenmax == versionlen
                     && memcmp (buf + filelen + 2, p, versionlen) <= 0))))
        continue;

      /* This directory has the largest version number seen so far.
         Append this highest numbered extension to the file name,
         prepending '0' to the number if it is all 9s.  */

      versionlenmax = all_9s + versionlen;
      result = (all_9s ? BACKUP_IS_LONGER : BACKUP_IS_SAME_LENGTH);
      new_buflen = filelen + 2 + versionlenmax + 1;
      if (buffer_size <= new_buflen)
        {
          buf = xnrealloc (buf, 2, new_buflen);
          buffer_size = new_buflen * 2;
        }
      q = buf + filelen;
      *q++ = '.';
      *q++ = '~';
      *q = '0';
      q += all_9s;
      memcpy (q, p, versionlen + 2);

      /* Add 1 to the version number.  */

      q += versionlen;
      while (*--q == '9')
        *q = '0';
      ++*q;
    }

  closedir (dirp);
  *buffer = buf;
  return result;
}
Exemple #9
0
char *
streamsavedir (DIR *dirp, enum savedir_option option)
{
  char *name_space = NULL;
  size_t allocated = 0;
  direntry_t *entries = NULL;
  size_t entries_allocated = 0;
  size_t entries_used = 0;
  size_t used = 0;
  int readdir_errno;
  comparison_function cmp = comparison_function_table[option];

  if (dirp == NULL)
    return NULL;

  for (;;)
    {
      struct dirent const *dp;
      char const *entry;

      errno = 0;
      dp = readdir (dirp);
      if (! dp)
        break;

      /* Skip "", ".", and "..".  "" is returned by at least one buggy
         implementation: Solaris 2.4 readdir on NFS file systems.  */
      entry = dp->d_name;
      if (entry[entry[0] != '.' ? 0 : entry[1] != '.' ? 1 : 2] != '\0')
        {
          size_t entry_size = _D_EXACT_NAMLEN (dp) + 1;
          if (cmp)
            {
              if (entries_allocated == entries_used)
                {
                  size_t n = entries_allocated;
                  entries = x2nrealloc (entries, &n, sizeof *entries);
                  entries_allocated = n;
                }
              entries[entries_used].name = xstrdup (entry);
#if D_INO_IN_DIRENT
              entries[entries_used].ino = dp->d_ino;
#endif
              entries_used++;
            }
          else
            {
              if (allocated - used <= entry_size)
                {
                  size_t n = used + entry_size;
                  if (n < used)
                    xalloc_die ();
                  name_space = x2nrealloc (name_space, &n, 1);
                  allocated = n;
                }
              memcpy (name_space + used, entry, entry_size);
            }
          used += entry_size;
        }
    }

  readdir_errno = errno;
  if (readdir_errno != 0)
    {
      free (entries);
      free (name_space);
      errno = readdir_errno;
      return NULL;
    }

  if (cmp)
    {
      size_t i;

      qsort (entries, entries_used, sizeof *entries, cmp);
      name_space = xmalloc (used + 1);
      used = 0;
      for (i = 0; i < entries_used; i++)
        {
          char *dest = name_space + used;
          used += stpcpy (dest, entries[i].name) - dest + 1;
          free (entries[i].name);
        }
      free (entries);
    }
  else if (used == allocated)
    name_space = xrealloc (name_space, used + 1);

  name_space[used] = '\0';
  return name_space;
}
Exemple #10
0
char *
__getcwd (char *buf, size_t size)
{
    /* Lengths of big file name components and entire file names, and a
       deep level of file name nesting.  These numbers are not upper
       bounds; they are merely large values suitable for initial
       allocations, designed to be large enough for most real-world
       uses.  */
    enum
    {
        BIG_FILE_NAME_COMPONENT_LENGTH = 255,
        BIG_FILE_NAME_LENGTH = MIN (4095, PATH_MAX - 1),
        DEEP_NESTING = 100
    };

#if HAVE_OPENAT_SUPPORT
    int fd = AT_FDCWD;
    bool fd_needs_closing = false;
#else
    char dots[DEEP_NESTING * sizeof ".." + BIG_FILE_NAME_COMPONENT_LENGTH + 1];
    char *dotlist = dots;
    size_t dotsize = sizeof dots;
    size_t dotlen = 0;
#endif
    DIR *dirstream = NULL;
    dev_t rootdev, thisdev;
    ino_t rootino, thisino;
    char *dir;
    register char *dirp;
    struct stat st;
    size_t allocated = size;
    size_t used;

#if HAVE_PARTLY_WORKING_GETCWD
    /* The system getcwd works, except it sometimes fails when it
       shouldn't, setting errno to ERANGE, ENAMETOOLONG, or ENOENT.  If
       AT_FDCWD is not defined, the algorithm below is O(N**2) and this
       is much slower than the system getcwd (at least on GNU/Linux).
       So trust the system getcwd's results unless they look
       suspicious.

       Use the system getcwd even if we have openat support, since the
       system getcwd works even when a parent is unreadable, while the
       openat-based approach does not.  */

# undef getcwd
    dir = getcwd (buf, size);
    if (dir || (errno != ERANGE && errno != ENAMETOOLONG && errno != ENOENT))
        return dir;
#endif

    if (size == 0)
    {
        if (buf != NULL)
        {
            __set_errno (EINVAL);
            return NULL;
        }

        allocated = BIG_FILE_NAME_LENGTH + 1;
    }

    if (buf == NULL)
    {
        dir = malloc (allocated);
        if (dir == NULL)
            return NULL;
    }
    else
        dir = buf;

    dirp = dir + allocated;
    *--dirp = '\0';

    if (__lstat (".", &st) < 0)
        goto lose;
    thisdev = st.st_dev;
    thisino = st.st_ino;

    if (__lstat ("/", &st) < 0)
        goto lose;
    rootdev = st.st_dev;
    rootino = st.st_ino;

    while (!(thisdev == rootdev && thisino == rootino))
    {
        struct dirent *d;
        dev_t dotdev;
        ino_t dotino;
        bool mount_point;
        int parent_status;
        size_t dirroom;
        size_t namlen;
        bool use_d_ino = true;

        /* Look at the parent directory.  */
#if HAVE_OPENAT_SUPPORT
        fd = openat (fd, "..", O_RDONLY);
        if (fd < 0)
            goto lose;
        fd_needs_closing = true;
        parent_status = fstat (fd, &st);
#else
        dotlist[dotlen++] = '.';
        dotlist[dotlen++] = '.';
        dotlist[dotlen] = '\0';
        parent_status = __lstat (dotlist, &st);
#endif
        if (parent_status != 0)
            goto lose;

        if (dirstream && __closedir (dirstream) != 0)
        {
            dirstream = NULL;
            goto lose;
        }

        /* Figure out if this directory is a mount point.  */
        dotdev = st.st_dev;
        dotino = st.st_ino;
        mount_point = dotdev != thisdev;

        /* Search for the last directory.  */
#if HAVE_OPENAT_SUPPORT
        dirstream = fdopendir (fd);
        if (dirstream == NULL)
            goto lose;
        /* Reset fd.  It may have been closed by fdopendir.  */
        fd = dirfd (dirstream);
        fd_needs_closing = false;
#else
        dirstream = __opendir (dotlist);
        if (dirstream == NULL)
            goto lose;
        dotlist[dotlen++] = '/';
#endif
        for (;;)
        {
            /* Clear errno to distinguish EOF from error if readdir returns
               NULL.  */
            __set_errno (0);
            d = __readdir (dirstream);

            /* When we've iterated through all directory entries without finding
               one with a matching d_ino, rewind the stream and consider each
               name again, but this time, using lstat.  This is necessary in a
               chroot on at least one system (glibc-2.3.6 + linux 2.6.12), where
               .., ../.., ../../.., etc. all had the same device number, yet the
               d_ino values for entries in / did not match those obtained
               via lstat.  */
            if (d == NULL && errno == 0 && use_d_ino)
            {
                use_d_ino = false;
                rewinddir (dirstream);
                d = __readdir (dirstream);
            }

            if (d == NULL)
            {
                if (errno == 0)
                    /* EOF on dirstream, which can mean e.g., that the current
                       directory has been removed.  */
                    __set_errno (ENOENT);
                goto lose;
            }
            if (d->d_name[0] == '.' &&
                    (d->d_name[1] == '\0' ||
                     (d->d_name[1] == '.' && d->d_name[2] == '\0')))
                continue;

            if (use_d_ino)
            {
                bool match = (MATCHING_INO (d, thisino) || mount_point);
                if (! match)
                    continue;
            }

            {
                int entry_status;
#if HAVE_OPENAT_SUPPORT
                entry_status = fstatat (fd, d->d_name, &st, AT_SYMLINK_NOFOLLOW);
#else
                /* Compute size needed for this file name, or for the file
                   name ".." in the same directory, whichever is larger.
                   Room for ".." might be needed the next time through
                   the outer loop.  */
                size_t name_alloc = _D_ALLOC_NAMLEN (d);
                size_t filesize = dotlen + MAX (sizeof "..", name_alloc);

                if (filesize < dotlen)
                    goto memory_exhausted;

                if (dotsize < filesize)
                {
                    /* My, what a deep directory tree you have, Grandma.  */
                    size_t newsize = MAX (filesize, dotsize * 2);
                    size_t i;
                    if (newsize < dotsize)
                        goto memory_exhausted;
                    if (dotlist != dots)
                        free (dotlist);
                    dotlist = malloc (newsize);
                    if (dotlist == NULL)
                        goto lose;
                    dotsize = newsize;

                    i = 0;
                    do
                    {
                        dotlist[i++] = '.';
                        dotlist[i++] = '.';
                        dotlist[i++] = '/';
                    }
                    while (i < dotlen);
                }

                memcpy (dotlist + dotlen, d->d_name, _D_ALLOC_NAMLEN (d));
                entry_status = __lstat (dotlist, &st);
#endif
                /* We don't fail here if we cannot stat() a directory entry.
                   This can happen when (network) file systems fail.  If this
                   entry is in fact the one we are looking for we will find
                   out soon as we reach the end of the directory without
                   having found anything.  */
                if (entry_status == 0 && S_ISDIR (st.st_mode)
                        && st.st_dev == thisdev && st.st_ino == thisino)
                    break;
            }
        }

        dirroom = dirp - dir;
        namlen = _D_EXACT_NAMLEN (d);

        if (dirroom <= namlen)
        {
            if (size != 0)
            {
                __set_errno (ERANGE);
                goto lose;
            }
            else
            {
                char *tmp;
                size_t oldsize = allocated;

                allocated += MAX (allocated, namlen);
                if (allocated < oldsize
                        || ! (tmp = realloc (dir, allocated)))
                    goto memory_exhausted;

                /* Move current contents up to the end of the buffer.
                This is guaranteed to be non-overlapping.  */
                dirp = memcpy (tmp + allocated - (oldsize - dirroom),
                               tmp + dirroom,
                               oldsize - dirroom);
                dir = tmp;
            }
        }
        dirp -= namlen;
        memcpy (dirp, d->d_name, namlen);
        *--dirp = '/';

        thisdev = dotdev;
        thisino = dotino;
    }

    if (dirstream && __closedir (dirstream) != 0)
    {
        dirstream = NULL;
        goto lose;
    }

    if (dirp == &dir[allocated - 1])
        *--dirp = '/';

#if ! HAVE_OPENAT_SUPPORT
    if (dotlist != dots)
        free (dotlist);
#endif

    used = dir + allocated - dirp;
    memmove (dir, dirp, used);

    if (size == 0)
        /* Ensure that the buffer is only as large as necessary.  */
        buf = realloc (dir, used);

    if (buf == NULL)
        /* Either buf was NULL all along, or `realloc' failed but
           we still have the original string.  */
        buf = dir;

    return buf;

memory_exhausted:
    __set_errno (ENOMEM);
lose:
    {
        int save = errno;
        if (dirstream)
            __closedir (dirstream);
#if HAVE_OPENAT_SUPPORT
        if (fd_needs_closing)
            close (fd);
#else
        if (dotlist != dots)
            free (dotlist);
#endif
        if (buf == NULL)
            free (dir);
        __set_errno (save);
    }
    return NULL;
}
Exemple #11
0
char *
__getcwd (char *buf, size_t size)
{
  /* Lengths of big file name components and entire file names, and a
     deep level of file name nesting.  These numbers are not upper
     bounds; they are merely large values suitable for initial
     allocations, designed to be large enough for most real-world
     uses.  */
  enum
    {
      BIG_FILE_NAME_COMPONENT_LENGTH = 255,
      BIG_FILE_NAME_LENGTH = MIN (4095, PATH_MAX - 1),
      DEEP_NESTING = 100
    };

#ifdef AT_FDCWD
  int fd = AT_FDCWD;
  bool fd_needs_closing = false;
#else
  char dots[DEEP_NESTING * sizeof ".." + BIG_FILE_NAME_COMPONENT_LENGTH + 1];
  char *dotlist = dots;
  size_t dotsize = sizeof dots;
  size_t dotlen = 0;
#endif
  DIR *dirstream = NULL;
  dev_t rootdev, thisdev;
  ino_t rootino, thisino;
  char *path;
  register char *pathp;
  struct stat st;
  size_t allocated = size;
  size_t used;

#if HAVE_PARTLY_WORKING_GETCWD && !defined AT_FDCWD
  /* The system getcwd works, except it sometimes fails when it
     shouldn't, setting errno to ERANGE, ENAMETOOLONG, or ENOENT.  If
     AT_FDCWD is not defined, the algorithm below is O(N**2) and this
     is much slower than the system getcwd (at least on GNU/Linux).
     So trust the system getcwd's results unless they look
     suspicious.  */
# undef getcwd
  path = getcwd (buf, size);
  if (path || (errno != ERANGE && !is_ENAMETOOLONG (errno) && errno != ENOENT))
    return path;
#endif

  if (size == 0)
    {
      if (buf != NULL)
	{
	  __set_errno (EINVAL);
	  return NULL;
	}

      allocated = BIG_FILE_NAME_LENGTH + 1;
    }

  if (buf == NULL)
    {
      path = malloc (allocated);
      if (path == NULL)
	return NULL;
    }
  else
    path = buf;

  pathp = path + allocated;
  *--pathp = '\0';

  if (__lstat (".", &st) < 0)
    goto lose;
  thisdev = st.st_dev;
  thisino = st.st_ino;

  if (__lstat ("/", &st) < 0)
    goto lose;
  rootdev = st.st_dev;
  rootino = st.st_ino;

  while (!(thisdev == rootdev && thisino == rootino))
    {
      struct dirent *d;
      dev_t dotdev;
      ino_t dotino;
      bool mount_point;
      int parent_status;

      /* Look at the parent directory.  */
#ifdef AT_FDCWD
      fd = openat (fd, "..", O_RDONLY);
      if (fd < 0)
	goto lose;
      fd_needs_closing = true;
      parent_status = fstat (fd, &st);
#else
      dotlist[dotlen++] = '.';
      dotlist[dotlen++] = '.';
      dotlist[dotlen] = '\0';
      parent_status = __lstat (dotlist, &st);
#endif
      if (parent_status != 0)
	goto lose;

      if (dirstream && __closedir (dirstream) != 0)
	{
	  dirstream = NULL;
	  goto lose;
	}

      /* Figure out if this directory is a mount point.  */
      dotdev = st.st_dev;
      dotino = st.st_ino;
      mount_point = dotdev != thisdev;

      /* Search for the last directory.  */
#ifdef AT_FDCWD
      dirstream = fdopendir (fd);
      if (dirstream == NULL)
	goto lose;
      fd_needs_closing = false;
#else
      dirstream = __opendir (dotlist);
      if (dirstream == NULL)
	goto lose;
      dotlist[dotlen++] = '/';
#endif
      /* Clear errno to distinguish EOF from error if readdir returns
	 NULL.  */
      __set_errno (0);
      while ((d = __readdir (dirstream)) != NULL)
	{
	  if (d->d_name[0] == '.' &&
	      (d->d_name[1] == '\0' ||
	       (d->d_name[1] == '.' && d->d_name[2] == '\0')))
	    continue;
	  if (MATCHING_INO (d, thisino) || mount_point)
	    {
	      int entry_status;
#ifdef AT_FDCWD
	      entry_status = fstatat (fd, d->d_name, &st, AT_SYMLINK_NOFOLLOW);
#else
	      /* Compute size needed for this file name, or for the file
		 name ".." in the same directory, whichever is larger.
	         Room for ".." might be needed the next time through
		 the outer loop.  */
	      size_t name_alloc = _D_ALLOC_NAMLEN (d);
	      size_t filesize = dotlen + MAX (sizeof "..", name_alloc);

	      if (filesize < dotlen)
		goto memory_exhausted;

	      if (dotsize < filesize)
		{
		  /* My, what a deep directory tree you have, Grandma.  */
		  size_t newsize = MAX (filesize, dotsize * 2);
		  size_t i;
		  if (newsize < dotsize)
		    goto memory_exhausted;
		  if (dotlist != dots)
		    free (dotlist);
		  dotlist = malloc (newsize);
		  if (dotlist == NULL)
		    goto lose;
		  dotsize = newsize;

		  i = 0;
		  do
		    {
		      dotlist[i++] = '.';
		      dotlist[i++] = '.';
		      dotlist[i++] = '/';
		    }
		  while (i < dotlen);
		}

	      strcpy (dotlist + dotlen, d->d_name);
	      entry_status = __lstat (dotlist, &st);
#endif
	      /* We don't fail here if we cannot stat() a directory entry.
		 This can happen when (network) file systems fail.  If this
		 entry is in fact the one we are looking for we will find
		 out soon as we reach the end of the directory without
		 having found anything.  */
	      if (entry_status == 0 && S_ISDIR (st.st_mode)
		  && st.st_dev == thisdev && st.st_ino == thisino)
		break;
	    }
	}
      if (d == NULL)
	{
	  if (errno == 0)
	    /* EOF on dirstream, which means that the current directory
	       has been removed.  */
	    __set_errno (ENOENT);
	  goto lose;
	}
      else
	{
	  size_t pathroom = pathp - path;
	  size_t namlen = _D_EXACT_NAMLEN (d);

	  if (pathroom <= namlen)
	    {
	      if (size != 0)
		{
		  __set_errno (ERANGE);
		  goto lose;
		}
	      else
		{
		  char *tmp;
		  size_t oldsize = allocated;

		  allocated += MAX (allocated, namlen);
		  if (allocated < oldsize
		      || ! (tmp = realloc (path, allocated)))
		    goto memory_exhausted;

		  /* Move current contents up to the end of the buffer.
		     This is guaranteed to be non-overlapping.  */
		  pathp = memcpy (tmp + allocated - (oldsize - pathroom),
				  tmp + pathroom,
				  oldsize - pathroom);
		  path = tmp;
		}
	    }
	  pathp -= namlen;
	  memcpy (pathp, d->d_name, namlen);
	  *--pathp = '/';
	}

      thisdev = dotdev;
      thisino = dotino;
    }

  if (dirstream && __closedir (dirstream) != 0)
    {
      dirstream = NULL;
      goto lose;
    }

  if (pathp == &path[allocated - 1])
    *--pathp = '/';

#ifndef AT_FDCWD
  if (dotlist != dots)
    free (dotlist);
#endif

  used = path + allocated - pathp;
  memmove (path, pathp, used);

  if (buf == NULL && size == 0)
    /* Ensure that the buffer is only as large as necessary.  */
    buf = realloc (path, used);

  if (buf == NULL)
    /* Either buf was NULL all along, or `realloc' failed but
       we still have the original string.  */
    buf = path;

  return buf;

 memory_exhausted:
  __set_errno (ENOMEM);
 lose:
  {
    int save = errno;
    if (dirstream)
      __closedir (dirstream);
#ifdef AT_FDCWD
    if (fd_needs_closing)
      close (fd);
#else
    if (dotlist != dots)
      free (dotlist);
#endif
    if (buf == NULL)
      free (path);
    __set_errno (save);
  }
  return NULL;
}
Exemple #12
0
int
main(
    int argc, char *argv[]) 
{
    (void) argc;
    (void) argv;

    /* File type macros */
    {
        assert (DTTOIF(DT_REG) == S_IFREG);
        assert (DTTOIF(DT_DIR) == S_IFDIR);
        assert (DTTOIF(DT_FIFO) == S_IFIFO);
        assert (DTTOIF(DT_SOCK) == S_IFSOCK);
        assert (DTTOIF(DT_CHR) == S_IFCHR);
        assert (DTTOIF(DT_BLK) == S_IFBLK);

        assert (IFTODT(S_IFREG) == DT_REG);
        assert (IFTODT(S_IFDIR) == DT_DIR);
        assert (IFTODT(S_IFIFO) == DT_FIFO);
        assert (IFTODT(S_IFSOCK) == DT_SOCK);
        assert (IFTODT(S_IFCHR) == DT_CHR);
        assert (IFTODT(S_IFBLK) == DT_BLK);
    }

    /* Basic directory retrieval */
    {
        DIR *dir;
        struct dirent *ent;
        int found = 0;

        /* Open directory */
        dir = opendir ("tests/1");
        if (dir == NULL) {
            fprintf (stderr, "Directory tests not found\n");
            abort ();
        }

        /* Read entries */
        while ((ent = readdir (dir)) != NULL) {

            /* Check each file */
            if (strcmp (ent->d_name, ".") == 0) {
                /* Directory itself */
#ifdef _DIRENT_HAVE_D_TYPE
                assert (ent->d_type == DT_DIR);
#endif
#ifdef _DIRENT_HAVE_D_NAMLEN
                assert (ent->d_namlen == 1);
#endif
#ifdef _D_EXACT_NAMLEN
                assert (_D_EXACT_NAMLEN(ent) == 1);
#endif
#ifdef _D_ALLOC_NAMLEN
                assert (_D_ALLOC_NAMLEN(ent) > 1);
#endif
                found |= 1;

            } else if (strcmp (ent->d_name, "..") == 0) {
                /* Parent directory */
#ifdef _DIRENT_HAVE_D_TYPE
                assert (ent->d_type == DT_DIR);
#endif
#ifdef _DIRENT_HAVE_D_NAMLEN
                assert (ent->d_namlen == 2);
#endif
#ifdef _D_EXACT_NAMLEN
                assert (_D_EXACT_NAMLEN(ent) == 2);
#endif
#ifdef _D_ALLOC_NAMLEN
                assert (_D_ALLOC_NAMLEN(ent) > 2);
#endif
                found |= 2;

            } else if (strcmp (ent->d_name, "file") == 0) {
                /* Regular file */
#ifdef _DIRENT_HAVE_D_TYPE
                assert (ent->d_type == DT_REG);
#endif
#ifdef _DIRENT_HAVE_D_NAMLEN
                assert (ent->d_namlen == 4);
#endif
#ifdef _D_EXACT_NAMLEN
                assert (_D_EXACT_NAMLEN(ent) == 4);
#endif
#ifdef _D_ALLOC_NAMLEN
                assert (_D_ALLOC_NAMLEN(ent) > 4);
#endif
                found |= 4;

            } else if (strcmp (ent->d_name, "dir") == 0) {
                /* Just a directory */
#ifdef _DIRENT_HAVE_D_TYPE
                assert (ent->d_type == DT_DIR);
#endif
#ifdef _DIRENT_HAVE_D_NAMLEN
                assert (ent->d_namlen == 3);
#endif
#ifdef _D_EXACT_NAMLEN
                assert (_D_EXACT_NAMLEN(ent) == 3);
#endif
#ifdef _D_ALLOC_NAMLEN
                assert (_D_ALLOC_NAMLEN(ent) > 3);
#endif
                found |= 8;

            } else {
                /* Other file */
                fprintf (stderr, "Unexpected file %s\n", ent->d_name);
                abort ();
            }

        }

        /* Make sure that all files were found */
        assert (found == 0xf);

        closedir (dir);
    }

    /* Rewind of directory stream */
    {
        DIR *dir;
        struct dirent *ent;
        int found = 0;

        /* Open directory */
        dir = opendir ("tests/1");
        assert (dir != NULL);

        /* Read entries */
        while ((ent = readdir (dir)) != NULL) {

            /* Check each file */
            if (strcmp (ent->d_name, ".") == 0) {
                /* Directory itself */
                found |= 1;

            } else if (strcmp (ent->d_name, "..") == 0) {
                /* Parent directory */
                found |= 2;

            } else if (strcmp (ent->d_name, "file") == 0) {
                /* Regular file */
                found |= 4;

            } else if (strcmp (ent->d_name, "dir") == 0) {
                /* Just a directory */
                found |= 8;

            } else {
                /* Other file */
                fprintf (stderr, "Unexpected file %s\n", ent->d_name);
                abort ();
            }

        }

        /* Make sure that all files were found */
        assert (found == 0xf);

        /* Rewind stream and read entries again */
        rewinddir (dir);
        found = 0;

        /* Read entries */
        while ((ent = readdir (dir)) != NULL) {

            /* Check each file */
            if (strcmp (ent->d_name, ".") == 0) {
                /* Directory itself */
                found |= 1;

            } else if (strcmp (ent->d_name, "..") == 0) {
                /* Parent directory */
                found |= 2;

            } else if (strcmp (ent->d_name, "file") == 0) {
                /* Regular file */
                found |= 4;

            } else if (strcmp (ent->d_name, "dir") == 0) {
                /* Just a directory */
                found |= 8;

            } else {
                /* Other file */
                fprintf (stderr, "Unexpected file %s\n", ent->d_name);
                abort ();
            }

        }

        /* Make sure that all files were found */
        assert (found == 0xf);

        closedir (dir);
    }

    printf ("OK\n");
    return EXIT_SUCCESS;
}
Exemple #13
0
/* Read a directory entry from DIRP.  */
int
__READDIR_R (DIR *dirp, DIRENT_TYPE *entry, DIRENT_TYPE **result)
{
  DIRENT_TYPE *dp;
  size_t reclen;
  const int saved_errno = errno;
  int ret;

  __libc_lock_lock (dirp->lock);

  do
    {
      if (dirp->offset >= dirp->size)
	{
	  /* We've emptied out our buffer.  Refill it.  */

	  size_t maxread;
	  ssize_t bytes;

#ifndef _DIRENT_HAVE_D_RECLEN
	  /* Fixed-size struct; must read one at a time (see below).  */
	  maxread = sizeof *dp;
#else
	  maxread = dirp->allocation;
#endif

	  bytes = __GETDENTS (dirp->fd, dirp->data, maxread);
	  if (bytes <= 0)
	    {
	      /* On some systems getdents fails with ENOENT when the
		 open directory has been rmdir'd already.  POSIX.1
		 requires that we treat this condition like normal EOF.  */
	      if (bytes < 0 && errno == ENOENT)
		{
		  bytes = 0;
		  __set_errno (saved_errno);
		}
	      if (bytes < 0)
		dirp->errcode = errno;

	      dp = NULL;
	      break;
	    }
	  dirp->size = (size_t) bytes;

	  /* Reset the offset into the buffer.  */
	  dirp->offset = 0;
	}

      dp = (DIRENT_TYPE *) &dirp->data[dirp->offset];

#ifdef _DIRENT_HAVE_D_RECLEN
      reclen = dp->d_reclen;
#else
      /* The only version of `struct dirent*' that lacks `d_reclen'
	 is fixed-size.  */
      assert (sizeof dp->d_name > 1);
      reclen = sizeof *dp;
      /* The name is not terminated if it is the largest possible size.
	 Clobber the following byte to ensure proper null termination.  We
	 read just one entry at a time above so we know that byte will not
	 be used later.  */
      dp->d_name[sizeof dp->d_name] = '\0';
#endif

      dirp->offset += reclen;

#ifdef _DIRENT_HAVE_D_OFF
      dirp->filepos = dp->d_off;
#else
      dirp->filepos += reclen;
#endif

#ifdef NAME_MAX
      if (reclen > offsetof (DIRENT_TYPE, d_name) + NAME_MAX + 1)
	{
	  /* The record is very long.  It could still fit into the
	     caller-supplied buffer if we can skip padding at the
	     end.  */
	  size_t namelen = _D_EXACT_NAMLEN (dp);
	  if (namelen <= NAME_MAX)
	    reclen = offsetof (DIRENT_TYPE, d_name) + namelen + 1;
	  else
	    {
	      /* The name is too long.  Ignore this file.  */
	      dirp->errcode = ENAMETOOLONG;
	      dp->d_ino = 0;
	      continue;
	    }
	}
#endif

      /* Skip deleted and ignored files.  */
    }
  while (dp->d_ino == 0);

  if (dp != NULL)
    {
      *result = memcpy (entry, dp, reclen);
#ifdef _DIRENT_HAVE_D_RECLEN
      entry->d_reclen = reclen;
#endif
      ret = 0;
    }
  else
    {
      *result = NULL;
      ret = dirp->errcode;
    }

  __libc_lock_unlock (dirp->lock);

  return ret;
}
Exemple #14
0
/* We expect four arguments:
   - source directory name
   - object directory
   - common object directory
   - the program name with path
*/
int
main (int argc, char *argv[])
{
    const char *srcdir;
    const char *objdir;
    const char *common_objdir;
    const char *progpath;
    struct stat64 st1;
    struct stat64 st2;
    struct stat64 st3;
    DIR *dir1;
    DIR *dir2;
    int result = 0;
    struct dirent64 *d;
    struct dirent64 direntbuf;
    char *objdir_copy1;
    char *objdir_copy2;
    char *buf;
    int fd;

    mtrace ();

    if (argc < 5)
    {
        puts ("not enough parameters");
        exit (1);
    }

    /* Make parameters available with nicer names.  */
    srcdir = argv[1];
    objdir = argv[2];
    common_objdir = argv[3];
    progpath = argv[4];

    /* First test the current source dir.  We cannot really compare the
       result of `getpwd' with the srcdir string but we have other means.  */
    if (stat64 (".", &st1) < 0)
    {
        printf ("cannot stat starting directory: %m\n");
        exit (1);
    }

    if (chdir (srcdir) < 0)
    {
        printf ("cannot change to source directory: %m\n");
        exit (1);
    }
    if (stat64 (".", &st2) < 0)
    {
        printf ("cannot stat source directory: %m\n");
        exit (1);
    }

    /* The two last stat64 calls better were for the same directory.  */
    if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
    {
        printf ("stat of source directory failed: (%lld,%lld) vs (%lld,%lld)\n",
                (long long int) st1.st_dev, (long long int) st1.st_ino,
                (long long int) st2.st_dev, (long long int) st2.st_ino);
        exit (1);
    }

    /* Change to the object directory.  */
    if (chdir (objdir) < 0)
    {
        printf ("cannot change to object directory: %m\n");
        exit (1);
    }
    if (stat64 (".", &st1) < 0)
    {
        printf ("cannot stat object directory: %m\n");
        exit (1);
    }
    /* Is this the same we get as with the full path?  */
    if (stat64 (objdir, &st2) < 0)
    {
        printf ("cannot stat object directory with full path: %m\n");
        exit (1);
    }
    if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
    {
        printf ("stat of object directory failed: (%lld,%lld) vs (%lld,%lld)\n",
                (long long int) st1.st_dev, (long long int) st1.st_ino,
                (long long int) st2.st_dev, (long long int) st2.st_ino);
        exit (1);
    }

    objdir_copy1 = getcwd (NULL, 0);
    if (objdir_copy1 == NULL)
    {
        printf ("cannot get current directory name for object directory: %m\n");
        result = 1;
    }

    /* First test: this directory must include our program.  */
    if (stat64 (progpath, &st2) < 0)
    {
        printf ("cannot stat program: %m\n");
        exit (1);
    }

    dir1 = opendir (".");
    if (dir1 == NULL)
    {
        printf ("cannot open object directory: %m\n");
        exit (1);
    }

    while ((d = readdir64 (dir1)) != NULL)
    {
#ifdef _DIRENT_HAVE_D_TYPE
        if (d->d_type != DT_UNKNOWN && d->d_type != DT_REG)
            continue;
#endif

        if (d->d_ino == st2.st_ino)
        {
            /* Might be it.  Test the device.  We could use the st_dev
               element from st1 but what the heck, do more testing.  */
            if (stat64 (d->d_name, &st3) < 0)
            {
                printf ("cannot stat entry from readdir: %m\n");
                result = 1;
                d = NULL;
                break;
            }

            if (st3.st_dev == st2.st_dev)
                break;
        }
    }

    if (d == NULL)
    {
        puts ("haven't found program in object directory");
        result = 1;
    }

    /* We leave dir1 open.  */

    /* Stat using file descriptor.  */
    if (fstat64 (dirfd (dir1), &st2) < 0)
    {
        printf ("cannot fstat object directory: %m\n");
        result = 1;
    }
    if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
    {
        printf ("fstat of object directory failed: (%lld,%lld) vs (%lld,%lld)\n",
                (long long int) st1.st_dev, (long long int) st1.st_ino,
                (long long int) st2.st_dev, (long long int) st2.st_ino);
        exit (1);
    }

    if (chdir ("..") < 0)
    {
        printf ("cannot go to common object directory with \"..\": %m\n");
        exit (1);
    }

    if (stat64 (".", &st1) < 0)
    {
        printf ("cannot stat common object directory: %m\n");
        exit (1);
    }
    /* Is this the same we get as with the full path?  */
    if (stat64 (common_objdir, &st2) < 0)
    {
        printf ("cannot stat common object directory with full path: %m\n");
        exit (1);
    }
    if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
    {
        printf ("stat of object directory failed: (%lld,%lld) vs (%lld,%lld)\n",
                (long long int) st1.st_dev, (long long int) st1.st_ino,
                (long long int) st2.st_dev, (long long int) st2.st_ino);
        exit (1);
    }

    /* Stat using file descriptor.  */
    if (fstat64 (dirfd (dir1), &st2) < 0)
    {
        printf ("cannot fstat object directory: %m\n");
        result = 1;
    }

    dir2 = opendir (common_objdir);
    if (dir2 == NULL)
    {
        printf ("cannot open common object directory: %m\n");
        exit (1);
    }

    while ((d = readdir64 (dir2)) != NULL)
    {
#ifdef _DIRENT_HAVE_D_TYPE
        if (d->d_type != DT_UNKNOWN && d->d_type != DT_DIR)
            continue;
#endif

        if (d->d_ino == st2.st_ino)
        {
            /* Might be it.  Test the device.  We could use the st_dev
               element from st1 but what the heck, do more testing.  */
            if (stat64 (d->d_name, &st3) < 0)
            {
                printf ("cannot stat entry from readdir: %m\n");
                result = 1;
                d = NULL;
                break;
            }

            if (st3.st_dev == st2.st_dev)
                break;
        }
    }

    /* This better should be the object directory again.  */
    if (fchdir (dirfd (dir1)) < 0)
    {
        printf ("cannot fchdir to object directory: %m\n");
        exit (1);
    }

    objdir_copy2 = getcwd (NULL, 0);
    if (objdir_copy2 == NULL)
    {
        printf ("cannot get current directory name for object directory: %m\n");
        result = 1;
    }
    if (strcmp (objdir_copy1, objdir_copy2) != 0)
    {
        puts ("getcwd returned a different string the second time");
        result = 1;
    }

    /* This better should be the common object directory again.  */
    if (fchdir (dirfd (dir2)) < 0)
    {
        printf ("cannot fchdir to common object directory: %m\n");
        exit (1);
    }

    if (stat64 (".", &st2) < 0)
    {
        printf ("cannot stat common object directory: %m\n");
        exit (1);
    }
    if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
    {
        printf ("stat of object directory failed: (%lld,%lld) vs (%lld,%lld)\n",
                (long long int) st1.st_dev, (long long int) st1.st_ino,
                (long long int) st2.st_dev, (long long int) st2.st_ino);
        exit (1);
    }

    buf = (char *) malloc (strlen (objdir_copy1) + 1 + sizeof "tst-dir.XXXXXX");
    if (buf == NULL)
    {
        printf ("cannot allocate buffer: %m");
        exit (1);
    }

    stpcpy (stpcpy (stpcpy (buf, objdir_copy1), "/"), "tst-dir.XXXXXX");
    if (mkdtemp (buf) == NULL)
    {
        printf ("cannot create test directory in object directory: %m\n");
        exit (1);
    }
    if (stat64 (buf, &st1) < 0)
    {
        printf ("cannot stat new directory \"%s\": %m\n", buf);
        exit (1);
    }
    if (chmod (buf, 0700) < 0)
    {
        printf ("cannot change mode of new directory: %m\n");
        exit (1);
    }

    /* Try to find the new directory.  */
    rewinddir (dir1);
    while (readdir64_r (dir1, &direntbuf, &d) == 0 && d != NULL)
    {
#ifdef _DIRENT_HAVE_D_TYPE
        if (d->d_type != DT_UNKNOWN && d->d_type != DT_DIR)
            continue;
#endif

        if (d->d_ino == st1.st_ino)
        {
            /* Might be it.  Test the device.  We could use the st_dev
               element from st1 but what the heck, do more testing.  */
            size_t len = strlen (objdir) + 1 + _D_EXACT_NAMLEN (d) + 1;
            char tmpbuf[len];

            stpcpy (stpcpy (stpcpy (tmpbuf, objdir), "/"), d->d_name);

            if (stat64 (tmpbuf, &st3) < 0)
            {
                printf ("cannot stat entry from readdir: %m\n");
                result = 1;
                d = NULL;
                break;
            }

            if (st3.st_dev == st2.st_dev
                    && strcmp (d->d_name, buf + strlen (buf) - 14) == 0)
                break;
        }
    }

    if (d == NULL)
    {
        printf ("haven't found new directory \"%s\"\n", buf);
        exit (1);
    }

    if (closedir (dir2) < 0)
    {
        printf ("closing dir2 failed: %m\n");
        result = 1;
    }

    if (chdir (buf) < 0)
    {
        printf ("cannot change to new directory: %m\n");
        exit (1);
    }

    dir2 = opendir (buf);
    if (dir2 == NULL)
    {
        printf ("cannot open new directory: %m\n");
        exit (1);
    }

    if (fstat64 (dirfd (dir2), &st2) < 0)
    {
        printf ("cannot fstat new directory \"%s\": %m\n", buf);
        exit (1);
    }
    if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
    {
        printf ("stat of new directory failed: (%lld,%lld) vs (%lld,%lld)\n",
                (long long int) st1.st_dev, (long long int) st1.st_ino,
                (long long int) st2.st_dev, (long long int) st2.st_ino);
        exit (1);
    }

    if (mkdir ("another-dir", 0777) < 0)
    {
        printf ("cannot create \"another-dir\": %m\n");
        exit (1);
    }
    fd = open ("and-a-file", O_RDWR | O_CREAT | O_EXCL, 0666);
    if (fd == -1)
    {
        printf ("cannot create \"and-a-file\": %m\n");
        exit (1);
    }
    close (fd);

    /* Some tests about error reporting.  */
    errno = 0;
    if (chdir ("and-a-file") >= 0)
    {
        printf ("chdir to \"and-a-file\" succeeded\n");
        exit (1);
    }
    if (errno != ENOTDIR)
    {
        printf ("chdir to \"and-a-file\" didn't set correct error\n");
        result = 1;
    }

    errno = 0;
    if (chdir ("and-a-file/..") >= 0)
    {
        printf ("chdir to \"and-a-file/..\" succeeded\n");
        exit (1);
    }
    if (errno != ENOTDIR)
    {
        printf ("chdir to \"and-a-file/..\" didn't set correct error\n");
        result = 1;
    }

    errno = 0;
    if (chdir ("another-dir/../and-a-file") >= 0)
    {
        printf ("chdir to \"another-dir/../and-a-file\" succeeded\n");
        exit (1);
    }
    if (errno != ENOTDIR)
    {
        printf ("chdir to \"another-dir/../and-a-file\" didn't set correct error\n");
        result = 1;
    }

    /* We now should have a directory and a file in the new directory.  */
    rewinddir (dir2);
    while (readdir64_r (dir2, &direntbuf, &d) == 0 && d != NULL)
    {
        if (strcmp (d->d_name, ".") == 0
                || strcmp (d->d_name, "..") == 0
                || strcmp (d->d_name, "another-dir") == 0)
        {
#ifdef _DIRENT_HAVE_D_TYPE
            if (d->d_type != DT_UNKNOWN && d->d_type != DT_DIR)
            {
                printf ("d_type for \"%s\" is wrong\n", d->d_name);
                result = 1;
            }
#endif
            if (stat64 (d->d_name, &st3) < 0)
            {
                printf ("cannot stat \"%s\" is wrong\n", d->d_name);
                result = 1;
            }
            else if (! S_ISDIR (st3.st_mode))
            {
                printf ("\"%s\" is no directory\n", d->d_name);
                result = 1;
            }
        }
        else if (strcmp (d->d_name, "and-a-file") == 0)
        {
#ifdef _DIRENT_HAVE_D_TYPE
            if (d->d_type != DT_UNKNOWN && d->d_type != DT_REG)
            {
                printf ("d_type for \"%s\" is wrong\n", d->d_name);
                result = 1;
            }
#endif
            if (stat64 (d->d_name, &st3) < 0)
            {
                printf ("cannot stat \"%s\" is wrong\n", d->d_name);
                result = 1;
            }
            else if (! S_ISREG (st3.st_mode))
            {
                printf ("\"%s\" is no regular file\n", d->d_name);
                result = 1;
            }
        }
        else
        {
            printf ("unexpected directory entry \"%s\"\n", d->d_name);
            result = 1;
        }
    }

    if (stat64 ("does-not-exist", &st1) >= 0)
    {
        puts ("stat for unexisting file did not fail");
        result = 1;
    }

    /* Free all resources.  */

    if (closedir (dir1) < 0)
    {
        printf ("closing dir1 failed: %m\n");
        result = 1;
    }
    if (closedir (dir2) < 0)
    {
        printf ("second closing dir2 failed: %m\n");
        result = 1;
    }

    if (rmdir ("another-dir") < 0)
    {
        printf ("cannot remove \"another-dir\": %m\n");
        result = 1;
    }

    if (unlink ("and-a-file") < 0)
    {
        printf ("cannot remove \"and-a-file\": %m\n");
        result = 1;
    }

    /* One more test before we leave: mkdir() is supposed to fail with
       EEXIST if the named file is a symlink.  */
    if (symlink ("a-symlink", "a-symlink") != 0)
    {
        printf ("cannot create symlink \"a-symlink\": %m\n");
        result = 1;
    }
    else
    {
        if (mkdir ("a-symlink", 0666) == 0)
        {
            puts ("can make directory \"a-symlink\"");
            result = 1;
        }
        else if (errno != EEXIST)
        {
            puts ("mkdir(\"a-symlink\") does not fail with EEXIST\n");
            result = 1;
        }
        if (unlink ("a-symlink") < 0)
        {
            printf ("cannot unlink \"a-symlink\": %m\n");
            result = 1;
        }
    }

    if (chdir (srcdir) < 0)
    {
        printf ("cannot change back to source directory: %m\n");
        exit (1);
    }

    if (rmdir (buf) < 0)
    {
        printf ("cannot remove \"%s\": %m\n", buf);
        result = 1;
    }
    free (objdir_copy1);
    free (objdir_copy2);

    if (result == 0)
        puts ("all OK");

    return result;
}