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