Skip to content

Some enhancements to the zosfile unit#643

Open
ChongZhou-Broadcom wants to merge 1 commit into
v3.x/stagingfrom
zhou/enhancements-zosfile
Open

Some enhancements to the zosfile unit#643
ChongZhou-Broadcom wants to merge 1 commit into
v3.x/stagingfrom
zhou/enhancements-zosfile

Conversation

@ChongZhou-Broadcom

@ChongZhou-Broadcom ChongZhou-Broadcom commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Purpose of the PR

This is an extension (a super set) of the old unmerged PR #633 . The old one was closed.

The previous PR aligned the directoryDeleteRecursive() function with the system command rm -rf with regards to the handling of symbolic links.

After that, I noticed that the directoryCopy() function has the same issue about symbolic links.

The issue can be summarized as follows: when deleting or copying a directory, symbolic links within the source directory should be unlinked or recreated in the target directory, rather than deleting or copying the files or directories to which those links point.

This PR fixes the inconsistant behavior of the previous implementation.

Additionally, it also extracts the directory traversal code into a function shared by all directory operation functions.

Summary of major changes

  • directoryDeleteRecursive() and directoryCopy() no longer follow links, now they only delete or create links;
  • New function directoryListEntries() was added and shared by all directory functions.
  • New function fileReadLink2() was added to implement a convenient and consistent way for checking if a path is a symlink and what the real path is.

Hints for unit tests

  1. The following functions should be tested: directoryDeleteRecursive, directoryCopy, directoryChangeModeRecursive, directoryChangeOwnerRecursive, fileReadLink2, directoryListEntries;
  2. Functions listed in point 1 can be tested in a group in a stable order;
  3. The test requires two valid system users and groups. (user1 from group1 and user2 from group2)
  4. Before all tests, the test framework should create the following directory structure as the test data:
test_data/
test_data/dir1/
test_data/dir1/file1
test_data/dir2/
test_data/dir2/file2
test_data/dir2/file1 --(symlink)--> test_data/dir1/file1
test_data/dir2/dir2.1/
test_data/dir2/dir2.1/file3
test_data/dir2/dir2.1/dir1 --(symlink)--> test_data/dir1/

All files must be in mode 644, all directories must be in mode 755.
All files and directories must owned by user1 and group1.

  1. test 1: directoryListEntries_should_return_expected_entry_list
int rc, rsn;
UnixDirectoryEntries entries;
directoryListEntries("test_data/dir2", &entries, &rc, &rsn);
EXPECT_EQUAL(rc, 0);
EXPECT_EQUAL(rsn, 0);
EXPECT_EQUAL(entries.numEntries, 3);
EXPECT_ARRAY_CONTAINS(entries.entryArray, entries.numEntries, "file1");
EXPECT_ARRAY_CONTAINS(entries.entryArray, entries.numEntries, "file2");
EXPECT_ARRAY_CONTAINS(entries.entryArray, entries.numEntries, "dir3");
  1. test2: fileReadLink2_should_return_expected_type
int rc, rsn;
ReadLinkResult result;
fileReadLink2("test_data", &result, &rc, &rsn);
EXPECT_EQUAL(rc, 0);
EXPECT_EQUAL(rsn, 0);
EXPECT_EQUAL(result.type, RL2_TypeRealDir);
fileReadLink2("test_data/dir1/file1", &result, &rc, &rsn);
EXPECT_EQUAL(rc, 0);
EXPECT_EQUAL(rsn, 0);
EXPECT_EQUAL(result.type, RL2_TypeRealFile);
fileReadLink2("test_data/dir2/file1", &result, &rc, &rsn);
EXPECT_EQUAL(rc, 0);
EXPECT_EQUAL(rsn, 0);
EXPECT_EQUAL(result.type, RL2_TypeSymlink);
EXPECT_EQUAL_STR(result.realPath, "test_data/dir1/file1");
fileReadLink2("test_data/dir2/dir2.1/dir1", &result, &rc, &rsn);
EXPECT_EQUAL(rc, 0);
EXPECT_EQUAL(rsn, 0);
EXPECT_EQUAL(result.type, RL2_TypeSymlink);
EXPECT_EQUAL_STR(result.realPath, "test_data/dir1/");
  1. test3: directoryCopy_should_create_identical_dir3_from_dir2
int rc, rsn;
directoryCopy("test_data/dir2", "test_data/dir3", &rc, &rsn);
EXPECT_EQUAL(rc, 0);
EXPECT_EQUAL(rsn, 0);
// must also check the shape of test_data/dir2 and test_data/dir3, they must be completely idential
  1. test4: directoryChangeModeRecursive_should_set_mode
int rc, rsn;
int mode777 = S_IRWXU2 | S_IRWXG | S_IRWXO;
directoryChangeModeRecursive("test_data/dir3/dir2.1", CHANGE_MODE_RECURSIVE, mode777, &rc, &rsn);
EXPECT_EQUAL(rc, 0);
EXPECT_EQUAL(rsn, 0);
FileInfo info;
fileInfo("test_data/dir3/dir2.1/file3", &info, &rc, &rsn);
EXPECT_EQUAL(rc, 0);
EXPECT_EQUAL(rsn, 0);
EXPECT_EQUAL(fileUnixMode(info), mode);
fileInfo("test_data/dir1", &info, &rc, &rsn);
EXPECT_EQUAL(rc, 0);
EXPECT_EQUAL(rsn, 0);
EXPECT_EQUAL(fileUnixMode(info), mode);
fileInfo("test_data/dir1/file1", &info, &rc, &rsn);
EXPECT_EQUAL(rc, 0);
EXPECT_EQUAL(rsn, 0);
EXPECT_EQUAL(fileUnixMode(info), mode);
  1. test5: directoryChangeModeRecursive_should_change_owner
