HardenedBSD src tree
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

296 lines
8.1KB

  1. /*-
  2. * Copyright (c) 2012 Michihiro NAKAJIMA
  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$");
  27. #ifdef HAVE_ERRNO_H
  28. #include <errno.h>
  29. #endif
  30. #ifdef HAVE_STDLIB_H
  31. #include <stdlib.h>
  32. #endif
  33. #ifdef HAVE_STRING_H
  34. #include <string.h>
  35. #endif
  36. #include "archive.h"
  37. #include "archive_private.h"
  38. #include "archive_string.h"
  39. #include "archive_write_private.h"
  40. #define LBYTES 45
  41. struct private_uuencode {
  42. int mode;
  43. struct archive_string name;
  44. struct archive_string encoded_buff;
  45. size_t bs;
  46. size_t hold_len;
  47. unsigned char hold[LBYTES];
  48. };
  49. static int archive_filter_uuencode_options(struct archive_write_filter *,
  50. const char *, const char *);
  51. static int archive_filter_uuencode_open(struct archive_write_filter *);
  52. static int archive_filter_uuencode_write(struct archive_write_filter *,
  53. const void *, size_t);
  54. static int archive_filter_uuencode_close(struct archive_write_filter *);
  55. static int archive_filter_uuencode_free(struct archive_write_filter *);
  56. static void uu_encode(struct archive_string *, const unsigned char *, size_t);
  57. static int64_t atol8(const char *, size_t);
  58. /*
  59. * Add a compress filter to this write handle.
  60. */
  61. int
  62. archive_write_add_filter_uuencode(struct archive *_a)
  63. {
  64. struct archive_write *a = (struct archive_write *)_a;
  65. struct archive_write_filter *f = __archive_write_allocate_filter(_a);
  66. struct private_uuencode *state;
  67. archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
  68. ARCHIVE_STATE_NEW, "archive_write_add_filter_uu");
  69. state = (struct private_uuencode *)calloc(1, sizeof(*state));
  70. if (state == NULL) {
  71. archive_set_error(f->archive, ENOMEM,
  72. "Can't allocate data for uuencode filter");
  73. return (ARCHIVE_FATAL);
  74. }
  75. archive_strcpy(&state->name, "-");
  76. state->mode = 0644;
  77. f->data = state;
  78. f->name = "uuencode";
  79. f->code = ARCHIVE_FILTER_UU;
  80. f->open = archive_filter_uuencode_open;
  81. f->options = archive_filter_uuencode_options;
  82. f->write = archive_filter_uuencode_write;
  83. f->close = archive_filter_uuencode_close;
  84. f->free = archive_filter_uuencode_free;
  85. return (ARCHIVE_OK);
  86. }
  87. /*
  88. * Set write options.
  89. */
  90. static int
  91. archive_filter_uuencode_options(struct archive_write_filter *f, const char *key,
  92. const char *value)
  93. {
  94. struct private_uuencode *state = (struct private_uuencode *)f->data;
  95. if (strcmp(key, "mode") == 0) {
  96. if (value == NULL) {
  97. archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
  98. "mode option requires octal digits");
  99. return (ARCHIVE_FAILED);
  100. }
  101. state->mode = (int)atol8(value, strlen(value)) & 0777;
  102. return (ARCHIVE_OK);
  103. } else if (strcmp(key, "name") == 0) {
  104. if (value == NULL) {
  105. archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
  106. "name option requires a string");
  107. return (ARCHIVE_FAILED);
  108. }
  109. archive_strcpy(&state->name, value);
  110. return (ARCHIVE_OK);
  111. }
  112. /* Note: The "warn" return is just to inform the options
  113. * supervisor that we didn't handle it. It will generate
  114. * a suitable error if no one used this option. */
  115. return (ARCHIVE_WARN);
  116. }
  117. /*
  118. * Setup callback.
  119. */
  120. static int
  121. archive_filter_uuencode_open(struct archive_write_filter *f)
  122. {
  123. struct private_uuencode *state = (struct private_uuencode *)f->data;
  124. size_t bs = 65536, bpb;
  125. if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
  126. /* Buffer size should be a multiple number of the of bytes
  127. * per block for performance. */
  128. bpb = archive_write_get_bytes_per_block(f->archive);
  129. if (bpb > bs)
  130. bs = bpb;
  131. else if (bpb != 0)
  132. bs -= bs % bpb;
  133. }
  134. state->bs = bs;
  135. if (archive_string_ensure(&state->encoded_buff, bs + 512) == NULL) {
  136. archive_set_error(f->archive, ENOMEM,
  137. "Can't allocate data for uuencode buffer");
  138. return (ARCHIVE_FATAL);
  139. }
  140. archive_string_sprintf(&state->encoded_buff, "begin %o %s\n",
  141. state->mode, state->name.s);
  142. f->data = state;
  143. return (0);
  144. }
  145. static void
  146. uu_encode(struct archive_string *as, const unsigned char *p, size_t len)
  147. {
  148. int c;
  149. c = (int)len;
  150. archive_strappend_char(as, c?c + 0x20:'`');
  151. for (; len >= 3; p += 3, len -= 3) {
  152. c = p[0] >> 2;
  153. archive_strappend_char(as, c?c + 0x20:'`');
  154. c = ((p[0] & 0x03) << 4) | ((p[1] & 0xf0) >> 4);
  155. archive_strappend_char(as, c?c + 0x20:'`');
  156. c = ((p[1] & 0x0f) << 2) | ((p[2] & 0xc0) >> 6);
  157. archive_strappend_char(as, c?c + 0x20:'`');
  158. c = p[2] & 0x3f;
  159. archive_strappend_char(as, c?c + 0x20:'`');
  160. }
  161. if (len > 0) {
  162. c = p[0] >> 2;
  163. archive_strappend_char(as, c?c + 0x20:'`');
  164. c = (p[0] & 0x03) << 4;
  165. if (len == 1) {
  166. archive_strappend_char(as, c?c + 0x20:'`');
  167. archive_strappend_char(as, '`');
  168. archive_strappend_char(as, '`');
  169. } else {
  170. c |= (p[1] & 0xf0) >> 4;
  171. archive_strappend_char(as, c?c + 0x20:'`');
  172. c = (p[1] & 0x0f) << 2;
  173. archive_strappend_char(as, c?c + 0x20:'`');
  174. archive_strappend_char(as, '`');
  175. }
  176. }
  177. archive_strappend_char(as, '\n');
  178. }
  179. /*
  180. * Write data to the encoded stream.
  181. */
  182. static int
  183. archive_filter_uuencode_write(struct archive_write_filter *f, const void *buff,
  184. size_t length)
  185. {
  186. struct private_uuencode *state = (struct private_uuencode *)f->data;
  187. const unsigned char *p = buff;
  188. int ret = ARCHIVE_OK;
  189. if (length == 0)
  190. return (ret);
  191. if (state->hold_len) {
  192. while (state->hold_len < LBYTES && length > 0) {
  193. state->hold[state->hold_len++] = *p++;
  194. length--;
  195. }
  196. if (state->hold_len < LBYTES)
  197. return (ret);
  198. uu_encode(&state->encoded_buff, state->hold, LBYTES);
  199. state->hold_len = 0;
  200. }
  201. for (; length >= LBYTES; length -= LBYTES, p += LBYTES)
  202. uu_encode(&state->encoded_buff, p, LBYTES);
  203. /* Save remaining bytes. */
  204. if (length > 0) {
  205. memcpy(state->hold, p, length);
  206. state->hold_len = length;
  207. }
  208. while (archive_strlen(&state->encoded_buff) >= state->bs) {
  209. ret = __archive_write_filter(f->next_filter,
  210. state->encoded_buff.s, state->bs);
  211. memmove(state->encoded_buff.s,
  212. state->encoded_buff.s + state->bs,
  213. state->encoded_buff.length - state->bs);
  214. state->encoded_buff.length -= state->bs;
  215. }
  216. return (ret);
  217. }
  218. /*
  219. * Finish the compression...
  220. */
  221. static int
  222. archive_filter_uuencode_close(struct archive_write_filter *f)
  223. {
  224. struct private_uuencode *state = (struct private_uuencode *)f->data;
  225. /* Flush remaining bytes. */
  226. if (state->hold_len != 0)
  227. uu_encode(&state->encoded_buff, state->hold, state->hold_len);
  228. archive_string_sprintf(&state->encoded_buff, "`\nend\n");
  229. /* Write the last block */
  230. archive_write_set_bytes_in_last_block(f->archive, 1);
  231. return __archive_write_filter(f->next_filter,
  232. state->encoded_buff.s, archive_strlen(&state->encoded_buff));
  233. }
  234. static int
  235. archive_filter_uuencode_free(struct archive_write_filter *f)
  236. {
  237. struct private_uuencode *state = (struct private_uuencode *)f->data;
  238. archive_string_free(&state->name);
  239. archive_string_free(&state->encoded_buff);
  240. free(state);
  241. return (ARCHIVE_OK);
  242. }
  243. static int64_t
  244. atol8(const char *p, size_t char_cnt)
  245. {
  246. int64_t l;
  247. int digit;
  248. l = 0;
  249. while (char_cnt-- > 0) {
  250. if (*p >= '0' && *p <= '7')
  251. digit = *p - '0';
  252. else
  253. break;
  254. p++;
  255. l <<= 3;
  256. l |= digit;
  257. }
  258. return (l);
  259. }