| 382 | } |
| 383 | |
| 384 | int |
| 385 | validate_uuid(const char *str, size_t size, struct uuid *uuid, int flags) |
| 386 | { |
| 387 | u_int c[11]; |
| 388 | int n; |
| 389 | |
| 390 | if (size == 0 || *str == '\0') { |
| 391 | /* An empty string may represent a nil UUID. */ |
| 392 | if ((flags & VUUIDF_EMPTYOK) != 0) { |
| 393 | if (uuid != NULL) |
| 394 | bzero(uuid, sizeof(*uuid)); |
| 395 | return (0); |
| 396 | } |
| 397 | |
| 398 | return (EINVAL); |
| 399 | } |
| 400 | |
| 401 | /* The UUID string representation has a fixed length. */ |
| 402 | if (size != 36) |
| 403 | return (EINVAL); |
| 404 | |
| 405 | /* |
| 406 | * We only work with "new" UUIDs. New UUIDs have the form: |
| 407 | * 01234567-89ab-cdef-0123-456789abcdef |
| 408 | * The so called "old" UUIDs, which we don't support, have the form: |
| 409 | * 0123456789ab.cd.ef.01.23.45.67.89.ab |
| 410 | */ |
| 411 | if (str[8] != '-') |
| 412 | return (EINVAL); |
| 413 | |
| 414 | /* Now check the format. */ |
| 415 | n = sscanf(str, "%8x-%4x-%4x-%2x%2x-%2x%2x%2x%2x%2x%2x", c + 0, c + 1, |
| 416 | c + 2, c + 3, c + 4, c + 5, c + 6, c + 7, c + 8, c + 9, c + 10); |
| 417 | /* Make sure we have all conversions. */ |
| 418 | if (n != 11) |
| 419 | return (EINVAL); |
| 420 | |
| 421 | /* Successful scan. Build the UUID if requested. */ |
| 422 | if (uuid != NULL) { |
| 423 | uuid->time_low = c[0]; |
| 424 | uuid->time_mid = c[1]; |
| 425 | uuid->time_hi_and_version = c[2]; |
| 426 | uuid->clock_seq_hi_and_reserved = c[3]; |
| 427 | uuid->clock_seq_low = c[4]; |
| 428 | for (n = 0; n < 6; n++) |
| 429 | uuid->node[n] = c[n + 5]; |
| 430 | } |
| 431 | |
| 432 | if ((flags & VUUIDF_CHECKSEMANTICS) == 0) |
| 433 | return (0); |
| 434 | |
| 435 | return (((c[3] & 0x80) != 0x00 && /* variant 0? */ |
| 436 | (c[3] & 0xc0) != 0x80 && /* variant 1? */ |
| 437 | (c[3] & 0xe0) != 0xc0) ? EINVAL : 0); /* variant 2? */ |
| 438 | } |
| 439 | |
| 440 | #define VUUIDF_PARSEFLAGS (VUUIDF_EMPTYOK | VUUIDF_CHECKSEMANTICS) |
| 441 |
no test coverage detected