On 2025/9/9 18:28, ChengyuZhu6 wrote:
From: Chengyu Zhu <hudson...@tencent.com>

This commit implements recovery support for OCI-based NBD mounts,
allowing the system to properly reattach NBD devices after
NBD disconnection.

Signed-off-by: Chengyu Zhu <hudson...@tencent.com>
---
  lib/liberofs_oci.h |   5 ++
  lib/remotes/oci.c  | 129 +++++++++++++++++++++++++++++++++++++++++
  mount/main.c       | 141 ++++++++++++++++++++++++++++++++++++---------
  3 files changed, 247 insertions(+), 28 deletions(-)

diff --git a/lib/liberofs_oci.h b/lib/liberofs_oci.h
index 01a83aa..e910e6a 100644
--- a/lib/liberofs_oci.h
+++ b/lib/liberofs_oci.h
@@ -71,6 +71,11 @@ int ocierofs_build_trees(struct erofs_importer *importer,
                         const struct ocierofs_config *cfg);
  int ocierofs_io_open(struct erofs_vfile *vf, const struct ocierofs_config 
*cfg);
+int ocierofs_b64_encode_userpass(const char *username, const char *password,
+                                char **out_b64);
+int ocierofs_b64_decode_userpass(const char *b64,
+                                char **out_user, char **out_pass);
+
  #ifdef __cplusplus
  }
  #endif
diff --git a/lib/remotes/oci.c b/lib/remotes/oci.c
index de18daa..4e46e0b 100644
--- a/lib/remotes/oci.c
+++ b/lib/remotes/oci.c
@@ -1471,6 +1471,135 @@ int ocierofs_io_open(struct erofs_vfile *vfile, const 
struct ocierofs_config *cf
        *(struct ocierofs_iostream **)vfile->payload = oci_iostream;
        return 0;
  }
+
+static const char ocierofs_b64_tbl[] =
+       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+int ocierofs_b64_encode_userpass(const char *username, const char *password,
+                                char **out_b64)

I think ocierofs_encode_userpass() is enough.


+{
+       const unsigned char *in;
+       size_t ulen = username ? strlen(username) : 0;
+       size_t plen = password ? strlen(password) : 0;
+       size_t inlen = ulen + 1 + plen;
+       size_t outlen;
+       unsigned char *buf;
+       char *out;
+       size_t i, j;
+       unsigned int octet_a, octet_b, octet_c, triple;
+
+       if (!out_b64)
+               return -EINVAL;
+       *out_b64 = NULL;
+
+       buf = malloc(inlen + 1);
+       if (!buf)
+               return -ENOMEM;
+       memcpy(buf, username ? username : "", ulen);
+       buf[ulen] = ':';
+       memcpy(buf + ulen + 1, password ? password : "", plen);
+       buf[inlen] = '\0';
+       in = buf;
+
+       outlen = 4 * ((inlen + 2) / 3);
+       out = malloc(outlen + 1);
+       if (!out) {
+               free(buf);
+               return -ENOMEM;
+       }
+
+       for (i = 0, j = 0; i < inlen;) {
+               octet_a = i < inlen ? in[i++] : 0;
+               octet_b = i < inlen ? in[i++] : 0;
+               octet_c = i < inlen ? in[i++] : 0;
+               triple = (octet_a << 16) | (octet_b << 8) | octet_c;
+               out[j++] = ocierofs_b64_tbl[(triple >> 18) & 0x3F];
+               out[j++] = ocierofs_b64_tbl[(triple >> 12) & 0x3F];
+               out[j++] = (i - 1 > inlen) ? '=' : ocierofs_b64_tbl[(triple >> 6) 
& 0x3F];
+               out[j++] = (i > inlen) ? '=' : ocierofs_b64_tbl[triple & 0x3F];
+       }
+       if (inlen % 3 == 1) {
+               out[outlen - 1] = '=';
+               out[outlen - 2] = '=';
+       } else if (inlen % 3 == 2) {
+               out[outlen - 1] = '=';
+       }
+       out[outlen] = '\0';
+       free(buf);
+       *out_b64 = out;
+       return 0;
+}
+
+static int ocierofs_b64_inv(int c)
+{
+       if (c >= 'A' && c <= 'Z')
+               return c - 'A';
+       if (c >= 'a' && c <= 'z')
+               return c - 'a' + 26;
+       if (c >= '0' && c <= '9')
+               return c - '0' + 52;
+       if (c == '+')
+               return 62;
+       if (c == '/')
+               return 63;
+       return -1;
+}
+
+int ocierofs_b64_decode_userpass(const char *b64,
+                                char **out_user, char **out_pass)

same ocierofs_decode_userpass().


Also lib/tar.c already has base64_decode(), I wonder
if it's can be reused.


+{
+       size_t len, i, j;
+       unsigned char *out;
+       int val = 0, valb = -8, c;
+
+       if (!b64 || !out_user || !out_pass)
+               return -EINVAL;
+       *out_user = NULL;
+       *out_pass = NULL;
+
+       len = strlen(b64);
+       out = malloc(len * 3 / 4 + 1);
+       if (!out)
+               return -ENOMEM;
+
+       for (i = 0, j = 0; i < len; i++) {
+               c = b64[i];
+
+               if (c == '=')
+                       break;
+               c = ocierofs_b64_inv(c);
+               if (c < 0)
+                       continue;
+               val = (val << 6) + c;
+               valb += 6;
+               if (valb >= 0) {
+                       out[j++] = (unsigned char)((val >> valb) & 0xFF);
+                       valb -= 8;
+               }
+       }
+       out[j] = '\0';
+
+       {
+               char *colon = (char *)memchr(out, ':', j);
+
+               if (!colon) {
+                       free(out);
+                       return -EINVAL;
+               }
+               *colon = '\0';
+               *out_user = strdup((char *)out);
+               *out_pass = strdup(colon + 1);
+               free(out);
+               if (!*out_user || !*out_pass) {
+                       free(*out_user);
+                       free(*out_pass);
+                       *out_user = *out_pass = NULL;
+                       return -ENOMEM;
+               }
+       }
+       return 0;
+}
+
  #else
  int ocierofs_io_open(struct erofs_vfile *vfile, const struct ocierofs_config 
*cfg)
  {
diff --git a/mount/main.c b/mount/main.c
index c52ac3b..4fe54c5 100644
--- a/mount/main.c
+++ b/mount/main.c
@@ -401,10 +401,48 @@ out_closefd:
        return err;
  }
-static char *erofsmount_write_recovery_info(const char *source)
+static int erofsmount_write_recovery_oci(FILE *f, struct erofs_nbd_source 
*source)
+{
+       char *b64cred = NULL;
+       int ret;
+
+       if (source->ocicfg.username || source->ocicfg.password) {
+               ret = ocierofs_b64_encode_userpass(
+                       source->ocicfg.username,
+                       source->ocicfg.password,
+                       &b64cred);

I think you could just return `char *` or ERR_PTR(-ENOMEM)

Thanks,
Gao Xiang

Reply via email to