From: Wayne Davison Date: Mon, 19 Sep 2011 16:18:18 +0000 (-0700) Subject: Make do_readlink() support fake-super w/o O_NOFOLLOW. X-Git-Tag: v3.1.0pre1~76 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=953feeadd2d02e646edd2a35e3cc8465335a09dc;p=thirdparty%2Frsync.git Make do_readlink() support fake-super w/o O_NOFOLLOW. --- diff --git a/syscall.c b/syscall.c index c6c571a6..6d51d3cb 100644 --- a/syscall.c +++ b/syscall.c @@ -87,7 +87,7 @@ ssize_t do_readlink(const char *path, char *buf, size_t bufsiz) { /* For --fake-super, we read the link from the file. */ if (am_root < 0) { - int fd = open(path, O_RDONLY|O_NOFOLLOW); + int fd = do_open_nofollow(path, O_RDONLY); if (fd >= 0) { int len = read(fd, buf, bufsiz); close(fd); @@ -443,3 +443,50 @@ int do_fallocate(int fd, OFF_T offset, OFF_T length) #endif } #endif + +int do_open_nofollow(const char *pathname, int flags) +{ +#ifndef O_NOFOLLOW + struct stat f_st, l_st; +#endif + int fd; + + if (flags != O_RDONLY) { + RETURN_ERROR_IF(dry_run, 0); + RETURN_ERROR_IF_RO_OR_LO; +#ifndef O_NOFOLLOW + /* This function doesn't support write attempts w/o O_NOFOLLOW. */ + errno = EINVAL; + return -1; +#endif + } + +#ifdef O_NOFOLLOW + fd = open(pathname, flags|O_NOFOLLOW); +#else + if ((fd = open(pathname, flags)) < 0) + return fd; + + if (do_fstat(fd, &f_st) < 0) { + close_and_return_error: + { + int save_errno = errno; + close(fd); + errno = save_errno; + } + return -1; + } + if (do_lstat(pathname, &l_st) < 0) + goto close_and_return_error; + if (S_ISLNK(l_st.st_mode)) { + errno = ELOOP; + goto close_and_return_error; + } + if (l_st.st_dev != f_st.st_dev || l_st.st_ino != f_st.st_ino) { + errno = EINVAL; + goto close_and_return_error; + } +#endif + + return fd; +}