blob: 5d6c6b7a1af4838e8dba7df9f0bb649c8e415bbc [file] [log] [blame]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001/* Update data structures for changes and write them out.
2 Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005 Red Hat, Inc.
3 Contributed by Ulrich Drepper <drepper@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
29static off_t
30write_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)
41 || (size_t) size > elf->maximum_size)
42 && unlikely (ftruncate (elf->fildes, size) != 0))
43 {
44 __libelf_seterrno (ELF_E_WRITE_ERROR);
45 return -1;
46 }
47
48 /* Try to map the file if this isn't done yet. */
49 if (elf->map_address == NULL && elf->cmd == ELF_C_WRITE_MMAP)
50 {
51#if _MUDFLAP
52 /* Mudflap doesn't grok that our mmap'd data is ok. */
53#else
54 elf->map_address = mmap (NULL, size, PROT_READ | PROT_WRITE,
55 MAP_SHARED, elf->fildes, 0);
56 if (unlikely (elf->map_address == MAP_FAILED))
57 elf->map_address = NULL;
58#endif
59 }
60
61 if (elf->map_address != NULL)
62 {
63 /* The file is mmaped. */
64 if ((class == ELFCLASS32
65 ? __elf32_updatemmap (elf, change_bo, shnum)
66 : __elf64_updatemmap (elf, change_bo, shnum)) != 0)
67 /* Some problem while writing. */
68 size = -1;
69 }
70 else
71 {
72 /* The file is not mmaped. */
73 if ((class == ELFCLASS32
74 ? __elf32_updatefile (elf, change_bo, shnum)
75 : __elf64_updatefile (elf, change_bo, shnum)) != 0)
76 /* Some problem while writing. */
77 size = -1;
78 }
79
80 if (size != -1
81 && elf->parent == NULL
82 && elf->maximum_size != ~((size_t) 0)
83 && (size_t) size < elf->maximum_size
84 && unlikely (ftruncate (elf->fildes, size) != 0))
85 {
86 __libelf_seterrno (ELF_E_WRITE_ERROR);
87 size = -1;
88 }
89
90 if (size != -1 && elf->parent == NULL)
91 elf->maximum_size = size;
92
93 return size;
94}
95
96
97off_t
98elf_update (elf, cmd)
99 Elf *elf;
100 Elf_Cmd cmd;
101{
102 size_t shnum;
103 off_t size;
104 int change_bo = 0;
105
106 if (cmd != ELF_C_NULL
107 && cmd != ELF_C_WRITE
108 && unlikely (cmd != ELF_C_WRITE_MMAP))
109 {
110 __libelf_seterrno (ELF_E_INVALID_CMD);
111 return -1;
112 }
113
114 if (elf == NULL)
115 return -1;
116
117 if (elf->kind != ELF_K_ELF)
118 {
119 __libelf_seterrno (ELF_E_INVALID_HANDLE);
120 return -1;
121 }
122
123 rwlock_wrlock (elf->lock);
124
125 /* Make sure we have an ELF header. */
126 if (elf->state.elf.ehdr == NULL)
127 {
128 __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR);
129 size = -1;
130 goto out;
131 }
132
133 /* Determine the number of sections. */
134 shnum = (elf->state.elf.scns_last->cnt == 0
135 ? 0
136 : 1 + elf->state.elf.scns_last->data[elf->state.elf.scns_last->cnt - 1].index);
137
138 /* Update the ELF descriptor. First, place the program header. It
139 will come right after the ELF header. The count the size of all
140 sections and finally place the section table. */
141 size = (elf->class == ELFCLASS32
142 ? __elf32_updatenull (elf, &change_bo, shnum)
143 : __elf64_updatenull (elf, &change_bo, shnum));
144 if (likely (size != -1)
145 /* See whether we actually have to write out the data. */
146 && (cmd == ELF_C_WRITE || cmd == ELF_C_WRITE_MMAP))
147 {
148 if (elf->cmd != ELF_C_RDWR
149 && elf->cmd != ELF_C_RDWR_MMAP
150 && elf->cmd != ELF_C_WRITE
151 && unlikely (elf->cmd != ELF_C_WRITE_MMAP))
152 {
153 __libelf_seterrno (ELF_E_UPDATE_RO);
154 size = -1;
155 }
156 else if (unlikely (elf->fildes == -1))
157 {
158 /* We closed the file already. */
159 __libelf_seterrno (ELF_E_FD_DISABLED);
160 size = -1;
161 }
162 else
163 {
164 if (elf->parent != NULL)
165 {
166 extern int puts (const char *);
167 puts ("this is an archive member");
168 }
169
170 size = write_file (elf, size, change_bo, shnum);
171 }
172 }
173
174 out:
175 rwlock_unlock (elf->lock);
176
177 return size;
178}