s3: fix build on platforms without st_blocks and st_blksize stat struct members
[samba.git] / source3 / lib / system.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Samba system utilities
4    Copyright (C) Andrew Tridgell 1992-1998
5    Copyright (C) Jeremy Allison  1998-2005
6    Copyright (C) Timur Bakeyev        2005
7    Copyright (C) Bjoern Jacke    2006-2007
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24
25 #ifdef HAVE_SYS_PRCTL_H
26 #include <sys/prctl.h>
27 #endif
28
29 /*
30    The idea is that this file will eventually have wrappers around all
31    important system calls in samba. The aims are:
32
33    - to enable easier porting by putting OS dependent stuff in here
34
35    - to allow for hooks into other "pseudo-filesystems"
36
37    - to allow easier integration of things like the japanese extensions
38
39    - to support the philosophy of Samba to expose the features of
40      the OS within the SMB model. In general whatever file/printer/variable
41      expansions/etc make sense to the OS should be acceptable to Samba.
42 */
43
44
45
46 /*******************************************************************
47  A wrapper for memalign
48 ********************************************************************/
49
50 void *sys_memalign( size_t align, size_t size )
51 {
52 #if defined(HAVE_POSIX_MEMALIGN)
53         void *p = NULL;
54         int ret = posix_memalign( &p, align, size );
55         if ( ret == 0 )
56                 return p;
57
58         return NULL;
59 #elif defined(HAVE_MEMALIGN)
60         return memalign( align, size );
61 #else
62         /* On *BSD systems memaligns doesn't exist, but memory will
63          * be aligned on allocations of > pagesize. */
64 #if defined(SYSCONF_SC_PAGESIZE)
65         size_t pagesize = (size_t)sysconf(_SC_PAGESIZE);
66 #elif defined(HAVE_GETPAGESIZE)
67         size_t pagesize = (size_t)getpagesize();
68 #else
69         size_t pagesize = (size_t)-1;
70 #endif
71         if (pagesize == (size_t)-1) {
72                 DEBUG(0,("memalign functionalaity not available on this platform!\n"));
73                 return NULL;
74         }
75         if (size < pagesize) {
76                 size = pagesize;
77         }
78         return SMB_MALLOC(size);
79 #endif
80 }
81
82 /*******************************************************************
83  A wrapper for usleep in case we don't have one.
84 ********************************************************************/
85
86 int sys_usleep(long usecs)
87 {
88 #ifndef HAVE_USLEEP
89         struct timeval tval;
90 #endif
91
92         /*
93          * We need this braindamage as the glibc usleep
94          * is not SPEC1170 complient... grumble... JRA.
95          */
96
97         if(usecs < 0 || usecs > 999999) {
98                 errno = EINVAL;
99                 return -1;
100         }
101
102 #if HAVE_USLEEP
103         usleep(usecs);
104         return 0;
105 #else /* HAVE_USLEEP */
106         /*
107          * Fake it with select...
108          */
109         tval.tv_sec = 0;
110         tval.tv_usec = usecs/1000;
111         select(0,NULL,NULL,NULL,&tval);
112         return 0;
113 #endif /* HAVE_USLEEP */
114 }
115
116 /*******************************************************************
117 A read wrapper that will deal with EINTR.
118 ********************************************************************/
119
120 ssize_t sys_read(int fd, void *buf, size_t count)
121 {
122         ssize_t ret;
123
124         do {
125                 ret = read(fd, buf, count);
126         } while (ret == -1 && errno == EINTR);
127         return ret;
128 }
129
130 /*******************************************************************
131 A write wrapper that will deal with EINTR.
132 ********************************************************************/
133
134 ssize_t sys_write(int fd, const void *buf, size_t count)
135 {
136         ssize_t ret;
137
138         do {
139                 ret = write(fd, buf, count);
140         } while (ret == -1 && errno == EINTR);
141         return ret;
142 }
143
144 /*******************************************************************
145 A writev wrapper that will deal with EINTR.
146 ********************************************************************/
147
148 ssize_t sys_writev(int fd, const struct iovec *iov, int iovcnt)
149 {
150         ssize_t ret;
151
152 #if 0
153         /* Try to confuse write_data_iov a bit */
154         if ((random() % 5) == 0) {
155                 return sys_write(fd, iov[0].iov_base, iov[0].iov_len);
156         }
157         if (iov[0].iov_len > 1) {
158                 return sys_write(fd, iov[0].iov_base,
159                                  (random() % (iov[0].iov_len-1)) + 1);
160         }
161 #endif
162
163         do {
164                 ret = writev(fd, iov, iovcnt);
165         } while (ret == -1 && errno == EINTR);
166         return ret;
167 }
168
169 /*******************************************************************
170 A pread wrapper that will deal with EINTR and 64-bit file offsets.
171 ********************************************************************/
172
173 #if defined(HAVE_PREAD) || defined(HAVE_PREAD64)
174 ssize_t sys_pread(int fd, void *buf, size_t count, SMB_OFF_T off)
175 {
176         ssize_t ret;
177
178         do {
179 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_PREAD64)
180                 ret = pread64(fd, buf, count, off);
181 #else
182                 ret = pread(fd, buf, count, off);
183 #endif
184         } while (ret == -1 && errno == EINTR);
185         return ret;
186 }
187 #endif
188
189 /*******************************************************************
190 A write wrapper that will deal with EINTR and 64-bit file offsets.
191 ********************************************************************/
192
193 #if defined(HAVE_PWRITE) || defined(HAVE_PWRITE64)
194 ssize_t sys_pwrite(int fd, const void *buf, size_t count, SMB_OFF_T off)
195 {
196         ssize_t ret;
197
198         do {
199 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_PWRITE64)
200                 ret = pwrite64(fd, buf, count, off);
201 #else
202                 ret = pwrite(fd, buf, count, off);
203 #endif
204         } while (ret == -1 && errno == EINTR);
205         return ret;
206 }
207 #endif
208
209 /*******************************************************************
210 A send wrapper that will deal with EINTR.
211 ********************************************************************/
212
213 ssize_t sys_send(int s, const void *msg, size_t len, int flags)
214 {
215         ssize_t ret;
216
217         do {
218                 ret = send(s, msg, len, flags);
219         } while (ret == -1 && errno == EINTR);
220         return ret;
221 }
222
223 /*******************************************************************
224 A sendto wrapper that will deal with EINTR.
225 ********************************************************************/
226
227 ssize_t sys_sendto(int s,  const void *msg, size_t len, int flags, const struct sockaddr *to, socklen_t tolen)
228 {
229         ssize_t ret;
230
231         do {
232                 ret = sendto(s, msg, len, flags, to, tolen);
233         } while (ret == -1 && errno == EINTR);
234         return ret;
235 }
236
237 /*******************************************************************
238 A recv wrapper that will deal with EINTR.
239 ********************************************************************/
240
241 ssize_t sys_recv(int fd, void *buf, size_t count, int flags)
242 {
243         ssize_t ret;
244
245         do {
246                 ret = recv(fd, buf, count, flags);
247         } while (ret == -1 && errno == EINTR);
248         return ret;
249 }
250
251 /*******************************************************************
252 A recvfrom wrapper that will deal with EINTR.
253 ********************************************************************/
254
255 ssize_t sys_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
256 {
257         ssize_t ret;
258
259         do {
260                 ret = recvfrom(s, buf, len, flags, from, fromlen);
261         } while (ret == -1 && errno == EINTR);
262         return ret;
263 }
264
265 /*******************************************************************
266 A fcntl wrapper that will deal with EINTR.
267 ********************************************************************/
268
269 int sys_fcntl_ptr(int fd, int cmd, void *arg)
270 {
271         int ret;
272
273         do {
274                 ret = fcntl(fd, cmd, arg);
275         } while (ret == -1 && errno == EINTR);
276         return ret;
277 }
278
279 /*******************************************************************
280 A fcntl wrapper that will deal with EINTR.
281 ********************************************************************/
282
283 int sys_fcntl_long(int fd, int cmd, long arg)
284 {
285         int ret;
286
287         do {
288                 ret = fcntl(fd, cmd, arg);
289         } while (ret == -1 && errno == EINTR);
290         return ret;
291 }
292
293 /****************************************************************************
294  Get/Set all the possible time fields from a stat struct as a timespec.
295 ****************************************************************************/
296
297 static struct timespec get_atimespec(const struct stat *pst)
298 {
299 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
300         struct timespec ret;
301
302         /* Old system - no ns timestamp. */
303         ret.tv_sec = pst->st_atime;
304         ret.tv_nsec = 0;
305         return ret;
306 #else
307 #if defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
308         return pst->st_atim;
309 #elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
310         struct timespec ret;
311         ret.tv_sec = pst->st_atime;
312         ret.tv_nsec = pst->st_atimensec;
313         return ret;
314 #elif defined(HAVE_STRUCT_STAT_ST_MTIME_N)
315         struct timespec ret;
316         ret.tv_sec = pst->st_atime;
317         ret.tv_nsec = pst->st_atime_n;
318         return ret;
319 #elif defined(HAVE_STRUCT_STAT_ST_UMTIME)
320         struct timespec ret;
321         ret.tv_sec = pst->st_atime;
322         ret.tv_nsec = pst->st_uatime * 1000;
323         return ret;
324 #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC)
325         return pst->st_atimespec;
326 #else
327 #error  CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
328 #endif
329 #endif
330 }
331
332 static struct timespec get_mtimespec(const struct stat *pst)
333 {
334 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
335         struct timespec ret;
336
337         /* Old system - no ns timestamp. */
338         ret.tv_sec = pst->st_mtime;
339         ret.tv_nsec = 0;
340         return ret;
341 #else
342 #if defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
343         return pst->st_mtim;
344 #elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
345         struct timespec ret;
346         ret.tv_sec = pst->st_mtime;
347         ret.tv_nsec = pst->st_mtimensec;
348         return ret;
349 #elif defined(HAVE_STRUCT_STAT_ST_MTIME_N)
350         struct timespec ret;
351         ret.tv_sec = pst->st_mtime;
352         ret.tv_nsec = pst->st_mtime_n;
353         return ret;
354 #elif defined(HAVE_STRUCT_STAT_ST_UMTIME)
355         struct timespec ret;
356         ret.tv_sec = pst->st_mtime;
357         ret.tv_nsec = pst->st_umtime * 1000;
358         return ret;
359 #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC)
360         return pst->st_mtimespec;
361 #else
362 #error  CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
363 #endif
364 #endif
365 }
366
367 static struct timespec get_ctimespec(const struct stat *pst)
368 {
369 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
370         struct timespec ret;
371
372         /* Old system - no ns timestamp. */
373         ret.tv_sec = pst->st_ctime;
374         ret.tv_nsec = 0;
375         return ret;
376 #else
377 #if defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
378         return pst->st_ctim;
379 #elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
380         struct timespec ret;
381         ret.tv_sec = pst->st_ctime;
382         ret.tv_nsec = pst->st_ctimensec;
383         return ret;
384 #elif defined(HAVE_STRUCT_STAT_ST_MTIME_N)
385         struct timespec ret;
386         ret.tv_sec = pst->st_ctime;
387         ret.tv_nsec = pst->st_ctime_n;
388         return ret;
389 #elif defined(HAVE_STRUCT_STAT_ST_UMTIME)
390         struct timespec ret;
391         ret.tv_sec = pst->st_ctime;
392         ret.tv_nsec = pst->st_uctime * 1000;
393         return ret;
394 #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC)
395         return pst->st_ctimespec;
396 #else
397 #error  CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
398 #endif
399 #endif
400 }
401
402 /****************************************************************************
403  Return the best approximation to a 'create time' under UNIX from a stat
404  structure.
405 ****************************************************************************/
406
407 static struct timespec calc_create_time_stat(const struct stat *st)
408 {
409         struct timespec ret, ret1;
410         struct timespec c_time = get_ctimespec(st);
411         struct timespec m_time = get_mtimespec(st);
412         struct timespec a_time = get_atimespec(st);
413
414         ret = timespec_compare(&c_time, &m_time) < 0 ? c_time : m_time;
415         ret1 = timespec_compare(&ret, &a_time) < 0 ? ret : a_time;
416
417         if(!null_timespec(ret1)) {
418                 return ret1;
419         }
420
421         /*
422          * One of ctime, mtime or atime was zero (probably atime).
423          * Just return MIN(ctime, mtime).
424          */
425         return ret;
426 }
427
428 /****************************************************************************
429  Return the best approximation to a 'create time' under UNIX from a stat_ex
430  structure.
431 ****************************************************************************/
432
433 static struct timespec calc_create_time_stat_ex(const struct stat_ex *st)
434 {
435         struct timespec ret, ret1;
436         struct timespec c_time = st->st_ex_ctime;
437         struct timespec m_time = st->st_ex_mtime;
438         struct timespec a_time = st->st_ex_atime;
439
440         ret = timespec_compare(&c_time, &m_time) < 0 ? c_time : m_time;
441         ret1 = timespec_compare(&ret, &a_time) < 0 ? ret : a_time;
442
443         if(!null_timespec(ret1)) {
444                 return ret1;
445         }
446
447         /*
448          * One of ctime, mtime or atime was zero (probably atime).
449          * Just return MIN(ctime, mtime).
450          */
451         return ret;
452 }
453
454 /****************************************************************************
455  Return the 'create time' from a stat struct if it exists (birthtime) or else
456  use the best approximation.
457 ****************************************************************************/
458
459 static void make_create_timespec(const struct stat *pst, struct stat_ex *dst,
460                                  bool fake_dir_create_times)
461 {
462         if (S_ISDIR(pst->st_mode) && fake_dir_create_times) {
463                 dst->st_ex_btime.tv_sec = 315493200L;          /* 1/1/1980 */
464                 dst->st_ex_btime.tv_nsec = 0;
465         }
466
467         dst->st_ex_calculated_birthtime = false;
468
469 #if defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC)
470         dst->st_ex_btime = pst->st_birthtimespec;
471 #elif defined(HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC)
472         dst->st_ex_btime.tv_sec = pst->st_birthtime;
473         dst->st_ex_btime.tv_nsec = pst->st_birthtimenspec;
474 #elif defined(HAVE_STRUCT_STAT_ST_BIRTHTIME)
475         dst->st_ex_btime.tv_sec = pst->st_birthtime;
476         dst->st_ex_btime.tv_nsec = 0;
477 #else
478         dst->st_ex_btime = calc_create_time_stat(pst);
479         dst->st_ex_calculated_birthtime = true;
480 #endif
481
482         /* Deal with systems that don't initialize birthtime correctly.
483          * Pointed out by SATOH Fumiyasu <fumiyas@osstech.jp>.
484          */
485         if (null_timespec(dst->st_ex_btime)) {
486                 dst->st_ex_btime = calc_create_time_stat(pst);
487                 dst->st_ex_calculated_birthtime = true;
488         }
489 }
490
491 /****************************************************************************
492  If we update a timestamp in a stat_ex struct we may have to recalculate
493  the birthtime. For now only implement this for write time, but we may
494  also need to do it for atime and ctime. JRA.
495 ****************************************************************************/
496
497 void update_stat_ex_mtime(struct stat_ex *dst,
498                                 struct timespec write_ts)
499 {
500         dst->st_ex_mtime = write_ts;
501
502         /* We may have to recalculate btime. */
503         if (dst->st_ex_calculated_birthtime) {
504                 dst->st_ex_btime = calc_create_time_stat_ex(dst);
505         }
506 }
507
508 void update_stat_ex_create_time(struct stat_ex *dst,
509                                 struct timespec create_time)
510 {
511         dst->st_ex_btime = create_time;
512         dst->st_ex_calculated_birthtime = false;
513 }
514
515 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_STAT64)
516 static void init_stat_ex_from_stat (struct stat_ex *dst,
517                                     const struct stat64 *src,
518                                     bool fake_dir_create_times)
519 #else
520 static void init_stat_ex_from_stat (struct stat_ex *dst,
521                                     const struct stat *src,
522                                     bool fake_dir_create_times)
523 #endif
524 {
525         dst->st_ex_dev = src->st_dev;
526         dst->st_ex_ino = src->st_ino;
527         dst->st_ex_mode = src->st_mode;
528         dst->st_ex_nlink = src->st_nlink;
529         dst->st_ex_uid = src->st_uid;
530         dst->st_ex_gid = src->st_gid;
531         dst->st_ex_rdev = src->st_rdev;
532         dst->st_ex_size = src->st_size;
533         dst->st_ex_atime = get_atimespec(src);
534         dst->st_ex_mtime = get_mtimespec(src);
535         dst->st_ex_ctime = get_ctimespec(src);
536         make_create_timespec(src, dst, fake_dir_create_times);
537 #ifdef HAVE_STAT_ST_BLKSIZE
538         dst->st_ex_blksize = src->st_blksize;
539 #else
540         dst->st_ex_blksize = STAT_ST_BLOCKSIZE;
541 #endif
542
543 #ifdef HAVE_STAT_ST_BLOCKS
544         dst->st_ex_blocks = src->st_blocks;
545 #else
546         dst->st_ex_blocks = src->st_size / dst->st_ex_blksize + 1;
547 #endif
548
549 #ifdef HAVE_STAT_ST_FLAGS
550         dst->st_ex_flags = src->st_flags;
551 #else
552         dst->st_ex_flags = 0;
553 #endif
554 }
555
556 /*******************************************************************
557 A stat() wrapper that will deal with 64 bit filesizes.
558 ********************************************************************/
559
560 int sys_stat(const char *fname, SMB_STRUCT_STAT *sbuf,
561              bool fake_dir_create_times)
562 {
563         int ret;
564 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_STAT64)
565         struct stat64 statbuf;
566         ret = stat64(fname, &statbuf);
567 #else
568         struct stat statbuf;
569         ret = stat(fname, &statbuf);
570 #endif
571         if (ret == 0) {
572                 /* we always want directories to appear zero size */
573                 if (S_ISDIR(statbuf.st_mode)) {
574                         statbuf.st_size = 0;
575                 }
576                 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
577         }
578         return ret;
579 }
580
581 /*******************************************************************
582  An fstat() wrapper that will deal with 64 bit filesizes.
583 ********************************************************************/
584
585 int sys_fstat(int fd, SMB_STRUCT_STAT *sbuf, bool fake_dir_create_times)
586 {
587         int ret;
588 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FSTAT64)
589         struct stat64 statbuf;
590         ret = fstat64(fd, &statbuf);
591 #else
592         struct stat statbuf;
593         ret = fstat(fd, &statbuf);
594 #endif
595         if (ret == 0) {
596                 /* we always want directories to appear zero size */
597                 if (S_ISDIR(statbuf.st_mode)) {
598                         statbuf.st_size = 0;
599                 }
600                 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
601         }
602         return ret;
603 }
604
605 /*******************************************************************
606  An lstat() wrapper that will deal with 64 bit filesizes.
607 ********************************************************************/
608
609 int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf,
610               bool fake_dir_create_times)
611 {
612         int ret;
613 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSTAT64)
614         struct stat64 statbuf;
615         ret = lstat64(fname, &statbuf);
616 #else
617         struct stat statbuf;
618         ret = lstat(fname, &statbuf);
619 #endif
620         if (ret == 0) {
621                 /* we always want directories to appear zero size */
622                 if (S_ISDIR(statbuf.st_mode)) {
623                         statbuf.st_size = 0;
624                 }
625                 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
626         }
627         return ret;
628 }
629
630 /*******************************************************************
631  An posix_fallocate() wrapper that will deal with 64 bit filesizes.
632 ********************************************************************/
633 int sys_posix_fallocate(int fd, SMB_OFF_T offset, SMB_OFF_T len)
634 {
635 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_POSIX_FALLOCATE64) && !defined(HAVE_BROKEN_POSIX_FALLOCATE)
636         return posix_fallocate64(fd, offset, len);
637 #elif defined(HAVE_POSIX_FALLOCATE) && !defined(HAVE_BROKEN_POSIX_FALLOCATE)
638         return posix_fallocate(fd, offset, len);
639 #else
640         return ENOSYS;
641 #endif
642 }
643
644 /*******************************************************************
645  An ftruncate() wrapper that will deal with 64 bit filesizes.
646 ********************************************************************/
647
648 int sys_ftruncate(int fd, SMB_OFF_T offset)
649 {
650 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FTRUNCATE64)
651         return ftruncate64(fd, offset);
652 #else
653         return ftruncate(fd, offset);
654 #endif
655 }
656
657 /*******************************************************************
658  An lseek() wrapper that will deal with 64 bit filesizes.
659 ********************************************************************/
660
661 SMB_OFF_T sys_lseek(int fd, SMB_OFF_T offset, int whence)
662 {
663 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSEEK64)
664         return lseek64(fd, offset, whence);
665 #else
666         return lseek(fd, offset, whence);
667 #endif
668 }
669
670 /*******************************************************************
671  An fseek() wrapper that will deal with 64 bit filesizes.
672 ********************************************************************/
673
674 int sys_fseek(FILE *fp, SMB_OFF_T offset, int whence)
675 {
676 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEK64)
677         return fseek64(fp, offset, whence);
678 #elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEKO64)
679         return fseeko64(fp, offset, whence);
680 #else
681         return fseek(fp, offset, whence);
682 #endif
683 }
684
685 /*******************************************************************
686  An ftell() wrapper that will deal with 64 bit filesizes.
687 ********************************************************************/
688
689 SMB_OFF_T sys_ftell(FILE *fp)
690 {
691 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELL64)
692         return (SMB_OFF_T)ftell64(fp);
693 #elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELLO64)
694         return (SMB_OFF_T)ftello64(fp);
695 #else
696         return (SMB_OFF_T)ftell(fp);
697 #endif
698 }
699
700 /*******************************************************************
701  A creat() wrapper that will deal with 64 bit filesizes.
702 ********************************************************************/
703
704 int sys_creat(const char *path, mode_t mode)
705 {
706 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_CREAT64)
707         return creat64(path, mode);
708 #else
709         /*
710          * If creat64 isn't defined then ensure we call a potential open64.
711          * JRA.
712          */
713         return sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
714 #endif
715 }
716
717 /*******************************************************************
718  An open() wrapper that will deal with 64 bit filesizes.
719 ********************************************************************/
720
721 int sys_open(const char *path, int oflag, mode_t mode)
722 {
723 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OPEN64)
724         return open64(path, oflag, mode);
725 #else
726         return open(path, oflag, mode);
727 #endif
728 }
729
730 /*******************************************************************
731  An fopen() wrapper that will deal with 64 bit filesizes.
732 ********************************************************************/
733
734 FILE *sys_fopen(const char *path, const char *type)
735 {
736 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_FOPEN64)
737         return fopen64(path, type);
738 #else
739         return fopen(path, type);
740 #endif
741 }
742
743
744 /*******************************************************************
745  A flock() wrapper that will perform the kernel flock.
746 ********************************************************************/
747
748 void kernel_flock(int fd, uint32 share_mode, uint32 access_mask)
749 {
750 #if HAVE_KERNEL_SHARE_MODES
751         int kernel_mode = 0;
752         if (share_mode == FILE_SHARE_WRITE) {
753                 kernel_mode = LOCK_MAND|LOCK_WRITE;
754         } else if (share_mode == FILE_SHARE_READ) {
755                 kernel_mode = LOCK_MAND|LOCK_READ;
756         } else if (share_mode == FILE_SHARE_NONE) {
757                 kernel_mode = LOCK_MAND;
758         }
759         if (kernel_mode) {
760                 flock(fd, kernel_mode);
761         }
762 #endif
763         ;
764 }
765
766
767
768 /*******************************************************************
769  An opendir wrapper that will deal with 64 bit filesizes.
770 ********************************************************************/
771
772 SMB_STRUCT_DIR *sys_opendir(const char *name)
773 {
774 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OPENDIR64)
775         return opendir64(name);
776 #else
777         return opendir(name);
778 #endif
779 }
780
781 /*******************************************************************
782  A readdir wrapper that will deal with 64 bit filesizes.
783 ********************************************************************/
784
785 SMB_STRUCT_DIRENT *sys_readdir(SMB_STRUCT_DIR *dirp)
786 {
787 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_READDIR64)
788         return readdir64(dirp);
789 #else
790         return readdir(dirp);
791 #endif
792 }
793
794 /*******************************************************************
795  A seekdir wrapper that will deal with 64 bit filesizes.
796 ********************************************************************/
797
798 void sys_seekdir(SMB_STRUCT_DIR *dirp, long offset)
799 {
800 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_SEEKDIR64)
801         seekdir64(dirp, offset);
802 #else
803         seekdir(dirp, offset);
804 #endif
805 }
806
807 /*******************************************************************
808  A telldir wrapper that will deal with 64 bit filesizes.
809 ********************************************************************/
810
811 long sys_telldir(SMB_STRUCT_DIR *dirp)
812 {
813 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_TELLDIR64)
814         return (long)telldir64(dirp);
815 #else
816         return (long)telldir(dirp);
817 #endif
818 }
819
820 /*******************************************************************
821  A rewinddir wrapper that will deal with 64 bit filesizes.
822 ********************************************************************/
823
824 void sys_rewinddir(SMB_STRUCT_DIR *dirp)
825 {
826 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_REWINDDIR64)
827         rewinddir64(dirp);
828 #else
829         rewinddir(dirp);
830 #endif
831 }
832
833 /*******************************************************************
834  A close wrapper that will deal with 64 bit filesizes.
835 ********************************************************************/
836
837 int sys_closedir(SMB_STRUCT_DIR *dirp)
838 {
839 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_CLOSEDIR64)
840         return closedir64(dirp);
841 #else
842         return closedir(dirp);
843 #endif
844 }
845
846 /*******************************************************************
847  An mknod() wrapper that will deal with 64 bit filesizes.
848 ********************************************************************/
849
850 int sys_mknod(const char *path, mode_t mode, SMB_DEV_T dev)
851 {
852 #if defined(HAVE_MKNOD) || defined(HAVE_MKNOD64)
853 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_MKNOD64) && defined(HAVE_DEV64_T)
854         return mknod64(path, mode, dev);
855 #else
856         return mknod(path, mode, dev);
857 #endif
858 #else
859         /* No mknod system call. */
860         errno = ENOSYS;
861         return -1;
862 #endif
863 }
864
865 /*******************************************************************
866 The wait() calls vary between systems
867 ********************************************************************/
868
869 int sys_waitpid(pid_t pid,int *status,int options)
870 {
871 #ifdef HAVE_WAITPID
872         return waitpid(pid,status,options);
873 #else /* HAVE_WAITPID */
874         return wait4(pid, status, options, NULL);
875 #endif /* HAVE_WAITPID */
876 }
877
878 /*******************************************************************
879  System wrapper for getwd
880 ********************************************************************/
881
882 char *sys_getwd(char *s)
883 {
884         char *wd;
885 #ifdef HAVE_GETCWD
886         wd = (char *)getcwd(s, PATH_MAX);
887 #else
888         wd = (char *)getwd(s);
889 #endif
890         return wd;
891 }
892
893 #if defined(HAVE_POSIX_CAPABILITIES)
894
895 /**************************************************************************
896  Try and abstract process capabilities (for systems that have them).
897 ****************************************************************************/
898
899 /* Set the POSIX capabilities needed for the given purpose into the effective
900  * capability set of the current process. Make sure they are always removed
901  * from the inheritable set, because there is no circumstance in which our
902  * children should inherit our elevated privileges.
903  */
904 static bool set_process_capability(enum smbd_capability capability,
905                                    bool enable)
906 {
907         cap_value_t cap_vals[2] = {0};
908         int num_cap_vals = 0;
909
910         cap_t cap;
911
912 #if defined(HAVE_PRCTL) && defined(PR_GET_KEEPCAPS) && defined(PR_SET_KEEPCAPS)
913         /* On Linux, make sure that any capabilities we grab are sticky
914          * across UID changes. We expect that this would allow us to keep both
915          * the effective and permitted capability sets, but as of circa 2.6.16,
916          * only the permitted set is kept. It is a bug (which we work around)
917          * that the effective set is lost, but we still require the effective
918          * set to be kept.
919          */
920         if (!prctl(PR_GET_KEEPCAPS)) {
921                 prctl(PR_SET_KEEPCAPS, 1);
922         }
923 #endif
924
925         cap = cap_get_proc();
926         if (cap == NULL) {
927                 DEBUG(0,("set_process_capability: cap_get_proc failed: %s\n",
928                         strerror(errno)));
929                 return False;
930         }
931
932         switch (capability) {
933                 case KERNEL_OPLOCK_CAPABILITY:
934 #ifdef CAP_NETWORK_MGT
935                         /* IRIX has CAP_NETWORK_MGT for oplocks. */
936                         cap_vals[num_cap_vals++] = CAP_NETWORK_MGT;
937 #endif
938                         break;
939                 case DMAPI_ACCESS_CAPABILITY:
940 #ifdef CAP_DEVICE_MGT
941                         /* IRIX has CAP_DEVICE_MGT for DMAPI access. */
942                         cap_vals[num_cap_vals++] = CAP_DEVICE_MGT;
943 #elif CAP_MKNOD
944                         /* Linux has CAP_MKNOD for DMAPI access. */
945                         cap_vals[num_cap_vals++] = CAP_MKNOD;
946 #endif
947                         break;
948                 case LEASE_CAPABILITY:
949 #ifdef CAP_LEASE
950                         cap_vals[num_cap_vals++] = CAP_LEASE;
951 #endif
952                         break;
953         }
954
955         SMB_ASSERT(num_cap_vals <= ARRAY_SIZE(cap_vals));
956
957         if (num_cap_vals == 0) {
958                 cap_free(cap);
959                 return True;
960         }
961
962         cap_set_flag(cap, CAP_EFFECTIVE, num_cap_vals, cap_vals,
963                 enable ? CAP_SET : CAP_CLEAR);
964
965         /* We never want to pass capabilities down to our children, so make
966          * sure they are not inherited.
967          */
968         cap_set_flag(cap, CAP_INHERITABLE, num_cap_vals, cap_vals, CAP_CLEAR);
969
970         if (cap_set_proc(cap) == -1) {
971                 DEBUG(0, ("set_process_capability: cap_set_proc failed: %s\n",
972                         strerror(errno)));
973                 cap_free(cap);
974                 return False;
975         }
976
977         cap_free(cap);
978         return True;
979 }
980
981 #endif /* HAVE_POSIX_CAPABILITIES */
982
983 /****************************************************************************
984  Gain the oplock capability from the kernel if possible.
985 ****************************************************************************/
986
987 void set_effective_capability(enum smbd_capability capability)
988 {
989 #if defined(HAVE_POSIX_CAPABILITIES)
990         set_process_capability(capability, True);
991 #endif /* HAVE_POSIX_CAPABILITIES */
992 }
993
994 void drop_effective_capability(enum smbd_capability capability)
995 {
996 #if defined(HAVE_POSIX_CAPABILITIES)
997         set_process_capability(capability, False);
998 #endif /* HAVE_POSIX_CAPABILITIES */
999 }
1000
1001 /**************************************************************************
1002  Wrapper for random().
1003 ****************************************************************************/
1004
1005 long sys_random(void)
1006 {
1007 #if defined(HAVE_RANDOM)
1008         return (long)random();
1009 #elif defined(HAVE_RAND)
1010         return (long)rand();
1011 #else
1012         DEBUG(0,("Error - no random function available !\n"));
1013         exit(1);
1014 #endif
1015 }
1016
1017 /**************************************************************************
1018  Wrapper for srandom().
1019 ****************************************************************************/
1020
1021 void sys_srandom(unsigned int seed)
1022 {
1023 #if defined(HAVE_SRANDOM)
1024         srandom(seed);
1025 #elif defined(HAVE_SRAND)
1026         srand(seed);
1027 #else
1028         DEBUG(0,("Error - no srandom function available !\n"));
1029         exit(1);
1030 #endif
1031 }
1032
1033 /**************************************************************************
1034  Returns equivalent to NGROUPS_MAX - using sysconf if needed.
1035 ****************************************************************************/
1036
1037 int groups_max(void)
1038 {
1039 #if defined(SYSCONF_SC_NGROUPS_MAX)
1040         int ret = sysconf(_SC_NGROUPS_MAX);
1041         return (ret == -1) ? NGROUPS_MAX : ret;
1042 #else
1043         return NGROUPS_MAX;
1044 #endif
1045 }
1046
1047 /**************************************************************************
1048  Wrap setgroups and getgroups for systems that declare getgroups() as
1049  returning an array of gid_t, but actuall return an array of int.
1050 ****************************************************************************/
1051
1052 #if defined(HAVE_BROKEN_GETGROUPS)
1053 static int sys_broken_getgroups(int setlen, gid_t *gidset)
1054 {
1055         GID_T gid;
1056         GID_T *group_list;
1057         int i, ngroups;
1058
1059         if(setlen == 0) {
1060                 return getgroups(setlen, &gid);
1061         }
1062
1063         /*
1064          * Broken case. We need to allocate a
1065          * GID_T array of size setlen.
1066          */
1067
1068         if(setlen < 0) {
1069                 errno = EINVAL; 
1070                 return -1;
1071         } 
1072
1073         if (setlen == 0)
1074                 setlen = groups_max();
1075
1076         if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
1077                 DEBUG(0,("sys_getgroups: Malloc fail.\n"));
1078                 return -1;
1079         }
1080
1081         if((ngroups = getgroups(setlen, group_list)) < 0) {
1082                 int saved_errno = errno;
1083                 SAFE_FREE(group_list);
1084                 errno = saved_errno;
1085                 return -1;
1086         }
1087
1088         for(i = 0; i < ngroups; i++)
1089                 gidset[i] = (gid_t)group_list[i];
1090
1091         SAFE_FREE(group_list);
1092         return ngroups;
1093 }
1094
1095 static int sys_broken_setgroups(int setlen, gid_t *gidset)
1096 {
1097         GID_T *group_list;
1098         int i ; 
1099
1100         if (setlen == 0)
1101                 return 0 ;
1102
1103         if (setlen < 0 || setlen > groups_max()) {
1104                 errno = EINVAL; 
1105                 return -1;   
1106         }
1107
1108         /*
1109          * Broken case. We need to allocate a
1110          * GID_T array of size setlen.
1111          */
1112
1113         if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
1114                 DEBUG(0,("sys_setgroups: Malloc fail.\n"));
1115                 return -1;    
1116         }
1117
1118         for(i = 0; i < setlen; i++) 
1119                 group_list[i] = (GID_T) gidset[i]; 
1120
1121         if(setgroups(setlen, group_list) != 0) {
1122                 int saved_errno = errno;
1123                 SAFE_FREE(group_list);
1124                 errno = saved_errno;
1125                 return -1;
1126         }
1127
1128         SAFE_FREE(group_list);
1129         return 0 ;
1130 }
1131
1132 #endif /* HAVE_BROKEN_GETGROUPS */
1133
1134 /* This is a list of systems that require the first GID passed to setgroups(2)
1135  * to be the effective GID. If your system is one of these, add it here.
1136  */
1137 #if defined (FREEBSD) || defined (DARWINOS)
1138 #define USE_BSD_SETGROUPS
1139 #endif
1140
1141 #if defined(USE_BSD_SETGROUPS)
1142 /* Depending on the particular BSD implementation, the first GID that is
1143  * passed to setgroups(2) will either be ignored or will set the credential's
1144  * effective GID. In either case, the right thing to do is to guarantee that
1145  * gidset[0] is the effective GID.
1146  */
1147 static int sys_bsd_setgroups(gid_t primary_gid, int setlen, const gid_t *gidset)
1148 {
1149         gid_t *new_gidset = NULL;
1150         int max;
1151         int ret;
1152
1153         /* setgroups(2) will fail with EINVAL if we pass too many groups. */
1154         max = groups_max();
1155
1156         /* No group list, just make sure we are setting the efective GID. */
1157         if (setlen == 0) {
1158                 return setgroups(1, &primary_gid);
1159         }
1160
1161         /* If the primary gid is not the first array element, grow the array
1162          * and insert it at the front.
1163          */
1164         if (gidset[0] != primary_gid) {
1165                 new_gidset = SMB_MALLOC_ARRAY(gid_t, setlen + 1);
1166                 if (new_gidset == NULL) {
1167                         return -1;
1168                 }
1169
1170                 memcpy(new_gidset + 1, gidset, (setlen * sizeof(gid_t)));
1171                 new_gidset[0] = primary_gid;
1172                 setlen++;
1173         }
1174
1175         if (setlen > max) {
1176                 DEBUG(3, ("forced to truncate group list from %d to %d\n",
1177                         setlen, max));
1178                 setlen = max;
1179         }
1180
1181 #if defined(HAVE_BROKEN_GETGROUPS)
1182         ret = sys_broken_setgroups(setlen, new_gidset ? new_gidset : gidset);
1183 #else
1184         ret = setgroups(setlen, new_gidset ? new_gidset : gidset);
1185 #endif
1186
1187         if (new_gidset) {
1188                 int errsav = errno;
1189                 SAFE_FREE(new_gidset);
1190                 errno = errsav;
1191         }
1192
1193         return ret;
1194 }
1195
1196 #endif /* USE_BSD_SETGROUPS */
1197
1198 /**************************************************************************
1199  Wrapper for getgroups. Deals with broken (int) case.
1200 ****************************************************************************/
1201
1202 int sys_getgroups(int setlen, gid_t *gidset)
1203 {
1204 #if defined(HAVE_BROKEN_GETGROUPS)
1205         return sys_broken_getgroups(setlen, gidset);
1206 #else
1207         return getgroups(setlen, gidset);
1208 #endif
1209 }
1210
1211 /**************************************************************************
1212  Wrapper for setgroups. Deals with broken (int) case and BSD case.
1213 ****************************************************************************/
1214
1215 int sys_setgroups(gid_t UNUSED(primary_gid), int setlen, gid_t *gidset)
1216 {
1217 #if !defined(HAVE_SETGROUPS)
1218         errno = ENOSYS;
1219         return -1;
1220 #endif /* HAVE_SETGROUPS */
1221
1222 #if defined(USE_BSD_SETGROUPS)
1223         return sys_bsd_setgroups(primary_gid, setlen, gidset);
1224 #elif defined(HAVE_BROKEN_GETGROUPS)
1225         return sys_broken_setgroups(setlen, gidset);
1226 #else
1227         return setgroups(setlen, gidset);
1228 #endif
1229 }
1230
1231 /**************************************************************************
1232  Wrappers for setpwent(), getpwent() and endpwent()
1233 ****************************************************************************/
1234
1235 void sys_setpwent(void)
1236 {
1237         setpwent();
1238 }
1239
1240 struct passwd *sys_getpwent(void)
1241 {
1242         return getpwent();
1243 }
1244
1245 void sys_endpwent(void)
1246 {
1247         endpwent();
1248 }
1249
1250 /**************************************************************************
1251  Wrappers for getpwnam(), getpwuid(), getgrnam(), getgrgid()
1252 ****************************************************************************/
1253
1254
1255 struct passwd *sys_getpwnam(const char *name)
1256 {
1257         return getpwnam(name);
1258 }
1259
1260 struct passwd *sys_getpwuid(uid_t uid)
1261 {
1262         return getpwuid(uid);
1263 }
1264
1265 struct group *sys_getgrnam(const char *name)
1266 {
1267         return getgrnam(name);
1268 }
1269
1270 struct group *sys_getgrgid(gid_t gid)
1271 {
1272         return getgrgid(gid);
1273 }
1274
1275 /**************************************************************************
1276  Extract a command into an arg list.
1277 ****************************************************************************/
1278
1279 static char **extract_args(TALLOC_CTX *mem_ctx, const char *command)
1280 {
1281         char *trunc_cmd;
1282         char *saveptr;
1283         char *ptr;
1284         int argcl;
1285         char **argl = NULL;
1286         int i;
1287
1288         if (!(trunc_cmd = talloc_strdup(mem_ctx, command))) {
1289                 DEBUG(0, ("talloc failed\n"));
1290                 goto nomem;
1291         }
1292
1293         if(!(ptr = strtok_r(trunc_cmd, " \t", &saveptr))) {
1294                 TALLOC_FREE(trunc_cmd);
1295                 errno = EINVAL;
1296                 return NULL;
1297         }
1298
1299         /*
1300          * Count the args.
1301          */
1302
1303         for( argcl = 1; ptr; ptr = strtok_r(NULL, " \t", &saveptr))
1304                 argcl++;
1305
1306         TALLOC_FREE(trunc_cmd);
1307
1308         if (!(argl = TALLOC_ARRAY(mem_ctx, char *, argcl + 1))) {
1309                 goto nomem;
1310         }
1311
1312         /*
1313          * Now do the extraction.
1314          */
1315
1316         if (!(trunc_cmd = talloc_strdup(mem_ctx, command))) {
1317                 goto nomem;
1318         }
1319
1320         ptr = strtok_r(trunc_cmd, " \t", &saveptr);
1321         i = 0;
1322
1323         if (!(argl[i++] = talloc_strdup(argl, ptr))) {
1324                 goto nomem;
1325         }
1326
1327         while((ptr = strtok_r(NULL, " \t", &saveptr)) != NULL) {
1328
1329                 if (!(argl[i++] = talloc_strdup(argl, ptr))) {
1330                         goto nomem;
1331                 }
1332         }
1333
1334         argl[i++] = NULL;
1335         TALLOC_FREE(trunc_cmd);
1336         return argl;
1337
1338  nomem:
1339         DEBUG(0, ("talloc failed\n"));
1340         TALLOC_FREE(trunc_cmd);
1341         TALLOC_FREE(argl);
1342         errno = ENOMEM;
1343         return NULL;
1344 }
1345
1346 /**************************************************************************
1347  Wrapper for popen. Safer as it doesn't search a path.
1348  Modified from the glibc sources.
1349  modified by tridge to return a file descriptor. We must kick our FILE* habit
1350 ****************************************************************************/
1351
1352 typedef struct _popen_list
1353 {
1354         int fd;
1355         pid_t child_pid;
1356         struct _popen_list *next;
1357 } popen_list;
1358
1359 static popen_list *popen_chain;
1360
1361 int sys_popen(const char *command)
1362 {
1363         int parent_end, child_end;
1364         int pipe_fds[2];
1365         popen_list *entry = NULL;
1366         char **argl = NULL;
1367
1368         if (pipe(pipe_fds) < 0)
1369                 return -1;
1370
1371         parent_end = pipe_fds[0];
1372         child_end = pipe_fds[1];
1373
1374         if (!*command) {
1375                 errno = EINVAL;
1376                 goto err_exit;
1377         }
1378
1379         if((entry = SMB_MALLOC_P(popen_list)) == NULL)
1380                 goto err_exit;
1381
1382         ZERO_STRUCTP(entry);
1383
1384         /*
1385          * Extract the command and args into a NULL terminated array.
1386          */
1387
1388         if(!(argl = extract_args(NULL, command)))
1389                 goto err_exit;
1390
1391         entry->child_pid = sys_fork();
1392
1393         if (entry->child_pid == -1) {
1394                 goto err_exit;
1395         }
1396
1397         if (entry->child_pid == 0) {
1398
1399                 /*
1400                  * Child !
1401                  */
1402
1403                 int child_std_end = STDOUT_FILENO;
1404                 popen_list *p;
1405
1406                 close(parent_end);
1407                 if (child_end != child_std_end) {
1408                         dup2 (child_end, child_std_end);
1409                         close (child_end);
1410                 }
1411
1412                 /*
1413                  * POSIX.2:  "popen() shall ensure that any streams from previous
1414                  * popen() calls that remain open in the parent process are closed
1415                  * in the new child process."
1416                  */
1417
1418                 for (p = popen_chain; p; p = p->next)
1419                         close(p->fd);
1420
1421                 execv(argl[0], argl);
1422                 _exit (127);
1423         }
1424
1425         /*
1426          * Parent.
1427          */
1428
1429         close (child_end);
1430         TALLOC_FREE(argl);
1431
1432         /* Link into popen_chain. */
1433         entry->next = popen_chain;
1434         popen_chain = entry;
1435         entry->fd = parent_end;
1436
1437         return entry->fd;
1438
1439 err_exit:
1440
1441         SAFE_FREE(entry);
1442         SAFE_FREE(argl);
1443         close(pipe_fds[0]);
1444         close(pipe_fds[1]);
1445         return -1;
1446 }
1447
1448 /**************************************************************************
1449  Wrapper for pclose. Modified from the glibc sources.
1450 ****************************************************************************/
1451
1452 int sys_pclose(int fd)
1453 {
1454         int wstatus;
1455         popen_list **ptr = &popen_chain;
1456         popen_list *entry = NULL;
1457         pid_t wait_pid;
1458         int status = -1;
1459
1460         /* Unlink from popen_chain. */
1461         for ( ; *ptr != NULL; ptr = &(*ptr)->next) {
1462                 if ((*ptr)->fd == fd) {
1463                         entry = *ptr;
1464                         *ptr = (*ptr)->next;
1465                         status = 0;
1466                         break;
1467                 }
1468         }
1469
1470         if (status < 0 || close(entry->fd) < 0)
1471                 return -1;
1472
1473         /*
1474          * As Samba is catching and eating child process
1475          * exits we don't really care about the child exit
1476          * code, a -1 with errno = ECHILD will do fine for us.
1477          */
1478
1479         do {
1480                 wait_pid = sys_waitpid (entry->child_pid, &wstatus, 0);
1481         } while (wait_pid == -1 && errno == EINTR);
1482
1483         SAFE_FREE(entry);
1484
1485         if (wait_pid == -1)
1486                 return -1;
1487         return wstatus;
1488 }
1489
1490 /**************************************************************************
1491  Wrapper for Admin Logs.
1492 ****************************************************************************/
1493
1494  void sys_adminlog(int priority, const char *format_str, ...) 
1495 {
1496         va_list ap;
1497         int ret;
1498         char *msgbuf = NULL;
1499
1500         va_start( ap, format_str );
1501         ret = vasprintf( &msgbuf, format_str, ap );
1502         va_end( ap );
1503
1504         if (ret == -1)
1505                 return;
1506
1507 #if defined(HAVE_SYSLOG)
1508         syslog( priority, "%s", msgbuf );
1509 #else
1510         DEBUG(0,("%s", msgbuf ));
1511 #endif
1512         SAFE_FREE(msgbuf);
1513 }
1514
1515 /******** Solaris EA helper function prototypes ********/
1516 #ifdef HAVE_ATTROPEN
1517 #define SOLARIS_ATTRMODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP
1518 static int solaris_write_xattr(int attrfd, const char *value, size_t size);
1519 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size);
1520 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size);
1521 static int solaris_unlinkat(int attrdirfd, const char *name);
1522 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode);
1523 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode);
1524 #endif
1525
1526 /**************************************************************************
1527  Wrappers for extented attribute calls. Based on the Linux package with
1528  support for IRIX and (Net|Free)BSD also. Expand as other systems have them.
1529 ****************************************************************************/
1530
1531 ssize_t sys_getxattr (const char *path, const char *name, void *value, size_t size)
1532 {
1533 #if defined(HAVE_GETXATTR)
1534 #ifndef XATTR_ADD_OPT
1535         return getxattr(path, name, value, size);
1536 #else
1537         int options = 0;
1538         return getxattr(path, name, value, size, 0, options);
1539 #endif
1540 #elif defined(HAVE_GETEA)
1541         return getea(path, name, value, size);
1542 #elif defined(HAVE_EXTATTR_GET_FILE)
1543         char *s;
1544         ssize_t retval;
1545         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1546                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1547         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1548         /*
1549          * The BSD implementation has a nasty habit of silently truncating
1550          * the returned value to the size of the buffer, so we have to check
1551          * that the buffer is large enough to fit the returned value.
1552          */
1553         if((retval=extattr_get_file(path, attrnamespace, attrname, NULL, 0)) >= 0) {
1554                 if(retval > size) {
1555                         errno = ERANGE;
1556                         return -1;
1557                 }
1558                 if((retval=extattr_get_file(path, attrnamespace, attrname, value, size)) >= 0)
1559                         return retval;
1560         }
1561
1562         DEBUG(10,("sys_getxattr: extattr_get_file() failed with: %s\n", strerror(errno)));
1563         return -1;
1564 #elif defined(HAVE_ATTR_GET)
1565         int retval, flags = 0;
1566         int valuelength = (int)size;
1567         char *attrname = strchr(name,'.') + 1;
1568
1569         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1570
1571         retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
1572
1573         return retval ? retval : valuelength;
1574 #elif defined(HAVE_ATTROPEN)
1575         ssize_t ret = -1;
1576         int attrfd = solaris_attropen(path, name, O_RDONLY, 0);
1577         if (attrfd >= 0) {
1578                 ret = solaris_read_xattr(attrfd, value, size);
1579                 close(attrfd);
1580         }
1581         return ret;
1582 #else
1583         errno = ENOSYS;
1584         return -1;
1585 #endif
1586 }
1587
1588 ssize_t sys_lgetxattr (const char *path, const char *name, void *value, size_t size)
1589 {
1590 #if defined(HAVE_LGETXATTR)
1591         return lgetxattr(path, name, value, size);
1592 #elif defined(HAVE_GETXATTR) && defined(XATTR_ADD_OPT)
1593         int options = XATTR_NOFOLLOW;
1594         return getxattr(path, name, value, size, 0, options);
1595 #elif defined(HAVE_LGETEA)
1596         return lgetea(path, name, value, size);
1597 #elif defined(HAVE_EXTATTR_GET_LINK)
1598         char *s;
1599         ssize_t retval;
1600         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1601                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1602         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1603
1604         if((retval=extattr_get_link(path, attrnamespace, attrname, NULL, 0)) >= 0) {
1605                 if(retval > size) {
1606                         errno = ERANGE;
1607                         return -1;
1608                 }
1609                 if((retval=extattr_get_link(path, attrnamespace, attrname, value, size)) >= 0)
1610                         return retval;
1611         }
1612
1613         DEBUG(10,("sys_lgetxattr: extattr_get_link() failed with: %s\n", strerror(errno)));
1614         return -1;
1615 #elif defined(HAVE_ATTR_GET)
1616         int retval, flags = ATTR_DONTFOLLOW;
1617         int valuelength = (int)size;
1618         char *attrname = strchr(name,'.') + 1;
1619
1620         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1621
1622         retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
1623
1624         return retval ? retval : valuelength;
1625 #elif defined(HAVE_ATTROPEN)
1626         ssize_t ret = -1;
1627         int attrfd = solaris_attropen(path, name, O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
1628         if (attrfd >= 0) {
1629                 ret = solaris_read_xattr(attrfd, value, size);
1630                 close(attrfd);
1631         }
1632         return ret;
1633 #else
1634         errno = ENOSYS;
1635         return -1;
1636 #endif
1637 }
1638
1639 ssize_t sys_fgetxattr (int filedes, const char *name, void *value, size_t size)
1640 {
1641 #if defined(HAVE_FGETXATTR)
1642 #ifndef XATTR_ADD_OPT
1643         return fgetxattr(filedes, name, value, size);
1644 #else
1645         int options = 0;
1646         return fgetxattr(filedes, name, value, size, 0, options);
1647 #endif
1648 #elif defined(HAVE_FGETEA)
1649         return fgetea(filedes, name, value, size);
1650 #elif defined(HAVE_EXTATTR_GET_FD)
1651         char *s;
1652         ssize_t retval;
1653         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1654                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1655         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1656
1657         if((retval=extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0)) >= 0) {
1658                 if(retval > size) {
1659                         errno = ERANGE;
1660                         return -1;
1661                 }
1662                 if((retval=extattr_get_fd(filedes, attrnamespace, attrname, value, size)) >= 0)
1663                         return retval;
1664         }
1665
1666         DEBUG(10,("sys_fgetxattr: extattr_get_fd() failed with: %s\n", strerror(errno)));
1667         return -1;
1668 #elif defined(HAVE_ATTR_GETF)
1669         int retval, flags = 0;
1670         int valuelength = (int)size;
1671         char *attrname = strchr(name,'.') + 1;
1672
1673         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1674
1675         retval = attr_getf(filedes, attrname, (char *)value, &valuelength, flags);
1676
1677         return retval ? retval : valuelength;
1678 #elif defined(HAVE_ATTROPEN)
1679         ssize_t ret = -1;
1680         int attrfd = solaris_openat(filedes, name, O_RDONLY|O_XATTR, 0);
1681         if (attrfd >= 0) {
1682                 ret = solaris_read_xattr(attrfd, value, size);
1683                 close(attrfd);
1684         }
1685         return ret;
1686 #else
1687         errno = ENOSYS;
1688         return -1;
1689 #endif
1690 }
1691
1692 #if defined(HAVE_EXTATTR_LIST_FILE)
1693
1694 #define EXTATTR_PREFIX(s)       (s), (sizeof((s))-1)
1695
1696 static struct {
1697         int space;
1698         const char *name;
1699         size_t len;
1700
1701 extattr[] = {
1702         { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("system.") },
1703         { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("user.") },
1704 };
1705
1706 typedef union {
1707         const char *path;
1708         int filedes;
1709 } extattr_arg;
1710
1711 static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size)
1712 {
1713         ssize_t list_size, total_size = 0;
1714         int i, t, len;
1715         char *buf;
1716         /* Iterate through extattr(2) namespaces */
1717         for(t = 0; t < (sizeof(extattr)/sizeof(extattr[0])); t++) {
1718                 switch(type) {
1719 #if defined(HAVE_EXTATTR_LIST_FILE)
1720                         case 0:
1721                                 list_size = extattr_list_file(arg.path, extattr[t].space, list, size);
1722                                 break;
1723 #endif
1724 #if defined(HAVE_EXTATTR_LIST_LINK)
1725                         case 1:
1726                                 list_size = extattr_list_link(arg.path, extattr[t].space, list, size);
1727                                 break;
1728 #endif
1729 #if defined(HAVE_EXTATTR_LIST_FD)
1730                         case 2:
1731                                 list_size = extattr_list_fd(arg.filedes, extattr[t].space, list, size);
1732                                 break;
1733 #endif
1734                         default:
1735                                 errno = ENOSYS;
1736                                 return -1;
1737                 }
1738                 /* Some error happend. Errno should be set by the previous call */
1739                 if(list_size < 0)
1740                         return -1;
1741                 /* No attributes */
1742                 if(list_size == 0)
1743                         continue;
1744                 /* XXX: Call with an empty buffer may be used to calculate
1745                    necessary buffer size. Unfortunately, we can't say, how
1746                    many attributes were returned, so here is the potential
1747                    problem with the emulation.
1748                 */
1749                 if(list == NULL) {
1750                         /* Take the worse case of one char attribute names - 
1751                            two bytes per name plus one more for sanity.
1752                         */
1753                         total_size += list_size + (list_size/2 + 1)*extattr[t].len;
1754                         continue;
1755                 }
1756                 /* Count necessary offset to fit namespace prefixes */
1757                 len = 0;
1758                 for(i = 0; i < list_size; i += list[i] + 1)
1759                         len += extattr[t].len;
1760
1761                 total_size += list_size + len;
1762                 /* Buffer is too small to fit the results */
1763                 if(total_size > size) {
1764                         errno = ERANGE;
1765                         return -1;
1766                 }
1767                 /* Shift results back, so we can prepend prefixes */
1768                 buf = memmove(list + len, list, list_size);
1769
1770                 for(i = 0; i < list_size; i += len + 1) {
1771                         len = buf[i];
1772                         strncpy(list, extattr[t].name, extattr[t].len + 1);
1773                         list += extattr[t].len;
1774                         strncpy(list, buf + i + 1, len);
1775                         list[len] = '\0';
1776                         list += len + 1;
1777                 }
1778                 size -= total_size;
1779         }
1780         return total_size;
1781 }
1782
1783 #endif
1784
1785 #if defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1786 static char attr_buffer[ATTR_MAX_VALUELEN];
1787
1788 static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
1789 {
1790         int retval = 0, index;
1791         attrlist_cursor_t *cursor = 0;
1792         int total_size = 0;
1793         attrlist_t * al = (attrlist_t *)attr_buffer;
1794         attrlist_ent_t *ae;
1795         size_t ent_size, left = size;
1796         char *bp = list;
1797
1798         while (True) {
1799             if (filedes)
1800                 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1801             else
1802                 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1803             if (retval) break;
1804             for (index = 0; index < al->al_count; index++) {
1805                 ae = ATTR_ENTRY(attr_buffer, index);
1806                 ent_size = strlen(ae->a_name) + sizeof("user.");
1807                 if (left >= ent_size) {
1808                     strncpy(bp, "user.", sizeof("user."));
1809                     strncat(bp, ae->a_name, ent_size - sizeof("user."));
1810                     bp += ent_size;
1811                     left -= ent_size;
1812                 } else if (size) {
1813                     errno = ERANGE;
1814                     retval = -1;
1815                     break;
1816                 }
1817                 total_size += ent_size;
1818             }
1819             if (al->al_more == 0) break;
1820         }
1821         if (retval == 0) {
1822             flags |= ATTR_ROOT;
1823             cursor = 0;
1824             while (True) {
1825                 if (filedes)
1826                     retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1827                 else
1828                     retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1829                 if (retval) break;
1830                 for (index = 0; index < al->al_count; index++) {
1831                     ae = ATTR_ENTRY(attr_buffer, index);
1832                     ent_size = strlen(ae->a_name) + sizeof("system.");
1833                     if (left >= ent_size) {
1834                         strncpy(bp, "system.", sizeof("system."));
1835                         strncat(bp, ae->a_name, ent_size - sizeof("system."));
1836                         bp += ent_size;
1837                         left -= ent_size;
1838                     } else if (size) {
1839                         errno = ERANGE;
1840                         retval = -1;
1841                         break;
1842                     }
1843                     total_size += ent_size;
1844                 }
1845                 if (al->al_more == 0) break;
1846             }
1847         }
1848         return (ssize_t)(retval ? retval : total_size);
1849 }
1850
1851 #endif
1852
1853 ssize_t sys_listxattr (const char *path, char *list, size_t size)
1854 {
1855 #if defined(HAVE_LISTXATTR)
1856 #ifndef XATTR_ADD_OPT
1857         return listxattr(path, list, size);
1858 #else
1859         int options = 0;
1860         return listxattr(path, list, size, options);
1861 #endif
1862 #elif defined(HAVE_LISTEA)
1863         return listea(path, list, size);
1864 #elif defined(HAVE_EXTATTR_LIST_FILE)
1865         extattr_arg arg;
1866         arg.path = path;
1867         return bsd_attr_list(0, arg, list, size);
1868 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1869         return irix_attr_list(path, 0, list, size, 0);
1870 #elif defined(HAVE_ATTROPEN)
1871         ssize_t ret = -1;
1872         int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
1873         if (attrdirfd >= 0) {
1874                 ret = solaris_list_xattr(attrdirfd, list, size);
1875                 close(attrdirfd);
1876         }
1877         return ret;
1878 #else
1879         errno = ENOSYS;
1880         return -1;
1881 #endif
1882 }
1883
1884 ssize_t sys_llistxattr (const char *path, char *list, size_t size)
1885 {
1886 #if defined(HAVE_LLISTXATTR)
1887         return llistxattr(path, list, size);
1888 #elif defined(HAVE_LISTXATTR) && defined(XATTR_ADD_OPT)
1889         int options = XATTR_NOFOLLOW;
1890         return listxattr(path, list, size, options);
1891 #elif defined(HAVE_LLISTEA)
1892         return llistea(path, list, size);
1893 #elif defined(HAVE_EXTATTR_LIST_LINK)
1894         extattr_arg arg;
1895         arg.path = path;
1896         return bsd_attr_list(1, arg, list, size);
1897 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1898         return irix_attr_list(path, 0, list, size, ATTR_DONTFOLLOW);
1899 #elif defined(HAVE_ATTROPEN)
1900         ssize_t ret = -1;
1901         int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
1902         if (attrdirfd >= 0) {
1903                 ret = solaris_list_xattr(attrdirfd, list, size);
1904                 close(attrdirfd);
1905         }
1906         return ret;
1907 #else
1908         errno = ENOSYS;
1909         return -1;
1910 #endif
1911 }
1912
1913 ssize_t sys_flistxattr (int filedes, char *list, size_t size)
1914 {
1915 #if defined(HAVE_FLISTXATTR)
1916 #ifndef XATTR_ADD_OPT
1917         return flistxattr(filedes, list, size);
1918 #else
1919         int options = 0;
1920         return flistxattr(filedes, list, size, options);
1921 #endif
1922 #elif defined(HAVE_FLISTEA)
1923         return flistea(filedes, list, size);
1924 #elif defined(HAVE_EXTATTR_LIST_FD)
1925         extattr_arg arg;
1926         arg.filedes = filedes;
1927         return bsd_attr_list(2, arg, list, size);
1928 #elif defined(HAVE_ATTR_LISTF)
1929         return irix_attr_list(NULL, filedes, list, size, 0);
1930 #elif defined(HAVE_ATTROPEN)
1931         ssize_t ret = -1;
1932         int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
1933         if (attrdirfd >= 0) {
1934                 ret = solaris_list_xattr(attrdirfd, list, size);
1935                 close(attrdirfd);
1936         }
1937         return ret;
1938 #else
1939         errno = ENOSYS;
1940         return -1;
1941 #endif
1942 }
1943
1944 int sys_removexattr (const char *path, const char *name)
1945 {
1946 #if defined(HAVE_REMOVEXATTR)
1947 #ifndef XATTR_ADD_OPT
1948         return removexattr(path, name);
1949 #else
1950         int options = 0;
1951         return removexattr(path, name, options);
1952 #endif
1953 #elif defined(HAVE_REMOVEEA)
1954         return removeea(path, name);
1955 #elif defined(HAVE_EXTATTR_DELETE_FILE)
1956         char *s;
1957         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1958                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1959         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1960
1961         return extattr_delete_file(path, attrnamespace, attrname);
1962 #elif defined(HAVE_ATTR_REMOVE)
1963         int flags = 0;
1964         char *attrname = strchr(name,'.') + 1;
1965
1966         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1967
1968         return attr_remove(path, attrname, flags);
1969 #elif defined(HAVE_ATTROPEN)
1970         int ret = -1;
1971         int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
1972         if (attrdirfd >= 0) {
1973                 ret = solaris_unlinkat(attrdirfd, name);
1974                 close(attrdirfd);
1975         }
1976         return ret;
1977 #else
1978         errno = ENOSYS;
1979         return -1;
1980 #endif
1981 }
1982
1983 int sys_lremovexattr (const char *path, const char *name)
1984 {
1985 #if defined(HAVE_LREMOVEXATTR)
1986         return lremovexattr(path, name);
1987 #elif defined(HAVE_REMOVEXATTR) && defined(XATTR_ADD_OPT)
1988         int options = XATTR_NOFOLLOW;
1989         return removexattr(path, name, options);
1990 #elif defined(HAVE_LREMOVEEA)
1991         return lremoveea(path, name);
1992 #elif defined(HAVE_EXTATTR_DELETE_LINK)
1993         char *s;
1994         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1995                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1996         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1997
1998         return extattr_delete_link(path, attrnamespace, attrname);
1999 #elif defined(HAVE_ATTR_REMOVE)
2000         int flags = ATTR_DONTFOLLOW;
2001         char *attrname = strchr(name,'.') + 1;
2002
2003         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
2004
2005         return attr_remove(path, attrname, flags);
2006 #elif defined(HAVE_ATTROPEN)
2007         int ret = -1;
2008         int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
2009         if (attrdirfd >= 0) {
2010                 ret = solaris_unlinkat(attrdirfd, name);
2011                 close(attrdirfd);
2012         }
2013         return ret;
2014 #else
2015         errno = ENOSYS;
2016         return -1;
2017 #endif
2018 }
2019
2020 int sys_fremovexattr (int filedes, const char *name)
2021 {
2022 #if defined(HAVE_FREMOVEXATTR)
2023 #ifndef XATTR_ADD_OPT
2024         return fremovexattr(filedes, name);
2025 #else
2026         int options = 0;
2027         return fremovexattr(filedes, name, options);
2028 #endif
2029 #elif defined(HAVE_FREMOVEEA)
2030         return fremoveea(filedes, name);
2031 #elif defined(HAVE_EXTATTR_DELETE_FD)
2032         char *s;
2033         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
2034                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
2035         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
2036
2037         return extattr_delete_fd(filedes, attrnamespace, attrname);
2038 #elif defined(HAVE_ATTR_REMOVEF)
2039         int flags = 0;
2040         char *attrname = strchr(name,'.') + 1;
2041
2042         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
2043
2044         return attr_removef(filedes, attrname, flags);
2045 #elif defined(HAVE_ATTROPEN)
2046         int ret = -1;
2047         int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
2048         if (attrdirfd >= 0) {
2049                 ret = solaris_unlinkat(attrdirfd, name);
2050                 close(attrdirfd);
2051         }
2052         return ret;
2053 #else
2054         errno = ENOSYS;
2055         return -1;
2056 #endif
2057 }
2058
2059 int sys_setxattr (const char *path, const char *name, const void *value, size_t size, int flags)
2060 {
2061 #if defined(HAVE_SETXATTR)
2062 #ifndef XATTR_ADD_OPT
2063         return setxattr(path, name, value, size, flags);
2064 #else
2065         int options = 0;
2066         return setxattr(path, name, value, size, 0, options);
2067 #endif
2068 #elif defined(HAVE_SETEA)
2069         return setea(path, name, value, size, flags);
2070 #elif defined(HAVE_EXTATTR_SET_FILE)
2071         char *s;
2072         int retval = 0;
2073         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
2074                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
2075         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
2076         if (flags) {
2077                 /* Check attribute existence */
2078                 retval = extattr_get_file(path, attrnamespace, attrname, NULL, 0);
2079                 if (retval < 0) {
2080                         /* REPLACE attribute, that doesn't exist */
2081                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
2082                                 errno = ENOATTR;
2083                                 return -1;
2084                         }
2085                         /* Ignore other errors */
2086                 }
2087                 else {
2088                         /* CREATE attribute, that already exists */
2089                         if (flags & XATTR_CREATE) {
2090                                 errno = EEXIST;
2091                                 return -1;
2092                         }
2093                 }
2094         }
2095         retval = extattr_set_file(path, attrnamespace, attrname, value, size);
2096         return (retval < 0) ? -1 : 0;
2097 #elif defined(HAVE_ATTR_SET)
2098         int myflags = 0;
2099         char *attrname = strchr(name,'.') + 1;
2100
2101         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
2102         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
2103         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
2104
2105         return attr_set(path, attrname, (const char *)value, size, myflags);
2106 #elif defined(HAVE_ATTROPEN)
2107         int ret = -1;
2108         int myflags = O_RDWR;
2109         int attrfd;
2110         if (flags & XATTR_CREATE) myflags |= O_EXCL;
2111         if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
2112         attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
2113         if (attrfd >= 0) {
2114                 ret = solaris_write_xattr(attrfd, value, size);
2115                 close(attrfd);
2116         }
2117         return ret;
2118 #else
2119         errno = ENOSYS;
2120         return -1;
2121 #endif
2122 }
2123
2124 int sys_lsetxattr (const char *path, const char *name, const void *value, size_t size, int flags)
2125 {
2126 #if defined(HAVE_LSETXATTR)
2127         return lsetxattr(path, name, value, size, flags);
2128 #elif defined(HAVE_SETXATTR) && defined(XATTR_ADD_OPT)
2129         int options = XATTR_NOFOLLOW;
2130         return setxattr(path, name, value, size, 0, options);
2131 #elif defined(LSETEA)
2132         return lsetea(path, name, value, size, flags);
2133 #elif defined(HAVE_EXTATTR_SET_LINK)
2134         char *s;
2135         int retval = 0;
2136         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
2137                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
2138         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
2139         if (flags) {
2140                 /* Check attribute existence */
2141                 retval = extattr_get_link(path, attrnamespace, attrname, NULL, 0);
2142                 if (retval < 0) {
2143                         /* REPLACE attribute, that doesn't exist */
2144                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
2145                                 errno = ENOATTR;
2146                                 return -1;
2147                         }
2148                         /* Ignore other errors */
2149                 }
2150                 else {
2151                         /* CREATE attribute, that already exists */
2152                         if (flags & XATTR_CREATE) {
2153                                 errno = EEXIST;
2154                                 return -1;
2155                         }
2156                 }
2157         }
2158
2159         retval = extattr_set_link(path, attrnamespace, attrname, value, size);
2160         return (retval < 0) ? -1 : 0;
2161 #elif defined(HAVE_ATTR_SET)
2162         int myflags = ATTR_DONTFOLLOW;
2163         char *attrname = strchr(name,'.') + 1;
2164
2165         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
2166         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
2167         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
2168
2169         return attr_set(path, attrname, (const char *)value, size, myflags);
2170 #elif defined(HAVE_ATTROPEN)
2171         int ret = -1;
2172         int myflags = O_RDWR | AT_SYMLINK_NOFOLLOW;
2173         int attrfd;
2174         if (flags & XATTR_CREATE) myflags |= O_EXCL;
2175         if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
2176         attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
2177         if (attrfd >= 0) {
2178                 ret = solaris_write_xattr(attrfd, value, size);
2179                 close(attrfd);
2180         }
2181         return ret;
2182 #else
2183         errno = ENOSYS;
2184         return -1;
2185 #endif
2186 }
2187
2188 int sys_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags)
2189 {
2190 #if defined(HAVE_FSETXATTR)
2191 #ifndef XATTR_ADD_OPT
2192         return fsetxattr(filedes, name, value, size, flags);
2193 #else
2194         int options = 0;
2195         return fsetxattr(filedes, name, value, size, 0, options);
2196 #endif
2197 #elif defined(HAVE_FSETEA)
2198         return fsetea(filedes, name, value, size, flags);
2199 #elif defined(HAVE_EXTATTR_SET_FD)
2200         char *s;
2201         int retval = 0;
2202         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
2203                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
2204         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
2205         if (flags) {
2206                 /* Check attribute existence */
2207                 retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
2208                 if (retval < 0) {
2209                         /* REPLACE attribute, that doesn't exist */
2210                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
2211                                 errno = ENOATTR;
2212                                 return -1;
2213                         }
2214                         /* Ignore other errors */
2215                 }
2216                 else {
2217                         /* CREATE attribute, that already exists */
2218                         if (flags & XATTR_CREATE) {
2219                                 errno = EEXIST;
2220                                 return -1;
2221                         }
2222                 }
2223         }
2224         retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size);
2225         return (retval < 0) ? -1 : 0;
2226 #elif defined(HAVE_ATTR_SETF)
2227         int myflags = 0;
2228         char *attrname = strchr(name,'.') + 1;
2229
2230         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
2231         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
2232         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
2233
2234         return attr_setf(filedes, attrname, (const char *)value, size, myflags);
2235 #elif defined(HAVE_ATTROPEN)
2236         int ret = -1;
2237         int myflags = O_RDWR | O_XATTR;
2238         int attrfd;
2239         if (flags & XATTR_CREATE) myflags |= O_EXCL;
2240         if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
2241         attrfd = solaris_openat(filedes, name, myflags, (mode_t) SOLARIS_ATTRMODE);
2242         if (attrfd >= 0) {
2243                 ret = solaris_write_xattr(attrfd, value, size);
2244                 close(attrfd);
2245         }
2246         return ret;
2247 #else
2248         errno = ENOSYS;
2249         return -1;
2250 #endif
2251 }
2252
2253 /**************************************************************************
2254  helper functions for Solaris' EA support
2255 ****************************************************************************/
2256 #ifdef HAVE_ATTROPEN
2257 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size)
2258 {
2259         struct stat sbuf;
2260
2261         if (fstat(attrfd, &sbuf) == -1) {
2262                 errno = ENOATTR;
2263                 return -1;
2264         }
2265
2266         /* This is to return the current size of the named extended attribute */
2267         if (size == 0) {
2268                 return sbuf.st_size;
2269         }
2270
2271         /* check size and read xattr */
2272         if (sbuf.st_size > size) {
2273                 errno = ERANGE;
2274                 return -1;
2275         }
2276
2277         return read(attrfd, value, sbuf.st_size);
2278 }
2279
2280 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size)
2281 {
2282         ssize_t len = 0;
2283         DIR *dirp;
2284         struct dirent *de;
2285         int newfd = dup(attrdirfd);
2286         /* CAUTION: The originating file descriptor should not be
2287                     used again following the call to fdopendir().
2288                     For that reason we dup() the file descriptor
2289                     here to make things more clear. */
2290         dirp = fdopendir(newfd);
2291
2292         while ((de = readdir(dirp))) {
2293                 size_t listlen = strlen(de->d_name);
2294                 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
2295                         /* we don't want "." and ".." here: */
2296                         DEBUG(10,("skipped EA %s\n",de->d_name));
2297                         continue;
2298                 }
2299
2300                 if (size == 0) {
2301                         /* return the current size of the list of extended attribute names*/
2302                         len += listlen + 1;
2303                 } else {
2304                         /* check size and copy entrieÑ• + nul into list. */
2305                         if ((len + listlen + 1) > size) {
2306                                 errno = ERANGE;
2307                                 len = -1;
2308                                 break;
2309                         } else {
2310                                 safe_strcpy(list + len, de->d_name, listlen);
2311                                 len += listlen;
2312                                 list[len] = '\0';
2313                                 ++len;
2314                         }
2315                 }
2316         }
2317
2318         if (closedir(dirp) == -1) {
2319                 DEBUG(0,("closedir dirp failed: %s\n",strerror(errno)));
2320                 return -1;
2321         }
2322         return len;
2323 }
2324
2325 static int solaris_unlinkat(int attrdirfd, const char *name)
2326 {
2327         if (unlinkat(attrdirfd, name, 0) == -1) {
2328                 if (errno == ENOENT) {
2329                         errno = ENOATTR;
2330                 }
2331                 return -1;
2332         }
2333         return 0;
2334 }
2335
2336 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode)
2337 {
2338         int filedes = attropen(path, attrpath, oflag, mode);
2339         if (filedes == -1) {
2340                 DEBUG(10,("attropen FAILED: path: %s, name: %s, errno: %s\n",path,attrpath,strerror(errno)));
2341                 if (errno == EINVAL) {
2342                         errno = ENOTSUP;
2343                 } else {
2344                         errno = ENOATTR;
2345                 }
2346         }
2347         return filedes;
2348 }
2349
2350 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
2351 {
2352         int filedes = openat(fildes, path, oflag, mode);
2353         if (filedes == -1) {
2354                 DEBUG(10,("openat FAILED: fd: %d, path: %s, errno: %s\n",filedes,path,strerror(errno)));
2355                 if (errno == EINVAL) {
2356                         errno = ENOTSUP;
2357                 } else {
2358                         errno = ENOATTR;
2359                 }
2360         }
2361         return filedes;
2362 }
2363
2364 static int solaris_write_xattr(int attrfd, const char *value, size_t size)
2365 {
2366         if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) {
2367                 return 0;
2368         } else {
2369                 DEBUG(10,("solaris_write_xattr FAILED!\n"));
2370                 return -1;
2371         }
2372 }
2373 #endif /*HAVE_ATTROPEN*/
2374
2375
2376 /****************************************************************************
2377  Return the major devicenumber for UNIX extensions.
2378 ****************************************************************************/
2379
2380 uint32 unix_dev_major(SMB_DEV_T dev)
2381 {
2382 #if defined(HAVE_DEVICE_MAJOR_FN)
2383         return (uint32)major(dev);
2384 #else
2385         return (uint32)(dev >> 8);
2386 #endif
2387 }
2388
2389 /****************************************************************************
2390  Return the minor devicenumber for UNIX extensions.
2391 ****************************************************************************/
2392
2393 uint32 unix_dev_minor(SMB_DEV_T dev)
2394 {
2395 #if defined(HAVE_DEVICE_MINOR_FN)
2396         return (uint32)minor(dev);
2397 #else
2398         return (uint32)(dev & 0xff);
2399 #endif
2400 }
2401
2402 #if defined(WITH_AIO)
2403
2404 /*******************************************************************
2405  An aio_read wrapper that will deal with 64-bit sizes.
2406 ********************************************************************/
2407
2408 int sys_aio_read(SMB_STRUCT_AIOCB *aiocb)
2409 {
2410 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_READ64)
2411         return aio_read64(aiocb);
2412 #elif defined(HAVE_AIO_READ)
2413         return aio_read(aiocb);
2414 #else
2415         errno = ENOSYS;
2416         return -1;
2417 #endif
2418 }
2419
2420 /*******************************************************************
2421  An aio_write wrapper that will deal with 64-bit sizes.
2422 ********************************************************************/
2423
2424 int sys_aio_write(SMB_STRUCT_AIOCB *aiocb)
2425 {
2426 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_WRITE64)
2427         return aio_write64(aiocb);
2428 #elif defined(HAVE_AIO_WRITE)
2429         return aio_write(aiocb);
2430 #else
2431         errno = ENOSYS;
2432         return -1;
2433 #endif
2434 }
2435
2436 /*******************************************************************
2437  An aio_return wrapper that will deal with 64-bit sizes.
2438 ********************************************************************/
2439
2440 ssize_t sys_aio_return(SMB_STRUCT_AIOCB *aiocb)
2441 {
2442 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_RETURN64)
2443         return aio_return64(aiocb);
2444 #elif defined(HAVE_AIO_RETURN)
2445         return aio_return(aiocb);
2446 #else
2447         errno = ENOSYS;
2448         return -1;
2449 #endif
2450 }
2451
2452 /*******************************************************************
2453  An aio_cancel wrapper that will deal with 64-bit sizes.
2454 ********************************************************************/
2455
2456 int sys_aio_cancel(int fd, SMB_STRUCT_AIOCB *aiocb)
2457 {
2458 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_CANCEL64)
2459         return aio_cancel64(fd, aiocb);
2460 #elif defined(HAVE_AIO_CANCEL)
2461         return aio_cancel(fd, aiocb);
2462 #else
2463         errno = ENOSYS;
2464         return -1;
2465 #endif
2466 }
2467
2468 /*******************************************************************
2469  An aio_error wrapper that will deal with 64-bit sizes.
2470 ********************************************************************/
2471
2472 int sys_aio_error(const SMB_STRUCT_AIOCB *aiocb)
2473 {
2474 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_ERROR64)
2475         return aio_error64(aiocb);
2476 #elif defined(HAVE_AIO_ERROR)
2477         return aio_error(aiocb);
2478 #else
2479         errno = ENOSYS;
2480         return -1;
2481 #endif
2482 }
2483
2484 /*******************************************************************
2485  An aio_fsync wrapper that will deal with 64-bit sizes.
2486 ********************************************************************/
2487
2488 int sys_aio_fsync(int op, SMB_STRUCT_AIOCB *aiocb)
2489 {
2490 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_FSYNC64)
2491         return aio_fsync64(op, aiocb);
2492 #elif defined(HAVE_AIO_FSYNC)
2493         return aio_fsync(op, aiocb);
2494 #else
2495         errno = ENOSYS;
2496         return -1;
2497 #endif
2498 }
2499
2500 /*******************************************************************
2501  An aio_fsync wrapper that will deal with 64-bit sizes.
2502 ********************************************************************/
2503
2504 int sys_aio_suspend(const SMB_STRUCT_AIOCB * const cblist[], int n, const struct timespec *timeout)
2505 {
2506 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_SUSPEND64)
2507         return aio_suspend64(cblist, n, timeout);
2508 #elif defined(HAVE_AIO_FSYNC)
2509         return aio_suspend(cblist, n, timeout);
2510 #else
2511         errno = ENOSYS;
2512         return -1;
2513 #endif
2514 }
2515 #else /* !WITH_AIO */
2516
2517 int sys_aio_read(SMB_STRUCT_AIOCB *aiocb)
2518 {
2519         errno = ENOSYS;
2520         return -1;
2521 }
2522
2523 int sys_aio_write(SMB_STRUCT_AIOCB *aiocb)
2524 {
2525         errno = ENOSYS;
2526         return -1;
2527 }
2528
2529 ssize_t sys_aio_return(SMB_STRUCT_AIOCB *aiocb)
2530 {
2531         errno = ENOSYS;
2532         return -1;
2533 }
2534
2535 int sys_aio_cancel(int fd, SMB_STRUCT_AIOCB *aiocb)
2536 {
2537         errno = ENOSYS;
2538         return -1;
2539 }
2540
2541 int sys_aio_error(const SMB_STRUCT_AIOCB *aiocb)
2542 {
2543         errno = ENOSYS;
2544         return -1;
2545 }
2546
2547 int sys_aio_fsync(int op, SMB_STRUCT_AIOCB *aiocb)
2548 {
2549         errno = ENOSYS;
2550         return -1;
2551 }
2552
2553 int sys_aio_suspend(const SMB_STRUCT_AIOCB * const cblist[], int n, const struct timespec *timeout)
2554 {
2555         errno = ENOSYS;
2556         return -1;
2557 }
2558 #endif /* WITH_AIO */
2559
2560 int sys_getpeereid( int s, uid_t *uid)
2561 {
2562 #if defined(HAVE_PEERCRED)
2563         struct ucred cred;
2564         socklen_t cred_len = sizeof(struct ucred);
2565         int ret;
2566
2567         ret = getsockopt(s, SOL_SOCKET, SO_PEERCRED, (void *)&cred, &cred_len);
2568         if (ret != 0) {
2569                 return -1;
2570         }
2571
2572         if (cred_len != sizeof(struct ucred)) {
2573                 errno = EINVAL;
2574                 return -1;
2575         }
2576
2577         *uid = cred.uid;
2578         return 0;
2579 #else
2580         errno = ENOSYS;
2581         return -1;
2582 #endif
2583 }
2584
2585 int sys_getnameinfo(const struct sockaddr *psa,
2586                         socklen_t salen,
2587                         char *host,
2588                         size_t hostlen,
2589                         char *service,
2590                         size_t servlen,
2591                         int flags)
2592 {
2593         /*
2594          * For Solaris we must make sure salen is the
2595          * correct length for the incoming sa_family.
2596          */
2597
2598         if (salen == sizeof(struct sockaddr_storage)) {
2599                 salen = sizeof(struct sockaddr_in);
2600 #if defined(HAVE_IPV6)
2601                 if (psa->sa_family == AF_INET6) {
2602                         salen = sizeof(struct sockaddr_in6);
2603                 }
2604 #endif
2605         }
2606         return getnameinfo(psa, salen, host, hostlen, service, servlen, flags);
2607 }
2608
2609 int sys_connect(int fd, const struct sockaddr * addr)
2610 {
2611         socklen_t salen = -1;
2612
2613         if (addr->sa_family == AF_INET) {
2614             salen = sizeof(struct sockaddr_in);
2615         } else if (addr->sa_family == AF_UNIX) {
2616             salen = sizeof(struct sockaddr_un);
2617         }
2618 #if defined(HAVE_IPV6)
2619         else if (addr->sa_family == AF_INET6) {
2620             salen = sizeof(struct sockaddr_in6);
2621         }
2622 #endif
2623
2624         return connect(fd, addr, salen);
2625 }