[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

[PATCH] issue #532 read-only admin area

From: Philip Martin <philip_at_codematters.co.uk>
Date: 2002-01-28 01:24:31 CET

Does this look OK?

Issue #532: make files in the .svn admin area readonly. Based on an
initial patch by Karl (which worked much better after I changed it so
that the code removed the write flag instead of removing the read
flag!), this goes further to make all the files in the admin area
readonly.

* subversion/include/svn_io.h
  (svn_io_copy_file): Add boolean permissions copying parameter.
  (svn_io_copy_dir_recursively): Add boolean permissions copying parameter.
  (svn_io_set_file_read_only): Add prototype.

* subversion/libsvn_subr/io.c
  (svn_io_copy_file): Add conditional permissions copying.
  (svn_io_copy_dir_recursively): Pass new parameter to svn_io_copy_file and
  recursive svn_io_copy_dir_recursively.
  (svn_io_set_file_read_only): Add function.

* subversion/libsvn_wc/adm_crawler.c
  (do_postfix_text_deltas, do_prop_deltas, restore_file): Pass new parameter
  to svn_io_copy_file.

* subversion/libsvn_wc/adm_files.c
  (maybe_copy_file): Pass new parameter to svn_io_copy_file.
  (sync_adm_file): Use svn_io_set_file_read_only to make permanent adm file
  readonly.
  (close_adm_file): Use svn_io_set_file_read_only to make permanent adm file
  readonly.

* subversion/libsvn_wc/copy.c
  (copy_file_administratively): Pass new parameter to svn_io_copy_file.
  (copy_dir_administratively): Pass new parameter to svn_io_copy_dir_recursively

* subversion/libsvn_wc/get_editor.c (close_file): Add log entry to
  make text-base readonly.

* subversion/libsvn_wc/log.c
  (replace_text_base): Pass new parameter to svn_io_copy_file.
  (log_do_file_readonly): New function.
  (start_handler): Handle SVN_WC__LOG_READONLY.

* subversion/libsvn_wc/props.c (svn_wc__do_property_merge): Add log entries
  to make property files readonly.

* subversion/libsvn_wc/translate.c (svn_wc_copy_and_translate): Pass new
  parameter to svn_io_copy_file.

* subversion/libsvn_wc/wc.h
  (SVN_WC__LOG_READONLY): Add log tag.

Index: ../svn/subversion/include/svn_io.h
===================================================================
--- ../svn/subversion/include/svn_io.h
+++ ../svn/subversion/include/svn_io.h Sun Jan 27 22:28:15 2002
@@ -108,18 +108,22 @@
                                       apr_pool_t *pool);
 
 
-/* Copy SRC to DST. DST will be overwritten if it exists, else it
- will be created. */
+/* Copy SRC to DST. DST will be overwritten if it exists, else it will be
+ created. If COPY_PERMS is set the file permissions of DST will be set to
+ match those of SRC, this will happen before the contents are copied. */
 svn_error_t *svn_io_copy_file (const char *src,
                                const char *dst,
+ svn_boolean_t copy_perms,
                                apr_pool_t *pool);
 
-/* Recursively copy directory SRC into DST_PARENT, as a new entry
- named DST_BASENAME. If DST_BASENAME already exists in DST_PARENT,
- return error. */
+/* Recursively copy directory SRC into DST_PARENT, as a new entry named
+ DST_BASENAME. If DST_BASENAME already exists in DST_PARENT, return
+ error. COPY_PERMS will be passed through to svn_io_copy_file when any
+ files are copied. */
 svn_error_t *svn_io_copy_dir_recursively (svn_stringbuf_t *src,
                                           svn_stringbuf_t *dst_parent,
                                           svn_stringbuf_t *dst_basename,
+ svn_boolean_t copy_perms,
                                           apr_pool_t *pool);
 
 
@@ -134,6 +138,17 @@
 svn_error_t *svn_io_append_file (svn_stringbuf_t *src,
                                  svn_stringbuf_t *dst,
                                  apr_pool_t *pool);
