Esempio n. 1
0
static void unzip_create_leading_dirs(const char *fn)
{
	/* Create all leading directories */
	char *name = xstrdup(fn);
	if (bb_make_directory(dirname(name), 0777, FILEUTILS_RECUR)) {
		xfunc_die(); /* bb_make_directory is noisy */
	}
	free(name);
}
Esempio n. 2
0
int mkdir_main (int argc, char **argv)
{
	mode_t mode = (mode_t)(-1);
	int status = EXIT_SUCCESS;
	int flags = 0;
	unsigned long opt;
	char *smode;
#ifdef CONFIG_SELINUX
	security_context_t scontext = NULL;
#endif

#if ENABLE_FEATURE_MKDIR_LONG_OPTIONS
	bb_applet_long_options = mkdir_long_options;
#endif
#ifdef CONFIG_SELINUX
	opt = bb_getopt_ulflags(argc, argv, "m:pZ:", &smode, &scontext);
#else
	opt = bb_getopt_ulflags(argc, argv, "m:p", &smode);
#endif
	if(opt & 1) {
			mode = 0777;
		if (!bb_parse_mode (smode, &mode)) {
			bb_error_msg_and_die ("invalid mode `%s'", smode);
		}
	}
	if(opt & 2)
		flags |= FILEUTILS_RECUR;
#ifdef CONFIG_SELINUX
	if(opt & 4) {
		if(!is_selinux_enabled()) {
			bb_error_msg_and_die ("Sorry, --context (-Z) can be used only on "
					      "a selinux-enabled kernel.\n" );
		}
		if (setfscreatecon(scontext)) {
			bb_error_msg_and_die ("Sorry, cannot set default context "
					      "to %s.\n", scontext);
		}
	}
#endif

	if (optind == argc) {
		bb_show_usage();
	}

	argv += optind;

	do {
		if (bb_make_directory(*argv, mode, flags)) {
			status = EXIT_FAILURE;
		}
	} while (*++argv);

	return status;
}
Esempio n. 3
0
int mkdir_main(int argc UNUSED_PARAM, char **argv)
{
	long mode = -1;
	int status = EXIT_SUCCESS;
	int flags = 0;
	unsigned opt;
	char *smode;
#if ENABLE_SELINUX
	security_context_t scontext;
#endif

#if ENABLE_FEATURE_MKDIR_LONG_OPTIONS
	applet_long_options = mkdir_longopts;
#endif
	opt = getopt32(argv, "m:pv" IF_SELINUX("Z:"), &smode IF_SELINUX(,&scontext));
	if (opt & 1) {
		mode_t mmode = bb_parse_mode(smode, 0777);
		if (mmode == (mode_t)-1) {
			bb_error_msg_and_die("invalid mode '%s'", smode);
		}
		mode = mmode;
	}
	if (opt & 2)
		flags |= FILEUTILS_RECUR;
	if ((opt & 4) && FILEUTILS_VERBOSE)
		flags |= FILEUTILS_VERBOSE;
#if ENABLE_SELINUX
	if (opt & 8) {
		selinux_or_die();
		setfscreatecon_or_die(scontext);
	}
#endif

	argv += optind;
	if (!argv[0])
		bb_show_usage();

	do {
		if (bb_make_directory(*argv, mode, flags)) {
			status = EXIT_FAILURE;
		}
	} while (*++argv);

	return status;
}
Esempio n. 4
0
int mkdir_main(int argc, char **argv)
{
	mode_t mode = (mode_t)(-1);
	int status = EXIT_SUCCESS;
	int flags = 0;
	unsigned opt;
	char *smode;
#if ENABLE_SELINUX
	security_context_t scontext;
#endif

#if ENABLE_FEATURE_MKDIR_LONG_OPTIONS
	applet_long_options = mkdir_longopts;
#endif
	opt = getopt32(argv, "m:p" USE_SELINUX("Z:"), &smode USE_SELINUX(,&scontext));
	if (opt & 1) {
		mode = 0777;
		if (!bb_parse_mode(smode, &mode)) {
			bb_error_msg_and_die("invalid mode '%s'", smode);
		}
	}
	if (opt & 2)
		flags |= FILEUTILS_RECUR;
#if ENABLE_SELINUX
	if (opt & 4) {
		selinux_or_die();
		setfscreatecon_or_die(scontext);
	}
#endif

	if (optind == argc) {
		bb_show_usage();
	}

	argv += optind;

	do {
		if (bb_make_directory(*argv, mode, flags)) {
			status = EXIT_FAILURE;
		}
	} while (*++argv);

	return status;
}
Esempio n. 5
0
/* Builds an alias path.
 * This function potentionally reallocates the alias parameter.
 * Only used for ENABLE_FEATURE_MDEV_RENAME
 */
