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

[PATCH] Make working copies read-only.

From: Kevin Pilch-Bisson <kevin_at_pilch-bisson.net>
Date: 2001-11-28 19:27:02 CET

Subject and log message say it all.

Log:
Make the .svn area read-only, with the exception of things in tmp, which
will be writable. This will have no effect on platforms other unix, since
apr_file_open does not obey the permission flags, and apr_file_perms_set
is not implemented.

This patch is safe to apply to an already existing working copy. It will
gradually make file read-only as they are updated or committed.

* subversion/include/svn_io.h:(svn_io_rename_file): New prototype for a
  wrapper around apr_file_rename;
  (svn_io_set_permissions): New prototype for a function which is able to
  set the permissions in a matter that obeys a user's umask.

* subversion/libsvn_subr/io.c:(svn_io_append_file): Format for 80 column
  lines.
  (svn_io_rename_file): New function, a wrapper around apr_file_rename.
  (svn_io_set_permissions): New function, on unix this is able to retreive
  the user's umask and set the file as if it were newly created. On other
  platforms this does nothing since apr_file_perms_set is not implemented
  on any other platform.

* subversion/libsvn_wc/wc.h:Doc chanes for SVN_LOG_ATTR_MV and
  SVN_LOG_ATTR_CP.
  (SVN_WC__LOG_ATTR_PERM): New define, use to indicate what permissions a
  move, copy, or append action should set the dest file to.
  (SVN_WC__LOG_PERM_SRC): New define, don't change permissions.
  (SVN_WC__LOG_DEFAULT): New define, use os-default permissions.
  (SVN_WC__LOG_EXEC): New define, make file executable(not currently used,
  but might be useful for making checkouts/updates recognize executable
  files.
  (SVN_WC__LOG_READONLY): New define, make file read-only.

* subversion/libsvn_wc/props.c:(svn_wc__do_property_merge): Pass
  permissions to log entries.

* subversion/libsvn_wc/adm_crawler.c:(restore_file): Make files writable
  when copying them out to the working copy.

* subversion/libsvn_wc/log.c:(svn_wc__perm_type): New enum.
  (file_xfer_under_path) Takes new `perm' argument, sets dest file
  permissions according to it.
  (log_do_file_xfer) Determine perm argument for file_xfer_under_path from
  the xml attributes.
 
* subversion/libsvn_wc/adm_files.c:(maybe_copy_file): Set permissions when
  copying the file to the tmp area.
  (sync_adm_file): Set permissions on the file when moving it out of the
  tmp area.
  (close_adm_file): Set permissions on the file when moving it
  out of the tmp area.
  (svn_wc__close_auth_file): Make the file readable only by the user when
  closing it.
  (svn_wc__remove_adm_file): Make the file writable before removing it.

* subversion/libsvn_wc/get_editor.c:(close_file): Pass permissions to be
  used to log entries.

Index: ./subversion/include/svn_io.h
===================================================================
--- ./subversion/include/.svn/text-base/svn_io.h.svn-base Wed Nov 21 12:45:58 2001
+++ ./subversion/include/svn_io.h Tue Nov 27 13:47:16 2001
@@ -129,6 +129,19 @@
                                  svn_stringbuf_t *dst,
                                  apr_pool_t *pool);
 
+/* Rename SRC to DST. DST will be overwritten if it exists. */
+svn_error_t *svn_io_rename_file (svn_stringbuf_t *src,
+ svn_stringbuf_t *dst,
+ apr_pool_t *pool);
+
+/* Change the permissions on PATH to PERMS. If APPLY_UMASK is true then
+ * the permissions will be combined with the umask in the same way as
+ * open, if the platform permits. Otherwise, the permissions will be set
+ * to exactly PERMS. */
+svn_error_t *svn_io_set_permissions (svn_stringbuf_t *path,
+ apr_fileperms_t perms,
+ svn_boolean_t apply_umask,
+ apr_pool_t *pool);
 
 /* Read a line from FILE into BUF, but not exceeding *LIMIT bytes.
  * Does not include newline, instead '\0' is put there.
Index: ./subversion/libsvn_wc/props.c
===================================================================
--- ./subversion/libsvn_wc/.svn/text-base/props.c.svn-base Wed Nov 21 11:22:30 2001
+++ ./subversion/libsvn_wc/props.c Wed Nov 28 12:25:44 2001
@@ -620,6 +620,8 @@
                          tmp_prop_base,
                          SVN_WC__LOG_ATTR_DEST,
                          real_prop_base,
+ SVN_WC__LOG_ATTR_PERM,
+ svn_stringbuf_create (SVN_WC__LOG_PERM_SRC, pool),
                          NULL);
 
   /* Write log entry to move working tmp copy to real working area. */
@@ -631,6 +633,8 @@
                          tmp_props,
                          SVN_WC__LOG_ATTR_DEST,
                          real_props,
+ SVN_WC__LOG_ATTR_PERM,
+ svn_stringbuf_create (SVN_WC__LOG_PERM_SRC, pool),
                          NULL);
 
   if (reject_tmp_fp)
Index: ./subversion/libsvn_wc/wc.h
===================================================================
--- ./subversion/libsvn_wc/.svn/text-base/wc.h.svn-base Mon Nov 26 09:35:17 2001
+++ ./subversion/libsvn_wc/wc.h Wed Nov 28 12:26:52 2001
@@ -373,10 +373,12 @@
  */
 #define SVN_WC__LOG_RUN_CMD "run"
 
-/* Move file SVN_WC__LOG_ATTR_NAME to SVN_WC__LOG_ATTR_DEST. */
+/* Move file SVN_WC__LOG_ATTR_NAME to SVN_WC__LOG_ATTR_DEST, with
+ * permissions SVN_WC__LOG_ATTR_PERM. */
 #define SVN_WC__LOG_MV "mv"
 
-/* Copy file SVN_WC__LOG_ATTR_NAME to SVN_WC__LOG_ATTR_DEST. */
+/* Copy file SVN_WC__LOG_ATTR_NAME to SVN_WC__LOG_ATTR_DEST, with
+ * permissions SVN_WC__LOG_ATTR_PERM. */
 #define SVN_WC__LOG_CP "cp"
 
 /* Remove file SVN_WC__LOG_ATTR_NAME. */
@@ -415,6 +417,7 @@
 #define SVN_WC__LOG_ATTR_NAME "name"
 #define SVN_WC__LOG_ATTR_DEST "dest"
 #define SVN_WC__LOG_ATTR_REVISION "revision"
+#define SVN_WC__LOG_ATTR_PERM "permission"
 #define SVN_WC__LOG_ATTR_TEXT_REJFILE "text-rejfile"
 #define SVN_WC__LOG_ATTR_PROP_REJFILE "prop-rejfile"
 /* The rest are for SVN_WC__LOG_RUN_CMD. Extend as necessary. */
@@ -430,6 +433,15 @@
 #define SVN_WC__LOG_ATTR_ARG_7 "arg7"
 #define SVN_WC__LOG_ATTR_ARG_8 "arg8"
 #define SVN_WC__LOG_ATTR_ARG_9 "arg9"
+
+/* Keep permissions the same as the source file. */
+#define SVN_WC__LOG_PERM_SRC "src"
+/* Make the permissions the operating system's default. */
+#define SVN_WC__LOG_PERM_DEFAULT "default"
+/* Make the permissions os/default, but with the execute bit set. */
+#define SVN_WC__LOG_PERM_EXEC "executable"
+/* Make the permissions read-only. */
+#define SVN_WC__LOG_PERM_READONLY "read-only"
 
 
 /* Starting at PATH, write out log entries indicating that a commit
Index: ./subversion/libsvn_wc/adm_crawler.c
===================================================================
--- ./subversion/libsvn_wc/.svn/text-base/adm_crawler.c.svn-base Mon Nov 26 09:35:17 2001
+++ ./subversion/libsvn_wc/adm_crawler.c Tue Nov 27 14:09:04 2001
@@ -1795,12 +1795,9 @@
   tmp_text_base_path = svn_wc__text_base_path (file_path, 1, pool);
 
   SVN_ERR (svn_io_copy_file (text_base_path, tmp_text_base_path, pool));
- status = apr_file_rename (tmp_text_base_path->data, file_path->data, pool);
- if (status)
- return svn_error_createf (status, 0, NULL, pool,
- "error renaming `%s' to `%s'",
- tmp_text_base_path->data,
- file_path->data);
+ SVN_ERR (svn_io_set_permissions (tmp_text_base_path, APR_OS_DEFAULT,
+ TRUE, pool));
+ SVN_ERR (svn_io_rename_file (tmp_text_base_path, file_path, pool));
 
   return SVN_NO_ERROR;
 }
