1 /* Copyright (C) 1991,92,93,94,95,96,97,98,99,2004,2005 Free Software 2 Foundation, Inc. 3 This file is part of the GNU C Library. 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 2, or (at your option) 8 any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License along 16 with this program; if not, write to the Free Software Foundation, 17 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ 18 19 #ifdef HAVE_CONFIG_H 20 # include <config.h> 21 #endif 22 23 #if !_LIBC 24 # include "getcwd.h" 25 #endif 26 27 #include <errno.h> 28 #include <sys/types.h> 29 #include <sys/stat.h> 30 #include <stdbool.h> 31 #include <stddef.h> 32 33 #include <fcntl.h> /* For AT_FDCWD on Solaris 9. */ 34 35 #ifndef __set_errno 36 # define __set_errno(val) (errno = (val)) 37 #endif 38 39 #if HAVE_DIRENT_H || _LIBC 40 # include <dirent.h> 41 # ifndef _D_EXACT_NAMLEN 42 # define _D_EXACT_NAMLEN(d) strlen ((d)->d_name) 43 # endif 44 #else 45 # define dirent direct 46 # if HAVE_SYS_NDIR_H 47 # include <sys/ndir.h> 48 # endif 49 # if HAVE_SYS_DIR_H 50 # include <sys/dir.h> 51 # endif 52 # if HAVE_NDIR_H 53 # include <ndir.h> 54 # endif 55 #endif 56 #ifndef _D_EXACT_NAMLEN 57 # define _D_EXACT_NAMLEN(d) ((d)->d_namlen) 58 #endif 59 #ifndef _D_ALLOC_NAMLEN 60 # define _D_ALLOC_NAMLEN(d) (_D_EXACT_NAMLEN (d) + 1) 61 #endif 62 63 #if HAVE_UNISTD_H || _LIBC 64 # include <unistd.h> 65 #endif 66 67 #include <stdlib.h> 68 #include <string.h> 69 70 #if _LIBC 71 # ifndef mempcpy 72 # define mempcpy __mempcpy 73 # endif 74 #else 75 # include "mempcpy.h" 76 #endif 77 78 #include <limits.h> 79 80 #ifdef ENAMETOOLONG 81 # define is_ENAMETOOLONG(x) ((x) == ENAMETOOLONG) 82 #else 83 # define is_ENAMETOOLONG(x) 0 84 #endif 85 86 #ifndef MAX 87 # define MAX(a, b) ((a) < (b) ? (b) : (a)) 88 #endif 89 #ifndef MIN 90 # define MIN(a, b) ((a) < (b) ? (a) : (b)) 91 #endif 92 93 #ifndef PATH_MAX 94 # ifdef MAXPATHLEN 95 # define PATH_MAX MAXPATHLEN 96 # else 97 # define PATH_MAX 1024 98 # endif 99 #endif 100 101 #if D_INO_IN_DIRENT 102 # define MATCHING_INO(dp, ino) ((dp)->d_ino == (ino)) 103 #else 104 # define MATCHING_INO(dp, ino) true 105 #endif 106 107 #if !_LIBC 108 # define __getcwd getcwd 109 # define __lstat lstat 110 # define __closedir closedir 111 # define __opendir opendir 112 # define __readdir readdir 113 #endif 114 115 /* Get the name of the current working directory, and put it in SIZE 116 bytes of BUF. Returns NULL if the directory couldn't be determined or 117 SIZE was too small. If successful, returns BUF. In GNU, if BUF is 118 NULL, an array is allocated with `malloc'; the array is SIZE bytes long, 119 unless SIZE == 0, in which case it is as big as necessary. */ 120 121 char * 122 __getcwd (char *buf, size_t size) 123 { 124 /* Lengths of big file name components and entire file names, and a 125 deep level of file name nesting. These numbers are not upper 126 bounds; they are merely large values suitable for initial 127 allocations, designed to be large enough for most real-world 128 uses. */ 129 enum 130 { 131 BIG_FILE_NAME_COMPONENT_LENGTH = 255, 132 BIG_FILE_NAME_LENGTH = MIN (4095, PATH_MAX - 1), 133 DEEP_NESTING = 100 134 }; 135 136 #ifdef AT_FDCWD 137 int fd = AT_FDCWD; 138 bool fd_needs_closing = false; 139 #else 140 char dots[DEEP_NESTING * sizeof ".." + BIG_FILE_NAME_COMPONENT_LENGTH + 1]; 141 char *dotlist = dots; 142 size_t dotsize = sizeof dots; 143 size_t dotlen = 0; 144 #endif 145 DIR *dirstream = NULL; 146 dev_t rootdev, thisdev; 147 ino_t rootino, thisino; 148 char *dir; 149 register char *dirp; 150 struct stat st; 151 size_t allocated = size; 152 size_t used; 153 154 #if HAVE_PARTLY_WORKING_GETCWD && !defined AT_FDCWD 155 /* The system getcwd works, except it sometimes fails when it 156 shouldn't, setting errno to ERANGE, ENAMETOOLONG, or ENOENT. If 157 AT_FDCWD is not defined, the algorithm below is O(N**2) and this 158 is much slower than the system getcwd (at least on GNU/Linux). 159 So trust the system getcwd's results unless they look 160 suspicious. */ 161 # undef getcwd 162 dir = getcwd (buf, size); 163 if (dir || (errno != ERANGE && !is_ENAMETOOLONG (errno) && errno != ENOENT)) 164 return dir; 165 #endif 166 167 if (size == 0) 168 { 169 if (buf != NULL) 170 { 171 __set_errno (EINVAL); 172 return NULL; 173 } 174 175 allocated = BIG_FILE_NAME_LENGTH + 1; 176 } 177 178 if (buf == NULL) 179 { 180 dir = malloc (allocated); 181 if (dir == NULL) 182 return NULL; 183 } 184 else 185 dir = buf; 186 187 dirp = dir + allocated; 188 *--dirp = '\0'; 189 190 if (__lstat (".", &st) < 0) 191 goto lose; 192 thisdev = st.st_dev; 193 thisino = st.st_ino; 194 195 if (__lstat ("/", &st) < 0) 196 goto lose; 197 rootdev = st.st_dev; 198 rootino = st.st_ino; 199 200 while (!(thisdev == rootdev && thisino == rootino)) 201 { 202 struct dirent *d; 203 dev_t dotdev; 204 ino_t dotino; 205 bool mount_point; 206 int parent_status; 207 208 /* Look at the parent directory. */ 209 #ifdef AT_FDCWD 210 fd = openat (fd, "..", O_RDONLY); 211 if (fd < 0) 212 goto lose; 213 fd_needs_closing = true; 214 parent_status = fstat (fd, &st); 215 #else 216 dotlist[dotlen++] = '.'; 217 dotlist[dotlen++] = '.'; 218 dotlist[dotlen] = '\0'; 219 parent_status = __lstat (dotlist, &st); 220 #endif 221 if (parent_status != 0) 222 goto lose; 223 224 if (dirstream && __closedir (dirstream) != 0) 225 { 226 dirstream = NULL; 227 goto lose; 228 } 229 230 /* Figure out if this directory is a mount point. */ 231 dotdev = st.st_dev; 232 dotino = st.st_ino; 233 mount_point = dotdev != thisdev; 234 235 /* Search for the last directory. */ 236 #ifdef AT_FDCWD 237 dirstream = fdopendir (fd); 238 if (dirstream == NULL) 239 goto lose; 240 fd_needs_closing = false; 241 #else 242 dirstream = __opendir (dotlist); 243 if (dirstream == NULL) 244 goto lose; 245 dotlist[dotlen++] = '/'; 246 #endif 247 /* Clear errno to distinguish EOF from error if readdir returns 248 NULL. */ 249 __set_errno (0); 250 while ((d = __readdir (dirstream)) != NULL) 251 { 252 if (d->d_name[0] == '.' && 253 (d->d_name[1] == '\0' || 254 (d->d_name[1] == '.' && d->d_name[2] == '\0'))) 255 continue; 256 if (MATCHING_INO (d, thisino) || mount_point) 257 { 258 int entry_status; 259 #ifdef AT_FDCWD 260 entry_status = fstatat (fd, d->d_name, &st, AT_SYMLINK_NOFOLLOW); 261 #else 262 /* Compute size needed for this file name, or for the file 263 name ".." in the same directory, whichever is larger. 264 Room for ".." might be needed the next time through 265 the outer loop. */ 266 size_t name_alloc = _D_ALLOC_NAMLEN (d); 267 size_t filesize = dotlen + MAX (sizeof "..", name_alloc); 268 269 if (filesize < dotlen) 270 goto memory_exhausted; 271 272 if (dotsize < filesize) 273 { 274 /* My, what a deep directory tree you have, Grandma. */ 275 size_t newsize = MAX (filesize, dotsize * 2); 276 size_t i; 277 if (newsize < dotsize) 278 goto memory_exhausted; 279 if (dotlist != dots) 280 free (dotlist); 281 dotlist = malloc (newsize); 282 if (dotlist == NULL) 283 goto lose; 284 dotsize = newsize; 285 286 i = 0; 287 do 288 { 289 dotlist[i++] = '.'; 290 dotlist[i++] = '.'; 291 dotlist[i++] = '/'; 292 } 293 while (i < dotlen); 294 } 295 296 strcpy (dotlist + dotlen, d->d_name); 297 entry_status = __lstat (dotlist, &st); 298 #endif 299 /* We don't fail here if we cannot stat() a directory entry. 300 This can happen when (network) file systems fail. If this 301 entry is in fact the one we are looking for we will find 302 out soon as we reach the end of the directory without 303 having found anything. */ 304 if (entry_status == 0 && S_ISDIR (st.st_mode) 305 && st.st_dev == thisdev && st.st_ino == thisino) 306 break; 307 } 308 } 309 if (d == NULL) 310 { 311 if (errno == 0) 312 /* EOF on dirstream, which means that the current directory 313 has been removed. */ 314 __set_errno (ENOENT); 315 goto lose; 316 } 317 else 318 { 319 size_t dirroom = dirp - dir; 320 size_t namlen = _D_EXACT_NAMLEN (d); 321 322 if (dirroom <= namlen) 323 { 324 if (size != 0) 325 { 326 __set_errno (ERANGE); 327 goto lose; 328 } 329 else 330 { 331 char *tmp; 332 size_t oldsize = allocated; 333 334 allocated += MAX (allocated, namlen); 335 if (allocated < oldsize 336 || ! (tmp = realloc (dir, allocated))) 337 goto memory_exhausted; 338 339 /* Move current contents up to the end of the buffer. 340 This is guaranteed to be non-overlapping. */ 341 dirp = memcpy (tmp + allocated - (oldsize - dirroom), 342 tmp + dirroom, 343 oldsize - dirroom); 344 dir = tmp; 345 } 346 } 347 dirp -= namlen; 348 memcpy (dirp, d->d_name, namlen); 349 *--dirp = '/'; 350 } 351 352 thisdev = dotdev; 353 thisino = dotino; 354 } 355 356 if (dirstream && __closedir (dirstream) != 0) 357 { 358 dirstream = NULL; 359 goto lose; 360 } 361 362 if (dirp == &dir[allocated - 1]) 363 *--dirp = '/'; 364 365 #ifndef AT_FDCWD 366 if (dotlist != dots) 367 free (dotlist); 368 #endif 369 370 used = dir + allocated - dirp; 371 memmove (dir, dirp, used); 372 373 if (buf == NULL && size == 0) 374 /* Ensure that the buffer is only as large as necessary. */ 375 buf = realloc (dir, used); 376 377 if (buf == NULL) 378 /* Either buf was NULL all along, or `realloc' failed but 379 we still have the original string. */ 380 buf = dir; 381 382 return buf; 383 384 memory_exhausted: 385 __set_errno (ENOMEM); 386 lose: 387 { 388 int save = errno; 389 if (dirstream) 390 __closedir (dirstream); 391 #ifdef AT_FDCWD 392 if (fd_needs_closing) 393 close (fd); 394 #else 395 if (dotlist != dots) 396 free (dotlist); 397 #endif 398 if (buf == NULL) 399 free (dir); 400 __set_errno (save); 401 } 402 return NULL; 403 } 404 405 #ifdef weak_alias 406 weak_alias (__getcwd, getcwd) 407 #endif 408