blob: d7f5f225c1160da9d505d511b5d6698f78ee8966 [file] [log] [blame]
H. Peter Anvinbdae10b2016-03-08 01:22:13 -08001/* ----------------------------------------------------------------------- *
2 *
3 * Copyright 1996-2016 The NASM Authors - All Rights Reserved
4 * See the file AUTHORS included with the NASM distribution for
5 * the specific copyright holders.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following
9 * conditions are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 * ----------------------------------------------------------------------- */
33
34#include "compiler.h"
35#include "nasmlib.h"
36
37#include <errno.h>
38
H. Peter Anvind81a2352016-09-21 14:03:18 -070039#ifdef HAVE_FCNTL_H
40# include <fcntl.h>
41#endif
42#ifdef HAVE_SYS_STAT_H
43# include <sys/stat.h>
44#endif
H. Peter Anvinbdae10b2016-03-08 01:22:13 -080045#ifdef HAVE_IO_H
46# include <io.h>
47#endif
48#ifdef HAVE_UNISTD_H
49# include <unistd.h>
50#endif
H. Peter Anvind81a2352016-09-21 14:03:18 -070051#ifdef HAVE_SYS_MMAN_H
52# include <sys/mman.h>
53#endif
H. Peter Anvinbdae10b2016-03-08 01:22:13 -080054
H. Peter Anvin7ab55952016-03-08 02:23:23 -080055/* Can we adjust the file size without actually writing all the bytes? */
56#ifdef HAVE_FILENO /* Useless without fileno() */
57# ifdef HAVE__CHSIZE_S
H. Peter Anvinc0aaf972016-05-10 15:18:00 -070058# define nasm_ftruncate(fd,size) _chsize_s(fd,size)
H. Peter Anvin7ab55952016-03-08 02:23:23 -080059# elif defined(HAVE__CHSIZE)
60# define nasm_ftruncate(fd,size) _chsize(fd,size)
61# elif defined(HAVE_FTRUNCATE)
62# define nasm_ftruncate(fd,size) ftruncate(fd,size)
63# endif
64#endif
65
H. Peter Anvinbdae10b2016-03-08 01:22:13 -080066void nasm_write(const void *ptr, size_t size, FILE *f)
67{
68 size_t n = fwrite(ptr, 1, size, f);
69 if (n != size || ferror(f) || feof(f))
70 nasm_fatal(0, "unable to write output: %s", strerror(errno));
71}
72
73#ifdef WORDS_LITTLEENDIAN
74
75void fwriteint16_t(uint16_t data, FILE * fp)
76{
77 nasm_write(&data, 2, fp);
78}
79
80void fwriteint32_t(uint32_t data, FILE * fp)
81{
82 nasm_write(&data, 4, fp);
83}
84
85void fwriteint64_t(uint64_t data, FILE * fp)
86{
87 nasm_write(&data, 8, fp);
88}
89
90void fwriteaddr(uint64_t data, int size, FILE * fp)
91{
92 nasm_write(&data, size, fp);
93}
94
95#else /* not WORDS_LITTLEENDIAN */
96
97void fwriteint16_t(uint16_t data, FILE * fp)
98{
99 char buffer[2], *p = buffer;
100 WRITESHORT(p, data);
101 nasm_write(buffer, 2, fp);
102}
103
104void fwriteint32_t(uint32_t data, FILE * fp)
105{
106 char buffer[4], *p = buffer;
107 WRITELONG(p, data);
108 nasm_write(buffer, 4, fp);
109}
110
111void fwriteint64_t(uint64_t data, FILE * fp)
112{
113 char buffer[8], *p = buffer;
114 WRITEDLONG(p, data);
115 nasm_write(buffer, 8, fp);
116}
117
118void fwriteaddr(uint64_t data, int size, FILE * fp)
119{
120 char buffer[8], *p = buffer;
121 WRITEADDR(p, data, size);
122 nasm_write(buffer, size, fp);
123}
124
125#endif
126
127
H. Peter Anvind81a2352016-09-21 14:03:18 -0700128void fwritezero(off_t bytes, FILE *fp)
H. Peter Anvinbdae10b2016-03-08 01:22:13 -0800129{
130 size_t blksize;
131
132#ifdef nasm_ftruncate
133 if (bytes >= BUFSIZ && !ferror(fp) && !feof(fp)) {
134 off_t pos = ftello(fp);
135 if (pos >= 0) {
H. Peter Anvind81a2352016-09-21 14:03:18 -0700136 pos += bytes;
H. Peter Anvinbdae10b2016-03-08 01:22:13 -0800137 if (!fflush(fp) &&
H. Peter Anvind81a2352016-09-21 14:03:18 -0700138 !nasm_ftruncate(fileno(fp), pos) &&
139 !fseeko(fp, pos, SEEK_SET))
H. Peter Anvinbdae10b2016-03-08 01:22:13 -0800140 return;
141 }
142 }
143#endif
144
H. Peter Anvind81a2352016-09-21 14:03:18 -0700145 while (bytes > 0) {
H. Peter Anvinbdae10b2016-03-08 01:22:13 -0800146 blksize = (bytes < ZERO_BUF_SIZE) ? bytes : ZERO_BUF_SIZE;
147
148 nasm_write(zero_buffer, blksize, fp);
149 bytes -= blksize;
150 }
151}
H. Peter Anvin3e83cec2016-05-25 04:28:46 -0700152
H. Peter Anvin3e83cec2016-05-25 04:28:46 -0700153FILE *nasm_open_read(const char *filename, enum file_flags flags)
154{
155 FILE *f;
H. Peter Anvind81a2352016-09-21 14:03:18 -0700156 bool again = true;
H. Peter Anvin3e83cec2016-05-25 04:28:46 -0700157
H. Peter Anvind81a2352016-09-21 14:03:18 -0700158#ifdef __GLIBC__
159 /*
160 * Try to open this file with memory mapping for speed, unless we are
161 * going to do it "manually" with nasm_map_file()
162 */
163 if (!(flags & NF_FORMAP)) {
164 f = fopen(filename, (flags & NF_TEXT) ? "rtm" : "rbm");
165 again = (!f) && (errno == EINVAL); /* Not supported, try without m */
166 }
167#endif
168
169 if (again)
170 f = fopen(filename, (flags & NF_TEXT) ? "rt" : "rb");
171
H. Peter Anvin3e83cec2016-05-25 04:28:46 -0700172 if (!f && (flags & NF_FATAL))
173 nasm_fatal(ERR_NOFILE, "unable to open input file: `%s': %s",
174 filename, strerror(errno));
175
176 return f;
177}
178
179FILE *nasm_open_write(const char *filename, enum file_flags flags)
180{
181 FILE *f;
182
H. Peter Anvind81a2352016-09-21 14:03:18 -0700183 f = fopen(filename, (flags & NF_TEXT) ? "wt" : "wb");
184
H. Peter Anvin3e83cec2016-05-25 04:28:46 -0700185 if (!f && (flags & NF_FATAL))
186 nasm_fatal(ERR_NOFILE, "unable to open output file: `%s': %s",
187 filename, strerror(errno));
188
189 return f;
190}
H. Peter Anvinc1700892016-09-20 18:26:42 -0700191
H. Peter Anvind81a2352016-09-21 14:03:18 -0700192/*
193 * Report the existence of a file
194 */
195bool nasm_file_exists(const char *filename)
196{
197#if defined(HAVE_FACCESSAT) && defined(AT_EACCESS)
198 return faccessat(AT_FDCWD, filename, R_OK, AT_EACCESS) == 0;
199#elif defined(HAVE_ACCESS)
200 return access(filename, R_OK) == 0;
201#else
202 FILE *f;
203
204 f = fopen(filename, "rb");
205 if (f) {
206 fclose(f);
207 return true;
208 } else {
209 return false;
210 }
211#endif
212}
213
214/*
215 * Report file size. This MAY move the file pointer.
216 */
217off_t nasm_file_size(FILE *f)
218{
219#if defined(HAVE_FILENO) && defined(HAVE_FSTAT)
220 struct stat st;
221
222 if (fstat(fileno(f), &st))
223 return (off_t)-1;
224
225 return st.st_size;
226#else
227 if (fseeko(f, 0, SEEK_END))
228 return (off_t)-1;
229
230 return ftello(f);
231#endif
232}
233
234/*
235 * Report file size given pathname
236 */
237off_t nasm_file_size_by_path(const char *pathname)
238{
239#ifdef HAVE_STAT
240 struct stat st;
241
242 if (stat(pathname, &st))
243 return (off_t)-1;
244
245 return st.st_size;
246#else
247 FILE *fp;
248 off_t len;
249
250 fp = nasm_open_read(pathname, NF_BINARY);
251 if (!fp)
252 return (off_t)-1;
253
254 len = nasm_file_size(fp);
255 fclose(fp);
256
257 return len;
258#endif
259}
260
261/*
262 * System page size
263 */
264
265/* File scope since not all compilers like static data in inline functions */
266static size_t nasm_pagemask;
267
268static size_t get_pagemask(void)
269{
270 size_t ps = 0;
271
272# if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
273 ps = sysconf(_SC_PAGESIZE);
274# elif defined(HAVE_GETPAGESIZE)
275 ps = getpagesize();
276# endif
277
278 nasm_pagemask = ps = is_power2(ps) ? (ps - 1) : 0;
279 return ps;
280}
281
282static inline size_t pagemask(void)
283{
284 size_t pm = nasm_pagemask;
285
286 if (unlikely(!pm))
287 return get_pagemask();
288
289 return pm;
290}
291
292/*
293 * Try to map an input file into memory
294 */
295const void *nasm_map_file(FILE *fp, off_t start, off_t len)
296{
297#if defined(HAVE_FILENO) && defined(HAVE_MMAP)
298 const char *p;
299 off_t astart; /* Aligned start */
300 size_t salign; /* Amount of start adjustment */
301 size_t alen; /* Aligned length */
302 const size_t page_mask = pagemask();
303
304 if (unlikely(!page_mask))
305 return NULL; /* Page size undefined? */
306
307 if (unlikely(!len))
308 return NULL; /* Mapping nothing... */
309
310 if (unlikely(len != (off_t)(size_t)len))
311 return NULL; /* Address space insufficient */
312
313 astart = start & ~(off_t)page_mask;
314 salign = start - astart;
315 alen = (len + salign + page_mask) & ~page_mask;
316
317 p = mmap(NULL, alen, PROT_READ, MAP_SHARED, fileno(fp), astart);
318 return unlikely(p == MAP_FAILED) ? NULL : p + salign;
319#else
320 /* XXX: add Windows support? */
321 return NULL;
322#endif
323}
324
325/*
326 * Unmap an input file
327 */
328void nasm_unmap_file(const void *p, size_t len)
329{
330#if defined(HAVE_FILENO) && defined(HAVE_MMAP)
331 const size_t page_mask = pagemask();
332 uintptr_t astart;
333 size_t salign;
334 size_t alen;
335
336 if (unlikely(!page_mask))
337 return;
338
339 astart = (uintptr_t)p & ~(uintptr_t)page_mask;
340 salign = (uintptr_t)p - astart;
341 alen = (len + salign + page_mask) & ~page_mask;
342
343 munmap((void *)astart, alen);
344#endif
345}