@@ -22,6 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
2222#define __XBCLOUD_AZURE_H__
2323
2424#include < iostream>
25+ #include < optional>
2526#include " object_store.h"
2627#include " xbcloud/http.h"
2728#include " xbcloud/util.h"
@@ -93,6 +94,8 @@ class Azure_client {
9394 ulong max_retries;
9495 ulong max_backoff;
9596
97+ std::optional<bool > hns_enabled;
98+
9699 static void upload_callback (Azure_client *client, std::string container,
97100 std::string name, Http_request *req,
98101 Http_response *resp,
@@ -171,6 +174,8 @@ class Azure_client {
171174 std::vector<std::string> &files,
172175 std::vector<std::string> &dirs);
173176
177+ bool is_hns_enabled ();
178+
174179 ulong get_max_retries () { return max_retries; }
175180
176181 ulong get_max_backoff () { return max_backoff; }
@@ -266,6 +271,20 @@ class Azure_object_store : public Object_store {
266271 return azure_client.list_objects_files_and_dirs (container, directory + " /" ,
267272 files, dirs);
268273 }
274+ // Strip leading slashes for HNS-enabled accounts.
275+ // Azure HNS silently normalizes blob paths by removing leading slashes,
276+ // so "/backup/chunk.00000" is stored as "backup/chunk.00000". Without
277+ // this, xbcloud's expected prefix no longer matches what the API returns.
278+ // Example: "/db/mybackup" -> "db/mybackup"
279+ // Flat accounts are unaffected — the name is returned as-is.
280+ std::string normalize_name (const std::string &name) override {
281+ if (azure_client.is_hns_enabled ()) {
282+ std::string result = name;
283+ ltrim_slashes (result);
284+ return result;
285+ }
286+ return name;
287+ }
269288};
270289} // namespace xbcloud
271290
0 commit comments