fix(vfs): Z-04 — implement webdav quota report
This commit is contained in:
@@ -885,6 +885,22 @@ impl DavFileSystem for CarrierFs {
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn get_quota(&self) -> FsFuture<'_, (u64, Option<u64>)> {
|
||||
Box::pin(async move {
|
||||
self.touch();
|
||||
let inner = self.inner.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let total_capacity = inner.manifest.total_blocks as u64 * crate::crypto::CHUNK_SIZE as u64;
|
||||
let used_bytes = inner
|
||||
.manifest
|
||||
.inodes
|
||||
.values()
|
||||
.filter(|i| !i.is_dir)
|
||||
.map(|i| i.size)
|
||||
.sum::<u64>();
|
||||
Ok((used_bytes, Some(total_capacity)))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Datei-Handle für Dateien innerhalb des Carrier-Dateisystems mit Streaming und Chunk-Pufferung.
|
||||
|
||||
@@ -349,6 +349,38 @@ impl Database {
|
||||
self.conn()
|
||||
}
|
||||
|
||||
/// Ermittelt den physischen Dateipfad des geöffneten Containers aus SQLite (sofern nicht in-memory).
|
||||
pub fn container_path(&self) -> Option<std::path::PathBuf> {
|
||||
let conn = self.conn();
|
||||
let path_str: String = conn
|
||||
.query_row("PRAGMA database_list;", [], |r| r.get(2))
|
||||
.ok()?;
|
||||
if path_str.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(std::path::PathBuf::from(path_str))
|
||||
}
|
||||
}
|
||||
|
||||
/// Ermittelt die physische Dateigröße des Containers über die SQLite-Page-Statistik (Z-04).
|
||||
pub fn get_container_file_size(&self) -> Result<u64> {
|
||||
let conn = self.conn();
|
||||
let page_count: i64 = conn.query_row("PRAGMA page_count;", [], |r| r.get(0))?;
|
||||
let page_size: i64 = conn.query_row("PRAGMA page_size;", [], |r| r.get(0))?;
|
||||
Ok((page_count.saturating_mul(page_size)).max(0) as u64)
|
||||
}
|
||||
|
||||
/// Ermittelt die kumulierte Dateigröße aller im Container gespeicherten Nutzdateien (Z-04).
|
||||
pub fn get_total_used_size(&self) -> Result<u64> {
|
||||
let conn = self.conn();
|
||||
let total: i64 = conn.query_row(
|
||||
"SELECT COALESCE(SUM(size), 0) FROM nodes WHERE is_dir = 0",
|
||||
[],
|
||||
|r| r.get(0),
|
||||
)?;
|
||||
Ok(total.max(0) as u64)
|
||||
}
|
||||
|
||||
/// Erzeugt eine geklonte Instanz mit einer isolierten aktiven Session (Slot & DEK).
|
||||
pub fn with_session(&self, slot_id: u32, dek: Zeroizing<[u8; 32]>) -> Self {
|
||||
Self {
|
||||
|
||||
+21
-3
@@ -1127,10 +1127,28 @@ impl DavFileSystem for SanctumFs {
|
||||
}
|
||||
|
||||
fn get_quota(&self) -> FsFuture<'_, (u64, Option<u64>)> {
|
||||
if let Some(ref cfs) = self.carrier_fs {
|
||||
return cfs.get_quota();
|
||||
}
|
||||
|
||||
Box::pin(async move {
|
||||
// Virtueller Speicherplatz für Explorer: 1 TB
|
||||
let total_capacity: u64 = 1024 * 1024 * 1024 * 1024;
|
||||
Ok((0, Some(total_capacity)))
|
||||
self.touch();
|
||||
// Z-04: Echte Containergröße (physisch auf Disk) und freier Host-Speicher
|
||||
let container_size = self.db.get_container_file_size().unwrap_or(0);
|
||||
let used_bytes = if container_size > 0 {
|
||||
container_size
|
||||
} else {
|
||||
self.db.get_total_used_size().unwrap_or(0)
|
||||
};
|
||||
|
||||
let free_host_space = self
|
||||
.db
|
||||
.container_path()
|
||||
.and_then(|p| crate::windows::get_available_disk_space(&p))
|
||||
.unwrap_or(1024 * 1024 * 1024 * 1024); // Fallback: 1 TB
|
||||
|
||||
let total_capacity = used_bytes.saturating_add(free_host_space);
|
||||
Ok((used_bytes, Some(total_capacity)))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -846,6 +846,55 @@ pub fn is_process_alive(pid: u32) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
/// Ermittelt den verfügbaren freien Speicherplatz auf dem Dateisystem des angegebenen Pfads (Z-04).
|
||||
pub fn get_available_disk_space<P: AsRef<std::path::Path>>(path: P) -> Option<u64> {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
use std::os::windows::ffi::OsStrExt;
|
||||
let p = path.as_ref();
|
||||
let dir = if p.is_dir() {
|
||||
p.to_path_buf()
|
||||
} else {
|
||||
p.parent().map(|parent| parent.to_path_buf()).unwrap_or_else(|| p.to_path_buf())
|
||||
};
|
||||
let mut wide: Vec<u16> = dir.as_os_str().encode_wide().collect();
|
||||
wide.push(0);
|
||||
|
||||
let mut free_bytes_available = 0u64;
|
||||
let mut total_number_of_bytes = 0u64;
|
||||
let mut total_number_of_free_bytes = 0u64;
|
||||
|
||||
extern "system" {
|
||||
fn GetDiskFreeSpaceExW(
|
||||
lpDirectoryName: *const u16,
|
||||
lpFreeBytesAvailableToCaller: *mut u64,
|
||||
lpTotalNumberOfBytes: *mut u64,
|
||||
lpTotalNumberOfFreeBytes: *mut u64,
|
||||
) -> i32;
|
||||
}
|
||||
|
||||
let success = unsafe {
|
||||
GetDiskFreeSpaceExW(
|
||||
wide.as_ptr(),
|
||||
&mut free_bytes_available,
|
||||
&mut total_number_of_bytes,
|
||||
&mut total_number_of_free_bytes,
|
||||
)
|
||||
};
|
||||
|
||||
if success != 0 {
|
||||
Some(free_bytes_available)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
let _ = path;
|
||||
Some(1024 * 1024 * 1024 * 1024)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
Reference in New Issue
Block a user