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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1911 - (hide 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 msalle 1884 /**
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 msalle 1891 #include "realpath.h"
24    
25 msalle 1884 #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 msalle 1890 #ifdef _POSIX_SYMLOOP_MAX
43 msalle 1884 #define SYMLOOP_MAX _POSIX_SYMLOOP_MAX
44 msalle 1890 #else
45     #define SYMLOOP_MAX 8
46 msalle 1884 #endif
47 msalle 1890 #endif
48 msalle 1884
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 msalle 1909 char olddirbuf[PATH_MAX]="";
61 msalle 1884 char buf[PATH_MAX],*path;
62    
63 msalle 1909 /* 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 msalle 1884 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 msalle 1909 /* Go back: when open() succeeded, use fchdir() & close(), otherwise use
72     * chdir(). Note that it's really bad if this fails! */
73 msalle 1910 if ( (olddir!=-1 && ( fchdir(olddir) || close(olddir) ) ) ||
74 msalle 1911 (olddir==-1 && chdir(olddirbuf) ) )
75 msalle 1909 return NULL;
76 msalle 1884 /* 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 msalle 1889 /* Note: snprintf retval excludes \0 */
125     if ( (pathlen=snprintf(path,PATH_MAX,"%s/%s",buf,inpath))>=PATH_MAX ) {
126 msalle 1884 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 msalle 1887 if (!canonicdir)
168     return NULL;
169 msalle 1884 /* 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 msalle 1889 /* Note: snprintf retval excludes \0 */
173     if (pathlen>=PATH_MAX) {
174 msalle 1884 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