1 /* Update data structures for changes and write them out. 2 Copyright (C) 1999, 2000, 2001, 2002, 2004 Red Hat, Inc. 3 Contributed by Ulrich Drepper <drepper (at) redhat.com>, 1999. 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation, version 2. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with this program; if not, write to the Free Software Foundation, 16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 17 18 #ifdef HAVE_CONFIG_H 19 # include <config.h> 20 #endif 21 22 #include <libelf.h> 23 #include <unistd.h> 24 #include <sys/mman.h> 25 26 #include "libelfP.h" 27 28 29 static off_t 30 write_file (Elf *elf, off_t size, int change_bo, size_t shnum) 31 { 32 int class = elf->class; 33 34 /* Adjust the size in any case. We do this even if we use `write'. 35 We cannot do this if this file is in an archive. We also don't 36 do it *now* if we are shortening the file since this would 37 prevent programs to use the data of the file in generating the 38 new file. We truncate the file later in this case. */ 39 if (elf->parent == NULL 40 && (elf->maximum_size == ~((size_t) 0) || size > elf->maximum_size) 41 && unlikely (ftruncate (elf->fildes, size) != 0)) 42 { 43 __libelf_seterrno (ELF_E_WRITE_ERROR); 44 return -1; 45 } 46 47 /* Try to map the file if this isn't done yet. */ 48 if (elf->map_address == NULL && elf->cmd == ELF_C_WRITE_MMAP) 49 { 50 elf->map_address = mmap (NULL, size, PROT_READ | PROT_WRITE, 51 MAP_SHARED, elf->fildes, 0); 52 if (unlikely (elf->map_address == MAP_FAILED)) 53 elf->map_address = NULL; 54 } 55 56 if (elf->map_address != NULL) 57 { 58 /* The file is mmaped. */ 59 if ((class == ELFCLASS32 60 ? __elf32_updatemmap (elf, change_bo, shnum) 61 : __elf64_updatemmap (elf, change_bo, shnum)) != 0) 62 /* Some problem while writing. */ 63 size = -1; 64 } 65 else 66 { 67 /* The file is not mmaped. */ 68 if ((class == ELFCLASS32 69 ? __elf32_updatefile (elf, change_bo, shnum) 70 : __elf64_updatefile (elf, change_bo, shnum)) != 0) 71 /* Some problem while writing. */ 72 size = -1; 73 } 74 75 if (size != -1 76 && elf->parent == NULL 77 && elf->maximum_size != ~((size_t) 0) 78 && size < elf->maximum_size 79 && unlikely (ftruncate (elf->fildes, size) != 0)) 80 { 81 __libelf_seterrno (ELF_E_WRITE_ERROR); 82 size = -1; 83 } 84 85 if (size != -1 && elf->parent == NULL) 86 elf->maximum_size = size; 87 88 return size; 89 } 90 91 92 off_t 93 elf_update (elf, cmd) 94 Elf *elf; 95 Elf_Cmd cmd; 96 { 97 size_t shnum; 98 off_t size; 99 int change_bo = 0; 100 101 if (cmd != ELF_C_NULL 102 && cmd != ELF_C_WRITE 103 && unlikely (cmd != ELF_C_WRITE_MMAP)) 104 { 105 __libelf_seterrno (ELF_E_INVALID_CMD); 106 return -1; 107 } 108 109 if (elf == NULL) 110 return -1; 111 112 if (elf->kind != ELF_K_ELF) 113 { 114 __libelf_seterrno (ELF_E_INVALID_HANDLE); 115 return -1; 116 } 117 118 rwlock_rdlock (elf->lock); 119 120 /* Make sure we have an ELF header. */ 121 if (elf->state.elf.ehdr == NULL) 122 { 123 __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR); 124 size = -1; 125 goto out; 126 } 127 128 /* Determine the number of sections. */ 129 shnum = (elf->state.elf.scns_last->cnt == 0 130 ? 0 131 : 1 + elf->state.elf.scns_last->data[elf->state.elf.scns_last->cnt - 1].index); 132 133 /* Update the ELF descriptor. First, place the program header. It 134 will come right after the ELF header. The count the size of all 135 sections and finally place the section table. */ 136 size = (elf->class == ELFCLASS32 137 ? __elf32_updatenull (elf, &change_bo, shnum) 138 : __elf64_updatenull (elf, &change_bo, shnum)); 139 if (likely (size != -1) 140 /* See whether we actually have to write out the data. */ 141 && (cmd == ELF_C_WRITE || cmd == ELF_C_WRITE_MMAP)) 142 { 143 if (elf->cmd != ELF_C_RDWR 144 && elf->cmd != ELF_C_RDWR_MMAP 145 && elf->cmd != ELF_C_WRITE 146 && unlikely (elf->cmd != ELF_C_WRITE_MMAP)) 147 { 148 __libelf_seterrno (ELF_E_UPDATE_RO); 149 size = -1; 150 } 151 else if (unlikely (elf->fildes == -1)) 152 { 153 /* We closed the file already. */ 154 __libelf_seterrno (ELF_E_FD_DISABLED); 155 size = -1; 156 } 157 else 158 { 159 if (elf->parent != NULL) 160 { 161 extern int puts (const char *); 162 puts ("this is an archive member"); 163 } 164 165 size = write_file (elf, size, change_bo, shnum); 166 } 167 } 168 169 out: 170 rwlock_unlock (elf->lock); 171 172 return size; 173 } 174