Fix bug #7067 - Linux asynchronous IO (aio) can cause smbd to fail to respond to...
[Samba/kamenim.git] / source3 / lib / system.c
blob9c1da3a78bdcdf301883cc74fcdc6bfcb00a5834
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
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.
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.
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/>.
23 #include "includes.h"
25 #ifdef HAVE_SYS_PRCTL_H
26 #include <sys/prctl.h>
27 #endif
30 The idea is that this file will eventually have wrappers around all
31 important system calls in samba. The aims are:
33 - to enable easier porting by putting OS dependent stuff in here
35 - to allow for hooks into other "pseudo-filesystems"
37 - to allow easier integration of things like the japanese extensions
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.
46 /*******************************************************************
47 A wrapper for memalign
48 ********************************************************************/
50 void *sys_memalign( size_t align, size_t size )
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;
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;
75 if (size < pagesize) {
76 size = pagesize;
78 return SMB_MALLOC(size);
79 #endif
82 /*******************************************************************
83 A wrapper for usleep in case we don't have one.
84 ********************************************************************/
86 int sys_usleep(long usecs)
88 #ifndef HAVE_USLEEP
89 struct timeval tval;
90 #endif
93 * We need this braindamage as the glibc usleep
94 * is not SPEC1170 complient... grumble... JRA.
97 if(usecs < 0 || usecs > 999999) {
98 errno = EINVAL;
99 return -1;
102 #if HAVE_USLEEP
103 usleep(usecs);
104 return 0;
105 #else /* HAVE_USLEEP */
107 * Fake it with select...
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 */
116 /*******************************************************************
117 A read wrapper that will deal with EINTR.
118 ********************************************************************/
120 ssize_t sys_read(int fd, void *buf, size_t count)
122 ssize_t ret;
124 do {
125 ret = read(fd, buf, count);
126 } while (ret == -1 && errno == EINTR);
127 return ret;
130 /*******************************************************************
131 A write wrapper that will deal with EINTR.
132 ********************************************************************/
134 ssize_t sys_write(int fd, const void *buf, size_t count)
136 ssize_t ret;
138 do {
139 ret = write(fd, buf, count);
140 } while (ret == -1 && errno == EINTR);
141 return ret;
144 /*******************************************************************
145 A writev wrapper that will deal with EINTR.
146 ********************************************************************/
148 ssize_t sys_writev(int fd, const struct iovec *iov, int iovcnt)
150 ssize_t ret;
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);
157 if (iov[0].iov_len > 1) {
158 return sys_write(fd, iov[0].iov_base,
159 (random() % (iov[0].iov_len-1)) + 1);
161 #endif
163 do {
164 ret = writev(fd, iov, iovcnt);
165 } while (ret == -1 && errno == EINTR);
166 return ret;
169 /*******************************************************************
170 A pread wrapper that will deal with EINTR and 64-bit file offsets.
171 ********************************************************************/
173 #if defined(HAVE_PREAD) || defined(HAVE_PREAD64)
174 ssize_t sys_pread(int fd, void *buf, size_t count, SMB_OFF_T off)
176 ssize_t ret;
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;
187 #endif
189 /*******************************************************************
190 A write wrapper that will deal with EINTR and 64-bit file offsets.
191 ********************************************************************/
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)
196 ssize_t ret;
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;
207 #endif
209 /*******************************************************************
210 A send wrapper that will deal with EINTR.
211 ********************************************************************/
213 ssize_t sys_send(int s, const void *msg, size_t len, int flags)
215 ssize_t ret;
217 do {
218 ret = send(s, msg, len, flags);
219 } while (ret == -1 && errno == EINTR);
220 return ret;
223 /*******************************************************************
224 A sendto wrapper that will deal with EINTR.
225 ********************************************************************/
227 ssize_t sys_sendto(int s, const void *msg, size_t len, int flags, const struct sockaddr *to, socklen_t tolen)
229 ssize_t ret;
231 do {
232 ret = sendto(s, msg, len, flags, to, tolen);
233 } while (ret == -1 && errno == EINTR);
234 return ret;
237 /*******************************************************************
238 A recv wrapper that will deal with EINTR.
239 ********************************************************************/
241 ssize_t sys_recv(int fd, void *buf, size_t count, int flags)
243 ssize_t ret;
245 do {
246 ret = recv(fd, buf, count, flags);
247 } while (ret == -1 && errno == EINTR);
248 return ret;
251 /*******************************************************************
252 A recvfrom wrapper that will deal with EINTR.
253 ********************************************************************/
255 ssize_t sys_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
257 ssize_t ret;
259 do {
260 ret = recvfrom(s, buf, len, flags, from, fromlen);
261 } while (ret == -1 && errno == EINTR);
262 return ret;
265 /*******************************************************************
266 A fcntl wrapper that will deal with EINTR.
267 ********************************************************************/
269 int sys_fcntl_ptr(int fd, int cmd, void *arg)
271 int ret;
273 do {
274 ret = fcntl(fd, cmd, arg);
275 } while (ret == -1 && errno == EINTR);
276 return ret;
279 /*******************************************************************
280 A fcntl wrapper that will deal with EINTR.
281 ********************************************************************/
283 int sys_fcntl_long(int fd, int cmd, long arg)
285 int ret;
287 do {
288 ret = fcntl(fd, cmd, arg);
289 } while (ret == -1 && errno == EINTR);
290 return ret;
293 /****************************************************************************
294 Get/Set all the possible time fields from a stat struct as a timespec.
295 ****************************************************************************/
297 static struct timespec get_atimespec(const struct stat *pst)
299 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
300 struct timespec ret;
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
332 static struct timespec get_mtimespec(const struct stat *pst)
334 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
335 struct timespec ret;
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
367 static struct timespec get_ctimespec(const struct stat *pst)
369 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
370 struct timespec ret;
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
402 /****************************************************************************
403 Return the best approximation to a 'create time' under UNIX from a stat
404 structure.
405 ****************************************************************************/
407 static struct timespec calc_create_time_stat(const struct stat *st)
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);
414 ret = timespec_compare(&c_time, &m_time) < 0 ? c_time : m_time;
415 ret1 = timespec_compare(&ret, &a_time) < 0 ? ret : a_time;
417 if(!null_timespec(ret1)) {
418 return ret1;
422 * One of ctime, mtime or atime was zero (probably atime).
423 * Just return MIN(ctime, mtime).
425 return ret;
428 /****************************************************************************
429 Return the best approximation to a 'create time' under UNIX from a stat_ex
430 structure.
431 ****************************************************************************/
433 static struct timespec calc_create_time_stat_ex(const struct stat_ex *st)
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;
440 ret = timespec_compare(&c_time, &m_time) < 0 ? c_time : m_time;
441 ret1 = timespec_compare(&ret, &a_time) < 0 ? ret : a_time;
443 if(!null_timespec(ret1)) {
444 return ret1;
448 * One of ctime, mtime or atime was zero (probably atime).
449 * Just return MIN(ctime, mtime).
451 return ret;
454 /****************************************************************************
455 Return the 'create time' from a stat struct if it exists (birthtime) or else
456 use the best approximation.
457 ****************************************************************************/
459 static void make_create_timespec(const struct stat *pst, struct stat_ex *dst,
460 bool fake_dir_create_times)
462 if (S_ISDIR(pst->st_mode) && fake_dir_create_times) {
463 dst->st_ex_btime.tv_sec = 315493200L; /* 1/1/1980 */
464 dst->st_ex_btime.tv_nsec = 0;
467 dst->st_ex_calculated_birthtime = false;
469 #if defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC)
470 dst->st_ex_btime = pst->st_birthtimespec;
471 #elif defined(HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC)
472 dst->st_ex_btime.tv_sec = pst->st_birthtime;
473 dst->st_ex_btime.tv_nsec = pst->st_birthtimenspec;
474 #elif defined(HAVE_STRUCT_STAT_ST_BIRTHTIME)
475 dst->st_ex_btime.tv_sec = pst->st_birthtime;
476 dst->st_ex_btime.tv_nsec = 0;
477 #else
478 dst->st_ex_btime = calc_create_time_stat(pst);
479 dst->st_ex_calculated_birthtime = true;
480 #endif
482 /* Deal with systems that don't initialize birthtime correctly.
483 * Pointed out by SATOH Fumiyasu <fumiyas@osstech.jp>.
485 if (null_timespec(dst->st_ex_btime)) {
486 dst->st_ex_btime = calc_create_time_stat(pst);
487 dst->st_ex_calculated_birthtime = true;
491 /****************************************************************************
492 If we update a timestamp in a stat_ex struct we may have to recalculate
493 the birthtime. For now only implement this for write time, but we may
494 also need to do it for atime and ctime. JRA.
495 ****************************************************************************/
497 void update_stat_ex_mtime(struct stat_ex *dst,
498 struct timespec write_ts)
500 dst->st_ex_mtime = write_ts;
502 /* We may have to recalculate btime. */
503 if (dst->st_ex_calculated_birthtime) {
504 dst->st_ex_btime = calc_create_time_stat_ex(dst);
508 void update_stat_ex_create_time(struct stat_ex *dst,
509 struct timespec create_time)
511 dst->st_ex_btime = create_time;
512 dst->st_ex_calculated_birthtime = false;
515 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_STAT64)
516 static void init_stat_ex_from_stat (struct stat_ex *dst,
517 const struct stat64 *src,
518 bool fake_dir_create_times)
519 #else
520 static void init_stat_ex_from_stat (struct stat_ex *dst,
521 const struct stat *src,
522 bool fake_dir_create_times)
523 #endif
525 dst->st_ex_dev = src->st_dev;
526 dst->st_ex_ino = src->st_ino;
527 dst->st_ex_mode = src->st_mode;
528 dst->st_ex_nlink = src->st_nlink;
529 dst->st_ex_uid = src->st_uid;
530 dst->st_ex_gid = src->st_gid;
531 dst->st_ex_rdev = src->st_rdev;
532 dst->st_ex_size = src->st_size;
533 dst->st_ex_atime = get_atimespec(src);
534 dst->st_ex_mtime = get_mtimespec(src);
535 dst->st_ex_ctime = get_ctimespec(src);
536 make_create_timespec(src, dst, fake_dir_create_times);
537 dst->st_ex_blksize = src->st_blksize;
538 dst->st_ex_blocks = src->st_blocks;
540 #ifdef HAVE_STAT_ST_FLAGS
541 dst->st_ex_flags = src->st_flags;
542 #else
543 dst->st_ex_flags = 0;
544 #endif
547 /*******************************************************************
548 A stat() wrapper that will deal with 64 bit filesizes.
549 ********************************************************************/
551 int sys_stat(const char *fname, SMB_STRUCT_STAT *sbuf,
552 bool fake_dir_create_times)
554 int ret;
555 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_STAT64)
556 struct stat64 statbuf;
557 ret = stat64(fname, &statbuf);
558 #else
559 struct stat statbuf;
560 ret = stat(fname, &statbuf);
561 #endif
562 if (ret == 0) {
563 /* we always want directories to appear zero size */
564 if (S_ISDIR(statbuf.st_mode)) {
565 statbuf.st_size = 0;
567 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
569 return ret;
572 /*******************************************************************
573 An fstat() wrapper that will deal with 64 bit filesizes.
574 ********************************************************************/
576 int sys_fstat(int fd, SMB_STRUCT_STAT *sbuf, bool fake_dir_create_times)
578 int ret;
579 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FSTAT64)
580 struct stat64 statbuf;
581 ret = fstat64(fd, &statbuf);
582 #else
583 struct stat statbuf;
584 ret = fstat(fd, &statbuf);
585 #endif
586 if (ret == 0) {
587 /* we always want directories to appear zero size */
588 if (S_ISDIR(statbuf.st_mode)) {
589 statbuf.st_size = 0;
591 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
593 return ret;
596 /*******************************************************************
597 An lstat() wrapper that will deal with 64 bit filesizes.
598 ********************************************************************/
600 int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf,
601 bool fake_dir_create_times)
603 int ret;
604 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSTAT64)
605 struct stat64 statbuf;
606 ret = lstat64(fname, &statbuf);
607 #else
608 struct stat statbuf;
609 ret = lstat(fname, &statbuf);
610 #endif
611 if (ret == 0) {
612 /* we always want directories to appear zero size */
613 if (S_ISDIR(statbuf.st_mode)) {
614 statbuf.st_size = 0;
616 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
618 return ret;
621 /*******************************************************************
622 An posix_fallocate() wrapper that will deal with 64 bit filesizes.
623 ********************************************************************/
624 int sys_posix_fallocate(int fd, SMB_OFF_T offset, SMB_OFF_T len)
626 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_POSIX_FALLOCATE64) && !defined(HAVE_BROKEN_POSIX_FALLOCATE)
627 return posix_fallocate64(fd, offset, len);
628 #elif defined(HAVE_POSIX_FALLOCATE) && !defined(HAVE_BROKEN_POSIX_FALLOCATE)
629 return posix_fallocate(fd, offset, len);
630 #else
631 return ENOSYS;
632 #endif
635 /*******************************************************************
636 An ftruncate() wrapper that will deal with 64 bit filesizes.
637 ********************************************************************/
639 int sys_ftruncate(int fd, SMB_OFF_T offset)
641 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FTRUNCATE64)
642 return ftruncate64(fd, offset);
643 #else
644 return ftruncate(fd, offset);
645 #endif
648 /*******************************************************************
649 An lseek() wrapper that will deal with 64 bit filesizes.
650 ********************************************************************/
652 SMB_OFF_T sys_lseek(int fd, SMB_OFF_T offset, int whence)
654 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSEEK64)
655 return lseek64(fd, offset, whence);
656 #else
657 return lseek(fd, offset, whence);
658 #endif
661 /*******************************************************************
662 An fseek() wrapper that will deal with 64 bit filesizes.
663 ********************************************************************/
665 int sys_fseek(FILE *fp, SMB_OFF_T offset, int whence)
667 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEK64)
668 return fseek64(fp, offset, whence);
669 #elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEKO64)
670 return fseeko64(fp, offset, whence);
671 #else
672 return fseek(fp, offset, whence);
673 #endif
676 /*******************************************************************
677 An ftell() wrapper that will deal with 64 bit filesizes.
678 ********************************************************************/
680 SMB_OFF_T sys_ftell(FILE *fp)
682 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELL64)
683 return (SMB_OFF_T)ftell64(fp);
684 #elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELLO64)
685 return (SMB_OFF_T)ftello64(fp);
686 #else
687 return (SMB_OFF_T)ftell(fp);
688 #endif
691 /*******************************************************************
692 A creat() wrapper that will deal with 64 bit filesizes.
693 ********************************************************************/
695 int sys_creat(const char *path, mode_t mode)
697 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_CREAT64)
698 return creat64(path, mode);
699 #else
701 * If creat64 isn't defined then ensure we call a potential open64.
702 * JRA.
704 return sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
705 #endif
708 /*******************************************************************
709 An open() wrapper that will deal with 64 bit filesizes.
710 ********************************************************************/
712 int sys_open(const char *path, int oflag, mode_t mode)
714 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OPEN64)
715 return open64(path, oflag, mode);
716 #else
717 return open(path, oflag, mode);
718 #endif
721 /*******************************************************************
722 An fopen() wrapper that will deal with 64 bit filesizes.
723 ********************************************************************/
725 FILE *sys_fopen(const char *path, const char *type)
727 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_FOPEN64)
728 return fopen64(path, type);
729 #else
730 return fopen(path, type);
731 #endif
735 /*******************************************************************
736 A flock() wrapper that will perform the kernel flock.
737 ********************************************************************/
739 void kernel_flock(int fd, uint32 share_mode, uint32 access_mask)
741 #if HAVE_KERNEL_SHARE_MODES
742 int kernel_mode = 0;
743 if (share_mode == FILE_SHARE_WRITE) {
744 kernel_mode = LOCK_MAND|LOCK_WRITE;
745 } else if (share_mode == FILE_SHARE_READ) {
746 kernel_mode = LOCK_MAND|LOCK_READ;
747 } else if (share_mode == FILE_SHARE_NONE) {
748 kernel_mode = LOCK_MAND;
750 if (kernel_mode) {
751 flock(fd, kernel_mode);
753 #endif
759 /*******************************************************************
760 An opendir wrapper that will deal with 64 bit filesizes.
761 ********************************************************************/
763 SMB_STRUCT_DIR *sys_opendir(const char *name)
765 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OPENDIR64)
766 return opendir64(name);
767 #else
768 return opendir(name);
769 #endif
772 /*******************************************************************
773 A readdir wrapper that will deal with 64 bit filesizes.
774 ********************************************************************/
776 SMB_STRUCT_DIRENT *sys_readdir(SMB_STRUCT_DIR *dirp)
778 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_READDIR64)
779 return readdir64(dirp);
780 #else
781 return readdir(dirp);
782 #endif
785 /*******************************************************************
786 A seekdir wrapper that will deal with 64 bit filesizes.
787 ********************************************************************/
789 void sys_seekdir(SMB_STRUCT_DIR *dirp, long offset)
791 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_SEEKDIR64)
792 seekdir64(dirp, offset);
793 #else
794 seekdir(dirp, offset);
795 #endif
798 /*******************************************************************
799 A telldir wrapper that will deal with 64 bit filesizes.
800 ********************************************************************/
802 long sys_telldir(SMB_STRUCT_DIR *dirp)
804 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_TELLDIR64)
805 return (long)telldir64(dirp);
806 #else
807 return (long)telldir(dirp);
808 #endif
811 /*******************************************************************
812 A rewinddir wrapper that will deal with 64 bit filesizes.
813 ********************************************************************/
815 void sys_rewinddir(SMB_STRUCT_DIR *dirp)
817 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_REWINDDIR64)
818 rewinddir64(dirp);
819 #else
820 rewinddir(dirp);
821 #endif
824 /*******************************************************************
825 A close wrapper that will deal with 64 bit filesizes.
826 ********************************************************************/
828 int sys_closedir(SMB_STRUCT_DIR *dirp)
830 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_CLOSEDIR64)
831 return closedir64(dirp);
832 #else
833 return closedir(dirp);
834 #endif
837 /*******************************************************************
838 An mknod() wrapper that will deal with 64 bit filesizes.
839 ********************************************************************/
841 int sys_mknod(const char *path, mode_t mode, SMB_DEV_T dev)
843 #if defined(HAVE_MKNOD) || defined(HAVE_MKNOD64)
844 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_MKNOD64) && defined(HAVE_DEV64_T)
845 return mknod64(path, mode, dev);
846 #else
847 return mknod(path, mode, dev);
848 #endif
849 #else
850 /* No mknod system call. */
851 errno = ENOSYS;
852 return -1;
853 #endif
856 /*******************************************************************
857 The wait() calls vary between systems
858 ********************************************************************/
860 int sys_waitpid(pid_t pid,int *status,int options)
862 #ifdef HAVE_WAITPID
863 return waitpid(pid,status,options);
864 #else /* HAVE_WAITPID */
865 return wait4(pid, status, options, NULL);
866 #endif /* HAVE_WAITPID */
869 /*******************************************************************
870 System wrapper for getwd
871 ********************************************************************/
873 char *sys_getwd(char *s)
875 char *wd;
876 #ifdef HAVE_GETCWD
877 wd = (char *)getcwd(s, PATH_MAX);
878 #else
879 wd = (char *)getwd(s);
880 #endif
881 return wd;
884 #if defined(HAVE_POSIX_CAPABILITIES)
886 /* This define hasn't made it into the glibc capabilities header yet. */
887 #ifndef SECURE_NO_SETUID_FIXUP
888 #define SECURE_NO_SETUID_FIXUP 2
889 #endif
891 /**************************************************************************
892 Try and abstract process capabilities (for systems that have them).
893 ****************************************************************************/
895 /* Set the POSIX capabilities needed for the given purpose into the effective
896 * capability set of the current process. Make sure they are always removed
897 * from the inheritable set, because there is no circumstance in which our
898 * children should inherit our elevated privileges.
900 static bool set_process_capability(enum smbd_capability capability,
901 bool enable)
903 cap_value_t cap_vals[2] = {0};
904 int num_cap_vals = 0;
906 cap_t cap;
908 #if defined(HAVE_PRCTL) && defined(PR_GET_KEEPCAPS) && defined(PR_SET_KEEPCAPS)
909 /* On Linux, make sure that any capabilities we grab are sticky
910 * across UID changes. We expect that this would allow us to keep both
911 * the effective and permitted capability sets, but as of circa 2.6.16,
912 * only the permitted set is kept. It is a bug (which we work around)
913 * that the effective set is lost, but we still require the effective
914 * set to be kept.
916 if (!prctl(PR_GET_KEEPCAPS)) {
917 prctl(PR_SET_KEEPCAPS, 1);
919 #endif
921 #if defined(HAVE_PRCTL) && defined(PR_SET_SECUREBITS) && defined(SECURE_NO_SETUID_FIXUP)
922 /* New way of setting capabilities as "sticky". */
925 * Use PR_SET_SECUREBITS to prevent setresuid()
926 * atomically dropping effective capabilities on
927 * uid change. Only available in Linux kernels
928 * 2.6.26 and above.
930 * See here:
931 * http://www.kernel.org/doc/man-pages/online/pages/man7/capabilities.7.html
932 * for details.
934 * Specifically the CAP_KILL capability we need
935 * to allow Linux threads under different euids
936 * to send signals to each other.
939 if (prctl(PR_SET_SECUREBITS, 1 << SECURE_NO_SETUID_FIXUP)) {
940 DEBUG(0,("set_process_capability: "
941 "prctl PR_SET_SECUREBITS failed with error %s\n",
942 strerror(errno) ));
943 return false;
945 #endif
947 cap = cap_get_proc();
948 if (cap == NULL) {
949 DEBUG(0,("set_process_capability: cap_get_proc failed: %s\n",
950 strerror(errno)));
951 return False;
954 switch (capability) {
955 case KERNEL_OPLOCK_CAPABILITY:
956 #ifdef CAP_NETWORK_MGT
957 /* IRIX has CAP_NETWORK_MGT for oplocks. */
958 cap_vals[num_cap_vals++] = CAP_NETWORK_MGT;
959 #endif
960 break;
961 case DMAPI_ACCESS_CAPABILITY:
962 #ifdef CAP_DEVICE_MGT
963 /* IRIX has CAP_DEVICE_MGT for DMAPI access. */
964 cap_vals[num_cap_vals++] = CAP_DEVICE_MGT;
965 #elif CAP_MKNOD
966 /* Linux has CAP_MKNOD for DMAPI access. */
967 cap_vals[num_cap_vals++] = CAP_MKNOD;
968 #endif
969 break;
970 case LEASE_CAPABILITY:
971 #ifdef CAP_LEASE
972 cap_vals[num_cap_vals++] = CAP_LEASE;
973 #endif
974 break;
975 case KILL_CAPABILITY:
976 #ifdef CAP_KILL
977 cap_vals[num_cap_vals++] = CAP_KILL;
978 #endif
979 break;
982 SMB_ASSERT(num_cap_vals <= ARRAY_SIZE(cap_vals));
984 if (num_cap_vals == 0) {
985 cap_free(cap);
986 return True;
990 * Ensure the capability is effective. We assume that as a root
991 * process it's always permitted.
994 if (cap_set_flag(cap, CAP_EFFECTIVE, num_cap_vals, cap_vals,
995 enable ? CAP_SET : CAP_CLEAR) == -1) {
996 DEBUG(0, ("set_process_capability: cap_set_flag effective "
997 "failed (%d): %s\n",
998 (int)capability,
999 strerror(errno)));
1000 cap_free(cap);
1001 return false;
1004 /* We never want to pass capabilities down to our children, so make
1005 * sure they are not inherited.
1007 if (cap_set_flag(cap, CAP_INHERITABLE, num_cap_vals,
1008 cap_vals, CAP_CLEAR) == -1) {
1009 DEBUG(0, ("set_process_capability: cap_set_flag inheritable "
1010 "failed (%d): %s\n",
1011 (int)capability,
1012 strerror(errno)));
1013 cap_free(cap);
1014 return false;
1017 if (cap_set_proc(cap) == -1) {
1018 DEBUG(0, ("set_process_capability: cap_set_flag (%d) failed: %s\n",
1019 (int)capability,
1020 strerror(errno)));
1021 cap_free(cap);
1022 return False;
1025 cap_free(cap);
1026 return True;
1029 #endif /* HAVE_POSIX_CAPABILITIES */
1031 /****************************************************************************
1032 Gain the oplock capability from the kernel if possible.
1033 ****************************************************************************/
1035 void set_effective_capability(enum smbd_capability capability)
1037 #if defined(HAVE_POSIX_CAPABILITIES)
1038 set_process_capability(capability, True);
1039 #endif /* HAVE_POSIX_CAPABILITIES */
1042 void drop_effective_capability(enum smbd_capability capability)
1044 #if defined(HAVE_POSIX_CAPABILITIES)
1045 set_process_capability(capability, False);
1046 #endif /* HAVE_POSIX_CAPABILITIES */
1049 /**************************************************************************
1050 Wrapper for random().
1051 ****************************************************************************/
1053 long sys_random(void)
1055 #if defined(HAVE_RANDOM)
1056 return (long)random();
1057 #elif defined(HAVE_RAND)
1058 return (long)rand();
1059 #else
1060 DEBUG(0,("Error - no random function available !\n"));
1061 exit(1);
1062 #endif
1065 /**************************************************************************
1066 Wrapper for srandom().
1067 ****************************************************************************/
1069 void sys_srandom(unsigned int seed)
1071 #if defined(HAVE_SRANDOM)
1072 srandom(seed);
1073 #elif defined(HAVE_SRAND)
1074 srand(seed);
1075 #else
1076 DEBUG(0,("Error - no srandom function available !\n"));
1077 exit(1);
1078 #endif
1081 /**************************************************************************
1082 Returns equivalent to NGROUPS_MAX - using sysconf if needed.
1083 ****************************************************************************/
1085 int groups_max(void)
1087 #if defined(SYSCONF_SC_NGROUPS_MAX)
1088 int ret = sysconf(_SC_NGROUPS_MAX);
1089 return (ret == -1) ? NGROUPS_MAX : ret;
1090 #else
1091 return NGROUPS_MAX;
1092 #endif
1095 /**************************************************************************
1096 Wrap setgroups and getgroups for systems that declare getgroups() as
1097 returning an array of gid_t, but actuall return an array of int.
1098 ****************************************************************************/
1100 #if defined(HAVE_BROKEN_GETGROUPS)
1101 static int sys_broken_getgroups(int setlen, gid_t *gidset)
1103 GID_T gid;
1104 GID_T *group_list;
1105 int i, ngroups;
1107 if(setlen == 0) {
1108 return getgroups(setlen, &gid);
1112 * Broken case. We need to allocate a
1113 * GID_T array of size setlen.
1116 if(setlen < 0) {
1117 errno = EINVAL;
1118 return -1;
1121 if (setlen == 0)
1122 setlen = groups_max();
1124 if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
1125 DEBUG(0,("sys_getgroups: Malloc fail.\n"));
1126 return -1;
1129 if((ngroups = getgroups(setlen, group_list)) < 0) {
1130 int saved_errno = errno;
1131 SAFE_FREE(group_list);
1132 errno = saved_errno;
1133 return -1;
1136 for(i = 0; i < ngroups; i++)
1137 gidset[i] = (gid_t)group_list[i];
1139 SAFE_FREE(group_list);
1140 return ngroups;
1143 static int sys_broken_setgroups(int setlen, gid_t *gidset)
1145 GID_T *group_list;
1146 int i ;
1148 if (setlen == 0)
1149 return 0 ;
1151 if (setlen < 0 || setlen > groups_max()) {
1152 errno = EINVAL;
1153 return -1;
1157 * Broken case. We need to allocate a
1158 * GID_T array of size setlen.
1161 if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
1162 DEBUG(0,("sys_setgroups: Malloc fail.\n"));
1163 return -1;
1166 for(i = 0; i < setlen; i++)
1167 group_list[i] = (GID_T) gidset[i];
1169 if(setgroups(setlen, group_list) != 0) {
1170 int saved_errno = errno;
1171 SAFE_FREE(group_list);
1172 errno = saved_errno;
1173 return -1;
1176 SAFE_FREE(group_list);
1177 return 0 ;
1180 #endif /* HAVE_BROKEN_GETGROUPS */
1182 /* This is a list of systems that require the first GID passed to setgroups(2)
1183 * to be the effective GID. If your system is one of these, add it here.
1185 #if defined (FREEBSD) || defined (DARWINOS)
1186 #define USE_BSD_SETGROUPS
1187 #endif
1189 #if defined(USE_BSD_SETGROUPS)
1190 /* Depending on the particular BSD implementation, the first GID that is
1191 * passed to setgroups(2) will either be ignored or will set the credential's
1192 * effective GID. In either case, the right thing to do is to guarantee that
1193 * gidset[0] is the effective GID.
1195 static int sys_bsd_setgroups(gid_t primary_gid, int setlen, const gid_t *gidset)
1197 gid_t *new_gidset = NULL;
1198 int max;
1199 int ret;
1201 /* setgroups(2) will fail with EINVAL if we pass too many groups. */
1202 max = groups_max();
1204 /* No group list, just make sure we are setting the efective GID. */
1205 if (setlen == 0) {
1206 return setgroups(1, &primary_gid);
1209 /* If the primary gid is not the first array element, grow the array
1210 * and insert it at the front.
1212 if (gidset[0] != primary_gid) {
1213 new_gidset = SMB_MALLOC_ARRAY(gid_t, setlen + 1);
1214 if (new_gidset == NULL) {
1215 return -1;
1218 memcpy(new_gidset + 1, gidset, (setlen * sizeof(gid_t)));
1219 new_gidset[0] = primary_gid;
1220 setlen++;
1223 if (setlen > max) {
1224 DEBUG(3, ("forced to truncate group list from %d to %d\n",
1225 setlen, max));
1226 setlen = max;
1229 #if defined(HAVE_BROKEN_GETGROUPS)
1230 ret = sys_broken_setgroups(setlen, new_gidset ? new_gidset : gidset);
1231 #else
1232 ret = setgroups(setlen, new_gidset ? new_gidset : gidset);
1233 #endif
1235 if (new_gidset) {
1236 int errsav = errno;
1237 SAFE_FREE(new_gidset);
1238 errno = errsav;
1241 return ret;
1244 #endif /* USE_BSD_SETGROUPS */
1246 /**************************************************************************
1247 Wrapper for getgroups. Deals with broken (int) case.
1248 ****************************************************************************/
1250 int sys_getgroups(int setlen, gid_t *gidset)
1252 #if defined(HAVE_BROKEN_GETGROUPS)
1253 return sys_broken_getgroups(setlen, gidset);
1254 #else
1255 return getgroups(setlen, gidset);
1256 #endif
1259 /**************************************************************************
1260 Wrapper for setgroups. Deals with broken (int) case and BSD case.
1261 ****************************************************************************/
1263 int sys_setgroups(gid_t UNUSED(primary_gid), int setlen, gid_t *gidset)
1265 #if !defined(HAVE_SETGROUPS)
1266 errno = ENOSYS;
1267 return -1;
1268 #endif /* HAVE_SETGROUPS */
1270 #if defined(USE_BSD_SETGROUPS)
1271 return sys_bsd_setgroups(primary_gid, setlen, gidset);
1272 #elif defined(HAVE_BROKEN_GETGROUPS)
1273 return sys_broken_setgroups(setlen, gidset);
1274 #else
1275 return setgroups(setlen, gidset);
1276 #endif
1279 /**************************************************************************
1280 Wrappers for setpwent(), getpwent() and endpwent()
1281 ****************************************************************************/
1283 void sys_setpwent(void)
1285 setpwent();
1288 struct passwd *sys_getpwent(void)
1290 return getpwent();
1293 void sys_endpwent(void)
1295 endpwent();
1298 /**************************************************************************
1299 Wrappers for getpwnam(), getpwuid(), getgrnam(), getgrgid()
1300 ****************************************************************************/
1303 struct passwd *sys_getpwnam(const char *name)
1305 return getpwnam(name);
1308 struct passwd *sys_getpwuid(uid_t uid)
1310 return getpwuid(uid);
1313 struct group *sys_getgrnam(const char *name)
1315 return getgrnam(name);
1318 struct group *sys_getgrgid(gid_t gid)
1320 return getgrgid(gid);
1323 /**************************************************************************
1324 Extract a command into an arg list.
1325 ****************************************************************************/
1327 static char **extract_args(TALLOC_CTX *mem_ctx, const char *command)
1329 char *trunc_cmd;
1330 char *saveptr;
1331 char *ptr;
1332 int argcl;
1333 char **argl = NULL;
1334 int i;
1336 if (!(trunc_cmd = talloc_strdup(mem_ctx, command))) {
1337 DEBUG(0, ("talloc failed\n"));
1338 goto nomem;
1341 if(!(ptr = strtok_r(trunc_cmd, " \t", &saveptr))) {
1342 TALLOC_FREE(trunc_cmd);
1343 errno = EINVAL;
1344 return NULL;
1348 * Count the args.
1351 for( argcl = 1; ptr; ptr = strtok_r(NULL, " \t", &saveptr))
1352 argcl++;
1354 TALLOC_FREE(trunc_cmd);
1356 if (!(argl = TALLOC_ARRAY(mem_ctx, char *, argcl + 1))) {
1357 goto nomem;
1361 * Now do the extraction.
1364 if (!(trunc_cmd = talloc_strdup(mem_ctx, command))) {
1365 goto nomem;
1368 ptr = strtok_r(trunc_cmd, " \t", &saveptr);
1369 i = 0;
1371 if (!(argl[i++] = talloc_strdup(argl, ptr))) {
1372 goto nomem;
1375 while((ptr = strtok_r(NULL, " \t", &saveptr)) != NULL) {
1377 if (!(argl[i++] = talloc_strdup(argl, ptr))) {
1378 goto nomem;
1382 argl[i++] = NULL;
1383 TALLOC_FREE(trunc_cmd);
1384 return argl;
1386 nomem:
1387 DEBUG(0, ("talloc failed\n"));
1388 TALLOC_FREE(trunc_cmd);
1389 TALLOC_FREE(argl);
1390 errno = ENOMEM;
1391 return NULL;
1394 /**************************************************************************
1395 Wrapper for popen. Safer as it doesn't search a path.
1396 Modified from the glibc sources.
1397 modified by tridge to return a file descriptor. We must kick our FILE* habit
1398 ****************************************************************************/
1400 typedef struct _popen_list
1402 int fd;
1403 pid_t child_pid;
1404 struct _popen_list *next;
1405 } popen_list;
1407 static popen_list *popen_chain;
1409 int sys_popen(const char *command)
1411 int parent_end, child_end;
1412 int pipe_fds[2];
1413 popen_list *entry = NULL;
1414 char **argl = NULL;
1416 if (pipe(pipe_fds) < 0)
1417 return -1;
1419 parent_end = pipe_fds[0];
1420 child_end = pipe_fds[1];
1422 if (!*command) {
1423 errno = EINVAL;
1424 goto err_exit;
1427 if((entry = SMB_MALLOC_P(popen_list)) == NULL)
1428 goto err_exit;
1430 ZERO_STRUCTP(entry);
1433 * Extract the command and args into a NULL terminated array.
1436 if(!(argl = extract_args(NULL, command)))
1437 goto err_exit;
1439 entry->child_pid = sys_fork();
1441 if (entry->child_pid == -1) {
1442 goto err_exit;
1445 if (entry->child_pid == 0) {
1448 * Child !
1451 int child_std_end = STDOUT_FILENO;
1452 popen_list *p;
1454 close(parent_end);
1455 if (child_end != child_std_end) {
1456 dup2 (child_end, child_std_end);
1457 close (child_end);
1461 * POSIX.2: "popen() shall ensure that any streams from previous
1462 * popen() calls that remain open in the parent process are closed
1463 * in the new child process."
1466 for (p = popen_chain; p; p = p->next)
1467 close(p->fd);
1469 execv(argl[0], argl);
1470 _exit (127);
1474 * Parent.
1477 close (child_end);
1478 TALLOC_FREE(argl);
1480 /* Link into popen_chain. */
1481 entry->next = popen_chain;
1482 popen_chain = entry;
1483 entry->fd = parent_end;
1485 return entry->fd;
1487 err_exit:
1489 SAFE_FREE(entry);
1490 SAFE_FREE(argl);
1491 close(pipe_fds[0]);
1492 close(pipe_fds[1]);
1493 return -1;
1496 /**************************************************************************
1497 Wrapper for pclose. Modified from the glibc sources.
1498 ****************************************************************************/
1500 int sys_pclose(int fd)
1502 int wstatus;
1503 popen_list **ptr = &popen_chain;
1504 popen_list *entry = NULL;
1505 pid_t wait_pid;
1506 int status = -1;
1508 /* Unlink from popen_chain. */
1509 for ( ; *ptr != NULL; ptr = &(*ptr)->next) {
1510 if ((*ptr)->fd == fd) {
1511 entry = *ptr;
1512 *ptr = (*ptr)->next;
1513 status = 0;
1514 break;
1518 if (status < 0 || close(entry->fd) < 0)
1519 return -1;
1522 * As Samba is catching and eating child process
1523 * exits we don't really care about the child exit
1524 * code, a -1 with errno = ECHILD will do fine for us.
1527 do {
1528 wait_pid = sys_waitpid (entry->child_pid, &wstatus, 0);
1529 } while (wait_pid == -1 && errno == EINTR);
1531 SAFE_FREE(entry);
1533 if (wait_pid == -1)
1534 return -1;
1535 return wstatus;
1538 /**************************************************************************
1539 Wrapper for Admin Logs.
1540 ****************************************************************************/
1542 void sys_adminlog(int priority, const char *format_str, ...)
1544 va_list ap;
1545 int ret;
1546 char *msgbuf = NULL;
1548 va_start( ap, format_str );
1549 ret = vasprintf( &msgbuf, format_str, ap );
1550 va_end( ap );
1552 if (ret == -1)
1553 return;
1555 #if defined(HAVE_SYSLOG)
1556 syslog( priority, "%s", msgbuf );
1557 #else
1558 DEBUG(0,("%s", msgbuf ));
1559 #endif
1560 SAFE_FREE(msgbuf);
1563 /******** Solaris EA helper function prototypes ********/
1564 #ifdef HAVE_ATTROPEN
1565 #define SOLARIS_ATTRMODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP
1566 static int solaris_write_xattr(int attrfd, const char *value, size_t size);
1567 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size);
1568 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size);
1569 static int solaris_unlinkat(int attrdirfd, const char *name);
1570 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode);
1571 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode);
1572 #endif
1574 /**************************************************************************
1575 Wrappers for extented attribute calls. Based on the Linux package with
1576 support for IRIX and (Net|Free)BSD also. Expand as other systems have them.
1577 ****************************************************************************/
1579 ssize_t sys_getxattr (const char *path, const char *name, void *value, size_t size)
1581 #if defined(HAVE_GETXATTR)
1582 #ifndef XATTR_ADD_OPT
1583 return getxattr(path, name, value, size);
1584 #else
1585 int options = 0;
1586 return getxattr(path, name, value, size, 0, options);
1587 #endif
1588 #elif defined(HAVE_GETEA)
1589 return getea(path, name, value, size);
1590 #elif defined(HAVE_EXTATTR_GET_FILE)
1591 char *s;
1592 ssize_t retval;
1593 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
1594 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1595 const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1597 * The BSD implementation has a nasty habit of silently truncating
1598 * the returned value to the size of the buffer, so we have to check
1599 * that the buffer is large enough to fit the returned value.
1601 if((retval=extattr_get_file(path, attrnamespace, attrname, NULL, 0)) >= 0) {
1602 if(retval > size) {
1603 errno = ERANGE;
1604 return -1;
1606 if((retval=extattr_get_file(path, attrnamespace, attrname, value, size)) >= 0)
1607 return retval;
1610 DEBUG(10,("sys_getxattr: extattr_get_file() failed with: %s\n", strerror(errno)));
1611 return -1;
1612 #elif defined(HAVE_ATTR_GET)
1613 int retval, flags = 0;
1614 int valuelength = (int)size;
1615 char *attrname = strchr(name,'.') + 1;
1617 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1619 retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
1621 return retval ? retval : valuelength;
1622 #elif defined(HAVE_ATTROPEN)
1623 ssize_t ret = -1;
1624 int attrfd = solaris_attropen(path, name, O_RDONLY, 0);
1625 if (attrfd >= 0) {
1626 ret = solaris_read_xattr(attrfd, value, size);
1627 close(attrfd);
1629 return ret;
1630 #else
1631 errno = ENOSYS;
1632 return -1;
1633 #endif
1636 ssize_t sys_lgetxattr (const char *path, const char *name, void *value, size_t size)
1638 #if defined(HAVE_LGETXATTR)
1639 return lgetxattr(path, name, value, size);
1640 #elif defined(HAVE_GETXATTR) && defined(XATTR_ADD_OPT)
1641 int options = XATTR_NOFOLLOW;
1642 return getxattr(path, name, value, size, 0, options);
1643 #elif defined(HAVE_LGETEA)
1644 return lgetea(path, name, value, size);
1645 #elif defined(HAVE_EXTATTR_GET_LINK)
1646 char *s;
1647 ssize_t retval;
1648 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
1649 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1650 const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1652 if((retval=extattr_get_link(path, attrnamespace, attrname, NULL, 0)) >= 0) {
1653 if(retval > size) {
1654 errno = ERANGE;
1655 return -1;
1657 if((retval=extattr_get_link(path, attrnamespace, attrname, value, size)) >= 0)
1658 return retval;
1661 DEBUG(10,("sys_lgetxattr: extattr_get_link() failed with: %s\n", strerror(errno)));
1662 return -1;
1663 #elif defined(HAVE_ATTR_GET)
1664 int retval, flags = ATTR_DONTFOLLOW;
1665 int valuelength = (int)size;
1666 char *attrname = strchr(name,'.') + 1;
1668 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1670 retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
1672 return retval ? retval : valuelength;
1673 #elif defined(HAVE_ATTROPEN)
1674 ssize_t ret = -1;
1675 int attrfd = solaris_attropen(path, name, O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
1676 if (attrfd >= 0) {
1677 ret = solaris_read_xattr(attrfd, value, size);
1678 close(attrfd);
1680 return ret;
1681 #else
1682 errno = ENOSYS;
1683 return -1;
1684 #endif
1687 ssize_t sys_fgetxattr (int filedes, const char *name, void *value, size_t size)
1689 #if defined(HAVE_FGETXATTR)
1690 #ifndef XATTR_ADD_OPT
1691 return fgetxattr(filedes, name, value, size);
1692 #else
1693 int options = 0;
1694 return fgetxattr(filedes, name, value, size, 0, options);
1695 #endif
1696 #elif defined(HAVE_FGETEA)
1697 return fgetea(filedes, name, value, size);
1698 #elif defined(HAVE_EXTATTR_GET_FD)
1699 char *s;
1700 ssize_t retval;
1701 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
1702 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1703 const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1705 if((retval=extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0)) >= 0) {
1706 if(retval > size) {
1707 errno = ERANGE;
1708 return -1;
1710 if((retval=extattr_get_fd(filedes, attrnamespace, attrname, value, size)) >= 0)
1711 return retval;
1714 DEBUG(10,("sys_fgetxattr: extattr_get_fd() failed with: %s\n", strerror(errno)));
1715 return -1;
1716 #elif defined(HAVE_ATTR_GETF)
1717 int retval, flags = 0;
1718 int valuelength = (int)size;
1719 char *attrname = strchr(name,'.') + 1;
1721 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1723 retval = attr_getf(filedes, attrname, (char *)value, &valuelength, flags);
1725 return retval ? retval : valuelength;
1726 #elif defined(HAVE_ATTROPEN)
1727 ssize_t ret = -1;
1728 int attrfd = solaris_openat(filedes, name, O_RDONLY|O_XATTR, 0);
1729 if (attrfd >= 0) {
1730 ret = solaris_read_xattr(attrfd, value, size);
1731 close(attrfd);
1733 return ret;
1734 #else
1735 errno = ENOSYS;
1736 return -1;
1737 #endif
1740 #if defined(HAVE_EXTATTR_LIST_FILE)
1742 #define EXTATTR_PREFIX(s) (s), (sizeof((s))-1)
1744 static struct {
1745 int space;
1746 const char *name;
1747 size_t len;
1749 extattr[] = {
1750 { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("system.") },
1751 { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("user.") },
1754 typedef union {
1755 const char *path;
1756 int filedes;
1757 } extattr_arg;
1759 static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size)
1761 ssize_t list_size, total_size = 0;
1762 int i, t, len;
1763 char *buf;
1764 /* Iterate through extattr(2) namespaces */
1765 for(t = 0; t < (sizeof(extattr)/sizeof(extattr[0])); t++) {
1766 switch(type) {
1767 #if defined(HAVE_EXTATTR_LIST_FILE)
1768 case 0:
1769 list_size = extattr_list_file(arg.path, extattr[t].space, list, size);
1770 break;
1771 #endif
1772 #if defined(HAVE_EXTATTR_LIST_LINK)
1773 case 1:
1774 list_size = extattr_list_link(arg.path, extattr[t].space, list, size);
1775 break;
1776 #endif
1777 #if defined(HAVE_EXTATTR_LIST_FD)
1778 case 2:
1779 list_size = extattr_list_fd(arg.filedes, extattr[t].space, list, size);
1780 break;
1781 #endif
1782 default:
1783 errno = ENOSYS;
1784 return -1;
1786 /* Some error happend. Errno should be set by the previous call */
1787 if(list_size < 0)
1788 return -1;
1789 /* No attributes */
1790 if(list_size == 0)
1791 continue;
1792 /* XXX: Call with an empty buffer may be used to calculate
1793 necessary buffer size. Unfortunately, we can't say, how
1794 many attributes were returned, so here is the potential
1795 problem with the emulation.
1797 if(list == NULL) {
1798 /* Take the worse case of one char attribute names -
1799 two bytes per name plus one more for sanity.
1801 total_size += list_size + (list_size/2 + 1)*extattr[t].len;
1802 continue;
1804 /* Count necessary offset to fit namespace prefixes */
1805 len = 0;
1806 for(i = 0; i < list_size; i += list[i] + 1)
1807 len += extattr[t].len;
1809 total_size += list_size + len;
1810 /* Buffer is too small to fit the results */
1811 if(total_size > size) {
1812 errno = ERANGE;
1813 return -1;
1815 /* Shift results back, so we can prepend prefixes */
1816 buf = memmove(list + len, list, list_size);
1818 for(i = 0; i < list_size; i += len + 1) {
1819 len = buf[i];
1820 strncpy(list, extattr[t].name, extattr[t].len + 1);
1821 list += extattr[t].len;
1822 strncpy(list, buf + i + 1, len);
1823 list[len] = '\0';
1824 list += len + 1;
1826 size -= total_size;
1828 return total_size;
1831 #endif
1833 #if defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1834 static char attr_buffer[ATTR_MAX_VALUELEN];
1836 static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
1838 int retval = 0, index;
1839 attrlist_cursor_t *cursor = 0;
1840 int total_size = 0;
1841 attrlist_t * al = (attrlist_t *)attr_buffer;
1842 attrlist_ent_t *ae;
1843 size_t ent_size, left = size;
1844 char *bp = list;
1846 while (True) {
1847 if (filedes)
1848 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1849 else
1850 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1851 if (retval) break;
1852 for (index = 0; index < al->al_count; index++) {
1853 ae = ATTR_ENTRY(attr_buffer, index);
1854 ent_size = strlen(ae->a_name) + sizeof("user.");
1855 if (left >= ent_size) {
1856 strncpy(bp, "user.", sizeof("user."));
1857 strncat(bp, ae->a_name, ent_size - sizeof("user."));
1858 bp += ent_size;
1859 left -= ent_size;
1860 } else if (size) {
1861 errno = ERANGE;
1862 retval = -1;
1863 break;
1865 total_size += ent_size;
1867 if (al->al_more == 0) break;
1869 if (retval == 0) {
1870 flags |= ATTR_ROOT;
1871 cursor = 0;
1872 while (True) {
1873 if (filedes)
1874 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1875 else
1876 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1877 if (retval) break;
1878 for (index = 0; index < al->al_count; index++) {
1879 ae = ATTR_ENTRY(attr_buffer, index);
1880 ent_size = strlen(ae->a_name) + sizeof("system.");
1881 if (left >= ent_size) {
1882 strncpy(bp, "system.", sizeof("system."));
1883 strncat(bp, ae->a_name, ent_size - sizeof("system."));
1884 bp += ent_size;
1885 left -= ent_size;
1886 } else if (size) {
1887 errno = ERANGE;
1888 retval = -1;
1889 break;
1891 total_size += ent_size;
1893 if (al->al_more == 0) break;
1896 return (ssize_t)(retval ? retval : total_size);
1899 #endif
1901 ssize_t sys_listxattr (const char *path, char *list, size_t size)
1903 #if defined(HAVE_LISTXATTR)
1904 #ifndef XATTR_ADD_OPT
1905 return listxattr(path, list, size);
1906 #else
1907 int options = 0;
1908 return listxattr(path, list, size, options);
1909 #endif
1910 #elif defined(HAVE_LISTEA)
1911 return listea(path, list, size);
1912 #elif defined(HAVE_EXTATTR_LIST_FILE)
1913 extattr_arg arg;
1914 arg.path = path;
1915 return bsd_attr_list(0, arg, list, size);
1916 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1917 return irix_attr_list(path, 0, list, size, 0);
1918 #elif defined(HAVE_ATTROPEN)
1919 ssize_t ret = -1;
1920 int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
1921 if (attrdirfd >= 0) {
1922 ret = solaris_list_xattr(attrdirfd, list, size);
1923 close(attrdirfd);
1925 return ret;
1926 #else
1927 errno = ENOSYS;
1928 return -1;
1929 #endif
1932 ssize_t sys_llistxattr (const char *path, char *list, size_t size)
1934 #if defined(HAVE_LLISTXATTR)
1935 return llistxattr(path, list, size);
1936 #elif defined(HAVE_LISTXATTR) && defined(XATTR_ADD_OPT)
1937 int options = XATTR_NOFOLLOW;
1938 return listxattr(path, list, size, options);
1939 #elif defined(HAVE_LLISTEA)
1940 return llistea(path, list, size);
1941 #elif defined(HAVE_EXTATTR_LIST_LINK)
1942 extattr_arg arg;
1943 arg.path = path;
1944 return bsd_attr_list(1, arg, list, size);
1945 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1946 return irix_attr_list(path, 0, list, size, ATTR_DONTFOLLOW);
1947 #elif defined(HAVE_ATTROPEN)
1948 ssize_t ret = -1;
1949 int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
1950 if (attrdirfd >= 0) {
1951 ret = solaris_list_xattr(attrdirfd, list, size);
1952 close(attrdirfd);
1954 return ret;
1955 #else
1956 errno = ENOSYS;
1957 return -1;
1958 #endif
1961 ssize_t sys_flistxattr (int filedes, char *list, size_t size)
1963 #if defined(HAVE_FLISTXATTR)
1964 #ifndef XATTR_ADD_OPT
1965 return flistxattr(filedes, list, size);
1966 #else
1967 int options = 0;
1968 return flistxattr(filedes, list, size, options);
1969 #endif
1970 #elif defined(HAVE_FLISTEA)
1971 return flistea(filedes, list, size);
1972 #elif defined(HAVE_EXTATTR_LIST_FD)
1973 extattr_arg arg;
1974 arg.filedes = filedes;
1975 return bsd_attr_list(2, arg, list, size);
1976 #elif defined(HAVE_ATTR_LISTF)
1977 return irix_attr_list(NULL, filedes, list, size, 0);
1978 #elif defined(HAVE_ATTROPEN)
1979 ssize_t ret = -1;
1980 int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
1981 if (attrdirfd >= 0) {
1982 ret = solaris_list_xattr(attrdirfd, list, size);
1983 close(attrdirfd);
1985 return ret;
1986 #else
1987 errno = ENOSYS;
1988 return -1;
1989 #endif
1992 int sys_removexattr (const char *path, const char *name)
1994 #if defined(HAVE_REMOVEXATTR)
1995 #ifndef XATTR_ADD_OPT
1996 return removexattr(path, name);
1997 #else
1998 int options = 0;
1999 return removexattr(path, name, options);
2000 #endif
2001 #elif defined(HAVE_REMOVEEA)
2002 return removeea(path, name);
2003 #elif defined(HAVE_EXTATTR_DELETE_FILE)
2004 char *s;
2005 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
2006 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
2007 const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
2009 return extattr_delete_file(path, attrnamespace, attrname);
2010 #elif defined(HAVE_ATTR_REMOVE)
2011 int flags = 0;
2012 char *attrname = strchr(name,'.') + 1;
2014 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
2016 return attr_remove(path, attrname, flags);
2017 #elif defined(HAVE_ATTROPEN)
2018 int ret = -1;
2019 int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
2020 if (attrdirfd >= 0) {
2021 ret = solaris_unlinkat(attrdirfd, name);
2022 close(attrdirfd);
2024 return ret;
2025 #else
2026 errno = ENOSYS;
2027 return -1;
2028 #endif
2031 int sys_lremovexattr (const char *path, const char *name)
2033 #if defined(HAVE_LREMOVEXATTR)
2034 return lremovexattr(path, name);
2035 #elif defined(HAVE_REMOVEXATTR) && defined(XATTR_ADD_OPT)
2036 int options = XATTR_NOFOLLOW;
2037 return removexattr(path, name, options);
2038 #elif defined(HAVE_LREMOVEEA)
2039 return lremoveea(path, name);
2040 #elif defined(HAVE_EXTATTR_DELETE_LINK)
2041 char *s;
2042 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
2043 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
2044 const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
2046 return extattr_delete_link(path, attrnamespace, attrname);
2047 #elif defined(HAVE_ATTR_REMOVE)
2048 int flags = ATTR_DONTFOLLOW;
2049 char *attrname = strchr(name,'.') + 1;
2051 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
2053 return attr_remove(path, attrname, flags);
2054 #elif defined(HAVE_ATTROPEN)
2055 int ret = -1;
2056 int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
2057 if (attrdirfd >= 0) {
2058 ret = solaris_unlinkat(attrdirfd, name);
2059 close(attrdirfd);
2061 return ret;
2062 #else
2063 errno = ENOSYS;
2064 return -1;
2065 #endif
2068 int sys_fremovexattr (int filedes, const char *name)
2070 #if defined(HAVE_FREMOVEXATTR)
2071 #ifndef XATTR_ADD_OPT
2072 return fremovexattr(filedes, name);
2073 #else
2074 int options = 0;
2075 return fremovexattr(filedes, name, options);
2076 #endif
2077 #elif defined(HAVE_FREMOVEEA)
2078 return fremoveea(filedes, name);
2079 #elif defined(HAVE_EXTATTR_DELETE_FD)
2080 char *s;
2081 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
2082 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
2083 const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
2085 return extattr_delete_fd(filedes, attrnamespace, attrname);
2086 #elif defined(HAVE_ATTR_REMOVEF)
2087 int flags = 0;
2088 char *attrname = strchr(name,'.') + 1;
2090 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
2092 return attr_removef(filedes, attrname, flags);
2093 #elif defined(HAVE_ATTROPEN)
2094 int ret = -1;
2095 int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
2096 if (attrdirfd >= 0) {
2097 ret = solaris_unlinkat(attrdirfd, name);
2098 close(attrdirfd);
2100 return ret;
2101 #else
2102 errno = ENOSYS;
2103 return -1;
2104 #endif
2107 int sys_setxattr (const char *path, const char *name, const void *value, size_t size, int flags)
2109 #if defined(HAVE_SETXATTR)
2110 #ifndef XATTR_ADD_OPT
2111 return setxattr(path, name, value, size, flags);
2112 #else
2113 int options = 0;
2114 return setxattr(path, name, value, size, 0, options);
2115 #endif
2116 #elif defined(HAVE_SETEA)
2117 return setea(path, name, value, size, flags);
2118 #elif defined(HAVE_EXTATTR_SET_FILE)
2119 char *s;
2120 int retval = 0;
2121 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
2122 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
2123 const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
2124 if (flags) {
2125 /* Check attribute existence */
2126 retval = extattr_get_file(path, attrnamespace, attrname, NULL, 0);
2127 if (retval < 0) {
2128 /* REPLACE attribute, that doesn't exist */
2129 if (flags & XATTR_REPLACE && errno == ENOATTR) {
2130 errno = ENOATTR;
2131 return -1;
2133 /* Ignore other errors */
2135 else {
2136 /* CREATE attribute, that already exists */
2137 if (flags & XATTR_CREATE) {
2138 errno = EEXIST;
2139 return -1;
2143 retval = extattr_set_file(path, attrnamespace, attrname, value, size);
2144 return (retval < 0) ? -1 : 0;
2145 #elif defined(HAVE_ATTR_SET)
2146 int myflags = 0;
2147 char *attrname = strchr(name,'.') + 1;
2149 if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
2150 if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
2151 if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
2153 return attr_set(path, attrname, (const char *)value, size, myflags);
2154 #elif defined(HAVE_ATTROPEN)
2155 int ret = -1;
2156 int myflags = O_RDWR;
2157 int attrfd;
2158 if (flags & XATTR_CREATE) myflags |= O_EXCL;
2159 if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
2160 attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
2161 if (attrfd >= 0) {
2162 ret = solaris_write_xattr(attrfd, value, size);
2163 close(attrfd);
2165 return ret;
2166 #else
2167 errno = ENOSYS;
2168 return -1;
2169 #endif
2172 int sys_lsetxattr (const char *path, const char *name, const void *value, size_t size, int flags)
2174 #if defined(HAVE_LSETXATTR)
2175 return lsetxattr(path, name, value, size, flags);
2176 #elif defined(HAVE_SETXATTR) && defined(XATTR_ADD_OPT)
2177 int options = XATTR_NOFOLLOW;
2178 return setxattr(path, name, value, size, 0, options);
2179 #elif defined(LSETEA)
2180 return lsetea(path, name, value, size, flags);
2181 #elif defined(HAVE_EXTATTR_SET_LINK)
2182 char *s;
2183 int retval = 0;
2184 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
2185 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
2186 const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
2187 if (flags) {
2188 /* Check attribute existence */
2189 retval = extattr_get_link(path, attrnamespace, attrname, NULL, 0);
2190 if (retval < 0) {
2191 /* REPLACE attribute, that doesn't exist */
2192 if (flags & XATTR_REPLACE && errno == ENOATTR) {
2193 errno = ENOATTR;
2194 return -1;
2196 /* Ignore other errors */
2198 else {
2199 /* CREATE attribute, that already exists */
2200 if (flags & XATTR_CREATE) {
2201 errno = EEXIST;
2202 return -1;
2207 retval = extattr_set_link(path, attrnamespace, attrname, value, size);
2208 return (retval < 0) ? -1 : 0;
2209 #elif defined(HAVE_ATTR_SET)
2210 int myflags = ATTR_DONTFOLLOW;
2211 char *attrname = strchr(name,'.') + 1;
2213 if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
2214 if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
2215 if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
2217 return attr_set(path, attrname, (const char *)value, size, myflags);
2218 #elif defined(HAVE_ATTROPEN)
2219 int ret = -1;
2220 int myflags = O_RDWR | AT_SYMLINK_NOFOLLOW;
2221 int attrfd;
2222 if (flags & XATTR_CREATE) myflags |= O_EXCL;
2223 if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
2224 attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
2225 if (attrfd >= 0) {
2226 ret = solaris_write_xattr(attrfd, value, size);
2227 close(attrfd);
2229 return ret;
2230 #else
2231 errno = ENOSYS;
2232 return -1;
2233 #endif
2236 int sys_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags)
2238 #if defined(HAVE_FSETXATTR)
2239 #ifndef XATTR_ADD_OPT
2240 return fsetxattr(filedes, name, value, size, flags);
2241 #else
2242 int options = 0;
2243 return fsetxattr(filedes, name, value, size, 0, options);
2244 #endif
2245 #elif defined(HAVE_FSETEA)
2246 return fsetea(filedes, name, value, size, flags);
2247 #elif defined(HAVE_EXTATTR_SET_FD)
2248 char *s;
2249 int retval = 0;
2250 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
2251 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
2252 const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
2253 if (flags) {
2254 /* Check attribute existence */
2255 retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
2256 if (retval < 0) {
2257 /* REPLACE attribute, that doesn't exist */
2258 if (flags & XATTR_REPLACE && errno == ENOATTR) {
2259 errno = ENOATTR;
2260 return -1;
2262 /* Ignore other errors */
2264 else {
2265 /* CREATE attribute, that already exists */
2266 if (flags & XATTR_CREATE) {
2267 errno = EEXIST;
2268 return -1;
2272 retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size);
2273 return (retval < 0) ? -1 : 0;
2274 #elif defined(HAVE_ATTR_SETF)
2275 int myflags = 0;
2276 char *attrname = strchr(name,'.') + 1;
2278 if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
2279 if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
2280 if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
2282 return attr_setf(filedes, attrname, (const char *)value, size, myflags);
2283 #elif defined(HAVE_ATTROPEN)
2284 int ret = -1;
2285 int myflags = O_RDWR | O_XATTR;
2286 int attrfd;
2287 if (flags & XATTR_CREATE) myflags |= O_EXCL;
2288 if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
2289 attrfd = solaris_openat(filedes, name, myflags, (mode_t) SOLARIS_ATTRMODE);
2290 if (attrfd >= 0) {
2291 ret = solaris_write_xattr(attrfd, value, size);
2292 close(attrfd);
2294 return ret;
2295 #else
2296 errno = ENOSYS;
2297 return -1;
2298 #endif
2301 /**************************************************************************
2302 helper functions for Solaris' EA support
2303 ****************************************************************************/
2304 #ifdef HAVE_ATTROPEN
2305 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size)
2307 struct stat sbuf;
2309 if (fstat(attrfd, &sbuf) == -1) {
2310 errno = ENOATTR;
2311 return -1;
2314 /* This is to return the current size of the named extended attribute */
2315 if (size == 0) {
2316 return sbuf.st_size;
2319 /* check size and read xattr */
2320 if (sbuf.st_size > size) {
2321 errno = ERANGE;
2322 return -1;
2325 return read(attrfd, value, sbuf.st_size);
2328 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size)
2330 ssize_t len = 0;
2331 DIR *dirp;
2332 struct dirent *de;
2333 int newfd = dup(attrdirfd);
2334 /* CAUTION: The originating file descriptor should not be
2335 used again following the call to fdopendir().
2336 For that reason we dup() the file descriptor
2337 here to make things more clear. */
2338 dirp = fdopendir(newfd);
2340 while ((de = readdir(dirp))) {
2341 size_t listlen = strlen(de->d_name);
2342 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
2343 /* we don't want "." and ".." here: */
2344 DEBUG(10,("skipped EA %s\n",de->d_name));
2345 continue;
2348 if (size == 0) {
2349 /* return the current size of the list of extended attribute names*/
2350 len += listlen + 1;
2351 } else {
2352 /* check size and copy entrieѕ + nul into list. */
2353 if ((len + listlen + 1) > size) {
2354 errno = ERANGE;
2355 len = -1;
2356 break;
2357 } else {
2358 safe_strcpy(list + len, de->d_name, listlen);
2359 len += listlen;
2360 list[len] = '\0';
2361 ++len;
2366 if (closedir(dirp) == -1) {
2367 DEBUG(0,("closedir dirp failed: %s\n",strerror(errno)));
2368 return -1;
2370 return len;
2373 static int solaris_unlinkat(int attrdirfd, const char *name)
2375 if (unlinkat(attrdirfd, name, 0) == -1) {
2376 if (errno == ENOENT) {
2377 errno = ENOATTR;
2379 return -1;
2381 return 0;
2384 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode)
2386 int filedes = attropen(path, attrpath, oflag, mode);
2387 if (filedes == -1) {
2388 DEBUG(10,("attropen FAILED: path: %s, name: %s, errno: %s\n",path,attrpath,strerror(errno)));
2389 if (errno == EINVAL) {
2390 errno = ENOTSUP;
2391 } else {
2392 errno = ENOATTR;
2395 return filedes;
2398 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
2400 int filedes = openat(fildes, path, oflag, mode);
2401 if (filedes == -1) {
2402 DEBUG(10,("openat FAILED: fd: %d, path: %s, errno: %s\n",filedes,path,strerror(errno)));
2403 if (errno == EINVAL) {
2404 errno = ENOTSUP;
2405 } else {
2406 errno = ENOATTR;
2409 return filedes;
2412 static int solaris_write_xattr(int attrfd, const char *value, size_t size)
2414 if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) {
2415 return 0;
2416 } else {
2417 DEBUG(10,("solaris_write_xattr FAILED!\n"));
2418 return -1;
2421 #endif /*HAVE_ATTROPEN*/
2424 /****************************************************************************
2425 Return the major devicenumber for UNIX extensions.
2426 ****************************************************************************/
2428 uint32 unix_dev_major(SMB_DEV_T dev)
2430 #if defined(HAVE_DEVICE_MAJOR_FN)
2431 return (uint32)major(dev);
2432 #else
2433 return (uint32)(dev >> 8);
2434 #endif
2437 /****************************************************************************
2438 Return the minor devicenumber for UNIX extensions.
2439 ****************************************************************************/
2441 uint32 unix_dev_minor(SMB_DEV_T dev)
2443 #if defined(HAVE_DEVICE_MINOR_FN)
2444 return (uint32)minor(dev);
2445 #else
2446 return (uint32)(dev & 0xff);
2447 #endif
2450 #if defined(WITH_AIO)
2452 /*******************************************************************
2453 An aio_read wrapper that will deal with 64-bit sizes.
2454 ********************************************************************/
2456 int sys_aio_read(SMB_STRUCT_AIOCB *aiocb)
2458 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_READ64)
2459 return aio_read64(aiocb);
2460 #elif defined(HAVE_AIO_READ)
2461 return aio_read(aiocb);
2462 #else
2463 errno = ENOSYS;
2464 return -1;
2465 #endif
2468 /*******************************************************************
2469 An aio_write wrapper that will deal with 64-bit sizes.
2470 ********************************************************************/
2472 int sys_aio_write(SMB_STRUCT_AIOCB *aiocb)
2474 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_WRITE64)
2475 return aio_write64(aiocb);
2476 #elif defined(HAVE_AIO_WRITE)
2477 return aio_write(aiocb);
2478 #else
2479 errno = ENOSYS;
2480 return -1;
2481 #endif
2484 /*******************************************************************
2485 An aio_return wrapper that will deal with 64-bit sizes.
2486 ********************************************************************/
2488 ssize_t sys_aio_return(SMB_STRUCT_AIOCB *aiocb)
2490 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_RETURN64)
2491 return aio_return64(aiocb);
2492 #elif defined(HAVE_AIO_RETURN)
2493 return aio_return(aiocb);
2494 #else
2495 errno = ENOSYS;
2496 return -1;
2497 #endif
2500 /*******************************************************************
2501 An aio_cancel wrapper that will deal with 64-bit sizes.
2502 ********************************************************************/
2504 int sys_aio_cancel(int fd, SMB_STRUCT_AIOCB *aiocb)
2506 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_CANCEL64)
2507 return aio_cancel64(fd, aiocb);
2508 #elif defined(HAVE_AIO_CANCEL)
2509 return aio_cancel(fd, aiocb);
2510 #else
2511 errno = ENOSYS;
2512 return -1;
2513 #endif
2516 /*******************************************************************
2517 An aio_error wrapper that will deal with 64-bit sizes.
2518 ********************************************************************/
2520 int sys_aio_error(const SMB_STRUCT_AIOCB *aiocb)
2522 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_ERROR64)
2523 return aio_error64(aiocb);
2524 #elif defined(HAVE_AIO_ERROR)
2525 return aio_error(aiocb);
2526 #else
2527 errno = ENOSYS;
2528 return -1;
2529 #endif
2532 /*******************************************************************
2533 An aio_fsync wrapper that will deal with 64-bit sizes.
2534 ********************************************************************/
2536 int sys_aio_fsync(int op, SMB_STRUCT_AIOCB *aiocb)
2538 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_FSYNC64)
2539 return aio_fsync64(op, aiocb);
2540 #elif defined(HAVE_AIO_FSYNC)
2541 return aio_fsync(op, aiocb);
2542 #else
2543 errno = ENOSYS;
2544 return -1;
2545 #endif
2548 /*******************************************************************
2549 An aio_fsync wrapper that will deal with 64-bit sizes.
2550 ********************************************************************/
2552 int sys_aio_suspend(const SMB_STRUCT_AIOCB * const cblist[], int n, const struct timespec *timeout)
2554 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_SUSPEND64)
2555 return aio_suspend64(cblist, n, timeout);
2556 #elif defined(HAVE_AIO_FSYNC)
2557 return aio_suspend(cblist, n, timeout);
2558 #else
2559 errno = ENOSYS;
2560 return -1;
2561 #endif
2563 #else /* !WITH_AIO */
2565 int sys_aio_read(SMB_STRUCT_AIOCB *aiocb)
2567 errno = ENOSYS;
2568 return -1;
2571 int sys_aio_write(SMB_STRUCT_AIOCB *aiocb)
2573 errno = ENOSYS;
2574 return -1;
2577 ssize_t sys_aio_return(SMB_STRUCT_AIOCB *aiocb)
2579 errno = ENOSYS;
2580 return -1;
2583 int sys_aio_cancel(int fd, SMB_STRUCT_AIOCB *aiocb)
2585 errno = ENOSYS;
2586 return -1;
2589 int sys_aio_error(const SMB_STRUCT_AIOCB *aiocb)
2591 errno = ENOSYS;
2592 return -1;
2595 int sys_aio_fsync(int op, SMB_STRUCT_AIOCB *aiocb)
2597 errno = ENOSYS;
2598 return -1;
2601 int sys_aio_suspend(const SMB_STRUCT_AIOCB * const cblist[], int n, const struct timespec *timeout)
2603 errno = ENOSYS;
2604 return -1;
2606 #endif /* WITH_AIO */
2608 int sys_getpeereid( int s, uid_t *uid)
2610 #if defined(HAVE_PEERCRED)
2611 struct ucred cred;
2612 socklen_t cred_len = sizeof(struct ucred);
2613 int ret;
2615 ret = getsockopt(s, SOL_SOCKET, SO_PEERCRED, (void *)&cred, &cred_len);
2616 if (ret != 0) {
2617 return -1;
2620 if (cred_len != sizeof(struct ucred)) {
2621 errno = EINVAL;
2622 return -1;
2625 *uid = cred.uid;
2626 return 0;
2627 #else
2628 errno = ENOSYS;
2629 return -1;
2630 #endif
2633 int sys_getnameinfo(const struct sockaddr *psa,
2634 socklen_t salen,
2635 char *host,
2636 size_t hostlen,
2637 char *service,
2638 size_t servlen,
2639 int flags)
2642 * For Solaris we must make sure salen is the
2643 * correct length for the incoming sa_family.
2646 if (salen == sizeof(struct sockaddr_storage)) {
2647 salen = sizeof(struct sockaddr_in);
2648 #if defined(HAVE_IPV6)
2649 if (psa->sa_family == AF_INET6) {
2650 salen = sizeof(struct sockaddr_in6);
2652 #endif
2654 return getnameinfo(psa, salen, host, hostlen, service, servlen, flags);
2657 int sys_connect(int fd, const struct sockaddr * addr)
2659 socklen_t salen = -1;
2661 if (addr->sa_family == AF_INET) {
2662 salen = sizeof(struct sockaddr_in);
2663 } else if (addr->sa_family == AF_UNIX) {
2664 salen = sizeof(struct sockaddr_un);
2666 #if defined(HAVE_IPV6)
2667 else if (addr->sa_family == AF_INET6) {
2668 salen = sizeof(struct sockaddr_in6);
2670 #endif
2672 return connect(fd, addr, salen);