mirror of
https://github.com/JuliaLang/julia.git
synced 2026-05-28 03:10:33 +08:00
As noted in https://github.com/JuliaLang/julia/issues/41584 and https://discourse.julialang.org/t/safe-overwriting-of-files/117758/3 `mv` is usually expected to be "best effort atomic". Currently calling `mv` with `force=true` calls `checkfor_mv_cp_cptree(src, dst, "moving"; force=true)` before renaming. `checkfor_mv_cp_cptree` will delete `dst` if exists and isn't the same as `src`. If `dst` is an existing file and julia stops after deleting `dst` but before doing the rename, `dst` will be removed but will not be replaced with `src`. This PR changes `mv` with `force=true` to first try rename, and only delete `dst` if that fails. Assuming file system support and the first rename works, julia stopping will not lead to `dst` being removed without being replaced. This also replaces a stopgap solution from https://github.com/JuliaLang/julia/pull/36638#discussion_r453820564
53 lines
1.6 KiB
Julia
53 lines
1.6 KiB
Julia
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
|
|
|
mktempdir() do dir
|
|
|
|
# Create test file
|
|
filename = joinpath(dir, "file.txt")
|
|
text = "123456"
|
|
write(filename, text)
|
|
|
|
# test filesystem truncate (shorten)
|
|
file = Base.Filesystem.open(filename, Base.Filesystem.JL_O_RDWR)
|
|
Base.Filesystem.truncate(file, 2)
|
|
text = text[1:2]
|
|
@test length(read(file)) == 2
|
|
close(file)
|
|
|
|
# test filesystem truncate (lengthen)
|
|
file = Base.Filesystem.open(filename, Base.Filesystem.JL_O_RDWR)
|
|
Base.Filesystem.truncate(file, 20)
|
|
@test length(read(file)) == 20
|
|
close(file)
|
|
|
|
# test filesystem futime
|
|
file = Base.Filesystem.open(filename, Base.Filesystem.JL_O_RDWR)
|
|
Base.Filesystem.futime(file, 1.0, 2.0)
|
|
@test Base.Filesystem.stat(file).mtime == 2.0
|
|
close(file)
|
|
|
|
# test filesystem readbytes!
|
|
file = Base.Filesystem.open(filename, Base.Filesystem.JL_O_RDWR)
|
|
res = ones(UInt8, 80)
|
|
Base.Filesystem.readbytes!(file, res)
|
|
@test res == UInt8[text..., (i > 20 for i in (length(text) + 1):length(res))...]
|
|
close(file)
|
|
|
|
end
|
|
|
|
import Base.Filesystem: S_IRUSR, S_IRGRP, S_IROTH
|
|
@testset "types of permission mask constants" begin
|
|
@test S_IRUSR & ~S_IRGRP == S_IRUSR
|
|
@test typeof(S_IRUSR) == typeof(S_IRGRP) == typeof(S_IROTH)
|
|
end
|
|
|
|
@testset "Base.Filesystem docstrings" begin
|
|
undoc = Docs.undocumented_names(Base.Filesystem)
|
|
@test_broken isempty(undoc)
|
|
@test undoc == [:File, :Filesystem, :cptree, :futime, :sendfile, :unlink]
|
|
end
|
|
|
|
@testset "write return type" begin
|
|
@test Base.return_types(write, (Base.Filesystem.File, UInt8)) == [Int]
|
|
end
|