~ubuntu-branches/ubuntu/maverick/evolution-data-server/maverick-proposed

« back to all changes in this revision

Viewing changes to libdb/clib/getcwd.c

  • Committer: Bazaar Package Importer
  • Author(s): Didier Roche
  • Date: 2010-05-17 17:02:06 UTC
  • mfrom: (1.1.79 upstream) (1.6.12 experimental)
  • Revision ID: james.westby@ubuntu.com-20100517170206-4ufr52vwrhh26yh0
Tags: 2.30.1-1ubuntu1
* Merge from debian experimental. Remaining change:
  (LP: #42199, #229669, #173703, #360344, #508494)
  + debian/control:
    - add Vcs-Bzr tag
    - don't use libgnome
    - Use Breaks instead of Conflicts against evolution 2.25 and earlier.
  + debian/evolution-data-server.install,
    debian/patches/45_libcamel_providers_version.patch:
    - use the upstream versioning, not a Debian-specific one 
  + debian/libedata-book1.2-dev.install, debian/libebackend-1.2-dev.install,
    debian/libcamel1.2-dev.install, debian/libedataserverui1.2-dev.install:
    - install html documentation
  + debian/rules:
    - don't build documentation it's shipped with the tarball

Show diffs side-by-side

added added

removed removed

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