This is an automated email from the ASF dual-hosted git repository.
acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git
The following commit(s) were added to refs/heads/master by this push:
new d0c15c8c8 system/nxpkg: make package storage crash-safe
d0c15c8c8 is described below
commit d0c15c8c8723f6af5615812033b1a8687a5b2415
Author: aviralgarg05 <[email protected]>
AuthorDate: Sun Aug 16 21:02:53 2026 +0530
system/nxpkg: make package storage crash-safe
Make the nxpkg storage root configurable and write owned files through
temporary paths before renaming them. Record lock ownership so processes can
recover abandoned locks safely.
Signed-off-by: aviralgarg05 <[email protected]>
---
system/nxpkg/pkg.h | 76 +++++++-
system/nxpkg/pkg_compat.c | 6 +
system/nxpkg/pkg_install.c | 4 +-
system/nxpkg/pkg_log.c | 22 ++-
system/nxpkg/pkg_store.c | 471 +++++++++++++++++++++++++++++++++++++++++----
5 files changed, 522 insertions(+), 57 deletions(-)
diff --git a/system/nxpkg/pkg.h b/system/nxpkg/pkg.h
index 39a4bf0c2..032c0dda3 100644
--- a/system/nxpkg/pkg.h
+++ b/system/nxpkg/pkg.h
@@ -27,30 +27,66 @@
* Included Files
****************************************************************************/
+#include <nuttx/config.h>
+
#include <limits.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
+#include <stdlib.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
-#define PKG_REPO_DIR "/etc/nxpkg"
-#define PKG_REPO_INDEX "/etc/nxpkg/index.json"
-#define PKG_REPO_INSTALLED "/var/lib/nxpkg/installed.json"
-#define PKG_STORE_DIR "/var/lib/nxpkg/pkgs"
-#define PKG_TMP_DIR "/var/cache/nxpkg"
-#define PKG_TMP_PKG_DIR "/var/cache/nxpkg/pkg"
+#define PKG_ROOT_DIR CONFIG_SYSTEM_NXPKG_ROOT
+#define PKG_REPO_DIR PKG_ROOT_DIR
+#define PKG_REPO_INDEX PKG_ROOT_DIR "/index.jsn"
+#define PKG_REPO_SOURCE PKG_ROOT_DIR "/repo.url"
+#define PKG_REPO_INSTALLED PKG_ROOT_DIR "/instpkg.jsn"
+#define PKG_STORE_DIR PKG_ROOT_DIR "/pkgs"
+#define PKG_TMP_DIR PKG_ROOT_DIR "/tmp"
+#define PKG_TMP_PKG_DIR PKG_ROOT_DIR "/tmp/pkg"
#define PKG_NAME_MAX 63
#define PKG_VERSION_MAX 31
#define PKG_ARCH_MAX 31
#define PKG_COMPAT_MAX 63
+#define PKG_DESCRIPTION_MAX 127
+#define PKG_CATEGORY_MAX 31
#define PKG_HASH_HEX_LEN 64
-#define PKG_INDEX_MAX 32
+/* Keep repository metadata memory bounded. */
+
+#define PKG_INDEX_MAX 16
#define PKG_INSTALLED_MAX 16
#define PKG_INSTALLED_VERSIONS_MAX 8
+#define PKG_LAUNCH_ARGS_MAX 8
+#define PKG_LAUNCH_ARG_MAX 127
+
+/* Bound metadata allocations and artifact downloads. */
+
+#define PKG_TEXT_MAX_SIZE (256 * 1024)
+#define PKG_DOWNLOAD_MAX_SIZE (32 * 1024 * 1024)
+
+static inline void *pkg_malloc(size_t size)
+{
+ return malloc(size);
+}
+
+static inline void *pkg_zalloc(size_t size)
+{
+ return calloc(1, size);
+}
+
+static inline void *pkg_realloc(void *ptr, size_t size)
+{
+ return realloc(ptr, size);
+}
+
+static inline void pkg_free(void *ptr)
+{
+ free(ptr);
+}
/****************************************************************************
* Public Types
@@ -83,7 +119,12 @@ struct pkg_manifest_s
char compat[PKG_COMPAT_MAX + 1];
char artifact[PATH_MAX];
char sha256[PKG_HASH_HEX_LEN + 1];
+ char launch_args[PKG_LAUNCH_ARGS_MAX][PKG_LAUNCH_ARG_MAX + 1];
+ char description[PKG_DESCRIPTION_MAX + 1];
+ char category[PKG_CATEGORY_MAX + 1];
+ char icon[PATH_MAX];
enum pkg_payload_type_e type;
+ size_t launch_argc;
};
struct pkg_index_s
@@ -116,6 +157,7 @@ struct pkg_installed_db_s
const char *pkg_manifest_type_str(enum pkg_payload_type_e type);
int pkg_manifest_validate(FAR const struct pkg_manifest_s *manifest);
+bool pkg_validate_path_component(FAR const char *value);
int pkg_manifest_parse_type(FAR const char *value,
FAR enum pkg_payload_type_e *type);
@@ -124,6 +166,7 @@ int pkg_store_ensure_package_root(FAR const char *name);
int pkg_store_ensure_version_dir(FAR const char *name,
FAR const char *version);
int pkg_store_format_index_path(FAR char *buffer, size_t size);
+int pkg_store_format_repo_source_path(FAR char *buffer, size_t size);
int pkg_store_format_installed_path(FAR char *buffer, size_t size);
int pkg_store_format_package_root(FAR char *buffer, size_t size,
FAR const char *name);
@@ -152,6 +195,8 @@ int pkg_store_read_text(FAR const char *path, FAR char
**buffer);
int pkg_store_write_text_atomic(FAR const char *path, FAR const char *text);
int pkg_store_copy_file(FAR const char *src, FAR const char *dest);
int pkg_store_remove_file(FAR const char *path);
+int pkg_store_remove_version_dir(FAR const char *name,
+ FAR const char *version);
const char *pkg_runtime_arch(void);
const char *pkg_runtime_compat(void);
@@ -160,7 +205,11 @@ int pkg_compat_check(FAR const struct pkg_manifest_s
*manifest);
int pkg_hash_file_sha256(FAR const char *path,
FAR char digest[PKG_HASH_HEX_LEN + 1]);
+int pkg_metadata_load_index_path(FAR const char *path,
+ FAR struct pkg_index_s *index);
int pkg_metadata_load_index(FAR struct pkg_index_s *index);
+int pkg_metadata_load_manifest_path(FAR const char *path,
+ FAR struct pkg_manifest_s *manifest);
FAR const struct pkg_manifest_s *
pkg_metadata_find_latest(FAR const struct pkg_index_s *index,
FAR const char *name);
@@ -178,7 +227,20 @@ const char *pkg_txn_state_str(enum pkg_txn_state_e state);
int pkg_txn_write_state(FAR const char *name, enum pkg_txn_state_e state);
int pkg_txn_clear_state(FAR const char *name);
+bool pkg_source_is_url(FAR const char *source);
+int pkg_resolve_artifact_source(FAR char *buffer, size_t size,
+ FAR const struct pkg_manifest_s *manifest);
+int pkg_resolve_icon_source(FAR char *buffer, size_t size,
+ FAR const struct pkg_manifest_s *manifest);
+int pkg_acquire_source(FAR const char *source, FAR const char *dest);
+int pkg_lock_create(FAR const char *path);
+void pkg_lock_remove(FAR const char *path);
+void pkg_reclaim_stale_lock(FAR const char *path);
+int pkg_sync(FAR const char *source);
int pkg_install(FAR const char *name);
+int pkg_uninstall(FAR const char *name);
+int pkg_rollback(FAR const char *name);
+int pkg_available(FAR FILE *stream);
int pkg_list(FAR FILE *stream);
void pkg_error(FAR const char *fmt, ...);
diff --git a/system/nxpkg/pkg_compat.c b/system/nxpkg/pkg_compat.c
index 301fb07aa..817a3b4bf 100644
--- a/system/nxpkg/pkg_compat.c
+++ b/system/nxpkg/pkg_compat.c
@@ -40,7 +40,13 @@ const char *pkg_runtime_arch(void)
const char *pkg_runtime_compat(void)
{
+#ifdef CONFIG_ARCH_BOARD
return CONFIG_ARCH_BOARD;
+#elif defined(CONFIG_ARCH_BOARD_CUSTOM_NAME)
+ return CONFIG_ARCH_BOARD_CUSTOM_NAME;
+#else
+ return "";
+#endif
}
int pkg_compat_check(FAR const struct pkg_manifest_s *manifest)
diff --git a/system/nxpkg/pkg_install.c b/system/nxpkg/pkg_install.c
index c40982001..b9b095597 100644
--- a/system/nxpkg/pkg_install.c
+++ b/system/nxpkg/pkg_install.c
@@ -433,7 +433,7 @@ int pkg_install(FAR const char *name)
pkg_txn_clear_state(name);
if (lock[0] != '\0')
{
- pkg_store_remove_file(lock);
+ pkg_lock_remove(lock);
}
pkg_info("installed %s version %s", manifest->name, manifest->version);
@@ -451,7 +451,7 @@ errout:
pkg_txn_clear_state(name);
if (lock[0] != '\0')
{
- pkg_store_remove_file(lock);
+ pkg_lock_remove(lock);
}
free(index);
diff --git a/system/nxpkg/pkg_log.c b/system/nxpkg/pkg_log.c
index bed06b13f..375b8880e 100644
--- a/system/nxpkg/pkg_log.c
+++ b/system/nxpkg/pkg_log.c
@@ -26,6 +26,7 @@
#include <stdarg.h>
#include <stdio.h>
+#include <syslog.h>
#include "pkg.h"
@@ -33,13 +34,18 @@
* Private Functions
****************************************************************************/
-static void pkg_vlog(FAR FILE *stream, FAR const char *level,
- FAR const char *fmt, va_list ap)
+static void pkg_vlog(int priority, FAR const char *fmt, va_list ap)
{
- fprintf(stream, "nxpkg: %s: ", level);
- vfprintf(stream, fmt, ap);
- fputc('\n', stream);
- fflush(stream);
+ char message[256];
+ int ret;
+
+ ret = vsnprintf(message, sizeof(message), fmt, ap);
+ if (ret < 0)
+ {
+ return;
+ }
+
+ syslog(priority, "nxpkg: %s", message);
}
/****************************************************************************
@@ -51,7 +57,7 @@ void pkg_error(FAR const char *fmt, ...)
va_list ap;
va_start(ap, fmt);
- pkg_vlog(stderr, "error", fmt, ap);
+ pkg_vlog(LOG_ERR, fmt, ap);
va_end(ap);
}
@@ -60,6 +66,6 @@ void pkg_info(FAR const char *fmt, ...)
va_list ap;
va_start(ap, fmt);
- pkg_vlog(stdout, "info", fmt, ap);
+ pkg_vlog(LOG_INFO, fmt, ap);
va_end(ap);
}
diff --git a/system/nxpkg/pkg_store.c b/system/nxpkg/pkg_store.c
index 0b23b054c..79ad7941b 100644
--- a/system/nxpkg/pkg_store.c
+++ b/system/nxpkg/pkg_store.c
@@ -24,8 +24,10 @@
* Included Files
****************************************************************************/
+#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
+#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -35,10 +37,60 @@
#include "pkg.h"
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define PKG_LOCK_OWNER "owner"
+
/****************************************************************************
* Private Functions
****************************************************************************/
+static int pkg_lock_read_owner(FAR const char *path, FAR pid_t *owner)
+{
+ char owner_path[PATH_MAX];
+ char record[32];
+ char extra;
+ long parsed_owner;
+ ssize_t nread;
+ int fd;
+ int ret;
+
+ ret = snprintf(owner_path, sizeof(owner_path), "%s/%s", path,
+ PKG_LOCK_OWNER);
+ if (ret < 0 || (size_t)ret >= sizeof(owner_path))
+ {
+ return ret < 0 ? ret : -ENAMETOOLONG;
+ }
+
+ fd = open(owner_path, O_RDONLY);
+ if (fd < 0)
+ {
+ return -errno;
+ }
+
+ nread = read(fd, record, sizeof(record) - 1);
+ if (nread < 0)
+ {
+ ret = -errno;
+ close(fd);
+ return ret;
+ }
+
+ close(fd);
+ record[nread] = '\0';
+ if (sscanf(record, "%ld%c", &parsed_owner, &extra) != 1 ||
+ parsed_owner <= 0 ||
+ (long)(pid_t)parsed_owner != parsed_owner)
+ {
+ return -EINVAL;
+ }
+
+ *owner = (pid_t)parsed_owner;
+ return 0;
+}
+
static int pkg_store_format(FAR char *buffer, size_t size,
FAR const char *fmt,
FAR const char *name,
@@ -145,6 +197,11 @@ static int pkg_store_write_all(int fd, FAR const char
*buffer, size_t length)
return -errno;
}
+ if (ret == 0)
+ {
+ return -EIO;
+ }
+
offset += (size_t)ret;
}
@@ -188,6 +245,122 @@ int pkg_store_prepare_layout(void)
return pkg_store_mkdirs(PKG_TMP_PKG_DIR);
}
+int pkg_lock_create(FAR const char *path)
+{
+ char owner_path[PATH_MAX];
+ char record[32];
+ int fd;
+ int ret;
+
+ if (mkdir(path, 0755) < 0)
+ {
+ return -errno;
+ }
+
+ ret = snprintf(owner_path, sizeof(owner_path), "%s/%s", path,
+ PKG_LOCK_OWNER);
+ if (ret < 0 || (size_t)ret >= sizeof(owner_path))
+ {
+ ret = ret < 0 ? ret : -ENAMETOOLONG;
+ rmdir(path);
+ return ret;
+ }
+
+ fd = open(owner_path, O_WRONLY | O_CREAT | O_EXCL, 0644);
+ if (fd < 0)
+ {
+ ret = -errno;
+ rmdir(path);
+ return ret;
+ }
+
+ ret = snprintf(record, sizeof(record), "%ld", (long)getpid());
+ if (ret < 0 || (size_t)ret >= sizeof(record))
+ {
+ ret = ret < 0 ? ret : -EOVERFLOW;
+ }
+ else
+ {
+ ret = pkg_store_write_all(fd, record, (size_t)ret);
+ }
+
+ if (ret == 0 && fsync(fd) < 0)
+ {
+ ret = -errno;
+ }
+
+ if (close(fd) < 0 && ret == 0)
+ {
+ ret = -errno;
+ }
+
+ if (ret < 0)
+ {
+ unlink(owner_path);
+ rmdir(path);
+ }
+
+ return ret;
+}
+
+void pkg_lock_remove(FAR const char *path)
+{
+ char owner_path[PATH_MAX];
+ int ret;
+
+ ret = snprintf(owner_path, sizeof(owner_path), "%s/%s", path,
+ PKG_LOCK_OWNER);
+ if (ret >= 0 && (size_t)ret < sizeof(owner_path))
+ {
+ unlink(owner_path);
+ }
+
+ rmdir(path);
+}
+
+void pkg_reclaim_stale_lock(FAR const char *path)
+{
+ pid_t owner;
+ int ret;
+
+ ret = pkg_lock_read_owner(path, &owner);
+ if (ret == -ENOENT || ret == -EINVAL)
+ {
+ /* The creator may not have written the owner marker yet. */
+
+ usleep(20 * 1000);
+ ret = pkg_lock_read_owner(path, &owner);
+ if (ret == -ENOENT || ret == -EINVAL)
+ {
+ pkg_lock_remove(path);
+ return;
+ }
+ }
+
+ if (ret < 0)
+ {
+ return;
+ }
+
+ if (owner == getpid())
+ {
+ pkg_lock_remove(path);
+ return;
+ }
+
+ if (kill(owner, 0) == 0 || errno == EPERM)
+ {
+ return;
+ }
+
+ if (errno == ESRCH)
+ {
+ pkg_error("reclaiming lock from exited task %ld '%s'",
+ (long)owner, path);
+ pkg_lock_remove(path);
+ }
+}
+
int pkg_store_ensure_package_root(FAR const char *name)
{
char path[PATH_MAX];
@@ -228,6 +401,11 @@ int pkg_store_format_index_path(FAR char *buffer, size_t
size)
return pkg_store_format(buffer, size, "%s", PKG_REPO_INDEX, "");
}
+int pkg_store_format_repo_source_path(FAR char *buffer, size_t size)
+{
+ return pkg_store_format(buffer, size, "%s", PKG_REPO_SOURCE, "");
+}
+
int pkg_store_format_installed_path(FAR char *buffer, size_t size)
{
return pkg_store_format(buffer, size, "%s", PKG_REPO_INSTALLED, "");
@@ -266,21 +444,40 @@ int pkg_store_format_previous_path(FAR char *buffer,
size_t size,
int pkg_store_format_txn_path(FAR char *buffer, size_t size,
FAR const char *name)
{
- return pkg_store_format(buffer, size, PKG_STORE_DIR "/%s/.txn", name, "");
+ return pkg_store_format(buffer, size, PKG_STORE_DIR "/%s/txn.tx", name,
+ "");
}
int pkg_store_format_lock_path(FAR char *buffer, size_t size,
FAR const char *name)
{
- return pkg_store_format(buffer, size, PKG_STORE_DIR "/%s/.lock", name, "");
+ return pkg_store_format(buffer, size, PKG_STORE_DIR "/%s/lock.lk", name,
+ "");
}
int pkg_store_format_download_path(FAR char *buffer, size_t size,
FAR const char *name,
FAR const char *version)
{
- return pkg_store_format(buffer, size, PKG_TMP_PKG_DIR "/%s-%s.npkg", name,
- version);
+ int ret;
+
+ UNUSED(name);
+ UNUSED(version);
+
+ /* Use the PID for a unique FAT 8.3-compatible staging name. */
+
+ ret = snprintf(buffer, size, PKG_TMP_PKG_DIR "/dl%d.pkg", (int)getpid());
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ if ((size_t)ret >= size)
+ {
+ return -ENAMETOOLONG;
+ }
+
+ return 0;
}
int pkg_store_format_payload_path(FAR char *buffer, size_t size,
@@ -311,16 +508,18 @@ int pkg_store_format_manifest_path(FAR char *buffer,
size_t size,
FAR const char *name,
FAR const char *version)
{
- return pkg_store_format(buffer, size, PKG_STORE_DIR "/%s/%s/manifest.json",
+ return pkg_store_format(buffer, size, PKG_STORE_DIR "/%s/%s/manifest.jsn",
name, version);
}
int pkg_store_read_text(FAR const char *path, FAR char **buffer)
{
- FAR FILE *stream;
FAR char *data;
- long length;
+ struct stat st;
+ size_t length;
size_t nread;
+ size_t total;
+ int fd;
if (buffer == NULL)
{
@@ -329,70 +528,161 @@ int pkg_store_read_text(FAR const char *path, FAR char
**buffer)
*buffer = NULL;
- stream = fopen(path, "rb");
- if (stream == NULL)
+ fd = open(path, O_RDONLY);
+ if (fd < 0)
{
return errno == ENOENT ? -ENOENT : -errno;
}
- if (fseek(stream, 0, SEEK_END) < 0)
+ if (fstat(fd, &st) < 0)
{
- fclose(stream);
+ close(fd);
return -errno;
}
- length = ftell(stream);
- if (length < 0)
+ if (!S_ISREG(st.st_mode))
{
- fclose(stream);
- return -errno;
+ close(fd);
+ return -EINVAL;
}
- if (fseek(stream, 0, SEEK_SET) < 0)
+ /* Validate the size before allocating length plus its terminator. */
+
+ if (st.st_size < 0 || st.st_size > (off_t)PKG_TEXT_MAX_SIZE)
{
- fclose(stream);
- return -errno;
+ close(fd);
+ return -EFBIG;
}
- data = malloc((size_t)length + 1);
+ length = (size_t)st.st_size;
+ data = pkg_malloc((size_t)length + 1);
if (data == NULL)
{
- fclose(stream);
+ close(fd);
return -ENOMEM;
}
- nread = fread(data, 1, (size_t)length, stream);
- if (nread != (size_t)length)
+ total = 0;
+ while (total < length)
{
- int err = ferror(stream);
+ ssize_t ret;
- fclose(stream);
- free(data);
- return err ? -EIO : -EINVAL;
+ ret = read(fd, data + total, length - total);
+ if (ret < 0)
+ {
+ if (errno == EINTR)
+ {
+ continue;
+ }
+
+ close(fd);
+ pkg_free(data);
+ return -errno;
+ }
+
+ if (ret == 0)
+ {
+ break;
+ }
+
+ total += (size_t)ret;
}
- fclose(stream);
+ nread = total;
+ close(fd);
+
+ if (nread != length)
+ {
+ pkg_free(data);
+ return -EINVAL;
+ }
data[length] = '\0';
*buffer = data;
return 0;
}
+#ifndef CONFIG_PSEUDOFS_FILE
+/****************************************************************************
+ * Name: pkg_store_make_tmp_path
+ *
+ * Description:
+ * Build a FAT short-name-compatible staging path.
+ *
+ ****************************************************************************/
+
+static int pkg_store_make_tmp_path(FAR char *tmp, size_t size,
+ FAR const char *path)
+{
+ FAR char *dot;
+ FAR char *slash;
+ int ret;
+
+ ret = snprintf(tmp, size, "%s", path);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ if ((size_t)ret >= size)
+ {
+ return -ENAMETOOLONG;
+ }
+
+ slash = strrchr(tmp, '/');
+ dot = strrchr(slash != NULL ? slash : tmp, '.');
+ if (dot != NULL)
+ {
+ *dot = '\0';
+ }
+
+ if (strlcat(tmp, ".tm", size) >= size)
+ {
+ return -ENAMETOOLONG;
+ }
+
+ return 0;
+}
+#endif
+
int pkg_store_write_text_atomic(FAR const char *path, FAR const char *text)
{
- char tmp[PATH_MAX];
+#ifdef CONFIG_PSEUDOFS_FILE
int fd;
int ret;
- ret = snprintf(tmp, sizeof(tmp), "%s.tmp", path);
+ fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (fd < 0)
+ {
+ return -errno;
+ }
+
+ ret = pkg_store_write_all(fd, text, strlen(text));
+ if (ret < 0)
+ {
+ close(fd);
+ unlink(path);
+ return ret;
+ }
+
+ ret = close(fd);
if (ret < 0)
{
+ ret = -errno;
+ unlink(path);
return ret;
}
- if ((size_t)ret >= sizeof(tmp))
+ return 0;
+#else
+ char tmp[PATH_MAX];
+ int fd;
+ int ret;
+
+ ret = pkg_store_make_tmp_path(tmp, sizeof(tmp), path);
+ if (ret < 0)
{
- return -ENAMETOOLONG;
+ return ret;
}
fd = open(tmp, O_WRONLY | O_CREAT | O_TRUNC, 0644);
@@ -409,19 +699,35 @@ int pkg_store_write_text_atomic(FAR const char *path, FAR
const char *text)
return ret;
}
- if (close(fd) < 0)
+ /* Commit the temporary file before the atomic rename. */
+
+ ret = fsync(fd);
+ if (ret < 0)
+ {
+ ret = -errno;
+ close(fd);
+ unlink(tmp);
+ return ret;
+ }
+
+ ret = close(fd);
+ if (ret < 0)
{
+ ret = -errno;
unlink(tmp);
- return -errno;
+ return ret;
}
- if (rename(tmp, path) < 0)
+ ret = rename(tmp, path);
+ if (ret < 0)
{
+ ret = -errno;
unlink(tmp);
- return -errno;
+ return ret;
}
return 0;
+#endif
}
int pkg_store_copy_file(FAR const char *src, FAR const char *dest)
@@ -430,6 +736,20 @@ int pkg_store_copy_file(FAR const char *src, FAR const
char *dest)
int outfd;
int ret;
char buffer[512];
+#ifndef CONFIG_PSEUDOFS_FILE
+ char tmp[PATH_MAX];
+ FAR const char *outpath;
+
+ ret = pkg_store_make_tmp_path(tmp, sizeof(tmp), dest);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ outpath = tmp;
+#else
+ FAR const char *outpath = dest;
+#endif
infd = open(src, O_RDONLY);
if (infd < 0)
@@ -437,7 +757,7 @@ int pkg_store_copy_file(FAR const char *src, FAR const char
*dest)
return -errno;
}
- outfd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ outfd = open(outpath, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (outfd < 0)
{
ret = -errno;
@@ -475,18 +795,41 @@ int pkg_store_copy_file(FAR const char *src, FAR const
char *dest)
close(infd);
- if (close(outfd) < 0)
+#ifndef CONFIG_PSEUDOFS_FILE
+ /* Commit the payload before the atomic rename. */
+
+ if (fsync(outfd) < 0)
{
- unlink(dest);
- return -errno;
+ ret = -errno;
+ close(outfd);
+ unlink(outpath);
+ return ret;
+ }
+#endif
+
+ ret = close(outfd);
+ if (ret < 0)
+ {
+ ret = -errno;
+ unlink(outpath);
+ return ret;
+ }
+
+#ifndef CONFIG_PSEUDOFS_FILE
+ if (rename(outpath, dest) < 0)
+ {
+ ret = -errno;
+ unlink(outpath);
+ return ret;
}
+#endif
return 0;
errout:
close(infd);
close(outfd);
- unlink(dest);
+ unlink(outpath);
return ret;
}
@@ -499,3 +842,51 @@ int pkg_store_remove_file(FAR const char *path)
return 0;
}
+
+int pkg_store_remove_version_dir(FAR const char *name,
+ FAR const char *version)
+{
+ char path[PATH_MAX];
+ char entry_path[PATH_MAX];
+ FAR DIR *dir;
+ FAR struct dirent *ent;
+ int ret;
+
+ /* Remove every file in a staged or installed version directory. */
+
+ ret = pkg_store_format_version_path(path, sizeof(path), name, version);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ dir = opendir(path);
+ if (dir == NULL)
+ {
+ return errno == ENOENT ? 0 : -errno;
+ }
+
+ while ((ent = readdir(dir)) != NULL)
+ {
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ {
+ continue;
+ }
+
+ ret = snprintf(entry_path, sizeof(entry_path), "%s/%s", path,
+ ent->d_name);
+ if (ret > 0 && (size_t)ret < sizeof(entry_path))
+ {
+ unlink(entry_path);
+ }
+ }
+
+ closedir(dir);
+
+ if (rmdir(path) < 0)
+ {
+ return errno == ENOENT ? 0 : -errno;
+ }
+
+ return 0;
+}