Try to do atomic file swap on UNIX when updating profile
authorKen Raeburn <raeburn@mit.edu>
Thu, 9 Jan 2003 00:20:20 +0000 (00:20 +0000)
committerKen Raeburn <raeburn@mit.edu>
Thu, 9 Jan 2003 00:20:20 +0000 (00:20 +0000)
* prof_file.c (make_hard_link): New function.
(profile_flush_file_data): Use it to attempt a safe profile file replacement.

ticket: 1301
status: open

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@15101 dc483132-0cff-0310-8789-dd5450dbe970

src/util/profile/ChangeLog
src/util/profile/prof_file.c

index 3d71969e5b0fc58eda0e41a2b1d479c7f9acc3b7..7dfe046c88e80a449c227116359ccf38f5920285 100644 (file)
@@ -1,5 +1,9 @@
 2003-01-08  Ken Raeburn  <raeburn@mit.edu>
 
+       * prof_file.c (make_hard_link): New function.
+       (profile_flush_file_data): Use it to attempt a safe profile file
+       replacement.
+
        * prof_parse.c (profile_parse_file)
        [PROFILE_SUPPORTS_FOREIGN_NEWLINES]: Look for \r and treat it as a
        line break.
index 749a7550db4561e9a2040e4f81a017b7645cf58d..22470cc6e6378178133f4af1fd4f1e416b3e98fa 100644 (file)
@@ -217,6 +217,16 @@ errcode_t profile_update_file_data(prf_data_t data)
        return 0;
 }
 
+static int
+make_hard_link(const char *oldpath, const char *newpath)
+{
+#ifdef _WIN32
+    return -1;
+#else
+    return link(oldpath, newpath);
+#endif
+}
+
 errcode_t profile_flush_file_data(data)
        prf_data_t data;
 {
@@ -279,14 +289,31 @@ errcode_t profile_flush_file_data(data)
 #endif
 
        unlink(old_file);
-       if (rename(data->filespec, old_file)) {
+       if (make_hard_link(data->filespec, old_file) == 0) {
+           /* Okay, got the hard link.  Yay.  Now we've got our
+              backup version, so just put the new version in
+              place.  */
+           if (rename(new_file, data->filespec)) {
+               /* Weird, the rename didn't work.  But the old version
+                  should still be in place, so no special cleanup is
+                  needed.  */
                retval = errno;
                goto errout;
-       }
-       if (rename(new_file, data->filespec)) {
+           }
+       } else {
+           /* Couldn't make the hard link, so there's going to be a
+              small window where data->filespec does not refer to
+              either version.  */
+           sync();
+           if (rename(data->filespec, old_file)) {
+               retval = errno;
+               goto errout;
+           }
+           if (rename(new_file, data->filespec)) {
                retval = errno;
                rename(old_file, data->filespec); /* back out... */
                goto errout;
+           }
        }
 
        data->flags = 0;