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)
50 return S_ISDIR(statBuf.st_mode);
55 * Copy one file to another, while possibly preserving its modes, times,
56 * and modes. Returns TRUE if successful, or FALSE on a failure with an
57 * error message output. (Failure is not indicted if the attributes cannot
61 copyFile( const char *srcName, const char *destName,
62 int setModes, int followLinks)
69 struct stat srcStatBuf;
70 struct stat dstStatBuf;
73 if (followLinks == FALSE)
74 result = stat(srcName, &srcStatBuf);
76 result = lstat(srcName, &srcStatBuf);
82 if (followLinks == FALSE)
83 result = stat(destName, &dstStatBuf);
85 result = lstat(destName, &dstStatBuf);
87 dstStatBuf.st_ino = -1;
88 dstStatBuf.st_dev = -1;
91 if ((srcStatBuf.st_dev == dstStatBuf.st_dev) &&
92 (srcStatBuf.st_ino == dstStatBuf.st_ino)) {
93 fprintf(stderr, "Copying file \"%s\" to itself\n", srcName);
97 if (S_ISDIR(srcStatBuf.st_mode)) {
98 //fprintf(stderr, "copying directory %s to %s\n", srcName, destName);
99 /* Make sure the directory is writable */
100 if (mkdir(destName, 0777777 ^ umask(0))) {
104 } else if (S_ISLNK(srcStatBuf.st_mode)) {
108 //fprintf(stderr, "copying link %s to %s\n", srcName, destName);
109 link_val = (char *) alloca(PATH_MAX + 2);
110 link_size = readlink(srcName, link_val, PATH_MAX + 1);
115 link_val[link_size] = '\0';
116 link_size = symlink(link_val, destName);
117 if (link_size != 0) {
121 } else if (S_ISFIFO(srcStatBuf.st_mode)) {
122 //fprintf(stderr, "copying fifo %s to %s\n", srcName, destName);
123 if (mkfifo(destName, 644)) {
127 } else if (S_ISBLK(srcStatBuf.st_mode) || S_ISCHR(srcStatBuf.st_mode)
128 || S_ISSOCK (srcStatBuf.st_mode)) {
129 //fprintf(stderr, "copying soc, blk, or chr %s to %s\n", srcName, destName);
130 if (mknod(destName, srcStatBuf.st_mode, srcStatBuf.st_rdev)) {
134 } else if (S_ISREG(srcStatBuf.st_mode)) {
135 //fprintf(stderr, "copying regular file %s to %s\n", srcName, destName);
136 rfd = open(srcName, O_RDONLY);
142 wfd = creat(destName, srcStatBuf.st_mode);
149 while ((rcc = read(rfd, buf, sizeof(buf))) > 0) {
150 if (fullWrite(wfd, buf, rcc) < 0)
158 if (close(wfd) < 0) {
163 if (setModes == TRUE) {
164 //fprintf(stderr, "Setting permissions for %s\n", destName);
165 chmod(destName, srcStatBuf.st_mode);
166 if (followLinks == TRUE)
167 chown(destName, srcStatBuf.st_uid, srcStatBuf.st_gid);
169 lchown(destName, srcStatBuf.st_uid, srcStatBuf.st_gid);
171 times.actime = srcStatBuf.st_atime;
172 times.modtime = srcStatBuf.st_mtime;
174 utime(destName, ×);
192 * Build a path name from the specified directory name and file name.
193 * If the directory name is NULL, then the original fileName is returned.
194 * The built path is in a static area, and is overwritten for each call.
196 char *buildName(const char *dirName, const char *fileName)
199 static char buf[PATH_LEN];
201 if ((dirName == NULL) || (*dirName == '\0')) {
202 strcpy(buf, fileName);
206 cp = strrchr(fileName, '/');
211 strcpy(buf, dirName);
221 * Return the standard ls-like mode string from a file mode.
222 * This is static and so is overwritten on each call.
224 const char *modeString(int mode)
228 strcpy(buf, "----------");
231 * Fill in the file type.
251 * Now fill in the normal file permissions.
273 * Finally fill in magic stuff like suid and sticky text.
276 buf[3] = ((mode & S_IXUSR) ? 's' : 'S');
278 buf[6] = ((mode & S_IXGRP) ? 's' : 'S');
280 buf[9] = ((mode & S_IXOTH) ? 't' : 'T');
288 * Get the time string to be used for a file.
289 * This is down to the minute for new files, but only the date for old files.
290 * The string is returned from a static buffer, and so is overwritten for
293 const char *timeString(time_t timeVal)
301 str = ctime(&timeVal);
303 strcpy(buf, &str[4]);
306 if ((timeVal > now) || (timeVal < now - 365 * 24 * 60 * 60L)) {
307 strcpy(&buf[7], &str[20]);
316 * Routine to see if a text string is matched by a wildcard pattern.
317 * Returns TRUE if the text is matched, or FALSE if it is not matched
318 * or if the pattern is invalid.
319 * * matches zero or more characters
320 * ? matches a single character
321 * [abc] matches 'a', 'b' or 'c'
322 * \c quotes character c
323 * Adapted from code written by Ingo Wilken.
325 int match(const char *text, const char *pattern)
327 const char *retryPat;
328 const char *retryText;
335 while (*text || *pattern) {
347 while ((ch = *pattern++) != ']') {
363 /* fall into next case */
377 /* fall into next case */
404 * Write all of the supplied buffer out to a file.
405 * This does multiple writes as necessary.
406 * Returns the amount written, or -1 on an error.
408 int fullWrite(int fd, const char *buf, int len)
416 cc = write(fd, buf, len);
431 * Read all of the supplied buffer from a file.
432 * This does multiple reads as necessary.
433 * Returns the amount read, or -1 on an error.
434 * A short read is returned on an end of file.
436 int fullRead(int fd, char *buf, int len)
444 cc = read(fd, buf, len);
462 #if defined (BB_CHOWN) || defined (BB_CP) || defined (BB_FIND) || defined (BB_LS)
464 * Walk down all the directories under the specified
465 * location, and do something (something specified
466 * by the fileAction and dirAction function pointers).
469 recursiveAction(const char *fileName, int recurse, int followLinks,
470 int (*fileAction) (const char *fileName),
471 int (*dirAction) (const char *fileName))
477 if (followLinks == FALSE)
478 status = stat(fileName, &statbuf);
480 status = lstat(fileName, &statbuf);
487 if (recurse == FALSE) {
488 if (S_ISDIR(statbuf.st_mode)) {
489 if (dirAction != NULL)
490 return (dirAction(fileName));
496 if (S_ISDIR(statbuf.st_mode)) {
498 dir = opendir(fileName);
503 if (dirAction != NULL) {
504 status = dirAction(fileName);
505 if (status == FALSE) {
510 while ((next = readdir(dir)) != NULL) {
511 char nextFile[NAME_MAX];
512 if ((strcmp(next->d_name, "..") == 0)
513 || (strcmp(next->d_name, ".") == 0)) {
516 sprintf(nextFile, "%s/%s", fileName, next->d_name);
518 recursiveAction(nextFile, TRUE, followLinks, fileAction,
525 status = closedir(dir);
531 if (fileAction == NULL)
534 return (fileAction(fileName));
543 #if defined (BB_TAR) || defined (BB_MKDIR)
545 * Attempt to create the directories along the specified path, except for
546 * the final component. The mode is given for the final directory only,
547 * while all previous ones get default protections. Errors are not reported
548 * here, as failures to restore files can be reported later.
550 extern void createPath (const char *name, int mode)
558 cp = strchr (buf, '/');
562 cp = strchr (cp + 1, '/');
566 if (mkdir (buf, cp ? 0777 : mode) == 0)
567 printf ("Directory \"%s\" created\n", buf);
576 #if defined (BB_CHMOD_CHOWN_CHGRP) || defined (BB_MKDIR)
577 /* [ugoa]{+|-|=}[rwxstl] */
578 extern int parse_mode( const char* s, mode_t* theMode)
583 mode_t groups = S_ISVTX;
589 switch ( c = *s++ ) {
593 groups |= S_ISUID|S_IRWXU;
596 groups |= S_ISGID|S_IRWXG;
602 groups |= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
608 if ( groups == S_ISVTX ) /* The default is "all" */
609 groups |= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
612 if ( c >= '0' && c <= '7' && mode == 0 && groups == S_ISVTX ) {
614 or = strtol(--s, 0, 010);
623 while ( (c = *s++) != '\0' ) {
628 mode |= S_IRUSR|S_IRGRP|S_IROTH;
631 mode |= S_IWUSR|S_IWGRP|S_IWOTH;
634 mode |= S_IXUSR|S_IXGRP|S_IXOTH;
637 mode |= S_IXGRP|S_ISUID|S_ISGID;
655 and &= ~(mode & groups);
659 } while ( c == ',' );