static char *build_alias(char *alias, const char *device_name)
{
	char *dest;

	/* ">bar/": rename to bar/device_name */
	/* ">bar[/]baz": rename to bar[/]baz */
	dest = strrchr(alias, '/');
	if (dest) { /* ">bar/[baz]" ? */
		*dest = '\0'; /* mkdir bar */
		bb_make_directory(alias, 0755, FILEUTILS_RECUR);
		*dest = '/';
		if (dest[1] == '\0') { /* ">bar/" => ">bar/device_name" */
			dest = alias;
			alias = concat_path_file(alias, device_name);
			free(dest);
		}
	}

	return alias;
}
Esempio n. 6
0
int patch_main(int argc UNUSED_PARAM, char **argv)
{
	int opts;
	int reverse, state = 0;
	char *oldname = NULL, *newname = NULL;
	char *opt_p, *opt_i;
	long oldlen = oldlen; /* for compiler */
	long newlen = newlen; /* for compiler */

	INIT_TT();

	opts = getopt32(argv, FLAG_STR, &opt_p, &opt_i);
	argv += optind;
	reverse = opts & FLAG_REVERSE;
	TT.prefix = (opts & FLAG_PATHLEN) ? xatoi(opt_p) : 0; // can be negative!
	TT.filein = TT.fileout = -1;
	if (opts & FLAG_INPUT) {
		xmove_fd(xopen_stdin(opt_i), STDIN_FILENO);
	} else {
		if (argv[0] && argv[1]) {
			xmove_fd(xopen_stdin(argv[1]), STDIN_FILENO);
		}
	}
	if (argv[0]) {
		oldname = xstrdup(argv[0]);
		newname = xstrdup(argv[0]);
	}

	// Loop through the lines in the patch
	for(;;) {
		char *patchline;

		patchline = xmalloc_fgetline(stdin);
		if (!patchline) break;

		// Other versions of patch accept damaged patches,
		// so we need to also.
		if (!*patchline) {
			free(patchline);
			patchline = xstrdup(" ");
		}

		// Are we assembling a hunk?
		if (state >= 2) {
			if (*patchline==' ' || *patchline=='+' || *patchline=='-') {
				dlist_add(&TT.current_hunk, patchline);

				if (*patchline != '+') oldlen--;
				if (*patchline != '-') newlen--;

				// Context line?
				if (*patchline==' ' && state==2) TT.context++;
				else state=3;

				// If we've consumed all expected hunk lines, apply the hunk.

				if (!oldlen && !newlen) state = apply_one_hunk();
				continue;
			}
			fail_hunk();
			state = 0;
			continue;
		}

		// Open a new file?
		if (!strncmp("--- ", patchline, 4) || !strncmp("+++ ", patchline, 4)) {
			char *s, **name = reverse ? &newname : &oldname;
			int i;

			if (*patchline == '+') {
				name = reverse ? &oldname : &newname;
				state = 1;
			}

			finish_oldfile();

			if (!argv[0]) {
				free(*name);
				// Trim date from end of filename (if any).  We don't care.
				for (s = patchline+4; *s && *s!='\t'; s++)
					if (*s=='\\' && s[1]) s++;
				i = atoi(s);
				if (i>1900 && i<=1970)
					*name = xstrdup("/dev/null");
				else {
					*s = 0;
					*name = xstrdup(patchline+4);
				}
			}

			// We defer actually opening the file because svn produces broken
			// patches that don't signal they want to create a new file the
			// way the patch man page says, so you have to read the first hunk
			// and _guess_.

		// Start a new hunk?  Usually @@ -oldline,oldlen +newline,newlen @@
		// but a missing ,value means the value is 1.
		} else if (state == 1 && !strncmp("@@ -", patchline, 4)) {
			int i;
			char *s = patchline+4;

			// Read oldline[,oldlen] +newline[,newlen]

			TT.oldlen = oldlen = TT.newlen = newlen = 1;
			TT.oldline = strtol(s, &s, 10);
			if (*s == ',') TT.oldlen = oldlen = strtol(s+1, &s, 10);
			TT.newline = strtol(s+2, &s, 10);
			if (*s == ',') TT.newlen = newlen = strtol(s+1, &s, 10);

			if (oldlen < 1 && newlen < 1)
				bb_error_msg_and_die("Really? %s", patchline);

			TT.context = 0;
			state = 2;

			// If this is the first hunk, open the file.
			if (TT.filein == -1) {
				int oldsum, newsum, empty = 0;
				char *name;

				oldsum = TT.oldline + oldlen;
				newsum = TT.newline + newlen;

				name = reverse ? oldname : newname;

				// We're deleting oldname if new file is /dev/null (before -p)
				// or if new hunk is empty (zero context) after patching
				if (!strcmp(name, "/dev/null") || !(reverse ? oldsum : newsum)) {
					name = reverse ? newname : oldname;
					empty++;
				}

				// handle -p path truncation.
				for (i=0, s = name; *s;) {
					if ((option_mask32 & FLAG_PATHLEN) && TT.prefix == i)
						break;
					if (*s++ != '/')
						continue;
					while (*s == '/')
						s++;
						i++;
					name = s;
				}

				if (empty) {
					// File is empty after the patches have been applied
					state = 0;
					if (option_mask32 & FLAG_RMEMPTY) {
						// If flag -E or --remove-empty-files is set
						printf("removing %s\n", name);
						xunlink(name);
					} else {
						printf("patching file %s\n", name);
						xclose(xopen(name, O_WRONLY | O_TRUNC));
					}
				// If we've got a file to open, do so.
				} else if (!(option_mask32 & FLAG_PATHLEN) || i <= TT.prefix) {
					struct stat statbuf;

					// If the old file was null, we're creating a new one.
					if (!strcmp(oldname, "/dev/null") || !oldsum) {
						printf("creating %s\n", name);
						s = strrchr(name, '/');
						if (s) {
							*s = 0;
							bb_make_directory(name, -1, FILEUTILS_RECUR);
							*s = '/';
						}
						TT.filein = xopen(name, O_CREAT|O_EXCL|O_RDWR);
					} else {
						printf("patching file %s\n", name);
						TT.filein = xopen(name, O_RDONLY);
					}

					TT.tempname = xasprintf("%sXXXXXX", name);
					TT.fileout = xmkstemp(TT.tempname);
					// Set permissions of output file
					fstat(TT.filein, &statbuf);
					fchmod(TT.fileout, statbuf.st_mode);

					TT.linenum = 0;
					TT.hunknum = 0;
				}
			}

			TT.hunknum++;

			continue;
		}

		// If we didn't continue above, discard this line.
		free(patchline);
	}

	finish_oldfile();

	if (ENABLE_FEATURE_CLEAN_UP) {
		free(oldname);
		free(newname);
	}

	return TT.exitval;
}
int main(int argc, char **argv)
{
	int opt;
	FILE *table = stdin;
	char *rootdir = NULL;
	char *line = NULL;
	int linenum = 0;
	int ret = EXIT_SUCCESS;

	bb_applet_name = basename(argv[0]);

	while ((opt = getopt(argc, argv, "d:")) != -1) {
		switch(opt) {
			case 'd':
				table = bb_xfopen((line=optarg), "r");
				break;
			default:
				bb_show_usage();
		}
	}

	if (optind >= argc || (rootdir=argv[optind])==NULL) {
		bb_error_msg_and_die("root directory not speficied");
	}

	if (chdir(rootdir) != 0) {
		bb_perror_msg_and_die("Couldnt chdir to %s", rootdir);
	}

	umask(0);

	printf("rootdir=%s\n", rootdir);
	if (line) {
		printf("table='%s'\n", line);
	} else {
		printf("table=<stdin>\n");
	}

	while ((line = bb_get_chomped_line_from_file(table))) {
		char type;
		unsigned int mode = 0755;
		unsigned int major = 0;
		unsigned int minor = 0;
		unsigned int count = 0;
		unsigned int increment = 0;
		unsigned int start = 0;
		char name[4096];
		char user[41];
		char group[41];
		char *full_name;
		uid_t uid;
		gid_t gid;

		linenum++;

		if ((2 > sscanf(line, "%4095s %c %o %40s %40s %u %u %u %u %u", name,
						&type, &mode, user, group, &major,
						&minor, &start, &increment, &count)) ||
				((major | minor | start | count | increment) > 0xfffff))
		{
			if (*line=='\0' || *line=='#' || isspace(*line))
				continue;
			bb_error_msg("line %d invalid: '%s'\n", linenum, line);
			ret = EXIT_FAILURE;
			continue;
		}
		if (name[0] == '#') {
			continue;
		}
		if (*group) {
			gid = get_ug_id(group, my_getgrnam);
		} else {
			gid = getgid();
		}
		if (*user) {
			uid = get_ug_id(user, my_getpwnam);
		} else {
			uid = getuid();
		}
		full_name = concat_path_file(rootdir, name);

		if (type == 'd') {
			bb_make_directory(full_name, mode | S_IFDIR, FILEUTILS_RECUR);
			if (chown(full_name, uid, gid) == -1) {
				bb_perror_msg("line %d: chown failed for %s", linenum, full_name);
				ret = EXIT_FAILURE;
				goto loop;
			}
			if ((mode != -1) && (chmod(full_name, mode) < 0)){
				bb_perror_msg("line %d: chmod failed for %s", linenum, full_name);
				ret = EXIT_FAILURE;
				goto loop;
			}
		} else if (type == 'f') {
			struct stat st;
			if ((stat(full_name, &st) < 0 || !S_ISREG(st.st_mode))) {
				bb_perror_msg("line %d: regular file '%s' does not exist", linenum, full_name);
				ret = EXIT_FAILURE;
				goto loop;
			}
			if (chown(full_name, uid, gid) == -1) {
				bb_perror_msg("line %d: chown failed for %s", linenum, full_name);
				ret = EXIT_FAILURE;
				goto loop;
			}
			if ((mode != -1) && (chmod(full_name, mode) < 0)){
				bb_perror_msg("line %d: chmod failed for %s", linenum, full_name);
				ret = EXIT_FAILURE;
				goto loop;
			}
		} else if (type == 'r') {
			recursive_uid = uid;
			recursive_gid = gid;
			recursive_mode = mode;
			if (nftw(full_name, bb_recursive, 20, FTW_MOUNT | FTW_PHYS) < 0) {
				bb_perror_msg("line %d: recursive failed for %s", linenum, full_name);
				ret = EXIT_FAILURE;
				goto loop;
			}
		} else
		{
			dev_t rdev;

			if (type == 'p') {
				mode |= S_IFIFO;
			}
			else if (type == 'c') {
				mode |= S_IFCHR;
			}
			else if (type == 'b') {
				mode |= S_IFBLK;
			} else {
				bb_error_msg("line %d: Unsupported file type %c", linenum, type);
				ret = EXIT_FAILURE;
				goto loop;
			}

			if (count > 0) {
				int i;
				char *full_name_inc;

				full_name_inc = xmalloc(strlen(full_name) + 8);
				for (i = 0; i < count; i++) {
					sprintf(full_name_inc, "%s%d", full_name, start + i);
					rdev = makedev(major, minor + i * increment);
					if (mknod(full_name_inc, mode, rdev) == -1) {
						bb_perror_msg("line %d: Couldnt create node %s", linenum, full_name_inc);
						ret = EXIT_FAILURE;
					}
					else if (chown(full_name_inc, uid, gid) == -1) {
						bb_perror_msg("line %d: chown failed for %s", linenum, full_name_inc);
						ret = EXIT_FAILURE;
					}
					if ((mode != -1) && (chmod(full_name_inc, mode) < 0)){
						bb_perror_msg("line %d: chmod failed for %s", linenum, full_name_inc);
						ret = EXIT_FAILURE;
					}
				}
				free(full_name_inc);
			} else {
				rdev = makedev(major, minor);
				if (mknod(full_name, mode, rdev) == -1) {
					bb_perror_msg("line %d: Couldnt create node %s", linenum, full_name);
					ret = EXIT_FAILURE;
				}
				else if (chown(full_name, uid, gid) == -1) {
					bb_perror_msg("line %d: chown failed for %s", linenum, full_name);
					ret = EXIT_FAILURE;
				}
				if ((mode != -1) && (chmod(full_name, mode) < 0)){
					bb_perror_msg("line %d: chmod failed for %s", linenum, full_name);
					ret = EXIT_FAILURE;
				}
			}
		}
loop:
		free(line);
		free(full_name);
	}
	fclose(table);

	return ret;
}
Esempio n. 8
0
void data_extract_all(archive_handle_t *archive_handle)
{
	file_header_t *file_header = archive_handle->file_header;
	int dst_fd;
	int res;

	if (archive_handle->flags & ARCHIVE_CREATE_LEADING_DIRS) {
		char *name = bb_xstrdup(file_header->name);
		bb_make_directory (dirname(name), -1, FILEUTILS_RECUR);
		free(name);
	}

	/* Check if the file already exists */
	if (archive_handle->flags & ARCHIVE_EXTRACT_UNCONDITIONAL) {
		/* Remove the existing entry if it exists */
		if (((file_header->mode & S_IFMT) != S_IFDIR) && (unlink(file_header->name) == -1) && (errno != ENOENT)) {
			bb_perror_msg_and_die("Couldnt remove old file");
		}
	}
	else if (archive_handle->flags & ARCHIVE_EXTRACT_NEWER) {
		/* Remove the existing entry if its older than the extracted entry */
		struct stat statbuf;
		if (lstat(file_header->name, &statbuf) == -1) {
			if (errno != ENOENT) {
				bb_perror_msg_and_die("Couldnt stat old file");
			}
		}
		else if (statbuf.st_mtime <= file_header->mtime) {
			if (!(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) {
				bb_error_msg("%s not created: newer or same age file exists", file_header->name);
			}
			data_skip(archive_handle);
			return;
		}
		else if ((unlink(file_header->name) == -1) && (errno != EISDIR)) {
			bb_perror_msg_and_die("Couldnt remove old file %s", file_header->name);
		}
	}

	/* Handle hard links separately
	 * We identified hard links as regular files of size 0 with a symlink */
	if (S_ISREG(file_header->mode) && (file_header->link_name) && (file_header->size == 0)) {
		/* hard link */
		res = link(file_header->link_name, file_header->name);
		if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) {
			bb_perror_msg("Couldnt create hard link");
		}
	} else {
		/* Create the filesystem entry */
		switch(file_header->mode & S_IFMT) {
			case S_IFREG: {
				/* Regular file */
				dst_fd = bb_xopen(file_header->name, O_WRONLY | O_CREAT | O_EXCL);
				bb_copyfd_size(archive_handle->src_fd, dst_fd, file_header->size);
				close(dst_fd);
				break;
				}
			case S_IFDIR:
				res = mkdir(file_header->name, file_header->mode);
				if ((errno != EISDIR) && (res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) {
					bb_perror_msg("extract_archive: %s", file_header->name);
				}
				break;
			case S_IFLNK:
				/* Symlink */
				res = symlink(file_header->link_name, file_header->name);
				if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) {
					bb_perror_msg("Cannot create symlink from %s to '%s'", file_header->name, file_header->link_name);
				}
				break;
			case S_IFSOCK:
			case S_IFBLK:
			case S_IFCHR:
			case S_IFIFO:
				res = mknod(file_header->name, file_header->mode, file_header->device);
				if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) {
					bb_perror_msg("Cannot create node %s", file_header->name);
				}
				break;
			default:
				bb_error_msg_and_die("Unrecognised file type");
		}
	}

	if (!(archive_handle->flags & ARCHIVE_NOPRESERVE_OWN)) {
		lchown(file_header->name, file_header->uid, file_header->gid);
	}
	if (!(archive_handle->flags & ARCHIVE_NOPRESERVE_PERM) &&
		 (file_header->mode & S_IFMT) != S_IFLNK)
	{
		chmod(file_header->name, file_header->mode);
	}

	if (archive_handle->flags & ARCHIVE_PRESERVE_DATE && !S_ISLNK(file_header->mode)) {
		struct utimbuf t;
		t.actime = t.modtime = file_header->mtime;
		utime(file_header->name, &t);
	}
}
Esempio n. 9
0
int cp_main(int argc, char **argv)
{
	struct stat source_stat;
	struct stat dest_stat;
	const char *last;
	const char *dest;
	int s_flags;
	int d_flags;
	int flags;
	int status;
	enum {
		OPT_a = 1 << (sizeof(FILEUTILS_CP_OPTSTR)-1),
		OPT_r = 1 << (sizeof(FILEUTILS_CP_OPTSTR)),
		OPT_P = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+1),
		OPT_v = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+2),
#if ENABLE_FEATURE_CP_LONG_OPTIONS
		OPT_parents = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+3),
