]> arthur.barton.de Git - netatalk.git/blob - libatalk/util/unix.c
Merge remote branch 'netafp/master' into branch-allea
[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 #include <sys/time.h>
34 #include <time.h>
35
36 #include <atalk/adouble.h>
37 #include <atalk/ea.h>
38 #include <atalk/afp.h>
39 #include <atalk/logger.h>
40 #include <atalk/vfs.h>
41 #include <atalk/util.h>
42 #include <atalk/unix.h>
43 #include <atalk/compat.h>
44
45 /*!
46  * @brief get cwd in static buffer
47  *
48  * @returns pointer to path or pointer to error messages on error
49  */
50 const char *getcwdpath(void)
51 {
52     static char cwd[MAXPATHLEN + 1];
53     char *p;
54
55     if ((p = getcwd(cwd, MAXPATHLEN)) != NULL)
56         return p;
57     else
58         return strerror(errno);
59 }
60
61 /*!
62  * Make argument path absoulte
63  *
64  * @returns pointer to path or pointer to error messages on error
65  */
66 const char *abspath(const char *name)
67 {
68     static char buf[MAXPATHLEN + 1];
69     char *p;
70     int n;
71
72     if (name[0] == '/')
73         return name;
74
75     if ((p = getcwd(buf, MAXPATHLEN)) == NULL)
76         return strerror(errno);
77
78     n = strlen(buf);
79     if (buf[n-1] != '/')
80         buf[n++] = '/';
81         
82     strlcpy(buf + n, name, MAXPATHLEN - n);
83     return buf;
84 }
85
86 /*!
87  * Takes a buffer with a path, strips slashs, returns basename
88  *
89  * @param p (rw) path
90  *        path may be
91  *          "[/][dir/[...]]file"
92  *        or
93  *          "[/][dir/[...]]dir/[/]"
94  *        Result is "file" or "dir" 
95  *
96  * @returns pointer to basename in path buffer, buffer is possibly modified
97  */
98 char *stripped_slashes_basename(char *p)
99 {
100     int i = strlen(p) - 1;
101     while (i > 0 && p[i] == '/')
102         p[i--] = 0;
103     return (strrchr(p, '/') ? strrchr(p, '/') + 1 : p);
104 }
105
106 /*!
107  * @brief symlink safe chdir replacement
108  *
109  * Only chdirs to dir if it doesn't contain symlinks.
110  *
111  * @returns 1 if a path element is a symlink, 0 otherwise, -1 on syserror
112  */
113 int lchdir(const char *dir)
114 {
115     char buf[MAXPATHLEN+1];
116     char cwd[MAXPATHLEN+1];
117     char *test;
118     int  i;
119
120     /*
121      dir is a canonical path (without "../" "./" "//" )
122      but may end with a / 
123     */
124     *cwd = 0;
125     if (*dir != '/') {
126         if (getcwd(cwd, MAXPATHLEN) == NULL)
127             return -1;
128     }
129     if (chdir(dir) != 0)
130         return -1;
131
132     /* 
133      * Cases:
134      * chdir request   | realpath result | ret
135      * (after getwcwd) |                 |
136      * =======================================
137      * /a/b/.          | /a/b            | 0
138      * /a/b/.          | /c              | 1
139      * /a/b/.          | /c/d/e/f        | 1
140      */
141     if (getcwd(buf, MAXPATHLEN) == NULL)
142         return 1;
143
144     i = 0;
145     if (*cwd) {
146         /* relative path requested, 
147          * Same directory?
148         */
149         for (; cwd[i]; i++) {
150             if (buf[i] != cwd[i])
151                 return 1;
152         }
153         if (buf[i]) {
154             if (buf[i] != '/')
155                 return 1;
156             i++;
157         }                    
158     }
159
160     test = &buf[i];    
161     for (i = 0; test[i]; i++) {
162         if (test[i] != dir[i]) {
163             return 1;
164         }
165     }
166     /* trailing '/' ? */
167     if (!dir[i])
168         return 0;
169
170     if (dir[i] != '/')
171         return 1;
172
173     i++;
174     if (dir[i])
175         return 1;
176
177     return 0;
178 }
179
180 /*!
181  * Store n random bytes an buf
182  */
183 void randombytes(void *buf, int n)
184 {
185     char *p = (char *)buf;
186     int fd, i;
187     struct timeval tv;
188
189     if ((fd = open("/dev/urandom", O_RDONLY)) != -1) {
190         /* generate from /dev/urandom */
191         if (read(fd, buf, n) != n) {
192             close(fd);
193             fd = -1;
194         } else {
195             close(fd);
196             /* fd now != -1, so srandom wont be called below */
197         }
198     }
199
200     if (fd == -1) {
201         gettimeofday(&tv, NULL);
202         srandom((unsigned int)tv.tv_usec);
203         for (i=0 ; i < n ; i++)
204             p[i] = random() & 0xFF;
205     }
206
207     return;
208 }