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 #ifdef HAVE_CONFIG_H
00040 #include "config.h"
00041 #endif
00042
00043 #include <assert.h>
00044 #include <stdlib.h>
00045 #include <string.h>
00046 #include <sys/types.h>
00047 #include <errno.h>
00048 #include <unistd.h>
00049
00050 #include "rdd.h"
00051 #include "rdd_internals.h"
00052 #include "alignedbuf.h"
00053 #include "reader.h"
00054
00055 #define MOD_ALIGN(r, n) ((n) % ((r)->align))
00056
00057 typedef struct _RDD_ALIGNED_READER {
00058 RDD_READER *parent;
00059 unsigned align;
00060 } RDD_ALIGNED_READER;
00061
00062
00063
00064
00065 static int rdd_aligned_read(RDD_READER *r, unsigned char *buf, unsigned nbyte,
00066 unsigned *nread);
00067 static int rdd_aligned_tell(RDD_READER *r, rdd_count_t *pos);
00068 static int rdd_aligned_seek(RDD_READER *r, rdd_count_t pos);
00069 static int rdd_aligned_close(RDD_READER *r, int recurse);
00070
00071 static RDD_READ_OPS aligned_read_ops = {
00072 rdd_aligned_read,
00073 rdd_aligned_tell,
00074 rdd_aligned_seek,
00075 rdd_aligned_close
00076 };
00077
00078 int
00079 rdd_open_aligned_reader(RDD_READER **self, RDD_READER *parent, unsigned align)
00080 {
00081 RDD_READER *r = 0;
00082 RDD_ALIGNED_READER *state = 0;
00083 int rc = RDD_OK;
00084
00085 rc = rdd_new_reader(&r, &aligned_read_ops, sizeof(RDD_ALIGNED_READER));
00086 if (rc != RDD_OK) {
00087 return rc;
00088 }
00089
00090 state = (RDD_ALIGNED_READER *) r->state;
00091 state->parent = parent;
00092 state->align = align;
00093
00094 *self = r;
00095 return RDD_OK;
00096 }
00097
00098 static int
00099 rdd_aligned_read(RDD_READER *self, unsigned char *buf, unsigned nbyte,
00100 unsigned *nread)
00101 {
00102 RDD_ALIGNED_READER *state = self->state;
00103 unsigned char *p = 0;
00104 rdd_count_t start_pos = 0;
00105 rdd_count_t file_pos = 0;
00106 unsigned sector_offset;
00107 unsigned sector_extra;
00108 unsigned done;
00109 int rc = RDD_OK;
00110 int all_aligned = 0;
00111 unsigned nparentread = 0;
00112 unsigned char *alignedbuf = 0;
00113 RDD_ALIGNEDBUF abuf;
00114 int todo;
00115
00116
00117
00118 if ((rc = rdd_aligned_tell(self, &start_pos)) != RDD_OK) {
00119 return rc;
00120 }
00121 file_pos = start_pos;
00122
00123 all_aligned = MOD_ALIGN(state, (unsigned) buf) == 0
00124 && MOD_ALIGN(state, nbyte) == 0
00125 && MOD_ALIGN(state, start_pos) == 0;
00126 if (all_aligned) {
00127 alignedbuf = buf;
00128 } else {
00129 rc = rdd_new_alignedbuf(&abuf, nbyte, state->align);
00130 if (rc != RDD_OK) {
00131 return rc;
00132 }
00133 alignedbuf = abuf.aligned;
00134 return RDD_BADARG;
00135 }
00136
00137 todo = nbyte;
00138
00139
00140
00141 if ((sector_offset = MOD_ALIGN(state, file_pos)) > 0) {
00142 file_pos -= sector_offset;
00143 todo += sector_offset;
00144 if (rdd_aligned_seek(self, file_pos) != RDD_OK) {
00145 return RDD_ESEEK;
00146 }
00147 }
00148
00149
00150
00151
00152 if ((sector_extra = MOD_ALIGN(state, todo)) > 0) {
00153 todo += RDD_SECTOR_SIZE - sector_extra;
00154 }
00155 assert(todo >= (signed) sector_offset);
00156
00157
00158
00159 done = 0;
00160 p = buf;
00161 while (todo > 0) {
00162 assert(MOD_ALIGN(state, todo) == 0);
00163 assert(MOD_ALIGN(state, (unsigned) (p)) == 0);
00164
00165 rc = rdd_reader_read(state->parent, p, todo, &nparentread);
00166 if (rc == RDD_EAGAIN) {
00167 continue;
00168 } else if (rc != RDD_OK) {
00169 return rc;
00170 }
00171
00172 if (nparentread == 0) {
00173 break;
00174 }
00175
00176 if (MOD_ALIGN(state, nparentread) != 0) {
00177 #if 0
00178 error("raw device returned an incomplete sector");
00179 #endif
00180 return RDD_EREAD;
00181 }
00182
00183 done += nparentread;
00184 todo -= nparentread;
00185 p += nparentread;
00186 }
00187
00188
00189
00190
00191
00192
00193 file_pos += done;
00194 if (file_pos < start_pos) {
00195 #if 0
00196 bug("fd %d: raw device does not supply enough data", state->fd);
00197 #endif
00198 return RDD_EREAD;
00199 }
00200
00201 if (file_pos > start_pos + nbyte) {
00202
00203
00204
00205
00206 file_pos = start_pos + nbyte;
00207 if ((rc = rdd_aligned_seek(self, file_pos)) != RDD_OK) {
00208 return rc;
00209 }
00210 }
00211
00212 *nread = file_pos - start_pos;
00213
00214 if (alignedbuf != buf) {
00215 memcpy(buf, alignedbuf, *nread);
00216 rdd_free_alignedbuf(&abuf);
00217 }
00218
00219 return RDD_OK;
00220 }
00221
00222 static int
00223 rdd_aligned_tell(RDD_READER *self, rdd_count_t *pos)
00224 {
00225 RDD_ALIGNED_READER *state = self->state;
00226
00227 return rdd_reader_tell(state->parent, pos);
00228 }
00229
00230 static int
00231 rdd_aligned_seek(RDD_READER *self, rdd_count_t pos)
00232 {
00233 RDD_ALIGNED_READER *state = self->state;
00234
00235 return rdd_reader_seek(state->parent, pos);
00236 }
00237
00238 static int
00239 rdd_aligned_close(RDD_READER *self, int recurse)
00240 {
00241 RDD_ALIGNED_READER *state = self->state;
00242 int rc = RDD_OK;
00243
00244 if (recurse) {
00245 rc = rdd_reader_close(state->parent, recurse);
00246 if (rc != RDD_OK) {
00247 return rc;
00248 }
00249 }
00250
00251 return RDD_OK;
00252 }