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