s3: Fix bug 7832
[Samba.git] / lib / replace / replace.c
blobd9a96ff8ef9219e92cd7ed09b3971b60c6da16f0
1 /*
2 Unix SMB/CIFS implementation.
3 replacement routines for broken systems
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Jelmer Vernooij 2005-2008
6 Copyright (C) Matthieu Patou 2010
8 ** NOTE! The following LGPL license applies to the replace
9 ** library. This does NOT imply that all of Samba is released
10 ** under the LGPL
12 This library is free software; you can redistribute it and/or
13 modify it under the terms of the GNU Lesser General Public
14 License as published by the Free Software Foundation; either
15 version 3 of the License, or (at your option) any later version.
17 This library is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 Lesser General Public License for more details.
22 You should have received a copy of the GNU Lesser General Public
23 License along with this library; if not, see <http://www.gnu.org/licenses/>.
26 #include "replace.h"
28 #include "system/filesys.h"
29 #include "system/time.h"
30 #include "system/passwd.h"
31 #include "system/syslog.h"
32 #include "system/locale.h"
33 #include "system/wait.h"
35 #ifdef _WIN32
36 #define mkdir(d,m) _mkdir(d)
37 #endif
39 void replace_dummy(void);
40 void replace_dummy(void) {}
42 #ifndef HAVE_FTRUNCATE
43 /*******************************************************************
44 ftruncate for operating systems that don't have it
45 ********************************************************************/
46 int rep_ftruncate(int f, off_t l)
48 #ifdef HAVE_CHSIZE
49 return chsize(f,l);
50 #elif defined(F_FREESP)
51 struct flock fl;
53 fl.l_whence = 0;
54 fl.l_len = 0;
55 fl.l_start = l;
56 fl.l_type = F_WRLCK;
57 return fcntl(f, F_FREESP, &fl);
58 #else
59 #error "you must have a ftruncate function"
60 #endif
62 #endif /* HAVE_FTRUNCATE */
65 #ifndef HAVE_STRLCPY
66 /* like strncpy but does not 0 fill the buffer and always null
67 terminates. bufsize is the size of the destination buffer */
68 size_t rep_strlcpy(char *d, const char *s, size_t bufsize)
70 size_t len = strlen(s);
71 size_t ret = len;
72 if (bufsize <= 0) return 0;
73 if (len >= bufsize) len = bufsize-1;
74 memcpy(d, s, len);
75 d[len] = 0;
76 return ret;
78 #endif
80 #ifndef HAVE_STRLCAT
81 /* like strncat but does not 0 fill the buffer and always null
82 terminates. bufsize is the length of the buffer, which should
83 be one more than the maximum resulting string length */
84 size_t rep_strlcat(char *d, const char *s, size_t bufsize)
86 size_t len1 = strlen(d);
87 size_t len2 = strlen(s);
88 size_t ret = len1 + len2;
90 if (len1+len2 >= bufsize) {
91 if (bufsize < (len1+1)) {
92 return ret;
94 len2 = bufsize - (len1+1);
96 if (len2 > 0) {
97 memcpy(d+len1, s, len2);
98 d[len1+len2] = 0;
100 return ret;
102 #endif
104 #ifndef HAVE_MKTIME
105 /*******************************************************************
106 a mktime() replacement for those who don't have it - contributed by
107 C.A. Lademann <cal@zls.com>
108 Corrections by richard.kettlewell@kewill.com
109 ********************************************************************/
111 #define MINUTE 60
112 #define HOUR 60*MINUTE
113 #define DAY 24*HOUR
114 #define YEAR 365*DAY
115 time_t rep_mktime(struct tm *t)
117 struct tm *u;
118 time_t epoch = 0;
119 int n;
120 int mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
121 y, m, i;
123 if(t->tm_year < 70)
124 return((time_t)-1);
126 n = t->tm_year + 1900 - 1;
127 epoch = (t->tm_year - 70) * YEAR +
128 ((n / 4 - n / 100 + n / 400) - (1969 / 4 - 1969 / 100 + 1969 / 400)) * DAY;
130 y = t->tm_year + 1900;
131 m = 0;
133 for(i = 0; i < t->tm_mon; i++) {
134 epoch += mon [m] * DAY;
135 if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
136 epoch += DAY;
138 if(++m > 11) {
139 m = 0;
140 y++;
144 epoch += (t->tm_mday - 1) * DAY;
145 epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec;
147 if((u = localtime(&epoch)) != NULL) {
148 t->tm_sec = u->tm_sec;
149 t->tm_min = u->tm_min;
150 t->tm_hour = u->tm_hour;
151 t->tm_mday = u->tm_mday;
152 t->tm_mon = u->tm_mon;
153 t->tm_year = u->tm_year;
154 t->tm_wday = u->tm_wday;
155 t->tm_yday = u->tm_yday;
156 t->tm_isdst = u->tm_isdst;
159 return(epoch);
161 #endif /* !HAVE_MKTIME */
164 #ifndef HAVE_INITGROUPS
165 /****************************************************************************
166 some systems don't have an initgroups call
167 ****************************************************************************/
168 int rep_initgroups(char *name, gid_t id)
170 #ifndef HAVE_SETGROUPS
171 /* yikes! no SETGROUPS or INITGROUPS? how can this work? */
172 errno = ENOSYS;
173 return -1;
174 #else /* HAVE_SETGROUPS */
176 #include <grp.h>
178 gid_t *grouplst = NULL;
179 int max_gr = NGROUPS_MAX;
180 int ret;
181 int i,j;
182 struct group *g;
183 char *gr;
185 if((grouplst = malloc(sizeof(gid_t) * max_gr)) == NULL) {
186 errno = ENOMEM;
187 return -1;
190 grouplst[0] = id;
191 i = 1;
192 while (i < max_gr && ((g = (struct group *)getgrent()) != (struct group *)NULL)) {
193 if (g->gr_gid == id)
194 continue;
195 j = 0;
196 gr = g->gr_mem[0];
197 while (gr && (*gr != (char)NULL)) {
198 if (strcmp(name,gr) == 0) {
199 grouplst[i] = g->gr_gid;
200 i++;
201 gr = (char *)NULL;
202 break;
204 gr = g->gr_mem[++j];
207 endgrent();
208 ret = setgroups(i, grouplst);
209 free(grouplst);
210 return ret;
211 #endif /* HAVE_SETGROUPS */
213 #endif /* HAVE_INITGROUPS */
216 #if (defined(SecureWare) && defined(SCO))
217 /* This is needed due to needing the nap() function but we don't want
218 to include the Xenix libraries since that will break other things...
219 BTW: system call # 0x0c28 is the same as calling nap() */
220 long nap(long milliseconds) {
221 return syscall(0x0c28, milliseconds);
223 #endif
226 #ifndef HAVE_MEMMOVE
227 /*******************************************************************
228 safely copies memory, ensuring no overlap problems.
229 this is only used if the machine does not have its own memmove().
230 this is not the fastest algorithm in town, but it will do for our
231 needs.
232 ********************************************************************/
233 void *rep_memmove(void *dest,const void *src,int size)
235 unsigned long d,s;
236 int i;
237 if (dest==src || !size) return(dest);
239 d = (unsigned long)dest;
240 s = (unsigned long)src;
242 if ((d >= (s+size)) || (s >= (d+size))) {
243 /* no overlap */
244 memcpy(dest,src,size);
245 return(dest);
248 if (d < s) {
249 /* we can forward copy */
250 if (s-d >= sizeof(int) &&
251 !(s%sizeof(int)) &&
252 !(d%sizeof(int)) &&
253 !(size%sizeof(int))) {
254 /* do it all as words */
255 int *idest = (int *)dest;
256 int *isrc = (int *)src;
257 size /= sizeof(int);
258 for (i=0;i<size;i++) idest[i] = isrc[i];
259 } else {
260 /* simplest */
261 char *cdest = (char *)dest;
262 char *csrc = (char *)src;
263 for (i=0;i<size;i++) cdest[i] = csrc[i];
265 } else {
266 /* must backward copy */
267 if (d-s >= sizeof(int) &&
268 !(s%sizeof(int)) &&
269 !(d%sizeof(int)) &&
270 !(size%sizeof(int))) {
271 /* do it all as words */
272 int *idest = (int *)dest;
273 int *isrc = (int *)src;
274 size /= sizeof(int);
275 for (i=size-1;i>=0;i--) idest[i] = isrc[i];
276 } else {
277 /* simplest */
278 char *cdest = (char *)dest;
279 char *csrc = (char *)src;
280 for (i=size-1;i>=0;i--) cdest[i] = csrc[i];
283 return(dest);
285 #endif /* HAVE_MEMMOVE */
287 #ifndef HAVE_STRDUP
288 /****************************************************************************
289 duplicate a string
290 ****************************************************************************/
291 char *rep_strdup(const char *s)
293 size_t len;
294 char *ret;
296 if (!s) return(NULL);
298 len = strlen(s)+1;
299 ret = (char *)malloc(len);
300 if (!ret) return(NULL);
301 memcpy(ret,s,len);
302 return(ret);
304 #endif /* HAVE_STRDUP */
306 #ifndef HAVE_SETLINEBUF
307 void rep_setlinebuf(FILE *stream)
309 setvbuf(stream, (char *)NULL, _IOLBF, 0);
311 #endif /* HAVE_SETLINEBUF */
313 #ifndef HAVE_VSYSLOG
314 #ifdef HAVE_SYSLOG
315 void rep_vsyslog (int facility_priority, const char *format, va_list arglist)
317 char *msg = NULL;
318 vasprintf(&msg, format, arglist);
319 if (!msg)
320 return;
321 syslog(facility_priority, "%s", msg);
322 free(msg);
324 #endif /* HAVE_SYSLOG */
325 #endif /* HAVE_VSYSLOG */
327 #ifndef HAVE_STRNLEN
329 Some platforms don't have strnlen
331 size_t rep_strnlen(const char *s, size_t max)
333 size_t len;
335 for (len = 0; len < max; len++) {
336 if (s[len] == '\0') {
337 break;
340 return len;
342 #endif
344 #ifndef HAVE_STRNDUP
346 Some platforms don't have strndup.
348 char *rep_strndup(const char *s, size_t n)
350 char *ret;
352 n = strnlen(s, n);
353 ret = malloc(n+1);
354 if (!ret)
355 return NULL;
356 memcpy(ret, s, n);
357 ret[n] = 0;
359 return ret;
361 #endif
363 #if !defined(HAVE_WAITPID) && defined(HAVE_WAIT4)
364 int rep_waitpid(pid_t pid,int *status,int options)
366 return wait4(pid, status, options, NULL);
368 #endif
370 #ifndef HAVE_SETEUID
371 int rep_seteuid(uid_t euid)
373 #ifdef HAVE_SETRESUID
374 return setresuid(-1, euid, -1);
375 #else
376 errno = ENOSYS;
377 return -1;
378 #endif
380 #endif
382 #ifndef HAVE_SETEGID
383 int rep_setegid(gid_t egid)
385 #ifdef HAVE_SETRESGID
386 return setresgid(-1, egid, -1);
387 #else
388 errno = ENOSYS;
389 return -1;
390 #endif
392 #endif
394 /*******************************************************************
395 os/2 also doesn't have chroot
396 ********************************************************************/
397 #ifndef HAVE_CHROOT
398 int rep_chroot(const char *dname)
400 errno = ENOSYS;
401 return -1;
403 #endif
405 /*****************************************************************
406 Possibly replace mkstemp if it is broken.
407 *****************************************************************/
409 #ifndef HAVE_SECURE_MKSTEMP
410 int rep_mkstemp(char *template)
412 /* have a reasonable go at emulating it. Hope that
413 the system mktemp() isn't completely hopeless */
414 char *p = mktemp(template);
415 if (!p)
416 return -1;
417 return open(p, O_CREAT|O_EXCL|O_RDWR, 0600);
419 #endif
421 #ifndef HAVE_MKDTEMP
422 char *rep_mkdtemp(char *template)
424 char *dname;
426 if ((dname = mktemp(template))) {
427 if (mkdir(dname, 0700) >= 0) {
428 return dname;
432 return NULL;
434 #endif
436 /*****************************************************************
437 Watch out: this is not thread safe.
438 *****************************************************************/
440 #ifndef HAVE_PREAD
441 ssize_t rep_pread(int __fd, void *__buf, size_t __nbytes, off_t __offset)
443 if (lseek(__fd, __offset, SEEK_SET) != __offset) {
444 return -1;
446 return read(__fd, __buf, __nbytes);
448 #endif
450 /*****************************************************************
451 Watch out: this is not thread safe.
452 *****************************************************************/
454 #ifndef HAVE_PWRITE
455 ssize_t rep_pwrite(int __fd, const void *__buf, size_t __nbytes, off_t __offset)
457 if (lseek(__fd, __offset, SEEK_SET) != __offset) {
458 return -1;
460 return write(__fd, __buf, __nbytes);
462 #endif
464 #ifndef HAVE_STRCASESTR
465 char *rep_strcasestr(const char *haystack, const char *needle)
467 const char *s;
468 size_t nlen = strlen(needle);
469 for (s=haystack;*s;s++) {
470 if (toupper(*needle) == toupper(*s) &&
471 strncasecmp(s, needle, nlen) == 0) {
472 return (char *)((uintptr_t)s);
475 return NULL;
477 #endif
479 #ifndef HAVE_STRTOK_R
480 /* based on GLIBC version, copyright Free Software Foundation */
481 char *rep_strtok_r(char *s, const char *delim, char **save_ptr)
483 char *token;
485 if (s == NULL) s = *save_ptr;
487 s += strspn(s, delim);
488 if (*s == '\0') {
489 *save_ptr = s;
490 return NULL;
493 token = s;
494 s = strpbrk(token, delim);
495 if (s == NULL) {
496 *save_ptr = token + strlen(token);
497 } else {
498 *s = '\0';
499 *save_ptr = s + 1;
502 return token;
504 #endif
507 #ifndef HAVE_STRTOLL
508 long long int rep_strtoll(const char *str, char **endptr, int base)
510 #ifdef HAVE_STRTOQ
511 return strtoq(str, endptr, base);
512 #elif defined(HAVE___STRTOLL)
513 return __strtoll(str, endptr, base);
514 #elif SIZEOF_LONG == SIZEOF_LONG_LONG
515 return (long long int) strtol(str, endptr, base);
516 #else
517 # error "You need a strtoll function"
518 #endif
520 #else
521 #ifdef HAVE_BSD_STRTOLL
522 #ifdef HAVE_STRTOQ
523 long long int rep_strtoll(const char *str, char **endptr, int base)
525 long long int nb = strtoq(str, endptr, base);
526 /* In linux EINVAL is only returned if base is not ok */
527 if (errno == EINVAL) {
528 if (base == 0 || (base >1 && base <37)) {
529 /* Base was ok so it's because we were not
530 * able to make the convertion.
531 * Let's reset errno.
533 errno = 0;
536 return nb;
538 #else
539 #error "You need the strtoq function"
540 #endif /* HAVE_STRTOQ */
541 #endif /* HAVE_BSD_STRTOLL */
542 #endif /* HAVE_STRTOLL */
545 #ifndef HAVE_STRTOULL
546 unsigned long long int rep_strtoull(const char *str, char **endptr, int base)
548 #ifdef HAVE_STRTOUQ
549 return strtouq(str, endptr, base);
550 #elif defined(HAVE___STRTOULL)
551 return __strtoull(str, endptr, base);
552 #elif SIZEOF_LONG == SIZEOF_LONG_LONG
553 return (unsigned long long int) strtoul(str, endptr, base);
554 #else
555 # error "You need a strtoull function"
556 #endif
558 #else
559 #ifdef HAVE_BSD_STRTOLL
560 #ifdef HAVE_STRTOUQ
561 unsigned long long int rep_strtoull(const char *str, char **endptr, int base)
563 unsigned long long int nb = strtouq(str, endptr, base);
564 /* In linux EINVAL is only returned if base is not ok */
565 if (errno == EINVAL) {
566 if (base == 0 || (base >1 && base <37)) {
567 /* Base was ok so it's because we were not
568 * able to make the convertion.
569 * Let's reset errno.
571 errno = 0;
574 return nb;
576 #else
577 #error "You need the strtouq function"
578 #endif /* HAVE_STRTOUQ */
579 #endif /* HAVE_BSD_STRTOLL */
580 #endif /* HAVE_STRTOULL */
582 #ifndef HAVE_SETENV
583 int rep_setenv(const char *name, const char *value, int overwrite)
585 char *p;
586 size_t l1, l2;
587 int ret;
589 if (!overwrite && getenv(name)) {
590 return 0;
593 l1 = strlen(name);
594 l2 = strlen(value);
596 p = malloc(l1+l2+2);
597 if (p == NULL) {
598 return -1;
600 memcpy(p, name, l1);
601 p[l1] = '=';
602 memcpy(p+l1+1, value, l2);
603 p[l1+l2+1] = 0;
605 ret = putenv(p);
606 if (ret != 0) {
607 free(p);
610 return ret;
612 #endif
614 #ifndef HAVE_UNSETENV
615 int rep_unsetenv(const char *name)
617 extern char **environ;
618 size_t len = strlen(name);
619 size_t i, count;
621 if (environ == NULL || getenv(name) == NULL) {
622 return 0;
625 for (i=0;environ[i];i++) /* noop */ ;
627 count=i;
629 for (i=0;i<count;) {
630 if (strncmp(environ[i], name, len) == 0 && environ[i][len] == '=') {
631 /* note: we do _not_ free the old variable here. It is unsafe to
632 do so, as the pointer may not have come from malloc */
633 memmove(&environ[i], &environ[i+1], (count-i)*sizeof(char *));
634 count--;
635 } else {
636 i++;
640 return 0;
642 #endif
644 #ifndef HAVE_UTIME
645 int rep_utime(const char *filename, const struct utimbuf *buf)
647 errno = ENOSYS;
648 return -1;
650 #endif
652 #ifndef HAVE_UTIMES
653 int rep_utimes(const char *filename, const struct timeval tv[2])
655 struct utimbuf u;
657 u.actime = tv[0].tv_sec;
658 if (tv[0].tv_usec > 500000) {
659 u.actime += 1;
662 u.modtime = tv[1].tv_sec;
663 if (tv[1].tv_usec > 500000) {
664 u.modtime += 1;
667 return utime(filename, &u);
669 #endif
671 #ifndef HAVE_DUP2
672 int rep_dup2(int oldfd, int newfd)
674 errno = ENOSYS;
675 return -1;
677 #endif
679 #ifndef HAVE_CHOWN
681 chown isn't used much but OS/2 doesn't have it
683 int rep_chown(const char *fname, uid_t uid, gid_t gid)
685 errno = ENOSYS;
686 return -1;
688 #endif
690 #ifndef HAVE_LINK
691 int rep_link(const char *oldpath, const char *newpath)
693 errno = ENOSYS;
694 return -1;
696 #endif
698 #ifndef HAVE_READLINK
699 int rep_readlink(const char *path, char *buf, size_t bufsiz)
701 errno = ENOSYS;
702 return -1;
704 #endif
706 #ifndef HAVE_SYMLINK
707 int rep_symlink(const char *oldpath, const char *newpath)
709 errno = ENOSYS;
710 return -1;
712 #endif
714 #ifndef HAVE_LCHOWN
715 int rep_lchown(const char *fname,uid_t uid,gid_t gid)
717 errno = ENOSYS;
718 return -1;
720 #endif
722 #ifndef HAVE_REALPATH
723 char *rep_realpath(const char *path, char *resolved_path)
725 /* As realpath is not a system call we can't return ENOSYS. */
726 errno = EINVAL;
727 return NULL;
729 #endif
732 #ifndef HAVE_MEMMEM
733 void *rep_memmem(const void *haystack, size_t haystacklen,
734 const void *needle, size_t needlelen)
736 if (needlelen == 0) {
737 return discard_const(haystack);
739 while (haystacklen >= needlelen) {
740 char *p = (char *)memchr(haystack, *(const char *)needle,
741 haystacklen-(needlelen-1));
742 if (!p) return NULL;
743 if (memcmp(p, needle, needlelen) == 0) {
744 return p;
746 haystack = p+1;
747 haystacklen -= (p - (const char *)haystack) + 1;
749 return NULL;
751 #endif
753 #ifndef HAVE_VDPRINTF
754 int rep_vdprintf(int fd, const char *format, va_list ap)
756 char *s = NULL;
757 int ret;
759 vasprintf(&s, format, ap);
760 if (s == NULL) {
761 errno = ENOMEM;
762 return -1;
764 ret = write(fd, s, strlen(s));
765 free(s);
766 return ret;
768 #endif
770 #ifndef HAVE_DPRINTF
771 int rep_dprintf(int fd, const char *format, ...)
773 int ret;
774 va_list ap;
776 va_start(ap, format);
777 ret = vdprintf(fd, format, ap);
778 va_end(ap);
780 return ret;
782 #endif
784 #ifndef HAVE_GET_CURRENT_DIR_NAME
785 char *rep_get_current_dir_name(void)
787 char buf[PATH_MAX+1];
788 char *p;
789 p = getcwd(buf, sizeof(buf));
790 if (p == NULL) {
791 return NULL;
793 return strdup(p);
795 #endif
797 #if !defined(HAVE_STRERROR_R) || !defined(STRERROR_R_PROTO_COMPATIBLE)
798 int rep_strerror_r(int errnum, char *buf, size_t buflen)
800 char *s = strerror(errnum);
801 if (strlen(s)+1 > buflen) {
802 errno = ERANGE;
803 return -1;
805 strncpy(buf, s, buflen);
806 return 0;
808 #endif
810 #ifndef HAVE_CLOCK_GETTIME
811 int rep_clock_gettime(clockid_t clk_id, struct timespec *tp)
813 struct timeval tval;
814 switch (clk_id) {
815 case 0: /* CLOCK_REALTIME :*/
816 #ifdef HAVE_GETTIMEOFDAY_TZ
817 gettimeofday(&tval,NULL);
818 #else
819 gettimeofday(&tval);
820 #endif
821 tp->tv_sec = tval.tv_sec;
822 tp->tv_nsec = tval.tv_usec * 1000;
823 break;
824 default:
825 errno = EINVAL;
826 return -1;
828 return 0;
830 #endif