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