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.