X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5dd5f9ec28f304ca377c42fd7f711d6cf12b90e1..5c19dc3ae3bd8e40a9c028b0deddd50ff337692c:/Security/libsecurity_codesigning/lib/bundlediskrep.cpp diff --git a/Security/libsecurity_codesigning/lib/bundlediskrep.cpp b/Security/libsecurity_codesigning/lib/bundlediskrep.cpp deleted file mode 100644 index d414ff31..00000000 --- a/Security/libsecurity_codesigning/lib/bundlediskrep.cpp +++ /dev/null @@ -1,691 +0,0 @@ -/* - * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -#include "bundlediskrep.h" -#include "filediskrep.h" -#include "dirscanner.h" -#include -#include -#include -#include -#include -#include -#include - -namespace Security { -namespace CodeSigning { - -using namespace UnixPlusPlus; - - -// -// Local helpers -// -static std::string findDistFile(const std::string &directory); - - -// -// We make a CFBundleRef immediately, but everything else is lazy -// -BundleDiskRep::BundleDiskRep(const char *path, const Context *ctx) - : mBundle(CFBundleCreate(NULL, CFTempURL(path))) -{ - if (!mBundle) - MacOSError::throwMe(errSecCSBadBundleFormat); - setup(ctx); - CODESIGN_DISKREP_CREATE_BUNDLE_PATH(this, (char*)path, (void*)ctx, mExecRep); -} - -BundleDiskRep::BundleDiskRep(CFBundleRef ref, const Context *ctx) -{ - mBundle = ref; // retains - setup(ctx); - CODESIGN_DISKREP_CREATE_BUNDLE_REF(this, ref, (void*)ctx, mExecRep); -} - -BundleDiskRep::~BundleDiskRep() -{ -} - -void BundleDiskRep::checkMoved(CFURLRef oldPath, CFURLRef newPath) -{ - char cOld[PATH_MAX]; - char cNew[PATH_MAX]; - // The realpath call is important because alot of Framework bundles have a symlink - // to their "Current" version binary in the main bundle - if (realpath(cfString(oldPath).c_str(), cOld) == NULL || - realpath(cfString(newPath).c_str(), cNew) == NULL) - MacOSError::throwMe(errSecCSInternalError); - - if (strcmp(cOld, cNew) != 0) - recordStrictError(errSecCSAmbiguousBundleFormat); -} - -// common construction code -void BundleDiskRep::setup(const Context *ctx) -{ - mInstallerPackage = false; // default - - // capture the path of the main executable before descending into a specific version - CFRef mainExecBefore = CFBundleCopyExecutableURL(mBundle); - CFRef infoPlistBefore = _CFBundleCopyInfoPlistURL(mBundle); - - // validate the bundle root; fish around for the desired framework version - string root = cfStringRelease(copyCanonicalPath()); - string contents = root + "/Contents"; - string supportFiles = root + "/Support Files"; - string version = root + "/Versions/" - + ((ctx && ctx->version) ? ctx->version : "Current") - + "/."; - if (::access(contents.c_str(), F_OK) == 0) { // not shallow - DirValidator val; - val.require("^Contents$", DirValidator::directory); // duh - val.allow("^(\\.LSOverride|\\.DS_Store|Icon\r|\\.SoftwareDepot\\.tracking)$", DirValidator::file | DirValidator::noexec); - try { - val.validate(root, errSecCSUnsealedAppRoot); - } catch (const MacOSError &err) { - recordStrictError(err.error); - } - } else if (::access(supportFiles.c_str(), F_OK) == 0) { // ancient legacy boondoggle bundle - // treat like a shallow bundle; do not allow Versions arbitration - } else if (::access(version.c_str(), F_OK) == 0) { // versioned bundle - if (CFBundleRef versionBundle = CFBundleCreate(NULL, CFTempURL(version))) - mBundle.take(versionBundle); // replace top bundle ref - else - MacOSError::throwMe(errSecCSStaticCodeNotFound); - validateFrameworkRoot(root); - } else { - if (ctx && ctx->version) // explicitly specified - MacOSError::throwMe(errSecCSStaticCodeNotFound); - } - - CFDictionaryRef infoDict = CFBundleGetInfoDictionary(mBundle); - assert(infoDict); // CFBundle will always make one up for us - CFTypeRef mainHTML = CFDictionaryGetValue(infoDict, CFSTR("MainHTML")); - CFTypeRef packageVersion = CFDictionaryGetValue(infoDict, CFSTR("IFMajorVersion")); - - // conventional executable bundle: CFBundle identifies an executable for us - if (CFRef mainExec = CFBundleCopyExecutableURL(mBundle)) // if CFBundle claims an executable... - if (mainHTML == NULL) { // ... and it's not a widget - - // Note that this check is skipped if there is a specific framework version checked. - // That's because you know what you are doing if you are looking at a specific version. - // This check is designed to stop someone who did a verification on an app root, from mistakenly - // verifying a framework - if (!ctx || !ctx->version) { - if (mainExecBefore) - checkMoved(mainExecBefore, mainExec); - if (infoPlistBefore) - if (CFRef infoDictPath = _CFBundleCopyInfoPlistURL(mBundle)) - checkMoved(infoPlistBefore, infoDictPath); - } - - mMainExecutableURL = mainExec; - mExecRep = DiskRep::bestFileGuess(this->mainExecutablePath(), ctx); - if (!mExecRep->fd().isPlainFile(this->mainExecutablePath())) - recordStrictError(errSecCSRegularFile); - mFormat = "bundle with " + mExecRep->format(); - return; - } - - // widget - if (mainHTML) { - if (CFGetTypeID(mainHTML) != CFStringGetTypeID()) - MacOSError::throwMe(errSecCSBadBundleFormat); - mMainExecutableURL.take(makeCFURL(cfString(CFStringRef(mainHTML)), false, - CFRef(CFBundleCopySupportFilesDirectoryURL(mBundle)))); - if (!mMainExecutableURL) - MacOSError::throwMe(errSecCSBadBundleFormat); - mExecRep = new FileDiskRep(this->mainExecutablePath().c_str()); - if (!mExecRep->fd().isPlainFile(this->mainExecutablePath())) - recordStrictError(errSecCSRegularFile); - mFormat = "widget bundle"; - return; - } - - // do we have a real Info.plist here? - if (CFRef infoURL = _CFBundleCopyInfoPlistURL(mBundle)) { - // focus on the Info.plist (which we know exists) as the nominal "main executable" file - mMainExecutableURL = infoURL; - mExecRep = new FileDiskRep(this->mainExecutablePath().c_str()); - if (!mExecRep->fd().isPlainFile(this->mainExecutablePath())) - recordStrictError(errSecCSRegularFile); - if (packageVersion) { - mInstallerPackage = true; - mFormat = "installer package bundle"; - } else { - mFormat = "bundle"; - } - return; - } - - // we're getting desperate here. Perhaps an oldish-style installer package? Look for a *.dist file - std::string distFile = findDistFile(this->resourcesRootPath()); - if (!distFile.empty()) { - mMainExecutableURL = makeCFURL(distFile); - mExecRep = new FileDiskRep(this->mainExecutablePath().c_str()); - if (!mExecRep->fd().isPlainFile(this->mainExecutablePath())) - recordStrictError(errSecCSRegularFile); - mInstallerPackage = true; - mFormat = "installer package bundle"; - return; - } - - // this bundle cannot be signed - MacOSError::throwMe(errSecCSBadBundleFormat); -} - - -// -// Return the full path to the one-and-only file named something.dist in a directory. -// Return empty string if none; throw an exception if multiple. Do not descend into subdirectories. -// -static std::string findDistFile(const std::string &directory) -{ - std::string found; - char *paths[] = {(char *)directory.c_str(), NULL}; - FTS *fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR | FTS_NOSTAT, NULL); - bool root = true; - while (FTSENT *ent = fts_read(fts)) { - switch (ent->fts_info) { - case FTS_F: - case FTS_NSOK: - if (!strcmp(ent->fts_path + ent->fts_pathlen - 5, ".dist")) { // found plain file foo.dist - if (found.empty()) // first found - found = ent->fts_path; - else // multiple *.dist files (bad) - MacOSError::throwMe(errSecCSBadBundleFormat); - } - break; - case FTS_D: - if (!root) - fts_set(fts, ent, FTS_SKIP); // don't descend - root = false; - break; - default: - break; - } - } - fts_close(fts); - return found; -} - - -// -// Create a path to a bundle signing resource, by name. -// If the BUNDLEDISKREP_DIRECTORY directory exists in the bundle's support directory, files -// will be read and written there. Otherwise, they go directly into the support directory. -// -string BundleDiskRep::metaPath(const char *name) -{ - if (mMetaPath.empty()) { - string support = cfStringRelease(CFBundleCopySupportFilesDirectoryURL(mBundle)); - mMetaPath = support + "/" BUNDLEDISKREP_DIRECTORY; - if (::access(mMetaPath.c_str(), F_OK) == 0) { - mMetaExists = true; - } else { - mMetaPath = support; - mMetaExists = false; - } - } - return mMetaPath + "/" + name; -} - - -// -// Try to create the meta-file directory in our bundle. -// Does nothing if the directory already exists. -// Throws if an error occurs. -// -void BundleDiskRep::createMeta() -{ - string meta = metaPath(BUNDLEDISKREP_DIRECTORY); - if (!mMetaExists) { - if (::mkdir(meta.c_str(), 0755) == 0) { - copyfile(cfStringRelease(copyCanonicalPath()).c_str(), meta.c_str(), NULL, COPYFILE_SECURITY); - mMetaPath = meta; - mMetaExists = true; - } else if (errno != EEXIST) - UnixError::throwMe(); - } -} - -// -// Load's a CFURL and makes sure that it is a regular file and not a symlink (or fifo, etc.) -// -CFDataRef BundleDiskRep::loadRegularFile(CFURLRef url) -{ - assert(url); - - CFDataRef data = NULL; - - std::string path(cfString(url)); - - AutoFileDesc fd(path); - - if (!fd.isPlainFile(path)) - recordStrictError(errSecCSRegularFile); - - data = cfLoadFile(fd, fd.fileSize()); - - if (!data) { - secdebug(__PRETTY_FUNCTION__, "failed to load %s", cfString(url).c_str()); - MacOSError::throwMe(errSecCSInternalError); - } - - return data; -} - -// -// Load and return a component, by slot number. -// Info.plist components come from the bundle, always (we don't look -// for Mach-O embedded versions). -// Everything else comes from the embedded blobs of a Mach-O image, or from -// files located in the Contents directory of the bundle. -// -CFDataRef BundleDiskRep::component(CodeDirectory::SpecialSlot slot) -{ - switch (slot) { - // the Info.plist comes from the magic CFBundle-indicated place and ONLY from there - case cdInfoSlot: - if (CFRef info = _CFBundleCopyInfoPlistURL(mBundle)) - return loadRegularFile(info); - else - return NULL; - // by default, we take components from the executable image or files - default: - if (CFDataRef data = mExecRep->component(slot)) - return data; - // falling through - // but the following always come from files - case cdResourceDirSlot: - if (const char *name = CodeDirectory::canonicalSlotName(slot)) - return metaData(name); - else - return NULL; - } -} - - -// -// The binary identifier is taken directly from the main executable. -// -CFDataRef BundleDiskRep::identification() -{ - return mExecRep->identification(); -} - - -// -// Various aspects of our DiskRep personality. -// -CFURLRef BundleDiskRep::copyCanonicalPath() -{ - if (CFURLRef url = CFBundleCopyBundleURL(mBundle)) - return url; - CFError::throwMe(); -} - -string BundleDiskRep::mainExecutablePath() -{ - return cfString(mMainExecutableURL); -} - -string BundleDiskRep::resourcesRootPath() -{ - return cfStringRelease(CFBundleCopySupportFilesDirectoryURL(mBundle)); -} - -void BundleDiskRep::adjustResources(ResourceBuilder &builder) -{ - // exclude entire contents of meta directory - builder.addExclusion("^" BUNDLEDISKREP_DIRECTORY "$"); - builder.addExclusion("^" CODERESOURCES_LINK "$"); // ancient-ish symlink into it - - // exclude the store manifest directory - builder.addExclusion("^" STORE_RECEIPT_DIRECTORY "$"); - - // exclude the main executable file - string resources = resourcesRootPath(); - if (resources.compare(resources.size() - 2, 2, "/.") == 0) // chop trailing /. - resources = resources.substr(0, resources.size()-2); - string executable = mainExecutablePath(); - if (!executable.compare(0, resources.length(), resources, 0, resources.length()) - && executable[resources.length()] == '/') // is proper directory prefix - builder.addExclusion(string("^") - + ResourceBuilder::escapeRE(executable.substr(resources.length()+1)) + "$"); -} - - - -Universal *BundleDiskRep::mainExecutableImage() -{ - return mExecRep->mainExecutableImage(); -} - -size_t BundleDiskRep::signingBase() -{ - return mExecRep->signingBase(); -} - -size_t BundleDiskRep::signingLimit() -{ - return mExecRep->signingLimit(); -} - -string BundleDiskRep::format() -{ - return mFormat; -} - -CFArrayRef BundleDiskRep::modifiedFiles() -{ - CFMutableArrayRef files = CFArrayCreateMutableCopy(NULL, 0, mExecRep->modifiedFiles()); - checkModifiedFile(files, cdCodeDirectorySlot); - checkModifiedFile(files, cdSignatureSlot); - checkModifiedFile(files, cdResourceDirSlot); - checkModifiedFile(files, cdEntitlementSlot); - return files; -} - -void BundleDiskRep::checkModifiedFile(CFMutableArrayRef files, CodeDirectory::SpecialSlot slot) -{ - if (CFDataRef data = mExecRep->component(slot)) // provided by executable file - CFRelease(data); - else if (const char *resourceName = CodeDirectory::canonicalSlotName(slot)) { - string file = metaPath(resourceName); - if (::access(file.c_str(), F_OK) == 0) - CFArrayAppendValue(files, CFTempURL(file)); - } -} - -FileDesc &BundleDiskRep::fd() -{ - return mExecRep->fd(); -} - -void BundleDiskRep::flush() -{ - mExecRep->flush(); -} - - -// -// Defaults for signing operations -// -string BundleDiskRep::recommendedIdentifier(const SigningContext &) -{ - if (CFStringRef identifier = CFBundleGetIdentifier(mBundle)) - return cfString(identifier); - if (CFDictionaryRef infoDict = CFBundleGetInfoDictionary(mBundle)) - if (CFStringRef identifier = CFStringRef(CFDictionaryGetValue(infoDict, kCFBundleNameKey))) - return cfString(identifier); - - // fall back to using the canonical path - return canonicalIdentifier(cfStringRelease(this->copyCanonicalPath())); -} - -string BundleDiskRep::resourcesRelativePath() -{ - // figure out the resource directory base. Clean up some gunk inserted by CFBundle in frameworks - string rbase = this->resourcesRootPath(); - size_t pos = rbase.find("/./"); // gratuitously inserted by CFBundle in some frameworks - while (pos != std::string::npos) { - rbase = rbase.replace(pos, 2, "", 0); - pos = rbase.find("/./"); - } - if (rbase.substr(rbase.length()-2, 2) == "/.") // produced by versioned bundle implicit "Current" case - rbase = rbase.substr(0, rbase.length()-2); // ... so take it off for this - - // find the resources directory relative to the resource base - string resources = cfStringRelease(CFBundleCopyResourcesDirectoryURL(mBundle)); - if (resources == rbase) - resources = ""; - else if (resources.compare(0, rbase.length(), rbase, 0, rbase.length()) != 0) // Resources not in resource root - MacOSError::throwMe(errSecCSBadBundleFormat); - else - resources = resources.substr(rbase.length() + 1) + "/"; // differential path segment - - return resources; -} - -CFDictionaryRef BundleDiskRep::defaultResourceRules(const SigningContext &ctx) -{ - string resources = this->resourcesRelativePath(); - - // installer package rules - if (mInstallerPackage) - return cfmake("{rules={" - "'^.*' = #T" // include everything, but... - "%s = {optional=#T, weight=1000}" // make localizations optional - "'^.*/.*\\.pkg/' = {omit=#T, weight=10000}" // and exclude all nested packages (by name) - "}}", - (string("^") + resources + ".*\\.lproj/").c_str() - ); - - // old (V1) executable bundle rules - compatible with before - if (ctx.signingFlags() & kSecCSSignV1) // *** must be exactly the same as before *** - return cfmake("{rules={" - "'^version.plist$' = #T" // include version.plist - "%s = #T" // include Resources - "%s = {optional=#T, weight=1000}" // make localizations optional - "%s = {omit=#T, weight=1100}" // exclude all locversion.plist files - "}}", - (string("^") + resources).c_str(), - (string("^") + resources + ".*\\.lproj/").c_str(), - (string("^") + resources + ".*\\.lproj/locversion.plist$").c_str() - ); - - // FMJ (everything is a resource) rules - if (ctx.signingFlags() & kSecCSSignOpaque) // Full Metal Jacket - everything is a resource file - return cfmake("{rules={" - "'^.*' = #T" // everything is a resource - "'^Info\\.plist$' = {omit=#T,weight=10}" // explicitly exclude this for backward compatibility - "}}"); - - // new (V2) executable bundle rules - return cfmake("{" // *** the new (V2) world *** - "rules={" // old (V1; legacy) version - "'^version.plist$' = #T" // include version.plist - "%s = #T" // include Resources - "%s = {optional=#T, weight=1000}" // make localizations optional - "%s = {omit=#T, weight=1100}" // exclude all locversion.plist files - "},rules2={" - "'^.*' = #T" // include everything as a resource, with the following exceptions - "'^[^/]+$' = {nested=#T, weight=10}" // files directly in Contents - "'^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/' = {nested=#T, weight=10}" // dynamic repositories - "'.*\\.dSYM($|/)' = {weight=11}" // but allow dSYM directories in code locations (parallel to their code) - "'^(.*/)?\\.DS_Store$' = {omit=#T,weight=2000}" // ignore .DS_Store files - "'^Info\\.plist$' = {omit=#T, weight=20}" // excluded automatically now, but old systems need to be told - "'^version\\.plist$' = {weight=20}" // include version.plist as resource - "'^embedded\\.provisionprofile$' = {weight=20}" // include embedded.provisionprofile as resource - "'^PkgInfo$' = {omit=#T, weight=20}" // traditionally not included - "%s = {weight=20}" // Resources override default nested (widgets) - "%s = {optional=#T, weight=1000}" // make localizations optional - "%s = {omit=#T, weight=1100}" // exclude all locversion.plist files - "}}", - - (string("^") + resources).c_str(), - (string("^") + resources + ".*\\.lproj/").c_str(), - (string("^") + resources + ".*\\.lproj/locversion.plist$").c_str(), - - (string("^") + resources).c_str(), - (string("^") + resources + ".*\\.lproj/").c_str(), - (string("^") + resources + ".*\\.lproj/locversion.plist$").c_str() - ); -} - - -CFArrayRef BundleDiskRep::allowedResourceOmissions() -{ - return cfmake("[" - "'^(.*/)?\\.DS_Store$'" - "'^Info\\.plist$'" - "'^PkgInfo$'" - "%s" - "]", - (string("^") + this->resourcesRelativePath() + ".*\\.lproj/locversion.plist$").c_str() - ); -} - - -const Requirements *BundleDiskRep::defaultRequirements(const Architecture *arch, const SigningContext &ctx) -{ - return mExecRep->defaultRequirements(arch, ctx); -} - -size_t BundleDiskRep::pageSize(const SigningContext &ctx) -{ - return mExecRep->pageSize(ctx); -} - - -// -// Strict validation. -// Takes an array of CFNumbers of errors to tolerate. -// -void BundleDiskRep::strictValidate(const CodeDirectory* cd, const ToleratedErrors& tolerated) -{ - std::vector fatalErrors; - set_difference(mStrictErrors.begin(), mStrictErrors.end(), tolerated.begin(), tolerated.end(), back_inserter(fatalErrors)); - if (!fatalErrors.empty()) - MacOSError::throwMe(fatalErrors[0]); - mExecRep->strictValidate(cd, tolerated); -} - -void BundleDiskRep::recordStrictError(OSStatus error) -{ - mStrictErrors.insert(error); -} - - -// -// Check framework root for unsafe symlinks and unsealed content. -// -void BundleDiskRep::validateFrameworkRoot(string root) -{ - // build regex element that matches either the "Current" symlink, or the name of the current version - string current = "Current"; - char currentVersion[PATH_MAX]; - ssize_t len = ::readlink((root + "/Versions/Current").c_str(), currentVersion, sizeof(currentVersion)-1); - if (len > 0) { - currentVersion[len] = '\0'; - current = string("(Current|") + ResourceBuilder::escapeRE(currentVersion) + ")"; - } - - DirValidator val; - val.require("^Versions$", DirValidator::directory | DirValidator::descend); // descend into Versions directory - val.require("^Versions/[^/]+$", DirValidator::directory); // require at least one version - val.require("^Versions/Current$", DirValidator::symlink, // require Current symlink... - "^(\\./)?(\\.\\.[^/]+|\\.?[^\\./][^/]*)$"); // ...must point to a version - val.allow("^(Versions/)?\\.DS_Store$", DirValidator::file | DirValidator::noexec); // allow .DS_Store files - val.allow("^[^/]+$", DirValidator::symlink, ^ string (const string &name, const string &target) { - // top-level symlinks must point to namesake in current version - return string("^(\\./)?Versions/") + current + "/" + ResourceBuilder::escapeRE(name) + "$"; - }); - // module.map must be regular non-executable file, or symlink to module.map in current version - val.allow("^module\\.map$", DirValidator::file | DirValidator::noexec | DirValidator::symlink, - string("^(\\./)?Versions/") + current + "/module\\.map$"); - - try { - val.validate(root, errSecCSUnsealedFrameworkRoot); - } catch (const MacOSError &err) { - recordStrictError(err.error); - } -} - - -// -// Writers -// -DiskRep::Writer *BundleDiskRep::writer() -{ - return new Writer(this); -} - -BundleDiskRep::Writer::Writer(BundleDiskRep *r) - : rep(r), mMadeMetaDirectory(false) -{ - execWriter = rep->mExecRep->writer(); -} - - -// -// Write a component. -// Note that this isn't concerned with Mach-O writing; this is handled at -// a much higher level. If we're called, we write to a file in the Bundle's meta directory. -// -void BundleDiskRep::Writer::component(CodeDirectory::SpecialSlot slot, CFDataRef data) -{ - switch (slot) { - default: - if (!execWriter->attribute(writerLastResort)) // willing to take the data... - return execWriter->component(slot, data); // ... so hand it through - // execWriter doesn't want the data; store it as a resource file (below) - case cdResourceDirSlot: - // the resource directory always goes into a bundle file - if (const char *name = CodeDirectory::canonicalSlotName(slot)) { - rep->createMeta(); - string path = rep->metaPath(name); - AutoFileDesc fd(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); - fd.writeAll(CFDataGetBytePtr(data), CFDataGetLength(data)); - } else - MacOSError::throwMe(errSecCSBadBundleFormat); - } -} - - -// -// Remove all signature data -// -void BundleDiskRep::Writer::remove() -{ - // remove signature from the executable - execWriter->remove(); - - // remove signature files from bundle - for (CodeDirectory::SpecialSlot slot = 0; slot < cdSlotCount; slot++) - remove(slot); - remove(cdSignatureSlot); -} - -void BundleDiskRep::Writer::remove(CodeDirectory::SpecialSlot slot) -{ - if (const char *name = CodeDirectory::canonicalSlotName(slot)) - if (::unlink(rep->metaPath(name).c_str())) - switch (errno) { - case ENOENT: // not found - that's okay - break; - default: - UnixError::throwMe(); - } -} - - -void BundleDiskRep::Writer::flush() -{ - execWriter->flush(); -} - - -} // end namespace CodeSigning -} // end namespace Security