Skip to main content

russh_sftp/protocol/
open.rs

1use std::fs;
2
3use super::{impl_packet_for, impl_request_id, FileAttributes, Packet, RequestId};
4
5/// Opening flags according to the specification
6#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
7pub struct OpenFlags(u32);
8
9bitflags! {
10    impl OpenFlags: u32 {
11        const READ = 0x00000001;
12        const WRITE = 0x00000002;
13        const APPEND = 0x00000004;
14        const CREATE = 0x00000008;
15        const TRUNCATE = 0x00000010;
16        const EXCLUDE = 0x00000020;
17    }
18}
19
20impl From<OpenFlags> for fs::OpenOptions {
21    fn from(value: OpenFlags) -> Self {
22        let mut open_options = fs::OpenOptions::new();
23        if value.contains(OpenFlags::READ) {
24            open_options.read(true);
25        }
26        if value.contains(OpenFlags::WRITE) {
27            open_options.write(true);
28        }
29        if value.contains(OpenFlags::APPEND) {
30            open_options.append(true);
31        }
32        if value.contains(OpenFlags::CREATE) {
33            // SFTPv3 spec requires the `CREATE` flag to be set if the `EXCLUDE` flag
34            // is set. Rusts `OpenOptions` has different semantics: it ignores
35            // whether `create` or `truncate` was set.
36            // SFTPv3 spec does not say anything about read/write flags, but
37            // they will be required to do anything else with the file.
38            // https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-02#section-6.3
39            if value.contains(OpenFlags::EXCLUDE) {
40                open_options.create_new(true);
41            } else {
42                open_options.create(true);
43            }
44        }
45        if value.contains(OpenFlags::TRUNCATE) {
46            open_options.truncate(true);
47        }
48
49        open_options
50    }
51}
52
53/// Implementation for `SSH_FXP_OPEN`
54#[derive(Debug, Serialize, Deserialize)]
55pub struct Open {
56    pub id: u32,
57    pub filename: String,
58    pub pflags: OpenFlags,
59    pub attrs: FileAttributes,
60}
61
62impl_request_id!(Open);
63impl_packet_for!(Open);