1 /*- 2 * Copyright (c) 2016 Kai Wang 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/param.h> 28 #include <assert.h> 29 #include <errno.h> 30 #include <stdlib.h> 31 #include <unistd.h> 32 33 #include "_libpe.h" 34 35 ELFTC_VCSID("$Id: libpe_buffer.c 3312 2016-01-10 09:23:51Z kaiwang27 $"); 36 37 PE_SecBuf * 38 libpe_alloc_buffer(PE_Scn *ps, size_t sz) 39 { 40 PE_SecBuf *sb; 41 42 if ((sb = malloc(sizeof(PE_SecBuf))) == NULL) { 43 errno = ENOMEM; 44 return (NULL); 45 } 46 47 sb->sb_ps = ps; 48 sb->sb_flags = 0; 49 sb->sb_pb.pb_align = 1; 50 sb->sb_pb.pb_off = 0; 51 sb->sb_pb.pb_size = sz; 52 if (sz > 0) { 53 if ((sb->sb_pb.pb_buf = malloc(sz)) == NULL) { 54 free(sb); 55 errno = ENOMEM; 56 return (NULL); 57 } 58 sb->sb_flags |= LIBPE_F_BUFFER_MALLOCED; 59 } else 60 sb->sb_pb.pb_buf = NULL; 61 62 STAILQ_INSERT_TAIL(&ps->ps_b, sb, sb_next); 63 64 return (sb); 65 } 66 67 void 68 libpe_release_buffer(PE_SecBuf *sb) 69 { 70 PE_Scn *ps; 71 72 assert(sb != NULL); 73 74 ps = sb->sb_ps; 75 76 STAILQ_REMOVE(&ps->ps_b, sb, _PE_SecBuf, sb_next); 77 78 if (sb->sb_flags & LIBPE_F_BUFFER_MALLOCED) 79 free(sb->sb_pb.pb_buf); 80 81 free(sb); 82 } 83 84 static int 85 cmp_sb(PE_SecBuf *a, PE_SecBuf *b) 86 { 87 88 if (a->sb_pb.pb_off < b->sb_pb.pb_off) 89 return (-1); 90 else if (a->sb_pb.pb_off == b->sb_pb.pb_off) 91 return (0); 92 else 93 return (1); 94 } 95 96 static void 97 sort_buffers(PE_Scn *ps) 98 { 99 100 if (STAILQ_EMPTY(&ps->ps_b)) 101 return; 102 103 STAILQ_SORT(&ps->ps_b, _PE_SecBuf, sb_next, cmp_sb); 104 } 105 106 size_t 107 libpe_resync_buffers(PE_Scn *ps) 108 { 109 PE_SecBuf *sb; 110 PE_Buffer *pb; 111 size_t sz; 112 113 assert(ps->ps_flags & LIBPE_F_LOAD_SECTION); 114 115 sort_buffers(ps); 116 117 sz = 0; 118 STAILQ_FOREACH(sb, &ps->ps_b, sb_next) { 119 if (ps->ps_flags & PE_F_DIRTY) 120 sb->sb_flags |= PE_F_DIRTY; 121 122 pb = (PE_Buffer *) sb; 123 if (pb->pb_align > ps->ps_falign) 124 pb->pb_align = ps->ps_falign; 125 if (pb->pb_buf == NULL || pb->pb_size == 0) 126 continue; 127 128 sz = roundup(sz, pb->pb_align); 129 130 if (pb->pb_off != (off_t) sz) { 131 pb->pb_off = sz; 132 sb->sb_flags |= PE_F_DIRTY; 133 } 134 sz += pb->pb_size; 135 } 136 137 return (sz); 138 } 139 140 int 141 libpe_write_buffers(PE_Scn *ps) 142 { 143 PE *pe; 144 PE_SecBuf *sb; 145 PE_Buffer *pb; 146 off_t off; 147 148 assert(ps->ps_flags & LIBPE_F_LOAD_SECTION); 149 150 pe = ps->ps_pe; 151 152 off = 0; 153 STAILQ_FOREACH(sb, &ps->ps_b, sb_next) { 154 pb = &sb->sb_pb; 155 if (pb->pb_buf == NULL || pb->pb_size == 0) 156 continue; 157 158 if ((sb->sb_flags & PE_F_DIRTY) == 0) { 159 assert((pe->pe_flags & LIBPE_F_SPECIAL_FILE) == 0); 160 if (lseek(pe->pe_fd, (off_t) pb->pb_size, SEEK_CUR) < 161 0) { 162 errno = EIO; 163 return (-1); 164 } 165 goto next_buf; 166 } 167 168 if (pb->pb_off > off) { 169 if (libpe_pad(pe, pb->pb_off - off) < 0) 170 return (-1); 171 off = pb->pb_off; 172 } 173 174 if (write(pe->pe_fd, pb->pb_buf, pb->pb_size) != 175 (ssize_t) pb->pb_size) { 176 errno = EIO; 177 return (-1); 178 } 179 180 next_buf: 181 off += pb->pb_size; 182 } 183 184 return (0); 185 } 186