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 */ 49const 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 */ 72char *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 */ 87int 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 */ 157void 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} 183