rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
98.4k stars 12.73k forks source link

fs::create_dir_all doesn't work on other computers #120054

Open DP1000 opened 10 months ago

DP1000 commented 10 months ago

Hi everyone, sorry for my bad english

I have this code:


// Here there is a path generation algorithm, i've excluded it because on the two computers the generated path are the same

//The generated path
let new_file_path = "Z:\NUOVO RAPPORTINO ELETTRONICO\2024\1 Gennaio\Name Surname";

match std::fs::create_dir_all(new_file_path) {
    Ok(_r) => {

        println!("Creazione cartelle avvenuta con successo!");

        //Other things to do if succeeds

    },

    Err(error) => {
        println!("Errore durante la creazione delle cartelle: {error}");
        println!("GetLastError: {}", unsafe { GetLastError().to_string() });
    },

}

that runs fine on my computer, but throws a runtime error on another.

On the other computer, std::fs::create_dir_all throws this error: failed to create whole tree and winapi's GetLastError() gives me: ERROR_PATH_NOT_FOUND

The OSs are not the same, mine is Windows 10, the other one is Windows 11, but i don't think that's the problem.

I've compiled it with cargo build --release

Z:\ is a shared network folder on a third computer (Windows 11), but both computer one and two have same permissions

The path Z:\NUOVO RAPPORTINO ELETTRONICO\2024 already exist, on my computer it generates \1 Gennaio\Name Surname in it and then proceed with the other code, on the other one it throws the same errors both if the path "fully" exists (doesn't need to create any folder) or if it needs to create it.

Does anyone have any clue on what's going on?

ChrisDenton commented 9 months ago

I don't know what's going on but I might be able to help diagnose. The std implementation of create_dir_all starts by trying to make the directory at the path and if that fails it calls path.parent() and retries until either it succeeds or else path.parent() returns None and then it fails. The error you're getting is when it fails. So for some reason it thinks the drive does not exist.

Can you print the generated path (new_file_path) on error to ensure it matches expectations? Is it a full path with a drive or relative to the current directory?

The path has "Name Surname", is it possible that may actually contain special ascii characters? Or a reserved name. I think this is less likely but worth checking. Sometimes invalid file names can cause weird path issues. See https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#naming-conventions.

Does std::fs::create_dir(r"Z:\NUOVO RAPPORTINO ELETTRONICO") work as expected? E.g. succeeds if it doesn't exist or errors with AlreadyExists if it does exist.

DP1000 commented 9 months ago

Hi @ChrisDenton , sorry for the delay in the answer,

i've printed new_file_path on both the computers, visually the are the same, don't know if for some reasons it contains some special ascii char, how can i check?

On my computer, create_dir(path) does not works as you say, if the path already "fully" exists, it doesn't throw an AlreadyExists error.

the line is_dir: bool is a print of Path::new(new_file_path.as_str()).is_dir(), because someone suggested on stackoverflow, that if the path fully exists, and it gives false, it's a permission error, but i don't think is correct or i wouldn't be able to manually create these folders

Screenshot of the second computer: Errore_ExToGs

Screenshot of My computer, first run ( "\1 Gennaio\Giuliano Marchi" doesn't exist ): ExToGs_Success

Screenshot of My computer, second run ( "\1 Gennaio\Giuliano Marchi" exists ): ExToGs_Success2

DP1000 commented 9 months ago

Hi everyone, i have some updates,

i've just tried this line of code: Path::new("Z:").try_exists() on the "second computer" and it gives me: Ok(false) according with try_exists()'s docs it doesn't seem to be a permission error, but he just think the Z: network drive it isn't mounted / doesn't exists

LGUG2Z commented 9 months ago

I have also had a report of this by a komorebi user when trying to create a log file via tracing_appender.

PS C:\Users\User\AppData\Local\komorebi> $Env:RUST_BACKTRACE="full"
PS C:\Users\User\AppData\Local\komorebi> komorebi.exe
The application panicked (crashed).
Message:  failed to create appender: Error { kind: Uncategorized, message: "failed to create whole tree" }
Location: C:\Users\runneradmin\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tracing-appender-0.2.2\src\rolling.rs:499

  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ BACKTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
   1: BaseThreadInitThunk<unknown>
      at <unknown source file>:<unknown line>
   2: RtlUserThreadStart<unknown>
      at <unknown source file>:<unknown line>

Run with COLORBT_SHOW_HIDDEN=1 environment variable to disable frame filtering.

I am not able to reproduce this myself, but I'm thinking maybe it's not a coincidence that this has been noted in both instances of this thread on Windows machines?

Relevant code being called here: https://github.com/LGUG2Z/komorebi/blob/21a5be040448548f1e641d5d6a9e9b080ec63504/komorebi/src/main.rs#L254

ChrisDenton commented 9 months ago

On my computer, create_dir(path) does not works as you say, if the path already "fully" exists, it doesn't throw an AlreadyExists error.

It should, if you unwrap? I'm not sure why it wouldn't. To be clear, the create_dir behaviour differs from create_dir_all in that it doesn't ignore AlreadyExists errors.


Anyway, create_dir_all isn't doing anything too involved. Here's the code: https://github.com/rust-lang/rust/blob/32ec40c68533f325a3c8fe787b77ef5c9e209b23/library/std/src/fs.rs#L2555-L2578

self.inner.mkdir is just the internal way of calling std::fs::create_dir. Which is why I was interested in the behaviour of create_dir as opposed to create_dir_all. If there's no issue with create_dir then it's surprising to me that there is with create_dir_all. That said, it is possible there's some spurious issue with certain network filesystems that maybe trips up create_dir_all. But that's just speculation without knowing more.