uboot/fs/fdos/vfat.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2002
   3 * Stäubli Faverges - <www.staubli.com>
   4 * Pierre AUBERT  p.aubert@staubli.com
   5 *
   6 * See file CREDITS for list of people who contributed to this
   7 * project.
   8 *
   9 * This program is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU General Public License as
  11 * published by the Free Software Foundation; either version 2 of
  12 * the License, or (at your option) any later version.
  13 *
  14 * This program is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17 * GNU General Public License for more details.
  18 *
  19 * You should have received a copy of the GNU General Public License
  20 * along with this program; if not, write to the Free Software
  21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  22 * MA 02111-1307 USA
  23 */
  24
  25#include <common.h>
  26#include <config.h>
  27#include <linux/ctype.h>
  28
  29#include "dos.h"
  30#include "fdos.h"
  31
  32static int dir_read (Fs_t *fs,
  33                     Slot_t *dir,
  34                     Directory_t *dirent,
  35                     int num,
  36                     struct vfat_state *v);
  37
  38static int unicode_read (char *in, char *out, int num);
  39static int match (const char *s, const char *p);
  40static unsigned char sum_shortname (char *name);
  41static int check_vfat (struct vfat_state *v, Directory_t *dir);
  42static char *conv_name (char *name, char *ext, char Case, char *ans);
  43
  44
  45/*-----------------------------------------------------------------------------
  46 * clear_vfat --
  47 *-----------------------------------------------------------------------------
  48 */
  49static void clear_vfat (struct vfat_state *v)
  50{
  51    v -> subentries = 0;
  52    v -> status = 0;
  53}
  54
  55/*-----------------------------------------------------------------------------
  56 * vfat_lookup --
  57 *-----------------------------------------------------------------------------
  58 */
  59int vfat_lookup (Slot_t *dir,
  60                 Fs_t *fs,
  61                 Directory_t *dirent,
  62                 int *entry,
  63                 int *vfat_start,
  64                 char *filename,
  65                 int flags,
  66                 char *outname,
  67                 Slot_t *file)
  68{
  69    int found;
  70    struct vfat_state vfat;
  71    char newfile [VSE_NAMELEN];
  72    int vfat_present = 0;
  73
  74    if (*entry == -1) {
  75        return -1;
  76    }
  77
  78    found = 0;
  79    clear_vfat (&vfat);
  80    while (1) {
  81        if (dir_read (fs, dir, dirent, *entry, &vfat) < 0) {
  82            if (vfat_start) {
  83                *vfat_start = *entry;
  84            }
  85            break;
  86        }
  87        (*entry)++;
  88
  89        /* Empty slot                                                        */
  90        if (dirent -> name[0] == '\0'){
  91            if (vfat_start == 0) {
  92                break;
  93            }
  94            continue;
  95        }
  96
  97        if (dirent -> attr == ATTR_VSE) {
  98            /* VSE entry, continue                                           */
  99            continue;
 100        }
 101        if ( (dirent -> name [0] == DELMARK) ||
 102             ((dirent -> attr & ATTR_DIRECTORY) != 0 &&
 103              (flags & ACCEPT_DIR) == 0) ||
 104             ((dirent -> attr & ATTR_VOLUME) != 0 &&
 105              (flags & ACCEPT_LABEL) == 0) ||
 106             (((dirent -> attr & (ATTR_DIRECTORY | ATTR_VOLUME)) == 0) &&
 107              (flags & ACCEPT_PLAIN) == 0)) {
 108            clear_vfat (&vfat);
 109            continue;
 110        }
 111
 112        vfat_present = check_vfat (&vfat, dirent);
 113        if (vfat_start) {
 114            *vfat_start = *entry - 1;
 115            if (vfat_present) {
 116                *vfat_start -= vfat.subentries;
 117            }
 118        }
 119
 120        if (dirent -> attr & ATTR_VOLUME) {
 121            strncpy (newfile, dirent -> name, 8);
 122            newfile [8] = '\0';
 123            strncat (newfile, dirent -> ext, 3);
 124            newfile [11] = '\0';
 125        }
 126        else {
 127            conv_name (dirent -> name, dirent -> ext, dirent -> Case, newfile);
 128        }
 129
 130        if (flags & MATCH_ANY) {
 131            found = 1;
 132            break;
 133        }
 134
 135        if ((vfat_present && match (vfat.name, filename)) ||
 136            (match (newfile, filename))) {
 137            found = 1;
 138            break;
 139        }
 140        clear_vfat (&vfat);
 141    }
 142
 143    if (found) {
 144        if ((flags & DO_OPEN) && file) {
 145            if (open_file (file, dirent) < 0) {
 146                return (-1);
 147            }
 148        }
 149        if (outname) {
 150            if (vfat_present) {
 151                strcpy (outname, vfat.name);
 152            }
 153            else {
 154                strcpy (outname, newfile);
 155            }
 156        }
 157        return (0);                    /* File found                         */
 158    } else {
 159        *entry = -1;
 160        return -1;                      /* File not found                    */
 161    }
 162}
 163
 164/*-----------------------------------------------------------------------------
 165 * dir_read -- Read one directory entry
 166 *-----------------------------------------------------------------------------
 167 */
 168static int dir_read (Fs_t *fs,
 169              Slot_t *dir,
 170              Directory_t *dirent,
 171              int num,
 172              struct vfat_state *v)
 173{
 174
 175    /* read the directory entry                                              */
 176    if (read_file (fs,
 177                   dir,
 178                   (char *)dirent,
 179                   num * MDIR_SIZE,
 180                   MDIR_SIZE) != MDIR_SIZE) {
 181        return (-1);
 182    }
 183
 184    if (v && (dirent -> attr == ATTR_VSE)) {
 185        struct vfat_subentry *vse;
 186        unsigned char id, last_flag;
 187        char *c;
 188
 189        vse = (struct vfat_subentry *) dirent;
 190        id = vse -> id & VSE_MASK;
 191        last_flag = (vse -> id & VSE_LAST);
 192        if (id > MAX_VFAT_SUBENTRIES) {
 193            /* Invalid VSE entry                                             */
 194            return (-1);
 195        }
 196
 197
 198        /* Decode VSE                                                        */
 199        if(v -> sum != vse -> sum) {
 200            clear_vfat (v);
 201            v -> sum = vse -> sum;
 202        }
 203
 204
 205        v -> status |= 1 << (id - 1);
 206        if (last_flag) {
 207            v -> subentries = id;
 208        }
 209
 210        c = &(v -> name [VSE_NAMELEN * (id - 1)]);
 211        c += unicode_read (vse->text1, c, VSE1SIZE);
 212        c += unicode_read (vse->text2, c, VSE2SIZE);
 213        c += unicode_read (vse->text3, c, VSE3SIZE);
 214
 215        if (last_flag) {
 216            *c = '\0';          /* Null terminate long name                  */
 217        }
 218
 219    }
 220    return (0);
 221}
 222
 223/*-----------------------------------------------------------------------------
 224 * unicode_read --
 225 *-----------------------------------------------------------------------------
 226 */
 227static int unicode_read (char *in, char *out, int num)
 228{
 229    int j;
 230
 231    for (j = 0; j < num; ++j) {
 232        if (in [1])
 233            *out = '_';
 234        else
 235            *out = in [0];
 236        out ++;
 237        in += 2;
 238    }
 239    return num;
 240}
 241
 242/*-----------------------------------------------------------------------------
 243 * match --
 244 *-----------------------------------------------------------------------------
 245 */
 246static int match (const char *s, const char *p)
 247{
 248
 249    for (; *p != '\0'; ) {
 250        if (toupper (*s) != toupper (*p)) {
 251            return (0);
 252        }
 253        p++;
 254        s++;
 255    }
 256
 257    if (*s != '\0') {
 258        return (0);
 259    }
 260    else {
 261        return (1);
 262    }
 263}
 264/*-----------------------------------------------------------------------------
 265 * sum_shortname --
 266 *-----------------------------------------------------------------------------
 267 */
 268static unsigned char sum_shortname (char *name)
 269{
 270    unsigned char sum;
 271    int j;
 272
 273    for (j = sum = 0; j < 11; ++j) {
 274        sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1) +
 275            (name [j] ? name [j] : ' ');
 276    }
 277    return (sum);
 278}
 279/*-----------------------------------------------------------------------------
 280 * check_vfat --
 281 * Return 1 if long name is valid, 0 else
 282 *-----------------------------------------------------------------------------
 283 */
 284static int check_vfat (struct vfat_state *v, Directory_t *dir)
 285{
 286    char name[12];
 287
 288    if (v -> subentries == 0) {
 289        return 0;
 290    }
 291
 292    strncpy (name, dir -> name, 8);
 293    strncpy (name + 8, dir -> ext, 3);
 294    name [11] = '\0';
 295
 296    if (v -> sum != sum_shortname (name)) {
 297        return 0;
 298    }
 299
 300    if( (v -> status & ((1 << v -> subentries) - 1)) !=
 301        (1 << v -> subentries) - 1) {
 302        return 0;
 303    }
 304    v->name [VSE_NAMELEN * v -> subentries] = 0;
 305
 306    return 1;
 307}
 308/*-----------------------------------------------------------------------------
 309 * conv_name --
 310 *-----------------------------------------------------------------------------
 311 */
 312static char *conv_name (char *name, char *ext, char Case, char *ans)
 313{
 314    char tname [9], text [4];
 315    int i;
 316
 317    i = 0;
 318    while (i < 8 && name [i] != ' ' && name [i] != '\0') {
 319        tname [i] = name [i];
 320        i++;
 321    }
 322    tname [i] = '\0';
 323
 324    if (Case & BASECASE) {
 325        for (i = 0; i < 8 && tname [i]; i++) {
 326            tname [i] = tolower (tname [i]);
 327        }
 328    }
 329
 330    i = 0;
 331    while (i < 3 && ext [i] != ' ' && ext [i] != '\0') {
 332        text [i] = ext [i];
 333        i++;
 334    }
 335    text [i] = '\0';
 336
 337    if (Case & EXTCASE){
 338        for (i = 0; i < 3 && text [i]; i++) {
 339            text [i] = tolower (text [i]);
 340        }
 341    }
 342
 343    if (*text) {
 344        strcpy (ans, tname);
 345        strcat (ans, ".");
 346        strcat (ans, text);
 347    }
 348    else {
 349        strcpy(ans, tname);
 350    }
 351    return (ans);
 352}
 353