1 /*
2  *  Copyright (C) 1995, 1996  Karl-Johan Johnsson.
3  */
4 
5 #include "global.h"
6 #include <sys/stat.h>
7 #include <paths.h>
8 #include "expand.h"
9 #include "file.h"
10 
11 #if 0
12 #  define FILE_MASK	0666
13 #  define DIR_MASK	0777
14 #else
15 #  define FILE_MASK	(S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
16 #  define DIR_MASK	((FILE_MASK)|S_IXUSR|S_IXGRP|S_IXOTH)
17 #endif
18 
19 #ifndef O_ACCMODE
20 #  define O_ACCMODE 3
21 #endif
22 
open_mkdir(char * path,int flags,int report)23 int open_mkdir(char *path, int flags, int report)
24 {
25     struct stat	stat_buf;
26     char	*c;
27     int		fd;
28 
29     if (flags & O_CREAT)
30 	fd = open(path, flags, FILE_MASK);
31     else
32 	fd = open(path, flags);
33 
34     if (fd >= 0)
35 	return fd;
36 
37     if (errno == ENOENT && (flags & O_ACCMODE) != O_RDONLY) {
38 	if (path[0] == '/')
39 	    c = strchr(path + 1, '/');
40 	else
41 	    c = strchr(path, '/');
42 
43 	while (c) {
44 	    *c = '\0';
45 	    if (stat(path, &stat_buf) < 0 &&
46 		(errno != ENOENT || mkdir(path, DIR_MASK) < 0)) {
47 		*c++ = '/';
48 		return -1;
49 	    }
50 
51 	    *c++ = '/';
52 	    c = strchr(c, '/');
53 	}
54     }
55 
56     if (flags & O_CREAT)
57 	fd = open(path, flags, FILE_MASK);
58     else
59 	fd = open(path, flags);
60 
61     if (fd < 0 && (report || errno != ENOENT)) {
62 	int oerrno = errno;
63 	perror(path);
64 	errno = oerrno;
65     }
66 
67     return fd;
68 }
69 
open_expand(char * file_name,int flags,int report)70 int open_expand(char *file_name, int flags, int report)
71 {
72     char	*path;
73     int		fd;
74 
75     path = expand_path(file_name);
76     if (!path)
77 	return -1;
78 
79     fd = open_mkdir(path, flags, report);
80     XtFree(path);
81 
82     return fd;
83 }
84 
fopen_mkdir(char * path,char * mode,int report)85 FILE *fopen_mkdir(char *path, char *mode, int report)
86 {
87     int		fd, flags;
88     FILE	*ret;
89 
90     switch (*mode) {
91     case 'a':
92 	flags = O_WRONLY|O_APPEND|O_CREAT;
93 	break;
94     case 'r':
95 	flags = O_RDONLY;
96 	break;
97     case 'w':
98 	flags = O_WRONLY|O_TRUNC|O_CREAT;
99 	break;
100     default:
101 	fputs("knews: invalid mode to fopen_mkdir.\n", stderr);
102 	return NULL;
103     }
104 
105     fd = open_mkdir(path, flags, report);
106     if (fd < 0)
107 	return NULL;
108 
109     ret = fdopen(fd, mode);
110     if (!ret) {
111 	perror("fdopen");
112 	close(fd);
113     }
114 
115     return ret;
116 }
117 
fopen_expand(char * file_name,char * mode,int report)118 FILE *fopen_expand(char *file_name, char *mode, int report)
119 {
120     char	*path;
121     FILE	*fp;
122 
123     path = expand_path(file_name);
124     if (!path)
125 	return NULL;
126 
127     fp = fopen_mkdir(path, mode, report);
128     XtFree(path);
129 
130     return fp;
131 }
132 
unlink_expand(char * file_name)133 int unlink_expand(char *file_name)
134 {
135     char	*path;
136     int		ret;
137 
138     path = expand_path(file_name);
139     if (!path)
140 	return -1;
141 
142     ret = unlink(path);
143     XtFree(path);
144 
145     return ret;
146 }
147 
chdir_mkdir(char * path)148 int chdir_mkdir(char *path)
149 {
150     char	*c, *p;
151 
152     if (path[0] == '~' && path[1] == '/')
153 	path += 2;
154     if (chdir(path) == 0)
155 	return 0;
156     if (errno != ENOENT) {
157 	perror(path);
158 	return -1;
159     }
160 
161     c = path;
162     p = strchr(c, '/');
163     for (;;) {
164 	int	tmp;
165 
166 	if (p)
167 	    *p = '\0';
168 	tmp = chdir(c);
169 	if (tmp < 0 && errno == ENOENT && mkdir(c, DIR_MASK) == 0)
170 	    tmp = chdir(c);
171 	if (p)
172 	    *p++ = '/';
173 	if (tmp < 0) {
174 	    perror(path);
175 	    return -1;
176 	}
177 	c = p;
178 	if (!c)
179 	    break;
180 	p = strchr(c, '\n');
181     }
182 
183     return 0;
184 }
185 
create_temp_fd(char ** name)186 int create_temp_fd(char **name)
187 {
188     int	fd;
189     char filename[FILENAME_MAX];
190     char *tmpdir;
191 
192     if ((tmpdir = getenv("TMPDIR")) == NULL)
193 	tmpdir = _PATH_TMP;
194     strlcpy(filename, tmpdir, FILENAME_MAX);
195     strlcat(filename, "/tmp.XXXXXX", FILENAME_MAX);
196 
197     if ((fd = mkstemp(filename)) == -1)
198 	*name = NULL;
199     else
200         *name = filename;
201 
202     return fd;
203 }
204 
create_temp_file(char ** name)205 FILE *create_temp_file(char **name)
206 {
207     int	fd;
208 
209     fd = create_temp_fd(name);
210     if (fd < 0)
211 	return NULL;
212 
213     return fdopen(fd, "w+");
214 }
215 
snarf_file(int fd,long * lenp)216 char *snarf_file(int fd, long *lenp)
217 {
218     struct stat	stat_buf;
219     char	*buffer;
220     long	len, pos, n;
221 
222     if (fstat(fd, &stat_buf) < 0) {
223 	perror("fstat");
224 	return NULL;
225     }
226 
227     if (!S_ISREG(stat_buf.st_mode)) {
228 	fputs("snarf_file: not a regular file!\n", stderr);
229 	errno = EINVAL;
230 	return NULL;
231     }
232 
233     pos = 0;
234     len = stat_buf.st_size + 256;
235     buffer = malloc(len + 1);
236     if (!buffer) {
237 	perror("malloc");
238 	return NULL;
239     }
240 
241     while ((n = read(fd, buffer + pos, len - pos)) != 0)
242 	if (n < 0)
243 	    if (errno == EINTR)
244 		continue;
245 	    else {
246 		perror("read");
247 		free(buffer);
248 		return NULL;
249 	    }
250 	else {
251 	    pos += n;
252 	    if (pos == len) {
253 		char	*tmp;
254 
255 		len *= 2;
256 		tmp = realloc(buffer, len + 1);
257 		if (!tmp) {
258 		    perror("realloc");
259 		    free(buffer);
260 		    return NULL;
261 		}
262 		buffer = tmp;
263 	    }
264 	}
265 
266     buffer[pos] = '\0';
267     if (lenp)
268 	*lenp = pos;
269 
270     return buffer;
271 }
272 
writen(int fd,char * buf,long n)273 int writen(int fd, char *buf, long n)
274 {
275     long	i;
276 
277     while (n > 0)
278 	switch ((i = write(fd, buf, n))) {
279 	case -1:
280 	    perror("write");
281 	    return -1;
282 	case 0:
283 	    fputs("knews: write(..) = 0, weird...\n", stderr);
284 	    return -1;
285 	default:
286 	    buf += i;
287 	    n -= i;
288 	    break;
289 	}
290 
291     return 0;
292 }
293