Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Persists Function results in an error #245

Closed
slayernominee opened this issue Aug 3, 2023 · 9 comments
Closed

Persists Function results in an error #245

slayernominee opened this issue Aug 3, 2023 · 9 comments

Comments

@slayernominee
Copy link

error[E0277]: the trait bound `PersistError: ResponseError` is not satisfied
   --> src/api.rs:195:66
    |
195 |         let mut persisted_file = file.persist("./saved_file.txt")?;
    |                                                                  ^ the trait `ResponseError` is not implemented for `PersistError`
    |
    = help: the following other types implement trait `ResponseError`:
              BlockingError
              Box<(dyn StdError + 'static)>
              CorsError
              HttpError
              Infallible
              InvalidHeaderValue
              JsonFieldError
              JsonPayloadError
            and 22 others
    = note: required for `actix_web::Error` to implement `std::convert::From<PersistError>`
    = note: required for `Result<_, actix_web::Error>` to implement `FromResidual<Result<Infallible, PersistError>>`

when using the code example from the documentation:

use tempfile::NamedTempFile;

let file = NamedTempFile::new()?;

let mut persisted_file = file.persist("./saved_file.txt")?;
writeln!(persisted_file, "Brian was here. Briefly.")?;

this is my whole method

#[post("/uploadImage")]
async fn upload_image(
    MultipartForm(form): MultipartForm<UploadForm>,
) -> Result<impl Responder, Error> {
        
        let file = NamedTempFile::new()?;
        
        let mut persisted_file = file.persist("./saved_file.txt")?;
        writeln!(persisted_file, "Brian was here. Briefly.")?;
        
        //f.file.persist(path).unwrap();
    
    Ok(HttpResponse::Ok())
}
@slayernominee
Copy link
Author

f.file.persist(path).unwrap(); results without the other code in this error:

thread 'actix-rt|system:0|arbiter:0' panicked at 'called `Result::unwrap()` on an `Err` value: PersistError(Os { code: 18, kind: CrossesDevices, message: "Invalid cross-device link" })', src/api.rs:190:30

that also shouldnt result in any error from the examples from the actix project

@Stebalien
Copy link
Owner

I'd take a closer look at that error message in your first post. You need to convert the error from this library into the appropriate error for your application.

@slayernominee
Copy link
Author

the final error is this one:
PersistError(Os { code: 18, kind: CrossesDevices, message: "Invalid cross-device link" }) but why do i get it? im using one partition ... no docker nothing

@Stebalien
Copy link
Owner

I assume you're writing the temporary file in /tmp? That's likely in memory.

@slayernominee
Copy link
Author

nope in the current working directy (in a subfolder of the home directory)

@Stebalien
Copy link
Owner

NamedTempFile::new() will create a temporary file in your system's temporary file directory. You need NamedTempFile::new_in().

@slayernominee
Copy link
Author

results in the same error if i specify my home directory

@slayernominee
Copy link
Author

but only on my manjaro system (using a btfrs formated partition), on a mac it just works fine the same code

@Stebalien
Copy link
Owner

Unfortunately, this is an OS error so there's not much I can do but help debug. At this point, I'd recommend printing out the .path() of the resulting temporary file and your current working directory to see if they appear to be on different filesystems (compare with the output of findmnt).

mikayla-maki pushed a commit to zed-industries/zed that referenced this issue Feb 28, 2024
This PR fix the "invalid cross-device link" error occurred in linux when
trying to write the settings file atomically, like when click the
"Enable vim mode" checkbox at first start.

```plain
[2024-02-26T22:59:25+08:00 ERROR util] .../zed/crates/settings/src/settings_file.rs:135: Failed to write settings to file "/home/$USER/.config/zed/settings.json"

Caused by:
0: failed to persist temporary file: Invalid cross-device link (os error 18)
1: Invalid cross-device link (os error 18)
```

Currently the `fs::RealFs::atomic_write()` method write to a temp file
created with `NamedTempFile::new()` and then call `persist()` method to
write to the config file path, which actually do a `rename` syscall
under the hood. As the
[issue](Stebalien/tempfile#245) said

> `NamedTempFile::new()` will create a temporary file in your system's
temporary file directory. You need `NamedTempFile::new_in()`.

The temporary file directory in linux is in `/tmp`, which is mounted to
`tmpfs` filesystem, and in most case(all case I guess)
`$HOME/.config/zed` is mounted to a different filesystem. And the
`rename` syscall between different filesystems will return a `EXDEV`
errno, as described in the man page
[rename(2)](https://man7.org/linux/man-pages/man2/renameat2.2.html):

```plain
       EXDEV  oldpath and newpath are not on the same mounted
              filesystem.  (Linux permits a filesystem to be mounted at
              multiple points, but rename() does not work across
              different mount points, even if the same filesystem is
              mounted on both.)
```

And as the issue above said, use a different temp dir with
`NamedTempFile::new_in()` for linux platform might be a solution, since
the `rename` syscall provides atomicity.

Release Notes:
- Fix `settings.json` save failed with invalid cross-device link error
in linux
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

No branches or pull requests

2 participants