int user2, group2;
int rc, rsn;
int directoryChangeOwnerRecursive(NULL, 0, "test_data/dir3/dir2.1", user2, group2, TRUE, NULL, &rc, &rsn);
EXPECT_EQUAL(rc, 0);
EXPECT_EQUAL(rsn, 0);
FileInfo info;
fileInfo("test_data/dir3/dir2.1/", &info, &rc, &rsn);
EXPECT_EQUAL(rc, 0);
EXPECT_EQUAL(rsn, 0);
EXPECT_EQUAL(info.ownerUID, user2);
EXPECT_EQUAL(info.ownerGID, group2);
fileInfo("test_data/dir3/dir2.1/file3", &info, &rc, &rsn);
EXPECT_EQUAL(rc, 0);
EXPECT_EQUAL(rsn, 0);
EXPECT_EQUAL(info.ownerUID, user2);
EXPECT_EQUAL(info.ownerGID, group2);
fileInfo("test_data/dir1/", &info, &rc, &rsn);
EXPECT_EQUAL(rc, 0);
EXPECT_EQUAL(rsn, 0);
EXPECT_EQUAL(info.ownerUID, user2);
EXPECT_EQUAL(info.ownerGID, group2);
fileInfo("test_data/dir1/file1", &info, &rc, &rsn);
EXPECT_EQUAL(rc, 0);
EXPECT_EQUAL(rsn, 0);
EXPECT_EQUAL(info.ownerUID, user2);
EXPECT_EQUAL(info.ownerGID, group2);
  1. test6: directoryDelete_should_delete_dir3
int rc, rsn;
directoryDelete("test_data/dir3", &rc, &rsn);
EXPECT_EQUAL(rc, 0);
EXPECT_EQUAL(rsn, 0);
FileInfo info;
fileInfo("test_data/dir3", &info, &rc, &rsn);
EXPECT_EQUAL(rc, ENOENT);
FileInfo info;
fileInfo("test_data/dir1", &info, &rc, &rsn);
EXPECT_EQUAL(rc, 0);
EXPECT_EQUAL(rsn, 0);
fileInfo("test_data/dir1/file1", &info, &rc, &rsn);
EXPECT_EQUAL(rc, 0);
EXPECT_EQUAL(rsn, 0);

@ChongZhou-Broadcom ChongZhou-Broadcom added enhancement New feature or request severity-low A bug that makes the usage of the Zowe less convenient but doesn't impact key use cases priority-low An issue that is recognized by the squad but that is not considered very important labels Jul 18, 2026
- Aligns the handling of symbolic links with system commands
- Extracts the directory traversal code into shared functions

Signed-off-by: ch.zhou <chong.zhou@broadcom.com>
@ChongZhou-Broadcom
ChongZhou-Broadcom force-pushed the zhou/enhancements-zosfile branch from aafcea3 to 61094e5 Compare July 22, 2026 08:21
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
C Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

💡 Need a hand with PR review? Try Gitar by Sonar!

Comment thread c/zosfile.c
}

int fileCreateSymlink(const char *from, const char *to, int *returnCode, int *reasonCode) {
int fromLen = strlen(from);
Comment thread c/zosfile.c

int fileCreateSymlink(const char *from, const char *to, int *returnCode, int *reasonCode) {
int fromLen = strlen(from);
int toLen = strlen(to);
@JoeNemo

JoeNemo commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Can you turn the "hints for testing" into tests that are part of this PR. The scripts should go in a subdir of zowe-common-c/tests that you create and one script should build the directory structure that can reproduce the problem, another can compile a tiny program to run the test. That would allow me show that the bug existed and was cleared by this fix by running the test in a local repo that does NOT have this fix in it yet.

@ChongZhou-Broadcom

Copy link
Copy Markdown
Contributor Author

After seeing your proposal to convert "hints for testing" into actual test cases, I’ve been wondering: since you are already building a ZSS-based regression testing framework, do we still need unit tests?

Assuming for a moment that we do need unit tests, could they also be structured as a framework? Here is the concept:

  • It would be an executable program with a single main entry point (essentially, a program similar to ZSS).
  • It would not be a ZSS server, so it might not require complex configuration or elevated privileges (though apf-auth might still be necessary).
  • Each unit test case would be written in a separate .c unit—containing an extern entry function and several static functions—and compiled into the executable.
  • Each test case would be selectable by a unique name and run independently, with no inter-test dependencies allowed.
  • The framework would also provide a shared utility module accessible to all test units.
  • To keep things simple, it would be compiled and executed solely within the z/OS environment.
  • CMS-related components could be ignored for the time being.
  • Its execution method could mirror that of the regression testing framework.

This is just a concept for now, and I’m not yet certain if implementation is necessary, but I believe it is technically feasible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request priority-low An issue that is recognized by the squad but that is not considered very important severity-low A bug that makes the usage of the Zowe less convenient but doesn't impact key use cases

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

3 participants