+
+/* Make a file as read-only as the operating system allows.
+ *
+ * For example, under Unix, this will make the file read-only for
+ * `user,' `group', and `other', leaving the file's other mode bits
+ * untouched.
+ *
+ * ### todo: someone care to document exactly how this behaves under
+ * Windows?
+ */
+svn_error_t *svn_io_set_file_read_only (const char *fname, apr_pool_t *pool);
 
 
 /* Read a line from FILE into BUF, but not exceeding *LIMIT bytes.
Index: ../svn/subversion/libsvn_wc/props.c
===================================================================
--- ../svn/subversion/libsvn_wc/props.c
+++ ../svn/subversion/libsvn_wc/props.c Sun Jan 27 19:10:12 2002
@@ -621,6 +621,15 @@
                          real_prop_base,
                          NULL);
 
+ /* Make prop-base readonly */
+ svn_xml_make_open_tag (entry_accum,
+ pool,
+ svn_xml_self_closing,
+ SVN_WC__LOG_READONLY,
+ SVN_WC__LOG_ATTR_NAME,
+ real_prop_base,
+ NULL);
+
   /* Write log entry to move working tmp copy to real working area. */
   svn_xml_make_open_tag (entry_accum,
                          pool,
@@ -629,6 +638,15 @@
                          SVN_WC__LOG_ATTR_NAME,
                          tmp_props,
                          SVN_WC__LOG_ATTR_DEST,
+ real_props,
+ NULL);
+
+ /* Make props readonly */
+ svn_xml_make_open_tag (entry_accum,
+ pool,
+ svn_xml_self_closing,
+ SVN_WC__LOG_READONLY,
+ SVN_WC__LOG_ATTR_NAME,
                          real_props,
                          NULL);
 
Index: ../svn/subversion/libsvn_wc/copy.c
===================================================================
--- ../svn/subversion/libsvn_wc/copy.c
+++ ../svn/subversion/libsvn_wc/copy.c Sun Jan 27 22:30:14 2002
@@ -147,7 +147,7 @@
        src_path->data);
 
   /* Now, make an actual copy of the working file. */
- SVN_ERR (svn_io_copy_file (src_path->data, dst_path->data, pool));
+ SVN_ERR (svn_io_copy_file (src_path->data, dst_path->data, TRUE, pool));
 
   /* Copy the pristine text-base over. Why? Because it's the *only*
      way we can detect any upcoming local mods on the copy.
@@ -178,17 +178,17 @@
     SVN_ERR (svn_wc__prop_base_path (&dst_bprop, dst_path, 0, pool));
 
     /* Copy the text-base over unconditionally. */
- SVN_ERR (svn_io_copy_file (src_txtb->data, dst_txtb->data, pool));
+ SVN_ERR (svn_io_copy_file (src_txtb->data, dst_txtb->data, TRUE, pool));
 
     /* Copy the props over if they exist. */
     SVN_ERR (svn_io_check_path (src_wprop, &kind, pool));
     if (kind == svn_node_file)
- SVN_ERR (svn_io_copy_file (src_wprop->data, dst_wprop->data, pool));
+ SVN_ERR (svn_io_copy_file (src_wprop->data, dst_wprop->data, TRUE, pool));
       
     /* Copy the base-props over if they exist */
     SVN_ERR (svn_io_check_path (src_bprop, &kind, pool));
     if (kind == svn_node_file)
- SVN_ERR (svn_io_copy_file (src_bprop->data, dst_bprop->data, pool));
+ SVN_ERR (svn_io_copy_file (src_bprop->data, dst_bprop->data, TRUE, pool));
   }
 
   /* Schedule the new file for addition in its parent, WITH HISTORY. */
@@ -248,7 +248,7 @@
       (This gets us all text-base, props, base-props, as well as entries,
       local mods, schedulings, existences, etc.) */
   SVN_ERR (svn_io_copy_dir_recursively (src_path, dst_parent, dst_basename,
- pool));
+ TRUE, pool));
 
   /* Remove all wcprops in the directory, because they're all bogus
      now. After the commit, ra_dav should regenerate them and
Index: ../svn/subversion/libsvn_wc/wc.h
===================================================================
--- ../svn/subversion/libsvn_wc/wc.h
+++ ../svn/subversion/libsvn_wc/wc.h Sun Jan 27 22:20:14 2002
@@ -443,6 +443,9 @@
 /* Append file from SVN_WC__LOG_ATTR_NAME to SVN_WC__LOG_ATTR_DEST. */
 #define SVN_WC__LOG_APPEND "append"
 