#endif
	};

	// Need at least two arguments
	// Soft- and hardlinking doesn't mix
	// -P and -d are the same (-P is POSIX, -d is GNU)
	// -r and -R are the same
	// -R (and therefore -r) turns on -d (coreutils does this)
	// -a = -pdR
	opt_complementary = "-2:l--s:s--l:Pd:rRd:Rd:apdR";
#if ENABLE_FEATURE_CP_LONG_OPTIONS
	applet_long_options =
		"archive\0"        No_argument "a"
		"force\0"          No_argument "f"
		"interactive\0"    No_argument "i"
		"link\0"           No_argument "l"
		"dereference\0"    No_argument "L"
		"no-dereference\0" No_argument "P"
		"recursive\0"      No_argument "R"
		"symbolic-link\0"  No_argument "s"
		"verbose\0"        No_argument "v"
		"parents\0"        No_argument "\xff"
		;
#endif
	flags = getopt32(argv, FILEUTILS_CP_OPTSTR "arPv");
	/* Options of cp from GNU coreutils 6.10:
	 * -a, --archive
	 * -f, --force
	 * -i, --interactive
	 * -l, --link
	 * -L, --dereference
	 * -P, --no-dereference
	 * -R, -r, --recursive
	 * -s, --symbolic-link
	 * -v, --verbose
	 * -H	follow command-line symbolic links in SOURCE
	 * -d	same as --no-dereference --preserve=links
	 * -p	same as --preserve=mode,ownership,timestamps
	 * -c	same as --preserve=context
	 * --parents
	 *	use full source file name under DIRECTORY
	 * NOT SUPPORTED IN BBOX:
	 * --backup[=CONTROL]
	 *	make a backup of each existing destination file
	 * -b	like --backup but does not accept an argument
	 * --copy-contents
	 *	copy contents of special files when recursive
	 * --preserve[=ATTR_LIST]
	 *	preserve attributes (default: mode,ownership,timestamps),
	 *	if possible additional attributes: security context,links,all
	 * --no-preserve=ATTR_LIST
	 * --remove-destination
	 *	remove  each existing destination file before attempting to open
	 * --sparse=WHEN
	 *	control creation of sparse files
	 * --strip-trailing-slashes
	 *	remove any trailing slashes from each SOURCE argument
	 * -S, --suffix=SUFFIX
	 *	override the usual backup suffix
	 * -t, --target-directory=DIRECTORY
	 *	copy all SOURCE arguments into DIRECTORY
	 * -T, --no-target-directory
	 *	treat DEST as a normal file
	 * -u, --update
	 *	copy only when the SOURCE file is newer than the destination
	 *	file or when the destination file is missing
	 * -x, --one-file-system
	 *	stay on this file system
	 * -Z, --context=CONTEXT
	 *	(SELinux) set SELinux security context of copy to CONTEXT
	 */
	argc -= optind;
	argv += optind;
	/* Reverse this bit. If there is -d, bit is not set: */
	flags ^= FILEUTILS_DEREFERENCE;
	/* coreutils 6.9 compat:
	 * by default, "cp" derefs symlinks (creates regular dest files),
	 * but "cp -R" does not. We switch off deref if -r or -R (see above).
	 * However, "cp -RL" must still deref symlinks: */
	if (flags & FILEUTILS_DEREF_SOFTLINK) /* -L */
		flags |= FILEUTILS_DEREFERENCE;

#if ENABLE_SELINUX
	if (flags & FILEUTILS_PRESERVE_SECURITY_CONTEXT) {
		selinux_or_die();
	}
#endif

	status = EXIT_SUCCESS;
	last = argv[argc - 1];
	/* If there are only two arguments and...  */
	if (argc == 2) {
		s_flags = cp_mv_stat2(*argv, &source_stat,
				(flags & FILEUTILS_DEREFERENCE) ? stat : lstat);
		if (s_flags < 0)
			return EXIT_FAILURE;
		d_flags = cp_mv_stat(last, &dest_stat);
		if (d_flags < 0)
			return EXIT_FAILURE;

#if ENABLE_FEATURE_CP_LONG_OPTIONS
		if (flags & OPT_parents) {
			if (!(d_flags & 2)) {
				bb_error_msg_and_die("with --parents, the destination must be a directory");
			}
		}
#endif

		/* ...if neither is a directory...  */
		if (!((s_flags | d_flags) & 2)
		    /* ...or: recursing, the 1st is a directory, and the 2nd doesn't exist... */
		 || ((flags & FILEUTILS_RECUR) && (s_flags & 2) && !d_flags)
		) {
			/* Do a simple copy */
			dest = last;
			goto DO_COPY; /* NB: argc==2 -> *++argv==last */
		}
	}

	while (1) {
#if ENABLE_FEATURE_CP_LONG_OPTIONS
		if (flags & OPT_parents) {
			char *dest_dup;
			char *dest_dir;
			dest = concat_path_file(last, *argv);
			dest_dup = xstrdup(dest);
			dest_dir = dirname(dest_dup);
			if (bb_make_directory(dest_dir, -1, FILEUTILS_RECUR)) {
				return EXIT_FAILURE;
			}
			free(dest_dup);
			goto DO_COPY;
		}
#endif
		dest = concat_path_file(last, bb_get_last_path_component_strip(*argv));
 DO_COPY:
		if (copy_file(*argv, dest, flags) < 0) {
			status = EXIT_FAILURE;
		}
		if (*++argv == last) {
			/* possibly leaking dest... */
			break;
		}
		/* don't move up: dest may be == last and not malloced! */
		free((void*)dest);
	}

	/* Exit. We are NOEXEC, not NOFORK. We do exit at the end of main() */
	return status;
}
Esempio n. 10
0
int makedevs_main(int argc, char **argv)
{
	FILE *table = stdin;
	char *rootdir = NULL;
	char *line = NULL;
	int linenum = 0;
	int ret = EXIT_SUCCESS;

	unsigned long flags;
	flags = bb_getopt_ulflags(argc, argv, "d:", &line);
	if (line)
		table = bb_xfopen(line, "r");

	if (optind >= argc || (rootdir=argv[optind])==NULL) {
		bb_error_msg_and_die("root directory not specified");
	}

	bb_xchdir(rootdir);

	umask(0);

	printf("rootdir=%s\n", rootdir);
	if (line) {
		printf("table='%s'\n", line);
	} else {
		printf("table=<stdin>\n");
	}

	while ((line = bb_get_chomped_line_from_file(table))) {
		char type;
		unsigned int mode = 0755;
		unsigned int major = 0;
		unsigned int minor = 0;
		unsigned int count = 0;
		unsigned int increment = 0;
		unsigned int start = 0;
		char name[41];
		char user[41];
		char group[41];
		char *full_name;
		uid_t uid;
		gid_t gid;

		linenum++;

		if ((2 > sscanf(line, "%40s %c %o %40s %40s %u %u %u %u %u", name,
						&type, &mode, user, group, &major,
						&minor, &start, &increment, &count)) ||
				((major | minor | start | count | increment) > 255))
		{
			if (*line=='\0' || *line=='#' || isspace(*line))
				continue;
			bb_error_msg("line %d invalid: '%s'\n", linenum, line);
			ret = EXIT_FAILURE;
			continue;
		}
		if (name[0] == '#') {
			continue;
		}

		gid = (*group) ? get_ug_id(group, bb_xgetgrnam) : getgid();
		uid = (*user) ? get_ug_id(user, bb_xgetpwnam) : getuid();
		full_name = concat_path_file(rootdir, name);

		if (type == 'd') {
			bb_make_directory(full_name, mode | S_IFDIR, FILEUTILS_RECUR);
			if (chown(full_name, uid, gid) == -1) {
				bb_perror_msg("line %d: chown failed for %s", linenum, full_name);
				ret = EXIT_FAILURE;
				goto loop;
			}
			if ((mode != -1) && (chmod(full_name, mode) < 0)){
				bb_perror_msg("line %d: chmod failed for %s", linenum, full_name);
				ret = EXIT_FAILURE;
				goto loop;
			}
		} else if (type == 'f') {
			struct stat st;
			if ((stat(full_name, &st) < 0 || !S_ISREG(st.st_mode))) {
				bb_perror_msg("line %d: regular file '%s' does not exist", linenum, full_name);
				ret = EXIT_FAILURE;
				goto loop;
			}
			if (chown(full_name, uid, gid) == -1) {
				bb_perror_msg("line %d: chown failed for %s", linenum, full_name);
				ret = EXIT_FAILURE;
				goto loop;
			}
			if ((mode != -1) && (chmod(full_name, mode) < 0)){
				bb_perror_msg("line %d: chmod failed for %s", linenum, full_name);
				ret = EXIT_FAILURE;
				goto loop;
			}
		} else
		{
			dev_t rdev;

			if (type == 'p') {
				mode |= S_IFIFO;
			}
			else if (type == 'c') {
				mode |= S_IFCHR;
			}
			else if (type == 'b') {
				mode |= S_IFBLK;
			} else {
				bb_error_msg("line %d: unsupported file type %c", linenum, type);
				ret = EXIT_FAILURE;
				goto loop;
			}

			if (count > 0) {
				int i;
				char *full_name_inc;

				full_name_inc = xmalloc(strlen(full_name) + 4);
				for (i = start; i < count; i++) {
					sprintf(full_name_inc, "%s%d", full_name, i);
					rdev = (major << 8) + minor + (i * increment - start);
					if (mknod(full_name_inc, mode, rdev) == -1) {
						bb_perror_msg("line %d: could not create node %s", linenum, full_name_inc);
						ret = EXIT_FAILURE;
					}
					else if (chown(full_name_inc, uid, gid) == -1) {
						bb_perror_msg("line %d: chown failed for %s", linenum, full_name_inc);
						ret = EXIT_FAILURE;
					}
					if ((mode != -1) && (chmod(full_name_inc, mode) < 0)){
						bb_perror_msg("line %d: chmod failed for %s", linenum, full_name_inc);
						ret = EXIT_FAILURE;
					}
				}
				free(full_name_inc);
			} else {
				rdev = (major << 8) + minor;
				if (mknod(full_name, mode, rdev) == -1) {
					bb_perror_msg("line %d: could not create node %s", linenum, full_name);
					ret = EXIT_FAILURE;
				}
				else if (chown(full_name, uid, gid) == -1) {
					bb_perror_msg("line %d: chown failed for %s", linenum, full_name);
					ret = EXIT_FAILURE;
				}
				if ((mode != -1) && (chmod(full_name, mode) < 0)){
					bb_perror_msg("line %d: chmod failed for %s", linenum, full_name);
					ret = EXIT_FAILURE;
				}
			}
		}
loop:
		free(line);
		free(full_name);
	}
	fclose(table);

	return ret;
}
Esempio n. 11
0
int file_mkdir_hier(const char *path, long mode)
{
    return bb_make_directory((char *)path, mode, FILEUTILS_RECUR);
}
Esempio n. 12
0
int patch_main(int argc, char **argv)
{
	int patch_level = -1;
	char *patch_line;
	int ret;
	FILE *patch_file = NULL;

	{
		char *p, *i;
		ret = getopt32(argv, "p:i:", &p, &i);
		if (ret & 1)
			patch_level = xatol_range(p, -1, USHRT_MAX);
		if (ret & 2) {
			patch_file = xfopen(i, "r");
		} else {
			patch_file = stdin;
		}
		ret = 0;
	}

	patch_line = xmalloc_getline(patch_file);
	while (patch_line) {
		FILE *src_stream;
		FILE *dst_stream;
		char *original_filename;
		char *new_filename;
		char *backup_filename;
		unsigned int src_cur_line = 1;
		unsigned int dest_cur_line = 0;
		unsigned int dest_beg_line;
		unsigned int bad_hunk_count = 0;
		unsigned int hunk_count = 0;
		char copy_trailing_lines_flag = 0;

		/* Skip everything upto the "---" marker
		 * No need to parse the lines "Only in <dir>", and "diff <args>"
		 */
		while (patch_line && strncmp(patch_line, "--- ", 4) != 0) {
			free(patch_line);
			patch_line = xmalloc_getline(patch_file);
		}
		/* FIXME: patch_line NULL check?? */

		/* Extract the filename used before the patch was generated */
		original_filename = extract_filename(patch_line, patch_level);
		free(patch_line);

		patch_line = xmalloc_getline(patch_file);
		/* FIXME: NULL check?? */
		if (strncmp(patch_line, "+++ ", 4) != 0) {
			ret = 2;
			bb_error_msg("invalid patch");
			continue;
		}
		new_filename = extract_filename(patch_line, patch_level);
		free(patch_line);

		if (file_doesnt_exist(new_filename)) {
			char *line_ptr;
			/* Create leading directories */
			line_ptr = strrchr(new_filename, '/');
			if (line_ptr) {
				*line_ptr = '\0';
				bb_make_directory(new_filename, -1, FILEUTILS_RECUR);
				*line_ptr = '/';
			}
			dst_stream = xfopen(new_filename, "w+");
			backup_filename = NULL;
		} else {
			backup_filename = xmalloc(strlen(new_filename) + 6);
			strcpy(backup_filename, new_filename);
			strcat(backup_filename, ".orig");
			if (rename(new_filename, backup_filename) == -1) {
				bb_perror_msg_and_die("cannot create file %s",
						backup_filename);
			}
			dst_stream = xfopen(new_filename, "w");
		}

		if ((backup_filename == NULL) || file_doesnt_exist(original_filename)) {
			src_stream = NULL;
		} else {
			if (strcmp(original_filename, new_filename) == 0) {
				src_stream = xfopen(backup_filename, "r");
			} else {
				src_stream = xfopen(original_filename, "r");
			}
		}

		printf("patching file %s\n", new_filename);

		/* Handle each hunk */
		patch_line = xmalloc_fgets(patch_file);
		while (patch_line) {
			unsigned int count;
			unsigned int src_beg_line;
			unsigned int unused;
			unsigned int hunk_offset_start = 0;
			int hunk_error = 0;

			/* This bit should be improved */
			if ((sscanf(patch_line, "@@ -%d,%d +%d,%d @@", &src_beg_line, &unused, &dest_beg_line, &unused) != 4) &&
				(sscanf(patch_line, "@@ -%d,%d +%d @@", &src_beg_line, &unused, &dest_beg_line) != 3) &&
				(sscanf(patch_line, "@@ -%d +%d,%d @@", &src_beg_line, &dest_beg_line, &unused) != 3)) {
				/* No more hunks for this file */
				break;
			}
			free(patch_line);
			hunk_count++;

			if (src_beg_line && dest_beg_line) {
				/* Copy unmodified lines upto start of hunk */
				/* src_beg_line will be 0 if its a new file */
				count = src_beg_line - src_cur_line;
				if (copy_lines(src_stream, dst_stream, count) != count) {
					bb_error_msg_and_die("bad src file");
				}
				src_cur_line += count;
				dest_cur_line += count;
				copy_trailing_lines_flag = 1;
			}
			hunk_offset_start = src_cur_line;

			while ((patch_line = xmalloc_fgets(patch_file)) != NULL) {
				if ((*patch_line == '-') || (*patch_line == ' ')) {
					char *src_line = NULL;
					if (src_stream) {
						src_line = xmalloc_fgets(src_stream);
						if (!src_line) {
							hunk_error++;
							break;
						} else {
							src_cur_line++;
						}
						if (strcmp(src_line, patch_line + 1) != 0) {
							bb_error_msg("hunk #%d FAILED at %d", hunk_count, hunk_offset_start);
							hunk_error++;
							free(patch_line);
							/* Probably need to find next hunk, etc... */
							/* but for now we just bail out */
							patch_line = NULL;
							break;
						}
						free(src_line);
					}
					if (*patch_line == ' ') {
						fputs(patch_line + 1, dst_stream);
						dest_cur_line++;
					}
				} else if (*patch_line == '+') {
					fputs(patch_line + 1, dst_stream);
					dest_cur_line++;
				} else {
					break;
				}
				free(patch_line);
			}
			if (hunk_error) {
				bad_hunk_count++;
			}
		}

		/* Cleanup last patched file */
		if (copy_trailing_lines_flag) {
			copy_lines(src_stream, dst_stream, -1);
		}
		if (src_stream) {
			fclose(src_stream);
		}
		if (dst_stream) {
			fclose(dst_stream);
		}
		if (bad_hunk_count) {
			if (!ret) {
				ret = 1;
			}
			bb_error_msg("%d out of %d hunk FAILED", bad_hunk_count, hunk_count);
		} else {
			/* It worked, we can remove the backup */
			if (backup_filename) {
				unlink(backup_filename);
			}
			if ((dest_cur_line == 0) || (dest_beg_line == 0)) {
				/* The new patched file is empty, remove it */
				xunlink(new_filename);
				if (strcmp(new_filename, original_filename) != 0)
					xunlink(original_filename);
			}
		}
	}

	/* 0 = SUCCESS
	 * 1 = Some hunks failed
	 * 2 = More serious problems
	 */
	return ret;
}
void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
{
	file_header_t *file_header = archive_handle->file_header;
	int dst_fd;
	int res;

#if ENABLE_FEATURE_TAR_SELINUX
	char *sctx = archive_handle->tar__sctx[PAX_NEXT_FILE];
#ifdef __BIONIC__
	matchpathcon_init(NULL);
#endif
	if (!sctx)
		sctx = archive_handle->tar__sctx[PAX_GLOBAL];
	if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */
		setfscreatecon(sctx);
		free(archive_handle->tar__sctx[PAX_NEXT_FILE]);
		archive_handle->tar__sctx[PAX_NEXT_FILE] = NULL;
	}
