/[pdpsoft]/trunk/grid-mw-security/cgul/realpath/realpath.c
ViewVC logotype

Contents of /trunk/grid-mw-security/cgul/realpath/realpath.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1911 - (show annotations) (download) (as text)
Wed Sep 1 13:30:16 2010 UTC (11 years, 8 months ago) by msalle
File MIME type: text/x-chdr
File size: 5924 byte(s)
Fix missing expression

1 /**
2 * Copyright (c) Members of the EGEE Collaboration. 2010.
3 * See http://www.eu-egee.org/partners/ for details on the copyright
4 * holders.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * Authors: Oscar Koeroo, Mischa Sall\'e, Aram Verstegen
19 * NIKHEF Amsterdam, the Netherlands
20 * <grid-mw-security@nikhef.nl>
21 */
22
23 #include "realpath.h"
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <fcntl.h>
30 #include <limits.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <errno.h>
34
35 /* Make sure at least internally we have a PATH_MAX */
36 #ifndef PATH_MAX
37 #define PATH_MAX 1024
38 #endif
39
40 /* Make sure at least internally we have a SYMLOOP_MAX */
41 #ifndef SYMLOOP_MAX
42 #ifdef _POSIX_SYMLOOP_MAX
43 #define SYMLOOP_MAX _POSIX_SYMLOOP_MAX
44 #else
45 #define SYMLOOP_MAX 8
46 #endif
47 #endif
48
49 /*!
50 * Returns the fully canonicalized and absolute path for a diretory or NULL on
51 * error. Memory for the return string is malloced and should be freed by the
52 * caller. Any path cannot be longer than PATH_MAX. Note that it is necessary
53 * that we can chdir to dir.
54 * NOTE: This function is not thread-safe
55 * \param dir non-absolute and/or non-canonical directory
56 * \return canonical absolute directory
57 */
58 char *cgul_realdir(const char *dir) {
59 int olddir;
60 char olddirbuf[PATH_MAX]="";
61 char buf[PATH_MAX],*path;
62
63 /* Safe old dir and then go to the new one: preferably use open, but for a
64 * non-readable directory, that fails: then use getcwd instead */
65 if ( ( (olddir=open(".",O_RDONLY))==-1 &&
66 getcwd(olddirbuf,PATH_MAX)==NULL ) ||
67 chdir(dir)==-1 )
68 return NULL;
69 /* Get the location, don't exit yet when failed: need to go back */
70 path=getcwd(buf,PATH_MAX);
71 /* Go back: when open() succeeded, use fchdir() & close(), otherwise use
72 * chdir(). Note that it's really bad if this fails! */
73 if ( (olddir!=-1 && ( fchdir(olddir) || close(olddir) ) ) ||
74 (olddir==-1 && chdir(olddirbuf) ) )
75 return NULL;
76 /* Make a copy */
77 if (path)
78 path=strdup(buf);
79
80 return path;
81 }
82
83 /*!
84 * Returns the fully canonicalized and absolute path for any path or NULL on
85 * error. Note that this function substitutes the unsafe realpath() or the
86 * GNU-only canonicalize_file_name().
87 * Memory for the return string is malloced and should be freed by the
88 * caller. Any path cannot be longer than PATH_MAX. Any directory has to be
89 * accessible, including if it's the last element.
90 * NOTE: This function is not thread-safe
91 * \param inpath non-absolute and/or non-canonical path
92 * \param instat optional stat information on the input (for performance, if
93 * already available). When NULL it will be determined locally
94 * when needed.
95 * \return canonical absolute path
96 */
97 char *cgul_realpath(const char *inpath, struct stat *instat) {
98 char buf[PATH_MAX], path[PATH_MAX];
99 char *pos,*canonicdir;
100 int pathlen,filelen,linklen, linkcount=0;
101 struct stat st;
102
103 /* Check and store the length of the input (incl \0) */
104 if ( (pathlen=1+strlen(inpath)) > PATH_MAX) {
105 errno=ENAMETOOLONG;
106 return NULL;
107 }
108 /* Check last compo is dir: then just return realdir() */
109 if (instat==NULL) {
110 if (stat(inpath, &st)==-1) /* Error */
111 return NULL;
112 instat=&st;
113 }
114 if (S_ISDIR(instat->st_mode))
115 return cgul_realdir(inpath);
116
117 /* Make path absolute */
118 if (inpath[0]!='/') { /* relative */
119 /* get and add cwd */
120 if (!getcwd(buf,PATH_MAX)) {
121 if (errno==ERANGE) errno=ENAMETOOLONG;
122 return NULL;
123 }
124 /* Note: snprintf retval excludes \0 */
125 if ( (pathlen=snprintf(path,PATH_MAX,"%s/%s",buf,inpath))>=PATH_MAX ) {
126 errno=ENAMETOOLONG;
127 return NULL;
128 }
129 } else /* absolute */
130 strcpy(path,inpath);
131
132 /* Now loop over symlink, if any */
133 /* readlink wants buffersize without \0: PATH_MAX-1 */
134 while ( (linklen=readlink(path,buf,PATH_MAX-1)) != -1 ) {
135 if (++linkcount > SYMLOOP_MAX) { /* Too many symlinks */
136 errno=ELOOP;
137 return NULL;
138 }
139 buf[linklen]='\0';
140 /* Check the symlink */
141 if (buf[0]=='/') /* absolute: replaces entire path */
142 strcpy(path,buf);
143 else { /* relative: replaces last component */
144 pos=strrchr(path,'/'); /* Has to exist, we made it absolute */
145 filelen=strlen(pos+1); /* length of remainder without \0 */
146 /* Note: pathlen is with \0, filelen and linklen without, hence
147 * combined as follows is with \0 and should be <= PATH_MAX */
148 if (pathlen-filelen+linklen>PATH_MAX) {
149 errno=ENAMETOOLONG;
150 return NULL;
151 }
152 strcpy(pos+1,buf); /* It fits, so use strcpy */
153 }
154 }
155 /* Alway end due to realink: check it's due to non-symlink */
156 if (errno!=EINVAL) /* i.e. other error */
157 return NULL;
158
159 /* Now path is not a symlink */
160
161 /* Find dir part */
162 pos=strrchr(path,'/'); /* Has to exist, we made it absolute */
163 /* dir: up to pos, file: pos+1 till end */
164 pos[0]='\0';
165 canonicdir=cgul_realdir(path);
166 pos[0]='/'; /* Clean but unnecessary */
167 if (!canonicdir)
168 return NULL;
169 /* Put them together, canonicdir doesn't end with a / */
170 pathlen=snprintf(buf,PATH_MAX,"%s/%s",canonicdir,pos+1);
171 free(canonicdir); /* Done with canonicdir */
172 /* Note: snprintf retval excludes \0 */
173 if (pathlen>=PATH_MAX) {
174 errno=ENAMETOOLONG;
175 return NULL;
176 }
177
178 /* Return duplicate, or NULL when fails */
179 return strdup(buf);
180 }

grid.support@nikhef.nl
ViewVC Help
Powered by ViewVC 1.1.28