Index: ./subversion/libsvn_wc/log.c
===================================================================
--- ./subversion/libsvn_wc/.svn/text-base/log.c.svn-base Wed Nov 21 08:50:24 2001
+++ ./subversion/libsvn_wc/log.c Tue Nov 27 14:21:19 2001
@@ -51,18 +51,27 @@
   svn_wc__xfer_mv,
 };
 
+enum svn_wc__perm_type {
+ svn_wc__perm_src,
+ svn_wc__perm_default,
+ svn_wc__perm_exec,
+ svn_wc__perm_readonly
+};
 
 
-/* Copy (or rename, if RENAME is non-zero) NAME to DEST, assuming that
- PATH is the common parent of both locations. */
+/* Transfer contents of NAME to DEST, assuming that PATH is the common
+ parent of both locations, according to ACTION. If ACTION requires that
+ DEST be created, give it permissions appropriate to PERM. */
 static svn_error_t *
 file_xfer_under_path (svn_stringbuf_t *path,
                       const char *name,
                       const char *dest,
                       enum svn_wc__xfer_action action,
+ enum svn_wc__perm_type perm,
                       apr_pool_t *pool)
 {
   apr_status_t status;
+ apr_fileperms_t fperms;
   svn_stringbuf_t *full_from_path, *full_dest_path;
 
   full_from_path = svn_stringbuf_dup (path, pool);
@@ -71,22 +80,39 @@
   svn_path_add_component_nts (full_from_path, name, svn_path_local_style);
   svn_path_add_component_nts (full_dest_path, dest, svn_path_local_style);
 
+ switch (perm)
+ {
+ case svn_wc__perm_default:
+ fperms = APR_OS_DEFAULT;
+ break;
+ case svn_wc__perm_exec:
+ fperms = APR_UREAD | APR_GREAD | APR_WREAD | APR_UWRITE
+ | APR_GWRITE | APR_WWRITE | APR_UEXECUTE | APR_GEXECUTE
+ | APR_WEXECUTE;
+ break;
+ case svn_wc__perm_src:
+ /* Doesn't matter, since the permissions won't be applied anyway. */
+ break;
+ case svn_wc__perm_readonly:
+ fperms = APR_UREAD | APR_GREAD | APR_WREAD;
+ }
+
   switch (action)
   {
   case svn_wc__xfer_append:
- return svn_io_append_file (full_from_path, full_dest_path, pool);
+ SVN_ERR (svn_io_append_file (full_from_path, full_dest_path, pool));
+ break;
   case svn_wc__xfer_cp:
- return svn_io_copy_file (full_from_path, full_dest_path, pool);
+ SVN_ERR (svn_io_copy_file (full_from_path, full_dest_path, pool));
+ break;
   case svn_wc__xfer_mv:
- status = apr_file_rename (full_from_path->data,
- full_dest_path->data, pool);
- if (status)
- return svn_error_createf (status, 0, NULL, pool,
- "file_xfer_under_path: "
- "can't move %s to %s",
- name, dest);
+ SVN_ERR (svn_io_rename_file (full_from_path, full_dest_path, pool));
+ break;
   }
 
+ if (perm != svn_wc__perm_src)
+ SVN_ERR (svn_io_set_permissions (full_dest_path, fperms, TRUE, pool));
+
   return SVN_NO_ERROR;
 }
 
