Skip to content

Commit 45210bd

Browse files
paulb777ncooke3
andauthored
[RTDB] Fix Fatal Exception: FirebaseDatabasePersistenceFailure (#15563)
Co-authored-by: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Co-authored-by: Nick Cooke <nickcooke@google.com>
1 parent 7865304 commit 45210bd

File tree

3 files changed

+79
-10
lines changed

3 files changed

+79
-10
lines changed

FirebaseDatabase/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# 12.7.0
2+
- [fixed] Fix `Fatal Exception: FirebaseDatabasePersistenceFailure`. (#4493)
23
- [fixed] Concurrency crash in FView. (#15514)
34

45
# 11.9.0

FirebaseDatabase/Sources/Persistence/FLevelDBStorageEngine.m

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -977,17 +977,40 @@ - (id)deserializePrimitive:(NSData *)data {
977977
}
978978

979979
+ (void)ensureDir:(NSString *)path markAsDoNotBackup:(BOOL)markAsDoNotBackup {
980+
NSFileManager *fileManager = [NSFileManager defaultManager];
980981
NSError *error;
981-
BOOL success =
982-
[[NSFileManager defaultManager] createDirectoryAtPath:path
983-
withIntermediateDirectories:YES
984-
attributes:nil
985-
error:&error];
982+
983+
// Create the directory if it doesn't exist. This call is a no-op if it
984+
// already exists.
985+
BOOL success = [fileManager createDirectoryAtPath:path
986+
withIntermediateDirectories:YES
987+
attributes:nil
988+
error:&error];
986989
if (!success) {
987990
@throw [NSException
988991
exceptionWithName:@"FailedToCreatePersistenceDir"
989992
reason:@"Failed to create persistence directory."
990-
userInfo:@{@"path" : path}];
993+
userInfo:@{
994+
@"path" : path,
995+
@"error" : error ?: [NSNull null]
996+
}];
997+
}
998+
999+
// Now, ensure the file protection attribute is set. This will apply it
1000+
// whether the directory was just created or already existed. Note, this
1001+
// attribute has no effect on simulators.
1002+
NSDictionary *attributes = @{
1003+
NSFileProtectionKey :
1004+
NSFileProtectionCompleteUntilFirstUserAuthentication
1005+
};
1006+
success = [fileManager setAttributes:attributes
1007+
ofItemAtPath:path
1008+
error:&error];
1009+
if (!success) {
1010+
FFWarn(@"I-RDB076036",
1011+
@"Failed to set file protection attribute on persistence "
1012+
@"directory: %@",
1013+
error);
9911014
}
9921015

9931016
if (markAsDoNotBackup) {
@@ -1000,9 +1023,6 @@ + (void)ensureDir:(NSString *)path markAsDoNotBackup:(BOOL)markAsDoNotBackup {
10001023
@"I-RDB076035",
10011024
@"Failed to mark firebase database folder as do not backup: %@",
10021025
error);
1003-
[NSException raise:@"Error marking as do not backup"
1004-
format:@"Failed to mark folder %@ as do not backup",
1005-
firebaseDirURL];
10061026
}
10071027
}
10081028
}

FirebaseDatabase/Tests/Unit/FLevelDBStorageEngineTests.m

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,11 @@
2525
#import "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h"
2626
#import "FirebaseDatabase/Tests/Helpers/FTestHelpers.h"
2727

28-
@interface FLevelDBStorageEngineTests : XCTestCase
28+
@interface FLevelDBStorageEngine (Tests)
29+
+ (void)ensureDir:(NSString *)path markAsDoNotBackup:(BOOL)markAsDoNotBackup;
30+
@end
2931

32+
@interface FLevelDBStorageEngineTests : XCTestCase
3033
@end
3134

3235
@implementation FLevelDBStorageEngineTests
@@ -685,4 +688,49 @@ - (void)testRemoveTrackedQueryRemovesTrackedQueryKeys {
685688
([NSSet setWithArray:@[ @"b", @"c" ]]));
686689
}
687690

691+
- (void)testEnsureDirSetsCorrectFileProtection {
692+
NSString *testDirName =
693+
[NSString stringWithFormat:@"fdb_persistence_test_%lu", (unsigned long)arc4random()];
694+
NSString *testPath = [NSTemporaryDirectory() stringByAppendingPathComponent:testDirName];
695+
NSFileManager *fileManager = [NSFileManager defaultManager];
696+
697+
// --- Test creation ---
698+
[fileManager removeItemAtPath:testPath error:nil];
699+
[FLevelDBStorageEngine ensureDir:testPath markAsDoNotBackup:NO];
700+
701+
NSError *error = nil;
702+
NSDictionary<NSFileAttributeKey, id> *attributes = [fileManager attributesOfItemAtPath:testPath
703+
error:&error];
704+
XCTAssertNil(error, @"Failed to get attributes of directory: %@", error);
705+
706+
#if !TARGET_OS_SIMULATOR
707+
// On a physical device, file protection should be set.
708+
XCTAssertEqualObjects(attributes[NSFileProtectionKey],
709+
NSFileProtectionCompleteUntilFirstUserAuthentication);
710+
#else
711+
XCTAssertNil(attributes[NSFileProtectionKey]);
712+
#endif
713+
714+
// --- Test update on existing directory ---
715+
#if !TARGET_OS_SIMULATOR
716+
// This part of the test is only relevant on devices where file protection is supported.
717+
[fileManager removeItemAtPath:testPath error:nil];
718+
NSDictionary *initialAttributes = @{NSFileProtectionKey : NSFileProtectionNone};
719+
XCTAssertTrue([fileManager createDirectoryAtPath:testPath
720+
withIntermediateDirectories:YES
721+
attributes:initialAttributes
722+
error:&error],
723+
@"Failed to create directory for update test: %@", error);
724+
725+
[FLevelDBStorageEngine ensureDir:testPath markAsDoNotBackup:NO];
726+
727+
attributes = [fileManager attributesOfItemAtPath:testPath error:&error];
728+
XCTAssertNil(error, @"Failed to get attributes after update: %@", error);
729+
XCTAssertEqualObjects(attributes[NSFileProtectionKey],
730+
NSFileProtectionCompleteUntilFirstUserAuthentication);
731+
#endif // !TARGET_OS_SIMULATOR
732+
733+
// Clean up
734+
[fileManager removeItemAtPath:testPath error:nil];
735+
}
688736
@end

0 commit comments

Comments
 (0)