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