Re: Strange NSFileManager file replacement issue

2011-08-19 Thread Ken Thomases
On Aug 19, 2011, at 12:43 AM, Ken Thomases wrote:

 On Aug 19, 2011, at 12:38 AM, Ken Thomases wrote:
 
 Although it is easy to interpret a temporary directory as provided by the 
 OS being compatible with NSTemporaryDirectory(), I suspect it really means 
 a directory returned by 
 -URLForDirectory:inDomain:appropriateForURL:create:error: with 
 NSItemReplacementDirectory passed for the directory and your ultimate 
 destination URL passed for the url parameter.
 
 Hmm.  Didn't follow the link to StackOverflow early enough.  Post there 
 claims it was tried and didn't help.

Sorry to reply to myself twice, but the StackOverflow post passed NO for the 
shouldCreate parameter of -URLForDirectory:...  It's worth trying with YES.

The other thing to try is the suggestion from the -replaceItemAtURL: docs for 
newItemURL.  Use a uniquely named directory placed in the same directory as 
the original item if the temporary directory is not available.

Regards,
Ken

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Strange NSFileManager file replacement issue

2011-08-19 Thread Sixten Otto
On Thu, Aug 18, 2011 at 10:14 PM, Quincey Morris 
quinceymor...@rivergatesoftware.com wrote:

 a. What version of iOS did this fail on?


The 4.3 simulator (running on Snow Leopard, Xcode 4.0.2).


 b. Can you assert that the receiver of the 'replace…' method is not nil?
 (If it was nil, the method call would behave exactly as you describe.)


Good thing to check, but since it's returning YES for the -fileExistsAtPath:
calls, and works in some of the other cases, I doubt that the NSFileManager
is nil.


 c. Can you show us the actual line of code that does the replacement?


I'll post my code when I get in to the office. (I got about this far before
I had to leave last night.)

Sixten
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Strange NSFileManager file replacement issue

2011-08-19 Thread Sixten Otto
On Thu, Aug 18, 2011 at 10:38 PM, Ken Thomases k...@codeweavers.com wrote:

 My thinking is that -replaceItemAtURL:... is a wrapper around
 exchangedata() or FSExchangeObjects().  Those functions, and the general
 operation that they perform, require that the files to be exchanged be on
 the same file system.  It would seem that, on iOS, the application's
 Document folder is on a different file system from the temporary directory.
  This is exactly the problem which
 -URLForDirectory:NSItemReplacementDirectory... is intended to solve.  It's
 to give you a temporary directory that's appropriate for a subsequent
 -replaceItemAtURL:... call.


If true, that certainly makes that method far less useful in the general
case than I expected, and really seems restricted to the saving a new copy
of an in-memory document and swapping it case. I really don't want to put
the in-process download into the Documents tree. (Both because it's
potentially visible to the user through iTunes, and because
NSTemporaryDirectory() will be swept up occasionally.) I'll see what I can
do to test this this morning.

I guess the question then becomes:
- Abandon the use of the atomic swap altogether, and roll my own
copy+remove?
- Or introduce an extra step, where I copy the temp file into
NSItemReplacementDirectory,
and then call replaceItemAtURL?
- Or is there some better pattern altogether?


 I recommend that you file bugs against the documentation for not adequately
 explaining the requirements on the newItemURL parameter and against the
 implementation for failing to provide a valid NSError pointer on failure in
 this case.


Definitely. I want to verify that I *can* make it work if the replacement
item is already in the Documents tree / replacement directory, and then I'll
be spending some time on the bug reporter.

Sixten
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Strange NSFileManager file replacement issue

2011-08-19 Thread Sixten Otto
On Thu, Aug 18, 2011 at 10:14 PM, Quincey Morris
quinceymor...@rivergatesoftware.com wrote:
 c. Can you show us the actual line of code that does the replacement?

Here's the original code (plus the addition of an assert on the file
manager). The property self.filePath has the path to the current
version of the file that's already on disk (from a previous pass
through this code). In my current test case, the paths look something
like:

