static int read_mtree_spec(FILE *fp) { char pathspec[PATH_MAX]; char *cp; int error; error = read_word(fp, pathspec, sizeof(pathspec)); if (error) goto out; cp = strchr(pathspec, '/'); if (cp != NULL) { /* Absolute pathname */ mtree_current = mtree_root; do { *cp++ = '\0'; /* Disallow '..' as a component. */ if (IS_DOTDOT(pathspec)) { mtree_error("absolute path cannot contain " ".. component"); goto out; } /* Ignore multiple adjacent slashes and '.'. */ if (pathspec[0] != '\0' && !IS_DOT(pathspec)) error = read_mtree_spec1(fp, false, pathspec); memmove(pathspec, cp, strlen(cp) + 1); cp = strchr(pathspec, '/'); } while (!error && cp != NULL); /* Disallow '.' and '..' as the last component. */ if (!error && (IS_DOT(pathspec) || IS_DOTDOT(pathspec))) { mtree_error("absolute path cannot contain . or .. " "components"); goto out; } } /* Ignore absolute specfications that end with a slash. */ if (!error && pathspec[0] != '\0') error = read_mtree_spec1(fp, true, pathspec); out: skip_to(fp, "\n"); (void)getc(fp); return (error); }
/* * Create path from the name and parent of an entry. */ static char * create_v1_path(struct mtree_entry *entry) { char *path; char *prefix = ""; size_t len; len = strlen(entry->name); if (entry->parent == NULL) { if (!IS_DOT(entry->name)) prefix = "./"; } else len += strlen(entry->parent->path) + 1; len += strlen(prefix); path = malloc(len + 1); if (path != NULL) snprintf(path, len + 1, "%s%s%s%s", prefix, entry->parent ? entry->parent->path : "", entry->parent ? "/" : "", entry->name); return (path); }
static int read_mtree_spec1(FILE *fp, bool def, const char *name) { fsnode *last, *node, *parent; u_int type; int error; assert(name[0] != '\0'); /* * Treat '..' specially, because it only changes our current * directory. We don't create a node for it. We simply ignore * any keywords that may appear on the line as well. * Going up a directory is a little non-obvious. A directory * node has a corresponding '.' child. The parent of '.' is * not the '.' node of the parent directory, but the directory * node within the parent to which the child relates. However, * going up a directory means we need to find the '.' node to * which the directoy node is linked. This we can do via the * first * pointer, because '.' is always the first entry in a * directory. */ if (IS_DOTDOT(name)) { /* This deals with NULL pointers as well. */ if (mtree_current == mtree_root) { mtree_warning("ignoring .. in root directory"); return (0); } node = mtree_current; assert(node != NULL); assert(IS_DOT(node->name)); assert(node->first == node); /* Get the corresponding directory node in the parent. */ node = mtree_current->parent; assert(node != NULL); assert(!IS_DOT(node->name)); node = node->first; assert(node != NULL); assert(IS_DOT(node->name)); assert(node->first == node); mtree_current = node; return (0); } /* * If we don't have a current directory and the first specification * (either implicit or defined) is not '.', then we need to create * a '.' node first (using a recursive call). */ if (!IS_DOT(name) && mtree_current == NULL) { error = read_mtree_spec1(fp, false, "."); if (error) return (error); } /* * Lookup the name in the current directory (if we have a current * directory) to make sure we do not create multiple nodes for the * same component. For non-definitions, if we find a node with the * same name, simply change the current directory. For definitions * more happens. */ last = NULL; node = mtree_current; while (node != NULL) { assert(node->first == mtree_current); if (strcmp(name, node->name) == 0) { if (def == true) { if (!dupsok) mtree_error( "duplicate definition of %s", name); else mtree_warning( "duplicate definition of %s", name); return (0); } if (node->type != S_IFDIR) { mtree_error("%s is not a directory", name); return (0); } assert(!IS_DOT(name)); node = node->child; assert(node != NULL); assert(IS_DOT(node->name)); mtree_current = node; return (0); } last = node; node = last->next; } parent = (mtree_current != NULL) ? mtree_current->parent : NULL; type = (def == false || IS_DOT(name)) ? S_IFDIR : 0; node = create_node(name, type, parent, &mtree_global); if (node == NULL) return (ENOMEM); if (def == true) { error = read_mtree_keywords(fp, node); if (error) { destroy_node(node); return (error); } } node->first = (mtree_current != NULL) ? mtree_current : node; if (last != NULL) last->next = node; if (node->type != S_IFDIR) return (0); if (!IS_DOT(node->name)) { parent = node; node = create_node(".", S_IFDIR, parent, parent); if (node == NULL) { last->next = NULL; destroy_node(parent); return (ENOMEM); } parent->child = node; node->first = node; } assert(node != NULL); assert(IS_DOT(node->name)); assert(node->first == node); mtree_current = node; if (mtree_root == NULL) mtree_root = node; return (0); }
/* dnormalize(): * The path will be normalized if it * 1) is "..", * 2) or starts with "../", * 3) or ends with "/..", * 4) or contains the string "/../", * then it will be normalized, unless those strings are quoted. * Otherwise, a copy is made and sent back. */ Char * dnormalize(const Char *cp, int expnd) { /* return true if dp is of the form "../xxx" or "/../xxx" */ #define IS_DOTDOT(sp, p) (ISDOTDOT(p) && ((p) == (sp) || *((p) - 1) == '/')) #define IS_DOT(sp, p) (ISDOT(p) && ((p) == (sp) || *((p) - 1) == '/')) #ifdef S_IFLNK if (expnd) { struct Strbuf buf = Strbuf_INIT; int dotdot = 0; Char *dp, *cwd; const Char *start = cp; # ifdef HAVE_SLASHSLASH int slashslash; # endif /* HAVE_SLASHSLASH */ /* * count the number of "../xxx" or "xxx/../xxx" in the path */ for ( ; *cp && *(cp + 1); cp++) if (IS_DOTDOT(start, cp)) dotdot++; /* * if none, we are done. */ if (dotdot == 0) return (Strsave(start)); # ifdef notdef struct stat sb; /* * We disable this test because: * cd /tmp; mkdir dir1 dir2; cd dir2; ln -s /tmp/dir1; cd dir1; * echo ../../dir1 does not expand. We had enabled this before * because it was bothering people with expansions in compilation * lines like -I../../foo. Maybe we need some kind of finer grain * control? * * If the path doesn't exist, we are done too. */ if (lstat(short2str(start), &sb) != 0 && errno == ENOENT) return (Strsave(start)); # endif cwd = xmalloc((Strlen(dcwd->di_name) + 3) * sizeof(Char)); (void) Strcpy(cwd, dcwd->di_name); /* * If the path starts with a slash, we are not relative to * the current working directory. */ if (ABSOLUTEP(start)) *cwd = '\0'; # ifdef HAVE_SLASHSLASH slashslash = cwd[0] == '/' && cwd[1] == '/'; # endif /* HAVE_SLASHSLASH */ /* * Ignore . and count ..'s */ cp = start; do { dotdot = 0; buf.len = 0; while (*cp) if (IS_DOT(start, cp)) { if (*++cp) cp++; } else if (IS_DOTDOT(start, cp)) { if (buf.len != 0) break; /* finish analyzing .././../xxx/[..] */ dotdot++; cp += 2; if (*cp) cp++; } else Strbuf_append1(&buf, *cp++); Strbuf_terminate(&buf); while (dotdot > 0) if ((dp = Strrchr(cwd, '/')) != NULL) { # ifdef HAVE_SLASHSLASH if (dp == &cwd[1]) slashslash = 1; # endif /* HAVE_SLASHSLASH */ *dp = '\0'; dotdot--; } else break; if (!*cwd) { /* too many ..'s, starts with "/" */ cwd[0] = '/'; # ifdef HAVE_SLASHSLASH /* * Only append another slash, if already the former cwd * was in a double-slash path. */ cwd[1] = slashslash ? '/' : '\0'; cwd[2] = '\0'; # else /* !HAVE_SLASHSLASH */ cwd[1] = '\0'; # endif /* HAVE_SLASHSLASH */ } # ifdef HAVE_SLASHSLASH else if (slashslash && cwd[1] == '\0') { cwd[1] = '/'; cwd[2] = '\0'; } # endif /* HAVE_SLASHSLASH */ if (buf.len != 0) { size_t i; i = Strlen(cwd); if (TRM(cwd[i - 1]) != '/') { cwd[i++] = '/'; cwd[i] = '\0'; } dp = Strspl(cwd, TRM(buf.s[0]) == '/' ? &buf.s[1] : buf.s); xfree(cwd); cwd = dp; i = Strlen(cwd) - 1; if (TRM(cwd[i]) == '/') cwd[i] = '\0'; } /* Reduction of ".." following the stuff we collected in buf * only makes sense if the directory item in buf really exists. * Avoid reduction of "-I../.." (typical compiler call) to "" * or "/usr/nonexistant/../bin" to "/usr/bin": */ if (cwd[0]) { struct stat exists; if (0 != stat(short2str(cwd), &exists)) { xfree(buf.s); xfree(cwd); return Strsave(start); } } } while (*cp != '\0'); xfree(buf.s); return cwd; } #endif /* S_IFLNK */ return Strsave(cp); }
/* * walkdir() * Toto je slavny `algoritmus pruchodu adresarouvou strukturou` * Funkce je napsana rekurzivne, nebot adresare mohou ukryvat podadresare. * Rekurzivni implementace bude prehledna a spolehliva. * Argumenty: * topdir - nazev adresare odkud se fce bude zanorovat dale * dea - dir entry action struktura popisuje akci, kterou * je treba vykonat nad kazdou nalezenou polozkou * Vraci: * 0 O.K., -1 Failure */ static int walkdir(const char *topdir) { DIR * d; struct dirent *de; int rv; struct stat st; unsigned int path_len; char *path; int i; size_t child_data; /* * vsimnete si pouziti funkce pathconf(), ktera nam zjisti maximalni * moznou velikost cesty na danem file systemu. je treba si uvedomit, * ze prave prochazeny adresar `topdir`, muze byt `mountpoint` na nemz * sedi uplne jiny filesystem s jinou delkou cesty. * * nasledna dynamicka alokace bufferu pro cestu je spolehlivejsi * alternativa k definici path jako `char path[20]`. Je to konec * dohadu jestli je napr. 4096 dost a nebo malo pro ulozeni cesty. * spravne je: * strlen(topdir) + pathconf(topdir, _PC_PATH_MAX). */ path_len = pathconf(topdir, _PC_PATH_MAX) + strlen(topdir); path = (char *)malloc(path_len); /* * Obvykla triada, kdyz dojde pamet, nemuzeme udelat nic jineho, * nez si postezovat a skoncit. */ if (path == NULL) { (void) fprintf(stderr, "malloc(%u) for path buffer failed (%s)\n", path_len, strerror(errno)); return (-1); } /* * jsme optimiste, predpokladame uspech */ rv = 0; if ((d = opendir(topdir)) != NULL) { /* * zacneme prochazet adresar, polozku po polozce. */ while ((de = readdir(d)) != NULL) { /* * pro stat() si musime sestavit absolutni cestu jako: * topdir + '/' + de->d_name */ (void) snprintf(path, path_len, "%s/%s", topdir, de->d_name); printf("%s\n", path); if (stat(path, &st) == 0) { /* * pro podadresare vytvorime novy proces. */ if (S_ISDIR(st.st_mode) && !IS_DOT(de->d_name)) { switch (fork()) { case 0: fifo_parent = open(fifo_path, O_WRONLY); proc_count = 0; length = 0; if (fifo_fd != -1) { rv = run_walkdir(path); } else { rv = 1; } exit(rv); break; case -1: exit(1); break; default: proc_count++; } } else if (S_ISREG(st.st_mode)) { length += st.st_size; } } } /* * Jakmile projdeme adresar, zavolame closedir(), abychom * nevykradali prilis mnoho zdroju. Jinak by nas OS mohl rychle * kleponout pres prsty u rozsahlejsich adresaru. */ (void)closedir(d); /* obtain results from child processes */ for (i = 0; i < proc_count; i++) { if (read(fifo_fd, &child_data, sizeof (size_t)) == (ssize_t)sizeof (size_t)) { length += child_data; } else { perror("read failed"); } } for (i = 0; i < proc_count; i++) { (void) wait(NULL); } } else { rv = -1; } /* * Je potreba vratit pamet, kterou jsme si `pujcili` na zacatku funkce. */ free(path); /* * posli rodici velikost, kterou jsme napocetli. */ if (fifo_parent != -1) { (void) write(fifo_parent, &length, sizeof (size_t)); (void) close(fifo_parent); } return (rv); }
/************************************************************************ ** get_real : gathers the real part/exponent of a real number. ** Input : ptr to the null terminator of the whole part ** pointer to receive value. ** Output : L_CFLOAT ** ** ASSUMES whole part is either at Exp_ptr or Reuse_W. ************************************************************************/ token_t get_real(REG PWCHAR p) { REG int c; token_t tok; c = get_non_eof(); if(Cross_compile && (Tiny_lexer_nesting == 0)) { strcpy (Msg_Text, GET_MSG (4012)); warning(4012); /* float constant in cross compilation */ Cross_compile = FALSE; /* only one msg per file */ } /* ** if the next char is a digit, then we've been called after ** finding a '.'. if this is true, then ** we want to find the fractional part of the number. ** if it's a '.', then we've been called after finding ** a whole part, and we want the fraction. */ if( LXC_IS_DIGIT((WCHAR)c) || IS_DOT(c) ) { do { *p++ = (WCHAR)c; c = (int)get_non_eof(); } while( LXC_IS_DIGIT((WCHAR)c) ); } if( IS_E((WCHAR)c) ) { /* now have found the exponent */ *p++ = (WCHAR)c; /* save the 'e' */ c = (WCHAR)get_non_eof(); /* skip it */ if( IS_SIGN(c) ) { /* optional sign */ *p++ = (WCHAR)c; /* save the sign */ c = (int)get_non_eof(); } if( ! LXC_IS_DIGIT((WCHAR)c)) { if( ! Rflag ) { if(Tiny_lexer_nesting == 0) { Msg_Temp = GET_MSG (2021); SET_MSG (Msg_Text, sizeof(Msg_Text), Msg_Temp, c); error(2021); /* missing or malformed exponent */ } *p++ = L'0'; } } else { do { /* gather the exponent */ *p++ = (WCHAR)c; c = (int)get_non_eof(); } while( LXC_IS_DIGIT((WCHAR)c) ); } } if( IS_F((WCHAR)c) ) { tok = L_CFLOAT; if( Prep ) { *p++ = (WCHAR)c; } } else if( IS_EL((WCHAR)c) ) { tok = L_CLDOUBLE; if( Prep ) { *p++ = (WCHAR)c; } } else { UNGETCH(); tok = L_CDOUBLE; } *p = L'\0'; if( Tiny_lexer_nesting > 0 ) { Exp_ptr = p; return(L_NOTOKEN); } else if( Prep ) { myfwrite( Reuse_W, (size_t)(p - Reuse_W) * sizeof(WCHAR), 1, OUTPUTFILE); return(L_NOTOKEN); } /* ** reals aren't used during preprocessing */ return(tok); }
/************************************************************************ * GETNUM - Get a number from the input stream. * * ARGUMENTS * radix - the radix of the number to be accumulated. Can only be 8, 10, * or 16 * pval - a pointer to a VALUE union to be filled in with the value * * RETURNS - type of the token (L_CINTEGER or L_CFLOAT) * * SIDE EFFECTS - * does push back on the input stream. * writes into pval by reference * uses buffer Reuse_W * * DESCRIPTION - * Accumulate the number according to the rules for each radix. * Set up the format string according to the radix (or distinguish * integer from float if radix is 10) and convert to binary. * * AUTHOR - Ralph Ryan, Sept. 8, 1982 * * MODIFICATIONS - none * ************************************************************************/ token_t getnum(REG WCHAR c) { REG WCHAR *p; WCHAR *start; int radix; token_t tok; value_t value; tok = L_CINTEGER; start = (Tiny_lexer_nesting ? Exp_ptr : Reuse_W); p = start; if( c == L'0' ) { c = get_non_eof(); if( IS_X(c) ) { radix = 16; if( Prep ) { *p++ = L'0'; *p++ = L'x'; } for(c = get_non_eof(); LXC_IS_XDIGIT(c); c = get_non_eof()) { /* no check for overflow? */ *p++ = c; } if((p == Reuse_W) && (Tiny_lexer_nesting == 0)) { strcpy (Msg_Text, GET_MSG (2153)); error(2153); } goto check_suffix; } else { radix = 8; *p++ = L'0'; /* for preprocessing or 0.xxx case */ } } else { radix = 10; } while( LXC_IS_DIGIT((WCHAR)c) ) { *p++ = c; c = get_non_eof(); } if( IS_DOT(c) || IS_E(c) ) { UNGETCH(); return(get_real(p)); } check_suffix: if( IS_EL(c) ) { if( Prep ) { *p++ = c; } c = get_non_eof(); if( IS_U(c) ) { if(Prep) { *p++ = c; } tok = L_LONGUNSIGNED; } else { tok = L_LONGINT; UNGETCH(); } } else if( IS_U(c) ) { if( Prep ) { *p++ = c; } c = get_non_eof(); if( IS_EL(c) ) { if( Prep ) { *p++ = c; } tok = L_LONGUNSIGNED; } else { tok = L_CUNSIGNED; UNGETCH(); } } else { UNGETCH(); } *p = L'\0'; if( start == Exp_ptr ) { Exp_ptr = p; return(L_NOTOKEN); } else if( Prep ) { myfwrite( Reuse_W, (size_t)(p - Reuse_W) * sizeof(WCHAR), 1, OUTPUTFILE); return(L_NOTOKEN); } value.v_long = matol(Reuse_W,radix); switch(tok) { case L_CINTEGER: tok = (radix == 10) ? c_size(value.v_long) : uc_size(value.v_long) ; break; case L_LONGINT: tok = l_size(value.v_long); break; case L_CUNSIGNED: tok = ul_size(value.v_long); break; } yylval.yy_tree = build_const(tok, &value); return(tok); }
/* * Read directory structure and store entries in `entries', which must initially * point to an empty list. */ static int read_path(struct mtree_reader *r, const char *path, struct mtree_entry **entries, struct mtree_entry *parent) { DIR *dirp; struct dirent *dp; struct mtree_entry *entry; struct mtree_entry *dirs = NULL; struct mtree_entry *dot = NULL; char *wd = NULL; int ret; int skip; int skip_children; if (parent == NULL) { entry = mtree_entry_create(path); if (entry == NULL) return (-1); ret = read_path_file(r, entry, &skip, &skip_children); if (ret == -1) { mtree_entry_free(entry); return (-1); } /* * If the path doesn't point to a directory, simply store * the single entry. */ if (entry->data.type != MTREE_ENTRY_DIR) { *entries = entry; return (0); } mtree_entry_free(entry); if ((r->options & MTREE_READ_PATH_DONT_CROSS_MOUNT) != 0) { struct stat st; if ((r->options & MTREE_READ_PATH_FOLLOW_SYMLINKS) != 0) ret = stat(path, &st); else ret = lstat(path, &st); if (ret == -1) { mtree_reader_set_error(r, errno, "`%s'", path); return (-1); } r->base_dev = st.st_dev; } /* * Change to the directory to be able to read the files * with the mtree's "./" prefix. */ wd = mtree_getcwd(); if (wd == NULL) { mtree_reader_set_error(r, errno, "Could not determine the current working directory"); return (-1); } if (chdir(path) == -1) { mtree_reader_set_error(r, errno, "Could not change the working directory to `%s'", path); return (-1); } } /* * Read the directory structure. */ ret = 0; if ((dirp = opendir((parent != NULL) ? path : ".")) == NULL) { if ((r->options & MTREE_READ_PATH_SKIP_ON_ERROR) == 0) { ret = -1; goto end; } return (0); } while ((dp = readdir(dirp)) != NULL) { if (IS_DOTDOT(dp->d_name)) continue; /* * Dot is read only in the initial directory. */ if (parent != NULL && IS_DOT(dp->d_name)) continue; entry = mtree_entry_create_empty(); if (entry == NULL) { ret = -1; break; } entry->name = strdup(dp->d_name); if (entry->name == NULL) { ret = -1; break; } entry->parent = parent; entry->path = create_v1_path(entry); if (entry->path == NULL) { ret = -1; break; } ret = read_path_file(r, entry, &skip, &skip_children); if (ret == -1) break; if (IS_DOT(dp->d_name)) { if (skip) mtree_entry_free(entry); else dot = entry; if (skip_children) { /* * This is a bit artificial, but when the user * asks to skip children below ".", remove * all the entries, except for the dot itself * (unless the dot is skipped as well). */ mtree_entry_free_all(*entries); mtree_entry_free_all(dirs); *entries = NULL; dirs = NULL; break; } continue; } if (skip && skip_children) { mtree_entry_free(entry); continue; } if (entry->data.type == MTREE_ENTRY_DIR) { if (skip) entry->flags |= __MTREE_ENTRY_SKIP; if (skip_children) entry->flags |= __MTREE_ENTRY_SKIP_CHILDREN; dirs = mtree_entry_prepend(dirs, entry); } else if (!skip) *entries = mtree_entry_prepend(*entries, entry); } end: if (ret == 0) { if (dot != NULL) { /* Put the initial dot at the (reversed) start. */ *entries = mtree_entry_append(*entries, dot); } closedir(dirp); /* Directories are processed after files. */ entry = dirs; while (entry != NULL) { struct mtree_entry *next = entry->next; if ((entry->flags & __MTREE_ENTRY_SKIP) == 0) { dirs = mtree_entry_unlink(dirs, entry); *entries = mtree_entry_prepend(*entries, entry); } if ((entry->flags & __MTREE_ENTRY_SKIP_CHILDREN) == 0) ret = read_path(r, entry->path, entries, entry); if (ret == -1) break; entry = next; } } else { /* Fatal error, clean up and make our way back to the caller. */ mtree_entry_free_all(*entries); *entries = NULL; } mtree_entry_free_all(dirs); if (parent == NULL && chdir(wd) == -1) WARN("Could not change the working directory back to `%s'", wd); return (ret); }