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@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
write_file(Elf * elf,off_t size,int change_bo,size_t shnum)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
elf_update(elf,cmd)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