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.
15 #pragma ident "%Z%%M% %I% %E% SMI"
22 /* LINTED: this file really is necessary */
27 * Insure that all the components of a pathname exist. Note that
28 * lookupname() and addentry() both expect complex names as
29 * input arguments, so a double NULL needs to be added to each name.
38 start
= strchr(name
, '/');
41 for (cp
= start
; *cp
!= '\0'; cp
++) {
47 ep
= lookupname(name
);
49 ep
= addentry(name
, psearch(name
), NODE
);
52 /* LINTED: result fits in a short */
53 ep
->e_flags
|= NEW
|KEEP
;
60 * Change a name to a unique temporary name.
63 mktempname(struct entry
*ep
)
67 if (ep
->e_flags
& TMPNAME
)
68 badentry(ep
, gettext("mktempname: called with TMPNAME"));
69 /* LINTED: result fits in a short */
70 ep
->e_flags
|= TMPNAME
;
71 newname
= savename(gentempname(ep
));
72 renameit(myname(ep
), newname
);
75 /* LINTED: savename guarantees strlen will fit */
76 ep
->e_namlen
= strlen(ep
->e_name
);
80 * Generate a temporary name for an entry.
83 gentempname(struct entry
*ep
)
85 static char name
[MAXPATHLEN
];
89 for (np
= lookupino(ep
->e_ino
); np
!= NIL
&& np
!= ep
; np
= np
->e_links
)
92 badentry(ep
, gettext("not on ino list"));
93 (void) snprintf(name
, sizeof (name
), "%s%ld%lu", TMPHDR
, i
, ep
->e_ino
);
98 * Rename a file or directory.
101 renameit(char *fp
, char *tp
)
105 char tobuf
[MAXPATHLEN
];
108 resolve(fp
, &fromfd
, &from
);
110 * The to pointer argument is assumed to be either a fully
111 * specified path (starting with "./") or a simple temporary
112 * file name (starting with TMPHDR). If passed a simple temp
113 * file name, we need to set up the descriptors explicitly.
115 if (strncmp(tp
, TMPHDR
, sizeof (TMPHDR
) - 1) == 0) {
117 if ((pathend
= strrchr(from
, '/')) != NULL
) {
118 strncpy(tobuf
, from
, pathend
- from
+ 1);
119 tobuf
[pathend
- from
+ 1] = NULL
;
120 strlcat(tobuf
, tp
, sizeof (tobuf
));
126 resolve(tp
, &tofd
, &to
);
127 if (renameat(fromfd
, from
, tofd
, to
) < 0) {
129 (void) fprintf(stderr
,
130 gettext("Warning: cannot rename %s to %s: %s\n"),
131 from
, to
, strerror(saverr
));
132 (void) fflush(stderr
);
134 vprintf(stdout
, gettext("rename %s to %s\n"), from
, to
);
136 if (fromfd
!= AT_FDCWD
) (void) close(fromfd
);
137 if (tofd
!= AT_FDCWD
) (void) close(tofd
);
141 * Create a new node (directory). Note that, because we have no
142 * mkdirat() function, fchdir() must be used set up the appropriate
143 * name space context prior to the call to mkdir() if we are
144 * operating in attribute space.
147 newnode(struct entry
*np
)
152 if (np
->e_type
!= NODE
)
153 badentry(np
, gettext("newnode: not a node"));
154 resolve(myname(np
), &dfd
, &cp
);
155 if (dfd
!= AT_FDCWD
) {
156 if (fchdir(dfd
) < 0) {
158 (void) fprintf(stderr
,
159 gettext("Warning: cannot create %s: %s"),
160 cp
, strerror(saverr
));
161 (void) fflush(stderr
);
166 if (mkdir(cp
, 0777) < 0) {
168 /* LINTED: result fits in a short */
169 np
->e_flags
|= EXISTED
;
170 (void) fprintf(stderr
, gettext("Warning: "));
171 (void) fflush(stderr
);
172 (void) fprintf(stderr
, "%s: %s\n", cp
, strerror(saverr
));
174 vprintf(stdout
, gettext("Make node %s\n"), cp
);
176 if (dfd
!= AT_FDCWD
) {
183 * Remove an old node (directory). See comment above on newnode()
184 * for explanation of fchdir() use below.
187 removenode(struct entry
*ep
)
192 if (ep
->e_type
!= NODE
)
193 badentry(ep
, gettext("removenode: not a node"));
194 if (ep
->e_entries
!= NIL
)
195 badentry(ep
, gettext("removenode: non-empty directory"));
196 /* LINTED: result fits in a short */
197 ep
->e_flags
|= REMOVED
;
198 /* LINTED: result fits in a short */
199 ep
->e_flags
&= ~TMPNAME
;
200 resolve(myname(ep
), &dfd
, &cp
);
201 if (dfd
!= AT_FDCWD
) {
202 if (fchdir(dfd
) < 0) {
204 (void) fprintf(stderr
,
205 gettext("Warning: cannot remove %s: %s"),
206 cp
, strerror(saverr
));
207 (void) fflush(stderr
);
212 if (rmdir(cp
) < 0) { /* NOTE: could use unlinkat (..,REMOVEDIR) */
214 (void) fprintf(stderr
, gettext("Warning: %s: %s\n"),
215 cp
, strerror(saverr
));
216 (void) fflush(stderr
);
218 vprintf(stdout
, gettext("Remove node %s\n"), cp
);
220 if (dfd
!= AT_FDCWD
) {
221 (void) fchdir(savepwd
);
230 removeleaf(struct entry
*ep
)
235 if (ep
->e_type
!= LEAF
)
236 badentry(ep
, gettext("removeleaf: not a leaf"));
237 /* LINTED: result fits in a short */
238 ep
->e_flags
|= REMOVED
;
239 /* LINTED: result fits in a short */
240 ep
->e_flags
&= ~TMPNAME
;
241 resolve(myname(ep
), &dfd
, &cp
);
242 if (unlinkat(dfd
, cp
, 0) < 0) {
244 (void) fprintf(stderr
, gettext("Warning: %s: %s\n"),
245 cp
, strerror(saverr
));
246 (void) fflush(stderr
);
248 vprintf(stdout
, gettext("Remove leaf %s\n"), cp
);
256 * This function assumes that the context has already been set
257 * for the link file to be created (i.e., we have "fchdir-ed"
258 * into attribute space already if this is an attribute link).
261 lf_linkit(char *existing
, char *new, int type
)
263 char linkbuf
[MAXPATHLEN
];
264 struct stat64 s1
[1], s2
[1];
268 resolve(existing
, &dfd
, &name
);
270 (void) fprintf(stderr
, gettext(
271 "Warning: cannot restore %s link %s->%s\n"),
272 (type
== SYMLINK
? "symbolic" : "hard"), new, existing
);
276 if (type
== SYMLINK
) {
277 if (symlink(name
, new) < 0) {
278 /* No trailing \0 from readlink(2) */
279 if (((l
= readlink(new, linkbuf
, sizeof (linkbuf
)))
281 (l
== strlen(name
)) &&
282 (strncmp(linkbuf
, name
, l
) == 0)) {
284 gettext("Symbolic link %s->%s ok\n"),
290 (void) fprintf(stderr
, gettext(
291 "Warning: cannot create symbolic link %s->%s: %s"),
292 new, name
, strerror(saverr
));
293 (void) fflush(stderr
);
298 } else if (type
== HARDLINK
) {
299 if (link(name
, new) < 0) {
301 if ((stat64(name
, s1
) == 0) &&
302 (stat64(new, s2
) == 0) &&
303 (s1
->st_dev
== s2
->st_dev
) &&
304 (s1
->st_ino
== s2
->st_ino
)) {
306 gettext("Hard link %s->%s ok\n"),
311 (void) fprintf(stderr
, gettext(
312 "Warning: cannot create hard link %s->%s: %s\n"),
313 new, name
, strerror(saverr
));
314 (void) fflush(stderr
);
320 panic(gettext("%s: unknown type %d\n"), "linkit", type
);
326 vprintf(stdout
, gettext("Create symbolic link %s->%s\n"),
329 vprintf(stdout
, gettext("Create hard link %s->%s\n"),
332 if (dfd
!= AT_FDCWD
) {
339 * Find lowest-numbered inode (above "start") that needs to be extracted.
340 * Caller knows that a return value of maxino means there's nothing left.
343 lowerbnd(ino_t start
)
347 for (; start
< maxino
; start
++) {
348 ep
= lookupino(start
);
349 if (ep
== NIL
|| ep
->e_type
== NODE
)
351 if (ep
->e_flags
& (NEW
|EXTRACT
))
358 * Find highest-numbered inode (below "start") that needs to be extracted.
361 upperbnd(ino_t start
)
365 for (; start
> ROOTINO
; start
--) {
366 ep
= lookupino(start
);
367 if (ep
== NIL
|| ep
->e_type
== NODE
)
369 if (ep
->e_flags
& (NEW
|EXTRACT
))
376 * report on a badly formed entry
379 badentry(struct entry
*ep
, char *msg
)
382 (void) fprintf(stderr
, gettext("bad entry: %s\n"), msg
);
383 (void) fprintf(stderr
, gettext("name: %s\n"), myname(ep
));
384 (void) fprintf(stderr
, gettext("parent name %s\n"),
385 myname(ep
->e_parent
));
386 if (ep
->e_sibling
!= NIL
)
387 (void) fprintf(stderr
, gettext("sibling name: %s\n"),
388 myname(ep
->e_sibling
));
389 if (ep
->e_entries
!= NIL
)
390 (void) fprintf(stderr
, gettext("next entry name: %s\n"),
391 myname(ep
->e_entries
));
392 if (ep
->e_links
!= NIL
)
393 (void) fprintf(stderr
, gettext("next link name: %s\n"),
394 myname(ep
->e_links
));
395 if (ep
->e_xattrs
!= NIL
)
396 (void) fprintf(stderr
, gettext("attribute root name: %s\n"),
397 myname(ep
->e_xattrs
));
398 if (ep
->e_next
!= NIL
)
399 (void) fprintf(stderr
, gettext("next hashchain name: %s\n"),
401 (void) fprintf(stderr
, gettext("entry type: %s\n"),
402 ep
->e_type
== NODE
? gettext("NODE") : gettext("LEAF"));
403 (void) fprintf(stderr
, gettext("inode number: %lu\n"), ep
->e_ino
);
404 panic(gettext("flags: %s\n"), flagvalues(ep
));
405 /* Our callers are expected to handle our returning. */
409 * Construct a string indicating the active flag bits of an entry.
412 flagvalues(struct entry
*ep
)
414 static char flagbuf
[BUFSIZ
];
416 (void) strlcpy(flagbuf
, gettext("|NIL"), sizeof (flagbuf
));
418 if (ep
->e_flags
& REMOVED
)
419 (void) strlcat(flagbuf
, gettext("|REMOVED"), sizeof (flagbuf
));
420 if (ep
->e_flags
& TMPNAME
)
421 (void) strlcat(flagbuf
, gettext("|TMPNAME"), sizeof (flagbuf
));
422 if (ep
->e_flags
& EXTRACT
)
423 (void) strlcat(flagbuf
, gettext("|EXTRACT"), sizeof (flagbuf
));
424 if (ep
->e_flags
& NEW
)
425 (void) strlcat(flagbuf
, gettext("|NEW"), sizeof (flagbuf
));
426 if (ep
->e_flags
& KEEP
)
427 (void) strlcat(flagbuf
, gettext("|KEEP"), sizeof (flagbuf
));
428 if (ep
->e_flags
& EXISTED
)
429 (void) strlcat(flagbuf
, gettext("|EXISTED"), sizeof (flagbuf
));
430 if (ep
->e_flags
& XATTR
)
431 (void) strlcat(flagbuf
, gettext("|XATTR"), sizeof (flagbuf
));
432 if (ep
->e_flags
& XATTRROOT
)
433 (void) strlcat(flagbuf
, gettext("|XATTRROOT"),
435 return (&flagbuf
[1]);
439 * Check to see if a name is on a dump tape.
442 dirlookup(char *name
)
447 if (ino
== 0 || BIT(ino
, dumpmap
) == 0)
448 (void) fprintf(stderr
, gettext("%s is not on volume\n"), name
);
456 reply(char *question
)
458 char *yesorno
= gettext("yn"); /* must be two characters, "yes" first */
462 (void) fprintf(stderr
, "%s? [%s] ", question
, yesorno
);
463 (void) fflush(stderr
);
465 while (c
!= '\n' && getc(terminal
) != '\n') {
466 if (ferror(terminal
)) {
467 (void) fprintf(stderr
, gettext(
468 "Error reading response\n"));
469 (void) fflush(stderr
);
477 } while (c
!= yesorno
[0] && c
!= yesorno
[1]);
484 * handle unexpected inconsistencies
487 * Note that a panic w/ EOF on the tty means all panics will return...
494 panic(const char *msg
, ...)
499 (void) vfprintf(stderr
, msg
, args
);
501 if (reply(gettext("abort")) == GOOD
) {
502 if (reply(gettext("dump core")) == GOOD
)
518 msg
= va_arg(args
, char *);
519 (void) vfprintf(stderr
, msg
, args
);
521 if (reply(gettext("abort")) == GOOD
) {
522 if (reply(gettext("dump core")) == GOOD
)
529 * Locale-specific version of ctime
534 static char buf
[256];
538 (void) strftime(buf
, sizeof (buf
), "%c\n", tm
);
543 statcmp(const struct stat
*left
, const struct stat
*right
)
547 if ((left
->st_dev
== right
->st_dev
) &&
548 (left
->st_ino
== right
->st_ino
) &&
549 (left
->st_mode
== right
->st_mode
) &&
550 (left
->st_nlink
== right
->st_nlink
) &&
551 (left
->st_uid
== right
->st_uid
) &&
552 (left
->st_gid
== right
->st_gid
) &&
553 (left
->st_rdev
== right
->st_rdev
) &&
554 (left
->st_ctim
.tv_sec
== right
->st_ctim
.tv_sec
) &&
555 (left
->st_ctim
.tv_nsec
== right
->st_ctim
.tv_nsec
) &&
556 (left
->st_mtim
.tv_sec
== right
->st_mtim
.tv_sec
) &&
557 (left
->st_mtim
.tv_nsec
== right
->st_mtim
.tv_nsec
) &&
558 (left
->st_blksize
== right
->st_blksize
) &&
559 (left
->st_blocks
== right
->st_blocks
)) {
567 * Safely open a file.
570 safe_open(int dfd
, const char *filename
, int mode
, int perms
)
572 static int init_syslog
= 1;
577 struct stat pre_stat
, pre_lstat
;
578 struct stat post_stat
, post_lstat
;
581 openlog(progname
, LOG_CONS
, LOG_DAEMON
);
586 * Don't want to be spoofed into trashing something we
587 * shouldn't, thus the following rigamarole. If it doesn't
588 * exist, we create it and proceed. Otherwise, require that
589 * what's there be a real file with no extraneous links and
590 * owned by whoever ran us.
592 * The silliness with using both lstat() and fstat() is to avoid
593 * race-condition games with someone replacing the file with a
594 * symlink after we've opened it. If there was an flstat(),
595 * we wouldn't need the fstat().
597 * The initial open with the hard-coded flags is ok even if we
598 * are intending to open only for reading. If it succeeds,
599 * then the file did not exist, and we'll synthesize an appropriate
600 * complaint below. Otherwise, it does exist, so we won't be
601 * truncating it with the open.
603 if ((fd
= openat(dfd
, filename
,
604 O_WRONLY
|O_CREAT
|O_TRUNC
|O_EXCL
|O_LARGEFILE
, perms
)) < 0) {
605 if (errno
== EEXIST
) {
606 if (fstatat(dfd
, filename
, &pre_lstat
,
607 AT_SYMLINK_NOFOLLOW
) < 0) {
614 if (fstatat(dfd
, filename
, &pre_stat
, 0) < 0) {
621 working_mode
= mode
& (O_WRONLY
|O_RDWR
|O_RDONLY
);
622 working_mode
|= O_LARGEFILE
;
624 if ((fd
= openat(dfd
, filename
, working_mode
)) < 0) {
625 if (errno
== ENOENT
) {
627 "Unexpected condition detected: %s used to exist, but doesn't any longer\n");
628 (void) fprintf(stderr
, errtext
,
630 syslog(LOG_WARNING
, errtext
, filename
);
636 if (fstatat(fd
, NULL
, &post_lstat
,
637 AT_SYMLINK_NOFOLLOW
) < 0) {
644 if (fstatat(fd
, NULL
, &post_stat
, 0) < 0) {
651 if (statcmp(&pre_lstat
, &post_lstat
) != 0) {
653 "Unexpected condition detected: %s's lstat(2) information changed\n");
654 (void) fprintf(stderr
, errtext
, filename
);
655 syslog(LOG_WARNING
, errtext
, filename
);
660 if (statcmp(&pre_stat
, &post_stat
) != 0) {
662 "Unexpected condition detected: %s's stat(2) information changed\n");
663 (void) fprintf(stderr
, errtext
, filename
);
664 syslog(LOG_WARNING
, errtext
, filename
);
670 * If inode, device, or type are wrong, bail out.
672 if ((!S_ISREG(post_lstat
.st_mode
) ||
673 (post_stat
.st_ino
!= post_lstat
.st_ino
) ||
674 (post_stat
.st_dev
!= post_lstat
.st_dev
))) {
676 "Unexpected condition detected: %s is not a regular file\n");
677 (void) fprintf(stderr
, errtext
, filename
);
678 syslog(LOG_WARNING
, errtext
, filename
);
685 * Bad link count implies someone's linked our
686 * target to something else, which we probably
689 if (post_lstat
.st_nlink
!= 1) {
691 "Unexpected condition detected: %s must have exactly one link\n");
692 (void) fprintf(stderr
, errtext
, filename
);
693 syslog(LOG_WARNING
, errtext
, filename
);
699 * Root might make a file, but non-root might
700 * need to open it. If the permissions let us
701 * get this far, then let it through.
703 if (post_lstat
.st_uid
!= getuid() &&
704 post_lstat
.st_uid
!= 0) {
706 "Unsupported condition detected: %s must be owned by uid %ld or 0\n");
707 (void) fprintf(stderr
, errtext
, filename
,
709 syslog(LOG_WARNING
, errtext
, filename
,
715 if (mode
& (O_WRONLY
|O_TRUNC
)) {
716 if (ftruncate(fd
, (off_t
)0) < 0) {
717 (void) fprintf(stderr
,
718 "ftruncate(%s): %s\n",
719 filename
, strerror(errno
));
726 * Didn't exist, but couldn't open it.
732 * If truncating open succeeded for a read-only open,
733 * bail out, as we really shouldn't have succeeded.
735 if (mode
& O_RDONLY
) {
736 /* Undo the O_CREAT */
737 (void) unlinkat(dfd
, filename
, 0);
738 (void) fprintf(stderr
, "open(%s): %s\n",
739 filename
, strerror(ENOENT
));
750 * STDIO version of safe_open. Equivalent to fopen64(...).
753 safe_fopen(const char *filename
, const char *smode
, int perms
)
759 * accepts only modes "r", "r+", and "w"
761 if (smode
[0] == 'r') {
762 if (smode
[1] == '\0') {
764 } else if ((smode
[1] == '+') && (smode
[2] == '\0')) {
767 } else if ((smode
[0] == 'w') && (smode
[1] == '\0')) {
770 (void) fprintf(stderr
,
771 gettext("internal error: safe_fopen: invalid mode `%s'\n"),
776 fd
= safe_open(AT_FDCWD
, filename
, bmode
, perms
);
779 * caller is expected to report error.
782 return (fdopen(fd
, smode
));
784 return ((FILE *)NULL
);
788 * Read the contents of a directory.
791 mkentry(char *name
, ino_t ino
, struct arglist
*ap
)
795 if (ap
->base
== NULL
) {
797 ap
->base
= (struct afile
*)calloc((unsigned)ap
->nent
,
798 sizeof (*(ap
->base
)));
799 if (ap
->base
== NULL
) {
800 (void) fprintf(stderr
,
801 gettext("%s: out of memory\n"), ap
->cmd
);
805 if (ap
->head
== NULL
)
806 ap
->head
= ap
->last
= ap
->base
;
809 fp
->fname
= savename(name
);
811 if (fp
== ap
->head
+ ap
->nent
) {
812 ap
->base
= (struct afile
*)realloc((char *)ap
->base
,
813 (size_t)(2 * ap
->nent
* (size_t)sizeof (*(ap
->base
))));
814 if (ap
->base
== NULL
) {
815 (void) fprintf(stderr
,
816 gettext("%s: out of memory\n"), ap
->cmd
);
820 fp
= ap
->head
+ ap
->nent
;
828 static int gmatch(wchar_t *, wchar_t *);
829 static int addg(struct direct
*, char *, char *, struct arglist
*);
836 * XXX This value is ASCII (but not language) dependent. In
837 * ASCII, it is the DEL character (unlikely to appear in paths).
838 * If you are compiling on an EBCDIC-based machine, re-define
839 * this (0x7f is '"') to be something like 0x7 (DEL). It's
840 * either this hack or re-write the expand() algorithm...
842 #define DELIMCHAR ((char)0x7f)
845 * Expand a file name.
846 * "as" is the pattern to expand.
847 * "rflg" non-zero indicates that we're recursing.
848 * "ap" is where to put the results of the expansion.
850 * Our caller guarantees that "as" is at least the string ".".
853 expand(char *as
, int rflg
, struct arglist
*ap
)
860 int sindex
, rindexa
, lindex
;
865 wchar_t w_fname
[PATH_MAX
+1];
866 wchar_t w_pname
[PATH_MAX
+1];
869 * check for meta chars
873 while (*cs
!= '*' && *cs
!= '?' && *cs
!= '[') {
879 } else if (*cs
== '/') {
887 } else if (*--cs
== '/') {
894 if ((dirp
= rst_opendir(s
)) != NULL
)
910 /* LINTED: result fits into an int */
911 sindex
= (int)(ap
->last
- ap
->head
);
912 (void) mbstowcs(w_pname
, cs
, PATH_MAX
);
913 w_pname
[PATH_MAX
- 1] = 0;
914 while ((dp
= rst_readdir(dirp
)) != NULL
&& dp
->d_ino
!= 0) {
915 if (!dflag
&& BIT(dp
->d_ino
, dumpmap
) == 0)
917 if ((*dp
->d_name
== '.' && *cs
!= '.'))
919 (void) mbstowcs(w_fname
, dp
->d_name
, PATH_MAX
);
920 w_fname
[PATH_MAX
- 1] = 0;
921 if (gmatch(w_fname
, w_pname
)) {
922 if (addg(dp
, s
, rescan
, ap
) < 0) {
931 /* LINTED: result fits into an int */
932 lindex
= (int)(ap
->last
- ap
->head
);
935 while (rindexa
< lindex
) {
936 size
= expand(ap
->head
[rindexa
].fname
,
946 /* LINTED: lint is confused about pointer size/type */
947 bcopy((void *)(&ap
->head
[lindex
]),
948 (void *)(&ap
->head
[sindex
]),
949 (size_t)((ap
->last
- &ap
->head
[rindexa
])) *
951 ap
->last
-= lindex
- sindex
;
957 while ((c
= *s
) != '\0')
958 *s
++ = (c
!= DELIMCHAR
? c
: '/');
964 * Check for a name match
967 gmatch(wchar_t *s
, wchar_t *p
)
969 long scc
; /* source character to text */
970 wchar_t c
; /* pattern character to match */
971 char ok
; /* [x-y] range match status */
972 long lc
; /* left character of [x-y] range */
982 return (ok
? gmatch(s
, p
) : 0);
983 } else if (c
== '-') {
986 * Check both ends must belong to
989 if (wcsetno(lc
) != wcsetno(rc
)) {
991 * If not, ignore the '-'
992 * operator and [x-y] is
993 * treated as if it were
998 if (scc
== (lc
= rc
))
1000 } else if (lc
<= scc
&& scc
<= rc
)
1008 /* No closing bracket => failure */
1017 return (scc
? gmatch(s
, p
) : 0);
1035 * Construct a matched name.
1038 addg(struct direct
*dp
, char *as1
, char *as3
, struct arglist
*ap
)
1040 char *s1
, *s2
, *limit
;
1042 char buf
[MAXPATHLEN
+ 1];
1045 limit
= buf
+ sizeof (buf
) - 1;
1047 while ((c
= *s1
++) != '\0' && s2
< limit
) {
1048 if (c
== DELIMCHAR
) {
1052 /* LINTED narrowing cast */
1056 while ((*s2
= *s1
++) != '\0' && s2
< limit
)
1059 if (s1
!= NULL
&& s2
< limit
) {
1062 while ((*s2
++ = *++s1
) != '\0' && s2
< limit
) {
1064 /*LINTED [empty loop body]*/
1068 if (mkentry(buf
, dp
->d_ino
, ap
) == FAIL
)
1075 * Resolve a "complex" pathname (as generated by myname()) into
1076 * a file descriptor and a relative path. The file descriptor
1077 * will reference the hidden directory containing the attribute
1078 * named by the relative path. If the provided path is not
1079 * complex, the returned file descriptor will be AT_FDCWD and rpath
1082 * This function is intended to be used to transform a complex
1083 * pathname into a pair of handles that can be used to actually
1084 * manipulate the named file. Since extended attributes have
1085 * an independant name space, a file descriptor for a directory
1086 * in the attribute name space is necessary to actually manipulate
1087 * the attribute file (via the path-relative xxxat() system calls
1088 * or a call to fchdir()).
1090 * In the event of an error, the returned file descriptor will be
1091 * -1. It is expected that callers will either check for this
1092 * condition directly, or attempt to use the descriptor, fail, and
1093 * generate an appropriate context-specific error message.
1095 * This function is pretty much a no-op for "simple" (non-attribute)
1099 resolve(char *path
, int *fd
, char **rpath
)
1103 *fd
= tfd
= AT_FDCWD
;
1105 path
= *rpath
+ strlen(*rpath
) +1;
1106 while (*path
!= '\0' &&
1107 (*fd
= openat64(tfd
, *rpath
, O_RDONLY
)) > 0) {
1108 if (tfd
!= AT_FDCWD
) (void) close(tfd
);
1111 path
= *rpath
+ strlen(*rpath
) +1;
1113 if (*fd
== AT_FDCWD
)
1115 if (*fd
< 0 || (*fd
= openat64(tfd
, ".", O_RDONLY
|O_XATTR
)) < 0) {
1117 (void) fprintf(stderr
,
1118 gettext("Warning: cannot fully resolve %s: %s"),
1119 path
, strerror(saverr
));
1120 (void) fflush(stderr
);
1122 if (tfd
!= AT_FDCWD
) (void) close(tfd
);
1126 * Copy a complex pathname to another string. Note that the
1127 * length returned by this function is the number of characters
1128 * up to (but not including) the final NULL.
1131 complexcpy(char *s1
, char *s2
, int max
)
1136 while (len
++ < max
) {
1138 if (*s2
++ == '\0') {
1151 gettext("Warning: unterminated source string in complexcpy\n"));