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