1 /*
2 Copyright (C) 2000 Masanao Izumo <mo@goice.co.jp>
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 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #include "config.h"
20 #include <stdio.h>
21 #include <stdlib.h>
22 #ifndef NO_STRING_H
23 #include <string.h>
24 #else
25 #include <strings.h>
26 #endif
27 #include <fcntl.h>
28
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif /* HAVE_UNISTD_H */
32
33 #ifdef __W32__
34 #include <windows.h>
35 #endif /* __W32__ */
36
37
38 #ifdef HAVE_MMAP
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <sys/mman.h>
42 #ifndef MAP_FAILED
43 #define MAP_FAILED ((caddr_t)-1)
44 #endif /* MAP_FAILED */
45
46 #else
47 /* mmap is not supported */
48 #ifdef __W32__
49 #define try_mmap(fname, size_ret) w32_mmap(fname, size_ret, &hFile, &hMap)
50 #define munmap(addr, size) w32_munmap(addr, size, hFile, hMap)
51 #else
52 #define try_mmap(dmy1, dmy2) NULL
53 #define munmap(addr, size) /* Do nothing */
54 #endif /* __W32__ */
55 #endif
56
57 #include "libarc/url.h"
58 #ifdef __MACOS__
59 #include "libarc/mblock.h"
60 #endif
61
62 #if !defined(__W32__) && !defined(O_BINARY)
63 #define O_BINARY 0
64 #endif
65
66 typedef struct _URL_file
67 {
68 char common[sizeof(struct _URL)];
69
70 char *mapptr; /* Non NULL if mmap is success */
71 long mapsize;
72 long pos;
73
74 #ifdef __W32__
75 HANDLE hFile, hMap;
76 #endif /* __W32__ */
77
78 FILE *fp; /* Non NULL if mmap is failure */
79 } URL_file;
80
81 static int name_file_check(char *url_string);
82 static long url_file_read(URL url, void *buff, long n);
83 static char *url_file_gets(URL url, char *buff, int n);
84 static int url_file_fgetc(URL url);
85 static long url_file_seek(URL url, long offset, int whence);
86 static long url_file_tell(URL url);
87 static void url_file_close(URL url);
88
89 struct URL_module URL_module_file =
90 {
91 URL_file_t, /* type */
92 name_file_check, /* URL checker */
93 NULL, /* initializer */
94 url_file_open, /* open */
95 NULL /* must be NULL */
96 };
97
name_file_check(char * s)98 static int name_file_check(char *s)
99 {
100 int i;
101
102 if(IS_PATH_SEP(s[0]))
103 return 1;
104
105 if(strncasecmp(s, "file:", 5) == 0)
106 return 1;
107
108 #ifdef __W32__
109 /* [A-Za-z]: (for Windows) */
110 if((('A' <= s[0] && s[0] <= 'Z') ||
111 ('a' <= s[0] && s[0] <= 'z')) &&
112 s[1] == ':')
113 return 1;
114 #endif /* __W32__ */
115
116 for(i = 0; s[i] && s[i] != ':' && s[i] != '/'; i++)
117 ;
118 if(s[i] == ':' && s[i + 1] == '/')
119 return 0;
120
121 return 1;
122 }
123
124 #ifdef HAVE_MMAP
try_mmap(char * path,long * size)125 static char *try_mmap(char *path, long *size)
126 {
127 int fd;
128 char *p;
129 struct stat st;
130
131 errno = 0;
132 fd = open(path, O_RDONLY | O_BINARY);
133 if(fd < 0)
134 return NULL;
135
136 if(fstat(fd, &st) < 0)
137 {
138 int save_errno = errno;
139 close(fd);
140 errno = save_errno;
141 return NULL;
142 }
143
144 p = (char *)mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
145 if(p == (char *)MAP_FAILED)
146 {
147 int save_errno = errno;
148 close(fd);
149 errno = save_errno;
150 return NULL;
151 }
152 close(fd);
153 *size = (long)st.st_size;
154 return p;
155 }
156 #elif defined(__W32__)
w32_mmap(char * fname,long * size_ret,HANDLE * hFilePtr,HANDLE * hMapPtr)157 static void *w32_mmap(char *fname, long *size_ret, HANDLE *hFilePtr, HANDLE *hMapPtr)
158 {
159 void *map;
160
161 *hFilePtr = CreateFile(fname, GENERIC_READ, 0, NULL,
162 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
163 if(*hFilePtr == INVALID_HANDLE_VALUE)
164 return NULL;
165 *size_ret = GetFileSize(*hFilePtr, NULL);
166 if(*size_ret == 0xffffffff)
167 {
168 CloseHandle(*hFilePtr);
169 return NULL;
170 }
171 *hMapPtr = CreateFileMapping(*hFilePtr, NULL, PAGE_READONLY,
172 0, 0, NULL);
173 if(*hMapPtr == NULL)
174 {
175 CloseHandle(*hFilePtr);
176 return NULL;
177 }
178 map = MapViewOfFile(*hMapPtr, FILE_MAP_READ, 0, 0, 0);
179 if(map == NULL)
180 {
181 CloseHandle(*hMapPtr);
182 CloseHandle(*hFilePtr);
183 return NULL;
184 }
185 return map;
186 }
w32_munmap(void * ptr,long size,HANDLE hFile,HANDLE hMap)187 static void w32_munmap(void *ptr, long size, HANDLE hFile, HANDLE hMap)
188 {
189 UnmapViewOfFile(ptr);
190 CloseHandle(hMap);
191 CloseHandle(hFile);
192 }
193 #endif /* HAVE_MMAP */
194
url_file_open(char * fname)195 URL url_file_open(char *fname)
196 {
197 URL_file *url;
198 char *mapptr; /* Non NULL if mmap is success */
199 long mapsize;
200 FILE *fp; /* Non NULL if mmap is failure */
201 #ifdef __W32__
202 HANDLE hFile, hMap;
203 #endif /* __W32__ */
204
205 #ifdef DEBUG
206 printf("url_file_open(%s)\n", fname);
207 #endif /* DEBUG */
208
209 if(!strcmp(fname, "-"))
210 {
211 mapptr = NULL;
212 mapsize = 0;
213 fp = stdin;
214 goto done;
215 }
216
217 if(strncasecmp(fname, "file:", 5) == 0)
218 fname += 5;
219 if(*fname == '\0')
220 {
221 url_errno = errno = ENOENT;
222 return NULL;
223 }
224 fname = url_expand_home_dir(fname);
225
226 fp = NULL;
227 mapsize = 0;
228 errno = 0;
229 mapptr = try_mmap(fname, &mapsize);
230 if(errno == ENOENT || errno == EACCES)
231 {
232 url_errno = errno;
233 return NULL;
234 }
235
236 #ifdef DEBUG
237 if(mapptr != NULL)
238 printf("mmap - success. size=%d\n", mapsize);
239 #ifdef HAVE_MMAP
240 else
241 printf("mmap - failure.\n");
242 #endif
243 #endif /* DEBUG */
244
245
246 if(mapptr == NULL)
247 {
248 #ifdef __MACOS__
249 char *cnvname;
250 MBlockList pool;
251 init_mblock(&pool);
252 cnvname = (char *)strdup_mblock(&pool, fname);
253 mac_TransPathSeparater(fname, cnvname);
254 fp = fopen(cnvname, "rb");
255 reuse_mblock(&pool);
256 if( fp==NULL ){ /*try original name*/
257 fp = fopen(fname, "rb");
258 }
259 #else
260 fp = fopen(fname, "rb");
261 #endif
262 if(fp == NULL)
263 {
264 url_errno = errno;
265 return NULL;
266 }
267 }
268
269 done:
270 url = (URL_file *)alloc_url(sizeof(URL_file));
271 if(url == NULL)
272 {
273 url_errno = errno;
274 if(mapptr)
275 munmap(mapptr, mapsize);
276 if(fp && fp != stdin)
277 fclose(fp);
278 errno = url_errno;
279 return NULL;
280 }
281
282 /* common members */
283 URLm(url, type) = URL_file_t;
284 URLm(url, url_read) = url_file_read;
285 URLm(url, url_gets) = url_file_gets;
286 URLm(url, url_fgetc) = url_file_fgetc;
287 URLm(url, url_close) = url_file_close;
288 if(fp == stdin)
289 {
290 URLm(url, url_seek) = NULL;
291 URLm(url, url_tell) = NULL;
292 }
293 else
294 {
295 URLm(url, url_seek) = url_file_seek;
296 URLm(url, url_tell) = url_file_tell;
297 }
298
299 /* private members */
300 url->mapptr = mapptr;
301 url->mapsize = mapsize;
302 url->pos = 0;
303 url->fp = fp;
304 #ifdef __W32__
305 url->hFile = hFile;
306 url->hMap = hMap;
307 #endif /* __W32__ */
308
309 return (URL)url;
310 }
311
url_file_read(URL url,void * buff,long n)312 static long url_file_read(URL url, void *buff, long n)
313 {
314 URL_file *urlp = (URL_file *)url;
315
316 if(urlp->mapptr != NULL)
317 {
318 if(urlp->pos + n > urlp->mapsize)
319 n = urlp->mapsize - urlp->pos;
320 memcpy(buff, urlp->mapptr + urlp->pos, n);
321 urlp->pos += n;
322 }
323 else
324 {
325 if((n = (long)fread(buff, 1, n, urlp->fp)) == 0)
326 {
327 if(ferror(urlp->fp))
328 {
329 url_errno = errno;
330 return -1;
331 }
332 return 0;
333 }
334 }
335 return n;
336 }
337
url_file_gets(URL url,char * buff,int n)338 char *url_file_gets(URL url, char *buff, int n)
339 {
340 URL_file *urlp = (URL_file *)url;
341
342 if(urlp->mapptr != NULL)
343 {
344 long s;
345 char *nlp, *p;
346
347 if(urlp->mapsize == urlp->pos)
348 return NULL;
349 if(n <= 0)
350 return buff;
351 if(n == 1)
352 {
353 *buff = '\0';
354 return buff;
355 }
356 n--; /* for '\0' */
357 s = urlp->mapsize - urlp->pos;
358 if(s > n)
359 s = n;
360 p = urlp->mapptr + urlp->pos;
361 nlp = (char *)memchr(p, url_newline_code, s);
362 if(nlp != NULL)
363 s = nlp - p + 1;
364 memcpy(buff, p, s);
365 buff[s] = '\0';
366 urlp->pos += s;
367 return buff;
368 }
369
370 return fgets(buff, n, urlp->fp);
371 }
372
url_file_fgetc(URL url)373 int url_file_fgetc(URL url)
374 {
375 URL_file *urlp = (URL_file *)url;
376
377 if(urlp->mapptr != NULL)
378 {
379 if(urlp->mapsize == urlp->pos)
380 return EOF;
381 return urlp->mapptr[urlp->pos++] & 0xff;
382 }
383
384 #ifdef getc
385 return getc(urlp->fp);
386 #else
387 return fgetc(urlp->fp);
388 #endif /* getc */
389 }
390
url_file_close(URL url)391 static void url_file_close(URL url)
392 {
393 URL_file *urlp = (URL_file *)url;
394
395 if(urlp->mapptr != NULL)
396 {
397 #ifdef __W32__
398 HANDLE hFile = urlp->hFile;
399 HANDLE hMap = urlp->hMap;
400 #endif /* __W32__ */
401 munmap(urlp->mapptr, urlp->mapsize);
402 }
403 if(urlp->fp != NULL)
404 {
405 if(urlp->fp == stdin)
406 rewind(stdin);
407 else
408 fclose(urlp->fp);
409 }
410 free(url);
411 }
412
url_file_seek(URL url,long offset,int whence)413 static long url_file_seek(URL url, long offset, int whence)
414 {
415 URL_file *urlp = (URL_file *)url;
416 long ret;
417
418 if(urlp->mapptr == NULL)
419 return fseek(urlp->fp, offset, whence);
420 ret = urlp->pos;
421 switch(whence)
422 {
423 case SEEK_SET:
424 urlp->pos = offset;
425 break;
426 case SEEK_CUR:
427 urlp->pos += offset;
428 break;
429 case SEEK_END:
430 urlp->pos = urlp->mapsize + offset;
431 break;
432 }
433 if(urlp->pos > urlp->mapsize)
434 urlp->pos = urlp->mapsize;
435 else if(urlp->pos < 0)
436 urlp->pos = 0;
437
438 return ret;
439 }
440
url_file_tell(URL url)441 static long url_file_tell(URL url)
442 {
443 URL_file *urlp = (URL_file *)url;
444
445 return urlp->mapptr ? urlp->pos : ftell(urlp->fp);
446 }
447