@@ -238,15 +264,34 @@
                   const XML_Char **atts)
 {
   svn_error_t *err;
+ enum svn_wc__perm_type perm = svn_wc__perm_src;
   const char *dest = svn_xml_get_attr_value (SVN_WC__LOG_ATTR_DEST, atts);
+ const char *permstr = svn_xml_get_attr_value (SVN_WC__LOG_ATTR_PERM, atts);
 
   if (! dest)
     return svn_error_createf (SVN_ERR_WC_BAD_ADM_LOG, 0, NULL, loggy->pool,
                               "missing dest attr in %s", loggy->path->data);
 
- /* Else. */
+ if (permstr)
+ {
+ if (strcmp (permstr, SVN_WC__LOG_PERM_SRC) == 0)
+ perm = svn_wc__perm_src;
+ else if (strcmp (permstr, SVN_WC__LOG_PERM_DEFAULT) == 0)
+ perm = svn_wc__perm_default;
+ else if (strcmp (permstr, SVN_WC__LOG_PERM_EXEC) == 0)
+ perm = svn_wc__perm_exec;
+ else if (strcmp (permstr, SVN_WC__LOG_PERM_READONLY) == 0)
+ perm = svn_wc__perm_readonly;
+ else
+ return svn_error_createf (SVN_ERR_WC_BAD_ADM_LOG, 0, NULL,
+ loggy->pool,
+ "unrecognized perm attr in %s",
+ loggy->path->data);
+ }
 
- err = file_xfer_under_path (loggy->path, name, dest, action, loggy->pool);
+ /* Else. */
+ err = file_xfer_under_path (loggy->path, name, dest, action,
+ perm, loggy->pool);
   if (err)
     signal_error (loggy, err);
 
Index: ./subversion/libsvn_wc/adm_ops.c
===================================================================
--- ./subversion/libsvn_wc/.svn/text-base/adm_ops.c.svn-base Mon Nov 26 09:35:18 2001
+++ ./subversion/libsvn_wc/adm_ops.c Wed Nov 28 13:05:32 2001
@@ -911,6 +911,9 @@
               (err->apr_err, 0, NULL, pool,
                "revert_admin_things: Error restoring pristine text for '%s'",
                full_path->data);
+ SVN_ERR (svn_io_set_permissions (full_path,
+ APR_OS_DEFAULT,
+ TRUE, pool));
           SVN_ERR (svn_io_file_affected_time (&tstamp, full_path, pool));
 
           /* Modify our entry structure. */
Index: ./subversion/libsvn_wc/adm_files.c
===================================================================
--- ./subversion/libsvn_wc/.svn/text-base/adm_files.c.svn-base Mon Nov 26 09:35:18 2001
+++ ./subversion/libsvn_wc/adm_files.c Wed Nov 28 13:10:44 2001
@@ -289,11 +289,10 @@
             return SVN_NO_ERROR;
         }
     }
