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
|
/// read only permission
|
||||||
const PERM_READ: u16 = 0o444;
|
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
|
/// max length of file name
|
||||||
const MAX_NAME_LEN: usize = 255;
|
const MAX_NAME_LEN: usize = 255;
|
||||||
|
|
||||||
@ -143,6 +149,11 @@ impl fuser::Filesystem for FuseClient {
|
|||||||
let mut server = self.server.lock();
|
let mut server = self.server.lock();
|
||||||
server.release(req, ino, fh, _flags, _lock_owner, _flush, reply)
|
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
|
/// fuse server
|
||||||
@ -494,6 +505,18 @@ impl fuser::Filesystem for FuseServer {
|
|||||||
reply.ok();
|
reply.ok();
|
||||||
return;
|
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 {
|
impl FuseServer {
|
||||||
@ -614,8 +637,13 @@ impl FileDescription {
|
|||||||
// skip reserved 32 bytes
|
// skip reserved 32 bytes
|
||||||
bytes.advance(32);
|
bytes.advance(32);
|
||||||
let attributes = bytes.get_u32_le();
|
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
|
// last write time from 1601-01-01 00:00:00, in 100ns
|
||||||
let last_write_time = bytes.get_u64_le();
|
let last_write_time = bytes.get_u64_le();
|
||||||
// file size
|
// file size
|
||||||
@ -632,6 +660,8 @@ impl FileDescription {
|
|||||||
CliprdrError::ConversionFailure
|
CliprdrError::ConversionFailure
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
let from_unix = flags & 0x08 != 0;
|
||||||
|
|
||||||
let valid_attributes = flags & 0x04 != 0;
|
let valid_attributes = flags & 0x04 != 0;
|
||||||
if !valid_attributes {
|
if !valid_attributes {
|
||||||
return Err(CliprdrError::InvalidRequest {
|
return Err(CliprdrError::InvalidRequest {
|
||||||
@ -641,6 +671,25 @@ impl FileDescription {
|
|||||||
|
|
||||||
// todo: check normal, hidden, system, readonly, archive...
|
// todo: check normal, hidden, system, readonly, archive...
|
||||||
let directory = attributes & 0x10 != 0;
|
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 {
|
let kind = if directory {
|
||||||
FileType::Directory
|
FileType::Directory
|
||||||
@ -677,7 +726,7 @@ impl FileDescription {
|
|||||||
|
|
||||||
creation_time: last_modified,
|
creation_time: last_modified,
|
||||||
size,
|
size,
|
||||||
perm: PERM_READ,
|
perm,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(desc)
|
Ok(desc)
|
||||||
@ -859,7 +908,7 @@ impl FuseNode {
|
|||||||
last_metadata_changed: SystemTime::UNIX_EPOCH,
|
last_metadata_changed: SystemTime::UNIX_EPOCH,
|
||||||
creation_time: SystemTime::UNIX_EPOCH,
|
creation_time: SystemTime::UNIX_EPOCH,
|
||||||
size: 0,
|
size: 0,
|
||||||
perm: PERM_READ,
|
perm: PERM_RWX,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
file.clone()
|
file.clone()
|
||||||
@ -910,13 +959,14 @@ pub struct InodeAttributes {
|
|||||||
last_metadata_changed: std::time::SystemTime,
|
last_metadata_changed: std::time::SystemTime,
|
||||||
creation_time: std::time::SystemTime,
|
creation_time: std::time::SystemTime,
|
||||||
kind: FileType,
|
kind: FileType,
|
||||||
|
perm: u16,
|
||||||
|
|
||||||
// not implemented
|
// not implemented
|
||||||
_xattrs: BTreeMap<Vec<u8>, Vec<u8>>,
|
_xattrs: BTreeMap<Vec<u8>, Vec<u8>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InodeAttributes {
|
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 {
|
Self {
|
||||||
inode,
|
inode,
|
||||||
size,
|
size,
|
||||||
@ -925,6 +975,7 @@ impl InodeAttributes {
|
|||||||
last_metadata_changed: std::time::SystemTime::now(),
|
last_metadata_changed: std::time::SystemTime::now(),
|
||||||
creation_time: std::time::SystemTime::now(),
|
creation_time: std::time::SystemTime::now(),
|
||||||
kind,
|
kind,
|
||||||
|
perm,
|
||||||
_xattrs: BTreeMap::new(),
|
_xattrs: BTreeMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -938,13 +989,14 @@ impl InodeAttributes {
|
|||||||
creation_time: desc.creation_time,
|
creation_time: desc.creation_time,
|
||||||
last_accessed: SystemTime::now(),
|
last_accessed: SystemTime::now(),
|
||||||
kind: desc.kind,
|
kind: desc.kind,
|
||||||
|
perm: desc.perm,
|
||||||
|
|
||||||
_xattrs: BTreeMap::new(),
|
_xattrs: BTreeMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_root() -> Self {
|
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) {
|
pub fn access(&mut self) {
|
||||||
@ -970,7 +1022,7 @@ impl From<&InodeAttributes> for fuser::FileAttr {
|
|||||||
kind: value.kind.into(),
|
kind: value.kind.into(),
|
||||||
|
|
||||||
// read only
|
// read only
|
||||||
perm: PERM_READ,
|
perm: value.perm,
|
||||||
|
|
||||||
nlink: 1,
|
nlink: 1,
|
||||||
// set to current user
|
// 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::{
|
use hbb_common::{
|
||||||
bytes::{BufMut, BytesMut},
|
bytes::{BufMut, BytesMut},
|
||||||
@ -8,6 +11,18 @@ use utf16string::WString;
|
|||||||
|
|
||||||
use crate::{platform::LDAP_EPOCH_DELTA, CliprdrError};
|
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)]
|
#[derive(Debug)]
|
||||||
pub(super) struct LocalFile {
|
pub(super) struct LocalFile {
|
||||||
pub path: PathBuf,
|
pub path: PathBuf,
|
||||||
@ -17,6 +32,7 @@ pub(super) struct LocalFile {
|
|||||||
pub size: u64,
|
pub size: u64,
|
||||||
pub last_write_time: SystemTime,
|
pub last_write_time: SystemTime,
|
||||||
pub is_dir: bool,
|
pub is_dir: bool,
|
||||||
|
pub perm: u32,
|
||||||
pub read_only: bool,
|
pub read_only: bool,
|
||||||
pub hidden: bool,
|
pub hidden: bool,
|
||||||
pub system: bool,
|
pub system: bool,
|
||||||
@ -34,11 +50,17 @@ impl LocalFile {
|
|||||||
let is_dir = mt.is_dir();
|
let is_dir = mt.is_dir();
|
||||||
let read_only = mt.permissions().readonly();
|
let read_only = mt.permissions().readonly();
|
||||||
let system = false;
|
let system = false;
|
||||||
let hidden = false;
|
let hidden = if path.to_string_lossy().starts_with('.') {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
let archive = 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 last_write_time = mt.modified().unwrap_or(SystemTime::UNIX_EPOCH);
|
||||||
|
|
||||||
|
let perm = mt.permissions().mode();
|
||||||
|
|
||||||
let name = path
|
let name = path
|
||||||
.display()
|
.display()
|
||||||
.to_string()
|
.to_string()
|
||||||
@ -66,6 +88,7 @@ impl LocalFile {
|
|||||||
read_only,
|
read_only,
|
||||||
system,
|
system,
|
||||||
hidden,
|
hidden,
|
||||||
|
perm,
|
||||||
archive,
|
archive,
|
||||||
normal,
|
normal,
|
||||||
})
|
})
|
||||||
@ -109,7 +132,11 @@ impl LocalFile {
|
|||||||
&self.name
|
&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
|
// flags, 4 bytes
|
||||||
buf.put_u32_le(flags);
|
buf.put_u32_le(flags);
|
||||||
@ -117,8 +144,16 @@ impl LocalFile {
|
|||||||
buf.put(&[0u8; 32][..]);
|
buf.put(&[0u8; 32][..]);
|
||||||
// file attributes, 4 bytes
|
// file attributes, 4 bytes
|
||||||
buf.put_u32_le(file_attributes);
|
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
|
// last write time, 8 bytes
|
||||||
buf.put_u64_le(win32_time);
|
buf.put_u64_le(win32_time);
|
||||||
// file size (high)
|
// file size (high)
|
||||||
@ -201,6 +236,7 @@ mod file_list_test {
|
|||||||
last_write_time: std::time::SystemTime::UNIX_EPOCH,
|
last_write_time: std::time::SystemTime::UNIX_EPOCH,
|
||||||
read_only: false,
|
read_only: false,
|
||||||
is_dir,
|
is_dir,
|
||||||
|
perm: 0o754,
|
||||||
hidden: false,
|
hidden: false,
|
||||||
system: false,
|
system: false,
|
||||||
archive: false,
|
archive: false,
|
||||||
@ -263,6 +299,11 @@ mod file_list_test {
|
|||||||
assert_eq!(parsed[3].name.to_str().unwrap(), "b/c.txt");
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,7 +131,6 @@ impl ClipboardContext {
|
|||||||
|
|
||||||
let mnt_opts = [
|
let mnt_opts = [
|
||||||
MountOption::FSName("rustdesk-cliprdr-fs".to_string()),
|
MountOption::FSName("rustdesk-cliprdr-fs".to_string()),
|
||||||
MountOption::RO,
|
|
||||||
MountOption::NoAtime,
|
MountOption::NoAtime,
|
||||||
];
|
];
|
||||||
log::info!(
|
log::info!(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user