Fix read/write calls over sockets to cope with EAGAIN/EWOULDBLOCK for non-blocking...
[Samba/gbeck.git] / source3 / lib / system.c
blob1c00ad87e4de092268dafde831c82150de51b645
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 #if defined(EWOULDBLOCK)
127 } while (ret == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
128 #else
129 } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
130 #endif
131 return ret;
134 /*******************************************************************
135 A write wrapper that will deal with EINTR.
136 ********************************************************************/
138 ssize_t sys_write(int fd, const void *buf, size_t count)
140 ssize_t ret;
142 do {
143 ret = write(fd, buf, count);
144 #if defined(EWOULDBLOCK)
145 } while (ret == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
146 #else
147 } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
148 #endif
149 return ret;
152 /*******************************************************************
153 A writev wrapper that will deal with EINTR.
154 ********************************************************************/
156 ssize_t sys_writev(int fd, const struct iovec *iov, int iovcnt)
158 ssize_t ret;
160 #if 0
161 /* Try to confuse write_data_iov a bit */
162 if ((random() % 5) == 0) {
163 return sys_write(fd, iov[0].iov_base, iov[0].iov_len);
165 if (iov[0].iov_len > 1) {
166 return sys_write(fd, iov[0].iov_base,
167 (random() % (iov[0].iov_len-1)) + 1);
169 #endif
171 do {
172 ret = writev(fd, iov, iovcnt);
173 #if defined(EWOULDBLOCK)
174 } while (ret == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
175 #else
176 } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
177 #endif
178 return ret;
181 /*******************************************************************
182 A pread wrapper that will deal with EINTR and 64-bit file offsets.
183 ********************************************************************/
185 #if defined(HAVE_PREAD) || defined(HAVE_PREAD64)
186 ssize_t sys_pread(int fd, void *buf, size_t count, SMB_OFF_T off)
188 ssize_t ret;
190 do {
191 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_PREAD64)
192 ret = pread64(fd, buf, count, off);
193 #else
194 ret = pread(fd, buf, count, off);
195 #endif
196 } while (ret == -1 && errno == EINTR);
197 return ret;
199 #endif
201 /*******************************************************************
202 A write wrapper that will deal with EINTR and 64-bit file offsets.
203 ********************************************************************/
205 #if defined(HAVE_PWRITE) || defined(HAVE_PWRITE64)
206 ssize_t sys_pwrite(int fd, const void *buf, size_t count, SMB_OFF_T off)
208 ssize_t ret;
210 do {
211 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_PWRITE64)
212 ret = pwrite64(fd, buf, count, off);
213 #else
214 ret = pwrite(fd, buf, count, off);
215 #endif
216 } while (ret == -1 && errno == EINTR);
217 return ret;
219 #endif
221 /*******************************************************************
222 A send wrapper that will deal with EINTR or EAGAIN or EWOULDBLOCK.
223 ********************************************************************/
225 ssize_t sys_send(int s, const void *msg, size_t len, int flags)
227 ssize_t ret;
229 do {
230 ret = send(s, msg, len, flags);
231 #if defined(EWOULDBLOCK)
232 } while (ret == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
233 #else
234 } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
235 #endif
236 return ret;
239 /*******************************************************************
240 A sendto wrapper that will deal with EINTR or EAGAIN or EWOULDBLOCK.
241 ********************************************************************/
243 ssize_t sys_sendto(int s, const void *msg, size_t len, int flags, const struct sockaddr *to, socklen_t tolen)
245 ssize_t ret;
247 do {
248 ret = sendto(s, msg, len, flags, to, tolen);
249 #if defined(EWOULDBLOCK)
250 } while (ret == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
251 #else
252 } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
253 #endif
254 return ret;
257 /*******************************************************************
258 A recv wrapper that will deal with EINTR or EAGAIN or EWOULDBLOCK.
259 ********************************************************************/
261 ssize_t sys_recv(int fd, void *buf, size_t count, int flags)
263 ssize_t ret;
265 do {
266 ret = recv(fd, buf, count, flags);
267 #if defined(EWOULDBLOCK)
268 } while (ret == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
269 #else
270 } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
271 #endif
272 return ret;
275 /*******************************************************************
276 A recvfrom wrapper that will deal with EINTR.
277 ********************************************************************/
279 ssize_t sys_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
281 ssize_t ret;
283 do {
284 ret = recvfrom(s, buf, len, flags, from, fromlen);
285 #if defined(EWOULDBLOCK)
286 } while (ret == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
287 #else
288 } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
289 #endif
290 return ret;
293 /*******************************************************************
294 A fcntl wrapper that will deal with EINTR.
295 ********************************************************************/
297 int sys_fcntl_ptr(int fd, int cmd, void *arg)
299 int ret;
301 do {
302 ret = fcntl(fd, cmd, arg);
303 } while (ret == -1 && errno == EINTR);
304 return ret;
307 /*******************************************************************
308 A fcntl wrapper that will deal with EINTR.
309 ********************************************************************/
311 int sys_fcntl_long(int fd, int cmd, long arg)
313 int ret;
315 do {
316 ret = fcntl(fd, cmd, arg);
317 } while (ret == -1 && errno == EINTR);
318 return ret;
321 /****************************************************************************
322 Get/Set all the possible time fields from a stat struct as a timespec.
323 ****************************************************************************/
325 static struct timespec get_atimespec(const struct stat *pst)
327 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
328 struct timespec ret;
330 /* Old system - no ns timestamp. */
331 ret.tv_sec = pst->st_atime;
332 ret.tv_nsec = 0;
333 return ret;
334 #else
335 #if defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
336 return pst->st_atim;
337 #elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
338 struct timespec ret;
339 ret.tv_sec = pst->st_atime;
340 ret.tv_nsec = pst->st_atimensec;
341 return ret;
342 #elif defined(HAVE_STRUCT_STAT_ST_MTIME_N)
343 struct timespec ret;
344 ret.tv_sec = pst->st_atime;
345 ret.tv_nsec = pst->st_atime_n;
346 return ret;
347 #elif defined(HAVE_STRUCT_STAT_ST_UMTIME)
348 struct timespec ret;
349 ret.tv_sec = pst->st_atime;
350 ret.tv_nsec = pst->st_uatime * 1000;
351 return ret;
352 #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC)
353 return pst->st_atimespec;
354 #else
355 #error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
356 #endif
357 #endif
360 static struct timespec get_mtimespec(const struct stat *pst)
362 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
363 struct timespec ret;
365 /* Old system - no ns timestamp. */
366 ret.tv_sec = pst->st_mtime;
367 ret.tv_nsec = 0;
368 return ret;
369 #else
370 #if defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
371 return pst->st_mtim;
372 #elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
373 struct timespec ret;
374 ret.tv_sec = pst->st_mtime;
375 ret.tv_nsec = pst->st_mtimensec;
376 return ret;
377 #elif defined(HAVE_STRUCT_STAT_ST_MTIME_N)
378 struct timespec ret;
379 ret.tv_sec = pst->st_mtime;
380 ret.tv_nsec = pst->st_mtime_n;
381 return ret;
382 #elif defined(HAVE_STRUCT_STAT_ST_UMTIME)
383 struct timespec ret;
384 ret.tv_sec = pst->st_mtime;
385 ret.tv_nsec = pst->st_umtime * 1000;
386 return ret;
387 #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC)
388 return pst->st_mtimespec;
389 #else
390 #error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
391 #endif
392 #endif
395 static struct timespec get_ctimespec(const struct stat *pst)
397 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
398 struct timespec ret;
400 /* Old system - no ns timestamp. */
401 ret.tv_sec = pst->st_ctime;
402 ret.tv_nsec = 0;
403 return ret;
404 #else
405 #if defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
406 return pst->st_ctim;
407 #elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
408 struct timespec ret;
409 ret.tv_sec = pst->st_ctime;
410 ret.tv_nsec = pst->st_ctimensec;
411 return ret;
412 #elif defined(HAVE_STRUCT_STAT_ST_MTIME_N)
413 struct timespec ret;
414 ret.tv_sec = pst->st_ctime;
415 ret.tv_nsec = pst->st_ctime_n;
416 return ret;
417 #elif defined(HAVE_STRUCT_STAT_ST_UMTIME)
418 struct timespec ret;
419 ret.tv_sec = pst->st_ctime;
420 ret.tv_nsec = pst->st_uctime * 1000;
421 return ret;
422 #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC)
423 return pst->st_ctimespec;
424 #else
425 #error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
426 #endif
427 #endif
430 /****************************************************************************
431 Return the best approximation to a 'create time' under UNIX from a stat
432 structure.
433 ****************************************************************************/
435 static struct timespec calc_create_time_stat(const struct stat *st)
437 struct timespec ret, ret1;
438 struct timespec c_time = get_ctimespec(st);
439 struct timespec m_time = get_mtimespec(st);
440 struct timespec a_time = get_atimespec(st);
442 ret = timespec_compare(&c_time, &m_time) < 0 ? c_time : m_time;
443 ret1 = timespec_compare(&ret, &a_time) < 0 ? ret : a_time;
445 if(!null_timespec(ret1)) {
446 return ret1;
450 * One of ctime, mtime or atime was zero (probably atime).
451 * Just return MIN(ctime, mtime).
453 return ret;
456 /****************************************************************************
457 Return the best approximation to a 'create time' under UNIX from a stat_ex
458 structure.
459 ****************************************************************************/
461 static struct timespec calc_create_time_stat_ex(const struct stat_ex *st)
463 struct timespec ret, ret1;
464 struct timespec c_time = st->st_ex_ctime;
465 struct timespec m_time = st->st_ex_mtime;
466 struct timespec a_time = st->st_ex_atime;
468 ret = timespec_compare(&c_time, &m_time) < 0 ? c_time : m_time;
469 ret1 = timespec_compare(&ret, &a_time) < 0 ? ret : a_time;
471 if(!null_timespec(ret1)) {
472 return ret1;
476 * One of ctime, mtime or atime was zero (probably atime).
477 * Just return MIN(ctime, mtime).
479 return ret;
482 /****************************************************************************
483 Return the 'create time' from a stat struct if it exists (birthtime) or else
484 use the best approximation.
485 ****************************************************************************/
487 static void make_create_timespec(const struct stat *pst, struct stat_ex *dst,
488 bool fake_dir_create_times)
490 if (S_ISDIR(pst->st_mode) && fake_dir_create_times) {
491 dst->st_ex_btime.tv_sec = 315493200L; /* 1/1/1980 */
492 dst->st_ex_btime.tv_nsec = 0;
495 dst->st_ex_calculated_birthtime = false;
497 #if defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC)
498 dst->st_ex_btime = pst->st_birthtimespec;
499 #elif defined(HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC)
500 dst->st_ex_btime.tv_sec = pst->st_birthtime;
501 dst->st_ex_btime.tv_nsec = pst->st_birthtimenspec;
502 #elif defined(HAVE_STRUCT_STAT_ST_BIRTHTIME)
503 dst->st_ex_btime.tv_sec = pst->st_birthtime;
504 dst->st_ex_btime.tv_nsec = 0;
505 #else
506 dst->st_ex_btime = calc_create_time_stat(pst);
507 dst->st_ex_calculated_birthtime = true;
508 #endif
510 /* Deal with systems that don't initialize birthtime correctly.
511 * Pointed out by SATOH Fumiyasu <fumiyas@osstech.jp>.
513 if (null_timespec(dst->st_ex_btime)) {
514 dst->st_ex_btime = calc_create_time_stat(pst);
515 dst->st_ex_calculated_birthtime = true;
519 /****************************************************************************
520 If we update a timestamp in a stat_ex struct we may have to recalculate
521 the birthtime. For now only implement this for write time, but we may
522 also need to do it for atime and ctime. JRA.
523 ****************************************************************************/
525 void update_stat_ex_mtime(struct stat_ex *dst,
526 struct timespec write_ts)
528 dst->st_ex_mtime = write_ts;
530 /* We may have to recalculate btime. */
531 if (dst->st_ex_calculated_birthtime) {
532 dst->st_ex_btime = calc_create_time_stat_ex(dst);
536 void update_stat_ex_create_time(struct stat_ex *dst,
537 struct timespec create_time)
539 dst->st_ex_btime = create_time;
540 dst->st_ex_calculated_birthtime = false;
543 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_STAT64)
544 static void init_stat_ex_from_stat (struct stat_ex *dst,
545 const struct stat64 *src,
546 bool fake_dir_create_times)
547 #else
548 static void init_stat_ex_from_stat (struct stat_ex *dst,
549 const struct stat *src,
550 bool fake_dir_create_times)
551 #endif
553 dst->st_ex_dev = src->st_dev;
554 dst->st_ex_ino = src->st_ino;
555 dst->st_ex_mode = src->st_mode;
556 dst->st_ex_nlink = src->st_nlink;
557 dst->st_ex_uid = src->st_uid;
558 dst->st_ex_gid = src->st_gid;
559 dst->st_ex_rdev = src->st_rdev;
560 dst->st_ex_size = src->st_size;
561 dst->st_ex_atime = get_atimespec(src);
562 dst->st_ex_mtime = get_mtimespec(src);
563 dst->st_ex_ctime = get_ctimespec(src);
564 make_create_timespec(src, dst, fake_dir_create_times);
565 #ifdef HAVE_STAT_ST_BLKSIZE
566 dst->st_ex_blksize = src->st_blksize;
567 #else
568 dst->st_ex_blksize = STAT_ST_BLOCKSIZE;
569 #endif
571 #ifdef HAVE_STAT_ST_BLOCKS
572 dst->st_ex_blocks = src->st_blocks;
573 #else
574 dst->st_ex_blocks = src->st_size / dst->st_ex_blksize + 1;
575 #endif
577 #ifdef HAVE_STAT_ST_FLAGS
578 dst->st_ex_flags = src->st_flags;
579 #else
580 dst->st_ex_flags = 0;
581 #endif
584 /*******************************************************************
585 A stat() wrapper that will deal with 64 bit filesizes.
586 ********************************************************************/
588 int sys_stat(const char *fname, SMB_STRUCT_STAT *sbuf,
589 bool fake_dir_create_times)
591 int ret;
592 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_STAT64)
593 struct stat64 statbuf;
594 ret = stat64(fname, &statbuf);
595 #else
596 struct stat statbuf;
597 ret = stat(fname, &statbuf);
598 #endif
599 if (ret == 0) {
600 /* we always want directories to appear zero size */
601 if (S_ISDIR(statbuf.st_mode)) {
602 statbuf.st_size = 0;
604 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
606 return ret;
609 /*******************************************************************
610 An fstat() wrapper that will deal with 64 bit filesizes.
611 ********************************************************************/
613 int sys_fstat(int fd, SMB_STRUCT_STAT *sbuf, bool fake_dir_create_times)
615 int ret;
616 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FSTAT64)
617 struct stat64 statbuf;
618 ret = fstat64(fd, &statbuf);
619 #else
620 struct stat statbuf;
621 ret = fstat(fd, &statbuf);
622 #endif
623 if (ret == 0) {
624 /* we always want directories to appear zero size */
625 if (S_ISDIR(statbuf.st_mode)) {
626 statbuf.st_size = 0;
628 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
630 return ret;
633 /*******************************************************************
634 An lstat() wrapper that will deal with 64 bit filesizes.
635 ********************************************************************/
637 int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf,
638 bool fake_dir_create_times)
640 int ret;
641 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSTAT64)
642 struct stat64 statbuf;
643 ret = lstat64(fname, &statbuf);
644 #else
645 struct stat statbuf;
646 ret = lstat(fname, &statbuf);
647 #endif
648 if (ret == 0) {
649 /* we always want directories to appear zero size */
650 if (S_ISDIR(statbuf.st_mode)) {
651 statbuf.st_size = 0;
653 init_stat_ex_from_stat(sbuf, &statbuf, fake_dir_create_times);
655 return ret;
658 /*******************************************************************
659 An posix_fallocate() wrapper that will deal with 64 bit filesizes.
660 ********************************************************************/
661 int sys_posix_fallocate(int fd, SMB_OFF_T offset, SMB_OFF_T len)
663 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_POSIX_FALLOCATE64) && !defined(HAVE_BROKEN_POSIX_FALLOCATE)
664 return posix_fallocate64(fd, offset, len);
665 #elif defined(HAVE_POSIX_FALLOCATE) && !defined(HAVE_BROKEN_POSIX_FALLOCATE)
666 return posix_fallocate(fd, offset, len);
667 #elif defined(F_RESVSP64)
668 /* this handles XFS on IRIX */
669 struct flock64 fl;
670 SMB_OFF_T new_len = offset + len;
671 int ret;
672 struct stat64 sbuf;
674 /* unlikely to get a too large file on a 64bit system but ... */
675 if (new_len < 0)
676 return EFBIG;
678 fl.l_whence = SEEK_SET;
679 fl.l_start = offset;
680 fl.l_len = len;
682 ret=fcntl(fd, F_RESVSP64, &fl);
684 if (ret != 0)
685 return errno;
687 /* Make sure the file gets enlarged after we allocated space: */
688 fstat64(fd, &sbuf);
689 if (new_len > sbuf.st_size)
690 ftruncate64(fd, new_len);
691 return 0;
692 #else
693 return ENOSYS;
694 #endif
697 /*******************************************************************
698 An ftruncate() wrapper that will deal with 64 bit filesizes.
699 ********************************************************************/
701 int sys_ftruncate(int fd, SMB_OFF_T offset)
703 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FTRUNCATE64)
704 return ftruncate64(fd, offset);
705 #else
706 return ftruncate(fd, offset);
707 #endif
710 /*******************************************************************
711 An lseek() wrapper that will deal with 64 bit filesizes.
712 ********************************************************************/
714 SMB_OFF_T sys_lseek(int fd, SMB_OFF_T offset, int whence)
716 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSEEK64)
717 return lseek64(fd, offset, whence);
718 #else
719 return lseek(fd, offset, whence);
720 #endif
723 /*******************************************************************
724 An fseek() wrapper that will deal with 64 bit filesizes.
725 ********************************************************************/
727 int sys_fseek(FILE *fp, SMB_OFF_T offset, int whence)
729 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEK64)
730 return fseek64(fp, offset, whence);
731 #elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEKO64)
732 return fseeko64(fp, offset, whence);
733 #else
734 return fseek(fp, offset, whence);
735 #endif
738 /*******************************************************************
739 An ftell() wrapper that will deal with 64 bit filesizes.
740 ********************************************************************/
742 SMB_OFF_T sys_ftell(FILE *fp)
744 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELL64)
745 return (SMB_OFF_T)ftell64(fp);
746 #elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELLO64)
747 return (SMB_OFF_T)ftello64(fp);
748 #else
749 return (SMB_OFF_T)ftell(fp);
750 #endif
753 /*******************************************************************
754 A creat() wrapper that will deal with 64 bit filesizes.
755 ********************************************************************/
757 int sys_creat(const char *path, mode_t mode)
759 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_CREAT64)
760 return creat64(path, mode);
761 #else
763 * If creat64 isn't defined then ensure we call a potential open64.
764 * JRA.
766 return sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
767 #endif
770 /*******************************************************************
771 An open() wrapper that will deal with 64 bit filesizes.
772 ********************************************************************/
774 int sys_open(const char *path, int oflag, mode_t mode)
776 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OPEN64)
777 return open64(path, oflag, mode);
778 #else
779 return open(path, oflag, mode);
780 #endif
783 /*******************************************************************
784 An fopen() wrapper that will deal with 64 bit filesizes.
785 ********************************************************************/
787 FILE *sys_fopen(const char *path, const char *type)
789 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_FOPEN64)
790 return fopen64(path, type);
791 #else
792 return fopen(path, type);
793 #endif
797 /*******************************************************************
798 A flock() wrapper that will perform the kernel flock.
799 ********************************************************************/
801 void kernel_flock(int fd, uint32 share_mode, uint32 access_mask)
803 #if HAVE_KERNEL_SHARE_MODES
804 int kernel_mode = 0;
805 if (share_mode == FILE_SHARE_WRITE) {
806 kernel_mode = LOCK_MAND|LOCK_WRITE;
807 } else if (share_mode == FILE_SHARE_READ) {
808 kernel_mode = LOCK_MAND|LOCK_READ;
809 } else if (share_mode == FILE_SHARE_NONE) {
810 kernel_mode = LOCK_MAND;
812 if (kernel_mode) {
813 flock(fd, kernel_mode);
815 #endif
821 /*******************************************************************
822 An opendir wrapper that will deal with 64 bit filesizes.
823 ********************************************************************/
825 SMB_STRUCT_DIR *sys_opendir(const char *name)
827 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OPENDIR64)
828 return opendir64(name);
829 #else
830 return opendir(name);
831 #endif
834 /*******************************************************************
835 A readdir wrapper that will deal with 64 bit filesizes.
836 ********************************************************************/
838 SMB_STRUCT_DIRENT *sys_readdir(SMB_STRUCT_DIR *dirp)
840 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_READDIR64)
841 return readdir64(dirp);
842 #else
843 return readdir(dirp);
844 #endif
847 /*******************************************************************
848 A seekdir wrapper that will deal with 64 bit filesizes.
849 ********************************************************************/
851 void sys_seekdir(SMB_STRUCT_DIR *dirp, long offset)
853 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_SEEKDIR64)
854 seekdir64(dirp, offset);
855 #else
856 seekdir(dirp, offset);
857 #endif
860 /*******************************************************************
861 A telldir wrapper that will deal with 64 bit filesizes.
862 ********************************************************************/
864 long sys_telldir(SMB_STRUCT_DIR *dirp)
866 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_TELLDIR64)
867 return (long)telldir64(dirp);
868 #else
869 return (long)telldir(dirp);
870 #endif
873 /*******************************************************************
874 A rewinddir wrapper that will deal with 64 bit filesizes.
875 ********************************************************************/
877 void sys_rewinddir(SMB_STRUCT_DIR *dirp)
879 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_REWINDDIR64)
880 rewinddir64(dirp);
881 #else
882 rewinddir(dirp);
883 #endif
886 /*******************************************************************
887 A close wrapper that will deal with 64 bit filesizes.
888 ********************************************************************/
890 int sys_closedir(SMB_STRUCT_DIR *dirp)
892 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_CLOSEDIR64)
893 return closedir64(dirp);
894 #else
895 return closedir(dirp);
896 #endif
899 /*******************************************************************
900 An mknod() wrapper that will deal with 64 bit filesizes.
901 ********************************************************************/
903 int sys_mknod(const char *path, mode_t mode, SMB_DEV_T dev)
905 #if defined(HAVE_MKNOD) || defined(HAVE_MKNOD64)
906 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_MKNOD64) && defined(HAVE_DEV64_T)
907 return mknod64(path, mode, dev);
908 #else
909 return mknod(path, mode, dev);
910 #endif
911 #else
912 /* No mknod system call. */
913 errno = ENOSYS;
914 return -1;
915 #endif
918 /*******************************************************************
919 The wait() calls vary between systems
920 ********************************************************************/
922 int sys_waitpid(pid_t pid,int *status,int options)
924 #ifdef HAVE_WAITPID
925 return waitpid(pid,status,options);
926 #else /* HAVE_WAITPID */
927 return wait4(pid, status, options, NULL);
928 #endif /* HAVE_WAITPID */
931 /*******************************************************************
932 System wrapper for getwd
933 ********************************************************************/
935 char *sys_getwd(char *s)
937 char *wd;
938 #ifdef HAVE_GETCWD
939 wd = (char *)getcwd(s, PATH_MAX);
940 #else
941 wd = (char *)getwd(s);
942 #endif
943 return wd;
946 #if defined(HAVE_POSIX_CAPABILITIES)
948 /**************************************************************************
949 Try and abstract process capabilities (for systems that have them).
950 ****************************************************************************/
952 /* Set the POSIX capabilities needed for the given purpose into the effective
953 * capability set of the current process. Make sure they are always removed
954 * from the inheritable set, because there is no circumstance in which our
955 * children should inherit our elevated privileges.
957 static bool set_process_capability(enum smbd_capability capability,
958 bool enable)
960 cap_value_t cap_vals[2] = {0};
961 int num_cap_vals = 0;
963 cap_t cap;
965 #if defined(HAVE_PRCTL) && defined(PR_GET_KEEPCAPS) && defined(PR_SET_KEEPCAPS)
966 /* On Linux, make sure that any capabilities we grab are sticky
967 * across UID changes. We expect that this would allow us to keep both
968 * the effective and permitted capability sets, but as of circa 2.6.16,
969 * only the permitted set is kept. It is a bug (which we work around)
970 * that the effective set is lost, but we still require the effective
971 * set to be kept.
973 if (!prctl(PR_GET_KEEPCAPS)) {
974 prctl(PR_SET_KEEPCAPS, 1);
976 #endif
978 cap = cap_get_proc();
979 if (cap == NULL) {
980 DEBUG(0,("set_process_capability: cap_get_proc failed: %s\n",
981 strerror(errno)));
982 return False;
985 switch (capability) {
986 case KERNEL_OPLOCK_CAPABILITY:
987 #ifdef CAP_NETWORK_MGT
988 /* IRIX has CAP_NETWORK_MGT for oplocks. */
989 cap_vals[num_cap_vals++] = CAP_NETWORK_MGT;
990 #endif
991 break;
992 case DMAPI_ACCESS_CAPABILITY:
993 #ifdef CAP_DEVICE_MGT
994 /* IRIX has CAP_DEVICE_MGT for DMAPI access. */
995 cap_vals[num_cap_vals++] = CAP_DEVICE_MGT;
996 #elif CAP_MKNOD
997 /* Linux has CAP_MKNOD for DMAPI access. */
998 cap_vals[num_cap_vals++] = CAP_MKNOD;
999 #endif
1000 break;
1001 case LEASE_CAPABILITY:
1002 #ifdef CAP_LEASE
1003 cap_vals[num_cap_vals++] = CAP_LEASE;
1004 #endif
1005 break;
1008 SMB_ASSERT(num_cap_vals <= ARRAY_SIZE(cap_vals));
1010 if (num_cap_vals == 0) {
1011 cap_free(cap);
1012 return True;
1015 cap_set_flag(cap, CAP_EFFECTIVE, num_cap_vals, cap_vals,
1016 enable ? CAP_SET : CAP_CLEAR);
1018 /* We never want to pass capabilities down to our children, so make
1019 * sure they are not inherited.
1021 cap_set_flag(cap, CAP_INHERITABLE, num_cap_vals, cap_vals, CAP_CLEAR);
1023 if (cap_set_proc(cap) == -1) {
1024 DEBUG(0, ("set_process_capability: cap_set_proc failed: %s\n",
1025 strerror(errno)));
1026 cap_free(cap);
1027 return False;
1030 cap_free(cap);
1031 return True;
1034 #endif /* HAVE_POSIX_CAPABILITIES */
1036 /****************************************************************************
1037 Gain the oplock capability from the kernel if possible.
1038 ****************************************************************************/
1040 void set_effective_capability(enum smbd_capability capability)
1042 #if defined(HAVE_POSIX_CAPABILITIES)
1043 set_process_capability(capability, True);
1044 #endif /* HAVE_POSIX_CAPABILITIES */
1047 void drop_effective_capability(enum smbd_capability capability)
1049 #if defined(HAVE_POSIX_CAPABILITIES)
1050 set_process_capability(capability, False);
1051 #endif /* HAVE_POSIX_CAPABILITIES */
1054 /**************************************************************************
1055 Wrapper for random().
1056 ****************************************************************************/
1058 long sys_random(void)
1060 #if defined(HAVE_RANDOM)
1061 return (long)random();
1062 #elif defined(HAVE_RAND)
1063 return (long)rand();
1064 #else
1065 DEBUG(0,("Error - no random function available !\n"));
1066 exit(1);
1067 #endif
1070 /**************************************************************************
1071 Wrapper for srandom().
1072 ****************************************************************************/
1074 void sys_srandom(unsigned int seed)
1076 #if defined(HAVE_SRANDOM)
1077 srandom(seed);
1078 #elif defined(HAVE_SRAND)
1079 srand(seed);
1080 #else
1081 DEBUG(0,("Error - no srandom function available !\n"));
1082 exit(1);
1083 #endif
1086 /**************************************************************************
1087 Returns equivalent to NGROUPS_MAX - using sysconf if needed.
1088 ****************************************************************************/
1090 int groups_max(void)
1092 #if defined(SYSCONF_SC_NGROUPS_MAX)
1093 int ret = sysconf(_SC_NGROUPS_MAX);
1094 return (ret == -1) ? NGROUPS_MAX : ret;
1095 #else
1096 return NGROUPS_MAX;
1097 #endif
1100 /**************************************************************************
1101 Wrap setgroups and getgroups for systems that declare getgroups() as
1102 returning an array of gid_t, but actuall return an array of int.
1103 ****************************************************************************/
1105 #if defined(HAVE_BROKEN_GETGROUPS)
1106 static int sys_broken_getgroups(int setlen, gid_t *gidset)
1108 GID_T gid;
1109 GID_T *group_list;
1110 int i, ngroups;
1112 if(setlen == 0) {
1113 return getgroups(setlen, &gid);
1117 * Broken case. We need to allocate a
1118 * GID_T array of size setlen.
1121 if(setlen < 0) {
1122 errno = EINVAL;
1123 return -1;
1126 if (setlen == 0)
1127 setlen = groups_max();
1129 if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
1130 DEBUG(0,("sys_getgroups: Malloc fail.\n"));
1131 return -1;
1134 if((ngroups = getgroups(setlen, group_list)) < 0) {
1135 int saved_errno = errno;
1136 SAFE_FREE(group_list);
1137 errno = saved_errno;
1138 return -1;
1141 for(i = 0; i < ngroups; i++)
1142 gidset[i] = (gid_t)group_list[i];
1144 SAFE_FREE(group_list);
1145 return ngroups;
1148 static int sys_broken_setgroups(int setlen, gid_t *gidset)
1150 GID_T *group_list;
1151 int i ;
1153 if (setlen == 0)
1154 return 0 ;
1156 if (setlen < 0 || setlen > groups_max()) {
1157 errno = EINVAL;
1158 return -1;
1162 * Broken case. We need to allocate a
1163 * GID_T array of size setlen.
1166 if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
1167 DEBUG(0,("sys_setgroups: Malloc fail.\n"));
1168 return -1;
1171 for(i = 0; i < setlen; i++)
1172 group_list[i] = (GID_T) gidset[i];
1174 if(setgroups(setlen, group_list) != 0) {
1175 int saved_errno = errno;
1176 SAFE_FREE(group_list);
1177 errno = saved_errno;
1178 return -1;
1181 SAFE_FREE(group_list);
1182 return 0 ;
1185 #endif /* HAVE_BROKEN_GETGROUPS */
1187 /* This is a list of systems that require the first GID passed to setgroups(2)
1188 * to be the effective GID. If your system is one of these, add it here.
1190 #if defined (FREEBSD) || defined (DARWINOS)
1191 #define USE_BSD_SETGROUPS
1192 #endif
1194 #if defined(USE_BSD_SETGROUPS)
1195 /* Depending on the particular BSD implementation, the first GID that is
1196 * passed to setgroups(2) will either be ignored or will set the credential's
1197 * effective GID. In either case, the right thing to do is to guarantee that
1198 * gidset[0] is the effective GID.
1200 static int sys_bsd_setgroups(gid_t primary_gid, int setlen, const gid_t *gidset)
1202 gid_t *new_gidset = NULL;
1203 int max;
1204 int ret;
1206 /* setgroups(2) will fail with EINVAL if we pass too many groups. */
1207 max = groups_max();
1209 /* No group list, just make sure we are setting the efective GID. */
1210 if (setlen == 0) {
1211 return setgroups(1, &primary_gid);
1214 /* If the primary gid is not the first array element, grow the array
1215 * and insert it at the front.
1217 if (gidset[0] != primary_gid) {
1218 new_gidset = SMB_MALLOC_ARRAY(gid_t, setlen + 1);
1219 if (new_gidset == NULL) {
1220 return -1;
1223 memcpy(new_gidset + 1, gidset, (setlen * sizeof(gid_t)));
1224 new_gidset[0] = primary_gid;
1225 setlen++;
1228 if (setlen > max) {
1229 DEBUG(3, ("forced to truncate group list from %d to %d\n",
1230 setlen, max));
1231 setlen = max;
1234 #if defined(HAVE_BROKEN_GETGROUPS)
1235 ret = sys_broken_setgroups(setlen, new_gidset ? new_gidset : gidset);
1236 #else
1237 ret = setgroups(setlen, new_gidset ? new_gidset : gidset);
1238 #endif
1240 if (new_gidset) {
1241 int errsav = errno;
1242 SAFE_FREE(new_gidset);
1243 errno = errsav;
1246 return ret;
1249 #endif /* USE_BSD_SETGROUPS */
1251 /**************************************************************************
1252 Wrapper for getgroups. Deals with broken (int) case.
1253 ****************************************************************************/
1255 int sys_getgroups(int setlen, gid_t *gidset)
1257 #if defined(HAVE_BROKEN_GETGROUPS)
1258 return sys_broken_getgroups(setlen, gidset);
1259 #else
1260 return getgroups(setlen, gidset);
1261 #endif
1264 /**************************************************************************
1265 Wrapper for setgroups. Deals with broken (int) case and BSD case.
1266 ****************************************************************************/
1268 int sys_setgroups(gid_t UNUSED(primary_gid), int setlen, gid_t *gidset)
1270 #if !defined(HAVE_SETGROUPS)
1271 errno = ENOSYS;
1272 return -1;
1273 #endif /* HAVE_SETGROUPS */
1275 #if defined(USE_BSD_SETGROUPS)
1276 return sys_bsd_setgroups(primary_gid, setlen, gidset);
1277 #elif defined(HAVE_BROKEN_GETGROUPS)
1278 return sys_broken_setgroups(setlen, gidset);
1279 #else
1280 return setgroups(setlen, gidset);
1281 #endif
1284 /**************************************************************************
1285 Wrappers for setpwent(), getpwent() and endpwent()
1286 ****************************************************************************/
1288 void sys_setpwent(void)
1290 setpwent();
1293 struct passwd *sys_getpwent(void)
1295 return getpwent();
1298 void sys_endpwent(void)
1300 endpwent();
1303 /**************************************************************************
1304 Wrappers for getpwnam(), getpwuid(), getgrnam(), getgrgid()
1305 ****************************************************************************/
1308 struct passwd *sys_getpwnam(const char *name)
1310 return getpwnam(name);
1313 struct passwd *sys_getpwuid(uid_t uid)
1315 return getpwuid(uid);
1318 struct group *sys_getgrnam(const char *name)
1320 return getgrnam(name);
1323 struct group *sys_getgrgid(gid_t gid)
1325 return getgrgid(gid);
1328 /**************************************************************************
1329 Extract a command into an arg list.
1330 ****************************************************************************/
1332 static char **extract_args(TALLOC_CTX *mem_ctx, const char *command)
1334 char *trunc_cmd;
1335 char *saveptr;
1336 char *ptr;
1337 int argcl;
1338 char **argl = NULL;
1339 int i;
1341 if (!(trunc_cmd = talloc_strdup(mem_ctx, command))) {
1342 DEBUG(0, ("talloc failed\n"));
1343 goto nomem;
1346 if(!(ptr = strtok_r(trunc_cmd, " \t", &saveptr))) {
1347 TALLOC_FREE(trunc_cmd);
1348 errno = EINVAL;
1349 return NULL;
1353 * Count the args.
1356 for( argcl = 1; ptr; ptr = strtok_r(NULL, " \t", &saveptr))
1357 argcl++;
1359 TALLOC_FREE(trunc_cmd);
1361 if (!(argl = TALLOC_ARRAY(mem_ctx, char *, argcl + 1))) {
1362 goto nomem;
1366 * Now do the extraction.
1369 if (!(trunc_cmd = talloc_strdup(mem_ctx, command))) {
1370 goto nomem;
1373 ptr = strtok_r(trunc_cmd, " \t", &saveptr);
1374 i = 0;
1376 if (!(argl[i++] = talloc_strdup(argl, ptr))) {
1377 goto nomem;
1380 while((ptr = strtok_r(NULL, " \t", &saveptr)) != NULL) {
1382 if (!(argl[i++] = talloc_strdup(argl, ptr))) {
1383 goto nomem;
1387 argl[i++] = NULL;
1388 TALLOC_FREE(trunc_cmd);
1389 return argl;
1391 nomem:
1392 DEBUG(0, ("talloc failed\n"));
1393 TALLOC_FREE(trunc_cmd);
1394 TALLOC_FREE(argl);
1395 errno = ENOMEM;
1396 return NULL;
1399 /**************************************************************************
1400 Wrapper for popen. Safer as it doesn't search a path.
1401 Modified from the glibc sources.
1402 modified by tridge to return a file descriptor. We must kick our FILE* habit
1403 ****************************************************************************/
1405 typedef struct _popen_list
1407 int fd;
1408 pid_t child_pid;
1409 struct _popen_list *next;
1410 } popen_list;
1412 static popen_list *popen_chain;
1414 int sys_popen(const char *command)
1416 int parent_end, child_end;
1417 int pipe_fds[2];
1418 popen_list *entry = NULL;
1419 char **argl = NULL;
1421 if (pipe(pipe_fds) < 0)
1422 return -1;
1424 parent_end = pipe_fds[0];
1425 child_end = pipe_fds[1];
1427 if (!*command) {
1428 errno = EINVAL;
1429 goto err_exit;
1432 if((entry = SMB_MALLOC_P(popen_list)) == NULL)
1433 goto err_exit;
1435 ZERO_STRUCTP(entry);
1438 * Extract the command and args into a NULL terminated array.
1441 if(!(argl = extract_args(NULL, command)))
1442 goto err_exit;
1444 entry->child_pid = sys_fork();
1446 if (entry->child_pid == -1) {
1447 goto err_exit;
1450 if (entry->child_pid == 0) {
1453 * Child !
1456 int child_std_end = STDOUT_FILENO;
1457 popen_list *p;
1459 close(parent_end);
1460 if (child_end != child_std_end) {
1461 dup2 (child_end, child_std_end);
1462 close (child_end);
1466 * POSIX.2: "popen() shall ensure that any streams from previous
1467 * popen() calls that remain open in the parent process are closed
1468 * in the new child process."
1471 for (p = popen_chain; p; p = p->next)
1472 close(p->fd);
1474 execv(argl[0], argl);
1475 _exit (127);
1479 * Parent.
1482 close (child_end);
1483 TALLOC_FREE(argl);
1485 /* Link into popen_chain. */
1486 entry->next = popen_chain;
1487 popen_chain = entry;
1488 entry->fd = parent_end;
1490 return entry->fd;
1492 err_exit:
1494 SAFE_FREE(entry);
1495 SAFE_FREE(argl);
1496 close(pipe_fds[0]);
1497 close(pipe_fds[1]);
1498 return -1;
1501 /**************************************************************************
1502 Wrapper for pclose. Modified from the glibc sources.
1503 ****************************************************************************/
1505 int sys_pclose(int fd)
1507 int wstatus;
1508 popen_list **ptr = &popen_chain;
1509 popen_list *entry = NULL;
1510 pid_t wait_pid;
1511 int status = -1;
1513 /* Unlink from popen_chain. */
1514 for ( ; *ptr != NULL; ptr = &(*ptr)->next) {
1515 if ((*ptr)->fd == fd) {
1516 entry = *ptr;
1517 *ptr = (*ptr)->next;
1518 status = 0;
1519 break;
1523 if (status < 0 || close(entry->fd) < 0)
1524 return -1;
1527 * As Samba is catching and eating child process
1528 * exits we don't really care about the child exit
1529 * code, a -1 with errno = ECHILD will do fine for us.
1532 do {
1533 wait_pid = sys_waitpid (entry->child_pid, &wstatus, 0);
1534 } while (wait_pid == -1 && errno == EINTR);
1536 SAFE_FREE(entry);
1538 if (wait_pid == -1)
1539 return -1;
1540 return wstatus;
1543 /**************************************************************************
1544 Wrapper for Admin Logs.
1545 ****************************************************************************/
1547 void sys_adminlog(int priority, const char *format_str, ...)
1549 va_list ap;
1550 int ret;
1551 char *msgbuf = NULL;
1553 va_start( ap, format_str );
1554 ret = vasprintf( &msgbuf, format_str, ap );
1555 va_end( ap );
1557 if (ret == -1)
1558 return;
1560 #if defined(HAVE_SYSLOG)
1561 syslog( priority, "%s", msgbuf );
1562 #else
1563 DEBUG(0,("%s", msgbuf ));
1564 #endif
1565 SAFE_FREE(msgbuf);
1568 /******** Solaris EA helper function prototypes ********/
1569 #ifdef HAVE_ATTROPEN
1570 #define SOLARIS_ATTRMODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP
1571 static int solaris_write_xattr(int attrfd, const char *value, size_t size);
1572 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size);
1573 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size);
1574 static int solaris_unlinkat(int attrdirfd, const char *name);
1575 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode);
1576 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode);
1577 #endif
1579 /**************************************************************************
1580 Wrappers for extented attribute calls. Based on the Linux package with
1581 support for IRIX and (Net|Free)BSD also. Expand as other systems have them.
1582 ****************************************************************************/
1584 ssize_t sys_getxattr (const char *path, const char *name, void *value, size_t size)
1586 #if defined(HAVE_GETXATTR)
1587 #ifndef XATTR_ADD_OPT
1588 return getxattr(path, name, value, size);
1589 #else
1590 int options = 0;
1591 return getxattr(path, name, value, size, 0, options);
1592 #endif
1593 #elif defined(HAVE_GETEA)
1594 return getea(path, name, value, size);
1595 #elif defined(HAVE_EXTATTR_GET_FILE)
1596 char *s;
1597 ssize_t retval;
1598 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
1599 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1600 const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1602 * The BSD implementation has a nasty habit of silently truncating
1603 * the returned value to the size of the buffer, so we have to check
1604 * that the buffer is large enough to fit the returned value.
1606 if((retval=extattr_get_file(path, attrnamespace, attrname, NULL, 0)) >= 0) {
1607 if(retval > size) {
1608 errno = ERANGE;
1609 return -1;
1611 if((retval=extattr_get_file(path, attrnamespace, attrname, value, size)) >= 0)
1612 return retval;
1615 DEBUG(10,("sys_getxattr: extattr_get_file() failed with: %s\n", strerror(errno)));
1616 return -1;
1617 #elif defined(HAVE_ATTR_GET)
1618 int retval, flags = 0;
1619 int valuelength = (int)size;
1620 char *attrname = strchr(name,'.') + 1;
1622 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1624 retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
1626 return retval ? retval : valuelength;
1627 #elif defined(HAVE_ATTROPEN)
1628 ssize_t ret = -1;
1629 int attrfd = solaris_attropen(path, name, O_RDONLY, 0);
1630 if (attrfd >= 0) {
1631 ret = solaris_read_xattr(attrfd, value, size);
1632 close(attrfd);
1634 return ret;
1635 #else
1636 errno = ENOSYS;
1637 return -1;
1638 #endif
1641 ssize_t sys_lgetxattr (const char *path, const char *name, void *value, size_t size)
1643 #if defined(HAVE_LGETXATTR)
1644 return lgetxattr(path, name, value, size);
1645 #elif defined(HAVE_GETXATTR) && defined(XATTR_ADD_OPT)
1646 int options = XATTR_NOFOLLOW;
1647 return getxattr(path, name, value, size, 0, options);
1648 #elif defined(HAVE_LGETEA)
1649 return lgetea(path, name, value, size);
1650 #elif defined(HAVE_EXTATTR_GET_LINK)
1651 char *s;
1652 ssize_t retval;
1653 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
1654 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1655 const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1657 if((retval=extattr_get_link(path, attrnamespace, attrname, NULL, 0)) >= 0) {
1658 if(retval > size) {
1659 errno = ERANGE;
1660 return -1;
1662 if((retval=extattr_get_link(path, attrnamespace, attrname, value, size)) >= 0)
1663 return retval;
1666 DEBUG(10,("sys_lgetxattr: extattr_get_link() failed with: %s\n", strerror(errno)));
1667 return -1;
1668 #elif defined(HAVE_ATTR_GET)
1669 int retval, flags = ATTR_DONTFOLLOW;
1670 int valuelength = (int)size;
1671 char *attrname = strchr(name,'.') + 1;
1673 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1675 retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
1677 return retval ? retval : valuelength;
1678 #elif defined(HAVE_ATTROPEN)
1679 ssize_t ret = -1;
1680 int attrfd = solaris_attropen(path, name, O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
1681 if (attrfd >= 0) {
1682 ret = solaris_read_xattr(attrfd, value, size);
1683 close(attrfd);
1685 return ret;
1686 #else
1687 errno = ENOSYS;
1688 return -1;
1689 #endif
1692 ssize_t sys_fgetxattr (int filedes, const char *name, void *value, size_t size)
1694 #if defined(HAVE_FGETXATTR)
1695 #ifndef XATTR_ADD_OPT
1696 return fgetxattr(filedes, name, value, size);
1697 #else
1698 int options = 0;
1699 return fgetxattr(filedes, name, value, size, 0, options);
1700 #endif
1701 #elif defined(HAVE_FGETEA)
1702 return fgetea(filedes, name, value, size);
1703 #elif defined(HAVE_EXTATTR_GET_FD)
1704 char *s;
1705 ssize_t retval;
1706 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
1707 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1708 const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1710 if((retval=extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0)) >= 0) {
1711 if(retval > size) {
1712 errno = ERANGE;
1713 return -1;
1715 if((retval=extattr_get_fd(filedes, attrnamespace, attrname, value, size)) >= 0)
1716 return retval;
1719 DEBUG(10,("sys_fgetxattr: extattr_get_fd() failed with: %s\n", strerror(errno)));
1720 return -1;
1721 #elif defined(HAVE_ATTR_GETF)
1722 int retval, flags = 0;
1723 int valuelength = (int)size;
1724 char *attrname = strchr(name,'.') + 1;
1726 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1728 retval = attr_getf(filedes, attrname, (char *)value, &valuelength, flags);
1730 return retval ? retval : valuelength;
1731 #elif defined(HAVE_ATTROPEN)
1732 ssize_t ret = -1;
1733 int attrfd = solaris_openat(filedes, name, O_RDONLY|O_XATTR, 0);
1734 if (attrfd >= 0) {
1735 ret = solaris_read_xattr(attrfd, value, size);
1736 close(attrfd);
1738 return ret;
1739 #else
1740 errno = ENOSYS;
1741 return -1;
1742 #endif
1745 #if defined(HAVE_EXTATTR_LIST_FILE)
1747 #define EXTATTR_PREFIX(s) (s), (sizeof((s))-1)
1749 static struct {
1750 int space;
1751 const char *name;
1752 size_t len;
1754 extattr[] = {
1755 { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("system.") },
1756 { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("user.") },
1759 typedef union {
1760 const char *path;
1761 int filedes;
1762 } extattr_arg;
1764 static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size)
1766 ssize_t list_size, total_size = 0;
1767 int i, t, len;
1768 char *buf;
1769 /* Iterate through extattr(2) namespaces */
1770 for(t = 0; t < (sizeof(extattr)/sizeof(extattr[0])); t++) {
1771 switch(type) {
1772 #if defined(HAVE_EXTATTR_LIST_FILE)
1773 case 0:
1774 list_size = extattr_list_file(arg.path, extattr[t].space, list, size);
1775 break;
1776 #endif
1777 #if defined(HAVE_EXTATTR_LIST_LINK)
1778 case 1:
1779 list_size = extattr_list_link(arg.path, extattr[t].space, list, size);
1780 break;
1781 #endif
1782 #if defined(HAVE_EXTATTR_LIST_FD)
1783 case 2:
1784 list_size = extattr_list_fd(arg.filedes, extattr[t].space, list, size);
1785 break;
1786 #endif
1787 default:
1788 errno = ENOSYS;
1789 return -1;
1791 /* Some error happend. Errno should be set by the previous call */
1792 if(list_size < 0)
1793 return -1;
1794 /* No attributes */
1795 if(list_size == 0)
1796 continue;
1797 /* XXX: Call with an empty buffer may be used to calculate
1798 necessary buffer size. Unfortunately, we can't say, how
1799 many attributes were returned, so here is the potential
1800 problem with the emulation.
1802 if(list == NULL) {
1803 /* Take the worse case of one char attribute names -
1804 two bytes per name plus one more for sanity.
1806 total_size += list_size + (list_size/2 + 1)*extattr[t].len;
1807 continue;
1809 /* Count necessary offset to fit namespace prefixes */
1810 len = 0;
1811 for(i = 0; i < list_size; i += list[i] + 1)
1812 len += extattr[t].len;
1814 total_size += list_size + len;
1815 /* Buffer is too small to fit the results */
1816 if(total_size > size) {
1817 errno = ERANGE;
1818 return -1;
1820 /* Shift results back, so we can prepend prefixes */
1821 buf = (char *)memmove(list + len, list, list_size);
1823 for(i = 0; i < list_size; i += len + 1) {
1824 len = buf[i];
1825 strncpy(list, extattr[t].name, extattr[t].len + 1);
1826 list += extattr[t].len;
1827 strncpy(list, buf + i + 1, len);
1828 list[len] = '\0';
1829 list += len + 1;
1831 size -= total_size;
1833 return total_size;
1836 #endif
1838 #if defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1839 static char attr_buffer[ATTR_MAX_VALUELEN];
1841 static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
1843 int retval = 0, index;
1844 attrlist_cursor_t *cursor = 0;
1845 int total_size = 0;
1846 attrlist_t * al = (attrlist_t *)attr_buffer;
1847 attrlist_ent_t *ae;
1848 size_t ent_size, left = size;
1849 char *bp = list;
1851 while (True) {
1852 if (filedes)
1853 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1854 else
1855 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1856 if (retval) break;
1857 for (index = 0; index < al->al_count; index++) {
1858 ae = ATTR_ENTRY(attr_buffer, index);
1859 ent_size = strlen(ae->a_name) + sizeof("user.");
1860 if (left >= ent_size) {
1861 strncpy(bp, "user.", sizeof("user."));
1862 strncat(bp, ae->a_name, ent_size - sizeof("user."));
1863 bp += ent_size;
1864 left -= ent_size;
1865 } else if (size) {
1866 errno = ERANGE;
1867 retval = -1;
1868 break;
1870 total_size += ent_size;
1872 if (al->al_more == 0) break;
1874 if (retval == 0) {
1875 flags |= ATTR_ROOT;
1876 cursor = 0;
1877 while (True) {
1878 if (filedes)
1879 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1880 else
1881 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1882 if (retval) break;
1883 for (index = 0; index < al->al_count; index++) {
1884 ae = ATTR_ENTRY(attr_buffer, index);
1885 ent_size = strlen(ae->a_name) + sizeof("system.");
1886 if (left >= ent_size) {
1887 strncpy(bp, "system.", sizeof("system."));
1888 strncat(bp, ae->a_name, ent_size - sizeof("system."));
1889 bp += ent_size;
1890 left -= ent_size;
1891 } else if (size) {
1892 errno = ERANGE;
1893 retval = -1;
1894 break;
1896 total_size += ent_size;
1898 if (al->al_more == 0) break;
1901 return (ssize_t)(retval ? retval : total_size);
1904 #endif
1906 ssize_t sys_listxattr (const char *path, char *list, size_t size)
1908 #if defined(HAVE_LISTXATTR)
1909 #ifndef XATTR_ADD_OPT
1910 return listxattr(path, list, size);
1911 #else
1912 int options = 0;
1913 return listxattr(path, list, size, options);
1914 #endif
1915 #elif defined(HAVE_LISTEA)
1916 return listea(path, list, size);
1917 #elif defined(HAVE_EXTATTR_LIST_FILE)
1918 extattr_arg arg;
1919 arg.path = path;
1920 return bsd_attr_list(0, arg, list, size);
1921 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1922 return irix_attr_list(path, 0, list, size, 0);
1923 #elif defined(HAVE_ATTROPEN)
1924 ssize_t ret = -1;
1925 int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
1926 if (attrdirfd >= 0) {
1927 ret = solaris_list_xattr(attrdirfd, list, size);
1928 close(attrdirfd);
1930 return ret;
1931 #else
1932 errno = ENOSYS;
1933 return -1;
1934 #endif
1937 ssize_t sys_llistxattr (const char *path, char *list, size_t size)
1939 #if defined(HAVE_LLISTXATTR)
1940 return llistxattr(path, list, size);
1941 #elif defined(HAVE_LISTXATTR) && defined(XATTR_ADD_OPT)
1942 int options = XATTR_NOFOLLOW;
1943 return listxattr(path, list, size, options);
1944 #elif defined(HAVE_LLISTEA)
1945 return llistea(path, list, size);
1946 #elif defined(HAVE_EXTATTR_LIST_LINK)
1947 extattr_arg arg;
1948 arg.path = path;
1949 return bsd_attr_list(1, arg, list, size);
1950 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1951 return irix_attr_list(path, 0, list, size, ATTR_DONTFOLLOW);
1952 #elif defined(HAVE_ATTROPEN)
1953 ssize_t ret = -1;
1954 int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
1955 if (attrdirfd >= 0) {
1956 ret = solaris_list_xattr(attrdirfd, list, size);
1957 close(attrdirfd);
1959 return ret;
1960 #else
1961 errno = ENOSYS;
1962 return -1;
1963 #endif
1966 ssize_t sys_flistxattr (int filedes, char *list, size_t size)
1968 #if defined(HAVE_FLISTXATTR)
1969 #ifndef XATTR_ADD_OPT
1970 return flistxattr(filedes, list, size);
1971 #else
1972 int options = 0;
1973 return flistxattr(filedes, list, size, options);
1974 #endif
1975 #elif defined(HAVE_FLISTEA)
1976 return flistea(filedes, list, size);
1977 #elif defined(HAVE_EXTATTR_LIST_FD)
1978 extattr_arg arg;
1979 arg.filedes = filedes;
1980 return bsd_attr_list(2, arg, list, size);
1981 #elif defined(HAVE_ATTR_LISTF)
1982 return irix_attr_list(NULL, filedes, list, size, 0);
1983 #elif defined(HAVE_ATTROPEN)
1984 ssize_t ret = -1;
1985 int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
1986 if (attrdirfd >= 0) {
1987 ret = solaris_list_xattr(attrdirfd, list, size);
1988 close(attrdirfd);
1990 return ret;
1991 #else
1992 errno = ENOSYS;
1993 return -1;
1994 #endif
1997 int sys_removexattr (const char *path, const char *name)
1999 #if defined(HAVE_REMOVEXATTR)
2000 #ifndef XATTR_ADD_OPT
2001 return removexattr(path, name);
2002 #else
2003 int options = 0;
2004 return removexattr(path, name, options);
2005 #endif
2006 #elif defined(HAVE_REMOVEEA)
2007 return removeea(path, name);
2008 #elif defined(HAVE_EXTATTR_DELETE_FILE)
2009 char *s;
2010 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
2011 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
2012 const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
2014 return extattr_delete_file(path, attrnamespace, attrname);
2015 #elif defined(HAVE_ATTR_REMOVE)
2016 int flags = 0;
2017 char *attrname = strchr(name,'.') + 1;
2019 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
2021 return attr_remove(path, attrname, flags);
2022 #elif defined(HAVE_ATTROPEN)
2023 int ret = -1;
2024 int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
2025 if (attrdirfd >= 0) {
2026 ret = solaris_unlinkat(attrdirfd, name);
2027 close(attrdirfd);
2029 return ret;
2030 #else
2031 errno = ENOSYS;
2032 return -1;
2033 #endif
2036 int sys_lremovexattr (const char *path, const char *name)
2038 #if defined(HAVE_LREMOVEXATTR)
2039 return lremovexattr(path, name);
2040 #elif defined(HAVE_REMOVEXATTR) && defined(XATTR_ADD_OPT)
2041 int options = XATTR_NOFOLLOW;
2042 return removexattr(path, name, options);
2043 #elif defined(HAVE_LREMOVEEA)
2044 return lremoveea(path, name);
2045 #elif defined(HAVE_EXTATTR_DELETE_LINK)
2046 char *s;
2047 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
2048 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
2049 const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
2051 return extattr_delete_link(path, attrnamespace, attrname);
2052 #elif defined(HAVE_ATTR_REMOVE)
2053 int flags = ATTR_DONTFOLLOW;
2054 char *attrname = strchr(name,'.') + 1;
2056 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
2058 return attr_remove(path, attrname, flags);
2059 #elif defined(HAVE_ATTROPEN)
2060 int ret = -1;
2061 int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
2062 if (attrdirfd >= 0) {
2063 ret = solaris_unlinkat(attrdirfd, name);
2064 close(attrdirfd);
2066 return ret;
2067 #else
2068 errno = ENOSYS;
2069 return -1;
2070 #endif
2073 int sys_fremovexattr (int filedes, const char *name)
2075 #if defined(HAVE_FREMOVEXATTR)
2076 #ifndef XATTR_ADD_OPT
2077 return fremovexattr(filedes, name);
2078 #else
2079 int options = 0;
2080 return fremovexattr(filedes, name, options);
2081 #endif
2082 #elif defined(HAVE_FREMOVEEA)
2083 return fremoveea(filedes, name);
2084 #elif defined(HAVE_EXTATTR_DELETE_FD)
2085 char *s;
2086 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
2087 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
2088 const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
2090 return extattr_delete_fd(filedes, attrnamespace, attrname);
2091 #elif defined(HAVE_ATTR_REMOVEF)
2092 int flags = 0;
2093 char *attrname = strchr(name,'.') + 1;
2095 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
2097 return attr_removef(filedes, attrname, flags);
2098 #elif defined(HAVE_ATTROPEN)
2099 int ret = -1;
2100 int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
2101 if (attrdirfd >= 0) {
2102 ret = solaris_unlinkat(attrdirfd, name);
2103 close(attrdirfd);
2105 return ret;
2106 #else
2107 errno = ENOSYS;
2108 return -1;
2109 #endif
2112 int sys_setxattr (const char *path, const char *name, const void *value, size_t size, int flags)
2114 #if defined(HAVE_SETXATTR)
2115 #ifndef XATTR_ADD_OPT
2116 return setxattr(path, name, value, size, flags);
2117 #else
2118 int options = 0;
2119 return setxattr(path, name, value, size, 0, options);
2120 #endif
2121 #elif defined(HAVE_SETEA)
2122 return setea(path, name, value, size, flags);
2123 #elif defined(HAVE_EXTATTR_SET_FILE)
2124 char *s;
2125 int retval = 0;
2126 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
2127 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
2128 const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
2129 if (flags) {
2130 /* Check attribute existence */
2131 retval = extattr_get_file(path, attrnamespace, attrname, NULL, 0);
2132 if (retval < 0) {
2133 /* REPLACE attribute, that doesn't exist */
2134 if (flags & XATTR_REPLACE && errno == ENOATTR) {
2135 errno = ENOATTR;
2136 return -1;
2138 /* Ignore other errors */
2140 else {
2141 /* CREATE attribute, that already exists */
2142 if (flags & XATTR_CREATE) {
2143 errno = EEXIST;
2144 return -1;
2148 retval = extattr_set_file(path, attrnamespace, attrname, value, size);
2149 return (retval < 0) ? -1 : 0;
2150 #elif defined(HAVE_ATTR_SET)
2151 int myflags = 0;
2152 char *attrname = strchr(name,'.') + 1;
2154 if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
2155 if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
2156 if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
2158 return attr_set(path, attrname, (const char *)value, size, myflags);
2159 #elif defined(HAVE_ATTROPEN)
2160 int ret = -1;
2161 int myflags = O_RDWR;
2162 int attrfd;
2163 if (flags & XATTR_CREATE) myflags |= O_EXCL;
2164 if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
2165 attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
2166 if (attrfd >= 0) {
2167 ret = solaris_write_xattr(attrfd, value, size);
2168 close(attrfd);
2170 return ret;
2171 #else
2172 errno = ENOSYS;
2173 return -1;
2174 #endif
2177 int sys_lsetxattr (const char *path, const char *name, const void *value, size_t size, int flags)
2179 #if defined(HAVE_LSETXATTR)
2180 return lsetxattr(path, name, value, size, flags);
2181 #elif defined(HAVE_SETXATTR) && defined(XATTR_ADD_OPT)
2182 int options = XATTR_NOFOLLOW;
2183 return setxattr(path, name, value, size, 0, options);
2184 #elif defined(LSETEA)
2185 return lsetea(path, name, value, size, flags);
2186 #elif defined(HAVE_EXTATTR_SET_LINK)
2187 char *s;
2188 int retval = 0;
2189 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
2190 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
2191 const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
2192 if (flags) {
2193 /* Check attribute existence */
2194 retval = extattr_get_link(path, attrnamespace, attrname, NULL, 0);
2195 if (retval < 0) {
2196 /* REPLACE attribute, that doesn't exist */
2197 if (flags & XATTR_REPLACE && errno == ENOATTR) {
2198 errno = ENOATTR;
2199 return -1;
2201 /* Ignore other errors */
2203 else {
2204 /* CREATE attribute, that already exists */
2205 if (flags & XATTR_CREATE) {
2206 errno = EEXIST;
2207 return -1;
2212 retval = extattr_set_link(path, attrnamespace, attrname, value, size);
2213 return (retval < 0) ? -1 : 0;
2214 #elif defined(HAVE_ATTR_SET)
2215 int myflags = ATTR_DONTFOLLOW;
2216 char *attrname = strchr(name,'.') + 1;
2218 if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
2219 if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
2220 if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
2222 return attr_set(path, attrname, (const char *)value, size, myflags);
2223 #elif defined(HAVE_ATTROPEN)
2224 int ret = -1;
2225 int myflags = O_RDWR | AT_SYMLINK_NOFOLLOW;
2226 int attrfd;
2227 if (flags & XATTR_CREATE) myflags |= O_EXCL;
2228 if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
2229 attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
2230 if (attrfd >= 0) {
2231 ret = solaris_write_xattr(attrfd, value, size);
2232 close(attrfd);
2234 return ret;
2235 #else
2236 errno = ENOSYS;
2237 return -1;
2238 #endif
2241 int sys_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags)
2243 #if defined(HAVE_FSETXATTR)
2244 #ifndef XATTR_ADD_OPT
2245 return fsetxattr(filedes, name, value, size, flags);
2246 #else
2247 int options = 0;
2248 return fsetxattr(filedes, name, value, size, 0, options);
2249 #endif
2250 #elif defined(HAVE_FSETEA)
2251 return fsetea(filedes, name, value, size, flags);
2252 #elif defined(HAVE_EXTATTR_SET_FD)
2253 char *s;
2254 int retval = 0;
2255 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
2256 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
2257 const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
2258 if (flags) {
2259 /* Check attribute existence */
2260 retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
2261 if (retval < 0) {
2262 /* REPLACE attribute, that doesn't exist */
2263 if (flags & XATTR_REPLACE && errno == ENOATTR) {
2264 errno = ENOATTR;
2265 return -1;
2267 /* Ignore other errors */
2269 else {
2270 /* CREATE attribute, that already exists */
2271 if (flags & XATTR_CREATE) {
2272 errno = EEXIST;
2273 return -1;
2277 retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size);
2278 return (retval < 0) ? -1 : 0;
2279 #elif defined(HAVE_ATTR_SETF)
2280 int myflags = 0;
2281 char *attrname = strchr(name,'.') + 1;
2283 if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
2284 if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
2285 if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
2287 return attr_setf(filedes, attrname, (const char *)value, size, myflags);
2288 #elif defined(HAVE_ATTROPEN)
2289 int ret = -1;
2290 int myflags = O_RDWR | O_XATTR;
2291 int attrfd;
2292 if (flags & XATTR_CREATE) myflags |= O_EXCL;
2293 if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
2294 attrfd = solaris_openat(filedes, name, myflags, (mode_t) SOLARIS_ATTRMODE);
2295 if (attrfd >= 0) {
2296 ret = solaris_write_xattr(attrfd, value, size);
2297 close(attrfd);
2299 return ret;
2300 #else
2301 errno = ENOSYS;
2302 return -1;
2303 #endif
2306 /**************************************************************************
2307 helper functions for Solaris' EA support
2308 ****************************************************************************/
2309 #ifdef HAVE_ATTROPEN
2310 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size)
2312 struct stat sbuf;
2314 if (fstat(attrfd, &sbuf) == -1) {
2315 errno = ENOATTR;
2316 return -1;
2319 /* This is to return the current size of the named extended attribute */
2320 if (size == 0) {
2321 return sbuf.st_size;
2324 /* check size and read xattr */
2325 if (sbuf.st_size > size) {
2326 errno = ERANGE;
2327 return -1;
2330 return read(attrfd, value, sbuf.st_size);
2333 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size)
2335 ssize_t len = 0;
2336 DIR *dirp;
2337 struct dirent *de;
2338 int newfd = dup(attrdirfd);
2339 /* CAUTION: The originating file descriptor should not be
2340 used again following the call to fdopendir().
2341 For that reason we dup() the file descriptor
2342 here to make things more clear. */
2343 dirp = fdopendir(newfd);
2345 while ((de = readdir(dirp))) {
2346 size_t listlen = strlen(de->d_name);
2347 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
2348 /* we don't want "." and ".." here: */
2349 DEBUG(10,("skipped EA %s\n",de->d_name));
2350 continue;
2353 if (size == 0) {
2354 /* return the current size of the list of extended attribute names*/
2355 len += listlen + 1;
2356 } else {
2357 /* check size and copy entrieѕ + nul into list. */
2358 if ((len + listlen + 1) > size) {
2359 errno = ERANGE;
2360 len = -1;
2361 break;
2362 } else {
2363 safe_strcpy(list + len, de->d_name, listlen);
2364 len += listlen;
2365 list[len] = '\0';
2366 ++len;
2371 if (closedir(dirp) == -1) {
2372 DEBUG(0,("closedir dirp failed: %s\n",strerror(errno)));
2373 return -1;
2375 return len;
2378 static int solaris_unlinkat(int attrdirfd, const char *name)
2380 if (unlinkat(attrdirfd, name, 0) == -1) {
2381 if (errno == ENOENT) {
2382 errno = ENOATTR;
2384 return -1;
2386 return 0;
2389 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode)
2391 int filedes = attropen(path, attrpath, oflag, mode);
2392 if (filedes == -1) {
2393 DEBUG(10,("attropen FAILED: path: %s, name: %s, errno: %s\n",path,attrpath,strerror(errno)));
2394 if (errno == EINVAL) {
2395 errno = ENOTSUP;
2396 } else {
2397 errno = ENOATTR;
2400 return filedes;
2403 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
2405 int filedes = openat(fildes, path, oflag, mode);
2406 if (filedes == -1) {
2407 DEBUG(10,("openat FAILED: fd: %d, path: %s, errno: %s\n",filedes,path,strerror(errno)));
2408 if (errno == EINVAL) {
2409 errno = ENOTSUP;
2410 } else {
2411 errno = ENOATTR;
2414 return filedes;
2417 static int solaris_write_xattr(int attrfd, const char *value, size_t size)
2419 if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) {
2420 return 0;
2421 } else {
2422 DEBUG(10,("solaris_write_xattr FAILED!\n"));
2423 return -1;
2426 #endif /*HAVE_ATTROPEN*/
2429 /****************************************************************************
2430 Return the major devicenumber for UNIX extensions.
2431 ****************************************************************************/
2433 uint32 unix_dev_major(SMB_DEV_T dev)
2435 #if defined(HAVE_DEVICE_MAJOR_FN)
2436 return (uint32)major(dev);
2437 #else
2438 return (uint32)(dev >> 8);
2439 #endif
2442 /****************************************************************************
2443 Return the minor devicenumber for UNIX extensions.
2444 ****************************************************************************/
2446 uint32 unix_dev_minor(SMB_DEV_T dev)
2448 #if defined(HAVE_DEVICE_MINOR_FN)
2449 return (uint32)minor(dev);
2450 #else
2451 return (uint32)(dev & 0xff);
2452 #endif
2455 #if defined(WITH_AIO)
2457 /*******************************************************************
2458 An aio_read wrapper that will deal with 64-bit sizes.
2459 ********************************************************************/
2461 int sys_aio_read(SMB_STRUCT_AIOCB *aiocb)
2463 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_READ64)
2464 return aio_read64(aiocb);
2465 #elif defined(HAVE_AIO_READ)
2466 return aio_read(aiocb);
2467 #else
2468 errno = ENOSYS;
2469 return -1;
2470 #endif
2473 /*******************************************************************
2474 An aio_write wrapper that will deal with 64-bit sizes.
2475 ********************************************************************/
2477 int sys_aio_write(SMB_STRUCT_AIOCB *aiocb)
2479 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_WRITE64)
2480 return aio_write64(aiocb);
2481 #elif defined(HAVE_AIO_WRITE)
2482 return aio_write(aiocb);
2483 #else
2484 errno = ENOSYS;
2485 return -1;
2486 #endif
2489 /*******************************************************************
2490 An aio_return wrapper that will deal with 64-bit sizes.
2491 ********************************************************************/
2493 ssize_t sys_aio_return(SMB_STRUCT_AIOCB *aiocb)
2495 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_RETURN64)
2496 return aio_return64(aiocb);
2497 #elif defined(HAVE_AIO_RETURN)
2498 return aio_return(aiocb);
2499 #else
2500 errno = ENOSYS;
2501 return -1;
2502 #endif
2505 /*******************************************************************
2506 An aio_cancel wrapper that will deal with 64-bit sizes.
2507 ********************************************************************/
2509 int sys_aio_cancel(int fd, SMB_STRUCT_AIOCB *aiocb)
2511 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_CANCEL64)
2512 return aio_cancel64(fd, aiocb);
2513 #elif defined(HAVE_AIO_CANCEL)
2514 return aio_cancel(fd, aiocb);
2515 #else
2516 errno = ENOSYS;
2517 return -1;
2518 #endif
2521 /*******************************************************************
2522 An aio_error wrapper that will deal with 64-bit sizes.
2523 ********************************************************************/
2525 int sys_aio_error(const SMB_STRUCT_AIOCB *aiocb)
2527 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_ERROR64)
2528 return aio_error64(aiocb);
2529 #elif defined(HAVE_AIO_ERROR)
2530 return aio_error(aiocb);
2531 #else
2532 errno = ENOSYS;
2533 return -1;
2534 #endif
2537 /*******************************************************************
2538 An aio_fsync wrapper that will deal with 64-bit sizes.
2539 ********************************************************************/
2541 int sys_aio_fsync(int op, SMB_STRUCT_AIOCB *aiocb)
2543 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_FSYNC64)
2544 return aio_fsync64(op, aiocb);
2545 #elif defined(HAVE_AIO_FSYNC)
2546 return aio_fsync(op, aiocb);
2547 #else
2548 errno = ENOSYS;
2549 return -1;
2550 #endif
2553 /*******************************************************************
2554 An aio_fsync wrapper that will deal with 64-bit sizes.
2555 ********************************************************************/
2557 int sys_aio_suspend(const SMB_STRUCT_AIOCB * const cblist[], int n, const struct timespec *timeout)
2559 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_SUSPEND64)
2560 return aio_suspend64(cblist, n, timeout);
2561 #elif defined(HAVE_AIO_FSYNC)
2562 return aio_suspend(cblist, n, timeout);
2563 #else
2564 errno = ENOSYS;
2565 return -1;
2566 #endif
2568 #else /* !WITH_AIO */
2570 int sys_aio_read(SMB_STRUCT_AIOCB *aiocb)
2572 errno = ENOSYS;
2573 return -1;
2576 int sys_aio_write(SMB_STRUCT_AIOCB *aiocb)
2578 errno = ENOSYS;
2579 return -1;
2582 ssize_t sys_aio_return(SMB_STRUCT_AIOCB *aiocb)
2584 errno = ENOSYS;
2585 return -1;
2588 int sys_aio_cancel(int fd, SMB_STRUCT_AIOCB *aiocb)
2590 errno = ENOSYS;
2591 return -1;
2594 int sys_aio_error(const SMB_STRUCT_AIOCB *aiocb)
2596 errno = ENOSYS;
2597 return -1;
2600 int sys_aio_fsync(int op, SMB_STRUCT_AIOCB *aiocb)
2602 errno = ENOSYS;
2603 return -1;
2606 int sys_aio_suspend(const SMB_STRUCT_AIOCB * const cblist[], int n, const struct timespec *timeout)
2608 errno = ENOSYS;
2609 return -1;
2611 #endif /* WITH_AIO */
2613 int sys_getpeereid( int s, uid_t *uid)
2615 #if defined(HAVE_PEERCRED)
2616 struct ucred cred;
2617 socklen_t cred_len = sizeof(struct ucred);
2618 int ret;
2620 ret = getsockopt(s, SOL_SOCKET, SO_PEERCRED, (void *)&cred, &cred_len);
2621 if (ret != 0) {
2622 return -1;
2625 if (cred_len != sizeof(struct ucred)) {
2626 errno = EINVAL;
2627 return -1;
2630 *uid = cred.uid;
2631 return 0;
2632 #else
2633 errno = ENOSYS;
2634 return -1;
2635 #endif
2638 int sys_getnameinfo(const struct sockaddr *psa,
2639 socklen_t salen,
2640 char *host,
2641 size_t hostlen,
2642 char *service,
2643 size_t servlen,
2644 int flags)
2647 * For Solaris we must make sure salen is the
2648 * correct length for the incoming sa_family.
2651 if (salen == sizeof(struct sockaddr_storage)) {
2652 salen = sizeof(struct sockaddr_in);
2653 #if defined(HAVE_IPV6)
2654 if (psa->sa_family == AF_INET6) {
2655 salen = sizeof(struct sockaddr_in6);
2657 #endif
2659 return getnameinfo(psa, salen, host, hostlen, service, servlen, flags);
2662 int sys_connect(int fd, const struct sockaddr * addr)
2664 socklen_t salen = -1;
2666 if (addr->sa_family == AF_INET) {
2667 salen = sizeof(struct sockaddr_in);
2668 } else if (addr->sa_family == AF_UNIX) {
2669 salen = sizeof(struct sockaddr_un);
2671 #if defined(HAVE_IPV6)
2672 else if (addr->sa_family == AF_INET6) {
2673 salen = sizeof(struct sockaddr_in6);
2675 #endif
2677 return connect(fd, addr, salen);