NSFileManager says a file not writable Mac - macos

I have been trying to use AVFoundation to record screen outputs. For reasons unknown it stopped working after I moved to the latest version of Mac (Mountain Lion). I have been trying to getting it work but is not fruitful so far. I know that the AVFoundation method startRecordingToOutputFileURL will not work if the output file already exists. So, I tried using NSFileManager to see if my destination file exists and if it is writable. My Filemanager always returns the values corresponding to non-existence of the destination file and not writable. I tried to set file permissions to no avail, could anyone throw some light on my possible mistake:
dest = [[NSURL alloc] initFileURLWithPath:#"~/Desktop/myMovie.mov"];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSMutableDictionary *attributes = [[NSMutableDictionary alloc] init];
[attributes setObject:[NSNumber numberWithInt:777] forKey:NSFilePosixPermissions]; //I tried 511 too, no avail
[fileManager setAttributes:attributes ofItemAtPath:[dest path] error:nil];
if (![fileManager fileExistsAtPath:[dest path]]) {
if ([fileManager isWritableFileAtPath:[dest path]]) {
/* Starts recording to a given URL. */
[captureMovieFileOutput startRecordingToOutputFileURL:dest recordingDelegate:self];
}
else{
NSLog(#"File doesnot exist but is not writable"); //This is the message I get as result
}
}
else
{
NSLog(#"File Exists...");
}

Unexpanded tildes are not valid paths in Cocoa. You must use -stringByExpandingTildeInPath or better, -stringByStandardizingPath on the string passed into NSURL's -initFileURLWithPath:.
Because of this, NSFileManager will return NO for isWritableFileAtPath because it's an invalid path (so it's not writable). This leads you to your NSLog() being fired.
Update based on comments:
You may still find NSURL is returning nil upon creation (so calling -path will return nil) because the path is still invalid. Also worth noting, the documentation says for -isWritableFileAtPath:, "It's far better to attempt an operation (such as loading a file or creating a directory), check for errors, and handle those errors gracefully than it is to try to figure out ahead of time whether the operation will succeed."
Take Peter Hosey's suggestion and make use of the NSError if the call fails as you attempt to write to the file and don't try to figure it out ahead of time.

Related

get file attributes with nsfilesustem in cocoa no such file exists

I've searching for about 3 hours of how to get the creation date of a file, I get the URL with an enumerator, after that I pass it to path correcting the percents, and finally I try to get the file attributes...so, I don no alter the path in anyway but I always get the same error "The operation couldn’t be completed. No such file or directory", and the path "file:///Users/raul/Desktop/DSC_0386.JPG".
The code sample:
NSError* error = nil;
//NSDictionary* fileAttribs = [[NSFileManager defaultManager] attributesOfItemAtPath:[[url absoluteString] stringByRemovingPercentEncoding] error:&error];
NSDictionary* fileAttribs = [[NSFileManager defaultManager] attributesOfItemAtPath:#"file://Users/raul/Desktop/DSC_0386.JPG" error:&error];
NSLog(#"%#",error);
NSDate *fecha = [fileAttribs objectForKey:NSFileCreationDate];
I've commented the first NSDictionary to try out the second statement with the nsstring directly.
I've checked that my file already exists.
Please, any help?? I'm missing anything?
Several issues:
1) In most cases, you shouldn't have to convert an NSURL to a path string in order to operate on a file. In particular, you can use the "resource value" API of NSURL to get the creation time directly:
NSDate* creationDate;
NSError* error;
if ([url getResourceValue:&creationDate forKey:NSURLCreationDateKey error:&error])
/* use creationDate */;
else
/* handle error */;
2) If you do need to get a path string from NSURL, don't use -absoluteString. That will still be a URL string, with things like "file://", etc. A URL string is not a valid path string. The error message you quoted in your question was already telling you this. It showed you a file "path" of "file:///Users/raul/Desktop/DSC_0386.JPG", but that's not a path at all.
You should just use the -path method. You do not need to do anything with percent encoding when you get the -path.
3) You should ignore any error output parameter until you have checked whether the method you called succeeded or failed, usually by examining its return value. That is, the code you posted should be reorganized like this:
NSError* error = nil;
NSDictionary* fileAttribs = [[NSFileManager defaultManager] attributesOfItemAtPath:#"file://Users/raul/Desktop/DSC_0386.JPG" error:&error];
if (fileAttribs)
{
NSDate *fecha = [fileAttribs objectForKey:NSFileCreationDate];
// ... use fecha ...
}
else
NSLog(#"%#",error);

NSFileManager enumeratorAtURL doesn't work properly on XCode 6 / iOS 8

I'm on Mavericks.
I'm using the simulator.
It appears that NSFileManager URL based methods don't work properly on XCode 6 / iOS 8.
In my code sample at bottom, the path being searched in 'directoryToScan' is ...
/Users/xxxx/Library/Developer/CoreSimulator/Devices/A092C58C-1A43-4AF3-A9B1-109D7BA27F8D/data/Containers/Data/Application/41232C14-CF90-4E5C-72A7-8FF464FE7C32/Documents
In the code at bottom, even though I have files at the path I'm providing, when my code reaches the "for in" enumerator, it jumps right over the "for in" block to the end of it, and continues at the next line, and I get NO ERROR message from the block in the errorHandler.
I also tried a while clause, and that did the same.
Also, I tried two other techniques...
// THIS DOES NOT WORK
NSArray *dirContents = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:directoryToScan includingPropertiesForKeys:nil options:NSDirectoryEnumerationSkipsHiddenFiles error:&theError];
// THIS DOES WORK
NSArray *dirContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:documentDirectory error:&theError];
So it appears there's a problem with NSURL's in iOS 8.
Any idea what's going on? I would think if there were a permission issue, I would have seen an error in my handler.
NSURL *directoryToScan = [NSURL fileURLWithPath:documentDirectory];
NSDirectoryEnumerator *dirEnumerator = [[NSFileManager defaultManager] enumeratorAtURL:directoryToScan
includingPropertiesForKeys:[NSArray arrayWithObjects:NSURLIsDirectoryKey, nil]
options:NSDirectoryEnumerationSkipsHiddenFiles | NSDirectoryEnumerationSkipsSubdirectoryDescendants | NSDirectoryEnumerationSkipsPackageDescendants
errorHandler:^(NSURL *url, NSError *error){
NSLog(#"Error occurred at url %#",url);
NSLog(#"Error message is %#",error);
return YES;}];
for (NSURL *theURL in dirEnumerator)
{
// Work with the files found by dirEnumerator.
// This whole block is being skipped over.
}
If you are still interesting in investigating the issue can You please provide the code for setting directoryToScan and documentDirectory? Have you tried to print both values during debug to ensure they both address same directory? In Xcode 6.1?
In Xcode 6.1 both for (NSURL *theURL in dirEnumerator) and for (NSURL* theURL = [dirEnumerator nextObject]) work fine for me.

Creating a security scope bookmark for a file from one of a directory containing it

I have a security scope bookmark for a directory, provided by a user via an openDialog request.
I'm trying to create another security scope bookmark for a file inside this directory:
NSURL *musicFolder = /* Secured URL Resolved from a NSData, bookmark not stale */;
if (![musicFolder startAccessingSecurityScopedResource]) {
NSLog(#"Error accessing bookmark.");
}
NSString *file = #"myfile.txt"; /* This file exists inside the directory */
NSURL *pathURL = [musicFolder URLByAppendingPathComponent:file];
NSError *systemError;
NSData *bookmarkData = [pathURL bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope
includingResourceValuesForKeys:nil
relativeToURL:nil
error:&systemError];
[musicFolder stopAccessingSecurityScopedResource];
if (!bookmarkData) {
NSLog(#"%#", systemError);
}
Both bookmarkData and systemError end up nil which is not very useful...
Is this even supported or can you only get valid secured scope bookmarks from the system?
In my test program this works fine. I suspect the append of the file name to the URL is failing in your case (but that's a huge guess) because it's the only thing that seems materially different.
I notice that the url for a security resolved location is: file://localhost/Users/dad/Desktop/TestFolder?applesecurityscope=343335323030663066393432306234363030346263613464636464643130663635353065373030373b30303030303030303b303030303030303030303030303032303b636f6d2e6170706c652e6170702d73616e64626f782e726561642d77726974653b30303030303030313b30313030303030323b303030303030303030326461363838663b2f75736572732f74796c65722f6465736b746f702f74657374666f6c646572
which is the other reason I wonder if the append is the issue.
In my test I have the user choose the folder, create the security scoped bookmark and then save that in user defaults.
Then I quit & relaunch the app and via a menu command I get that bookmark and then resolve it. Then I added a case where I use the resolved bookmark to a folder and make a new bookmark to the file within the folder.
It seems to work fine.
In my test where it's working I'm getting the path to the file like this:
NSURL * resolvedURL = [NSURL URLByResolvingBookmarkData: data
options: NSURLBookmarkResolutionWithSecurityScope
relativeToURL: nil
bookmarkDataIsStale: &isStale
error: &error];
... // (error checking)
[resolvedURL startAccessingSecurityScopedResource];
NSArray * files = [[NSFileManager defaultManager]
contentsOfDirectoryAtURL: resolvedURL
includingPropertiesForKeys: #[NSURLLocalizedNameKey, NSURLCreationDateKey]
options: NSDirectoryEnumerationSkipsHiddenFiles
error: &error];
if ( files != nil )
{
NSURL * fileURL = [files objectAtIndex: 0]; // hard coded for my quick test
NSData * newData = [fileURL bookmarkDataWithOptions: NSURLBookmarkCreationWithSecurityScope
includingResourceValuesForKeys: nil
relativeToURL: nil
error: &error];
if ( newData != nil )
{
NSLog(#"it's good!");
}
.... // error checking and logging.
if that doesn't get you on the right track, I'm going to need to see more code (you'll probably need to make a simple example).
Note that in my case I'm resolving the bookmark and calling startAccessingSecurityScopedResource even when I just got the url & created the bookmark (when I tried to create a bookmark from the path I'd just acquired from PowerBox (openPanel) it failed with an error 256).
Some configuration details: OS X 10.8.4, Xcode 5 (first public release from today 9/18/2013).
For creating bookmarks for locked files, use NSURLBookmarkCreationSecurityScopeAllowOnlyReadAccess flag combined with NSURLBookmarkCreationWithSecurityScope flag in API call for creating bookmark.
For example:
NSURL* fileURL = [NSURL fileURLWithPath:filePath];
NSError* error = NULL;
NSData* bookmarkData = [fileURL bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope|NSURLBookmarkCreationSecurityScopeAllowOnlyReadAccess includingResourceValuesForKeys:nil relativeToURL:nil error:&error];
I have tried this in Mac OS 10.9.5
Following up after reporting the problem with security-scoped bookmarks and locked-files, this is the reply from Apple:
"Also, as you've noticed, creating a security-scoped bookmark requires write access to the target file. That should no longer be the case in OS X Mavericks."
Which would indicate that it is a bug in version of OS X pre-10.9.

initWithContentsOfURL often returns nil

NSError *error;
NSString *string = [[NSString alloc]
initWithContentsOfURL:URL
encoding:NSUTF8StringEncoding
error:&error];
When I test this on my iPhone it always works when I have wifi turned on. However when I'm on 3G I often get nil. If I try perhaps 15 times in a row (I have an update button for this) I finally get the desired result.
My question is, is this problem located at the server side or is my code unstable? Should I use a different approach to get a more secure fetch of data?
You haven't provided enough information to give anything but a vague answer, but you do have some options here.
Most importantly, you have an "error" parameter that you should be printing out the results of. There's also a slightly better API you could be using in the NSString class.
Change your code to something like this:
NSError *error = NULL;
NSStringEncoding actualEncoding;
// variable names in Objective-C should usually start with lower case letters, so change
// URL in your code to "url", or even something more descriptive, like "urlOfOurString"
NSString *string = [[NSString alloc] initWithContentsOfURL:urlOfOurString usedEncoding:&actualEncoding error:&error];
if(string)
{
NSLog( #"hey, I actually got a result of %#", string);
if(actualEncoding != NSUTF8StringEncoding)
{
// I also suspect the string you're trying to load really isn't UTF8
NSLog( #"and look at that, the actual encoding wasn't NSUTF8StringEncoding");
}
} else {
NSLog( #"error when trying to fetch from URL %# - %#", [urlOfOurString absoluteString], [error localizedDescription]);
}
I'm now using STHTTPRequest instead. I recommend this library very much, easy to use yet powerful.

strange behavior of xcode 4.2

Strange and funny think is going on
Code:
-(void)saveFile
{
NSFileManager *fileMng = [NSFileManager defaultManager];
if(![fileMng fileExistsAtPath:self.appFilesPath])
{
NSError *error = nil;
BOOL success = [fileMng createDirectoryAtPath:self.appFilesPath withIntermediateDirectories:YES attributes:nil error:&error];
if(!success)
{
NSLog([error localizedDescription]);
}
}
NSLog([NSString stringWithFormat:#"%#",self.appFilesPath]);
[fileMng createFileAtPath:self.fileFullPath contents:self.fileData attributes:nil];
[self.fileData writeToFile:self.fileFullPath atomically:YES];
}
and this line
NSLog([NSString stringWithFormat:#"%#",self.appFilesPath]);
should give me something like this
file://localhost/Users/user/Library/Application%20Support/iPhone%20Simulator/5.0/Applications/BF35B859-514B-45AA-8E3A-B2CE65BD82B6/Documents/AppFiles
Directory AppFiles should be created under ../Documents/ directory,
but it's not there...
and the nslog gives me something like this:
file://localhost/Users/user/Library/Application瑳楲杮楗桴潆浲瑡:敲敬獡e摡䕤瑮楲獥牆浯楄瑣潩慮祲:扯敪瑣潆䭲祥:汣獡s獩楋摮晏汃獡㩳氀湥瑧h畡潴敲敬獡e敳佴橢捥㩴潦䭲祥:敲潭敶扏敪瑣潆䭲祥:湩整敧噲污敵戀潯噬污敵爀浥癯䅥汬扏敪瑣s湩瑩猀慨敲䥤獮慴据e敲楧瑳牥敎睴牯䑫晥畡瑬䙳牯灁䥰㩄挀灯y摡佤橢捥㩴洀楡䉮湵汤e畢摮敬摉湥楴楦牥椀䕳畱污潔瑓楲杮:桳牡摥潃普杩牵瑡潩n潣湵牴䑹晥畡瑬潆..few more screens of this bush..帴㽻椽絩8筞㴿楩}ㅶ䀶㨰帴㽻椽絩椸㈱䀀䜢佅楐數偬楯瑮"㽻搽絤䀸㨰4㉶䀴㨰笴㴿摤㡽䀀倢剂煥敵瑳牥"ㅶ䀶㨰⌴匸㈱䀀㰢䕇协灵潰瑲摥楔敬敓獴敓癲牥牐硯䑹汥来瑡㹥"㍶䀶㨰笴㴿摤㡽㉤椴㈳瘀㘱぀㐺㡀ㅩ2㉶䀸㨰帴㽻搽絤䤸㈱ㅤ椶㐲瘀㈱぀㐺癞8ㅀ䀶㨰帴㡶ㅣ2筞硟捰损湯敮瑣潩彮㵳}ㅀ䀶㨰䀴常彻䍟剆湵潌灯紽㈱帀彻䍟剆湵潌灯紽䀸㨰4筞彟䙃畒䱮潯㵰}癞䀸㨰4ㅀ䀲㨰帴㡶瘀〲぀㐺㡀ㅀ䤲㘱䀀㰢华慃档䑥汥来瑡㹥"㉀䀸㨰䀴笸㴿摤ㅽ2㽻搽絤㠲぀㐺㽻搽絤常㉤4㽻∽慬楴畴敤搢氢湯楧畴敤搢}upport/iPhone 貌Š߈imulator/5.0/Applications/CAF90A92-5B85-4FC0-8482-3702C3E98F8D/Documents/AppFiles
when i run code second time, the if condision is skiped, but ../Documents/ directory is stil empty
来瑡㹥"㉀䀸 - i mean wtf, first time something like this,
restarting xcode, mac did't help,
simulator is all set to english,
it also happen in other projects,
keyboard setting ant nationalization looks ok,
so realy I have no clue what is wrong
any ideas?
You can not just NSLog a string. The string argument it takes is a format (like in printf) which interpeted specially. In your case, it is reading random memory because %20S means to interpret the next argument as pointer to null-terminated string of wide characters and print it right-aligned in 20 columns; and they are Chinese because most of Unicode is occupied by Chinese hieroglyphs.
This is the correct way to do it:
NSLog(#"%#", self.appFilesPath);

Resources