Fix bug #5980 - Race condition when granting level2 oplocks can cause break notify...
[Samba/gbeck.git] / lib / replace / replace.c
blob78c688d50c72ef8d621e5b0a1bc36f3f0119fd1e
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
7 ** NOTE! The following LGPL license applies to the replace
8 ** library. This does NOT imply that all of Samba is released
9 ** under the LGPL
11 This library is free software; you can redistribute it and/or
12 modify it under the terms of the GNU Lesser General Public
13 License as published by the Free Software Foundation; either
14 version 3 of the License, or (at your option) any later version.
16 This library is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 Lesser General Public License for more details.
21 You should have received a copy of the GNU Lesser General Public
22 License along with this library; if not, see <http://www.gnu.org/licenses/>.
25 #include "replace.h"
27 #include "system/filesys.h"
28 #include "system/time.h"
29 #include "system/passwd.h"
30 #include "system/syslog.h"
31 #include "system/locale.h"
32 #include "system/wait.h"
34 void replace_dummy(void);
35 void replace_dummy(void) {}
37 #ifndef HAVE_FTRUNCATE
38 /*******************************************************************
39 ftruncate for operating systems that don't have it
40 ********************************************************************/
41 int rep_ftruncate(int f, off_t l)
43 #ifdef HAVE_CHSIZE
44 return chsize(f,l);
45 #elif defined(F_FREESP)
46 struct flock fl;
48 fl.l_whence = 0;
49 fl.l_len = 0;
50 fl.l_start = l;
51 fl.l_type = F_WRLCK;
52 return fcntl(f, F_FREESP, &fl);
53 #else
54 #error "you must have a ftruncate function"
55 #endif
57 #endif /* HAVE_FTRUNCATE */
60 #ifndef HAVE_STRLCPY
61 /* like strncpy but does not 0 fill the buffer and always null
62 terminates. bufsize is the size of the destination buffer */
63 size_t rep_strlcpy(char *d, const char *s, size_t bufsize)
65 size_t len = strlen(s);
66 size_t ret = len;
67 if (bufsize <= 0) return 0;
68 if (len >= bufsize) len = bufsize-1;
69 memcpy(d, s, len);
70 d[len] = 0;
71 return ret;
73 #endif
75 #ifndef HAVE_STRLCAT
76 /* like strncat but does not 0 fill the buffer and always null
77 terminates. bufsize is the length of the buffer, which should
78 be one more than the maximum resulting string length */
79 size_t rep_strlcat(char *d, const char *s, size_t bufsize)
81 size_t len1 = strlen(d);
82 size_t len2 = strlen(s);
83 size_t ret = len1 + len2;
85 if (len1+len2 >= bufsize) {
86 if (bufsize < (len1+1)) {
87 return ret;
89 len2 = bufsize - (len1+1);
91 if (len2 > 0) {
92 memcpy(d+len1, s, len2);
93 d[len1+len2] = 0;
95 return ret;
97 #endif
99 #ifndef HAVE_MKTIME
100 /*******************************************************************
101 a mktime() replacement for those who don't have it - contributed by
102 C.A. Lademann <cal@zls.com>
103 Corrections by richard.kettlewell@kewill.com
104 ********************************************************************/
106 #define MINUTE 60
107 #define HOUR 60*MINUTE
108 #define DAY 24*HOUR
109 #define YEAR 365*DAY
110 time_t rep_mktime(struct tm *t)
112 struct tm *u;
113 time_t epoch = 0;
114 int n;
115 int mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
116 y, m, i;
118 if(t->tm_year < 70)
119 return((time_t)-1);
121 n = t->tm_year + 1900 - 1;
122 epoch = (t->tm_year - 70) * YEAR +
123 ((n / 4 - n / 100 + n / 400) - (1969 / 4 - 1969 / 100 + 1969 / 400)) * DAY;
125 y = t->tm_year + 1900;
126 m = 0;
128 for(i = 0; i < t->tm_mon; i++) {
129 epoch += mon [m] * DAY;
130 if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
131 epoch += DAY;
133 if(++m > 11) {
134 m = 0;
135 y++;
139 epoch += (t->tm_mday - 1) * DAY;
140 epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec;
142 if((u = localtime(&epoch)) != NULL) {
143 t->tm_sec = u->tm_sec;
144 t->tm_min = u->tm_min;
145 t->tm_hour = u->tm_hour;
146 t->tm_mday = u->tm_mday;
147 t->tm_mon = u->tm_mon;
148 t->tm_year = u->tm_year;
149 t->tm_wday = u->tm_wday;
150 t->tm_yday = u->tm_yday;
151 t->tm_isdst = u->tm_isdst;
154 return(epoch);
156 #endif /* !HAVE_MKTIME */
159 #ifndef HAVE_INITGROUPS
160 /****************************************************************************
161 some systems don't have an initgroups call
162 ****************************************************************************/
163 int rep_initgroups(char *name, gid_t id)
165 #ifndef HAVE_SETGROUPS
166 /* yikes! no SETGROUPS or INITGROUPS? how can this work? */
167 errno = ENOSYS;
168 return -1;
169 #else /* HAVE_SETGROUPS */
171 #include <grp.h>
173 gid_t *grouplst = NULL;
174 int max_gr = NGROUPS_MAX;
175 int ret;
176 int i,j;
177 struct group *g;
178 char *gr;
180 if((grouplst = malloc(sizeof(gid_t) * max_gr)) == NULL) {
181 errno = ENOMEM;
182 return -1;
185 grouplst[0] = id;
186 i = 1;
187 while (i < max_gr && ((g = (struct group *)getgrent()) != (struct group *)NULL)) {
188 if (g->gr_gid == id)
189 continue;
190 j = 0;
191 gr = g->gr_mem[0];
192 while (gr && (*gr != (char)NULL)) {
193 if (strcmp(name,gr) == 0) {
194 grouplst[i] = g->gr_gid;
195 i++;
196 gr = (char *)NULL;
197 break;
199 gr = g->gr_mem[++j];
202 endgrent();
203 ret = setgroups(i, grouplst);
204 free(grouplst);
205 return ret;
206 #endif /* HAVE_SETGROUPS */
208 #endif /* HAVE_INITGROUPS */
211 #if (defined(SecureWare) && defined(SCO))
212 /* This is needed due to needing the nap() function but we don't want
213 to include the Xenix libraries since that will break other things...
214 BTW: system call # 0x0c28 is the same as calling nap() */
215 long nap(long milliseconds) {
216 return syscall(0x0c28, milliseconds);
218 #endif
221 #ifndef HAVE_MEMMOVE
222 /*******************************************************************
223 safely copies memory, ensuring no overlap problems.
224 this is only used if the machine does not have its own memmove().
225 this is not the fastest algorithm in town, but it will do for our
226 needs.
227 ********************************************************************/
228 void *rep_memmove(void *dest,const void *src,int size)
230 unsigned long d,s;
231 int i;
232 if (dest==src || !size) return(dest);
234 d = (unsigned long)dest;
235 s = (unsigned long)src;
237 if ((d >= (s+size)) || (s >= (d+size))) {
238 /* no overlap */
239 memcpy(dest,src,size);
240 return(dest);
243 if (d < s) {
244 /* we can forward copy */
245 if (s-d >= sizeof(int) &&
246 !(s%sizeof(int)) &&
247 !(d%sizeof(int)) &&
248 !(size%sizeof(int))) {
249 /* do it all as words */
250 int *idest = (int *)dest;
251 int *isrc = (int *)src;
252 size /= sizeof(int);
253 for (i=0;i<size;i++) idest[i] = isrc[i];
254 } else {
255 /* simplest */
256 char *cdest = (char *)dest;
257 char *csrc = (char *)src;
258 for (i=0;i<size;i++) cdest[i] = csrc[i];
260 } else {
261 /* must backward copy */
262 if (d-s >= sizeof(int) &&
263 !(s%sizeof(int)) &&
264 !(d%sizeof(int)) &&
265 !(size%sizeof(int))) {
266 /* do it all as words */
267 int *idest = (int *)dest;
268 int *isrc = (int *)src;
269 size /= sizeof(int);
270 for (i=size-1;i>=0;i--) idest[i] = isrc[i];
271 } else {
272 /* simplest */
273 char *cdest = (char *)dest;
274 char *csrc = (char *)src;
275 for (i=size-1;i>=0;i--) cdest[i] = csrc[i];
278 return(dest);
280 #endif /* HAVE_MEMMOVE */
282 #ifndef HAVE_STRDUP
283 /****************************************************************************
284 duplicate a string
285 ****************************************************************************/
286 char *rep_strdup(const char *s)
288 size_t len;
289 char *ret;
291 if (!s) return(NULL);
293 len = strlen(s)+1;
294 ret = (char *)malloc(len);
295 if (!ret) return(NULL);
296 memcpy(ret,s,len);
297 return(ret);
299 #endif /* HAVE_STRDUP */
301 #ifndef HAVE_SETLINEBUF
302 void rep_setlinebuf(FILE *stream)
304 setvbuf(stream, (char *)NULL, _IOLBF, 0);
306 #endif /* HAVE_SETLINEBUF */
308 #ifndef HAVE_VSYSLOG
309 #ifdef HAVE_SYSLOG
310 void rep_vsyslog (int facility_priority, const char *format, va_list arglist)
312 char *msg = NULL;
313 vasprintf(&msg, format, arglist);
314 if (!msg)
315 return;
316 syslog(facility_priority, "%s", msg);
317 free(msg);
319 #endif /* HAVE_SYSLOG */
320 #endif /* HAVE_VSYSLOG */
322 #ifndef HAVE_STRNLEN
324 Some platforms don't have strnlen
326 size_t rep_strnlen(const char *s, size_t max)
328 size_t len;
330 for (len = 0; len < max; len++) {
331 if (s[len] == '\0') {
332 break;
335 return len;
337 #endif
339 #ifndef HAVE_STRNDUP
341 Some platforms don't have strndup.
343 char *rep_strndup(const char *s, size_t n)
345 char *ret;
347 n = strnlen(s, n);
348 ret = malloc(n+1);
349 if (!ret)
350 return NULL;
351 memcpy(ret, s, n);
352 ret[n] = 0;
354 return ret;
356 #endif
358 #ifndef HAVE_WAITPID
359 int rep_waitpid(pid_t pid,int *status,int options)
361 return wait4(pid, status, options, NULL);
363 #endif
365 #ifndef HAVE_SETEUID
366 int rep_seteuid(uid_t euid)
368 #ifdef HAVE_SETRESUID
369 return setresuid(-1, euid, -1);
370 #else
371 # error "You need a seteuid function"
372 #endif
374 #endif
376 #ifndef HAVE_SETEGID
377 int rep_setegid(gid_t egid)
379 #ifdef HAVE_SETRESGID
380 return setresgid(-1, egid, -1);
381 #else
382 # error "You need a setegid function"
383 #endif
385 #endif
387 /*******************************************************************
388 os/2 also doesn't have chroot
389 ********************************************************************/
390 #ifndef HAVE_CHROOT
391 int rep_chroot(const char *dname)
393 errno = ENOSYS;
394 return -1;
396 #endif
398 /*****************************************************************
399 Possibly replace mkstemp if it is broken.
400 *****************************************************************/
402 #ifndef HAVE_SECURE_MKSTEMP
403 int rep_mkstemp(char *template)
405 /* have a reasonable go at emulating it. Hope that
406 the system mktemp() isn't completly hopeless */
407 char *p = mktemp(template);
408 if (!p)
409 return -1;
410 return open(p, O_CREAT|O_EXCL|O_RDWR, 0600);
412 #endif
414 #ifndef HAVE_MKDTEMP
415 char *rep_mkdtemp(char *template)
417 char *dname;
419 if ((dname = mktemp(template))) {
420 if (mkdir(dname, 0700) >= 0) {
421 return dname;
425 return NULL;
427 #endif
429 /*****************************************************************
430 Watch out: this is not thread safe.
431 *****************************************************************/
433 #ifndef HAVE_PREAD
434 ssize_t rep_pread(int __fd, void *__buf, size_t __nbytes, off_t __offset)
436 if (lseek(__fd, __offset, SEEK_SET) != __offset) {
437 return -1;
439 return read(__fd, __buf, __nbytes);
441 #endif
443 /*****************************************************************
444 Watch out: this is not thread safe.
445 *****************************************************************/
447 #ifndef HAVE_PWRITE
448 ssize_t rep_pwrite(int __fd, const void *__buf, size_t __nbytes, off_t __offset)
450 if (lseek(__fd, __offset, SEEK_SET) != __offset) {
451 return -1;
453 return write(__fd, __buf, __nbytes);
455 #endif
457 #ifndef HAVE_STRCASESTR
458 char *rep_strcasestr(const char *haystack, const char *needle)
460 const char *s;
461 size_t nlen = strlen(needle);
462 for (s=haystack;*s;s++) {
463 if (toupper(*needle) == toupper(*s) &&
464 strncasecmp(s, needle, nlen) == 0) {
465 return (char *)((uintptr_t)s);
468 return NULL;
470 #endif
472 #ifndef HAVE_STRTOK_R
473 /* based on GLIBC version, copyright Free Software Foundation */
474 char *rep_strtok_r(char *s, const char *delim, char **save_ptr)
476 char *token;
478 if (s == NULL) s = *save_ptr;
480 s += strspn(s, delim);
481 if (*s == '\0') {
482 *save_ptr = s;
483 return NULL;
486 token = s;
487 s = strpbrk(token, delim);
488 if (s == NULL) {
489 *save_ptr = token + strlen(token);
490 } else {
491 *s = '\0';
492 *save_ptr = s + 1;
495 return token;
497 #endif
499 #ifndef HAVE_STRTOLL
500 long long int rep_strtoll(const char *str, char **endptr, int base)
502 #ifdef HAVE_STRTOQ
503 return strtoq(str, endptr, base);
504 #elif defined(HAVE___STRTOLL)
505 return __strtoll(str, endptr, base);
506 #elif SIZEOF_LONG == SIZEOF_LONG_LONG
507 return (long long int) strtol(str, endptr, base);
508 #else
509 # error "You need a strtoll function"
510 #endif
512 #endif
515 #ifndef HAVE_STRTOULL
516 unsigned long long int rep_strtoull(const char *str, char **endptr, int base)
518 #ifdef HAVE_STRTOUQ
519 return strtouq(str, endptr, base);
520 #elif defined(HAVE___STRTOULL)
521 return __strtoull(str, endptr, base);
522 #elif SIZEOF_LONG == SIZEOF_LONG_LONG
523 return (unsigned long long int) strtoul(str, endptr, base);
524 #else
525 # error "You need a strtoull function"
526 #endif
528 #endif
530 #ifndef HAVE_SETENV
531 int rep_setenv(const char *name, const char *value, int overwrite)
533 char *p;
534 size_t l1, l2;
535 int ret;
537 if (!overwrite && getenv(name)) {
538 return 0;
541 l1 = strlen(name);
542 l2 = strlen(value);
544 p = malloc(l1+l2+2);
545 if (p == NULL) {
546 return -1;
548 memcpy(p, name, l1);
549 p[l1] = '=';
550 memcpy(p+l1+1, value, l2);
551 p[l1+l2+1] = 0;
553 ret = putenv(p);
554 if (ret != 0) {
555 free(p);
558 return ret;
560 #endif
562 #ifndef HAVE_UNSETENV
563 int rep_unsetenv(const char *name)
565 extern char **environ;
566 size_t len = strlen(name);
567 size_t i, count;
569 if (environ == NULL || getenv(name) == NULL) {
570 return 0;
573 for (i=0;environ[i];i++) /* noop */ ;
575 count=i;
577 for (i=0;i<count;) {
578 if (strncmp(environ[i], name, len) == 0 && environ[i][len] == '=') {
579 /* note: we do _not_ free the old variable here. It is unsafe to
580 do so, as the pointer may not have come from malloc */
581 memmove(&environ[i], &environ[i+1], (count-i)*sizeof(char *));
582 count--;
583 } else {
584 i++;
588 return 0;
590 #endif
592 #ifndef HAVE_UTIME
593 int rep_utime(const char *filename, const struct utimbuf *buf)
595 errno = ENOSYS;
596 return -1;
598 #endif
600 #ifndef HAVE_UTIMES
601 int rep_utimes(const char *filename, const struct timeval tv[2])
603 struct utimbuf u;
605 u.actime = tv[0].tv_sec;
606 if (tv[0].tv_usec > 500000) {
607 u.actime += 1;
610 u.modtime = tv[1].tv_sec;
611 if (tv[1].tv_usec > 500000) {
612 u.modtime += 1;
615 return utime(filename, &u);
617 #endif
619 #ifndef HAVE_DUP2
620 int rep_dup2(int oldfd, int newfd)
622 errno = ENOSYS;
623 return -1;
625 #endif
627 #ifndef HAVE_CHOWN
629 chown isn't used much but OS/2 doesn't have it
631 int rep_chown(const char *fname, uid_t uid, gid_t gid)
633 errno = ENOSYS;
634 return -1;
636 #endif
638 #ifndef HAVE_LINK
639 int rep_link(const char *oldpath, const char *newpath)
641 errno = ENOSYS;
642 return -1;
644 #endif
646 #ifndef HAVE_READLINK
647 int rep_readlink(const char *path, char *buf, size_t bufsiz)
649 errno = ENOSYS;
650 return -1;
652 #endif
654 #ifndef HAVE_SYMLINK
655 int rep_symlink(const char *oldpath, const char *newpath)
657 errno = ENOSYS;
658 return -1;
660 #endif
662 #ifndef HAVE_LCHOWN
663 int rep_lchown(const char *fname,uid_t uid,gid_t gid)
665 errno = ENOSYS;
666 return -1;
668 #endif
670 #ifndef HAVE_REALPATH
671 char *rep_realpath(const char *path, char *resolved_path)
673 /* As realpath is not a system call we can't return ENOSYS. */
674 errno = EINVAL;
675 return NULL;
677 #endif