monotone-commits-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Monotone-commits-diffs] net.venge.monotone.nfs_mount_in_workspace: e326


From: code
Subject: [Monotone-commits-diffs] net.venge.monotone.nfs_mount_in_workspace: e326e60813b2c5144716140b432cc601404e2ea9
Date: Mon, 30 Apr 2012 16:14:25 +0200 (CEST)

revision:            e326e60813b2c5144716140b432cc601404e2ea9
date:                2012-04-26T20:31:08
author:              address@hidden
branch:              net.venge.monotone.nfs_mount_in_workspace
changelog:
* src/unix/fs.cc: handle nfs mounted directory in workspace

manifest:
format_version "1"

new_manifest [7ee34f14e6508741edba9d8cd12f0793bba8b9fe]

old_revision [7338faf653922c1c9ce0eb944f8c7c00f5e54bfd]

patch "src/unix/fs.cc"
 from [d34f7ed4b5cf3655d7920568e4e1a146fa670e13]
   to [cd0a6fb223a4351035c3d2c32a5d4dafc609ba91]
============================================================
--- src/unix/fs.cc	d34f7ed4b5cf3655d7920568e4e1a146fa670e13
+++ src/unix/fs.cc	cd0a6fb223a4351035c3d2c32a5d4dafc609ba91
@@ -1,3 +1,4 @@
+// Copyright (C) 2012 Stephe Leake <address@hidden>
 // Copyright (C) 2005 nathaniel smith <address@hidden>
 //
 // This program is made available under the GNU GPL version 2.0 or
@@ -28,6 +29,7 @@
 #include "../platform.hh"
 #include "../vector.hh"
 
+using std::malloc;
 using std::string;
 using std::vector;
 
@@ -288,11 +290,74 @@ rename_clobberingly(string const & from,
 void
 rename_clobberingly(string const & from, string const & to)
 {
+  // rename doesn't work across devices, which can happen if part of the
+  // workspace is NFS mounted.
+  //
+  // We only check for that if rename fails, to avoid slowing down normal
+  // workspaces.
+
   if (rename(from.c_str(), to.c_str()))
     {
-      const int err = errno;
-      E(false, origin::system,
-        F("renaming '%s' to '%s' failed: %s") % from % to % os_strerror(err));
+      // rename failed
+      int err = errno;
+
+      int from_fd = open(from.c_str(), O_RDONLY);
+      int to_fd = open(to.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
+      struct stat from_stat;
+      struct stat to_stat;
+      fstat(from_fd, &from_stat);
+      fstat(to_fd, &to_stat);
+
+      if (from_stat.st_dev != to_stat.st_dev)
+        {
+          // different devices; use cp, rm
+          //
+          // except there isn't a C function that does 'cp', so we read in
+          // the file and write it out again.
+
+          char * buffer    = (char * )malloc(from_stat.st_size);
+          char * ptr       = buffer;
+          size_t remaining = from_stat.st_size;
+
+          do
+            {
+              ssize_t read_count = read(from_fd, ptr, remaining);
+
+              err = errno;
+
+              E(read_count >= 0, origin::system,
+                F ("error reading file '%s': %s") % from % os_strerror(err));
+
+              remaining -= read_count;
+              ptr       += read_count;
+            }
+          while (remaining > 0);
+          close(from_fd);
+
+          ptr       = buffer;
+          remaining = from_stat.st_size;
+          do
+            {
+              ssize_t write_count = write(to_fd, ptr, remaining);
+              err = errno;
+              E(write_count >= 0, origin::system,
+                F("error writing file '%s': %s") % to % os_strerror(err));
+
+              remaining -= write_count;
+              ptr       += write_count;
+            }
+          while (remaining > 0);
+          close(to_fd);
+
+          free(buffer);
+
+          remove(from.c_str());
+        }
+      else
+        {
+          E(false, origin::system,
+            F("renaming '%s' to '%s' failed: %s") % from % to % os_strerror(err));
+        }
     }
 }
 

reply via email to

[Prev in Thread] Current Thread [Next in Thread]