From 6c0d2a63e03bd6aa11469c9482924353af5ca27a Mon Sep 17 00:00:00 2001 From: Erick Guan <297343+erickguan@users.noreply.github.com> Date: Tue, 19 Nov 2024 16:55:39 +0100 Subject: [PATCH 1/2] feat(core/services-gdrive): return stat metadata result --- core/src/layers/complete.rs | 17 ++++++++++++++--- core/src/services/gdrive/backend.rs | 13 +++++++++---- core/src/services/gdrive/lister.rs | 12 ++++++++---- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/core/src/layers/complete.rs b/core/src/layers/complete.rs index 2d178763852d..91bb68e62ca7 100644 --- a/core/src/layers/complete.rs +++ b/core/src/layers/complete.rs @@ -177,8 +177,19 @@ impl CompleteAccessor { return Ok(RpStat::new(Metadata::new(EntryMode::DIR))); } - // Forward to inner if create_dir is supported. - if path.ends_with('/') && capability.create_dir { + if path.ends_with('/') + && (capability.create_dir || // Delegate to the service if the service supports `create_dir` + capability.stat_has_cache_control || // Delegate to the service if the service returns metadata. + capability.stat_has_content_disposition || + capability.stat_has_content_length || + capability.stat_has_content_md5 || + capability.stat_has_content_range || + capability.stat_has_content_type || + capability.stat_has_etag || + capability.stat_has_last_modified || + capability.stat_has_version || + capability.stat_has_user_metadata) + { let meta = self.inner.stat(path, args).await?.into_metadata(); if meta.is_file() { @@ -188,7 +199,7 @@ impl CompleteAccessor { )); } - return Ok(RpStat::new(Metadata::new(EntryMode::DIR))); + return Ok(RpStat::new(meta)); } // Otherwise, we can simulate stat dir via `list`. diff --git a/core/src/services/gdrive/backend.rs b/core/src/services/gdrive/backend.rs index 9809d741ff77..c0d118ded346 100644 --- a/core/src/services/gdrive/backend.rs +++ b/core/src/services/gdrive/backend.rs @@ -53,10 +53,14 @@ impl Access for GdriveBackend { .set_root(&self.core.root) .set_native_capability(Capability { stat: true, + stat_has_content_length: true, + stat_has_content_type: true, + stat_has_last_modified: true, read: true, list: true, + list_has_content_type: true, write: true, @@ -91,11 +95,12 @@ impl Access for GdriveBackend { let gdrive_file: GdriveFile = serde_json::from_reader(bs.reader()).map_err(new_json_deserialize_error)?; - if gdrive_file.mime_type == "application/vnd.google-apps.folder" { - return Ok(RpStat::new(Metadata::new(EntryMode::DIR))); + let file_type = if gdrive_file.mime_type == "application/vnd.google-apps.folder" { + EntryMode::DIR + } else { + EntryMode::FILE }; - - let mut meta = Metadata::new(EntryMode::FILE); + let mut meta = Metadata::new(file_type).with_content_type(gdrive_file.mime_type); if let Some(v) = gdrive_file.size { meta = meta.with_content_length(v.parse::().map_err(|e| { Error::new(ErrorKind::Unexpected, "parse content length").set_source(e) diff --git a/core/src/services/gdrive/lister.rs b/core/src/services/gdrive/lister.rs index 2dfec0e739c7..7719f986f35f 100644 --- a/core/src/services/gdrive/lister.rs +++ b/core/src/services/gdrive/lister.rs @@ -58,13 +58,13 @@ impl oio::PageList for GdriveLister { _ => return Err(parse_error(resp)), }; - // Gdrive returns empty content when this dir is not exist. + // Google Drive returns an empty response when attempting to list a non-existent directory. if bytes.is_empty() { ctx.done = true; return Ok(()); } - // Return self at the first page. + // Include the current directory itself when handling the first page of the listing. if ctx.token.is_empty() && !ctx.done { let path = build_rel_path(&self.core.root, &self.path); let e = oio::Entry::new(&path, Metadata::new(EntryMode::DIR)); @@ -94,8 +94,12 @@ impl oio::PageList for GdriveLister { let path = format!("{}{}", &self.path, file.name); let normalized_path = build_rel_path(root, &path); - // Update path cache with list result. - self.core.path_cache.insert(&path, &file.id).await; + // Update path cache when path doesn't exist. + // When Google Drive converts a format, for example, Microsoft PowerPoint, + // Google Drive keeps two entries with the same ID. + if let Ok(None) = self.core.path_cache.get(&path).await { + self.core.path_cache.insert(&path, &file.id).await; + } let entry = oio::Entry::new(&normalized_path, Metadata::new(file_type)); ctx.entries.push_back(entry); From 44823a28ebff4517a35cf7a37d0175c25e2e22c7 Mon Sep 17 00:00:00 2001 From: Erick Guan <297343+erickguan@users.noreply.github.com> Date: Wed, 20 Nov 2024 19:38:25 +0100 Subject: [PATCH 2/2] fixup! feat(core/services-gdrive): return stat metadata result --- core/src/layers/complete.rs | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/core/src/layers/complete.rs b/core/src/layers/complete.rs index 91bb68e62ca7..46f9e4ccc0c1 100644 --- a/core/src/layers/complete.rs +++ b/core/src/layers/complete.rs @@ -177,19 +177,8 @@ impl CompleteAccessor { return Ok(RpStat::new(Metadata::new(EntryMode::DIR))); } - if path.ends_with('/') - && (capability.create_dir || // Delegate to the service if the service supports `create_dir` - capability.stat_has_cache_control || // Delegate to the service if the service returns metadata. - capability.stat_has_content_disposition || - capability.stat_has_content_length || - capability.stat_has_content_md5 || - capability.stat_has_content_range || - capability.stat_has_content_type || - capability.stat_has_etag || - capability.stat_has_last_modified || - capability.stat_has_version || - capability.stat_has_user_metadata) - { + // Forward to inner if create_dir is supported. + if path.ends_with('/') && capability.create_dir { let meta = self.inner.stat(path, args).await?.into_metadata(); if meta.is_file() {