14629
|
1 /* Copyright (C) 2011 Free Software Foundation, Inc. |
|
2 This file is part of gnulib. |
|
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 #include <config.h> |
|
18 |
|
19 /* Specification */ |
|
20 #include <unistd.h> |
|
21 |
|
22 #include <errno.h> |
|
23 #include <string.h> |
|
24 |
|
25 #if GNULIB_GETCWD |
|
26 /* Favor GPL getcwd.c if both getcwd and getcwd-lgpl modules are in use. */ |
|
27 typedef int dummy; |
|
28 #else |
|
29 |
|
30 /* Get the name of the current working directory, and put it in SIZE |
|
31 bytes of BUF. Returns NULL if the directory couldn't be determined |
|
32 (perhaps because the absolute name was longer than PATH_MAX, or |
|
33 because of missing read/search permissions on parent directories) |
|
34 or SIZE was too small. If successful, returns BUF. If BUF is |
|
35 NULL, an array is allocated with `malloc'; the array is SIZE bytes |
|
36 long, unless SIZE == 0, in which case it is as big as |
|
37 necessary. */ |
|
38 |
|
39 # undef getcwd |
|
40 char * |
|
41 rpl_getcwd (char *buf, size_t size) |
|
42 { |
|
43 char *ptr; |
|
44 char *result; |
|
45 |
|
46 /* Handle single size operations. */ |
|
47 if (buf) |
|
48 return getcwd (buf, size); |
|
49 |
|
50 if (size) |
|
51 { |
|
52 buf = malloc (size); |
|
53 if (!buf) |
|
54 { |
|
55 errno = ENOMEM; |
14641
|
56 return NULL; |
14629
|
57 } |
|
58 result = getcwd (buf, size); |
|
59 if (!result) |
|
60 { |
|
61 int saved_errno = errno; |
|
62 free (buf); |
|
63 errno = saved_errno; |
|
64 } |
|
65 return result; |
|
66 } |
|
67 |
|
68 /* Flexible sizing requested. Avoid over-allocation for the common |
|
69 case of a name that fits within a 4k page, minus some space for |
|
70 local variables, to be sure we don't skip over a guard page. */ |
|
71 { |
|
72 char tmp[4032]; |
|
73 size = sizeof tmp; |
|
74 ptr = getcwd (tmp, size); |
|
75 if (ptr) |
|
76 { |
|
77 result = strdup (ptr); |
|
78 if (!result) |
|
79 errno = ENOMEM; |
|
80 return result; |
|
81 } |
|
82 if (errno != ERANGE) |
|
83 return NULL; |
|
84 } |
|
85 |
|
86 /* My what a large directory name we have. */ |
|
87 do |
|
88 { |
|
89 size <<= 1; |
|
90 ptr = realloc (buf, size); |
|
91 if (ptr == NULL) |
|
92 { |
|
93 free (buf); |
|
94 errno = ENOMEM; |
|
95 return NULL; |
|
96 } |
|
97 buf = ptr; |
|
98 result = getcwd (buf, size); |
|
99 } |
|
100 while (!result && errno == ERANGE); |
|
101 |
|
102 if (!result) |
|
103 { |
|
104 int saved_errno = errno; |
|
105 free (buf); |
|
106 errno = saved_errno; |
|
107 } |
|
108 else |
|
109 { |
|
110 /* Trim to fit, if possible. */ |
|
111 result = realloc (buf, strlen (buf) + 1); |
|
112 if (!result) |
|
113 result = buf; |
|
114 } |
|
115 return result; |
|
116 } |
|
117 |
|
118 #endif |