source: rtems/c/src/exec/libcsupport/src/getcwd.c @ 3165b4d3

4.104.114.84.95
Last change on this file since 3165b4d3 was 3165b4d3, checked in by Joel Sherrill <joel.sherrill@…>, on 02/10/99 at 17:04:12

Added getcwd().

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