@@ -1151,6 +1151,11 @@ defmodule File do
11511151 dereferenced and have their contents copied instead when set to `true`. If the dereferenced
11521152 files do not exist, than the operation fails. The default is `false`.
11531153
1154+ * `:preserve_directory_permissions` - (since v1.20.0) when `true`, the permissions of
1155+ source directories are copied to the destination directories after their contents are
1156+ written. This is useful when source directories are read-only or have restricted
1157+ permissions that must be preserved. The default is `false`.
1158+
11541159 ## Examples
11551160
11561161 # Copies file "a.txt" to "b.txt"
@@ -1176,7 +1181,8 @@ defmodule File do
11761181 """
11771182 @ spec cp_r ( Path . t ( ) , Path . t ( ) ,
11781183 on_conflict: on_conflict_callback ,
1179- dereference_symlinks: boolean ( )
1184+ dereference_symlinks: boolean ( ) ,
1185+ preserve_directory_permissions: boolean ( )
11801186 ) ::
11811187 { :ok , [ binary ] } | { :error , posix | :badarg | :terminated , binary }
11821188
@@ -1198,6 +1204,7 @@ defmodule File do
11981204 def cp_r ( source , destination , options ) when is_list ( options ) do
11991205 on_conflict = Keyword . get ( options , :on_conflict , fn _ , _ -> true end )
12001206 dereference? = Keyword . get ( options , :dereference_symlinks , false )
1207+ preserve_directory_permissions? = Keyword . get ( options , :preserve_directory_permissions , false )
12011208
12021209 source =
12031210 source
@@ -1217,7 +1224,14 @@ defmodule File do
12171224 else
12181225 dereference = if dereference? , do: MapSet . new ( ) , else: nil
12191226
1220- case do_cp_r ( source , destination , on_conflict , dereference , [ ] ) do
1227+ case do_cp_r (
1228+ source ,
1229+ destination ,
1230+ on_conflict ,
1231+ dereference ,
1232+ preserve_directory_permissions? ,
1233+ [ ]
1234+ ) do
12211235 { :error , _ , _ } = error -> error
12221236 res -> { :ok , res }
12231237 end
@@ -1241,7 +1255,8 @@ defmodule File do
12411255 """
12421256 @ spec cp_r! ( Path . t ( ) , Path . t ( ) ,
12431257 on_conflict: on_conflict_callback ,
1244- dereference_symlinks: boolean ( )
1258+ dereference_symlinks: boolean ( ) ,
1259+ preserve_directory_permissions: boolean ( )
12451260 ) :: [ binary ]
12461261 def cp_r! ( source , destination , options \\ [ ] ) do
12471262 case cp_r ( source , destination , options ) do
@@ -1258,7 +1273,7 @@ defmodule File do
12581273 end
12591274 end
12601275
1261- defp do_cp_r ( src , dest , on_conflict , dereference , acc ) when is_list ( acc ) do
1276+ defp do_cp_r ( src , dest , on_conflict , dereference , preserve_dir_perms? , acc ) when is_list ( acc ) do
12621277 case :elixir_utils . read_link_type ( src ) do
12631278 { :ok , :regular } ->
12641279 case do_cp_file ( src , dest , on_conflict , acc ) do
@@ -1278,7 +1293,7 @@ defmodule File do
12781293 { :error , :eloop , src }
12791294 else
12801295 dereference = MapSet . put ( dereference , resolved )
1281- do_cp_r ( resolved , dest , on_conflict , dereference , acc )
1296+ do_cp_r ( resolved , dest , on_conflict , dereference , preserve_dir_perms? , acc )
12821297 end
12831298
12841299 { :ok , link } ->
@@ -1300,6 +1315,7 @@ defmodule File do
13001315 Path . join ( dest , x ) ,
13011316 on_conflict ,
13021317 dereference ,
1318+ preserve_dir_perms? ,
13031319 acc
13041320 ) do
13051321 { :error , _ , _ } = error -> { :halt , error }
@@ -1310,13 +1326,16 @@ defmodule File do
13101326 { :error , _ , _ } = error ->
13111327 error
13121328
1313- files ->
1329+ files when preserve_dir_perms? ->
13141330 # Change the directory after writing files in case
13151331 # it was originally read only
13161332 case copy_file_mode ( src , dest ) do
13171333 :ok -> files
13181334 { :error , reason } -> { :error , reason , src }
13191335 end
1336+
1337+ files ->
1338+ files
13201339 end
13211340
13221341 { :error , reason } ->
@@ -1336,7 +1355,7 @@ defmodule File do
13361355 end
13371356
13381357 # If we reach this clause, there was an error while processing a file.
1339- defp do_cp_r ( _ , _ , _ , _ , acc ) do
1358+ defp do_cp_r ( _ , _ , _ , _ , _ , acc ) do
13401359 acc
13411360 end
13421361
0 commit comments