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