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