*** samba-3.0.37/source/modules/vfs_default.c 2009-09-30 22:21:56.000000000 +1000 --- samba-3.0.37-aw/source/modules/vfs_default.c 2009-10-11 22:00:40.000000000 +1100 *************** *** 352,362 **** /********************************************************* For rename across filesystems Patch from Warren Birnbaum **********************************************************/ static int copy_reg(const char *source, const char *dest) { ! SMB_STRUCT_STAT source_stats; int saved_errno; int ifd = -1; int ofd = -1; --- 352,372 ---- /********************************************************* For rename across filesystems Patch from Warren Birnbaum + + Modified by Anthony Wesley + to copy to a temporary name and then rename. The temp name + starts with a "." and has permissions of "---------" as a hint that + it should be ignored. + + TODO: SHould attempt to copy ACL's from source to dest + **********************************************************/ static int copy_reg(const char *source, const char *dest) { ! SMB_STRUCT_STAT source_stats,dest_tmp_stats; ! char *dest_tmp,*dptr; ! int sfx,dest_tmp_len; int saved_errno; int ifd = -1; int ofd = -1; *************** *** 373,382 **** if (unlink (dest) && errno != ENOENT) return -1; #ifdef O_NOFOLLOW ! if((ofd = sys_open (dest, O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW, 0600)) < 0 ) #else ! if((ofd = sys_open (dest, O_WRONLY | O_CREAT | O_TRUNC , 0600)) < 0 ) #endif goto err; --- 383,432 ---- if (unlink (dest) && errno != ENOENT) return -1; + // Generate a temp name in the destination directory, + // the temp name will not be more than 32 chars longer + // than the real dest name + + dest_tmp_len = strlen(dest) + 32; // safe margin, half this would be ok + dest_tmp = SMB_MALLOC(dest_tmp_len); + + if (! dest_tmp) + return -1; + + // Find the last path component in the dest. May be start of string if + // there is no path. + dptr = (char *)dest+strlen(dest); + while(dptr != dest && *(dptr-1) != '/') --dptr; + + // Copy the directory portion of the destination, including the + // last '/' if it exists + if (! strncpy(dest_tmp,dest,dptr-dest)) { + SAFE_FREE(dest_tmp); + return -1; + } + + // Make a temporary name, make sure we pick something that + // doesn't exist in the destination dir. Use a filename prefix of '.' + // and a suffix that's numeric and vaguely random. + // Keep trying until we get something that doesn't already exist + + sfx = sys_getpid() + 1000 + (sys_random() % 10000); + while(sfx >= 0) { + slprintf(dest_tmp + (dptr-dest),dest_tmp_len,".%s.%d",dptr,sfx); + if (sys_stat(dest_tmp,&dest_tmp_stats)) break; + sfx--; + } + + // If we couldn't find a satisfactory temp name then bail out + if (sfx==0) { + SAFE_FREE(dest_tmp); + return -1; + } + #ifdef O_NOFOLLOW ! if((ofd = sys_open (dest_tmp, O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW, 0000)) < 0 ) #else ! if((ofd = sys_open (dest_tmp, O_WRONLY | O_CREAT | O_TRUNC , 0000)) < 0 ) #endif goto err; *************** *** 391,397 **** #ifdef HAVE_FCHOWN if ((fchown(ofd, source_stats.st_uid, source_stats.st_gid) == -1) && (errno != EPERM)) #else ! if ((chown(dest, source_stats.st_uid, source_stats.st_gid) == -1) && (errno != EPERM)) #endif goto err; --- 441,447 ---- #ifdef HAVE_FCHOWN if ((fchown(ofd, source_stats.st_uid, source_stats.st_gid) == -1) && (errno != EPERM)) #else ! if ((chown(dest_tmp, source_stats.st_uid, source_stats.st_gid) == -1) && (errno != EPERM)) #endif goto err; *************** *** 403,417 **** #if defined(HAVE_FCHMOD) if (fchmod (ofd, source_stats.st_mode & 07777)) #else ! if (chmod (dest, source_stats.st_mode & 07777)) #endif goto err; if (close (ifd) == -1) goto err; ! if (close (ofd) == -1) return -1; /* Try to copy the old file's modtime and access time. */ { --- 453,470 ---- #if defined(HAVE_FCHMOD) if (fchmod (ofd, source_stats.st_mode & 07777)) #else ! if (chmod (dest_tmp, source_stats.st_mode & 07777)) #endif goto err; if (close (ifd) == -1) goto err; ! if (close (ofd) == -1) { ! unlink(dest_tmp); // unlink anyway even if close() gave error ! SAFE_FREE(dest_tmp); return -1; + } /* Try to copy the old file's modtime and access time. */ { *************** *** 419,440 **** tv.actime = source_stats.st_atime; tv.modtime = source_stats.st_mtime; ! utime(dest, &tv); } ! if (unlink (source) == -1) return -1; return 0; err: saved_errno = errno; if (ifd != -1) close(ifd); if (ofd != -1) close(ofd); errno = saved_errno; return -1; } --- 472,510 ---- tv.actime = source_stats.st_atime; tv.modtime = source_stats.st_mtime; ! utime(dest_tmp, &tv); } ! // Rename temp to final ! if (rename(dest_tmp,dest)) { ! unlink(dest_tmp); ! SAFE_FREE(dest_tmp); return -1; + } + + SAFE_FREE(dest_tmp); + + if (unlink (source) == -1) { + unlink (dest); + return -1; + } return 0; err: saved_errno = errno; + if (ifd != -1) close(ifd); if (ofd != -1) close(ofd); + + unlink(dest_tmp); + SAFE_FREE(dest_tmp); + errno = saved_errno; + return -1; }