diff options
Diffstat (limited to 'dosfstools/src/file.c')
-rw-r--r-- | dosfstools/src/file.c | 276 |
1 files changed, 276 insertions, 0 deletions
diff --git a/dosfstools/src/file.c b/dosfstools/src/file.c new file mode 100644 index 000000000..dffcec1cd --- /dev/null +++ b/dosfstools/src/file.c @@ -0,0 +1,276 @@ +/* file.c - Additional file attributes + + Copyright (C) 1993 Werner Almesberger <werner.almesberger@lrc.di.epfl.ch> + Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> + Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + The complete text of the GNU General Public License + can be found in /usr/share/common-licenses/GPL-3 file. +*/ + +/* FAT32, VFAT, Atari format support, and various fixes additions May 1998 + * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <unistd.h> + +#include "common.h" +#include "file.h" +#include "msdos_fs.h" + +FDSC *fp_root = NULL; + +static void put_char(char **p, unsigned char c) +{ + if ((c >= ' ' && c < 0x7f) || c >= 0xa0) + *(*p)++ = c; + else { + *(*p)++ = '\\'; + *(*p)++ = '0' + (c >> 6); + *(*p)++ = '0' + ((c >> 3) & 7); + *(*p)++ = '0' + (c & 7); + } +} + +/** + * Construct the "pretty-printed" representation of the name in a short directory entry. + * + * @param[in] fixed Pointer to name[0] of a DIR_ENT + * + * @return Pointer to static string containing pretty "8.3" equivalent of the + * name in the directory entry. + */ +char *file_name(unsigned char *fixed) +{ + static char path[MSDOS_NAME * 4 + 2]; + char *p; + int i, j; + + p = path; + for (i = j = 0; i < 8; i++) + if (fixed[i] != ' ') { + while (j++ < i) + *p++ = ' '; + put_char(&p, fixed[i]); + } + if (strncmp((const char *)(fixed + 8), " ", 3)) { + *p++ = '.'; + for (i = j = 0; i < 3; i++) + if (fixed[i + 8] != ' ') { + while (j++ < i) + *p++ = ' '; + put_char(&p, fixed[i + 8]); + } + } + *p = 0; + return path; +} + +int file_cvt(unsigned char *name, unsigned char *fixed) +{ + unsigned char c; + int size, ext, cnt; + + size = 8; + ext = 0; + while (*name) { + c = *name; + if (c < ' ' || c > 0x7e || strchr("*?<>|\"/", c)) { + printf("Invalid character in name. Use \\ooo for special " + "characters.\n"); + return 0; + } + if (c == '.') { + if (ext) { + printf("Duplicate dots in name.\n"); + return 0; + } + while (size--) + *fixed++ = ' '; + size = 3; + ext = 1; + name++; + continue; + } + if (c == '\\') { + c = 0; + for (cnt = 3; cnt; cnt--) { + if (*name < '0' || *name > '7') { + printf("Invalid octal character.\n"); + return 0; + } + c = c * 8 + *name++ - '0'; + } + if (cnt < 4) { + printf("Expected three octal digits.\n"); + return 0; + } + name += 3; + } + if (islower(c)) + c = toupper(c); + if (size) { + *fixed++ = c; + size--; + } + name++; + } + if (*name || size == 8) + return 0; + if (!ext) { + while (size--) + *fixed++ = ' '; + size = 3; + } + while (size--) + *fixed++ = ' '; + return 1; +} + +void file_add(char *path, FD_TYPE type) +{ + FDSC **current, *walk; + char name[MSDOS_NAME]; + char *here; + + current = &fp_root; + if (*path != '/') + die("%s: Absolute path required.", path); + path++; + while (1) { + if ((here = strchr(path, '/'))) + *here = 0; + if (!file_cvt((unsigned char *)path, (unsigned char *)name)) + exit(2); + for (walk = *current; walk; walk = walk->next) + if (!here && (!strncmp(name, walk->name, MSDOS_NAME) || (type == + fdt_undelete + && + !strncmp + (name + 1, + walk->name + + 1, + MSDOS_NAME + - 1)))) + die("Ambiguous name: \"%s\"", path); + else if (here && !strncmp(name, walk->name, MSDOS_NAME)) + break; + if (!walk) { + walk = alloc(sizeof(FDSC)); + strncpy(walk->name, name, MSDOS_NAME); + walk->type = here ? fdt_none : type; + walk->first = NULL; + walk->next = *current; + *current = walk; + } + current = &walk->first; + if (!here) + break; + *here = '/'; + path = here + 1; + } +} + +FDSC **file_cd(FDSC ** curr, char *fixed) +{ + FDSC **walk; + + if (!curr || !*curr) + return NULL; + for (walk = curr; *walk; walk = &(*walk)->next) + if (!strncmp((*walk)->name, fixed, MSDOS_NAME) && (*walk)->first) + return &(*walk)->first; + return NULL; +} + +static FDSC **file_find(FDSC ** dir, char *fixed) +{ + if (!dir || !*dir) + return NULL; + if (*(unsigned char *)fixed == DELETED_FLAG) { + while (*dir) { + if (!strncmp((*dir)->name + 1, fixed + 1, MSDOS_NAME - 1) + && !(*dir)->first) + return dir; + dir = &(*dir)->next; + } + return NULL; + } + while (*dir) { + if (!strncmp((*dir)->name, fixed, MSDOS_NAME) && !(*dir)->first) + return dir; + dir = &(*dir)->next; + } + return NULL; +} + +/* Returns the attribute of the file FIXED in directory CURR or FDT_NONE if no + such file exists or if CURR is NULL. */ +FD_TYPE file_type(FDSC ** curr, char *fixed) +{ + FDSC **this; + + if ((this = file_find(curr, fixed))) + return (*this)->type; + return fdt_none; +} + +void file_modify(FDSC ** curr, char *fixed) +{ + FDSC **this, *next; + + if (!(this = file_find(curr, fixed))) + die("Internal error: file_find failed"); + switch ((*this)->type) { + case fdt_drop: + printf("Dropping %s\n", file_name((unsigned char *)fixed)); + *(unsigned char *)fixed = DELETED_FLAG; + break; + case fdt_undelete: + *fixed = *(*this)->name; + printf("Undeleting %s\n", file_name((unsigned char *)fixed)); + break; + default: + die("Internal error: file_modify"); + } + next = (*this)->next; + free(*this); + *this = next; +} + +static void report_unused(FDSC * this) +{ + FDSC *next; + + while (this) { + next = this->next; + if (this->first) + report_unused(this->first); + else if (this->type != fdt_none) + printf("Warning: did not %s file %s\n", this->type == fdt_drop ? + "drop" : "undelete", file_name((unsigned char *)this->name)); + free(this); + this = next; + } +} + +void file_unused(void) +{ + report_unused(fp_root); +} |