Skip to content

Commit 38c6083

Browse files
committed
system/nxpkg: Address follow-up review findings.
Shorten the installed-database lock description and centralize pkg_sync() cleanup, as requested in review. Replace repeated protocol literals with named constants and preserve errno before cleanup calls can overwrite it. Store the synchronized catalog source in the catalog itself so the catalog and its relative-artifact base are committed atomically. Continue reading the former sidecar format for upgrade compatibility, and normalize array-form catalogs before adding the private source field. Compare numeric version prefixes without strtol() overflow and retain lexical comparison of suffixes. Assisted-by: Codex:gpt-5 Signed-off-by: aviralgarg05 <gargaviral99@gmail.com>
1 parent 8571175 commit 38c6083

4 files changed

Lines changed: 204 additions & 166 deletions

File tree

system/nxpkg/pkg_install.c

Lines changed: 2 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -78,37 +78,8 @@ static int pkg_install_acquire_lock(FAR const char *name, FAR char *path,
7878
* Name: pkg_install_acquire_installed_lock
7979
*
8080
* Description:
81-
* The per-package lock above (pkg_install_acquire_lock()) only ever
82-
* protects one package's own version directory/manifest - it says
83-
* nothing about the single shared installed-packages database
84-
* (instpkg.jsn) that every install/uninstall/rollback reads, modifies
85-
* in memory, and writes back as a whole. Two of those operations for
86-
* *different* packages (their own per-package locks don't conflict)
87-
* can each load a snapshot of that shared file, add/change their own
88-
* entry, and save - and whichever one saves last wins, silently
89-
* discarding whatever the other one had just added. This is exactly
90-
* what "a previously-installed package vanishes from `nxpkg list`
91-
* with no error" looks like, without needing any corrupted file or
92-
* non-atomic write at all: the write path is already atomic
93-
* (pkg_store_write_text_atomic() writes to a temp file, fsyncs, then
94-
* renames), so the *file* is always internally consistent - it just
95-
* might be a consistent snapshot that's missing an entry a concurrent
96-
* operation already believed it had durably saved.
97-
*
98-
* A separate, single global lock file (independent of any specific
99-
* package's own lock) closes that window: acquire it right before
100-
* pkg_metadata_load_installed() and hold it until immediately after
101-
* pkg_metadata_save_installed(), so that whole read-modify-write
102-
* sequence is atomic with respect to every other caller of this
103-
* function, regardless of which package(s) they're touching.
104-
*
105-
* Blocking (bounded retry loop) rather than instant-EBUSY like the
106-
* per-package lock: the critical section this protects is a handful
107-
* of local SD-card JSON operations with no network I/O in it, so a
108-
* real holder releases it within milliseconds - a caller should wait
109-
* that out rather than fail an otherwise-healthy install/uninstall/
110-
* rollback just because another one's shared-db update was in
111-
* flight at the same instant.
81+
* Acquire the global installed-database lock. This serializes the
82+
* read-modify-write sequence used by install, uninstall, and rollback.
11283
*
11384
****************************************************************************/
11485

system/nxpkg/pkg_metadata.c

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
* Included Files
2525
****************************************************************************/
2626

27+
#include <ctype.h>
2728
#include <errno.h>
2829
#include <stdlib.h>
2930
#include <string.h>
@@ -400,41 +401,63 @@ static int pkg_metadata_parse_installed_entry(
400401
static int pkg_metadata_version_token_cmp(FAR const char *lhs,
401402
FAR const char *rhs)
402403
{
403-
long leftnum;
404-
long rightnum;
405-
FAR char *leftend;
406-
FAR char *rightend;
407404
FAR const char *cmpleft;
408405
FAR const char *cmpright;
406+
FAR const char *leftdigits;
407+
FAR const char *rightdigits;
408+
size_t leftlen;
409+
size_t rightlen;
409410
int ret;
410411

411-
leftnum = strtol(lhs, &leftend, 10);
412-
rightnum = strtol(rhs, &rightend, 10);
412+
leftdigits = lhs;
413+
rightdigits = rhs;
414+
while (isdigit((unsigned char)*leftdigits))
415+
{
416+
leftdigits++;
417+
}
418+
419+
while (isdigit((unsigned char)*rightdigits))
420+
{
421+
rightdigits++;
422+
}
413423

414-
if (leftend != lhs && rightend != rhs)
424+
if (leftdigits != lhs && rightdigits != rhs)
415425
{
416-
if (leftnum < rightnum)
426+
while (*lhs == '0' && lhs + 1 < leftdigits)
427+
{
428+
lhs++;
429+
}
430+
431+
while (*rhs == '0' && rhs + 1 < rightdigits)
432+
{
433+
rhs++;
434+
}
435+
436+
leftlen = (size_t)(leftdigits - lhs);
437+
rightlen = (size_t)(rightdigits - rhs);
438+
if (leftlen < rightlen)
417439
{
418440
return -1;
419441
}
420442

421-
if (leftnum > rightnum)
443+
if (leftlen > rightlen)
422444
{
423445
return 1;
424446
}
425447

426-
/* Equal numeric prefixes don't make the tokens equal if what
427-
* follows the number differs - e.g. "1a" and "1b" both parse as
428-
* 1, but are documented to compare lexically by their non-numeric
429-
* component. Falling through to "equal" here (as this used to)
430-
* silently treated any such pair as the same version, which is
431-
* exactly backwards for tokens whose whole point is to be
432-
* distinguishable. Compare what's left after the numeric prefix
433-
* - leftend/rightend - lexically instead of falling through.
434-
*/
448+
ret = memcmp(lhs, rhs, leftlen);
449+
if (ret < 0)
450+
{
451+
return -1;
452+
}
453+
454+
if (ret > 0)
455+
{
456+
return 1;
457+
}
435458

436-
cmpleft = leftend;
437-
cmpright = rightend;
459+
cmpleft = leftdigits;
460+
cmpright = rightdigits;
438461
}
439462
else
440463
{

0 commit comments

Comments
 (0)