This is duplink.c in view mode; [Download] [Up]
/* DUPLINK, link duplicatie files in a directory tree. Copyright 1993 by Michael L.H. Brouwer (michael@urc.tue.nl) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. $Modified: Mon Apr 5 00:56:47 1993 by michael $ $Id: duplink.c,v 1.15 1993/04/04 22:57:24 michael Exp $ */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_LIBC_H #include <libc.h> #endif #ifdef HAVE_UNISTD_H #include <unistd.h> #endif #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <string.h> #include <sys/types.h> #include <sys/dir.h> #include <sys/param.h> #include <sys/stat.h> #include <sys/wait.h> #include "global.h" #include "getopt.h" #include "dirtree.h" char *version_string = "duplink 1.1 (5 apr 93)"; /* No include file contains this one! */ extern char *realpath (const char *file_name, char *resolved_name); /* Command line options. */ bool doit = FALSE; bool shellout = TRUE; bool remove_empty = TRUE; static struct option longopts[] = { {"doit", 0, NULL, 'd'}, {"remove_empty", 0, NULL, 'e'}, {"help", 0 ,NULL, 'h'}, {"nowarn", 0, NULL, 'n'}, {"quiet", 0, NULL, 'q'}, {"silent", 0, NULL, 'q'}, {"verbose", 0, NULL, 'v'}, {"version", 0, NULL, 'V'}, {NULL, 0, NULL, 0} }; /* Link duplicate files in T. Return 0 on succes and -1 on failure. */ static int link_same_files (dt_tree *t) { dt_file *entry, *last_entry = NULL; char path1[MAXPATHLEN], path2[MAXPATHLEN]; long last_id; int i; if (verbose) fprintf (stderr, "Linking identical files\n"); sort_by_id (t); last_id = -1; for (i = t->elems, entry = t->files; i > 0; --i, entry++) { if (remove_empty && entry->size == 0) { strcat (strcpy (path1, entry->dir), entry->name); if (shellout) printf ("rm %s\n", path1); if (doit) if (unlink (path1)) errorf ("unlink %s", path1); last_id = entry->id; last_entry = entry; } else if (last_id != entry->id) { last_id = entry->id; last_entry = entry; } else { if (entry->device != last_entry->device) { if (warnings) errorf ("link %s%s %s%s imposible, filesystems differ.", last_entry->dir, last_entry->name, entry->dir, entry->name); } else if (entry->inode != last_entry->inode) { strcat (strcpy (path1, last_entry->dir), last_entry->name); strcat (strcpy (path2, entry->dir), entry->name); if (shellout) printf ("rm %s && ln %s %s\n", path2, path1, path2); if (doit) { if (unlink (path2)) errorf ("unlink %s", path2); else if (link (path1, path2)) errorf ("link %s %s", path1, path2); } } } } return 0; } /* link_same_files */ /* Link duplicate files in DIR. Return 0 on success and -1 on failure. */ static int duplink_dir (char *dir) { char path[MAXPATHLEN]; dt_tree *t; int files; /* Build name of store-file. */ if (!realpath (dir, path)) { errorf ("realpath %s", path); return 1; } chdir (path); t = dt_read (); if (t == (dt_tree *) -1) return 1; files = dt_calc_ids (t); if (files == -1) return 1; if (link_same_files (t)) return 1; return 0; } /* duplink_dir */ /* If PRINTHELP is TRUE, print verbose help otherwise just show a short usage line. Exit return code 4. */ static void usage (bool printhelp) { if (!printhelp) fprintf (stderr, "\ usage: %s [-dehnqvV] dir...\n\ for more help, type: %s -h\n", prog, prog); else fprintf (stderr, "\ %s\n\ usage: %s [-dehnqvV] dir...\n\ -d --doit really link files (implies -n)\n\ -e --remove_empty remove files that are 0 bytes long\n\ -h --help give this help\n\ -n --nowarn don't print warnings for unrecognized files\n\ -q --quiet don't output a shell script\n\ --silent\n\ -v --verbose verbose mode\n\ -V --version display version number\n\ dir... directories to scan.\n", version_string, prog); exit (4); } /* usage */ /* Yes, the main program, which parses arguments, and does the right thing with them. */ int main (int argc, char **argv) { int opt; init_prog (argv[0]); while ((opt = getopt_long (argc, argv, "dehnqvV", longopts, (int *) 0)) != EOF) { switch (opt) { case 'd': doit = TRUE; shellout = FALSE; break; case 'e': remove_empty = TRUE; break; case 'h': usage (TRUE); case 'n': warnings = FALSE; break; case 'q': shellout = FALSE; break; case 'v': verbose = TRUE; break; case 'V': fprintf (stderr, "%s\n", version_string); break; default: usage (FALSE); } } if (optind == argc) usage (FALSE); /* Loop though all the directory arguments. Exit when the first one goes wrong. */ while (optind < argc) if (duplink_dir (argv[optind++])) return 1; return 0; } /* main */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.