mod_musicindex  1.4.1
output-tarball.c
Go to the documentation of this file.
1 /*
2  * output-tarball.c
3  * mod_musicindex
4  *
5  * $Id: output-tarball.c 1023 2013-04-09 11:13:16Z varenet $
6  *
7  * Created by Thibaut VARENE on Mon Jun 26 2006.
8  * Copyright (c) 2006-2008,2012-2013 Thibaut VARENE
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU Lesser General Public License version 2.1,
12  * as published by the Free Software Foundation.
13  *
14  */
15 
30 /* build flag: -D_FILE_OFFSET_BITS=64 - libarchive goes AWOL without it */
31 #ifndef _FILE_OFFSET_BITS
32 #define _FILE_OFFSET_BITS 64
33 #endif
34 
35 #include "mod_musicindex.h"
36 
37 #include <http_core.h>
38 #include <archive.h> /* libarchive */
39 #include <archive_entry.h>
40 #ifdef HAVE_SYS_TYPES_H
41 #include <sys/types.h> /* stat */
42 #endif
43 #ifdef HAVE_SYS_STAT_H
44 #include <sys/stat.h> /* stat */
45 #endif
46 #ifdef HAVE_UNISTD_H
47 #include <unistd.h> /* stat */
48 #endif
49 #include <stdio.h> /* fopen... */
50 
51 #define OT_SEND_DATA 0
52 #define OT_SEND_SIZE 1
54 #define RWBUFSIZE 8192
56 #define QSKIP_CHECKS(q) (!(q->flags & EF_ALLOWTARBALL))
57 
58 
60 struct cdata {
61  request_rec *r;
62 };
63 
64 static int
65 wrapopen(struct archive *a, void *client_data)
66 {
67  return (ARCHIVE_OK);
68 }
69 
70 static ssize_t
71 wrapwrite(struct archive *a, void *client_data, const void *buff, size_t n)
72 {
73  struct cdata *mydata = client_data;
74 
75  return (ap_rwrite(buff, n, mydata->r));
76 }
77 
78 static ssize_t
79 wrapwritesize(struct archive *a, void *client_data, const void *buff, size_t n)
80 {
81  ssize_t *mysize = client_data;
82  *mysize += n;
83  return n;
84 }
100 static ssize_t
101 tarball_op(request_rec *r, const mu_pack *const pack, int op)
102 {
103  const mu_ent *q = pack->fhead;
104  ssize_t tbsize = 0;
105  struct cdata mydata;
106  struct archive *a;
107  struct archive_entry *entry;
108  struct stat st;
109  static char buff[RWBUFSIZE];
110  int len;
111  FILE *file;
112  off_t fsize;
113 
114  if (!q)
115  return 0;
116 
117  if (!(a = archive_write_new()))
118  return 0;
119 
120  if (!(entry = archive_entry_new()))
121  goto fail;
122 
123  archive_write_set_compression_none(a);
124  archive_write_set_format_ustar(a);
125 
126  if (op == OT_SEND_DATA) {
127  mydata.r = r;
128  archive_write_open(a, &mydata, wrapopen, wrapwrite, NULL);
129  }
130  else /* OT_SEND_SIZE */
131  archive_write_open(a, &tbsize, NULL, wrapwritesize, NULL);
132 
133  for (; q; q = q->next) {
134  if (unlikely(QSKIP_CHECKS(q)))
135  continue;
136 
137  stat(q->filename, &st);
138  archive_entry_clear(entry);
139  archive_entry_copy_stat(entry, &st);
140  archive_entry_set_pathname(entry, q->file);
141  archive_write_header(a, entry);
142 
143  if (op == OT_SEND_DATA) {
144  file = fopen(q->filename, "r");
145  len = fread(buff, 1, sizeof(buff), file);
146  /* NB: size of buffer is 3rd arg, 1-byte long elements, otherwise everything fucks up */
147  while (len > 0) {
148  archive_write_data(a, buff, len);
149  len = fread(buff, 1, sizeof(buff), file);
150  }
151  fclose(file);
152  }
153  else { /* OT_SEND_SIZE */
154  fsize = q->size;
155  len = (likely(fsize > sizeof(buff)) ? sizeof(buff) : fsize);
156  while (len > 0) {
157  fsize -= archive_write_data(a, buff, len);
158  len = (likely(fsize > sizeof(buff)) ? sizeof(buff) : fsize);
159  }
160  }
161  }
162 
163  archive_entry_free(entry);
164 fail:
165  archive_write_finish(a);
166 
167  return tbsize;
168 }
169 
176 void send_tarball(request_rec *r, const mu_pack *const pack)
177 {
178  tarball_op(r, pack, OT_SEND_DATA);
179 }
180 
189 ssize_t
190 tarball_size(request_rec *r, const mu_pack *const pack)
191 {
192  return tarball_op(r, pack, OT_SEND_SIZE);
193 }