Esempio n. 1
0
static
int
check_dir(uint32_t ino, uint32_t parentino, const char *pathsofar)
{
	struct sfs_inode sfi;
	struct sfs_dir *direntries;
	int *sortvector;
	uint32_t dirsize, ndirentries, maxdirentries, subdircount, i;
	int ichanged=0, dchanged=0, dotseen=0, dotdotseen=0;

	diskread(&sfi, ino);
	swapinode(&sfi);

	if (remember_dir(ino, pathsofar)) {
		/* crosslinked dir */
		return 1;
	}

	bitmap_mark(ino, B_INODE, ino);
	count_dirs++;

	if (sfi.sfi_size % sizeof(struct sfs_dir) != 0) {
		setbadness(EXIT_RECOV);
		warnx("Directory /%s has illegal size %lu (fixed)",
		      pathsofar, (unsigned long) sfi.sfi_size);
		sfi.sfi_size = SFS_ROUNDUP(sfi.sfi_size,
					   sizeof(struct sfs_dir));
		ichanged = 1;
	}

	if (check_inode_blocks(ino, &sfi, 1)) {
		ichanged = 1;
	}

	ndirentries = sfi.sfi_size/sizeof(struct sfs_dir);
	maxdirentries = SFS_ROUNDUP(ndirentries,
				    SFS_BLOCKSIZE/sizeof(struct sfs_dir));
	dirsize = maxdirentries * sizeof(struct sfs_dir);
	direntries = domalloc(dirsize);
	sortvector = domalloc(ndirentries * sizeof(int));

	dirread(&sfi, direntries, ndirentries);
	for (i=ndirentries; i<maxdirentries; i++) {
		direntries[i].sfd_ino = SFS_NOINO;
		bzero(direntries[i].sfd_name, sizeof(direntries[i].sfd_name));
	}

	for (i=0; i<ndirentries; i++) {
		if (check_dir_entry(pathsofar, i, &direntries[i])) {
			dchanged = 1;
		}
		sortvector[i] = i;
	}

	sortdir(sortvector, direntries, ndirentries);

	/* don't use ndirentries-1 here in case ndirentries == 0 */
	for (i=0; i+1<ndirentries; i++) {
		struct sfs_dir *d1 = &direntries[sortvector[i]];
		struct sfs_dir *d2 = &direntries[sortvector[i+1]];
		assert(d1 != d2);

		if (d1->sfd_ino == SFS_NOINO) {
			continue;
		}

		if (!strcmp(d1->sfd_name, d2->sfd_name)) {
			if (d1->sfd_ino == d2->sfd_ino) {
				setbadness(EXIT_RECOV);
				warnx("Directory /%s: Duplicate entries for "
				      "%s (merged)",
				      pathsofar, d1->sfd_name);
				d1->sfd_ino = SFS_NOINO;
				d1->sfd_name[0] = 0;
			}
			else {
				snprintf(d1->sfd_name, sizeof(d1->sfd_name),
					 "FSCK.%lu.%lu",
					 (unsigned long) d1->sfd_ino,
					 (unsigned long) uniquecounter++);
				setbadness(EXIT_RECOV);
				warnx("Directory /%s: Duplicate names %s "
				      "(one renamed: %s)",
				      pathsofar, d2->sfd_name, d1->sfd_name);
			}
			dchanged = 1;
		}
	}

	for (i=0; i<ndirentries; i++) {
		if (!strcmp(direntries[i].sfd_name, ".")) {
			if (direntries[i].sfd_ino != ino) {
				setbadness(EXIT_RECOV);
				warnx("Directory /%s: Incorrect `.' entry "
				      "(fixed)", pathsofar);
				direntries[i].sfd_ino = ino;
				dchanged = 1;
			}
			assert(dotseen==0); /* due to duplicate checking */
			dotseen = 1;
		}
		else if (!strcmp(direntries[i].sfd_name, "..")) {
			if (direntries[i].sfd_ino != parentino) {
				setbadness(EXIT_RECOV);
				warnx("Directory /%s: Incorrect `..' entry "
				      "(fixed)", pathsofar);
				direntries[i].sfd_ino = parentino;
				dchanged = 1;
			}
			assert(dotdotseen==0); /* due to duplicate checking */
			dotdotseen = 1;
		}
	}

	if (!dotseen) {
		if (dir_tryadd(direntries, ndirentries, ".", ino)==0) {
			setbadness(EXIT_RECOV);
			warnx("Directory /%s: No `.' entry (added)",
			      pathsofar);
			dchanged = 1;
		}
		else if (dir_tryadd(direntries, maxdirentries, ".", ino)==0) {
			setbadness(EXIT_RECOV);
			warnx("Directory /%s: No `.' entry (added)",
			      pathsofar);
			ndirentries++;
			dchanged = 1;
			sfi.sfi_size += sizeof(struct sfs_dir);
			ichanged = 1;
		}
		else {
			setbadness(EXIT_UNRECOV);
			warnx("Directory /%s: No `.' entry (NOT FIXED)",
			      pathsofar);
		}
	}

	if (!dotdotseen) {
		if (dir_tryadd(direntries, ndirentries, "..", parentino)==0) {
			setbadness(EXIT_RECOV);
			warnx("Directory /%s: No `..' entry (added)",
			      pathsofar);
			dchanged = 1;
		}
		else if (dir_tryadd(direntries, maxdirentries, "..",
				    parentino)==0) {
			setbadness(EXIT_RECOV);
			warnx("Directory /%s: No `..' entry (added)",
			      pathsofar);
			ndirentries++;
			dchanged = 1;
			sfi.sfi_size += sizeof(struct sfs_dir);
			ichanged = 1;
		}
		else {
			setbadness(EXIT_UNRECOV);
			warnx("Directory /%s: No `..' entry (NOT FIXED)",
			      pathsofar);
		}
	}

	subdircount=0;
	for (i=0; i<ndirentries; i++) {
		if (!strcmp(direntries[i].sfd_name, ".")) {
			/* nothing */
		}
		else if (!strcmp(direntries[i].sfd_name, "..")) {
			/* nothing */
		}
		else if (direntries[i].sfd_ino == SFS_NOINO) {
			/* nothing */
		}
		else {
			char path[strlen(pathsofar)+SFS_NAMELEN+1];
			struct sfs_inode subsfi;

			diskread(&subsfi, direntries[i].sfd_ino);
			swapinode(&subsfi);
			snprintf(path, sizeof(path), "%s/%s",
				 pathsofar, direntries[i].sfd_name);

			switch (subsfi.sfi_type) {
			    case SFS_TYPE_FILE:
				if (check_inode_blocks(direntries[i].sfd_ino,
						       &subsfi, 0)) {
					swapinode(&subsfi);
					diskwrite(&subsfi,
						  direntries[i].sfd_ino);
				}
				observe_filelink(direntries[i].sfd_ino);
				break;
			    case SFS_TYPE_DIR:
				if (check_dir(direntries[i].sfd_ino,
					      ino,
					      path)) {
					setbadness(EXIT_RECOV);
					warnx("Directory /%s: Crosslink to "
					      "other directory (removed)",
					      path);
					direntries[i].sfd_ino = SFS_NOINO;
					direntries[i].sfd_name[0] = 0;
					dchanged = 1;
				}
				else {
					subdircount++;
				}
				break;
			    default:
				setbadness(EXIT_RECOV);
				warnx("Object /%s: Invalid inode type "
				      "(removed)", path);
				direntries[i].sfd_ino = SFS_NOINO;
				direntries[i].sfd_name[0] = 0;
				dchanged = 1;
				break;
			}
		}
	}

	if (sfi.sfi_linkcount != subdircount+2) {
		setbadness(EXIT_RECOV);
		warnx("Directory /%s: Link count %lu should be %lu (fixed)",
		      pathsofar, (unsigned long) sfi.sfi_linkcount,
		      (unsigned long) subdircount+2);
		sfi.sfi_linkcount = subdircount+2;
		ichanged = 1;
	}

	if (dchanged) {
		dirwrite(&sfi, direntries, ndirentries);
	}

	if (ichanged) {
		swapinode(&sfi);
		diskwrite(&sfi, ino);
	}

	free(direntries);
	free(sortvector);

	return 0;
}
Esempio n. 2
0
/* 
 * Scans a directory for files matching a pattern and returns them in an GEList
 *
 * <dir_stack>	If not NULL, will be used to store the names of subdirectories 
 *		found (not subject to matching)
 * <dir_memory>	If not NULL, will be used to remember visited dirs. This 
 *		guarantees that each dir is only visited once. 
 *		ALWAYS USE THIS PARAMETER WHEN DOING RECURSIVE SCANS!
 * <base_dir>	Directory to scan
 * <patterns>	NULL terminated array of glob pattern strings
 * <sort>	If TRUE the result will be sorted
 *
 * return	GEList with matching files. File names will be prefixed with
 *		the <base_dir>, unless it is "."
 *		This list should be freed with g_elist_free_data().
 */
