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