xref: /netbsd/external/bsd/fetch/dist/libfetch/file.c (revision 6550d01e)
1 /*	$NetBSD: file.c,v 1.1.1.6 2009/10/15 12:59:59 joerg 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 fetchStatFile(struct url *u, struct url_stat *us, const char *flags)
208 {
209 	char *path;
210 	int fd, rv;
211 
212 	if ((path = fetchUnquotePath(u)) == NULL) {
213 		fetch_syserr();
214 		return -1;
215 	}
216 
217 	fd = open(path, O_RDONLY);
218 	free(path);
219 
220 	if (fd == -1) {
221 		fetch_syserr();
222 		return -1;
223 	}
224 
225 	rv = fetch_stat_file(fd, us);
226 	close(fd);
227 
228 	return rv;
229 }
230 
231 int
232 fetchListFile(struct url_list *ue, struct url *u, const char *pattern, const char *flags)
233 {
234 	char *path;
235 	struct dirent *de;
236 	DIR *dir;
237 	int ret;
238 
239 	if ((path = fetchUnquotePath(u)) == NULL) {
240 		fetch_syserr();
241 		return -1;
242 	}
243 
244 	dir = opendir(path);
245 	free(path);
246 
247 	if (dir == NULL) {
248 		fetch_syserr();
249 		return -1;
250 	}
251 
252 	ret = 0;
253 
254 	while ((de = readdir(dir)) != NULL) {
255 		if (pattern && fnmatch(pattern, de->d_name, 0) != 0)
256 			continue;
257 		ret = fetch_add_entry(ue, u, de->d_name, 0);
258 		if (ret)
259 			break;
260 	}
261 
262 	closedir(dir);
263 
264 	return ret;
265 }
266