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