lib: Move x_fgets_slash to xfile.c
[martins/samba.git] / lib / util / util_file.c
1 /*
2  * Unix SMB/CIFS implementation.
3  * SMB parameters and setup
4  * Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995.
5  *
6  * Added afdgets() Jelmer Vernooij 2005
7  *
8  * This program is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License as published by the Free
10  * Software Foundation; either version 3 of the License, or (at your option)
11  * any later version.
12  *
13  * This program is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
16  * more details.
17  *
18  * You should have received a copy of the GNU General Public License along with
19  * this program; if not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include "replace.h"
23 #include "system/shmem.h"
24 #include "system/filesys.h"
25 #include <talloc.h>
26 #include "lib/util/samba_util.h"
27 #include "lib/util/debug.h"
28
29 /**
30  * Read one line (data until next newline or eof) and allocate it
31  */
32 _PUBLIC_ char *afdgets(int fd, TALLOC_CTX *mem_ctx, size_t hint)
33 {
34         char *data = NULL;
35         ssize_t alloc_size = 0, offset = 0, ret;
36         int p;
37
38         if (hint <= 0) hint = 0x100;
39
40         do {
41                 alloc_size += hint;
42
43                 data = talloc_realloc(mem_ctx, data, char, alloc_size);
44
45                 if (!data)
46                         return NULL;
47
48                 ret = read(fd, data + offset, hint);
49
50                 if (ret == 0) {
51                         return NULL;
52                 }
53
54                 if (ret == -1) {
55                         talloc_free(data);
56                         return NULL;
57                 }
58
59                 /* Find newline */
60                 for (p = 0; p < ret; p++) {
61                         if (data[offset + p] == '\n')
62                                 break;
63                 }
64
65                 if (p < ret) {
66                         data[offset + p] = '\0';
67
68                         /* Go back to position of newline */
69                         lseek(fd, p - ret + 1, SEEK_CUR);
70                         return data;
71                 }
72
73                 offset += ret;
74
75         } while (ret == hint);
76
77         data[offset] = '\0';
78
79         return data;
80 }
81
82
83 /**
84 load a file into memory from a fd.
85 **/
86 _PUBLIC_ char *fd_load(int fd, size_t *psize, size_t maxsize, TALLOC_CTX *mem_ctx)
87 {
88         struct stat sbuf;
89         char *p;
90         size_t size;
91
92         if (fstat(fd, &sbuf) != 0) return NULL;
93
94         size = sbuf.st_size;
95
96         if (maxsize) {
97                 size = MIN(size, maxsize);
98         }
99
100         p = (char *)talloc_size(mem_ctx, size+1);
101         if (!p) return NULL;
102
103         if (read(fd, p, size) != size) {
104                 talloc_free(p);
105                 return NULL;
106         }
107         p[size] = 0;
108
109         if (psize) *psize = size;
110
111         return p;
112 }
113
114 /**
115 load a file into memory
116 **/
117 _PUBLIC_ char *file_load(const char *fname, size_t *size, size_t maxsize, TALLOC_CTX *mem_ctx)
118 {
119         int fd;
120         char *p;
121
122         if (!fname || !*fname) return NULL;
123
124         fd = open(fname,O_RDONLY);
125         if (fd == -1) return NULL;
126
127         p = fd_load(fd, size, maxsize, mem_ctx);
128
129         close(fd);
130
131         return p;
132 }
133
134 /**
135 parse a buffer into lines
136 'p' will be freed on error, and otherwise will be made a child of the returned array
137 **/
138 char **file_lines_parse(char *p, size_t size, int *numlines, TALLOC_CTX *mem_ctx)
139 {
140         int i;
141         char *s, **ret;
142
143         if (!p) return NULL;
144
145         for (s = p, i=0; s < p+size; s++) {
146                 if (s[0] == '\n') i++;
147         }
148
149         ret = talloc_zero_array(mem_ctx, char *, i+2);
150         if (!ret) {
151                 talloc_free(p);
152                 return NULL;
153         }
154
155         talloc_steal(ret, p);
156
157         ret[0] = p;
158         for (s = p, i=0; s < p+size; s++) {
159                 if (s[0] == '\n') {
160                         s[0] = 0;
161                         i++;
162                         ret[i] = s+1;
163                 }
164                 if (s[0] == '\r') s[0] = 0;
165         }
166
167         /* remove any blank lines at the end */
168         while (i > 0 && ret[i-1][0] == 0) {
169                 i--;
170         }
171
172         if (numlines) *numlines = i;
173
174         return ret;
175 }
176
177
178 /**
179 load a file into memory and return an array of pointers to lines in the file
180 must be freed with talloc_free().
181 **/
182 _PUBLIC_ char **file_lines_load(const char *fname, int *numlines, size_t maxsize, TALLOC_CTX *mem_ctx)
183 {
184         char *p;
185         size_t size;
186
187         p = file_load(fname, &size, maxsize, mem_ctx);
188         if (!p) return NULL;
189
190         return file_lines_parse(p, size, numlines, mem_ctx);
191 }
192
193 /**
194 load a fd into memory and return an array of pointers to lines in the file
195 must be freed with talloc_free(). If convert is true calls unix_to_dos on
196 the list.
197 **/
198 _PUBLIC_ char **fd_lines_load(int fd, int *numlines, size_t maxsize, TALLOC_CTX *mem_ctx)
199 {
200         char *p;
201         size_t size;
202
203         p = fd_load(fd, &size, maxsize, mem_ctx);
204         if (!p) return NULL;
205
206         return file_lines_parse(p, size, numlines, mem_ctx);
207 }
208
209 _PUBLIC_ bool file_save_mode(const char *fname, const void *packet,
210                              size_t length, mode_t mode)
211 {
212         int fd;
213         fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, mode);
214         if (fd == -1) {
215                 return false;
216         }
217         if (write(fd, packet, length) != (size_t)length) {
218                 close(fd);
219                 return false;
220         }
221         close(fd);
222         return true;
223 }
224
225 /**
226   save a lump of data into a file. Mostly used for debugging
227 */
228 _PUBLIC_ bool file_save(const char *fname, const void *packet, size_t length)
229 {
230         return file_save_mode(fname, packet, length, 0644);
231 }
232
233 _PUBLIC_ int vfdprintf(int fd, const char *format, va_list ap)
234 {
235         char *p;
236         int len, ret;
237         va_list ap2;
238
239         va_copy(ap2, ap);
240         len = vasprintf(&p, format, ap2);
241         va_end(ap2);
242         if (len <= 0) return len;
243         ret = write(fd, p, len);
244         SAFE_FREE(p);
245         return ret;
246 }
247
248 _PUBLIC_ int fdprintf(int fd, const char *format, ...)
249 {
250         va_list ap;
251         int ret;
252
253         va_start(ap, format);
254         ret = vfdprintf(fd, format, ap);
255         va_end(ap);
256         return ret;
257 }
258
259
260 /*
261   compare two files, return true if the two files have the same content
262  */
263 bool file_compare(const char *path1, const char *path2)
264 {
265         size_t size1, size2;
266         char *p1, *p2;
267         TALLOC_CTX *mem_ctx = talloc_new(NULL);
268
269         p1 = file_load(path1, &size1, 0, mem_ctx);
270         p2 = file_load(path2, &size2, 0, mem_ctx);
271         if (!p1 || !p2 || size1 != size2) {
272                 talloc_free(mem_ctx);
273                 return false;
274         }
275         if (memcmp(p1, p2, size1) != 0) {
276                 talloc_free(mem_ctx);
277                 return false;
278         }
279         talloc_free(mem_ctx);
280         return true;
281 }