[opkg-devel][PATCH 1/3] libopkg: remove trailing '/' when generating list from package

8 views
Skip to first unread message

Shruthi Ravichandran

unread,
Aug 8, 2022, 8:33:54 PM8/8/22
to opkg-...@googlegroups.com, Shruthi Ravichandran
In pkg_write_filelist(), the trailing '/' is removed from each entry
before writing to the .list file. But the same is not done when the
.list file doesn't exist yet for a package, and it has to be
generated from the package in pkg_get_installed(). This leads to a
different entry in the file hash for the same file, and multiple
packages claiming ownership of a file.

Fixes commit 70df4de62313cf973e98b296d467be1d73b9b9f9

Signed-off-by: Shruthi Ravichandran <shruthi.ra...@ni.com>
---
libopkg/pkg.c | 9 +++++++++
1 file changed, 9 insertions(+)

diff --git a/libopkg/pkg.c b/libopkg/pkg.c
index 88012fa..a196714 100644
--- a/libopkg/pkg.c
+++ b/libopkg/pkg.c
@@ -1231,6 +1231,15 @@ file_list_t *pkg_get_installed_files(pkg_t * pkg)
if (*file_name == '/') {
file_name++;
}
+ // now we need to remove the trailing '/' in each entry to
+ // be consistent with pkg_write_filelist() that does the
+ // same.
+ int size = strlen(file_name);
+ if (size > 0 && file_name[size-1] == '/')
+ {
+ file_name[size-1] = '\0';
+ }
+
sprintf_alloc(&installed_file_name, "%s%s", pkg->dest->root_dir,
file_name);
} else {
--
2.20.1

Shruthi Ravichandran

unread,
Aug 8, 2022, 8:34:15 PM8/8/22
to opkg-...@googlegroups.com, Shruthi Ravichandran
Multiple packages can install the same directory, or a symlink to a
directory. Ensure that these entries are not removed from the
filelists of packages that are installed following a package that
first installs the directory or a symlink to a directory.
This is later used to ensure that out-of-order package removals do
not result in directory or symlink deletion.

Fixes Bugzilla #10461.

Signed-off-by: Shruthi Ravichandran <shruthi.ra...@ni.com>
---
libopkg/file_util.c | 16 ++++++++++++++++
libopkg/file_util.h | 1 +
libopkg/opkg_install.c | 14 ++++++++++++++
libopkg/pkg_hash.c | 8 +++++++-
4 files changed, 38 insertions(+), 1 deletion(-)

diff --git a/libopkg/file_util.c b/libopkg/file_util.c
index ee9f59d..050e4a7 100644
--- a/libopkg/file_util.c
+++ b/libopkg/file_util.c
@@ -96,6 +96,22 @@ int file_is_symlink(const char *file_name)
return S_ISLNK(st.st_mode);
}

+int file_is_symlink_to_dir(const char *file_name)
+{
+ int is_symlink_to_dir = 0;
+ if(file_is_symlink(file_name)) {
+ char *link_target;
+ struct stat target_stat;
+
+ link_target = realpath(file_name, NULL);
+ if (link_target) {
+ is_symlink_to_dir = (xlstat(link_target, &target_stat) == 0) && S_ISDIR(target_stat.st_mode);
+ free(link_target);
+ }
+ }
+ return is_symlink_to_dir;
+}
+
char *file_readlink_alloc(const char *file_name)
{
struct stat st;
diff --git a/libopkg/file_util.h b/libopkg/file_util.h
index 2487649..87d3944 100644
--- a/libopkg/file_util.h
+++ b/libopkg/file_util.h
@@ -31,6 +31,7 @@ int xlstat(const char *file_name, struct stat *st);
int file_exists(const char *file_name);
int file_is_dir(const char *file_name);
int file_is_symlink(const char *file_name);
+int file_is_symlink_to_dir(const char *file_name);
char *file_readlink_alloc(const char *file_name);
char *file_read_line_alloc(FILE * file);
int file_link(const char *src, const char *dest);
diff --git a/libopkg/opkg_install.c b/libopkg/opkg_install.c
index f05d778..354dc10 100644
--- a/libopkg/opkg_install.c
+++ b/libopkg/opkg_install.c
@@ -67,6 +67,20 @@ static int update_file_ownership(pkg_t * new_pkg, pkg_t * old_pkg)

if (!owner || (owner == old_pkg) || obs)
file_hash_set_file_owner(new_file->path, new_pkg);
+
+ /*
+ * If the path is a directory or a symlink to a directory, it
+ * can be owned by multiple packages without clashes.
+ * Therefore, ensure that the path gets written to the filelist
+ * of every package that installs it, even if it already exists
+ * on the system.
+ */
+ int existing_is_dir = file_is_dir(new_file->path);
+ int existing_is_symlink = file_is_symlink_to_dir(new_file->path);
+ if ((existing_is_dir && S_ISDIR(new_file->mode)) ||
+ (existing_is_symlink && S_ISDIR(new_file->mode)))
+ file_hash_set_file_owner(new_file->path, new_pkg);
+
}

