2727#include <dirent.h>
2828#include <errno.h>
2929#include <fcntl.h>
30- #include <inttypes.h>
31- #include <pthread.h>
3230#include <signal.h>
33- #include <stdint.h>
3431#include <stdlib.h>
3532#include <stdio.h>
3633#include <string.h>
4441 * Pre-processor Definitions
4542 ****************************************************************************/
4643
47- #define PKG_LOCK_RECORD_MAGIC "NXPKG1"
48- #define PKG_LOCK_RECORD_SIZE 64
49-
50- /****************************************************************************
51- * Private Data
52- ****************************************************************************/
53-
54- static pthread_once_t g_pkg_lock_boot_once = PTHREAD_ONCE_INIT ;
55- static uint64_t g_pkg_lock_boot_id ;
44+ #define PKG_LOCK_OWNER "owner"
5645
5746/****************************************************************************
5847 * Private Functions
5948 ****************************************************************************/
6049
61- static void pkg_lock_init_boot_id (void )
62- {
63- arc4random_buf (& g_pkg_lock_boot_id , sizeof (g_pkg_lock_boot_id ));
64- if (g_pkg_lock_boot_id == 0 )
65- {
66- g_pkg_lock_boot_id = 1 ;
67- }
68- }
69-
70- static uint64_t pkg_lock_get_boot_id (void )
71- {
72- if (pthread_once (& g_pkg_lock_boot_once , pkg_lock_init_boot_id ) != 0 )
73- {
74- return 1 ;
75- }
76-
77- return g_pkg_lock_boot_id ;
78- }
79-
80- static int pkg_lock_read_owner (FAR const char * path ,
81- FAR uint64_t * boot_id ,
82- FAR pid_t * owner )
50+ static int pkg_lock_read_owner (FAR const char * path , FAR pid_t * owner )
8351{
84- char record [PKG_LOCK_RECORD_SIZE ];
85- unsigned long long parsed_boot ;
52+ char owner_path [PATH_MAX ];
53+ char record [32 ];
54+ char extra ;
8655 long parsed_owner ;
8756 ssize_t nread ;
8857 int fd ;
8958 int ret ;
9059
91- fd = open (path , O_RDONLY );
60+ ret = snprintf (owner_path , sizeof (owner_path ), "%s/%s" , path ,
61+ PKG_LOCK_OWNER );
62+ if (ret < 0 || (size_t )ret >= sizeof (owner_path ))
63+ {
64+ return ret < 0 ? ret : - ENAMETOOLONG ;
65+ }
66+
67+ fd = open (owner_path , O_RDONLY );
9268 if (fd < 0 )
9369 {
9470 return - errno ;
@@ -104,16 +80,13 @@ static int pkg_lock_read_owner(FAR const char *path,
10480
10581 close (fd );
10682 record [nread ] = '\0' ;
107-
108- ret = sscanf (record , PKG_LOCK_RECORD_MAGIC " %llx %ld" ,
109- & parsed_boot , & parsed_owner );
110- if (ret != 2 || parsed_owner <= 0 ||
83+ if (sscanf (record , "%ld%c" , & parsed_owner , & extra ) != 1 ||
84+ parsed_owner <= 0 ||
11185 (long )(pid_t )parsed_owner != parsed_owner )
11286 {
11387 return - EINVAL ;
11488 }
11589
116- * boot_id = (uint64_t )parsed_boot ;
11790 * owner = (pid_t )parsed_owner ;
11891 return 0 ;
11992}
@@ -274,78 +247,104 @@ int pkg_store_prepare_layout(void)
274247
275248int pkg_lock_create (FAR const char * path )
276249{
277- char record [PKG_LOCK_RECORD_SIZE ];
250+ char owner_path [PATH_MAX ];
251+ char record [32 ];
278252 int fd ;
279253 int ret ;
280254
281- fd = open (path , O_WRONLY | O_CREAT | O_EXCL , 0644 );
282- if (fd < 0 )
255+ if (mkdir (path , 0755 ) < 0 )
283256 {
284257 return - errno ;
285258 }
286259
287- ret = snprintf (record , sizeof (record ), PKG_LOCK_RECORD_MAGIC
288- " %016" PRIx64 " %ld\n" ,
289- pkg_lock_get_boot_id (), (long )getpid ());
290- if (ret < 0 || (size_t )ret >= sizeof (record ))
260+ ret = snprintf (owner_path , sizeof (owner_path ), "%s/%s" , path ,
261+ PKG_LOCK_OWNER );
262+ if (ret < 0 || (size_t )ret >= sizeof (owner_path ))
291263 {
292264 ret = ret < 0 ? ret : - ENAMETOOLONG ;
293- goto errout ;
265+ rmdir (path );
266+ return ret ;
294267 }
295268
296- ret = pkg_store_write_all ( fd , record , ( size_t ) ret );
297- if (ret < 0 )
269+ fd = open ( owner_path , O_WRONLY | O_CREAT | O_EXCL , 0644 );
270+ if (fd < 0 )
298271 {
299- goto errout ;
272+ ret = - errno ;
273+ rmdir (path );
274+ return ret ;
300275 }
301276
302- if (fsync (fd ) < 0 )
277+ ret = snprintf (record , sizeof (record ), "%ld" , (long )getpid ());
278+ if (ret < 0 || (size_t )ret >= sizeof (record ))
279+ {
280+ ret = ret < 0 ? ret : - EOVERFLOW ;
281+ }
282+ else
283+ {
284+ ret = pkg_store_write_all (fd , record , (size_t )ret );
285+ }
286+
287+ if (ret == 0 && fsync (fd ) < 0 )
303288 {
304289 ret = - errno ;
305- goto errout ;
306290 }
307291
308- if (close (fd ) < 0 )
292+ if (close (fd ) < 0 && ret == 0 )
309293 {
310294 ret = - errno ;
311- unlink (path );
312- return ret ;
313295 }
314296
315- return 0 ;
297+ if (ret < 0 )
298+ {
299+ unlink (owner_path );
300+ rmdir (path );
301+ }
316302
317- errout :
318- close (fd );
319- unlink (path );
320303 return ret ;
321304}
322305
306+ void pkg_lock_remove (FAR const char * path )
307+ {
308+ char owner_path [PATH_MAX ];
309+ int ret ;
310+
311+ ret = snprintf (owner_path , sizeof (owner_path ), "%s/%s" , path ,
312+ PKG_LOCK_OWNER );
313+ if (ret >= 0 && (size_t )ret < sizeof (owner_path ))
314+ {
315+ unlink (owner_path );
316+ }
317+
318+ rmdir (path );
319+ }
320+
323321void pkg_reclaim_stale_lock (FAR const char * path )
324322{
325- uint64_t boot_id ;
326323 pid_t owner ;
327324 int ret ;
328325
329- ret = pkg_lock_read_owner (path , & boot_id , & owner );
330- if (ret == - EINVAL )
326+ ret = pkg_lock_read_owner (path , & owner );
327+ if (ret == - ENOENT || ret == - EINVAL )
331328 {
332- /* The creator may have completed open(O_EXCL) without writing yet.
333- * Give that window time to close before reading again.
334- */
329+ /* The creator may not have written the owner marker yet. */
335330
336331 usleep (20 * 1000 );
337- ret = pkg_lock_read_owner (path , & boot_id , & owner );
332+ ret = pkg_lock_read_owner (path , & owner );
333+ if (ret == - ENOENT || ret == - EINVAL )
334+ {
335+ pkg_lock_remove (path );
336+ return ;
337+ }
338338 }
339339
340340 if (ret < 0 )
341341 {
342342 return ;
343343 }
344344
345- if (boot_id != pkg_lock_get_boot_id ())
345+ if (owner == getpid ())
346346 {
347- pkg_error ("reclaiming lock from an earlier boot '%s'" , path );
348- unlink (path );
347+ pkg_lock_remove (path );
349348 return ;
350349 }
351350
@@ -358,7 +357,7 @@ void pkg_reclaim_stale_lock(FAR const char *path)
358357 {
359358 pkg_error ("reclaiming lock from exited task %ld '%s'" ,
360359 (long )owner , path );
361- unlink (path );
360+ pkg_lock_remove (path );
362361 }
363362}
364363
@@ -550,12 +549,7 @@ int pkg_store_read_text(FAR const char *path, FAR char **buffer)
550549 return - EINVAL ;
551550 }
552551
553- /* Reject anything unreasonably large before the size is trusted for an
554- * allocation: guards both against a malicious/oversized text file (this
555- * path is used for the network-fetched index.jsn) and against
556- * "length + 1" wrapping if st_size were ever attacker-influenced up to
557- * SIZE_MAX.
558- */
552+ /* Validate the size before allocating length plus its terminator. */
559553
560554 if (st .st_size < 0 || st .st_size > (off_t )PKG_TEXT_MAX_SIZE )
561555 {
@@ -616,10 +610,7 @@ int pkg_store_read_text(FAR const char *path, FAR char **buffer)
616610 * Name: pkg_store_make_tmp_path
617611 *
618612 * Description:
619- * Derive a staging path for an atomic write/copy to "path", under a
620- * short-name-compatible extension instead of appending ".tmp" (which
621- * would produce a second '.' in the final path component and break on
622- * FAT filesystems without long file name support).
613+ * Build a FAT short-name-compatible staging path.
623614 *
624615 ****************************************************************************/
625616
@@ -711,14 +702,7 @@ int pkg_store_write_text_atomic(FAR const char *path, FAR const char *text)
711702 return ret ;
712703 }
713704
714- /* Force the write through to disk before renaming. nxpkg writes
715- * several small, unrelated files back-to-back during install (per-
716- * package txn state, then the shared installed-packages database);
717- * without an explicit sync here, the FAT driver's single shared
718- * sector cache can still hold a not-yet-committed buffer for this
719- * file when the very next atomic write starts touching a different
720- * file, corrupting one or both.
721- */
705+ /* Commit the temporary file before the atomic rename. */
722706
723707 ret = fsync (fd );
724708 if (ret < 0 )
@@ -815,11 +799,7 @@ int pkg_store_copy_file(FAR const char *src, FAR const char *dest)
815799 close (infd );
816800
817801#ifndef CONFIG_PSEUDOFS_FILE
818- /* Force the payload through to disk before renaming - this is the
819- * largest write in the whole install pipeline (WAD/game-ELF-sized
820- * payloads), so a hard power-loss here is the scenario the atomic
821- * temp+rename is specifically protecting against.
822- */
802+ /* Commit the payload before the atomic rename. */
823803
824804 if (fsync (outfd ) < 0 )
825805 {
@@ -875,15 +855,7 @@ int pkg_store_remove_version_dir(FAR const char *name,
875855 FAR struct dirent * ent ;
876856 int ret ;
877857
878- /* Generic directory-content removal (rather than unlinking the payload
879- * and manifest.jsn by their known names) so this same helper works both
880- * to reclaim a partially staged version directory after a failed
881- * install (pkg_install.c) and to prune/remove a fully-installed
882- * version, without needing to already know that version's artifact
883- * filename. Best-effort throughout: this runs from error/cleanup
884- * paths where a still-failing removal shouldn't itself abort the
885- * caller.
886- */
858+ /* Remove every file in a staged or installed version directory. */
887859
888860 ret = pkg_store_format_version_path (path , sizeof (path ), name , version );
889861 if (ret < 0 )
0 commit comments