diff options
author | Wayne Davison <wayned@samba.org> | 2011-09-19 09:18:18 -0700 |
---|---|---|
committer | Wayne Davison <wayned@samba.org> | 2011-09-19 09:29:00 -0700 |
commit | 953feeadd2d02e646edd2a35e3cc8465335a09dc (patch) | |
tree | 8fcb41ef5abde526d31a43dacd9e194d79617d7d /syscall.c | |
parent | 3417881d5cf5358faa9484fb487775f0e8b14556 (diff) | |
download | rsync-953feeadd2d02e646edd2a35e3cc8465335a09dc.tar.gz |
Make do_readlink() support fake-super w/o O_NOFOLLOW.
Diffstat (limited to 'syscall.c')
-rw-r--r-- | syscall.c | 49 |
1 files changed, 48 insertions, 1 deletions
@@ -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; +} |