[ENG-1229] Show hidden files not working correctly (#1583)

* Ensure hidden prop is updated when file is modified

* Fix show hidden files in ephemeral locations

* Restore hidden prop for NonIndexedPathItem
This commit is contained in:
Vítor Vasconcellos 2023-10-19 02:14:42 -03:00 committed by GitHub
parent 7ea5a0ee5b
commit 34fe26e442
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 61 additions and 27 deletions

View file

@ -79,6 +79,7 @@ file_path::select!(file_path_walker {
date_modified
inode
size_in_bytes_bytes
hidden
});
file_path::select!(file_path_to_handle_custom_uri {
pub_id
@ -128,12 +129,13 @@ pub struct FilePathMetadata {
pub hidden: bool,
}
pub fn path_is_hidden(path: &Path, metadata: &Metadata) -> bool {
pub fn path_is_hidden(path: impl AsRef<Path>, metadata: &Metadata) -> bool {
#[cfg(target_family = "unix")]
{
use std::ffi::OsStr;
let _ = metadata; // just to avoid warnings on Linux
if path
.as_ref()
.file_name()
.and_then(OsStr::to_str)
.map(|s| s.starts_with('.'))
@ -147,6 +149,7 @@ pub fn path_is_hidden(path: &Path, metadata: &Metadata) -> bool {
{
use std::os::macos::fs::MetadataExt;
// https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemDetails/FileSystemDetails.html#:~:text=UF_HIDDEN
const UF_HIDDEN: u32 = 0x8000;
if (metadata.st_flags() & UF_HIDDEN) == UF_HIDDEN {
@ -171,7 +174,10 @@ pub fn path_is_hidden(path: &Path, metadata: &Metadata) -> bool {
}
impl FilePathMetadata {
pub async fn from_path(path: &Path, metadata: &Metadata) -> Result<Self, FilePathError> {
pub async fn from_path(
path: impl AsRef<Path>,
metadata: &Metadata,
) -> Result<Self, FilePathError> {
let inode = {
#[cfg(target_family = "unix")]
{
@ -180,13 +186,13 @@ impl FilePathMetadata {
#[cfg(target_family = "windows")]
{
get_inode_from_path(&path).await?
get_inode_from_path(path.as_ref()).await?
}
};
Ok(Self {
inode,
hidden: path_is_hidden(path, metadata),
hidden: path_is_hidden(path.as_ref(), metadata),
size_in_bytes: metadata.len(),
created_at: metadata.created_or_now().into(),
modified_at: metadata.modified_or_now().into(),

View file

@ -232,6 +232,10 @@ async fn execute_indexer_update_step(
(date_modified::NAME, json!(entry.metadata.modified_at)),
date_modified::set(Some(entry.metadata.modified_at.into())),
),
(
(hidden::NAME, json!(entry.metadata.hidden)),
hidden::set(Some(entry.metadata.hidden)),
),
]
.into_iter()
.unzip();

View file

@ -104,7 +104,7 @@ pub fn no_os_protected() -> SystemIndexerRule {
"C:/Users/*/ntuser.dat*",
"C:/Users/*/{ntuser.ini,ntuser.dat,NTUSER.DAT}",
// User special folders (most of these the user dont even have permission to access)
"C:/Users/*/{Cookies,AppData,NetHood,Recent,PrintHood,SendTo,Templates,Start Menu,Application Data,Local Settings}",
"C:/Users/*/{Cookies,AppData,NetHood,Recent,PrintHood,SendTo,Templates,Start Menu,Application Data,Local Settings,My Documents}",
// System special folders
"C:/{$Recycle.Bin,$WinREAgent,Documents and Settings,Program Files,Program Files (x86),ProgramData,Recovery,PerfLogs,Windows,Windows.old}",
// NTFS internal dir, can exists on any drive

View file

@ -296,7 +296,7 @@ where
indexed_paths.insert(WalkingEntry {
iso_file_path: iso_file_path_factory(root, true)?,
maybe_metadata: Some(FilePathMetadata::from_path(root, &metadata).await?),
maybe_metadata: Some(FilePathMetadata::from_path(&root, &metadata).await?),
});
}
@ -378,7 +378,7 @@ where
// Datetimes stored in DB loses a bit of precision, so we need to check against a delta
// instead of using != operator
|| DateTime::<FixedOffset>::from(metadata.modified_at) - *date_modified
> Duration::milliseconds(1)
> Duration::milliseconds(1) || file_path.hidden.is_none() || metadata.hidden != file_path.hidden.unwrap_or_default()
)
// We ignore the size of directories because it is not reliable, we need to
// calculate it ourselves later
@ -528,7 +528,7 @@ where
let Ok(metadata) = entry
.metadata()
.await
.map_err(|e| errors.push(FileIOError::from((entry.path(), e)).into()))
.map_err(|e| errors.push(FileIOError::from((&current_path, e)).into()))
else {
continue 'entries;
};
@ -575,7 +575,7 @@ where
// Then we mark this directory the be walked in too
if let Some(ref mut to_walk) = maybe_to_walk {
to_walk.push_back(ToWalkEntry {
path: entry.path(),
path: current_path.clone(),
parent_dir_accepted_by_its_children: accept_by_children_dir,
maybe_parent: Some(path.clone()),
});
@ -640,7 +640,7 @@ where
continue;
};
let Ok(metadata) = FilePathMetadata::from_path(ancestor, &metadata)
let Ok(metadata) = FilePathMetadata::from_path(&ancestor, &metadata)
.await
.map_err(|e| errors.push(e.into()))
else {

View file

@ -7,7 +7,7 @@ use crate::{
check_file_path_exists, create_file_path, file_path_with_object,
filter_existing_file_path_params,
isolated_file_path_data::extract_normalized_materialized_path_str,
loose_find_existing_file_path_params, FilePathError, FilePathMetadata,
loose_find_existing_file_path_params, path_is_hidden, FilePathError, FilePathMetadata,
IsolatedFilePathData, MetadataExt,
},
find_location,
@ -123,7 +123,7 @@ pub(super) async fn create_dir(
library,
iso_file_path,
None,
FilePathMetadata::from_path(path, metadata).await?,
FilePathMetadata::from_path(&path, metadata).await?,
)
.await?;
@ -176,7 +176,7 @@ async fn inner_create_file(
let iso_file_path = IsolatedFilePathData::new(location_id, location_path, path, false)?;
let extension = iso_file_path.extension.to_string();
let metadata = FilePathMetadata::from_path(path, metadata).await?;
let metadata = FilePathMetadata::from_path(&path, metadata).await?;
// First we check if already exist a file with this same inode number
// if it does, we just update it
@ -416,6 +416,7 @@ async fn inner_update_file(
}
};
let is_hidden = path_is_hidden(full_path, &fs_metadata);
if file_path.cas_id != cas_id {
let (sync_params, db_params): (Vec<_>, Vec<_>) = {
use file_path::*;
@ -470,6 +471,16 @@ async fn inner_update_file(
((inode::NAME, serde_json::Value::Null), None)
}
},
{
if is_hidden != file_path.hidden.unwrap_or_default() {
(
(hidden::NAME, json!(inode)),
Some(hidden::set(Some(is_hidden))),
)
} else {
((hidden::NAME, serde_json::Value::Null), None)
}
},
]
.into_iter()
.filter_map(|(sync_param, maybe_db_param)| {
@ -578,6 +589,26 @@ async fn inner_update_file(
invalidate_query!(library, "search.paths");
invalidate_query!(library, "search.objects");
} else if is_hidden != file_path.hidden.unwrap_or_default() {
sync.write_ops(
db,
(
vec![sync.shared_update(
prisma_sync::file_path::SyncId {
pub_id: file_path.pub_id.clone(),
},
file_path::hidden::NAME,
json!(is_hidden),
)],
db.file_path().update(
file_path::pub_id::equals(file_path.pub_id.clone()),
vec![file_path::hidden::set(Some(is_hidden))],
),
),
)
.await?;
invalidate_query!(library, "search.paths");
}
Ok(())
@ -649,7 +680,7 @@ pub(super) async fn rename(
trace!("Updated {updated} file_paths");
}
let metadata = FilePathMetadata::from_path(new_path, &new_path_metadata).await?;
let is_hidden = path_is_hidden(new_path, &new_path_metadata);
library
.db
@ -663,7 +694,7 @@ pub(super) async fn rename(
file_path::date_modified::set(Some(
DateTime::<Utc>::from(new_path_metadata.modified_or_now()).into(),
)),
file_path::hidden::set(Some(metadata.hidden)),
file_path::hidden::set(Some(is_hidden)),
],
)
.exec()

View file

@ -131,11 +131,11 @@ impl<'lib> EventHandler<'lib> for WindowsEventHandler<'lib> {
)
.await?;
} else {
let metadata = fs::metadata(&paths[0])
.await
.map_err(|e| FileIOError::from((&paths[0], e)))?;
let path = paths.remove(0);
let metadata = fs::metadata(&path)
.await
.map_err(|e| FileIOError::from((&path, e)))?;
if metadata.is_dir() {
// Don't need to dispatch a recalculate directory event as `create_dir` dispatches
// a `scan_location_sub_path` function, which recalculates the size already

View file

@ -46,7 +46,7 @@ const EphemeralExplorer = memo((props: { args: PathParams }) => {
'search.ephemeralPaths',
{
path: path ?? (os === 'windows' ? 'C:\\' : '/'),
withHiddenFiles: false,
withHiddenFiles: settingsSnapshot.showHiddenFiles,
order: settingsSnapshot.order
}
],
@ -63,13 +63,6 @@ const EphemeralExplorer = memo((props: { args: PathParams }) => {
const ret: ExplorerItem[] = [];
for (const item of query.data.entries) {
if (
!settingsSnapshot.showHiddenFiles &&
item.type === 'NonIndexedPath' &&
item.item.hidden
)
continue;
if (settingsSnapshot.layoutMode !== 'media') ret.push(item);
else {
const { kind } = getExplorerItemData(item);