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