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;
+}

Reply via email to