#endif

	if (archive_handle->ah_flags & ARCHIVE_CREATE_LEADING_DIRS) {
		char *slash = strrchr(file_header->name, '/');
		if (slash) {
			*slash = '\0';
			bb_make_directory(file_header->name, -1, FILEUTILS_RECUR);
			*slash = '/';
		}
	}

	if (archive_handle->ah_flags & ARCHIVE_UNLINK_OLD) {
		/* Remove the entry if it exists */
		if (!S_ISDIR(file_header->mode)) {
			/* Is it hardlink?
			 * We encode hard links as regular files of size 0 with a symlink */
			if (S_ISREG(file_header->mode)
			 && file_header->link_target
			 && file_header->size == 0
			) {
				/* Ugly special case:
				 * tar cf t.tar hardlink1 hardlink2 hardlink1
				 * results in this tarball structure:
				 * hardlink1
				 * hardlink2 -> hardlink1
				 * hardlink1 -> hardlink1 <== !!!
				 */
				if (strcmp(file_header->link_target, file_header->name) == 0)
					goto ret;
			}
			/* Proceed with deleting */
			if (unlink(file_header->name) == -1
			 && errno != ENOENT
			) {
				bb_perror_msg_and_die("can't remove old file %s",
						file_header->name);
			}
		}
	}
	else if (archive_handle->ah_flags & ARCHIVE_EXTRACT_NEWER) {
		/* Remove the existing entry if its older than the extracted entry */
		struct stat existing_sb;
		if (lstat(file_header->name, &existing_sb) == -1) {
			if (errno != ENOENT) {
				bb_perror_msg_and_die("can't stat old file");
			}
		}
		else if ((time_t) existing_sb.st_mtime >= (time_t) file_header->mtime) {
			if (!(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)
			 && !S_ISDIR(file_header->mode)
			) {
				bb_error_msg("%s not created: newer or "
					"same age file exists", file_header->name);
			}
			data_skip(archive_handle);
			goto ret;
		}
		else if ((unlink(file_header->name) == -1) && (errno != EISDIR)) {
			bb_perror_msg_and_die("can't remove old file %s",
					file_header->name);
		}
	}

	/* Handle hard links separately
	 * We encode hard links as regular files of size 0 with a symlink */
	if (S_ISREG(file_header->mode)
	 && file_header->link_target
	 && file_header->size == 0
	) {
		/* hard link */
		res = link(file_header->link_target, file_header->name);
		if ((res == -1) && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) {
			bb_perror_msg("can't create %slink "
					"from %s to %s", "hard",
					file_header->name,
					file_header->link_target);
		}
		/* Hardlinks have no separate mode/ownership, skip chown/chmod */
		goto ret;
	}

	/* Create the filesystem entry */
	switch (file_header->mode & S_IFMT) {
	case S_IFREG: {
		/* Regular file */
		char *dst_name;
		int flags = O_WRONLY | O_CREAT | O_EXCL;
		if (archive_handle->ah_flags & ARCHIVE_O_TRUNC)
			flags = O_WRONLY | O_CREAT | O_TRUNC;
		dst_name = file_header->name;
#ifdef ARCHIVE_REPLACE_VIA_RENAME
		if (archive_handle->ah_flags & ARCHIVE_REPLACE_VIA_RENAME)
			/* rpm-style temp file name */
			dst_name = xasprintf("%s;%x", dst_name, (int)getpid());
#endif
		dst_fd = xopen3(dst_name,
			flags,
			file_header->mode
			);
		bb_copyfd_exact_size(archive_handle->src_fd, dst_fd, file_header->size);
		close(dst_fd);
#ifdef ARCHIVE_REPLACE_VIA_RENAME
		if (archive_handle->ah_flags & ARCHIVE_REPLACE_VIA_RENAME) {
			xrename(dst_name, file_header->name);
			free(dst_name);
		}
#endif
		break;
	}
	case S_IFDIR:
		res = mkdir(file_header->name, file_header->mode);
		if ((res == -1)
		 && (errno != EISDIR) /* btw, Linux doesn't return this */
		 && (errno != EEXIST)
		 && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)
		) {
			bb_perror_msg("can't make dir %s", file_header->name);
		}
		break;
	case S_IFLNK:
		/* Symlink */
