xref: /netbsd-src/external/bsd/fetch/dist/libfetch/file.c (revision c8a35b6227034951e874c2def577388e79ede4a5)
1 /*	$NetBSD: file.c,v 1.1.1.4 2009/03/10 00:44:20 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 		fetchLastErrCode = FETCH_UNCHANGED;
110 		snprintf(fetchLastErrString, MAXERRSTRING, "Unchanged");
111 		return NULL;
112 	}
113 
114 	if (u->offset && lseek(fd, u->offset, SEEK_SET) == -1) {
115 		close(fd);
116 		fetch_syserr();
117 		return NULL;
118 	}
119 
120 	cookie = malloc(sizeof(int));
121 	if (cookie == NULL) {
122 		close(fd);
123 		fetch_syserr();
124 		return NULL;
125 	}
126 
127 	*cookie = fd;
128 	f = fetchIO_unopen(cookie, fetchFile_read, fetchFile_write, fetchFile_close);
129 	if (f == NULL) {
130 		close(fd);
131 		free(cookie);
132 	}
133 	return f;
134 }
135 
136 fetchIO *
137 fetchGetFile(struct url *u, const char *flags)
138 {
139 	return (fetchXGetFile(u, NULL, flags));
140 }
141 
142 fetchIO *
143 fetchPutFile(struct url *u, const char *flags)
144 {
145 	char *path;
146 	fetchIO *f;
147 	int fd, *cookie;
148 
149 	if ((path = fetchUnquotePath(u)) == NULL) {
150 		fetch_syserr();
151 		return NULL;
152 	}
153 
154 	if (CHECK_FLAG('a'))
155 		fd = open(path, O_WRONLY | O_APPEND);
156 	else
157 		fd = open(path, O_WRONLY);
158 
159 	free(path);
160 
161 	if (fd == -1) {
162 		fetch_syserr();
163 		return NULL;
164 	}
165 
166 	if (u->offset && lseek(fd, u->offset, SEEK_SET) == -1) {
167 		close(fd);
168 		fetch_syserr();
169 		return NULL;
170 	}
171 
172 	cookie = malloc(sizeof(int));
173 	if (cookie == NULL) {
174 		close(fd);
175 		fetch_syserr();
176 		return NULL;
177 	}
178 
179 	*cookie = fd;
180 	f = fetchIO_unopen(cookie, fetchFile_read, fetchFile_write, fetchFile_close);
181 	if (f == NULL) {
182 		close(fd);
183 		free(cookie);
184 	}
185 	return f;
186 }
187 
188 static int
189 fetch_stat_file(int fd, struct url_stat *us)
190 {
191 	struct stat sb;
192 
193 	us->size = -1;
194 	us->atime = us->mtime = 0;
195 	if (fstat(fd, &sb) == -1) {
196 		fetch_syserr();
197 		return (-1);
198 	}
199 	us->size = sb.st_size;
200 	us->atime = sb.st_atime;
201 	us->mtime = sb.st_mtime;
202 	return (0);
203 }
204 
205 int
206 fetchStatFile(struct url *u, struct url_stat *us, const char *flags)
207 {
208 	char *path;
209 	int fd, rv;
210 
211 	if ((path = fetchUnquotePath(u)) == NULL) {
212 		fetch_syserr();
213 		return -1;
214 	}
215 
216 	fd = open(path, O_RDONLY);
217 	free(path);
218 
219 	if (fd == -1) {
220 		fetch_syserr();
221 		return -1;
222 	}
223 
224 	rv = fetch_stat_file(fd, us);
225 	close(fd);
226 
227 	return rv;
228 }
229 
230 int
231 fetchListFile(struct url_list *ue, struct url *u, const char *pattern, const char *flags)
232 {
233 	char *path;
234 	struct dirent *de;
235 	DIR *dir;
236 
237 	if ((path = fetchUnquotePath(u)) == NULL) {
238 		fetch_syserr();
239 		return -1;
240 	}
241 
242 	dir = opendir(path);
243 	free(path);
244 
245 	if (dir == NULL) {
246 		fetch_syserr();
247 		return -1;
248 	}
249 
250 	while ((de = readdir(dir)) != NULL) {
251 		if (pattern && fnmatch(pattern, de->d_name, 0) != 0)
252 			continue;
253 		fetch_add_entry(ue, u, de->d_name, 0);
254 	}
255 
256 	return 0;
257 }
258