2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
6 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
7 /* All Rights Reserved */
10 * Copyright (c) 1983 Regents of the University of California.
11 * All rights reserved. The Berkeley software License Agreement
12 * specifies the terms and conditions for redistribution.
20 /* LINTED: this file really is necessary */
25 * Insure that all the components of a pathname exist. Note that
26 * lookupname() and addentry() both expect complex names as
27 * input arguments, so a double NULL needs to be added to each name.
36 start
= strchr(name
, '/');
39 for (cp
= start
; *cp
!= '\0'; cp
++) {
45 ep
= lookupname(name
);
47 ep
= addentry(name
, psearch(name
), NODE
);
50 /* LINTED: result fits in a short */
51 ep
->e_flags
|= NEW
|KEEP
;
58 * Change a name to a unique temporary name.
61 mktempname(struct entry
*ep
)
65 if (ep
->e_flags
& TMPNAME
)
66 badentry(ep
, gettext("mktempname: called with TMPNAME"));
67 /* LINTED: result fits in a short */
68 ep
->e_flags
|= TMPNAME
;
69 newname
= savename(gentempname(ep
));
70 renameit(myname(ep
), newname
);
73 /* LINTED: savename guarantees strlen will fit */
74 ep
->e_namlen
= strlen(ep
->e_name
);
78 * Generate a temporary name for an entry.
81 gentempname(struct entry
*ep
)
83 static char name
[MAXPATHLEN
];
87 for (np
= lookupino(ep
->e_ino
); np
!= NIL
&& np
!= ep
; np
= np
->e_links
)
90 badentry(ep
, gettext("not on ino list"));
91 (void) snprintf(name
, sizeof (name
), "%s%ld%lu", TMPHDR
, i
, ep
->e_ino
);
96 * Rename a file or directory.
99 renameit(char *fp
, char *tp
)
103 char tobuf
[MAXPATHLEN
];
106 resolve(fp
, &fromfd
, &from
);
108 * The to pointer argument is assumed to be either a fully
109 * specified path (starting with "./") or a simple temporary
110 * file name (starting with TMPHDR). If passed a simple temp
111 * file name, we need to set up the descriptors explicitly.
113 if (strncmp(tp
, TMPHDR
, sizeof (TMPHDR
) - 1) == 0) {
115 if ((pathend
= strrchr(from
, '/')) != NULL
) {
116 strncpy(tobuf
, from
, pathend
- from
+ 1);
117 tobuf
[pathend
- from
+ 1] = NULL
;
118 strlcat(tobuf
, tp
, sizeof (tobuf
));
124 resolve(tp
, &tofd
, &to
);
125 if (renameat(fromfd
, from
, tofd
, to
) < 0) {
127 (void) fprintf(stderr
,
128 gettext("Warning: cannot rename %s to %s: %s\n"),
129 from
, to
, strerror(saverr
));
130 (void) fflush(stderr
);
132 vprintf(stdout
, gettext("rename %s to %s\n"), from
, to
);
134 if (fromfd
!= AT_FDCWD
) (void) close(fromfd
);
135 if (tofd
!= AT_FDCWD
) (void) close(tofd
);
139 * Create a new node (directory). Note that, because we have no
140 * mkdirat() function, fchdir() must be used set up the appropriate
141 * name space context prior to the call to mkdir() if we are
142 * operating in attribute space.
145 newnode(struct entry
*np
)
150 if (np
->e_type
!= NODE
)
151 badentry(np
, gettext("newnode: not a node"));
152 resolve(myname(np
), &dfd
, &cp
);
153 if (dfd
!= AT_FDCWD
) {
154 if (fchdir(dfd
) < 0) {
156 (void) fprintf(stderr
,
157 gettext("Warning: cannot create %s: %s"),
158 cp
, strerror(saverr
));
159 (void) fflush(stderr
);
164 if (mkdir(cp
, 0777) < 0) {
166 /* LINTED: result fits in a short */
167 np
->e_flags
|= EXISTED
;
168 (void) fprintf(stderr
, gettext("Warning: "));
169 (void) fflush(stderr
);
170 (void) fprintf(stderr
, "%s: %s\n", cp
, strerror(saverr
));
172 vprintf(stdout
, gettext("Make node %s\n"), cp
);
174 if (dfd
!= AT_FDCWD
) {
181 * Remove an old node (directory). See comment above on newnode()
182 * for explanation of fchdir() use below.
185 removenode(struct entry
*ep
)
190 if (ep
->e_type
!= NODE
)
191 badentry(ep
, gettext("removenode: not a node"));
192 if (ep
->e_entries
!= NIL
)
193 badentry(ep
, gettext("removenode: non-empty directory"));
194 /* LINTED: result fits in a short */
195 ep
->e_flags
|= REMOVED
;
196 /* LINTED: result fits in a short */
197 ep
->e_flags
&= ~TMPNAME
;
198 resolve(myname(ep
), &dfd
, &cp
);
199 if (dfd
!= AT_FDCWD
) {
200 if (fchdir(dfd
) < 0) {
202 (void) fprintf(stderr
,
203 gettext("Warning: cannot remove %s: %s"),
204 cp
, strerror(saverr
));
205 (void) fflush(stderr
);
210 if (rmdir(cp
) < 0) { /* NOTE: could use unlinkat (..,REMOVEDIR) */
212 (void) fprintf(stderr
, gettext("Warning: %s: %s\n"),
213 cp
, strerror(saverr
));
214 (void) fflush(stderr
);
216 vprintf(stdout
, gettext("Remove node %s\n"), cp
);
218 if (dfd
!= AT_FDCWD
) {
219 (void) fchdir(savepwd
);
228 removeleaf(struct entry
*ep
)
233 if (ep
->e_type
!= LEAF
)
234 badentry(ep
, gettext("removeleaf: not a leaf"));
235 /* LINTED: result fits in a short */
236 ep
->e_flags
|= REMOVED
;
237 /* LINTED: result fits in a short */
238 ep
->e_flags
&= ~TMPNAME
;
239 resolve(myname(ep
), &dfd
, &cp
);
240 if (unlinkat(dfd
, cp
, 0) < 0) {
242 (void) fprintf(stderr
, gettext("Warning: %s: %s\n"),
243 cp
, strerror(saverr
));
244 (void) fflush(stderr
);
246 vprintf(stdout
, gettext("Remove leaf %s\n"), cp
);
254 * This function assumes that the context has already been set
255 * for the link file to be created (i.e., we have "fchdir-ed"
256 * into attribute space already if this is an attribute link).
259 lf_linkit(char *existing
, char *new, int type
)
261 char linkbuf
[MAXPATHLEN
];
262 struct stat64 s1
[1], s2
[1];
266 resolve(existing
, &dfd
, &name
);
268 (void) fprintf(stderr
, gettext(
269 "Warning: cannot restore %s link %s->%s\n"),
270 (type
== SYMLINK
? "symbolic" : "hard"), new, existing
);
274 if (type
== SYMLINK
) {
275 if (symlink(name
, new) < 0) {
276 /* No trailing \0 from readlink(2) */
277 if (((l
= readlink(new, linkbuf
, sizeof (linkbuf
)))
279 (l
== strlen(name
)) &&
280 (strncmp(linkbuf
, name
, l
) == 0)) {
282 gettext("Symbolic link %s->%s ok\n"),
288 (void) fprintf(stderr
, gettext(
289 "Warning: cannot create symbolic link %s->%s: %s"),
290 new, name
, strerror(saverr
));
291 (void) fflush(stderr
);
296 } else if (type
== HARDLINK
) {
297 if (link(name
, new) < 0) {
299 if ((stat64(name
, s1
) == 0) &&
300 (stat64(new, s2
) == 0) &&
301 (s1
->st_dev
== s2
->st_dev
) &&
302 (s1
->st_ino
== s2
->st_ino
)) {
304 gettext("Hard link %s->%s ok\n"),
309 (void) fprintf(stderr
, gettext(
310 "Warning: cannot create hard link %s->%s: %s\n"),
311 new, name
, strerror(saverr
));
312 (void) fflush(stderr
);
318 panic(gettext("%s: unknown type %d\n"), "linkit", type
);
324 vprintf(stdout
, gettext("Create symbolic link %s->%s\n"),
327 vprintf(stdout
, gettext("Create hard link %s->%s\n"),
330 if (dfd
!= AT_FDCWD
) {
337 * Find lowest-numbered inode (above "start") that needs to be extracted.
338 * Caller knows that a return value of maxino means there's nothing left.
341 lowerbnd(ino_t start
)
345 for (; start
< maxino
; start
++) {
346 ep
= lookupino(start
);
347 if (ep
== NIL
|| ep
->e_type
== NODE
)
349 if (ep
->e_flags
& (NEW
|EXTRACT
))
356 * Find highest-numbered inode (below "start") that needs to be extracted.
359 upperbnd(ino_t start
)
363 for (; start
> ROOTINO
; start
--) {
364 ep
= lookupino(start
);
365 if (ep
== NIL
|| ep
->e_type
== NODE
)
367 if (ep
->e_flags
& (NEW
|EXTRACT
))
374 * report on a badly formed entry
377 badentry(struct entry
*ep
, char *msg
)
380 (void) fprintf(stderr
, gettext("bad entry: %s\n"), msg
);
381 (void) fprintf(stderr
, gettext("name: %s\n"), myname(ep
));
382 (void) fprintf(stderr
, gettext("parent name %s\n"),
383 myname(ep
->e_parent
));
384 if (ep
->e_sibling
!= NIL
)
385 (void) fprintf(stderr
, gettext("sibling name: %s\n"),
386 myname(ep
->e_sibling
));
387 if (ep
->e_entries
!= NIL
)
388 (void) fprintf(stderr
, gettext("next entry name: %s\n"),
389 myname(ep
->e_entries
));
390 if (ep
->e_links
!= NIL
)
391 (void) fprintf(stderr
, gettext("next link name: %s\n"),
392 myname(ep
->e_links
));
393 if (ep
->e_xattrs
!= NIL
)
394 (void) fprintf(stderr
, gettext("attribute root name: %s\n"),
395 myname(ep
->e_xattrs
));
396 if (ep
->e_next
!= NIL
)
397 (void) fprintf(stderr
, gettext("next hashchain name: %s\n"),
399 (void) fprintf(stderr
, gettext("entry type: %s\n"),
400 ep
->e_type
== NODE
? gettext("NODE") : gettext("LEAF"));
401 (void) fprintf(stderr
, gettext("inode number: %lu\n"), ep
->e_ino
);
402 panic(gettext("flags: %s\n"), flagvalues(ep
));
403 /* Our callers are expected to handle our returning. */
407 * Construct a string indicating the active flag bits of an entry.
410 flagvalues(struct entry
*ep
)
412 static char flagbuf
[BUFSIZ
];
414 (void) strlcpy(flagbuf
, gettext("|NIL"), sizeof (flagbuf
));
416 if (ep
->e_flags
& REMOVED
)
417 (void) strlcat(flagbuf
, gettext("|REMOVED"), sizeof (flagbuf
));
418 if (ep
->e_flags
& TMPNAME
)
419 (void) strlcat(flagbuf
, gettext("|TMPNAME"), sizeof (flagbuf
));
420 if (ep
->e_flags
& EXTRACT
)
421 (void) strlcat(flagbuf
, gettext("|EXTRACT"), sizeof (flagbuf
));
422 if (ep
->e_flags
& NEW
)
423 (void) strlcat(flagbuf
, gettext("|NEW"), sizeof (flagbuf
));
424 if (ep
->e_flags
& KEEP
)
425 (void) strlcat(flagbuf
, gettext("|KEEP"), sizeof (flagbuf
));
426 if (ep
->e_flags
& EXISTED
)
427 (void) strlcat(flagbuf
, gettext("|EXISTED"), sizeof (flagbuf
));
428 if (ep
->e_flags
& XATTR
)
429 (void) strlcat(flagbuf
, gettext("|XATTR"), sizeof (flagbuf
));
430 if (ep
->e_flags
& XATTRROOT
)
431 (void) strlcat(flagbuf
, gettext("|XATTRROOT"),
433 return (&flagbuf
[1]);
437 * Check to see if a name is on a dump tape.
440 dirlookup(char *name
)
445 if (ino
== 0 || BIT(ino
, dumpmap
) == 0)
446 (void) fprintf(stderr
, gettext("%s is not on volume\n"), name
);
454 reply(char *question
)
456 char *yesorno
= gettext("yn"); /* must be two characters, "yes" first */
460 (void) fprintf(stderr
, "%s? [%s] ", question
, yesorno
);
461 (void) fflush(stderr
);
463 while (c
!= '\n' && getc(terminal
) != '\n') {
464 if (ferror(terminal
)) {
465 (void) fprintf(stderr
, gettext(
466 "Error reading response\n"));
467 (void) fflush(stderr
);
475 } while (c
!= yesorno
[0] && c
!= yesorno
[1]);
482 * handle unexpected inconsistencies
485 * Note that a panic w/ EOF on the tty means all panics will return...
492 panic(const char *msg
, ...)
497 (void) vfprintf(stderr
, msg
, args
);
499 if (reply(gettext("abort")) == GOOD
) {
500 if (reply(gettext("dump core")) == GOOD
)
516 msg
= va_arg(args
, char *);
517 (void) vfprintf(stderr
, msg
, args
);
519 if (reply(gettext("abort")) == GOOD
) {
520 if (reply(gettext("dump core")) == GOOD
)
527 * Locale-specific version of ctime
532 static char buf
[256];
536 (void) strftime(buf
, sizeof (buf
), "%c\n", tm
);
541 statcmp(const struct stat
*left
, const struct stat
*right
)
545 if ((left
->st_dev
== right
->st_dev
) &&
546 (left
->st_ino
== right
->st_ino
) &&
547 (left
->st_mode
== right
->st_mode
) &&
548 (left
->st_nlink
== right
->st_nlink
) &&
549 (left
->st_uid
== right
->st_uid
) &&
550 (left
->st_gid
== right
->st_gid
) &&
551 (left
->st_rdev
== right
->st_rdev
) &&
552 (left
->st_ctim
.tv_sec
== right
->st_ctim
.tv_sec
) &&
553 (left
->st_ctim
.tv_nsec
== right
->st_ctim
.tv_nsec
) &&
554 (left
->st_mtim
.tv_sec
== right
->st_mtim
.tv_sec
) &&
555 (left
->st_mtim
.tv_nsec
== right
->st_mtim
.tv_nsec
) &&
556 (left
->st_blksize
== right
->st_blksize
) &&
557 (left
->st_blocks
== right
->st_blocks
)) {
565 * Safely open a file.
568 safe_open(int dfd
, const char *filename
, int mode
, int perms
)
570 static int init_syslog
= 1;
575 struct stat pre_stat
, pre_lstat
;
576 struct stat post_stat
, post_lstat
;
579 openlog(progname
, LOG_CONS
, LOG_DAEMON
);
584 * Don't want to be spoofed into trashing something we
585 * shouldn't, thus the following rigamarole. If it doesn't
586 * exist, we create it and proceed. Otherwise, require that
587 * what's there be a real file with no extraneous links and
588 * owned by whoever ran us.
590 * The silliness with using both lstat() and fstat() is to avoid
591 * race-condition games with someone replacing the file with a
592 * symlink after we've opened it. If there was an flstat(),
593 * we wouldn't need the fstat().
595 * The initial open with the hard-coded flags is ok even if we
596 * are intending to open only for reading. If it succeeds,
597 * then the file did not exist, and we'll synthesize an appropriate
598 * complaint below. Otherwise, it does exist, so we won't be
599 * truncating it with the open.
601 if ((fd
= openat(dfd
, filename
,
602 O_WRONLY
|O_CREAT
|O_TRUNC
|O_EXCL
|O_LARGEFILE
, perms
)) < 0) {
603 if (errno
== EEXIST
) {
604 if (fstatat(dfd
, filename
, &pre_lstat
,
605 AT_SYMLINK_NOFOLLOW
) < 0) {
612 if (fstatat(dfd
, filename
, &pre_stat
, 0) < 0) {
619 working_mode
= mode
& (O_WRONLY
|O_RDWR
|O_RDONLY
);
620 working_mode
|= O_LARGEFILE
;
622 if ((fd
= openat(dfd
, filename
, working_mode
)) < 0) {
623 if (errno
== ENOENT
) {
625 "Unexpected condition detected: %s used to exist, but doesn't any longer\n");
626 (void) fprintf(stderr
, errtext
,
628 syslog(LOG_WARNING
, errtext
, filename
);
634 if (fstatat(fd
, NULL
, &post_lstat
,
635 AT_SYMLINK_NOFOLLOW
) < 0) {
642 if (fstatat(fd
, NULL
, &post_stat
, 0) < 0) {
649 if (statcmp(&pre_lstat
, &post_lstat
) != 0) {
651 "Unexpected condition detected: %s's lstat(2) information changed\n");
652 (void) fprintf(stderr
, errtext
, filename
);
653 syslog(LOG_WARNING
, errtext
, filename
);
658 if (statcmp(&pre_stat
, &post_stat
) != 0) {
660 "Unexpected condition detected: %s's stat(2) information changed\n");
661 (void) fprintf(stderr
, errtext
, filename
);
662 syslog(LOG_WARNING
, errtext
, filename
);
668 * If inode, device, or type are wrong, bail out.
670 if ((!S_ISREG(post_lstat
.st_mode
) ||
671 (post_stat
.st_ino
!= post_lstat
.st_ino
) ||
672 (post_stat
.st_dev
!= post_lstat
.st_dev
))) {
674 "Unexpected condition detected: %s is not a regular file\n");
675 (void) fprintf(stderr
, errtext
, filename
);
676 syslog(LOG_WARNING
, errtext
, filename
);
683 * Bad link count implies someone's linked our
684 * target to something else, which we probably
687 if (post_lstat
.st_nlink
!= 1) {
689 "Unexpected condition detected: %s must have exactly one link\n");
690 (void) fprintf(stderr
, errtext
, filename
);
691 syslog(LOG_WARNING
, errtext
, filename
);
697 * Root might make a file, but non-root might
698 * need to open it. If the permissions let us
699 * get this far, then let it through.
701 if (post_lstat
.st_uid
!= getuid() &&
702 post_lstat
.st_uid
!= 0) {
704 "Unsupported condition detected: %s must be owned by uid %ld or 0\n");
705 (void) fprintf(stderr
, errtext
, filename
,
707 syslog(LOG_WARNING
, errtext
, filename
,
713 if (mode
& (O_WRONLY
|O_TRUNC
)) {
714 if (ftruncate(fd
, (off_t
)0) < 0) {
715 (void) fprintf(stderr
,
716 "ftruncate(%s): %s\n",
717 filename
, strerror(errno
));
724 * Didn't exist, but couldn't open it.
730 * If truncating open succeeded for a read-only open,
731 * bail out, as we really shouldn't have succeeded.
733 if (mode
& O_RDONLY
) {
734 /* Undo the O_CREAT */
735 (void) unlinkat(dfd
, filename
, 0);
736 (void) fprintf(stderr
, "open(%s): %s\n",
737 filename
, strerror(ENOENT
));
748 * STDIO version of safe_open. Equivalent to fopen64(...).
751 safe_fopen(const char *filename
, const char *smode
, int perms
)
757 * accepts only modes "r", "r+", and "w"
759 if (smode
[0] == 'r') {
760 if (smode
[1] == '\0') {
762 } else if ((smode
[1] == '+') && (smode
[2] == '\0')) {
765 } else if ((smode
[0] == 'w') && (smode
[1] == '\0')) {
768 (void) fprintf(stderr
,
769 gettext("internal error: safe_fopen: invalid mode `%s'\n"),
774 fd
= safe_open(AT_FDCWD
, filename
, bmode
, perms
);
777 * caller is expected to report error.
780 return (fdopen(fd
, smode
));
782 return ((FILE *)NULL
);
786 * Read the contents of a directory.
789 mkentry(char *name
, ino_t ino
, struct arglist
*ap
)
793 if (ap
->base
== NULL
) {
795 ap
->base
= (struct afile
*)calloc((unsigned)ap
->nent
,
796 sizeof (*(ap
->base
)));
797 if (ap
->base
== NULL
) {
798 (void) fprintf(stderr
,
799 gettext("%s: out of memory\n"), ap
->cmd
);
803 if (ap
->head
== NULL
)
804 ap
->head
= ap
->last
= ap
->base
;
807 fp
->fname
= savename(name
);
809 if (fp
== ap
->head
+ ap
->nent
) {
810 ap
->base
= (struct afile
*)realloc((char *)ap
->base
,
811 (size_t)(2 * ap
->nent
* (size_t)sizeof (*(ap
->base
))));
812 if (ap
->base
== NULL
) {
813 (void) fprintf(stderr
,
814 gettext("%s: out of memory\n"), ap
->cmd
);
818 fp
= ap
->head
+ ap
->nent
;
826 static int gmatch(wchar_t *, wchar_t *);
827 static int addg(struct direct
*, char *, char *, struct arglist
*);
834 * XXX This value is ASCII (but not language) dependent. In
835 * ASCII, it is the DEL character (unlikely to appear in paths).
836 * If you are compiling on an EBCDIC-based machine, re-define
837 * this (0x7f is '"') to be something like 0x7 (DEL). It's
838 * either this hack or re-write the expand() algorithm...
840 #define DELIMCHAR ((char)0x7f)
843 * Expand a file name.
844 * "as" is the pattern to expand.
845 * "rflg" non-zero indicates that we're recursing.
846 * "ap" is where to put the results of the expansion.
848 * Our caller guarantees that "as" is at least the string ".".
851 expand(char *as
, int rflg
, struct arglist
*ap
)
858 int sindex
, rindexa
, lindex
;
863 wchar_t w_fname
[PATH_MAX
+1];
864 wchar_t w_pname
[PATH_MAX
+1];
867 * check for meta chars
871 while (*cs
!= '*' && *cs
!= '?' && *cs
!= '[') {
877 } else if (*cs
== '/') {
885 } else if (*--cs
== '/') {
892 if ((dirp
= rst_opendir(s
)) != NULL
)
908 /* LINTED: result fits into an int */
909 sindex
= (int)(ap
->last
- ap
->head
);
910 (void) mbstowcs(w_pname
, cs
, PATH_MAX
);
911 w_pname
[PATH_MAX
- 1] = 0;
912 while ((dp
= rst_readdir(dirp
)) != NULL
&& dp
->d_ino
!= 0) {
913 if (!dflag
&& BIT(dp
->d_ino
, dumpmap
) == 0)
915 if ((*dp
->d_name
== '.' && *cs
!= '.'))
917 (void) mbstowcs(w_fname
, dp
->d_name
, PATH_MAX
);
918 w_fname
[PATH_MAX
- 1] = 0;
919 if (gmatch(w_fname
, w_pname
)) {
920 if (addg(dp
, s
, rescan
, ap
) < 0) {
929 /* LINTED: result fits into an int */
930 lindex
= (int)(ap
->last
- ap
->head
);
933 while (rindexa
< lindex
) {
934 size
= expand(ap
->head
[rindexa
].fname
,
944 /* LINTED: lint is confused about pointer size/type */
945 bcopy((void *)(&ap
->head
[lindex
]),
946 (void *)(&ap
->head
[sindex
]),
947 (size_t)((ap
->last
- &ap
->head
[rindexa
])) *
949 ap
->last
-= lindex
- sindex
;
955 while ((c
= *s
) != '\0')
956 *s
++ = (c
!= DELIMCHAR
? c
: '/');
962 * Check for a name match
965 gmatch(wchar_t *s
, wchar_t *p
)
967 long scc
; /* source character to text */
968 wchar_t c
; /* pattern character to match */
969 char ok
; /* [x-y] range match status */
970 long lc
; /* left character of [x-y] range */
980 return (ok
? gmatch(s
, p
) : 0);
981 } else if (c
== '-') {
984 * Check both ends must belong to
987 if (wcsetno(lc
) != wcsetno(rc
)) {
989 * If not, ignore the '-'
990 * operator and [x-y] is
991 * treated as if it were
996 if (scc
== (lc
= rc
))
998 } else if (lc
<= scc
&& scc
<= rc
)
1006 /* No closing bracket => failure */
1015 return (scc
? gmatch(s
, p
) : 0);
1033 * Construct a matched name.
1036 addg(struct direct
*dp
, char *as1
, char *as3
, struct arglist
*ap
)
1038 char *s1
, *s2
, *limit
;
1040 char buf
[MAXPATHLEN
+ 1];
1043 limit
= buf
+ sizeof (buf
) - 1;
1045 while ((c
= *s1
++) != '\0' && s2
< limit
) {
1046 if (c
== DELIMCHAR
) {
1050 /* LINTED narrowing cast */
1054 while ((*s2
= *s1
++) != '\0' && s2
< limit
)
1057 if (s1
!= NULL
&& s2
< limit
) {
1060 while ((*s2
++ = *++s1
) != '\0' && s2
< limit
) {
1062 /*LINTED [empty loop body]*/
1066 if (mkentry(buf
, dp
->d_ino
, ap
) == FAIL
)
1073 * Resolve a "complex" pathname (as generated by myname()) into
1074 * a file descriptor and a relative path. The file descriptor
1075 * will reference the hidden directory containing the attribute
1076 * named by the relative path. If the provided path is not
1077 * complex, the returned file descriptor will be AT_FDCWD and rpath
1080 * This function is intended to be used to transform a complex
1081 * pathname into a pair of handles that can be used to actually
1082 * manipulate the named file. Since extended attributes have
1083 * an independant name space, a file descriptor for a directory
1084 * in the attribute name space is necessary to actually manipulate
1085 * the attribute file (via the path-relative xxxat() system calls
1086 * or a call to fchdir()).
1088 * In the event of an error, the returned file descriptor will be
1089 * -1. It is expected that callers will either check for this
1090 * condition directly, or attempt to use the descriptor, fail, and
1091 * generate an appropriate context-specific error message.
1093 * This function is pretty much a no-op for "simple" (non-attribute)
1097 resolve(char *path
, int *fd
, char **rpath
)
1101 *fd
= tfd
= AT_FDCWD
;
1103 path
= *rpath
+ strlen(*rpath
) +1;
1104 while (*path
!= '\0' &&
1105 (*fd
= openat64(tfd
, *rpath
, O_RDONLY
)) > 0) {
1106 if (tfd
!= AT_FDCWD
) (void) close(tfd
);
1109 path
= *rpath
+ strlen(*rpath
) +1;
1111 if (*fd
== AT_FDCWD
)
1113 if (*fd
< 0 || (*fd
= openat64(tfd
, ".", O_RDONLY
|O_XATTR
)) < 0) {
1115 (void) fprintf(stderr
,
1116 gettext("Warning: cannot fully resolve %s: %s"),
1117 path
, strerror(saverr
));
1118 (void) fflush(stderr
);
1120 if (tfd
!= AT_FDCWD
) (void) close(tfd
);
1124 * Copy a complex pathname to another string. Note that the
1125 * length returned by this function is the number of characters
1126 * up to (but not including) the final NULL.
1129 complexcpy(char *s1
, char *s2
, int max
)
1134 while (len
++ < max
) {
1136 if (*s2
++ == '\0') {
1149 gettext("Warning: unterminated source string in complexcpy\n"));