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
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/>.
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"
37 #define mkdir(d,m) _mkdir(d)
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
)
51 #elif defined(F_FREESP)
58 return fcntl(f
, F_FREESP
, &fl
);
60 #error "you must have a ftruncate function"
63 #endif /* HAVE_FTRUNCATE */
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
);
73 if (bufsize
<= 0) return 0;
74 if (len
>= bufsize
) len
= bufsize
-1;
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
= strlen(d
);
88 size_t len2
= strlen(s
);
89 size_t ret
= len1
+ len2
;
91 if (len1
+len2
>= bufsize
) {
92 if (bufsize
< (len1
+1)) {
95 len2
= bufsize
- (len1
+1);
98 memcpy(d
+len1
, s
, len2
);
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 ********************************************************************/
113 #define HOUR 60*MINUTE
116 time_t rep_mktime(struct tm
*t
)
121 int mon
[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
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;
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))
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
;
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? */
175 #else /* HAVE_SETGROUPS */
179 gid_t
*grouplst
= NULL
;
180 int max_gr
= NGROUPS_MAX
;
186 if((grouplst
= malloc(sizeof(gid_t
) * max_gr
)) == NULL
) {
193 while (i
< max_gr
&& ((g
= (struct group
*)getgrent()) != (struct group
*)NULL
)) {
198 while (gr
&& (*gr
!= (char)NULL
)) {
199 if (strcmp(name
,gr
) == 0) {
200 grouplst
[i
] = g
->gr_gid
;
209 ret
= setgroups(i
, grouplst
);
212 #endif /* HAVE_SETGROUPS */
214 #endif /* HAVE_INITGROUPS */
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
223 ********************************************************************/
224 void *rep_memmove(void *dest
,const void *src
,int size
)
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
))) {
235 memcpy(dest
,src
,size
);
240 /* we can forward copy */
241 if (s
-d
>= sizeof(int) &&
244 !(size
%sizeof(int))) {
245 /* do it all as words */
246 int *idest
= (int *)dest
;
247 int *isrc
= (int *)src
;
249 for (i
=0;i
<size
;i
++) idest
[i
] = isrc
[i
];
252 char *cdest
= (char *)dest
;
253 char *csrc
= (char *)src
;
254 for (i
=0;i
<size
;i
++) cdest
[i
] = csrc
[i
];
257 /* must backward copy */
258 if (d
-s
>= sizeof(int) &&
261 !(size
%sizeof(int))) {
262 /* do it all as words */
263 int *idest
= (int *)dest
;
264 int *isrc
= (int *)src
;
266 for (i
=size
-1;i
>=0;i
--) idest
[i
] = isrc
[i
];
269 char *cdest
= (char *)dest
;
270 char *csrc
= (char *)src
;
271 for (i
=size
-1;i
>=0;i
--) cdest
[i
] = csrc
[i
];
276 #endif /* HAVE_MEMMOVE */
279 /****************************************************************************
281 ****************************************************************************/
282 char *rep_strdup(const char *s
)
287 if (!s
) return(NULL
);
290 ret
= (char *)malloc(len
);
291 if (!ret
) return(NULL
);
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 */
306 void rep_vsyslog (int facility_priority
, const char *format
, va_list arglist
)
309 vasprintf(&msg
, format
, arglist
);
312 syslog(facility_priority
, "%s", msg
);
315 #endif /* HAVE_SYSLOG */
316 #endif /* HAVE_VSYSLOG */
320 Some platforms don't have strnlen
322 size_t rep_strnlen(const char *s
, size_t max
)
326 for (len
= 0; len
< max
; len
++) {
327 if (s
[len
] == '\0') {
337 Some platforms don't have strndup.
339 char *rep_strndup(const char *s
, size_t n
)
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
);
362 int rep_seteuid(uid_t euid
)
364 #ifdef HAVE_SETRESUID
365 return setresuid(-1, euid
, -1);
374 int rep_setegid(gid_t egid
)
376 #ifdef HAVE_SETRESGID
377 return setresgid(-1, egid
, -1);
385 /*******************************************************************
386 os/2 also doesn't have chroot
387 ********************************************************************/
389 int rep_chroot(const char *dname
)
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 */
406 if (template[0] == 0)
408 return open(p
, O_CREAT
|O_EXCL
|O_RDWR
, 0600);
413 char *rep_mkdtemp(char *template)
417 if ((dname
= mktemp(template))) {
418 if (mkdir(dname
, 0700) >= 0) {
427 /*****************************************************************
428 Watch out: this is not thread safe.
429 *****************************************************************/
432 ssize_t
rep_pread(int __fd
, void *__buf
, size_t __nbytes
, off_t __offset
)
434 if (lseek(__fd
, __offset
, SEEK_SET
) != __offset
) {
437 return read(__fd
, __buf
, __nbytes
);
441 /*****************************************************************
442 Watch out: this is not thread safe.
443 *****************************************************************/
446 ssize_t
rep_pwrite(int __fd
, const void *__buf
, size_t __nbytes
, off_t __offset
)
448 if (lseek(__fd
, __offset
, SEEK_SET
) != __offset
) {
451 return write(__fd
, __buf
, __nbytes
);
455 #ifndef HAVE_STRCASESTR
456 char *rep_strcasestr(const char *haystack
, const char *needle
)
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
);
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
)
476 if (s
== NULL
) s
= *save_ptr
;
478 s
+= strspn(s
, delim
);
485 s
= strpbrk(token
, delim
);
487 *save_ptr
= token
+ strlen(token
);
499 long long int rep_strtoll(const char *str
, char **endptr
, int base
)
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
);
508 # error "You need a strtoll function"
512 #ifdef HAVE_BSD_STRTOLL
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.
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
)
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
);
546 # error "You need a strtoull function"
550 #ifdef HAVE_BSD_STRTOLL
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.
568 #error "You need the strtouq function"
569 #endif /* HAVE_STRTOUQ */
570 #endif /* HAVE_BSD_STRTOLL */
571 #endif /* HAVE_STRTOULL */
574 int rep_setenv(const char *name
, const char *value
, int overwrite
)
580 if (!overwrite
&& getenv(name
)) {
593 memcpy(p
+l1
+1, value
, l2
);
605 #ifndef HAVE_UNSETENV
606 int rep_unsetenv(const char *name
)
608 extern char **environ
;
609 size_t len
= strlen(name
);
612 if (environ
== NULL
|| getenv(name
) == NULL
) {
616 for (i
=0;environ
[i
];i
++) /* noop */ ;
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 *));
636 int rep_utime(const char *filename
, const struct utimbuf
*buf
)
644 int rep_utimes(const char *filename
, const struct timeval tv
[2])
648 u
.actime
= tv
[0].tv_sec
;
649 if (tv
[0].tv_usec
> 500000) {
653 u
.modtime
= tv
[1].tv_sec
;
654 if (tv
[1].tv_usec
> 500000) {
658 return utime(filename
, &u
);
663 int rep_dup2(int oldfd
, int newfd
)
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
)
682 int rep_link(const char *oldpath
, const char *newpath
)
689 #ifndef HAVE_READLINK
690 int rep_readlink(const char *path
, char *buf
, size_t bufsiz
)
698 int rep_symlink(const char *oldpath
, const char *newpath
)
706 int rep_lchown(const char *fname
,uid_t uid
,gid_t gid
)
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. */
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));
734 if (memcmp(p
, needle
, needlelen
) == 0) {
738 haystacklen
-= (p
- (const char *)haystack
) + 1;
744 #ifndef HAVE_VDPRINTF
745 int rep_vdprintf(int fd
, const char *format
, va_list ap
)
750 vasprintf(&s
, format
, ap
);
755 ret
= write(fd
, s
, strlen(s
));
762 int rep_dprintf(int fd
, const char *format
, ...)
767 va_start(ap
, format
);
768 ret
= vdprintf(fd
, format
, ap
);
775 #ifndef HAVE_GET_CURRENT_DIR_NAME
776 char *rep_get_current_dir_name(void)
778 char buf
[PATH_MAX
+1];
780 p
= getcwd(buf
, sizeof(buf
));
788 #if !defined(HAVE_STRERROR_R) || !defined(STRERROR_R_PROTO_COMPATIBLE)
789 int rep_strerror_r(int errnum
, char *buf
, size_t buflen
)
791 char *s
= strerror(errnum
);
792 if (strlen(s
)+1 > buflen
) {
796 strncpy(buf
, s
, buflen
);
801 #ifndef HAVE_CLOCK_GETTIME
802 int rep_clock_gettime(clockid_t clk_id
, struct timespec
*tp
)
806 case 0: /* CLOCK_REALTIME :*/
807 #ifdef HAVE_GETTIMEOFDAY_TZ
808 gettimeofday(&tval
,NULL
);
812 tp
->tv_sec
= tval
.tv_sec
;
813 tp
->tv_nsec
= tval
.tv_usec
* 1000;
823 #ifndef HAVE_MEMALIGN
824 void *rep_memalign( size_t align
, size_t size
)
826 #if defined(HAVE_POSIX_MEMALIGN)
828 int ret
= posix_memalign( &p
, align
, size
);
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();
841 size_t pagesize
= (size_t)-1;
843 if (pagesize
== (size_t)-1) {
847 if (size
< pagesize
) {
855 #ifndef HAVE_GETPEEREID
856 int rep_getpeereid(int s
, uid_t
*uid
, gid_t
*gid
)
858 #if defined(HAVE_PEERCRED)
860 socklen_t cred_len
= sizeof(struct ucred
);
864 ret
= getsockopt(s
, SOL_SOCKET
, SO_PEERCRED
, (void *)&cred
, &cred_len
);
869 if (cred_len
!= sizeof(struct ucred
)) {
885 int rep_usleep(useconds_t sec
)
889 * Fake it with select...
892 tval
.tv_usec
= usecs
/1000;
893 select(0,NULL
,NULL
,NULL
,&tval
);
896 #endif /* HAVE_USLEEP */