Skip to content

Commit

Permalink
Merge branch 'cxxsucks-master'
Browse files Browse the repository at this point in the history
  • Loading branch information
tronkko committed May 21, 2023
2 parents c00ec6d + 77d1445 commit ab35ddf
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 33 deletions.
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/.vscode
/CMakeCache.txt
/CMakeFiles
/CTestTestfile.cmake
Expand All @@ -21,7 +22,13 @@
/t-strverscmp
/t-telldir
/t-utf8
/t-symlink
/updatedb
/build
/*.filters
/*.vcxproj
/*.dir

# Some filesystems do not support symlinks, therefore
# it is a bad idea to include symlinks in a git source tree
/tests/1/link_*
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,5 @@ if(DIRENT_BUILD_TESTS)
add_test_executable(t-telldir tests/t-telldir.c)
add_test_executable(t-strverscmp tests/t-strverscmp.c)
add_test_executable(t-utf8 tests/t-utf8.c)
add_test_executable(t-symlink tests/t-symlink.c)
endif(DIRENT_BUILD_TESTS)
20 changes: 18 additions & 2 deletions include/dirent.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,13 @@
# define S_IFBLK 0
#endif

/* Link */
/* Link
* S_IFLNK is not defined in Windows's `stat.h`, so we define it here.
* In Windows's `stat.h`, file type macros (S_IFDIR, S_IFREG...) are defined
* bitmasks, except that they are NOT on Linux. So long as S_* & ~S_IFMT == 0,
* as is the case in Linux, the S_IS*(mode) macros works fine. */
#if !defined(S_IFLNK)
# define S_IFLNK 0
# define S_IFLNK (S_IFMT & 0XCCCCCCCC)
#endif

/* Socket */
Expand Down Expand Up @@ -527,6 +531,12 @@ _wreaddir_r(
DWORD attr = datap->dwFileAttributes;
if ((attr & FILE_ATTRIBUTE_DEVICE) != 0)
entry->d_type = DT_CHR;
#ifdef FILE_ATTRIBUTE_REPARSE_POINT
/* A Windows link to directory is both symlink (reparse point) and
* directory. Symlink takes precedence, just as Linux does. */
else if ((attr & FILE_ATTRIBUTE_REPARSE_POINT))
entry->d_type = DT_LNK;
#endif
else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0)
entry->d_type = DT_DIR;
else
Expand Down Expand Up @@ -787,6 +797,12 @@ readdir_r(
DWORD attr = datap->dwFileAttributes;
if ((attr & FILE_ATTRIBUTE_DEVICE) != 0)
entry->d_type = DT_CHR;
#ifdef FILE_ATTRIBUTE_REPARSE_POINT
/* A Windows link to directory is both symlink (reparse point) and
* directory. Symlink takes precedence, just as Linux does. */
else if ((attr & FILE_ATTRIBUTE_REPARSE_POINT))
entry->d_type = DT_LNK;
#endif
else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0)
entry->d_type = DT_DIR;
else
Expand Down
2 changes: 1 addition & 1 deletion tests/1/dir/readme.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
This file ensures that the directory dir will be created accordingly when
you unzip dirent to your computer. The directory itself is needed by the
test program t-dirent.
test program t-dirent, t-cplusplus and t-symlink.
8 changes: 6 additions & 2 deletions tests/t-cplusplus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,12 @@ test_retrieval(void)
assert(_D_ALLOC_NAMLEN(ent) > 3);
#endif
found += 8;
} else {
/* Other file */
#ifdef _DIRENT_HAVE_D_TYPE
} else if (ent->d_type != DT_LNK || ent->d_name[0] != 'l') {
#else
} else if (ent->d_name[0] != 'l') {
#endif
/* Other file. Symlinks created by t-symlink are ignored. */
cerr << "Unexpected file " << ent->d_name << endl;
abort();
}
Expand Down
80 changes: 52 additions & 28 deletions tests/t-dirent.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,12 @@ test_retrieval(void)
assert(_D_ALLOC_NAMLEN(ent) > 3);
#endif
found += 8;
} else {
/* Other file */
#ifdef _DIRENT_HAVE_D_TYPE
} else if (ent->d_type != DT_LNK || ent->d_name[0] != 'l') {
#else
} else if (ent->d_name[0] != 'l') {
#endif
/* Other file. Symlinks created by t-symlink are ignored. */
fprintf(stderr, "Unexpected file %s\n", ent->d_name);
abort();
}
Expand Down Expand Up @@ -215,8 +219,12 @@ test_rewind(void)
} else if (strcmp(ent->d_name, "dir") == 0) {
/* Just a directory */
found += 8;
} else {
/* Other file */
#ifdef _DIRENT_HAVE_D_TYPE
} else if (ent->d_type != DT_LNK || ent->d_name[0] != 'l') {
#else
} else if (ent->d_name[0] != 'l') {
#endif
/* Other file. Symlinks created by t-symlink are ignored. */
fprintf(stderr, "Unexpected file %s\n", ent->d_name);
abort();
}
Expand Down Expand Up @@ -244,8 +252,12 @@ test_rewind(void)
} else if (strcmp(ent->d_name, "dir") == 0) {
/* Just a directory */
found += 8;
} else {
/* Other file */
#ifdef _DIRENT_HAVE_D_TYPE
} else if (ent->d_type != DT_LNK || ent->d_name[0] != 'l') {
#else
} else if (ent->d_name[0] != 'l') {
#endif
/* Other file. Symlinks created by t-symlink are ignored. */
fprintf(stderr, "Unexpected file %s\n", ent->d_name);
abort();
}
Expand Down Expand Up @@ -282,8 +294,12 @@ test_chdir(void)
} else if (strcmp(ent->d_name, "dir") == 0) {
/* Just a directory */
found += 8;
} else {
/* Other file */
#ifdef _DIRENT_HAVE_D_TYPE
} else if (ent->d_type != DT_LNK || ent->d_name[0] != 'l') {
#else
} else if (ent->d_name[0] != 'l') {
#endif
/* Other file. Symlinks created by t-symlink are ignored. */
fprintf(stderr, "Unexpected file %s\n", ent->d_name);
abort();
}
Expand Down Expand Up @@ -316,8 +332,12 @@ test_chdir(void)
} else if (strcmp(ent->d_name, "dir") == 0) {
/* Just a directory */
found += 8;
} else {
/* Other file */
#ifdef _DIRENT_HAVE_D_TYPE
} else if (ent->d_type != DT_LNK || ent->d_name[0] != 'l') {
#else
} else if (ent->d_name[0] != 'l') {
#endif
/* Other file. Symlinks created by t-symlink are ignored. */
fprintf(stderr, "Unexpected file %s\n", ent->d_name);
abort();
}
Expand Down Expand Up @@ -414,17 +434,15 @@ test_readdir(void)
struct dirent *entry;
size_t i = 0;
size_t n = 0;
while (readdir_r(dir, &ent[n], &entry) == /*OK*/0 && entry != 0) {
while (n < 10 && readdir_r(dir, &ent[n], &entry) == /*OK*/0 && entry != NULL)
n++;
assert(n <= 4);
}

