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.
30 join_paths(char * buffer, const char * a, const char * b)
36 memcpy(buffer, a, length);
39 if ( length > 0 && buffer[length - 1] != '/' )
40 buffer[length++] = '/';
43 strcpy(&buffer[length], b);
55 static CHUNK * chunkList;
58 name_and_error(const char * name)
60 fprintf(stderr, "%s: %s\n", name, strerror(errno));
66 * Return the standard ls-like mode string from a file mode.
67 * This is static and so is overwritten on each call.
74 strcpy(buf, "----------");
77 * Fill in the file type.
97 * Now fill in the normal file permissions.
119 * Finally fill in magic stuff like suid and sticky text.
122 buf[3] = ((mode & S_IXUSR) ? 's' : 'S');
124 buf[6] = ((mode & S_IXGRP) ? 's' : 'S');
126 buf[9] = ((mode & S_IXOTH) ? 't' : 'T');
133 * Get the time string to be used for a file.
134 * This is down to the minute for new files, but only the date for old files.
135 * The string is returned from a static buffer, and so is overwritten for
139 timeString(time_t timeVal)
147 str = ctime(&timeVal);
149 strcpy(buf, &str[4]);
152 if ((timeVal > now) || (timeVal < now - 365*24*60*60L))
154 strcpy(&buf[7], &str[20]);
163 * Return TRUE if a fileName is a directory.
164 * Nonexistant files return FALSE.
167 isDirectory(const char * name)
171 if (stat(name, &statBuf) < 0)
174 return S_ISDIR(statBuf.st_mode);
179 * Return TRUE if a filename is a block or character device.
180 * Nonexistant files return FALSE.
183 isDevice(const char * name)
187 if (stat(name, &statBuf) < 0)
190 return S_ISBLK(statBuf.st_mode) || S_ISCHR(statBuf.st_mode);
195 * Copy one file to another, while possibly preserving its modes, times,
196 * and modes. Returns TRUE if successful, or FALSE on a failure with an
197 * error message output. (Failure is not indicted if the attributes cannot
202 const char * srcName,
203 const char * destName,
211 struct stat statBuf1;
212 struct stat statBuf2;
213 struct utimbuf times;
215 if (stat(srcName, &statBuf1) < 0)
222 if (stat(destName, &statBuf2) < 0)
224 statBuf2.st_ino = -1;
225 statBuf2.st_dev = -1;
228 if ((statBuf1.st_dev == statBuf2.st_dev) &&
229 (statBuf1.st_ino == statBuf2.st_ino))
231 fprintf(stderr, "Copying file \"%s\" to itself\n", srcName);
236 rfd = open(srcName, O_RDONLY);
245 wfd = creat(destName, statBuf1.st_mode);
255 while ((rcc = read(rfd, buf, sizeof(buf))) > 0)
257 if (fullWrite(wfd, buf, rcc) < 0)
278 (void) chmod(destName, statBuf1.st_mode);
280 (void) chown(destName, statBuf1.st_uid, statBuf1.st_gid);
282 times.actime = statBuf1.st_atime;
283 times.modtime = statBuf1.st_mtime;
285 (void) utime(destName, ×);
300 * Build a path name from the specified directory name and file name.
301 * If the directory name is NULL, then the original fileName is returned.
302 * The built path is in a static area, and is overwritten for each call.
305 buildName(const char * dirName, const char * fileName)
308 static char buf[PATH_LEN];
310 if ((dirName == NULL) || (*dirName == '\0'))
313 cp = strrchr(fileName, '/');
318 strcpy(buf, dirName);
320 strcat(buf, fileName);
328 * Expand the wildcards in a fileName wildcard pattern, if any.
329 * Returns an argument list with matching fileNames in sorted order.
330 * The expanded names are stored in memory chunks which can later all
331 * be freed at once. The returned list is only valid until the next
332 * call or until the next command. Returns zero if the name is not a
333 * wildcard, or returns the count of matched files if the name is a
334 * wildcard and there was at least one match, or returns -1 if either
335 * no fileNames matched or there was an allocation error.
338 expandWildCards(const char * fileNamePattern, const char *** retFileTable)
348 int newFileTableSize;
349 char ** newFileTable;
350 char dirName[PATH_LEN];
352 static int fileCount;
353 static int fileTableSize;
354 static char ** fileTable;
357 * Clear the return values until we know their final values.
360 *retFileTable = NULL;
363 * Scan the file name pattern for any wildcard characters.
365 cp1 = strchr(fileNamePattern, '*');
366 cp2 = strchr(fileNamePattern, '?');
367 cp3 = strchr(fileNamePattern, '[');
370 * If there are no wildcard characters then return zero to
371 * indicate that there was actually no wildcard pattern.
373 if ((cp1 == NULL) && (cp2 == NULL) && (cp3 == NULL))
377 * There are wildcards in the specified filename.
378 * Get the last component of the file name.
380 last = strrchr(fileNamePattern, '/');
385 last = fileNamePattern;
388 * If any wildcards were found before the last filename component
389 * then return an error.
391 if ((cp1 && (cp1 < last)) || (cp2 && (cp2 < last)) ||
392 (cp3 && (cp3 < last)))
395 "Wildcards only implemented for last file name component\n");
401 * Assume at first that we are scanning the current directory.
407 * If there was a directory given as part of the file name then
408 * copy it and null terminate it.
410 if (last != fileNamePattern)
412 memcpy(dirName, fileNamePattern, last - fileNamePattern);
413 dirName[last - fileNamePattern - 1] = '\0';
415 if (dirName[0] == '\0')
423 * Open the directory containing the files to be checked.
425 dirp = opendir(dirName);
435 * Prepare the directory name for use in making full path names.
437 dirLen = strlen(dirName);
439 if (last == fileNamePattern)
444 else if (dirName[dirLen - 1] != '/')
446 dirName[dirLen++] = '/';
447 dirName[dirLen] = '\0';
451 * Find all of the files in the directory and check them against
452 * the wildcard pattern.
454 while ((dp = readdir(dirp)) != NULL)
457 * Skip the current and parent directories.
459 if ((strcmp(dp->d_name, ".") == 0) ||
460 (strcmp(dp->d_name, "..") == 0))
466 * If the file name doesn't match the pattern then skip it.
468 if (!match(dp->d_name, last))
472 * This file name is selected.
473 * See if we need to reallocate the file name table.
475 if (fileCount >= fileTableSize)
478 * Increment the file table size and reallocate it.
480 newFileTableSize = fileTableSize + EXPAND_ALLOC;
482 newFileTable = (char **) realloc((char *) fileTable,
483 (newFileTableSize * sizeof(char *)));
485 if (newFileTable == NULL)
487 fprintf(stderr, "Cannot allocate file list\n");
493 fileTable = newFileTable;
494 fileTableSize = newFileTableSize;
498 * Allocate space for storing the file name in a chunk.
500 str = getChunk(dirLen + strlen(dp->d_name) + 1);
504 fprintf(stderr, "No memory for file name\n");
511 * Save the file name in the chunk.
514 memcpy(str, dirName, dirLen);
516 strcpy(str + dirLen, dp->d_name);
519 * Save the allocated file name into the file table.
521 fileTable[fileCount++] = str;
525 * Close the directory and check for any matches.
531 fprintf(stderr, "No matches\n");
537 * Sort the list of file names.
539 qsort((void *) fileTable, fileCount, sizeof(char *), nameSort);
542 * Return the file list and count.
544 *retFileTable = (const char **) fileTable;
551 * Sort routine for list of fileNames.
554 nameSort(const void * p1, const void * p2)
559 s1 = (const char **) p1;
560 s2 = (const char **) p2;
562 return strcmp(*s1, *s2);
568 * Routine to see if a text string is matched by a wildcard pattern.
569 * Returns TRUE if the text is matched, or FALSE if it is not matched
570 * or if the pattern is invalid.
571 * * matches zero or more characters
572 * ? matches a single character
573 * [abc] matches 'a', 'b' or 'c'
574 * \c quotes character c
575 * Adapted from code written by Ingo Wilken.
578 match(const char * text, const char * pattern)
580 const char * retryPat;
581 const char * retryText;
588 while (*text || *pattern)
602 while ((ch = *pattern++) != ']')
620 /* fall into next case */
634 /* fall into next case */
663 * Take a command string and break it up into an argc, argv list while
664 * handling quoting and wildcards. The returned argument list and
665 * strings are in static memory, and so are overwritten on each call.
666 * The argument list is ended with a NULL pointer for convenience.
667 * Returns TRUE if successful, or FALSE on an error with a message
671 makeArgs(const char * cmd, int * retArgc, const char *** retArgv)
673 const char * argument;
677 const char ** fileTable;
678 const char ** newArgTable;
684 BOOL quotedWildCards;
685 BOOL unquotedWildCards;
687 static int stringsLength;
688 static char * strings;
690 static int argTableSize;
691 static const char ** argTable;
694 * Clear the returned values until we know them.
701 * Copy the command string into a buffer that we can modify,
702 * reallocating it if necessary.
704 len = strlen(cmd) + 1;
706 if (len > stringsLength)
708 newStrings = realloc(strings, len);
710 if (newStrings == NULL)
712 fprintf(stderr, "Cannot allocate string\n");
717 strings = newStrings;
721 memcpy(strings, cmd, len);
725 * Keep parsing the command string as long as there are any
731 * Save the beginning of this argument.
737 * Reset quoting and wildcarding for this argument.
740 quotedWildCards = FALSE;
741 unquotedWildCards = FALSE;
744 * Loop over the string collecting the next argument while
745 * looking for quoted strings or quoted characters, and
746 * remembering whether there are any wildcard characters
754 * If we are not in a quote and we see a blank then
755 * this argument is done.
757 if (isBlank(ch) && (quote == '\0'))
761 * If we see a backslash then accept the next
762 * character no matter what it is.
769 * Make sure there is a next character.
774 "Bad quoted character\n");
780 * Remember whether the quoted character
784 quotedWildCards = TRUE;
792 * If we see one of the wildcard characters then
793 * remember whether it was seen inside or outside
799 quotedWildCards = TRUE;
801 unquotedWildCards = TRUE;
805 * If we were in a quote and we saw the same quote
806 * character again then the quote is done.
816 * If we weren't in a quote and we see either type
817 * of quote character, then remember that we are
818 * now inside of a quote.
820 if ((quote == '\0') && ((ch == '\'') || (ch == '"')))
828 * Store the character.
834 * Make sure that quoting is terminated properly.
838 fprintf(stderr, "Unmatched quote character\n");
844 * Null terminate the argument if it had shrunk, and then
845 * skip over all blanks to the next argument, nulling them
855 * If both quoted and unquoted wildcards were used then
856 * complain since we don't handle them properly.
858 if (quotedWildCards && unquotedWildCards)
861 "Cannot use quoted and unquoted wildcards\n");
867 * Expand the argument into the matching filenames or accept
868 * it as is depending on whether there were any unquoted
869 * wildcard characters in it.
871 if (unquotedWildCards)
874 * Expand the argument into the matching filenames.
876 fileCount = expandWildCards(argument, &fileTable);
879 * Return an error if the wildcards failed to match.
886 fprintf(stderr, "Wildcard expansion error\n");
894 * Set up to only store the argument itself.
896 fileTable = &argument;
901 * Now reallocate the argument table to hold the file name.
903 if (argCount + fileCount >= argTableSize)
905 newArgTableSize = argCount + fileCount + 1;
907 newArgTable = (const char **) realloc(argTable,
908 (sizeof(const char *) * newArgTableSize));
910 if (newArgTable == NULL)
912 fprintf(stderr, "No memory for arg list\n");
917 argTable = newArgTable;
918 argTableSize = newArgTableSize;
922 * Copy the new arguments to the end of the old ones.
924 memcpy((void *) &argTable[argCount], (const void *) fileTable,
925 (sizeof(const char **) * fileCount));
928 * Add to the argument count.
930 argCount += fileCount;
934 * Null terminate the argument list and return it.
936 argTable[argCount] = NULL;
946 * Make a NULL-terminated string out of an argc, argv pair.
947 * Returns TRUE if successful, or FALSE if the string is too long,
948 * with an error message given. This does not handle spaces within
949 * arguments correctly.
967 fprintf(stderr, "Argument string too long\n");
972 strcpy(buf, *argv++);
990 * Allocate a chunk of memory (like malloc).
991 * The difference, though, is that the memory allocated is put on a
992 * list of chunks which can be freed all at one time. You CAN NOT free
993 * an individual chunk.
1000 if (size < CHUNK_INIT_SIZE)
1001 size = CHUNK_INIT_SIZE;
1003 chunk = (CHUNK *) malloc(size + sizeof(CHUNK) - CHUNK_INIT_SIZE);
1008 chunk->next = chunkList;
1016 * Duplicate a string value using the chunk allocator.
1017 * The returned string cannot be individually freed, but can only be freed
1018 * with other strings when freeChunks is called. Returns NULL on failure.
1021 chunkstrdup(const char * str)
1026 len = strlen(str) + 1;
1027 newStr = getChunk(len);
1030 memcpy(newStr, str, len);
1037 * Free all chunks of memory that had been allocated since the last
1038 * call to this routine.
1048 chunkList = chunk->next;
1049 free((char *) chunk);
1055 * Write all of the supplied buffer out to a file.
1056 * This does multiple writes as necessary.
1057 * Returns the amount written, or -1 on an error.
1060 fullWrite(int fd, const char * buf, int len)
1069 cc = write(fd, buf, len);
1084 * Read all of the supplied buffer from a file.
1085 * This does multiple reads as necessary.
1086 * Returns the amount read, or -1 on an error.
1087 * A short read is returned on an end of file.
1090 fullRead(int fd, char * buf, int len)
1099 cc = read(fd, buf, len);
1117 * Read all of the supplied buffer from a file.
1118 * This does multiple reads as necessary.
1119 * Returns the amount read, or -1 on an error.
1120 * A short read is returned on an end of file.
1123 recursive( const char *fileName, BOOL followLinks, const char* pattern,
1124 int (*fileAction)(const char* fileName, const struct stat* statbuf),
1125 int (*dirAction)(const char* fileName, const struct stat* statbuf))
1128 struct stat statbuf;
1129 struct dirent* next;
1132 status = stat(fileName, &statbuf);
1134 status = lstat(fileName, &statbuf);
1141 if (S_ISREG(statbuf.st_mode)) {
1142 if (match(fileName, pattern)) {
1143 if (fileAction==NULL)
1144 fprintf( stdout, "%s\n", fileName);
1146 return(fileAction(fileName, &statbuf));
1149 else if (S_ISDIR(statbuf.st_mode)) {
1150 if (dirAction==NULL) {
1152 if (! match(fileName, pattern))
1154 dir = opendir(fileName);
1159 while ((next = readdir (dir)) != NULL) {
1160 status = recursive(fileName, followLinks, pattern, fileAction, dirAction);
1166 status = closedir (dir);
1173 return(dirAction(fileName, &statbuf));