- else /* SRC exists, so copy it to DST. */
+ else /* SRC exists, so copy it to DST, and make sure we can write to it. */
     {
- err = svn_io_copy_file (src, dst, pool);
- if (err)
- return err;
+ SVN_ERR (svn_io_copy_file (src, dst, pool));
+ SVN_ERR (svn_io_set_permissions (dst, APR_OS_DEFAULT, TRUE, pool));
     }
 
   return SVN_NO_ERROR;
@@ -313,7 +312,7 @@
      given how C va_lists work. */
 
   svn_stringbuf_t *tmp_path = svn_stringbuf_dup (path, pool);
- apr_status_t apr_err;
+ svn_error_t *err;
   int components_added;
   va_list ap;
   
@@ -327,18 +326,22 @@
   v_extend_with_adm_name (tmp_path, extension, 1, pool, ap);
   va_end (ap);
   
- /* Rename. */
- apr_err = apr_file_rename (tmp_path->data, path->data, pool);
+ /* Rename. 1) Make write-able, rename, make read-only. */
+ err = svn_io_set_permissions (path, APR_UREAD | APR_UWRITE, FALSE, pool);
+ if (!err || APR_STATUS_IS_ENOENT (err->apr_err))
+ {
+ err = svn_io_rename_file (tmp_path, path, pool);
+ if (!err)
+ err = svn_io_set_permissions (path,
+ APR_UREAD | APR_GREAD | APR_WREAD,
+ TRUE, pool);
+ }
+
 
   /* Unconditionally restore path. */
   chop_admin_name (path, components_added);
       
