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