Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F145430028
D55286.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
7 KB
Referenced Files
None
Subscribers
None
D55286.diff
View Options
diff --git a/usr.bin/find/extern.h b/usr.bin/find/extern.h
--- a/usr.bin/find/extern.h
+++ b/usr.bin/find/extern.h
@@ -122,6 +122,8 @@
exec_f f_type;
exec_f f_user;
exec_f f_writable;
+exec_f f_xattr;
+exec_f f_xattrname;
extern int ftsoptions, ignore_readdir_race, isdepth, isoutput;
extern int issort, isxargs;
diff --git a/usr.bin/find/find.1 b/usr.bin/find/find.1
--- a/usr.bin/find/find.1
+++ b/usr.bin/find/find.1
@@ -28,7 +28,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd July 26, 2025
+.Dd February 14, 2026
.Dt FIND 1
.Os
.Sh NAME
@@ -976,6 +976,23 @@
.Xr access 2
system call, and so can be fooled by NFS servers which do UID mapping (or root-squashing).
This is a GNU find extension.
+.It Ic -xattr
+Matches files which have extended attributes set in any supported namespace.
+.It Ic -xattrname Ar xattr
+Matches files which have the specified
+.Ar xattr
+extended attribute set.
+All supported namespaces are searched by default, but
+.Ar xattr
+may be prefixed with
+.Dq user:
+or
+.Dq system:
+to filter by namespace.
+.Pp
+Note that named attributes are not supported, only extended attributes as set
+by, e.g.,
+.Xr setextattr 8 .
.El
.Sh OPERATORS
The primaries may be combined using the following operators.
@@ -1245,6 +1262,7 @@
.Xr whereis 1 ,
.Xr which 1 ,
.Xr xargs 1 ,
+.Xr extattr 2 ,
.Xr stat 2 ,
.Xr acl 3 ,
.Xr fts 3 ,
@@ -1253,7 +1271,8 @@
.Xr strmode 3 ,
.Xr ascii 7 ,
.Xr re_format 7 ,
-.Xr symlink 7
+.Xr symlink 7 ,
+.Xr setextattr 8
.Sh STANDARDS
The
.Nm
diff --git a/usr.bin/find/function.c b/usr.bin/find/function.c
--- a/usr.bin/find/function.c
+++ b/usr.bin/find/function.c
@@ -37,6 +37,7 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/acl.h>
+#include <sys/extattr.h>
#include <sys/wait.h>
#include <sys/mount.h>
@@ -49,6 +50,7 @@
#include <limits.h>
#include <pwd.h>
#include <regex.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -57,6 +59,8 @@
#include "find.h"
+static const char * const xattr_ns[] = EXTATTR_NAMESPACE_NAMES;
+
static PLAN *palloc(OPTION *);
static long long find_parsenum(PLAN *, const char *, char *, char *);
static long long find_parsetime(PLAN *, const char *, char *);
@@ -1752,6 +1756,96 @@
return new;
}
+/*
+ * -xattr functions --
+ *
+ * True if the entry has any extended attribute in any namespace.
+ */
+int
+f_xattr(PLAN *plan __unused, FTSENT *entry)
+{
+ ssize_t asz;
+ bool deref_link;
+
+ deref_link = (ftsoptions & FTS_LOGICAL) != 0;
+ if (entry->fts_level == 0 && (ftsoptions & FTS_COMFOLLOW) != 0)
+ deref_link = true;
+
+ for (size_t ns = 0; ns < nitems(xattr_ns); ns++) {
+ if (ns == EXTATTR_NAMESPACE_EMPTY)
+ continue;
+
+ if (deref_link)
+ asz = extattr_list_file(entry->fts_accpath, ns, NULL, 0);
+ else
+ asz = extattr_list_link(entry->fts_accpath, ns, NULL, 0);
+ if (asz > 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+static bool
+find_has_xattr(const char *path, int ns, const char *aname, bool deref_link)
+{
+ size_t asz;
+
+ if (deref_link)
+ asz = extattr_get_file(path, ns, aname, NULL, 0);
+ else
+ asz = extattr_get_link(path, ns, aname, NULL, 0);
+
+ return asz != (size_t)-1;
+}
+
+/*
+ * -xattrname xattr functions --
+ *
+ * True if the entry has the given extended attribute xattr. The xattr
+ * may be prefixed with "user:" or "system:" to scope the search
+ * explicitly, otherwise we assume the user namespace is requested.
+ */
+int
+f_xattrname(PLAN *plan, FTSENT *entry)
+{
+ const char *aname;
+ bool deref_link;
+
+ deref_link = (ftsoptions & FTS_LOGICAL) != 0;
+ if (entry->fts_level == 0 && (ftsoptions & FTS_COMFOLLOW) != 0)
+ deref_link = true;
+
+ aname = plan->c_data;
+ for (size_t ns = 0; ns < nitems(xattr_ns); ns++) {
+ const char *name;
+ size_t namelen;
+
+ if (ns == EXTATTR_NAMESPACE_EMPTY)
+ continue;
+
+ name = xattr_ns[ns];
+ namelen = strlen(xattr_ns[ns]);
+ if (strncmp(aname, name, namelen) == 0 &&
+ aname[namelen] == ':') {
+ aname += namelen + 1;
+ return find_has_xattr(entry->fts_accpath, ns, aname,
+ deref_link);
+ }
+ }
+
+ for (size_t ns = 0; ns < nitems(xattr_ns); ns++) {
+ if (ns == EXTATTR_NAMESPACE_EMPTY)
+ continue;
+
+ if (find_has_xattr(entry->fts_accpath, ns, aname,
+ deref_link))
+ return 1;
+ }
+
+ return 0;
+}
+
/*
* -xdev functions --
*
diff --git a/usr.bin/find/option.c b/usr.bin/find/option.c
--- a/usr.bin/find/option.c
+++ b/usr.bin/find/option.c
@@ -162,6 +162,8 @@
{ "-user", c_user, f_user, 0 },
{ "-wholename", c_name, f_path, 0 },
{ "-writable", c_simple, f_writable, 0 },
+ { "-xattr", c_simple, f_xattr, 0 },
+ { "-xattrname", c_name, f_xattrname, 0 },
{ "-xdev", c_xdev, f_always_true, 0 },
// -xtype
};
diff --git a/usr.bin/find/tests/find_test.sh b/usr.bin/find/tests/find_test.sh
--- a/usr.bin/find/tests/find_test.sh
+++ b/usr.bin/find/tests/find_test.sh
@@ -174,9 +174,89 @@
find -s dir -printf '%Te\n'
}
+atf_test_case find_xattr
+find_xattr_head()
+{
+ atf_set "descr" "Test the -xattr primary"
+}
+find_xattr_body()
+{
+ mkdir dir
+ ln -s dir dirlink
+
+ # No xattrs here
+ atf_check find dir -xattr
+ atf_check find dirlink -xattr
+
+ # Set one on the directory and be sure that we also dereference symlinks
+ # as appropriate with -H/-L.
+ if ! setextattr user find_test.attr val dir; then
+ atf_skip "Failed to set xattr (not supported on this fs?)"
+ fi
+
+ atf_check -o match:"dir$" find dir -xattr
+ atf_check -o match:"dirlink$" find -H dirlink -xattr
+ atf_check -o match:"dirlink$" find -L dirlink -xattr
+
+ atf_check -o match:"dir$" -o match:"dirlink" find -sL . -xattr
+ atf_check -o match:"dir$" -o not-match:"dirlink$" find -sH . -xattr
+ atf_check -o match:"dir$" -o not-match:"dirlink$" find -s . -xattr
+}
+
+atf_test_case find_xattrname
+find_xattrname_head()
+{
+ atf_set "descr" "Test the -xattrname primary"
+ atf_set "require.user" "root"
+}
+find_xattrname_body()
+{
+ touch foo bar baz none
+
+ ln -s foo link
+ if ! setextattr user find_test.special1 val foo; then
+ atf_skip "Failed to set xattr (not supported on this fs?)"
+ fi
+
+ atf_check setextattr user find_test.special2 val bar
+ atf_check setextattr user find_test.special2 val baz
+
+ # We want an unqualified 'find_test.special2' search to find all three
+ # of these, while 'user:' and 'system:' filter appropriately.
+ atf_check setextattr system find_test.special2 val foo
+
+ atf_check find . -xattrname 'find_test.special3'
+
+ # Be sure that we get symlink dereferencing right, so that one can use
+ # -H/-L/-P to get the right behavior.
+ atf_check -o match:foo -o not-match:"bar|baz|link|none" \
+ find . -xattrname 'find_test.special1'
+ atf_check -o match:foo -o match:link \
+ find -H foo link -xattrname 'find_test.special1'
+ atf_check -o match:foo -o match:link -o not-match:"bar|baz|none" \
+ find -L . -xattrname 'find_test.special1'
+
+ atf_check -o match:foo -o match:bar -o match:baz \
+ -o not-match:"none|link" find . -xattrname 'find_test.special2'
+ atf_check -o not-match:"foo|none|link" -o match:bar -o match:baz \
+ find . -xattrname 'user:find_test.special2'
+ atf_check -o match:foo -o not-match:"bar|baz|none|link" \
+ find . -xattrname 'system:find_test.special2'
+
+ # Now set an extattr on the link itself and be sure that find(1) can
+ # detect it. With -L, we shouldn't see anything with a special3 xattr
+ # as symlinks are dereferenced.
+ atf_check setextattr -h user find_test.special3 val link
+ atf_check -o match:link find . -xattrname "find_test.special3"
+ atf_check find -L . -xattrname "find_test.special3"
+ atf_check find -H link -xattrname "find_test.special3"
+}
+
atf_init_test_cases()
{
atf_add_test_case find_newer_link
atf_add_test_case find_samefile_link
atf_add_test_case find_printf
+ atf_add_test_case find_xattr
+ atf_add_test_case find_xattrname
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Feb 20, 6:34 PM (6 h, 44 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28902788
Default Alt Text
D55286.diff (7 KB)
Attached To
Mode
D55286: find: add -xattr and -xttrname
Attached
Detach File
Event Timeline
Log In to Comment