Implement SMB AFP_Resource Stream via AppleDouble files (Phase 3 complete)
This commit is contained in:
85
vendor/smb-server/src/handlers/create.rs
vendored
85
vendor/smb-server/src/handlers/create.rs
vendored
@@ -7,7 +7,7 @@ use crate::proto::header::Smb2Header;
|
||||
use crate::proto::messages::{CreateRequest, CreateResponse};
|
||||
use tracing::{debug, warn};
|
||||
|
||||
use crate::backend::{OpenIntent, OpenOptions};
|
||||
use crate::backend::{OpenIntent, OpenOptions, FileInfo};
|
||||
use crate::builder::Access;
|
||||
use crate::conn::state::{Connection, Open};
|
||||
use crate::dispatch::HandlerResponse;
|
||||
@@ -144,11 +144,86 @@ pub async fn handle(
|
||||
if stream_path.is_afp_resource() {
|
||||
debug!(base_path = %stream_path.base_path(), stream = %stream_path.stream_name(), "AFP_Resource named stream open");
|
||||
|
||||
// For AFP_Resource, we return a virtual handle that reads/writes ._ file
|
||||
// TODO: Implement actual AFP_Resource handling via AppleDouble files
|
||||
// Create AfpResourceHandle to read/write AppleDouble file (._filename)
|
||||
let base_smb_path = stream_path.base_path().clone();
|
||||
|
||||
// Return STATUS_OBJECT_NAME_NOT_FOUND for now (phase 3 will implement)
|
||||
return HandlerResponse::err(ntstatus::STATUS_OBJECT_NAME_NOT_FOUND);
|
||||
// Check write permission
|
||||
let want_write = req.desired_access & (FILE_WRITE_DATA | GENERIC_WRITE | GENERIC_ALL) != 0;
|
||||
if want_write && !granted.allows_write() {
|
||||
return HandlerResponse::err(ntstatus::STATUS_ACCESS_DENIED);
|
||||
}
|
||||
|
||||
// Allocate file_id
|
||||
let mut tree = tree_arc.write().await;
|
||||
let file_id = tree.alloc_file_id();
|
||||
let read_only = tree.share.backend.capabilities().is_read_only;
|
||||
|
||||
let handle = crate::backend::AfpResourceHandle::new(base_smb_path.clone(), backend, want_write && read_only);
|
||||
|
||||
let open = Open::new(
|
||||
file_id,
|
||||
Box::new(handle),
|
||||
if want_write { granted } else { Access::Read },
|
||||
base_smb_path,
|
||||
false, // is_directory
|
||||
false, // delete_on_close
|
||||
0, // oplock_level
|
||||
0, // share_access
|
||||
);
|
||||
|
||||
let open_arc = Arc::new(RwLock::new(open));
|
||||
tree.opens.write().await.insert(file_id, open_arc.clone());
|
||||
drop(tree);
|
||||
|
||||
// Load resource fork size for response
|
||||
let open_lock = open_arc.read().await;
|
||||
let info = match open_lock.handle.as_ref() {
|
||||
Some(h) => h.stat().await.unwrap_or(FileInfo {
|
||||
name: "".to_string(),
|
||||
end_of_file: 0,
|
||||
allocation_size: 0,
|
||||
creation_time: 0,
|
||||
last_access_time: 0,
|
||||
last_write_time: 0,
|
||||
change_time: 0,
|
||||
is_directory: false,
|
||||
file_index: 0,
|
||||
}),
|
||||
None => FileInfo {
|
||||
name: "".to_string(),
|
||||
end_of_file: 0,
|
||||
allocation_size: 0,
|
||||
creation_time: 0,
|
||||
last_access_time: 0,
|
||||
last_write_time: 0,
|
||||
change_time: 0,
|
||||
is_directory: false,
|
||||
file_index: 0,
|
||||
},
|
||||
};
|
||||
drop(open_lock);
|
||||
|
||||
let resp = CreateResponse {
|
||||
structure_size: 89,
|
||||
oplock_level: 0,
|
||||
flags: 0,
|
||||
create_action: FILE_OPENED,
|
||||
creation_time: 0,
|
||||
last_access_time: 0,
|
||||
last_write_time: 0,
|
||||
change_time: 0,
|
||||
allocation_size: info.allocation_size,
|
||||
end_of_file: info.end_of_file,
|
||||
file_attributes: 0,
|
||||
reserved2: 0,
|
||||
file_id,
|
||||
create_contexts_offset: 0,
|
||||
create_contexts_length: 0,
|
||||
create_contexts: vec![],
|
||||
};
|
||||
let mut buf = Vec::new();
|
||||
resp.write_to(&mut buf).expect("encode");
|
||||
return HandlerResponse::ok(buf);
|
||||
}
|
||||
|
||||
// Unknown named stream type
|
||||
|
||||
Reference in New Issue
Block a user