diff --git a/src/internfile/internfile.cpp b/src/internfile/internfile.cpp index 7ff74a51..92805367 100644 --- a/src/internfile/internfile.cpp +++ b/src/internfile/internfile.cpp @@ -1007,49 +1007,21 @@ bool FileInterner::maybeUncompressToTemp(TempFile& temp, const string& fn, return false; } - // uncompressfile choses the output file name, there is good - // reason for this, but it's not nice here. Have to copy or rename - // the uncompressed file string uncomped; if (!uncompressfile(cnf, fn, ucmd, tmpdir, uncomped)) { return false; } // uncompressfile choses the output file name, there is good - // reason for this, but it's not nice here. Have to copy or rename - // the uncompressed file. - // Hopefully the cross-dev case won't happen as we're - // probably choosing the temp names in the same dir. However... - // Unix really should have a rename-else-copy call... - if (stat(temp->filename(), &st) < 0) { - LOGERR(("FileInterner::maybeUncompressToTemp: can't stat [%s]\n", - temp->filename())); + // reason for this, but it's not nice here. Have to move, the + // uncompressed file, hopefully staying on the same dev. + string reason; + if (!renameormove(uncomped.c_str(), temp->filename(), reason)) { + LOGERR(("FileInterner::maybeUncompress: move [%s] -> [%s] " + "failed: %s\n", + uncomped.c_str(), temp->filename(), reason.c_str())); return false; } - struct stat st1; - if (stat(uncomped.c_str(), &st1) < 0) { - LOGERR(("FileInterner::maybeUncompressToTemp: can't stat [%s]\n", - uncomped.c_str())); - return false; - } - if (st.st_dev == st1.st_dev) { - if (rename(uncomped.c_str(), temp->filename()) < 0) { - LOGERR(("FileInterner::maybeUncompress: rename [%s] -> [%s]" - "failed, errno %d\n", - uncomped.c_str(), temp->filename(), errno)); - return false; - } - } else { - string reason; - bool ret = copyfile(uncomped.c_str(), temp->filename(), reason); - if (ret == false) { - LOGERR(("FileInterner::maybeUncompress: copy [%s] -> [%s]" - "failed: %s\n", - uncomped.c_str(), temp->filename(), reason.c_str())); - return false; - } - // We let the tempdir cleanup get rid of uncomped - } return true; } diff --git a/src/utils/Makefile b/src/utils/Makefile index 6c139a49..7fb2c01c 100644 --- a/src/utils/Makefile +++ b/src/utils/Makefile @@ -1,7 +1,8 @@ depth = .. include $(depth)/mk/sysconf -PROGS = trcircache trmd5 trreadfile trfileudi trconftree wipedir smallut \ +PROGS = trcopyfile trcircache trmd5 trreadfile trfileudi trconftree \ + wipedir smallut \ trfstreewalk trpathut \ transcode trbase64 \ trmimeparse trexecmd utf8iter idfile @@ -33,6 +34,13 @@ trcircache.o : circache.cpp circache.h $(CXX) -o trcircache.o -c $(ALL_CXXFLAGS) \ -DTEST_CIRCACHE circache.cpp +COPYFILE_OBJS= trcopyfile.o copyfile.o $(BIGLIB) +trcopyfile : $(COPYFILE_OBJS) + $(CXX) -o trcopyfile $(COPYFILE_OBJS) $(LIBICONV) $(LIBSYS) +trcopyfile.o : copyfile.cpp copyfile.h + $(CXX) -o trcopyfile.o -c $(ALL_CXXFLAGS) \ + -DTEST_COPYFILE copyfile.cpp + MD5_OBJS= trmd5.o md5.o $(BIGLIB) trmd5 : $(MD5_OBJS) $(CXX) -o trmd5 $(MD5_OBJS) $(LIBICONV) $(LIBSYS) diff --git a/src/utils/copyfile.cpp b/src/utils/copyfile.cpp index 99a739e0..dc31c3a8 100644 --- a/src/utils/copyfile.cpp +++ b/src/utils/copyfile.cpp @@ -17,30 +17,28 @@ static char rcsid[] = "@(#$Id: copyfile.cpp,v 1.4 2007-12-13 06:58:22 dockes Exp * Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - +#ifndef TEST_COPYFILE #include #include #include #include #include +#include +#include -#include -using std::string; - +#include "copyfile.h" #include "debuglog.h" #define CPBSIZ 8192 #define COPYFILE_NOERRUNLINK 1 -bool copyfile(const char *src, const char *dst, string &reason, int flags = 0) +bool copyfile(const char *src, const char *dst, string &reason, int flags) { int sfd = -1; int dfd = -1; bool ret = false; char buf[CPBSIZ]; - reason.erase(); - LOGDEB(("copyfile: %s to %s\n", src, dst)); if ((sfd = open(src, O_RDONLY)) < 0) { @@ -70,6 +68,7 @@ bool copyfile(const char *src, const char *dst, string &reason, int flags = 0) goto out; } } + ret = true; out: if (ret == false && !(flags©FILE_NOERRUNLINK)) @@ -80,3 +79,121 @@ bool copyfile(const char *src, const char *dst, string &reason, int flags = 0) close(dfd); return ret; } + +bool renameormove(const char *src, const char *dst, string &reason) +{ + // First try rename(2). If this succeeds we're done. If this fails + // with EXDEV, try to copy. Unix really should have a library function + // for this. + if (rename(src, dst) == 0) { + return true; + } + if (errno != EXDEV) { + reason += string("rename(2) failed: ") + strerror(errno); + return false; + } + + struct stat st; + if (stat(src, &st) < 0) { + reason += string("Can't stat ") + src + " : " + strerror(errno); + return false; + } + if (!copyfile(src, dst, reason)) + return false; + + struct stat st1; + if (stat(dst, &st1) < 0) { + reason += string("Can't stat ") + dst + " : " + strerror(errno); + return false; + } + + // Try to preserve modes, owner, times. This may fail for a number + // of reasons + if ((st1.st_mode & 0777) != (st.st_mode & 0777)) { + chmod(dst, st.st_mode&0777); + } + if (st.st_uid != st1.st_uid || st.st_gid != st1.st_gid) { + chown(dst, st.st_uid, st.st_gid); + } + struct timeval times[2]; + times[0].tv_sec = st.st_atime; + times[0].tv_usec = 0; + times[1].tv_sec = st.st_mtime; + times[1].tv_usec = 0; + utimes(dst, times); + + // All ok, get rid of origin + if (unlink(src) < 0) { + reason += string("Can't unlink ") + src + "Error : " + strerror(errno); + } + + return true; +} + + +#else + +#include +#include + +#include +#include +using namespace std; + +#include "copyfile.h" + +static int op_flags; +#define OPT_MOINS 0x1 +#define OPT_m 0x2 + +static const char *thisprog; +static char usage [] = +"trcopyfile [-m] src dst\n" +" -m : move instead of copying\n" +"\n" +; +static void +Usage(void) +{ + fprintf(stderr, "%s: usage:\n%s", thisprog, usage); + exit(1); +} + +int main(int argc, const char **argv) +{ + thisprog = argv[0]; + argc--; argv++; + + while (argc > 0 && **argv == '-') { + (*argv)++; + if (!(**argv)) + /* Cas du "adb - core" */ + Usage(); + while (**argv) + switch (*(*argv)++) { + case 'm': op_flags |= OPT_m; break; + default: Usage(); break; + } + argc--; argv++; + } + + if (argc != 2) + Usage(); + string src = *argv++;argc--; + string dst = *argv++;argc--; + bool ret; + string reason; + if (op_flags & OPT_m) { + ret = renameormove(src.c_str(), dst.c_str(), reason); + } else { + ret = copyfile(src.c_str(), dst.c_str(), reason); + } + if (!ret) { + cerr << reason << endl; + exit(1); + } + exit(0); +} + + +#endif diff --git a/src/utils/copyfile.h b/src/utils/copyfile.h index 6f6b7800..9df30e3b 100644 --- a/src/utils/copyfile.h +++ b/src/utils/copyfile.h @@ -19,10 +19,14 @@ /* @(#$Id: copyfile.h,v 1.2 2006-01-30 11:15:28 dockes Exp $ (C) 2004 J.F.Dockes */ #include +using std::string; enum CopyfileFlags {COPYFILE_NONE = 0, COPYFILE_NOERRUNLINK = 1}; -extern bool copyfile(const char *src, const char *dst, std::string &reason, +extern bool copyfile(const char *src, const char *dst, string &reason, int flags = 0); +// Try to rename, copy/unlink source if this fails (different devs) +extern bool renameormove(const char *src, const char *dst, string &reason); + #endif /* _COPYFILE_H_INCLUDED_ */