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