@@ -5,7 +5,7 @@ module ferp_dir |
| 5 | 5 | implicit none |
| 6 | 6 | private |
| 7 | 7 | |
| 8 | | - public :: is_directory, is_regular_file, collect_files |
| 8 | + public :: is_directory, is_regular_file, is_symlink, collect_files |
| 9 | 9 | public :: glob_match |
| 10 | 10 | public :: read_patterns_from_file, matches_any_pattern |
| 11 | 11 | |
@@ -89,6 +89,35 @@ contains |
| 89 | 89 | |
| 90 | 90 | end function is_regular_file |
| 91 | 91 | |
| 92 | + function is_symlink(path) result(is_link) |
| 93 | + !> Check if path is a symbolic link using lstat |
| 94 | + character(len=*), intent(in) :: path |
| 95 | + logical :: is_link |
| 96 | + |
| 97 | + character(len=max_path_len+1) :: c_path |
| 98 | + character(len=STAT_BUF_SIZE), target :: statbuf |
| 99 | + integer(c_int) :: istat |
| 100 | + integer :: mode_offset, mode_val |
| 101 | + |
| 102 | + is_link = .false. |
| 103 | + |
| 104 | + c_path = trim(path) // c_null_char |
| 105 | + istat = c_lstat(c_path, c_loc(statbuf)) |
| 106 | + |
| 107 | + if (istat /= 0) return |
| 108 | + |
| 109 | + ! On Linux x86_64, st_mode is at offset 24 (bytes 25-28) |
| 110 | + ! st_mode is typically uint32_t |
| 111 | + mode_offset = 24 |
| 112 | + mode_val = transfer(statbuf(mode_offset+1:mode_offset+4), 0) |
| 113 | + |
| 114 | + ! S_IFLNK = 0120000 (octal) = 40960 (decimal) |
| 115 | + ! The file type is in bits 12-15 of mode |
| 116 | + ! S_IFMT mask = 0170000 (octal) = 61440 |
| 117 | + is_link = iand(mode_val, 61440) == 40960 |
| 118 | + |
| 119 | + end function is_symlink |
| 120 | + |
| 92 | 121 | subroutine collect_files(start_path, file_list, num_files, recursive, & |
| 93 | 122 | follow_links, include_globs, num_include, & |
| 94 | 123 | exclude_globs, num_exclude, exclude_dirs, num_exclude_dirs) |
@@ -159,6 +188,9 @@ contains |
| 159 | 188 | entry_path = trim(current_dir) // '/' // trim(entry_name) |
| 160 | 189 | end if |
| 161 | 190 | |
| 191 | + ! Skip symlinks if not following them (like grep -r vs grep -R) |
| 192 | + if (.not. follow_links .and. is_symlink(entry_path)) cycle |
| 193 | + |
| 162 | 194 | ! Check if it's a directory |
| 163 | 195 | if (is_directory(entry_path)) then |
| 164 | 196 | if (recursive) then |