Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Does not show 'folders' that do not contain a .bzEmpty object #14768

Closed
metadaddy opened this issue Jun 7, 2023 · 6 comments · Fixed by #14792
Closed

Does not show 'folders' that do not contain a .bzEmpty object #14768

metadaddy opened this issue Jun 7, 2023 · 6 comments · Fixed by #14792
Labels
b2 Backblaze B2 Protocol Implementation
Milestone

Comments

@metadaddy
Copy link

metadaddy commented Jun 7, 2023

Describe the bug

The .bzEmpty object is optional in Backblaze B2. Many applications create objects with path-like keys without ever creating a .bzEmpty object.

Cyberduck version 8.6.0 fails to display a 'folder' if it does not contain a .bzEmpty object.

To Reproduce
Steps to reproduce the behavior:

  1. In a B2 bucket, create an object with a path-like key, for example, with the B2 CLI:
    % b2 upload-file my-bucket hello.txt folder/hello.txt
    URL by file name: https://f004.backblazeb2.com/file/my-bucket/folder/hello.txt
    ...
  2. Confirm the 'folder' is there:
    % b2 ls my-bucket
    folder/
  3. Open the bucket in Cyberduck.
  4. The 'folder' is not displayed.

Expected behavior
The 'folder' should be displayed.

Desktop:

  • OS: macOS
  • Version 13.4

Log Files

