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 */
217 #if (defined(SecureWare) && defined(SCO))
218 /* This is needed due to needing the nap() function but we don't want
219 to include the Xenix libraries since that will break other things...
220 BTW: system call # 0x0c28 is the same as calling nap() */
221 long nap(long milliseconds
) {
222 return syscall(0x0c28, milliseconds
);
228 /*******************************************************************
229 safely copies memory, ensuring no overlap problems.
230 this is only used if the machine does not have its own memmove().
231 this is not the fastest algorithm in town, but it will do for our
233 ********************************************************************/
234 void *rep_memmove(void *dest
,const void *src
,int size
)
238 if (dest
==src
|| !size
) return(dest
);
240 d
= (unsigned long)dest
;
241 s
= (unsigned long)src
;
243 if ((d
>= (s
+size
)) || (s
>= (d
+size
))) {
245 memcpy(dest
,src
,size
);
250 /* we can forward copy */
251 if (s
-d
>= sizeof(int) &&
254 !(size
%sizeof(int))) {
255 /* do it all as words */
256 int *idest
= (int *)dest
;
257 int *isrc
= (int *)src
;
259 for (i
=0;i
<size
;i
++) idest
[i
] = isrc
[i
];
262 char *cdest
= (char *)dest
;
263 char *csrc
= (char *)src
;
264 for (i
=0;i
<size
;i
++) cdest
[i
] = csrc
[i
];
267 /* must backward copy */
268 if (d
-s
>= sizeof(int) &&
271 !(size
%sizeof(int))) {
272 /* do it all as words */
273 int *idest
= (int *)dest
;
274 int *isrc
= (int *)src
;
276 for (i
=size
-1;i
>=0;i
--) idest
[i
] = isrc
[i
];
279 char *cdest
= (char *)dest
;
280 char *csrc
= (char *)src
;
281 for (i
=size
-1;i
>=0;i
--) cdest
[i
] = csrc
[i
];
286 #endif /* HAVE_MEMMOVE */
289 /****************************************************************************
291 ****************************************************************************/
292 char *rep_strdup(const char *s
)
297 if (!s
) return(NULL
);
300 ret
= (char *)malloc(len
);
301 if (!ret
) return(NULL
);
305 #endif /* HAVE_STRDUP */
307 #ifndef HAVE_SETLINEBUF
308 void rep_setlinebuf(FILE *stream
)
310 setvbuf(stream
, (char *)NULL
, _IOLBF
, 0);
312 #endif /* HAVE_SETLINEBUF */
316 void rep_vsyslog (int facility_priority
, const char *format
, va_list arglist
)
319 vasprintf(&msg
, format
, arglist
);
322 syslog(facility_priority
, "%s", msg
);
325 #endif /* HAVE_SYSLOG */
326 #endif /* HAVE_VSYSLOG */
330 Some platforms don't have strnlen
332 size_t rep_strnlen(const char *s
, size_t max
)
336 for (len
= 0; len
< max
; len
++) {
337 if (s
[len
] == '\0') {
347 Some platforms don't have strndup.
349 char *rep_strndup(const char *s
, size_t n
)
364 #if !defined(HAVE_WAITPID) && defined(HAVE_WAIT4)
365 int rep_waitpid(pid_t pid
,int *status
,int options
)
367 return wait4(pid
, status
, options
, NULL
);
372 int rep_seteuid(uid_t euid
)
374 #ifdef HAVE_SETRESUID
375 return setresuid(-1, euid
, -1);
384 int rep_setegid(gid_t egid
)
386 #ifdef HAVE_SETRESGID
387 return setresgid(-1, egid
, -1);
395 /*******************************************************************
396 os/2 also doesn't have chroot
397 ********************************************************************/
399 int rep_chroot(const char *dname
)
406 /*****************************************************************
407 Possibly replace mkstemp if it is broken.
408 *****************************************************************/
410 #ifndef HAVE_SECURE_MKSTEMP
411 int rep_mkstemp(char *template)
413 /* have a reasonable go at emulating it. Hope that
414 the system mktemp() isn't completely hopeless */
416 if (template[0] == 0)
418 return open(p
, O_CREAT
|O_EXCL
|O_RDWR
, 0600);
423 char *rep_mkdtemp(char *template)
427 if ((dname
= mktemp(template))) {
428 if (mkdir(dname
, 0700) >= 0) {
437 /*****************************************************************
438 Watch out: this is not thread safe.
439 *****************************************************************/
442 ssize_t
rep_pread(int __fd
, void *__buf
, size_t __nbytes
, off_t __offset
)
444 if (lseek(__fd
, __offset
, SEEK_SET
) != __offset
) {
447 return read(__fd
, __buf
, __nbytes
);
451 /*****************************************************************
452 Watch out: this is not thread safe.
453 *****************************************************************/
456 ssize_t
rep_pwrite(int __fd
, const void *__buf
, size_t __nbytes
, off_t __offset
)
458 if (lseek(__fd
, __offset
, SEEK_SET
) != __offset
) {
461 return write(__fd
, __buf
, __nbytes
);
465 #ifndef HAVE_STRCASESTR
466 char *rep_strcasestr(const char *haystack
, const char *needle
)
469 size_t nlen
= strlen(needle
);
470 for (s
=haystack
;*s
;s
++) {
471 if (toupper(*needle
) == toupper(*s
) &&
472 strncasecmp(s
, needle
, nlen
) == 0) {
473 return (char *)((uintptr_t)s
);
480 #ifndef HAVE_STRTOK_R
481 /* based on GLIBC version, copyright Free Software Foundation */
482 char *rep_strtok_r(char *s
, const char *delim
, char **save_ptr
)
486 if (s
== NULL
) s
= *save_ptr
;
488 s
+= strspn(s
, delim
);
495 s
= strpbrk(token
, delim
);
497 *save_ptr
= token
+ strlen(token
);
509 long long int rep_strtoll(const char *str
, char **endptr
, int base
)
512 return strtoq(str
, endptr
, base
);
513 #elif defined(HAVE___STRTOLL)
514 return __strtoll(str
, endptr
, base
);
515 #elif SIZEOF_LONG == SIZEOF_LONG_LONG
516 return (long long int) strtol(str
, endptr
, base
);
518 # error "You need a strtoll function"
522 #ifdef HAVE_BSD_STRTOLL
524 long long int rep_strtoll(const char *str
, char **endptr
, int base
)
526 long long int nb
= strtoq(str
, endptr
, base
);
527 /* In linux EINVAL is only returned if base is not ok */
528 if (errno
== EINVAL
) {
529 if (base
== 0 || (base
>1 && base
<37)) {
530 /* Base was ok so it's because we were not
531 * able to make the convertion.
540 #error "You need the strtoq function"
541 #endif /* HAVE_STRTOQ */
542 #endif /* HAVE_BSD_STRTOLL */
543 #endif /* HAVE_STRTOLL */
546 #ifndef HAVE_STRTOULL
547 unsigned long long int rep_strtoull(const char *str
, char **endptr
, int base
)
550 return strtouq(str
, endptr
, base
);
551 #elif defined(HAVE___STRTOULL)
552 return __strtoull(str
, endptr
, base
);
553 #elif SIZEOF_LONG == SIZEOF_LONG_LONG
554 return (unsigned long long int) strtoul(str
, endptr
, base
);
556 # error "You need a strtoull function"
560 #ifdef HAVE_BSD_STRTOLL
562 unsigned long long int rep_strtoull(const char *str
, char **endptr
, int base
)
564 unsigned long long int nb
= strtouq(str
, endptr
, base
);
565 /* In linux EINVAL is only returned if base is not ok */
566 if (errno
== EINVAL
) {
567 if (base
== 0 || (base
>1 && base
<37)) {
568 /* Base was ok so it's because we were not
569 * able to make the convertion.
578 #error "You need the strtouq function"
579 #endif /* HAVE_STRTOUQ */
580 #endif /* HAVE_BSD_STRTOLL */
581 #endif /* HAVE_STRTOULL */
584 int rep_setenv(const char *name
, const char *value
, int overwrite
)
590 if (!overwrite
&& getenv(name
)) {
603 memcpy(p
+l1
+1, value
, l2
);
615 #ifndef HAVE_UNSETENV
616 int rep_unsetenv(const char *name
)
618 extern char **environ
;
619 size_t len
= strlen(name
);
622 if (environ
== NULL
|| getenv(name
) == NULL
) {
626 for (i
=0;environ
[i
];i
++) /* noop */ ;
631 if (strncmp(environ
[i
], name
, len
) == 0 && environ
[i
][len
] == '=') {
632 /* note: we do _not_ free the old variable here. It is unsafe to
633 do so, as the pointer may not have come from malloc */
634 memmove(&environ
[i
], &environ
[i
+1], (count
-i
)*sizeof(char *));
646 int rep_utime(const char *filename
, const struct utimbuf
*buf
)
654 int rep_utimes(const char *filename
, const struct timeval tv
[2])
658 u
.actime
= tv
[0].tv_sec
;
659 if (tv
[0].tv_usec
> 500000) {
663 u
.modtime
= tv
[1].tv_sec
;
664 if (tv
[1].tv_usec
> 500000) {
668 return utime(filename
, &u
);
673 int rep_dup2(int oldfd
, int newfd
)
682 chown isn't used much but OS/2 doesn't have it
684 int rep_chown(const char *fname
, uid_t uid
, gid_t gid
)
692 int rep_link(const char *oldpath
, const char *newpath
)
699 #ifndef HAVE_READLINK
700 int rep_readlink(const char *path
, char *buf
, size_t bufsiz
)
708 int rep_symlink(const char *oldpath
, const char *newpath
)
716 int rep_lchown(const char *fname
,uid_t uid
,gid_t gid
)
723 #ifndef HAVE_REALPATH
724 char *rep_realpath(const char *path
, char *resolved_path
)
726 /* As realpath is not a system call we can't return ENOSYS. */
734 void *rep_memmem(const void *haystack
, size_t haystacklen
,
735 const void *needle
, size_t needlelen
)
737 if (needlelen
== 0) {
738 return discard_const(haystack
);
740 while (haystacklen
>= needlelen
) {
741 char *p
= (char *)memchr(haystack
, *(const char *)needle
,
742 haystacklen
-(needlelen
-1));
744 if (memcmp(p
, needle
, needlelen
) == 0) {
748 haystacklen
-= (p
- (const char *)haystack
) + 1;
754 #ifndef HAVE_VDPRINTF
755 int rep_vdprintf(int fd
, const char *format
, va_list ap
)
760 vasprintf(&s
, format
, ap
);
765 ret
= write(fd
, s
, strlen(s
));
772 int rep_dprintf(int fd
, const char *format
, ...)
777 va_start(ap
, format
);
778 ret
= vdprintf(fd
, format
, ap
);
785 #ifndef HAVE_GET_CURRENT_DIR_NAME
786 char *rep_get_current_dir_name(void)
788 char buf
[PATH_MAX
+1];
790 p
= getcwd(buf
, sizeof(buf
));
798 #if !defined(HAVE_STRERROR_R) || !defined(STRERROR_R_PROTO_COMPATIBLE)
799 int rep_strerror_r(int errnum
, char *buf
, size_t buflen
)
801 char *s
= strerror(errnum
);
802 if (strlen(s
)+1 > buflen
) {
806 strncpy(buf
, s
, buflen
);
811 #ifndef HAVE_CLOCK_GETTIME
812 int rep_clock_gettime(clockid_t clk_id
, struct timespec
*tp
)
816 case 0: /* CLOCK_REALTIME :*/
817 #ifdef HAVE_GETTIMEOFDAY_TZ
818 gettimeofday(&tval
,NULL
);
822 tp
->tv_sec
= tval
.tv_sec
;
823 tp
->tv_nsec
= tval
.tv_usec
* 1000;
833 #ifndef HAVE_MEMALIGN
834 void *rep_memalign( size_t align
, size_t size
)
836 #if defined(HAVE_POSIX_MEMALIGN)
838 int ret
= posix_memalign( &p
, align
, size
);
844 /* On *BSD systems memaligns doesn't exist, but memory will
845 * be aligned on allocations of > pagesize. */
846 #if defined(SYSCONF_SC_PAGESIZE)
847 size_t pagesize
= (size_t)sysconf(_SC_PAGESIZE
);
848 #elif defined(HAVE_GETPAGESIZE)
849 size_t pagesize
= (size_t)getpagesize();
851 size_t pagesize
= (size_t)-1;
853 if (pagesize
== (size_t)-1) {
857 if (size
< pagesize
) {
865 #ifndef HAVE_GETPEEREID
866 int rep_getpeereid(int s
, uid_t
*uid
, gid_t
*gid
)
868 #if defined(HAVE_PEERCRED)
870 socklen_t cred_len
= sizeof(struct ucred
);
874 ret
= getsockopt(s
, SOL_SOCKET
, SO_PEERCRED
, (void *)&cred
, &cred_len
);
879 if (cred_len
!= sizeof(struct ucred
)) {
895 int rep_usleep(useconds_t sec
)
899 * Fake it with select...
902 tval
.tv_usec
= usecs
/1000;
903 select(0,NULL
,NULL
,NULL
,&tval
);
906 #endif /* HAVE_USLEEP */