Skip to content

Commit f236d31

Browse files
committed
Initial fchmodat support
1 parent cc0274d commit f236d31

File tree

11 files changed

+73
-0
lines changed

11 files changed

+73
-0
lines changed

lib_eio/fs.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ module Pi = struct
7171
val rename : t -> path -> _ dir -> path -> unit
7272
val read_link : t -> path -> string
7373
val symlink : link_to:path -> t -> path -> unit
74+
val chmod : t -> follow:bool -> perm:File.Unix_perm.t -> path -> unit
7475
val pp : t Fmt.t
7576
val native : t -> string -> string option
7677
end

lib_eio/path.ml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,14 @@ let symlink ~link_to source =
218218
let bt = Printexc.get_raw_backtrace () in
219219
Exn.reraise_with_context ex bt "creating symlink %a -> %s" pp source link_to
220220

221+
let chmod ~follow ~perm t =
222+
let (Resource.T (dir, ops), path) = t in
223+
let module X = (val (Resource.get ops Fs.Pi.Dir)) in
224+
try X.chmod dir ~follow ~perm path
225+
with Exn.Io _ as ex ->
226+
let bt = Printexc.get_raw_backtrace () in
227+
Exn.reraise_with_context ex bt "chmoding file %a" pp t
228+
221229
let rec mkdirs ?(exists_ok=false) ~perm t =
222230
(* Check parent exists first. *)
223231
split t |> Option.iter (fun (parent, _) ->

lib_eio/path.mli

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,3 +217,8 @@ val symlink : link_to:string -> _ t -> unit
217217
{[
218218
Eio.Path.symlink (dir / "current") ~link_to:"version-1.0"
219219
]} *)
220+
221+
val chmod : follow:bool -> perm:int -> _ t -> unit
222+
(** [chmod ~follow ~perm t] allows you to change the file mode bits.
223+
224+
@param follow If [true] and [t] is a symlink then change the file mode bits target. *)

lib_eio_linux/eio_linux.ml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,9 @@ end = struct
455455
let symlink ~link_to t path =
456456
Low_level.symlink ~link_to t.fd path
457457

458+
let chmod t ~follow ~perm path =
459+
Low_level.chmod t.fd ~follow ~mode:perm path
460+
458461
let pp f t = Fmt.string f (String.escaped t.label)
459462

460463
let fd t = t.fd

lib_eio_linux/eio_stubs.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,20 @@ CAMLprim value caml_eio_symlinkat(value v_old_path, value v_new_fd, value v_new_
115115
CAMLreturn(Val_unit);
116116
}
117117

