Esempio n. 1
0
int openat(int dirfd,const char * pathname, int flags, mode_t mode)
{
    _openat = (int (*)(int dirfd,const char * pathname, int flags, ...)) dlsym(RTLD_NEXT, "openat");
	
	if(flags & O_CREAT)
	{
		return _openat(dirfd,pathname, flags | O_NOATIME, mode);
	}
	else
	{
		
		return _openat(dirfd,pathname, flags | O_NOATIME, 0);	
	}   
}
Esempio n. 2
0
/*
 * For a directory at the top of a unionfs stack, the entire directory's
 * contents are read and cached locally until the next call to rewinddir().
 * For the fdopendir() case, the initial seek position must be preserved.
 * For rewinddir(), the full directory should always be re-read from the
 * beginning.
 *
 * If an error occurs, the existing buffer and state of 'dirp' is left
 * unchanged.
 */
bool
_filldir(DIR *dirp, bool use_current_pos)
{
	struct dirent **dpv;
	char *buf, *ddptr, *ddeptr;
	off_t pos;
	int fd2, incr, len, n, saved_errno, space;
	
	len = 0;
	space = 0;
	buf = NULL;
	ddptr = NULL;

	/*
	 * Use the system page size if that is a multiple of DIRBLKSIZ.
	 * Hopefully this can be a big win someday by allowing page
	 * trades to user space to be done by _getdirentries().
	 */
	incr = getpagesize();
	if ((incr % DIRBLKSIZ) != 0) 
		incr = DIRBLKSIZ;

	/*
	 * The strategy here is to read all the directory
	 * entries into a buffer, sort the buffer, and
	 * remove duplicate entries by setting the inode
	 * number to zero.
	 *
	 * We reopen the directory because _getdirentries()
	 * on a MNT_UNION mount modifies the open directory,
	 * making it refer to the lower directory after the
	 * upper directory's entries are exhausted.
	 * This would otherwise break software that uses
	 * the directory descriptor for fchdir or *at
	 * functions, such as fts.c.
	 */
	if ((fd2 = _openat(dirp->dd_fd, ".", O_RDONLY | O_CLOEXEC)) == -1)
		return (false);

	if (use_current_pos) {
		pos = lseek(dirp->dd_fd, 0, SEEK_CUR);
		if (pos == -1 || lseek(fd2, pos, SEEK_SET) == -1) {
			saved_errno = errno;
			_close(fd2);
			errno = saved_errno;
			return (false);
		}
	}

	do {
		/*
		 * Always make at least DIRBLKSIZ bytes
		 * available to _getdirentries
		 */
		if (space < DIRBLKSIZ) {
			space += incr;
			len += incr;
			buf = reallocf(buf, len);
			if (buf == NULL) {
				saved_errno = errno;
				_close(fd2);
				errno = saved_errno;
				return (false);
			}
			ddptr = buf + (len - space);
		}

		n = _getdirentries(fd2, ddptr, space, &dirp->dd_seek);
		if (n > 0) {
			ddptr += n;
			space -= n;
		}
		if (n < 0) {
			saved_errno = errno;
			_close(fd2);
			errno = saved_errno;
			return (false);
		}
	} while (n > 0);
	_close(fd2);

	ddeptr = ddptr;

	/*
	 * There is now a buffer full of (possibly) duplicate
	 * names.
	 */
	dirp->dd_buf = buf;

	/*
	 * Go round this loop twice...
	 *
	 * Scan through the buffer, counting entries.
	 * On the second pass, save pointers to each one.
	 * Then sort the pointers and remove duplicate names.
	 */
	for (dpv = 0;;) {
		n = 0;
		ddptr = buf;
		while (ddptr < ddeptr) {
			struct dirent *dp;

			dp = (struct dirent *) ddptr;
			if ((long)dp & 03L)
				break;
			if ((dp->d_reclen <= 0) ||
			    (dp->d_reclen > (ddeptr + 1 - ddptr)))
				break;
			ddptr += dp->d_reclen;
			if (dp->d_fileno) {
				if (dpv)
					dpv[n] = dp;
				n++;
			}
		}

		if (dpv) {
			struct dirent *xp;

			/*
			 * This sort must be stable.
			 */
			mergesort(dpv, n, sizeof(*dpv), opendir_compar);

			dpv[n] = NULL;
			xp = NULL;

			/*
			 * Scan through the buffer in sort order,
			 * zapping the inode number of any
			 * duplicate names.
			 */
			for (n = 0; dpv[n]; n++) {
				struct dirent *dp = dpv[n];

				if ((xp == NULL) ||
				    strcmp(dp->d_name, xp->d_name)) {
					xp = dp;
				} else {
					dp->d_fileno = 0;
				}
				if (dp->d_type == DT_WHT &&
				    (dirp->dd_flags & DTF_HIDEW))
					dp->d_fileno = 0;
			}

			free(dpv);
			break;
		} else {
			dpv = malloc((n+1) * sizeof(struct dirent *));
			if (dpv == NULL)
				break;
		}
	}

	dirp->dd_len = len;
	dirp->dd_size = ddptr - dirp->dd_buf;
	return (true);
}
Esempio n. 3
0
char *
getcwd(char *pt, size_t size)
{
	struct dirent *dp;
	DIR *dir = NULL;
	dev_t dev;
	ino_t ino;
	int first;
	char *bpt;
	struct stat s;
	dev_t root_dev;
	ino_t root_ino;
	size_t ptsize;
	int save_errno;
	char *ept, c;
	int fd;

	/*
	 * If no buffer specified by the user, allocate one as necessary.
	 * If a buffer is specified, the size has to be non-zero.  The path
	 * is built from the end of the buffer backwards.
	 */
	if (pt) {
		ptsize = 0;
		if (!size) {
			errno = EINVAL;
			return (NULL);
		}
		if (size == 1) {
			errno = ERANGE;
			return (NULL);
		}
		ept = pt + size;
	} else {
		if ((pt = malloc(ptsize = PATH_MAX)) == NULL)
			return (NULL);
		ept = pt + ptsize;
	}
	if (__getcwd(pt, ept - pt) == 0) {
		if (*pt != '/') {
			bpt = pt;
			ept = pt + strlen(pt) - 1;
			while (bpt < ept) {
				c = *bpt;
				*bpt++ = *ept;
				*ept-- = c;
			}
		}
		return (pt);
	}
	bpt = ept - 1;
	*bpt = '\0';

	/* Save root values, so know when to stop. */
	if (stat("/", &s))
		goto err;
	root_dev = s.st_dev;
	root_ino = s.st_ino;

	errno = 0;			/* XXX readdir has no error return. */

	for (first = 1;; first = 0) {
		/* Stat the current level. */
		if (dir != NULL ? _fstat(_dirfd(dir), &s) : lstat(".", &s))
			goto err;

		/* Save current node values. */
		ino = s.st_ino;
		dev = s.st_dev;

		/* Check for reaching root. */
		if (root_dev == dev && root_ino == ino) {
			*--bpt = '/';
			/*
			 * It's unclear that it's a requirement to copy the
			 * path to the beginning of the buffer, but it's always
			 * been that way and stuff would probably break.
			 */
			bcopy(bpt, pt, ept - bpt);
			if (dir)
				(void) closedir(dir);
			return (pt);
		}

		/* Open and stat parent directory. */
		fd = _openat(dir != NULL ? _dirfd(dir) : AT_FDCWD,
				"..", O_RDONLY | O_CLOEXEC);
		if (fd == -1)
			goto err;
		if (dir)
			(void) closedir(dir);
		if (!(dir = fdopendir(fd)) || _fstat(_dirfd(dir), &s)) {
			_close(fd);
			goto err;
		}

		/*
		 * If it's a mount point, have to stat each element because
		 * the inode number in the directory is for the entry in the
		 * parent directory, not the inode number of the mounted file.
		 */
		save_errno = 0;
		if (s.st_dev == dev) {
			for (;;) {
				if (!(dp = readdir(dir)))
					goto notfound;
				if (dp->d_fileno == ino)
					break;
			}
		} else
			for (;;) {
				if (!(dp = readdir(dir)))
					goto notfound;
				if (ISDOT(dp))
					continue;

				/* Save the first error for later. */
				if (fstatat(_dirfd(dir), dp->d_name, &s,
				    AT_SYMLINK_NOFOLLOW)) {
					if (!save_errno)
						save_errno = errno;
					errno = 0;
					continue;
				}
				if (s.st_dev == dev && s.st_ino == ino)
					break;
			}

		/*
		 * Check for length of the current name, preceding slash,
		 * leading slash.
		 */
		while (bpt - pt < dp->d_namlen + (first ? 1 : 2)) {
			size_t len, off;

			if (!ptsize) {
				errno = ERANGE;
				goto err;
			}
			off = bpt - pt;
			len = ept - bpt;
			if ((pt = reallocf(pt, ptsize *= 2)) == NULL)
				goto err;
			bpt = pt + off;
			ept = pt + ptsize;
			bcopy(bpt, ept - len, len);
			bpt = ept - len;
		}
		if (!first)
			*--bpt = '/';
		bpt -= dp->d_namlen;
		bcopy(dp->d_name, bpt, dp->d_namlen);
	}

notfound:
	/*
	 * If readdir set errno, use it, not any saved error; otherwise,
	 * didn't find the current directory in its parent directory, set
	 * errno to ENOENT.
	 */
	if (!errno)
		errno = save_errno ? save_errno : ENOENT;
	/* FALLTHROUGH */
err:
	save_errno = errno;

	if (ptsize)
		free(pt);
	if (dir)
		(void) closedir(dir);

	errno = save_errno;
	return (NULL);
}