//TODO: what if file_header->link_target == NULL (say, corrupted tarball?)
		res = symlink(file_header->link_target, file_header->name);
		if ((res == -1)
		 && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)
		) {
			bb_perror_msg("can't create %slink "
				"from %s to %s", "sym",
				file_header->name,
				file_header->link_target);
		}
		break;
	case S_IFSOCK:
	case S_IFBLK:
	case S_IFCHR:
	case S_IFIFO:
		res = mknod(file_header->name, file_header->mode, file_header->device);
		if ((res == -1)
		 && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)
		) {
			bb_perror_msg("can't create node %s", file_header->name);
		}
		break;
	default:
		bb_error_msg_and_die("unrecognized file type");
	}

	if (!S_ISLNK(file_header->mode)) {
		if (!(archive_handle->ah_flags & ARCHIVE_DONT_RESTORE_OWNER)) {
			uid_t uid = file_header->uid;
			gid_t gid = file_header->gid;
#if ENABLE_FEATURE_TAR_UNAME_GNAME
			if (!(archive_handle->ah_flags & ARCHIVE_NUMERIC_OWNER)) {
				if (file_header->tar__uname) {
//TODO: cache last name/id pair?
					struct passwd *pwd = getpwnam(file_header->tar__uname);
					if (pwd) uid = pwd->pw_uid;
				}
				if (file_header->tar__gname) {
					struct group *grp = getgrnam(file_header->tar__gname);
					if (grp) gid = grp->gr_gid;
				}
			}
#endif
			/* GNU tar 1.15.1 uses chown, not lchown */
			chown(file_header->name, uid, gid);
		}
		/* uclibc has no lchmod, glibc is even stranger -
		 * it has lchmod which seems to do nothing!
		 * so we use chmod... */
		if (!(archive_handle->ah_flags & ARCHIVE_DONT_RESTORE_PERM)) {
			chmod(file_header->name, file_header->mode);
		}
		if (archive_handle->ah_flags & ARCHIVE_RESTORE_DATE) {
			struct timeval t[2];

			t[1].tv_sec = t[0].tv_sec = file_header->mtime;
			t[1].tv_usec = t[0].tv_usec = 0;
			utimes(file_header->name, t);
		}
	}

 ret: ;
#if ENABLE_FEATURE_TAR_SELINUX
	if (sctx) {
		/* reset the context after creating an entry */
		setfscreatecon(NULL);
	}
