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