/* Fonctions sur les noms de fichiers. */ /* Copyright (C) 2008 Emmanuel Varoquaux This file is part of XOS. 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 . */ #include "names.h" #include "file_info.h" #include #include #define ustrchr(s, c) (unsigned char *)strchr((const char *)s, c) #define ustrrchr(s, c) (unsigned char *)strrchr((const char *)s, c) /* Dit si un caractere est valide dans le jeu de caracteres des noms courts. */ static inline int isvalid(unsigned char c) { return isalnum(c) || c > 127 || (c && strchr("$%'-_@~(){}^#&", c)); } /* Decode un nom court a partir de sa representation en memoire. * * buffer doit pointer sur une zone d'au moins 13 octets. */ static void decode(const unsigned char shortname[], unsigned char buffer[]) { unsigned char *pd; pd = buffer; memcpy(pd, shortname, 8); pd[8] = ' '; pd = ustrchr(pd, ' '); if (shortname[8] != ' ') { *pd++ = '.'; memcpy(pd, shortname + 8, 3); pd[3] = ' '; pd = ustrchr(pd, ' '); } *pd = '\0'; } /* Dit si un nom long coincide avec le nom court specifie, en tenant compte de * la casse. */ static int fit(const unsigned short *longname, const unsigned char shortname[]) { unsigned char buffer[13]; unsigned char *pb; decode(shortname, pb = buffer); do { if (*pb != *longname) return 0; if (!*pb) return 1; pb++; longname++; } while (1); } /* Dit si un nom long coincide avec le nom court specifie, sans tenir compte de * la casse. */ static int ifit(const unsigned short *longname, const unsigned char shortname[]) { unsigned char buffer[13]; unsigned char *pb; decode(shortname, pb = buffer); while (*pb && *longname && toupper(*pb++) == toupper(*longname++)); return !*pb && !*longname; } /* Dit si le dernier nom court d'un repertoire coincide avec un nom court deja * present dans le repertoire. */ static int collide(const struct file_info_struct *dir_info) { unsigned int i; for (i = 0; i < dir_info->count - 1; i++) if (!memcmp(dir_info->entries[dir_info->count - 1].shortname, dir_info->entries[i].shortname, 11)) return 1; return 0; } /* Insere "~n" a la fin de la base d'un nom court. */ static void insert_numerictail(unsigned char shortname[], unsigned int n) { unsigned char buffer[8]; unsigned char *pd; unsigned int i; for (i = 7; n && i > 0; i--) { buffer[i] = (n % 10) + '0'; n /= 10; } buffer[i] = '~'; pd = shortname; while (*pd != ' ' && pd < shortname + i) pd++; memcpy(pd, buffer + i, 8 - i); } /* Genere un nom court a partir d'un nom long. * * shortname doit pointer sur une zone d'au moins 11 octets. * lossy_conversion indique si des caracteres invalides ont du etre * remplaces. */ static void generate_basisname(const unsigned short *longname, unsigned char shortname[], int *lossy_conversion) { unsigned char buffer[256]; const unsigned short *pss; const unsigned char *ps; unsigned char *pd; unsigned int i; *lossy_conversion = 0; memset(shortname, ' ', 11); pss = longname; /* 1 */ pd = buffer; do *pd++ = toupper((unsigned char)*pss); while (*pss++ && (size_t)(pd - buffer) < sizeof buffer - 1); buffer[sizeof buffer - 1] = '\0'; for (pd = buffer; *pd; pd++) /* 2 */ if (!isvalid(*pd) && *pd != ' ' && *pd != '.') { *pd = '_'; *lossy_conversion = 1; } ps = pd = buffer; /* 3 */ do if (*ps != ' ') *pd++ = *ps; while (*ps++); ps = pd = buffer; /* 4 */ while (*ps == '.') ps++; do *pd++ = *ps; while (*ps++); ps = buffer; /* 5 */ pd = shortname; i = 0; while (*ps && *ps != '.' && i++ < 8) *pd++ = *ps++; ps = ustrrchr(buffer, '.'); /* 6, 7 */ if (ps && *++ps) { pd = shortname + 8; i = 0; while (*ps && i++ < 3) *pd++ = *ps++; } } /* Insere "~n" dans le dernier nom court du repertoire, de facon a ce qu'il n'y * ait pas deux noms courts identiques. * * lossy_conversion doit provenir de generate_basisname(). */ static void generate_numerictail(struct file_info_struct *dir_info, int lossy_conversion) { unsigned int n; if (!lossy_conversion && ifit(dir_info->entries[dir_info->count - 1].longname, dir_info->entries[dir_info->count - 1].shortname) && !collide(dir_info)) return; n = 1; do insert_numerictail(dir_info->entries[dir_info->count - 1].shortname, n++); while (collide(dir_info)); } /* Genere le nom long de la derniere entree du repertoire. */ void generate_longname(struct file_info_struct *dir_info) { unsigned int i; for (i = 0; dir_info->entries[dir_info->count - 1].filename[i] && i < 255; i++) dir_info->entries[dir_info->count - 1].longname[i] = dir_info->entries[dir_info->count - 1].filename[i]; dir_info->entries[dir_info->count - 1].longname[i] = '\0'; } /* Genere le nom court de la derniere entree du repertoire. */ void generate_shortname(struct file_info_struct *dir_info) { int lossy_conversion; generate_basisname(dir_info->entries[dir_info->count - 1].longname, dir_info->entries[dir_info->count - 1].shortname, &lossy_conversion); generate_numerictail(dir_info, lossy_conversion); } /* Retourne le nombre d'entrees de repertoire supplementaires necessaires pour * stocker le nom long de file_info. S'il n'est pas necessaire de stocker un * nom long pour file_info, retourne 0. */ unsigned int n_long_entries(const struct file_info_struct *file_info) { unsigned int len; for (len = 0; file_info->longname[len]; len++); return fit(file_info->longname, file_info->shortname) ? 0 : (len + 12) / 13; }