+/* Make file SVN_WC__LOG_ATTR_NAME readonly */
+#define SVN_WC__LOG_READONLY "readonly"
+
 /* Handle closure after a commit completes successfully:
  *
  * If SVN/tmp/text-base/SVN_WC__LOG_ATTR_NAME exists, then
Index: ../svn/subversion/libsvn_wc/adm_crawler.c
===================================================================
--- ../svn/subversion/libsvn_wc/adm_crawler.c
+++ ../svn/subversion/libsvn_wc/adm_crawler.c Sun Jan 27 22:17:43 2002
@@ -528,7 +528,8 @@
 
       SVN_ERR (svn_wc_translated_file (&tmp_wfile, entrypath, pool));
       tmp_text_base = svn_wc__text_base_path (entrypath, TRUE, pool);
- SVN_ERR (svn_io_copy_file (tmp_wfile->data, tmp_text_base->data, pool));
+ SVN_ERR (svn_io_copy_file (tmp_wfile->data, tmp_text_base->data, FALSE,
+ pool));
       if (tmp_wfile != entrypath)
         SVN_ERR (svn_io_remove_file (tmp_wfile->data, pool));
 
@@ -574,7 +575,8 @@
 
   /* Copy the local prop file to the administrative temp area */
   SVN_ERR (svn_wc__prop_path (&tmp_prop_path, path, 1, pool));
- SVN_ERR (svn_io_copy_file (prop_path->data, tmp_prop_path->data, pool));
+ SVN_ERR (svn_io_copy_file (prop_path->data, tmp_prop_path->data, FALSE,
+ pool));
 
   /* Load all properties into hashes */
   SVN_ERR (svn_wc__load_prop_file (tmp_prop_path->data, localprops, pool));
@@ -1771,7 +1773,7 @@
   tmp_text_base_path = svn_wc__text_base_path (file_path, TRUE, pool);
 
   SVN_ERR (svn_io_copy_file (text_base_path->data, tmp_text_base_path->data,
- pool));
+ FALSE, pool));
 
   SVN_ERR (svn_wc__get_eol_style (&eol_style, &eol,
                                   file_path->data, pool));
Index: ../svn/subversion/libsvn_wc/log.c
===================================================================
--- ../svn/subversion/libsvn_wc/log.c
+++ ../svn/subversion/libsvn_wc/log.c Sun Jan 27 22:10:23 2002
@@ -194,7 +194,8 @@
                (&same, tmp_wfile, filepath, pool));
 
       if (! same)
- SVN_ERR (svn_io_copy_file (tmp_wfile->data, filepath->data, pool));
+ SVN_ERR (svn_io_copy_file (tmp_wfile->data, filepath->data, FALSE,
+ pool));
 
       SVN_ERR (svn_io_remove_file (tmp_wfile->data, pool));
 
@@ -384,6 +385,22 @@
   return SVN_NO_ERROR;
 }
 
+/* Make file NAME in log's CWD readonly */
+static svn_error_t *
+log_do_file_readonly (struct log_runner *loggy,
+ const char *name,
+ enum svn_wc__xfer_action action,
+ const XML_Char **atts)
+{
+ svn_stringbuf_t *full_path;
+
+ full_path = svn_stringbuf_dup (loggy->path, loggy->pool);
+ svn_path_add_component_nts (full_path, name);
+
+ SVN_ERR (svn_io_set_file_read_only (full_path->data, loggy->pool));
+
+ return SVN_NO_ERROR;
+}
 
 /* Remove file NAME in log's CWD. */
 static svn_error_t *
@@ -871,6 +888,9 @@
                                           "error renaming %s to %s",
                                           tmp_prop_path->data,
                                           prop_base_path->data);
+
+ SVN_ERR (svn_io_set_file_read_only (prop_base_path->data,
+ loggy->pool));
             }
           
 