static GEList *aux_file_list( GEList *dir_stack,
			      GHashTable *dir_memory,
			      const gchar *base_dir,
			      const gchar **patterns, 
			      gboolean sort )
{
	GEList *result;
	GEList *aux_stack = NULL;
	DIR* dir;
	int dir_fd;
	struct stat dir_stat;
	struct dirent *dir_entry;
	struct stat stat_data;
	gint res;
	gchar *buffer;
	gchar *buffer_fname;
	gint buffer_size;
	gboolean matched;
	gint i;

	result = g_elist_new();
	if (dir_stack != NULL)
		aux_stack = g_elist_new();

	dir = opendir(base_dir);
	if (dir == NULL) {
		g_warning("couldn't open dir: %s", base_dir);
		return result;
	}

	/* guard against loops in the directory structure */
	if (dir_memory != NULL) {
		dir_fd = dirfd(dir);
		if (dir_fd >= 0)
			fstat(dir_fd, &dir_stat);
		else 
			stat(base_dir, &dir_stat);
		if (remember_dir(dir_memory, &dir_stat)) {
			//printf("skipping directory, already been here: %s", base_dir);
			closedir(dir);
			return result;
		}
	}

	// XXX - fixed size buffer
	buffer = g_malloc(buffer_size = 1024);
	if (strcmp(base_dir, ".") == 0) {
		buffer_fname = buffer;
	} else {
		buffer_fname = memccpy(buffer, base_dir, 0, buffer_size);
		if (buffer_fname == NULL) {
			g_warning("FIXME - buffer too small for file name!!!");
			closedir(dir);
			g_free(buffer);
			return result;
		} else {
			*(buffer_fname-1) = '/';
			buffer_size -= (gint)(buffer_fname - buffer);
		}
	}

	while ( (dir_entry = readdir(dir)) ) {
		if (memccpy(buffer_fname, dir_entry->d_name, 0, buffer_size) == NULL) {
			g_warning("FIXME - buffer too small for file name!!!");
			continue;
		}

		res = stat(buffer, &stat_data);
		if (res < 0) {
			//printf("couldn't stat file: %s", buffer);
			continue;
		}
		if (S_ISDIR(stat_data.st_mode)) {
			if ((aux_stack != NULL) &&
			    (strcmp(dir_entry->d_name, ".") != 0) &&
			    (strcmp(dir_entry->d_name, "..") != 0)) {
				g_elist_push(aux_stack, g_strdup(buffer));
			}
			continue;
		}
		if (patterns == NULL) {
			matched = TRUE;
		} else {
			matched = FALSE;
			for (i = 0; patterns[i]; i++) {
				if (fnmatch(patterns[i], dir_entry->d_name, FNM_NOESCAPE) == 0) {
					matched = TRUE;
					break;
				}
			}
		}	
		if (matched)
			g_elist_append(result, g_strdup(buffer));
	}

	if (sort) {
		g_elist_sort(result, (GCompareFunc)strcoll);
		if (aux_stack != NULL)
			g_elist_sort(aux_stack, rev_strcoll);
	}
	
	if (aux_stack != NULL)
		g_elist_concat(dir_stack, aux_stack);

	closedir(dir);
	g_free(buffer);
	return result;
}