dir.c
1 #include <dirent.h> 2 #include <fcntl.h> 3 #include <stdio.h> 4 #include <unistd.h> 5 6 #include <darwintest.h> 7 #include <darwintest_utils.h> 8 9 T_DECL(seekdir_basic, "seekdir") 10 { 11 const char *path = dt_tmpdir(); 12 // make sure there are a couple of entries in the dir aside from . and .. 13 int fd = open(path, O_RDONLY | O_DIRECTORY); 14 openat(fd, "a", O_CREAT | O_WRONLY, 0600); 15 openat(fd, "b", O_CREAT | O_WRONLY, 0600); 16 openat(fd, "c", O_CREAT | O_WRONLY, 0600); 17 18 DIR *dirp = fdopendir(fd); 19 struct dirent *entry = NULL; 20 21 T_ASSERT_NOTNULL(dirp, NULL); 22 23 T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); // . 24 T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); // .. 25 26 // we can get any entry -- no ordering 27 T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); 28 // remember position for the second entry 29 long second_pos = telldir(dirp); 30 // read the second entry 31 T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); 32 char *second_name = strdup(entry->d_name); 33 T_ASSERT_NOTNULL(second_name, NULL); 34 // read the third entry 35 T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); 36 37 // go back to the second entry and read it 38 seekdir(dirp, second_pos); 39 T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); 40 41 // make sure the name matches the old copy 42 T_ASSERT_EQ_STR(second_name, entry->d_name, NULL); 43 44 // return to 2nd once again, reinitializing second_pos and re-reading 45 seekdir(dirp, second_pos); 46 second_pos = telldir(dirp); 47 T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); 48 49 // make sure the name matches the old copy 50 T_ASSERT_EQ_STR(second_name, entry->d_name, NULL); 51 52 // verify that last pos 53 seekdir(dirp, second_pos); 54 T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); 55 T_ASSERT_EQ_STR(second_name, entry->d_name, NULL); 56 57 free(second_name); 58 T_ASSERT_POSIX_ZERO(closedir(dirp), NULL); 59 } 60 61 T_DECL(readdir, "readdir") 62 { 63 const char *path = dt_tmpdir(); 64 int fd = open(path, O_RDONLY | O_DIRECTORY); 65 openat(fd, "foobarbaz", O_CREAT | O_WRONLY, 0600); 66 67 DIR *dirp = fdopendir(fd); 68 T_ASSERT_NOTNULL(dirp, NULL); 69 70 struct dirent *entry = NULL; 71 while ((entry = readdir(dirp)) != NULL) { 72 if (strcmp(entry->d_name, "foobarbaz")) { 73 break; 74 } 75 } 76 77 T_ASSERT_NOTNULL(entry, "found the entry"); 78 79 T_ASSERT_POSIX_ZERO(closedir(dirp), NULL); 80 } 81 82 T_DECL(tell_seek_tell, "tell-seek-tell returns the same location") 83 { 84 // http://pubs.opengroup.org/onlinepubs/009695399/functions/telldir.html 85 // If the most recent operation on the directory stream was a seekdir(), 86 // the directory position returned from the telldir() shall be the same as 87 // that supplied as a loc argument for seekdir(). 88 89 const char *path = dt_tmpdir(); 90 // make sure there are a couple of entries in the dir aside from . and .. 91 { 92 int fd = open(path, O_RDONLY | O_DIRECTORY); 93 openat(fd, "a", O_CREAT | O_WRONLY, 0600); 94 openat(fd, "b", O_CREAT | O_WRONLY, 0600); 95 openat(fd, "c", O_CREAT | O_WRONLY, 0600); 96 close(fd); 97 } 98 99 DIR *dirp = opendir(path); 100 T_ASSERT_NOTNULL(dirp, NULL); 101 struct dirent *entry = NULL; 102 103 T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); 104 T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); 105 long pos1 = telldir(dirp); 106 T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); 107 T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); 108 seekdir(dirp, pos1); 109 long pos2 = telldir(dirp); 110 111 T_ASSERT_EQ(pos1, pos2, NULL); 112 113 T_ASSERT_POSIX_ZERO(closedir(dirp), NULL); 114 } 115 116 T_DECL(rewinddir, "rewinddir") 117 { 118 const char *path = dt_tmpdir(); 119 // make sure there are a couple of entries in the dir aside from . and .. 120 { 121 int fd = open(path, O_RDONLY | O_DIRECTORY); 122 openat(fd, "a", O_CREAT | O_WRONLY, 0600); 123 openat(fd, "b", O_CREAT | O_WRONLY, 0600); 124 openat(fd, "c", O_CREAT | O_WRONLY, 0600); 125 close(fd); 126 } 127 128 DIR *dirp = opendir(path); 129 T_ASSERT_NOTNULL(dirp, NULL); 130 struct dirent *entry = NULL; 131 132 T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); 133 T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); 134 T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); 135 char *third_name = strdup(entry->d_name); 136 137 rewinddir(dirp); 138 139 T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); 140 T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); 141 T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); 142 143 T_ASSERT_EQ_STR(third_name, entry->d_name, NULL); 144 145 free(third_name); 146 T_ASSERT_POSIX_ZERO(closedir(dirp), NULL); 147 } 148 149 150 T_DECL(rewinddir_dup, "rewinddir dup") 151 { 152 // An older implementation of rewinddir failed to seek the fd which was 153 // passed to fdopendir() 154 155 const char *path = dt_tmpdir(); 156 // make sure there are a couple of entries in the dir aside from . and .. 157 int fd = open(path, O_RDONLY | O_DIRECTORY); 158 openat(fd, "a", O_CREAT | O_WRONLY, 0600); 159 openat(fd, "b", O_CREAT | O_WRONLY, 0600); 160 openat(fd, "c", O_CREAT | O_WRONLY, 0600); 161 162 // prep an fd with a non-zero seek 163 DIR *dirp = fdopendir(fd); 164 T_ASSERT_NOTNULL(dirp, NULL); 165 struct dirent *entry = NULL; 166 167 T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); 168 T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); 169 T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); 170 171 // remember the entry name and dup the fd 172 char *third_name = strdup(entry->d_name); 173 int fd2 = dup(fd); 174 175 T_ASSERT_POSIX_ZERO(closedir(dirp), NULL); 176 177 dirp = fdopendir(fd2); 178 // rewind back to 0 179 rewinddir(dirp); 180 181 T_ASSERT_NOTNULL(dirp, NULL); 182 T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); 183 T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); 184 T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); 185 186 T_ASSERT_EQ_STR(third_name, entry->d_name, NULL); 187 188 free(third_name); 189 T_ASSERT_POSIX_ZERO(closedir(dirp), NULL); 190 } 191 192 static int 193 _select_abc(const struct dirent *entry) 194 { 195 return strcmp(entry->d_name, "a") == 0 || 196 strcmp(entry->d_name, "b") == 0 || 197 strcmp(entry->d_name, "c") == 0; 198 } 199 200 T_DECL(scandir, "scandir") 201 { 202 const char *path = dt_tmpdir(); 203 { 204 int fd = open(path, O_RDONLY | O_DIRECTORY); 205 openat(fd, "a", O_CREAT | O_WRONLY, 0600); 206 openat(fd, "b", O_CREAT | O_WRONLY, 0600); 207 openat(fd, "c", O_CREAT | O_WRONLY, 0600); 208 close(fd); 209 } 210 211 struct dirent **entries = NULL; 212 int found = scandir(path, &entries, _select_abc, alphasort); 213 214 T_ASSERT_EQ(found, 3, NULL); 215 216 T_ASSERT_EQ_STR(entries[0]->d_name, "a", NULL); 217 T_ASSERT_EQ_STR(entries[1]->d_name, "b", NULL); 218 T_ASSERT_EQ_STR(entries[2]->d_name, "c", NULL); 219 220 free(entries[0]); 221 free(entries[1]); 222 free(entries[2]); 223 free(entries); 224 } 225 226 T_DECL(scandir_b, "scandir_b") 227 { 228 const char *path = dt_tmpdir(); 229 { 230 int fd = open(path, O_RDONLY | O_DIRECTORY); 231 openat(fd, "a", O_CREAT | O_WRONLY, 0600); 232 openat(fd, "b", O_CREAT | O_WRONLY, 0600); 233 openat(fd, "c", O_CREAT | O_WRONLY, 0600); 234 close(fd); 235 } 236 237 const struct dirent **entries = NULL; 238 int found = scandir_b(path, &entries, 239 ^(const struct dirent *entry) { 240 return strcmp(entry->d_name, "a") == 0 || 241 strcmp(entry->d_name, "b") == 0 || 242 strcmp(entry->d_name, "c") == 0; 243 }, 244 ^(const struct dirent **d1, const struct dirent **d2) { 245 return strcoll((*d1)->d_name, (*d2)->d_name); 246 }); 247 248 T_ASSERT_EQ(found, 3, NULL); 249 250 T_ASSERT_EQ_STR(entries[0]->d_name, "a", NULL); 251 T_ASSERT_EQ_STR(entries[1]->d_name, "b", NULL); 252 T_ASSERT_EQ_STR(entries[2]->d_name, "c", NULL); 253 254 free(entries[0]); 255 free(entries[1]); 256 free(entries[2]); 257 free(entries); 258 }