+//
+// HELPER FUNCTIONS
+//
+
+#ifdef EA_BSD
+
+struct BsdNamespaceInfo {
+ const char *name;
+ int value;
+};
+
+static struct BsdNamespaceInfo bsd_extattr_namespaces[] = {
+ {"user" , EXTATTR_NAMESPACE_USER},
+ {"system" , EXTATTR_NAMESPACE_SYSTEM}
+};
+
+static int bsd_check_flags (gint32 flags)
+{
+ // BSD doesn't support flags, but always provides the same behaviour as
+ // XATTR_AUTO. So we enforce that here.
+ if (flags != Mono_Posix_XattrFlags_XATTR_AUTO) {
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
+}
+
+// On FreeBSD, we need to convert "user.blah" into namespace 1 and attribute
+// name "blah", or maybe "6.blah" into namespace 6 attribute "blah"
+static int
+bsd_handle_nsprefix (const char *name, char **_name, int *namespace)
+{
+ int i;
+ gchar **components = g_strsplit (name, ".", 2);
+
+ // Find namespace number from textual representation
+ for (i = 0; i < G_N_ELEMENTS(bsd_extattr_namespaces); i++)
+ if (strcmp (bsd_extattr_namespaces[i].name, components[0]) == 0) {
+ *namespace = bsd_extattr_namespaces[i].value;
+ break;
+ }
+
+ if (*namespace == 0) {
+ // Perhaps they specified the namespace number themselves..?
+ char *endptr;
+ *namespace = (int) strtol (components[0], &endptr, 10);
+ if (*endptr != '\0')
+ return -1;
+ }
+
+ *_name = g_strdup (components[1]);
+ g_strfreev (components);
+ return 0;
+}
+
+static void
+init_attrlists (char *attrlists[])
+{
+ memset (attrlists, 0, G_N_ELEMENTS(bsd_extattr_namespaces) * sizeof(char*));
+}
+
+static void
+free_attrlists (char *attrlists[])
+{
+ int i;
+ for (i = 0; i < G_N_ELEMENTS(bsd_extattr_namespaces); i++)
+ g_free (attrlists[i]);
+}
+
+// Counts the number of attributes in the result of a
+// extattr_list_*() call. Note that the format of the data
+// is: \3one\3two\6eleven where the leading charaters represent the length
+// of the following attribute. (the description in the man-page is wrong)
+static unsigned int
+count_num_attrs (char *attrs, size_t size)
+{
+ size_t i = 0;
+ unsigned int num_attrs = 0;
+
+ if (!attrs || !size)
+ return 0;
+
+ while (i < size) {
+ num_attrs++;
+ i += attrs[i] + 1;
+ }
+
+ return num_attrs;
+}
+
+// Convert a BSD-style list buffer (see the description for count_num_attrs)
+// into a Linux-style NULL-terminated list including namespace prefix.
+static char
+*bsd_convert_list (const char *nsprefix, const char *src, size_t size, char *dest)
+{
+ size_t i = 0;
+ if (src == NULL || dest == NULL || size == 0)
+ return NULL;
+
+ while (i < size) {
+ // Read length
+ int attr_len = (int) src[i];
+ int prefix_len = strlen (nsprefix);
+
+ // Add namespace prefix
+ strncpy (dest, nsprefix, prefix_len);
+ dest[prefix_len] = '.';
+ dest += prefix_len + 1;
+
+ // Copy attribute
+ memcpy(dest, src + ++i, attr_len);
+
+ // NULL-terminate
+ i += attr_len;
+ dest[attr_len] = '\0';
+ dest += attr_len + 1;
+ }
+
+ return dest;
+}
+
+// Combine all the lists of attributes that we know about into a single
+// Linux-style buffer
+static ssize_t
+bsd_combine_lists (char *attrlists[], char *dest, size_t dest_size_needed, size_t dest_size)
+{
+ int i;
+ if (!dest)
+ return dest_size_needed;
+
+ if (dest_size < dest_size_needed) {
+ errno = ERANGE;
+ return -1;
+ }
+
+ for (i = 0; i < G_N_ELEMENTS(bsd_extattr_namespaces); i++)
+ if (attrlists[i])
+ dest = bsd_convert_list (bsd_extattr_namespaces[i].name, attrlists[i], strlen (attrlists[i]), dest);
+
+ return dest_size_needed;
+}
+
+static mph_ssize_t
+bsd_listxattr (const char *path, void *list, mph_size_t size)
+{
+ size_t full_size = 0;
+ int i;
+ char *attrlists[G_N_ELEMENTS(bsd_extattr_namespaces)];
+
+ init_attrlists (attrlists);
+ for (i = 0; i < G_N_ELEMENTS(bsd_extattr_namespaces); i++) {
+ size_t buf_size;
+ int num_attrs;
+
+ buf_size = (size_t) extattr_list_file (path, i + 1, NULL, 0);
+ if (buf_size == -1)
+ continue;
+
+ attrlists[i] = g_malloc0 (buf_size + 1);
+ buf_size = (size_t) extattr_list_file (path, i + 1, attrlists[i], buf_size);
+ if (buf_size == -1)
+ continue;
+
+ num_attrs = count_num_attrs(attrlists[i], buf_size);
+ full_size += buf_size + (num_attrs * (strlen (bsd_extattr_namespaces[i].name) + 1));
+ }
+
+ full_size = bsd_combine_lists (attrlists, (char *) list, full_size, size);
+ free_attrlists (attrlists);
+ return full_size;
+}
+
+static mph_ssize_t
+bsd_llistxattr (const char *path, void *list, mph_size_t size)
+{
+ size_t full_size = 0;
+ int i;
+ char *attrlists[G_N_ELEMENTS(bsd_extattr_namespaces)];
+
+ init_attrlists (attrlists);
+ for (i = 0; i < G_N_ELEMENTS(bsd_extattr_namespaces); i++) {
+ size_t buf_size;
+ int num_attrs;
+
+ buf_size = (size_t) extattr_list_link (path, i + 1, NULL, 0);
+ if (buf_size == -1)
+ continue;
+
+ attrlists[i] = g_malloc0 (buf_size + 1);
+ buf_size = (size_t) extattr_list_link (path, i + 1, attrlists[i], buf_size);
+ if (buf_size == -1)
+ continue;
+
+ num_attrs = count_num_attrs(attrlists[i], buf_size);
+ full_size += buf_size + (num_attrs * (strlen (bsd_extattr_namespaces[i].name) + 1));
+ }
+
+ full_size = bsd_combine_lists (attrlists, (char *) list, full_size, size);
+ free_attrlists (attrlists);
+ return full_size;
+}
+
+static mph_ssize_t
+bsd_flistxattr (int fd, void *list, mph_size_t size)
+{
+ size_t full_size = 0;
+ int i;
+ char *attrlists[G_N_ELEMENTS(bsd_extattr_namespaces)];
+
+ init_attrlists (attrlists);
+ for (i = 0; i < G_N_ELEMENTS(bsd_extattr_namespaces); i++) {
+ size_t buf_size;
+ int num_attrs;
+
+ buf_size = (size_t) extattr_list_fd (fd, i + 1, NULL, 0);
+ if (buf_size == -1)
+ continue;
+
+ attrlists[i] = g_malloc0 (buf_size + 1);
+ buf_size = (size_t) extattr_list_fd (fd, i + 1, attrlists[i], buf_size);
+ if (buf_size == -1)
+ continue;
+
+ num_attrs = count_num_attrs(attrlists[i], buf_size);
+ full_size += buf_size + (num_attrs * (strlen (bsd_extattr_namespaces[i].name) + 1));
+ }
+
+ full_size = bsd_combine_lists (attrlists, (char *) list, full_size, size);
+ free_attrlists (attrlists);
+ return full_size;
+}
+
+#endif /* EA_BSD */
+
+//
+// THE PROVIDED API
+//
+