/* Make sure that we got all the files from directory */
assert(n == 4);
/* Make sure that we got all the files from directory,
* with or without the two symlinks created by `t-symlink` */
assert(n >= 4 && n <= 6);

/* Check entries in memory */
int found = 0;
for (i = 0; i < 4; i++) {
for (i = 0; i < n; i++) {
entry = &ent[i];

/* Check each file */
Expand Down Expand Up @@ -488,8 +506,12 @@ test_readdir(void)
assert(_D_ALLOC_NAMLEN(entry) > 3);
#endif
found += 8;
} else {
/* Other file */
#ifdef _DIRENT_HAVE_D_TYPE
} else if (entry->d_type != DT_LNK || entry->d_name[0] != 'l') {
#else
} else if (entry->d_name[0] != 'l') {
#endif
/* Other file. Symlinks created by t-symlink are ignored. */
fprintf(stderr, "Unexpected file %s\n", entry->d_name);
abort();
}
Expand Down Expand Up @@ -519,17 +541,15 @@ test_wreaddir(void)
struct _wdirent *entry;
size_t i = 0;
size_t n = 0;
while (_wreaddir_r(dir, &ent[n], &entry) == /*OK*/0 && entry != 0) {
while (n < 10 && _wreaddir_r(dir, &ent[n], &entry) == /*OK*/0 && entry != NULL)
n++;
assert(n <= 4);
}

/* Make sure that we got all the files from directory */
assert(n == 4);
/* Make sure that we got all the files from directory,
* with or without the two symlinks created by `t-symlink` */
assert(n >= 4 && n <= 6);

/* Check entries in memory */
int found = 0;
for (i = 0; i < 4; i++) {
for (i = 0; i < n; i++) {
entry = &ent[i];

/* Check each file */
Expand Down Expand Up @@ -593,8 +613,12 @@ test_wreaddir(void)
assert(_D_ALLOC_NAMLEN(entry) > 3);
#endif
found += 8;
} else {
/* Other file */
#ifdef _DIRENT_HAVE_D_TYPE
} else if (entry->d_type != DT_LNK || entry->d_name[0] != 'l') {
#else
} else if (entry->d_name[0] != 'l') {
#endif
/* Other file. Symlinks created by t-symlink are ignored. */
fprintf(stderr, "Unexpected file\n");
abort();
}
Expand Down
53 changes: 53 additions & 0 deletions tests/t-symlink.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* A test program to make sure that dirent can identify symlinks.
*
* Copyright (C) 1998-2019 Toni Ronkko
* This file is part of dirent. Dirent may be freely distributed
* under the MIT license. For all details and documentation, see
* https://github.com/tronkko/dirent
*/

#include <dirent.h>
#include <assert.h>
#include <stdio.h>

int countSymlink(const char* dirName) {
DIR* dir = opendir(dirName);
if (!dir) {
fprintf(stderr, "Open directory error: %d", GetLastError());
return 1;
}

struct dirent *ent;
int found = 0;
/* Read the directory and count symlinks */
while ((ent = readdir(dir)) != NULL)
found += (ent->d_type == DT_LNK);
return found;
}

int main(int argc, char** argv) {
/* -s makes link creation failures fatal. Symlink creation requires
* root access, unless a so-called "Developer Mode" is on, therefore
* by default creation failure is not a fatal error. */
int failRet = (argc >= 2 && strcmp(argv[1], "-s") == 0) ? 127 : 0;
DWORD flag = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;

/* Chances are that the links are created in previous runs. */
if (countSymlink("tests\\1") >= 2)
return 0;

/* Create symlinks */
if (!CreateSymbolicLinkA("tests\\1\\link_file", ".\\file", flag)) {
fprintf(stderr, "Create file symlink error: %d", GetLastError());
return failRet;
}
flag |= SYMBOLIC_LINK_FLAG_DIRECTORY;
if (!CreateSymbolicLinkA("tests\\1\\link_dir", ".\\dir", flag)) {
fprintf(stderr, "Create file symlink error: %d", GetLastError());
return failRet;
}

assert(countSymlink("tests\\1") >= 2);
return 0;
}

0 comments on commit ab35ddf

Please sign in to comment.