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