- if (apr_err)
- return svn_error_createf (apr_err, 0, NULL, pool,
- "error renaming %s to %s",
- tmp_path->data, path->data);
- else
- return SVN_NO_ERROR;
+ return err;
 }
 
 
@@ -635,6 +638,7 @@
                 ...)
 {
   apr_status_t apr_err = 0;
+ svn_error_t *err;
   int components_added;
   va_list ap;
 
@@ -672,17 +676,20 @@
       va_end (ap);
       
       /* Rename. */
- apr_err = apr_file_rename (tmp_path->data, path->data, pool);
+ err = svn_io_set_permissions (path, APR_UREAD | APR_UWRITE, FALSE, pool);
+ if (!err || APR_STATUS_IS_ENOENT (err->apr_err))
+ {
+ err = svn_io_rename_file (tmp_path, path, pool);
+ if (!err)
+ err = svn_io_set_permissions (path,
+ APR_UREAD | APR_GREAD | APR_WREAD,
+ TRUE, pool);
+ }
       
       /* Unconditionally restore path. */
       chop_admin_name (path, components_added);
       
- if (apr_err)
- return svn_error_createf (apr_err, 0, NULL, pool,
- "error renaming %s to %s",
- tmp_path->data, path->data);
- else
- return SVN_NO_ERROR;
+ return err;
     }
 
   return SVN_NO_ERROR;
@@ -767,8 +774,13 @@
                          int sync,
                          apr_pool_t *pool)
 {
- return close_adm_file (handle, path, NULL, sync, pool,
- SVN_WC__ADM_AUTH_DIR, file->data, NULL);
+ svn_stringbuf_t *full_path = svn_stringbuf_dup(path, pool);
+ SVN_ERR (close_adm_file (handle, path, NULL, sync, pool,
+ SVN_WC__ADM_AUTH_DIR, file->data, NULL));
+ extend_with_adm_name (full_path, NULL, FALSE, pool, SVN_WC__ADM_AUTH_DIR,
+ file->data, NULL);
+ SVN_ERR (svn_io_set_permissions (full_path, APR_UREAD, FALSE, pool));
+ return SVN_NO_ERROR;
 }
 
 svn_error_t *
@@ -966,9 +978,18 @@
   components_added = v_extend_with_adm_name (path, NULL, 0, pool, ap);
   va_end (ap);
 
- apr_err = apr_file_remove (path->data, pool);
- if (apr_err)
- err = svn_error_create (apr_err, 0, NULL, pool, path->data);
+ /* Make sure we have permission to remove the file. */
+ err = svn_io_set_permissions (path, APR_UREAD | APR_UWRITE, FALSE, pool);
+
+ if (!err || APR_STATUS_IS_ENOENT (err->apr_err))
+ {
+ /* It's okay if we couldn't change permissions because the file
+ * didn't exist, since all we wanted to do was remove it. */
+ err = NULL;
+ apr_err = apr_file_remove (path->data, pool);
+ if (apr_err)
+ err = svn_error_create (apr_err, 0, NULL, pool, path->data);
+ }
 
   /* Restore path to its original state no matter what. */
   chop_admin_name (path, components_added);
Index: ./subversion/libsvn_wc/get_editor.c
===================================================================
--- ./subversion/libsvn_wc/.svn/text-base/get_editor.c.svn-base Mon Nov 26 09:35:19 2001
+++ ./subversion/libsvn_wc/get_editor.c Tue Nov 27 09:42:39 2001
@@ -1155,6 +1155,9 @@
                              tmp_txtb,
                              SVN_WC__LOG_ATTR_DEST,
                              txtb,
+ SVN_WC__LOG_ATTR_PERM,
+ svn_stringbuf_create
+ (SVN_WC__LOG_PERM_READONLY, fb->pool),
                              NULL);
 
       if ( (! is_locally_modified)
@@ -1171,6 +1174,9 @@
                                  txtb,
                                  SVN_WC__LOG_ATTR_DEST,
                                  fb->name,
+ SVN_WC__LOG_ATTR_PERM,
+ svn_stringbuf_create
+ (SVN_WC__LOG_PERM_DEFAULT, fb->pool),
                                  NULL);
         }
   
