]> arthur.barton.de Git - netatalk.git/blob - libatalk/util/unix.c
previous commit 'lchdir: use chdir + getcwd' was only testing for symlink outside...
[netatalk.git] / libatalk / util / unix.c
1 /*
2   $Id: unix.c,v 1.6 2010-02-28 22:29:16 didg Exp $
3   Copyright (c) 2010 Frank Lahm <franklahm@gmail.com>
4
5   This program is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 2 of the License, or
8   (at your option) any later version.
9
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14 */
15
16 /*!
17  * @file
18  * Netatalk utility functions
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif /* HAVE_CONFIG_H */
24
25 #include <unistd.h>
26 #include <stdint.h>
27 #include <errno.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 #include <dirent.h>
34
35 #include <atalk/adouble.h>
36 #include <atalk/ea.h>
37 #include <atalk/afp.h>
38 #include <atalk/logger.h>
39 #include <atalk/vfs.h>
40 #include <atalk/util.h>
41 #include <atalk/unix.h>
42
43 /*!
44  * @brief get cwd in static buffer
45  *
46  * @returns pointer to path or pointer to error messages on error
47  */
48 const char *getcwdpath(void)
49 {
50     static char cwd[MAXPATHLEN + 1];
51     char *p;
52
53     if ((p = getcwd(cwd, MAXPATHLEN)) != NULL)
54         return p;
55     else
56         return strerror(errno);
57 }
58
59 /*!
60  * @brief symlink safe chdir replacement
61  *
62  * Only chdirs to dir if it doesn't contain symlinks.
63  *
64  * @returns 1 if a path element is a symlink, 0 otherwise, -1 on syserror
65  */
66 int lchdir(const char *dir)
67 {
68     char buf[MAXPATHLEN+1];
69     char cwd[MAXPATHLEN+1];
70     char *test;
71     int  i;
72
73     /*
74      dir is a canonical path (without "../" "./" "//" )
75      but may end with a / 
76     */
77     *cwd = 0;
78     if (*dir != '/') {
79         if (getcwd(cwd, MAXPATHLEN) == NULL)
80             return -1;
81     }
82     if (chdir(dir) != 0)
83         return -1;
84
85     /* 
86      * Cases:
87      * chdir request   | realpath result | ret
88      * (after getwcwd) |                 |
89      * =======================================
90      * /a/b/.          | /a/b            | 0
91      * /a/b/.          | /c              | 1
92      * /a/b/.          | /c/d/e/f        | 1
93      */
94     if (getcwd(buf, MAXPATHLEN) == NULL)
95         return 1;
96
97     i = 0;
98     if (*cwd) {
99         /* relative path requested, 
100          * Same directory?
101         */
102         for (; cwd[i]; i++) {
103             if (buf[i] != cwd[i])
104                 return 1;
105         }
106         if (buf[i]) {
107             if (buf[i] != '/')
108                 return 1;
109             i++;
110         }                    
111     }
112
113     test = &buf[i];    
114     for (i = 0; test[i]; i++) {
115         if (test[i] != dir[i]) {
116             return 1;
117         }
118     }
119     /* trailing '/' ? */
120     if (!dir[i])
121         return 0;
122
123     if (dir[i] != '/')
124         return 1;
125
126     i++;
127     if (dir[i])
128         return 1;
129
130     return 0;
131 }