1 /*
2 	Copyright (C) 2004, 2005 Stephen Bach
3 	This file is part of the Viewglob package.
4 
5 	Viewglob 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; either version 2 of the License, or
8 	(at your option) any later version.
9 
10 	Viewglob is distributed in the hope that it will be useful,
11 	but WITHOUT ANY WARRANTY; without even the implied warranty of
12 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 	GNU General Public License for more details.
14 
15 	You should have received a copy of the GNU General Public License
16 	along with Viewglob; if not, write to the Free Software
17 	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19 
20 #include "common.h"
21 #include "hardened-io.h"
22 
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 
26 
27 /* Attempt to open the given file with the given flags and mode.
28    Emit warning if it doesn't work out. */
open_warning(gchar * file_name,gint flags,mode_t mode)29 gint open_warning(gchar* file_name, gint flags, mode_t mode) {
30 
31 	g_return_val_if_fail(file_name != NULL, -1);
32 
33 	gint fd;
34 
35 	if ((fd = open(file_name, flags, mode)) == -1)
36 		g_warning("Could not open file \"%s\": %s", file_name,
37 				g_strerror(errno));
38 
39 	return fd;
40 }
41 
42 
43 /* Attempt to close the given file.  Emit warning on failure. */
close_warning(gint fd,gchar * file_name)44 void close_warning(gint fd, gchar* file_name) {
45 	if (fd != -1 && close(fd) == -1)
46 		g_warning("Could not close file \"%s\": %s", file_name,
47 				g_strerror(errno));
48 }
49 
50 
51 /* Retry read on EINTR. */
hardened_read(gint fd,void * buf,gsize count,gssize * nread)52 enum io_result hardened_read(gint fd, void* buf, gsize count, gssize* nread) {
53 
54 	g_return_val_if_fail(fd >= 0, IOR_ERROR);
55 	g_return_val_if_fail(buf != NULL, IOR_ERROR);
56 
57 	gboolean result = IOR_OK;
58 
59 	do {
60 		*nread = read(fd, buf, count);
61 	} while (*nread == -1 && errno == EINTR);
62 
63 	if (*nread == -1)
64 		result = IOR_ERROR;
65 	else if (*nread == 0)
66 		result = IOR_EOF;
67 
68 	return result;
69 }
70 
71 
72 /* Read exactly the given number of bytes. */
read_all(gint fd,void * buf,gsize bytes)73 enum io_result read_all(gint fd, void* buf, gsize bytes) {
74 
75 	g_return_val_if_fail(fd >= 0, IOR_ERROR);
76 	g_return_val_if_fail(buf != NULL, IOR_ERROR);
77 
78 	gboolean result = IOR_OK;
79 	gssize nread = 0;
80 
81 	gchar* pos = buf;
82 	while (bytes) {
83 		errno = 0;
84 		if ( (nread = read(fd, pos, bytes)) == -1) {
85 			if (errno == EINTR)
86 				nread = 0;
87 			else {
88 				result = IOR_ERROR;
89 				break;
90 			}
91 		}
92 		else if (nread == 0) {
93 			result = IOR_EOF;
94 			break;
95 		}
96 		bytes -= nread;
97 		pos += nread;
98 	}
99 
100 	return result;
101 }
102 
103 
104 /* Write all length bytes of buf to fd, even if it requires several tries.
105    Retry after signal interrupts. */
write_all(gint fd,void * buf,gsize bytes)106 enum io_result write_all(gint fd, void* buf, gsize bytes) {
107 
108 	g_return_val_if_fail(fd >= 0, IOR_ERROR);
109 	g_return_val_if_fail(buf != NULL, IOR_ERROR);
110 
111 	enum io_result result = IOR_OK;
112 	gssize nwritten;
113 
114 	gchar* pos = buf;
115 	while (bytes) {
116 		errno = 0;
117 		if ( (nwritten = write(fd, pos, bytes)) == -1 ) {
118 			if (errno == EINTR)
119 				nwritten = 0;
120 			else {
121 				result = IOR_ERROR;
122 				break;
123 			}
124 		}
125 		bytes -= nwritten;
126 		pos += nwritten;
127 	}
128 
129 	return result;
130 }
131 
132 
133 /* Wrapper for writev() to ensure everything is written. */
writev_all(gint fd,struct iovec * vec,gint count)134 enum io_result writev_all(gint fd, struct iovec* vec, gint count) {
135 
136 	g_return_val_if_fail(fd >= 0, IOR_ERROR);
137 	g_return_val_if_fail(vec != NULL, IOR_ERROR);
138 	g_return_val_if_fail(count >= 0, IOR_ERROR);
139 
140 	gssize nwritten;
141 	enum io_result result = IOR_OK;
142 
143 	do
144 		nwritten = writev(fd, vec, count);
145 	while (nwritten == -1 && errno == EINTR);
146 
147 	if (nwritten == -1)
148 		result = IOR_ERROR;
149 	else {
150 		gchar* ptr;
151 		while (count > 0) {
152 			if (nwritten >= vec->iov_len) {
153 				/* This buffer was completely written. */
154 				nwritten -= vec->iov_len;
155 				vec++;
156 				count--;
157 			}
158 			else {
159 				/* This buffer was partially written. */
160 				ptr = vec->iov_base;
161 				ptr += nwritten;
162 				vec->iov_base = ptr;
163 				vec->iov_len -= nwritten;
164 				break;
165 			}
166 		}
167 
168 		if (count > 1)
169 			result = writev_all(fd, vec, count);
170 		else if (count == 1)
171 			result = write_all(fd, vec->iov_base, vec->iov_len);
172 	}
173 
174 	return result;
175 }
176 
177 
178 /* If select is interrupted by a signal, try again. */
179 //int hardened_select(gint n, fd_set* readfds, struct timeval* timeout) {
hardened_select(gint n,fd_set * readfds,long milliseconds)180 int hardened_select(gint n, fd_set* readfds, long milliseconds) {
181 
182 	g_return_val_if_fail(n > 0, -1);
183 	g_return_val_if_fail(readfds != NULL, -1);
184 
185 	int result;
186 	struct timeval* t = NULL;
187 
188 	/* Create a timestruct for the given number of milliseconds. */
189 	if (milliseconds >= 0) {
190 		t = g_new(struct timeval, 1);
191 		t->tv_sec = milliseconds / 1000;
192 		t->tv_usec = (milliseconds - (1000 * t->tv_sec)) * 1000;
193 	}
194 
195 	do {
196 		result = select(n, readfds, NULL, NULL, t);
197 	} while (result == -1 && errno == EINTR);
198 
199 	g_free(t);
200 	return result;
201 }
202 
203