xref: /minix/external/bsd/fetch/dist/libfetch/file.c (revision 0a6a1f1d)
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