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