uboot/fs/fdos/subdir.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 <malloc.h>
  28
  29#include "dos.h"
  30#include "fdos.h"
  31
  32static int cache_sect;
  33static unsigned char cache [SZ_STD_SECTOR];
  34
  35
  36#define min(x,y) ((x)<(y)?(x):(y))
  37
  38static int descend (Slot_t *parent,
  39             Fs_t *fs,
  40                    char *path);
  41
  42/*-----------------------------------------------------------------------------
  43 * init_subdir --
  44 *-----------------------------------------------------------------------------
  45 */
  46void init_subdir (void)
  47{
  48    cache_sect = -1;
  49}
  50/*-----------------------------------------------------------------------------
  51 * basename --
  52 *-----------------------------------------------------------------------------
  53 */
  54char *basename (char *name)
  55{
  56    register char *cptr;
  57
  58    if (!name || !*name) {
  59        return ("");
  60    }
  61
  62    for (cptr= name; *cptr++; );
  63    while (--cptr >= name) {
  64        if (*cptr == '/')    {
  65            return (cptr + 1);
  66        }
  67    }
  68    return(name);
  69}
  70/*-----------------------------------------------------------------------------
  71 * root_map --
  72 *-----------------------------------------------------------------------------
  73 */
  74static int root_map (Fs_t *fs, Slot_t *file, int where, int *len)
  75{
  76    *len = min (*len, fs -> dir_len * SZ_STD_SECTOR - where);
  77    if (*len < 0 ) {
  78        *len = 0;
  79        return (-1);
  80    }
  81    return fs -> dir_start * SZ_STD_SECTOR + where;
  82}
  83/*-----------------------------------------------------------------------------
  84 * normal_map --
  85 *-----------------------------------------------------------------------------
  86 */
  87static int normal_map (Fs_t *fs, Slot_t *file, int where, int *len)
  88{
  89    int offset;
  90    int NrClu;
  91    unsigned short RelCluNr;
  92    unsigned short CurCluNr;
  93    unsigned short NewCluNr;
  94    unsigned short AbsCluNr;
  95    int clus_size;
  96
  97    clus_size = fs -> cluster_size * SZ_STD_SECTOR;
  98    offset = where % clus_size;
  99
 100    *len = min (*len, file -> FileSize - where);
 101
 102    if (*len < 0 ) {
 103        *len = 0;
 104        return (0);
 105    }
 106
 107    if (file -> FirstAbsCluNr < 2){
 108        *len = 0;
 109        return (0);
 110    }
 111
 112    RelCluNr = where / clus_size;
 113
 114    if (RelCluNr >= file -> PreviousRelCluNr){
 115        CurCluNr = file -> PreviousRelCluNr;
 116        AbsCluNr = file -> PreviousAbsCluNr;
 117    } else {
 118        CurCluNr = 0;
 119        AbsCluNr = file -> FirstAbsCluNr;
 120    }
 121
 122
 123    NrClu = (offset + *len - 1) / clus_size;
 124    while (CurCluNr <= RelCluNr + NrClu) {
 125        if (CurCluNr == RelCluNr){
 126            /* we have reached the beginning of our zone. Save
 127             * coordinates */
 128            file -> PreviousRelCluNr = RelCluNr;
 129            file -> PreviousAbsCluNr = AbsCluNr;
 130        }
 131        NewCluNr = fat_decode (fs, AbsCluNr);
 132        if (NewCluNr == 1 || NewCluNr == 0) {
 133            PRINTF("Fat problem while decoding %d %x\n",
 134                    AbsCluNr, NewCluNr);
 135            return (-1);
 136        }
 137        if (CurCluNr == RelCluNr + NrClu) {
 138            break;
 139        }
 140
 141        if (CurCluNr < RelCluNr && NewCluNr == FAT12_END) {
 142            *len = 0;
 143            return 0;
 144        }
 145
 146        if (CurCluNr >= RelCluNr && NewCluNr != AbsCluNr + 1)
 147            break;
 148        CurCluNr++;
 149        AbsCluNr = NewCluNr;
 150    }
 151
 152    *len = min (*len, (1 + CurCluNr - RelCluNr) * clus_size - offset);
 153
 154    return (((file -> PreviousAbsCluNr - 2) * fs -> cluster_size +
 155             fs -> dir_start + fs -> dir_len) *
 156            SZ_STD_SECTOR + offset);
 157}
 158/*-----------------------------------------------------------------------------
 159 * open_subdir -- open the subdir containing the file
 160 *-----------------------------------------------------------------------------
 161 */
 162int open_subdir (File_t *desc)
 163{
 164    char *pathname;
 165    char *tmp, *s, *path;
 166    char terminator;
 167
 168    if ((pathname = (char *)malloc (MAX_PATH)) == NULL) {
 169        return (-1);
 170    }
 171
 172    strcpy (pathname, desc -> name);
 173
 174    /* Suppress file name                                                    */
 175    tmp = basename (pathname);
 176    *tmp = '\0';
 177
 178    /* root directory  init                                                  */
 179    desc -> subdir.FirstAbsCluNr = 0;
 180    desc -> subdir.FileSize = -1;
 181    desc -> subdir.map = root_map;
 182    desc -> subdir.dir.attr = ATTR_DIRECTORY;
 183
 184    tmp = pathname;
 185    for (s = tmp; ; ++s) {
 186        if (*s == '/' || *s == '\0') {
 187            path = tmp;
 188            terminator = *s;
 189            *s = '\0';
 190            if (s != tmp && strcmp (path,".")) {
 191                if (descend (&desc -> subdir, desc -> fs, path) < 0) {
 192                    free (pathname);
 193                    return (-1);
 194                }
 195            }
 196            if (terminator == 0) {
 197                break;
 198            }
 199            tmp = s + 1;
 200        }
 201    }
 202    free (pathname);
 203    return (0);
 204}
 205/*-----------------------------------------------------------------------------
 206 * descend --
 207 *-----------------------------------------------------------------------------
 208 */
 209static int descend (Slot_t *parent,
 210             Fs_t *fs,
 211             char *path)
 212{
 213    int entry;
 214    Slot_t SubDir;
 215
 216    if(path[0] == '\0' || strcmp (path, ".") == 0) {
 217        return (0);
 218    }
 219
 220
 221    entry = 0;
 222    if (vfat_lookup (parent,
 223                     fs,
 224                     &(SubDir.dir),
 225                     &entry,
 226                     0,
 227                     path,
 228                     ACCEPT_DIR | SINGLE | DO_OPEN,
 229                     0,
 230                     &SubDir) == 0) {
 231        *parent = SubDir;
 232        return (0);
 233    }
 234
 235    if (strcmp(path, "..") == 0) {
 236        parent -> FileSize = -1;
 237        parent -> FirstAbsCluNr = 0;
 238        parent -> map = root_map;
 239        return (0);
 240    }
 241    return (-1);
 242}
 243/*-----------------------------------------------------------------------------
 244 * open_file --
 245 *-----------------------------------------------------------------------------
 246 */
 247int open_file (Slot_t *file, Directory_t *dir)
 248{
 249    int first;
 250    unsigned long size;
 251
 252    first = __le16_to_cpu (dir -> start);
 253
 254    if(first == 0 &&
 255       (dir -> attr & ATTR_DIRECTORY) != 0) {
 256        file -> FirstAbsCluNr = 0;
 257        file -> FileSize = -1;
 258        file -> map = root_map;
 259        return (0);
 260    }
 261
 262    if ((dir -> attr & ATTR_DIRECTORY) != 0) {
 263        size = (1UL << 31) - 1;
 264    }
 265    else {
 266        size = __le32_to_cpu (dir -> size);
 267    }
 268
 269    file -> map = normal_map;
 270    file -> FirstAbsCluNr = first;
 271    file -> PreviousRelCluNr = 0xffff;
 272    file -> FileSize = size;
 273    return (0);
 274}
 275/*-----------------------------------------------------------------------------
 276 * read_file --
 277 *-----------------------------------------------------------------------------
 278 */
 279int read_file (Fs_t *fs,
 280               Slot_t *file,
 281               char *buf,
 282               int where,
 283               int len)
 284{
 285    int pos;
 286    int read, nb, sect, offset;
 287
 288    pos = file -> map (fs, file, where, &len);
 289    if  (pos < 0) {
 290        return -1;
 291    }
 292    if (len == 0) {
 293        return (0);
 294    }
 295
 296    /* Compute sector number                                                 */
 297    sect = pos / SZ_STD_SECTOR;
 298    offset = pos % SZ_STD_SECTOR;
 299    read = 0;
 300
 301    if (offset) {
 302        /* Read doesn't start at the sector beginning. We need to use our    */
 303        /* cache                                                             */
 304        if (sect != cache_sect) {
 305            if (dev_read (cache, sect, 1) < 0) {
 306                return (-1);
 307            }
 308            cache_sect = sect;
 309        }
 310        nb = min (len, SZ_STD_SECTOR - offset);
 311
 312        memcpy (buf, cache + offset, nb);
 313        read += nb;
 314        len -= nb;
 315        sect += 1;
 316    }
 317
 318    if (len > SZ_STD_SECTOR) {
 319        nb = (len - 1) / SZ_STD_SECTOR;
 320        if (dev_read (buf + read, sect, nb) < 0) {
 321            return ((read) ? read : -1);
 322        }
 323        /* update sector position                                            */
 324        sect += nb;
 325
 326        /* Update byte position                                              */
 327        nb *= SZ_STD_SECTOR;
 328        read += nb;
 329        len -= nb;
 330    }
 331
 332    if (len) {
 333        if (sect != cache_sect) {
 334            if (dev_read (cache, sect, 1) < 0) {
 335                return ((read) ? read : -1);
 336                cache_sect = -1;
 337            }
 338            cache_sect = sect;
 339        }
 340
 341        memcpy (buf + read, cache, len);
 342        read += len;
 343    }
 344    return (read);
 345}
 346