blob: 1bf08b094e47b4504c012fff84a6cceba8d2708b [file] [log] [blame]
From 42243c105b6a067b9e680ba84c417c972eaa4d3f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Degros?= <fdegros@chromium.org>
Date: Mon, 29 Jun 2020 00:29:00 +1000
Subject: [PATCH] Better error reporting via exceptions
Added exception class ZipError to carry libzip error code.
Made DataNode exception-transparent.
Removed some try-catch thanks to the use of unique_ptr.
If the ZIP archive cannot be opened and mounted, fuse-zip now returns
different error codes depending on the underlying error condition.
Ensured that C++ exceptions cannot escape from the following C-style
FUSE callbacks: fusezip_open, fusezip_create, fusezip_mknod,
fusezip_read, fusezip_write, fusezip_release, fusezip_ftruncate,
fusezip_truncate and fusezip_rename. This pattern could (should) be
applied to the rest of these FUSE callbacks.
Avoid logging filenames in syslog. Filenames can contain PII.
---
lib/dataNode.cpp | 30 ++----
lib/fileNode.cpp | 33 ------
lib/fuse-zip.cpp | 243 ++++++++++++++++++++++----------------------
lib/fuse-zip.h | 4 +-
lib/fuseZipData.cpp | 74 ++++++++------
lib/util.h | 50 +++++++++
main.cpp | 17 ++--
7 files changed, 231 insertions(+), 220 deletions(-)
diff --git a/lib/dataNode.cpp b/lib/dataNode.cpp
index 17c94c2..0efd7bc 100644
--- a/lib/dataNode.cpp
+++ b/lib/dataNode.cpp
@@ -27,9 +27,6 @@
#include <cstring>
#include <ctime>
#include <memory>
-#include <stdexcept>
-
-#include <syslog.h>
#include "dataNode.h"
#include "extraField.h"
@@ -118,21 +115,13 @@ int DataNode::open(struct zip *zip) {
}
if (_state == NodeState::CLOSED) {
_open_count = 1;
- try {
- assert(zip != NULL);
- if (_size > std::numeric_limits<size_t>::max()) {
- return -ENOMEM;
- }
- assert(_id != FAKE_ID);
- _buffer.reset(new BigBuffer(zip, _id, static_cast<size_t>(_size)));
- _state = NodeState::OPENED;
- }
- catch (std::bad_alloc&) {
+ assert(zip != NULL);
+ if (_size > std::numeric_limits<size_t>::max()) {
return -ENOMEM;
}
- catch (std::exception&) {
- return -EIO;
- }
+ assert(_id != FAKE_ID);
+ _buffer.reset(new BigBuffer(zip, _id, static_cast<size_t>(_size)));
+ _state = NodeState::OPENED;
}
return 0;
}
@@ -184,15 +173,10 @@ int DataNode::truncate(size_t offset) {
if (_state != NodeState::NEW) {
_state = NodeState::CHANGED;
}
- try {
- _buffer->truncate(offset);
- return 0;
- }
- catch (const std::bad_alloc &) {
- return EIO;
- }
+ _buffer->truncate(offset);
_mtime = currentTime();
_metadataChanged = true;
+ return 0;
} else {
return EBADF;
}
diff --git a/lib/fileNode.cpp b/lib/fileNode.cpp
index bd1538c..efe1105 100644
--- a/lib/fileNode.cpp
+++ b/lib/fileNode.cpp
@@ -30,8 +30,6 @@
#include <memory>
#include <stdexcept>
-#include <syslog.h>
-
#include "fileNode.h"
#include "extraField.h"
@@ -54,22 +52,14 @@ FileNode *FileNode::createFile (struct zip *zip, const char *fname,
uid_t owner, gid_t group, mode_t mode, dev_t dev) {
auto data = DataNode::createNew(mode, owner, group, dev);
FileNode *n = new FileNode(zip, fname, NEW_NODE_INDEX, std::move(data));
- if (n == NULL) {
- return NULL;
- }
n->parse_name();
-
return n;
}
FileNode *FileNode::createSymlink(struct zip *zip, const char *fname) {
auto data = DataNode::createNew(S_IFLNK | 0777, 0, 0, 0);
FileNode *n = new FileNode(zip, fname, NEW_NODE_INDEX, std::move(data));
- if (n == NULL) {
- return NULL;
- }
n->parse_name();
-
return n;
}
@@ -80,12 +70,8 @@ FileNode *FileNode::createIntermediateDir(struct zip *zip,
const char *fname) {
auto data = DataNode::createTmpDir(S_IFDIR | 0755, 0, 0, 0);
FileNode *n = new FileNode(zip, fname, TMP_DIR_INDEX, std::move(data));
- if (n == NULL) {
- return NULL;
- }
n->m_commentChanged = false;
n->parse_name();
-
return n;
}
@@ -95,21 +81,14 @@ FileNode *FileNode::createDir(struct zip *zip, const char *fname,
// FUSE does not pass S_IFDIR bit here
auto data = DataNode::createNew(S_IFDIR | mode, owner, group, 0);
FileNode *n = new FileNode(zip, fname, id, std::move(data));
- if (n == NULL) {
- return NULL;
- }
n->m_commentChanged = false;
n->parse_name();
-
return n;
}
FileNode *FileNode::createRootNode(struct zip *zip) {
auto data = DataNode::createNew(S_IFDIR | 0755, 0, 0, 0);
FileNode *n = new FileNode(zip, "", ROOT_NODE_INDEX, std::move(data));
- if (n == NULL) {
- return NULL;
- }
n->name = n->full_name.c_str();
int len = 0;
@@ -133,13 +112,8 @@ FileNode *FileNode::createNodeForZipEntry(struct zip *zip,
assert(id >= 0);
auto data = DataNode::createExisting(zip, static_cast<zip_uint64_t>(id), mode);
FileNode *n = new FileNode(zip, fname, id, data);
- if (n == NULL) {
- return NULL;
- }
-
n->parse_name();
n->readComment();
-
return n;
}
@@ -147,13 +121,8 @@ FileNode *FileNode::createHardlink(struct zip *zip,
const char *fname, zip_int64_t id, FileNode *target) {
assert(id >= 0);
FileNode *n = new FileNode(zip, fname, id, target->_data);
- if (n == NULL) {
- return NULL;
- }
-
n->parse_name();
n->readComment();
-
return n;
}
@@ -427,8 +396,6 @@ bool FileNode::setComment(const char *value, uint16_t length) {
char *newComment = NULL;
if (value != NULL) {
newComment = new char[length];
- if (newComment == NULL)
- return false;
memcpy(newComment, value, length);
}
diff --git a/lib/fuse-zip.cpp b/lib/fuse-zip.cpp
index 0db402e..061cc6d 100644
--- a/lib/fuse-zip.cpp
+++ b/lib/fuse-zip.cpp
@@ -41,76 +41,67 @@
#include <cstring>
#include <cstdlib>
#include <limits>
+#include <memory>
#include <queue>
#include "fuse-zip.h"
#include "types.h"
#include "fileNode.h"
#include "fuseZipData.h"
+#include "util.h"
static const char FILE_COMMENT_XATTR_NAME[] = "user.comment";
static const size_t FILE_COMMENT_XATTR_NAME_LENZ = 13; // length including NULL-byte
using namespace std;
-//TODO: Move printf-s out this function
+// Converts a C++ exception into a negative error code.
+// Logs the error to stderr and syslog.
+// Must be called from within a catch block.
+static int exceptionToError(const char *const action, const char *const file) {
+ const auto log = [action, file](const char *const reason) {
+ fprintf(stderr, "Cannot %s '%s': %s\n", action, file, reason);
+ syslog(LOG_ERR, "Cannot %s: %s", action, reason);
+ };
+
+ try {
+ throw;
+ } catch (const std::bad_alloc &) {
+ log("No memory");
+ return -ENOMEM;
+ } catch (const std::exception &e) {
+ log(e.what());
+ return -EIO;
+ } catch (...) {
+ log("Unknown error");
+ return -EIO;
+ }
+}
+
FuseZipData *initFuseZip(const char *program, const char *fileName,
- bool readonly, bool force_precise_time) {
- FuseZipData *data = NULL;
+ bool readonly, bool force_precise_time) {
+ (void)program;
int err;
- struct zip *zip_file;
-
- int flags = (readonly) ? ZIP_RDONLY : ZIP_CREATE;
- if ((zip_file = zip_open(fileName, flags, &err)) == NULL) {
- zip_error_t error;
- zip_error_init_with_code(&error, err);
- fprintf(stderr, "%s: cannot open ZIP archive %s: %s\n", program, fileName, zip_error_strerror(&error));
- zip_error_fini(&error);
- return data;
- }
+ const int flags = readonly ? ZIP_RDONLY : ZIP_CREATE;
+ struct zip *const zip_file = zip_open(fileName, flags, &err);
- try {
- // current working directory
- char *cwd = (char*)malloc(PATH_MAX + 1);
- if (cwd == NULL) {
- throw std::bad_alloc();
- }
- if (getcwd(cwd, PATH_MAX) == NULL) {
- perror(NULL);
- free(cwd);
- return data;
- }
+ if (!zip_file)
+ throw ZipError("Cannot open ZIP archive", err);
- data = new FuseZipData(fileName, zip_file, cwd, force_precise_time);
- free(cwd);
- if (data == NULL) {
- throw std::bad_alloc();
- }
- try {
- data->build_tree(readonly);
- }
- catch (...) {
- delete data;
- throw;
- }
- }
- catch (std::bad_alloc&) {
- syslog(LOG_ERR, "no enough memory");
- fprintf(stderr, "%s: no enough memory\n", program);
- return NULL;
- }
- catch (const std::exception &e) {
- syslog(LOG_ERR, "error opening ZIP file: %s", e.what());
- fprintf(stderr, "%s: unable to open ZIP file: %s\n", program, e.what());
- return NULL;
- }
- return data;
+ // current working directory
+ char cwd[PATH_MAX + 1];
+ if (!getcwd(cwd, PATH_MAX))
+ throw std::runtime_error("Cannot get current directory");
+
+ std::unique_ptr<FuseZipData> data(
+ new FuseZipData(fileName, zip_file, cwd, force_precise_time));
+ data->build_tree(readonly);
+ return data.release();
}
void *fusezip_init(struct fuse_conn_info *conn) {
(void) conn;
FuseZipData *data = (FuseZipData*)fuse_get_context()->private_data;
- syslog(LOG_INFO, "Mounting file system on %s (cwd=%s)", data->m_archiveName, data->m_cwd.c_str());
return data;
}
@@ -126,7 +117,6 @@ void fusezip_destroy(void *data) {
FuseZipData *d = (FuseZipData*)data;
d->save ();
delete d;
- syslog(LOG_INFO, "File system unmounted");
}
FileNode *get_file_node(const char *fname) {
@@ -208,7 +198,7 @@ int fusezip_statfs(const char *path, struct statvfs *buf) {
return 0;
}
-int fusezip_open(const char *path, struct fuse_file_info *fi) {
+int fusezip_open(const char *path, struct fuse_file_info *fi) try {
if (*path == '\0') {
return -ENOENT;
}
@@ -221,18 +211,13 @@ int fusezip_open(const char *path, struct fuse_file_info *fi) {
}
fi->fh = (uint64_t)node;
- try {
- return node->open();
- }
- catch (std::bad_alloc&) {
- return -ENOMEM;
- }
- catch (std::exception&) {
- return -EIO;
- }
+ return node->open();
+} catch (...) {
+ return exceptionToError("open file", path);
}
-int fusezip_create(const char *path, mode_t mode, struct fuse_file_info *fi) {
+int fusezip_create(const char *path, mode_t mode,
+ struct fuse_file_info *fi) try {
if (*path == '\0') {
return -EACCES;
}
@@ -240,18 +225,20 @@ int fusezip_create(const char *path, mode_t mode, struct fuse_file_info *fi) {
if (node != NULL) {
return -EEXIST;
}
- node = FileNode::createFile (get_zip(), path + 1,
- fuse_get_context()->uid, fuse_get_context()->gid, mode);
+ node = FileNode::createFile(get_zip(), path + 1, fuse_get_context()->uid,
+ fuse_get_context()->gid, mode);
if (node == NULL) {
return -ENOMEM;
}
- get_data()->insertNode (node);
+ get_data()->insertNode(node);
fi->fh = (uint64_t)node;
return node->open();
+} catch (...) {
+ return exceptionToError("create file", path);
}
-int fusezip_mknod(const char *path, mode_t mode, dev_t dev) {
+int fusezip_mknod(const char *path, mode_t mode, dev_t dev) try {
if (*path == '\0') {
return -EACCES;
}
@@ -259,47 +246,55 @@ int fusezip_mknod(const char *path, mode_t mode, dev_t dev) {
if (node != NULL) {
return -EEXIST;
}
- node = FileNode::createFile (get_zip(), path + 1,
- fuse_get_context()->uid, fuse_get_context()->gid, mode, dev);
+ node = FileNode::createFile(get_zip(), path + 1, fuse_get_context()->uid,
+ fuse_get_context()->gid, mode, dev);
if (node == NULL) {
return -ENOMEM;
}
- get_data()->insertNode (node);
+ get_data()->insertNode(node);
return 0;
+} catch (...) {
+ return exceptionToError("mknod", path);
}
-int fusezip_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) {
- (void) path;
-
+int fusezip_read(const char *path, char *buf, size_t size, off_t offset,
+ struct fuse_file_info *fi) try {
if (offset < 0)
return -EINVAL;
- return ((FileNode*)fi->fh)->read(buf, size, static_cast<size_t>(offset));
+ return reinterpret_cast<FileNode *>(fi->fh)->read(
+ buf, size, static_cast<size_t>(offset));
+} catch (...) {
+ return exceptionToError("read file", path);
}
-int fusezip_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) {
- (void) path;
-
+int fusezip_write(const char *path, const char *buf, size_t size, off_t offset,
+ struct fuse_file_info *fi) try {
if (offset < 0)
return -EINVAL;
- return ((FileNode*)fi->fh)->write(buf, size, static_cast<size_t>(offset));
+ return reinterpret_cast<FileNode *>(fi->fh)->write(
+ buf, size, static_cast<size_t>(offset));
+} catch (...) {
+ return exceptionToError("write file", path);
}
-int fusezip_release (const char *path, struct fuse_file_info *fi) {
- (void) path;
-
- return ((FileNode*)fi->fh)->close();
+int fusezip_release(const char *path, struct fuse_file_info *fi) try {
+ return reinterpret_cast<FileNode *>(fi->fh)->close();
+} catch (...) {
+ return exceptionToError("close file", path);
}
-int fusezip_ftruncate(const char *path, off_t offset, struct fuse_file_info *fi) {
- (void) path;
-
+int fusezip_ftruncate(const char *path, off_t offset,
+ struct fuse_file_info *fi) try {
if (offset < 0)
return -EINVAL;
- return -((FileNode*)fi->fh)->truncate(static_cast<size_t>(offset));
+ return -reinterpret_cast<FileNode *>(fi->fh)->truncate(
+ static_cast<size_t>(offset));
+} catch (...) {
+ return exceptionToError("truncate file", path);
}
-int fusezip_truncate(const char *path, off_t offset) {
+int fusezip_truncate(const char *path, off_t offset) try {
if (*path == '\0') {
return -EACCES;
}
@@ -321,6 +316,8 @@ int fusezip_truncate(const char *path, off_t offset) {
return -res;
}
return node->close();
+} catch (...) {
+ return exceptionToError("truncate file", path);
}
int fusezip_unlink(const char *path) {
@@ -371,7 +368,7 @@ int fusezip_mkdir(const char *path, mode_t mode) {
return 0;
}
-int fusezip_rename(const char *path, const char *new_path) {
+int fusezip_rename(const char *path, const char *new_path) try {
if (*path == '\0') {
return -ENOENT;
}
@@ -385,7 +382,7 @@ int fusezip_rename(const char *path, const char *new_path) {
FileNode *new_node = get_file_node(new_path + 1);
if (new_node != NULL) {
int res = get_data()->removeNode(new_node);
- if (res !=0) {
+ if (res != 0) {
return -res;
}
}
@@ -403,48 +400,46 @@ int fusezip_rename(const char *path, const char *new_path) {
new_name.push_back('/');
}
- try {
- struct zip *z = get_zip();
- // Renaming directory and its content recursively
- if (node->is_dir()) {
- queue<FileNode*> q;
- q.push(node);
- while (!q.empty()) {
- FileNode *n = q.front();
- q.pop();
- for (nodelist_t::const_iterator i = n->childs.begin(); i != n->childs.end(); ++i) {
- FileNode *nn = *i;
- q.push(nn);
- char *name = (char*)malloc(len + nn->full_name.size() - oldLen + (nn->is_dir() ? 2 : 1));
- if (name == NULL) {
- //TODO: check that we are have enough memory before entering this loop
- return -ENOMEM;
- }
- strcpy(name, new_name.c_str());
- strcpy(name + len, nn->full_name.c_str() + oldLen);
- if (nn->is_dir()) {
- strcat(name, "/");
- }
- if (nn->present_in_zip()) {
- zip_file_rename(z, nn->id(), name, ZIP_FL_ENC_GUESS);
- }
- // changing child list may cause loop iterator corruption
- get_data()->renameNode (nn, name, false);
-
- free(name);
+ struct zip *z = get_zip();
+ // Renaming directory and its content recursively
+ if (node->is_dir()) {
+ queue<FileNode *> q;
+ q.push(node);
+ while (!q.empty()) {
+ FileNode *n = q.front();
+ q.pop();
+ for (FileNode *const nn : n->childs) {
+ q.push(nn);
+ char *name = (char *)malloc(len + nn->full_name.size() -
+ oldLen + (nn->is_dir() ? 2 : 1));
+ if (name == NULL) {
+ // TODO: check that we are have enough memory before
+ // entering this loop
+ return -ENOMEM;
}
+ strcpy(name, new_name.c_str());
+ strcpy(name + len, nn->full_name.c_str() + oldLen);
+ if (nn->is_dir()) {
+ strcat(name, "/");
+ }
+ if (nn->present_in_zip()) {
+ zip_file_rename(z, nn->id(), name, ZIP_FL_ENC_GUESS);
+ }
+ // changing child list may cause loop iterator corruption
+ get_data()->renameNode(nn, name, false);
+
+ free(name);
}
}
- if (node->present_in_zip()) {
- zip_file_rename(z, node->id(), new_name.c_str(), ZIP_FL_ENC_GUESS);
- }
- get_data()->renameNode (node, new_name.c_str(), true);
-
- return 0;
}
- catch (...) {
- return -EIO;
+ if (node->present_in_zip()) {
+ zip_file_rename(z, node->id(), new_name.c_str(), ZIP_FL_ENC_GUESS);
}
+ get_data()->renameNode(node, new_name.c_str(), true);
+
+ return 0;
+} catch (...) {
+ return exceptionToError("rename", path);
}
int fusezip_utimens(const char *path, const struct timespec tv[2]) {
diff --git a/lib/fuse-zip.h b/lib/fuse-zip.h
index c52cc62..0e9730f 100644
--- a/lib/fuse-zip.h
+++ b/lib/fuse-zip.h
@@ -42,8 +42,6 @@ class FuseZipData *initFuseZip(const char *program, const char *fileName,
/**
* Initialize filesystem
*
- * Report current working dir and archive file name to syslog.
- *
* @return filesystem-private data
*/
void *fusezip_init(struct fuse_conn_info *conn);
@@ -51,7 +49,7 @@ void *fusezip_init(struct fuse_conn_info *conn);
/**
* Destroy filesystem
*
- * Save all modified data back to ZIP archive and report to syslog about completion.
+ * Save all modified data back to ZIP archive.
* Note that filesystem unmounted before this method finishes
* (see https://bitbucket.org/agalanin/fuse-zip/issues/7).
*/
diff --git a/lib/fuseZipData.cpp b/lib/fuseZipData.cpp
index 6852678..d9ff5cb 100644
--- a/lib/fuseZipData.cpp
+++ b/lib/fuseZipData.cpp
@@ -18,7 +18,6 @@
////////////////////////////////////////////////////////////////////////////
#include <zip.h>
-#include <syslog.h>
#include <cassert>
#include <cerrno>
#include <cstring>
@@ -37,21 +36,24 @@ FuseZipData::FuseZipData(const char *archiveName, struct zip *z, const char *cwd
FuseZipData::~FuseZipData() {
if (chdir(m_cwd.c_str()) != 0) {
- syslog(LOG_ERR, "Unable to chdir() to archive directory %s: %s. Trying to save file into $TMP or /tmp...",
+ fprintf(stderr, "Cannot chdir to archive directory '%s': %s\n",
m_cwd.c_str(), strerror(errno));
const char *tmpDir = getenv("TMP");
if (tmpDir == NULL || chdir(tmpDir) != 0) {
if (tmpDir != NULL) {
- syslog(LOG_WARNING, "Unable to chdir() to %s: %s.", tmpDir, strerror(errno));
+ fprintf(stderr, "Cannot chdir to '%s': %s\n", tmpDir,
+ strerror(errno));
}
if (chdir("/tmp") != 0) {
- syslog(LOG_ERR, "Unable to chdir() to /tmp: %s!", strerror(errno));
+ fprintf(stderr, "Cannot chdir to '/tmp': %s\n",
+ strerror(errno));
}
}
}
int res = zip_close(m_zip);
if (res != 0) {
- syslog(LOG_ERR, "Error while closing archive: %s", zip_strerror(m_zip));
+ fprintf(stderr, "Error while closing archive: %s\n",
+ zip_strerror(m_zip));
}
for (filemap_t::iterator i = files.begin(); i != files.end(); ++i) {
delete i->second;
@@ -103,7 +105,8 @@ void FuseZipData::build_tree(bool readonly) {
if (notHLink)
attachNode(i, name, mode, readonly, needPrefix, origNames);
else if (!readonly)
- throw std::runtime_error("hard links are supported only in read-only mode");
+ throw ZipError("Hard links are supported only in read-only mode",
+ ZIP_ER_OPNOTSUPP);
}
// Connect nodes to tree. Missing intermediate nodes created on demand.
for (filemap_t::const_iterator i = files.begin(); i != files.end(); ++i)
@@ -126,7 +129,7 @@ void FuseZipData::connectNodeToTree (FileNode *node) {
files[parent->full_name.c_str()] = parent;
connectNodeToTree (parent);
} else if (!parent->is_dir()) {
- throw std::runtime_error ("bad archive structure");
+ throw ZipError("Bad archive structure", ZIP_ER_INCONS);
}
// connecting to parent
node->parent = parent;
@@ -241,8 +244,8 @@ void FuseZipData::attachNode(zip_int64_t id, const char *name, mode_t mode, bool
convertFileName(name, readonly, needPrefix, converted);
const char *cname = converted.c_str();
if (files.find(cname) != files.end()) {
- syslog(LOG_ERR, "duplicated file name: %s", cname);
- throw std::runtime_error("duplicate file names");
+ throw ZipError(std::string("Duplicated file name: ") + cname,
+ ZIP_ER_EXISTS);
}
FileNode *node = FileNode::createNodeForZipEntry(m_zip, cname, id, mode);
if (node == NULL) {
@@ -263,7 +266,7 @@ bool FuseZipData::attachHardlink(zip_int64_t sid, const char *name, mode_t mode,
field = zip_file_extra_field_get_by_id(m_zip, id, FZ_EF_PKWARE_UNIX, 0, &len, ZIP_FL_LOCAL);
if (!field) {
// ignoring hardlink without PKWARE UNIX field
- syslog(LOG_INFO, "%s: PKWARE UNIX field is absent for hardlink\n", name);
+ fprintf(stderr, "%s: PKWARE UNIX field is absent for hardlink\n", name);
return false;
}
@@ -276,13 +279,13 @@ bool FuseZipData::attachHardlink(zip_int64_t sid, const char *name, mode_t mode,
if (!ExtraField::parsePkWareUnixField(len, field, mode, mt, at,
uid, gid, dev, link, link_len))
{
- syslog(LOG_WARNING, "%s: unable to parse PKWARE UNIX field\n", name);
+ fprintf(stderr, "%s: unable to parse PKWARE UNIX field\n", name);
return false;
}
if (link_len == 0 || !link)
{
- syslog(LOG_ERR, "%s: hard link target is empty\n", name);
+ fprintf(stderr, "%s: hard link target is empty\n", name);
return true;
}
@@ -291,7 +294,8 @@ bool FuseZipData::attachHardlink(zip_int64_t sid, const char *name, mode_t mode,
auto it = origNames.find(linkStr.c_str());
if (it == origNames.end())
{
- syslog(LOG_ERR, "%s: unable to find link target %s\n", name, linkStr.c_str());
+ fprintf(stderr, "%s: unable to find link target %s\n", name,
+ linkStr.c_str());
return true;
}
@@ -304,7 +308,8 @@ bool FuseZipData::attachHardlink(zip_int64_t sid, const char *name, mode_t mode,
}
else
{
- syslog(LOG_ERR, "%s: file format differs with link target %s\n", name, linkStr.c_str());
+ fprintf(stderr, "%s: file format differs with link target %s\n",
+ name, linkStr.c_str());
return true;
}
}
@@ -313,8 +318,8 @@ bool FuseZipData::attachHardlink(zip_int64_t sid, const char *name, mode_t mode,
convertFileName(name, readonly, needPrefix, converted);
const char *cname = converted.c_str();
if (files.find(cname) != files.end()) {
- syslog(LOG_ERR, "duplicated file name: %s", cname);
- throw std::runtime_error("duplicate file names");
+ throw ZipError(std::string("Duplicated file name: ") + cname,
+ ZIP_ER_EXISTS);
}
FileNode *node = FileNode::createHardlink(m_zip, cname, sid, it->second);
if (node == NULL) {
@@ -345,10 +350,10 @@ int FuseZipData::removeNode(FileNode *node) {
void FuseZipData::validateFileName(const char *fname) {
if (fname[0] == 0) {
- throw std::runtime_error("empty file name");
+ throw ZipError("Empty file name", ZIP_ER_INCONS);
}
if (strstr(fname, "//") != NULL) {
- throw std::runtime_error(std::string("bad file name (two slashes): ") + fname);
+ throw ZipError(std::string("Bad file name: ") + fname, ZIP_ER_INCONS);
}
}
@@ -367,7 +372,9 @@ void FuseZipData::convertFileName(const char *fname, bool readonly,
// add prefix
if (fname[0] == '/') {
if (!readonly) {
- throw std::runtime_error("absolute paths are not supported in read-write mode");
+ throw ZipError(
+ "Absolute paths are not supported in read-write mode",
+ ZIP_ER_OPNOTSUPP);
} else {
assert(needPrefix);
converted.append(ROOT_PREFIX);
@@ -377,7 +384,9 @@ void FuseZipData::convertFileName(const char *fname, bool readonly,
bool parentRelative = false;
while (strncmp(fname, "../", 3) == 0) {
if (!readonly) {
- throw std::runtime_error("paths relative to parent directory are not supported in read-write mode");
+ throw ZipError("Paths relative to parent directory are not "
+ "supported in read-write mode",
+ ZIP_ER_OPNOTSUPP);
}
assert(needPrefix);
converted.append(UP_PREFIX);
@@ -400,14 +409,15 @@ void FuseZipData::convertFileName(const char *fname, bool readonly,
while (start[0] != 0 && (cur = strchr(start + 1, '/')) != NULL) {
if ((cur - start == 1 && start[0] == '.') ||
(cur - start == 2 && start[0] == '.' && start[1] == '.')) {
- throw std::runtime_error(std::string("bad file name: ") + orig);
+ throw ZipError(std::string("Bad file name: ") + orig,
+ ZIP_ER_INCONS);
}
converted.append(start, static_cast<size_t>(cur - start + 1));
start = cur + 1;
}
// end of string is reached
if (strcmp(start, ".") == 0 || strcmp(start, "..") == 0) {
- throw std::runtime_error(std::string("bad file name: ") + orig);
+ throw ZipError(std::string("Bad file name: ") + orig, ZIP_ER_INCONS);
}
converted.append(start);
}
@@ -471,7 +481,8 @@ void FuseZipData::save () {
if (node->isCommentChanged()) {
int res = node->saveComment();
if (res != 0) {
- syslog(LOG_ERR, "Error while saving archive comment: %d", res);
+ fprintf(stderr, "Error %d while saving archive comment\n",
+ res);
}
}
continue;
@@ -483,8 +494,8 @@ void FuseZipData::save () {
int res = node->save();
if (res != 0) {
saveMetadata = false;
- syslog(LOG_ERR, "Error while saving file %s in ZIP archive: %d",
- node->full_name.c_str(), res);
+ fprintf(stderr, "Error %d while saving file '%s'\n", res,
+ node->full_name.c_str());
}
}
if (saveMetadata) {
@@ -493,23 +504,24 @@ void FuseZipData::save () {
zip_int64_t idx = zip_dir_add(m_zip,
node->full_name.c_str(), ZIP_FL_ENC_GUESS);
if (idx < 0) {
- syslog(LOG_ERR, "Unable to save directory %s in ZIP archive",
- node->full_name.c_str());
+ fprintf(stderr, "Cannot save directory '%s'\n",
+ node->full_name.c_str());
continue;
}
node->set_id(idx);
}
int res = node->saveMetadata(m_force_precise_time);
if (res != 0) {
- syslog(LOG_ERR, "Error while saving metadata for file %s in ZIP archive: %d",
- node->full_name.c_str(), res);
+ fprintf(stderr,
+ "Error %d while saving metadata for file '%s'\n", res,
+ node->full_name.c_str());
}
}
if (node->isCommentChanged()) {
int res = node->saveComment();
if (res != 0) {
- syslog(LOG_ERR, "Error while saving comment for file %s in ZIP archive: %d",
- node->full_name.c_str(), res);
+ fprintf(stderr, "Error %d while saving comment for file '%s'\n",
+ res, node->full_name.c_str());
}
}
}
diff --git a/lib/util.h b/lib/util.h
index 94ac191..1fe63be 100644
--- a/lib/util.h
+++ b/lib/util.h
@@ -20,8 +20,58 @@
#ifndef UTIL_H
#define UTIL_H
+#include <stdexcept>
+#include <string>
+#include <utility>
+
#include <time.h>
+#include <zip.h>
struct timespec currentTime();
+/** An exception carrying a libzip error code. */
+class ZipError : public std::runtime_error {
+ public:
+ ZipError(std::string message, zip_t *const archive)
+ : std::runtime_error(MakeMessage(std::move(message), archive)),
+ code_(zip_error_code_zip(zip_get_error(archive))) {}
+
+ ZipError(std::string message, zip_file_t *const file)
+ : std::runtime_error(MakeMessage(std::move(message), file)),
+ code_(zip_error_code_zip(zip_file_get_error(file))) {}
+
+ ZipError(std::string message, const int code)
+ : std::runtime_error(MakeMessage(std::move(message), code)),
+ code_(code) {}
+
+ /** Gets the libzip error code. */
+ int code() const { return code_; }
+
+ static std::string MakeMessage(std::string message, zip_t *const archive) {
+ message += ": ";
+ message += zip_strerror(archive);
+ return message;
+ }
+
+ static std::string MakeMessage(std::string message,
+ zip_file_t *const file) {
+ message += ": ";
+ message += zip_file_strerror(file);
+ return message;
+ }
+
+ static std::string MakeMessage(std::string message, const int code) {
+ message += ": ";
+ zip_error_t ze;
+ zip_error_init_with_code(&ze, code);
+ message += zip_error_strerror(&ze);
+ zip_error_fini(&ze);
+ return message;
+ }
+
+ private:
+ /** libzip error code. */
+ const int code_;
+};
+
#endif
diff --git a/main.cpp b/main.cpp
index cb19ac5..1503523 100644
--- a/main.cpp
+++ b/main.cpp
@@ -41,6 +41,7 @@
#include "fuse-zip.h"
#include "fuseZipData.h"
+#include "util.h"
#if (LIBZIP_VERSION_MAJOR < 1)
#error "libzip >= 1.0 is required!"
@@ -191,7 +192,7 @@ static const struct fuse_opt fusezip_opts[] = {
{NULL, 0, 0}
};
-int main(int argc, char *argv[]) {
+int main(int argc, char *argv[]) try {
if (sizeof(void*) > sizeof(uint64_t)) {
fprintf(stderr,"%s: This program cannot be run on your system because of FUSE design limitation\n", PROGRAM);
return EXIT_FAILURE;
@@ -237,11 +238,7 @@ int main(int argc, char *argv[]) {
}
openlog(PROGRAM, LOG_PID, LOG_USER);
- if ((data = initFuseZip(PROGRAM, param.fileName, param.readonly, param.force_precise_time))
- == NULL) {
- fuse_opt_free_args(&args);
- return EXIT_FAILURE;
- }
+ data = initFuseZip(PROGRAM, param.fileName, param.readonly, param.force_precise_time);
}
static struct fuse_operations fusezip_oper;
@@ -301,5 +298,13 @@ int main(int argc, char *argv[]) {
res = fuse_loop(fuse);
fuse_teardown(fuse, mountpoint);
return (res == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+} catch (const ZipError& e) {
+ fprintf(stderr,"%s: %s\n", PROGRAM, e.what());
+ // Shift libzip error codes in order to avoid collision with FUSE errors.
+ const int ZIP_ER_BASE = 10;
+ return ZIP_ER_BASE + e.code();
+} catch (const std::exception& e) {
+ fprintf(stderr,"%s: %s\n", PROGRAM, e.what());
+ return EXIT_FAILURE;
}
--
2.29.1.341.ge80a0c044ae-goog