/* * Returns non-zero if the argument file is a symbolic link. */ int islink (const char *file) { #ifdef S_ISLNK struct stat sb; if (CVS_LSTAT (file, &sb) < 0) return (0); return (S_ISLNK (sb.st_mode)); #else return (0); #endif }
/* * Returns non-zero if the argument file is a block or * character special device. */ int isdevice (const char *file) { struct stat sb; if (CVS_LSTAT (file, &sb) < 0) return (0); #ifdef S_ISBLK if (S_ISBLK (sb.st_mode)) return 1; #endif #ifdef S_ISCHR if (S_ISCHR (sb.st_mode)) return 1; #endif return 0; }
/* * Process the current directory, looking for files not in ILIST and * not on the global ignore list for this directory. If we find one, * call PROC passing it the name of the file and the update dir. * ENTRIES is the entries list, which is used to identify known * directories. ENTRIES may be NULL, in which case we assume that any * directory with a CVS administration directory is known. */ void ignore_files (List *ilist, List *entries, char *update_dir, Ignore_proc proc) { int subdirs; DIR *dirp; struct dirent *dp; struct stat sb; char *file; char *xdir; List *files; Node *p; /* Set SUBDIRS if we have subdirectory information in ENTRIES. */ if (entries == NULL) subdirs = 0; else { struct stickydirtag *sdtp; sdtp = (struct stickydirtag *) entries->list->data; subdirs = sdtp == NULL || sdtp->subdirs; } /* we get called with update_dir set to "." sometimes... strip it */ if (strcmp (update_dir, ".") == 0) xdir = ""; else xdir = update_dir; dirp = opendir ("."); if (dirp == NULL) { error (0, errno, "cannot open current directory"); return; } ign_add_file (CVSDOTIGNORE, 1); wrap_add_file (CVSDOTWRAPPER, true); /* Make a list for the files. */ files = getlist (); while (errno = 0, (dp = readdir (dirp)) != NULL) { file = dp->d_name; if (strcmp (file, ".") == 0 || strcmp (file, "..") == 0) continue; if (findnode_fn (ilist, file) != NULL) continue; if (subdirs) { Node *node; node = findnode_fn (entries, file); if (node != NULL && ((Entnode *) node->data)->type == ENT_SUBDIR) { char *p; int dir; /* For consistency with past behaviour, we only ignore this directory if there is a CVS subdirectory. This will normally be the case, but the user may have messed up the working directory somehow. */ p = (char*)xmalloc (strlen (file) + sizeof CVSADM + 10); sprintf (p, "%s/%s", file, CVSADM); dir = isdir (p); xfree (p); if (dir) continue; } } /* We could be ignoring FIFOs and other files which are neither regular files nor directories here. */ if (ign_name (file)) continue; if (CVS_LSTAT(file, &sb) != -1) { if (S_ISDIR (sb.st_mode)) { if (! subdirs) { char *temp; temp = (char*)xmalloc (strlen (file) + sizeof (CVSADM) + 10); sprintf (temp, "%s/%s", file, CVSADM); if (isdir (temp)) { xfree (temp); continue; } xfree (temp); } } #ifdef S_ISLNK else if (S_ISLNK (sb.st_mode)) { continue; } #endif } p = getnode (); p->type = FILES; p->key = xstrdup (file); addnode (files, p); } if (errno != 0) error (0, errno, "error reading current directory"); closedir (dirp); sortlist (files, fsortcmp); for (p = files->list->next; p != files->list; p = p->next) (*proc) (p->key, xdir); dellist (&files); }
/* * Compare "file1" to "file2". Return non-zero if they don't compare exactly. * If FILE1 and FILE2 are special files, compare their salient characteristics * (i.e. major/minor device numbers, links, etc. */ int xcmp (const char *file1, const char *file2) { char *buf1, *buf2; struct stat sb1, sb2; int fd1, fd2; int ret; if (CVS_LSTAT (file1, &sb1) < 0) error (1, errno, "cannot lstat %s", fn_root(file1)); if (CVS_LSTAT (file2, &sb2) < 0) error (1, errno, "cannot lstat %s", fn_root(file2)); /* If FILE1 and FILE2 are not the same file type, they are unequal. */ if ((sb1.st_mode & S_IFMT) != (sb2.st_mode & S_IFMT)) return 1; /* If FILE1 and FILE2 are symlinks, they are equal if they point to the same thing. */ if (S_ISLNK (sb1.st_mode) && S_ISLNK (sb2.st_mode)) { int result; buf1 = xreadlink (file1); buf2 = xreadlink (file2); result = (strcmp (buf1, buf2) == 0); xfree (buf1); xfree (buf2); return result; } /* If FILE1 and FILE2 are devices, they are equal if their device numbers match. */ if (S_ISBLK (sb1.st_mode) || S_ISCHR (sb1.st_mode)) { #ifdef HAVE_STRUCT_STAT_ST_RDEV if (sb1.st_rdev == sb2.st_rdev) return 0; else return 1; #else error (1, 0, "cannot compare device files on this system (%s and %s)", file1, file2); #endif } if ((fd1 = CVS_OPEN (file1, O_RDONLY)) < 0) error (1, errno, "cannot open file %s for comparing", fn_root(file1)); if ((fd2 = CVS_OPEN (file2, O_RDONLY)) < 0) error (1, errno, "cannot open file %s for comparing", fn_root(file2)); /* A generic file compare routine might compare st_dev & st_ino here to see if the two files being compared are actually the same file. But that won't happen in CVS, so we won't bother. */ if (sb1.st_size != sb2.st_size) ret = 1; else if (sb1.st_size == 0) ret = 0; else { /* FIXME: compute the optimal buffer size by computing the least common multiple of the files st_blocks field */ size_t buf_size = 8 * 1024; size_t read1; size_t read2; buf1 = (char*)xmalloc (buf_size); buf2 = (char*)xmalloc (buf_size); do { read1 = block_read (fd1, buf1, buf_size); if (read1 == (size_t)-1) error (1, errno, "cannot read file %s for comparing", fn_root(file1)); read2 = block_read (fd2, buf2, buf_size); if (read2 == (size_t)-1) error (1, errno, "cannot read file %s for comparing", fn_root(file2)); /* assert (read1 == read2); */ ret = memcmp(buf1, buf2, read1); } while (ret == 0 && read1 == buf_size); xfree (buf1); xfree (buf2); } (void) close (fd1); (void) close (fd2); return (ret); }