+ usage();
+
+ my_umask = umask(0);
+ (void)umask(my_umask);
+
+ buf = (char *)malloc(MAXBSIZE);
+ if (!buf) {
+ (void)fprintf(stderr, "cp: out of space.\n");
+ exit(1);
+ }
+
+ /* Consume last argument first. */
+ if (!path_set(&to, argv[--argc]))
+ exit(exit_val);
+
+ /*
+ * Cp has two distinct cases:
+ *
+ * Case (1) $ cp [-rip] source target
+ *
+ * Case (2) $ cp [-rip] source1 ... directory
+ *
+ * In both cases, source can be either a file or a directory.
+ *
+ * In (1), the target becomes a copy of the source. That is, if the
+ * source is a file, the target will be a file, and likewise for
+ * directories.
+ *
+ * In (2), the real target is not directory, but "directory/source".
+ */
+
+ r = stat(to.p_path, &to_stat);
+ if (r == -1 && errno != ENOENT) {
+ error(to.p_path);
+ exit(1);
+ }
+ if (r == -1 || (to_stat.st_mode & S_IFMT) != S_IFDIR) {
+ /*
+ * Case (1). Target is not a directory.
+ */
+ if (argc > 1) {
+ usage();
+ exit(1);
+ }
+ if (!path_set(&from, *argv))
+ exit(exit_val);
+ copy();
+ }
+ else {
+ /*
+ * Case (2). Target is a directory.
+ */
+ for (; argc; --argc, ++argv) {
+ if (!path_set(&from, *argv))
+ continue;
+ old_to = path_append(&to, path_basename(&from), -1);
+ if (!old_to)
+ continue;
+ copy();
+ path_restore(&to, old_to);
+ }
+ }
+ exit(exit_val);
+}
+
+/*
+ * Copy file or directory at "from" to "to".
+ */
+copy()
+{
+ struct stat from_stat, to_stat;
+ int new_target_dir, statval;
+
+ statval = symfollow || !recursive_flag ?
+ stat(from.p_path, &from_stat) : lstat(from.p_path, &from_stat);
+ if (statval == -1) {
+ error(from.p_path);
+ return;
+ }
+
+ /* not an error, but need to remember it happened */
+ if (stat(to.p_path, &to_stat) == -1)
+ to_stat.st_ino = -1;
+ else if (to_stat.st_dev == from_stat.st_dev &&
+ to_stat.st_ino == from_stat.st_ino) {
+ (void)fprintf(stderr,
+ "cp: %s and %s are identical (not copied).\n",
+ to.p_path, from.p_path);
+ exit_val = 1;
+ return;
+ }
+
+ if ((from_stat.st_mode & S_IFMT) == S_IFLNK) {
+ copy_link(to_stat.st_ino != -1);
+ return;
+ }
+
+ new_target_dir = 0;
+ if ((from_stat.st_mode & S_IFMT) != S_IFDIR) {
+ if (!copy_file(from_stat.st_mode))
+ return;
+ }
+ else {
+ if (!recursive_flag) {
+ (void)fprintf(stderr,
+ "cp: \"%s\" is a directory (not copied).\n",
+ from.p_path);
+ exit_val = 1;
+ return;
+ }
+ if (to_stat.st_ino == -1) {
+ if (mkdir(to.p_path, 0777) < 0) {
+ error(to.p_path);
+ return;