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