-
Notifications
You must be signed in to change notification settings - Fork 35
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
Add support for decoding erofs into lcfs_node, and some tooling using it #185
Changes from all commits
7fa6107
1c69f93
1b0e9f3
fc30bb6
6ca622f
ccb7374
55067ad
d186f4c
fe81a66
30bcbe5
0366de5
cc73fbf
1340829
e958ded
f0594cb
90676ee
7c65eb0
4110ef4
fbdf4e4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
SUBDIRS=libcomposefs tools | ||
SUBDIRS=libcomposefs tools tests | ||
|
||
EXTRA_DIST=\ | ||
composefs.pc.in \ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
/* lcfs | ||
Copyright (C) 2023 Alexander Larsson <[email protected]> | ||
|
||
This file is free software: you can redistribute it and/or modify | ||
it under the terms of the GNU Lesser General Public License as | ||
published by the Free Software Foundation; either version 2.1 of the | ||
License, or (at your option) any later version. | ||
|
||
This file is distributed in the hope that it will be useful, | ||
but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
GNU Lesser General Public License for more details. | ||
|
||
You should have received a copy of the GNU Lesser General Public License | ||
along with this program. If not, see <https://www.gnu.org/licenses/>. */ | ||
|
||
#ifndef _LCFS_EROFS_INTERNAL_H | ||
#define _LCFS_EROFS_INTERNAL_H | ||
|
||
#include <string.h> | ||
|
||
#include "lcfs-internal.h" | ||
#include "lcfs-erofs.h" | ||
#include "erofs_fs_wrapper.h" | ||
|
||
typedef union { | ||
__le16 i_format; | ||
struct erofs_inode_compact compact; | ||
struct erofs_inode_extended extended; | ||
} erofs_inode; | ||
|
||
static const char *erofs_xattr_prefixes[] = { | ||
"", | ||
"user.", | ||
"system.posix_acl_access", | ||
"system.posix_acl_default", | ||
"trusted.", | ||
"lustre.", | ||
"security.", | ||
}; | ||
|
||
static inline uint16_t erofs_inode_version(const erofs_inode *cino) | ||
{ | ||
uint16_t i_format = lcfs_u16_from_file(cino->i_format); | ||
return (i_format >> EROFS_I_VERSION_BIT) & EROFS_I_VERSION_MASK; | ||
} | ||
|
||
static inline bool erofs_inode_is_compact(const erofs_inode *cino) | ||
{ | ||
return erofs_inode_version(cino) == 0; | ||
} | ||
|
||
static inline uint16_t erofs_inode_datalayout(const erofs_inode *cino) | ||
{ | ||
uint16_t i_format = lcfs_u16_from_file(cino->i_format); | ||
return (i_format >> EROFS_I_DATALAYOUT_BIT) & EROFS_I_DATALAYOUT_MASK; | ||
} | ||
|
||
static inline bool erofs_inode_is_tailpacked(const erofs_inode *cino) | ||
{ | ||
return erofs_inode_datalayout(cino) == EROFS_INODE_FLAT_INLINE; | ||
} | ||
|
||
static inline bool erofs_inode_is_flat(const erofs_inode *cino) | ||
{ | ||
return erofs_inode_datalayout(cino) == EROFS_INODE_FLAT_INLINE || | ||
erofs_inode_datalayout(cino) == EROFS_INODE_FLAT_PLAIN; | ||
} | ||
|
||
static inline size_t erofs_xattr_inode_size(uint16_t xattr_icount) | ||
{ | ||
size_t xattr_size = 0; | ||
if (xattr_icount > 0) | ||
xattr_size = sizeof(struct erofs_xattr_ibody_header) + | ||
(xattr_icount - 1) * 4; | ||
return xattr_size; | ||
} | ||
|
||
#define EROFS_N_XATTR_PREFIXES (sizeof(erofs_xattr_prefixes) / sizeof(char *)) | ||
|
||
static inline bool erofs_is_acl_xattr(int prefix, const char *name, size_t name_len) | ||
{ | ||
const char *const nfs_acl = "system.nfs4_acl"; | ||
|
||
if ((prefix == EROFS_XATTR_INDEX_POSIX_ACL_ACCESS || | ||
prefix == EROFS_XATTR_INDEX_POSIX_ACL_DEFAULT) && | ||
name_len == 0) | ||
return true; | ||
if (prefix == 0 && name_len == strlen(nfs_acl) && | ||
memcmp(name, nfs_acl, strlen(nfs_acl)) == 0) | ||
return true; | ||
return false; | ||
} | ||
|
||
static inline int erofs_get_xattr_prefix(const char *str) | ||
{ | ||
for (int i = 1; i < EROFS_N_XATTR_PREFIXES; i++) { | ||
const char *prefix = erofs_xattr_prefixes[i]; | ||
if (strlen(str) >= strlen(prefix) && | ||
memcmp(str, prefix, strlen(prefix)) == 0) { | ||
return i; | ||
} | ||
} | ||
return 0; | ||
} | ||
|
||
static inline char *erofs_get_xattr_name(uint8_t index, const char *name, | ||
size_t name_len) | ||
{ | ||
char *res; | ||
const char *prefix; | ||
size_t prefix_len; | ||
|
||
if (index >= EROFS_N_XATTR_PREFIXES) { | ||
errno = EINVAL; | ||
return NULL; | ||
} | ||
|
||
prefix = erofs_xattr_prefixes[index]; | ||
prefix_len = strlen(prefix); | ||
|
||
res = malloc(prefix_len + name_len + 1); | ||
if (res == NULL) { | ||
errno = ENOMEM; | ||
return NULL; | ||
} | ||
memcpy(res, prefix, prefix_len); | ||
memcpy(res + prefix_len, name, name_len); | ||
res[prefix_len + name_len] = 0; | ||
|
||
return res; | ||
} | ||
|
||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,6 +29,28 @@ | |
*/ | ||
#define LCFS_BUILD_INLINE_FILE_SIZE_LIMIT 64 | ||
|
||
#define OVERLAY_XATTR_USER_PREFIX "user." | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Aweseome, I think this helps a lot to have these. Then we can also followup with some links to the kernel sources. |
||
#define OVERLAY_XATTR_TRUSTED_PREFIX "trusted." | ||
#define OVERLAY_XATTR_PARTIAL_PREFIX "overlay." | ||
#define OVERLAY_XATTR_PREFIX \ | ||
OVERLAY_XATTR_TRUSTED_PREFIX OVERLAY_XATTR_PARTIAL_PREFIX | ||
#define OVERLAY_XATTR_USERXATTR_PREFIX \ | ||
OVERLAY_XATTR_USER_PREFIX OVERLAY_XATTR_PARTIAL_PREFIX | ||
#define OVERLAY_XATTR_ESCAPE_PREFIX OVERLAY_XATTR_PREFIX "overlay." | ||
#define OVERLAY_XATTR_METACOPY OVERLAY_XATTR_PREFIX "metacopy" | ||
#define OVERLAY_XATTR_REDIRECT OVERLAY_XATTR_PREFIX "redirect" | ||
#define OVERLAY_XATTR_WHITEOUT OVERLAY_XATTR_PREFIX "whiteout" | ||
#define OVERLAY_XATTR_WHITEOUTS OVERLAY_XATTR_PREFIX "whiteouts" | ||
#define OVERLAY_XATTR_OPAQUE OVERLAY_XATTR_PREFIX "opaque" | ||
|
||
#define OVERLAY_XATTR_ESCAPED_WHITEOUT OVERLAY_XATTR_ESCAPE_PREFIX "whiteout" | ||
#define OVERLAY_XATTR_ESCAPED_WHITEOUTS OVERLAY_XATTR_ESCAPE_PREFIX "whiteouts" | ||
|
||
#define OVERLAY_XATTR_USERXATTR_WHITEOUT \ | ||
OVERLAY_XATTR_USERXATTR_PREFIX "whiteout" | ||
#define OVERLAY_XATTR_USERXATTR_WHITEOUTS \ | ||
OVERLAY_XATTR_USERXATTR_PREFIX "whiteouts" | ||
|
||
#define ALIGN_TO(_offset, _align_size) \ | ||
(((_offset) + _align_size - 1) & ~(_align_size - 1)) | ||
|
||
|
@@ -147,6 +169,15 @@ struct lcfs_ctx_s { | |
void (*finalize)(struct lcfs_ctx_s *ctx); | ||
}; | ||
|
||
static inline void lcfs_node_unrefp(struct lcfs_node_s **nodep) | ||
{ | ||
if (*nodep != NULL) { | ||
lcfs_node_unref(*nodep); | ||
*nodep = NULL; | ||
} | ||
} | ||
#define cleanup_node __attribute__((cleanup(lcfs_node_unrefp))) | ||
|
||
/* lcfs-writer.c */ | ||
size_t hash_memory(const char *string, size_t len, size_t n_buckets); | ||
int lcfs_write(struct lcfs_ctx_s *ctx, void *_data, size_t data_len); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,12 +19,41 @@ | |
|
||
#include <assert.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <errno.h> | ||
#include <unistd.h> | ||
|
||
#define max(a, b) ((a > b) ? (a) : (b)) | ||
#define min(a, b) (((a) < (b)) ? (a) : (b)) | ||
|
||
static inline bool str_has_prefix(const char *str, const char *prefix) | ||
{ | ||
return strncmp(str, prefix, strlen(prefix)) == 0; | ||
} | ||
|
||
static inline char *memdup(const char *s, size_t len) | ||
{ | ||
char *s2 = malloc(len); | ||
if (s2 == NULL) { | ||
errno = ENOMEM; | ||
return NULL; | ||
} | ||
memcpy(s2, s, len); | ||
return s2; | ||
} | ||
|
||
static inline char *str_join(const char *a, const char *b) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. optional: This is just code motion, so OK, but same question re |
||
{ | ||
size_t a_len = strlen(a); | ||
size_t b_len = strlen(b); | ||
char *res = malloc(a_len + b_len + 1); | ||
if (res) { | ||
memcpy(res, a, a_len); | ||
memcpy(res + a_len, b, b_len + 1); | ||
} | ||
return res; | ||
} | ||
|
||
static inline void _lcfs_reset_errno_(int *saved_errno) | ||
{ | ||
if (*saved_errno < 0) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is all just
return asprintf("%s%.*s", prefix, name_len, name)
right?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, but I'm not super found of asprintf like this, because I always have to look up the length modifier in the manpage to get it right.
And also, I always worry about the integer format conversion in varargs calls like this.
Like, name_len is size_t, which could be larger than int in some compilers, and the field width must be int. So, do we need to cast? etc.