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