r17316: More C++ warnings -- 456 left
[samba.git] / source3 / 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
23 #ifndef MAP_FAILED
24 #define MAP_FAILED ((void *)-1)
25 #endif
26
27 static int gotalarm;
28
29 /***************************************************************
30  Signal function to tell us we timed out.
31 ****************************************************************/
32
33 static void gotalarm_sig(void)
34 {
35         gotalarm = 1;
36 }
37
38 /***************************************************************
39  Lock or unlock a fd for a known lock type. Abandon after waitsecs 
40  seconds.
41 ****************************************************************/
42
43 BOOL do_file_lock(int fd, int waitsecs, int type)
44 {
45         SMB_STRUCT_FLOCK lock;
46         int             ret;
47         void (*oldsig_handler)(int);
48
49         gotalarm = 0;
50         oldsig_handler = CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
51
52         lock.l_type = type;
53         lock.l_whence = SEEK_SET;
54         lock.l_start = 0;
55         lock.l_len = 1;
56         lock.l_pid = 0;
57
58         alarm(waitsecs);
59         /* Note we must *NOT* use sys_fcntl here ! JRA */
60         ret = fcntl(fd, SMB_F_SETLKW, &lock);
61         alarm(0);
62         CatchSignal(SIGALRM, SIGNAL_CAST oldsig_handler);
63
64         if (gotalarm) {
65                 DEBUG(0, ("do_file_lock: failed to %s file.\n",
66                         type == F_UNLCK ? "unlock" : "lock"));
67                 return False;
68         }
69
70         return (ret == 0);
71 }
72
73 /***************************************************************
74  Lock an fd. Abandon after waitsecs seconds.
75 ****************************************************************/
76
77 BOOL file_lock(int fd, int type, int secs, int *plock_depth)
78 {
79         if (fd < 0)
80                 return False;
81
82         (*plock_depth)++;
83
84         if ((*plock_depth) == 0) {
85                 if (!do_file_lock(fd, secs, type)) {
86                         DEBUG(10,("file_lock: locking file failed, error = %s.\n", strerror(errno)));
87                         return False;
88                 }
89         }
90
91         return True;
92 }
93
94 /***************************************************************
95  Unlock an fd. Abandon after waitsecs seconds.
96 ****************************************************************/
97
98 BOOL file_unlock(int fd, int *plock_depth)
99 {
100         BOOL ret=True;
101
102         if(*plock_depth == 1) {
103                 ret = do_file_lock(fd, 5, F_UNLCK);
104         }
105
106         (*plock_depth)--;
107
108         if(!ret) {
109                 DEBUG(10,("file_unlock: unlocking file failed, error = %s.\n", strerror(errno)));
110         }
111         return ret;
112 }
113
114 /***************************************************************
115  Locks a file for enumeration / modification.
116  update to be set = True if modification is required.
117 ****************************************************************/
118
119 void *startfilepwent(char *pfile, char *s_readbuf, int bufsize,
120                                 int *file_lock_depth, BOOL update)
121 {
122         FILE *fp = NULL;
123
124         if (!*pfile) {
125                 DEBUG(0, ("startfilepwent: No file set\n"));
126                 return (NULL);
127         }
128         DEBUG(10, ("startfilepwent: opening file %s\n", pfile));
129
130         fp = sys_fopen(pfile, update ? "r+b" : "rb");
131
132         if (fp == NULL) {
133                 DEBUG(0, ("startfilepwent: unable to open file %s\n", pfile));
134                 return NULL;
135         }
136
137         /* Set a buffer to do more efficient reads */
138         setvbuf(fp, s_readbuf, _IOFBF, bufsize);
139
140         if (!file_lock(fileno(fp), (update ? F_WRLCK : F_RDLCK), 5, file_lock_depth)) {
141                 DEBUG(0, ("startfilepwent: unable to lock file %s\n", pfile));
142                 fclose(fp);
143                 return NULL;
144         }
145
146         /* Make sure it is only rw by the owner */
147         chmod(pfile, 0600);
148
149         /* We have a lock on the file. */
150         return (void *)fp;
151 }
152
153 /***************************************************************
154  End enumeration of the file.
155 ****************************************************************/
156
157 void endfilepwent(void *vp, int *file_lock_depth)
158 {
159         FILE *fp = (FILE *)vp;
160
161         file_unlock(fileno(fp), file_lock_depth);
162         fclose(fp);
163         DEBUG(7, ("endfilepwent: closed file.\n"));
164 }
165
166 /*************************************************************************
167  Return the current position in the file list as an SMB_BIG_UINT.
168  This must be treated as an opaque token.
169 *************************************************************************/
170
171 SMB_BIG_UINT getfilepwpos(void *vp)
172 {
173         return (SMB_BIG_UINT)sys_ftell((FILE *)vp);
174 }
175
176 /*************************************************************************
177  Set the current position in the file list from an SMB_BIG_UINT.
178  This must be treated as an opaque token.
179 *************************************************************************/
180
181 BOOL setfilepwpos(void *vp, SMB_BIG_UINT tok)
182 {
183         return !sys_fseek((FILE *)vp, (SMB_OFF_T)tok, SEEK_SET);
184 }
185
186 /*************************************************************************
187  Gets a line out of a file.
188  line is of format "xxxx:xxxxxx:xxxxx:".
189  lines with "#" at the front are ignored.
190 *************************************************************************/
191
192 int getfileline(void *vp, char *linebuf, int linebuf_size)
193 {
194         /* Static buffers we will return. */
195         FILE *fp = (FILE *)vp;
196         unsigned char   c;
197         unsigned char  *p;
198         size_t linebuf_len;
199
200         if (fp == NULL) {
201                 DEBUG(0,("getfileline: Bad file pointer.\n"));
202                 return -1;
203         }
204
205         /*
206          * Scan the file, a line at a time.
207          */
208         while (!feof(fp)) {
209                 linebuf[0] = '\0';
210
211                 fgets(linebuf, linebuf_size, fp);
212                 if (ferror(fp)) {
213                         return -1;
214                 }
215
216                 /*
217                  * Check if the string is terminated with a newline - if not
218                  * then we must keep reading and discard until we get one.
219                  */
220
221                 linebuf_len = strlen(linebuf);
222                 if (linebuf_len == 0) {
223                         linebuf[0] = '\0';
224                         return 0;
225                 }
226
227                 if (linebuf[linebuf_len - 1] != '\n') {
228                         c = '\0';
229                         while (!ferror(fp) && !feof(fp)) {
230                                 c = fgetc(fp);
231                                 if (c == '\n') {
232                                         break;
233                                 }
234                         }
235                 } else {
236                         linebuf[linebuf_len - 1] = '\0';
237                 }
238
239 #ifdef DEBUG_PASSWORD
240                 DEBUG(100, ("getfileline: got line |%s|\n", linebuf));
241 #endif
242                 if ((linebuf[0] == 0) && feof(fp)) {
243                         DEBUG(4, ("getfileline: end of file reached\n"));
244                         return 0;
245                 }
246
247                 if (linebuf[0] == '#' || linebuf[0] == '\0') {
248                         DEBUG(6, ("getfileline: skipping comment or blank line\n"));
249                         continue;
250                 }
251
252                 p = (unsigned char *) strchr_m(linebuf, ':');
253                 if (p == NULL) {
254                         DEBUG(0, ("getfileline: malformed line entry (no :)\n"));
255                         continue;
256                 }
257                 return linebuf_len;
258         }
259         return -1;
260 }
261
262 /****************************************************************************
263  Read a line from a file with possible \ continuation chars. 
264  Blanks at the start or end of a line are stripped.
265  The string will be allocated if s2 is NULL.
266 ****************************************************************************/
267
268 char *fgets_slash(char *s2,int maxlen,XFILE *f)
269 {
270         char *s=s2;
271         int len = 0;
272         int c;
273         BOOL start_of_line = True;
274
275         if (x_feof(f)) {
276                 return(NULL);
277         }
278
279         if (maxlen <2) {
280                 return(NULL);
281         }
282
283         if (!s2) {
284                 maxlen = MIN(maxlen,8);
285                 s = (char *)SMB_MALLOC(maxlen);
286         }
287
288         if (!s) {
289                 return(NULL);
290         }
291
292         *s = 0;
293
294         while (len < maxlen-1) {
295                 c = x_getc(f);
296                 switch (c) {
297                         case '\r':
298                                 break;
299                         case '\n':
300                                 while (len > 0 && s[len-1] == ' ') {
301                                         s[--len] = 0;
302                                 }
303                                 if (len > 0 && s[len-1] == '\\') {
304                                         s[--len] = 0;
305                                         start_of_line = True;
306                                         break;
307                                 }
308                                 return(s);
309                         case EOF:
310                                 if (len <= 0 && !s2)  {
311                                         SAFE_FREE(s);
312                                 }
313                                 return(len>0?s:NULL);
314                         case ' ':
315                                 if (start_of_line) {
316                                         break;
317                                 }
318                         default:
319                                 start_of_line = False;
320                                 s[len++] = c;
321                                 s[len] = 0;
322                 }
323
324                 if (!s2 && len > maxlen-3) {
325                         maxlen *= 2;
326                         s = (char *)SMB_REALLOC(s,maxlen);
327                         if (!s) {
328                                 DEBUG(0,("fgets_slash: failed to expand buffer!\n"));
329                                 return(NULL);
330                         }
331                 }
332         }
333         return(s);
334 }
335
336 /****************************************************************************
337  Load from a pipe into memory.
338 ****************************************************************************/
339
340 char *file_pload(char *syscmd, size_t *size)
341 {
342         int fd, n;
343         char *p;
344         pstring buf;
345         size_t total;
346         
347         fd = sys_popen(syscmd);
348         if (fd == -1) {
349                 return NULL;
350         }
351
352         p = NULL;
353         total = 0;
354
355         while ((n = read(fd, buf, sizeof(buf))) > 0) {
356                 p = (char *)SMB_REALLOC(p, total + n + 1);
357                 if (!p) {
358                         DEBUG(0,("file_pload: failed to expand buffer!\n"));
359                         close(fd);
360                         return NULL;
361                 }
362                 memcpy(p+total, buf, n);
363                 total += n;
364         }
365
366         if (p) {
367                 p[total] = 0;
368         }
369
370         /* FIXME: Perhaps ought to check that the command completed
371          * successfully (returned 0); if not the data may be
372          * truncated. */
373         sys_pclose(fd);
374
375         if (size) {
376                 *size = total;
377         }
378
379         return p;
380 }
381
382 /****************************************************************************
383  Load a file into memory from a fd.
384  Truncate at maxsize. If maxsize == 0 - no limit.
385 ****************************************************************************/ 
386
387 char *fd_load(int fd, size_t *psize, size_t maxsize)
388 {
389         SMB_STRUCT_STAT sbuf;
390         size_t size;
391         char *p;
392
393         if (sys_fstat(fd, &sbuf) != 0) {
394                 return NULL;
395         }
396
397         size = sbuf.st_size;
398         if (maxsize) {
399                 size = MIN(size, maxsize);
400         }
401
402         p = (char *)SMB_MALLOC(size+1);
403         if (!p) {
404                 return NULL;
405         }
406
407         if (read(fd, p, size) != size) {
408                 SAFE_FREE(p);
409                 return NULL;
410         }
411         p[size] = 0;
412
413         if (psize) {
414                 *psize = size;
415         }
416
417         return p;
418 }
419
420 /****************************************************************************
421  Load a file into memory.
422 ****************************************************************************/
423
424 char *file_load(const char *fname, size_t *size, size_t maxsize)
425 {
426         int fd;
427         char *p;
428
429         if (!fname || !*fname) {
430                 return NULL;
431         }
432         
433         fd = open(fname,O_RDONLY);
434         if (fd == -1) {
435                 return NULL;
436         }
437
438         p = fd_load(fd, size, maxsize);
439         close(fd);
440         return p;
441 }
442
443 /*******************************************************************
444  unmap or free memory
445 *******************************************************************/
446
447 BOOL unmap_file(void* start, size_t size)
448 {
449 #ifdef HAVE_MMAP
450         if ( munmap( start, size ) != 0 ) {
451                 DEBUG( 1, ("map_file: Failed to unmap address %p "
452                         "of size %u - %s\n", 
453                         start, (unsigned int)size, strerror(errno) ));
454                 return False;
455         }
456         return True;
457 #else
458         SAFE_FREE( start );
459         return True;
460 #endif
461 }
462
463 /*******************************************************************
464  mmap (if possible) or read a file.
465 ********************************************************************/
466
467 void *map_file(char *fname, size_t size)
468 {
469         size_t s2 = 0;
470         void *p = NULL;
471 #ifdef HAVE_MMAP
472         int fd;
473         fd = open(fname, O_RDONLY, 0);
474         if (fd == -1) {
475                 DEBUG(2,("map_file: Failed to load %s - %s\n", fname, strerror(errno)));
476                 return NULL;
477         }
478         p = mmap(NULL, size, PROT_READ, MAP_SHARED|MAP_FILE, fd, 0);
479         close(fd);
480         if (p == MAP_FAILED) {
481                 DEBUG(1,("map_file: Failed to mmap %s - %s\n", fname, strerror(errno)));
482                 return NULL;
483         }
484 #endif
485         if (!p) {
486                 p = file_load(fname, &s2, 0);
487                 if (!p) {
488                         return NULL;
489                 }
490                 if (s2 != size) {
491                         DEBUG(1,("map_file: incorrect size for %s - got %lu expected %lu\n",
492                                  fname, (unsigned long)s2, (unsigned long)size));
493                         SAFE_FREE(p);   
494                         return NULL;
495                 }
496         }
497         return p;
498 }
499
500 /****************************************************************************
501  Parse a buffer into lines.
502 ****************************************************************************/
503
504 static char **file_lines_parse(char *p, size_t size, int *numlines)
505 {
506         int i;
507         char *s, **ret;
508
509         if (!p) {
510                 return NULL;
511         }
512
513         for (s = p, i=0; s < p+size; s++) {
514                 if (s[0] == '\n') i++;
515         }
516
517         ret = SMB_MALLOC_ARRAY(char *, i+2);
518         if (!ret) {
519                 SAFE_FREE(p);
520                 return NULL;
521         }       
522         memset(ret, 0, sizeof(ret[0])*(i+2));
523         if (numlines) {
524                 *numlines = i;
525         }
526
527         ret[0] = p;
528         for (s = p, i=0; s < p+size; s++) {
529                 if (s[0] == '\n') {
530                         s[0] = 0;
531                         i++;
532                         ret[i] = s+1;
533                 }
534                 if (s[0] == '\r') {
535                         s[0] = 0;
536                 }
537         }
538
539         return ret;
540 }
541
542 /****************************************************************************
543  Load a file into memory and return an array of pointers to lines in the file
544  must be freed with file_lines_free(). 
545 ****************************************************************************/
546
547 char **file_lines_load(const char *fname, int *numlines, size_t maxsize)
548 {
549         char *p;
550         size_t size = 0;
551
552         p = file_load(fname, &size, maxsize);
553         if (!p) {
554                 return NULL;
555         }
556
557         return file_lines_parse(p, size, numlines);
558 }
559
560 /****************************************************************************
561  Load a fd into memory and return an array of pointers to lines in the file
562  must be freed with file_lines_free(). If convert is true calls unix_to_dos on
563  the list.
564 ****************************************************************************/
565
566 char **fd_lines_load(int fd, int *numlines, size_t maxsize)
567 {
568         char *p;
569         size_t size;
570
571         p = fd_load(fd, &size, maxsize);
572         if (!p) {
573                 return NULL;
574         }
575
576         return file_lines_parse(p, size, numlines);
577 }
578
579 /****************************************************************************
580  Load a pipe into memory and return an array of pointers to lines in the data
581  must be freed with file_lines_free(). 
582 ****************************************************************************/
583
584 char **file_lines_pload(char *syscmd, int *numlines)
585 {
586         char *p;
587         size_t size;
588
589         p = file_pload(syscmd, &size);
590         if (!p) {
591                 return NULL;
592         }
593
594         return file_lines_parse(p, size, numlines);
595 }
596
597 /****************************************************************************
598  Free lines loaded with file_lines_load.
599 ****************************************************************************/
600
601 void file_lines_free(char **lines)
602 {
603         if (!lines) {
604                 return;
605         }
606         SAFE_FREE(lines[0]);
607         SAFE_FREE(lines);
608 }
609
610 /****************************************************************************
611  Take a list of lines and modify them to produce a list where \ continues
612  a line.
613 ****************************************************************************/
614
615 void file_lines_slashcont(char **lines)
616 {
617         int i, j;
618
619         for (i=0; lines[i];) {
620                 int len = strlen(lines[i]);
621                 if (lines[i][len-1] == '\\') {
622                         lines[i][len-1] = ' ';
623                         if (lines[i+1]) {
624                                 char *p = &lines[i][len];
625                                 while (p < lines[i+1]) {
626                                         *p++ = ' ';
627                                 }
628                                 for (j = i+1; lines[j]; j++) {
629                                         lines[j] = lines[j+1];
630                                 }
631                         }
632                 } else {
633                         i++;
634                 }
635         }
636 }
637
638 /****************************************************************************
639  Save a lump of data into a file. Mostly used for debugging.
640 ****************************************************************************/
641
642 BOOL file_save(const char *fname, void *packet, size_t length)
643 {
644         int fd;
645         fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0644);
646         if (fd == -1) {
647                 return False;
648         }
649         if (write(fd, packet, length) != (size_t)length) {
650                 return False;
651         }
652         close(fd);
653         return True;
654 }