2 * Copyright (c) 2017 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
26 #include <mach/mach.h>
27 #include <dispatch/dispatch.h>
28 #include <bootstrap.h>
30 #include "ClosureBuffer.h"
31 #include "PathOverrides.h"
36 TypedContentBuffer::TypedContentBuffer(size_t elementsCount
, size_t elementsTotalSize
)
38 _size
= elementsTotalSize
+ (elementsCount
+1)*(sizeof(Element
)+4); // worst case padding, plus "end" element
39 vm_address_t bufferAddress
= 0;
40 assert(::vm_allocate(mach_task_self(), &bufferAddress
, _size
, VM_FLAGS_ANYWHERE
) == 0);
41 _buffer
= (Element
*)bufferAddress
;
42 _currentEnd
= _buffer
;
46 void TypedContentBuffer::free()
48 if ( _buffer
!= nullptr )
49 vm_deallocate(mach_task_self(), (long)_buffer
, _size
);
53 void TypedContentBuffer::addItem(uint32_t k
, const void* content
, size_t len
)
56 assert(((char*)_currentEnd
+ len
) < ((char*)_buffer
+ _size
));
57 _currentEnd
->kind
= k
;
58 _currentEnd
->contentLength
= (uint32_t)len
;
60 memmove(&(_currentEnd
->content
), content
, len
);
61 size_t delta
= (sizeof(Element
) + len
+ 3) & (-4);
62 _currentEnd
= (Element
*)((char*)_currentEnd
+ delta
);
65 vm_address_t
TypedContentBuffer::vmBuffer() const
68 return (vm_address_t
)_buffer
;
71 uint32_t TypedContentBuffer::vmBufferSize() const
74 return (uint32_t)_size
;
77 void TypedContentBuffer::doneBuilding()
83 const TypedContentBuffer::Element
* TypedContentBuffer::Element::next() const
85 return (Element
*)((char*)this + sizeof(Element
) + ((contentLength
+ 3) & -4));
88 TypedContentBuffer::TypedContentBuffer(const void* buff
, size_t buffSize
)
89 : _size(buffSize
), _buffer((Element
*)buff
), _currentEnd((Element
*)((char*)buff
+buffSize
)), _readOnly(true)
93 unsigned TypedContentBuffer::count(uint32_t kind
) const
97 for (const Element
* e
= _buffer
; e
->kind
!= 0; e
= e
->next()) {
98 if ( e
->kind
== kind
)
104 void TypedContentBuffer::forEach(uint32_t kind
, void (^callback
)(const void* content
, size_t length
)) const
107 for (const Element
* e
= _buffer
; e
->kind
!= 0; e
= e
->next()) {
108 if ( e
->kind
== kind
) {
109 callback(&(e
->content
), e
->contentLength
);
114 #if !BUILDING_CLOSURED
116 ClosureBuffer::ClosureBuffer(const CacheIdent
& cacheIdent
, const char* path
, const launch_cache::ImageGroupList
& groups
, const PathOverrides
& envVars
)
117 : TypedContentBuffer(2 + envVars
.envVarCount() + groups
.count(), computeSize(path
, groups
, envVars
))
119 addItem(kindCacheIdent
, &cacheIdent
, sizeof(CacheIdent
));
120 addItem(kindTargetPath
, path
, strlen(path
)+1);
121 envVars
.forEachEnvVar(^(const char* envVar
) {
122 addItem(kindEnvVar
, envVar
, strlen(envVar
)+1);
124 for (size_t i
=0; i
< groups
.count(); ++i
) {
125 launch_cache::ImageGroup
group(groups
[i
]);
126 addItem(kindImageGroup
, group
.binaryData(), group
.size());
128 addItem(kindEnd
, nullptr, 0);
132 size_t ClosureBuffer::computeSize(const char* path
, const launch_cache::ImageGroupList
& groups
, const PathOverrides
& envVars
)
134 __block
size_t result
= sizeof(CacheIdent
);
135 result
+= (strlen(path
) + 1);
136 envVars
.forEachEnvVar(^(const char* envVar
) {
137 result
+= (strlen(envVar
) + 1);
139 for (size_t i
=0; i
< groups
.count(); ++i
) {
140 launch_cache::ImageGroup
group(groups
[i
]);
141 result
+= group
.size();
148 ClosureBuffer::ClosureBuffer(const char* errorMessage
)
149 : TypedContentBuffer(1, strlen(errorMessage
+2))
151 addItem(kindErrorMessage
, errorMessage
, strlen(errorMessage
)+1);
155 ClosureBuffer::ClosureBuffer(const launch_cache::BinaryImageGroupData
* imageGroup
)
156 : TypedContentBuffer(1, launch_cache::ImageGroup(imageGroup
).size())
158 addItem(kindImageGroup
, imageGroup
, launch_cache::ImageGroup(imageGroup
).size());
162 ClosureBuffer::ClosureBuffer(const launch_cache::BinaryClosureData
* closure
)
163 : TypedContentBuffer(1, launch_cache::Closure(closure
).size())
165 addItem(kindClosure
, closure
, launch_cache::Closure(closure
).size());
170 ClosureBuffer::ClosureBuffer(const void* buff
, size_t buffSize
)
171 : TypedContentBuffer(buff
, buffSize
)
175 const ClosureBuffer::CacheIdent
& ClosureBuffer::cacheIndent() const
177 __block CacheIdent
* ident
= nullptr;
178 forEach(kindCacheIdent
, ^(const void* content
, size_t length
) {
179 ident
= (CacheIdent
*)content
;
180 assert(length
== sizeof(CacheIdent
));
182 assert(ident
!= nullptr);
186 const char* ClosureBuffer::targetPath() const
188 __block
char* path
= nullptr;
189 forEach(kindTargetPath
, ^(const void* content
, size_t length
) {
190 path
= (char*)content
;
192 assert(path
!= nullptr);
196 uint32_t ClosureBuffer::envVarCount() const
198 __block
uint32_t count
= 0;
199 forEach(kindEnvVar
, ^(const void* content
, size_t length
) {
205 void ClosureBuffer::copyImageGroups(const char* envVars
[]) const
207 __block
uint32_t index
= 0;
208 forEach(kindEnvVar
, ^(const void* content
, size_t length
) {
209 envVars
[index
] = (char*)content
;
214 uint32_t ClosureBuffer::imageGroupCount() const
216 __block
uint32_t count
= 0;
217 forEach(kindImageGroup
, ^(const void* content
, size_t length
) {
223 void ClosureBuffer::copyImageGroups(const launch_cache::BinaryImageGroupData
* imageGroups
[]) const
225 __block
uint32_t index
= 0;
226 forEach(kindImageGroup
, ^(const void* content
, size_t length
) {
227 imageGroups
[index
] = (launch_cache::BinaryImageGroupData
*)content
;
232 bool ClosureBuffer::isError() const
234 return ( errorMessage() != nullptr );
237 const char* ClosureBuffer::errorMessage() const
239 __block
char* message
= nullptr;
240 forEach(kindErrorMessage
, ^(const void* content
, size_t length
) {
241 message
= (char*)content
;
246 const launch_cache::BinaryClosureData
* ClosureBuffer::closure() const
248 __block
const launch_cache::BinaryClosureData
* result
= nullptr;
249 forEach(kindClosure
, ^(const void* content
, size_t length
) {
250 result
= (const launch_cache::BinaryClosureData
*)content
;
252 assert(result
!= nullptr);
257 const launch_cache::BinaryImageGroupData
* ClosureBuffer::imageGroup() const
259 __block
const launch_cache::BinaryImageGroupData
* result
= nullptr;
260 forEach(kindImageGroup
, ^(const void* content
, size_t length
) {
261 result
= (const launch_cache::BinaryImageGroupData
*)content
;
263 assert(result
!= nullptr);