erlware / relx

Sane, simple release creation for Erlang
http://erlware.github.io/relx
Apache License 2.0
697 stars 232 forks source link

Unable to rewrite .app files with mode 0444 #756

Open limeytexan opened 5 years ago

limeytexan commented 5 years ago

I recently observed that relx is unable to rewrite .app files with mode 0444, despite those files being in a directory with mode 0755. The error encountered was the following:

===> Unable to rewrite .app file /path/to/foo-x.y.z/ebin/foo.app due to {error,
                                                                         eacces}

The problem occurs within the write_file_if_contents_differ() function which attempts to replace the contents of the file in situ rather than writing to a new file and renaming the new version into place. The following patch solves the problem for me, although as I'm not an Erlang programmer I imagine there must be other/better solutions available:

diff --git a/src/rlx_prv_assembler.erl b/src/rlx_prv_assembler.erl
index 4f9a41eb..09ef271d 100644
--- a/src/rlx_prv_assembler.erl
+++ b/src/rlx_prv_assembler.erl
@@ -279,9 +279,13 @@ write_file_if_contents_differ(Filename, Spec) ->
         {ok, Spec} ->
             ok;
         {ok,  _} ->
-            file:write_file(Filename, ToWrite);
+            TempFile = string:strip(os:cmd("mktemp"), right, $\n),
+            file:write_file(TempFile , ToWrite),
+            file:rename(TempFile , Filename);
         {error,  _} ->
-            file:write_file(Filename, ToWrite)
+            TempFile = string:strip(os:cmd("mktemp"), right, $\n),
+            file:write_file(TempFile , ToWrite),
+            file:rename(TempFile , Filename)
     end.

 remove_symlink_or_directory(TargetDir) ->

By way of context this patch is required for the use of relx on Nix where all files are mode 0444 by default.

ferd commented 5 years ago

Yeah that patch is not workable for portable code (don't recall mktemp existing on windows; also if the tmp file is made in /tmp then rename won't work if /tmp is not on the same filesystem as the target), but the approach as a whole probably makes sense.