]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/bsys.c
kes Add dynamic dll entry point for SHGetFolderPath to Win32 code.
[bacula/bacula] / bacula / src / lib / bsys.c
1 /*
2  * Miscellaneous Bacula memory and thread safe routines
3  *   Generally, these are interfaces to system or standard
4  *   library routines.
5  *
6  *  Bacula utility functions are in util.c
7  *
8  *   Version $Id$
9  */
10 /*
11    Bacula® - The Network Backup Solution
12
13    Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
14
15    The main author of Bacula is Kern Sibbald, with contributions from
16    many others, a complete list can be found in the file AUTHORS.
17    This program is Free Software; you can redistribute it and/or
18    modify it under the terms of version two of the GNU General Public
19    License as published by the Free Software Foundation plus additions
20    that are listed in the file LICENSE.
21
22    This program is distributed in the hope that it will be useful, but
23    WITHOUT ANY WARRANTY; without even the implied warranty of
24    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25    General Public License for more details.
26
27    You should have received a copy of the GNU General Public License
28    along with this program; if not, write to the Free Software
29    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
30    02110-1301, USA.
31
32    Bacula® is a registered trademark of John Walker.
33    The licensor of Bacula is the Free Software Foundation Europe
34    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
35    Switzerland, email:ftf@fsfeurope.org.
36 */
37
38
39 #include "bacula.h"
40 #ifdef HAVE_PWD_H
41 #include <pwd.h>
42 #endif
43 #ifdef HAVE_GRP_H
44 #include <grp.h>
45 #endif
46
47 static pthread_mutex_t timer_mutex = PTHREAD_MUTEX_INITIALIZER;
48 static pthread_cond_t timer = PTHREAD_COND_INITIALIZER;
49
50 /*
51  * This routine will sleep (sec, microsec).  Note, however, that if a
52  *   signal occurs, it will return early.  It is up to the caller
53  *   to recall this routine if he/she REALLY wants to sleep the
54  *   requested time.
55  */
56 int bmicrosleep(time_t sec, long usec)
57 {
58    struct timespec timeout;
59    struct timeval tv;
60    struct timezone tz;
61    int stat;
62
63    timeout.tv_sec = sec;
64    timeout.tv_nsec = usec * 1000;
65
66 #ifdef HAVE_NANOSLEEP
67    stat = nanosleep(&timeout, NULL);
68    if (!(stat < 0 && errno == ENOSYS)) {
69       return stat;
70    }
71    /* If we reach here it is because nanosleep is not supported by the OS */
72 #endif
73
74    /* Do it the old way */
75    gettimeofday(&tv, &tz);
76    timeout.tv_nsec += tv.tv_usec * 1000;
77    timeout.tv_sec += tv.tv_sec;
78    while (timeout.tv_nsec >= 1000000000) {
79       timeout.tv_nsec -= 1000000000;
80       timeout.tv_sec++;
81    }
82
83    Dmsg2(200, "pthread_cond_timedwait sec=%d usec=%d\n", sec, usec);
84    /* Note, this unlocks mutex during the sleep */
85    P(timer_mutex);
86    stat = pthread_cond_timedwait(&timer, &timer_mutex, &timeout);
87    if (stat != 0) {
88       berrno be;
89       Dmsg2(200, "pthread_cond_timedwait stat=%d ERR=%s\n", stat,
90          be.strerror(stat));
91    }
92    V(timer_mutex);
93    return stat;
94 }
95
96 /*
97  * Guarantee that the string is properly terminated */
98 char *bstrncpy(char *dest, const char *src, int maxlen)
99 {
100    strncpy(dest, src, maxlen-1);
101    dest[maxlen-1] = 0;
102    return dest;
103 }
104
105 /*
106  * Guarantee that the string is properly terminated */
107 char *bstrncpy(char *dest, POOL_MEM &src, int maxlen)
108 {
109    strncpy(dest, src.c_str(), maxlen-1);
110    dest[maxlen-1] = 0;
111    return dest;
112 }
113
114
115 char *bstrncat(char *dest, const char *src, int maxlen)
116 {
117    strncat(dest, src, maxlen-1);
118    dest[maxlen-1] = 0;
119    return dest;
120 }
121
122 char *bstrncat(char *dest, POOL_MEM &src, int maxlen)
123 {
124    strncat(dest, src.c_str(), maxlen-1);
125    dest[maxlen-1] = 0;
126    return dest;
127 }
128
129 /*
130  * Allows one or both pointers to be NULL
131  */
132 bool bstrcmp(const char *s1, const char *s2)
133 {
134    if (s1 == s2) return true;
135    if (s1 == NULL || s2 == NULL) return false;
136    return strcmp(s1, s2) == 0;
137 }
138
139 /*
140  * Get character length of UTF-8 string
141  *
142  * Valid UTF-8 codes
143  * U-00000000 - U-0000007F: 0xxxxxxx 
144  * U-00000080 - U-000007FF: 110xxxxx 10xxxxxx 
145  * U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx 
146  * U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 
147  * U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 
148  * U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
149  */
150 int cstrlen(const char *str)
151 {
152    uint8_t *p = (uint8_t *)str;
153    int len = 0;
154    while (*p) {
155       if ((*p & 0xC0) != 0xC0) {
156          p++;
157          len++;
158          continue;
159       }
160       if ((*p & 0xD0) == 0xC0) {
161          p += 2;
162          len++;
163          continue;
164       }
165       if ((*p & 0xF0) == 0xD0) {
166          p += 3;
167          len++;
168          continue;
169       }
170       if ((*p & 0xF8) == 0xF0) {
171          p += 4;
172          len++;
173          continue;
174       }
175       if ((*p & 0xFC) == 0xF8) {
176          p += 5;
177          len++;
178          continue;
179       }
180       if ((*p & 0xFE) == 0xFC) {
181          p += 6;
182          len++;
183          continue;
184       }
185       p++;                      /* Shouln't get here but must advance */
186    }
187    return len;
188 }
189
190
191
192 #ifndef bmalloc
193 void *bmalloc(size_t size)
194 {
195   void *buf;
196
197 #ifdef SMARTALLOC
198   buf = sm_malloc(file, line, size);
199 #else
200   buf = malloc(size);
201 #endif
202   if (buf == NULL) {
203      berrno be;
204      Emsg1(M_ABORT, 0, _("Out of memory: ERR=%s\n"), be.strerror());
205   }
206   return buf;
207 }
208 #endif
209
210 void *b_malloc(const char *file, int line, size_t size)
211 {
212   void *buf;
213
214 #ifdef SMARTALLOC
215   buf = sm_malloc(file, line, size);
216 #else
217   buf = malloc(size);
218 #endif
219   if (buf == NULL) {
220      berrno be;
221      e_msg(file, line, M_ABORT, 0, _("Out of memory: ERR=%s\n"), be.strerror());
222   }
223   return buf;
224 }
225
226
227 void bfree(void *buf)
228 {
229 #ifdef SMARTALLOC
230   sm_free(__FILE__, __LINE__, buf);
231 #else
232   free(buf);
233 #endif
234 }
235
236
237
238
239 void *brealloc (void *buf, size_t size)
240 {
241    buf = realloc(buf, size);
242    if (buf == NULL) {
243       berrno be;
244       Emsg1(M_ABORT, 0, _("Out of memory: ERR=%s\n"), be.strerror());
245    }
246    return buf;
247 }
248
249
250 void *bcalloc (size_t size1, size_t size2)
251 {
252   void *buf;
253
254    buf = calloc(size1, size2);
255    if (buf == NULL) {
256       berrno be;
257       Emsg1(M_ABORT, 0, _("Out of memory: ERR=%s\n"), be.strerror());
258    }
259    return buf;
260 }
261
262 /* Code now in src/lib/bsnprintf.c */
263 #ifndef USE_BSNPRINTF
264
265 #define BIG_BUF 5000
266 /*
267  * Implement snprintf
268  */
269 int bsnprintf(char *str, int32_t size, const char *fmt,  ...)
270 {
271    va_list   arg_ptr;
272    int len;
273
274    va_start(arg_ptr, fmt);
275    len = bvsnprintf(str, size, fmt, arg_ptr);
276    va_end(arg_ptr);
277    return len;
278 }
279
280 /*
281  * Implement vsnprintf()
282  */
283 int bvsnprintf(char *str, int32_t size, const char  *format, va_list ap)
284 {
285 #ifdef HAVE_VSNPRINTF
286    int len;
287    len = vsnprintf(str, size, format, ap);
288    str[size-1] = 0;
289    return len;
290
291 #else
292
293    int len, buflen;
294    char *buf;
295    buflen = size > BIG_BUF ? size : BIG_BUF;
296    buf = get_memory(buflen);
297    len = vsprintf(buf, format, ap);
298    if (len >= buflen) {
299       Emsg0(M_ABORT, 0, _("Buffer overflow.\n"));
300    }
301    memcpy(str, buf, len);
302    str[len] = 0;                /* len excludes the null */
303    free_memory(buf);
304    return len;
305 #endif
306 }
307 #endif /* USE_BSNPRINTF */
308
309 #ifndef HAVE_LOCALTIME_R
310
311 struct tm *localtime_r(const time_t *timep, struct tm *tm)
312 {
313     static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
314     struct tm *ltm,
315
316     P(mutex);
317     ltm = localtime(timep);
318     if (ltm) {
319        memcpy(tm, ltm, sizeof(struct tm));
320     }
321     V(mutex);
322     return ltm ? tm : NULL;
323 }
324 #endif /* HAVE_LOCALTIME_R */
325
326 #ifndef HAVE_READDIR_R
327 #ifndef HAVE_WIN32
328 #include <dirent.h>
329
330 int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
331 {
332     static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
333     struct dirent *ndir;
334     int stat;
335
336     P(mutex);
337     errno = 0;
338     ndir = readdir(dirp);
339     stat = errno;
340     if (ndir) {
341        memcpy(entry, ndir, sizeof(struct dirent));
342        strcpy(entry->d_name, ndir->d_name);
343        *result = entry;
344     } else {
345        *result = NULL;
346     }
347     V(mutex);
348     return stat;
349
350 }
351 #endif
352 #endif /* HAVE_READDIR_R */
353
354
355 int bstrerror(int errnum, char *buf, size_t bufsiz)
356 {
357     static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
358     int stat = 0;
359     const char *msg;
360
361     P(mutex);
362
363     msg = strerror(errnum);
364     if (!msg) {
365        msg = _("Bad errno");
366        stat = -1;
367     }
368     bstrncpy(buf, msg, bufsiz);
369     V(mutex);
370     return stat;
371 }
372
373 /*
374  * These are mutex routines that do error checking
375  *  for deadlock and such.  Normally not turned on.
376  */
377 #ifdef DEBUG_MUTEX
378 void _p(char *file, int line, pthread_mutex_t *m)
379 {
380    int errstat;
381    if ((errstat = pthread_mutex_trylock(m))) {
382       e_msg(file, line, M_ERROR, 0, _("Possible mutex deadlock.\n"));
383       /* We didn't get the lock, so do it definitely now */
384       if ((errstat=pthread_mutex_lock(m))) {
385          berrno be;
386          e_msg(file, line, M_ABORT, 0, _("Mutex lock failure. ERR=%s\n"),
387                be.strerror(errstat));
388       } else {
389          e_msg(file, line, M_ERROR, 0, _("Possible mutex deadlock resolved.\n"));
390       }
391
392    }
393 }
394
395 void _v(char *file, int line, pthread_mutex_t *m)
396 {
397    int errstat;
398
399    /* Note, this trylock *should* fail if the mutex is locked */
400    if ((errstat=pthread_mutex_trylock(m)) == 0) {
401       berrno be;
402       e_msg(file, line, M_ERROR, 0, _("Mutex unlock not locked. ERR=%s\n"),
403            be.strerror(errstat));
404     }
405     if ((errstat=pthread_mutex_unlock(m))) {
406        berrno be;
407        e_msg(file, line, M_ABORT, 0, _("Mutex unlock failure. ERR=%s\n"),
408               be.strerror(errstat));
409     }
410 }
411
412 #else
413
414 void _p(pthread_mutex_t *m)
415 {
416    int errstat;
417    if ((errstat=pthread_mutex_lock(m))) {
418       berrno be;
419       e_msg(__FILE__, __LINE__, M_ABORT, 0, _("Mutex lock failure. ERR=%s\n"),
420             be.strerror(errstat));
421    }
422 }
423
424 void _v(pthread_mutex_t *m)
425 {
426    int errstat;
427    if ((errstat=pthread_mutex_unlock(m))) {
428       berrno be;
429       e_msg(__FILE__, __LINE__, M_ABORT, 0, _("Mutex unlock failure. ERR=%s\n"),
430             be.strerror(errstat));
431    }
432 }
433
434 #endif /* DEBUG_MUTEX */
435
436 #ifdef DEBUG_MEMSET
437 /* These routines are not normally turned on */
438 #undef memset
439 void b_memset(const char *file, int line, void *mem, int val, size_t num)
440 {
441    /* Testing for 2000 byte zero at beginning of Volume block */
442    if (num > 1900 && num < 3000) {
443       Pmsg3(000, _("Memset for %d bytes at %s:%d\n"), (int)num, file, line);
444    }
445    memset(mem, val, num);
446 }
447 #endif
448
449 #if !defined(HAVE_WIN32)
450 static int del_pid_file_ok = FALSE;
451 #endif
452
453 /*
454  * Create a standard "Unix" pid file.
455  */
456 void create_pid_file(char *dir, const char *progname, int port)
457 {
458 #if !defined(HAVE_WIN32)
459    int pidfd, len;
460    int oldpid;
461    char  pidbuf[20];
462    POOLMEM *fname = get_pool_memory(PM_FNAME);
463    struct stat statp;
464
465    Mmsg(&fname, "%s/%s.%d.pid", dir, progname, port);
466    if (stat(fname, &statp) == 0) {
467       /* File exists, see what we have */
468       *pidbuf = 0;
469       if ((pidfd = open(fname, O_RDONLY|O_BINARY, 0)) < 0 ||
470            read(pidfd, &pidbuf, sizeof(pidbuf)) < 0 ||
471            sscanf(pidbuf, "%d", &oldpid) != 1) {
472          Emsg2(M_ERROR_TERM, 0, _("Cannot open pid file. %s ERR=%s\n"), fname, strerror(errno));
473       }
474       /* See if other Bacula is still alive */
475       if (kill(oldpid, 0) != -1 || errno != ESRCH) {
476          Emsg3(M_ERROR_TERM, 0, _("%s is already running. pid=%d\nCheck file %s\n"),
477                progname, oldpid, fname);
478       }
479       /* He is not alive, so take over file ownership */
480       unlink(fname);                  /* remove stale pid file */
481    }
482    /* Create new pid file */
483    if ((pidfd = open(fname, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0640)) >= 0) {
484       len = sprintf(pidbuf, "%d\n", (int)getpid());
485       write(pidfd, pidbuf, len);
486       close(pidfd);
487       del_pid_file_ok = TRUE;         /* we created it so we can delete it */
488    } else {
489       Emsg2(M_ERROR_TERM, 0, _("Could not open pid file. %s ERR=%s\n"), fname, strerror(errno));
490    }
491    free_pool_memory(fname);
492 #endif
493 }
494
495
496 /*
497  * Delete the pid file if we created it
498  */
499 int delete_pid_file(char *dir, const char *progname, int port)
500 {
501 #if !defined(HAVE_WIN32)
502    POOLMEM *fname = get_pool_memory(PM_FNAME);
503
504    if (!del_pid_file_ok) {
505       free_pool_memory(fname);
506       return 0;
507    }
508    del_pid_file_ok = FALSE;
509    Mmsg(&fname, "%s/%s.%d.pid", dir, progname, port);
510    unlink(fname);
511    free_pool_memory(fname);
512 #endif
513    return 1;
514 }
515
516 struct s_state_hdr {
517    char id[14];
518    int32_t version;
519    uint64_t last_jobs_addr;
520    uint64_t reserved[20];
521 };
522
523 static struct s_state_hdr state_hdr = {
524    "Bacula State\n",
525    3,
526    0
527 };
528
529 /*
530  * Open and read the state file for the daemon
531  */
532 void read_state_file(char *dir, const char *progname, int port)
533 {
534    int sfd;
535    ssize_t stat;
536    bool ok = false;
537    POOLMEM *fname = get_pool_memory(PM_FNAME);
538    struct s_state_hdr hdr;
539    int hdr_size = sizeof(hdr);
540
541    Mmsg(&fname, "%s/%s.%d.state", dir, progname, port);
542    /* If file exists, see what we have */
543 // Dmsg1(10, "O_BINARY=%d\n", O_BINARY);
544    if ((sfd = open(fname, O_RDONLY|O_BINARY)) < 0) {
545       Dmsg3(010, "Could not open state file. sfd=%d size=%d: ERR=%s\n",
546                     sfd, sizeof(hdr), strerror(errno));
547       goto bail_out;
548    }
549    if ((stat=read(sfd, &hdr, hdr_size)) != hdr_size) {
550       Dmsg4(010, "Could not read state file. sfd=%d stat=%d size=%d: ERR=%s\n",
551                     sfd, (int)stat, hdr_size, strerror(errno));
552       goto bail_out;
553    }
554    if (hdr.version != state_hdr.version) {
555       Dmsg2(010, "Bad hdr version. Wanted %d got %d\n",
556          state_hdr.version, hdr.version);
557       goto bail_out;
558    }
559    hdr.id[13] = 0;
560    if (strcmp(hdr.id, state_hdr.id) != 0) {
561       Dmsg0(000, "State file header id invalid.\n");
562       goto bail_out;
563    }
564 // Dmsg1(010, "Read header of %d bytes.\n", sizeof(hdr));
565    if (!read_last_jobs_list(sfd, hdr.last_jobs_addr)) {
566       goto bail_out;
567    }
568    ok = true;
569 bail_out:
570    if (sfd >= 0) {
571       close(sfd);
572    }
573    if (!ok) {
574       unlink(fname);
575     }
576    free_pool_memory(fname);
577 }
578
579 /*
580  * Write the state file
581  */
582 void write_state_file(char *dir, const char *progname, int port)
583 {
584    int sfd;
585    bool ok = false;
586    POOLMEM *fname = get_pool_memory(PM_FNAME);
587
588    Mmsg(&fname, "%s/%s.%d.state", dir, progname, port);
589    /* Create new state file */
590    unlink(fname);
591    if ((sfd = open(fname, O_CREAT|O_WRONLY|O_BINARY, 0640)) < 0) {
592       berrno be;
593       Dmsg2(000, "Could not create state file. %s ERR=%s\n", fname, be.strerror());
594       Emsg2(M_ERROR, 0, _("Could not create state file. %s ERR=%s\n"), fname, be.strerror());
595       goto bail_out;
596    }
597    if (write(sfd, &state_hdr, sizeof(state_hdr)) != sizeof(state_hdr)) {
598       berrno be;
599       Dmsg1(000, "Write hdr error: ERR=%s\n", be.strerror());
600       goto bail_out;
601    }
602 // Dmsg1(010, "Wrote header of %d bytes\n", sizeof(state_hdr));
603    state_hdr.last_jobs_addr = sizeof(state_hdr);
604    state_hdr.reserved[0] = write_last_jobs_list(sfd, state_hdr.last_jobs_addr);
605 // Dmsg1(010, "write last job end = %d\n", (int)state_hdr.reserved[0]);
606    if (lseek(sfd, 0, SEEK_SET) < 0) {
607       berrno be;
608       Dmsg1(000, "lseek error: ERR=%s\n", be.strerror());
609       goto bail_out;
610    }
611    if (write(sfd, &state_hdr, sizeof(state_hdr)) != sizeof(state_hdr)) {
612       berrno be;
613       Pmsg1(000, _("Write final hdr error: ERR=%s\n"), be.strerror());
614       goto bail_out;
615    }
616    ok = true;
617 // Dmsg1(010, "rewrote header = %d\n", sizeof(state_hdr));
618 bail_out:
619    if (sfd >= 0) {
620       close(sfd);
621    }
622    if (!ok) {
623       unlink(fname);
624    }
625    free_pool_memory(fname);
626 }
627
628
629 /*
630  * Drop to privilege new userid and new gid if non-NULL
631  */
632 void drop(char *uname, char *gname)
633 {
634 #if   defined(HAVE_PWD_H) && defined(HAVE_GRP_H)
635    struct passwd *passw = NULL;
636    struct group *group = NULL;
637    gid_t gid;
638    uid_t uid;
639    char username[1000];         
640
641    Dmsg2(900, "uname=%s gname=%s\n", uname?uname:"NONE", gname?gname:"NONE");
642    if (!uname && !gname) {
643       return;                            /* Nothing to do */
644    }
645
646    if (uname) {
647       if ((passw = getpwnam(uname)) == NULL) {
648          berrno be;
649          Emsg2(M_ERROR_TERM, 0, _("Could not find userid=%s: ERR=%s\n"), uname,
650             be.strerror());
651       }
652    } else {
653       if ((passw = getpwuid(getuid())) == NULL) {
654          berrno be;
655          Emsg1(M_ERROR_TERM, 0, _("Could not find password entry. ERR=%s\n"),
656             be.strerror());
657       } else {
658          uname = passw->pw_name;
659       }
660    }
661    /* Any OS uname pointer may get overwritten, so save name, uid, and gid */
662    bstrncpy(username, uname, sizeof(username));
663    uid = passw->pw_uid;
664    gid = passw->pw_gid;
665    if (gname) {
666       if ((group = getgrnam(gname)) == NULL) {
667          berrno be;
668          Emsg2(M_ERROR_TERM, 0, _("Could not find group=%s: ERR=%s\n"), gname,
669             be.strerror());
670       }
671       gid = group->gr_gid;
672    }
673    if (initgroups(username, gid)) {
674       berrno be;
675       if (gname) {
676          Emsg3(M_ERROR_TERM, 0, _("Could not initgroups for group=%s, userid=%s: ERR=%s\n"),         
677             gname, username, be.strerror());
678       } else {
679          Emsg2(M_ERROR_TERM, 0, _("Could not initgroups for userid=%s: ERR=%s\n"),         
680             username, be.strerror());
681       }
682    }
683    if (gname) {
684       if (setgid(gid)) {
685          berrno be;
686          Emsg2(M_ERROR_TERM, 0, _("Could not set group=%s: ERR=%s\n"), gname,
687             be.strerror());
688       }
689    }
690    if (setuid(uid)) {
691       berrno be;
692       Emsg1(M_ERROR_TERM, 0, _("Could not set specified userid: %s\n"), username);
693    }
694 #endif
695 }
696
697
698 /* BSDI does not have this.  This is a *poor* simulation */
699 #ifndef HAVE_STRTOLL
700 long long int
701 strtoll(const char *ptr, char **endptr, int base)
702 {
703    return (long long int)strtod(ptr, endptr);
704 }
705 #endif
706
707 /*
708  * Bacula's implementation of fgets(). The difference is that it handles
709  *   being interrupted by a signal (e.g. a SIGCHLD).
710  */
711 #undef fgetc
712 char *bfgets(char *s, int size, FILE *fd)
713 {
714    char *p = s;
715    int ch;
716    *p = 0;
717    for (int i=0; i < size-1; i++) {
718       do {
719          errno = 0;
720          ch = fgetc(fd);
721       } while (ch == EOF && ferror(fd) && (errno == EINTR || errno == EAGAIN));
722       if (ch == EOF) {
723          if (i == 0) {
724             return NULL;
725          } else {
726             return s;
727          }
728       }
729       *p++ = ch;
730       *p = 0;
731       if (ch == '\r') { /* Support for Mac/Windows file format */
732          ch = fgetc(fd);
733          if (ch != '\n') { /* Mac (\r only) */
734             (void)ungetc(ch, fd); /* Push next character back to fd */
735          }
736          p[-1] = '\n';
737          break;
738       }
739       if (ch == '\n') {
740          break;
741       }
742    }
743    return s;
744 }
745
746 /*
747  * Make a "unique" filename.  It is important that if
748  *   called again with the same "what" that the result
749  *   will be identical. This allows us to use the file
750  *   without saving its name, and re-generate the name
751  *   so that it can be deleted.
752  */
753 void make_unique_filename(POOLMEM **name, int Id, char *what)
754 {
755    Mmsg(name, "%s/%s.%s.%d.tmp", working_directory, my_name, what, Id);
756 }
757
758 char *escape_filename(const char *file_path)
759 {
760    if (file_path == NULL || strpbrk(file_path, "\"\\") == NULL) {
761       return NULL;
762    }
763
764    char *escaped_path = (char *)bmalloc(2 * (strlen(file_path) + 1));
765    char *cur_char = escaped_path;
766
767    while (*file_path) {
768       if (*file_path == '\\' || *file_path == '"') {
769          *cur_char++ = '\\';
770       }
771
772       *cur_char++ = *file_path++;
773    }
774
775    *cur_char = '\0';
776
777    return escaped_path;
778 }
779