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