r3447: more include/system/XXX.h include files
[jelmer/samba4-debian.git] / source / lib / 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  * This program is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License as published by the Free
8  * Software Foundation; either version 2 of the License, or (at your option)
9  * any later version.
10  * 
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14  * more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with
17  * this program; if not, write to the Free Software Foundation, Inc., 675
18  * Mass Ave, Cambridge, MA 02139, USA.
19  */
20
21 #include "includes.h"
22 #include "system/shmem.h"
23
24 /*************************************************************************
25  gets a line out of a file.
26  line is of format "xxxx:xxxxxx:xxxxx:".
27  lines with "#" at the front are ignored.
28 *************************************************************************/
29 int getfileline(void *vp, char *linebuf, int linebuf_size)
30 {
31         /* Static buffers we will return. */
32         FILE *fp = (FILE *)vp;
33         uint8_t   c;
34         uint8_t  *p;
35         size_t            linebuf_len;
36
37         if (fp == NULL)
38         {
39                 DEBUG(0,("getfileline: Bad file pointer.\n"));
40                 return -1;
41         }
42
43         /*
44          * Scan the file, a line at a time.
45          */
46         while (!feof(fp))
47         {
48                 linebuf[0] = '\0';
49
50                 fgets(linebuf, linebuf_size, fp);
51                 if (ferror(fp))
52                 {
53                         return -1;
54                 }
55
56                 /*
57                  * Check if the string is terminated with a newline - if not
58                  * then we must keep reading and discard until we get one.
59                  */
60
61                 linebuf_len = strlen(linebuf);
62                 if (linebuf_len == 0)
63                 {
64                         linebuf[0] = '\0';
65                         return 0;
66                 }
67
68                 if (linebuf[linebuf_len - 1] != '\n')
69                 {
70                         c = '\0';
71                         while (!ferror(fp) && !feof(fp))
72                         {
73                                 c = fgetc(fp);
74                                 if (c == '\n')
75                                 {
76                                         break;
77                                 }
78                         }
79                 }
80                 else
81                 {
82                         linebuf[linebuf_len - 1] = '\0';
83                 }
84
85 #ifdef DEBUG_PASSWORD
86                 DEBUG(100, ("getfileline: got line |%s|\n", linebuf));
87 #endif
88                 if ((linebuf[0] == 0) && feof(fp))
89                 {
90                         DEBUG(4, ("getfileline: end of file reached\n"));
91                         return 0;
92                 }
93
94                 if (linebuf[0] == '#' || linebuf[0] == '\0')
95                 {
96                         DEBUG(6, ("getfileline: skipping comment or blank line\n"));
97                         continue;
98                 }
99
100                 p = (uint8_t *) strchr_m(linebuf, ':');
101                 if (p == NULL)
102                 {
103                         DEBUG(0, ("getfileline: malformed line entry (no :)\n"));
104                         continue;
105                 }
106                 return linebuf_len;
107         }
108         return -1;
109 }
110
111
112 /****************************************************************************
113 read a line from a file with possible \ continuation chars. 
114 Blanks at the start or end of a line are stripped.
115 The string will be allocated if s2 is NULL
116 ****************************************************************************/
117 char *fgets_slash(char *s2,int maxlen,XFILE *f)
118 {
119   char *s=s2;
120   int len = 0;
121   int c;
122   BOOL start_of_line = True;
123
124   if (x_feof(f))
125     return(NULL);
126
127   if (maxlen <2) return(NULL);
128
129   if (!s2)
130     {
131       maxlen = MIN(maxlen,8);
132       s = (char *)malloc(maxlen);
133     }
134
135   if (!s) return(NULL);
136
137   *s = 0;
138
139   while (len < maxlen-1)
140     {
141       c = x_getc(f);
142       switch (c)
143         {
144         case '\r':
145           break;
146         case '\n':
147           while (len > 0 && s[len-1] == ' ')
148             {
149               s[--len] = 0;
150             }
151           if (len > 0 && s[len-1] == '\\')
152             {
153               s[--len] = 0;
154               start_of_line = True;
155               break;
156             }
157           return(s);
158         case EOF:
159           if (len <= 0 && !s2) 
160             SAFE_FREE(s);
161           return(len>0?s:NULL);
162         case ' ':
163           if (start_of_line)
164             break;
165         default:
166           start_of_line = False;
167           s[len++] = c;
168           s[len] = 0;
169         }
170       if (!s2 && len > maxlen-3)
171         {
172           char *t;
173           
174           maxlen *= 2;
175           t = (char *)Realloc(s,maxlen);
176           if (!t) {
177             DEBUG(0,("fgets_slash: failed to expand buffer!\n"));
178             SAFE_FREE(s);
179             return(NULL);
180           } else s = t;
181         }
182     }
183   return(s);
184 }
185
186
187
188 /****************************************************************************
189 load a file into memory from a fd.
190 ****************************************************************************/ 
191
192 char *fd_load(int fd, size_t *size)
193 {
194         struct stat sbuf;
195         char *p;
196
197         if (fstat(fd, &sbuf) != 0) return NULL;
198
199         p = (char *)malloc(sbuf.st_size+1);
200         if (!p) return NULL;
201
202         if (read(fd, p, sbuf.st_size) != sbuf.st_size) {
203                 SAFE_FREE(p);
204                 return NULL;
205         }
206         p[sbuf.st_size] = 0;
207
208         if (size) *size = sbuf.st_size;
209
210         return p;
211 }
212
213 /****************************************************************************
214 load a file into memory
215 ****************************************************************************/
216 char *file_load(const char *fname, size_t *size)
217 {
218         int fd;
219         char *p;
220
221         if (!fname || !*fname) return NULL;
222         
223         fd = open(fname,O_RDONLY);
224         if (fd == -1) return NULL;
225
226         p = fd_load(fd, size);
227
228         close(fd);
229
230         return p;
231 }
232
233
234 /*******************************************************************
235 mmap (if possible) or read a file
236 ********************************************************************/
237 void *map_file(char *fname, size_t size)
238 {
239         size_t s2 = 0;
240         void *p = NULL;
241 #ifdef HAVE_MMAP
242         int fd;
243         fd = open(fname, O_RDONLY, 0);
244         if (fd == -1) {
245                 DEBUG(2,("Failed to load %s - %s\n", fname, strerror(errno)));
246                 return NULL;
247         }
248         p = mmap(NULL, size, PROT_READ, MAP_SHARED|MAP_FILE, fd, 0);
249         close(fd);
250         if (p == MAP_FAILED) {
251                 DEBUG(1,("Failed to mmap %s - %s\n", fname, strerror(errno)));
252                 return NULL;
253         }
254 #endif
255         if (!p) {
256                 p = file_load(fname, &s2);
257                 if (!p) return NULL;
258                 if (s2 != size) {
259                         DEBUG(1,("incorrect size for %s - got %d expected %d\n",
260                                  fname, s2, size));
261                         if (p) free(p);
262                         return NULL;
263                 }
264         }
265
266         return p;
267 }
268
269
270 /****************************************************************************
271 parse a buffer into lines
272 ****************************************************************************/
273 static char **file_lines_parse(char *p, size_t size, int *numlines)
274 {
275         int i;
276         char *s, **ret;
277
278         if (!p) return NULL;
279
280         for (s = p, i=0; s < p+size; s++) {
281                 if (s[0] == '\n') i++;
282         }
283
284         ret = (char **)malloc(sizeof(ret[0])*(i+2));
285         if (!ret) {
286                 SAFE_FREE(p);
287                 return NULL;
288         }       
289         memset(ret, 0, sizeof(ret[0])*(i+2));
290         if (numlines) *numlines = i;
291
292         ret[0] = p;
293         for (s = p, i=0; s < p+size; s++) {
294                 if (s[0] == '\n') {
295                         s[0] = 0;
296                         i++;
297                         ret[i] = s+1;
298                 }
299                 if (s[0] == '\r') s[0] = 0;
300         }
301
302         return ret;
303 }
304
305
306 /****************************************************************************
307 load a file into memory and return an array of pointers to lines in the file
308 must be freed with file_lines_free(). 
309 ****************************************************************************/
310 char **file_lines_load(const char *fname, int *numlines)
311 {
312         char *p;
313         size_t size;
314
315         p = file_load(fname, &size);
316         if (!p) return NULL;
317
318         return file_lines_parse(p, size, numlines);
319 }
320
321 /****************************************************************************
322 load a fd into memory and return an array of pointers to lines in the file
323 must be freed with file_lines_free(). If convert is true calls unix_to_dos on
324 the list.
325 ****************************************************************************/
326 char **fd_lines_load(int fd, int *numlines)
327 {
328         char *p;
329         size_t size;
330
331         p = fd_load(fd, &size);
332         if (!p) return NULL;
333
334         return file_lines_parse(p, size, numlines);
335 }
336
337
338 /****************************************************************************
339 free lines loaded with file_lines_load
340 ****************************************************************************/
341 void file_lines_free(char **lines)
342 {
343         if (!lines) return;
344         SAFE_FREE(lines[0]);
345         SAFE_FREE(lines);
346 }
347
348
349 /****************************************************************************
350 take a lislist of lines and modify them to produce a list where \ continues
351 a line
352 ****************************************************************************/
353 void file_lines_slashcont(char **lines)
354 {
355         int i, j;
356
357         for (i=0; lines[i];) {
358                 int len = strlen(lines[i]);
359                 if (lines[i][len-1] == '\\') {
360                         lines[i][len-1] = ' ';
361                         if (lines[i+1]) {
362                                 char *p = &lines[i][len];
363                                 while (p < lines[i+1]) *p++ = ' ';
364                                 for (j = i+1; lines[j]; j++) lines[j] = lines[j+1];
365                         }
366                 } else {
367                         i++;
368                 }
369         }
370 }
371
372 /*
373   save a lump of data into a file. Mostly used for debugging 
374 */
375 BOOL file_save(const char *fname, void *packet, size_t length)
376 {
377         int fd;
378         fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0644);
379         if (fd == -1) {
380                 return False;
381         }
382         if (write(fd, packet, length) != (size_t)length) {
383                 return False;
384         }
385         close(fd);
386         return True;
387 }