4 * Copyright (C) 1998 by Erik Andersen <andersee@debian.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
21 * Permission has been granted to redistribute this code under the GPL.
38 #if defined (BB_CP) || defined (BB_MV)
40 * Return TRUE if a fileName is a directory.
41 * Nonexistant files return FALSE.
43 int isDirectory(const char *name)
47 if (stat(name, &statBuf) < 0)
49 if (S_ISDIR(statBuf.st_mode))
56 * Copy one file to another, while possibly preserving its modes, times,
57 * and modes. Returns TRUE if successful, or FALSE on a failure with an
58 * error message output. (Failure is not indicted if the attributes cannot
62 copyFile( const char *srcName, const char *destName,
63 int setModes, int followLinks)
70 struct stat srcStatBuf;
71 struct stat dstStatBuf;
74 if (followLinks == FALSE)
75 result = stat(srcName, &srcStatBuf);
77 result = lstat(srcName, &srcStatBuf);
83 if (followLinks == FALSE)
84 result = stat(destName, &dstStatBuf);
86 result = lstat(destName, &dstStatBuf);
88 dstStatBuf.st_ino = -1;
89 dstStatBuf.st_dev = -1;
92 if ((srcStatBuf.st_dev == dstStatBuf.st_dev) &&
93 (srcStatBuf.st_ino == dstStatBuf.st_ino)) {
94 fprintf(stderr, "Copying file \"%s\" to itself\n", srcName);
98 if (S_ISDIR(srcStatBuf.st_mode)) {
99 //fprintf(stderr, "copying directory %s to %s\n", srcName, destName);
100 /* Make sure the directory is writable */
101 if (mkdir(destName, 0777777 ^ umask(0))) {
105 } else if (S_ISLNK(srcStatBuf.st_mode)) {
109 //fprintf(stderr, "copying link %s to %s\n", srcName, destName);
110 link_val = (char *) alloca(PATH_MAX + 2);
111 link_size = readlink(srcName, link_val, PATH_MAX + 1);
116 link_val[link_size] = '\0';
117 link_size = symlink(link_val, destName);
118 if (link_size != 0) {
122 } else if (S_ISFIFO(srcStatBuf.st_mode)) {
123 //fprintf(stderr, "copying fifo %s to %s\n", srcName, destName);
124 if (mkfifo(destName, 644)) {
128 } else if (S_ISBLK(srcStatBuf.st_mode) || S_ISCHR(srcStatBuf.st_mode)
129 || S_ISSOCK (srcStatBuf.st_mode)) {
130 //fprintf(stderr, "copying soc, blk, or chr %s to %s\n", srcName, destName);
131 if (mknod(destName, srcStatBuf.st_mode, srcStatBuf.st_rdev)) {
135 } else if (S_ISREG(srcStatBuf.st_mode)) {
136 //fprintf(stderr, "copying regular file %s to %s\n", srcName, destName);
137 rfd = open(srcName, O_RDONLY);
143 wfd = creat(destName, srcStatBuf.st_mode);
150 while ((rcc = read(rfd, buf, sizeof(buf))) > 0) {
151 if (fullWrite(wfd, buf, rcc) < 0)
159 if (close(wfd) < 0) {
164 if (setModes == TRUE) {
165 //fprintf(stderr, "Setting permissions for %s\n", destName);
166 chmod(destName, srcStatBuf.st_mode);
167 if (followLinks == TRUE)
168 chown(destName, srcStatBuf.st_uid, srcStatBuf.st_gid);
170 lchown(destName, srcStatBuf.st_uid, srcStatBuf.st_gid);
172 times.actime = srcStatBuf.st_atime;
173 times.modtime = srcStatBuf.st_mtime;
175 utime(destName, ×);
193 * Build a path name from the specified directory name and file name.
194 * If the directory name is NULL, then the original fileName is returned.
195 * The built path is in a static area, and is overwritten for each call.
197 char *buildName(const char *dirName, const char *fileName)
200 static char buf[PATH_LEN];
202 if ((dirName == NULL) || (*dirName == '\0')) {
203 strcpy(buf, fileName);
207 cp = strrchr(fileName, '/');
212 strcpy(buf, dirName);
222 * Return the standard ls-like mode string from a file mode.
223 * This is static and so is overwritten on each call.
225 const char *modeString(int mode)
229 strcpy(buf, "----------");
232 * Fill in the file type.
252 * Now fill in the normal file permissions.
274 * Finally fill in magic stuff like suid and sticky text.
277 buf[3] = ((mode & S_IXUSR) ? 's' : 'S');
279 buf[6] = ((mode & S_IXGRP) ? 's' : 'S');
281 buf[9] = ((mode & S_IXOTH) ? 't' : 'T');
289 * Get the time string to be used for a file.
290 * This is down to the minute for new files, but only the date for old files.
291 * The string is returned from a static buffer, and so is overwritten for
294 const char *timeString(time_t timeVal)
302 str = ctime(&timeVal);
304 strcpy(buf, &str[4]);
307 if ((timeVal > now) || (timeVal < now - 365 * 24 * 60 * 60L)) {
308 strcpy(&buf[7], &str[20]);
317 * Routine to see if a text string is matched by a wildcard pattern.
318 * Returns TRUE if the text is matched, or FALSE if it is not matched
319 * or if the pattern is invalid.
320 * * matches zero or more characters
321 * ? matches a single character
322 * [abc] matches 'a', 'b' or 'c'
323 * \c quotes character c
324 * Adapted from code written by Ingo Wilken.
326 int match(const char *text, const char *pattern)
328 const char *retryPat;
329 const char *retryText;
336 while (*text || *pattern) {
348 while ((ch = *pattern++) != ']') {
364 /* fall into next case */
378 /* fall into next case */
405 * Write all of the supplied buffer out to a file.
406 * This does multiple writes as necessary.
407 * Returns the amount written, or -1 on an error.
409 int fullWrite(int fd, const char *buf, int len)
417 cc = write(fd, buf, len);
432 * Read all of the supplied buffer from a file.
433 * This does multiple reads as necessary.
434 * Returns the amount read, or -1 on an error.
435 * A short read is returned on an end of file.
437 int fullRead(int fd, char *buf, int len)
445 cc = read(fd, buf, len);
463 #if defined (BB_CHOWN) || defined (BB_CP) || defined (BB_FIND) || defined (BB_LS)
465 * Walk down all the directories under the specified
466 * location, and do something (something specified
467 * by the fileAction and dirAction function pointers).
470 recursiveAction(const char *fileName, int recurse, int followLinks,
471 int (*fileAction) (const char *fileName, struct stat* statbuf),
472 int (*dirAction) (const char *fileName, struct stat* statbuf))
478 if (followLinks == FALSE)
479 status = stat(fileName, &statbuf);
481 status = lstat(fileName, &statbuf);
488 if (recurse == FALSE) {
489 if (S_ISDIR(statbuf.st_mode)) {
490 if (dirAction != NULL)
491 return (dirAction(fileName, &statbuf));
497 if (S_ISDIR(statbuf.st_mode)) {
499 dir = opendir(fileName);
504 if (dirAction != NULL) {
505 status = dirAction(fileName, &statbuf);
506 if (status == FALSE) {
511 while ((next = readdir(dir)) != NULL) {
512 char nextFile[NAME_MAX];
513 if ((strcmp(next->d_name, "..") == 0)
514 || (strcmp(next->d_name, ".") == 0)) {
517 sprintf(nextFile, "%s/%s", fileName, next->d_name);
519 recursiveAction(nextFile, TRUE, followLinks, fileAction,
526 status = closedir(dir);
532 if (fileAction == NULL)
535 return (fileAction(fileName, &statbuf));
544 #if defined (BB_TAR) || defined (BB_MKDIR)
546 * Attempt to create the directories along the specified path, except for
547 * the final component. The mode is given for the final directory only,
548 * while all previous ones get default protections. Errors are not reported
549 * here, as failures to restore files can be reported later.
551 extern void createPath (const char *name, int mode)
559 cp = strchr (buf, '/');
563 cp = strchr (cp + 1, '/');
567 if (mkdir (buf, cp ? 0777 : mode) == 0)
568 printf ("Directory \"%s\" created\n", buf);
577 #if defined (BB_CHMOD_CHOWN_CHGRP) || defined (BB_MKDIR)
578 /* [ugoa]{+|-|=}[rwxstl] */
579 extern int parse_mode( const char* s, mode_t* theMode)
584 mode_t groups = S_ISVTX;
590 switch ( c = *s++ ) {
594 groups |= S_ISUID|S_IRWXU;
597 groups |= S_ISGID|S_IRWXG;
603 groups |= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
609 if ( groups == S_ISVTX ) /* The default is "all" */
610 groups |= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
613 if ( c >= '0' && c <= '7' && mode == 0 && groups == S_ISVTX ) {
615 or = strtol(--s, 0, 010);
624 while ( (c = *s++) != '\0' ) {
629 mode |= S_IRUSR|S_IRGRP|S_IROTH;
632 mode |= S_IWUSR|S_IWGRP|S_IWOTH;
635 mode |= S_IXUSR|S_IXGRP|S_IXOTH;
638 mode |= S_IXGRP|S_ISUID|S_ISGID;
656 and &= ~(mode & groups);
660 } while ( c == ',' );