@@ -1007,6 +1027,9 @@
   }
   else if (strcmp (eltname, SVN_WC__LOG_APPEND) == 0) {
     err = log_do_file_xfer (loggy, name, svn_wc__xfer_append, atts);
+ }
+ else if (strcmp (eltname, SVN_WC__LOG_READONLY) == 0) {
+ err = log_do_file_readonly (loggy, name, svn_wc__xfer_append, atts);
   }
   else
     {
Index: ../svn/subversion/libsvn_wc/adm_ops.c
===================================================================
--- ../svn/subversion/libsvn_wc/adm_ops.c
+++ ../svn/subversion/libsvn_wc/adm_ops.c Sun Jan 27 22:10:03 2002
@@ -863,7 +863,7 @@
       SVN_ERR (svn_io_check_path (pthing, &kind, pool));
       if (kind == svn_node_file)
         {
- if ((err = svn_io_copy_file (pthing->data, thing->data, pool)))
+ if ((err = svn_io_copy_file (pthing->data, thing->data, FALSE, pool)))
             return revert_error (err, fullpath, "restoring props", pool);
           SVN_ERR (svn_io_file_affected_time (&tstamp, thing, pool));
           entry->prop_time = tstamp;
Index: ../svn/subversion/libsvn_wc/adm_files.c
===================================================================
--- ../svn/subversion/libsvn_wc/adm_files.c
+++ ../svn/subversion/libsvn_wc/adm_files.c Sun Jan 27 22:18:53 2002
@@ -290,7 +290,7 @@
     }
   else /* SRC exists, so copy it to DST. */
     {
- err = svn_io_copy_file (src->data, dst->data, pool);
+ err = svn_io_copy_file (src->data, dst->data, FALSE, pool);
       if (err)
         return err;
     }
@@ -328,6 +328,8 @@
   
   /* Rename. */
   apr_err = apr_file_rename (tmp_path->data, path->data, pool);
+ if (APR_STATUS_IS_SUCCESS (apr_err))
+ SVN_ERR (svn_io_set_file_read_only (path->data, pool));
 
   /* Unconditionally restore path. */
   chop_admin_name (path, components_added);
@@ -681,6 +683,8 @@
       
       /* Rename. */
       apr_err = apr_file_rename (tmp_path->data, path->data, pool);
+ if (APR_STATUS_IS_SUCCESS(apr_err))
+ SVN_ERR (svn_io_set_file_read_only (path->data, pool));
       
       /* Unconditionally restore path. */
       chop_admin_name (path, components_added);
Index: ../svn/subversion/libsvn_wc/get_editor.c
===================================================================
--- ../svn/subversion/libsvn_wc/get_editor.c
+++ ../svn/subversion/libsvn_wc/get_editor.c Sun Jan 27 17:02:24 2002
@@ -1907,7 +1907,16 @@
                                      NULL);
             }
         }
-
+
+ /* Make text-base readonly */
+ svn_xml_make_open_tag (&entry_accum,
+ fb->pool,
+ svn_xml_self_closing,
+ SVN_WC__LOG_READONLY,
+ SVN_WC__LOG_ATTR_NAME,
+ txtb,
+ NULL);
+
     } /* End of "textual" merging process */
   
 