2023-06-06 12:57:29,680 [main] DEBUG ch.cyberduck.binding.application.NSApplication - NSConcreteNotification 0x600000489400 {name = NSApplicationWillBecomeActiveNotification; object = <NSApplication: 0x104e0f560>}
2023-06-06 12:57:29,680 [main] DEBUG ch.cyberduck.binding.WindowController - Become main for window <NSWindow: 0x1459a8530>
2023-06-06 12:57:29,680 [main] DEBUG ch.cyberduck.binding.WindowController - Become key for window <NSWindow: 0x1459a8530>
2023-06-06 12:57:29,683 [main] DEBUG ch.cyberduck.binding.application.NSApplication - NSConcreteNotification 0x6000004a3120 {name = NSApplicationDidBecomeActiveNotification; object = <NSApplication: 0x104e0f560>}
2023-06-06 12:57:29,696 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - No cached image for eject.pdf
2023-06-06 12:57:29,696 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - Return default size for eject.pdf
2023-06-06 12:57:29,847 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - No cached image for eject.pdf
2023-06-06 12:57:29,847 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - Return default size for eject.pdf
2023-06-06 12:57:29,849 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - No cached image for eject.pdf
2023-06-06 12:57:29,849 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - Return default size for eject.pdf
2023-06-06 12:57:29,852 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - No cached image for eject.pdf
2023-06-06 12:57:29,852 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - Return default size for eject.pdf
2023-06-06 12:57:34,159 [main] DEBUG ch.cyberduck.binding.WindowController - Resign key for window <NSWindow: 0x1459a8530>
2023-06-06 12:57:34,159 [main] DEBUG ch.cyberduck.binding.WindowController - Become key for window <NSWindow: 0x104e4c370>
2023-06-06 12:57:34,160 [main] DEBUG ch.cyberduck.binding.WindowController - Resign main for window <NSWindow: 0x1459a8530>
2023-06-06 12:57:34,160 [main] DEBUG ch.cyberduck.binding.WindowController - Become main for window <NSWindow: 0x104e4c370>
2023-06-06 12:57:34,173 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - No cached image for eject.pdf
2023-06-06 12:57:34,173 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - Return default size for eject.pdf
2023-06-06 12:57:34,173 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - No cached image for eject.pdf
2023-06-06 12:57:34,174 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - Return default size for eject.pdf
2023-06-06 12:57:34,310 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - No cached image for eject.pdf
2023-06-06 12:57:34,310 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - Return default size for eject.pdf
2023-06-06 12:57:34,312 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - No cached image for eject.pdf
2023-06-06 12:57:34,312 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - Return default size for eject.pdf
2023-06-06 12:57:34,466 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - No cached image for eject.pdf
2023-06-06 12:57:34,466 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - Return default size for eject.pdf
2023-06-06 12:57:34,468 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - No cached image for eject.pdf
2023-06-06 12:57:34,468 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - Return default size for eject.pdf
2023-06-06 12:57:34,469 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - No cached image for eject.pdf
2023-06-06 12:57:34,469 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - Return default size for eject.pdf
2023-06-06 12:57:34,469 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - No cached image for eject.pdf
2023-06-06 12:57:34,469 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - Return default size for eject.pdf
2023-06-06 12:57:36,765 [Finalizer] DEBUG org.rococoa - Draining autorelease pool
2023-06-06 12:57:36,767 [Finalizer] DEBUG org.rococoa - Draining autorelease pool
2023-06-06 12:57:38,398 [main] DEBUG org.rococoa.callback - No method _windowForToolbar for selector:_windowForToolbar
2023-06-06 12:57:38,399 [main] DEBUG ch.cyberduck.ui.cocoa.controller.BrowserController - Reload data with selected files []
2023-06-06 12:57:38,399 [main] INFO  ch.cyberduck.core.AbstractCache - Invalidate Path{path='/metadaddy-synology', type=[directory, volume]}
2023-06-06 12:57:38,399 [main] DEBUG ch.cyberduck.core.threading.DefaultBackgroundExecutor - Run action WorkerBackgroundAction{worker=SessionListWorker{directory=Path{path='/metadaddy-synology', type=[directory, volume]}}} in background
2023-06-06 12:57:38,400 [main] INFO  ch.cyberduck.core.threading.DefaultBackgroundExecutor - Scheduled background runnable WorkerBackgroundAction{worker=SessionListWorker{directory=Path{path='/metadaddy-synology', type=[directory, volume]}}} for execution
2023-06-06 12:57:38,401 [Thread-109] DEBUG ch.cyberduck.core.threading.BackgroundCallable - Running background action WorkerBackgroundAction{worker=SessionListWorker{directory=Path{path='/metadaddy-synology', type=[directory, volume]}}}
2023-06-06 12:57:38,401 [Thread-109] DEBUG ch.cyberduck.core.threading.BackgroundCallable - Prepare background action WorkerBackgroundAction{worker=SessionListWorker{directory=Path{path='/metadaddy-synology', type=[directory, volume]}}}
2023-06-06 12:57:38,401 [Thread-109] DEBUG ch.cyberduck.core.threading.AbstractBackgroundAction - Prepare background task WorkerBackgroundAction{worker=SessionListWorker{directory=Path{path='/metadaddy-synology', type=[directory, volume]}}}
2023-06-06 12:57:38,402 [Thread-109] DEBUG ch.cyberduck.core.AbstractController - Start action WorkerBackgroundAction{worker=SessionListWorker{directory=Path{path='/metadaddy-synology', type=[directory, volume]}}}
2023-06-06 12:57:38,402 [Thread-109] DEBUG ch.cyberduck.core.threading.BackgroundCallable - Call background action WorkerBackgroundAction{worker=SessionListWorker{directory=Path{path='/metadaddy-synology', type=[directory, volume]}}}
2023-06-06 12:57:38,402 [Thread-109] DEBUG ch.cyberduck.core.Session - Add listener ch.cyberduck.ui.cocoa.controller.BrowserController@75753427
2023-06-06 12:57:38,402 [Thread-109] DEBUG ch.cyberduck.core.LoginConnectionService - Skip opening connection for session Session{host=Host{protocol=Profile{parent=b2, vendor=iterate GmbH, description=Backblaze B2 Cloud Storage, image=Local{path='/var/folders/ms/57rpbl_x5q91l6b9ng1kv8bm0000gq/T/ch.sudo.cyberduck/36ef7c4f-4f4a-4515-9937-8196297f6e6e/GKCOxNYu'}}, region='null', port=443, hostname='api.backblazeb2.com', credentials=Credentials{user='00415f935cf4dcb0000000046', oauth='OAuthTokens{accessToken='', refreshToken='', expiryInMilliseconds=9223372036854775807}', token='', identity=null}, uuid='5409d56a-ace0-49a7-bca9-8382b49f7b4b', nickname='B2', defaultpath='/metadaddy-trino-getting-started/data_20220101_parquet', workdir=null, custom=null, labels=null}, state=open}
2023-06-06 12:57:38,402 [Thread-109] DEBUG ch.cyberduck.core.Session - Add listener WorkerBackgroundAction{worker=SessionListWorker{directory=Path{path='/metadaddy-synology', type=[directory, volume]}}}
2023-06-06 12:57:38,402 [Thread-109] DEBUG ch.cyberduck.core.threading.WorkerBackgroundAction - Run worker SessionListWorker{directory=Path{path='/metadaddy-synology', type=[directory, volume]}}
2023-06-06 12:57:38,402 [Thread-109] DEBUG ch.cyberduck.core.worker.SessionListWorker - Run with feature VaultRegistryListService{proxy=ch.cyberduck.core.b2.B2ListService@872d507}
2023-06-06 12:57:38,402 [Thread-109] DEBUG ch.cyberduck.core.b2.B2VersionIdProvider - Return version e1652f0973958cff74ed0c1b from attributes for file Path{path='/metadaddy-synology', type=[directory, volume]}
2023-06-06 12:57:38,402 [Thread-109] DEBUG ch.cyberduck.core.b2.B2ObjectListService - List directory Path{path='/metadaddy-synology', type=[directory, volume]} with marker Marker{nextFilename='', nextFileId='null'}
2023-06-06 12:57:38,402 [Thread-109] DEBUG synapticloop.b2.request.BaseB2Request - Setting key 'startFileName' to value ''
2023-06-06 12:57:38,402 [Thread-109] DEBUG synapticloop.b2.request.BaseB2Request - Setting key 'prefix' to value ''
2023-06-06 12:57:38,402 [Thread-109] DEBUG synapticloop.b2.request.BaseB2Request - Setting key 'delimiter' to value '/'
2023-06-06 12:57:38,402 [Thread-109] DEBUG synapticloop.b2.request.BaseB2Request - Setting key 'maxFileCount' to value '1000'
2023-06-06 12:57:38,402 [Thread-109] DEBUG synapticloop.b2.request.BaseB2Request - Setting key 'bucketId' to value 'e1652f0973958cff74ed0c1b'
2023-06-06 12:57:38,402 [Thread-109] DEBUG synapticloop.b2.request.BaseB2Request - POST request to URL 'https://api004.backblazeb2.com/b2api/v2/b2_list_file_versions'
2023-06-06 12:57:38,402 [Thread-109] DEBUG org.apache.http.client.protocol.RequestAddCookies - CookieSpec selected: default
2023-06-06 12:57:38,402 [Thread-109] DEBUG org.apache.http.client.protocol.RequestAuthCache - Auth cache not set in the context
2023-06-06 12:57:38,402 [Thread-109] DEBUG org.apache.http.impl.conn.PoolingHttpClientConnectionManager - Connection request: [route: {s}->https://api004.backblazeb2.com:443][total available: 2; route allocated: 1 of 10; total allocated: 2 of 2147483647]
2023-06-06 12:57:38,403 [Thread-109] DEBUG org.apache.http.impl.conn.CPool - Connection [id:15][route:{s}->https://api004.backblazeb2.com:443][state:null] expired @ Tue Jun 06 12:46:59 PDT 2023
2023-06-06 12:57:38,403 [Thread-109] DEBUG org.apache.http.impl.conn.DefaultManagedHttpClientConnection - http-outgoing-15: Close connection
2023-06-06 12:57:38,403 [Thread-109] DEBUG org.apache.http.impl.conn.PoolingHttpClientConnectionManager - Connection leased: [id: 21][route: {s}->https://api004.backblazeb2.com:443][total available: 1; route allocated: 1 of 10; total allocated: 2 of 2147483647]
2023-06-06 12:57:38,403 [Thread-109] DEBUG org.apache.http.impl.execchain.MainClientExec - Opening connection {s}->https://api004.backblazeb2.com:443
2023-06-06 12:57:38,405 [Thread-109] INFO  ch.cyberduck.core.proxy.SystemConfigurationProxy - No proxy configuration found for target https://api.backblazeb2.com
2023-06-06 12:57:38,405 [Thread-109] INFO  ch.cyberduck.core.socket.DefaultSocketConfigurator - Set timeout to 30000ms for socket Socket[unconnected]
2023-06-06 12:57:38,405 [Thread-109] DEBUG org.apache.http.impl.conn.DefaultHttpClientConnectionOperator - Connecting to api004.backblazeb2.com/149.137.128.15:443
2023-06-06 12:57:38,405 [Thread-109] DEBUG ch.cyberduck.core.http.HttpConnectionPoolBuilder$2 - Connecting socket to api004.backblazeb2.com/149.137.128.15:443 with timeout 30000
2023-06-06 12:57:38,435 [Thread-109] DEBUG ch.cyberduck.core.ssl.CustomTrustSSLProtocolSocketFactory - Configure SSL parameters with protocols [TLSv1.3, TLSv1.2, TLSv1.1, TLSv1]
2023-06-06 12:57:38,435 [Thread-109] INFO  ch.cyberduck.core.ssl.CustomTrustSSLProtocolSocketFactory - Enabled cipher suites [TLS_AES_256_GCM_SHA384, TLS_AES_128_GCM_SHA256, TLS_CHACHA20_POLY1305_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_GCM_SHA384, TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
2023-06-06 12:57:38,435 [Thread-109] DEBUG ch.cyberduck.core.ssl.CustomTrustSSLProtocolSocketFactory - Handshake for socket SSLSocket[hostname=api004.backblazeb2.com, port=443, Session(1686081458435|SSL_NULL_WITH_NULL_NULL)]
2023-06-06 12:57:38,436 [Thread-109] DEBUG ch.cyberduck.core.http.HttpConnectionPoolBuilder$2 - Enabled protocols: [TLSv1.3, TLSv1.2, TLSv1.1, TLSv1]
2023-06-06 12:57:38,436 [Thread-109] DEBUG ch.cyberduck.core.http.HttpConnectionPoolBuilder$2 - Enabled cipher suites:[TLS_AES_256_GCM_SHA384, TLS_AES_128_GCM_SHA256, TLS_CHACHA20_POLY1305_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_GCM_SHA384, TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
2023-06-06 12:57:38,436 [Thread-109] DEBUG ch.cyberduck.core.http.HttpConnectionPoolBuilder$2 - Starting handshake
2023-06-06 12:57:38,486 [Thread-109] INFO  ch.cyberduck.core.ssl.CertificateStoreX509TrustManager - Certificate for api004.backblazeb2.com previously trusted
2023-06-06 12:57:38,488 [Thread-109] DEBUG ch.cyberduck.core.http.HttpConnectionPoolBuilder$2 - Secure session established
2023-06-06 12:57:38,488 [Thread-109] DEBUG ch.cyberduck.core.http.HttpConnectionPoolBuilder$2 -  negotiated protocol: TLSv1.3
2023-06-06 12:57:38,489 [Thread-109] DEBUG ch.cyberduck.core.http.HttpConnectionPoolBuilder$2 -  negotiated cipher suite: TLS_AES_128_GCM_SHA256
2023-06-06 12:57:38,489 [Thread-109] DEBUG ch.cyberduck.core.http.HttpConnectionPoolBuilder$2 -  peer principal: CN=backblazeb2.com
2023-06-06 12:57:38,489 [Thread-109] DEBUG ch.cyberduck.core.http.HttpConnectionPoolBuilder$2 -  peer alternative names: [*.backblazeb2.com, *.s3.eu-central-003.backblazeb2.com, *.s3.us-east-005.backblazeb2.com, *.s3.us-west-000.backblazeb2.com, *.s3.us-west-001.backblazeb2.com, *.s3.us-west-002.backblazeb2.com, *.s3.us-west-004.backblazeb2.com, backblazeb2.com, s3.eu-central-003.backblazeb2.com, s3.us-east-005.backblazeb2.com, s3.us-west-000.backblazeb2.com, s3.us-west-001.backblazeb2.com, s3.us-west-002.backblazeb2.com, s3.us-west-004.backblazeb2.com]
2023-06-06 12:57:38,489 [Thread-109] DEBUG ch.cyberduck.core.http.HttpConnectionPoolBuilder$2 -  issuer principal: CN=R3, O=Let's Encrypt, C=US
2023-06-06 12:57:38,489 [Thread-109] DEBUG ch.cyberduck.core.http.DisabledX509HostnameVerifier - Hostname verification disabled for api004.backblazeb2.com handled in system trust manager
2023-06-06 12:57:38,489 [Thread-109] DEBUG org.apache.http.impl.conn.DefaultHttpClientConnectionOperator - Connection established 192.168.69.12:52301<->149.137.128.15:443
2023-06-06 12:57:38,489 [Thread-109] DEBUG org.apache.http.impl.conn.DefaultManagedHttpClientConnection - http-outgoing-21: set socket timeout to 30000
2023-06-06 12:57:38,489 [Thread-109] DEBUG org.apache.http.impl.execchain.MainClientExec - Executing request POST /b2api/v2/b2_list_file_versions HTTP/1.1
2023-06-06 12:57:38,489 [Thread-109] DEBUG org.apache.http.impl.execchain.MainClientExec - Proxy auth state: UNCHALLENGED
2023-06-06 12:57:38,489 [Thread-109] INFO  ch.cyberduck.transcript.request - POST /b2api/v2/b2_list_file_versions HTTP/1.1
2023-06-06 12:57:38,489 [Thread-109] INFO  ch.cyberduck.transcript.request - Content-Length: 106
2023-06-06 12:57:38,489 [Thread-109] INFO  ch.cyberduck.transcript.request - Content-Type: application/json; charset=UTF-8
2023-06-06 12:57:38,489 [Thread-109] INFO  ch.cyberduck.transcript.request - Host: api004.backblazeb2.com
2023-06-06 12:57:38,489 [Thread-109] INFO  ch.cyberduck.transcript.request - Connection: Keep-Alive
2023-06-06 12:57:38,489 [Thread-109] INFO  ch.cyberduck.transcript.request - User-Agent: Cyberduck/8.6.0.39818 (Mac OS X/13.4) (aarch64)
2023-06-06 12:57:38,489 [Thread-109] INFO  ch.cyberduck.transcript.request - Accept-Encoding: gzip,deflate
2023-06-06 12:57:38,489 [Thread-109] INFO  ch.cyberduck.transcript.request - Authorization: ********
2023-06-06 12:57:38,554 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - No cached image for eject.pdf
2023-06-06 12:57:38,555 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - Return default size for eject.pdf
2023-06-06 12:57:38,557 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - No cached image for eject.pdf
2023-06-06 12:57:38,557 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - Return default size for eject.pdf
2023-06-06 12:57:38,559 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - No cached image for transferstop.pdf
2023-06-06 12:57:38,559 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - Return default size for transferstop.pdf
2023-06-06 12:57:38,560 [main] DEBUG org.rococoa.callback - No method _sidebarTrackingAdapter for selector:_sidebarTrackingAdapter
2023-06-06 12:57:38,563 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - No cached image for eject.pdf
2023-06-06 12:57:38,563 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - Return default size for eject.pdf
2023-06-06 12:57:38,619 [Thread-109] INFO  ch.cyberduck.transcript.response - HTTP/1.1 200 
2023-06-06 12:57:38,620 [Thread-109] INFO  ch.cyberduck.transcript.response - Cache-Control: max-age=0, no-cache, no-store
2023-06-06 12:57:38,620 [Thread-109] INFO  ch.cyberduck.transcript.response - Content-Type: application/json;charset=UTF-8
2023-06-06 12:57:38,620 [Thread-109] INFO  ch.cyberduck.transcript.response - Content-Length: 401
2023-06-06 12:57:38,620 [Thread-109] INFO  ch.cyberduck.transcript.response - Date: Tue, 06 Jun 2023 19:57:38 GMT
2023-06-06 12:57:38,620 [Thread-109] INFO  ch.cyberduck.transcript.response - Keep-Alive: timeout=5
2023-06-06 12:57:38,620 [Thread-109] INFO  ch.cyberduck.transcript.response - Connection: keep-alive
2023-06-06 12:57:38,620 [Thread-109] DEBUG org.apache.http.impl.execchain.MainClientExec - Connection can be kept alive for 5000 MILLISECONDS
2023-06-06 12:57:38,620 [Thread-109] DEBUG synapticloop.b2.request.BaseB2Request - Received status code of: 200, for POST request to url 'https://api004.backblazeb2.com/b2api/v2/b2_list_file_versions'
2023-06-06 12:57:38,621 [Thread-109] DEBUG org.apache.http.impl.conn.PoolingHttpClientConnectionManager - Connection [id: 21][route: {s}->https://api004.backblazeb2.com:443] can be kept alive for 5.0 seconds
2023-06-06 12:57:38,621 [Thread-109] DEBUG org.apache.http.impl.conn.DefaultManagedHttpClientConnection - http-outgoing-21: set socket timeout to 0
2023-06-06 12:57:38,621 [Thread-109] DEBUG org.apache.http.impl.conn.PoolingHttpClientConnectionManager - Connection released: [id: 21][route: {s}->https://api004.backblazeb2.com:443][total available: 2; route allocated: 1 of 10; total allocated: 2 of 2147483647]
2023-06-06 12:57:38,621 [Thread-109] WARN  synapticloop.b2.response.B2ListFilesResponse - No field for key accountId
2023-06-06 12:57:38,621 [Thread-109] WARN  synapticloop.b2.response.B2ListFilesResponse - No field for key bucketId
2023-06-06 12:57:38,621 [Thread-109] WARN  synapticloop.b2.response.B2ListFilesResponse - No field for key nextFileName
2023-06-06 12:57:38,621 [Thread-109] WARN  synapticloop.b2.response.B2ListFilesResponse - No field for key nextFileId
2023-06-06 12:57:38,621 [Thread-109] WARN  synapticloop.b2.response.B2FileInfoResponse - No field for key fileId
2023-06-06 12:57:38,621 [Thread-109] WARN  synapticloop.b2.response.B2FileInfoResponse - No field for key contentType
2023-06-06 12:57:38,621 [Thread-109] WARN  synapticloop.b2.response.B2FileInfoResponse - No field for key contentSha1
2023-06-06 12:57:38,621 [Thread-109] WARN  synapticloop.b2.response.B2FileInfoResponse - Unknown action value folder
2023-06-06 12:57:38,621 [Thread-109] WARN  synapticloop.b2.response.B2FileInfoResponse - No field for key size
2023-06-06 12:57:38,621 [Thread-109] WARN  synapticloop.b2.response.B2FileInfoResponse - Found an unexpected key of 'contentMd5' in JSON that is not mapped to a field, with value 'null'.
2023-06-06 12:57:38,621 [Thread-109] DEBUG ch.cyberduck.core.b2.B2VersionIdProvider - Return version e1652f0973958cff74ed0c1b from attributes for file Path{path='/metadaddy-synology', type=[directory, volume]}
2023-06-06 12:57:38,622 [Thread-109] DEBUG synapticloop.b2.request.BaseB2Request - Setting key 'startFileName' to value 'DS920plus_1.hbk/.bzEmpty'
2023-06-06 12:57:38,622 [Thread-109] DEBUG synapticloop.b2.request.BaseB2Request - Setting key 'maxFileCount' to value '1'
2023-06-06 12:57:38,622 [Thread-109] DEBUG synapticloop.b2.request.BaseB2Request - Setting key 'bucketId' to value 'e1652f0973958cff74ed0c1b'
2023-06-06 12:57:38,622 [Thread-109] DEBUG synapticloop.b2.request.BaseB2Request - POST request to URL 'https://api004.backblazeb2.com/b2api/v2/b2_list_file_names'
2023-06-06 12:57:38,622 [Thread-109] DEBUG org.apache.http.client.protocol.RequestAddCookies - CookieSpec selected: default
2023-06-06 12:57:38,622 [Thread-109] DEBUG org.apache.http.client.protocol.RequestAuthCache - Auth cache not set in the context
2023-06-06 12:57:38,622 [Thread-109] DEBUG org.apache.http.impl.conn.PoolingHttpClientConnectionManager - Connection request: [route: {s}->https://api004.backblazeb2.com:443][total available: 2; route allocated: 1 of 10; total allocated: 2 of 2147483647]
2023-06-06 12:57:38,622 [Thread-109] DEBUG org.apache.http.impl.conn.PoolingHttpClientConnectionManager - Connection leased: [id: 21][route: {s}->https://api004.backblazeb2.com:443][total available: 1; route allocated: 1 of 10; total allocated: 2 of 2147483647]
2023-06-06 12:57:38,622 [Thread-109] DEBUG org.apache.http.impl.conn.DefaultManagedHttpClientConnection - http-outgoing-21: set socket timeout to 0
2023-06-06 12:57:38,622 [Thread-109] DEBUG org.apache.http.impl.conn.DefaultManagedHttpClientConnection - http-outgoing-21: set socket timeout to 30000
2023-06-06 12:57:38,622 [Thread-109] DEBUG org.apache.http.impl.execchain.MainClientExec - Executing request POST /b2api/v2/b2_list_file_names HTTP/1.1
2023-06-06 12:57:38,622 [Thread-109] DEBUG org.apache.http.impl.execchain.MainClientExec - Proxy auth state: UNCHALLENGED
2023-06-06 12:57:38,622 [Thread-109] INFO  ch.cyberduck.transcript.request - POST /b2api/v2/b2_list_file_names HTTP/1.1
2023-06-06 12:57:38,622 [Thread-109] INFO  ch.cyberduck.transcript.request - Content-Length: 99
2023-06-06 12:57:38,622 [Thread-109] INFO  ch.cyberduck.transcript.request - Content-Type: application/json; charset=UTF-8
2023-06-06 12:57:38,622 [Thread-109] INFO  ch.cyberduck.transcript.request - Host: api004.backblazeb2.com
2023-06-06 12:57:38,622 [Thread-109] INFO  ch.cyberduck.transcript.request - Connection: Keep-Alive
2023-06-06 12:57:38,622 [Thread-109] INFO  ch.cyberduck.transcript.request - User-Agent: Cyberduck/8.6.0.39818 (Mac OS X/13.4) (aarch64)
2023-06-06 12:57:38,623 [Thread-109] INFO  ch.cyberduck.transcript.request - Accept-Encoding: gzip,deflate
2023-06-06 12:57:38,623 [Thread-109] INFO  ch.cyberduck.transcript.request - Authorization: ********
2023-06-06 12:57:38,653 [Thread-109] INFO  ch.cyberduck.transcript.response - HTTP/1.1 200 
2023-06-06 12:57:38,653 [Thread-109] INFO  ch.cyberduck.transcript.response - Cache-Control: max-age=0, no-cache, no-store
2023-06-06 12:57:38,653 [Thread-109] INFO  ch.cyberduck.transcript.response - Content-Type: application/json;charset=UTF-8
2023-06-06 12:57:38,653 [Thread-109] INFO  ch.cyberduck.transcript.response - Content-Length: 1005
2023-06-06 12:57:38,653 [Thread-109] INFO  ch.cyberduck.transcript.response - Date: Tue, 06 Jun 2023 19:57:38 GMT
2023-06-06 12:57:38,653 [Thread-109] INFO  ch.cyberduck.transcript.response - Keep-Alive: timeout=5
2023-06-06 12:57:38,654 [Thread-109] INFO  ch.cyberduck.transcript.response - Connection: keep-alive
2023-06-06 12:57:38,654 [Thread-109] DEBUG org.apache.http.impl.execchain.MainClientExec - Connection can be kept alive for 5000 MILLISECONDS
2023-06-06 12:57:38,654 [Thread-109] DEBUG synapticloop.b2.request.BaseB2Request - Received status code of: 200, for POST request to url 'https://api004.backblazeb2.com/b2api/v2/b2_list_file_names'
2023-06-06 12:57:38,654 [Thread-109] DEBUG org.apache.http.impl.conn.PoolingHttpClientConnectionManager - Connection [id: 21][route: {s}->https://api004.backblazeb2.com:443] can be kept alive for 5.0 seconds
2023-06-06 12:57:38,654 [Thread-109] DEBUG org.apache.http.impl.conn.DefaultManagedHttpClientConnection - http-outgoing-21: set socket timeout to 0
2023-06-06 12:57:38,654 [Thread-109] DEBUG org.apache.http.impl.conn.PoolingHttpClientConnectionManager - Connection released: [id: 21][route: {s}->https://api004.backblazeb2.com:443][total available: 2; route allocated: 1 of 10; total allocated: 2 of 2147483647]
2023-06-06 12:57:38,655 [Thread-109] WARN  synapticloop.b2.response.B2ListFilesResponse - No field for key accountId
2023-06-06 12:57:38,655 [Thread-109] WARN  synapticloop.b2.response.B2ListFilesResponse - No field for key bucketId
2023-06-06 12:57:38,655 [Thread-109] WARN  synapticloop.b2.response.B2ListFilesResponse - No field for key nextFileId
2023-06-06 12:57:38,655 [Thread-109] WARN  synapticloop.b2.response.B2FileInfoResponse - No field for key size
2023-06-06 12:57:38,655 [Thread-109] WARN  synapticloop.b2.response.B2FileInfoResponse - Found an unexpected key of 'contentMd5' in JSON that is not mapped to a field, with value 'f44436c3ee4c4cdb8ea981e481268329'.
2023-06-06 12:57:38,655 [Thread-109] WARN  synapticloop.b2.response.B2FileInfoResponse - Found an unexpected key of 'serverSideEncryption' in JSON that is not mapped to a field, with value '{"mode":null,"algorithm":null}'.
2023-06-06 12:57:38,655 [Thread-109] WARN  synapticloop.b2.response.B2FileInfoResponse - Found an unexpected key of 'legalHold' in JSON that is not mapped to a field, with value '{"isClientAuthorizedToRead":true,"value":null}'.
2023-06-06 12:57:38,655 [Thread-109] WARN  synapticloop.b2.response.B2FileInfoResponse - Found an unexpected key of 'fileRetention' in JSON that is not mapped to a field, with value '{"isClientAuthorizedToRead":true,"value":{"mode":null,"retainUntilTimestamp":null}}'.
2023-06-06 12:57:38,655 [Thread-109] INFO  ch.cyberduck.core.worker.SessionListWorker - Retrieved chunk of 1 items in Path{path='/metadaddy-synology', type=[directory, volume]}
2023-06-06 12:57:38,655 [Thread-109] DEBUG ch.cyberduck.core.threading.BackgroundCallable - Return result ch.cyberduck.core.AttributedList@fd2ba045 from background action WorkerBackgroundAction{worker=SessionListWorker{directory=Path{path='/metadaddy-synology', type=[directory, volume]}}}
2023-06-06 12:57:38,655 [Thread-109] DEBUG ch.cyberduck.core.threading.AbstractBackgroundAction - Finish background task WorkerBackgroundAction{worker=SessionListWorker{directory=Path{path='/metadaddy-synology', type=[directory, volume]}}}
2023-06-06 12:57:38,655 [Thread-109] DEBUG ch.cyberduck.core.threading.BackgroundActionRegistry - Remove action WorkerBackgroundAction{worker=SessionListWorker{directory=Path{path='/metadaddy-synology', type=[directory, volume]}}}
2023-06-06 12:57:38,655 [Thread-109] DEBUG ch.cyberduck.core.threading.BackgroundActionRegistry - Remove action WorkerBackgroundAction{worker=SessionListWorker{directory=Path{path='/metadaddy-synology', type=[directory, volume]}}}
2023-06-06 12:57:38,657 [Thread-109] DEBUG ch.cyberduck.core.AbstractController - Stop action WorkerBackgroundAction{worker=SessionListWorker{directory=Path{path='/metadaddy-synology', type=[directory, volume]}}}
2023-06-06 12:57:38,657 [Thread-109] DEBUG ch.cyberduck.core.threading.BackgroundCallable - Invoke cleanup for background action WorkerBackgroundAction{worker=SessionListWorker{directory=Path{path='/metadaddy-synology', type=[directory, volume]}}}
2023-06-06 12:57:38,657 [main] DEBUG ch.cyberduck.core.threading.WorkerBackgroundAction - Cleanup worker SessionListWorker{directory=Path{path='/metadaddy-synology', type=[directory, volume]}}
2023-06-06 12:57:38,658 [main] DEBUG ch.cyberduck.core.AbstractCache - Caching Path{path='/metadaddy-synology', type=[directory, volume]}
2023-06-06 12:57:38,658 [Thread-109] DEBUG ch.cyberduck.core.threading.BackgroundCallable - Releasing lock for background runnable WorkerBackgroundAction{worker=SessionListWorker{directory=Path{path='/metadaddy-synology', type=[directory, volume]}}}
2023-06-06 12:57:38,658 [Thread-109] DEBUG org.rococoa - Draining autorelease pool
2023-06-06 12:57:38,659 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - No cached image for /var/folders/ms/57rpbl_x5q91l6b9ng1kv8bm0000gq/T/ch.sudo.cyberduck/36ef7c4f-4f4a-4515-9937-8196297f6e6e/GKCOxNYu
2023-06-06 12:57:38,660 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - No cached image for /var/folders/ms/57rpbl_x5q91l6b9ng1kv8bm0000gq/T/ch.sudo.cyberduck/36ef7c4f-4f4a-4515-9937-8196297f6e6e/GKCOxNYu
2023-06-06 12:57:38,661 [main] DEBUG ch.cyberduck.ui.cocoa.datasource.BrowserOutlineViewDataSource - Reload table view <CDOutlineView: 0x12103c800> for changes files [Path{path='/metadaddy-synology', type=[directory, volume]}]
2023-06-06 12:57:38,662 [main] DEBUG ch.cyberduck.core.AttributedList - Sort list ch.cyberduck.core.AttributedList@fd2ba045 with comparator ch.cyberduck.ui.comparator.TimestampComparator@3e
2023-06-06 12:57:38,662 [main] DEBUG ch.cyberduck.core.AttributedList - Filter list ch.cyberduck.core.AttributedList@fd2ba045 with filter RegexFilter{pattern=\..*}
2023-06-06 12:57:38,662 [main] DEBUG ch.cyberduck.binding.Proxy - Already on main thread. Invoke ch.cyberduck.ui.cocoa.controller.BrowserController$15@5a06904 directly.
2023-06-06 12:57:38,662 [main] DEBUG ch.cyberduck.binding.Proxy - Already on main thread. Invoke ch.cyberduck.ui.cocoa.controller.BrowserController$15@fabef2e directly.
2023-06-06 12:57:41,954 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - No cached image for eject.pdf
2023-06-06 12:57:41,954 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - Return default size for eject.pdf
2023-06-06 12:57:41,956 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - No cached image for eject.pdf
2023-06-06 12:57:41,956 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - Return default size for eject.pdf
2023-06-06 12:57:41,958 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - No cached image for eject.pdf
2023-06-06 12:57:41,958 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - Return default size for eject.pdf
2023-06-06 12:57:41,959 [main] DEBUG org.rococoa.callback - No method _sidebarTrackingAdapter for selector:_sidebarTrackingAdapter
2023-06-06 12:57:41,962 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - No cached image for eject.pdf
2023-06-06 12:57:41,962 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - Return default size for eject.pdf
2023-06-06 12:57:43,533 [main] DEBUG ch.cyberduck.binding.application.NSApplication - NSConcreteNotification 0x6000004a5680 {name = NSApplicationWillResignActiveNotification; object = <NSApplication: 0x104e0f560>}
2023-06-06 12:57:43,534 [main] DEBUG ch.cyberduck.binding.WindowController - Resign key for window <NSWindow: 0x104e4c370>
2023-06-06 12:57:43,534 [main] DEBUG ch.cyberduck.binding.WindowController - Resign main for window <NSWindow: 0x104e4c370>
2023-06-06 12:57:43,536 [main] DEBUG ch.cyberduck.binding.application.NSApplication - NSConcreteNotification 0x6000004bea00 {name = NSApplicationDidResignActiveNotification; object = <NSApplication: 0x104e0f560>}
2023-06-06 12:57:43,542 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - No cached image for eject.pdf
2023-06-06 12:57:43,542 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - Return default size for eject.pdf
2023-06-06 12:57:43,637 [main] DEBUG org.rococoa.callback - No method applicationSupportsSecureRestorableState for selector:applicationSupportsSecureRestorableState:
2023-06-06 12:57:43,708 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - No cached image for eject.pdf
2023-06-06 12:57:43,708 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - Return default size for eject.pdf
2023-06-06 12:57:43,710 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - No cached image for eject.pdf
2023-06-06 12:57:43,711 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - Return default size for eject.pdf
2023-06-06 12:57:43,714 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - No cached image for eject.pdf
2023-06-06 12:57:43,714 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - Return default size for eject.pdf
2023-06-06 12:57:43,716 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - No cached image for eject.pdf
2023-06-06 12:57:43,716 [main] DEBUG ch.cyberduck.core.resources.NSImageIconCache - Return default size for eject.pdf

Additional context
This bug seems to have been introduced with 8287d23 or c8bf429. Tracing through the code, the issue is in this section of code in B2ObjectListService.parse:

            if(StringUtils.isBlank(info.getFileId())) {
                // Common prefix
                final Path placeholder = new Path(directory.isDirectory() ? directory : directory.getParent(),
                        PathNormalizer.name(StringUtils.chomp(info.getFileName(), String.valueOf(Path.DELIMITER))),
                        EnumSet.of(Path.Type.directory, Path.Type.placeholder));
                // Read .bzEmpty
                try {
                    placeholder.withAttributes(attr.find(placeholder, new DisabledListProgressListener()));
                }
                catch(NotfoundException e) {
                    // No placeholder object or hidden flag set
                    placeholder.attributes().setDuplicate(true);
                }
                objects.add(placeholder);
                continue;
            }

As evidenced by the comment, this code assumes that .bzEmpty will be present. The attr.find() call ends up calling B2VersionIdProvider.getVersionId(), which, correctly, throws NotfoundException, since /my-bucket/folder does not have a fileId. The code interprets this as meaning that it has found .bzEmpty, and sets the duplicate flag on /my-bucket/folder.

Note - I'm not sure that it's possible to successfully implement #14431 . Consider a bucket with millions of objects with keys of the form folder00000001/foo, folder00000002/foo, folder00000003/foo, etc. This is not a particularly contrived example - analytical data can have this kind of structure. Every 'folder name' will need to be inspected, via a B2 API call, to determine whether it should be shown.

@dkocher dkocher added the b2 Backblaze B2 Protocol Implementation label Jun 7, 2023
@dkocher dkocher changed the title Backblaze B2 connector does not show 'folders' that do not contain a .bzEmpty object Does not show 'folders' that do not contain a .bzEmpty object Jun 7, 2023
@dkocher
Copy link
Contributor

dkocher commented Jun 7, 2023

@metadaddy Thanks for your thorough analysis of the issue. Previously discussed in #14759.

@dkocher
Copy link
Contributor

dkocher commented Jun 11, 2023

@metadaddy To give you some context on the changeset in #14431 and what it is trying to solve. We are using this client implementation in Mountain Duck working with B2 as a filesystem. Thus it must be possible to delete folders aka directory placeholder files and these should no longer appear in directory listings. Otherwise it is impossible for users to delete folders when making us of b2_hide_file which was introduced with #13265.

@metadaddy
Copy link
Author

metadaddy commented Jun 13, 2023

@dkocher b2_list_file_names will give you the list of visible files, including .bzEmpty placeholders. A prefix will not appear in the results unless it is part of a visible file's name.

If I "create a folder" in an empty bucket using the web UI or by uploading the zero length placeholder, then b2_list_file_names will return me a single result:

{
  "files": [
    {
      "accountId": "...",
      "action": "upload",
      "bucketId": "...",
      "contentLength": 0,
      "fileId": "4_z0145cfc9e3f5ec0f74ed0c1b_f404ce2fe0a91f670_d20230613_m015603_c004_v0402018_t0038_u01686621363510",
      "fileName": "testfolder/.bzEmpty",
      ...
    },
  ],
  "nextFileName": null
}

If I now "upload a file into the folder", b2_list_file_names returns two results:

{
  "files": [
    {
      "accountId": "...",
      "action": "upload",
      "bucketId": "...",
      "contentLength": 0,
      "fileId": "4_z0145cfc9e3f5ec0f74ed0c1b_f404ce2fe0a91f670_d20230613_m015603_c004_v0402018_t0038_u01686621363510",
      "fileName": "testfolder/.bzEmpty",
      ...
    },
    {
      "accountId": "...",
      "action": "upload",
      "bucketId": "...",
      "fileId": "4_z0145cfc9e3f5ec0f74ed0c1b_f110de288a449bf16_d20230613_m020029_c004_v0402017_t0058_u01686621629033",
      "fileName": "testfolder/data.csv",
      ...
    },
  ],
  "nextFileName": null
}

If I now hide the files, b2_list_file_names doesn't return anything:

{
  "files": [],
  "nextFileName": null
}

So, you can get exactly the file tree that you want from the output of b2_list_file_names by including all prefixes (based on the / delimiter) from the list and removing any items with the suffix /.bzEmpty (you already gathered the "folder name" for each one). You can also consider one level of the tree at a time by using the prefix and delimiter

You could also use b2_list_file_versions, which will return the hidden files and hide markers.

{
  "files": [
    {
      "accountId": "...",
      "action": "hide",
      "bucketId": "...",
      "contentLength": 0,
      "fileId": "4_z0145cfc9e3f5ec0f74ed0c1b_f4104e52bfe48aa99_d20230613_m020319_c004_v0402006_t0025_u01686621799026",
      "fileName": "testfolder/.bzEmpty",
      ...
    },
    {
      "accountId": "...",
      "action": "upload",
      "bucketId": "...",
      "contentLength": 0,
      "fileId": "4_z0145cfc9e3f5ec0f74ed0c1b_f404ce2fe0a91f670_d20230613_m015603_c004_v0402018_t0038_u01686621363510",
      "fileName": "testfolder/.bzEmpty",
      ...
    },
    {
      "accountId": "...",
      "action": "hide",
      "bucketId": "...",
      "contentLength": 0,
      "fileId": "4_z0145cfc9e3f5ec0f74ed0c1b_f41848b64ec7f090e_d20230613_m020311_c004_v0402017_t0000_u01686621791337",
      "fileName": "testfolder/data.csv",
      ...
    },
    {
      "accountId": "...",
      "action": "upload",
      "bucketId": "...",
      "contentLength": 766,
      "fileId": "4_z0145cfc9e3f5ec0f74ed0c1b_f110de288a449bf16_d20230613_m020029_c004_v0402017_t0058_u01686621629033",
      "fileName": "testfolder/data.csv",
      ...
    },
  ],
  "nextFileId": null,
  "nextFileName": null
}

Note that the results are ordered "by reverse of date/time uploaded for versions of files with the same name", so it's easy to build the desired tree, with similar logic.

Bottom line - the B2 APIs give you everything you need to implement your desired functionality, without hiding "folders" that don't contain a .bzEmpty file, and without making an API call per file.

@dkocher
Copy link
Contributor

dkocher commented Jun 13, 2023

@metadaddy We make use of the b2_list_file_versions API where prefixes are always returned regardless if all containing files are hidden. When working on a single level in the hierarchy I don't see a way to achieve the described result (hiding prefixes only containing hidden files) with a single API call.

@metadaddy
Copy link
Author

metadaddy commented Jun 14, 2023

@dkocher I don't think there is a way to consider a level at a time (in a bounded amount of time). For each "folder", you have to examine all of its "descendants" to determine whether that folder should be hidden, so, to list the entries in a bucket's "root folder", you have to examine all objects in the bucket.

b2_list_file_versions can return up to 1,000 entries at a time. If we assume 0.25 seconds per API call, we can calculate the time required to retrieve the data by number of files (technically file versions) in the bucket:

  • < 1000 files: 0.25 s
  • 10,000 files: 2.5 s
  • 100,000 files: 25 s
  • 1,000,000 files: > 4 minutes

Buckets with 100k+ files are quite common - the bucket with my Synology NAS backup contains just 4 TB of data, but nearly 200k files.

@dkocher
Copy link
Contributor

dkocher commented Jun 14, 2023

I don't consider working with the API with no delimiter parameter as an option performance wise.

dkocher added a commit that referenced this issue Jul 7, 2023
dkocher added a commit that referenced this issue Jul 7, 2023
dkocher added a commit that referenced this issue Jul 7, 2023
Revert looking up directory placeholder file
SheromS pushed a commit to SheromS/cyberduck that referenced this issue Jul 8, 2023
IsmCadi pushed a commit to SheromS/cyberduck that referenced this issue Jul 11, 2023
@dkocher dkocher added this to the 8.6.2 milestone Jul 16, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
b2 Backblaze B2 Protocol Implementation
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants