source: trunk/server/source3/lib/system.c@ 454

Last change on this file since 454 was 454, checked in by Silvan Scherrer, 15 years ago

Samba Server 3.5: merged changes from 3.3

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