+
+ /*
+ * See if this file looks like it is laid out correctly to contain
+ * extended attributes. If so, then do the following:
+ *
+ * - If we're going to be writing, try to make sure the Finder Info
+ * entry has room to store the extended attribute header, plus some
+ * space for extended attributes.
+ *
+ * - Swap and sanity check the extended attribute header and entries
+ * (if any).
+ */
+ if (filehdr->numEntries == 2 &&
+ ainfop->finderinfo == &filehdr->entries[0] &&
+ ainfop->rsrcfork == &filehdr->entries[1] &&
+ ainfop->finderinfo->offset == offsetof(apple_double_header_t, finfo)) {
+ attr_header_t *attrhdr;
+ attrhdr = (attr_header_t *)filehdr;
+ /*
+ * If we're going to be writing, try to make sure the Finder
+ * Info entry has room to store the extended attribute header,
+ * plus some space for extended attributes.
+ */
+ if (setting && ainfop->finderinfo->length == FINDERINFOSIZE) {
+ size_t delta;
+ size_t writesize;
+
+ delta = ATTR_BUF_SIZE - (filehdr->entries[0].offset + FINDERINFOSIZE);
+ if (ainfop->rsrcfork && filehdr->entries[1].length) {
+ /* Make some room before existing resource fork. */
+ shift_data_down(xvp,
+ filehdr->entries[1].offset,
+ filehdr->entries[1].length,
+ delta, context);
+ writesize = sizeof(attr_header_t);
+ } else {
+ /* Create a new, empty resource fork. */
+ rsrcfork_header_t *rsrcforkhdr;
+
+ vnode_setsize(xvp, filehdr->entries[1].offset + delta, 0, context);
+
+ /* Steal some space for an empty RF header. */
+ delta -= sizeof(rsrcfork_header_t);
+
+ bzero(&attrhdr->appledouble.pad[0], delta);
+ rsrcforkhdr = (rsrcfork_header_t *)((char *)filehdr + filehdr->entries[1].offset + delta);
+
+ /* Fill in Empty Resource Fork Header. */
+ init_empty_resource_fork(rsrcforkhdr);
+
+ filehdr->entries[1].length = sizeof(rsrcfork_header_t);
+ writesize = ATTR_BUF_SIZE;
+ }
+ filehdr->entries[0].length += delta;
+ filehdr->entries[1].offset += delta;
+
+ /* Fill in Attribute Header. */
+ attrhdr->magic = ATTR_HDR_MAGIC;
+ attrhdr->debug_tag = (u_int32_t)va.va_fileid;
+ attrhdr->total_size = filehdr->entries[1].offset;
+ attrhdr->data_start = sizeof(attr_header_t);
+ attrhdr->data_length = 0;
+ attrhdr->reserved[0] = 0;
+ attrhdr->reserved[1] = 0;
+ attrhdr->reserved[2] = 0;
+ attrhdr->flags = 0;
+ attrhdr->num_attrs = 0;
+
+ /* Push out new header */
+ uio_reset(auio, 0, UIO_SYSSPACE32, UIO_WRITE);
+ uio_addiov(auio, (uintptr_t)filehdr, writesize);
+
+ swap_adhdr(filehdr); /* to big endian */
+ swap_attrhdr(attrhdr, ainfop); /* to big endian */
+ error = VNOP_WRITE(xvp, auio, 0, context);
+ swap_adhdr(filehdr); /* back to native */
+ /* The attribute header gets swapped below. */
+ }
+ }
+
+ /*
+ * Swap and sanity check the extended attribute header and
+ * entries (if any). The Finder Info content must be big enough
+ * to include the extended attribute header; if not, we just
+ * ignore it.
+ *
+ * Note that we're passing the offset + length (i.e. the end)
+ * of the Finder Info instead of rawsize to validate_attrhdr.
+ * This ensures that all extended attributes lie within the
+ * Finder Info content according to the AppleDouble entry.
+ *
+ * Sets ainfop->attrhdr and ainfop->attr_entry if a valid
+ * header was found.
+ */
+ if (ainfop->finderinfo &&
+ ainfop->finderinfo == &filehdr->entries[0] &&
+ ainfop->finderinfo->length >= (sizeof(attr_header_t) - sizeof(apple_double_header_t))) {
+ attr_header_t *attrhdr = (attr_header_t*)filehdr;
+ if ((error = check_and_swap_attrhdr(attrhdr, ainfop)) == 0) {
+ ainfop->attrhdr = attrhdr; /* valid attribute header */
+ /* First attr_entry starts immediately following attribute header */
+ ainfop->attr_entry = (attr_entry_t *)&attrhdr[1];
+ }
+ }
+