build: Remove sys_open 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 /*******************************************************************
588  An fopen() wrapper.
589 ********************************************************************/
590
591 FILE *sys_fopen(const char *path, const char *type)
592 {
593         return fopen(path, type);
594 }
595
596
597 #if HAVE_KERNEL_SHARE_MODES
598 #ifndef LOCK_MAND
599 #define LOCK_MAND       32      /* This is a mandatory flock */
600 #define LOCK_READ       64      /* ... Which allows concurrent read operations */
601 #define LOCK_WRITE      128     /* ... Which allows concurrent write operations */
602 #define LOCK_RW         192     /* ... Which allows concurrent read & write ops */
603 #endif
604 #endif
605
606 /*******************************************************************
607  A flock() wrapper that will perform the kernel flock.
608 ********************************************************************/
609
610 void kernel_flock(int fd, uint32 share_mode, uint32 access_mask)
611 {
612 #if HAVE_KERNEL_SHARE_MODES
613         int kernel_mode = 0;
614         if (share_mode == FILE_SHARE_WRITE) {
615                 kernel_mode = LOCK_MAND|LOCK_WRITE;
616         } else if (share_mode == FILE_SHARE_READ) {
617                 kernel_mode = LOCK_MAND|LOCK_READ;
618         } else if (share_mode == FILE_SHARE_NONE) {
619                 kernel_mode = LOCK_MAND;
620         }
621         if (kernel_mode) {
622                 flock(fd, kernel_mode);
623         }
624 #endif
625         ;
626 }
627
628
629
630 /*******************************************************************
631  An opendir wrapper.
632 ********************************************************************/
633
634 SMB_STRUCT_DIR *sys_opendir(const char *name)
635 {
636         return opendir(name);
637 }
638
639 /*******************************************************************
640  An fdopendir wrapper.
641  Ugly hack - we need dirfd for this to work correctly in the
642  calling code.. JRA.
643 ********************************************************************/
644
645 SMB_STRUCT_DIR *sys_fdopendir(int fd)
646 {
647 #if defined(HAVE_FDOPENDIR) && defined(HAVE_DIRFD)
648         return fdopendir(fd);
649 #else
650         errno = ENOSYS;
651         return NULL;
652 #endif
653 }
654
655 /*******************************************************************
656  A readdir wrapper.
657 ********************************************************************/
658
659 SMB_STRUCT_DIRENT *sys_readdir(SMB_STRUCT_DIR *dirp)
660 {
661         return readdir(dirp);
662 }
663
664 /*******************************************************************
665  A seekdir wrapper.
666 ********************************************************************/
667
668 void sys_seekdir(SMB_STRUCT_DIR *dirp, long offset)
669 {
670         seekdir(dirp, offset);
671 }
672
673 /*******************************************************************
674  A telldir wrapper.
675 ********************************************************************/
676
677 long sys_telldir(SMB_STRUCT_DIR *dirp)
678 {
679         return (long)telldir(dirp);
680 }
681
682 /*******************************************************************
683  A rewinddir wrapper.
684 ********************************************************************/
685
686 void sys_rewinddir(SMB_STRUCT_DIR *dirp)
687 {
688         rewinddir(dirp);
689 }
690
691 /*******************************************************************
692  A close wrapper.
693 ********************************************************************/
694
695 int sys_closedir(SMB_STRUCT_DIR *dirp)
696 {
697         return closedir(dirp);
698 }
699
700 /*******************************************************************
701  An mknod() wrapper.
702 ********************************************************************/
703
704 int sys_mknod(const char *path, mode_t mode, SMB_DEV_T dev)
705 {
706 #if defined(HAVE_MKNOD)
707         return mknod(path, mode, dev);
708 #else
709         /* No mknod system call. */
710         errno = ENOSYS;
711         return -1;
712 #endif
713 }
714
715 /*******************************************************************
716 The wait() calls vary between systems
717 ********************************************************************/
718
719 int sys_waitpid(pid_t pid,int *status,int options)
720 {
721 #ifdef HAVE_WAITPID
722         return waitpid(pid,status,options);
723 #else /* HAVE_WAITPID */
724         return wait4(pid, status, options, NULL);
725 #endif /* HAVE_WAITPID */
726 }
727
728 /*******************************************************************
729  System wrapper for getwd. Always returns MALLOC'ed memory, or NULL
730  on error (malloc fail usually).
731 ********************************************************************/
732
733 char *sys_getwd(void)
734 {
735 #ifdef GETCWD_TAKES_NULL
736         return getcwd(NULL, 0);
737 #elif HAVE_GETCWD
738         char *wd = NULL, *s = NULL;
739         size_t allocated = PATH_MAX;
740
741         while (1) {
742                 s = SMB_REALLOC_ARRAY(s, char, allocated);
743                 if (s == NULL) {
744                         return NULL;
745                 }
746                 wd = getcwd(s, allocated);
747                 if (wd) {
748                         break;
749                 }
750                 if (errno != ERANGE) {
751                         SAFE_FREE(s);
752                         break;
753                 }
754                 allocated *= 2;
755                 if (allocated < PATH_MAX) {
756                         SAFE_FREE(s);
757                         break;
758                 }
759         }
760         return wd;
761 #else
762         char *s = SMB_MALLOC_ARRAY(char, PATH_MAX);
763         if (s == NULL) {
764                 return NULL;
765         }
766         return getwd(s);
767 #endif
768 }
769
770 #if defined(HAVE_POSIX_CAPABILITIES)
771
772 /**************************************************************************
773  Try and abstract process capabilities (for systems that have them).
774 ****************************************************************************/
775
776 /* Set the POSIX capabilities needed for the given purpose into the effective
777  * capability set of the current process. Make sure they are always removed
778  * from the inheritable set, because there is no circumstance in which our
779  * children should inherit our elevated privileges.
780  */
781 static bool set_process_capability(enum smbd_capability capability,
782                                    bool enable)
783 {
784         cap_value_t cap_vals[2] = {0};
785         int num_cap_vals = 0;
786
787         cap_t cap;
788
789 #if defined(HAVE_PRCTL) && defined(PR_GET_KEEPCAPS) && defined(PR_SET_KEEPCAPS)
790         /* On Linux, make sure that any capabilities we grab are sticky
791          * across UID changes. We expect that this would allow us to keep both
792          * the effective and permitted capability sets, but as of circa 2.6.16,
793          * only the permitted set is kept. It is a bug (which we work around)
794          * that the effective set is lost, but we still require the effective
795          * set to be kept.
796          */
797         if (!prctl(PR_GET_KEEPCAPS)) {
798                 prctl(PR_SET_KEEPCAPS, 1);
799         }
800 #endif
801
802         cap = cap_get_proc();
803         if (cap == NULL) {
804                 DEBUG(0,("set_process_capability: cap_get_proc failed: %s\n",
805                         strerror(errno)));
806                 return False;
807         }
808
809         switch (capability) {
810                 case KERNEL_OPLOCK_CAPABILITY:
811 #ifdef CAP_NETWORK_MGT
812                         /* IRIX has CAP_NETWORK_MGT for oplocks. */
813                         cap_vals[num_cap_vals++] = CAP_NETWORK_MGT;
814 #endif
815                         break;
816                 case DMAPI_ACCESS_CAPABILITY:
817 #ifdef CAP_DEVICE_MGT
818                         /* IRIX has CAP_DEVICE_MGT for DMAPI access. */
819                         cap_vals[num_cap_vals++] = CAP_DEVICE_MGT;
820 #elif CAP_MKNOD
821                         /* Linux has CAP_MKNOD for DMAPI access. */
822                         cap_vals[num_cap_vals++] = CAP_MKNOD;
823 #endif
824                         break;
825                 case LEASE_CAPABILITY:
826 #ifdef CAP_LEASE
827                         cap_vals[num_cap_vals++] = CAP_LEASE;
828 #endif
829                         break;
830         }
831
832         SMB_ASSERT(num_cap_vals <= ARRAY_SIZE(cap_vals));
833
834         if (num_cap_vals == 0) {
835                 cap_free(cap);
836                 return True;
837         }
838
839         cap_set_flag(cap, CAP_EFFECTIVE, num_cap_vals, cap_vals,
840                 enable ? CAP_SET : CAP_CLEAR);
841
842         /* We never want to pass capabilities down to our children, so make
843          * sure they are not inherited.
844          */
845         cap_set_flag(cap, CAP_INHERITABLE, num_cap_vals, cap_vals, CAP_CLEAR);
846
847         if (cap_set_proc(cap) == -1) {
848                 DEBUG(0, ("set_process_capability: cap_set_proc failed: %s\n",
849                         strerror(errno)));
850                 cap_free(cap);
851                 return False;
852         }
853
854         cap_free(cap);
855         return True;
856 }
857
858 #endif /* HAVE_POSIX_CAPABILITIES */
859
860 /****************************************************************************
861  Gain the oplock capability from the kernel if possible.
862 ****************************************************************************/
863
864 void set_effective_capability(enum smbd_capability capability)
865 {
866 #if defined(HAVE_POSIX_CAPABILITIES)
867         set_process_capability(capability, True);
868 #endif /* HAVE_POSIX_CAPABILITIES */
869 }
870
871 void drop_effective_capability(enum smbd_capability capability)
872 {
873 #if defined(HAVE_POSIX_CAPABILITIES)
874         set_process_capability(capability, False);
875 #endif /* HAVE_POSIX_CAPABILITIES */
876 }
877
878 /**************************************************************************
879  Wrapper for random().
880 ****************************************************************************/
881
882 long sys_random(void)
883 {
884 #if defined(HAVE_RANDOM)
885         return (long)random();
886 #elif defined(HAVE_RAND)
887         return (long)rand();
888 #else
889         DEBUG(0,("Error - no random function available !\n"));
890         exit(1);
891 #endif
892 }
893
894 /**************************************************************************
895  Wrapper for srandom().
896 ****************************************************************************/
897
898 void sys_srandom(unsigned int seed)
899 {
900 #if defined(HAVE_SRANDOM)
901         srandom(seed);
902 #elif defined(HAVE_SRAND)
903         srand(seed);
904 #else
905         DEBUG(0,("Error - no srandom function available !\n"));
906         exit(1);
907 #endif
908 }
909
910 #ifndef NGROUPS_MAX
911 #define NGROUPS_MAX 32 /* Guess... */
912 #endif
913
914 /**************************************************************************
915  Returns equivalent to NGROUPS_MAX - using sysconf if needed.
916 ****************************************************************************/
917
918 int groups_max(void)
919 {
920 #if defined(SYSCONF_SC_NGROUPS_MAX)
921         int ret = sysconf(_SC_NGROUPS_MAX);
922         return (ret == -1) ? NGROUPS_MAX : ret;
923 #else
924         return NGROUPS_MAX;
925 #endif
926 }
927
928 /**************************************************************************
929  Wrap setgroups and getgroups for systems that declare getgroups() as
930  returning an array of gid_t, but actuall return an array of int.
931 ****************************************************************************/
932
933 #if defined(HAVE_BROKEN_GETGROUPS)
934
935 #ifdef HAVE_BROKEN_GETGROUPS
936 #define GID_T int
937 #else
938 #define GID_T gid_t
939 #endif
940
941 static int sys_broken_getgroups(int setlen, gid_t *gidset)
942 {
943         GID_T gid;
944         GID_T *group_list;
945         int i, ngroups;
946
947         if(setlen == 0) {
948                 return getgroups(setlen, &gid);
949         }
950
951         /*
952          * Broken case. We need to allocate a
953          * GID_T array of size setlen.
954          */
955
956         if(setlen < 0) {
957                 errno = EINVAL; 
958                 return -1;
959         } 
960
961         if (setlen == 0)
962                 setlen = groups_max();
963
964         if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
965                 DEBUG(0,("sys_getgroups: Malloc fail.\n"));
966                 return -1;
967         }
968
969         if((ngroups = getgroups(setlen, group_list)) < 0) {
970                 int saved_errno = errno;
971                 SAFE_FREE(group_list);
972                 errno = saved_errno;
973                 return -1;
974         }
975
976         for(i = 0; i < ngroups; i++)
977                 gidset[i] = (gid_t)group_list[i];
978
979         SAFE_FREE(group_list);
980         return ngroups;
981 }
982
983 static int sys_broken_setgroups(int setlen, gid_t *gidset)
984 {
985         GID_T *group_list;
986         int i ; 
987
988         if (setlen == 0)
989                 return 0 ;
990
991         if (setlen < 0 || setlen > groups_max()) {
992                 errno = EINVAL; 
993                 return -1;   
994         }
995
996         /*
997          * Broken case. We need to allocate a
998          * GID_T array of size setlen.
999          */
1000
1001         if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
1002                 DEBUG(0,("sys_setgroups: Malloc fail.\n"));
1003                 return -1;    
1004         }
1005
1006         for(i = 0; i < setlen; i++) 
1007                 group_list[i] = (GID_T) gidset[i]; 
1008
1009         if(setgroups(setlen, group_list) != 0) {
1010                 int saved_errno = errno;
1011                 SAFE_FREE(group_list);
1012                 errno = saved_errno;
1013                 return -1;
1014         }
1015
1016         SAFE_FREE(group_list);
1017         return 0 ;
1018 }
1019
1020 #endif /* HAVE_BROKEN_GETGROUPS */
1021
1022 /* This is a list of systems that require the first GID passed to setgroups(2)
1023  * to be the effective GID. If your system is one of these, add it here.
1024  */
1025 #if defined (FREEBSD) || defined (DARWINOS)
1026 #define USE_BSD_SETGROUPS
1027 #endif
1028
1029 #if defined(USE_BSD_SETGROUPS)
1030 /* Depending on the particular BSD implementation, the first GID that is
1031  * passed to setgroups(2) will either be ignored or will set the credential's
1032  * effective GID. In either case, the right thing to do is to guarantee that
1033  * gidset[0] is the effective GID.
1034  */
1035 static int sys_bsd_setgroups(gid_t primary_gid, int setlen, const gid_t *gidset)
1036 {
1037         gid_t *new_gidset = NULL;
1038         int max;
1039         int ret;
1040
1041         /* setgroups(2) will fail with EINVAL if we pass too many groups. */
1042         max = groups_max();
1043
1044         /* No group list, just make sure we are setting the efective GID. */
1045         if (setlen == 0) {
1046                 return setgroups(1, &primary_gid);
1047         }
1048
1049         /* If the primary gid is not the first array element, grow the array
1050          * and insert it at the front.
1051          */
1052         if (gidset[0] != primary_gid) {
1053                 new_gidset = SMB_MALLOC_ARRAY(gid_t, setlen + 1);
1054                 if (new_gidset == NULL) {
1055                         return -1;
1056                 }
1057
1058                 memcpy(new_gidset + 1, gidset, (setlen * sizeof(gid_t)));
1059                 new_gidset[0] = primary_gid;
1060                 setlen++;
1061         }
1062
1063         if (setlen > max) {
1064                 DEBUG(3, ("forced to truncate group list from %d to %d\n",
1065                         setlen, max));
1066                 setlen = max;
1067         }
1068
1069 #if defined(HAVE_BROKEN_GETGROUPS)
1070         ret = sys_broken_setgroups(setlen, new_gidset ? new_gidset : gidset);
1071 #else
1072         ret = setgroups(setlen, new_gidset ? new_gidset : gidset);
1073 #endif
1074
1075         if (new_gidset) {
1076                 int errsav = errno;
1077                 SAFE_FREE(new_gidset);
1078                 errno = errsav;
1079         }
1080
1081         return ret;
1082 }
1083
1084 #endif /* USE_BSD_SETGROUPS */
1085
1086 /**************************************************************************
1087  Wrapper for getgroups. Deals with broken (int) case.
1088 ****************************************************************************/
1089
1090 int sys_getgroups(int setlen, gid_t *gidset)
1091 {
1092 #if defined(HAVE_BROKEN_GETGROUPS)
1093         return sys_broken_getgroups(setlen, gidset);
1094 #else
1095         return getgroups(setlen, gidset);
1096 #endif
1097 }
1098
1099 /**************************************************************************
1100  Wrapper for setgroups. Deals with broken (int) case and BSD case.
1101 ****************************************************************************/
1102
1103 int sys_setgroups(gid_t UNUSED(primary_gid), int setlen, gid_t *gidset)
1104 {
1105 #if !defined(HAVE_SETGROUPS)
1106         errno = ENOSYS;
1107         return -1;
1108 #endif /* HAVE_SETGROUPS */
1109
1110 #if defined(USE_BSD_SETGROUPS)
1111         return sys_bsd_setgroups(primary_gid, setlen, gidset);
1112 #elif defined(HAVE_BROKEN_GETGROUPS)
1113         return sys_broken_setgroups(setlen, gidset);
1114 #else
1115         return setgroups(setlen, gidset);
1116 #endif
1117 }
1118
1119 /**************************************************************************
1120  Extract a command into an arg list.
1121 ****************************************************************************/
1122
1123 static char **extract_args(TALLOC_CTX *mem_ctx, const char *command)
1124 {
1125         char *trunc_cmd;
1126         char *saveptr;
1127         char *ptr;
1128         int argcl;
1129         char **argl = NULL;
1130         int i;
1131
1132         if (!(trunc_cmd = talloc_strdup(mem_ctx, command))) {
1133                 DEBUG(0, ("talloc failed\n"));
1134                 goto nomem;
1135         }
1136
1137         if(!(ptr = strtok_r(trunc_cmd, " \t", &saveptr))) {
1138                 TALLOC_FREE(trunc_cmd);
1139                 errno = EINVAL;
1140                 return NULL;
1141         }
1142
1143         /*
1144          * Count the args.
1145          */
1146
1147         for( argcl = 1; ptr; ptr = strtok_r(NULL, " \t", &saveptr))
1148                 argcl++;
1149
1150         TALLOC_FREE(trunc_cmd);
1151
1152         if (!(argl = talloc_array(mem_ctx, char *, argcl + 1))) {
1153                 goto nomem;
1154         }
1155
1156         /*
1157          * Now do the extraction.
1158          */
1159
1160         if (!(trunc_cmd = talloc_strdup(mem_ctx, command))) {
1161                 goto nomem;
1162         }
1163
1164         ptr = strtok_r(trunc_cmd, " \t", &saveptr);
1165         i = 0;
1166
1167         if (!(argl[i++] = talloc_strdup(argl, ptr))) {
1168                 goto nomem;
1169         }
1170
1171         while((ptr = strtok_r(NULL, " \t", &saveptr)) != NULL) {
1172
1173                 if (!(argl[i++] = talloc_strdup(argl, ptr))) {
1174                         goto nomem;
1175                 }
1176         }
1177
1178         argl[i++] = NULL;
1179         TALLOC_FREE(trunc_cmd);
1180         return argl;
1181
1182  nomem:
1183         DEBUG(0, ("talloc failed\n"));
1184         TALLOC_FREE(trunc_cmd);
1185         TALLOC_FREE(argl);
1186         errno = ENOMEM;
1187         return NULL;
1188 }
1189
1190 /**************************************************************************
1191  Wrapper for popen. Safer as it doesn't search a path.
1192  Modified from the glibc sources.
1193  modified by tridge to return a file descriptor. We must kick our FILE* habit
1194 ****************************************************************************/
1195
1196 typedef struct _popen_list
1197 {
1198         int fd;
1199         pid_t child_pid;
1200         struct _popen_list *next;
1201 } popen_list;
1202
1203 static popen_list *popen_chain;
1204
1205 int sys_popen(const char *command)
1206 {
1207         int parent_end, child_end;
1208         int pipe_fds[2];
1209         popen_list *entry = NULL;
1210         char **argl = NULL;
1211
1212         if (pipe(pipe_fds) < 0)
1213                 return -1;
1214
1215         parent_end = pipe_fds[0];
1216         child_end = pipe_fds[1];
1217
1218         if (!*command) {
1219                 errno = EINVAL;
1220                 goto err_exit;
1221         }
1222
1223         if((entry = SMB_MALLOC_P(popen_list)) == NULL)
1224                 goto err_exit;
1225
1226         ZERO_STRUCTP(entry);
1227
1228         /*
1229          * Extract the command and args into a NULL terminated array.
1230          */
1231
1232         if(!(argl = extract_args(NULL, command)))
1233                 goto err_exit;
1234
1235         entry->child_pid = fork();
1236
1237         if (entry->child_pid == -1) {
1238                 goto err_exit;
1239         }
1240
1241         if (entry->child_pid == 0) {
1242
1243                 /*
1244                  * Child !
1245                  */
1246
1247                 int child_std_end = STDOUT_FILENO;
1248                 popen_list *p;
1249
1250                 close(parent_end);
1251                 if (child_end != child_std_end) {
1252                         dup2 (child_end, child_std_end);
1253                         close (child_end);
1254                 }
1255
1256                 /*
1257                  * POSIX.2:  "popen() shall ensure that any streams from previous
1258                  * popen() calls that remain open in the parent process are closed
1259                  * in the new child process."
1260                  */
1261
1262                 for (p = popen_chain; p; p = p->next)
1263                         close(p->fd);
1264
1265                 execv(argl[0], argl);
1266                 _exit (127);
1267         }
1268
1269         /*
1270          * Parent.
1271          */
1272
1273         close (child_end);
1274         TALLOC_FREE(argl);
1275
1276         /* Link into popen_chain. */
1277         entry->next = popen_chain;
1278         popen_chain = entry;
1279         entry->fd = parent_end;
1280
1281         return entry->fd;
1282
1283 err_exit:
1284
1285         SAFE_FREE(entry);
1286         TALLOC_FREE(argl);
1287         close(pipe_fds[0]);
1288         close(pipe_fds[1]);
1289         return -1;
1290 }
1291
1292 /**************************************************************************
1293  Wrapper for pclose. Modified from the glibc sources.
1294 ****************************************************************************/
1295
1296 int sys_pclose(int fd)
1297 {
1298         int wstatus;
1299         popen_list **ptr = &popen_chain;
1300         popen_list *entry = NULL;
1301         pid_t wait_pid;
1302         int status = -1;
1303
1304         /* Unlink from popen_chain. */
1305         for ( ; *ptr != NULL; ptr = &(*ptr)->next) {
1306                 if ((*ptr)->fd == fd) {
1307                         entry = *ptr;
1308                         *ptr = (*ptr)->next;
1309                         status = 0;
1310                         break;
1311                 }
1312         }
1313
1314         if (status < 0 || close(entry->fd) < 0)
1315                 return -1;
1316
1317         /*
1318          * As Samba is catching and eating child process
1319          * exits we don't really care about the child exit
1320          * code, a -1 with errno = ECHILD will do fine for us.
1321          */
1322
1323         do {
1324                 wait_pid = sys_waitpid (entry->child_pid, &wstatus, 0);
1325         } while (wait_pid == -1 && errno == EINTR);
1326
1327         SAFE_FREE(entry);
1328
1329         if (wait_pid == -1)
1330                 return -1;
1331         return wstatus;
1332 }
1333
1334 /**************************************************************************
1335  Wrapper for Admin Logs.
1336 ****************************************************************************/
1337
1338  void sys_adminlog(int priority, const char *format_str, ...) 
1339 {
1340         va_list ap;
1341         int ret;
1342         char *msgbuf = NULL;
1343
1344         va_start( ap, format_str );
1345         ret = vasprintf( &msgbuf, format_str, ap );
1346         va_end( ap );
1347
1348         if (ret == -1)
1349                 return;
1350
1351 #if defined(HAVE_SYSLOG)
1352         syslog( priority, "%s", msgbuf );
1353 #else
1354         DEBUG(0,("%s", msgbuf ));
1355 #endif
1356         SAFE_FREE(msgbuf);
1357 }
1358
1359 /******** Solaris EA helper function prototypes ********/
1360 #ifdef HAVE_ATTROPEN
1361 #define SOLARIS_ATTRMODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP
1362 static int solaris_write_xattr(int attrfd, const char *value, size_t size);
1363 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size);
1364 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size);
1365 static int solaris_unlinkat(int attrdirfd, const char *name);
1366 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode);
1367 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode);
1368 #endif
1369
1370 /**************************************************************************
1371  Wrappers for extented attribute calls. Based on the Linux package with
1372  support for IRIX and (Net|Free)BSD also. Expand as other systems have them.
1373 ****************************************************************************/
1374
1375 ssize_t sys_getxattr (const char *path, const char *name, void *value, size_t size)
1376 {
1377 #if defined(HAVE_GETXATTR)
1378 #ifndef XATTR_ADD_OPT
1379         return getxattr(path, name, value, size);
1380 #else
1381         int options = 0;
1382         return getxattr(path, name, value, size, 0, options);
1383 #endif
1384 #elif defined(HAVE_GETEA)
1385         return getea(path, name, value, size);
1386 #elif defined(HAVE_EXTATTR_GET_FILE)
1387         char *s;
1388         ssize_t retval;
1389         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1390                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1391         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1392         /*
1393          * The BSD implementation has a nasty habit of silently truncating
1394          * the returned value to the size of the buffer, so we have to check
1395          * that the buffer is large enough to fit the returned value.
1396          */
1397         if((retval=extattr_get_file(path, attrnamespace, attrname, NULL, 0)) >= 0) {
1398                 if(retval > size) {
1399                         errno = ERANGE;
1400                         return -1;
1401                 }
1402                 if((retval=extattr_get_file(path, attrnamespace, attrname, value, size)) >= 0)
1403                         return retval;
1404         }
1405
1406         DEBUG(10,("sys_getxattr: extattr_get_file() failed with: %s\n", strerror(errno)));
1407         return -1;
1408 #elif defined(HAVE_ATTR_GET)
1409         int retval, flags = 0;
1410         int valuelength = (int)size;
1411         char *attrname = strchr(name,'.') + 1;
1412
1413         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1414
1415         retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
1416
1417         return retval ? retval : valuelength;
1418 #elif defined(HAVE_ATTROPEN)
1419         ssize_t ret = -1;
1420         int attrfd = solaris_attropen(path, name, O_RDONLY, 0);
1421         if (attrfd >= 0) {
1422                 ret = solaris_read_xattr(attrfd, value, size);
1423                 close(attrfd);
1424         }
1425         return ret;
1426 #else
1427         errno = ENOSYS;
1428         return -1;
1429 #endif
1430 }
1431
1432 ssize_t sys_lgetxattr (const char *path, const char *name, void *value, size_t size)
1433 {
1434 #if defined(HAVE_LGETXATTR)
1435         return lgetxattr(path, name, value, size);
1436 #elif defined(HAVE_GETXATTR) && defined(XATTR_ADD_OPT)
1437         int options = XATTR_NOFOLLOW;
1438         return getxattr(path, name, value, size, 0, options);
1439 #elif defined(HAVE_LGETEA)
1440         return lgetea(path, name, value, size);
1441 #elif defined(HAVE_EXTATTR_GET_LINK)
1442         char *s;
1443         ssize_t retval;
1444         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1445                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1446         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1447
1448         if((retval=extattr_get_link(path, attrnamespace, attrname, NULL, 0)) >= 0) {
1449                 if(retval > size) {
1450                         errno = ERANGE;
1451                         return -1;
1452                 }
1453                 if((retval=extattr_get_link(path, attrnamespace, attrname, value, size)) >= 0)
1454                         return retval;
1455         }
1456
1457         DEBUG(10,("sys_lgetxattr: extattr_get_link() failed with: %s\n", strerror(errno)));
1458         return -1;
1459 #elif defined(HAVE_ATTR_GET)
1460         int retval, flags = ATTR_DONTFOLLOW;
1461         int valuelength = (int)size;
1462         char *attrname = strchr(name,'.') + 1;
1463
1464         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1465
1466         retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
1467
1468         return retval ? retval : valuelength;
1469 #elif defined(HAVE_ATTROPEN)
1470         ssize_t ret = -1;
1471         int attrfd = solaris_attropen(path, name, O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
1472         if (attrfd >= 0) {
1473                 ret = solaris_read_xattr(attrfd, value, size);
1474                 close(attrfd);
1475         }
1476         return ret;
1477 #else
1478         errno = ENOSYS;
1479         return -1;
1480 #endif
1481 }
1482
1483 ssize_t sys_fgetxattr (int filedes, const char *name, void *value, size_t size)
1484 {
1485 #if defined(HAVE_FGETXATTR)
1486 #ifndef XATTR_ADD_OPT
1487         return fgetxattr(filedes, name, value, size);
1488 #else
1489         int options = 0;
1490         return fgetxattr(filedes, name, value, size, 0, options);
1491 #endif
1492 #elif defined(HAVE_FGETEA)
1493         return fgetea(filedes, name, value, size);
1494 #elif defined(HAVE_EXTATTR_GET_FD)
1495         char *s;
1496         ssize_t retval;
1497         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1498                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1499         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1500
1501         if((retval=extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0)) >= 0) {
1502                 if(retval > size) {
1503                         errno = ERANGE;
1504                         return -1;
1505                 }
1506                 if((retval=extattr_get_fd(filedes, attrnamespace, attrname, value, size)) >= 0)
1507                         return retval;
1508         }
1509
1510         DEBUG(10,("sys_fgetxattr: extattr_get_fd() failed with: %s\n", strerror(errno)));
1511         return -1;
1512 #elif defined(HAVE_ATTR_GETF)
1513         int retval, flags = 0;
1514         int valuelength = (int)size;
1515         char *attrname = strchr(name,'.') + 1;
1516
1517         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1518
1519         retval = attr_getf(filedes, attrname, (char *)value, &valuelength, flags);
1520
1521         return retval ? retval : valuelength;
1522 #elif defined(HAVE_ATTROPEN)
1523         ssize_t ret = -1;
1524         int attrfd = solaris_openat(filedes, name, O_RDONLY|O_XATTR, 0);
1525         if (attrfd >= 0) {
1526                 ret = solaris_read_xattr(attrfd, value, size);
1527                 close(attrfd);
1528         }
1529         return ret;
1530 #else
1531         errno = ENOSYS;
1532         return -1;
1533 #endif
1534 }
1535
1536 #if defined(HAVE_EXTATTR_LIST_FILE)
1537
1538 #define EXTATTR_PREFIX(s)       (s), (sizeof((s))-1)
1539
1540 static struct {
1541         int space;
1542         const char *name;
1543         size_t len;
1544
1545 extattr[] = {
1546         { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("system.") },
1547         { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("user.") },
1548 };
1549
1550 typedef union {
1551         const char *path;
1552         int filedes;
1553 } extattr_arg;
1554
1555 static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size)
1556 {
1557         ssize_t list_size, total_size = 0;
1558         int i, t, len;
1559         char *buf;
1560         /* Iterate through extattr(2) namespaces */
1561         for(t = 0; t < ARRAY_SIZE(extattr); t++) {
1562                 switch(type) {
1563 #if defined(HAVE_EXTATTR_LIST_FILE)
1564                         case 0:
1565                                 list_size = extattr_list_file(arg.path, extattr[t].space, list, size);
1566                                 break;
1567 #endif
1568 #if defined(HAVE_EXTATTR_LIST_LINK)
1569                         case 1:
1570                                 list_size = extattr_list_link(arg.path, extattr[t].space, list, size);
1571                                 break;
1572 #endif
1573 #if defined(HAVE_EXTATTR_LIST_FD)
1574                         case 2:
1575                                 list_size = extattr_list_fd(arg.filedes, extattr[t].space, list, size);
1576                                 break;
1577 #endif
1578                         default:
1579                                 errno = ENOSYS;
1580                                 return -1;
1581                 }
1582                 /* Some error happend. Errno should be set by the previous call */
1583                 if(list_size < 0)
1584                         return -1;
1585                 /* No attributes */
1586                 if(list_size == 0)
1587                         continue;
1588                 /* XXX: Call with an empty buffer may be used to calculate
1589                    necessary buffer size. Unfortunately, we can't say, how
1590                    many attributes were returned, so here is the potential
1591                    problem with the emulation.
1592                 */
1593                 if(list == NULL) {
1594                         /* Take the worse case of one char attribute names - 
1595                            two bytes per name plus one more for sanity.
1596                         */
1597                         total_size += list_size + (list_size/2 + 1)*extattr[t].len;
1598                         continue;
1599                 }
1600                 /* Count necessary offset to fit namespace prefixes */
1601                 len = 0;
1602                 for(i = 0; i < list_size; i += list[i] + 1)
1603                         len += extattr[t].len;
1604
1605                 total_size += list_size + len;
1606                 /* Buffer is too small to fit the results */
1607                 if(total_size > size) {
1608                         errno = ERANGE;
1609                         return -1;
1610                 }
1611                 /* Shift results back, so we can prepend prefixes */
1612                 buf = (char *)memmove(list + len, list, list_size);
1613
1614                 for(i = 0; i < list_size; i += len + 1) {
1615                         len = buf[i];
1616                         strncpy(list, extattr[t].name, extattr[t].len + 1);
1617                         list += extattr[t].len;
1618                         strncpy(list, buf + i + 1, len);
1619                         list[len] = '\0';
1620                         list += len + 1;
1621                 }
1622                 size -= total_size;
1623         }
1624         return total_size;
1625 }
1626
1627 #endif
1628
1629 #if defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1630 static char attr_buffer[ATTR_MAX_VALUELEN];
1631
1632 static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
1633 {
1634         int retval = 0, index;
1635         attrlist_cursor_t *cursor = 0;
1636         int total_size = 0;
1637         attrlist_t * al = (attrlist_t *)attr_buffer;
1638         attrlist_ent_t *ae;
1639         size_t ent_size, left = size;
1640         char *bp = list;
1641
1642         while (True) {
1643             if (filedes)
1644                 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1645             else
1646                 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1647             if (retval) break;
1648             for (index = 0; index < al->al_count; index++) {
1649                 ae = ATTR_ENTRY(attr_buffer, index);
1650                 ent_size = strlen(ae->a_name) + sizeof("user.");
1651                 if (left >= ent_size) {
1652                     strncpy(bp, "user.", sizeof("user."));
1653                     strncat(bp, ae->a_name, ent_size - sizeof("user."));
1654                     bp += ent_size;
1655                     left -= ent_size;
1656                 } else if (size) {
1657                     errno = ERANGE;
1658                     retval = -1;
1659                     break;
1660                 }
1661                 total_size += ent_size;
1662             }
1663             if (al->al_more == 0) break;
1664         }
1665         if (retval == 0) {
1666             flags |= ATTR_ROOT;
1667             cursor = 0;
1668             while (True) {
1669                 if (filedes)
1670                     retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1671                 else
1672                     retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1673                 if (retval) break;
1674                 for (index = 0; index < al->al_count; index++) {
1675                     ae = ATTR_ENTRY(attr_buffer, index);
1676                     ent_size = strlen(ae->a_name) + sizeof("system.");
1677                     if (left >= ent_size) {
1678                         strncpy(bp, "system.", sizeof("system."));
1679                         strncat(bp, ae->a_name, ent_size - sizeof("system."));
1680                         bp += ent_size;
1681                         left -= ent_size;
1682                     } else if (size) {
1683                         errno = ERANGE;
1684                         retval = -1;
1685                         break;
1686                     }
1687                     total_size += ent_size;
1688                 }
1689                 if (al->al_more == 0) break;
1690             }
1691         }
1692         return (ssize_t)(retval ? retval : total_size);
1693 }
1694
1695 #endif
1696
1697 ssize_t sys_listxattr (const char *path, char *list, size_t size)
1698 {
1699 #if defined(HAVE_LISTXATTR)
1700 #ifndef XATTR_ADD_OPT
1701         return listxattr(path, list, size);
1702 #else
1703         int options = 0;
1704         return listxattr(path, list, size, options);
1705 #endif
1706 #elif defined(HAVE_LISTEA)
1707         return listea(path, list, size);
1708 #elif defined(HAVE_EXTATTR_LIST_FILE)
1709         extattr_arg arg;
1710         arg.path = path;
1711         return bsd_attr_list(0, arg, list, size);
1712 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1713         return irix_attr_list(path, 0, list, size, 0);
1714 #elif defined(HAVE_ATTROPEN)
1715         ssize_t ret = -1;
1716         int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
1717         if (attrdirfd >= 0) {
1718                 ret = solaris_list_xattr(attrdirfd, list, size);
1719                 close(attrdirfd);
1720         }
1721         return ret;
1722 #else
1723         errno = ENOSYS;
1724         return -1;
1725 #endif
1726 }
1727
1728 ssize_t sys_llistxattr (const char *path, char *list, size_t size)
1729 {
1730 #if defined(HAVE_LLISTXATTR)
1731         return llistxattr(path, list, size);
1732 #elif defined(HAVE_LISTXATTR) && defined(XATTR_ADD_OPT)
1733         int options = XATTR_NOFOLLOW;
1734         return listxattr(path, list, size, options);
1735 #elif defined(HAVE_LLISTEA)
1736         return llistea(path, list, size);
1737 #elif defined(HAVE_EXTATTR_LIST_LINK)
1738         extattr_arg arg;
1739         arg.path = path;
1740         return bsd_attr_list(1, arg, list, size);
1741 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1742         return irix_attr_list(path, 0, list, size, ATTR_DONTFOLLOW);
1743 #elif defined(HAVE_ATTROPEN)
1744         ssize_t ret = -1;
1745         int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
1746         if (attrdirfd >= 0) {
1747                 ret = solaris_list_xattr(attrdirfd, list, size);
1748                 close(attrdirfd);
1749         }
1750         return ret;
1751 #else
1752         errno = ENOSYS;
1753         return -1;
1754 #endif
1755 }
1756
1757 ssize_t sys_flistxattr (int filedes, char *list, size_t size)
1758 {
1759 #if defined(HAVE_FLISTXATTR)
1760 #ifndef XATTR_ADD_OPT
1761         return flistxattr(filedes, list, size);
1762 #else
1763         int options = 0;
1764         return flistxattr(filedes, list, size, options);
1765 #endif
1766 #elif defined(HAVE_FLISTEA)
1767         return flistea(filedes, list, size);
1768 #elif defined(HAVE_EXTATTR_LIST_FD)
1769         extattr_arg arg;
1770         arg.filedes = filedes;
1771         return bsd_attr_list(2, arg, list, size);
1772 #elif defined(HAVE_ATTR_LISTF)
1773         return irix_attr_list(NULL, filedes, list, size, 0);
1774 #elif defined(HAVE_ATTROPEN)
1775         ssize_t ret = -1;
1776         int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
1777         if (attrdirfd >= 0) {
1778                 ret = solaris_list_xattr(attrdirfd, list, size);
1779                 close(attrdirfd);
1780         }
1781         return ret;
1782 #else
1783         errno = ENOSYS;
1784         return -1;
1785 #endif
1786 }
1787
1788 int sys_removexattr (const char *path, const char *name)
1789 {
1790 #if defined(HAVE_REMOVEXATTR)
1791 #ifndef XATTR_ADD_OPT
1792         return removexattr(path, name);
1793 #else
1794         int options = 0;
1795         return removexattr(path, name, options);
1796 #endif
1797 #elif defined(HAVE_REMOVEEA)
1798         return removeea(path, name);
1799 #elif defined(HAVE_EXTATTR_DELETE_FILE)
1800         char *s;
1801         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1802                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1803         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1804
1805         return extattr_delete_file(path, attrnamespace, attrname);
1806 #elif defined(HAVE_ATTR_REMOVE)
1807         int flags = 0;
1808         char *attrname = strchr(name,'.') + 1;
1809
1810         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1811
1812         return attr_remove(path, attrname, flags);
1813 #elif defined(HAVE_ATTROPEN)
1814         int ret = -1;
1815         int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
1816         if (attrdirfd >= 0) {
1817                 ret = solaris_unlinkat(attrdirfd, name);
1818                 close(attrdirfd);
1819         }
1820         return ret;
1821 #else
1822         errno = ENOSYS;
1823         return -1;
1824 #endif
1825 }
1826
1827 int sys_lremovexattr (const char *path, const char *name)
1828 {
1829 #if defined(HAVE_LREMOVEXATTR)
1830         return lremovexattr(path, name);
1831 #elif defined(HAVE_REMOVEXATTR) && defined(XATTR_ADD_OPT)
1832         int options = XATTR_NOFOLLOW;
1833         return removexattr(path, name, options);
1834 #elif defined(HAVE_LREMOVEEA)
1835         return lremoveea(path, name);
1836 #elif defined(HAVE_EXTATTR_DELETE_LINK)
1837         char *s;
1838         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1839                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1840         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1841
1842         return extattr_delete_link(path, attrnamespace, attrname);
1843 #elif defined(HAVE_ATTR_REMOVE)
1844         int flags = ATTR_DONTFOLLOW;
1845         char *attrname = strchr(name,'.') + 1;
1846
1847         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1848
1849         return attr_remove(path, attrname, flags);
1850 #elif defined(HAVE_ATTROPEN)
1851         int ret = -1;
1852         int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
1853         if (attrdirfd >= 0) {
1854                 ret = solaris_unlinkat(attrdirfd, name);
1855                 close(attrdirfd);
1856         }
1857         return ret;
1858 #else
1859         errno = ENOSYS;
1860         return -1;
1861 #endif
1862 }
1863
1864 int sys_fremovexattr (int filedes, const char *name)
1865 {
1866 #if defined(HAVE_FREMOVEXATTR)
1867 #ifndef XATTR_ADD_OPT
1868         return fremovexattr(filedes, name);
1869 #else
1870         int options = 0;
1871         return fremovexattr(filedes, name, options);
1872 #endif
1873 #elif defined(HAVE_FREMOVEEA)
1874         return fremoveea(filedes, name);
1875 #elif defined(HAVE_EXTATTR_DELETE_FD)
1876         char *s;
1877         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1878                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1879         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1880
1881         return extattr_delete_fd(filedes, attrnamespace, attrname);
1882 #elif defined(HAVE_ATTR_REMOVEF)
1883         int flags = 0;
1884         char *attrname = strchr(name,'.') + 1;
1885
1886         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1887
1888         return attr_removef(filedes, attrname, flags);
1889 #elif defined(HAVE_ATTROPEN)
1890         int ret = -1;
1891         int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
1892         if (attrdirfd >= 0) {
1893                 ret = solaris_unlinkat(attrdirfd, name);
1894                 close(attrdirfd);
1895         }
1896         return ret;
1897 #else
1898         errno = ENOSYS;
1899         return -1;
1900 #endif
1901 }
1902
1903 int sys_setxattr (const char *path, const char *name, const void *value, size_t size, int flags)
1904 {
1905 #if defined(HAVE_SETXATTR)
1906 #ifndef XATTR_ADD_OPT
1907         return setxattr(path, name, value, size, flags);
1908 #else
1909         int options = 0;
1910         return setxattr(path, name, value, size, 0, options);
1911 #endif
1912 #elif defined(HAVE_SETEA)
1913         return setea(path, name, value, size, flags);
1914 #elif defined(HAVE_EXTATTR_SET_FILE)
1915         char *s;
1916         int retval = 0;
1917         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1918                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1919         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1920         if (flags) {
1921                 /* Check attribute existence */
1922                 retval = extattr_get_file(path, attrnamespace, attrname, NULL, 0);
1923                 if (retval < 0) {
1924                         /* REPLACE attribute, that doesn't exist */
1925                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
1926                                 errno = ENOATTR;
1927                                 return -1;
1928                         }
1929                         /* Ignore other errors */
1930                 }
1931                 else {
1932                         /* CREATE attribute, that already exists */
1933                         if (flags & XATTR_CREATE) {
1934                                 errno = EEXIST;
1935                                 return -1;
1936                         }
1937                 }
1938         }
1939         retval = extattr_set_file(path, attrnamespace, attrname, value, size);
1940         return (retval < 0) ? -1 : 0;
1941 #elif defined(HAVE_ATTR_SET)
1942         int myflags = 0;
1943         char *attrname = strchr(name,'.') + 1;
1944
1945         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
1946         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
1947         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
1948
1949         return attr_set(path, attrname, (const char *)value, size, myflags);
1950 #elif defined(HAVE_ATTROPEN)
1951         int ret = -1;
1952         int myflags = O_RDWR;
1953         int attrfd;
1954         if (flags & XATTR_CREATE) myflags |= O_EXCL;
1955         if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
1956         attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
1957         if (attrfd >= 0) {
1958                 ret = solaris_write_xattr(attrfd, value, size);
1959                 close(attrfd);
1960         }
1961         return ret;
1962 #else
1963         errno = ENOSYS;
1964         return -1;
1965 #endif
1966 }
1967
1968 int sys_lsetxattr (const char *path, const char *name, const void *value, size_t size, int flags)
1969 {
1970 #if defined(HAVE_LSETXATTR)
1971         return lsetxattr(path, name, value, size, flags);
1972 #elif defined(HAVE_SETXATTR) && defined(XATTR_ADD_OPT)
1973         int options = XATTR_NOFOLLOW;
1974         return setxattr(path, name, value, size, 0, options);
1975 #elif defined(LSETEA)
1976         return lsetea(path, name, value, size, flags);
1977 #elif defined(HAVE_EXTATTR_SET_LINK)
1978         char *s;
1979         int retval = 0;
1980         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1981                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1982         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1983         if (flags) {
1984                 /* Check attribute existence */
1985                 retval = extattr_get_link(path, attrnamespace, attrname, NULL, 0);
1986                 if (retval < 0) {
1987                         /* REPLACE attribute, that doesn't exist */
1988                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
1989                                 errno = ENOATTR;
1990                                 return -1;
1991                         }
1992                         /* Ignore other errors */
1993                 }
1994                 else {
1995                         /* CREATE attribute, that already exists */
1996                         if (flags & XATTR_CREATE) {
1997                                 errno = EEXIST;
1998                                 return -1;
1999                         }
2000                 }
2001         }
2002
2003         retval = extattr_set_link(path, attrnamespace, attrname, value, size);
2004         return (retval < 0) ? -1 : 0;
2005 #elif defined(HAVE_ATTR_SET)
2006         int myflags = ATTR_DONTFOLLOW;
2007         char *attrname = strchr(name,'.') + 1;
2008
2009         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
2010         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
2011         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
2012
2013         return attr_set(path, attrname, (const char *)value, size, myflags);
2014 #elif defined(HAVE_ATTROPEN)
2015         int ret = -1;
2016         int myflags = O_RDWR | AT_SYMLINK_NOFOLLOW;
2017         int attrfd;
2018         if (flags & XATTR_CREATE) myflags |= O_EXCL;
2019         if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
2020         attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
2021         if (attrfd >= 0) {
2022                 ret = solaris_write_xattr(attrfd, value, size);
2023                 close(attrfd);
2024         }
2025         return ret;
2026 #else
2027         errno = ENOSYS;
2028         return -1;
2029 #endif
2030 }
2031
2032 int sys_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags)
2033 {
2034 #if defined(HAVE_FSETXATTR)
2035 #ifndef XATTR_ADD_OPT
2036         return fsetxattr(filedes, name, value, size, flags);
2037 #else
2038         int options = 0;
2039         return fsetxattr(filedes, name, value, size, 0, options);
2040 #endif
2041 #elif defined(HAVE_FSETEA)
2042         return fsetea(filedes, name, value, size, flags);
2043 #elif defined(HAVE_EXTATTR_SET_FD)
2044         char *s;
2045         int retval = 0;
2046         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
2047                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
2048         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
2049         if (flags) {
2050                 /* Check attribute existence */
2051                 retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
2052                 if (retval < 0) {
2053                         /* REPLACE attribute, that doesn't exist */
2054                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
2055                                 errno = ENOATTR;
2056                                 return -1;
2057                         }
2058                         /* Ignore other errors */
2059                 }
2060                 else {
2061                         /* CREATE attribute, that already exists */
2062                         if (flags & XATTR_CREATE) {
2063                                 errno = EEXIST;
2064                                 return -1;
2065                         }
2066                 }
2067         }
2068         retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size);
2069         return (retval < 0) ? -1 : 0;
2070 #elif defined(HAVE_ATTR_SETF)
2071         int myflags = 0;
2072         char *attrname = strchr(name,'.') + 1;
2073
2074         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
2075         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
2076         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
2077
2078         return attr_setf(filedes, attrname, (const char *)value, size, myflags);
2079 #elif defined(HAVE_ATTROPEN)
2080         int ret = -1;
2081         int myflags = O_RDWR | O_XATTR;
2082         int attrfd;
2083         if (flags & XATTR_CREATE) myflags |= O_EXCL;
2084         if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
2085         attrfd = solaris_openat(filedes, name, myflags, (mode_t) SOLARIS_ATTRMODE);
2086         if (attrfd >= 0) {
2087                 ret = solaris_write_xattr(attrfd, value, size);
2088                 close(attrfd);
2089         }
2090         return ret;
2091 #else
2092         errno = ENOSYS;
2093         return -1;
2094 #endif
2095 }
2096
2097 /**************************************************************************
2098  helper functions for Solaris' EA support
2099 ****************************************************************************/
2100 #ifdef HAVE_ATTROPEN
2101 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size)
2102 {
2103         struct stat sbuf;
2104
2105         if (fstat(attrfd, &sbuf) == -1) {
2106                 errno = ENOATTR;
2107                 return -1;
2108         }
2109
2110         /* This is to return the current size of the named extended attribute */
2111         if (size == 0) {
2112                 return sbuf.st_size;
2113         }
2114
2115         /* check size and read xattr */
2116         if (sbuf.st_size > size) {
2117                 errno = ERANGE;
2118                 return -1;
2119         }
2120
2121         return read(attrfd, value, sbuf.st_size);
2122 }
2123
2124 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size)
2125 {
2126         ssize_t len = 0;
2127         DIR *dirp;
2128         struct dirent *de;
2129         int newfd = dup(attrdirfd);
2130         /* CAUTION: The originating file descriptor should not be
2131                     used again following the call to fdopendir().
2132                     For that reason we dup() the file descriptor
2133                     here to make things more clear. */
2134         dirp = fdopendir(newfd);
2135
2136         while ((de = readdir(dirp))) {
2137                 size_t listlen = strlen(de->d_name) + 1;
2138                 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
2139                         /* we don't want "." and ".." here: */
2140                         DEBUG(10,("skipped EA %s\n",de->d_name));
2141                         continue;
2142                 }
2143
2144                 if (size == 0) {
2145                         /* return the current size of the list of extended attribute names*/
2146                         len += listlen;
2147                 } else {
2148                         /* check size and copy entrieÑ• + nul into list. */
2149                         if ((len + listlen) > size) {
2150                                 errno = ERANGE;
2151                                 len = -1;
2152                                 break;
2153                         } else {
2154                                 strlcpy(list + len, de->d_name, listlen);
2155                                 len += listlen;
2156                         }
2157                 }
2158         }
2159
2160         if (closedir(dirp) == -1) {
2161                 DEBUG(0,("closedir dirp failed: %s\n",strerror(errno)));
2162                 return -1;
2163         }
2164         return len;
2165 }
2166
2167 static int solaris_unlinkat(int attrdirfd, const char *name)
2168 {
2169         if (unlinkat(attrdirfd, name, 0) == -1) {
2170                 if (errno == ENOENT) {
2171                         errno = ENOATTR;
2172                 }
2173                 return -1;
2174         }
2175         return 0;
2176 }
2177
2178 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode)
2179 {
2180         int filedes = attropen(path, attrpath, oflag, mode);
2181         if (filedes == -1) {
2182                 DEBUG(10,("attropen FAILED: path: %s, name: %s, errno: %s\n",path,attrpath,strerror(errno)));
2183                 if (errno == EINVAL) {
2184                         errno = ENOTSUP;
2185                 } else {
2186                         errno = ENOATTR;
2187                 }
2188         }
2189         return filedes;
2190 }
2191
2192 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
2193 {
2194         int filedes = openat(fildes, path, oflag, mode);
2195         if (filedes == -1) {
2196                 DEBUG(10,("openat FAILED: fd: %d, path: %s, errno: %s\n",filedes,path,strerror(errno)));
2197                 if (errno == EINVAL) {
2198                         errno = ENOTSUP;
2199                 } else {
2200                         errno = ENOATTR;
2201                 }
2202         }
2203         return filedes;
2204 }
2205
2206 static int solaris_write_xattr(int attrfd, const char *value, size_t size)
2207 {
2208         if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) {
2209                 return 0;
2210         } else {
2211                 DEBUG(10,("solaris_write_xattr FAILED!\n"));
2212                 return -1;
2213         }
2214 }
2215 #endif /*HAVE_ATTROPEN*/
2216
2217
2218 /****************************************************************************
2219  Return the major devicenumber for UNIX extensions.
2220 ****************************************************************************/
2221
2222 uint32 unix_dev_major(SMB_DEV_T dev)
2223 {
2224 #if defined(HAVE_DEVICE_MAJOR_FN)
2225         return (uint32)major(dev);
2226 #else
2227         return (uint32)(dev >> 8);
2228 #endif
2229 }
2230
2231 /****************************************************************************
2232  Return the minor devicenumber for UNIX extensions.
2233 ****************************************************************************/
2234
2235 uint32 unix_dev_minor(SMB_DEV_T dev)
2236 {
2237 #if defined(HAVE_DEVICE_MINOR_FN)
2238         return (uint32)minor(dev);
2239 #else
2240         return (uint32)(dev & 0xff);
2241 #endif
2242 }
2243
2244 #if 0
2245 /*******************************************************************
2246  Return the number of CPUs.
2247 ********************************************************************/
2248
2249 int sys_get_number_of_cores(void)
2250 {
2251         int ret = -1;
2252
2253 #if defined(HAVE_SYSCONF)
2254 #if defined(_SC_NPROCESSORS_ONLN)
2255         ret = (int)sysconf(_SC_NPROCESSORS_ONLN);
2256 #endif
2257 #if defined(_SC_NPROCESSORS_CONF)
2258         if (ret < 1) {
2259                 ret = (int)sysconf(_SC_NPROCESSORS_CONF);
2260         }
2261 #endif
2262 #elif defined(HAVE_SYSCTL) && defined(CTL_HW)
2263         int name[2];
2264         unsigned int len = sizeof(ret);
2265
2266         name[0] = CTL_HW;
2267 #if defined(HW_AVAILCPU)
2268         name[1] = HW_AVAILCPU;
2269
2270         if (sysctl(name, 2, &ret, &len, NULL, 0) == -1) {
2271                 ret = -1;
2272         }
2273 #endif
2274 #if defined(HW_NCPU)
2275         if(ret < 1) {
2276                 name[0] = CTL_HW;
2277                 name[1] = HW_NCPU;
2278                 if (sysctl(nm, 2, &count, &len, NULL, 0) == -1) {
2279                         ret = -1;
2280                 }
2281         }
2282 #endif
2283 #endif
2284         if (ret < 1) {
2285                 ret = 1;
2286         }
2287         return ret;
2288 }
2289 #endif
2290
2291 #if defined(WITH_AIO)
2292
2293 /*******************************************************************
2294  An aio_read wrapper.
2295 ********************************************************************/
2296
2297 int sys_aio_read(SMB_STRUCT_AIOCB *aiocb)
2298 {
2299 #if defined(HAVE_AIO_READ)
2300         return aio_read(aiocb);
2301 #else
2302         errno = ENOSYS;
2303         return -1;
2304 #endif
2305 }
2306
2307 /*******************************************************************
2308  An aio_write wrapper.
2309 ********************************************************************/
2310
2311 int sys_aio_write(SMB_STRUCT_AIOCB *aiocb)
2312 {
2313 #if defined(HAVE_AIO_WRITE)
2314         return aio_write(aiocb);
2315 #else
2316         errno = ENOSYS;
2317         return -1;
2318 #endif
2319 }
2320
2321 /*******************************************************************
2322  An aio_return wrapper.
2323 ********************************************************************/
2324
2325 ssize_t sys_aio_return(SMB_STRUCT_AIOCB *aiocb)
2326 {
2327 #if defined(HAVE_AIO_RETURN)
2328         return aio_return(aiocb);
2329 #else
2330         errno = ENOSYS;
2331         return -1;
2332 #endif
2333 }
2334
2335 /*******************************************************************
2336  An aio_cancel wrapper.
2337 ********************************************************************/
2338
2339 int sys_aio_cancel(int fd, SMB_STRUCT_AIOCB *aiocb)
2340 {
2341 #if defined(HAVE_AIO_CANCEL)
2342         return aio_cancel(fd, aiocb);
2343 #else
2344         errno = ENOSYS;
2345         return -1;
2346 #endif
2347 }
2348
2349 /*******************************************************************
2350  An aio_error wrapper.
2351 ********************************************************************/
2352
2353 int sys_aio_error(const SMB_STRUCT_AIOCB *aiocb)
2354 {
2355 #if defined(HAVE_AIO_ERROR)
2356         return aio_error(aiocb);
2357 #else
2358         errno = ENOSYS;
2359         return -1;
2360 #endif
2361 }
2362
2363 /*******************************************************************
2364  An aio_fsync wrapper.
2365 ********************************************************************/
2366
2367 int sys_aio_fsync(int op, SMB_STRUCT_AIOCB *aiocb)
2368 {
2369 #if defined(HAVE_AIO_FSYNC)
2370         return aio_fsync(op, aiocb);
2371 #else
2372         errno = ENOSYS;
2373         return -1;
2374 #endif
2375 }
2376
2377 /*******************************************************************
2378  An aio_fsync wrapper.
2379 ********************************************************************/
2380
2381 int sys_aio_suspend(const SMB_STRUCT_AIOCB * const cblist[], int n, const struct timespec *timeout)
2382 {
2383 #if defined(HAVE_AIO_FSYNC)
2384         return aio_suspend(cblist, n, timeout);
2385 #else
2386         errno = ENOSYS;
2387         return -1;
2388 #endif
2389 }
2390 #else /* !WITH_AIO */
2391
2392 int sys_aio_read(SMB_STRUCT_AIOCB *aiocb)
2393 {
2394         errno = ENOSYS;
2395         return -1;
2396 }
2397
2398 int sys_aio_write(SMB_STRUCT_AIOCB *aiocb)
2399 {
2400         errno = ENOSYS;
2401         return -1;
2402 }
2403
2404 ssize_t sys_aio_return(SMB_STRUCT_AIOCB *aiocb)
2405 {
2406         errno = ENOSYS;
2407         return -1;
2408 }
2409
2410 int sys_aio_cancel(int fd, SMB_STRUCT_AIOCB *aiocb)
2411 {
2412         errno = ENOSYS;
2413         return -1;
2414 }
2415
2416 int sys_aio_error(const SMB_STRUCT_AIOCB *aiocb)
2417 {
2418         errno = ENOSYS;
2419         return -1;
2420 }
2421
2422 int sys_aio_fsync(int op, SMB_STRUCT_AIOCB *aiocb)
2423 {
2424         errno = ENOSYS;
2425         return -1;
2426 }
2427
2428 int sys_aio_suspend(const SMB_STRUCT_AIOCB * const cblist[], int n, const struct timespec *timeout)
2429 {
2430         errno = ENOSYS;
2431         return -1;
2432 }
2433 #endif /* WITH_AIO */