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