示例#1
0
文件: mkfs.jffs2.c 项目: jhbsz/102
static struct filesystem_entry *find_filesystem_entry(
		struct filesystem_entry *dir, char *fullname, uint32_t type)
{
	struct filesystem_entry *e = dir;

	if (S_ISDIR(dir->sb.st_mode)) {
		e = dir->files;
	}
	while (e) {
		/* Only bother to do the expensive strcmp on matching file types */
		if (type == (e->sb.st_mode & S_IFMT)) {
			if (S_ISDIR(e->sb.st_mode)) {
				int len = strlen(e->fullname);

				/* Check if we are a parent of the correct path */
				if (strncmp(e->fullname, fullname, len) == 0) {
					/* Is this an _exact_ match? */
					if (strcmp(fullname, e->fullname) == 0) {
						return (e);
					}
					/* Looks like we found a parent of the correct path */
					if (fullname[len] == '/') {
						if (e->files) {
							return (find_filesystem_entry (e, fullname, type));
						} else {
							return NULL;
						}
					}
				}
			} else {
				if (strcmp(fullname, e->fullname) == 0) {
					return (e);
				}
			}
		}
		e = e->next;
	}
	return (NULL);
}
示例#2
0
文件: mkfs.jffs2.c 项目: jhbsz/102
/*  device table entries take the form of:
    <path>	<type> <mode>	<uid>	<gid>	<major>	<minor>	<start>	<inc>	<count>
    /dev/mem     c    640       0       0         1       1       0     0         -

    type can be one of:
	f	A regular file
	d	Directory
	c	Character special device file
	b	Block special device file
	p	Fifo (named pipe)

    I don't bother with symlinks (permissions are irrelevant), hard
    links (special cases of regular files), or sockets (why bother).

    Regular files must exist in the target root directory.  If a char,
    block, fifo, or directory does not exist, it will be created.
*/
static int interpret_table_entry(struct filesystem_entry *root, char *line)
{
	char *hostpath;
	char type, *name = NULL, *tmp, *dir;
	unsigned long mode = 0755, uid = 0, gid = 0, major = 0, minor = 0;
	unsigned long start = 0, increment = 1, count = 0;
	struct filesystem_entry *parent, *entry;

	if (sscanf (line, "%" SCANF_PREFIX "s %c %lo %lu %lu %lu %lu %lu %lu %lu",
		 SCANF_STRING(name), &type, &mode, &uid, &gid, &major, &minor,
		 &start, &increment, &count) < 0)
	{
		return 1;
	}

	if (!strcmp(name, "/")) {
		error_msg_and_die("Device table entries require absolute paths");
	}

	asprintf(&hostpath, "%s%s", rootdir, name);

	/* Check if this file already exists... */
	switch (type) {
		case 'd':
			mode |= S_IFDIR;
			break;
		case 'f':
			mode |= S_IFREG;
			break;
		case 'p':
			mode |= S_IFIFO;
			break;
		case 'c':
			mode |= S_IFCHR;
			break;
		case 'b':
			mode |= S_IFBLK;
			break;
		default:
			error_msg_and_die("Unsupported file type");
	}
	entry = find_filesystem_entry(root, name, mode);
	if (entry) {
		/* Ok, we just need to fixup the existing entry
		 * and we will be all done... */
		entry->sb.st_uid = uid;
		entry->sb.st_gid = gid;
		entry->sb.st_mode = mode;
		if (major && minor) {
			entry->sb.st_rdev = makedev(major, minor);
		}
	} else {
		/* If parent is NULL (happens with device table entries),
		 * try and find our parent now) */
		tmp = strdup(name);
		dir = dirname(tmp);
		parent = find_filesystem_entry(root, dir, S_IFDIR);
		free(tmp);
		if (parent == NULL) {
			error_msg ("skipping device_table entry '%s': no parent directory!", name);
			free(name);
			free(hostpath);
			return 1;
		}

		switch (type) {
			case 'd':
				add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0, parent);
				break;
			case 'f':
				add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0, parent);
				break;
			case 'p':
				add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0, parent);
				break;
			case 'c':
			case 'b':
				if (count > 0) {
					dev_t rdev;
					unsigned long i;
					char *dname, *hpath;

					for (i = start; i < count; i++) {
						asprintf(&dname, "%s%lu", name, i);
						asprintf(&hpath, "%s/%s%lu", rootdir, name, i);
						rdev = makedev(major, minor + (i * increment - start));
						add_host_filesystem_entry(dname, hpath, uid, gid,
								mode, rdev, parent);
						free(dname);
						free(hpath);
					}
				} else {
					dev_t rdev = makedev(major, minor);
					add_host_filesystem_entry(name, hostpath, uid, gid,
							mode, rdev, parent);
				}
				break;
			default:
				error_msg_and_die("Unsupported file type");
		}
	}
	free(name);
	free(hostpath);
	return 0;
}
示例#3
0
void modify_entry(char *full_path, unsigned long uid, unsigned long gid, 
	unsigned long mode, unsigned long rdev, struct entry *root, off_t *fslen_ub)
{
	char *name, *path, *full;
	struct entry *curr, *parent, *entry, *prev;
	
	full = xstrdup(full_path);
	path = xstrdup(dirname(full));
	name = full_path + strlen(path) + 1;
	free(full);
	if (strcmp(path, "/") == 0) {
		parent = root;
		name = full_path + 1;
	} else {
		if (!(parent = find_filesystem_entry(root, path+1, S_IFDIR)))
			error_msg_and_die("%s/%s: could not find parent\n", path, name);
	}
	if ((entry = find_filesystem_entry(parent, name, (mode & S_IFMT)))) {
		/* its there, just modify permissions */
		entry->mode = mode;
		entry->uid = uid;
		entry->gid = gid;
	} else { /* make a new entry */
	
		/* code partially replicated from parse_directory() */
		size_t namelen;
		if (S_ISREG(mode)) {
			error_msg_and_die("%s: regular file from device_table file must exist on disk!", full_path);
		}

		namelen = strlen(name);
		if (namelen > MAX_INPUT_NAMELEN) {
			error_msg_and_die(
				"Very long (%u bytes) filename `%s' found.\n"
				" Please increase MAX_INPUT_NAMELEN in mkcramfs.c and recompile.  Exiting.\n",
				namelen, name);
		}
		entry = xcalloc(1, sizeof(struct entry));
		entry->name = xstrdup(name);
		/* truncate multi-byte UTF-8 filenames on character boundary */
		if (namelen > CRAMFS_MAXPATHLEN) {
			namelen = CRAMFS_MAXPATHLEN;
			warn_namelen = 1;
			/* the first lost byte must not be a trail byte */
			while ((entry->name[namelen] & 0xc0) == 0x80) {
				namelen--;
				/* are we reasonably certain it was UTF-8 ? */
				if (entry->name[namelen] < 0x80 || !namelen) {
					error_msg_and_die("cannot truncate filenames not encoded in UTF-8");
				}
			}
			entry->name[namelen] = '\0';
		}
		entry->mode = mode;
		entry->uid = uid;
		entry->gid = gid;
		entry->size = 0;
		if (S_ISBLK(mode) || S_ISCHR(mode)) {
			entry->size = rdev;
			if (entry->size & -(1<<CRAMFS_SIZE_WIDTH))
				warn_dev = 1;
		}
		
		/* ok, now we have to backup and correct the size of all the entries above us */
		*fslen_ub += sizeof(struct cramfs_inode) + ((namelen + 3) & ~3);
		parent->size += sizeof(struct cramfs_inode) + ((namelen + 3) & ~3);

		/* alright, time to link us in */
		curr = parent->child;
		prev = NULL;
		while (curr && strcmp(name, curr->name) > 0) {
			prev = curr;
			curr = curr->next;
		}
		if (!prev) parent->child = entry;
		else prev->next = entry;
		entry->next = curr;
		entry->child = NULL;
	}
	if (entry->uid >= 1 << CRAMFS_UID_WIDTH)
		warn_uid = 1;
	if (entry->gid >= 1 << CRAMFS_GID_WIDTH) {
		/* TODO: We ought to replace with a default
		   gid instead of truncating; otherwise there
		   are security problems.  Maybe mode should
		   be &= ~070.  Same goes for uid once Linux
		   supports >16-bit uids. */
		warn_gid = 1;
	}
	free(path);
}