@@ -1198,6 +1204,10 @@
                                          txtb,
                                          SVN_WC__LOG_ATTR_DEST,
                                          fb->name,
+ SVN_WC__LOG_ATTR_PERM,
+ svn_stringbuf_create
+ (SVN_WC__LOG_PERM_DEFAULT,
+ fb->pool),
                                          NULL);
                 }
               else /* working file exists */
@@ -1411,6 +1421,9 @@
                                      fb->name,
                                      SVN_WC__LOG_ATTR_DEST,
                                      renamed_basename,
+ SVN_WC__LOG_ATTR_PERM,
+ svn_stringbuf_create
+ (SVN_WC__LOG_PERM_SRC, fb->pool),
                                      NULL);
               
               /* Copy the new file out into working area. */
@@ -1422,6 +1435,9 @@
                                      txtb,
                                      SVN_WC__LOG_ATTR_DEST,
                                      fb->name,
+ SVN_WC__LOG_ATTR_PERM,
+ svn_stringbuf_create
+ (SVN_WC__LOG_PERM_DEFAULT, fb->pool),
                                      NULL);
             }
         }
Index: ./subversion/libsvn_subr/io.c
===================================================================
--- ./subversion/libsvn_subr/.svn/text-base/io.c.svn-base Wed Nov 21 12:45:58 2001
+++ ./subversion/libsvn_subr/io.c Wed Nov 28 12:31:56 2001
@@ -342,7 +342,8 @@
 
 
 svn_error_t *
-svn_io_append_file (svn_stringbuf_t *src, svn_stringbuf_t *dst, apr_pool_t *pool)
+svn_io_append_file (svn_stringbuf_t *src, svn_stringbuf_t *dst,
+ apr_pool_t *pool)
 {
   apr_status_t apr_err;
 
@@ -358,8 +359,45 @@
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_io_rename_file (svn_stringbuf_t *src, svn_stringbuf_t *dst,
+ apr_pool_t *pool)
+{
+ apr_status_t apr_err = apr_file_rename (src->data, dst->data, pool);
+ if (apr_err)
+ return svn_error_createf (apr_err, 0, NULL, pool,
+ "Couldn't rename `%s' to `%s'.",
+ src->data, dst->data);
 
+ return SVN_NO_ERROR;
+}
 
+svn_error_t *
+svn_io_set_permissions (svn_stringbuf_t *path, apr_fileperms_t perms,
+ svn_boolean_t apply_umask, apr_pool_t *pool)
+{
+ apr_status_t apr_err;
+#if (!defined(OS2) && !defined(BEOS) && !defined(WIN32) && !defined(NETWARE))
+ if (apply_umask)
+ {
+ apr_fileperms_t mask = apr_unix_mode2perms (umask (0777));
+ umask (apr_unix_perms2mode (mask));
+ /* In order to apply the mask, we need to have an or of flags. For
+ * some reason, apr's APR_OS_DEFAULT is not an or of flags, but
+ * rather a special value. Convert it to its meaning here. */
+ if (perms == APR_OS_DEFAULT)
+ perms = APR_UREAD | APR_UWRITE | APR_GREAD | APR_GWRITE | APR_WREAD
+ | APR_WWRITE;
+ perms = perms & ~mask;
+ }
+#endif
+ apr_err = apr_file_perms_set (path->data, perms);
+ if (apr_err && !APR_STATUS_IS_EINCOMPLETE (apr_err)
+ && !APR_STATUS_IS_ENOTIMPL (apr_err))
+ return svn_error_createf (apr_err, 0, NULL, pool, "Could not change "
+ "permissions on `%s'.", path->data);
+ return SVN_NO_ERROR;
+}
 
 svn_error_t *svn_io_copy_dir_recursively (svn_stringbuf_t *src,
                                           svn_stringbuf_t *dst_parent,

-- 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Kevin Pilch-Bisson                    http://www.pilch-bisson.net
     "Historically speaking, the presences of wheels in Unix
     has never precluded their reinvention." - Larry Wall
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  • application/pgp-signature attachment: stored
Received on Sat Oct 21 14:36:49 2006

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