+static void
+set_object_id(HANDLE h, const struct wim_inode *inode,
+ struct win32_apply_ctx *ctx)
+{
+ const void *object_id;
+ u32 len;
+ NTSTATUS status;
+
+ if (!ctx->common.supported_features.object_ids)
+ return;
+
+ object_id = inode_get_object_id(inode, &len);
+ if (likely(object_id == NULL)) /* No object ID? */
+ return;
+
+ status = winnt_fsctl(h, FSCTL_SET_OBJECT_ID,
+ object_id, len, NULL, 0, NULL);
+ if (NT_SUCCESS(status))
+ return;
+
+ /* Object IDs must be unique within the filesystem. A duplicate might
+ * occur if an image containing object IDs is applied twice to the same
+ * filesystem. Arguably, the user should be warned in this case; but
+ * the reality seems to be that nothing important cares about object IDs
+ * except the Distributed Link Tracking Service... so for now these
+ * failures are just ignored. */
+ if (status == STATUS_DUPLICATE_NAME ||
+ status == STATUS_OBJECT_NAME_COLLISION)
+ return;
+
+ ctx->num_object_id_failures++;
+ if (ctx->num_object_id_failures < 10) {
+ winnt_warning(status, L"Can't set object ID on \"%ls\"",
+ current_path(ctx));
+ } else if (ctx->num_object_id_failures == 10) {
+ WARNING("Suppressing further warnings about failure to set "
+ "object IDs.");
+ }
+}
+
+static int
+set_xattrs(HANDLE h, const struct wim_inode *inode, struct win32_apply_ctx *ctx)
+{
+ const void *entries, *entries_end;
+ u32 len;
+ const struct wim_xattr_entry *entry;
+ size_t bufsize = 0;
+ u8 _buf[1024] _aligned_attribute(4);
+ u8 *buf = _buf;
+ FILE_FULL_EA_INFORMATION *ea, *ea_prev;
+ NTSTATUS status;
+ int ret;
+
+ if (!ctx->common.supported_features.xattrs)
+ return 0;
+
+ entries = inode_get_xattrs(inode, &len);
+ if (likely(entries == NULL || len == 0)) /* No extended attributes? */
+ return 0;
+ entries_end = entries + len;
+
+ entry = entries;
+ for (entry = entries; (void *)entry < entries_end;
+ entry = xattr_entry_next(entry)) {
+ if (!valid_xattr_entry(entry, entries_end - (void *)entry)) {
+ ERROR("\"%"TS"\": extended attribute is corrupt or unsupported",
+ inode_any_full_path(inode));
+ return WIMLIB_ERR_INVALID_XATTR;
+ }
+
+ bufsize += ALIGN(offsetof(FILE_FULL_EA_INFORMATION, EaName) +
+ entry->name_len + 1 +
+ le16_to_cpu(entry->value_len), 4);
+ }
+
+ if (unlikely(bufsize != (u32)bufsize)) {
+ ERROR("\"%"TS"\": too many extended attributes to extract!",
+ inode_any_full_path(inode));
+ return WIMLIB_ERR_INVALID_XATTR;
+ }
+
+ if (unlikely(bufsize > sizeof(_buf))) {
+ buf = MALLOC(bufsize);
+ if (!buf)
+ return WIMLIB_ERR_NOMEM;
+ }
+
+ ea_prev = NULL;
+ ea = (FILE_FULL_EA_INFORMATION *)buf;
+ for (entry = entries; (void *)entry < entries_end;
+ entry = xattr_entry_next(entry)) {
+ u8 *p;
+
+ if (ea_prev)
+ ea_prev->NextEntryOffset = (u8 *)ea - (u8 *)ea_prev;
+ ea->Flags = entry->flags;
+ ea->EaNameLength = entry->name_len;
+ ea->EaValueLength = le16_to_cpu(entry->value_len);
+ p = mempcpy(ea->EaName, entry->name,
+ ea->EaNameLength + 1 + ea->EaValueLength);
+ while ((uintptr_t)p & 3)
+ *p++ = 0;
+ ea_prev = ea;
+ ea = (FILE_FULL_EA_INFORMATION *)p;
+ }
+ ea_prev->NextEntryOffset = 0;
+ wimlib_assert((u8 *)ea - buf == bufsize);
+
+ status = NtSetEaFile(h, &ctx->iosb, buf, bufsize);
+ if (unlikely(!NT_SUCCESS(status))) {
+ if (status == STATUS_EAS_NOT_SUPPORTED) {
+ /* This happens with Samba. */
+ WARNING("Filesystem advertised extended attribute (EA) support, but it doesn't\n"
+ " work. EAs will not be extracted.");
+ ctx->common.supported_features.xattrs = 0;
+ } else if (status == STATUS_INVALID_EA_NAME) {
+ ctx->num_xattr_failures++;
+ if (ctx->num_xattr_failures < 5) {
+ winnt_warning(status,
+ L"Can't set extended attributes on \"%ls\"",
+ current_path(ctx));
+ } else if (ctx->num_xattr_failures == 5) {
+ WARNING("Suppressing further warnings about "
+ "failure to set extended attributes.");
+ }
+ } else {
+ winnt_error(status, L"Can't set extended attributes on \"%ls\"",
+ current_path(ctx));
+ ret = WIMLIB_ERR_SET_XATTR;
+ goto out;
+ }
+ }
+ ret = 0;
+out:
+ if (buf != _buf)
+ FREE(buf);
+ return ret;
+}
+