@@ -27,6 +27,7 @@
io_context_t io_ctx;
#endif
#include <sys/syscall.h>
+#include <sys/xattr.h>
#ifndef FS_IOC_GETFLAGS
#define FS_IOC_GETFLAGS _IOR('f', 1, long)
@@ -84,6 +85,7 @@ typedef enum {
OP_RESVSP,
OP_RMDIR,
OP_SETATTR,
+ OP_SETFATTR,
OP_SETXATTR,
OP_SPLICE,
OP_STAT,
@@ -110,6 +112,7 @@ typedef struct opdesc {
typedef struct fent {
int id;
int parent;
+ int xattr_counter;
} fent_t;
typedef struct flist {
@@ -156,6 +159,8 @@ struct print_string {
#define MAXFSIZE ((1ULL << 63) - 1ULL)
#define MAXFSIZE32 ((1ULL << 40) - 1ULL)
+#define XATTR_NAME_BUF_SIZE 18
+
void afsync_f(int, long);
void allocsp_f(int, long);
void aread_f(int, long);
@@ -176,6 +181,7 @@ void fdatasync_f(int, long);
void fiemap_f(int, long);
void freesp_f(int, long);
void fsync_f(int, long);
+char *gen_random_string(int);
void getattr_f(int, long);
void getdents_f(int, long);
void link_f(int, long);
@@ -194,6 +200,7 @@ void rename_f(int, long);
void resvsp_f(int, long);
void rmdir_f(int, long);
void setattr_f(int, long);
+void setfattr_f(int, long);
void setxattr_f(int, long);
void splice_f(int, long);
void stat_f(int, long);
@@ -204,6 +211,7 @@ void unlink_f(int, long);
void unresvsp_f(int, long);
void write_f(int, long);
void writev_f(int, long);
+char *xattr_flag_to_string(int);
opdesc_t ops[] = {
/* { OP_ENUM, "name", function, freq, iswrite }, */
@@ -244,7 +252,11 @@ opdesc_t ops[] = {
{ OP_RENAME, "rename", rename_f, 2, 1 },
{ OP_RESVSP, "resvsp", resvsp_f, 1, 1 },
{ OP_RMDIR, "rmdir", rmdir_f, 1, 1 },
+ /* set attribute flag (FS_IOC_SETFLAGS ioctl) */
{ OP_SETATTR, "setattr", setattr_f, 0, 1 },
+ /* set extended attribute */
+ { OP_SETFATTR, "setfattr", setfattr_f, 2, 1 },
+ /* set project id (XFS_IOC_FSSETXATTR ioctl) */
{ OP_SETXATTR, "setxattr", setxattr_f, 1, 1 },
{ OP_SPLICE, "splice", splice_f, 1, 1 },
{ OP_STAT, "stat", stat_f, 1, 0 },
@@ -296,7 +308,7 @@ char *execute_cmd = NULL;
int execute_freq = 1;
struct print_string flag_str = {0};
-void add_to_flist(int, int, int);
+void add_to_flist(int, int, int, int);
void append_pathname(pathname_t *, char *);
int attr_list_path(pathname_t *, char *, const int, int, attrlist_cursor_t *);
int attr_remove_path(pathname_t *, const char *, int);
@@ -315,6 +327,7 @@ int fent_to_name(pathname_t *, flist_t *, fent_t *);
void fix_parent(int, int);
void free_pathname(pathname_t *);
int generate_fname(fent_t *, int, pathname_t *, int *, int *);
+int generate_xattr_name(int, char *, int);
int get_fname(int, long, pathname_t *, flist_t **, fent_t **, int *);
void init_pathname(pathname_t *);
int lchown_path(pathname_t *, uid_t, gid_t);
@@ -716,7 +729,7 @@ translate_flags(int flags, const char *delim,
}
void
-add_to_flist(int ft, int id, int parent)
+add_to_flist(int ft, int id, int parent, int xattr_counter)
{
fent_t *fep;
flist_t *ftp;
@@ -729,6 +742,7 @@ add_to_flist(int ft, int id, int parent)
fep = &ftp->fents[ftp->nfiles++];
fep->id = id;
fep->parent = parent;
+ fep->xattr_counter = xattr_counter;
}
void
@@ -1122,6 +1136,18 @@ generate_fname(fent_t *fep, int ft, pathname_t *name, int *idp, int *v)
return 1;
}
+int generate_xattr_name(int xattr_num, char *buffer, int buflen)
+{
+ int ret;
+
+ ret = snprintf(buffer, buflen, "user.x%d", xattr_num);
+ if (ret < 0)
+ return ret;
+ if (ret < buflen)
+ return 0;
+ return -EOVERFLOW;
+}
+
/*
* Get file
* Input: "which" to choose the file-types eg. non-directory
@@ -3030,7 +3056,7 @@ creat_f(int opno, long r)
if (xfsctl(f.path, fd, XFS_IOC_FSSETXATTR, &a) < 0)
e1 = errno;
}
- add_to_flist(type, id, parid);
+ add_to_flist(type, id, parid, 0);
close(fd);
}
if (v) {
@@ -3495,6 +3521,28 @@ fsync_f(int opno, long r)
close(fd);
}
+char *
+gen_random_string(int len)
+{
+ static const char charset[] = "0123456789"
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ int i;
+ char *s;
+
+ if (len == 0)
+ return NULL;
+
+ s = malloc(len);
+ if (!s)
+ return NULL;
+
+ for (i = 0; i < len; i++)
+ s[i] = charset[random() % sizeof(charset)];
+
+ return s;
+}
+
void
getattr_f(int opno, long r)
{
@@ -3551,6 +3599,7 @@ link_f(int opno, long r)
int e;
pathname_t f;
fent_t *fep;
+ fent_t *fep_src;
flist_t *flp;
int id;
pathname_t l;
@@ -3559,7 +3608,7 @@ link_f(int opno, long r)
int v1;
init_pathname(&f);
- if (!get_fname(FT_NOTDIR, r, &f, &flp, NULL, &v1)) {
+ if (!get_fname(FT_NOTDIR, r, &f, &flp, &fep_src, &v1)) {
if (v1)
printf("%d/%d: link - no file\n", procid, opno);
free_pathname(&f);
@@ -3586,7 +3635,7 @@ link_f(int opno, long r)
e = link_path(&f, &l) < 0 ? errno : 0;
check_cwd();
if (e == 0)
- add_to_flist(flp - flist, id, parid);
+ add_to_flist(flp - flist, id, parid, fep_src->xattr_counter);
if (v) {
printf("%d/%d: link %s %s %d\n", procid, opno, f.path, l.path,
e);
@@ -3626,7 +3675,7 @@ mkdir_f(int opno, long r)
e = mkdir_path(&f, 0777) < 0 ? errno : 0;
check_cwd();
if (e == 0)
- add_to_flist(FT_DIR, id, parid);
+ add_to_flist(FT_DIR, id, parid, 0);
if (v) {
printf("%d/%d: mkdir %s %d\n", procid, opno, f.path, e);
printf("%d/%d: mkdir add id=%d,parent=%d\n", procid, opno, id, parid);
@@ -3664,7 +3713,7 @@ mknod_f(int opno, long r)
e = mknod_path(&f, S_IFCHR|0444, 0) < 0 ? errno : 0;
check_cwd();
if (e == 0)
- add_to_flist(FT_DEV, id, parid);
+ add_to_flist(FT_DEV, id, parid, 0);
if (v) {
printf("%d/%d: mknod %s %d\n", procid, opno, f.path, e);
printf("%d/%d: mknod add id=%d,parent=%d\n", procid, opno, id, parid);
@@ -4040,12 +4089,14 @@ rename_f(int opno, long r)
e = rename_path(&f, &newf) < 0 ? errno : 0;
check_cwd();
if (e == 0) {
+ int xattr_counter = fep->xattr_counter;
+
if (flp - flist == FT_DIR) {
oldid = fep->id;
fix_parent(oldid, id);
}
del_from_flist(flp - flist, fep - flp->fents);
- add_to_flist(flp - flist, id, parid);
+ add_to_flist(flp - flist, id, parid, xattr_counter);
}
if (v) {
printf("%d/%d: rename %s to %s %d\n", procid, opno, f.path,
@@ -4168,6 +4219,81 @@ setattr_f(int opno, long r)
}
void
+setfattr_f(int opno, long r)
+{
+ int e;
+ pathname_t f;
+ fent_t *fep;
+ int v;
+ int value_len;
+ char name[XATTR_NAME_BUF_SIZE];
+ char *value = NULL;
+ int flag = 0;
+ int xattr_num;
+
+ init_pathname(&f);
+ if (!get_fname(FT_REGFILE | FT_DIRm, r, &f, NULL, &fep, &v)) {
+ if (v)
+ printf("%d/%d: setfattr - no filename\n", procid, opno);
+ goto out;
+ }
+ check_cwd();
+
+ if ((fep->xattr_counter > 0) && (random() % 2)) {
+ /*
+ * Use an existing xattr name for replacing its value or
+ * create again a xattr that was previously deleted.
+ */
+ xattr_num = (random() % fep->xattr_counter) + 1;
+ if (random() % 2)
+ flag = XATTR_REPLACE;
+ } else {
+ /* Use a new xattr name. */
+ xattr_num = fep->xattr_counter + 1;
+ /*
+ * Don't always use the create flag because even if our xattr
+ * counter is 0, we may still have xattrs associated to this
+ * file (this happens when xattrs are added to a file through
+ * one of its other hard links), so we can end up updating an
+ * existing xattr too.
+ */
+ if (random() % 2)
+ flag = XATTR_CREATE;
+ }
+
+ /*
+ * The maximum supported value size depends on the filesystem
+ * implementation, but 100 bytes is a safe value for most filesystems
+ * at least.
+ */
+ value_len = random() % 101;
+ value = gen_random_string(value_len);
+ if (!value && value_len > 0) {
+ if (v)
+ printf("%d/%d: setfattr - file %s failed to allocate value with %d bytes\n",
+ procid, opno, f.path, value_len);
+ goto out;
+ }
+ e = generate_xattr_name(xattr_num, name, sizeof(name));
+ if (e < 0) {
+ printf("%d/%d: setfattr - file %s failed to generate xattr name: %d\n",
+ procid, opno, f.path, e);
+ goto out;
+ }
+
+ e = setxattr(f.path, name, value, value_len, flag) < 0 ? errno : 0;
+ if (e == 0)
+ fep->xattr_counter++;
+ if (v)
+ printf("%d/%d: setfattr file %s name %s flag %s value length %d: %d\n",
+ procid, opno, f.path, name, xattr_flag_to_string(flag),
+ value_len, e);
+out:
+ free(value);
+ free_pathname(&f);
+}
+
+void
stat_f(int opno, long r)
{
int e;
@@ -4229,7 +4355,7 @@ symlink_f(int opno, long r)
e = symlink_path(val, &f) < 0 ? errno : 0;
check_cwd();
if (e == 0)
- add_to_flist(FT_SYM, id, parid);
+ add_to_flist(FT_SYM, id, parid, 0);
free(val);
if (v) {
printf("%d/%d: symlink %s %d\n", procid, opno, f.path, e);
@@ -4498,3 +4624,13 @@ writev_f(int opno, long r)
free_pathname(&f);
close(fd);
}
+
+char *
+xattr_flag_to_string(int flag)
+{
+ if (flag == XATTR_CREATE)
+ return "create";
+ if (flag == XATTR_REPLACE)
+ return "replace";
+ return "none";
+}