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