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; }
/* * 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; }