Unable to delete the contents of a Directory in my Home Directory using NSDirectoryEnumerator

Viewed 49

I have been unable to delete the contents of a directory using NSDirectoryEnumerator.

Here is my method:

- (BOOL) deleteDirectoryContents:(NSString *)directoryPath
{
    BOOL success = FALSE;
    BOOL isDir;
    NSFileManager *fileManager = [NSFileManager defaultManager];
    if ([fileManager fileExistsAtPath:directoryPath isDirectory:&isDir] && isDir)
    {
        NSDirectoryEnumerator *dirEnum = [fileManager enumeratorAtPath:directoryPath];
        NSLog(@"dirEnum in deleteDirectoryContents is %@", dirEnum);
        NSString *documentsName;
        // NSLog(@"[dirEnum nextObject] is: %@", [dirEnum nextObject]);
        while (documentsName = [dirEnum nextObject])
        {
            NSString *filePath = [directoryPath stringByAppendingString:documentsName];
            NSLog(@"filePath is: %@", filePath);
            BOOL isFileDeleted = [fileManager removeItemAtPath:filePath error:nil];
            if(isFileDeleted == NO)
            {
                NSLog(@"All Contents not removed");
                success = FALSE;
                break;
            }
            success = TRUE;
        }
        if (success) NSLog(@"All Contents Removed");
    }
    return success;
}

And this is my code in my main program:

NSString *testDir = @"/Users/grinch/MyTestTemp";
//testDir = [NSHomeDirectory() stringByAppendingPathComponent:  @"MyTestTemp"];
NSLog(@"testDir is: %@", testDir);
BOOL result = [self deleteDirectoryContents:testDir];
NSLog(@"result is: %d", result);

Here is my console output:

testDir is: /Users/grinch/MyTestTemp
dirEnum in deleteDirectoryContents is <NSAllDescendantPathsEnumerator: 0x60000008c300>
result is: 0

I also checked the value of [dirEnum nextObject] (by uncommenting the NSLog statement in my code). It returns null. And I never see the "filePath is" NSLog statement. So the inner while loop is NEVER executed.

And yes the directory (with files) does exist in my home directory. I created these files. I have permissions. I can easily delete the files in this directory using Finder

What am I missing?

P.S. I did some more testing. It looks like my simple program in Xcode does not have permissions to access files and folders in my home directory. Why? I have no idea.

Here is my additional test code:

NSError *errorMsg;
[[NSFileManager defaultManager] removeItemAtPath:@"/Users/grinch/myTestTemp/Hello.txt" error:&errorMsg];
if (errorMsg) NSLog(@"ERROR - File delete errorMsg is: %@", errorMsg);
    
success = [[NSFileManager defaultManager] removeItemAtPath:testDir error:&errorMsg];
if (errorMsg) NSLog(@"ERROR - Folder delete errorMsg is: %@", errorMsg);}

And here is my console output:

2022-09-10 09:56:48.958352-0400 NSAlert[97106:7511815] ERROR - File delete errorMsg is: Error Domain=NSCocoaErrorDomain Code=513 "“Hello.txt” couldn’t be removed because you don’t have permission to access it." UserInfo={NSFilePath=/Users/grinch/myTestTemp/Hello.txt, NSUserStringVariant=(
), NSUnderlyingError=0x6040006421f0 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}
2022-09-10 09:56:48.960560-0400 NSAlert[97106:7511815] ERROR - Folder delete errorMsg is: Error Domain=NSCocoaErrorDomain Code=513 "“MyTestTemp” couldn’t be removed because you don’t have permission to access it." UserInfo={NSFilePath=/Users/grinch/MyTestTemp, NSUserStringVariant=(
), NSUnderlyingError=0x60400045ff80 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}

So my questions are:

  1. Why didn't the directory enumerator work?
  2. Why doesn't Xcode have the permissions to delete items in my home folder?
  3. How can I give Xcode the the ability (or permissions) to delete items in my home directory?
1 Answers

I have found a bug in my deleteDirectoryContents: method above. And as a result, have answered most of my questions!

First, the statement NSString *filePath = [directoryPath stringByAppendingString:documentsName]; in the while loop will not work. One must insert a / before documentsname. So the line should be NSString *filePath = [directoryPath stringByAppendingFormat:@"/%@",documentsName]; OR even better use NSString *filePath = [directoryPath stringByAppendingPathComponent:documentsName];.

Now the method deleteDirectoryContents: will work as expected.

Here is the code to the fixed method:

- (BOOL) deleteDirectoryContents:(NSString *)directoryPath
{
    BOOL success = FALSE;
    BOOL isDir;
    NSFileManager *fileManager = [NSFileManager defaultManager];
    if ([fileManager fileExistsAtPath:directoryPath isDirectory:&isDir] && isDir)
    {
        NSDirectoryEnumerator *dirEnum = [fileManager enumeratorAtPath:directoryPath];
        NSLog(@"dirEnum in deleteDirectoryContents is %@", dirEnum);
        NSString *documentsName;
        // NSLog(@"[dirEnum nextObject] is: %@", [dirEnum nextObject]);
        while (documentsName = [dirEnum nextObject])
        {
            //NSString *filePath = [directoryPath stringByAppendingFormat:@"/%@",documentsName];
            NSString *filePath = [directoryPath stringByAppendingPathComponent:documentsName];
            NSLog(@"filePath is: %@", filePath);
            NSError *errorMsg = nil;
            BOOL isFileDeleted = [fileManager removeItemAtPath:filePath error:&errorMsg];
            if (errorMsg) NSLog(@"ERROR - Failed to delete file or folder at: %@.  Error message is: %@", filePath, errorMsg);
            if(isFileDeleted == NO)
            {
                NSLog(@"All Contents not removed");
                success = FALSE;
                break;
            }
            success = TRUE;
        }
        if (success) NSLog(@"All Contents Removed");
    }
    return success;
}

And I can confirm that if your program creates the directory and the files within it, the program can also delete these files using deleteDirectoryContents: while running in the Xcode sandbox DEPENDING on where the folder was originally created.

If the program creates the folder and files in a temporary directory (e.g. caches directory) NOT the users home folder, it works.

But due to Xcode sandboxing, deleteDirectoryContents: does not appear to work on folder and files created by the program in the users Home directory when running within Xcode.

P.S. I used the following to obtain a temporary directory name:

- (NSString *) get_temporary_dir
{
    NSString *path = nil;
    NSString *bundleName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleIdentifier"];
    
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
    if ([paths count]) {
        path = [[paths objectAtIndex:0] stringByAppendingPathComponent:bundleName];
    } else {
        path = NSTemporaryDirectory();
        path = [path stringByAppendingPathComponent:bundleName];
    }
    return [[[NSString alloc] initWithUTF8String:[path UTF8String]] autorelease];
}

Then the program created the temporary directory using that name. The program created some files in that temporary directory and then was able to delete them using the deleteDirectoryContents: method above.

Related