118+
CAMLprim value caml_eio_fchmodat(value v_fd, value v_path, value v_mode, value v_flags) {
119+
CAMLparam1(v_path);
120+
char *path;
121+
int ret;
122+
caml_unix_check_path(v_path, "fchmodat");
123+
path = caml_stat_strdup(String_val(v_path));
124+
caml_enter_blocking_section();
125+
ret = fchmodat(Int_val(v_fd), path, Int_val(v_mode), Int_val(v_flags));
126+
caml_leave_blocking_section();
127+
caml_stat_free(path);
128+
if (ret == -1) uerror("fchmodat", v_path);
129+
CAMLreturn(Val_unit);
130+
}
131+
118132
CAMLprim value caml_eio_getrandom(value v_ba, value v_off, value v_len) {
119133
CAMLparam1(v_ba);
120134
ssize_t ret;

lib_eio_linux/low_level.ml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,8 @@ external eio_renameat : Unix.file_descr -> string -> Unix.file_descr -> string -
360360

361361
external eio_symlinkat : string -> Unix.file_descr -> string -> unit = "caml_eio_symlinkat"
362362

363+
external eio_fchmodat : Unix.file_descr -> string -> int -> int -> unit = "caml_eio_fchmodat"
364+
363365
external eio_getrandom : Cstruct.buffer -> int -> int -> int = "caml_eio_getrandom"
364366

365367
external eio_getdents : Unix.file_descr -> string list = "caml_eio_getdents"
@@ -486,6 +488,15 @@ let symlink ~link_to dir path =
486488
eio_symlinkat link_to parent leaf
487489
with Unix.Unix_error (code, name, arg) -> raise @@ Err.wrap_fs code name arg
488490

491+
492+
let chmod ~follow ~mode dir path =
493+
let module X = Uring.Statx in
494+
with_parent_dir "chmodat" dir path @@ fun parent leaf ->
495+
let flags = if follow then 0 else (* at_symlink_nofollow *) 0x100 in
496+
try
497+
eio_fchmodat parent leaf mode flags
498+
with Unix.Unix_error (code, name, arg) -> raise @@ Err.wrap_fs code name arg
499+
489500
let shutdown socket command =
490501
try
491502
Fd.use_exn "shutdown" socket @@ fun fd ->

lib_eio_linux/low_level.mli

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,9 @@ val rename : dir_fd -> string -> dir_fd -> string -> unit
153153
val symlink : link_to:string -> dir_fd -> string -> unit
154154
(** [symlink ~link_to dir path] creates a new symlink at [dir / path] pointing to [link_to]. *)
155155

156+
val chmod : follow:bool -> mode:int -> dir_fd -> string -> unit
157+
(** [chmod ~follow ~mode dir path] changes the file mode bits of [dir / path]. *)
158+
156159
val pipe : sw:Switch.t -> fd * fd
157160
(** [pipe ~sw] returns a pair [r, w] with the readable and writeable ends of a new pipe. *)
158161

lib_eio_posix/eio_posix_stubs.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,20 @@ CAMLprim value caml_eio_posix_symlinkat(value v_old_path, value v_new_fd, value
405405
CAMLreturn(Val_unit);
406406
}
407407

408+
CAMLprim value caml_eio_posix_fchmodat(value v_fd, value v_path, value v_mode, value v_flags) {
409+
CAMLparam1(v_path);
410+
char *path;
411+
int ret;
412+
caml_unix_check_path(v_path, "fchmodat");
413+
path = caml_stat_strdup(String_val(v_path));
414+
caml_enter_blocking_section();
415+
ret = fchmodat(Int_val(v_fd), path, Int_val(v_mode), Int_val(v_flags));
416+
caml_leave_blocking_section();
417+
caml_stat_free_preserving_errno(path);
418+
if (ret == -1) uerror("fchmodat", v_path);
419+
CAMLreturn(Val_unit);
420+
}
421+
408422
CAMLprim value caml_eio_posix_spawn(value v_errors, value v_actions) {
409423
CAMLparam1(v_actions);
410424
pid_t child_pid;

lib_eio_posix/fs.ml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ end = struct
9797
let symlink ~link_to t path =
9898
Err.run (Low_level.symlink ~link_to t.fd) path
9999

100+
let chmod t ~follow ~perm path =
101+
Err.run (Low_level.chmod ~follow ~mode:perm t.fd) path
102+
100103
let open_dir t ~sw path =
101104
let flags = Low_level.Open_flags.(rdonly + directory +? path) in
102105
let fd = Err.run (Low_level.openat ~sw ~mode:0 t.fd path) flags in

lib_eio_posix/low_level.ml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,15 @@ let symlink ~link_to new_dir new_path =
423423
let new_dir = Option.value new_dir ~default:at_fdcwd in
424424
eio_symlinkat link_to new_dir new_path
425425

426+
external eio_fchmodat : Unix.file_descr -> string -> int -> int -> unit = "caml_eio_posix_fchmodat"
427+
428+
let chmod ~follow ~mode dir path =
429+
in_worker_thread "chmod" @@ fun () ->
430+
Resolve.with_parent "chmod" dir path @@ fun dir path ->
431+
let new_dir = Option.value dir ~default:at_fdcwd in
432+
let flags = if follow then 0 else Config.at_symlink_nofollow in
433+
eio_fchmodat new_dir path mode flags
434+
426435
let read_link dirfd path =
427436
in_worker_thread "read_link" @@ fun () ->
428437
Resolve.with_parent "read_link" dirfd path @@ fun dirfd path ->

0 commit comments

Comments
 (0)