Commit c7c11a0d authored by David Dykstra's avatar David Dykstra

When a file cannot be deleted because of ETXTBSY (in particular, when an

executable is busy on HPUX), rename it instead to .rsyncNNN.  Most of
the code was submitted by Ketil Kristiansen <ketil-k@osc.no>
parent c27f2592
...@@ -182,7 +182,7 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out) ...@@ -182,7 +182,7 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out)
if (S_ISDIR(file->mode)) { if (S_ISDIR(file->mode)) {
if (dry_run) return; if (dry_run) return;
if (statret == 0 && !S_ISDIR(st.st_mode)) { if (statret == 0 && !S_ISDIR(st.st_mode)) {
if (do_unlink(fname) != 0) { if (robust_unlink(fname) != 0) {
rprintf(FERROR,"unlink %s : %s\n",fname,strerror(errno)); rprintf(FERROR,"unlink %s : %s\n",fname,strerror(errno));
return; return;
} }
......
...@@ -120,7 +120,7 @@ static void hard_link_one(int i) ...@@ -120,7 +120,7 @@ static void hard_link_one(int i)
} else { } else {
if (st2.st_dev == st1.st_dev && st2.st_ino == st1.st_ino) return; if (st2.st_dev == st1.st_dev && st2.st_ino == st1.st_ino) return;
if (do_unlink(f_name(&hlink_list[i])) != 0 || if (robust_unlink(f_name(&hlink_list[i])) != 0 ||
do_link(f_name(&hlink_list[i-1]),f_name(&hlink_list[i])) != 0) { do_link(f_name(&hlink_list[i-1]),f_name(&hlink_list[i])) != 0) {
if (verbose > 0) if (verbose > 0)
rprintf(FINFO,"link %s => %s : %s\n", rprintf(FINFO,"link %s => %s : %s\n",
......
...@@ -83,7 +83,7 @@ static void add_delete_entry(struct file_struct *file) ...@@ -83,7 +83,7 @@ static void add_delete_entry(struct file_struct *file)
static void delete_one(struct file_struct *f) static void delete_one(struct file_struct *f)
{ {
if (!S_ISDIR(f->mode)) { if (!S_ISDIR(f->mode)) {
if (do_unlink(f_name(f)) != 0) { if (robust_unlink(f_name(f)) != 0) {
rprintf(FERROR,"unlink %s : %s\n",f_name(f),strerror(errno)); rprintf(FERROR,"unlink %s : %s\n",f_name(f),strerror(errno));
} else if (verbose) { } else if (verbose) {
rprintf(FINFO,"deleting %s\n",f_name(f)); rprintf(FINFO,"deleting %s\n",f_name(f));
......
...@@ -57,7 +57,7 @@ int delete_file(char *fname) ...@@ -57,7 +57,7 @@ int delete_file(char *fname)
int ret; int ret;
extern int recurse; extern int recurse;
if (do_unlink(fname) == 0 || errno == ENOENT) return 0; if (robust_unlink(fname) == 0 || errno == ENOENT) return 0;
#if SUPPORT_LINKS #if SUPPORT_LINKS
ret = do_lstat(fname, &st); ret = do_lstat(fname, &st);
...@@ -262,7 +262,7 @@ void finish_transfer(char *fname, char *fnametmp, struct file_struct *file) ...@@ -262,7 +262,7 @@ void finish_transfer(char *fname, char *fnametmp, struct file_struct *file)
return; return;
/* move tmp file over real file */ /* move tmp file over real file */
if (do_rename(fnametmp,fname) != 0) { if (robust_rename(fnametmp,fname) != 0) {
if (errno == EXDEV) { if (errno == EXDEV) {
/* rename failed on cross-filesystem link. /* rename failed on cross-filesystem link.
Copy the file instead. */ Copy the file instead. */
...@@ -272,12 +272,11 @@ void finish_transfer(char *fname, char *fnametmp, struct file_struct *file) ...@@ -272,12 +272,11 @@ void finish_transfer(char *fname, char *fnametmp, struct file_struct *file)
} else { } else {
set_perms(fname,file,NULL,0); set_perms(fname,file,NULL,0);
} }
do_unlink(fnametmp);
} else { } else {
rprintf(FERROR,"rename %s -> %s : %s\n", rprintf(FERROR,"rename %s -> %s : %s\n",
fnametmp,fname,strerror(errno)); fnametmp,fname,strerror(errno));
do_unlink(fnametmp);
} }
do_unlink(fnametmp);
} else { } else {
set_perms(fname,file,NULL,0); set_perms(fname,file,NULL,0);
} }
......
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
*/ */
#include "rsync.h" #include "rsync.h"
extern int verbose;
/**************************************************************************** /****************************************************************************
Set a fd into nonblocking mode. Uses POSIX O_NONBLOCK if available, Set a fd into nonblocking mode. Uses POSIX O_NONBLOCK if available,
else else
...@@ -287,7 +289,7 @@ int copy_file(char *source, char *dest, mode_t mode) ...@@ -287,7 +289,7 @@ int copy_file(char *source, char *dest, mode_t mode)
return -1; return -1;
} }
if (do_unlink(dest) && errno != ENOENT) { if (robust_unlink(dest) && errno != ENOENT) {
rprintf(FERROR,"unlink %s: %s\n", rprintf(FERROR,"unlink %s: %s\n",
dest,strerror(errno)); dest,strerror(errno));
return -1; return -1;
...@@ -323,6 +325,81 @@ int copy_file(char *source, char *dest, mode_t mode) ...@@ -323,6 +325,81 @@ int copy_file(char *source, char *dest, mode_t mode)
return 0; return 0;
} }
/*
Robust unlink: some OS'es (HPUX) refuse to unlink busy files, so
rename to <path>/.rsyncNNN instead. Note that successive rsync runs
will shuffle the filenames around a bit as long as the file is still
busy; this is because this function does not know if the unlink call
is due to a new file coming in, or --delete trying to remove old
.rsyncNNN files, hence it renames it each time.
*/
/* MAX_RENAMES should be 10**MAX_RENAMES_DIGITS */
#define MAX_RENAMES_DIGITS 3
#define MAX_RENAMES 1000
int robust_unlink(char *fname)
{
#ifndef ETXTBSY
return do_unlink(fname);
#else
static int counter = 1;
int rc, pos, start;
char path[MAXPATHLEN];
rc = do_unlink(fname);
if ((rc == 0) || (errno != ETXTBSY))
return rc;
strlcpy(path, fname, MAXPATHLEN);
pos = strlen(path);
while((path[--pos] != '/') && (pos >= 0))
;
++pos;
strlcpy(&path[pos], ".rsync", MAXPATHLEN-pos);
pos += sizeof(".rsync")-1;
if (pos > (MAXPATHLEN-MAX_RENAMES_DIGITS-1)) {
errno = ETXTBSY;
return -1;
}
/* start where the last one left off to reduce chance of clashes */
start = counter;
do {
sprintf(&path[pos], "%03d", counter);
if (++counter >= MAX_RENAMES)
counter = 1;
} while (((rc = access(path, 0)) == 0) && (counter != start));
if (verbose > 0)
rprintf(FINFO,"renaming %s to %s because of text busy\n",
fname, path);
/* maybe we should return rename()'s exit status? Nah. */
if (do_rename(fname, path) != 0) {
errno = ETXTBSY;
return -1;
}
return 0;
#endif
}
int robust_rename(char *from, char *to)
{
#ifndef ETXTBSY
return do_rename(from, to);
#else
int rc = do_rename(from, to);
if ((rc == 0) || (errno != ETXTBSY))
return rc;
if (robust_unlink(to) != 0)
return -1;
return do_rename(from, to);
#endif
}
/* sleep for a while via select */ /* sleep for a while via select */
void u_sleep(int usec) void u_sleep(int usec)
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment