source: vendor/3.5.7/source3/lib/system.c

Last change on this file was 587, checked in by Herwig Bauernfeind, 14 years ago

Samba 3.5: Update vendor to version 3.5.6

File size: 71.3 KB
Line 
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}
Note: See TracBrowser for help on using the repository browser.