archive_read_open_filename.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. /*-
  2. * Copyright (c) 2003-2007 Tim Kientzle
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
  15. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  16. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  17. * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
  18. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  19. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  20. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  21. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  23. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. #include "archive_platform.h"
  26. __FBSDID("$FreeBSD: src/lib/libarchive/archive_read_open_filename.c,v 1.21 2008/02/19 06:10:48 kientzle Exp $");
  27. #ifdef HAVE_SYS_STAT_H
  28. #include <sys/stat.h>
  29. #endif
  30. #ifdef HAVE_ERRNO_H
  31. #include <errno.h>
  32. #endif
  33. #ifdef HAVE_FCNTL_H
  34. #include <fcntl.h>
  35. #endif
  36. #ifdef HAVE_IO_H
  37. #include <io.h>
  38. #endif
  39. #ifdef HAVE_STDLIB_H
  40. #include <stdlib.h>
  41. #endif
  42. #ifdef HAVE_STRING_H
  43. #include <string.h>
  44. #endif
  45. #ifdef HAVE_UNISTD_H
  46. #include <unistd.h>
  47. #endif
  48. #include "archive.h"
  49. #ifndef O_BINARY
  50. #define O_BINARY 0
  51. #endif
  52. struct read_file_data {
  53. int fd;
  54. size_t block_size;
  55. void *buffer;
  56. mode_t st_mode; /* Mode bits for opened file. */
  57. char can_skip; /* This file supports skipping. */
  58. char filename[1]; /* Must be last! */
  59. };
  60. static int file_close(struct archive *, void *);
  61. static ssize_t file_read(struct archive *, void *, const void **buff);
  62. #if ARCHIVE_API_VERSION < 2
  63. static ssize_t file_skip(struct archive *, void *, size_t request);
  64. #else
  65. static off_t file_skip(struct archive *, void *, off_t request);
  66. #endif
  67. int
  68. archive_read_open_file(struct archive *a, const char *filename,
  69. size_t block_size)
  70. {
  71. return (archive_read_open_filename(a, filename, block_size));
  72. }
  73. int
  74. archive_read_open_filename(struct archive *a, const char *filename,
  75. size_t block_size)
  76. {
  77. struct stat st;
  78. struct read_file_data *mine;
  79. void *b;
  80. int fd;
  81. archive_clear_error(a);
  82. if (filename == NULL || filename[0] == '\0') {
  83. /* We used to invoke archive_read_open_fd(a,0,block_size)
  84. * here, but that doesn't (and shouldn't) handle the
  85. * end-of-file flush when reading stdout from a pipe.
  86. * Basically, read_open_fd() is intended for folks who
  87. * are willing to handle such details themselves. This
  88. * API is intended to be a little smarter for folks who
  89. * want easy handling of the common case.
  90. */
  91. filename = ""; /* Normalize NULL to "" */
  92. fd = 0;
  93. #if defined(__CYGWIN__) || defined(__BORLANDC__)
  94. setmode(0, O_BINARY);
  95. #elif defined(_WIN32)
  96. _setmode(0, _O_BINARY);
  97. #endif
  98. } else {
  99. fd = open(filename, O_RDONLY | O_BINARY);
  100. if (fd < 0) {
  101. archive_set_error(a, errno,
  102. "Failed to open '%s'", filename);
  103. return (ARCHIVE_FATAL);
  104. }
  105. }
  106. if (fstat(fd, &st) != 0) {
  107. archive_set_error(a, errno, "Can't stat '%s'", filename);
  108. return (ARCHIVE_FATAL);
  109. }
  110. mine = (struct read_file_data *)calloc(1,
  111. sizeof(*mine) + strlen(filename));
  112. b = malloc(block_size);
  113. if (mine == NULL || b == NULL) {
  114. archive_set_error(a, ENOMEM, "No memory");
  115. free(mine);
  116. free(b);
  117. return (ARCHIVE_FATAL);
  118. }
  119. strcpy(mine->filename, filename);
  120. mine->block_size = block_size;
  121. mine->buffer = b;
  122. mine->fd = fd;
  123. /* Remember mode so close can decide whether to flush. */
  124. mine->st_mode = st.st_mode;
  125. /* If we're reading a file from disk, ensure that we don't
  126. overwrite it with an extracted file. */
  127. if (S_ISREG(st.st_mode)) {
  128. archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino);
  129. /*
  130. * Enabling skip here is a performance optimization
  131. * for anything that supports lseek(). On FreeBSD
  132. * (and probably many other systems), only regular
  133. * files and raw disk devices support lseek() (on
  134. * other input types, lseek() returns success but
  135. * doesn't actually change the file pointer, which
  136. * just completely screws up the position-tracking
  137. * logic). In addition, I've yet to find a portable
  138. * way to determine if a device is a raw disk device.
  139. * So I don't see a way to do much better than to only
  140. * enable this optimization for regular files.
  141. */
  142. mine->can_skip = 1;
  143. }
  144. return (archive_read_open2(a, mine,
  145. NULL, file_read, file_skip, file_close));
  146. }
  147. static ssize_t
  148. file_read(struct archive *a, void *client_data, const void **buff)
  149. {
  150. struct read_file_data *mine = (struct read_file_data *)client_data;
  151. ssize_t bytes_read;
  152. *buff = mine->buffer;
  153. bytes_read = read(mine->fd, mine->buffer, mine->block_size);
  154. if (bytes_read < 0) {
  155. if (mine->filename[0] == '\0')
  156. archive_set_error(a, errno, "Error reading stdin");
  157. else
  158. archive_set_error(a, errno, "Error reading '%s'",
  159. mine->filename);
  160. }
  161. return (bytes_read);
  162. }
  163. #if ARCHIVE_API_VERSION < 2
  164. static ssize_t
  165. file_skip(struct archive *a, void *client_data, size_t request)
  166. #else
  167. static off_t
  168. file_skip(struct archive *a, void *client_data, off_t request)
  169. #endif
  170. {
  171. struct read_file_data *mine = (struct read_file_data *)client_data;
  172. off_t old_offset, new_offset;
  173. if (!mine->can_skip) /* We can't skip, so ... */
  174. return (0); /* ... skip zero bytes. */
  175. /* Reduce request to the next smallest multiple of block_size */
  176. request = (request / mine->block_size) * mine->block_size;
  177. if (request == 0)
  178. return (0);
  179. /*
  180. * Hurray for lazy evaluation: if the first lseek fails, the second
  181. * one will not be executed.
  182. */
  183. if (((old_offset = lseek(mine->fd, 0, SEEK_CUR)) < 0) ||
  184. ((new_offset = lseek(mine->fd, request, SEEK_CUR)) < 0))
  185. {
  186. /* If skip failed once, it will probably fail again. */
  187. mine->can_skip = 0;
  188. if (errno == ESPIPE)
  189. {
  190. /*
  191. * Failure to lseek() can be caused by the file
  192. * descriptor pointing to a pipe, socket or FIFO.
  193. * Return 0 here, so the compression layer will use
  194. * read()s instead to advance the file descriptor.
  195. * It's slower of course, but works as well.
  196. */
  197. return (0);
  198. }
  199. /*
  200. * There's been an error other than ESPIPE. This is most
  201. * likely caused by a programmer error (too large request)
  202. * or a corrupted archive file.
  203. */
  204. if (mine->filename[0] == '\0')
  205. /*
  206. * Should never get here, since lseek() on stdin ought
  207. * to return an ESPIPE error.
  208. */
  209. archive_set_error(a, errno, "Error seeking in stdin");
  210. else
  211. archive_set_error(a, errno, "Error seeking in '%s'",
  212. mine->filename);
  213. return (-1);
  214. }
  215. return (new_offset - old_offset);
  216. }
  217. static int
  218. file_close(struct archive *a, void *client_data)
  219. {
  220. struct read_file_data *mine = (struct read_file_data *)client_data;
  221. (void)a; /* UNUSED */
  222. /* Only flush and close if open succeeded. */
  223. if (mine->fd >= 0) {
  224. /*
  225. * Sometimes, we should flush the input before closing.
  226. * Regular files: faster to just close without flush.
  227. * Devices: must not flush (user might need to
  228. * read the "next" item on a non-rewind device).
  229. * Pipes and sockets: must flush (otherwise, the
  230. * program feeding the pipe or socket may complain).
  231. * Here, I flush everything except for regular files and
  232. * device nodes.
  233. */
  234. if (!S_ISREG(mine->st_mode)
  235. && !S_ISCHR(mine->st_mode)
  236. && !S_ISBLK(mine->st_mode)) {
  237. ssize_t bytesRead;
  238. do {
  239. bytesRead = read(mine->fd, mine->buffer,
  240. mine->block_size);
  241. } while (bytesRead > 0);
  242. }
  243. /* If a named file was opened, then it needs to be closed. */
  244. if (mine->filename[0] != '\0')
  245. close(mine->fd);
  246. }
  247. free(mine->buffer);
  248. free(mine);
  249. return (ARCHIVE_OK);
  250. }