Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ pin-project = "1.0.4"
pin-utils = "0.1.0"
regex = "1.4.0"
tokio = { version = "1.3.0", features = [ "rt-multi-thread", "io-util", "net", "time", "sync" ] }
time = { version = "0.2.24", default-features = false }
time = { version = "0.2.24", features = ["std"] }
url = "2.2.0"
uuid = { version = "0.8.0", features = ["v4"] }
xml-rs = "0.8.0"
Expand Down
15 changes: 13 additions & 2 deletions src/davpath.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
//! Utility module to handle the path part of an URL as a filesytem path.
//!
//#![cfg_attr(target_os = "windows", allow(unused_imports))]
use std::error::Error;
use std::ffi::OsStr;
use std::os::unix::ffi::OsStrExt;
#[cfg(not(target_os = "windows"))]
use {std::ffi::OsStr, std::os::unix::ffi::OsStrExt};
#[cfg(target_os = "windows")]
use {std::ffi::OsStr, std::ffi::OsString}; // std::os::windows::prelude::*,
use std::path::{Path, PathBuf};

use mime_guess;
Expand Down Expand Up @@ -339,7 +342,12 @@ impl DavPathRef {
if b.len() > 1 && b.ends_with(b"/") {
b = &b[..b.len() - 1];
}

#[cfg(not(target_os = "windows"))]
let os_string = OsStr::from_bytes(b).to_owned();
#[cfg(target_os = "windows")]
let os_string = OsString::from(String::from_utf8(b.to_vec()).unwrap());

PathBuf::from(os_string)
}

Expand Down Expand Up @@ -376,7 +384,10 @@ impl DavPathRef {
if path.ends_with(b"/") {
path = &path[..path.len() - 1];
}
#[cfg(not(target_os = "windows"))]
let os_string = OsStr::from_bytes(path);
#[cfg(target_os = "windows")]
let os_string : &OsStr = std::str::from_utf8(path).unwrap().as_ref();
Path::new(os_string)
}

