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