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