Index: ../svn/subversion/libsvn_wc/translate.c
===================================================================
--- ../svn/subversion/libsvn_wc/translate.c
+++ ../svn/subversion/libsvn_wc/translate.c Sun Jan 27 23:14:28 2002
@@ -420,7 +420,7 @@
                            apr_pool_t *pool)
 {
 #ifndef SVN_TRANSLATE
- return svn_io_copy_file (src, dst, pool);
+ return svn_io_copy_file (src, dst, FALSE, pool);
 #else /* ! SVN_TRANSLATE */
   apr_file_t *s = NULL, *d = NULL; /* init to null important for APR */
   apr_status_t apr_err;
@@ -437,7 +437,7 @@
   apr_size_t src_format_len = 0;
 
   if (! (eol_str || keywords))
- return svn_io_copy_file (src, dst, pool);
+ return svn_io_copy_file (src, dst, FALSE, pool);
 
   /* Open source file. */
   apr_err = apr_file_open (&s, src, APR_READ | APR_BUFFERED,
Index: ../svn/subversion/libsvn_subr/io.c
===================================================================
--- ../svn/subversion/libsvn_subr/io.c
+++ ../svn/subversion/libsvn_subr/io.c Sun Jan 27 22:28:57 2002
@@ -324,15 +324,55 @@
 
 
 svn_error_t *
-svn_io_copy_file (const char *src, const char *dst, apr_pool_t *pool)
+svn_io_copy_file (const char *src,
+ const char *dst,
+ svn_boolean_t copy_perms,
+ apr_pool_t *pool)
 {
   apr_status_t apr_err;
+ apr_finfo_t finfo;
+
+ /* apr_copy_file will copy the permissions, if that is not wanted we need
+ to get the initial permissions and restore them after the copy. */
+ if (!copy_perms)
+ {
+ apr_file_t *tmp;
+
+ /* It must be possible to open APR_WRITE if the copy is going to
+ succeed. */
+ apr_err = apr_file_open (&tmp, dst,
+ APR_WRITE | APR_CREATE, APR_OS_DEFAULT,
+ pool);
+ if (! APR_STATUS_IS_SUCCESS (apr_err))
+ return svn_error_createf (apr_err, 0, NULL, pool,
+ "cannot open '%s'", dst);
+
+ apr_err = apr_stat (&finfo, dst,
+ APR_FINFO_UPROT | APR_FINFO_GROUP | APR_FINFO_WPROT,
+ pool);
+ if (! APR_STATUS_IS_SUCCESS (apr_err))
+ return svn_error_createf (apr_err, 0, NULL, pool,
+ "cannot stat '%s'", dst);
+
+ apr_err = apr_file_close (tmp);
+ if (! APR_STATUS_IS_SUCCESS (apr_err))
+ return svn_error_createf (apr_err, 0, NULL, pool,
+ "cannot close '%s'", dst);
+ }
 
   apr_err = apr_copy_file (src, dst, pool);
   if (apr_err)
     return svn_error_createf
       (apr_err, 0, NULL, pool, "svn_io_copy_file: copying %s to %s", src, dst);
 
+ if (!copy_perms)
+ {
+ apr_err = apr_file_perms_set (dst, finfo.protection);
+ if (! APR_STATUS_IS_SUCCESS (apr_err))
+ return svn_error_createf (apr_err, 0, NULL, pool,
+ "cannot set permissions for %s'", dst);
+ }
+
   return SVN_NO_ERROR;
 }
 
@@ -358,6 +398,7 @@
 svn_error_t *svn_io_copy_dir_recursively (svn_stringbuf_t *src,
                                           svn_stringbuf_t *dst_parent,
                                           svn_stringbuf_t *dst_basename,
+ svn_boolean_t copy_perms,
                                           apr_pool_t *pool)
 {
   enum svn_node_kind kind;
@@ -393,6 +434,7 @@
                               "'%s' already exists.", dst_path->data);
   
   /* Create the new directory. */
+ /* ### TODO: copy permissions? */
   status = apr_dir_make (dst_path->data, APR_OS_DEFAULT, pool);
   if (status)
     return svn_error_createf (status, 0, NULL, pool,
@@ -427,7 +469,7 @@
           /* Telescope and de-telescope the dst_target in here */
           svn_path_add_component_nts (dst_target, entryname);
           SVN_ERR (svn_io_copy_file (src_target->data, dst_target->data,
- subpool));
+ copy_perms, subpool));
           svn_path_remove_component (dst_target);
         }
 
@@ -437,6 +479,7 @@
                                               dst_target,
                                               svn_stringbuf_create (entryname,
                                                                     subpool),
+ copy_perms,
                                               subpool));
 
       /* ### someday deal with other node kinds? */
@@ -478,6 +521,40 @@
 
   return SVN_NO_ERROR;
 }
+
+
+/*** Permissions and modes. ***/
+
+svn_error_t *
+svn_io_set_file_read_only (const char *fname, apr_pool_t *pool)
+{
+ apr_status_t apr_err;
+ apr_finfo_t finfo;
+
+ apr_err = apr_stat (&finfo, fname, APR_FINFO_PROT, pool);
+ if (! APR_STATUS_IS_SUCCESS (apr_err))
+ return svn_error_createf
+ (apr_err, 0, NULL, pool,
+ "svn_io_set_file_read_only: problem stat'ing \"%s\"", fname);
+
+ finfo.protection &= ~APR_UWRITE;
+ finfo.protection &= ~APR_GWRITE;
+ finfo.protection &= ~APR_WWRITE;
+
+ apr_err = apr_file_perms_set (fname, finfo.protection);
+ if (! APR_STATUS_IS_SUCCESS (apr_err)
+ /* These two kinds of errors are okay, it just means the OS
+ doesn't support everything we're trying to do. */
+ && ! APR_STATUS_IS_INCOMPLETE (apr_err)
+ && ! APR_STATUS_IS_ENOTIMPL (apr_err))
+ return svn_error_createf
+ (apr_err, 0, NULL, pool,
+ "svn_io_set_file_read_only: problem setting \"%s\" read only", fname);
+
+ return SVN_NO_ERROR;
+}
+
+
 
 
 

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Sat Oct 21 14:37:00 2006

This is an archived mail posted to the Subversion Dev mailing list.

This site is subject to the Apache Privacy Policy and the Apache Public Forum Archive Policy.