Produce error string for any failure from saving with NSFileManager

This commit is contained in:
Allan Odgaard
2019-07-07 22:10:11 +02:00
parent 3f8c2d0bbd
commit 824981eaa2
4 changed files with 67 additions and 43 deletions

View File

@@ -134,17 +134,12 @@ namespace
path::intermediate_t dest(path, atomicSave);
int fd = open(dest, O_CREAT|O_TRUNC|O_WRONLY|O_CLOEXEC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH);
int fd = dest.open(&error);
if(fd == -1)
error = text::format("open(\"%s\"): %s", (char const*)dest, strerror(errno));
;
else if(write(fd, bytes->get(), bytes->size()) != bytes->size())
{
error = text::format("write: %s", strerror(errno));
close(fd);
}
else if(close(fd) != 0)
error = text::format("close: %s", strerror(errno));
else if(!dest.commit(&error))
else if(!dest.close(&error))
;
else if(!path::set_attributes(path, attributes))
error = text::format("Setting extended attributes");

View File

@@ -14,16 +14,18 @@ namespace path
struct strategy_t
{
virtual ~strategy_t () { }
virtual char const* path () const = 0;
virtual bool commit (std::string* errorMsg) const = 0;
virtual char const* setup (std::string* errorMsg) = 0;
virtual bool commit (std::string* errorMsg) = 0;
};
intermediate_t (std::string const& dest, atomic_t atomicSave = atomic_t::always);
operator char const* () const { return _strategy->path(); }
bool commit (std::string* errorMsg = nullptr) const { return _strategy->commit(errorMsg); }
~intermediate_t ();
int open (std::string* errorMsg = nullptr, int oflag = O_CREAT|O_TRUNC|O_WRONLY|O_CLOEXEC, mode_t mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH);
bool close (std::string* errorMsg = nullptr);
private:
std::unique_ptr<strategy_t> _strategy;
int _fileDescriptor = -1;
};
} /* path */

View File

