1 /* $NetBSD: file.c,v 1.2 2011/06/25 20:27:01 christos Exp $ */ 2 /*- 3 * Copyright (c) 1998-2004 Dag-Erling Co�dan Sm�rgrav 4 * Copyright (c) 2008, 2009 Joerg Sonnenberger <joerg@NetBSD.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer 12 * in this position and unchanged. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * 30 * $FreeBSD: file.c,v 1.18 2007/12/14 10:26:58 des Exp $ 31 */ 32 33 #if HAVE_CONFIG_H 34 #include "config.h" 35 #endif 36 #ifndef NETBSD 37 #include <nbcompat.h> 38 #endif 39 40 #include <sys/stat.h> 41 42 #include <dirent.h> 43 #include <fcntl.h> 44 #include <fnmatch.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <unistd.h> 49 50 #include "fetch.h" 51 #include "common.h" 52 53 static int fetch_stat_file(int, struct url_stat *); 54 55 static ssize_t 56 fetchFile_read(void *cookie, void *buf, size_t len) 57 { 58 return read(*(int *)cookie, buf, len); 59 } 60 61 static ssize_t 62 fetchFile_write(void *cookie, const void *buf, size_t len) 63 { 64 return write(*(int *)cookie, buf, len); 65 } 66 67 static void 68 fetchFile_close(void *cookie) 69 { 70 int fd = *(int *)cookie; 71 72 free(cookie); 73 74 close(fd); 75 } 76 77 fetchIO * 78 fetchXGetFile(struct url *u, struct url_stat *us, const char *flags) 79 { 80 char *path; 81 fetchIO *f; 82 struct url_stat local_us; 83 int if_modified_since, fd, *cookie; 84 85 if_modified_since = CHECK_FLAG('i'); 86 if (if_modified_since && us == NULL) 87 us = &local_us; 88 89 if ((path = fetchUnquotePath(u)) == NULL) { 90 fetch_syserr(); 91 return NULL; 92 } 93 94 fd = open(path, O_RDONLY); 95 free(path); 96 if (fd == -1) { 97 fetch_syserr(); 98 return NULL; 99 } 100 101 if (us && fetch_stat_file(fd, us) == -1) { 102 close(fd); 103 fetch_syserr(); 104 return NULL; 105 } 106 107 if (if_modified_since && u->last_modified > 0 && 108 u->last_modified >= us->mtime) { 109 close(fd); 110 fetchLastErrCode = FETCH_UNCHANGED; 111 snprintf(fetchLastErrString, MAXERRSTRING, "Unchanged"); 112 return NULL; 113 } 114 115 if (u->offset && lseek(fd, u->offset, SEEK_SET) == -1) { 116 close(fd); 117 fetch_syserr(); 118 return NULL; 119 } 120 121 cookie = malloc(sizeof(int)); 122 if (cookie == NULL) { 123 close(fd); 124 fetch_syserr(); 125 return NULL; 126 } 127 128 *cookie = fd; 129 f = fetchIO_unopen(cookie, fetchFile_read, fetchFile_write, fetchFile_close); 130 if (f == NULL) { 131 close(fd); 132 free(cookie); 133 } 134 return f; 135 } 136 137 fetchIO * 138 fetchGetFile(struct url *u, const char *flags) 139 { 140 return (fetchXGetFile(u, NULL, flags)); 141 } 142 143 fetchIO * 144 fetchPutFile(struct url *u, const char *flags) 145 { 146 char *path; 147 fetchIO *f; 148 int fd, *cookie; 149 150 if ((path = fetchUnquotePath(u)) == NULL) { 151 fetch_syserr(); 152 return NULL; 153 } 154 155 if (CHECK_FLAG('a')) 156 fd = open(path, O_WRONLY | O_APPEND); 157 else 158 fd = open(path, O_WRONLY); 159 160 free(path); 161 162 if (fd == -1) { 163 fetch_syserr(); 164 return NULL; 165 } 166 167 if (u->offset && lseek(fd, u->offset, SEEK_SET) == -1) { 168 close(fd); 169 fetch_syserr(); 170 return NULL; 171 } 172 173 cookie = malloc(sizeof(int)); 174 if (cookie == NULL) { 175 close(fd); 176 fetch_syserr(); 177 return NULL; 178 } 179 180 *cookie = fd; 181 f = fetchIO_unopen(cookie, fetchFile_read, fetchFile_write, fetchFile_close); 182 if (f == NULL) { 183 close(fd); 184 free(cookie); 185 } 186 return f; 187 } 188 189 static int 190 fetch_stat_file(int fd, struct url_stat *us) 191 { 192 struct stat sb; 193 194 us->size = -1; 195 us->atime = us->mtime = 0; 196 if (fstat(fd, &sb) == -1) { 197 fetch_syserr(); 198 return (-1); 199 } 200 us->size = sb.st_size; 201 us->atime = sb.st_atime; 202 us->mtime = sb.st_mtime; 203 return (0); 204 } 205 206 int 207 /*ARGSUSED*/ 208 fetchStatFile(struct url *u, struct url_stat *us, const char *flags __unused) 209 { 210 char *path; 211 int fd, rv; 212 213 if ((path = fetchUnquotePath(u)) == NULL) { 214 fetch_syserr(); 215 return -1; 216 } 217 218 fd = open(path, O_RDONLY); 219 free(path); 220 221 if (fd == -1) { 222 fetch_syserr(); 223 return -1; 224 } 225 226 rv = fetch_stat_file(fd, us); 227 close(fd); 228 229 return rv; 230 } 231 232 int 233 /*ARGSUSED*/ 234 fetchListFile(struct url_list *ue, struct url *u, const char *pattern, 235 const char *flags __unused) 236 { 237 char *path; 238 struct dirent *de; 239 DIR *dir; 240 int ret; 241 242 if ((path = fetchUnquotePath(u)) == NULL) { 243 fetch_syserr(); 244 return -1; 245 } 246 247 dir = opendir(path); 248 free(path); 249 250 if (dir == NULL) { 251 fetch_syserr(); 252 return -1; 253 } 254 255 ret = 0; 256 257 while ((de = readdir(dir)) != NULL) { 258 if (pattern && fnmatch(pattern, de->d_name, 0) != 0) 259 continue; 260 ret = fetch_add_entry(ue, u, de->d_name, 0); 261 if (ret) 262 break; 263 } 264 265 closedir(dir); 266 267 return ret; 268 } 269