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 #include <sys/types.h>
00027 #include <sys/stat.h>
00028 #include <sys/mman.h>
00029 #include <stdlib.h>
00030 #include <string.h>
00031 #include <errno.h>
00032 #include <unistd.h>
00033
00034 #include "data_object.h"
00035 #include "data_object_internal.h"
00036 #include "data_object_file.h"
00037 #include "type_limits.h"
00038 #include "debug.h"
00039 #include "util.h"
00040
00041
00042
00043 static int data_object_file_get_size(data_object_t *obj, off_t *size);
00044 static int data_object_file_free(data_object_t *obj);
00045 static int data_object_file_get_data(data_object_t *obj, void **buf,
00046 off_t offset, off_t *length, data_object_flags flags);
00047 static int data_object_file_compare(int *result, data_object_t *obj1,
00048 data_object_t *obj2);
00049
00050
00051 static struct data_object_funcs data_object_file_funcs = {
00052 .get_data = data_object_file_get_data,
00053 .free = data_object_file_free,
00054 .get_size = data_object_file_get_size,
00055 .compare = data_object_file_compare
00056 };
00057
00058
00059 struct data_object_file_impl {
00060 int fd;
00061 off_t size;
00062
00063 void *page_data;
00064 off_t page_offset;
00065 long page_size;
00066
00067
00068 dev_t dev;
00069 ino_t inode;
00070
00071 data_object_file_close_func *file_close;
00072
00073
00074 char *path;
00075 };
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090 int data_object_file_new(data_object_t **obj, int fd)
00091 {
00092 if (obj == NULL)
00093 return_error(EINVAL);
00094
00095 if (fd < 0)
00096 return_error(EBADF);
00097
00098
00099 struct data_object_file_impl *impl =
00100 malloc (sizeof(struct data_object_file_impl));
00101
00102 if (impl == NULL)
00103 return_error(ENOMEM);
00104
00105
00106 int err = data_object_create_impl(obj, impl, &data_object_file_funcs);
00107
00108 if (err) {
00109 free(impl);
00110 return_error(err);
00111 }
00112
00113 impl->fd = fd;
00114
00115
00116 struct stat st;
00117 err = fstat(fd, &st);
00118 if (err) {
00119 err = errno;
00120 goto fail;
00121 }
00122
00123 impl->dev = st.st_dev;
00124 impl->inode = st.st_ino;
00125
00126
00127 impl->size = lseek(fd, 0, SEEK_END);
00128 if (impl->size == -1) {
00129 err = errno;
00130 goto fail;
00131 }
00132
00133 impl->page_size = sysconf(_SC_PAGESIZE);
00134 if (impl->page_size == -1) {
00135 err = errno;
00136 goto fail;
00137 }
00138
00139 impl->page_data = NULL;
00140
00141
00142 impl->file_close = NULL;
00143
00144 impl->path = NULL;
00145
00146 return 0;
00147
00148 fail:
00149 free(impl);
00150 return_error(err);
00151 }
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170 int data_object_tempfile_new(data_object_t **obj, int fd, char *path)
00171 {
00172 int err = data_object_file_new(obj, fd);
00173 if (err)
00174 return_error(err);
00175
00176 struct data_object_file_impl *impl =
00177 data_object_get_impl(*obj);
00178
00179
00180 size_t path_len = strlen(path);
00181
00182 impl->path = malloc(path_len + 1);
00183 if (impl->path == NULL) {
00184 data_object_free(*obj);
00185 return_error(ENOMEM);
00186 }
00187
00188 strncpy(impl->path, path, path_len + 1);
00189
00190 return 0;
00191 }
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204 int data_object_file_set_close_func(data_object_t *obj,
00205 data_object_file_close_func *file_close)
00206 {
00207 if (obj == NULL)
00208 return_error(EINVAL);
00209
00210 struct data_object_file_impl *impl =
00211 data_object_get_impl(obj);
00212
00213 impl->file_close = file_close;
00214
00215 return 0;
00216 }
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229 static int data_object_file_get_data(data_object_t *obj, void **buf,
00230 off_t offset, off_t *length, data_object_flags flags)
00231 {
00232 UNUSED_PARAM(flags);
00233
00234 if (obj == NULL || buf == NULL || length == NULL || offset < 0)
00235 return_error(EINVAL);
00236
00237 off_t len = *length;
00238
00239
00240 if (__MAX(off_t) - offset < len - 1 * (len != 0))
00241 return_error(EOVERFLOW);
00242
00243 struct data_object_file_impl *impl =
00244 data_object_get_impl(obj);
00245
00246
00247 if (offset + len - 1 * (len != 0) >= impl->size)
00248 return_error(EINVAL);
00249
00250
00251 if (impl->page_data == NULL || offset < impl->page_offset
00252 || offset >= impl->page_offset + impl->page_size)
00253 {
00254 int err;
00255
00256
00257 if (impl->page_data != NULL) {
00258 err = munmap(impl->page_data, impl->page_size);
00259 if (err)
00260 return_error(errno);
00261
00262 impl->page_data = NULL;
00263 }
00264
00265
00266 off_t page_offset = (offset / impl->page_size) * impl->page_size;
00267
00268 void *mmap_addr = mmap(NULL, impl->page_size, PROT_READ, MAP_PRIVATE,
00269 impl->fd, page_offset);
00270
00271 if (mmap_addr == MAP_FAILED)
00272 return_error(errno);
00273
00274 impl->page_data = mmap_addr;
00275 impl->page_offset = page_offset;
00276 }
00277
00278
00279 off_t loaded_length = impl->page_size - (offset - impl->page_offset);
00280 if (loaded_length > len)
00281 *length = len;
00282 else
00283 *length = loaded_length;
00284
00285 *buf = (unsigned char *)impl->page_data + offset - impl->page_offset;
00286
00287 return 0;
00288 }
00289
00290 static int data_object_file_free(data_object_t *obj)
00291 {
00292 if (obj == NULL)
00293 return_error(EINVAL);
00294
00295 struct data_object_file_impl *impl =
00296 data_object_get_impl(obj);
00297
00298
00299 if (impl->page_data != NULL) {
00300 int err = munmap(impl->page_data, impl->page_size);
00301 if (err == -1)
00302 return_error(errno);
00303 }
00304
00305
00306 data_object_file_close_func *file_close = impl->file_close;
00307
00308 if (file_close != NULL) {
00309 int err = file_close(impl->fd);
00310 if (err)
00311 return_error(err);
00312 }
00313
00314
00315 if (impl->path != NULL) {
00316 unlink(impl->path);
00317 free(impl->path);
00318 }
00319
00320 free(impl);
00321
00322 return 0;
00323 }
00324
00325 static int data_object_file_get_size(data_object_t *obj, off_t *size)
00326 {
00327 if (obj == NULL || size == NULL)
00328 return_error(EINVAL);
00329
00330 struct data_object_file_impl *impl =
00331 data_object_get_impl(obj);
00332
00333 *size = impl->size;
00334
00335 return 0;
00336 }
00337
00338 static int data_object_file_compare(int *result, data_object_t *obj1,
00339 data_object_t *obj2)
00340 {
00341 if (obj1 == NULL || obj2 == NULL || result == NULL)
00342 return_error(EINVAL);
00343
00344 struct data_object_file_impl *impl1 =
00345 data_object_get_impl(obj1);
00346
00347 struct data_object_file_impl *impl2 =
00348 data_object_get_impl(obj2);
00349
00350 *result = !((impl1->dev == impl2->dev) && (impl1->inode == impl2->inode));
00351
00352 return 0;
00353 }
00354