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