#endif
}
Esempio n. 14
0
int patch_main(int argc UNUSED_PARAM, char **argv)
{
	struct stat saved_stat;
	char *patch_line;
	FILE *patch_file;
	int patch_level;
	int ret = 0;
	char plus = '+';
	unsigned opt;
	enum {
		OPT_R = (1 << 2),
		OPT_N = (1 << 3),
		/*OPT_f = (1 << 4), ignored */
		/*OPT_E = (1 << 5), ignored, this is the default */
		/*OPT_g = (1 << 6), ignored */
		OPT_dry_run = (1 << 7) * ENABLE_LONG_OPTS,
	};

	xfunc_error_retval = 2;
	{
		const char *p = "-1";
		const char *i = "-"; /* compat */
#if ENABLE_LONG_OPTS
		static const char patch_longopts[] ALIGN1 =
			"strip\0"                 Required_argument "p"
			"input\0"                 Required_argument "i"
			"reverse\0"               No_argument       "R"
			"forward\0"               No_argument       "N"
		/* "Assume user knows what [s]he is doing, do not ask any questions": */
			"force\0"                 No_argument       "f" /*ignored*/
# if ENABLE_DESKTOP
			"remove-empty-files\0"    No_argument       "E" /*ignored*/
		/* "Controls actions when a file is under RCS or SCCS control,
		 * and does not exist or is read-only and matches the default version,
		 * or when a file is under ClearCase control and does not exist..."
		 * IOW: rather obscure option.
		 * But Gentoo's portage does use -g0 */
			"get\0"                   Required_argument "g" /*ignored*/
# endif
			"dry-run\0"               No_argument       "\xfd"
# if ENABLE_DESKTOP
			"backup-if-mismatch\0"    No_argument       "\xfe" /*ignored*/
			"no-backup-if-mismatch\0" No_argument       "\xff" /*ignored*/
# endif
			;
		applet_long_options = patch_longopts;
#endif
		/* -f,-E,-g are ignored */
		opt = getopt32(argv, "p:i:RN""fEg:", &p, &i, NULL);
		if (opt & OPT_R)
			plus = '-';
		patch_level = xatoi(p); /* can be negative! */
		patch_file = xfopen_stdin(i);
	}

	patch_line = xmalloc_fgetline(patch_file);
	while (patch_line) {
		FILE *src_stream;
		FILE *dst_stream;
		//char *old_filename;
		char *new_filename;
		char *backup_filename = NULL;
		unsigned src_cur_line = 1;
		unsigned dst_cur_line = 0;
		unsigned dst_beg_line;
		unsigned bad_hunk_count = 0;
		unsigned hunk_count = 0;
		smallint copy_trailing_lines_flag = 0;

		/* Skip everything upto the "---" marker
		 * No need to parse the lines "Only in <dir>", and "diff <args>"
		 */
		do {
			/* Extract the filename ugsed before the patch was generated */
			new_filename = extract_filename(patch_line, patch_level, "--- ");
			// was old_filename above
			patch_line = xmalloc_fgetline(patch_file);
			if (!patch_line) goto quit;
		} while (!new_filename);
		free(new_filename); // "source" filename is irrelevant

		new_filename = extract_filename(patch_line, patch_level, "+++ ");
		if (!new_filename) {
			bb_error_msg_and_die("invalid patch");
		}

		/* Get access rights from the file to be patched */
		if (stat(new_filename, &saved_stat) != 0) {
			char *slash = strrchr(new_filename, '/');
			if (slash) {
				/* Create leading directories */
				*slash = '\0';
				bb_make_directory(new_filename, -1, FILEUTILS_RECUR);
				*slash = '/';
			}
			src_stream = NULL;
			saved_stat.st_mode = 0644;
		} else if (!(opt & OPT_dry_run)) {
			backup_filename = xasprintf("%s.orig", new_filename);
			xrename(new_filename, backup_filename);
			src_stream = xfopen_for_read(backup_filename);
		} else
			src_stream = xfopen_for_read(new_filename);

		if (opt & OPT_dry_run) {
			dst_stream = xfopen_for_write("/dev/null");
		} else {
			dst_stream = xfopen_for_write(new_filename);
			fchmod(fileno(dst_stream), saved_stat.st_mode);
		}

		printf("patching file %s\n", new_filename);

		/* Handle all hunks for this file */
		patch_line = xmalloc_fgets(patch_file);
		while (patch_line) {
			unsigned count;
			unsigned src_beg_line;
			unsigned hunk_offset_start;
			unsigned src_last_line = 1;
			unsigned dst_last_line = 1;

			if ((sscanf(patch_line, "@@ -%u,%u +%u,%u", &src_beg_line, &src_last_line, &dst_beg_line, &dst_last_line) < 3)
			 && (sscanf(patch_line, "@@ -%u +%u,%u", &src_beg_line, &dst_beg_line, &dst_last_line) < 2)
			) {
				/* No more hunks for this file */
				break;
			}
			if (plus != '+') {
				/* reverse patch */
				unsigned tmp = src_last_line;
				src_last_line = dst_last_line;
				dst_last_line = tmp;
				tmp = src_beg_line;
				src_beg_line = dst_beg_line;
				dst_beg_line = tmp;
			}
			hunk_count++;

			if (src_beg_line && dst_beg_line) {
				/* Copy unmodified lines upto start of hunk */
				/* src_beg_line will be 0 if it's a new file */
				count = src_beg_line - src_cur_line;
				if (copy_lines(src_stream, dst_stream, count)) {
					bb_error_msg_and_die("bad src file");
				}
				src_cur_line += count;
				dst_cur_line += count;
				copy_trailing_lines_flag = 1;
			}
			src_last_line += hunk_offset_start = src_cur_line;
			dst_last_line += dst_cur_line;

			while (1) {
				free(patch_line);
				patch_line = xmalloc_fgets(patch_file);
				if (patch_line == NULL)
					break; /* EOF */
				if (!*patch_line) {
					/* whitespace-damaged patch with "" lines */
					free(patch_line);
					patch_line = xstrdup(" ");
				}
				if ((*patch_line != '-') && (*patch_line != '+')
				 && (*patch_line != ' ')
				) {
					break; /* End of hunk */
				}
				if (*patch_line != plus) { /* '-' or ' ' */
					char *src_line = NULL;
					if (src_cur_line == src_last_line)
						break;
					if (src_stream) {
						src_line = xmalloc_fgets(src_stream);
						if (src_line) {
							int diff = strcmp(src_line, patch_line + 1);
							src_cur_line++;
							free(src_line);
							if (diff)
								src_line = NULL;
						}
					}
					/* Do not patch an already patched hunk with -N */
					if (src_line == 0 && (opt & OPT_N)) {
						continue;
					}
					if (!src_line) {
						bb_error_msg("hunk #%u FAILED at %u", hunk_count, hunk_offset_start);
						bad_hunk_count++;
						break;
					}
					if (*patch_line != ' ') { /* '-' */
						continue;
					}
				}
				if (dst_cur_line == dst_last_line)
					break;
				fputs(patch_line + 1, dst_stream);
				dst_cur_line++;
			} /* end of while loop handling one hunk */
		} /* end of while loop handling one file */

		/* Cleanup last patched file */
		if (copy_trailing_lines_flag) {
			copy_lines(src_stream, dst_stream, (unsigned)(-1));
		}
		if (src_stream) {
			fclose(src_stream);
		}
		fclose(dst_stream);
		if (bad_hunk_count) {
			ret = 1;
			bb_error_msg("%u out of %u hunk FAILED", bad_hunk_count, hunk_count);
		} else {
			/* It worked, we can remove the backup */
			if (backup_filename) {
				unlink(backup_filename);
			}
			if (!(opt & OPT_dry_run)
			 && ((dst_cur_line == 0) || (dst_beg_line == 0))
			) {
				/* The new patched file is empty, remove it */
				xunlink(new_filename);
				// /* old_filename and new_filename may be the same file */
				// unlink(old_filename);
			}
		}
		free(backup_filename);
		//free(old_filename);
		free(new_filename);
	} /* end of "while there are patch lines" */
 quit:
	/* 0 = SUCCESS
	 * 1 = Some hunks failed
	 * 2 = More serious problems (exited earlier)
	 */
	return ret;
}
Esempio n. 15
0
int patch_main(int argc UNUSED_PARAM, char **argv)
{
	struct stat saved_stat;
	char *patch_line;
	FILE *patch_file;
	int patch_level;
	int ret = 0;
	char plus = '+';

	xfunc_error_retval = 2;
	{
		const char *p = "-1";
		const char *i = "-"; /* compat */
		if (getopt32(argv, "p:i:R", &p, &i) & 4)
			plus = '-';
		patch_level = xatoi(p); /* can be negative! */
		patch_file = xfopen_stdin(i);
	}

	patch_line = xmalloc_fgetline(patch_file);
	while (patch_line) {
		FILE *src_stream;
		FILE *dst_stream;
		//char *old_filename;
		char *new_filename;
		char *backup_filename;
		unsigned src_cur_line = 1;
		unsigned dst_cur_line = 0;
		unsigned dst_beg_line;
		unsigned bad_hunk_count = 0;
		unsigned hunk_count = 0;
		smallint copy_trailing_lines_flag = 0;

		/* Skip everything upto the "---" marker
		 * No need to parse the lines "Only in <dir>", and "diff <args>"
		 */
		do {
			/* Extract the filename used before the patch was generated */
			new_filename = extract_filename(patch_line, patch_level, "--- ");
			// was old_filename above
			patch_line = xmalloc_fgetline(patch_file);
			if (!patch_line) goto quit;
		} while (!new_filename);
		free(new_filename); // "source" filename is irrelevant

		new_filename = extract_filename(patch_line, patch_level, "+++ ");
		if (!new_filename) {
			bb_error_msg_and_die("invalid patch");
		}

		/* Get access rights from the file to be patched */
		if (stat(new_filename, &saved_stat) != 0) {
			char *slash = strrchr(new_filename, '/');
			if (slash) {
				/* Create leading directories */
				*slash = '\0';
				bb_make_directory(new_filename, -1, FILEUTILS_RECUR);
				*slash = '/';
			}
			backup_filename = NULL;
			src_stream = NULL;
			saved_stat.st_mode = 0644;
		} else {
			backup_filename = xasprintf("%s.orig", new_filename);
			xrename(new_filename, backup_filename);
			src_stream = xfopen_for_read(backup_filename);
		}
		dst_stream = xfopen_for_write(new_filename);
		fchmod(fileno(dst_stream), saved_stat.st_mode);

		printf("patching file %s\n", new_filename);

		/* Handle all hunks for this file */
		patch_line = xmalloc_fgets(patch_file);
		while (patch_line) {
			unsigned count;
			unsigned src_beg_line;
			unsigned hunk_offset_start;
			unsigned src_last_line = 1;
			unsigned dst_last_line = 1;

			if ((sscanf(patch_line, "@@ -%d,%d +%d,%d", &src_beg_line, &src_last_line, &dst_beg_line, &dst_last_line) < 3)
			 && (sscanf(patch_line, "@@ -%d +%d,%d", &src_beg_line, &dst_beg_line, &dst_last_line) < 2)
			) {
				/* No more hunks for this file */
				break;
			}
			if (plus != '+') {
				/* reverse patch */
				unsigned tmp = src_last_line;
				src_last_line = dst_last_line;
				dst_last_line = tmp;
				tmp = src_beg_line;
				src_beg_line = dst_beg_line;
				dst_beg_line = tmp;
			}
			hunk_count++;

			if (src_beg_line && dst_beg_line) {
				/* Copy unmodified lines upto start of hunk */
				/* src_beg_line will be 0 if it's a new file */
				count = src_beg_line - src_cur_line;
				if (copy_lines(src_stream, dst_stream, count)) {
					bb_error_msg_and_die("bad src file");
				}
				src_cur_line += count;
				dst_cur_line += count;
				copy_trailing_lines_flag = 1;
			}
			src_last_line += hunk_offset_start = src_cur_line;
			dst_last_line += dst_cur_line;

			while (1) {
				free(patch_line);
				patch_line = xmalloc_fgets(patch_file);
				if (patch_line == NULL)
					break; /* EOF */
				if ((*patch_line != '-') && (*patch_line != '+')
				 && (*patch_line != ' ')
				) {
					break; /* End of hunk */
				}
				if (*patch_line != plus) { /* '-' or ' ' */
					char *src_line = NULL;
					if (src_cur_line == src_last_line)
						break;
					if (src_stream) {
						src_line = xmalloc_fgets(src_stream);
						if (src_line) {
							int diff = strcmp(src_line, patch_line + 1);
							src_cur_line++;
							free(src_line);
							if (diff)
								src_line = NULL;
						}
					}
					if (!src_line) {
						bb_error_msg("hunk #%u FAILED at %u", hunk_count, hunk_offset_start);
						bad_hunk_count++;
						break;
					}
					if (*patch_line != ' ') { /* '-' */
						continue;
					}
				}
				if (dst_cur_line == dst_last_line)
					break;
				fputs(patch_line + 1, dst_stream);
				dst_cur_line++;
			} /* end of while loop handling one hunk */
		} /* end of while loop handling one file */

		/* Cleanup last patched file */
		if (copy_trailing_lines_flag) {
			copy_lines(src_stream, dst_stream, (unsigned)(-1));
		}
		if (src_stream) {
			fclose(src_stream);
		}
		fclose(dst_stream);
		if (bad_hunk_count) {
			ret = 1;
			bb_error_msg("%u out of %u hunk FAILED", bad_hunk_count, hunk_count);
		} else {
			/* It worked, we can remove the backup */
			if (backup_filename) {
				unlink(backup_filename);
			}
			if ((dst_cur_line == 0) || (dst_beg_line == 0)) {
				/* The new patched file is empty, remove it */
				xunlink(new_filename);
				// /* old_filename and new_filename may be the same file */
				// unlink(old_filename);
			}
		}
		free(backup_filename);
		//free(old_filename);
		free(new_filename);
	} /* end of "while there are patch lines" */
 quit:
	/* 0 = SUCCESS
	 * 1 = Some hunks failed
	 * 2 = More serious problems (exited earlier)
	 */
	return ret;
}
Esempio n. 16
0
int unzip_main(int argc, char **argv)
{
	enum { O_PROMPT, O_NEVER, O_ALWAYS };

	zip_header_t zip_header;
	smallint verbose = 1;
	smallint listing = 0;
	smallint overwrite = O_PROMPT;
	unsigned total_size;
	unsigned total_entries;
	int src_fd = -1;
	int dst_fd = -1;
	char *src_fn = NULL;
	char *dst_fn = NULL;
	llist_t *zaccept = NULL;
	llist_t *zreject = NULL;
	char *base_dir = NULL;
	int i, opt;
	int opt_range = 0;
	char key_buf[80];
	struct stat stat_buf;

	/* '-' makes getopt return 1 for non-options */
	while ((opt = getopt(argc, argv, "-d:lnopqx")) != -1) {
		switch (opt_range) {
		case 0: /* Options */
			switch (opt) {
			case 'l': /* List */
				listing = 1;
				break;

			case 'n': /* Never overwrite existing files */
				overwrite = O_NEVER;
				break;

			case 'o': /* Always overwrite existing files */
				overwrite = O_ALWAYS;
				break;

			case 'p': /* Extract files to stdout and fall through to set verbosity */
				dst_fd = STDOUT_FILENO;

			case 'q': /* Be quiet */
				verbose = 0;
				break;

			case 1: /* The zip file */
				/* +5: space for ".zip" and NUL */
				src_fn = xmalloc(strlen(optarg) + 5);
				strcpy(src_fn, optarg);
				opt_range++;
				break;

			default:
				bb_show_usage();

			}
			break;

		case 1: /* Include files */
			if (opt == 1) {
				llist_add_to(&zaccept, optarg);
				break;
			}
			if (opt == 'd') {
				base_dir = optarg;
				opt_range += 2;
				break;
			}
			if (opt == 'x') {
				opt_range++;
				break;
			}
			bb_show_usage();

		case 2 : /* Exclude files */
			if (opt == 1) {
				llist_add_to(&zreject, optarg);
				break;
			}
			if (opt == 'd') { /* Extract to base directory */
				base_dir = optarg;
				opt_range++;
				break;
			}
			/* fall through */

		default:
			bb_show_usage();
		}
	}

	if (src_fn == NULL) {
		bb_show_usage();
	}

	/* Open input file */
	if (LONE_DASH(src_fn)) {
		src_fd = STDIN_FILENO;
		/* Cannot use prompt mode since zip data is arriving on STDIN */
		if (overwrite == O_PROMPT)
			overwrite = O_NEVER;
	} else {
		static const char extn[][5] = {"", ".zip", ".ZIP"};
		int orig_src_fn_len = strlen(src_fn);

		for (i = 0; (i < 3) && (src_fd == -1); i++) {
			strcpy(src_fn + orig_src_fn_len, extn[i]);
			src_fd = open(src_fn, O_RDONLY);
		}
		if (src_fd == -1) {
			src_fn[orig_src_fn_len] = '\0';
			bb_error_msg_and_die("can't open %s, %s.zip, %s.ZIP", src_fn, src_fn, src_fn);
		}
	}

	/* Change dir if necessary */
	if (base_dir)
		xchdir(base_dir);

	if (verbose) {
		printf("Archive:  %s\n", src_fn);
		if (listing){
			puts("  Length     Date   Time    Name\n"
			     " --------    ----   ----    ----");
		}
	}

	total_size = 0;
	total_entries = 0;
	while (1) {
		uint32_t magic;

		/* Check magic number */
		xread(src_fd, &magic, 4);
		if (magic == ZIP_CDS_MAGIC)
			break;
		if (magic != ZIP_FILEHEADER_MAGIC)
			bb_error_msg_and_die("invalid zip magic %08X", magic);

		/* Read the file header */
		xread(src_fd, zip_header.raw, ZIP_HEADER_LEN);
		FIX_ENDIANNESS(zip_header);
		if ((zip_header.formatted.method != 0) && (zip_header.formatted.method != 8)) {
			bb_error_msg_and_die("unsupported method %d", zip_header.formatted.method);
		}

		/* Read filename */
		free(dst_fn);
		dst_fn = xzalloc(zip_header.formatted.filename_len + 1);
		xread(src_fd, dst_fn, zip_header.formatted.filename_len);

		/* Skip extra header bytes */
		unzip_skip(src_fd, zip_header.formatted.extra_len);

		/* Filter zip entries */
		if (find_list_entry(zreject, dst_fn)
		 || (zaccept && !find_list_entry(zaccept, dst_fn))
		) { /* Skip entry */
			i = 'n';

		} else { /* Extract entry */
			if (listing) { /* List entry */
				if (verbose) {
					unsigned dostime = zip_header.formatted.modtime | (zip_header.formatted.moddate << 16);
					printf("%9u  %02u-%02u-%02u %02u:%02u   %s\n",
					   zip_header.formatted.ucmpsize,
					   (dostime & 0x01e00000) >> 21,
					   (dostime & 0x001f0000) >> 16,
					   (((dostime & 0xfe000000) >> 25) + 1980) % 100,
					   (dostime & 0x0000f800) >> 11,
					   (dostime & 0x000007e0) >> 5,
					   dst_fn);
					total_size += zip_header.formatted.ucmpsize;
					total_entries++;
				} else {
					/* short listing -- filenames only */
					puts(dst_fn);
				}
				i = 'n';
			} else if (dst_fd == STDOUT_FILENO) { /* Extracting to STDOUT */
				i = -1;
			} else if (last_char_is(dst_fn, '/')) { /* Extract directory */
				if (stat(dst_fn, &stat_buf) == -1) {
					if (errno != ENOENT) {
						bb_perror_msg_and_die("cannot stat '%s'",dst_fn);
					}
					if (verbose) {
						printf("   creating: %s\n", dst_fn);
					}
					unzip_create_leading_dirs(dst_fn);
					if (bb_make_directory(dst_fn, 0777, 0)) {
						bb_error_msg_and_die("exiting");
					}
				} else {
					if (!S_ISDIR(stat_buf.st_mode)) {
						bb_error_msg_and_die("'%s' exists but is not directory", dst_fn);
					}
				}
				i = 'n';

			} else {  /* Extract file */
 _check_file:
				if (stat(dst_fn, &stat_buf) == -1) { /* File does not exist */
					if (errno != ENOENT) {
						bb_perror_msg_and_die("cannot stat '%s'",dst_fn);
					}
					i = 'y';
				} else { /* File already exists */
					if (overwrite == O_NEVER) {
						i = 'n';
					} else if (S_ISREG(stat_buf.st_mode)) { /* File is regular file */
						if (overwrite == O_ALWAYS) {
							i = 'y';
						} else {
							printf("replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ", dst_fn);
							if (!fgets(key_buf, sizeof(key_buf), stdin)) {
								bb_perror_msg_and_die("cannot read input");
							}
							i = key_buf[0];
						}
					} else { /* File is not regular file */
						bb_error_msg_and_die("'%s' exists but is not regular file",dst_fn);
					}
				}
			}
		}
Esempio n. 17
0
int makedevs_main(int argc UNUSED_PARAM, char **argv)
{
	parser_t *parser;
	char *line = (char *)"-";
	int ret = EXIT_SUCCESS;

	opt_complementary = "=1"; /* exactly one param */
	getopt32(argv, "d:", &line);
	argv += optind;

	xchdir(*argv); /* ensure root dir exists */

	umask(0);

	printf("rootdir=%s\ntable=", *argv);
	if (NOT_LONE_DASH(line)) {
		printf("'%s'\n", line);
	} else {
		puts("<stdin>");
	}

	parser = config_open(line);
	while (config_read(parser, &line, 1, 1, "# \t", PARSE_NORMAL)) {
		int linenum;
		char type;
		unsigned mode = 0755;
		unsigned major = 0;
		unsigned minor = 0;
		unsigned count = 0;
		unsigned increment = 0;
		unsigned start = 0;
		char name[41];
		char user[41];
		char group[41];
		char *full_name = name;
		uid_t uid;
		gid_t gid;

		linenum = parser->lineno;

		if ((2 > sscanf(line, "%40s %c %o %40s %40s %u %u %u %u %u",
					name, &type, &mode, user, group,
					&major, &minor, &start, &increment, &count))
		 || ((unsigned)(major | minor | start | count | increment) > 255)
		) {
			bb_error_msg("invalid line %d: '%s'", linenum, line);
			ret = EXIT_FAILURE;
			continue;
		}

		gid = (*group) ? get_ug_id(group, xgroup2gid) : getgid();
		uid = (*user) ? get_ug_id(user, xuname2uid) : getuid();
		/* We are already in the right root dir,
		 * so make absolute paths relative */
		if ('/' == *full_name)
			full_name++;

		if (type == 'd') {
			bb_make_directory(full_name, mode | S_IFDIR, FILEUTILS_RECUR);
			if (chown(full_name, uid, gid) == -1) {
 chown_fail:
				bb_perror_msg("line %d: can't chown %s", linenum, full_name);
				ret = EXIT_FAILURE;
				continue;
			}
			if (chmod(full_name, mode) < 0) {
 chmod_fail:
				bb_perror_msg("line %d: can't chmod %s", linenum, full_name);
				ret = EXIT_FAILURE;
				continue;
			}
		} else if (type == 'f') {
			struct stat st;
			if ((stat(full_name, &st) < 0 || !S_ISREG(st.st_mode))) {
				bb_perror_msg("line %d: regular file '%s' does not exist", linenum, full_name);
				ret = EXIT_FAILURE;
				continue;
			}
			if (chown(full_name, uid, gid) < 0)
				goto chown_fail;
			if (chmod(full_name, mode) < 0)
				goto chmod_fail;
		} else {
			dev_t rdev;
			unsigned i;
			char *full_name_inc;

			if (type == 'p') {
				mode |= S_IFIFO;
			} else if (type == 'c') {
				mode |= S_IFCHR;
			} else if (type == 'b') {
				mode |= S_IFBLK;
			} else {
				bb_error_msg("line %d: unsupported file type %c", linenum, type);
				ret = EXIT_FAILURE;
				continue;
			}

			full_name_inc = xmalloc(strlen(full_name) + sizeof(int)*3 + 2);
			if (count)
				count--;
			for (i = start; i <= start + count; i++) {
				sprintf(full_name_inc, count ? "%s%u" : "%s", full_name, i);
				rdev = makedev(major, minor + (i - start) * increment);
				if (mknod(full_name_inc, mode, rdev) != 0
				 && errno != EEXIST
				) {
					bb_perror_msg("line %d: can't create node %s", linenum, full_name_inc);
					ret = EXIT_FAILURE;
				} else if (chown(full_name_inc, uid, gid) < 0) {
					bb_perror_msg("line %d: can't chown %s", linenum, full_name_inc);
					ret = EXIT_FAILURE;
				} else if (chmod(full_name_inc, mode) < 0) {
					bb_perror_msg("line %d: can't chmod %s", linenum, full_name_inc);
					ret = EXIT_FAILURE;
				}
			}
			free(full_name_inc);
		}
	}
	if (ENABLE_FEATURE_CLEAN_UP)
		config_close(parser);

	return ret;
}
Esempio n. 18
0
int install_main(int argc, char **argv)
{
	struct stat statbuf;
	mode_t mode;
	uid_t uid;
	gid_t gid;
	char *arg, *last;
	const char *gid_str;
	const char *uid_str;
	const char *mode_str;
	int copy_flags = FILEUTILS_DEREFERENCE | FILEUTILS_FORCE;
	int opts;
	int min_args = 1;
	int ret = EXIT_SUCCESS;
	int isdir = 0;
#if ENABLE_SELINUX
	security_context_t scontext;
	bool use_default_selinux_context = 1;
#endif
	enum {
		OPT_c             = 1 << 0,
		OPT_v             = 1 << 1,
		OPT_b             = 1 << 2,
		OPT_MKDIR_LEADING = 1 << 3,
		OPT_DIRECTORY     = 1 << 4,
		OPT_PRESERVE_TIME = 1 << 5,
		OPT_STRIP         = 1 << 6,
		OPT_GROUP         = 1 << 7,
		OPT_MODE          = 1 << 8,
		OPT_OWNER         = 1 << 9,
#if ENABLE_SELINUX
		OPT_SET_SECURITY_CONTEXT = 1 << 10,
		OPT_PRESERVE_SECURITY_CONTEXT = 1 << 11,
#endif
	};

#if ENABLE_FEATURE_INSTALL_LONG_OPTIONS
	applet_long_options = install_longopts;
#endif
	opt_complementary = "s--d:d--s" IF_FEATURE_INSTALL_LONG_OPTIONS(IF_SELINUX(":Z--\xff:\xff--Z"));
	/* -c exists for backwards compatibility, it's needed */
	/* -v is ignored ("print name of each created directory") */
	/* -b is ignored ("make a backup of each existing destination file") */
	opts = getopt32(argv, "cvb" "Ddpsg:m:o:" IF_SELINUX("Z:"),
			&gid_str, &mode_str, &uid_str IF_SELINUX(, &scontext));
	argc -= optind;
	argv += optind;

#if ENABLE_SELINUX
	if (opts & (OPT_PRESERVE_SECURITY_CONTEXT|OPT_SET_SECURITY_CONTEXT)) {
		selinux_or_die();
		use_default_selinux_context = 0;
		if (opts & OPT_PRESERVE_SECURITY_CONTEXT) {
			copy_flags |= FILEUTILS_PRESERVE_SECURITY_CONTEXT;
		}
		if (opts & OPT_SET_SECURITY_CONTEXT) {
			setfscreatecon_or_die(scontext);
			copy_flags |= FILEUTILS_SET_SECURITY_CONTEXT;
		}
	}
#endif

	/* preserve access and modification time, this is GNU behaviour,
	 * BSD only preserves modification time */
	if (opts & OPT_PRESERVE_TIME) {
		copy_flags |= FILEUTILS_PRESERVE_STATUS;
	}
	mode = 0755; /* GNU coreutils 6.10 compat */
	if (opts & OPT_MODE)
		bb_parse_mode(mode_str, &mode);
	uid = (opts & OPT_OWNER) ? get_ug_id(uid_str, xuname2uid) : getuid();
	gid = (opts & OPT_GROUP) ? get_ug_id(gid_str, xgroup2gid) : getgid();

	last = argv[argc - 1];
	if (!(opts & OPT_DIRECTORY)) {
		argv[argc - 1] = NULL;
		min_args++;

		/* coreutils install resolves link in this case, don't use lstat */
		isdir = stat(last, &statbuf) < 0 ? 0 : S_ISDIR(statbuf.st_mode);
	}

	if (argc < min_args)
		bb_show_usage();

	while ((arg = *argv++) != NULL) {
		char *dest = last;
		if (opts & OPT_DIRECTORY) {
			dest = arg;
			/* GNU coreutils 6.9 does not set uid:gid
			 * on intermediate created directories
			 * (only on last one) */
			if (bb_make_directory(dest, 0755, FILEUTILS_RECUR)) {
				ret = EXIT_FAILURE;
				goto next;
			}
		} else {
			if (opts & OPT_MKDIR_LEADING) {
				char *ddir = xstrdup(dest);
				bb_make_directory(dirname(ddir), 0755, FILEUTILS_RECUR);
				/* errors are not checked. copy_file
				 * will fail if dir is not created. */
				free(ddir);
			}
			if (isdir)
				dest = concat_path_file(last, bb_basename(arg));
			if (copy_file(arg, dest, copy_flags) != 0) {
				/* copy is not made */
				ret = EXIT_FAILURE;
				goto next;
			}
			if (opts & OPT_STRIP) {
				char *args[4];
				args[0] = (char*)"strip";
				args[1] = (char*)"-p"; /* -p --preserve-dates */
				args[2] = dest;
				args[3] = NULL;
				if (spawn_and_wait(args)) {
					bb_perror_msg("strip");
					ret = EXIT_FAILURE;
				}
			}
		}

		/* Set the file mode (always, not only with -m).
		 * GNU coreutils 6.10 is not affected by umask. */
		if (chmod(dest, mode) == -1) {
			bb_perror_msg("can't change %s of %s", "permissions", dest);
			ret = EXIT_FAILURE;
		}
#if ENABLE_SELINUX
		if (use_default_selinux_context)
			setdefaultfilecon(dest);
#endif
		/* Set the user and group id */
		if ((opts & (OPT_OWNER|OPT_GROUP))
		 && lchown(dest, uid, gid) == -1
		) {
			bb_perror_msg("can't change %s of %s", "ownership", dest);
			ret = EXIT_FAILURE;
		}
 next:
		if (ENABLE_FEATURE_CLEAN_UP && isdir)
			free(dest);
	}

	return ret;
}
Esempio n. 19
0
void data_extract_all(archive_handle_t *archive_handle)
{
	file_header_t *file_header = archive_handle->file_header;
	int dst_fd;
	int res;

	if (archive_handle->flags & ARCHIVE_CREATE_LEADING_DIRS) {
		char *name = xstrdup(file_header->name);
		bb_make_directory(dirname(name), -1, FILEUTILS_RECUR);
		free(name);
	}

	/* Check if the file already exists */
	if (archive_handle->flags & ARCHIVE_EXTRACT_UNCONDITIONAL) {
		/* Remove the existing entry if it exists */
		if (((file_header->mode & S_IFMT) != S_IFDIR)
		 && (unlink(file_header->name) == -1)
		 && (errno != ENOENT)
		) {
			bb_perror_msg_and_die("cannot remove old file %s",
					file_header->name);
		}
	}
	else if (archive_handle->flags & ARCHIVE_EXTRACT_NEWER) {
		/* Remove the existing entry if its older than the extracted entry */
		struct stat statbuf;
		if (lstat(file_header->name, &statbuf) == -1) {
			if (errno != ENOENT) {
				bb_perror_msg_and_die("cannot stat old file");
			}
		}
		else if (statbuf.st_mtime <= file_header->mtime) {
			if (!(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) {
				bb_error_msg("%s not created: newer or "
					"same age file exists", file_header->name);
			}
			data_skip(archive_handle);
			return;
		}
		else if ((unlink(file_header->name) == -1) && (errno != EISDIR)) {
			bb_perror_msg_and_die("cannot remove old file %s",
					file_header->name);
		}
	}

	/* Handle hard links separately
	 * We identified hard links as regular files of size 0 with a symlink */
	if (S_ISREG(file_header->mode) && (file_header->link_target)
	 && (file_header->size == 0)
	) {
		/* hard link */
		res = link(file_header->link_target, file_header->name);
		if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) {
			bb_perror_msg("cannot create %slink "
					"from %s to %s", "hard",
					file_header->name,
					file_header->link_target);
		}
	} else {
		/* Create the filesystem entry */
		switch (file_header->mode & S_IFMT) {
		case S_IFREG: {
			/* Regular file */
			dst_fd = xopen3(file_header->name, O_WRONLY | O_CREAT | O_EXCL,
							file_header->mode);
			bb_copyfd_exact_size(archive_handle->src_fd, dst_fd, file_header->size);
			close(dst_fd);
			break;
		}
		case S_IFDIR:
			res = mkdir(file_header->name, file_header->mode);
			if ((res == -1) && (errno != EISDIR)
			 && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)
			) {
				bb_perror_msg("cannot make dir %s", file_header->name);
			}
			break;
		case S_IFLNK:
			/* Symlink */
			res = symlink(file_header->link_target, file_header->name);
			if ((res == -1)
			 && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)
			) {
				bb_perror_msg("cannot create %slink "
					"from %s to %s", "sym",
					file_header->name,
					file_header->link_target);
			}
			break;
#ifndef _WIN32
		case S_IFSOCK:
		case S_IFBLK:
		case S_IFCHR:
		case S_IFIFO:
			res = mknod(file_header->name, file_header->mode, file_header->device);
			if ((res == -1)
			 && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)
			) {
				bb_perror_msg("cannot create node %s", file_header->name);
			}
			break;
#endif
		default:
			bb_error_msg_and_die("unrecognized file type");
		}
	}

