Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 19 additions & 7 deletions Source/ios-framework/CommonSource/Store.swift
Original file line number Diff line number Diff line change
Expand Up @@ -258,14 +258,11 @@ public class Store: CustomDebugStringConvertible {
let entitlements = signingInfo[kSecCodeInfoEntitlementsDict] as? [NSString: NSObject],
let applicationGroups = entitlements["com.apple.security.application-groups"] as? [NSString] {

// Semaphore names in macOS are limited to 31 characters.
// Internally, we need up to 11 chars to identify the semaphore,
// thus the group ID must be equal or less than 20 (ASCII) charaters.
if let appGroupIdentifier = applicationGroups.first(where: { $0.length <= 20 }) {
obx_posix_sem_prefix_set(appGroupIdentifier.appending("/"))
// print("found appGroupIdentifier \(appGroupIdentifier)")
if let prefix = Store.semaphorePrefix(from: applicationGroups.map { $0 as String }) {
obx_posix_sem_prefix_set(prefix)
// print("found appGroupIdentifier \(prefix)")
} else {
print("Could not find an application group identifier of 20 characters or fewer.")
print("Could not find an application group identifier that fits within the 20-character prefix limit.")
}
} else if err3 != noErr { // noErr means app has no entitlements, likely not sandboxed.
print("Error reading entitlements: \(err3)")
Expand Down Expand Up @@ -375,4 +372,19 @@ public class Store: CustomDebugStringConvertible {
try block()
})
}

// MARK: - POSIX Semaphore Prefix

/// Finds the first application group identifier that fits within the POSIX semaphore name budget.
///
/// Semaphore names in macOS are limited to 31 characters. Internally, ObjectBox needs up to 11 characters
/// to identify the semaphore, so the prefix (group ID + "/") must be at most 20 characters.
///
/// The trailing "/" is appended if not already present before checking the length, matching the behavior
/// of the Dart API.
static func semaphorePrefix(from applicationGroups: [String]) -> String? {
return applicationGroups.lazy
.map { $0.hasSuffix("/") ? $0 : $0.appending("/") }
.first(where: { $0.count <= 20 })
}
}
11 changes: 11 additions & 0 deletions Source/ios-framework/CommonTests/StoreTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -346,4 +346,15 @@ class StoreTests: XCTestCase {
func testClone() throws {
try testAttachOrClone(clone: true)
}

// MARK: - Semaphore Prefix

func testSemaphorePrefix() {
// Appends "/" and checks total length <= 20
XCTAssertEqual(Store.semaphorePrefix(from: ["ABCDEFGHIJ.12345678"]), "ABCDEFGHIJ.12345678/") // 19 + "/" = 20, OK
XCTAssertNil(Store.semaphorePrefix(from: ["ABCDEFGHIJ.123456789"])) // 20 + "/" = 21, too long
XCTAssertEqual(Store.semaphorePrefix(from: ["ABCDEFGHIJ.1234567/"]), "ABCDEFGHIJ.1234567/") // already has "/", no double slash
XCTAssertEqual(Store.semaphorePrefix(from: ["ABCDEFGHIJ.123456789", "SHORT.id"]), "SHORT.id/") // skips first, picks second
XCTAssertNil(Store.semaphorePrefix(from: [])) // empty
}
}