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 <errno.h>
00028 #include <string.h>
00029 #include <stdlib.h>
00030 #include <unistd.h>
00031 
00032 #include "buffer.h"
00033 #include "buffer_util.h"
00034 #include "buffer_internal.h"
00035 #include "buffer_action.h"
00036 #include "segcol.h"
00037 #include "segment.h"
00038 #include "data_object.h"
00039 #include "data_object_memory.h"
00040 #include "data_object_file.h"
00041 #include "util.h"
00042 #include "debug.h"
00043 
00044 #include "type_limits.h"
00045 
00046 
00047 
00048 
00049 
00050 
00051 
00052 
00053 
00054 
00055 
00056 
00057 int read_data_object(data_object_t *dobj, off_t offset, void *mem, off_t length)
00058 {
00059     unsigned char *cur_dst = mem;
00060 
00061     while (length > 0) {
00062         void *data;
00063         off_t nbytes = length;
00064         int err = data_object_get_data(dobj, &data, offset, &nbytes,
00065                 DATA_OBJECT_READ);
00066         if (err)
00067             return_error(err);
00068 
00069         
00070         
00071 
00072 
00073 
00074         memcpy(cur_dst, data, (ssize_t)nbytes);
00075 
00076         
00077 
00078 
00079 
00080 
00081 
00082 
00083 
00084         if (__MAX(off_t) - offset >= nbytes)
00085             offset += nbytes;
00086         cur_dst += nbytes;
00087         length -= nbytes;
00088     }
00089 
00090     return 0;
00091 }
00092 
00093 
00094 
00095 
00096 
00097 
00098 
00099 
00100 
00101 
00102 
00103 
00104 
00105 
00106 
00107 
00108 
00109 int write_data_object(data_object_t *dobj, off_t offset, off_t length,
00110         int fd, off_t file_offset)
00111 {
00112     off_t s = lseek(fd, file_offset, SEEK_SET);
00113     if (s != file_offset)
00114         return_error(errno);
00115 
00116     while (length > 0) {
00117         void *data;
00118         off_t nbytes = length;
00119         int err = data_object_get_data(dobj, &data, offset, &nbytes,
00120                 DATA_OBJECT_READ);
00121         if (err)
00122             return_error(err);
00123 
00124         
00125 
00126 
00127 
00128         ssize_t nwritten = write(fd, data, (ssize_t)nbytes);
00129         if (nwritten < (ssize_t)nbytes)
00130             return_error(errno);
00131 
00132         
00133         if (__MAX(off_t) - offset >= nbytes)
00134             offset += nbytes;
00135         length -= nbytes;
00136     }
00137 
00138     return 0;
00139 }
00140 
00141 
00142 
00143 
00144 
00145 
00146 
00147 
00148 
00149 
00150 
00151 
00152 
00153 
00154 
00155 
00156 
00157 int write_data_object_safe(data_object_t *dobj, off_t offset, off_t length,
00158         int fd, off_t file_offset)
00159 {
00160     void *data = malloc(4096);
00161     if (data == NULL)
00162         return_error(ENOMEM);
00163 
00164     off_t nread = 0;
00165 
00166     
00167     off_t start_offset = offset + length - (offset + length) % 4096;
00168 
00169     if (start_offset < offset)
00170         start_offset = offset;
00171 
00172     while (nread < length) {
00173         off_t nbytes = (offset + length) - nread - start_offset;
00174         if (nbytes > 4096)
00175             nbytes = 4096;
00176 
00177         
00178         int err = read_data_object(dobj, start_offset, data, nbytes);
00179         if (err) {
00180             free(data);
00181             return_error(err);
00182         }
00183 
00184         
00185         off_t s = lseek(fd, file_offset + start_offset - offset, SEEK_SET);
00186         if (s != file_offset + start_offset - offset) {
00187             free(data);
00188             return_error(errno);
00189         }
00190         
00191         ssize_t nwritten = write(fd, data, (ssize_t)nbytes);
00192         if (nwritten < (ssize_t)nbytes) {
00193             free(data);
00194             return_error(errno);
00195         }
00196 
00197         
00198         start_offset -= 4096;
00199         
00200         if (__MAX(off_t) - nread >= nbytes)
00201             nread += nbytes;
00202 
00203         if (start_offset < offset)
00204             start_offset = offset;
00205     }
00206 
00207     free(data);
00208 
00209     return 0;
00210 }
00211 
00212 
00213 
00214 
00215 
00216 
00217 
00218 
00219 
00220 
00221 
00222 
00223 
00224 
00225 
00226 static int get_data_from_iter(segcol_iter_t *iter, segment_t **segment,
00227         off_t *mapping, off_t *read_start, off_t *read_length, off_t offset,
00228         off_t length)
00229 {
00230     int err = segcol_iter_get_segment(iter, segment);
00231     if (err)
00232         return_error(err);
00233 
00234     err = segcol_iter_get_mapping(iter, mapping);
00235     if (err)
00236         return_error(err);
00237 
00238     off_t seg_start;
00239     err = segment_get_start(*segment, &seg_start);
00240     if (err)
00241         return_error(err);
00242 
00243     off_t seg_size;
00244     err = segment_get_size(*segment, &seg_size);
00245     if (err)
00246         return_error(err);
00247 
00248     if (length == 0 || seg_size == 0) {
00249         *read_length = 0;
00250         return 0;
00251     }
00252 
00253     
00254     off_t start_index = offset - *mapping;
00255 
00256     
00257     if (__MAX(off_t) - offset < length - 1 * (length != 0))
00258         return_error(EOVERFLOW);
00259 
00260     
00261     off_t end_index = (offset + length - 1 * (length != 0)) - *mapping;
00262 
00263     
00264 
00265 
00266 
00267     if (end_index >= seg_size)
00268         end_index = seg_size - 1;
00269 
00270     if (__MAX(off_t) - seg_start < start_index)
00271         return_error(EOVERFLOW);
00272 
00273     
00274     *read_start = seg_start + start_index;
00275 
00276     
00277 
00278 
00279 
00280     *read_length = end_index - start_index + 1;
00281 
00282     return 0;
00283 }
00284 
00285 
00286 
00287 
00288 
00289 
00290 
00291 
00292 
00293 
00294 
00295 
00296 int segcol_foreach(segcol_t *segcol, off_t offset, off_t length,
00297         segcol_foreach_func *func, void *user_data)
00298 {
00299     if (segcol == NULL || offset < 0 || length < 0 || func == NULL)
00300         return_error(EINVAL);
00301 
00302     
00303     if (__MAX(off_t) - offset < length - 1 * (length != 0))
00304         return_error(EOVERFLOW);
00305 
00306     
00307     off_t segcol_size;
00308     segcol_get_size(segcol, &segcol_size);
00309 
00310     if (offset + length - 1 * (length != 0) >= segcol_size)
00311         return_error(EINVAL);
00312 
00313     
00314     segcol_iter_t *iter;
00315     int err = segcol_find(segcol, &iter, offset);
00316     if (err)
00317         return_error(err);
00318 
00319     off_t cur_offset = offset;
00320 
00321     
00322     off_t bytes_left = length;
00323 
00324     int iter_valid;
00325 
00326     
00327 
00328 
00329     while (!(err = segcol_iter_is_valid(iter, &iter_valid)) && iter_valid) {
00330         
00331         segment_t *segment;
00332         off_t mapping;
00333         off_t read_start = 0; 
00334         off_t read_length;
00335 
00336         err = get_data_from_iter(iter, &segment, &mapping, &read_start, 
00337                 &read_length, cur_offset, bytes_left);
00338         if (err)
00339             goto fail;
00340 
00341         
00342         err = (*func)(segcol, segment, mapping, read_start, read_length,
00343                 user_data);
00344         if (err)
00345             goto fail;
00346 
00347         bytes_left -= read_length;
00348 
00349         
00350         if (__MAX(off_t) - cur_offset >= read_length)
00351             cur_offset += read_length;
00352 
00353         if (bytes_left == 0)
00354             break;
00355 
00356         
00357         err = segcol_iter_next(iter);
00358         if (err)
00359             goto fail;
00360     }
00361 
00362     segcol_iter_free(iter);
00363     return 0;
00364 
00365 fail:
00366     segcol_iter_free(iter);
00367     return_error(err);
00368 
00369 }
00370 
00371 
00372 
00373 
00374 
00375 
00376 
00377 
00378 
00379 
00380 
00381 
00382 
00383 
00384 static int read_segment_func(segcol_t *segcol, segment_t *seg,
00385         off_t mapping, off_t read_start, off_t read_length, void *user_data)
00386 {
00387     UNUSED_PARAM(segcol);
00388     UNUSED_PARAM(mapping);
00389 
00390     data_object_t *dobj;
00391     segment_get_data(seg, (void **)&dobj);
00392 
00393     
00394     unsigned char **dst = (unsigned char **)user_data;
00395 
00396     int err = read_data_object(dobj, read_start, *dst, read_length);
00397     if (err)
00398         return_error(err);
00399 
00400     
00401     *dst += read_length;
00402 
00403     return 0;
00404 }
00405 
00406 
00407 
00408 
00409 
00410 
00411 
00412 
00413 
00414 
00415 int segcol_store_in_memory(segcol_t *segcol, off_t offset, off_t length)
00416 {
00417     if (segcol == NULL || offset < 0 || length < 0)
00418         return_error(EINVAL);
00419 
00420     
00421     void *new_data = malloc(length);
00422     if (new_data == NULL)
00423         return_error(ENOMEM);
00424 
00425     data_object_t *new_dobj;
00426     int err = data_object_memory_new(&new_dobj, new_data, length);
00427     if (err) {
00428         free(new_data);
00429         return_error(err);
00430     }
00431 
00432     
00433     err = data_object_memory_set_free_func(new_dobj, free);
00434     if (err) {
00435         free(new_data);
00436         data_object_free(new_dobj);
00437         return_error(err);
00438     }
00439 
00440     
00441     segment_t *new_seg;
00442     err = segment_new(&new_seg, new_dobj, 0, length, data_object_update_usage);
00443     if (err) {
00444         data_object_free(new_dobj);
00445         return_error(err);
00446     }
00447 
00448     void *data_ptr = new_data;
00449 
00450     
00451     err = segcol_foreach(segcol, offset, length, read_segment_func, &data_ptr);
00452     if (err) {
00453         segment_free(new_seg);
00454         return_error(err);
00455     }
00456 
00457     
00458     err = segcol_delete(segcol, NULL, offset, length);
00459     if (err) {
00460         segment_free(new_seg);
00461         return_error(err);
00462     }
00463 
00464     off_t segcol_size;
00465     segcol_get_size(segcol, &segcol_size);
00466 
00467     
00468 
00469 
00470 
00471     if (offset < segcol_size)
00472         err = segcol_insert(segcol, offset, new_seg);
00473     else if (offset == segcol_size)
00474         err = segcol_append(segcol, new_seg);
00475 
00476     
00477     if (err)
00478         return_error(err);
00479 
00480     return 0;
00481 }
00482 
00483 
00484 
00485 
00486 
00487 
00488 
00489 
00490 
00491 
00492 
00493 
00494 
00495 static int store_segment_func(segcol_t *segcol, segment_t *seg,
00496         off_t mapping, off_t read_start, off_t read_length, void *user_data)
00497 {
00498     UNUSED_PARAM(segcol);
00499     UNUSED_PARAM(mapping);
00500 
00501     data_object_t *dobj;
00502     segment_get_data(seg, (void **)&dobj);
00503 
00504     
00505     int fd = *(int *)user_data;
00506 
00507     off_t cur_off = lseek(fd, 0, SEEK_CUR);
00508 
00509     int err = write_data_object(dobj, read_start, read_length, fd, cur_off);
00510     if (err)
00511         return_error(err);
00512 
00513     return 0;
00514 }
00515 
00516 
00517 
00518 
00519 
00520 
00521 
00522 
00523 
00524 
00525 
00526 
00527 int segcol_store_in_file(segcol_t *segcol, off_t offset, off_t length,
00528         char *tmpdir)
00529 {
00530     if (segcol == NULL || offset < 0 || length < 0 || tmpdir == NULL)
00531         return_error(EINVAL);
00532 
00533     
00534     char *file_tmpl = "lb-XXXXXX";
00535     char *tmpl = NULL;
00536 
00537     int err = path_join(&tmpl, tmpdir, file_tmpl);
00538     if (err)
00539         return err;
00540 
00541     
00542     int fd = mkstemp(tmpl);
00543     if (fd == -1) {
00544         free(tmpl);
00545         return_error(errno);
00546     }
00547 
00548     int *fd_ptr = &fd;
00549 
00550     err = segcol_foreach(segcol, offset, length, store_segment_func,
00551             fd_ptr);
00552     if (err) {
00553         close(fd);
00554         unlink(tmpl);
00555         free(tmpl);
00556         return_error(err);
00557     }
00558 
00559     
00560 
00561 
00562 
00563 
00564 
00565     data_object_t *new_dobj;
00566     err = data_object_tempfile_new(&new_dobj, fd, tmpl);
00567     if (err) {
00568         close(fd);
00569         unlink(tmpl);
00570         free(tmpl);
00571         return_error(err);
00572     }
00573 
00574     
00575     free(tmpl);
00576 
00577     
00578     err = data_object_file_set_close_func(new_dobj, close);
00579     if (err) {
00580         close(fd);
00581         data_object_free(new_dobj);
00582         return_error(err);
00583     }
00584 
00585     
00586     segment_t *new_seg;
00587     err = segment_new(&new_seg, new_dobj, 0, length, data_object_update_usage);
00588     if (err) {
00589         data_object_free(new_dobj);
00590         return_error(err);
00591     }
00592 
00593     
00594     err = segcol_delete(segcol, NULL, offset, length);
00595     if (err) {
00596         segment_free(new_seg);
00597         return_error(err);
00598     }
00599 
00600     off_t segcol_size;
00601     segcol_get_size(segcol, &segcol_size);
00602 
00603     
00604 
00605 
00606 
00607     if (offset < segcol_size)
00608         err = segcol_insert(segcol, offset, new_seg);
00609     else if (offset == segcol_size)
00610         err = segcol_append(segcol, new_seg);
00611 
00612     
00613     if (err)
00614         return_error(err);
00615 
00616     return 0;
00617 }
00618 
00619 
00620 
00621 
00622 
00623 
00624 
00625 
00626 
00627 
00628 
00629 
00630 int segcol_add_copy(segcol_t *dst, off_t offset, segcol_t *src)
00631 {
00632     if (dst == NULL || src == NULL || offset < 0 || dst == src)
00633         return_error(EINVAL);
00634 
00635     off_t dst_size;
00636     int err = segcol_get_size(dst, &dst_size);
00637     if (err)
00638         return_error(err);
00639 
00640     segcol_iter_t *iter;
00641     err = segcol_iter_new(src, &iter);
00642     if (err)
00643         return_error(err);
00644 
00645     
00646     int use_append = (offset >= dst_size);
00647 
00648     
00649     off_t offset_reached = offset - 1;
00650 
00651     int valid;
00652 
00653     
00654     while (!segcol_iter_is_valid(iter, &valid) && valid) {
00655         segment_t *seg;
00656         off_t mapping;
00657         segcol_iter_get_segment(iter, &seg);
00658         segcol_iter_get_mapping(iter, &mapping);
00659 
00660         segment_t *seg_copy;
00661         segment_copy(seg, &seg_copy);
00662 
00663         if (use_append)
00664             err = segcol_append(dst, seg_copy);
00665         else
00666             err = segcol_insert(dst, offset + mapping, seg_copy);
00667 
00668         if (err) {
00669             segment_free(seg_copy);
00670             goto fail;
00671         }
00672 
00673         offset_reached = offset + mapping - 1;
00674 
00675         err = segcol_iter_next(iter);
00676         if (err)
00677             goto fail;
00678     }
00679 
00680     err = segcol_iter_free(iter);
00681     if (err)
00682         goto fail_iter_free;
00683 
00684     return 0;
00685 
00686 fail:
00687     segcol_iter_free(iter);
00688 fail_iter_free:
00689     
00690 
00691 
00692 
00693     if (offset_reached >= offset)
00694         segcol_delete(dst, NULL, offset, offset_reached - offset + 1);
00695 
00696     return_error(err);
00697 }
00698 
00699 
00700 
00701 
00702 
00703 
00704 
00705 
00706 
00707 
00708 
00709 
00710 
00711 
00712 
00713 int undo_list_enforce_limit(bless_buffer_t *buf, int ensure_vacancy)
00714 {
00715     if (buf == NULL)
00716         return_error(EINVAL);
00717 
00718     size_t limit = buf->options->undo_limit;
00719     
00720 
00721 
00722 
00723     if (limit != 0 && ensure_vacancy)
00724         limit--;
00725 
00726     
00727 
00728 
00729 
00730     struct list_node *node;
00731     struct list_node *tmp;
00732 
00733     list_for_each_safe(list_head(buf->undo_list)->next, node, tmp) {
00734         if (buf->undo_list_size <= limit)
00735             break;
00736 
00737         int err = list_delete_chain(node, node);
00738         if (err)
00739             return_error(err);
00740 
00741         --buf->undo_list_size;
00742 
00743         struct buffer_action_entry *del_entry = 
00744             list_entry(node, struct buffer_action_entry, ln);
00745 
00746         buffer_action_free(del_entry->action);
00747         free(del_entry);
00748     }
00749 
00750     
00751 
00752 
00753 
00754     if (limit == 0)
00755         buf->multi_action = NULL;
00756 
00757     return 0;
00758 }
00759 
00760 
00761 
00762 
00763 
00764 
00765 
00766 
00767 int action_list_clear(list_t *action_list)
00768 {
00769     if (action_list == NULL)
00770         return_error(EINVAL);
00771 
00772     struct list_node *node;
00773     struct list_node *tmp;
00774 
00775     
00776 
00777 
00778 
00779     list_for_each_safe(list_head(action_list)->next, node, tmp) {
00780         struct buffer_action_entry *entry =
00781             list_entry(node, struct buffer_action_entry , ln);
00782 
00783         list_delete_chain(node, node);
00784         buffer_action_free(entry->action);
00785         free(entry);
00786     }
00787 
00788     return 0;
00789 }
00790 
00791 
00792 
00793 
00794 
00795 
00796 
00797 
00798 
00799 int undo_list_append(bless_buffer_t *buf, buffer_action_t *action)
00800 {
00801     if (buf == NULL || action == NULL)
00802         return_error(EINVAL);
00803 
00804     
00805     struct buffer_action_entry *entry;
00806 
00807     entry = malloc(sizeof(struct buffer_action_entry));
00808     if (entry == NULL)
00809         return_error(ENOMEM);
00810 
00811     entry->action = action;
00812 
00813     
00814     int err = list_insert_before(list_tail(buf->undo_list), &entry->ln);
00815     if (err) {
00816         free(entry);
00817         return_error(err);
00818     }
00819 
00820     ++buf->undo_list_size;
00821 
00822     return 0;
00823 }