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