Expand Down
116 changes: 97 additions & 19 deletions src/localfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,15 @@ use std::any::Any;
use std::collections::VecDeque;
use std::future::Future;
use std::io::{self, ErrorKind, Read, Seek, SeekFrom, Write};
use std::os::unix::ffi::OsStrExt;
use std::os::unix::fs::DirBuilderExt;
use std::os::unix::fs::MetadataExt;
use std::os::unix::fs::OpenOptionsExt;
use std::os::unix::fs::PermissionsExt;
#[cfg(not(target_os = "windows"))]
use {
std::os::unix::ffi::OsStrExt,
std::os::unix::fs::DirBuilderExt,
std::os::unix::fs::MetadataExt,
std::os::unix::fs::OpenOptionsExt,
std::os::unix::fs::PermissionsExt};
#[cfg(target_os = "windows")]
use std::os::windows::prelude::*;
use std::path::{Path, PathBuf};
use std::pin::Pin;
use std::sync::atomic::{AtomicU32, Ordering};
Expand Down Expand Up @@ -309,9 +313,11 @@ impl DavFileSystem for LocalFs {
if self.is_forbidden(path) {
return Err(FsError::Forbidden);
}
#[cfg(not(target_os = "windows"))]
let mode = if self.inner.public { 0o644 } else { 0o600 };
let path = self.fspath(path);
self.blocking(move || {
#[cfg(not(target_os = "windows"))]
let res = std::fs::OpenOptions::new()
.read(options.read)
.write(options.write)
Expand All @@ -321,6 +327,16 @@ impl DavFileSystem for LocalFs {
.create_new(options.create_new)
.mode(mode)
.open(path);
#[cfg(target_os = "windows")]
let res = std::fs::OpenOptions::new()
.read(options.read)
.write(options.write)
.append(options.append)
.truncate(options.truncate)
.create(options.create)
.create_new(options.create_new)
//.mode(mode)
.open(path);
match res {
Ok(file) => Ok(Box::new(LocalFsFile(Some(file))) as Box<dyn DavFile>),
Err(e) => Err(e.into()),
Expand All @@ -337,13 +353,24 @@ impl DavFileSystem for LocalFs {
if self.is_forbidden(path) {
return Err(FsError::Forbidden);
}
#[cfg(not(target_os = "windows"))]
let mode = if self.inner.public { 0o755 } else { 0o700 };
let path = self.fspath(path);
self.blocking(move || {
std::fs::DirBuilder::new()
#[cfg(not(target_os = "windows"))]
{
std::fs::DirBuilder::new()
.mode(mode)
.create(path)
.map_err(|e| e.into())
.map_err(|e| e.into())
}
#[cfg(target_os = "windows")]
{
std::fs::DirBuilder::new()
//.mode(mode)
.create(path)
.map_err(|e| e.into())
}
})
.await
}
Expand Down Expand Up @@ -605,7 +632,14 @@ impl DavDirEntry for LocalFsDirEntry {
}

fn name(&self) -> Vec<u8> {
self.entry.file_name().as_bytes().to_vec()
#[cfg(not(target_os = "windows"))]
{
self.entry.file_name().as_bytes().to_vec()
}
#[cfg(target_os = "windows")]
{
self.entry.file_name().to_str().unwrap().as_bytes().to_vec()
}
}

fn is_dir<'a>(&'a self) -> FsFuture<bool> {
Expand Down Expand Up @@ -719,7 +753,14 @@ impl DavMetaData for LocalFsMetaData {
}

fn status_changed(&self) -> FsResult<SystemTime> {
Ok(UNIX_EPOCH + Duration::new(self.0.ctime() as u64, 0))
#[cfg(not(target_os = "windows"))]
{
Ok(UNIX_EPOCH + Duration::new(self.0.ctime() as u64, 0))
}
#[cfg(target_os = "windows")]
{
Ok(UNIX_EPOCH + Duration::from_nanos(self.0.creation_time() - 116444736000000000))
}
}

fn is_dir(&self) -> bool {
Expand All @@ -732,21 +773,40 @@ impl DavMetaData for LocalFsMetaData {
self.0.file_type().is_symlink()
}
fn executable(&self) -> FsResult<bool> {
if self.0.is_file() {
return Ok((self.0.permissions().mode() & 0o100) > 0);
#[cfg(not(target_os = "windows"))]
{
if self.0.is_file() {
return Ok((self.0.permissions().mode() & 0o100) > 0);
}
Err(FsError::NotImplemented)
}
Err(FsError::NotImplemented)
#[cfg(target_os = "windows")]
panic!();
}

// same as the default apache etag.
fn etag(&self) -> Option<String> {
let modified = self.0.modified().ok()?;
let t = modified.duration_since(UNIX_EPOCH).ok()?;
let t = t.as_secs() * 1000000 + t.subsec_nanos() as u64 / 1000;
if self.is_file() {
Some(format!("{:x}-{:x}-{:x}", self.0.ino(), self.0.len(), t))
} else {
Some(format!("{:x}-{:x}", self.0.ino(), t))
#[cfg(not(target_os = "windows"))]
{
let modified = self.0.modified().ok()?;
let t = modified.duration_since(UNIX_EPOCH).ok()?;
let t = t.as_secs() * 1000000 + t.subsec_nanos() as u64 / 1000;
if self.is_file() {
Some(format!("{:x}-{:x}-{:x}", self.0.ino(), self.0.len(), t))
} else {
Some(format!("{:x}-{:x}", self.0.ino(), t))
}
}
#[cfg(target_os = "windows")]
{
let modified = self.0.modified().ok()?;
let t = modified.duration_since(UNIX_EPOCH).ok()?;
let t = t.as_secs() * 1000000 + t.subsec_nanos() as u64 / 1000;
if self.is_file() {
Some(format!("{:x}-{:x}", self.0.len(), t))
} else {
Some(format!("{:x}", t))
}
}
}
}
Expand All @@ -755,6 +815,7 @@ impl From<&io::Error> for FsError {
fn from(e: &io::Error) -> Self {
if let Some(errno) = e.raw_os_error() {
// specific errors.
#[cfg(not(target_os = "windows"))]
match errno {
libc::EMLINK | libc::ENOSPC | libc::EDQUOT => return FsError::InsufficientStorage,
libc::EFBIG => return FsError::TooLarge,
Expand All @@ -770,6 +831,23 @@ impl From<&io::Error> for FsError {
libc::EXDEV => return FsError::IsRemote,
_ => {},
}
#[cfg(target_os = "windows")]
match errno {
// libc::EMLINK | libc::ENOSPC | libc::EDQUOT => return FsError::InsufficientStorage,
libc::EMLINK | libc::ENOSPC => return FsError::InsufficientStorage,
libc::EFBIG => return FsError::TooLarge,
libc::EACCES | libc::EPERM => return FsError::Forbidden,
libc::ENOTEMPTY | libc::EEXIST => return FsError::Exists,
libc::ELOOP => return FsError::LoopDetected,
libc::ENAMETOOLONG => return FsError::PathTooLong,
libc::ENOTDIR => return FsError::Forbidden,
libc::EISDIR => return FsError::Forbidden,
libc::EROFS => return FsError::Forbidden,
libc::ENOENT => return FsError::NotFound,
libc::ENOSYS => return FsError::NotImplemented,
libc::EXDEV => return FsError::IsRemote,
_ => {},
}
} else {
// not an OS error - must be "not implemented"
// (e.g. metadata().created() on systems without st_crtime)
Expand Down
16 changes: 16 additions & 0 deletions src/localfs_macos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@
// - fake a ".metadata_never_index" in the root
// - fake a ".ql_disablethumbnails" file in the root.
//

use std::ffi::OsString;
#[cfg(not(target_os = "windows"))]
use std::os::unix::ffi::OsStrExt;
//#[cfg(target_os = "windows")]
//use std::os::windows::prelude::*;
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
Expand Down Expand Up @@ -154,9 +158,14 @@ impl DUCacheBuilder {
// add a filename to the list we have
pub fn add(&mut self, filename: OsString) {
if let Some(f) = Path::new(&filename).file_name() {
#[cfg(not(target_os = "windows"))]
if f.as_bytes().starts_with(b"._") {
self.entries.push(filename);
}
#[cfg(target_os = "windows")]
if f.to_str().unwrap().as_bytes().starts_with(b"._") {
self.entries.push(filename);
}
}
}

Expand Down Expand Up @@ -263,11 +272,18 @@ impl LocalFs {
if !self.inner.macos {
return false;
}
#[cfg(not(target_os = "windows"))]
match path.file_name().map(|p| p.as_bytes()) {
Some(b".localized") => true,
Some(name) if name.starts_with(b"._") => DU_CACHE.negative(path),
_ => false,
}
#[cfg(target_os = "windows")]
match path.file_name().map(|p| p.to_str().unwrap().as_bytes()) {
Some(b".localized") => true,
Some(name) if name.starts_with(b"._") => DU_CACHE.negative(path),
_ => false,
}
}

// Return a "directory cache builder".
Expand Down
4 changes: 2 additions & 2 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,9 @@ pub(crate) fn systemtime_to_offsetdatetime(t: SystemTime) -> time::OffsetDateTim
match t.duration_since(UNIX_EPOCH) {
Ok(t) => {
let tm = time::OffsetDateTime::from_unix_timestamp(t.as_secs() as i64);
tm.to_offset(time::offset!(UTC))
tm.to_offset(time::UtcOffset::try_current_local_offset().unwrap_or(time::offset!(UTC)))
},
Err(_) => time::OffsetDateTime::unix_epoch().to_offset(time::offset!(UTC)),
Err(_) => time::OffsetDateTime::unix_epoch().to_offset(time::UtcOffset::try_current_local_offset().unwrap_or(time::offset!(UTC))),
}
}

Expand Down