smbd: Factor out unlocking from smbd_do_locking
[Samba.git] / lib / replace / replace.c
blob2a9ca3e5abb6b27c021ce903ed5099b2b5cd1762
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/network.h"
31 #include "system/passwd.h"
32 #include "system/syslog.h"
33 #include "system/locale.h"
34 #include "system/wait.h"
36 #ifdef _WIN32
37 #define mkdir(d,m) _mkdir(d)
38 #endif
40 void replace_dummy(void);
41 void replace_dummy(void) {}
43 #ifndef HAVE_FTRUNCATE
44 /*******************************************************************
45 ftruncate for operating systems that don't have it
46 ********************************************************************/
47 int rep_ftruncate(int f, off_t l)
49 #ifdef HAVE_CHSIZE
50 return chsize(f,l);
51 #elif defined(F_FREESP)
52 struct flock fl;
54 fl.l_whence = 0;
55 fl.l_len = 0;
56 fl.l_start = l;
57 fl.l_type = F_WRLCK;
58 return fcntl(f, F_FREESP, &fl);
59 #else
60 #error "you must have a ftruncate function"
61 #endif
63 #endif /* HAVE_FTRUNCATE */
66 #ifndef HAVE_STRLCPY
67 /* like strncpy but does not 0 fill the buffer and always null
68 terminates. bufsize is the size of the destination buffer */
69 size_t rep_strlcpy(char *d, const char *s, size_t bufsize)
71 size_t len = strlen(s);
72 size_t ret = len;
73 if (bufsize <= 0) return 0;
74 if (len >= bufsize) len = bufsize-1;
75 memcpy(d, s, len);
76 d[len] = 0;
77 return ret;
79 #endif
81 #ifndef HAVE_STRLCAT
82 /* like strncat but does not 0 fill the buffer and always null
83 terminates. bufsize is the length of the buffer, which should
84 be one more than the maximum resulting string length */
85 size_t rep_strlcat(char *d, const char *s, size_t bufsize)
87 size_t len1 = strnlen(d, bufsize);
88 size_t len2 = strlen(s);
89 size_t ret = len1 + len2;
91 if (len1+len2 >= bufsize) {
92 if (bufsize < (len1+1)) {
93 return ret;
95 len2 = bufsize - (len1+1);
97 if (len2 > 0) {
98 memcpy(d+len1, s, len2);
99 d[len1+len2] = 0;
101 return ret;
103 #endif
105 #ifndef HAVE_MKTIME
106 /*******************************************************************
107 a mktime() replacement for those who don't have it - contributed by
108 C.A. Lademann <cal@zls.com>
109 Corrections by richard.kettlewell@kewill.com
110 ********************************************************************/
112 #define MINUTE 60
113 #define HOUR 60*MINUTE
114 #define DAY 24*HOUR
115 #define YEAR 365*DAY
116 time_t rep_mktime(struct tm *t)
118 struct tm *u;
119 time_t epoch = 0;
120 int n;
121 int mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
122 y, m, i;
124 if(t->tm_year < 70)
125 return((time_t)-1);
127 n = t->tm_year + 1900 - 1;
128 epoch = (t->tm_year - 70) * YEAR +
129 ((n / 4 - n / 100 + n / 400) - (1969 / 4 - 1969 / 100 + 1969 / 400)) * DAY;
131 y = t->tm_year + 1900;
132 m = 0;
134 for(i = 0; i < t->tm_mon; i++) {
135 epoch += mon [m] * DAY;
136 if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
137 epoch += DAY;
139 if(++m > 11) {
140 m = 0;
141 y++;
145 epoch += (t->tm_mday - 1) * DAY;
146 epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec;
148 if((u = localtime(&epoch)) != NULL) {
149 t->tm_sec = u->tm_sec;
150 t->tm_min = u->tm_min;
151 t->tm_hour = u->tm_hour;
152 t->tm_mday = u->tm_mday;
153 t->tm_mon = u->tm_mon;
154 t->tm_year = u->tm_year;
155 t->tm_wday = u->tm_wday;
156 t->tm_yday = u->tm_yday;
157 t->tm_isdst = u->tm_isdst;
160 return(epoch);
162 #endif /* !HAVE_MKTIME */
165 #ifndef HAVE_INITGROUPS
166 /****************************************************************************
167 some systems don't have an initgroups call
168 ****************************************************************************/
169 int rep_initgroups(char *name, gid_t id)
171 #ifndef HAVE_SETGROUPS
172 /* yikes! no SETGROUPS or INITGROUPS? how can this work? */
173 errno = ENOSYS;
174 return -1;
175 #else /* HAVE_SETGROUPS */
177 #include <grp.h>
179 gid_t *grouplst = NULL;
180 int max_gr = NGROUPS_MAX;
181 int ret;
182 int i,j;
183 struct group *g;
184 char *gr;
186 if((grouplst = malloc(sizeof(gid_t) * max_gr)) == NULL) {
187 errno = ENOMEM;
188 return -1;
191 grouplst[0] = id;
192 i = 1;
193 while (i < max_gr && ((g = (struct group *)getgrent()) != (struct group *)NULL)) {
194 if (g->gr_gid == id)
195 continue;
196 j = 0;
197 gr = g->gr_mem[0];
198 while (gr && (*gr != (char)NULL)) {
199 if (strcmp(name,gr) == 0) {
200 grouplst[i] = g->gr_gid;
201 i++;
202 gr = (char *)NULL;
203 break;
205 gr = g->gr_mem[++j];
208 endgrent();
209 ret = setgroups(i, grouplst);
210 free(grouplst);
211 return ret;
212 #endif /* HAVE_SETGROUPS */
214 #endif /* HAVE_INITGROUPS */
217 #ifndef HAVE_MEMMOVE
218 /*******************************************************************
219 safely copies memory, ensuring no overlap problems.
220 this is only used if the machine does not have its own memmove().
221 this is not the fastest algorithm in town, but it will do for our
222 needs.
223 ********************************************************************/
224 void *rep_memmove(void *dest,const void *src,int size)
226 unsigned long d,s;
227 int i;
228 if (dest==src || !size) return(dest);
230 d = (unsigned long)dest;
231 s = (unsigned long)src;
233 if ((d >= (s+size)) || (s >= (d+size))) {
234 /* no overlap */
235 memcpy(dest,src,size);
236 return(dest);
239 if (d < s) {
240 /* we can forward copy */
241 if (s-d >= sizeof(int) &&
242 !(s%sizeof(int)) &&
243 !(d%sizeof(int)) &&
244 !(size%sizeof(int))) {
245 /* do it all as words */
246 int *idest = (int *)dest;
247 int *isrc = (int *)src;
248 size /= sizeof(int);
249 for (i=0;i<size;i++) idest[i] = isrc[i];
250 } else {
251 /* simplest */
252 char *cdest = (char *)dest;
253 char *csrc = (char *)src;
254 for (i=0;i<size;i++) cdest[i] = csrc[i];
256 } else {
257 /* must backward copy */
258 if (d-s >= sizeof(int) &&
259 !(s%sizeof(int)) &&
260 !(d%sizeof(int)) &&
261 !(size%sizeof(int))) {
262 /* do it all as words */
263 int *idest = (int *)dest;
264 int *isrc = (int *)src;
265 size /= sizeof(int);
266 for (i=size-1;i>=0;i--) idest[i] = isrc[i];
267 } else {
268 /* simplest */
269 char *cdest = (char *)dest;
270 char *csrc = (char *)src;
271 for (i=size-1;i>=0;i--) cdest[i] = csrc[i];
274 return(dest);
276 #endif /* HAVE_MEMMOVE */
278 #ifndef HAVE_STRDUP
279 /****************************************************************************
280 duplicate a string
281 ****************************************************************************/
282 char *rep_strdup(const char *s)
284 size_t len;
285 char *ret;
287 if (!s) return(NULL);
289 len = strlen(s)+1;
290 ret = (char *)malloc(len);
291 if (!ret) return(NULL);
292 memcpy(ret,s,len);
293 return(ret);
295 #endif /* HAVE_STRDUP */
297 #ifndef HAVE_SETLINEBUF
298 void rep_setlinebuf(FILE *stream)
300 setvbuf(stream, (char *)NULL, _IOLBF, 0);
302 #endif /* HAVE_SETLINEBUF */
304 #ifndef HAVE_VSYSLOG
305 #ifdef HAVE_SYSLOG
306 void rep_vsyslog (int facility_priority, const char *format, va_list arglist)
308 char *msg = NULL;
309 vasprintf(&msg, format, arglist);
310 if (!msg)
311 return;
312 syslog(facility_priority, "%s", msg);
313 free(msg);
315 #endif /* HAVE_SYSLOG */
316 #endif /* HAVE_VSYSLOG */
318 #ifndef HAVE_STRNLEN
320 Some platforms don't have strnlen
322 size_t rep_strnlen(const char *s, size_t max)
324 size_t len;
326 for (len = 0; len < max; len++) {
327 if (s[len] == '\0') {
328 break;
331 return len;
333 #endif
335 #ifndef HAVE_STRNDUP
337 Some platforms don't have strndup.
339 char *rep_strndup(const char *s, size_t n)
341 char *ret;
343 n = strnlen(s, n);
344 ret = malloc(n+1);
345 if (!ret)
346 return NULL;
347 memcpy(ret, s, n);
348 ret[n] = 0;
350 return ret;
352 #endif
354 #if !defined(HAVE_WAITPID) && defined(HAVE_WAIT4)
355 int rep_waitpid(pid_t pid,int *status,int options)
357 return wait4(pid, status, options, NULL);
359 #endif
361 #ifndef HAVE_SETEUID
362 int rep_seteuid(uid_t euid)
364 #ifdef HAVE_SETRESUID
365 return setresuid(-1, euid, -1);
366 #else
367 errno = ENOSYS;
368 return -1;
369 #endif
371 #endif
373 #ifndef HAVE_SETEGID
374 int rep_setegid(gid_t egid)
376 #ifdef HAVE_SETRESGID
377 return setresgid(-1, egid, -1);
378 #else
379 errno = ENOSYS;
380 return -1;
381 #endif
383 #endif
385 /*******************************************************************
386 os/2 also doesn't have chroot
387 ********************************************************************/
388 #ifndef HAVE_CHROOT
389 int rep_chroot(const char *dname)
391 errno = ENOSYS;
392 return -1;
394 #endif
396 /*****************************************************************
397 Possibly replace mkstemp if it is broken.
398 *****************************************************************/
400 #ifndef HAVE_SECURE_MKSTEMP
401 int rep_mkstemp(char *template)
403 /* have a reasonable go at emulating it. Hope that
404 the system mktemp() isn't completely hopeless */
405 mktemp(template);
406 if (template[0] == 0)
407 return -1;
408 return open(template, O_CREAT|O_EXCL|O_RDWR, 0600);
410 #endif
412 #ifndef HAVE_MKDTEMP
413 char *rep_mkdtemp(char *template)
415 char *dname;
417 if ((dname = mktemp(template))) {
418 if (mkdir(dname, 0700) >= 0) {
419 return dname;
423 return NULL;
425 #endif
427 /*****************************************************************
428 Watch out: this is not thread safe.
429 *****************************************************************/
431 #ifndef HAVE_PREAD
432 ssize_t rep_pread(int __fd, void *__buf, size_t __nbytes, off_t __offset)
434 if (lseek(__fd, __offset, SEEK_SET) != __offset) {
435 return -1;
437 return read(__fd, __buf, __nbytes);
439 #endif
441 /*****************************************************************
442 Watch out: this is not thread safe.
443 *****************************************************************/
445 #ifndef HAVE_PWRITE
446 ssize_t rep_pwrite(int __fd, const void *__buf, size_t __nbytes, off_t __offset)
448 if (lseek(__fd, __offset, SEEK_SET) != __offset) {
449 return -1;
451 return write(__fd, __buf, __nbytes);
453 #endif
455 #ifndef HAVE_STRCASESTR
456 char *rep_strcasestr(const char *haystack, const char *needle)
458 const char *s;
459 size_t nlen = strlen(needle);
460 for (s=haystack;*s;s++) {
461 if (toupper(*needle) == toupper(*s) &&
462 strncasecmp(s, needle, nlen) == 0) {
463 return (char *)((uintptr_t)s);
466 return NULL;
468 #endif
470 #ifndef HAVE_STRTOK_R
471 /* based on GLIBC version, copyright Free Software Foundation */
472 char *rep_strtok_r(char *s, const char *delim, char **save_ptr)
474 char *token;
476 if (s == NULL) s = *save_ptr;
478 s += strspn(s, delim);
479 if (*s == '\0') {
480 *save_ptr = s;
481 return NULL;
484 token = s;
485 s = strpbrk(token, delim);
486 if (s == NULL) {
487 *save_ptr = token + strlen(token);
488 } else {
489 *s = '\0';
490 *save_ptr = s + 1;
493 return token;
495 #endif
498 #ifndef HAVE_STRTOLL
499 long long int rep_strtoll(const char *str, char **endptr, int base)
501 #ifdef HAVE_STRTOQ
502 return strtoq(str, endptr, base);
503 #elif defined(HAVE___STRTOLL)
504 return __strtoll(str, endptr, base);
505 #elif SIZEOF_LONG == SIZEOF_LONG_LONG
506 return (long long int) strtol(str, endptr, base);
507 #else
508 # error "You need a strtoll function"
509 #endif
511 #else
512 #ifdef HAVE_BSD_STRTOLL
513 #ifdef HAVE_STRTOQ
514 long long int rep_strtoll(const char *str, char **endptr, int base)
516 long long int nb = strtoq(str, endptr, base);
517 /* In linux EINVAL is only returned if base is not ok */
518 if (errno == EINVAL) {
519 if (base == 0 || (base >1 && base <37)) {
520 /* Base was ok so it's because we were not
521 * able to make the convertion.
522 * Let's reset errno.
524 errno = 0;
527 return nb;
529 #else
530 #error "You need the strtoq function"
531 #endif /* HAVE_STRTOQ */
532 #endif /* HAVE_BSD_STRTOLL */
533 #endif /* HAVE_STRTOLL */
536 #ifndef HAVE_STRTOULL
537 unsigned long long int rep_strtoull(const char *str, char **endptr, int base)
539 #ifdef HAVE_STRTOUQ
540 return strtouq(str, endptr, base);
541 #elif defined(HAVE___STRTOULL)
542 return __strtoull(str, endptr, base);
543 #elif SIZEOF_LONG == SIZEOF_LONG_LONG
544 return (unsigned long long int) strtoul(str, endptr, base);
545 #else
546 # error "You need a strtoull function"
547 #endif
549 #else
550 #ifdef HAVE_BSD_STRTOLL
551 #ifdef HAVE_STRTOUQ
552 unsigned long long int rep_strtoull(const char *str, char **endptr, int base)
554 unsigned long long int nb = strtouq(str, endptr, base);
555 /* In linux EINVAL is only returned if base is not ok */
556 if (errno == EINVAL) {
557 if (base == 0 || (base >1 && base <37)) {
558 /* Base was ok so it's because we were not
559 * able to make the convertion.
560 * Let's reset errno.
562 errno = 0;
565 return nb;
567 #else
568 #error "You need the strtouq function"
569 #endif /* HAVE_STRTOUQ */
570 #endif /* HAVE_BSD_STRTOLL */
571 #endif /* HAVE_STRTOULL */
573 #ifndef HAVE_SETENV
574 int rep_setenv(const char *name, const char *value, int overwrite)
576 char *p;
577 size_t l1, l2;
578 int ret;
580 if (!overwrite && getenv(name)) {
581 return 0;
584 l1 = strlen(name);
585 l2 = strlen(value);
587 p = malloc(l1+l2+2);
588 if (p == NULL) {
589 return -1;
591 memcpy(p, name, l1);
592 p[l1] = '=';
593 memcpy(p+l1+1, value, l2);
594 p[l1+l2+1] = 0;
596 ret = putenv(p);
597 if (ret != 0) {
598 free(p);
601 return ret;
603 #endif
605 #ifndef HAVE_UNSETENV
606 int rep_unsetenv(const char *name)
608 extern char **environ;
609 size_t len = strlen(name);
610 size_t i, count;
612 if (environ == NULL || getenv(name) == NULL) {
613 return 0;
616 for (i=0;environ[i];i++) /* noop */ ;
618 count=i;
620 for (i=0;i<count;) {
621 if (strncmp(environ[i], name, len) == 0 && environ[i][len] == '=') {
622 /* note: we do _not_ free the old variable here. It is unsafe to
623 do so, as the pointer may not have come from malloc */
624 memmove(&environ[i], &environ[i+1], (count-i)*sizeof(char *));
625 count--;
626 } else {
627 i++;
631 return 0;
633 #endif
635 #ifndef HAVE_UTIME
636 int rep_utime(const char *filename, const struct utimbuf *buf)
638 errno = ENOSYS;
639 return -1;
641 #endif
643 #ifndef HAVE_UTIMES
644 int rep_utimes(const char *filename, const struct timeval tv[2])
646 struct utimbuf u;
648 u.actime = tv[0].tv_sec;
649 if (tv[0].tv_usec > 500000) {
650 u.actime += 1;
653 u.modtime = tv[1].tv_sec;
654 if (tv[1].tv_usec > 500000) {
655 u.modtime += 1;
658 return utime(filename, &u);
660 #endif
662 #ifndef HAVE_DUP2
663 int rep_dup2(int oldfd, int newfd)
665 errno = ENOSYS;
666 return -1;
668 #endif
670 #ifndef HAVE_CHOWN
672 chown isn't used much but OS/2 doesn't have it
674 int rep_chown(const char *fname, uid_t uid, gid_t gid)
676 errno = ENOSYS;
677 return -1;
679 #endif
681 #ifndef HAVE_LINK
682 int rep_link(const char *oldpath, const char *newpath)
684 errno = ENOSYS;
685 return -1;
687 #endif
689 #ifndef HAVE_READLINK
690 int rep_readlink(const char *path, char *buf, size_t bufsiz)
692 errno = ENOSYS;
693 return -1;
695 #endif
697 #ifndef HAVE_SYMLINK
698 int rep_symlink(const char *oldpath, const char *newpath)
700 errno = ENOSYS;
701 return -1;
703 #endif
705 #ifndef HAVE_LCHOWN
706 int rep_lchown(const char *fname,uid_t uid,gid_t gid)
708 errno = ENOSYS;
709 return -1;
711 #endif
713 #ifndef HAVE_REALPATH
714 char *rep_realpath(const char *path, char *resolved_path)
716 /* As realpath is not a system call we can't return ENOSYS. */
717 errno = EINVAL;
718 return NULL;
720 #endif
723 #ifndef HAVE_MEMMEM
724 void *rep_memmem(const void *haystack, size_t haystacklen,
725 const void *needle, size_t needlelen)
727 if (needlelen == 0) {
728 return discard_const(haystack);
730 while (haystacklen >= needlelen) {
731 char *p = (char *)memchr(haystack, *(const char *)needle,
732 haystacklen-(needlelen-1));
733 if (!p) return NULL;
734 if (memcmp(p, needle, needlelen) == 0) {
735 return p;
737 haystack = p+1;
738 haystacklen -= (p - (const char *)haystack) + 1;
740 return NULL;
742 #endif
744 #if !defined(HAVE_VDPRINTF) || !defined(HAVE_C99_VSNPRINTF)
745 int rep_vdprintf(int fd, const char *format, va_list ap)
747 char *s = NULL;
748 int ret;
750 vasprintf(&s, format, ap);
751 if (s == NULL) {
752 errno = ENOMEM;
753 return -1;
755 ret = write(fd, s, strlen(s));
756 free(s);
757 return ret;
759 #endif
761 #if !defined(HAVE_DPRINTF) || !defined(HAVE_C99_VSNPRINTF)
762 int rep_dprintf(int fd, const char *format, ...)
764 int ret;
765 va_list ap;
767 va_start(ap, format);
768 ret = vdprintf(fd, format, ap);
769 va_end(ap);
771 return ret;
773 #endif
775 #ifndef HAVE_GET_CURRENT_DIR_NAME
776 char *rep_get_current_dir_name(void)
778 char buf[PATH_MAX+1];
779 char *p;
780 p = getcwd(buf, sizeof(buf));
781 if (p == NULL) {
782 return NULL;
784 return strdup(p);
786 #endif
788 #ifndef HAVE_STRERROR_R
789 int rep_strerror_r(int errnum, char *buf, size_t buflen)
791 char *s = strerror(errnum);
792 if (strlen(s)+1 > buflen) {
793 errno = ERANGE;
794 return -1;
796 strncpy(buf, s, buflen);
797 return 0;
799 #endif
801 #ifndef HAVE_CLOCK_GETTIME
802 int rep_clock_gettime(clockid_t clk_id, struct timespec *tp)
804 struct timeval tval;
805 switch (clk_id) {
806 case 0: /* CLOCK_REALTIME :*/
807 #ifdef HAVE_GETTIMEOFDAY_TZ
808 gettimeofday(&tval,NULL);
809 #else
810 gettimeofday(&tval);
811 #endif
812 tp->tv_sec = tval.tv_sec;
813 tp->tv_nsec = tval.tv_usec * 1000;
814 break;
815 default:
816 errno = EINVAL;
817 return -1;
819 return 0;
821 #endif
823 #ifndef HAVE_MEMALIGN
824 void *rep_memalign( size_t align, size_t size )
826 #if defined(HAVE_POSIX_MEMALIGN)
827 void *p = NULL;
828 int ret = posix_memalign( &p, align, size );
829 if ( ret == 0 )
830 return p;
832 return NULL;
833 #else
834 /* On *BSD systems memaligns doesn't exist, but memory will
835 * be aligned on allocations of > pagesize. */
836 #if defined(SYSCONF_SC_PAGESIZE)
837 size_t pagesize = (size_t)sysconf(_SC_PAGESIZE);
838 #elif defined(HAVE_GETPAGESIZE)
839 size_t pagesize = (size_t)getpagesize();
840 #else
841 size_t pagesize = (size_t)-1;
842 #endif
843 if (pagesize == (size_t)-1) {
844 errno = ENOSYS;
845 return NULL;
847 if (size < pagesize) {
848 size = pagesize;
850 return malloc(size);
851 #endif
853 #endif
855 #ifndef HAVE_GETPEEREID
856 int rep_getpeereid(int s, uid_t *uid, gid_t *gid)
858 #if defined(HAVE_PEERCRED)
859 struct ucred cred;
860 socklen_t cred_len = sizeof(struct ucred);
861 int ret;
863 #undef getsockopt
864 ret = getsockopt(s, SOL_SOCKET, SO_PEERCRED, (void *)&cred, &cred_len);
865 if (ret != 0) {
866 return -1;
869 if (cred_len != sizeof(struct ucred)) {
870 errno = EINVAL;
871 return -1;
874 *uid = cred.uid;
875 *gid = cred.gid;
876 return 0;
877 #else
878 errno = ENOSYS;
879 return -1;
880 #endif
882 #endif
884 #ifndef HAVE_USLEEP
885 int rep_usleep(useconds_t sec)
887 struct timeval tval;
889 * Fake it with select...
891 tval.tv_sec = 0;
892 tval.tv_usec = usecs/1000;
893 select(0,NULL,NULL,NULL,&tval);
894 return 0;
896 #endif /* HAVE_USLEEP */
898 #ifndef HAVE_SETPROCTITLE
899 void rep_setproctitle(const char *fmt, ...)
902 #endif