Makefile: Activate optimization and -Wuninitialized.
[osl.git] / fd.c
1 /*
2  * Copyright (C) 2006-2008 Andre Noll <maan@systemlinux.org>
3  *
4  * Licensed under the GPL v2. For licencing details see COPYING.
5  */
6
7 /** \file fd.c Helper functions for file descriptor handling. */
8
9 #include <sys/types.h>
10 #include <dirent.h>
11 #include <sys/mman.h>
12 #include <fcntl.h>
13 #include <sys/select.h>
14
15 #include "log.h"
16 #include "osl.h"
17 #include "error.h"
18
19 /**
20  * Write a buffer to a file descriptor, re-write on short writes.
21  *
22  * \param fd The file descriptor.
23  * \param buf The buffer to be sent.
24  * \param len The length of \a buf.
25  *
26  * \return Standard. In any case, the number of bytes that have been written is
27  * stored in \a len.
28  */
29 int write_all(int fd, const char *buf, size_t *len)
30 {
31         size_t total = *len;
32
33         assert(total);
34         *len = 0;
35         while (*len < total) {
36                 int ret = write(fd, buf + *len, total - *len);
37                 if (ret == -1)
38                         return -ERRNO_TO_ERROR(errno);
39                 *len += ret;
40         }
41         return 1;
42 }
43
44 /**
45  * Wrapper for the open(2) system call.
46  *
47  * \param path The filename.
48  * \param flags The usual open(2) flags.
49  * \param mode Specifies the permissions to use.
50  *
51  * The mode parameter must be specified when O_CREAT is in the flags, and is
52  * ignored otherwise.
53  *
54  * \return The file descriptor on success, negative on errors.
55  *
56  * \sa open(2).
57  */
58 int osl_open(const char *path, int flags, mode_t mode)
59 {
60         int ret = open(path, flags, mode);
61
62         if (ret >= 0)
63                 return ret;
64         return -ERRNO_TO_ERROR(errno);
65 }
66
67 /**
68  * Wrapper for chdir(2).
69  *
70  * \param path The specified directory.
71  *
72  * \return Standard.
73  */
74 static int para_chdir(const char *path)
75 {
76         int ret = chdir(path);
77
78         if (ret >= 0)
79                 return 1;
80         return -ERRNO_TO_ERROR(errno);
81 }
82
83 /**
84  * Save the cwd and open a given directory.
85  *
86  * \param dirname Path to the directory to open.
87  * \param dir Result pointer.
88  * \param cwd File descriptor of the current working directory.
89  *
90  * \return Standard.
91  *
92  * Opening the current directory (".") and calling fchdir() to return is
93  * usually faster and more reliable than saving cwd in some buffer and calling
94  * chdir() afterwards.
95  *
96  * If \a cwd is not \p NULL "." is opened and the resulting file descriptor is
97  * stored in \a cwd. If the function returns success, and \a cwd is not \p
98  * NULL, the caller must close this file descriptor (probably after calling
99  * fchdir(*cwd)).
100  *
101  * On errors, the function undos everything, so the caller needs neither close
102  * any files, nor change back to the original working directory.
103  *
104  * \sa getcwd(3).
105  *
106  */
107 int para_opendir(const char *dirname, DIR **dir, int *cwd)
108 {
109         int ret;
110
111         if (cwd) {
112                 ret = osl_open(".", O_RDONLY, 0);
113                 if (ret < 0)
114                         return ret;
115                 *cwd = ret;
116         }
117         ret = para_chdir(dirname);
118         if (ret < 0)
119                 goto close_cwd;
120         *dir = opendir(".");
121         if (*dir)
122                 return 1;
123         ret = -ERRNO_TO_ERROR(errno);
124 /* Ignore return value of fchdir() and close(). We're busted anyway. */
125         if (cwd)
126                 fchdir(*cwd);
127 close_cwd:
128         if (cwd)
129                 close(*cwd);
130         return ret;
131 }
132
133 /**
134  * A wrapper for fchdir().
135  *
136  * \param fd An open file descriptor.
137  *
138  * \return Standard.
139  */
140 int para_fchdir(int fd)
141 {
142         if (fchdir(fd) < 0)
143                 return -ERRNO_TO_ERROR(errno);
144         return 1;
145 }
146
147 /**
148  * A wrapper for mkdir(2).
149  *
150  * \param path Name of the directory to create.
151  * \param mode The permissions to use.
152  *
153  * \return Standard.
154  */
155 int para_mkdir(const char *path, mode_t mode)
156 {
157         if (!mkdir(path, mode))
158                 return 1;
159         return -ERRNO_TO_ERROR(errno);
160 }
161
162 /**
163  * Open a file and map it into memory.
164  *
165  * \param path Name of the regular file to map.
166  * \param open_mode Either \p O_RDONLY or \p O_RDWR.
167  * \param map On success, the mapping is returned here.
168  * \param size size of the mapping.
169  * \param fd_ptr The file descriptor of the mapping.
170  *
171  * If \a fd_ptr is \p NULL, the file descriptor resulting from the underlying
172  * open call is closed after mmap().  Otherwise the file is kept open and the
173  * file descriptor is returned in \a fd_ptr.
174  *
175  * \return Standard.
176  *
177  * \sa osl_open(), mmap(2).
178  */
179 int mmap_full_file(const char *path, int open_mode, void **map,
180                 size_t *size, int *fd_ptr)
181 {
182         int fd, ret, mmap_prot, mmap_flags;
183         struct stat file_status;
184
185         if (open_mode == O_RDONLY) {
186                 mmap_prot = PROT_READ;
187                 mmap_flags = MAP_PRIVATE;
188         } else {
189                 mmap_prot = PROT_READ | PROT_WRITE;
190                 mmap_flags = MAP_SHARED;
191         }
192         ret = osl_open(path, open_mode, 0);
193         if (ret < 0)
194                 return ret;
195         fd = ret;
196         if (fstat(fd, &file_status) < 0) {
197                 ret = -ERRNO_TO_ERROR(errno);
198                 goto out;
199         }
200         *size = file_status.st_size;
201         ret = -E_OSL_EMPTY;
202         DEBUG_LOG("%s: size %zu\n", path, *size);
203         if (!*size)
204                 goto out;
205         *map = mmap(NULL, *size, mmap_prot, mmap_flags, fd, 0);
206         if (*map == MAP_FAILED) {
207                 *map = NULL;
208                 ret = -E_OSL_MMAP;
209                 goto out;
210         }
211         ret = 1;
212 out:
213         if (ret < 0 || !fd_ptr)
214                 close(fd);
215         else
216                 *fd_ptr = fd;
217         return ret;
218 }
219
220 /**
221  * A wrapper for munmap(2).
222  *
223  * \param start The start address of the memory mapping.
224  * \param length The size of the mapping.
225  *
226  * \return Positive on success, \p -E_MUNMAP on errors.
227  *
228  * \sa munmap(2), mmap_full_file().
229  */
230 int para_munmap(void *start, size_t length)
231 {
232         int err;
233         if (munmap(start, length) >= 0)
234                 return 1;
235         err = errno;
236         ERROR_LOG("munmap (%p/%zu) failed: %s\n", start, length,
237                 strerror(err));
238         return -ERRNO_TO_ERROR(err);
239 }