修订版 | b08d5b5caca499902844099ab6ddf016a7ec8e3d (tree) |
---|---|
时间 | 2018-01-21 20:44:19 |
作者 | Waldemar Brodkorb <wbx@ucli...> |
Commiter | Waldemar Brodkorb |
simplify and fix getcwd
The fallback code is not used as all supported kernels have the
syscall. Check if a absolute path is returned from syscall.
@@ -16,154 +16,10 @@ | ||
16 | 16 | #include <sys/syscall.h> |
17 | 17 | |
18 | 18 | |
19 | - | |
20 | -#ifdef __NR_getcwd | |
21 | - | |
22 | 19 | # define __NR___syscall_getcwd __NR_getcwd |
23 | 20 | static __always_inline |
24 | 21 | _syscall2(int, __syscall_getcwd, char *, buf, unsigned long, size) |
25 | 22 | |
26 | -#else | |
27 | - | |
28 | -/* If the syscall is not present, we have to walk up the | |
29 | - * directory tree till we hit the root. Now we _could_ | |
30 | - * use /proc/self/cwd if /proc is mounted... That approach | |
31 | - * is left an an exercise for the reader... */ | |
32 | - | |
33 | - | |
34 | -/* Seems a few broken filesystems (like coda) don't like this */ | |
35 | -/* #undef FAST_DIR_SEARCH_POSSIBLE on Linux */ | |
36 | - | |
37 | - | |
38 | -/* Routine to find the step back down */ | |
39 | -static char *search_dir(dev_t this_dev, ino_t this_ino, char *path_buf, int path_size) | |
40 | -{ | |
41 | - DIR *dp; | |
42 | - struct dirent *d; | |
43 | - char *ptr; | |
44 | - int slen; | |
45 | - struct stat st; | |
46 | - | |
47 | -# ifdef FAST_DIR_SEARCH_POSSIBLE | |
48 | - /* The test is for ELKS lib 0.0.9, this should be fixed in the real kernel */ | |
49 | - int slow_search = (sizeof(ino_t) != sizeof(d->d_ino)); | |
50 | -# endif | |
51 | - | |
52 | - if (stat(path_buf, &st) < 0) { | |
53 | - goto oops; | |
54 | - } | |
55 | -# ifdef FAST_DIR_SEARCH_POSSIBLE | |
56 | - if (this_dev != st.st_dev) | |
57 | - slow_search = 1; | |
58 | -# endif | |
59 | - | |
60 | - slen = strlen(path_buf); | |
61 | - ptr = path_buf + slen - 1; | |
62 | - if (*ptr != '/') { | |
63 | - if (slen + 2 > path_size) { | |
64 | - goto oops; | |
65 | - } | |
66 | - strcpy(++ptr, "/"); | |
67 | - slen++; | |
68 | - } | |
69 | - slen++; | |
70 | - | |
71 | - dp = opendir(path_buf); | |
72 | - if (!dp) { | |
73 | - goto oops; | |
74 | - } | |
75 | - | |
76 | - while ((d = readdir(dp)) != 0) { | |
77 | -# ifdef FAST_DIR_SEARCH_POSSIBLE | |
78 | - if (slow_search || this_ino == d->d_ino) { | |
79 | -# endif | |
80 | - if (slen + strlen(d->d_name) > path_size) { | |
81 | - closedir(dp); | |
82 | - goto oops; | |
83 | - } | |
84 | - strcpy(ptr + 1, d->d_name); | |
85 | - if (stat(path_buf, &st) < 0) | |
86 | - continue; | |
87 | - if (st.st_ino == this_ino && st.st_dev == this_dev) { | |
88 | - closedir(dp); | |
89 | - return path_buf; | |
90 | - } | |
91 | -# ifdef FAST_DIR_SEARCH_POSSIBLE | |
92 | - } | |
93 | -# endif | |
94 | - } | |
95 | - | |
96 | - closedir(dp); | |
97 | - return 0; | |
98 | - | |
99 | -oops: | |
100 | - __set_errno(ERANGE); | |
101 | - return 0; | |
102 | -} | |
103 | - | |
104 | -/* Routine to go up tree */ | |
105 | -static char *recurser(char *path_buf, int path_size, dev_t root_dev, ino_t root_ino) | |
106 | -{ | |
107 | - struct stat st; | |
108 | - dev_t this_dev; | |
109 | - ino_t this_ino; | |
110 | - | |
111 | - if (stat(path_buf, &st) < 0) { | |
112 | - if (errno != EFAULT) | |
113 | - goto oops; | |
114 | - return 0; | |
115 | - } | |
116 | - this_dev = st.st_dev; | |
117 | - this_ino = st.st_ino; | |
118 | - if (this_dev == root_dev && this_ino == root_ino) { | |
119 | - if (path_size < 2) { | |
120 | - goto oops; | |
121 | - } | |
122 | - strcpy(path_buf, "/"); | |
123 | - return path_buf; | |
124 | - } | |
125 | - if (strlen(path_buf) + 4 > path_size) { | |
126 | - goto oops; | |
127 | - } | |
128 | - strcat(path_buf, "/.."); | |
129 | - if (recurser(path_buf, path_size, root_dev, root_ino) == 0) | |
130 | - return 0; | |
131 | - | |
132 | - return search_dir(this_dev, this_ino, path_buf, path_size); | |
133 | -oops: | |
134 | - __set_errno(ERANGE); | |
135 | - return 0; | |
136 | -} | |
137 | - | |
138 | -static __always_inline | |
139 | -int __syscall_getcwd(char * buf, unsigned long size) | |
140 | -{ | |
141 | - int len; | |
142 | - char *cwd; | |
143 | - struct stat st; | |
144 | - int olderrno; | |
145 | - | |
146 | - olderrno = errno; | |
147 | - len = -1; | |
148 | - | |
149 | - /* get stat for root to have a valid parameters for the terminating condition */ | |
150 | - if (stat("/", &st) < 0) { | |
151 | - /* root dir not found! */ | |
152 | - return -1; | |
153 | - } | |
154 | - /* start with actual dir */ | |
155 | - if (buf) strncpy(buf, ".", size); | |
156 | - | |
157 | - cwd = recurser(buf, size, st.st_dev, st.st_ino); | |
158 | - if (cwd) { | |
159 | - len = strlen(buf) + 1; | |
160 | - __set_errno(olderrno); | |
161 | - } | |
162 | - return len; | |
163 | -} | |
164 | - | |
165 | -#endif /* __NR_getcwd */ | |
166 | - | |
167 | 23 | char *getcwd(char *buf, size_t size) |
168 | 24 | { |
169 | 25 | int ret; |
@@ -184,7 +40,7 @@ char *getcwd(char *buf, size_t size) | ||
184 | 40 | return NULL; |
185 | 41 | } |
186 | 42 | ret = __syscall_getcwd(path, alloc_size); |
187 | - if (ret >= 0) | |
43 | + if (ret > 0 && path[0] == '/') | |
188 | 44 | { |
189 | 45 | if (buf == NULL && size == 0) |
190 | 46 | buf = realloc(path, ret); |