source: trunk/athena/bin/attach/pathcan.c @ 8843

Revision 8843, 5.3 KB checked in by ghudson, 28 years ago (diff)
BSD -> ANSI string and memory functions
Line 
1/*
2 *      $Source: /afs/dev.mit.edu/source/repository/athena/bin/attach/pathcan.c,v $
3 *      $Author: ghudson $
4 *      $Header: /afs/dev.mit.edu/source/repository/athena/bin/attach/pathcan.c,v 1.5 1996-09-19 22:13:15 ghudson Exp $
5 */
6
7#ifndef lint
8static char *rcsid_pathcan_c = "$Header: /afs/dev.mit.edu/source/repository/athena/bin/attach/pathcan.c,v 1.5 1996-09-19 22:13:15 ghudson Exp $";
9#endif
10
11#include <stdio.h>
12#include <errno.h>
13#include <string.h>
14#include <sys/types.h>
15#include <sys/param.h>
16#include <sys/stat.h>
17#ifdef POSIX
18#include <unistd.h>
19#endif
20#define MAXLINKS        16
21
22extern int      errno;
23extern  char    *malloc();
24
25int     pc_symlinkcnt;
26int     pc_depthcnt;
27
28#ifdef DEBUG
29static char     *strdup();
30#else
31extern char     *strdup();
32#endif
33
34struct filestack {
35        char    *path;
36        char    *ptr;           /* pointer to the next thing to fix */
37};
38
39char    *path_canon(infile)
40        char    *infile;
41{
42#ifndef POSIX
43        extern char *getwd();
44#endif
45        static struct filestack stack[MAXLINKS];
46        int                     stkcnt = 0;     /* Stack counter */
47        struct filestack        *stkptr = &stack[0]; /*Always = &stack[stkcnt]*/
48        register int    i;
49        register char   *cp, *token;
50        static char     outpath[MAXPATHLEN];
51        char    *outpathend = outpath; /* Always points to the end of outpath*/
52        char            bfr[MAXPATHLEN];
53        struct  stat    statbuf;
54        int             errorflag = 0;
55       
56        pc_symlinkcnt = pc_depthcnt = 0;
57       
58        if (!infile)
59                return(NULL);
60
61        stkptr->ptr = stkptr->path = strdup(infile);
62
63        if (*infile == '/') {
64                /*
65                 * We're starting at the root; normal case
66                 */
67                stkptr->ptr++;
68                outpath[0]='\0';
69        } else {
70                /*
71                 * We're being asked to interpret a relative pathname;
72                 * assume this is happening relative to the current
73                 * directory.
74                 */
75#ifdef POSIX
76                if (getcwd(outpath, sizeof(outpath)) == NULL) {
77#else
78                if (getwd(outpath) == NULL) {
79#endif
80#ifdef TEST
81                        printf("getwd returned error, %s", outpath);
82#endif
83                        return(NULL);
84                }
85                outpathend += strlen(outpathend);
86        }
87       
88        while (stkcnt >= 0) {
89                /*
90                 * If there's no more pathname elements in this level
91                 * of recursion, pop the stack and continue.
92                 */
93                if (!stkptr->ptr || !*stkptr->ptr) {
94#ifdef TEST
95                        printf("Popping.... stkcnt = %d\n", stkcnt);
96#endif
97                        free(stkptr->path);
98                        stkcnt--;
99                        stkptr--;
100                        continue;
101                }
102#ifdef TEST
103                printf("stkcnt = %d, ptr = %s, out = '%s'\n", stkcnt,
104                       stkptr->ptr, outpath);
105#endif
106
107                /*
108                 * Peel off the next token and bump the pointer
109                 */
110                token = stkptr->ptr;
111                if (cp = strchr(stkptr->ptr, '/')) {
112                        *cp = '\0';
113                        stkptr->ptr = cp+1;
114                } else
115                        stkptr->ptr = NULL;
116
117                /*
118                 * If the token is "" or ".", then just continue
119                 */
120                if (!*token || !strcmp(token, "."))
121                        continue;
122               
123                /*
124                 * If the token is "..", then lop off the last part of
125                 * outpath, and continue.
126                 */
127                if (!strcmp(token, "..")) {
128                        if (cp = strrchr(outpath, '/'))
129                                *(outpathend = cp) = '\0';
130                        continue;
131                }
132
133                /*
134                 * Tack on the new token, but don't advance outpathend
135                 * yet (we may need to back out).
136                 */
137                *outpathend = '/';
138                (void) strcpy(outpathend+1, token);
139                if (!errorflag && lstat(outpath, &statbuf)) {
140#ifdef TEST
141                        if (errno)
142                                perror(outpath);
143#endif
144                        /*
145                         * If we get a file not found, or the file is
146                         * not a directory, set a flag so that
147                         * lstat() is skipped from being called, since
148                         * there's no point in trying any future
149                         * lstat()'s.
150                         */
151                        if (errno == ENOTDIR || errno == ENOENT) {
152                                errorflag = errno;
153                                outpathend += strlen(outpathend);
154                                continue;       /* Go back and pop stack */
155                        }
156                        return(NULL);
157                }
158
159                /*
160                 * If outpath expanded to a symlink, we're going to
161                 * expand it.  This entails: 1) reading the value of
162                 * the symlink.  2) Removing the appended token to
163                 * outpath.  3) Recursively expanding the value of the
164                 * symlink by pushing it onto the stack.
165                 */
166                if (!errorflag && (statbuf.st_mode & S_IFMT) == S_IFLNK) {
167                        pc_symlinkcnt++;
168
169                        if ((i = readlink(outpath, bfr, sizeof(bfr))) < 0) {
170#ifdef TEST
171                                perror("readlink");
172#endif
173                                return(NULL);
174                        }
175                        bfr[i] = '\0';
176#ifdef TEST
177                        printf("stkcnt = %d, found symlink to %s\n",
178                               stkcnt, bfr);
179#endif
180                        *outpathend = '\0'; /* Back it out */
181                        stkcnt++;
182                        stkptr++;
183                        if (stkcnt >= MAXLINKS) {
184                                errno = ELOOP;
185#ifdef TEST
186                                printf("Stack limit exceeded! Aborting...\n");
187#endif
188                                return(NULL);
189                        }
190                        stkptr->ptr = stkptr->path = strdup(bfr);
191                        if (bfr[0] == '/') {
192                                /* This is a sym link to root, we can */
193                                /* blast outpath and start over */
194                                outpathend = outpath;
195                                *outpath = '\0';
196                                stkptr->ptr++; /* Bump past / */
197                        }
198                        if (stkcnt > pc_depthcnt)
199                                pc_depthcnt = stkcnt;
200                        continue;
201                }
202                /*
203                 * This is a normal case.  Extend out outpathend,
204                 * and continue to the next path element
205                 */
206                outpathend += strlen(outpathend);
207        }
208        /*
209         * Special case: if outpath is empty, this means we're at the
210         * filesystem root
211         */
212        if (!*outpath)
213                return("/");
214        else
215                return(outpath);
216}
217
218
219#ifdef DEBUG
220/*
221 * Duplicate a string in malloc'ed memory
222 */
223static char *strdup(s)
224        char    *s;
225{
226        register char   *cp;
227       
228        if (!(cp = malloc(strlen(s)+1))) {
229                printf("Out of memory!!!\n");
230                abort();
231        }
232        return(strcpy(cp,s));
233}
234
235main (argc, argv)
236        int argc;
237        char **argv;
238{
239        if (argc != 2) {
240                fprintf(stderr, "Usage: %s pathname\n", argv[0]);
241                exit(1);
242        }
243        printf("Result: %s\n", path_canon(argv[1]));
244        printf("Number of symlinks traversed: %d\n", pc_symlinkcnt);
245        printf("Maximum depth of symlink traversal: %d\n", pc_depthcnt);
246        exit(0);
247}
248#endif
Note: See TracBrowser for help on using the repository browser.