self.filePath: 
/Users/sixten/Library/Application%20Support/iPhone%20Simulator/4.3.2/Applications/840B5926-8107-458E-87ED-ABF0F084BC12/Documents/Subdir/MyFile.pdf
tempFilePath: /var/folders/KP/KPl-d+TMHGaIJ6QIjMYNQTI/-Tmp-/2212

// start original code
NSFileManager* fileManager = [[NSFileManager alloc] init];
NSAssert(fileManager != nil, @File manager wasn't created.);

NSString* directoryPath = [fileManager
rd_documentsSubdirectory:self.document.volume];
BOOL isDirectory;
NSAssert1([fileManager fileExistsAtPath:tempFilePath
isDirectory:isDirectory]  isDirectory == NO, @Bad temp file path
%@, tempFilePath);
NSAssert1([fileManager fileExistsAtPath:directoryPath
isDirectory:isDirectory]  isDirectory == YES, @Bad document
directory %@, directoryPath);

if( [desiredName length] == 0 ) {
  if( self.filePath ) {
desiredName = [self.filePath lastPathComponent];
  }
  else {
desiredName = [tempFilePath lastPathComponent];
  }
}

NSString* finalPath = [directoryPath
stringByAppendingPathComponent:desiredName];
NSError* error = nil;
if( [finalPath isEqualToString:self.filePath] || [self.filePath
hasPrefix:directoryPath] ) {
  NSURL* existingFileURL = [NSURL fileURLWithPath:finalPath];
  NSURL* newFileURL = [NSURL fileURLWithPath:tempFilePath];
  NSString* backupItemName = [NSString
stringWithFormat:@__%@__.bak, self.documentId];
  NSURL* resultURL = nil;

  // *** 1
  if( [fileManager replaceItemAtURL:existingFileURL
withItemAtURL:newFileURL backupItemName:backupItemName options:0
resultingItemURL:resultURL error:error] ) {
self.filePath = [resultURL path];
success = YES;
  }
  else {
// *** ends up here, with no error == nil
LOG_GENERAL(LOG_PRIORITY_HIGHEST, @Error attempting to
replace »%@« with »%@«: %@\n%@, tempFilePath, finalPath, [error
localizedDescription]);
NSAssert(NO, @Couldn't move file to designated location);
  }
  // *** 2
}
else {
  // ... move the temp file to finalPath, which works just fine,
and update self.filePath
}

[fileManager release];
// end original code


This morning, I replaced the code between the *** 1 and *** 2 with
the following, which still failed in exactly the same way. It does get
create a replacement directory and return it, my temp file moves into
that directory without issue, but the swap still mysteriously fails.
The value of swapURL looks like:

file://localhost/Users/sixten/Library/Application%20Support/iPhone%20Simulator/4.3.2/Applications/840B5926-8107-458E-87ED-ABF0F084BC12/Documents/Subdir/(A%20Document%20Being%20Saved%20By%20MyApp)/MyFile.pdf

  // *** 1
  NSURL* swapURL = [fileManager
URLForDirectory:NSItemReplacementDirectory inDomain:NSUserDomainMask
appropriateForURL:existingFileURL create:YES error:error];
  if( swapURL ) {
swapURL = [swapURL URLByAppendingPathComponent:desiredName];
if( [fileManager moveItemAtURL:newFileURL toURL:swapURL error:NULL] ) {
  if( [fileManager replaceItemAtURL:existingFileURL
withItemAtURL:swapURL backupItemName:backupItemName options:0
resultingItemURL:resultURL error:error] ) {
self.filePath = [resultURL path];
success = YES;
  }
  else {
// *** still gets here, with no error set!
LOG_GENERAL(LOG_PRIORITY_HIGHEST, @Error attempting to
replace »%@« with »%@«: %@\n%@, tempFilePath, finalPath, [error
localizedDescription]);
NSAssert(NO, @Couldn't move file to designated location);
  }
}
  }
  else {
LOG_GENERAL(LOG_PRIORITY_HIGHEST, @Error attempting to
replace »%@« with »%@«: %@\n%@, tempFilePath, finalPath, [error
localizedDescription]);
NSAssert(NO, @Couldn't find/create swap location);
  }
  // *** 2
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Strange NSFileManager file replacement issue

2011-08-19 Thread Steve Christensen
On Aug 19, 2011, at 7:17 AM, Sixten Otto wrote:

 On Thu, Aug 18, 2011 at 10:38 PM, Ken Thomases k...@codeweavers.com wrote:
 
 Those functions, and the general operation that they perform, require that
 the files to be exchanged be on the same file system.
 
 If true, that certainly makes that method far less useful in the general
 case than I expected, and really seems restricted to the saving a new copy
 of an in-memory document and swapping it case. I really don't want to put
 the in-process download into the Documents tree. (Both because it's
 potentially visible to the user through iTunes, and because
 NSTemporaryDirectory() will be swept up occasionally.)

Is there any reason why you can't put the downloaded file in your app's private 
cache directory (.../appdir/Library/Caches), i.e., what gets returned by 
NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)? 
That should certainly be within the bigger app directory hierarchy, and thus a 
peer of the app's Documents directory.


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Strange NSFileManager file replacement issue

2011-08-19 Thread Sixten Otto
On Fri, Aug 19, 2011 at 1:14 PM, Steve Christensen puns...@mac.com wrote:

 Is there any reason why you can't put the downloaded file in your app's
 private cache directory (.../appdir/Library/Caches), i.e., what gets
 returned by NSSearchPathForDirectoriesInDomains(NSCachesDirectory,
 NSUserDomainMask, YES)? That should certainly be within the bigger app
 directory hierarchy, and thus a peer of the app's Documents directory.


Can't? No. My preference for NSTemporaryDirectory() was mainly the notion
that I had help from the OS in clearing out any old partial downloads that
whatever weird circumstances might have orphaned.

But I'm not sure that it'd matter. Even when I moved the file from there to
the NSItemReplacementDirectory given by the file manager,
-replaceItemAtURL:... was still behaving identically. (See my previous
message for the details.)

Sixten
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Strange NSFileManager file replacement issue

2011-08-19 Thread Ken Thomases
On Aug 19, 2011, at 10:29 AM, Sixten Otto wrote:

 This morning, I replaced the code between the *** 1 and *** 2 with
 the following, which still failed in exactly the same way. It does get
 create a replacement directory and return it, my temp file moves into
 that directory without issue, but the swap still mysteriously fails.

I realize this is getting further and further from what you actually want, but 
you might try using the exchangedata() or FSExchangeObjects() functions 
directly.  At least that way, you should receive a clearer error result.  For 
the latter, you can get FSRefs from NSURLs via CFURLGetFSRef(), since NSURL and 
CFURLRef are toll-free bridged.

The ability to exchange objects has to be supported by the file system.  Maybe 
the file system on an iOS device simply doesn't support it.  The errors you get 
back from the above functions ought to make that clear.

Regards,
Ken

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Strange NSFileManager file replacement issue

2011-08-18 Thread Sixten Otto
I have an iOS app where I'm storing files in the app's Documents directory,
and occasionally downloading new versions from the server to replace them.
The actual code is split across a number of files and classes, but the end
of the process goes like this:

- The download of the new data to a temporary file in NSTemporaryDirectory()
finishes successfully.
- I calculate the path I want to copy it to.
- I see that there's already a previous version of the file at that path.
- I try to use -[NSFileManager
replaceItemAtURL:withItemAtURL:backupItemName:options:resultingItemURL:error:]
to
swap in the new file.

That method returns NO for failure, so I check the error... but it's nil.
There's nothing there to tell me what the heck is failing. (In fact, when I
wasn't initializing my error pointer to nil, it was left as a garbage
pointer, and crashed my app.) My app put the original file there, so
(presumably) that path is writable. The file manager does return true from
-fileExistsAtPath: for both files.

The only thing that Google can turn up is this StackOverflow question. Same
exact symptoms. But, of course, no answers.
http://stackoverflow.com/questions/4899618/replaceitematurl-fails-without-error-on-ios-but-works-fine-on-osx

I can *remove* the file that I can't overwrite, and I can move the temp file
into Documents in the case where there isn't already a version on disk.
Obviously, neither of those cases uses replaceItemAtURL.

Does anyone know what circumstances might cause this failure? Any
recommendations on what things I should check next?

Sixten
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Strange NSFileManager file replacement issue

2011-08-18 Thread Quincey Morris
On Aug 18, 2011, at 21:24 , Sixten Otto wrote:

 That method returns NO for failure, so I check the error... but it's nil.
 There's nothing there to tell me what the heck is failing. (In fact, when I
 wasn't initializing my error pointer to nil, it was left as a garbage
 pointer, and crashed my app.) My app put the original file there, so
 (presumably) that path is writable. The file manager does return true from
 -fileExistsAtPath: for both files.

a. What version of iOS did this fail on?

b. Can you assert that the receiver of the 'replace…' method is not nil? (If it 
was nil, the method call would behave exactly as you describe.)

c. Can you show us the actual line of code that does the replacement?


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Strange NSFileManager file replacement issue

2011-08-18 Thread Ken Thomases
On Aug 18, 2011, at 11:24 PM, Sixten Otto wrote:

 - The download of the new data to a temporary file in NSTemporaryDirectory()
 finishes successfully.
 - I calculate the path I want to copy it to.
 - I see that there's already a previous version of the file at that path.
 - I try to use -[NSFileManager
 replaceItemAtURL:withItemAtURL:backupItemName:options:resultingItemURL:error:]
 to
 swap in the new file.
 
 That method returns NO for failure, so I check the error... but it's nil.

This is something of a guess:

The documentation for 
-replaceItemAtURL:withItemAtURL:backupItemName:options:resultingItemURL:error: 
is a bit vague in its description of the newItemURL parameter:

 The item which will replace the originalItemURL. This item should be placed 
 in a temporary directory as provided by the OS, or in a uniquely named 
 directory placed in the same directory as the original item if the temporary 
 directory is not available.

Although it is easy to interpret a temporary directory as provided by the OS 
being compatible with NSTemporaryDirectory(), I suspect it really means a 
directory returned by -URLForDirectory:inDomain:appropriateForURL:create:error: 
with NSItemReplacementDirectory passed for the directory and your ultimate 
destination URL passed for the url parameter.

My thinking is that -replaceItemAtURL:... is a wrapper around exchangedata() or 
FSExchangeObjects().  Those functions, and the general operation that they 
perform, require that the files to be exchanged be on the same file system.  It 
would seem that, on iOS, the application's Document folder is on a different 
file system from the temporary directory.  This is exactly the problem which 
-URLForDirectory:NSItemReplacementDirectory... is intended to solve.  It's to 
give you a temporary directory that's appropriate for a subsequent 
-replaceItemAtURL:... call.

For what it's worth, I can reproduce this on Mac OS X (Snow Leopard 10.6.8), 
when the two files to be exchanged are on different file systems (a.k.a. 
volumes).

I recommend that you file bugs against the documentation for not adequately 
explaining the requirements on the newItemURL parameter and against the 
implementation for failing to provide a valid NSError pointer on failure in 
this case.

Regards,
Ken

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Strange NSFileManager file replacement issue

2011-08-18 Thread Ken Thomases
On Aug 19, 2011, at 12:38 AM, Ken Thomases wrote:

 Although it is easy to interpret a temporary directory as provided by the 
 OS being compatible with NSTemporaryDirectory(), I suspect it really means a 
 directory returned by 
 -URLForDirectory:inDomain:appropriateForURL:create:error: with 
 NSItemReplacementDirectory passed for the directory and your ultimate 
 destination URL passed for the url parameter.

Hmm.  Didn't follow the link to StackOverflow early enough.  Post there claims 
it was tried and didn't help.

Sorry,
Ken

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com