| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * Common code for working with directory trees. | ||
| 3 | * Copyright © 2007-2026, albinoloverats ~ Software Development | ||
| 4 | * email: stegfs@albinoloverats.net | ||
| 5 | * | ||
| 6 | * This program is free software: you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation, either version 3 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | * | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <stdio.h> | ||
| 22 | #include <stdlib.h> | ||
| 23 | #include <string.h> | ||
| 24 | |||
| 25 | #include <fcntl.h> | ||
| 26 | #include <dirent.h> | ||
| 27 | #include <sys/stat.h> | ||
| 28 | #include <unistd.h> | ||
| 29 | |||
| 30 | #include "non-gnu.h" | ||
| 31 | #include "common.h" | ||
| 32 | #include "error.h" | ||
| 33 | #include "mem.h" | ||
| 34 | #include "dir.h" | ||
| 35 | #include "list.h" | ||
| 36 | |||
| 37 | 431 | extern char *dir_get_name_aux(const char * const path, const char ext) | |
| 38 | { | ||
| 39 | 431 | const char *file = strrchr(path, DIR_SEPARATOR_CHAR); | |
| 40 |
2/2✓ Branch 0 taken 429 times.
✓ Branch 1 taken 2 times.
|
431 | if (file) |
| 41 | 429 | file++; | |
| 42 | else | ||
| 43 | 2 | file = path; | |
| 44 | 431 | const char *pass = strrchr(path, ext); | |
| 45 |
2/2✓ Branch 0 taken 266 times.
✓ Branch 1 taken 165 times.
|
431 | if (!pass) |
| 46 | 266 | pass = strchr(file, '\0'); | |
| 47 | 431 | return m_strndup(file, pass - file); | |
| 48 | } | ||
| 49 | |||
| 50 | 966 | extern uint16_t dir_get_deep(const char * const path) | |
| 51 | { | ||
| 52 | 1 | uint16_t d = 0; | |
| 53 | 1 | char *ptr = (char *)path; | |
| 54 |
2/2✓ Branch 0 taken 1010 times.
✓ Branch 1 taken 966 times.
|
1976 | while ((ptr = strchr(ptr, DIR_SEPARATOR_CHAR))) |
| 55 | { | ||
| 56 | 1010 | d++; | |
| 57 | 1010 | ptr++; | |
| 58 | } | ||
| 59 | 966 | return d; | |
| 60 | } | ||
| 61 | |||
| 62 | 45 | extern char *dir_get_part(const char * const path, const uint16_t index) | |
| 63 | { | ||
| 64 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 44 times.
|
45 | if (!index) |
| 65 | 1 | return m_strdup(DIR_SEPARATOR); | |
| 66 | 2 | char *ptr = (char *)path; | |
| 67 |
2/2✓ Branch 0 taken 58 times.
✓ Branch 1 taken 43 times.
|
101 | for (uint16_t i = 0; i < index; i++) |
| 68 | { | ||
| 69 | 58 | char *separator = strchr(ptr, DIR_SEPARATOR_CHAR); | |
| 70 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 57 times.
|
58 | if (!separator) |
| 71 | { | ||
| 72 | 1 | ptr += strlen(ptr); | |
| 73 | 1 | break; | |
| 74 | } | ||
| 75 | 57 | ptr = separator + 1; | |
| 76 | } | ||
| 77 | 44 | return m_strndup(ptr, strchrnul(ptr, DIR_SEPARATOR_CHAR) - ptr); | |
| 78 | } | ||
| 79 | |||
| 80 | 102 | extern char *dir_get_pass(const char * const restrict path) | |
| 81 | { | ||
| 82 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 101 times.
|
102 | if (!strrchr(path, ':')) |
| 83 | 1 | return m_strdup(""); | |
| 84 | 101 | return m_strdup(strrchr(path, ':') + 1); | |
| 85 | } | ||
| 86 | |||
| 87 | 47 | extern char *dir_get_path(const char * const restrict path) | |
| 88 | { | ||
| 89 | 47 | const char *s = strrchr(path, DIR_SEPARATOR_CHAR); | |
| 90 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 46 times.
|
47 | if (!s) |
| 91 | 1 | return m_strdup(""); | |
| 92 | 46 | char *p = strndup(path, s - path); | |
| 93 |
2/2✓ Branch 0 taken 40 times.
✓ Branch 1 taken 6 times.
|
46 | if (strlen(p)) |
| 94 | 1 | return p; | |
| 95 | 40 | free(p); | |
| 96 | 40 | return m_strdup(DIR_SEPARATOR); | |
| 97 | } | ||
| 98 | |||
| 99 | /* | ||
| 100 | * Taken from http://nion.modprobe.de/tmp/mkdir.c | ||
| 101 | */ | ||
| 102 | 3 | extern void dir_mk_recursive(const char *path, mode_t mode) | |
| 103 | { | ||
| 104 | #ifdef _WIN32 | ||
| 105 | (void)mode; | ||
| 106 | #endif | ||
| 107 | 3 | char *opath = m_strdup(path); | |
| 108 | 3 | size_t len = strlen(opath); | |
| 109 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
|
3 | if (!len) |
| 110 | { | ||
| 111 | 1 | free(opath); | |
| 112 | 1 | return; | |
| 113 | } | ||
| 114 |
3/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
|
2 | if (len > 1 && opath[len - 1] == '/') |
| 115 | 1 | opath[len - 1] = '\0'; | |
| 116 |
2/2✓ Branch 0 taken 54 times.
✓ Branch 1 taken 2 times.
|
56 | for (char *p = opath; *p; p++) |
| 117 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 46 times.
|
54 | if (*p == '/') |
| 118 | { | ||
| 119 | 8 | *p = '\0'; | |
| 120 |
2/2✓ Branch 1 taken 3 times.
✓ Branch 2 taken 5 times.
|
8 | if (access(opath, F_OK)) |
| 121 | 3 | mkdir(opath, mode); | |
| 122 | 8 | *p = '/'; | |
| 123 | } | ||
| 124 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
|
2 | if (access(opath, F_OK)) /* if path is not terminated with / */ |
| 125 | 1 | mkdir(opath, mode); | |
| 126 | 2 | free(opath); | |
| 127 | 2 | return; | |
| 128 | } | ||
| 129 | |||
| 130 | 33 | static void get_tree(list_t l, const char *path, dir_type_e type) | |
| 131 | { | ||
| 132 |
7/8✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 98 times.
✓ Branch 4 taken 33 times.
✓ Branch 5 taken 33 times.
✓ Branch 6 taken 65 times.
✓ Branch 8 taken 131 times.
✓ Branch 9 taken 33 times.
|
164 | DIR_SCAN_TOP; |
| 133 | |||
| 134 | 65 | bool add = false; | |
| 135 | 65 | bool dir = false; | |
| 136 | /* | ||
| 137 | * eps[i]->d_type doesn't always give a proper | ||
| 138 | * answer, so we've gotta stat | ||
| 139 | */ | ||
| 140 | struct stat s; | ||
| 141 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 65 times.
|
65 | if (lstat(file, &s)) |
| 142 | { | ||
| 143 | ✗ | free(file); | |
| 144 | ✗ | continue; | |
| 145 | } | ||
| 146 |
6/8✓ Branch 0 taken 24 times.
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 13 times.
✓ Branch 5 taken 7 times.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
|
65 | switch (s.st_mode & S_IFMT) |
| 147 | { | ||
| 148 | 24 | case S_IFDIR: | |
| 149 | 24 | add = type & DIR_FOLDER; | |
| 150 | 24 | dir = true; | |
| 151 | 24 | break; | |
| 152 | 7 | case S_IFCHR: | |
| 153 | 7 | add = type & DIR_CHAR; | |
| 154 | 7 | break; | |
| 155 | ✗ | case S_IFBLK: | |
| 156 | ✗ | add = type & DIR_BLOCK; | |
| 157 | ✗ | break; | |
| 158 | 7 | case S_IFREG: | |
| 159 | 7 | add = type & DIR_FILE; | |
| 160 | 7 | break; | |
| 161 | #ifndef _WIN32 | ||
| 162 | 13 | case S_IFLNK: | |
| 163 | 13 | add = type & DIR_LINK; | |
| 164 | 13 | break; | |
| 165 | 7 | case S_IFSOCK: | |
| 166 | 7 | add = type & DIR_SOCKET; | |
| 167 | 7 | break; | |
| 168 | #endif | ||
| 169 | 7 | case S_IFIFO: | |
| 170 | 7 | add = type & DIR_PIPE; | |
| 171 | 7 | break; | |
| 172 | } | ||
| 173 |
2/2✓ Branch 0 taken 21 times.
✓ Branch 1 taken 44 times.
|
65 | if (add) |
| 174 | { | ||
| 175 | 21 | char *f = m_strdup(file); | |
| 176 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
|
21 | if (!list_add(l, f)) |
| 177 | ✗ | free(f); | |
| 178 | } | ||
| 179 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 41 times.
|
65 | if (dir) |
| 180 | 24 | get_tree(l, file, type); | |
| 181 | |||
| 182 |
2/2✓ Branch 0 taken 131 times.
✓ Branch 1 taken 33 times.
|
229 | DIR_SCAN_END; |
| 183 | |||
| 184 | 33 | return; | |
| 185 | } | ||
| 186 | |||
| 187 | 9 | extern list_t dir_get_tree(const char *path, dir_type_e type) | |
| 188 | { | ||
| 189 | 9 | list_t l = list_string(); | |
| 190 | 9 | get_tree(l, path, type); | |
| 191 | 9 | return l; | |
| 192 | } | ||
| 193 |