if (old_pkg) {
diff --git a/libopkg/pkg_hash.c b/libopkg/pkg_hash.c
index 6c6c269..1371bb6 100644
--- a/libopkg/pkg_hash.c
+++ b/libopkg/pkg_hash.c
@@ -907,12 +907,18 @@ void file_hash_set_file_owner(const char *file_name, pkg_t * owning_pkg)
{
pkg_t *old_owning_pkg;

+ const char* long_file_name = file_name;
file_name = strip_offline_root(file_name);

old_owning_pkg = hash_table_get(&opkg_config->file_hash, file_name);
hash_table_insert(&opkg_config->file_hash, file_name, owning_pkg);

- if (old_owning_pkg) {
+ /*
+ * Multiple packages can claim ownership of a directory or a
+ * symlink to a directory. Therefore, do not remove the file_name
+ * from old_owning_pkg's list file in such cases.
+ */
+ if (old_owning_pkg && !file_is_dir(long_file_name) && !file_is_symlink_to_dir(long_file_name)) {
if (!old_owning_pkg->installed_files)
pkg_get_installed_files(old_owning_pkg);
file_list_remove_elt(old_owning_pkg->installed_files, file_name);
--
2.20.1

Shruthi Ravichandran

unread,
Aug 8, 2022, 8:34:15 PM8/8/22
to opkg-...@googlegroups.com, Shruthi Ravichandran
Create a dir-hash to track the number of packages installing the
same directory or a symlink to a directory. This directory or
symlink is deleted only when there is no other package using it.
This is in line with how dpkg deletes directories.

Fixes Bugzilla #10461.

Signed-off-by: Shruthi Ravichandran <shruthi.ra...@ni.com>
---
libopkg/opkg_conf.c | 5 +++
libopkg/opkg_conf.h | 1 +
libopkg/opkg_remove.c | 31 ++++++++++++++-
libopkg/pkg.c | 10 +++++
libopkg/pkg_hash.c | 30 +++++++++++++++
libopkg/pkg_hash.h | 4 ++
tests/Makefile | 2 +
tests/regress/issue10461a.py | 64 ++++++++++++++++++++++++++++++
tests/regress/issue10461b.py | 75 ++++++++++++++++++++++++++++++++++++
tests/regress/issue13574.py | 2 +-
10 files changed, 221 insertions(+), 3 deletions(-)
create mode 100644 tests/regress/issue10461a.py
create mode 100644 tests/regress/issue10461b.py

diff --git a/libopkg/opkg_conf.c b/libopkg/opkg_conf.c
index e13ebc1..c2e1c2f 100644
--- a/libopkg/opkg_conf.c
+++ b/libopkg/opkg_conf.c
@@ -770,6 +770,8 @@ int opkg_conf_load(void)
pkg_hash_init();
hash_table_init("file-hash", &opkg_config->file_hash,
OPKG_CONF_DEFAULT_HASH_LEN);
+ hash_table_init("dir-hash", &opkg_config->dir_hash,
+ OPKG_CONF_DEFAULT_HASH_LEN);
hash_table_init("obs-file-hash", &opkg_config->obs_file_hash,
OPKG_CONF_DEFAULT_HASH_LEN / 16);

@@ -871,6 +873,7 @@ int opkg_conf_load(void)
err4:
pkg_hash_deinit();
hash_table_deinit(&opkg_config->file_hash);
+ hash_table_deinit(&opkg_config->dir_hash);
hash_table_deinit(&opkg_config->obs_file_hash);

r = rmdir(opkg_config->tmp_dir);
@@ -925,11 +928,13 @@ void opkg_conf_deinit(void)
if (opkg_config->verbosity >= DEBUG) {
hash_print_stats(&opkg_config->pkg_hash);
hash_print_stats(&opkg_config->file_hash);
+ hash_print_stats(&opkg_config->dir_hash);
hash_print_stats(&opkg_config->obs_file_hash);
}

pkg_hash_deinit();
hash_table_deinit(&opkg_config->file_hash);
+ hash_table_deinit(&opkg_config->dir_hash);
hash_table_deinit(&opkg_config->obs_file_hash);

for (i = 0; options[i].name; i++) {
diff --git a/libopkg/opkg_conf.h b/libopkg/opkg_conf.h
index b7caa74..d13d50b 100644
--- a/libopkg/opkg_conf.h
+++ b/libopkg/opkg_conf.h
@@ -166,6 +166,7 @@ typedef struct opkg_conf {
hash_table_t pkg_hash;
hash_table_t file_hash;
hash_table_t obs_file_hash;
+ hash_table_t dir_hash;
} opkg_conf_t;

enum opkg_option_type {
diff --git a/libopkg/opkg_remove.c b/libopkg/opkg_remove.c
index 09a7c48..889c672 100644
--- a/libopkg/opkg_remove.c
+++ b/libopkg/opkg_remove.c
@@ -72,7 +72,20 @@ void remove_data_files_and_list(pkg_t * pkg)
continue;

if (file_is_dir(file_name)) {
- str_list_append(&installed_dirs, file_name);
+ /*
+ Ensure that the directory is marked for deletion only if
+ no other installed package is using that directory.
+ */
+ if (dir_hash_get_ref_count(file_name) == 1)
+ {
+ str_list_append(&installed_dirs, file_name);
+ dir_hash_remove(file_name);
+ }
+ else
+ {
+ /* directory should get a new owner in the file hash*/
+ file_hash_remove(file_name);
+ }
continue;
} else if (file_is_symlink(file_name)) {
char *link_target;
@@ -81,7 +94,21 @@ void remove_data_files_and_list(pkg_t * pkg)
link_target = realpath(file_name, NULL);
if (link_target) {
if ((xlstat(link_target, &target_stat) == 0) && S_ISDIR(target_stat.st_mode)) {
- str_list_append(&installed_dirs_symlinks, file_name);
+ /*
+ * Ensure that the symlink is marked for deletion
+ * only if no other installed package uses that symlink.
+ */
+ if (dir_hash_get_ref_count(file_name) == 1)
+ {
+ str_list_append(&installed_dirs_symlinks, file_name);
+ dir_hash_remove(file_name);
+ }
+ else
+ {
+ /* directory should get a new owner in the file hash*/
+ file_hash_remove(file_name);
+ }
+
free(link_target);
continue;
}
diff --git a/libopkg/pkg.c b/libopkg/pkg.c
index a196714..6b1bd8f 100644
--- a/libopkg/pkg.c
+++ b/libopkg/pkg.c
@@ -1434,6 +1434,16 @@ void pkg_info_preinstall_check(void)
iter = niter, niter = file_list_next(installed_files, iter)) {
file_info_t *installed_file = (file_info_t *)iter->data;
file_hash_set_file_owner(installed_file->path, pkg);
+ /*
+ * Ensure that directories or symlink to directories used
+ * by multiple packages are tracked in the dir_hash.
+ * This is later used in remove operations to determine if
+ * the directory or symlink can be deleted.
+ */
+ if(file_is_dir(installed_file->path) || file_is_symlink_to_dir(installed_file->path))
+ {
+ dir_hash_add_ref_count(installed_file->path);
+ }
}
pkg_free_installed_files(pkg);
}
diff --git a/libopkg/pkg_hash.c b/libopkg/pkg_hash.c
index 1371bb6..3ca1804 100644
--- a/libopkg/pkg_hash.c
+++ b/libopkg/pkg_hash.c
@@ -928,3 +928,33 @@ void file_hash_set_file_owner(const char *file_name, pkg_t * owning_pkg)
owning_pkg->state_flag |= SF_FILELIST_CHANGED;
}
}
+
+int dir_hash_get_ref_count(const char* file_name)
+{
+ int* current_count = hash_table_get(&opkg_config->dir_hash, file_name);
+ if (!current_count)
+ return 0;
+
+ return *current_count;
+}
+
+void dir_hash_add_ref_count(const char* file_name)
+{
+ int* current_count = hash_table_get(&opkg_config->dir_hash, file_name);
+ if(!current_count)
+ {
+ current_count = xmalloc(sizeof(int*));
+ *current_count = 0;
+ }
+ *current_count = *current_count + 1;
+ hash_table_insert(&opkg_config->dir_hash, file_name, current_count);
+}
+
+void dir_hash_remove(const char* file_name)
+{
+ int* current_count = hash_table_get(&opkg_config->dir_hash, file_name);
+ if (current_count) {
+ hash_table_remove(&opkg_config->dir_hash, file_name);
+ free(current_count);
+ }
+}
diff --git a/libopkg/pkg_hash.h b/libopkg/pkg_hash.h
index 2ab9356..acac797 100644
--- a/libopkg/pkg_hash.h
+++ b/libopkg/pkg_hash.h
@@ -66,6 +66,10 @@ void file_hash_remove(const char *file_name);
pkg_t *file_hash_get_file_owner(const char *file_name);
void file_hash_set_file_owner(const char *file_name, pkg_t * pkg);

+int dir_hash_get_ref_count(const char* file_name);
+void dir_hash_add_ref_count(const char* file_name);
+void dir_hash_remove(const char* file_name);
+
#ifdef __cplusplus
}
#endif
diff --git a/tests/Makefile b/tests/Makefile
index dd883c8..e1efa17 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -87,6 +87,8 @@ REGRESSION_TESTS := core/01_install.py \
regress/issue9939.py \
regress/issue10358.py \
regress/issue10358b.py \
+ regress/issue10461a.py \
+ regress/issue10461b.py \
regress/issue10777.py \
regress/issue10781.py \
regress/issue11033.py \
diff --git a/tests/regress/issue10461a.py b/tests/regress/issue10461a.py
new file mode 100644
index 0000000..8895f18
--- /dev/null
+++ b/tests/regress/issue10461a.py
@@ -0,0 +1,64 @@
+#! /usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Reporter: Gabe Jones
+#
+# What steps will reproduce the problem?
+# ======================================
+#
+# 1.- Create package 'a' and 'b', which install files to
+# a shared new directory.
+# 2.- Install package 'b', followed by package 'a'.
+# 3.- Remove package 'b', followed by package 'a'.
+#
+# What is the expected output? What do you see instead?
+# ======================================
+#
+# The shared new directory is deleted when the package 'a'
+# is uninstalled.
+# The shared directory is orphaned and not deleted after
+# both packages are uninstalled.
+
+import os
+import opk, cfg, opkgcl
+
+opk.regress_init()
+o = opk.OpkGroup()
+
+dir = "dir10461"
+filename1 = os.path.join(dir, "myfile1")
+filename2 = os.path.join(dir, "myfile2")
+
+os.makedirs(dir)
+open(filename1, "w").close()
+a = opk.Opk(Package="a")
+a.write(data_files=[dir])
+o.addOpk(a)
+
+os.unlink(filename1)
+
+open(filename2, "w").close()
+b = opk.Opk(Package="b")
+b.write(data_files=[dir])
+o.addOpk(b)
+
+os.unlink(filename2)
+os.rmdir(dir)
+
+o.write_list()
+opkgcl.update()
+
+opkgcl.install("b")
+if not opkgcl.is_installed("b"):
+ opk.fail("Package 'b' installed but reports as not installed.")
+
+opkgcl.install("a")
+if not opkgcl.is_installed("a"):
+ opk.fail("Package 'a' installed but reports as not installed.")
+
+opkgcl.remove("b")
+opkgcl.remove("a")
+
+
+if os.path.exists("{}/{}".format(cfg.offline_root, dir)):
+ opk.fail("Dir '{}' incorrectly orphaned.".format(dir))
diff --git a/tests/regress/issue10461b.py b/tests/regress/issue10461b.py
new file mode 100644
index 0000000..ac2bd17
--- /dev/null
+++ b/tests/regress/issue10461b.py
@@ -0,0 +1,75 @@
+#! /usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# 1.- Create package 'a', 'b' and 'c', which install files to
+# a shared new directory.
+# 2.- Install package 'b', followed by packages 'a' and 'c'.
+# 3.- Remove package 'c', followed by packages 'b' and 'a'.
+#
+# The shared new directory should be deleted only when the last package
+# 'a' is uninstalled.
+#
+# 4. Install and remove package 'c' again
+#
+# The new directory should be deleted correctly after 'c' is uninstalled.
+#
+
+
+import os
+import opk, cfg, opkgcl
+
+opk.regress_init()
+o = opk.OpkGroup()
+
+dir = "dir10461"
+
+os.makedirs(dir)
+a = opk.Opk(Package="a")
+a.write(data_files=[dir])
+o.addOpk(a)
+
+b = opk.Opk(Package="b")
+b.write(data_files=[dir])
+o.addOpk(b)
+
+c = opk.Opk(Package="c")
+c.write(data_files=[dir])
+o.addOpk(c)
+
+os.rmdir(dir)
+
+o.write_list()
+opkgcl.update()
+
+opkgcl.install("b")
+if not opkgcl.is_installed("b"):
+ opk.fail("Package 'b' installed but reports as not installed.")
+
+opkgcl.install("a")
+if not opkgcl.is_installed("a"):
+ opk.fail("Package 'a' installed but reports as not installed.")
+
+opkgcl.install("c")
+if not opkgcl.is_installed("c"):
+ opk.fail("Package 'c' installed but reports as not installed.")
+
+opkgcl.remove("c")
+if not os.path.exists("{}/{}".format(cfg.offline_root, dir)):
+ opk.fail("Dir '{}' incorrectly deleted.".format(dir))
+
+opkgcl.remove("b")
+if not os.path.exists("{}/{}".format(cfg.offline_root, dir)):
+ opk.fail("Dir '{}' incorrectly deleted.".format(dir))
+
+opkgcl.remove("a")
+if os.path.exists("{}/{}".format(cfg.offline_root, dir)):
+ opk.fail("Dir '{}' incorrectly orphaned.".format(dir))
+
+
+opkgcl.install("c")
+if not os.path.exists("{}/{}".format(cfg.offline_root, dir)):
+ opk.fail("Dir '{}' not created by package 'c'.".format(dir))
+
+opkgcl.remove("c")
+if os.path.exists("{}/{}".format(cfg.offline_root, dir)):
+ opk.fail("Dir '{}' incorrectly orphaned.".format(dir))
\ No newline at end of file
diff --git a/tests/regress/issue13574.py b/tests/regress/issue13574.py
index e9c9fd5..614e34c 100755
--- a/tests/regress/issue13574.py
+++ b/tests/regress/issue13574.py
@@ -48,7 +48,7 @@ if not os.path.exists("%s/lib64/testfile2.txt" % cfg.offline_root):
opk.fail("Package 'a' removed package 'b' file")

if not os.path.exists("%s/lib" % cfg.offline_root):
- opk.fail("Package 'a' incorrectly removed symlink that should belong to Package 'b'")
+ opk.fail("Package 'a' incorrectly removed symlink that should is in use by Package 'b'")

opkgcl.remove('b')
if os.path.exists("%s/lib64/testfile2.txt" % cfg.offline_root):
--
2.20.1

Alex Stewart

unread,
Aug 12, 2022, 8:33:07 AM8/12/22
to Shruthi Ravichandran, opkg-...@googlegroups.com
Should this free() call be placed outside of the if() clause, to free
the realpath() call in all cases?
Alex Stewart
Software Engineer - NI Real-Time OS
NI (National Instruments)

alex.s...@ni.com

Alex Stewart

unread,
Aug 12, 2022, 8:47:38 AM8/12/22
to Shruthi Ravichandran, opkg-...@googlegroups.com
NIT: extraneous word :)

On 8/8/22 19:33, Shruthi Ravichandran wrote:
s/should//

>
> opkgcl.remove('b')
> if os.path.exists("%s/lib64/testfile2.txt" % cfg.offline_root):

--

Alex Stewart

unread,
Aug 12, 2022, 8:51:08 AM8/12/22
to Shruthi Ravichandran, opkg-...@googlegroups.com
Patchset looks good to me, pending some minor fixups.

I'll pull once you have a Rev 2 available. Thanks!

On 8/8/22 19:33, Shruthi Ravichandran wrote:

Shruthi Ravichandran

unread,
Aug 12, 2022, 5:03:24 PM8/12/22
to Alex Stewart, opkg-...@googlegroups.com
This is a pattern followed in opkg to prevent calling free() on a NULL
pointer. realpath() can return NULL on error. Do you prefer to call
free() anyway?
INTERNAL - NI CONFIDENTIAL

Alex Stewart

unread,
Aug 13, 2022, 7:37:11 AM8/13/22
to Shruthi Ravichandran, opkg-...@googlegroups.com
Ah; I see. That's reasonable - no need to move it.

Shruthi Ravichandran

unread,
Aug 15, 2022, 12:27:17 PM8/15/22
to opkg-...@googlegroups.com, Shruthi Ravichandran
In pkg_write_filelist(), the trailing '/' is removed from each entry
before writing to the .list file. But the same is not done when the
.list file doesn't exist yet for a package, and it has to be
generated from the package in pkg_get_installed(). This leads to a
different entry in the file hash for the same file, and multiple
packages claiming ownership of a file.

Fixes commit 70df4de62313cf973e98b296d467be1d73b9b9f9

Signed-off-by: Shruthi Ravichandran <shruthi.ra...@ni.com>
---
libopkg/pkg.c | 9 +++++++++
1 file changed, 9 insertions(+)

diff --git a/libopkg/pkg.c b/libopkg/pkg.c
index 88012fa..a196714 100644
--- a/libopkg/pkg.c
+++ b/libopkg/pkg.c
@@ -1231,6 +1231,15 @@ file_list_t *pkg_get_installed_files(pkg_t * pkg)
if (*file_name == '/') {
file_name++;
}
+ // now we need to remove the trailing '/' in each entry to
+ // be consistent with pkg_write_filelist() that does the
+ // same.
+ int size = strlen(file_name);
+ if (size > 0 && file_name[size-1] == '/')
+ {
+ file_name[size-1] = '\0';
+ }
+
sprintf_alloc(&installed_file_name, "%s%s", pkg->dest->root_dir,
file_name);
} else {
--
2.20.1

Shruthi Ravichandran

unread,
Aug 15, 2022, 12:27:20 PM8/15/22
to opkg-...@googlegroups.com, Shruthi Ravichandran
Multiple packages can install the same directory, or a symlink to a
directory. Ensure that these entries are not removed from the
filelists of packages that are installed following a package that
first installs the directory or a symlink to a directory.
This is later used to ensure that out-of-order package removals do
not result in directory or symlink deletion.

Fixes Bugzilla #10461.

Signed-off-by: Shruthi Ravichandran <shruthi.ra...@ni.com>
---
libopkg/file_util.c | 16 ++++++++++++++++
libopkg/file_util.h | 1 +
libopkg/opkg_install.c | 14 ++++++++++++++
libopkg/pkg_hash.c | 8 +++++++-
4 files changed, 38 insertions(+), 1 deletion(-)

diff --git a/libopkg/file_util.c b/libopkg/file_util.c
index ee9f59d..050e4a7 100644
--- a/libopkg/file_util.c
+++ b/libopkg/file_util.c
@@ -96,6 +96,22 @@ int file_is_symlink(const char *file_name)
return S_ISLNK(st.st_mode);
}

+int file_is_symlink_to_dir(const char *file_name)
+{
+ int is_symlink_to_dir = 0;
+ if(file_is_symlink(file_name)) {
+ char *link_target;
+ struct stat target_stat;
+
+ link_target = realpath(file_name, NULL);
+ if (link_target) {
+ is_symlink_to_dir = (xlstat(link_target, &target_stat) == 0) && S_ISDIR(target_stat.st_mode);
+ free(link_target);
2.20.1

Shruthi Ravichandran

unread,
Aug 15, 2022, 12:27:25 PM8/15/22
to opkg-...@googlegroups.com, Shruthi Ravichandran
Create a dir-hash to track the number of packages installing the
same directory or a symlink to a directory. This directory or
symlink is deleted only when there is no other package using it.
This is in line with how dpkg deletes directories.

Fixes Bugzilla #10461.

Signed-off-by: Shruthi Ravichandran <shruthi.ra...@ni.com>
---
diff --git a/libopkg/pkg.c b/libopkg/pkg.c
index a196714..6b1bd8f 100644
--- a/libopkg/pkg.c
+++ b/libopkg/pkg.c
@@ -1434,6 +1434,16 @@ void pkg_info_preinstall_check(void)
iter = niter, niter = file_list_next(installed_files, iter)) {
file_info_t *installed_file = (file_info_t *)iter->data;
file_hash_set_file_owner(installed_file->path, pkg);
+ /*
+ * Ensure that directories or symlink to directories used
+ * by multiple packages are tracked in the dir_hash.
+ * This is later used in remove operations to determine if
+ * the directory or symlink can be deleted.
+ */
+ if(file_is_dir(installed_file->path) || file_is_symlink_to_dir(installed_file->path))
+ {
+ dir_hash_add_ref_count(installed_file->path);
+ }
}
pkg_free_installed_files(pkg);
}
diff --git a/libopkg/pkg_hash.c b/libopkg/pkg_hash.c
index 1371bb6..3ca1804 100644
--- a/libopkg/pkg_hash.c
+++ b/libopkg/pkg_hash.c
index e9c9fd5..6dda761 100755
--- a/tests/regress/issue13574.py
+++ b/tests/regress/issue13574.py
@@ -48,7 +48,7 @@ if not os.path.exists("%s/lib64/testfile2.txt" % cfg.offline_root):
opk.fail("Package 'a' removed package 'b' file")

if not os.path.exists("%s/lib" % cfg.offline_root):
- opk.fail("Package 'a' incorrectly removed symlink that should belong to Package 'b'")
+ opk.fail("Package 'a' incorrectly removed symlink that is in use by Package 'b'")

opkgcl.remove('b')
if os.path.exists("%s/lib64/testfile2.txt" % cfg.offline_root):
--
2.20.1

Alex Stewart

unread,
Aug 15, 2022, 7:02:31 PM8/15/22
to Shruthi Ravichandran, opkg-...@googlegroups.com
Reply all
Reply to author
Forward
0 new messages