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