| // Copyright 2026 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package runtime |
| |
| import "unsafe" |
| |
| const ( |
| maxPathLen = 1024 |
| _kCFStringEncodingUTF8 = 0x08000100 |
| ) |
| |
| // initWorkingDir sets the current working directory to the app root on iOS. |
| // By default ios/arm64 processes start in "/". |
| func initWorkingDir() { |
| bundle := cfBundleGetMainBundle() |
| if bundle == 0 { |
| writeErrStr("runtime/cgo: no main bundle\n") |
| return |
| } |
| if !bundleHasInfoPlist(bundle) { |
| // Not an app bundle; keep the inherited working directory. |
| return |
| } |
| url := cfBundleCopyBundleURL(bundle) |
| if url == 0 { |
| // No app bundle URL found. |
| return |
| } |
| |
| var buf [maxPathLen]byte |
| path := &buf[0] |
| ok := cfURLGetFileSystemRepresentation(url, true, path, uintptr(len(buf))) |
| cfRelease(url) |
| if !ok { |
| writeErrStr("runtime/cgo: cannot get bundle URL path\n") |
| return |
| } |
| |
| if chdir(path) != 0 { |
| writeErrStr("runtime/cgo: chdir(") |
| writeErrData(path, int32(findnull(path))) |
| writeErrStr(") failed\n") |
| } |
| |
| const goExecWrapperWorkingDirectoryKey = "GoExecWrapperWorkingDirectory\x00" |
| key := cfStringCreateWithCString(0, unsafe.StringData(goExecWrapperWorkingDirectoryKey), _kCFStringEncodingUTF8) |
| if key == 0 { |
| writeErrStr("runtime/cgo: cannot create GoExecWrapperWorkingDirectory string\n") |
| return |
| } |
| wd := cfBundleGetValueForInfoDictionaryKey(bundle, key) |
| cfRelease(key) |
| if wd == 0 { |
| return |
| } |
| if !cfStringGetCString(wd, path, uintptr(len(buf)), _kCFStringEncodingUTF8) { |
| writeErrStr("runtime/cgo: cannot get GoExecWrapperWorkingDirectory string\n") |
| return |
| } |
| |
| if chdir(path) != 0 { |
| writeErrStr("runtime/cgo: chdir(") |
| writeErrData(path, int32(findnull(path))) |
| writeErrStr(") failed\n") |
| } |
| } |
| |
| // bundleHasInfoPlist reports whether bundle contains an Info.plist. The main |
| // bundle of an executable that is not inside an app bundle is the directory |
| // holding the executable, which has no Info.plist. It can also happen on |
| // Corellium virtual devices. |
| func bundleHasInfoPlist(bundle uintptr) bool { |
| const ( |
| infoName = "Info\x00" |
| infoType = "plist\x00" |
| ) |
| name := cfStringCreateWithCString(0, unsafe.StringData(infoName), _kCFStringEncodingUTF8) |
| if name == 0 { |
| writeErrStr("runtime/cgo: cannot create Info.plist strings\n") |
| return false |
| } |
| typ := cfStringCreateWithCString(0, unsafe.StringData(infoType), _kCFStringEncodingUTF8) |
| if typ == 0 { |
| cfRelease(name) |
| writeErrStr("runtime/cgo: cannot create Info.plist strings\n") |
| return false |
| } |
| url := cfBundleCopyResourceURL(bundle, name, typ, 0) |
| cfRelease(name) |
| cfRelease(typ) |
| if url == 0 { |
| return false |
| } |
| cfRelease(url) |
| return true |
| } |