source: trunk/libs/newlib/src/newlib/libc/unix/getcwd.c @ 577

Last change on this file since 577 was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 6.5 KB
Line 
1#ifndef _NO_GETCWD
2/*
3 * Copyright (c) 1989, 1991 The Regents of the University of California.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 4. Neither the name of the University nor the names of its contributors
15 *    may be used to endorse or promote products derived from this software
16 *    without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#if defined(LIBC_SCCS) && !defined(lint)
32static char sccsid[] = "@(#)getcwd.c    5.11 (Berkeley) 2/24/91";
33#endif /* LIBC_SCCS and not lint */
34
35#include <sys/param.h>
36#include <sys/stat.h>
37#include <errno.h>
38#include <dirent.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42#include <unistd.h>
43#include <reent.h>
44#include <_syslist.h>
45
46#define bcopy(a,b,c)    memmove (b,a,c)
47
48#define ISDOT(dp) \
49        (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \
50           (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
51
52#ifndef _REENT_ONLY
53
54char *
55getcwd (pt, size)
56     char *pt;
57     size_t size;
58{
59  register struct dirent *dp;
60  register DIR *dir = NULL;
61  register dev_t dev;
62  register ino_t ino;
63  register int first;
64  register char *bpt, *bup;
65  struct stat s;
66  dev_t root_dev;
67  ino_t root_ino;
68  size_t ptsize, upsize;
69  int save_errno;
70  char *ept, *eup, *up;
71
72  /*
73   * If no buffer specified by the user, allocate one as necessary.
74   * If a buffer is specified, the size has to be non-zero.  The path
75   * is built from the end of the buffer backwards.
76   */
77
78  if (pt)
79    {
80      ptsize = 0;
81      if (!size)
82        {
83          errno = EINVAL;
84          return (char *) NULL;
85        }
86      ept = pt + size;
87    }
88  else
89    {
90      if (!(pt = (char *) malloc (ptsize = 1024 - 4)))
91        {
92          return (char *) NULL;
93        }
94      ept = pt + ptsize;
95    }
96  bpt = ept - 1;
97  *bpt = '\0';
98
99  /*
100   * Allocate bytes (1024 - malloc space) for the string of "../"'s.
101   * Should always be enough (it's 340 levels).  If it's not, allocate
102   * as necessary.  Special * case the first stat, it's ".", not "..".
103   */
104
105  if (!(up = (char *) malloc (upsize = 1024 - 4)))
106    {
107      goto err;
108    }
109  eup = up + MAXPATHLEN;
110  bup = up;
111  up[0] = '.';
112  up[1] = '\0';
113
114  /* Save root values, so know when to stop. */
115  if (stat ("/", &s))
116    goto err;
117  root_dev = s.st_dev;
118  root_ino = s.st_ino;
119
120  errno = 0;                    /* XXX readdir has no error return. */
121
122  for (first = 1;; first = 0)
123    {
124      /* Stat the current level. */
125      if (stat (up, &s))
126        goto err;
127
128      /* Save current node values. */
129      ino = s.st_ino;
130      dev = s.st_dev;
131
132      /* Check for reaching root. */
133      if (root_dev == dev && root_ino == ino)
134        {
135          *--bpt = '/';
136          /*
137           * It's unclear that it's a requirement to copy the
138           * path to the beginning of the buffer, but it's always
139           * been that way and stuff would probably break.
140           */
141          (void) bcopy (bpt, pt, ept - bpt);
142          free (up);
143          return pt;
144        }
145
146      /*
147       * Build pointer to the parent directory, allocating memory
148       * as necessary.  Max length is 3 for "../", the largest
149       * possible component name, plus a trailing NULL.
150       */
151
152      if (bup + 3 + MAXNAMLEN + 1 >= eup)
153        {
154          if (!(up = (char *) realloc (up, upsize *= 2)))
155            {
156              goto err;
157            }
158          bup = up;
159          eup = up + upsize;
160        }
161      *bup++ = '.';
162      *bup++ = '.';
163      *bup = '\0';
164
165      /* Open and stat parent directory. */
166      if (!(dir = opendir (up)) || fstat (__dirfd (dir), &s))
167        goto err;
168
169      /* Add trailing slash for next directory. */
170      *bup++ = '/';
171
172      /*
173       * If it's a mount point, have to stat each element because
174       * the inode number in the directory is for the entry in the
175       * parent directory, not the inode number of the mounted file.
176       */
177
178      save_errno = 0;
179      if (s.st_dev == dev)
180        {
181          for (;;)
182            {
183              if (!(dp = readdir (dir)))
184                goto notfound;
185              if (dp->d_ino == ino)
186                break;
187            }
188        }
189      else
190        for (;;)
191          {
192            if (!(dp = readdir (dir)))
193              goto notfound;
194            if (ISDOT (dp))
195              continue;
196            bcopy (dp->d_name, bup, strlen (dp->d_name) + 1);
197
198            /* Save the first error for later. */
199            if (stat (up, &s))
200              {
201                if (!save_errno)
202                  save_errno = errno;
203                errno = 0;
204                continue;
205              }
206            if (s.st_dev == dev && s.st_ino == ino)
207              break;
208          }
209
210      /*
211       * Check for length of the current name, preceding slash,
212       * leading slash.
213       */
214
215      if (bpt - pt <= strlen (dp->d_name) + (first ? 1 : 2))
216        {
217          size_t len, off;
218
219          if (!ptsize)
220            {
221              errno = ERANGE;
222              goto err;
223            }
224          off = bpt - pt;
225          len = ept - bpt;
226          if (!(pt = (char *) realloc (pt, ptsize *= 2)))
227            {
228              goto err;
229            }
230          bpt = pt + off;
231          ept = pt + ptsize;
232          (void) bcopy (bpt, ept - len, len);
233          bpt = ept - len;
234        }
235      if (!first)
236        *--bpt = '/';
237      bpt -= strlen (dp->d_name);
238      bcopy (dp->d_name, bpt, strlen (dp->d_name));
239      (void) closedir (dir);
240      dir = NULL;
241
242      /* Truncate any file name. */
243      *bup = '\0';
244    }
245
246notfound:
247  /*
248   * If readdir set errno, use it, not any saved error; otherwise,
249   * didn't find the current directory in its parent directory, set
250   * errno to ENOENT.
251   */
252
253  if (!errno)
254    errno = save_errno ? save_errno : ENOENT;
255  /* FALLTHROUGH */
256
257err:
258  if (ptsize)
259    free (pt);
260  if (dir)
261    (void) closedir (dir);
262  free (up);
263  return (char *) NULL;
264}
265
266#endif /* _REENT_ONLY */
267#endif /* !_NO_GETCWD  */
Note: See TracBrowser for help on using the repository browser.