00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #ifndef lint
00034 static char copyright[] =
00035 "@(#) Copyright (c) 2002-2004\n\
00036 Netherlands Forensic Institute. All rights reserved.\n";
00037 #endif
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048 #ifdef HAVE_CONFIG_H
00049 #include <config.h>
00050 #endif
00051
00052 #include <assert.h>
00053 #include <errno.h>
00054 #include <fcntl.h>
00055 #include <stdarg.h>
00056 #include <stdlib.h>
00057 #include <stdio.h>
00058 #include <string.h>
00059 #include <unistd.h>
00060 #include <sys/stat.h>
00061
00062 #include "rdd.h"
00063 #include "writer.h"
00064
00065 #define GIGABYTE (1024*1024*1024)
00066
00067
00068
00069 static int part_write(RDD_WRITER *w, const unsigned char *buf, unsigned nbyte);
00070 static int part_close(RDD_WRITER *w);
00071 static int part_compare_address(RDD_WRITER *w, struct addrinfo *addr, int *result);
00072
00073 static RDD_WRITE_OPS part_write_ops = {
00074 part_write,
00075 part_close,
00076 part_compare_address
00077 };
00078
00079 typedef struct _RDD_PART_WRITER {
00080 char *path;
00081 char *pathbuf;
00082 unsigned maxpathlen;
00083 rdd_count_t splitlen;
00084 unsigned next_partnum;
00085 rdd_write_mode_t writemode;
00086 unsigned ndigit;
00087 rdd_count_t written;
00088 RDD_WRITER *parent;
00089 } RDD_PART_WRITER;
00090
00091
00092
00093
00094
00095
00096
00097
00098 static unsigned
00099 count_digits(rdd_count_t maxlen, rdd_count_t splitlen)
00100 {
00101 rdd_count_t npart;
00102 unsigned ndigit;
00103
00104 if (maxlen == RDD_WHOLE_FILE) {
00105
00106
00107 maxlen = ((rdd_count_t) 1000) * ((rdd_count_t) GIGABYTE);
00108 }
00109
00110 npart = (maxlen + splitlen - 1) / splitlen;
00111 for (ndigit = 0; npart != 0; ndigit++, npart /= 10) {
00112 }
00113
00114 return ndigit;
00115 }
00116
00117
00118
00119
00120
00121 static int
00122 open_next_part(RDD_PART_WRITER *state)
00123 {
00124 char *sep;
00125 int rc;
00126
00127 assert(state->path != 0);
00128 sep = strrchr(state->path, '/');
00129 if (sep == 0) {
00130
00131
00132
00133 snprintf(state->pathbuf, state->maxpathlen, "%0*d-%s",
00134 state->ndigit, state->next_partnum, state->path);
00135 state->pathbuf[state->maxpathlen-1] = '\000';
00136 } else {
00137
00138
00139
00140 char *dir = state->path;
00141 char *file = sep + 1;
00142 *sep = '\000';
00143 snprintf(state->pathbuf, state->maxpathlen, "%s/%0*d-%s",
00144 dir, state->ndigit, state->next_partnum, file);
00145 state->pathbuf[state->maxpathlen-1] = '\000';
00146 *sep = '/';
00147 }
00148
00149 rc = rdd_open_safe_writer(&state->parent, state->pathbuf,
00150 state->writemode);
00151
00152 if (rc != RDD_OK) {
00153 return rc;
00154 }
00155
00156 state->next_partnum++;
00157
00158 return RDD_OK;
00159 }
00160
00161 int
00162 rdd_open_part_writer(RDD_WRITER **self,
00163 const char *path, rdd_count_t maxlen, rdd_count_t splitlen,
00164 rdd_write_mode_t wrmode)
00165 {
00166 RDD_WRITER *w = 0;
00167 RDD_PART_WRITER *state = 0;
00168 char *pathcopy = 0;
00169 char *pathbuf = 0;
00170 int rc = RDD_OK;
00171
00172 if (self == 0) {
00173 return RDD_BADARG;
00174 }
00175 if (splitlen <= 0) {
00176 return RDD_BADARG;
00177 }
00178 if (maxlen <= 0) {
00179 return RDD_BADARG;
00180 }
00181 if (path == 0 || strlen(path) == 0) {
00182 return RDD_BADARG;
00183 }
00184
00185 rc = rdd_new_writer(&w, &part_write_ops, sizeof(RDD_PART_WRITER));
00186 if (rc != RDD_OK) {
00187 goto error;
00188 }
00189 state = (RDD_PART_WRITER *) w->state;
00190
00191 state->ndigit = count_digits(maxlen, splitlen);
00192 state->next_partnum = 0;
00193 state->splitlen = splitlen;
00194 state->written = 0;
00195 state->writemode = wrmode;
00196
00197 if ((pathcopy = malloc(strlen(path) + 1)) == 0) {
00198 rc = RDD_NOMEM;
00199 goto error;
00200 }
00201 strcpy(pathcopy, path);
00202 state->path = pathcopy;
00203 state->maxpathlen = strlen(state->path) + 128;
00204
00205 if ((pathbuf = malloc(state->maxpathlen)) == 0) {
00206 goto error;
00207 }
00208 memset(pathbuf, 0, state->maxpathlen);
00209 state->pathbuf = pathbuf;
00210
00211 if ((rc = open_next_part(state)) != RDD_OK) {
00212 goto error;
00213 }
00214
00215 *self = w;
00216 return RDD_OK;
00217
00218 error:
00219 *self = 0;
00220 if (pathbuf != 0) {
00221 free(pathbuf);
00222 }
00223 if (pathcopy != 0) {
00224 free(pathcopy);
00225 }
00226 if (state != 0) {
00227 free(state);
00228 }
00229 if (w != 0) {
00230 free(w);
00231 }
00232 return rc;
00233 }
00234
00235 static int
00236 part_write(RDD_WRITER *w, const unsigned char *buf, unsigned nbyte)
00237 {
00238 RDD_PART_WRITER *state = w->state;
00239 unsigned to_write;
00240 int rc;
00241
00242 while (nbyte > 0) {
00243 if (state->written >= state->splitlen) {
00244
00245
00246 if ((rc = rdd_writer_close(state->parent)) != RDD_OK) {
00247 return rc;
00248 }
00249 state->parent = 0;
00250 if ((rc = open_next_part(state)) != RDD_OK) {
00251 return rc;
00252 }
00253 state->written = 0;
00254 }
00255
00256
00257
00258
00259 if (state->written + nbyte > state->splitlen) {
00260 to_write = state->splitlen - state->written;
00261 } else {
00262 to_write = nbyte;
00263 }
00264
00265 rc = rdd_writer_write(state->parent, buf, to_write);
00266 if (rc != RDD_OK) {
00267 return rc;
00268 }
00269 buf += to_write;
00270 nbyte -= to_write;
00271 state->written += to_write;
00272 }
00273
00274 return RDD_OK;
00275 }
00276
00277 static int
00278 part_close(RDD_WRITER *self)
00279 {
00280 RDD_PART_WRITER *state = self->state;
00281 int rc;
00282
00283 assert(state->parent != 0);
00284
00285 if ((rc = rdd_writer_close(state->parent)) != RDD_OK) {
00286 return rc;
00287 }
00288
00289 free(state->pathbuf);
00290 state->pathbuf = 0;
00291 free(state->path);
00292 state->path = 0;
00293
00294 return RDD_OK;
00295 }
00296
00297 static int
00298 part_compare_address(RDD_WRITER *self, struct addrinfo *address, int *result)
00299 {
00300
00301 if (self == 0) {
00302 return RDD_BADARG;
00303 }
00304 if (result == 0) {
00305 return RDD_BADARG;
00306 }
00307
00308 *result = (address == 0);
00309 return RDD_OK;
00310 }