1 /* 2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 /* IOData.m created by rsulack on Thu 25-Sep-1997 */ 29 30 #include <string.h> 31 32 #include <vm/vm_kern.h> 33 34 #define IOKIT_ENABLE_SHARED_PTR 35 36 #include <libkern/c++/OSData.h> 37 #include <libkern/c++/OSSerialize.h> 38 #include <libkern/c++/OSLib.h> 39 #include <libkern/c++/OSString.h> 40 #include <IOKit/IOLib.h> 41 42 #define super OSObject 43 44 OSDefineMetaClassAndStructorsWithZone(OSData, OSObject, ZC_ZFREE_CLEARMEM) 45 OSMetaClassDefineReservedUsedX86(OSData, 0); // setDeallocFunction 46 OSMetaClassDefineReservedUnused(OSData, 1); 47 OSMetaClassDefineReservedUnused(OSData, 2); 48 OSMetaClassDefineReservedUnused(OSData, 3); 49 OSMetaClassDefineReservedUnused(OSData, 4); 50 OSMetaClassDefineReservedUnused(OSData, 5); 51 OSMetaClassDefineReservedUnused(OSData, 6); 52 OSMetaClassDefineReservedUnused(OSData, 7); 53 54 #define EXTERNAL ((unsigned int) -1) 55 56 static SECURITY_READ_ONLY_LATE(vm_map_t) alloc_map; 57 __startup_func 58 static void 59 getAllocMap(void) 60 { 61 alloc_map = KHEAP_DATA_BUFFERS->kh_fallback_map; 62 } 63 STARTUP(ZALLOC, STARTUP_RANK_LAST, getAllocMap); 64 65 bool 66 OSData::initWithCapacity(unsigned int inCapacity) 67 { 68 void *_data = NULL; 69 70 if (data) { 71 OSCONTAINER_ACCUMSIZE(-((size_t)capacity)); 72 if (!inCapacity || (capacity < inCapacity)) { 73 // clean out old data's storage if it isn't big enough 74 if (capacity < page_size) { 75 kfree_data_container(data, capacity); 76 } else { 77 kmem_free(alloc_map, (vm_offset_t)data, capacity); 78 } 79 data = NULL; 80 capacity = 0; 81 } 82 } 83 84 if (!super::init()) { 85 return false; 86 } 87 88 if (inCapacity && !data) { 89 if (inCapacity < page_size) { 90 data = (void *)kalloc_data_container(inCapacity, Z_WAITOK); 91 } else { 92 kern_return_t kr; 93 if (round_page_overflow(inCapacity, &inCapacity)) { 94 kr = KERN_RESOURCE_SHORTAGE; 95 } else { 96 kr = kernel_memory_allocate(alloc_map, 97 (vm_offset_t *)&_data, inCapacity, 98 0, KMA_ATOMIC, IOMemoryTag(alloc_map)); 99 data = _data; 100 } 101 if (KERN_SUCCESS != kr) { 102 data = NULL; 103 } 104 } 105 if (!data) { 106 return false; 107 } 108 capacity = inCapacity; 109 } 110 OSCONTAINER_ACCUMSIZE(capacity); 111 112 length = 0; 113 if (inCapacity < 16) { 114 capacityIncrement = 16; 115 } else { 116 capacityIncrement = inCapacity; 117 } 118 119 return true; 120 } 121 122 bool 123 OSData::initWithBytes(const void *bytes, unsigned int inLength) 124 { 125 if ((inLength && !bytes) || !initWithCapacity(inLength)) { 126 return false; 127 } 128 129 if (bytes != data) { 130 bcopy(bytes, data, inLength); 131 } 132 length = inLength; 133 134 return true; 135 } 136 137 bool 138 OSData::initWithBytesNoCopy(void *bytes, unsigned int inLength) 139 { 140 if (!super::init()) { 141 return false; 142 } 143 144 length = inLength; 145 capacity = EXTERNAL; 146 data = bytes; 147 148 return true; 149 } 150 151 bool 152 OSData::initWithData(const OSData *inData) 153 { 154 return initWithBytes(inData->data, inData->length); 155 } 156 157 bool 158 OSData::initWithData(const OSData *inData, 159 unsigned int start, unsigned int inLength) 160 { 161 const void *localData = inData->getBytesNoCopy(start, inLength); 162 163 if (localData) { 164 return initWithBytes(localData, inLength); 165 } else { 166 return false; 167 } 168 } 169 170 OSSharedPtr<OSData> 171 OSData::withCapacity(unsigned int inCapacity) 172 { 173 OSSharedPtr<OSData> me = OSMakeShared<OSData>(); 174 175 if (me && !me->initWithCapacity(inCapacity)) { 176 return nullptr; 177 } 178 179 return me; 180 } 181 182 OSSharedPtr<OSData> 183 OSData::withBytes(const void *bytes, unsigned int inLength) 184 { 185 OSSharedPtr<OSData> me = OSMakeShared<OSData>(); 186 187 if (me && !me->initWithBytes(bytes, inLength)) { 188 return nullptr; 189 } 190 return me; 191 } 192 193 OSSharedPtr<OSData> 194 OSData::withBytesNoCopy(void *bytes, unsigned int inLength) 195 { 196 OSSharedPtr<OSData> me = OSMakeShared<OSData>(); 197 198 if (me && !me->initWithBytesNoCopy(bytes, inLength)) { 199 return nullptr; 200 } 201 202 return me; 203 } 204 205 OSSharedPtr<OSData> 206 OSData::withData(const OSData *inData) 207 { 208 OSSharedPtr<OSData> me = OSMakeShared<OSData>(); 209 210 if (me && !me->initWithData(inData)) { 211 return nullptr; 212 } 213 214 return me; 215 } 216 217 OSSharedPtr<OSData> 218 OSData::withData(const OSData *inData, 219 unsigned int start, unsigned int inLength) 220 { 221 OSSharedPtr<OSData> me = OSMakeShared<OSData>(); 222 223 if (me && !me->initWithData(inData, start, inLength)) { 224 return nullptr; 225 } 226 227 return me; 228 } 229 230 void 231 OSData::free() 232 { 233 if ((capacity != EXTERNAL) && data && capacity) { 234 if (capacity < page_size) { 235 kfree_data_container(data, capacity); 236 } else { 237 kmem_free(alloc_map, (vm_offset_t)data, capacity); 238 } 239 OSCONTAINER_ACCUMSIZE( -((size_t)capacity)); 240 } else if (capacity == EXTERNAL) { 241 DeallocFunction freemem = reserved ? reserved->deallocFunction : NULL; 242 if (freemem && data && length) { 243 freemem(data, length); 244 } 245 } 246 if (reserved) { 247 kfree_type(ExpansionData, reserved); 248 } 249 super::free(); 250 } 251 252 unsigned int 253 OSData::getLength() const 254 { 255 return length; 256 } 257 unsigned int 258 OSData::getCapacity() const 259 { 260 return capacity; 261 } 262 263 unsigned int 264 OSData::getCapacityIncrement() const 265 { 266 return capacityIncrement; 267 } 268 269 unsigned int 270 OSData::setCapacityIncrement(unsigned increment) 271 { 272 return capacityIncrement = increment; 273 } 274 275 // xx-review: does not check for capacity == EXTERNAL 276 277 unsigned int 278 OSData::ensureCapacity(unsigned int newCapacity) 279 { 280 unsigned char * newData; 281 unsigned int finalCapacity; 282 void * copydata; 283 kern_return_t kr; 284 285 if (newCapacity <= capacity) { 286 return capacity; 287 } 288 289 finalCapacity = (((newCapacity - 1) / capacityIncrement) + 1) 290 * capacityIncrement; 291 292 // integer overflow check 293 if (finalCapacity < newCapacity) { 294 return capacity; 295 } 296 297 copydata = data; 298 299 if (finalCapacity >= page_size) { 300 // round up 301 finalCapacity = round_page_32(finalCapacity); 302 // integer overflow check 303 if (finalCapacity < newCapacity) { 304 return capacity; 305 } 306 if (capacity >= page_size) { 307 copydata = NULL; 308 kr = kmem_realloc(alloc_map, 309 (vm_offset_t)data, 310 capacity, 311 (vm_offset_t *)&newData, 312 finalCapacity, 313 IOMemoryTag(alloc_map)); 314 } else { 315 kr = kernel_memory_allocate(alloc_map, (vm_offset_t *)&newData, 316 finalCapacity, 0, KMA_ATOMIC, IOMemoryTag(alloc_map)); 317 } 318 if (KERN_SUCCESS != kr) { 319 newData = NULL; 320 } 321 } else { 322 newData = (unsigned char *)kalloc_data_container(finalCapacity, Z_WAITOK); 323 } 324 325 if (newData) { 326 bzero(newData + capacity, finalCapacity - capacity); 327 if (copydata) { 328 bcopy(copydata, newData, capacity); 329 } 330 if (data) { 331 if (capacity < page_size) { 332 kfree_data_container(data, capacity); 333 } else { 334 kmem_free(alloc_map, (vm_offset_t)data, capacity); 335 } 336 } 337 OSCONTAINER_ACCUMSIZE(((size_t)finalCapacity) - ((size_t)capacity)); 338 data = (void *) newData; 339 capacity = finalCapacity; 340 } 341 342 return capacity; 343 } 344 345 bool 346 OSData::appendBytes(const void *bytes, unsigned int inLength) 347 { 348 unsigned int newSize; 349 350 if (!inLength) { 351 return true; 352 } 353 354 if (capacity == EXTERNAL) { 355 return false; 356 } 357 358 if (os_add_overflow(length, inLength, &newSize)) { 359 return false; 360 } 361 362 if ((newSize > capacity) && newSize > ensureCapacity(newSize)) { 363 return false; 364 } 365 366 if (bytes) { 367 bcopy(bytes, &((unsigned char *)data)[length], inLength); 368 } else { 369 bzero(&((unsigned char *)data)[length], inLength); 370 } 371 372 length = newSize; 373 374 return true; 375 } 376 377 bool 378 OSData::appendByte(unsigned char byte, unsigned int inLength) 379 { 380 unsigned int newSize; 381 382 if (!inLength) { 383 return true; 384 } 385 386 if (capacity == EXTERNAL) { 387 return false; 388 } 389 390 if (os_add_overflow(length, inLength, &newSize)) { 391 return false; 392 } 393 394 if ((newSize > capacity) && newSize > ensureCapacity(newSize)) { 395 return false; 396 } 397 398 memset(&((unsigned char *)data)[length], byte, inLength); 399 length = newSize; 400 401 return true; 402 } 403 404 bool 405 OSData::appendBytes(const OSData *other) 406 { 407 return appendBytes(other->data, other->length); 408 } 409 410 const void * 411 OSData::getBytesNoCopy() const 412 { 413 if (!length) { 414 return NULL; 415 } else { 416 return data; 417 } 418 } 419 420 const void * 421 OSData::getBytesNoCopy(unsigned int start, 422 unsigned int inLength) const 423 { 424 const void *outData = NULL; 425 426 if (length 427 && start < length 428 && (start + inLength) >= inLength // overflow check 429 && (start + inLength) <= length) { 430 outData = (const void *) ((char *) data + start); 431 } 432 433 return outData; 434 } 435 436 bool 437 OSData::isEqualTo(const OSData *aData) const 438 { 439 unsigned int len; 440 441 len = aData->length; 442 if (length != len) { 443 return false; 444 } 445 446 return isEqualTo(aData->data, len); 447 } 448 449 bool 450 OSData::isEqualTo(const void *someData, unsigned int inLength) const 451 { 452 return (length >= inLength) && (bcmp(data, someData, inLength) == 0); 453 } 454 455 bool 456 OSData::isEqualTo(const OSMetaClassBase *obj) const 457 { 458 OSData * otherData; 459 OSString * str; 460 461 if ((otherData = OSDynamicCast(OSData, obj))) { 462 return isEqualTo(otherData); 463 } else if ((str = OSDynamicCast(OSString, obj))) { 464 return isEqualTo(str); 465 } else { 466 return false; 467 } 468 } 469 470 bool 471 OSData::isEqualTo(const OSString *obj) const 472 { 473 const char * aCString; 474 char * dataPtr; 475 unsigned int checkLen = length; 476 unsigned int stringLen; 477 478 if (!obj) { 479 return false; 480 } 481 482 stringLen = obj->getLength(); 483 484 dataPtr = (char *)data; 485 486 if (stringLen != checkLen) { 487 // check for the fact that OSData may be a buffer that 488 // that includes a termination byte and will thus have 489 // a length of the actual string length PLUS 1. In this 490 // case we verify that the additional byte is a terminator 491 // and if so count the two lengths as being the same. 492 493 if ((checkLen - stringLen) == 1) { 494 if (dataPtr[checkLen - 1] != 0) { // non-zero means not a terminator and thus not likely the same 495 return false; 496 } 497 checkLen--; 498 } else { 499 return false; 500 } 501 } 502 503 aCString = obj->getCStringNoCopy(); 504 505 for (unsigned int i = 0; i < checkLen; i++) { 506 if (*dataPtr++ != aCString[i]) { 507 return false; 508 } 509 } 510 511 return true; 512 } 513 514 //this was taken from CFPropertyList.c 515 static const char __CFPLDataEncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 516 517 bool 518 OSData::serialize(OSSerialize *s) const 519 { 520 unsigned int i; 521 const unsigned char *p; 522 unsigned char c; 523 unsigned int serializeLength; 524 525 if (s->previouslySerialized(this)) { 526 return true; 527 } 528 529 if (!s->addXMLStartTag(this, "data")) { 530 return false; 531 } 532 533 serializeLength = length; 534 if (reserved && reserved->disableSerialization) { 535 serializeLength = 0; 536 } 537 538 for (i = 0, p = (unsigned char *)data; i < serializeLength; i++, p++) { 539 /* 3 bytes are encoded as 4 */ 540 switch (i % 3) { 541 case 0: 542 c = __CFPLDataEncodeTable[((p[0] >> 2) & 0x3f)]; 543 if (!s->addChar(c)) { 544 return false; 545 } 546 break; 547 case 1: 548 c = __CFPLDataEncodeTable[((((p[-1] << 8) | p[0]) >> 4) & 0x3f)]; 549 if (!s->addChar(c)) { 550 return false; 551 } 552 break; 553 case 2: 554 c = __CFPLDataEncodeTable[((((p[-1] << 8) | p[0]) >> 6) & 0x3f)]; 555 if (!s->addChar(c)) { 556 return false; 557 } 558 c = __CFPLDataEncodeTable[(p[0] & 0x3f)]; 559 if (!s->addChar(c)) { 560 return false; 561 } 562 break; 563 } 564 } 565 switch (i % 3) { 566 case 0: 567 break; 568 case 1: 569 c = __CFPLDataEncodeTable[((p[-1] << 4) & 0x30)]; 570 if (!s->addChar(c)) { 571 return false; 572 } 573 if (!s->addChar('=')) { 574 return false; 575 } 576 if (!s->addChar('=')) { 577 return false; 578 } 579 break; 580 case 2: 581 c = __CFPLDataEncodeTable[((p[-1] << 2) & 0x3c)]; 582 if (!s->addChar(c)) { 583 return false; 584 } 585 if (!s->addChar('=')) { 586 return false; 587 } 588 break; 589 } 590 591 return s->addXMLEndTag("data"); 592 } 593 594 void 595 OSData::setDeallocFunction(DeallocFunction func) 596 { 597 if (!reserved) { 598 reserved = (typeof(reserved))kalloc_type(ExpansionData, (zalloc_flags_t)(Z_WAITOK | Z_ZERO)); 599 if (!reserved) { 600 return; 601 } 602 } 603 reserved->deallocFunction = func; 604 } 605 606 void 607 OSData::setSerializable(bool serializable) 608 { 609 if (!reserved) { 610 reserved = (typeof(reserved))kalloc_type(ExpansionData, (zalloc_flags_t)(Z_WAITOK | Z_ZERO)); 611 if (!reserved) { 612 return; 613 } 614 } 615 reserved->disableSerialization = (!serializable); 616 } 617 618 bool 619 OSData::isSerializable(void) 620 { 621 return !reserved || !reserved->disableSerialization; 622 } 623