Whamcloud - gitweb
Ignore generated files.
[fs/lustre-release.git] / libsysio / src / chdir.c
1 /*
2  *    This Cplant(TM) source code is the property of Sandia National
3  *    Laboratories.
4  *
5  *    This Cplant(TM) source code is copyrighted by Sandia National
6  *    Laboratories.
7  *
8  *    The redistribution of this Cplant(TM) source code is subject to the
9  *    terms of the GNU Lesser General Public License
10  *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
11  *
12  *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
13  *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
14  *    license for use of this work by or on behalf of the US Government.
15  *    Export of this program may require a license from the United States
16  *    Government.
17  */
18
19 /*
20  * #############################################################################
21  * #
22  * #     This Cplant(TM) source code is the property of Sandia National
23  * #     Laboratories.
24  * #
25  * #     This Cplant(TM) source code is copyrighted by Sandia National
26  * #     Laboratories.
27  * #
28  * #     The redistribution of this Cplant(TM) source code is subject to the
29  * #     terms of the GNU Lesser General Public License
30  * #     (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
31  * #
32  * #     Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
33  * #     Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
34  * #     license for use of this work by or on behalf of the US Government.
35  * #     Export of this program may require a license from the United States
36  * #     Government.
37  * #
38  * #############################################################################
39  */
40
41 /*
42  * This library is free software; you can redistribute it and/or
43  * modify it under the terms of the GNU Lesser General Public
44  * License as published by the Free Software Foundation; either
45  * version 2.1 of the License, or (at your option) any later version.
46  * 
47  * This library is distributed in the hope that it will be useful,
48  * but WITHOUT ANY WARRANTY; without even the implied warranty of
49  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
50  * Lesser General Public License for more details.
51  * 
52  * You should have received a copy of the GNU Lesser General Public
53  * License along with this library; if not, write to the Free Software
54  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
55  *
56  * Questions or comments about this library should be sent to:
57  *
58  * Lee Ward
59  * Sandia National Laboratories, New Mexico
60  * P.O. Box 5800
61  * Albuquerque, NM 87185-1110
62  *
63  * lee@sandia.gov
64  */
65
66 #include <stdlib.h>
67 #include <sys/types.h>
68 #include <sys/stat.h>
69 #include <unistd.h>
70 #include <string.h>
71 #include <limits.h>
72 #include <errno.h>
73 #include <assert.h>
74 #include <sys/queue.h>
75
76 #include "sysio.h"
77 #include "inode.h"
78 #include "mount.h"
79 #include "file.h"
80 #include "sysio-symbols.h"
81
82 struct pnode *_sysio_cwd = NULL;
83
84 /*
85  * Change to directory specified by the given pnode.
86  */
87 int
88 _sysio_p_chdir(struct pnode *pno)
89 {
90         int     err;
91
92         /*
93          * Revalidate the pnode, and ensure it's a directory
94          */
95         err = _sysio_p_validate(pno, NULL, NULL);
96         if (err)
97                 return err;
98
99         if (!(pno->p_base->pb_ino &&
100               S_ISDIR(pno->p_base->pb_ino->i_mode)))
101                 return -ENOTDIR;
102         /*
103          * Release old if set.
104          */
105         if (_sysio_cwd)
106                 P_RELE(_sysio_cwd);
107
108         /*
109          * Finally, change to the new.
110          */
111         _sysio_cwd = pno;
112
113         return 0;
114 }
115
116 int
117 SYSIO_INTERFACE_NAME(chdir)(const char *path)
118 {
119         int     err;
120         struct pnode *pno;
121         SYSIO_INTERFACE_DISPLAY_BLOCK;
122
123         SYSIO_INTERFACE_ENTER;
124         err = _sysio_namei(_sysio_cwd, path, 0, NULL, &pno);
125         if (err)
126                 SYSIO_INTERFACE_RETURN(-1, err);
127
128         err = _sysio_p_chdir(pno);
129         if (err)
130                 P_RELE(pno);
131         SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
132 }
133
134 #ifdef REDSTORM
135 #undef __chdir
136 sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(chdir),
137                      PREPEND(__, SYSIO_INTERFACE_NAME(chdir)))
138 #endif
139
140 /*
141  * Return path tracked by the path ancestor chain.
142  *
143  * If the buf pointer is NULL, a buffer large enough to hold the path
144  * is allocated from the heap.
145  */
146
147 static int
148 _sysio_p_path(struct pnode *pno, char **buf, size_t size)
149 {
150         struct pnode *cur;
151         size_t  len;
152         size_t  n;
153         char    *cp;
154
155         cur = pno;
156
157         /*
158          * Walk up the tree to the root, summing the component name
159          * lengths and counting the vertices.
160          */
161         len = 0;
162         n = 0;
163         do {
164                 /*
165                  * If this is a covering path-node then the name should be
166                  * the *covered* nodes name, not this one unless we are at
167                  * the root of the name-space.
168                  */
169                 while (pno == pno->p_mount->mnt_root && pno != pno->p_parent )
170                         pno = pno->p_mount->mnt_covers;
171
172                 /*
173                  * Add length of this component to running sum and
174                  * account for this vertex.
175                  */
176                 assert((len >= pno->p_base->pb_name.len &&
177                         (size_t )~0 - pno->p_base->pb_name.len > len) ||
178                        (size_t )~0 - len > pno->p_base->pb_name.len);
179                 len += pno->p_base->pb_name.len;
180                 n++;
181                 assert(n);
182                 pno = pno->p_parent;
183         } while (pno != pno->p_parent);
184
185         if (!*buf)
186                 size = len + n + 1;
187         if (len >= size || n >= size - len)
188                 return -ERANGE;
189         if (!*buf) {
190                 /*
191                  * Allocate path buffer from the heap.
192                  */
193                 *buf = malloc(size * sizeof(char));
194                 if (!*buf)
195                         return -ENOMEM;
196         }
197
198         /*
199          * Fill in the path buffer.
200          */
201         pno = cur;
202         cp = *buf + len + n;
203         *cp = '\0';                                     /* NUL terminate */
204         do {
205                 /*
206                  * If this is a covering path-node then the name should be
207                  * the *covered* nodes name, not this one unless we are at
208                  * the root of the name-space.
209                  */
210                 while (pno == pno->p_mount->mnt_root && pno != pno->p_parent )
211                         pno = pno->p_mount->mnt_covers;
212
213                 /*
214                  * Add component and separator.
215                  */
216                 cp -= pno->p_base->pb_name.len;
217                 (void )memcpy(cp, pno->p_base->pb_name.name,
218                               pno->p_base->pb_name.len);
219
220                 *--cp = PATH_SEPARATOR;
221                 pno = pno->p_parent;
222         } while (pno != pno->p_parent);
223
224         return 0;
225 }
226
227 char *
228 SYSIO_INTERFACE_NAME(getcwd)(char *buf, size_t size)
229 {
230         int     err;
231         SYSIO_INTERFACE_DISPLAY_BLOCK;
232
233         SYSIO_INTERFACE_ENTER;
234         err = _sysio_p_path(_sysio_cwd, &buf, buf ? size : 0);
235         SYSIO_INTERFACE_RETURN(err ? NULL : buf, err);
236 }
237
238 #ifdef __GLIBC__
239 #undef __getcwd
240 sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(getcwd), 
241                      PREPEND(__, SYSIO_INTERFACE_NAME(getcwd)))
242 #endif
243
244 #if defined(PATH_MAX) && !(defined(REDSTORM))
245 char    *
246 SYSIO_INTERFACE_NAME(getwd)(char *buf)
247 {
248
249         if (!buf) {
250                 errno = EFAULT;
251                 return NULL;
252         }
253
254         return SYSIO_INTERFACE_NAME(getcwd)(buf, PATH_MAX);
255 }
256 #endif