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