feat: extend file list PDU to transfer UNIX PERM
1. used 4 bytes out of a reserved 16 bytes section to store perm u32 2. add FLAGS_FD_UNIX_MODE: u32 = 0x08, used with flags, indicating this message is from UNIX peer Signed-off-by: ClSlaid <cailue@bupt.edu.cn>
This commit is contained in:
parent
7fbb4045e2
commit
fc3187a781
@ -50,6 +50,12 @@ const BLOCK_SIZE: u32 = 128 * 1024;
|
||||
|
||||
/// read only permission
|
||||
const PERM_READ: u16 = 0o444;
|
||||
/// read and write permission
|
||||
const PERM_RW: u16 = 0o644;
|
||||
/// only self can read and readonly
|
||||
const PERM_SELF_RO: u16 = 0o400;
|
||||
/// rwx
|
||||
const PERM_RWX: u16 = 0o755;
|
||||
/// max length of file name
|
||||
const MAX_NAME_LEN: usize = 255;
|
||||
|
||||
@ -143,6 +149,11 @@ impl fuser::Filesystem for FuseClient {
|
||||
let mut server = self.server.lock();
|
||||
server.release(req, ino, fh, _flags, _lock_owner, _flush, reply)
|
||||
}
|
||||
|
||||
fn getattr(&mut self, req: &fuser::Request<'_>, ino: u64, reply: fuser::ReplyAttr) {
|
||||
let mut server = self.server.lock();
|
||||
server.getattr(req, ino, reply)
|
||||
}
|
||||
}
|
||||
|
||||
/// fuse server
|
||||
@ -494,6 +505,18 @@ impl fuser::Filesystem for FuseServer {
|
||||
reply.ok();
|
||||
return;
|
||||
}
|
||||
|
||||
fn getattr(&mut self, _req: &fuser::Request<'_>, ino: u64, reply: fuser::ReplyAttr) {
|
||||
let files = &self.files;
|
||||
let Some(entry) = files.get(ino as usize - 1) else {
|
||||
reply.error(libc::ENOENT);
|
||||
log::error!("fuse: getattr: entry not found");
|
||||
return;
|
||||
};
|
||||
|
||||
let attr = (&entry.attributes).into();
|
||||
reply.attr(&std::time::Duration::default(), &attr)
|
||||
}
|
||||
}
|
||||
|
||||
impl FuseServer {
|
||||
@ -614,8 +637,13 @@ impl FileDescription {
|
||||
// skip reserved 32 bytes
|
||||
bytes.advance(32);
|
||||
let attributes = bytes.get_u32_le();
|
||||
// skip reserved 16 bytes
|
||||
bytes.advance(16);
|
||||
|
||||
// in original specification, this is 16 bytes reserved
|
||||
// we use the last 4 bytes to store the file mode
|
||||
// skip reserved 12 bytes
|
||||
bytes.advance(12);
|
||||
let perm = bytes.get_u32_le() as u16;
|
||||
|
||||
// last write time from 1601-01-01 00:00:00, in 100ns
|
||||
let last_write_time = bytes.get_u64_le();
|
||||
// file size
|
||||
@ -632,6 +660,8 @@ impl FileDescription {
|
||||
CliprdrError::ConversionFailure
|
||||
})?;
|
||||
|
||||
let from_unix = flags & 0x08 != 0;
|
||||
|
||||
let valid_attributes = flags & 0x04 != 0;
|
||||
if !valid_attributes {
|
||||
return Err(CliprdrError::InvalidRequest {
|
||||
@ -641,6 +671,25 @@ impl FileDescription {
|
||||
|
||||
// todo: check normal, hidden, system, readonly, archive...
|
||||
let directory = attributes & 0x10 != 0;
|
||||
let normal = attributes == 0x80;
|
||||
let hidden = attributes & 0x02 != 0;
|
||||
let readonly = attributes & 0x01 != 0;
|
||||
|
||||
let perm = if from_unix {
|
||||
// as is
|
||||
perm
|
||||
// cannot set as is...
|
||||
} else if normal {
|
||||
PERM_RWX
|
||||
} else if readonly {
|
||||
PERM_READ
|
||||
} else if hidden {
|
||||
PERM_SELF_RO
|
||||
} else if directory {
|
||||
PERM_RWX
|
||||
} else {
|
||||
PERM_RW
|
||||
};
|
||||
|
||||
let kind = if directory {
|
||||
FileType::Directory
|
||||
@ -677,7 +726,7 @@ impl FileDescription {
|
||||
|
||||
creation_time: last_modified,
|
||||
size,
|
||||
perm: PERM_READ,
|
||||
perm,
|
||||
};
|
||||
|
||||
Ok(desc)
|
||||
@ -859,7 +908,7 @@ impl FuseNode {
|
||||
last_metadata_changed: SystemTime::UNIX_EPOCH,
|
||||
creation_time: SystemTime::UNIX_EPOCH,
|
||||
size: 0,
|
||||
perm: PERM_READ,
|
||||
perm: PERM_RWX,
|
||||
}
|
||||
} else {
|
||||
file.clone()
|
||||
@ -910,13 +959,14 @@ pub struct InodeAttributes {
|
||||
last_metadata_changed: std::time::SystemTime,
|
||||
creation_time: std::time::SystemTime,
|
||||
kind: FileType,
|
||||
perm: u16,
|
||||
|
||||
// not implemented
|
||||
_xattrs: BTreeMap<Vec<u8>, Vec<u8>>,
|
||||
}
|
||||
|
||||
impl InodeAttributes {
|
||||
pub fn new(inode: u64, size: u64, kind: FileType) -> Self {
|
||||
pub fn new(inode: u64, size: u64, perm: u16, kind: FileType) -> Self {
|
||||
Self {
|
||||
inode,
|
||||
size,
|
||||
@ -925,6 +975,7 @@ impl InodeAttributes {
|
||||
last_metadata_changed: std::time::SystemTime::now(),
|
||||
creation_time: std::time::SystemTime::now(),
|
||||
kind,
|
||||
perm,
|
||||
_xattrs: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
@ -938,13 +989,14 @@ impl InodeAttributes {
|
||||
creation_time: desc.creation_time,
|
||||
last_accessed: SystemTime::now(),
|
||||
kind: desc.kind,
|
||||
perm: desc.perm,
|
||||
|
||||
_xattrs: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_root() -> Self {
|
||||
Self::new(FUSE_ROOT_ID, 0, FileType::Directory)
|
||||
Self::new(FUSE_ROOT_ID, 0, PERM_RWX, FileType::Directory)
|
||||
}
|
||||
|
||||
pub fn access(&mut self) {
|
||||
@ -970,7 +1022,7 @@ impl From<&InodeAttributes> for fuser::FileAttr {
|
||||
kind: value.kind.into(),
|
||||
|
||||
// read only
|
||||
perm: PERM_READ,
|
||||
perm: value.perm,
|
||||
|
||||
nlink: 1,
|
||||
// set to current user
|
||||
|
@ -1,4 +1,7 @@
|
||||
use std::{collections::HashSet, fs::File, path::PathBuf, time::SystemTime};
|
||||
use std::{
|
||||
collections::HashSet, fs::File, os::unix::prelude::PermissionsExt, path::PathBuf,
|
||||
time::SystemTime,
|
||||
};
|
||||
|
||||
use hbb_common::{
|
||||
bytes::{BufMut, BytesMut},
|
||||
@ -8,6 +11,18 @@ use utf16string::WString;
|
||||
|
||||
use crate::{platform::LDAP_EPOCH_DELTA, CliprdrError};
|
||||
|
||||
/// has valid file attributes
|
||||
const FLAGS_FD_ATTRIBUTES: u32 = 0x04;
|
||||
/// has valid file size
|
||||
const FLAGS_FD_SIZE: u32 = 0x40;
|
||||
/// has valid last write time
|
||||
const FLAGS_FD_LAST_WRITE: u32 = 0x20;
|
||||
/// show progress
|
||||
const FLAGS_FD_PROGRESSUI: u32 = 0x4000;
|
||||
/// transferred from unix, contains file mode
|
||||
/// P.S. this flag is not used in windows
|
||||
const FLAGS_FD_UNIX_MODE: u32 = 0x08;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) struct LocalFile {
|
||||
pub path: PathBuf,
|
||||
@ -17,6 +32,7 @@ pub(super) struct LocalFile {
|
||||
pub size: u64,
|
||||
pub last_write_time: SystemTime,
|
||||
pub is_dir: bool,
|
||||
pub perm: u32,
|
||||
pub read_only: bool,
|
||||
pub hidden: bool,
|
||||
pub system: bool,
|
||||
@ -34,11 +50,17 @@ impl LocalFile {
|
||||
let is_dir = mt.is_dir();
|
||||
let read_only = mt.permissions().readonly();
|
||||
let system = false;
|
||||
let hidden = false;
|
||||
let hidden = if path.to_string_lossy().starts_with('.') {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
let archive = false;
|
||||
let normal = !is_dir;
|
||||
let normal = !(is_dir || read_only || system || hidden || archive);
|
||||
let last_write_time = mt.modified().unwrap_or(SystemTime::UNIX_EPOCH);
|
||||
|
||||
let perm = mt.permissions().mode();
|
||||
|
||||
let name = path
|
||||
.display()
|
||||
.to_string()
|
||||
@ -66,6 +88,7 @@ impl LocalFile {
|
||||
read_only,
|
||||
system,
|
||||
hidden,
|
||||
perm,
|
||||
archive,
|
||||
normal,
|
||||
})
|
||||
@ -109,7 +132,11 @@ impl LocalFile {
|
||||
&self.name
|
||||
);
|
||||
|
||||
let flags = 0x4064;
|
||||
let flags = FLAGS_FD_SIZE
|
||||
| FLAGS_FD_LAST_WRITE
|
||||
| FLAGS_FD_ATTRIBUTES
|
||||
| FLAGS_FD_PROGRESSUI
|
||||
| FLAGS_FD_UNIX_MODE;
|
||||
|
||||
// flags, 4 bytes
|
||||
buf.put_u32_le(flags);
|
||||
@ -117,8 +144,16 @@ impl LocalFile {
|
||||
buf.put(&[0u8; 32][..]);
|
||||
// file attributes, 4 bytes
|
||||
buf.put_u32_le(file_attributes);
|
||||
// 16 bytes reserved
|
||||
buf.put(&[0u8; 16][..]);
|
||||
|
||||
// NOTE: this is not used in windows
|
||||
// in the specification, this is 16 bytes reserved
|
||||
// lets use the last 4 bytes to store the file mode
|
||||
//
|
||||
// 12 bytes reserved
|
||||
buf.put(&[0u8; 12][..]);
|
||||
// file permissions, 4 bytes
|
||||
buf.put_u32_le(self.perm);
|
||||
|
||||
// last write time, 8 bytes
|
||||
buf.put_u64_le(win32_time);
|
||||
// file size (high)
|
||||
@ -201,6 +236,7 @@ mod file_list_test {
|
||||
last_write_time: std::time::SystemTime::UNIX_EPOCH,
|
||||
read_only: false,
|
||||
is_dir,
|
||||
perm: 0o754,
|
||||
hidden: false,
|
||||
system: false,
|
||||
archive: false,
|
||||
@ -263,6 +299,11 @@ mod file_list_test {
|
||||
assert_eq!(parsed[3].name.to_str().unwrap(), "b/c.txt");
|
||||
}
|
||||
|
||||
assert!(parsed[0].perm & 0o777 == 0o754);
|
||||
assert!(parsed[1].perm & 0o777 == 0o754);
|
||||
assert!(parsed[2].perm & 0o777 == 0o754);
|
||||
assert!(parsed[3].perm & 0o777 == 0o754);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -131,7 +131,6 @@ impl ClipboardContext {
|
||||
|
||||
let mnt_opts = [
|
||||
MountOption::FSName("rustdesk-cliprdr-fs".to_string()),
|
||||
MountOption::RO,
|
||||
MountOption::NoAtime,
|
||||
];
|
||||
log::info!(
|
||||
|
Loading…
x
Reference in New Issue
Block a user