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