archive_read_open_filename.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  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_STDLIB_H
  37. #include <stdlib.h>
  38. #endif
  39. #ifdef HAVE_STRING_H
  40. #include <string.h>
  41. #endif
  42. #ifdef HAVE_UNISTD_H
  43. #include <unistd.h>
  44. #endif
  45. #include "archive.h"
  46. #ifndef O_BINARY
  47. #define O_BINARY 0
  48. #endif
  49. struct read_file_data {
  50. int fd;
  51. size_t block_size;
  52. void *buffer;
  53. mode_t st_mode; /* Mode bits for opened file. */
  54. char can_skip; /* This file supports skipping. */
  55. char filename[1]; /* Must be last! */
  56. };
  57. static int file_close(struct archive *, void *);
  58. static ssize_t file_read(struct archive *, void *, const void **buff);
  59. #if ARCHIVE_API_VERSION < 2
  60. static ssize_t file_skip(struct archive *, void *, size_t request);
  61. #else
  62. static off_t file_skip(struct archive *, void *, off_t request);
  63. #endif
  64. int
  65. archive_read_open_file(struct archive *a, const char *filename,
  66. size_t block_size)
  67. {
  68. return (archive_read_open_filename(a, filename, block_size));
  69. }
  70. int
  71. archive_read_open_filename(struct archive *a, const char *filename,
  72. size_t block_size)
  73. {
  74. struct stat st;
  75. struct read_file_data *mine;
  76. void *b;
  77. int fd;
  78. if (filename == NULL || filename[0] == '\0')
  79. return (archive_read_open_fd(a, 0, block_size));
  80. fd = open(filename, O_RDONLY | O_BINARY);
  81. if (fd < 0) {
  82. archive_set_error(a, errno, "Failed to open '%s'", filename);
  83. return (ARCHIVE_FATAL);
  84. }
  85. if (fstat(fd, &st) != 0) {
  86. archive_set_error(a, errno, "Can't stat '%s'", filename);
  87. close(fd);
  88. return (ARCHIVE_FATAL);
  89. }
  90. mine = (struct read_file_data *)malloc(sizeof(*mine) + strlen(filename));
  91. b = malloc(block_size);
  92. if (mine == NULL || b == NULL) {
  93. archive_set_error(a, ENOMEM, "No memory");
  94. close(fd);
  95. free(mine);
  96. free(b);
  97. return (ARCHIVE_FATAL);
  98. }
  99. strcpy(mine->filename, filename);
  100. mine->block_size = block_size;
  101. mine->buffer = b;
  102. mine->fd = fd;
  103. /* Remember mode so close can decide whether to flush. */
  104. mine->st_mode = st.st_mode;
  105. /* If we're reading a file from disk, ensure that we don't
  106. overwrite it with an extracted file. */
  107. if (S_ISREG(st.st_mode)) {
  108. archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino);
  109. /*
  110. * Skip is a performance optimization for anything
  111. * that supports lseek(). Generally, that only
  112. * includes regular files and possibly raw disk
  113. * devices, but there's no good portable way to detect
  114. * raw disks.
  115. */
  116. mine->can_skip = 1;
  117. } else
  118. mine->can_skip = 0;
  119. return (archive_read_open2(a, mine,
  120. NULL, file_read, file_skip, file_close));
  121. }
  122. static ssize_t
  123. file_read(struct archive *a, void *client_data, const void **buff)
  124. {
  125. struct read_file_data *mine = (struct read_file_data *)client_data;
  126. ssize_t bytes_read;
  127. *buff = mine->buffer;
  128. bytes_read = read(mine->fd, mine->buffer, mine->block_size);
  129. if (bytes_read < 0) {
  130. archive_set_error(a, errno, "Error reading '%s'",
  131. mine->filename);
  132. }
  133. return (bytes_read);
  134. }
  135. #if ARCHIVE_API_VERSION < 2
  136. static ssize_t
  137. file_skip(struct archive *a, void *client_data, size_t request)
  138. #else
  139. static off_t
  140. file_skip(struct archive *a, void *client_data, off_t request)
  141. #endif
  142. {
  143. struct read_file_data *mine = (struct read_file_data *)client_data;
  144. off_t old_offset, new_offset;
  145. if (!mine->can_skip) /* We can't skip, so ... */
  146. return (0); /* ... skip zero bytes. */
  147. /* Reduce request to the next smallest multiple of block_size */
  148. request = (request / mine->block_size) * mine->block_size;
  149. if (request == 0)
  150. return (0);
  151. /*
  152. * Hurray for lazy evaluation: if the first lseek fails, the second
  153. * one will not be executed.
  154. */
  155. if (((old_offset = lseek(mine->fd, 0, SEEK_CUR)) < 0) ||
  156. ((new_offset = lseek(mine->fd, request, SEEK_CUR)) < 0))
  157. {
  158. /* If skip failed once, it will probably fail again. */
  159. mine->can_skip = 0;
  160. if (errno == ESPIPE)
  161. {
  162. /*
  163. * Failure to lseek() can be caused by the file
  164. * descriptor pointing to a pipe, socket or FIFO.
  165. * Return 0 here, so the compression layer will use
  166. * read()s instead to advance the file descriptor.
  167. * It's slower of course, but works as well.
  168. */
  169. return (0);
  170. }
  171. /*
  172. * There's been an error other than ESPIPE. This is most
  173. * likely caused by a programmer error (too large request)
  174. * or a corrupted archive file.
  175. */
  176. archive_set_error(a, errno, "Error seeking in '%s'",
  177. mine->filename);
  178. return (-1);
  179. }
  180. return (new_offset - old_offset);
  181. }
  182. static int
  183. file_close(struct archive *a, void *client_data)
  184. {
  185. struct read_file_data *mine = (struct read_file_data *)client_data;
  186. (void)a; /* UNUSED */
  187. /* Only flush and close if open succeeded. */
  188. if (mine->fd >= 0) {
  189. /*
  190. * Sometimes, we should flush the input before closing.
  191. * Regular files: faster to just close without flush.
  192. * Devices: must not flush (user might need to
  193. * read the "next" item on a non-rewind device).
  194. * Pipes and sockets: must flush (otherwise, the
  195. * program feeding the pipe or socket may complain).
  196. * Here, I flush everything except for regular files and
  197. * device nodes.
  198. */
  199. if (!S_ISREG(mine->st_mode)
  200. && !S_ISCHR(mine->st_mode)
  201. && !S_ISBLK(mine->st_mode)) {
  202. ssize_t bytesRead;
  203. do {
  204. bytesRead = read(mine->fd, mine->buffer,
  205. mine->block_size);
  206. } while (bytesRead > 0);
  207. }
  208. close(mine->fd);
  209. }
  210. free(mine->buffer);
  211. free(mine);
  212. return (ARCHIVE_OK);
  213. }