| /* 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> |
| |
| 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/>. |
| |
| On Debian systems, 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> |
| |
| #define _LINUX_STAT_H /* hack to avoid inclusion of <linux/stat.h> */ |
| #define _LINUX_STRING_H_ /* hack to avoid inclusion of <linux/string.h>*/ |
| #define _LINUX_FS_H /* hack to avoid inclusion of <linux/fs.h> */ |
| |
| # include <asm/types.h> |
| |
| #include <linux/msdos_fs.h> |
| |
| #include "common.h" |
| #include "file.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); |
| } |
| } |
| |
| |
| 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(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(path,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; |
| } |
| |
| |
| 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(fixed)); |
| *(unsigned char *) fixed = DELETED_FLAG; |
| break; |
| case fdt_undelete: |
| *fixed = *(*this)->name; |
| printf("Undeleting %s\n",file_name(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(this->name)); |
| free(this); |
| this = next; |
| } |
| } |
| |
| |
| void file_unused(void) |
| { |
| report_unused(fp_root); |
| } |
| |
| /* Local Variables: */ |
| /* tab-width: 8 */ |
| /* End: */ |