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 }