Fix more POSIX path lstat calls. Fix bug where close can return
[Samba.git] / source / lib / replace / replace.c
blob98d799b07e8f3950fe30039da961c6944964c34f
1 /*
2 Unix SMB/CIFS implementation.
3 replacement routines for broken systems
4 Copyright (C) Andrew Tridgell 1992-1998
6 ** NOTE! The following LGPL license applies to the replace
7 ** library. This does NOT imply that all of Samba is released
8 ** under the LGPL
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 3 of the License, or (at your option) any later version.
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
20 You should have received a copy of the GNU Lesser General Public
21 License along with this library; if not, see <http://www.gnu.org/licenses/>.
24 #include "replace.h"
26 #include "system/filesys.h"
27 #include "system/time.h"
28 #include "system/passwd.h"
29 #include "system/syslog.h"
30 #include "system/locale.h"
31 #include "system/wait.h"
33 void replace_dummy(void);
34 void replace_dummy(void) {}
36 #ifndef HAVE_FTRUNCATE
37 /*******************************************************************
38 ftruncate for operating systems that don't have it
39 ********************************************************************/
40 int rep_ftruncate(int f, off_t l)
42 #ifdef HAVE_CHSIZE
43 return chsize(f,l);
44 #elif defined(F_FREESP)
45 struct flock fl;
47 fl.l_whence = 0;
48 fl.l_len = 0;
49 fl.l_start = l;
50 fl.l_type = F_WRLCK;
51 return fcntl(f, F_FREESP, &fl);
52 #else
53 #error "you must have a ftruncate function"
54 #endif
56 #endif /* HAVE_FTRUNCATE */
59 #ifndef HAVE_STRLCPY
60 /* like strncpy but does not 0 fill the buffer and always null
61 terminates. bufsize is the size of the destination buffer */
62 size_t rep_strlcpy(char *d, const char *s, size_t bufsize)
64 size_t len = strlen(s);
65 size_t ret = len;
66 if (bufsize <= 0) return 0;
67 if (len >= bufsize) len = bufsize-1;
68 memcpy(d, s, len);
69 d[len] = 0;
70 return ret;
72 #endif
74 #ifndef HAVE_STRLCAT
75 /* like strncat but does not 0 fill the buffer and always null
76 terminates. bufsize is the length of the buffer, which should
77 be one more than the maximum resulting string length */
78 size_t rep_strlcat(char *d, const char *s, size_t bufsize)
80 size_t len1 = strlen(d);
81 size_t len2 = strlen(s);
82 size_t ret = len1 + len2;
84 if (len1+len2 >= bufsize) {
85 if (bufsize < (len1+1)) {
86 return ret;
88 len2 = bufsize - (len1+1);
90 if (len2 > 0) {
91 memcpy(d+len1, s, len2);
92 d[len1+len2] = 0;
94 return ret;
96 #endif
98 #ifndef HAVE_MKTIME
99 /*******************************************************************
100 a mktime() replacement for those who don't have it - contributed by
101 C.A. Lademann <cal@zls.com>
102 Corrections by richard.kettlewell@kewill.com
103 ********************************************************************/
105 #define MINUTE 60
106 #define HOUR 60*MINUTE
107 #define DAY 24*HOUR
108 #define YEAR 365*DAY
109 time_t rep_mktime(struct tm *t)
111 struct tm *u;
112 time_t epoch = 0;
113 int n;
114 int mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
115 y, m, i;
117 if(t->tm_year < 70)
118 return((time_t)-1);
120 n = t->tm_year + 1900 - 1;
121 epoch = (t->tm_year - 70) * YEAR +
122 ((n / 4 - n / 100 + n / 400) - (1969 / 4 - 1969 / 100 + 1969 / 400)) * DAY;
124 y = t->tm_year + 1900;
125 m = 0;
127 for(i = 0; i < t->tm_mon; i++) {
128 epoch += mon [m] * DAY;
129 if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
130 epoch += DAY;
132 if(++m > 11) {
133 m = 0;
134 y++;
138 epoch += (t->tm_mday - 1) * DAY;
139 epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec;
141 if((u = localtime(&epoch)) != NULL) {
142 t->tm_sec = u->tm_sec;
143 t->tm_min = u->tm_min;
144 t->tm_hour = u->tm_hour;
145 t->tm_mday = u->tm_mday;
146 t->tm_mon = u->tm_mon;
147 t->tm_year = u->tm_year;
148 t->tm_wday = u->tm_wday;
149 t->tm_yday = u->tm_yday;
150 t->tm_isdst = u->tm_isdst;
153 return(epoch);
155 #endif /* !HAVE_MKTIME */
158 #ifndef HAVE_INITGROUPS
159 /****************************************************************************
160 some systems don't have an initgroups call
161 ****************************************************************************/
162 int rep_initgroups(char *name, gid_t id)
164 #ifndef HAVE_SETGROUPS
165 /* yikes! no SETGROUPS or INITGROUPS? how can this work? */
166 errno = ENOSYS;
167 return -1;
168 #else /* HAVE_SETGROUPS */
170 #include <grp.h>
172 gid_t *grouplst = NULL;
173 int max_gr = NGROUPS_MAX;
174 int ret;
175 int i,j;
176 struct group *g;
177 char *gr;
179 if((grouplst = malloc(sizeof(gid_t) * max_gr)) == NULL) {
180 errno = ENOMEM;
181 return -1;
184 grouplst[0] = id;
185 i = 1;
186 while (i < max_gr && ((g = (struct group *)getgrent()) != (struct group *)NULL)) {
187 if (g->gr_gid == id)
188 continue;
189 j = 0;
190 gr = g->gr_mem[0];
191 while (gr && (*gr != (char)NULL)) {
192 if (strcmp(name,gr) == 0) {
193 grouplst[i] = g->gr_gid;
194 i++;
195 gr = (char *)NULL;
196 break;
198 gr = g->gr_mem[++j];
201 endgrent();
202 ret = setgroups(i, grouplst);
203 free(grouplst);
204 return ret;
205 #endif /* HAVE_SETGROUPS */
207 #endif /* HAVE_INITGROUPS */
210 #if (defined(SecureWare) && defined(SCO))
211 /* This is needed due to needing the nap() function but we don't want
212 to include the Xenix libraries since that will break other things...
213 BTW: system call # 0x0c28 is the same as calling nap() */
214 long nap(long milliseconds) {
215 return syscall(0x0c28, milliseconds);
217 #endif
220 #ifndef HAVE_MEMMOVE
221 /*******************************************************************
222 safely copies memory, ensuring no overlap problems.
223 this is only used if the machine does not have its own memmove().
224 this is not the fastest algorithm in town, but it will do for our
225 needs.
226 ********************************************************************/
227 void *rep_memmove(void *dest,const void *src,int size)
229 unsigned long d,s;
230 int i;
231 if (dest==src || !size) return(dest);
233 d = (unsigned long)dest;
234 s = (unsigned long)src;
236 if ((d >= (s+size)) || (s >= (d+size))) {
237 /* no overlap */
238 memcpy(dest,src,size);
239 return(dest);
242 if (d < s) {
243 /* we can forward copy */
244 if (s-d >= sizeof(int) &&
245 !(s%sizeof(int)) &&
246 !(d%sizeof(int)) &&
247 !(size%sizeof(int))) {
248 /* do it all as words */
249 int *idest = (int *)dest;
250 int *isrc = (int *)src;
251 size /= sizeof(int);
252 for (i=0;i<size;i++) idest[i] = isrc[i];
253 } else {
254 /* simplest */
255 char *cdest = (char *)dest;
256 char *csrc = (char *)src;
257 for (i=0;i<size;i++) cdest[i] = csrc[i];
259 } else {
260 /* must backward copy */
261 if (d-s >= sizeof(int) &&
262 !(s%sizeof(int)) &&
263 !(d%sizeof(int)) &&
264 !(size%sizeof(int))) {
265 /* do it all as words */
266 int *idest = (int *)dest;
267 int *isrc = (int *)src;
268 size /= sizeof(int);
269 for (i=size-1;i>=0;i--) idest[i] = isrc[i];
270 } else {
271 /* simplest */
272 char *cdest = (char *)dest;
273 char *csrc = (char *)src;
274 for (i=size-1;i>=0;i--) cdest[i] = csrc[i];
277 return(dest);
279 #endif /* HAVE_MEMMOVE */
281 #ifndef HAVE_STRDUP
282 /****************************************************************************
283 duplicate a string
284 ****************************************************************************/
285 char *rep_strdup(const char *s)
287 size_t len;
288 char *ret;
290 if (!s) return(NULL);
292 len = strlen(s)+1;
293 ret = (char *)malloc(len);
294 if (!ret) return(NULL);
295 memcpy(ret,s,len);
296 return(ret);
298 #endif /* HAVE_STRDUP */
300 #ifndef HAVE_SETLINEBUF
301 void rep_setlinebuf(FILE *stream)
303 setvbuf(stream, (char *)NULL, _IOLBF, 0);
305 #endif /* HAVE_SETLINEBUF */
307 #ifndef HAVE_VSYSLOG
308 #ifdef HAVE_SYSLOG
309 void rep_vsyslog (int facility_priority, const char *format, va_list arglist)
311 char *msg = NULL;
312 vasprintf(&msg, format, arglist);
313 if (!msg)
314 return;
315 syslog(facility_priority, "%s", msg);
316 free(msg);
318 #endif /* HAVE_SYSLOG */
319 #endif /* HAVE_VSYSLOG */
321 #ifndef HAVE_STRNLEN
323 Some platforms don't have strnlen
325 size_t rep_strnlen(const char *s, size_t max)
327 size_t len;
329 for (len = 0; len < max; len++) {
330 if (s[len] == '\0') {
331 break;
334 return len;
336 #endif
338 #ifndef HAVE_STRNDUP
340 Some platforms don't have strndup.
342 char *rep_strndup(const char *s, size_t n)
344 char *ret;
346 n = strnlen(s, n);
347 ret = malloc(n+1);
348 if (!ret)
349 return NULL;
350 memcpy(ret, s, n);
351 ret[n] = 0;
353 return ret;
355 #endif
357 #ifndef HAVE_WAITPID
358 int rep_waitpid(pid_t pid,int *status,int options)
360 return wait4(pid, status, options, NULL);
362 #endif
364 #ifndef HAVE_SETEUID
365 int rep_seteuid(uid_t euid)
367 #ifdef HAVE_SETRESUID
368 return setresuid(-1, euid, -1);
369 #else
370 # error "You need a seteuid function"
371 #endif
373 #endif
375 #ifndef HAVE_SETEGID
376 int rep_setegid(gid_t egid)
378 #ifdef HAVE_SETRESGID
379 return setresgid(-1, egid, -1);
380 #else
381 # error "You need a setegid function"
382 #endif
384 #endif
386 /*******************************************************************
387 os/2 also doesn't have chroot
388 ********************************************************************/
389 #ifndef HAVE_CHROOT
390 int rep_chroot(const char *dname)
392 errno = ENOSYS;
393 return -1;
395 #endif
397 /*****************************************************************
398 Possibly replace mkstemp if it is broken.
399 *****************************************************************/
401 #ifndef HAVE_SECURE_MKSTEMP
402 int rep_mkstemp(char *template)
404 /* have a reasonable go at emulating it. Hope that
405 the system mktemp() isn't completly hopeless */
406 char *p = mktemp(template);
407 if (!p)
408 return -1;
409 return open(p, O_CREAT|O_EXCL|O_RDWR, 0600);
411 #endif
413 #ifndef HAVE_MKDTEMP
414 char *rep_mkdtemp(char *template)
416 char *dname;
418 if ((dname = mktemp(template))) {
419 if (mkdir(dname, 0700) >= 0) {
420 return dname;
424 return NULL;
426 #endif
428 /*****************************************************************
429 Watch out: this is not thread safe.
430 *****************************************************************/
432 #ifndef HAVE_PREAD
433 ssize_t rep_pread(int __fd, void *__buf, size_t __nbytes, off_t __offset)
435 if (lseek(__fd, __offset, SEEK_SET) != __offset) {
436 return -1;
438 return read(__fd, __buf, __nbytes);
440 #endif
442 /*****************************************************************
443 Watch out: this is not thread safe.
444 *****************************************************************/
446 #ifndef HAVE_PWRITE
447 ssize_t rep_pwrite(int __fd, const void *__buf, size_t __nbytes, off_t __offset)
449 if (lseek(__fd, __offset, SEEK_SET) != __offset) {
450 return -1;
452 return write(__fd, __buf, __nbytes);
454 #endif
456 #ifndef HAVE_STRCASESTR
457 char *rep_strcasestr(const char *haystack, const char *needle)
459 const char *s;
460 size_t nlen = strlen(needle);
461 for (s=haystack;*s;s++) {
462 if (toupper(*needle) == toupper(*s) &&
463 strncasecmp(s, needle, nlen) == 0) {
464 return (char *)((uintptr_t)s);
467 return NULL;
469 #endif
471 #ifndef HAVE_STRTOK_R
472 /* based on GLIBC version, copyright Free Software Foundation */
473 char *rep_strtok_r(char *s, const char *delim, char **save_ptr)
475 char *token;
477 if (s == NULL) s = *save_ptr;
479 s += strspn(s, delim);
480 if (*s == '\0') {
481 *save_ptr = s;
482 return NULL;
485 token = s;
486 s = strpbrk(token, delim);
487 if (s == NULL) {
488 *save_ptr = token + strlen(token);
489 } else {
490 *s = '\0';
491 *save_ptr = s + 1;
494 return token;
496 #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 #endif
514 #ifndef HAVE_STRTOULL
515 unsigned long long int rep_strtoull(const char *str, char **endptr, int base)
517 #ifdef HAVE_STRTOUQ
518 return strtouq(str, endptr, base);
519 #elif defined(HAVE___STRTOULL)
520 return __strtoull(str, endptr, base);
521 #elif SIZEOF_LONG == SIZEOF_LONG_LONG
522 return (unsigned long long int) strtoul(str, endptr, base);
523 #else
524 # error "You need a strtoull function"
525 #endif
527 #endif
529 #ifndef HAVE_SETENV
530 int rep_setenv(const char *name, const char *value, int overwrite)
532 char *p;
533 size_t l1, l2;
534 int ret;
536 if (!overwrite && getenv(name)) {
537 return 0;
540 l1 = strlen(name);
541 l2 = strlen(value);
543 p = malloc(l1+l2+2);
544 if (p == NULL) {
545 return -1;
547 memcpy(p, name, l1);
548 p[l1] = '=';
549 memcpy(p+l1+1, value, l2);
550 p[l1+l2+1] = 0;
552 ret = putenv(p);
553 if (ret != 0) {
554 free(p);
557 return ret;
559 #endif
561 #ifndef HAVE_UNSETENV
562 int rep_unsetenv(const char *name)
564 extern char **environ;
565 size_t len = strlen(name);
566 size_t i, count;
568 if (environ == NULL || getenv(name) == NULL) {
569 return 0;
572 for (i=0;environ[i];i++) /* noop */ ;
574 count=i;
576 for (i=0;i<count;) {
577 if (strncmp(environ[i], name, len) == 0 && environ[i][len] == '=') {
578 /* note: we do _not_ free the old variable here. It is unsafe to
579 do so, as the pointer may not have come from malloc */
580 memmove(&environ[i], &environ[i+1], (count-i)*sizeof(char *));
581 count--;
582 } else {
583 i++;
587 return 0;
589 #endif
591 #ifndef HAVE_UTIME
592 int rep_utime(const char *filename, const struct utimbuf *buf)
594 errno = ENOSYS;
595 return -1;
597 #endif
599 #ifndef HAVE_UTIMES
600 int rep_utimes(const char *filename, const struct timeval tv[2])
602 struct utimbuf u;
604 u.actime = tv[0].tv_sec;
605 if (tv[0].tv_usec > 500000) {
606 u.actime += 1;
609 u.modtime = tv[1].tv_sec;
610 if (tv[1].tv_usec > 500000) {
611 u.modtime += 1;
614 return utime(filename, &u);
616 #endif