@@ -109,16 +109,6 @@ namespace path
filemanager_strategy_t (NSURL* destURL)
{
_destURL = destURL;
NSError* error;
if(_tempDirectoryURL = [NSFileManager.defaultManager URLForDirectory:NSItemReplacementDirectory inDomain:NSUserDomainMask appropriateForURL:destURL create:YES error:&error])
{
_tempURL = [_tempDirectoryURL URLByAppendingPathComponent:_destURL.lastPathComponent];
}
else
{
os_log_error(OS_LOG_DEFAULT, "Failed to obtain NSItemReplacementDirectory for %{public}@: %{public}@\n", destURL, error);
}
}
~filemanager_strategy_t ()
@@ -128,17 +118,34 @@ namespace path
os_log_error(OS_LOG_DEFAULT, "failed removing %{public}@: %{public}@\n", _tempDirectoryURL, error);
}
char const* path () const
char const* setup (std::string* errorMsg)
{
return _tempURL.fileSystemRepresentation;
NSError* error;
if(_tempDirectoryURL = [NSFileManager.defaultManager URLForDirectory:NSItemReplacementDirectory inDomain:NSUserDomainMask appropriateForURL:_destURL create:YES error:&error])
{
_tempURL = [_tempDirectoryURL URLByAppendingPathComponent:_destURL.lastPathComponent];
return _tempURL.fileSystemRepresentation;
}
NSString* displayName;
[_destURL getResourceValue:&displayName forKey:NSURLLocalizedNameKey error:nil];
*errorMsg = to_s([NSString stringWithFormat:@"Failed to obtain replacement directory for %@: %@", displayName ?: _destURL.path, error.localizedDescription]);
os_log_error(OS_LOG_DEFAULT, "failed to obtain NSItemReplacementDirectory for %{public}@: %{public}@\n", _destURL, error);
return nullptr;
}
bool commit (std::string* errorMsg) const
bool commit (std::string* errorMsg)
{
NSError* error;
if([NSFileManager.defaultManager replaceItemAtURL:_destURL withItemAtURL:_tempURL backupItemName:nil options:NSFileManagerItemReplacementUsingNewMetadataOnly resultingItemURL:nil error:&error])
return true;
os_log_error(OS_LOG_DEFAULT, "failed replacing %{public}@ with %{public}@: %{public}@\n", _tempURL, _destURL, error);
NSString* displayName;
[_destURL getResourceValue:&displayName forKey:NSURLLocalizedNameKey error:nil];
*errorMsg = to_s([NSString stringWithFormat:@"Failed replacing %@ with %@: %@", displayName ?: _destURL.path, _tempURL.path, error.localizedDescription]);
os_log_error(OS_LOG_DEFAULT, "failed replacing %{public}@ with %{public}@: %{public}@\n", _destURL, _tempURL, error);
return false;
}
@@ -155,16 +162,15 @@ namespace path
D(DBF_IO_Intermediate, bug("%s → %s → %s\n", dest.c_str(), _resolved.c_str(), _intermediate.c_str()););
}
char const* path () const
char const* setup (std::string* errorMsg)
{
return _intermediate.c_str();
}
bool commit (std::string* errorMsg) const
bool commit (std::string* errorMsg)
{
D(DBF_IO_Intermediate, bug("%s ⇔ %s (swap: %s)\n", _resolved.c_str(), _intermediate.c_str(), BSTR(_intermediate != _resolved)););
std::string ignoreErrorMsg;
return _intermediate == _resolved ? true : swap_and_unlink(_intermediate, _resolved, errorMsg ? *errorMsg : ignoreErrorMsg);
return _intermediate == _resolved ? true : swap_and_unlink(_intermediate, _resolved, *errorMsg);
}
private:
@@ -178,12 +184,12 @@ namespace path
{
}
char const* path () const
char const* setup (std::string* errorMsg)
{
return _path.c_str();
}
bool commit (std::string* errorMsg) const
bool commit (std::string* errorMsg)
{
return true;
}
@@ -200,7 +206,7 @@ namespace path
}
else if(path::exists(dest))
{
NSURL* destURL = [NSURL fileURLWithPath:to_ns(path::resolve_head(dest)) isDirectory:NO];
NSURL* destURL = [NSURL fileURLWithPath:to_ns(dest) isDirectory:NO];
NSError* error;
NSNumber* boolean;
@@ -218,4 +224,33 @@ namespace path
}
}
intermediate_t::~intermediate_t ()
{
if(_fileDescriptor != -1)
::close(_fileDescriptor);
}
int intermediate_t::open (std::string* errorMsg, int oflag, mode_t mode)
{
std::string ignoredErrorMsg;
if(char const* path = _strategy->setup(errorMsg ?: &ignoredErrorMsg))
{
_fileDescriptor = ::open(path, oflag, mode);
if(_fileDescriptor == -1 && errorMsg)
*errorMsg = text::format("open(\"%s\"): %s", path, strerror(errno));
}
return _fileDescriptor;
}
bool intermediate_t::close (std::string* errorMsg)
{
int res = ::close(_fileDescriptor);
if(res == -1 && errorMsg)
*errorMsg = text::format("close(\"%d\"): %s", _fileDescriptor, strerror(errno));
_fileDescriptor = -1;
std::string ignoredErrorMsg;
return res != -1 && _strategy->commit(errorMsg ?: &ignoredErrorMsg);
}
} /* path */

View File

@@ -587,16 +587,8 @@ namespace path
{
intermediate_t dest(path);
int fd = open(dest, O_CREAT|O_TRUNC|O_WRONLY|O_CLOEXEC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH);
if(fd == -1)
return false;
int res DB_VAR = write(fd, first, last - first);
ASSERT_EQ(res, last - first);
int rc DB_VAR = close(fd);
ASSERT_EQ(rc, 0);
return dest.commit();
int fd = dest.open();
return fd != -1 && write(fd, first, last - first) == last - first && dest.close();
}
std::string get_attr (std::string const& p, std::string const& attr)