1/* 2 * Syscall wrappers to ensure that nothing gets done in dry_run mode 3 * and to handle system peculiarities. 4 * 5 * Copyright (C) 1998 Andrew Tridgell 6 * Copyright (C) 2002 Martin Pool 7 * Copyright (C) 2003, 2004, 2005, 2006 Wayne Davison 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License along 20 * with this program; if not, write to the Free Software Foundation, Inc., 21 * 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. 22 */ 23 24#include "rsync.h" 25 26#if !defined MKNOD_CREATES_SOCKETS && defined HAVE_SYS_UN_H 27#include <sys/un.h> 28#endif 29 30#ifdef HAVE_COPYFILE_H 31#include <libgen.h> 32#include <copyfile.h> 33#endif 34 35extern int dry_run; 36extern int read_only; 37extern int list_only; 38extern int preserve_perms; 39#ifdef EA_SUPPORT 40extern int extended_attributes; 41extern int preserve_links; 42#endif 43 44#define RETURN_ERROR_IF(x,e) \ 45 do { \ 46 if (x) { \ 47 errno = (e); \ 48 return -1; \ 49 } \ 50 } while (0) 51 52#define RETURN_ERROR_IF_RO_OR_LO RETURN_ERROR_IF(read_only || list_only, EROFS) 53 54int do_unlink(const char *fname) 55{ 56 if (dry_run) return 0; 57 RETURN_ERROR_IF_RO_OR_LO; 58#ifdef HAVE_COPYFILE 59 if (extended_attributes && !strncmp("._", basename(fname), 2)) 60 { 61 int ret; 62 ret = unlink(fname); 63 64 if(ret == -1 && errno != ENOENT) 65 return -1; 66 else 67 return 0; 68 } 69#endif 70 return unlink(fname); 71} 72 73int do_symlink(const char *fname1, const char *fname2) 74{ 75 if (dry_run) return 0; 76 RETURN_ERROR_IF_RO_OR_LO; 77 return symlink(fname1, fname2); 78} 79 80#ifdef HAVE_LINK 81int do_link(const char *fname1, const char *fname2) 82{ 83 if (dry_run) return 0; 84 RETURN_ERROR_IF_RO_OR_LO; 85 return link(fname1, fname2); 86} 87#endif 88 89int do_lchown(const char *path, uid_t owner, gid_t group) 90{ 91 if (dry_run) return 0; 92 RETURN_ERROR_IF_RO_OR_LO; 93#ifndef HAVE_LCHOWN 94#define lchown chown 95#endif 96 return lchown(path, owner, group); 97} 98 99int do_mknod(char *pathname, mode_t mode, dev_t dev) 100{ 101 if (dry_run) return 0; 102 RETURN_ERROR_IF_RO_OR_LO; 103#if !defined MKNOD_CREATES_FIFOS && defined HAVE_MKFIFO 104 if (S_ISFIFO(mode)) 105 return mkfifo(pathname, mode); 106#endif 107#if !defined MKNOD_CREATES_SOCKETS && defined HAVE_SYS_UN_H 108 if (S_ISSOCK(mode)) { 109 int sock; 110 struct sockaddr_un saddr; 111 unsigned int len; 112 113 saddr.sun_family = AF_UNIX; 114 len = strlcpy(saddr.sun_path, pathname, sizeof saddr.sun_path); 115#ifdef HAVE_SOCKADDR_UN_LEN 116 saddr.sun_len = len >= sizeof saddr.sun_path 117 ? sizeof saddr.sun_path : len + 1; 118#endif 119 120 if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0 121 || (unlink(pathname) < 0 && errno != ENOENT) 122 || (bind(sock, (struct sockaddr*)&saddr, sizeof saddr)) < 0) 123 return -1; 124 close(sock); 125#ifdef HAVE_CHMOD 126 return do_chmod(pathname, mode); 127#else 128 return 0; 129#endif 130 } 131#endif 132#ifdef HAVE_MKNOD 133 return mknod(pathname, mode, dev); 134#else 135 return -1; 136#endif 137} 138 139int do_rmdir(const char *pathname) 140{ 141 if (dry_run) return 0; 142 RETURN_ERROR_IF_RO_OR_LO; 143 return rmdir(pathname); 144} 145 146int do_open(const char *pathname, int flags, mode_t mode) 147{ 148 if (flags != O_RDONLY) { 149 RETURN_ERROR_IF(dry_run, 0); 150 RETURN_ERROR_IF_RO_OR_LO; 151 } 152 153 return open(pathname, flags | O_BINARY, mode); 154} 155 156#ifdef HAVE_CHMOD 157int do_chmod(const char *path, mode_t mode) 158{ 159 int code; 160 if (dry_run) return 0; 161 RETURN_ERROR_IF_RO_OR_LO; 162 if (S_ISLNK(mode)) { 163#ifdef HAVE_LCHMOD 164 code = lchmod(path, mode & CHMOD_BITS); 165#else 166 code = 1; 167#endif 168 } else 169 code = chmod(path, mode & CHMOD_BITS); 170 if (code != 0 && preserve_perms) 171 return code; 172 return 0; 173} 174#endif 175 176int do_rename(const char *fname1, const char *fname2) 177{ 178 if (dry_run) return 0; 179 RETURN_ERROR_IF_RO_OR_LO; 180#ifdef HAVE_COPYFILE 181 if(extended_attributes) 182 { 183 char dst_fname[MAXPATHLEN]; 184 if(!strncmp(basename(fname1), ".._", 3)) 185 { 186 snprintf(dst_fname, MAXPATHLEN, "%s/%s", dirname(fname2), basename(fname2) + 2); 187 if(copyfile(fname1, dst_fname, 0, 188 COPYFILE_UNPACK | COPYFILE_ACL | COPYFILE_XATTR | (preserve_links ? COPYFILE_NOFOLLOW : 0)) == 0) 189 return unlink(fname1); 190 else 191 rprintf(FERROR,"copyfile(%s,%s, COPYFILE_UNPACK) failed:%d\n", fname1, dst_fname, errno); 192 193 } 194 } 195#endif 196 return rename(fname1, fname2); 197} 198 199void trim_trailing_slashes(char *name) 200{ 201 int l; 202 /* Some BSD systems cannot make a directory if the name 203 * contains a trailing slash. 204 * <http://www.opensource.apple.com/bugs/X/BSD%20Kernel/2734739.html> */ 205 206 /* Don't change empty string; and also we can't improve on 207 * "/" */ 208 209 l = strlen(name); 210 while (l > 1) { 211 if (name[--l] != '/') 212 break; 213 name[l] = '\0'; 214 } 215} 216 217int do_mkdir(char *fname, mode_t mode) 218{ 219 if (dry_run) return 0; 220 RETURN_ERROR_IF_RO_OR_LO; 221 trim_trailing_slashes(fname); 222 return mkdir(fname, mode); 223} 224 225/* like mkstemp but forces permissions */ 226int do_mkstemp(char *template, mode_t perms) 227{ 228 RETURN_ERROR_IF(dry_run, 0); 229 RETURN_ERROR_IF(read_only, EROFS); 230 231#if defined HAVE_SECURE_MKSTEMP && defined HAVE_FCHMOD && (!defined HAVE_OPEN64 || defined HAVE_MKSTEMP64) 232 { 233 int fd = mkstemp(template); 234 if (fd == -1) 235 return -1; 236 if (fchmod(fd, perms) != 0 && preserve_perms) { 237 int errno_save = errno; 238 close(fd); 239 unlink(template); 240 errno = errno_save; 241 return -1; 242 } 243#if defined HAVE_SETMODE && O_BINARY 244 setmode(fd, O_BINARY); 245#endif 246 return fd; 247 } 248#else 249 if (!mktemp(template)) 250 return -1; 251 return do_open(template, O_RDWR|O_EXCL|O_CREAT, perms); 252#endif 253} 254 255int do_stat(const char *fname, STRUCT_STAT *st) 256{ 257#ifdef USE_STAT64_FUNCS 258 return stat64(fname, st); 259#else 260 return stat(fname, st); 261#endif 262} 263 264int do_lstat(const char *fname, STRUCT_STAT *st) 265{ 266#ifdef SUPPORT_LINKS 267# ifdef USE_STAT64_FUNCS 268 return lstat64(fname, st); 269# else 270 return lstat(fname, st); 271# endif 272#else 273 return do_stat(fname, st); 274#endif 275} 276 277int do_fstat(int fd, STRUCT_STAT *st) 278{ 279#ifdef USE_STAT64_FUNCS 280 return fstat64(fd, st); 281#else 282 return fstat(fd, st); 283#endif 284} 285 286OFF_T do_lseek(int fd, OFF_T offset, int whence) 287{ 288#ifdef HAVE_LSEEK64 289#if !SIZEOF_OFF64_T 290 OFF_T lseek64(); 291#else 292 off64_t lseek64(); 293#endif 294 return lseek64(fd, offset, whence); 295#else 296 return lseek(fd, offset, whence); 297#endif 298} 299 300char *d_name(struct dirent *di) 301{ 302#ifdef HAVE_BROKEN_READDIR 303 return (di->d_name - 2); 304#else 305 return di->d_name; 306#endif 307} 308