]>
git.saurik.com Git - apple/libsecurity_codesigning.git/blob - lib/bundlediskrep.cpp
ad4d8195f42f29d3bcea4c55ce160ad21c7ee4f4
2 * Copyright (c) 2006-2007 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@
23 #include "bundlediskrep.h"
24 #include <CoreFoundation/CFURLAccess.h>
25 #include <CoreFoundation/CFBundlePriv.h>
26 #include <security_codesigning/cfmunge.h>
30 namespace CodeSigning
{
32 using namespace UnixPlusPlus
;
36 // We make a CFBundleRef immediately, but everything else is lazy
38 BundleDiskRep::BundleDiskRep(const char *path
)
39 : mBundle(_CFBundleCreateIfLooksLikeBundle(NULL
, CFTempURL(path
)))
42 MacOSError::throwMe(errSecCSBadObjectFormat
);
43 mExecRep
= DiskRep::bestFileGuess(this->mainExecutablePath());
46 BundleDiskRep::BundleDiskRep(CFBundleRef ref
)
48 mBundle
= ref
; // retains
49 mExecRep
= DiskRep::bestFileGuess(this->mainExecutablePath());
54 // Create a path to a bundle signing resource, by name.
55 // Note that these are stored in the bundle's Content directory,
56 // not its Resources directory.
58 string
BundleDiskRep::resourcePath(const char *name
)
60 if (mResourcePath
.empty())
61 mResourcePath
= cfString(CFBundleCopySupportFilesDirectoryURL(mBundle
), true);
62 return mResourcePath
+ "/" + name
;
67 // Load the data for a signing resource, by URL.
69 CFDataRef
BundleDiskRep::resourceData(CFURLRef url
)
73 if (CFURLCreateDataAndPropertiesFromResource(NULL
, url
,
74 &data
, NULL
, NULL
, &error
)) {
77 secdebug("bundlerep", "failed to fetch %s error=%d",
78 cfString(url
).c_str(), int(error
));
85 // Load and return a component, by slot number.
86 // Info.plist components come from the bundle, always (we don't look
87 // for Mach-O embedded versions).
88 // Everything else comes from the embedded blobs of a Mach-O image, or from
89 // files located in the Contents directory of the bundle.
91 CFDataRef
BundleDiskRep::component(CodeDirectory::SpecialSlot slot
)
94 // the Info.plist comes from the magic CFBundle-indicated place and ONLY from there
96 if (CFRef
<CFURLRef
> info
= _CFBundleCopyInfoPlistURL(mBundle
))
97 return resourceData(info
);
100 // by default, we take components from the executable image or files
102 if (CFDataRef data
= mExecRep
->component(slot
))
105 // but the following always come from files
106 case cdResourceDirSlot
:
107 if (const char *name
= CodeDirectory::canonicalSlotName(slot
))
108 return resourceData(name
);
116 // Various aspects of our DiskRep personality.
118 CFURLRef
BundleDiskRep::canonicalPath()
120 return CFBundleCopyBundleURL(mBundle
);
123 string
BundleDiskRep::recommendedIdentifier()
125 if (CFStringRef identifier
= CFBundleGetIdentifier(mBundle
))
126 return cfString(identifier
);
127 if (CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(mBundle
))
128 if (CFStringRef identifier
= CFStringRef(CFDictionaryGetValue(infoDict
, kCFBundleNameKey
)))
129 return cfString(identifier
);
131 // fall back to using the $(basename) of the canonical path. Drop any .app suffix
132 string path
= cfString(this->canonicalPath());
133 if (path
.substr(path
.size() - 4) == ".app")
134 path
= path
.substr(0, path
.size() - 4);
135 string::size_type p
= path
.rfind('/');
136 if (p
== string::npos
)
139 return path
.substr(p
+1);
142 string
BundleDiskRep::mainExecutablePath()
144 if (CFURLRef exec
= CFBundleCopyExecutableURL(mBundle
))
145 return cfString(exec
, true);
147 MacOSError::throwMe(errSecCSBadObjectFormat
);
150 string
BundleDiskRep::resourcesRootPath()
152 return cfString(CFBundleCopySupportFilesDirectoryURL(mBundle
), true);
155 CFDictionaryRef
BundleDiskRep::defaultResourceRules()
157 return cfmake
<CFDictionaryRef
>("{rules={"
158 "'^version.plist$' = #T"
160 "'^Resources/.*\\.lproj/' = {optional=#T, weight=1000}"
161 "'^Resources/.*\\.lproj/locversion.plist$' = {omit=#T, weight=1100}"
165 const Requirements
*BundleDiskRep::defaultRequirements(const Architecture
*arch
)
167 return mExecRep
->defaultRequirements(arch
);
171 Universal
*BundleDiskRep::mainExecutableImage()
173 return mExecRep
->mainExecutableImage();
176 size_t BundleDiskRep::pageSize()
178 return mExecRep
->pageSize();
181 size_t BundleDiskRep::signingBase()
183 return mExecRep
->signingBase();
186 size_t BundleDiskRep::signingLimit()
188 return mExecRep
->signingLimit();
191 string
BundleDiskRep::format()
193 return string("bundle with ") + mExecRep
->format();
196 CFArrayRef
BundleDiskRep::modifiedFiles()
198 CFMutableArrayRef files
= CFArrayCreateMutableCopy(NULL
, 0, mExecRep
->modifiedFiles());
199 checkModifiedFile(files
, cdCodeDirectorySlot
);
200 checkModifiedFile(files
, cdSignatureSlot
);
201 checkModifiedFile(files
, cdResourceDirSlot
);
205 void BundleDiskRep::checkModifiedFile(CFMutableArrayRef files
, CodeDirectory::SpecialSlot slot
)
207 if (CFDataRef data
= mExecRep
->component(slot
)) // provided by executable file
209 else if (const char *resourceName
= CodeDirectory::canonicalSlotName(slot
)) // bundle file
210 CFArrayAppendValue(files
, CFTempURL(resourcePath(resourceName
)));
212 /* we don't have that one */;
215 FileDesc
&BundleDiskRep::fd()
217 return mExecRep
->fd();
220 void BundleDiskRep::flush()
229 DiskRep::Writer
*BundleDiskRep::writer()
231 return new Writer(this);
234 BundleDiskRep::Writer::Writer(BundleDiskRep
*r
)
237 execWriter
= rep
->mExecRep
->writer();
242 // Write a component.
243 // Note that this isn't concerned with Mach-O writing; this is handled at
244 // a much higher level. If we're called, we write to a file in the Bundle's contents directory.
246 void BundleDiskRep::Writer::component(CodeDirectory::SpecialSlot slot
, CFDataRef data
)
250 if (!execWriter
->attribute(writerLastResort
)) // willing to take the data...
251 return execWriter
->component(slot
, data
); // ... so hand it through
252 // execWriter doesn't want the data; store it as a resource file (below)
253 case cdResourceDirSlot
:
254 case cdRequirementsSlot
:
255 // the resource directory always goes into a bundle file
256 if (const char *name
= CodeDirectory::canonicalSlotName(slot
)) {
257 AutoFileDesc
fd(rep
->resourcePath(name
), O_WRONLY
| O_CREAT
| O_TRUNC
);
258 fd
.writeAll(CFDataGetBytePtr(data
), CFDataGetLength(data
));
260 MacOSError::throwMe(errSecCSBadObjectFormat
);
265 void BundleDiskRep::Writer::flush()
271 } // end namespace CodeSigning
272 } // end namespace Security