add some utils
[libelf-compat.git] / src / elf_update.c
blobec621466ce80f3377aac8d2c98bd2da630f809dd
1 /* Update data structures for changes and write them out.
2 Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006 Red Hat, Inc.
3 This file is part of elfutils.
4 Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
6 This file is free software; you can redistribute it and/or modify
7 it under the terms of either
9 * the GNU Lesser General Public License as published by the Free
10 Software Foundation; either version 3 of the License, or (at
11 your option) any later version
15 * the GNU General Public License as published by the Free
16 Software Foundation; either version 2 of the License, or (at
17 your option) any later version
19 or both in parallel, as here.
21 elfutils is distributed in the hope that it will be useful, but
22 WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 General Public License for more details.
26 You should have received copies of the GNU General Public License and
27 the GNU Lesser General Public License along with this program. If
28 not, see <http://www.gnu.org/licenses/>. */
30 #ifdef HAVE_CONFIG_H
31 # include <config.h>
32 #endif
34 #include <unistd.h>
35 #include <sys/mman.h>
36 #include <sys/stat.h>
38 #include "libelf.h"
39 #include "libelfP.h"
42 static off_t
43 write_file (Elf *elf, off_t size, int change_bo, size_t shnum)
45 int class = elf->class;
47 /* Check the mode bits now, before modification might change them. */
48 struct stat st;
49 if (unlikely (fstat (elf->fildes, &st) != 0))
51 __libelf_seterrno (ELF_E_WRITE_ERROR);
52 return -1;
55 /* Adjust the size in any case. We do this even if we use `write'.
56 We cannot do this if this file is in an archive. We also don't
57 do it *now* if we are shortening the file since this would
58 prevent programs to use the data of the file in generating the
59 new file. We truncate the file later in this case. */
60 if (elf->parent == NULL
61 && (elf->maximum_size == ~((size_t) 0)
62 || (size_t) size > elf->maximum_size)
63 && unlikely (ftruncate (elf->fildes, size) != 0))
65 __libelf_seterrno (ELF_E_WRITE_ERROR);
66 return -1;
69 /* Try to map the file if this isn't done yet. */
70 if (elf->map_address == NULL && elf->cmd == ELF_C_WRITE_MMAP)
72 #if _MUDFLAP
73 /* Mudflap doesn't grok that our mmap'd data is ok. */
74 #else
75 elf->map_address = mmap (NULL, size, PROT_READ | PROT_WRITE,
76 MAP_SHARED, elf->fildes, 0);
77 if (unlikely (elf->map_address == MAP_FAILED))
78 elf->map_address = NULL;
79 #endif
82 if (elf->map_address != NULL)
84 /* The file is mmaped. */
85 if ((class == ELFCLASS32
86 ? __elf32_updatemmap (elf, change_bo, shnum)
87 : __elf64_updatemmap (elf, change_bo, shnum)) != 0)
88 /* Some problem while writing. */
89 size = -1;
91 else
93 /* The file is not mmaped. */
94 if ((class == ELFCLASS32
95 ? __elf32_updatefile (elf, change_bo, shnum)
96 : __elf64_updatefile (elf, change_bo, shnum)) != 0)
97 /* Some problem while writing. */
98 size = -1;
101 if (size != -1
102 && elf->parent == NULL
103 && elf->maximum_size != ~((size_t) 0)
104 && (size_t) size < elf->maximum_size
105 && unlikely (ftruncate (elf->fildes, size) != 0))
107 __libelf_seterrno (ELF_E_WRITE_ERROR);
108 size = -1;
111 /* POSIX says that ftruncate and write may clear the S_ISUID and S_ISGID
112 mode bits. So make sure we restore them afterwards if they were set.
113 This is not atomic if someone else chmod's the file while we operate. */
114 if (size != -1
115 && unlikely (st.st_mode & (S_ISUID | S_ISGID))
116 /* fchmod ignores the bits we cannot change. */
117 && unlikely (fchmod (elf->fildes, st.st_mode) != 0))
119 __libelf_seterrno (ELF_E_WRITE_ERROR);
120 size = -1;
123 if (size != -1 && elf->parent == NULL)
124 elf->maximum_size = size;
126 return size;
130 off_t
131 elf_update (elf, cmd)
132 Elf *elf;
133 Elf_Cmd cmd;
135 size_t shnum;
136 off_t size;
137 int change_bo = 0;
139 if (cmd != ELF_C_NULL
140 && cmd != ELF_C_WRITE
141 && unlikely (cmd != ELF_C_WRITE_MMAP))
143 __libelf_seterrno (ELF_E_INVALID_CMD);
144 return -1;
147 if (elf == NULL)
148 return -1;
150 if (elf->kind != ELF_K_ELF)
152 __libelf_seterrno (ELF_E_INVALID_HANDLE);
153 return -1;
156 rwlock_wrlock (elf->lock);
158 /* Make sure we have an ELF header. */
159 if (elf->state.elf.ehdr == NULL)
161 __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR);
162 size = -1;
163 goto out;
166 /* Determine the number of sections. */
167 shnum = (elf->state.elf.scns_last->cnt == 0
169 : 1 + elf->state.elf.scns_last->data[elf->state.elf.scns_last->cnt - 1].index);
171 /* Update the ELF descriptor. First, place the program header. It
172 will come right after the ELF header. The count the size of all
173 sections and finally place the section table. */
174 size = (elf->class == ELFCLASS32
175 ? __elf32_updatenull_wrlock (elf, &change_bo, shnum)
176 : __elf64_updatenull_wrlock (elf, &change_bo, shnum));
177 if (likely (size != -1)
178 /* See whether we actually have to write out the data. */
179 && (cmd == ELF_C_WRITE || cmd == ELF_C_WRITE_MMAP))
181 if (elf->cmd != ELF_C_RDWR
182 && elf->cmd != ELF_C_RDWR_MMAP
183 && elf->cmd != ELF_C_WRITE
184 && unlikely (elf->cmd != ELF_C_WRITE_MMAP))
186 __libelf_seterrno (ELF_E_UPDATE_RO);
187 size = -1;
189 else if (unlikely (elf->fildes == -1))
191 /* We closed the file already. */
192 __libelf_seterrno (ELF_E_FD_DISABLED);
193 size = -1;
195 else
196 size = write_file (elf, size, change_bo, shnum);
199 out:
200 rwlock_unlock (elf->lock);
202 return size;