Skip to content

[Files.save_as]: just write directly to special files#60

Merged
rr0gi merged 7 commits into
ahrefs:masterfrom
arvidj:aj/save_as-no-clobber
May 11, 2026
Merged

[Files.save_as]: just write directly to special files#60
rr0gi merged 7 commits into
ahrefs:masterfrom
arvidj:aj/save_as-no-clobber

Conversation

@arvidj
Copy link
Copy Markdown
Contributor

@arvidj arvidj commented Apr 29, 2026

What

This is a backport of ahrefs/passage#28

In [Files.save_as]: just write directly to special files instead of doing the temp-file dance. Also, if [name] is a symbolic link, resolve it first.

Also, if [name] is a symbolic link, resolve it first.
Comment thread files.ml
Comment thread files.mli Outdated
Comment thread files.mli Outdated
Comment thread files.ml Outdated
Comment on lines +85 to +93
let save_as name ?mode f =
let name =
match (Unix.lstat name).st_kind with
| Unix.S_LNK -> Unix.realpath name
| (exception Unix.Unix_error (Unix.ENOENT, _, _)) | _ -> name
in
match (Unix.stat name).st_kind with
| Unix.S_REG | (exception Unix.Unix_error (Unix.ENOENT, _, _)) -> save_as_regular name ?mode f
| _ -> Out_channel.with_open_gen [ Open_wronly ] 0 name f
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't matter perf-wise but lets not do two stats in the most common case of regular file, call save_as recursively in case of S_LNK

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see the latest, recursive version. Like the old version, I noticed (or CC rather) that the function will throw an error on broken symlinks. That seems like reasonable behavior to me but I clarified it in the mli. I got a bunch of vibe coded tests as well, see latest commit. Do you want to keep them?

arvidj and others added 5 commits May 8, 2026 08:35
Co-authored-by: rr0gi <igor@ahrefs.com>
Co-authored-by: rr0gi <igor@ahrefs.com>
Comment thread files.ml
Comment on lines +87 to +88
| Unix.S_LNK -> save_as (Unix.realpath name) ?mode f
| Unix.S_REG | (exception Unix.Unix_error (Unix.ENOENT, _, _)) -> save_as_regular name ?mode f
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
| Unix.S_LNK -> save_as (Unix.realpath name) ?mode f
| Unix.S_REG | (exception Unix.Unix_error (Unix.ENOENT, _, _)) -> save_as_regular name ?mode f
| S_LNK -> save_as (Unix.realpath name) ?mode f
| S_REG | (exception Unix.Unix_error (ENOENT, _, _)) -> save_as_regular name ?mode f

Comment thread test.ml
let () = test "Files.save_as no temp file left on failure" @@ fun () ->
with_temp_path "test_save_as_fail.txt" @@ fun path ->
(try Files.save_as path (fun _oc -> failwith "boom") with Failure _ -> ());
let temp = Printf.sprintf "%s.save.%d.tmp" path (U.gettid ()) in
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this test is kind of fragile but i guess can fix when if ever it breaks

@rr0gi rr0gi merged commit 91ff69d into ahrefs:master May 11, 2026
1 of 3 checks passed
raphael-proust added a commit that referenced this pull request May 12, 2026
* master:
  [Files.save_as]: just write directly to special files (#60)
  web: expose http_request_k (#58)
  structured logging (#59)
  log: add critical due to error level inflation
  ci: use ocaml 5.4
  files: add mkdir_p (#57)
  [Action.config_lines] document and test behavior of commented lines (#56)
  update to trace 0.12 and OTEL main
  web: track content-type
  fix: avoid curl.ml crash
  web: track more information about request/response in span
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants