1 /* NFSv4.1 client for Windows 2 * Copyright � 2012 The Regents of the University of Michigan 3 * 4 * Olga Kornievskaia <aglo@umich.edu> 5 * Casey Bodley <cbodley@umich.edu> 6 * 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. 11 * 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. 16 * 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 20 */ 21 22 #include "nfs41_callback.h" 23 #include "nfs41_ops.h" 24 #include "util.h" 25 #include "daemon_debug.h" 26 27 28 #define CBXLVL 2 /* dprintf level for callback xdr logging */ 29 #ifdef __REACTOS__ 30 #define CBX_ERR(msg) dprintf((CBXLVL), "%s: failed at %s\n", __FUNCTION__, msg) 31 #else 32 #define CBX_ERR(msg) dprintf((CBXLVL), __FUNCTION__ ": failed at " msg "\n") 33 #endif 34 35 /* common types */ 36 bool_t xdr_bitmap4(XDR *xdr, bitmap4 *bitmap); 37 bool_t xdr_fattr4(XDR *xdr, fattr4 *fattr); 38 39 static bool_t common_stateid(XDR *xdr, stateid4 *stateid) 40 { 41 return xdr_u_int32_t(xdr, &stateid->seqid) 42 && xdr_opaque(xdr, (char*)stateid->other, NFS4_STATEID_OTHER); 43 } 44 45 static bool_t common_fh(XDR *xdr, nfs41_fh *fh) 46 { 47 return xdr_u_int32_t(xdr, &fh->len) 48 && fh->len <= NFS4_FHSIZE 49 && xdr_opaque(xdr, (char*)fh->fh, fh->len); 50 } 51 52 static bool_t common_fsid(XDR *xdr, nfs41_fsid *fsid) 53 { 54 return xdr_u_int64_t(xdr, &fsid->major) 55 && xdr_u_int64_t(xdr, &fsid->minor); 56 } 57 58 static bool_t common_notify4(XDR *xdr, struct notify4 *notify) 59 { 60 return xdr_bitmap4(xdr, ¬ify->mask) 61 && xdr_bytes(xdr, ¬ify->list, ¬ify->len, NFS4_OPAQUE_LIMIT); 62 } 63 64 /* OP_CB_LAYOUTRECALL */ 65 static bool_t op_cb_layoutrecall_file(XDR *xdr, struct cb_recall_file *args) 66 { 67 bool_t result; 68 69 result = common_fh(xdr, &args->fh); 70 if (!result) { CBX_ERR("layoutrecall_file.fh"); goto out; } 71 72 result = xdr_u_int64_t(xdr, &args->offset); 73 if (!result) { CBX_ERR("layoutrecall_file.offset"); goto out; } 74 75 result = xdr_u_int64_t(xdr, &args->length); 76 if (!result) { CBX_ERR("layoutrecall_file.length"); goto out; } 77 78 result = common_stateid(xdr, &args->stateid); 79 if (!result) { CBX_ERR("layoutrecall_file.stateid"); goto out; } 80 out: 81 return result; 82 } 83 84 static bool_t op_cb_layoutrecall_fsid(XDR *xdr, union cb_recall_file_args *args) 85 { 86 bool_t result; 87 88 result = common_fsid(xdr, &args->fsid); 89 if (!result) { CBX_ERR("layoutrecall_fsid.fsid"); goto out; } 90 out: 91 return result; 92 } 93 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 }, 98 { 0, NULL_xdrproc_t } 99 }; 100 101 static bool_t op_cb_layoutrecall_args(XDR *xdr, struct cb_layoutrecall_args *args) 102 { 103 bool_t result; 104 105 result = xdr_enum(xdr, (enum_t*)&args->type); 106 if (!result) { CBX_ERR("layoutrecall_args.type"); goto out; } 107 108 result = xdr_enum(xdr, (enum_t*)&args->iomode); 109 if (!result) { CBX_ERR("layoutrecall_args.iomode"); goto out; } 110 111 result = xdr_bool(xdr, &args->changed); 112 if (!result) { CBX_ERR("layoutrecall_args.changed"); goto out; } 113 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; } 117 out: 118 return result; 119 } 120 121 static bool_t op_cb_layoutrecall_res(XDR *xdr, struct cb_layoutrecall_res *res) 122 { 123 bool_t result; 124 125 result = xdr_enum(xdr, &res->status); 126 if (!result) { CBX_ERR("layoutrecall_res.status"); goto out; } 127 out: 128 return result; 129 } 130 131 132 /* OP_CB_RECALL_SLOT */ 133 static bool_t op_cb_recall_slot_args(XDR *xdr, struct cb_recall_slot_args *res) 134 { 135 bool_t result; 136 137 result = xdr_u_int32_t(xdr, &res->target_highest_slotid); 138 if (!result) { CBX_ERR("recall_slot.target_highest_slotid"); goto out; } 139 out: 140 return result; 141 } 142 143 static bool_t op_cb_recall_slot_res(XDR *xdr, struct cb_recall_slot_res *res) 144 { 145 bool_t result; 146 147 result = xdr_enum(xdr, &res->status); 148 if (!result) { CBX_ERR("recall_slot.status"); goto out; } 149 out: 150 return result; 151 } 152 153 154 /* OP_CB_SEQUENCE */ 155 static bool_t op_cb_sequence_ref(XDR *xdr, struct cb_sequence_ref *args) 156 { 157 bool_t result; 158 159 result = xdr_u_int32_t(xdr, &args->sequenceid); 160 if (!result) { CBX_ERR("sequence_ref.sequenceid"); goto out; } 161 162 result = xdr_u_int32_t(xdr, &args->slotid); 163 if (!result) { CBX_ERR("sequence_ref.slotid"); goto out; } 164 out: 165 return result; 166 } 167 168 static bool_t op_cb_sequence_ref_list(XDR *xdr, struct cb_sequence_ref_list *args) 169 { 170 bool_t result; 171 172 result = xdr_opaque(xdr, args->sessionid, NFS4_SESSIONID_SIZE); 173 if (!result) { CBX_ERR("sequence_ref_list.sessionid"); goto out; } 174 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; } 178 out: 179 return result; 180 } 181 182 static bool_t op_cb_sequence_args(XDR *xdr, struct cb_sequence_args *args) 183 { 184 bool_t result; 185 186 result = xdr_opaque(xdr, args->sessionid, NFS4_SESSIONID_SIZE); 187 if (!result) { CBX_ERR("sequence_args.sessionid"); goto out; } 188 189 result = xdr_u_int32_t(xdr, &args->sequenceid); 190 if (!result) { CBX_ERR("sequence_args.sequenceid"); goto out; } 191 192 result = xdr_u_int32_t(xdr, &args->slotid); 193 if (!result) { CBX_ERR("sequence_args.slotid"); goto out; } 194 195 result = xdr_u_int32_t(xdr, &args->highest_slotid); 196 if (!result) { CBX_ERR("sequence_args.highest_slotid"); goto out; } 197 198 result = xdr_bool(xdr, &args->cachethis); 199 if (!result) { CBX_ERR("sequence_args.cachethis"); goto out; } 200 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; } 205 out: 206 return result; 207 } 208 209 static bool_t op_cb_sequence_res_ok(XDR *xdr, struct cb_sequence_res_ok *res) 210 { 211 bool_t result; 212 213 result = xdr_opaque(xdr, res->sessionid, NFS4_SESSIONID_SIZE); 214 if (!result) { CBX_ERR("sequence_res.sessionid"); goto out; } 215 216 result = xdr_u_int32_t(xdr, &res->sequenceid); 217 if (!result) { CBX_ERR("sequence_res.sequenceid"); goto out; } 218 219 result = xdr_u_int32_t(xdr, &res->slotid); 220 if (!result) { CBX_ERR("sequence_res.slotid"); goto out; } 221 222 result = xdr_u_int32_t(xdr, &res->highest_slotid); 223 if (!result) { CBX_ERR("sequence_res.highest_slotid"); goto out; } 224 225 result = xdr_u_int32_t(xdr, &res->target_highest_slotid); 226 if (!result) { CBX_ERR("sequence_res.target_highest_slotid"); goto out; } 227 out: 228 return result; 229 } 230 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 } 234 }; 235 236 static bool_t op_cb_sequence_res(XDR *xdr, struct cb_sequence_res *res) 237 { 238 bool_t result; 239 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; } 243 out: 244 return result; 245 } 246 247 /* OP_CB_GETATTR */ 248 static bool_t op_cb_getattr_args(XDR *xdr, struct cb_getattr_args *args) 249 { 250 bool_t result; 251 252 result = common_fh(xdr, &args->fh); 253 if (!result) { CBX_ERR("getattr.fh"); goto out; } 254 255 result = xdr_bitmap4(xdr, &args->attr_request); 256 if (!result) { CBX_ERR("getattr.attr_request"); goto out; } 257 out: 258 return result; 259 } 260 261 static bool_t info_to_fattr4(nfs41_file_info *info, fattr4 *fattr) 262 { 263 XDR fattr_xdr; 264 bool_t result = TRUE; 265 266 /* encode nfs41_file_info into fattr4 */ 267 xdrmem_create(&fattr_xdr, (char*)fattr->attr_vals, 268 NFS4_OPAQUE_LIMIT, XDR_ENCODE); 269 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); 276 } 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); 281 } 282 fattr->attr_vals_len = xdr_getpos(&fattr_xdr); 283 out: 284 return result; 285 } 286 287 static bool_t op_cb_getattr_res(XDR *xdr, struct cb_getattr_res *res) 288 { 289 bool_t result; 290 291 result = xdr_enum(xdr, &res->status); 292 if (!result) { CBX_ERR("getattr.status"); goto out; } 293 294 if (res->status == NFS4_OK) { 295 fattr4 fattr = { 0 }; 296 297 result = info_to_fattr4(&res->info, &fattr); 298 if (!result) { goto out; } 299 300 result = xdr_fattr4(xdr, &fattr); 301 if (!result) { CBX_ERR("getattr.obj_attributes"); goto out; } 302 } 303 out: 304 return result; 305 } 306 307 /* OP_CB_RECALL */ 308 static bool_t op_cb_recall_args(XDR *xdr, struct cb_recall_args *args) 309 { 310 bool_t result; 311 312 result = common_stateid(xdr, &args->stateid); 313 if (!result) { CBX_ERR("recall.stateid"); goto out; } 314 315 result = xdr_bool(xdr, &args->truncate); 316 if (!result) { CBX_ERR("recall.truncate"); goto out; } 317 318 result = common_fh(xdr, &args->fh); 319 if (!result) { CBX_ERR("recall.fh"); goto out; } 320 out: 321 return result; 322 } 323 324 static bool_t op_cb_recall_res(XDR *xdr, struct cb_recall_res *res) 325 { 326 bool_t result; 327 328 result = xdr_enum(xdr, &res->status); 329 if (!result) { CBX_ERR("recall.status"); goto out; } 330 out: 331 return result; 332 } 333 334 /* OP_CB_NOTIFY */ 335 static bool_t op_cb_notify_args(XDR *xdr, struct cb_notify_args *res) 336 { 337 bool_t result; 338 339 result = xdr_u_int32_t(xdr, &res->target_highest_slotid); 340 if (!result) { CBX_ERR("notify.target_highest_slotid"); goto out; } 341 out: 342 return result; 343 } 344 345 static bool_t op_cb_notify_res(XDR *xdr, struct cb_notify_res *res) 346 { 347 bool_t result; 348 349 result = xdr_enum(xdr, &res->status); 350 if (!result) { CBX_ERR("notify.status"); goto out; } 351 out: 352 return result; 353 } 354 355 /* OP_CB_PUSH_DELEG */ 356 static bool_t op_cb_push_deleg_args(XDR *xdr, struct cb_push_deleg_args *res) 357 { 358 bool_t result; 359 360 result = xdr_u_int32_t(xdr, &res->target_highest_slotid); 361 if (!result) { CBX_ERR("push_deleg.target_highest_slotid"); goto out; } 362 out: 363 return result; 364 } 365 366 static bool_t op_cb_push_deleg_res(XDR *xdr, struct cb_push_deleg_res *res) 367 { 368 bool_t result; 369 370 result = xdr_enum(xdr, &res->status); 371 if (!result) { CBX_ERR("push_deleg.status"); goto out; } 372 out: 373 return result; 374 } 375 376 /* OP_CB_RECALL_ANY */ 377 static bool_t op_cb_recall_any_args(XDR *xdr, struct cb_recall_any_args *res) 378 { 379 bool_t result; 380 381 result = xdr_u_int32_t(xdr, &res->target_highest_slotid); 382 if (!result) { CBX_ERR("recall_any.target_highest_slotid"); goto out; } 383 out: 384 return result; 385 } 386 387 static bool_t op_cb_recall_any_res(XDR *xdr, struct cb_recall_any_res *res) 388 { 389 bool_t result; 390 391 result = xdr_enum(xdr, &res->status); 392 if (!result) { CBX_ERR("recall_any.status"); goto out; } 393 out: 394 return result; 395 } 396 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) 399 { 400 bool_t result; 401 402 result = xdr_u_int32_t(xdr, &res->target_highest_slotid); 403 if (!result) { CBX_ERR("recallable_obj_avail.target_highest_slotid"); goto out; } 404 out: 405 return result; 406 } 407 408 static bool_t op_cb_recallable_obj_avail_res(XDR *xdr, struct cb_recallable_obj_avail_res *res) 409 { 410 bool_t result; 411 412 result = xdr_enum(xdr, &res->status); 413 if (!result) { CBX_ERR("recallable_obj_avail.status"); goto out; } 414 out: 415 return result; 416 } 417 418 /* OP_CB_WANTS_CANCELLED */ 419 static bool_t op_cb_wants_cancelled_args(XDR *xdr, struct cb_wants_cancelled_args *res) 420 { 421 bool_t result; 422 423 result = xdr_u_int32_t(xdr, &res->target_highest_slotid); 424 if (!result) { CBX_ERR("wants_cancelled.target_highest_slotid"); goto out; } 425 out: 426 return result; 427 } 428 429 static bool_t op_cb_wants_cancelled_res(XDR *xdr, struct cb_wants_cancelled_res *res) 430 { 431 bool_t result; 432 433 result = xdr_enum(xdr, &res->status); 434 if (!result) { CBX_ERR("wants_cancelled.status"); goto out; } 435 out: 436 return result; 437 } 438 439 /* OP_CB_NOTIFY_LOCK */ 440 static bool_t op_cb_notify_lock_args(XDR *xdr, struct cb_notify_lock_args *res) 441 { 442 bool_t result; 443 444 result = xdr_u_int32_t(xdr, &res->target_highest_slotid); 445 if (!result) { CBX_ERR("notify_lock.target_highest_slotid"); goto out; } 446 out: 447 return result; 448 } 449 450 static bool_t op_cb_notify_lock_res(XDR *xdr, struct cb_notify_lock_res *res) 451 { 452 bool_t result; 453 454 result = xdr_enum(xdr, &res->status); 455 if (!result) { CBX_ERR("notify_lock.status"); goto out; } 456 out: 457 return result; 458 } 459 460 /* OP_CB_NOTIFY_DEVICEID */ 461 static bool_t cb_notify_deviceid_change(XDR *xdr, struct notify_deviceid4 *change) 462 { 463 bool_t result; 464 465 result = xdr_u_int32_t(xdr, (uint32_t*)&change->layouttype); 466 if (!result) { CBX_ERR("notify_deviceid.change.layouttype"); goto out; } 467 468 result = xdr_opaque(xdr, (char*)change->deviceid, PNFS_DEVICEID_SIZE); 469 if (!result) { CBX_ERR("notify_deviceid.change.deviceid"); goto out; } 470 471 result = xdr_bool(xdr, &change->immediate); 472 if (!result) { CBX_ERR("notify_deviceid.change.immediate"); goto out; } 473 out: 474 return result; 475 } 476 477 static bool_t cb_notify_deviceid_delete(XDR *xdr, struct notify_deviceid4 *change) 478 { 479 bool_t result; 480 481 result = xdr_u_int32_t(xdr, (uint32_t*)&change->layouttype); 482 if (!result) { CBX_ERR("notify_deviceid.delete.layouttype"); goto out; } 483 484 result = xdr_opaque(xdr, (char*)change->deviceid, PNFS_DEVICEID_SIZE); 485 if (!result) { CBX_ERR("notify_deviceid.delete.deviceid"); goto out; } 486 out: 487 return result; 488 } 489 490 static bool_t op_cb_notify_deviceid_args(XDR *xdr, struct cb_notify_deviceid_args *args) 491 { 492 XDR notify_xdr; 493 uint32_t i, j, c; 494 bool_t result; 495 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; } 501 502 switch (xdr->x_op) { 503 case XDR_FREE: 504 free(args->change_list); 505 case XDR_ENCODE: 506 return TRUE; 507 } 508 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; 513 514 args->change_list = calloc(args->change_count, sizeof(struct notify_deviceid4)); 515 if (args->change_list == NULL) 516 return FALSE; 517 518 c = 0; 519 for (i = 0; i < args->notify_count; i++) { 520 struct notify4 *notify = &args->notify_list[i]; 521 522 /* decode the device notifications out of the opaque buffer */ 523 xdrmem_create(¬ify_xdr, notify->list, notify->len, XDR_DECODE); 524 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]; 528 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; } 533 break; 534 case NOTIFY_DEVICEID4_DELETE: 535 result = cb_notify_deviceid_delete(¬ify_xdr, change); 536 if (!result) { CBX_ERR("notify_deviceid.delete"); goto out; } 537 break; 538 } 539 } 540 } 541 out: 542 return result; 543 } 544 545 static bool_t op_cb_notify_deviceid_res(XDR *xdr, struct cb_notify_deviceid_res *res) 546 { 547 bool_t result; 548 549 result = xdr_enum(xdr, &res->status); 550 if (!result) { CBX_ERR("notify_deviceid.status"); goto out; } 551 out: 552 return result; 553 } 554 555 /* CB_COMPOUND */ 556 static bool_t cb_compound_tag(XDR *xdr, struct cb_compound_tag *args) 557 { 558 return xdr_u_int32_t(xdr, &args->len) 559 && args->len <= CB_COMPOUND_MAX_TAG 560 && xdr_opaque(xdr, args->str, args->len); 561 } 562 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 }, 577 }; 578 579 static bool_t cb_compound_argop(XDR *xdr, struct cb_argop *args) 580 { 581 bool_t result; 582 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; } 586 out: 587 return result; 588 } 589 590 bool_t proc_cb_compound_args(XDR *xdr, struct cb_compound_args *args) 591 { 592 bool_t result; 593 594 result = cb_compound_tag(xdr, &args->tag); 595 if (!result) { CBX_ERR("compound.tag"); goto out; } 596 597 result = xdr_u_int32_t(xdr, &args->minorversion); 598 if (!result) { CBX_ERR("compound.minorversion"); goto out; } 599 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; } 603 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; } 608 out: 609 return result; 610 } 611 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 }, 626 }; 627 628 static bool_t cb_compound_resop(XDR *xdr, struct cb_resop *res) 629 { 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; } 634 out: 635 return res->xdr_ok; 636 } 637 638 bool_t proc_cb_compound_res(XDR *xdr, struct cb_compound_res *res) 639 { 640 bool_t result; 641 642 if (res == NULL) 643 return TRUE; 644 645 result = xdr_enum(xdr, &res->status); 646 if (!result) { CBX_ERR("compound_res.status"); goto out; } 647 648 result = cb_compound_tag(xdr, &res->tag); 649 if (!result) { CBX_ERR("compound_res.tag"); goto out; } 650 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; } 655 out: 656 if (xdr->x_op == XDR_FREE) 657 free(res); 658 return result; 659 } 660