1 /* NFSv4.1 client for Windows
2 * Copyright © 2012 The Regents of the University of Michigan
4 * Olga Kornievskaia <aglo@umich.edu>
5 * Casey Bodley <cbodley@umich.edu>
7 * This library is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; either version 2.1 of the License, or (at
10 * your option) any later version.
12 * This library is distributed in the hope that it will be useful, but
13 * without any warranty; without even the implied warranty of merchantability
14 * or fitness for a particular purpose. See the GNU Lesser General Public
15 * License for more details.
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 #include "nfs41_callback.h"
23 #include "nfs41_ops.h"
25 #include "daemon_debug.h"
28 #define CBXLVL 2 /* dprintf level for callback xdr logging */
30 #define CBX_ERR(msg) dprintf((CBXLVL), "%s: failed at %s\n", __FUNCTION__, msg)
32 #define CBX_ERR(msg) dprintf((CBXLVL), __FUNCTION__ ": failed at " msg "\n")
36 bool_t
xdr_bitmap4(XDR
*xdr
, bitmap4
*bitmap
);
37 bool_t
xdr_fattr4(XDR
*xdr
, fattr4
*fattr
);
39 static bool_t
common_stateid(XDR
*xdr
, stateid4
*stateid
)
41 return xdr_u_int32_t(xdr
, &stateid
->seqid
)
42 && xdr_opaque(xdr
, (char*)stateid
->other
, NFS4_STATEID_OTHER
);
45 static bool_t
common_fh(XDR
*xdr
, nfs41_fh
*fh
)
47 return xdr_u_int32_t(xdr
, &fh
->len
)
48 && fh
->len
<= NFS4_FHSIZE
49 && xdr_opaque(xdr
, (char*)fh
->fh
, fh
->len
);
52 static bool_t
common_fsid(XDR
*xdr
, nfs41_fsid
*fsid
)
54 return xdr_u_int64_t(xdr
, &fsid
->major
)
55 && xdr_u_int64_t(xdr
, &fsid
->minor
);
58 static bool_t
common_notify4(XDR
*xdr
, struct notify4
*notify
)
60 return xdr_bitmap4(xdr
, ¬ify
->mask
)
61 && xdr_bytes(xdr
, ¬ify
->list
, ¬ify
->len
, NFS4_OPAQUE_LIMIT
);
64 /* OP_CB_LAYOUTRECALL */
65 static bool_t
op_cb_layoutrecall_file(XDR
*xdr
, struct cb_recall_file
*args
)
69 result
= common_fh(xdr
, &args
->fh
);
70 if (!result
) { CBX_ERR("layoutrecall_file.fh"); goto out
; }
72 result
= xdr_u_int64_t(xdr
, &args
->offset
);
73 if (!result
) { CBX_ERR("layoutrecall_file.offset"); goto out
; }
75 result
= xdr_u_int64_t(xdr
, &args
->length
);
76 if (!result
) { CBX_ERR("layoutrecall_file.length"); goto out
; }
78 result
= common_stateid(xdr
, &args
->stateid
);
79 if (!result
) { CBX_ERR("layoutrecall_file.stateid"); goto out
; }
84 static bool_t
op_cb_layoutrecall_fsid(XDR
*xdr
, union cb_recall_file_args
*args
)
88 result
= common_fsid(xdr
, &args
->fsid
);
89 if (!result
) { CBX_ERR("layoutrecall_fsid.fsid"); goto out
; }
94 static const struct xdr_discrim cb_layoutrecall_discrim
[] = {
95 { PNFS_RETURN_FILE
, (xdrproc_t
)op_cb_layoutrecall_file
},
96 { PNFS_RETURN_FSID
, (xdrproc_t
)op_cb_layoutrecall_fsid
},
97 { PNFS_RETURN_ALL
, (xdrproc_t
)xdr_void
},
101 static bool_t
op_cb_layoutrecall_args(XDR
*xdr
, struct cb_layoutrecall_args
*args
)
105 result
= xdr_enum(xdr
, (enum_t
*)&args
->type
);
106 if (!result
) { CBX_ERR("layoutrecall_args.type"); goto out
; }
108 result
= xdr_enum(xdr
, (enum_t
*)&args
->iomode
);
109 if (!result
) { CBX_ERR("layoutrecall_args.iomode"); goto out
; }
111 result
= xdr_bool(xdr
, &args
->changed
);
112 if (!result
) { CBX_ERR("layoutrecall_args.changed"); goto out
; }
114 result
= xdr_union(xdr
, (enum_t
*)&args
->recall
.type
,
115 (char*)&args
->recall
.args
, cb_layoutrecall_discrim
, NULL_xdrproc_t
);
116 if (!result
) { CBX_ERR("layoutrecall_args.recall"); goto out
; }
121 static bool_t
op_cb_layoutrecall_res(XDR
*xdr
, struct cb_layoutrecall_res
*res
)
125 result
= xdr_enum(xdr
, &res
->status
);
126 if (!result
) { CBX_ERR("layoutrecall_res.status"); goto out
; }
132 /* OP_CB_RECALL_SLOT */
133 static bool_t
op_cb_recall_slot_args(XDR
*xdr
, struct cb_recall_slot_args
*res
)
137 result
= xdr_u_int32_t(xdr
, &res
->target_highest_slotid
);
138 if (!result
) { CBX_ERR("recall_slot.target_highest_slotid"); goto out
; }
143 static bool_t
op_cb_recall_slot_res(XDR
*xdr
, struct cb_recall_slot_res
*res
)
147 result
= xdr_enum(xdr
, &res
->status
);
148 if (!result
) { CBX_ERR("recall_slot.status"); goto out
; }
155 static bool_t
op_cb_sequence_ref(XDR
*xdr
, struct cb_sequence_ref
*args
)
159 result
= xdr_u_int32_t(xdr
, &args
->sequenceid
);
160 if (!result
) { CBX_ERR("sequence_ref.sequenceid"); goto out
; }
162 result
= xdr_u_int32_t(xdr
, &args
->slotid
);
163 if (!result
) { CBX_ERR("sequence_ref.slotid"); goto out
; }
168 static bool_t
op_cb_sequence_ref_list(XDR
*xdr
, struct cb_sequence_ref_list
*args
)
172 result
= xdr_opaque(xdr
, args
->sessionid
, NFS4_SESSIONID_SIZE
);
173 if (!result
) { CBX_ERR("sequence_ref_list.sessionid"); goto out
; }
175 result
= xdr_array(xdr
, (char**)&args
->calls
, &args
->call_count
,
176 64, sizeof(struct cb_sequence_ref
), (xdrproc_t
)op_cb_sequence_ref
);
177 if (!result
) { CBX_ERR("sequence_ref_list.calls"); goto out
; }
182 static bool_t
op_cb_sequence_args(XDR
*xdr
, struct cb_sequence_args
*args
)
186 result
= xdr_opaque(xdr
, args
->sessionid
, NFS4_SESSIONID_SIZE
);
187 if (!result
) { CBX_ERR("sequence_args.sessionid"); goto out
; }
189 result
= xdr_u_int32_t(xdr
, &args
->sequenceid
);
190 if (!result
) { CBX_ERR("sequence_args.sequenceid"); goto out
; }
192 result
= xdr_u_int32_t(xdr
, &args
->slotid
);
193 if (!result
) { CBX_ERR("sequence_args.slotid"); goto out
; }
195 result
= xdr_u_int32_t(xdr
, &args
->highest_slotid
);
196 if (!result
) { CBX_ERR("sequence_args.highest_slotid"); goto out
; }
198 result
= xdr_bool(xdr
, &args
->cachethis
);
199 if (!result
) { CBX_ERR("sequence_args.cachethis"); goto out
; }
201 result
= xdr_array(xdr
, (char**)&args
->ref_lists
,
202 &args
->ref_list_count
, 64, sizeof(struct cb_sequence_ref_list
),
203 (xdrproc_t
)op_cb_sequence_ref_list
);
204 if (!result
) { CBX_ERR("sequence_args.ref_lists"); goto out
; }
209 static bool_t
op_cb_sequence_res_ok(XDR
*xdr
, struct cb_sequence_res_ok
*res
)
213 result
= xdr_opaque(xdr
, res
->sessionid
, NFS4_SESSIONID_SIZE
);
214 if (!result
) { CBX_ERR("sequence_res.sessionid"); goto out
; }
216 result
= xdr_u_int32_t(xdr
, &res
->sequenceid
);
217 if (!result
) { CBX_ERR("sequence_res.sequenceid"); goto out
; }
219 result
= xdr_u_int32_t(xdr
, &res
->slotid
);
220 if (!result
) { CBX_ERR("sequence_res.slotid"); goto out
; }
222 result
= xdr_u_int32_t(xdr
, &res
->highest_slotid
);
223 if (!result
) { CBX_ERR("sequence_res.highest_slotid"); goto out
; }
225 result
= xdr_u_int32_t(xdr
, &res
->target_highest_slotid
);
226 if (!result
) { CBX_ERR("sequence_res.target_highest_slotid"); goto out
; }
231 static const struct xdr_discrim cb_sequence_res_discrim
[] = {
232 { NFS4_OK
, (xdrproc_t
)op_cb_sequence_res_ok
},
233 { 0, NULL_xdrproc_t
}
236 static bool_t
op_cb_sequence_res(XDR
*xdr
, struct cb_sequence_res
*res
)
240 result
= xdr_union(xdr
, &res
->status
, (char*)&res
->ok
,
241 cb_sequence_res_discrim
, (xdrproc_t
)xdr_void
);
242 if (!result
) { CBX_ERR("seq:argop.args"); goto out
; }
248 static bool_t
op_cb_getattr_args(XDR
*xdr
, struct cb_getattr_args
*args
)
252 result
= common_fh(xdr
, &args
->fh
);
253 if (!result
) { CBX_ERR("getattr.fh"); goto out
; }
255 result
= xdr_bitmap4(xdr
, &args
->attr_request
);
256 if (!result
) { CBX_ERR("getattr.attr_request"); goto out
; }
261 static bool_t
info_to_fattr4(nfs41_file_info
*info
, fattr4
*fattr
)
264 bool_t result
= TRUE
;
266 /* encode nfs41_file_info into fattr4 */
267 xdrmem_create(&fattr_xdr
, (char*)fattr
->attr_vals
,
268 NFS4_OPAQUE_LIMIT
, XDR_ENCODE
);
270 /* The only attributes that the server can reliably
271 * query via CB_GETATTR are size and change. */
272 if (bitmap_isset(&info
->attrmask
, 0, FATTR4_WORD0_CHANGE
)) {
273 result
= xdr_u_hyper(&fattr_xdr
, &info
->change
);
274 if (!result
) { CBX_ERR("getattr.info.change"); goto out
; }
275 bitmap_set(&fattr
->attrmask
, 0, FATTR4_WORD0_CHANGE
);
277 if (bitmap_isset(&info
->attrmask
, 0, FATTR4_WORD0_SIZE
)) {
278 result
= xdr_u_hyper(&fattr_xdr
, &info
->size
);
279 if (!result
) { CBX_ERR("getattr.info.size"); goto out
; }
280 bitmap_set(&fattr
->attrmask
, 0, FATTR4_WORD0_SIZE
);
282 fattr
->attr_vals_len
= xdr_getpos(&fattr_xdr
);
287 static bool_t
op_cb_getattr_res(XDR
*xdr
, struct cb_getattr_res
*res
)
291 result
= xdr_enum(xdr
, &res
->status
);
292 if (!result
) { CBX_ERR("getattr.status"); goto out
; }
294 if (res
->status
== NFS4_OK
) {
295 fattr4 fattr
= { 0 };
297 result
= info_to_fattr4(&res
->info
, &fattr
);
298 if (!result
) { goto out
; }
300 result
= xdr_fattr4(xdr
, &fattr
);
301 if (!result
) { CBX_ERR("getattr.obj_attributes"); goto out
; }
308 static bool_t
op_cb_recall_args(XDR
*xdr
, struct cb_recall_args
*args
)
312 result
= common_stateid(xdr
, &args
->stateid
);
313 if (!result
) { CBX_ERR("recall.stateid"); goto out
; }
315 result
= xdr_bool(xdr
, &args
->truncate
);
316 if (!result
) { CBX_ERR("recall.truncate"); goto out
; }
318 result
= common_fh(xdr
, &args
->fh
);
319 if (!result
) { CBX_ERR("recall.fh"); goto out
; }
324 static bool_t
op_cb_recall_res(XDR
*xdr
, struct cb_recall_res
*res
)
328 result
= xdr_enum(xdr
, &res
->status
);
329 if (!result
) { CBX_ERR("recall.status"); goto out
; }
335 static bool_t
op_cb_notify_args(XDR
*xdr
, struct cb_notify_args
*res
)
339 result
= xdr_u_int32_t(xdr
, &res
->target_highest_slotid
);
340 if (!result
) { CBX_ERR("notify.target_highest_slotid"); goto out
; }
345 static bool_t
op_cb_notify_res(XDR
*xdr
, struct cb_notify_res
*res
)
349 result
= xdr_enum(xdr
, &res
->status
);
350 if (!result
) { CBX_ERR("notify.status"); goto out
; }
355 /* OP_CB_PUSH_DELEG */
356 static bool_t
op_cb_push_deleg_args(XDR
*xdr
, struct cb_push_deleg_args
*res
)
360 result
= xdr_u_int32_t(xdr
, &res
->target_highest_slotid
);
361 if (!result
) { CBX_ERR("push_deleg.target_highest_slotid"); goto out
; }
366 static bool_t
op_cb_push_deleg_res(XDR
*xdr
, struct cb_push_deleg_res
*res
)
370 result
= xdr_enum(xdr
, &res
->status
);
371 if (!result
) { CBX_ERR("push_deleg.status"); goto out
; }
376 /* OP_CB_RECALL_ANY */
377 static bool_t
op_cb_recall_any_args(XDR
*xdr
, struct cb_recall_any_args
*res
)
381 result
= xdr_u_int32_t(xdr
, &res
->target_highest_slotid
);
382 if (!result
) { CBX_ERR("recall_any.target_highest_slotid"); goto out
; }
387 static bool_t
op_cb_recall_any_res(XDR
*xdr
, struct cb_recall_any_res
*res
)
391 result
= xdr_enum(xdr
, &res
->status
);
392 if (!result
) { CBX_ERR("recall_any.status"); goto out
; }
397 /* OP_CB_RECALLABLE_OBJ_AVAIL */
398 static bool_t
op_cb_recallable_obj_avail_args(XDR
*xdr
, struct cb_recallable_obj_avail_args
*res
)
402 result
= xdr_u_int32_t(xdr
, &res
->target_highest_slotid
);
403 if (!result
) { CBX_ERR("recallable_obj_avail.target_highest_slotid"); goto out
; }
408 static bool_t
op_cb_recallable_obj_avail_res(XDR
*xdr
, struct cb_recallable_obj_avail_res
*res
)
412 result
= xdr_enum(xdr
, &res
->status
);
413 if (!result
) { CBX_ERR("recallable_obj_avail.status"); goto out
; }
418 /* OP_CB_WANTS_CANCELLED */
419 static bool_t
op_cb_wants_cancelled_args(XDR
*xdr
, struct cb_wants_cancelled_args
*res
)
423 result
= xdr_u_int32_t(xdr
, &res
->target_highest_slotid
);
424 if (!result
) { CBX_ERR("wants_cancelled.target_highest_slotid"); goto out
; }
429 static bool_t
op_cb_wants_cancelled_res(XDR
*xdr
, struct cb_wants_cancelled_res
*res
)
433 result
= xdr_enum(xdr
, &res
->status
);
434 if (!result
) { CBX_ERR("wants_cancelled.status"); goto out
; }
439 /* OP_CB_NOTIFY_LOCK */
440 static bool_t
op_cb_notify_lock_args(XDR
*xdr
, struct cb_notify_lock_args
*res
)
444 result
= xdr_u_int32_t(xdr
, &res
->target_highest_slotid
);
445 if (!result
) { CBX_ERR("notify_lock.target_highest_slotid"); goto out
; }
450 static bool_t
op_cb_notify_lock_res(XDR
*xdr
, struct cb_notify_lock_res
*res
)
454 result
= xdr_enum(xdr
, &res
->status
);
455 if (!result
) { CBX_ERR("notify_lock.status"); goto out
; }
460 /* OP_CB_NOTIFY_DEVICEID */
461 static bool_t
cb_notify_deviceid_change(XDR
*xdr
, struct notify_deviceid4
*change
)
465 result
= xdr_u_int32_t(xdr
, (uint32_t*)&change
->layouttype
);
466 if (!result
) { CBX_ERR("notify_deviceid.change.layouttype"); goto out
; }
468 result
= xdr_opaque(xdr
, (char*)change
->deviceid
, PNFS_DEVICEID_SIZE
);
469 if (!result
) { CBX_ERR("notify_deviceid.change.deviceid"); goto out
; }
471 result
= xdr_bool(xdr
, &change
->immediate
);
472 if (!result
) { CBX_ERR("notify_deviceid.change.immediate"); goto out
; }
477 static bool_t
cb_notify_deviceid_delete(XDR
*xdr
, struct notify_deviceid4
*change
)
481 result
= xdr_u_int32_t(xdr
, (uint32_t*)&change
->layouttype
);
482 if (!result
) { CBX_ERR("notify_deviceid.delete.layouttype"); goto out
; }
484 result
= xdr_opaque(xdr
, (char*)change
->deviceid
, PNFS_DEVICEID_SIZE
);
485 if (!result
) { CBX_ERR("notify_deviceid.delete.deviceid"); goto out
; }
490 static bool_t
op_cb_notify_deviceid_args(XDR
*xdr
, struct cb_notify_deviceid_args
*args
)
496 /* decode the generic notify4 list */
497 result
= xdr_array(xdr
, (char**)&args
->notify_list
,
498 &args
->notify_count
, CB_COMPOUND_MAX_OPERATIONS
,
499 sizeof(struct notify4
), (xdrproc_t
)common_notify4
);
500 if (!result
) { CBX_ERR("notify_deviceid.notify_list"); goto out
; }
504 free(args
->change_list
);
509 /* count the number of device changes */
510 args
->change_count
= 0;
511 for (i
= 0; i
< args
->notify_count
; i
++)
512 args
->change_count
+= args
->notify_list
[i
].mask
.count
;
514 args
->change_list
= calloc(args
->change_count
, sizeof(struct notify_deviceid4
));
515 if (args
->change_list
== NULL
)
519 for (i
= 0; i
< args
->notify_count
; i
++) {
520 struct notify4
*notify
= &args
->notify_list
[i
];
522 /* decode the device notifications out of the opaque buffer */
523 xdrmem_create(¬ify_xdr
, notify
->list
, notify
->len
, XDR_DECODE
);
525 for (j
= 0; j
< notify
->mask
.count
; j
++) {
526 struct notify_deviceid4
*change
= &args
->change_list
[c
++];
527 change
->type
= notify
->mask
.arr
[j
];
529 switch (change
->type
) {
530 case NOTIFY_DEVICEID4_CHANGE
:
531 result
= cb_notify_deviceid_change(¬ify_xdr
, change
);
532 if (!result
) { CBX_ERR("notify_deviceid.change"); goto out
; }
534 case NOTIFY_DEVICEID4_DELETE
:
535 result
= cb_notify_deviceid_delete(¬ify_xdr
, change
);
536 if (!result
) { CBX_ERR("notify_deviceid.delete"); goto out
; }
545 static bool_t
op_cb_notify_deviceid_res(XDR
*xdr
, struct cb_notify_deviceid_res
*res
)
549 result
= xdr_enum(xdr
, &res
->status
);
550 if (!result
) { CBX_ERR("notify_deviceid.status"); goto out
; }
556 static bool_t
cb_compound_tag(XDR
*xdr
, struct cb_compound_tag
*args
)
558 return xdr_u_int32_t(xdr
, &args
->len
)
559 && args
->len
<= CB_COMPOUND_MAX_TAG
560 && xdr_opaque(xdr
, args
->str
, args
->len
);
563 static const struct xdr_discrim cb_argop_discrim
[] = {
564 { OP_CB_LAYOUTRECALL
, (xdrproc_t
)op_cb_layoutrecall_args
},
565 { OP_CB_RECALL_SLOT
, (xdrproc_t
)op_cb_recall_slot_args
},
566 { OP_CB_SEQUENCE
, (xdrproc_t
)op_cb_sequence_args
},
567 { OP_CB_GETATTR
, (xdrproc_t
)op_cb_getattr_args
},
568 { OP_CB_RECALL
, (xdrproc_t
)op_cb_recall_args
},
569 { OP_CB_NOTIFY
, (xdrproc_t
)op_cb_notify_args
},
570 { OP_CB_PUSH_DELEG
, (xdrproc_t
)op_cb_push_deleg_args
},
571 { OP_CB_RECALL_ANY
, (xdrproc_t
)op_cb_recall_any_args
},
572 { OP_CB_RECALLABLE_OBJ_AVAIL
, (xdrproc_t
)op_cb_recallable_obj_avail_args
},
573 { OP_CB_WANTS_CANCELLED
, (xdrproc_t
)op_cb_wants_cancelled_args
},
574 { OP_CB_NOTIFY_LOCK
, (xdrproc_t
)op_cb_notify_lock_args
},
575 { OP_CB_NOTIFY_DEVICEID
, (xdrproc_t
)op_cb_notify_deviceid_args
},
576 { OP_CB_ILLEGAL
, NULL_xdrproc_t
},
579 static bool_t
cb_compound_argop(XDR
*xdr
, struct cb_argop
*args
)
583 result
= xdr_union(xdr
, &args
->opnum
, (char*)&args
->args
,
584 cb_argop_discrim
, NULL_xdrproc_t
);
585 if (!result
) { CBX_ERR("cmb:argop.args"); goto out
; }
590 bool_t
proc_cb_compound_args(XDR
*xdr
, struct cb_compound_args
*args
)
594 result
= cb_compound_tag(xdr
, &args
->tag
);
595 if (!result
) { CBX_ERR("compound.tag"); goto out
; }
597 result
= xdr_u_int32_t(xdr
, &args
->minorversion
);
598 if (!result
) { CBX_ERR("compound.minorversion"); goto out
; }
600 /* "superfluous in NFSv4.1 and MUST be ignored by the client" */
601 result
= xdr_u_int32_t(xdr
, &args
->callback_ident
);
602 if (!result
) { CBX_ERR("compound.callback_ident"); goto out
; }
604 result
= xdr_array(xdr
, (char**)&args
->argarray
,
605 &args
->argarray_count
, CB_COMPOUND_MAX_OPERATIONS
,
606 sizeof(struct cb_argop
), (xdrproc_t
)cb_compound_argop
);
607 if (!result
) { CBX_ERR("compound.argarray"); goto out
; }
612 static const struct xdr_discrim cb_resop_discrim
[] = {
613 { OP_CB_LAYOUTRECALL
, (xdrproc_t
)op_cb_layoutrecall_res
},
614 { OP_CB_RECALL_SLOT
, (xdrproc_t
)op_cb_recall_slot_res
},
615 { OP_CB_SEQUENCE
, (xdrproc_t
)op_cb_sequence_res
},
616 { OP_CB_GETATTR
, (xdrproc_t
)op_cb_getattr_res
},
617 { OP_CB_RECALL
, (xdrproc_t
)op_cb_recall_res
},
618 { OP_CB_NOTIFY
, (xdrproc_t
)op_cb_notify_res
},
619 { OP_CB_PUSH_DELEG
, (xdrproc_t
)op_cb_push_deleg_res
},
620 { OP_CB_RECALL_ANY
, (xdrproc_t
)op_cb_recall_any_res
},
621 { OP_CB_RECALLABLE_OBJ_AVAIL
, (xdrproc_t
)op_cb_recallable_obj_avail_res
},
622 { OP_CB_WANTS_CANCELLED
, (xdrproc_t
)op_cb_wants_cancelled_res
},
623 { OP_CB_NOTIFY_LOCK
, (xdrproc_t
)op_cb_notify_lock_res
},
624 { OP_CB_NOTIFY_DEVICEID
, (xdrproc_t
)op_cb_notify_deviceid_res
},
625 { OP_CB_ILLEGAL
, NULL_xdrproc_t
},
628 static bool_t
cb_compound_resop(XDR
*xdr
, struct cb_resop
*res
)
630 /* save xdr encode/decode status to see which operation failed */
631 res
->xdr_ok
= xdr_union(xdr
, &res
->opnum
, (char*)&res
->res
,
632 cb_resop_discrim
, NULL_xdrproc_t
);
633 if (!res
->xdr_ok
) { CBX_ERR("resop.res"); goto out
; }
638 bool_t
proc_cb_compound_res(XDR
*xdr
, struct cb_compound_res
*res
)
645 result
= xdr_enum(xdr
, &res
->status
);
646 if (!result
) { CBX_ERR("compound_res.status"); goto out
; }
648 result
= cb_compound_tag(xdr
, &res
->tag
);
649 if (!result
) { CBX_ERR("compound_res.tag"); goto out
; }
651 result
= xdr_array(xdr
, (char**)&res
->resarray
,
652 &res
->resarray_count
, CB_COMPOUND_MAX_OPERATIONS
,
653 sizeof(struct cb_resop
), (xdrproc_t
)cb_compound_resop
);
654 if (!result
) { CBX_ERR("compound_res.resarray"); goto out
; }
656 if (xdr
->x_op
== XDR_FREE
)