#ifndef _WIN32
	if (!(archive_handle->flags & ARCHIVE_NOPRESERVE_OWN)) {
#if ENABLE_FEATURE_TAR_UNAME_GNAME
		uid_t uid = file_header->uid;
		gid_t gid = file_header->gid;

		if (file_header->uname) {
			struct passwd *pwd = getpwnam(file_header->uname);
			if (pwd) uid = pwd->pw_uid;
		}
		if (file_header->gname) {
			struct group *grp = getgrnam(file_header->gname);
			if (grp) gid = grp->gr_gid;
		}
		lchown(file_header->name, uid, gid);
#else
		lchown(file_header->name, file_header->uid, file_header->gid);
#endif
	}
#endif
	if ((file_header->mode & S_IFMT) != S_IFLNK) {
		/* uclibc has no lchmod, glibc is even stranger -
		 * it has lchmod which seems to do nothing!
		 * so we use chmod... */
		if (!(archive_handle->flags & ARCHIVE_NOPRESERVE_PERM)) {
			chmod(file_header->name, file_header->mode);
		}
		/* same for utime */
		if (archive_handle->flags & ARCHIVE_PRESERVE_DATE) {
			struct utimbuf t;
			t.actime = t.modtime = file_header->mtime;
			utime(file_header->name, &t);
		}
	}
}
void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
{
	file_header_t *file_header = archive_handle->file_header;
	int dst_fd;
	int res;

	if (archive_handle->ah_flags & ARCHIVE_CREATE_LEADING_DIRS) {
		char *slash = strrchr(file_header->name, '/');
		if (slash) {
			*slash = '\0';
			bb_make_directory(file_header->name, -1, FILEUTILS_RECUR);
			*slash = '/';
		}
	}

	if (archive_handle->ah_flags & ARCHIVE_UNLINK_OLD) {
		/* Remove the entry if it exists */
		if ((!S_ISDIR(file_header->mode))
		 && (unlink(file_header->name) == -1)
		 && (errno != ENOENT)
		) {
			bb_perror_msg_and_die("can't remove old file %s",
					file_header->name);
		}
	}
	else if (archive_handle->ah_flags & ARCHIVE_EXTRACT_NEWER) {
		/* Remove the existing entry if its older than the extracted entry */
		struct stat existing_sb;
		if (lstat(file_header->name, &existing_sb) == -1) {
			if (errno != ENOENT) {
				bb_perror_msg_and_die("can't stat old file");
			}
		}
		else if (existing_sb.st_mtime >= file_header->mtime) {
			if (!(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) {
				bb_error_msg("%s not created: newer or "
					"same age file exists", file_header->name);
			}
			data_skip(archive_handle);
			return;
		}
		else if ((unlink(file_header->name) == -1) && (errno != EISDIR)) {
			bb_perror_msg_and_die("can't remove old file %s",
					file_header->name);
		}
	}

	/* Handle hard links separately
	 * We identified hard links as regular files of size 0 with a symlink */
	if (S_ISREG(file_header->mode)
	 && file_header->link_target
	 && file_header->size == 0
	) {
		/* hard link */
		res = link(file_header->link_target, file_header->name);
		if ((res == -1) && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) {
			bb_perror_msg("can't create %slink "
					"from %s to %s", "hard",
					file_header->name,
					file_header->link_target);
		}
	} else {
		/* Create the filesystem entry */
		switch (file_header->mode & S_IFMT) {
		case S_IFREG: {
			/* Regular file */
			int flags = O_WRONLY | O_CREAT | O_EXCL;
			if (archive_handle->ah_flags & ARCHIVE_O_TRUNC)
				flags = O_WRONLY | O_CREAT | O_TRUNC;
			dst_fd = xopen3(file_header->name,
				flags,
				file_header->mode
				);
			bb_copyfd_exact_size(archive_handle->src_fd, dst_fd, file_header->size);
			close(dst_fd);
			break;
		}
		case S_IFDIR:
			res = mkdir(file_header->name, file_header->mode);
			if ((res == -1)
			 && (errno != EISDIR) /* btw, Linux doesn't return this */
			 && (errno != EEXIST)
			 && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)
			) {
				bb_perror_msg("can't make dir %s", file_header->name);
			}
			break;
		case S_IFLNK:
			/* Symlink */
			res = symlink(file_header->link_target, file_header->name);
			if ((res == -1)
			 && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)
			) {
				bb_perror_msg("can't create %slink "
					"from %s to %s", "sym",
					file_header->name,
					file_header->link_target);
			}
			break;
		case S_IFSOCK:
		case S_IFBLK:
		case S_IFCHR:
		case S_IFIFO:
			res = mknod(file_header->name, file_header->mode, file_header->device);
			if ((res == -1)
			 && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)
			) {
				bb_perror_msg("can't create node %s", file_header->name);
			}
			break;
		default:
			bb_error_msg_and_die("unrecognized file type");
		}
	}

	if (!(archive_handle->ah_flags & ARCHIVE_DONT_RESTORE_OWNER)) {
#if ENABLE_FEATURE_TAR_UNAME_GNAME
		if (!(archive_handle->ah_flags & ARCHIVE_NUMERIC_OWNER)) {
			uid_t uid = file_header->uid;
			gid_t gid = file_header->gid;

			if (file_header->tar__uname) {
//TODO: cache last name/id pair?
				struct passwd *pwd = getpwnam(file_header->tar__uname);
				if (pwd) uid = pwd->pw_uid;
			}
			if (file_header->tar__gname) {
				struct group *grp = getgrnam(file_header->tar__gname);
				if (grp) gid = grp->gr_gid;
			}
			/* GNU tar 1.15.1 uses chown, not lchown */
			chown(file_header->name, uid, gid);
		} else
#endif
			chown(file_header->name, file_header->uid, file_header->gid);
	}
	if (!S_ISLNK(file_header->mode)) {
		/* uclibc has no lchmod, glibc is even stranger -
		 * it has lchmod which seems to do nothing!
		 * so we use chmod... */
		if (!(archive_handle->ah_flags & ARCHIVE_DONT_RESTORE_PERM)) {
			chmod(file_header->name, file_header->mode);
		}
		/* same for utime */
		if (archive_handle->ah_flags & ARCHIVE_RESTORE_DATE) {
			struct timeval t[2];

			t[1].tv_sec = t[0].tv_sec = file_header->mtime;
			t[1].tv_usec = t[0].tv_usec = 0;
			utimes(file_header->name, t);
		}
	}
}