• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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