OLD | NEW |
| (Empty) |
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 | |
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 | |
10 | |
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. | |
15 | |
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. | |
20 | |
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/>. | |
23 */ | |
24 | |
25 #include "replace.h" | |
26 | |
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" | |
33 | |
34 #ifdef _WIN32 | |
35 #define mkdir(d,m) _mkdir(d) | |
36 #endif | |
37 | |
38 void replace_dummy(void); | |
39 void replace_dummy(void) {} | |
40 | |
41 #ifndef HAVE_FTRUNCATE | |
42 /******************************************************************* | |
43 ftruncate for operating systems that don't have it | |
44 ********************************************************************/ | |
45 int rep_ftruncate(int f, off_t l) | |
46 { | |
47 #ifdef HAVE_CHSIZE | |
48 return chsize(f,l); | |
49 #elif defined(F_FREESP) | |
50 struct flock fl; | |
51 | |
52 fl.l_whence = 0; | |
53 fl.l_len = 0; | |
54 fl.l_start = l; | |
55 fl.l_type = F_WRLCK; | |
56 return fcntl(f, F_FREESP, &fl); | |
57 #else | |
58 #error "you must have a ftruncate function" | |
59 #endif | |
60 } | |
61 #endif /* HAVE_FTRUNCATE */ | |
62 | |
63 | |
64 #ifndef HAVE_STRLCPY | |
65 /* like strncpy but does not 0 fill the buffer and always null | |
66 terminates. bufsize is the size of the destination buffer */ | |
67 size_t rep_strlcpy(char *d, const char *s, size_t bufsize) | |
68 { | |
69 size_t len = strlen(s); | |
70 size_t ret = len; | |
71 if (bufsize <= 0) return 0; | |
72 if (len >= bufsize) len = bufsize-1; | |
73 memcpy(d, s, len); | |
74 d[len] = 0; | |
75 return ret; | |
76 } | |
77 #endif | |
78 | |
79 #ifndef HAVE_STRLCAT | |
80 /* like strncat but does not 0 fill the buffer and always null | |
81 terminates. bufsize is the length of the buffer, which should | |
82 be one more than the maximum resulting string length */ | |
83 size_t rep_strlcat(char *d, const char *s, size_t bufsize) | |
84 { | |
85 size_t len1 = strlen(d); | |
86 size_t len2 = strlen(s); | |
87 size_t ret = len1 + len2; | |
88 | |
89 if (len1+len2 >= bufsize) { | |
90 if (bufsize < (len1+1)) { | |
91 return ret; | |
92 } | |
93 len2 = bufsize - (len1+1); | |
94 } | |
95 if (len2 > 0) { | |
96 memcpy(d+len1, s, len2); | |
97 d[len1+len2] = 0; | |
98 } | |
99 return ret; | |
100 } | |
101 #endif | |
102 | |
103 #ifndef HAVE_MKTIME | |
104 /******************************************************************* | |
105 a mktime() replacement for those who don't have it - contributed by | |
106 C.A. Lademann <cal@zls.com> | |
107 Corrections by richard.kettlewell@kewill.com | |
108 ********************************************************************/ | |
109 | |
110 #define MINUTE 60 | |
111 #define HOUR 60*MINUTE | |
112 #define DAY 24*HOUR | |
113 #define YEAR 365*DAY | |
114 time_t rep_mktime(struct tm *t) | |
115 { | |
116 struct tm *u; | |
117 time_t epoch = 0; | |
118 int n; | |
119 int mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, | |
120 y, m, i; | |
121 | |
122 if(t->tm_year < 70) | |
123 return((time_t)-1); | |
124 | |
125 n = t->tm_year + 1900 - 1; | |
126 epoch = (t->tm_year - 70) * YEAR + | |
127 ((n / 4 - n / 100 + n / 400) - (1969 / 4 - 1969 / 100 + 1969 / 400)) * DAY; | |
128 | |
129 y = t->tm_year + 1900; | |
130 m = 0; | |
131 | |
132 for(i = 0; i < t->tm_mon; i++) { | |
133 epoch += mon [m] * DAY; | |
134 if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) | |
135 epoch += DAY; | |
136 | |
137 if(++m > 11) { | |
138 m = 0; | |
139 y++; | |
140 } | |
141 } | |
142 | |
143 epoch += (t->tm_mday - 1) * DAY; | |
144 epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec; | |
145 | |
146 if((u = localtime(&epoch)) != NULL) { | |
147 t->tm_sec = u->tm_sec; | |
148 t->tm_min = u->tm_min; | |
149 t->tm_hour = u->tm_hour; | |
150 t->tm_mday = u->tm_mday; | |
151 t->tm_mon = u->tm_mon; | |
152 t->tm_year = u->tm_year; | |
153 t->tm_wday = u->tm_wday; | |
154 t->tm_yday = u->tm_yday; | |
155 t->tm_isdst = u->tm_isdst; | |
156 } | |
157 | |
158 return(epoch); | |
159 } | |
160 #endif /* !HAVE_MKTIME */ | |
161 | |
162 | |
163 #ifndef HAVE_INITGROUPS | |
164 /**************************************************************************** | |
165 some systems don't have an initgroups call | |
166 ****************************************************************************/ | |
167 int rep_initgroups(char *name, gid_t id) | |
168 { | |
169 #ifndef HAVE_SETGROUPS | |
170 /* yikes! no SETGROUPS or INITGROUPS? how can this work? */ | |
171 errno = ENOSYS; | |
172 return -1; | |
173 #else /* HAVE_SETGROUPS */ | |
174 | |
175 #include <grp.h> | |
176 | |
177 gid_t *grouplst = NULL; | |
178 int max_gr = NGROUPS_MAX; | |
179 int ret; | |
180 int i,j; | |
181 struct group *g; | |
182 char *gr; | |
183 | |
184 if((grouplst = malloc(sizeof(gid_t) * max_gr)) == NULL) { | |
185 errno = ENOMEM; | |
186 return -1; | |
187 } | |
188 | |
189 grouplst[0] = id; | |
190 i = 1; | |
191 while (i < max_gr && ((g = (struct group *)getgrent()) != (struct group
*)NULL)) { | |
192 if (g->gr_gid == id) | |
193 continue; | |
194 j = 0; | |
195 gr = g->gr_mem[0]; | |
196 while (gr && (*gr != (char)NULL)) { | |
197 if (strcmp(name,gr) == 0) { | |
198 grouplst[i] = g->gr_gid; | |
199 i++; | |
200 gr = (char *)NULL; | |
201 break; | |
202 } | |
203 gr = g->gr_mem[++j]; | |
204 } | |
205 } | |
206 endgrent(); | |
207 ret = setgroups(i, grouplst); | |
208 free(grouplst); | |
209 return ret; | |
210 #endif /* HAVE_SETGROUPS */ | |
211 } | |
212 #endif /* HAVE_INITGROUPS */ | |
213 | |
214 | |
215 #if (defined(SecureWare) && defined(SCO)) | |
216 /* This is needed due to needing the nap() function but we don't want | |
217 to include the Xenix libraries since that will break other things... | |
218 BTW: system call # 0x0c28 is the same as calling nap() */ | |
219 long nap(long milliseconds) { | |
220 return syscall(0x0c28, milliseconds); | |
221 } | |
222 #endif | |
223 | |
224 | |
225 #ifndef HAVE_MEMMOVE | |
226 /******************************************************************* | |
227 safely copies memory, ensuring no overlap problems. | |
228 this is only used if the machine does not have its own memmove(). | |
229 this is not the fastest algorithm in town, but it will do for our | |
230 needs. | |
231 ********************************************************************/ | |
232 void *rep_memmove(void *dest,const void *src,int size) | |
233 { | |
234 unsigned long d,s; | |
235 int i; | |
236 if (dest==src || !size) return(dest); | |
237 | |
238 d = (unsigned long)dest; | |
239 s = (unsigned long)src; | |
240 | |
241 if ((d >= (s+size)) || (s >= (d+size))) { | |
242 /* no overlap */ | |
243 memcpy(dest,src,size); | |
244 return(dest); | |
245 } | |
246 | |
247 if (d < s) { | |
248 /* we can forward copy */ | |
249 if (s-d >= sizeof(int) && | |
250 !(s%sizeof(int)) && | |
251 !(d%sizeof(int)) && | |
252 !(size%sizeof(int))) { | |
253 /* do it all as words */ | |
254 int *idest = (int *)dest; | |
255 int *isrc = (int *)src; | |
256 size /= sizeof(int); | |
257 for (i=0;i<size;i++) idest[i] = isrc[i]; | |
258 } else { | |
259 /* simplest */ | |
260 char *cdest = (char *)dest; | |
261 char *csrc = (char *)src; | |
262 for (i=0;i<size;i++) cdest[i] = csrc[i]; | |
263 } | |
264 } else { | |
265 /* must backward copy */ | |
266 if (d-s >= sizeof(int) && | |
267 !(s%sizeof(int)) && | |
268 !(d%sizeof(int)) && | |
269 !(size%sizeof(int))) { | |
270 /* do it all as words */ | |
271 int *idest = (int *)dest; | |
272 int *isrc = (int *)src; | |
273 size /= sizeof(int); | |
274 for (i=size-1;i>=0;i--) idest[i] = isrc[i]; | |
275 } else { | |
276 /* simplest */ | |
277 char *cdest = (char *)dest; | |
278 char *csrc = (char *)src; | |
279 for (i=size-1;i>=0;i--) cdest[i] = csrc[i]; | |
280 } | |
281 } | |
282 return(dest); | |
283 } | |
284 #endif /* HAVE_MEMMOVE */ | |
285 | |
286 #ifndef HAVE_STRDUP | |
287 /**************************************************************************** | |
288 duplicate a string | |
289 ****************************************************************************/ | |
290 char *rep_strdup(const char *s) | |
291 { | |
292 size_t len; | |
293 char *ret; | |
294 | |
295 if (!s) return(NULL); | |
296 | |
297 len = strlen(s)+1; | |
298 ret = (char *)malloc(len); | |
299 if (!ret) return(NULL); | |
300 memcpy(ret,s,len); | |
301 return(ret); | |
302 } | |
303 #endif /* HAVE_STRDUP */ | |
304 | |
305 #ifndef HAVE_SETLINEBUF | |
306 void rep_setlinebuf(FILE *stream) | |
307 { | |
308 setvbuf(stream, (char *)NULL, _IOLBF, 0); | |
309 } | |
310 #endif /* HAVE_SETLINEBUF */ | |
311 | |
312 #ifndef HAVE_VSYSLOG | |
313 #ifdef HAVE_SYSLOG | |
314 void rep_vsyslog (int facility_priority, const char *format, va_list arglist) | |
315 { | |
316 char *msg = NULL; | |
317 vasprintf(&msg, format, arglist); | |
318 if (!msg) | |
319 return; | |
320 syslog(facility_priority, "%s", msg); | |
321 free(msg); | |
322 } | |
323 #endif /* HAVE_SYSLOG */ | |
324 #endif /* HAVE_VSYSLOG */ | |
325 | |
326 #ifndef HAVE_STRNLEN | |
327 /** | |
328 Some platforms don't have strnlen | |
329 **/ | |
330 size_t rep_strnlen(const char *s, size_t max) | |
331 { | |
332 size_t len; | |
333 | |
334 for (len = 0; len < max; len++) { | |
335 if (s[len] == '\0') { | |
336 break; | |
337 } | |
338 } | |
339 return len; | |
340 } | |
341 #endif | |
342 | |
343 #ifndef HAVE_STRNDUP | |
344 /** | |
345 Some platforms don't have strndup. | |
346 **/ | |
347 char *rep_strndup(const char *s, size_t n) | |
348 { | |
349 char *ret; | |
350 | |
351 n = strnlen(s, n); | |
352 ret = malloc(n+1); | |
353 if (!ret) | |
354 return NULL; | |
355 memcpy(ret, s, n); | |
356 ret[n] = 0; | |
357 | |
358 return ret; | |
359 } | |
360 #endif | |
361 | |
362 #if !defined(HAVE_WAITPID) && defined(HAVE_WAIT4) | |
363 int rep_waitpid(pid_t pid,int *status,int options) | |
364 { | |
365 return wait4(pid, status, options, NULL); | |
366 } | |
367 #endif | |
368 | |
369 #ifndef HAVE_SETEUID | |
370 int rep_seteuid(uid_t euid) | |
371 { | |
372 #ifdef HAVE_SETRESUID | |
373 return setresuid(-1, euid, -1); | |
374 #else | |
375 errno = ENOSYS; | |
376 return -1; | |
377 #endif | |
378 } | |
379 #endif | |
380 | |
381 #ifndef HAVE_SETEGID | |
382 int rep_setegid(gid_t egid) | |
383 { | |
384 #ifdef HAVE_SETRESGID | |
385 return setresgid(-1, egid, -1); | |
386 #else | |
387 errno = ENOSYS; | |
388 return -1; | |
389 #endif | |
390 } | |
391 #endif | |
392 | |
393 /******************************************************************* | |
394 os/2 also doesn't have chroot | |
395 ********************************************************************/ | |
396 #ifndef HAVE_CHROOT | |
397 int rep_chroot(const char *dname) | |
398 { | |
399 errno = ENOSYS; | |
400 return -1; | |
401 } | |
402 #endif | |
403 | |
404 /***************************************************************** | |
405 Possibly replace mkstemp if it is broken. | |
406 *****************************************************************/ | |
407 | |
408 #ifndef HAVE_SECURE_MKSTEMP | |
409 int rep_mkstemp(char *template) | |
410 { | |
411 /* have a reasonable go at emulating it. Hope that | |
412 the system mktemp() isn't completly hopeless */ | |
413 char *p = mktemp(template); | |
414 if (!p) | |
415 return -1; | |
416 return open(p, O_CREAT|O_EXCL|O_RDWR, 0600); | |
417 } | |
418 #endif | |
419 | |
420 #ifndef HAVE_MKDTEMP | |
421 char *rep_mkdtemp(char *template) | |
422 { | |
423 char *dname; | |
424 | |
425 if ((dname = mktemp(template))) { | |
426 if (mkdir(dname, 0700) >= 0) { | |
427 return dname; | |
428 } | |
429 } | |
430 | |
431 return NULL; | |
432 } | |
433 #endif | |
434 | |
435 /***************************************************************** | |
436 Watch out: this is not thread safe. | |
437 *****************************************************************/ | |
438 | |
439 #ifndef HAVE_PREAD | |
440 ssize_t rep_pread(int __fd, void *__buf, size_t __nbytes, off_t __offset) | |
441 { | |
442 if (lseek(__fd, __offset, SEEK_SET) != __offset) { | |
443 return -1; | |
444 } | |
445 return read(__fd, __buf, __nbytes); | |
446 } | |
447 #endif | |
448 | |
449 /***************************************************************** | |
450 Watch out: this is not thread safe. | |
451 *****************************************************************/ | |
452 | |
453 #ifndef HAVE_PWRITE | |
454 ssize_t rep_pwrite(int __fd, const void *__buf, size_t __nbytes, off_t __offset) | |
455 { | |
456 if (lseek(__fd, __offset, SEEK_SET) != __offset) { | |
457 return -1; | |
458 } | |
459 return write(__fd, __buf, __nbytes); | |
460 } | |
461 #endif | |
462 | |
463 #ifndef HAVE_STRCASESTR | |
464 char *rep_strcasestr(const char *haystack, const char *needle) | |
465 { | |
466 const char *s; | |
467 size_t nlen = strlen(needle); | |
468 for (s=haystack;*s;s++) { | |
469 if (toupper(*needle) == toupper(*s) && | |
470 strncasecmp(s, needle, nlen) == 0) { | |
471 return (char *)((uintptr_t)s); | |
472 } | |
473 } | |
474 return NULL; | |
475 } | |
476 #endif | |
477 | |
478 #ifndef HAVE_STRTOK_R | |
479 /* based on GLIBC version, copyright Free Software Foundation */ | |
480 char *rep_strtok_r(char *s, const char *delim, char **save_ptr) | |
481 { | |
482 char *token; | |
483 | |
484 if (s == NULL) s = *save_ptr; | |
485 | |
486 s += strspn(s, delim); | |
487 if (*s == '\0') { | |
488 *save_ptr = s; | |
489 return NULL; | |
490 } | |
491 | |
492 token = s; | |
493 s = strpbrk(token, delim); | |
494 if (s == NULL) { | |
495 *save_ptr = token + strlen(token); | |
496 } else { | |
497 *s = '\0'; | |
498 *save_ptr = s + 1; | |
499 } | |
500 | |
501 return token; | |
502 } | |
503 #endif | |
504 | |
505 #ifndef HAVE_STRTOLL | |
506 long long int rep_strtoll(const char *str, char **endptr, int base) | |
507 { | |
508 #ifdef HAVE_STRTOQ | |
509 return strtoq(str, endptr, base); | |
510 #elif defined(HAVE___STRTOLL) | |
511 return __strtoll(str, endptr, base); | |
512 #elif SIZEOF_LONG == SIZEOF_LONG_LONG | |
513 return (long long int) strtol(str, endptr, base); | |
514 #else | |
515 # error "You need a strtoll function" | |
516 #endif | |
517 } | |
518 #endif | |
519 | |
520 | |
521 #ifndef HAVE_STRTOULL | |
522 unsigned long long int rep_strtoull(const char *str, char **endptr, int base) | |
523 { | |
524 #ifdef HAVE_STRTOUQ | |
525 return strtouq(str, endptr, base); | |
526 #elif defined(HAVE___STRTOULL) | |
527 return __strtoull(str, endptr, base); | |
528 #elif SIZEOF_LONG == SIZEOF_LONG_LONG | |
529 return (unsigned long long int) strtoul(str, endptr, base); | |
530 #else | |
531 # error "You need a strtoull function" | |
532 #endif | |
533 } | |
534 #endif | |
535 | |
536 #ifndef HAVE_SETENV | |
537 int rep_setenv(const char *name, const char *value, int overwrite) | |
538 { | |
539 char *p; | |
540 size_t l1, l2; | |
541 int ret; | |
542 | |
543 if (!overwrite && getenv(name)) { | |
544 return 0; | |
545 } | |
546 | |
547 l1 = strlen(name); | |
548 l2 = strlen(value); | |
549 | |
550 p = malloc(l1+l2+2); | |
551 if (p == NULL) { | |
552 return -1; | |
553 } | |
554 memcpy(p, name, l1); | |
555 p[l1] = '='; | |
556 memcpy(p+l1+1, value, l2); | |
557 p[l1+l2+1] = 0; | |
558 | |
559 ret = putenv(p); | |
560 if (ret != 0) { | |
561 free(p); | |
562 } | |
563 | |
564 return ret; | |
565 } | |
566 #endif | |
567 | |
568 #ifndef HAVE_UNSETENV | |
569 int rep_unsetenv(const char *name) | |
570 { | |
571 extern char **environ; | |
572 size_t len = strlen(name); | |
573 size_t i, count; | |
574 | |
575 if (environ == NULL || getenv(name) == NULL) { | |
576 return 0; | |
577 } | |
578 | |
579 for (i=0;environ[i];i++) /* noop */ ; | |
580 | |
581 count=i; | |
582 | |
583 for (i=0;i<count;) { | |
584 if (strncmp(environ[i], name, len) == 0 && environ[i][len] == '=
') { | |
585 /* note: we do _not_ free the old variable here. It is u
nsafe to | |
586 do so, as the pointer may not have come from malloc *
/ | |
587 memmove(&environ[i], &environ[i+1], (count-i)*sizeof(cha
r *)); | |
588 count--; | |
589 } else { | |
590 i++; | |
591 } | |
592 } | |
593 | |
594 return 0; | |
595 } | |
596 #endif | |
597 | |
598 #ifndef HAVE_UTIME | |
599 int rep_utime(const char *filename, const struct utimbuf *buf) | |
600 { | |
601 errno = ENOSYS; | |
602 return -1; | |
603 } | |
604 #endif | |
605 | |
606 #ifndef HAVE_UTIMES | |
607 int rep_utimes(const char *filename, const struct timeval tv[2]) | |
608 { | |
609 struct utimbuf u; | |
610 | |
611 u.actime = tv[0].tv_sec; | |
612 if (tv[0].tv_usec > 500000) { | |
613 u.actime += 1; | |
614 } | |
615 | |
616 u.modtime = tv[1].tv_sec; | |
617 if (tv[1].tv_usec > 500000) { | |
618 u.modtime += 1; | |
619 } | |
620 | |
621 return utime(filename, &u); | |
622 } | |
623 #endif | |
624 | |
625 #ifndef HAVE_DUP2 | |
626 int rep_dup2(int oldfd, int newfd) | |
627 { | |
628 errno = ENOSYS; | |
629 return -1; | |
630 } | |
631 #endif | |
632 | |
633 #ifndef HAVE_CHOWN | |
634 /** | |
635 chown isn't used much but OS/2 doesn't have it | |
636 **/ | |
637 int rep_chown(const char *fname, uid_t uid, gid_t gid) | |
638 { | |
639 errno = ENOSYS; | |
640 return -1; | |
641 } | |
642 #endif | |
643 | |
644 #ifndef HAVE_LINK | |
645 int rep_link(const char *oldpath, const char *newpath) | |
646 { | |
647 errno = ENOSYS; | |
648 return -1; | |
649 } | |
650 #endif | |
651 | |
652 #ifndef HAVE_READLINK | |
653 int rep_readlink(const char *path, char *buf, size_t bufsiz) | |
654 { | |
655 errno = ENOSYS; | |
656 return -1; | |
657 } | |
658 #endif | |
659 | |
660 #ifndef HAVE_SYMLINK | |
661 int rep_symlink(const char *oldpath, const char *newpath) | |
662 { | |
663 errno = ENOSYS; | |
664 return -1; | |
665 } | |
666 #endif | |
667 | |
668 #ifndef HAVE_LCHOWN | |
669 int rep_lchown(const char *fname,uid_t uid,gid_t gid) | |
670 { | |
671 errno = ENOSYS; | |
672 return -1; | |
673 } | |
674 #endif | |
675 | |
676 #ifndef HAVE_REALPATH | |
677 char *rep_realpath(const char *path, char *resolved_path) | |
678 { | |
679 /* As realpath is not a system call we can't return ENOSYS. */ | |
680 errno = EINVAL; | |
681 return NULL; | |
682 } | |
683 #endif | |
OLD | NEW |