phatvol.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2005-2006 by egnite Software GmbH. All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00018  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00021  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00023  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00024  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00025  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00026  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00027  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * For additional information see http://www.ethernut.de/
00031  */
00032 
00086 #include <dev/blockdev.h>
00087 
00088 #include <sys/event.h>
00089 
00090 #include <fs/dospart.h>
00091 #include <fs/phatio.h>
00092 #include <fs/phatutil.h>
00093 #include <fs/phatvol.h>
00094 
00095 #include <errno.h>
00096 #include <stdlib.h>
00097 #include <string.h>
00098 
00099 
00100 #if 0
00101 /* Use for local debugging. */
00102 #define NUTDEBUG
00103 #include <stdio.h>
00104 #include <fs/phatdbg.h>
00105 #endif
00106 
00111 
00119 static uint32_t PhatCountFreeClusters(NUTDEVICE * dev)
00120 {
00121     uint32_t rc = 0;
00122     uint32_t i = 2;
00123     uint32_t link;
00124     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00125 
00126     if (vol->vol_type == 32) {
00127         while (i < vol->vol_last_clust) {
00128             if (Phat32GetClusterLink(dev, i, &link)) {
00129                 break;
00130             }
00131             if (link == 0) {
00132                 rc++;
00133             }
00134             i++;
00135         }
00136     } else if (vol->vol_type == 16) {
00137         while (i < vol->vol_last_clust) {
00138             if (Phat16GetClusterLink(dev, i, &link)) {
00139                 break;
00140             }
00141             if (link == 0) {
00142                 rc++;
00143             }
00144             i++;
00145         }
00146     } else {
00147         while (i < vol->vol_last_clust) {
00148             if (Phat12GetClusterLink(dev, i, &link)) {
00149                 break;
00150             }
00151             if (link == 0) {
00152                 rc++;
00153             }
00154             i++;
00155         }
00156     }
00157     return rc;
00158 }
00159 
00182 int PhatVolMount(NUTDEVICE * dev, NUTFILE * blkmnt, uint8_t part_type)
00183 {
00184     PHATVOL *vol;
00185     PHATVBR *vbr;
00186     BLKPAR_INFO pari;
00187     int sbn;
00188     NUTDEVICE *blkdev = blkmnt->nf_dev;
00189 
00190     /*
00191      * Allocate the volume information structure 
00192      */
00193     if ((dev->dev_dcb = malloc(sizeof(PHATVOL))) == 0) {
00194         return -1;
00195     }
00196     vol = (PHATVOL *) memset(dev->dev_dcb, 0, sizeof(PHATVOL));
00197 
00198     /*
00199      * Determine the PHAT type.
00200      */
00201     switch (part_type) {
00202     case PTYPE_FAT32:
00203     case PTYPE_FAT32_LBA:
00204         vol->vol_type = 32;
00205         break;
00206     case PTYPE_FAT16:
00207     case PTYPE_FAT16_BIG:
00208     case PTYPE_FAT16_LBA:
00209         vol->vol_type = 16;
00210         break;
00211     case PTYPE_FAT12:
00212         vol->vol_type = 12;
00213         break;
00214     }
00215 
00216     /*
00217      * Query information from the block device driver.
00218      */
00219     pari.par_nfp = blkmnt;
00220     if ((*blkdev->dev_ioctl) (blkdev, NUTBLKDEV_INFO, &pari)) {
00221         free(vol);
00222         errno = ENODEV;
00223         return -1;
00224     }
00225 #if PHAT_SECTOR_BUFFERS
00226     for (sbn = 0; sbn < PHAT_SECTOR_BUFFERS; sbn++) {
00227         if ((vol->vol_buf[sbn].sect_data = malloc(pari.par_blksz)) == NULL) {
00228             PhatVolUnmount(dev);
00229             return -1;
00230         }
00231         vol->vol_buf[sbn].sect_num = (uint32_t)-1;
00232     }
00233 #else
00234     vol->vol_buf[0].sect_data = pari.par_blkbp;
00235 #endif
00236     sbn = 0;
00237 
00238     /*
00239      * We use PhatSectorRead() instead of PhatSectorLoad() for our 
00240      * very first read to properly initialize the caching status.
00241      */
00242     if (PhatSectorRead(blkmnt, 0, vol->vol_buf[sbn].sect_data)) {
00243         PhatVolUnmount(dev);
00244         return -1;
00245     }
00246     vol->vol_buf[sbn].sect_num = 0;
00247     vbr = (PHATVBR *) vol->vol_buf[sbn].sect_data;
00248 
00249     /*
00250      * PHAT32 doesn't have a fixed root directory. At this point
00251      * we reliably know wether we got PHAT32 or not. After having
00252      * determined the total number of clusters later, we can check
00253      * for PHAT12 or PHAT16.
00254      */
00255     if (vol->vol_type == 0 && vbr->bios_rootsz == 0) {
00256         vol->vol_type = 32;
00257     }
00258 
00259     /* Convert to PHAT12/PHAT16 layout. */
00260     if (vol->vol_type != 32) {
00261         memcpy(&vbr->boot_drive, &vbr->bios_tabsz_big, 26);
00262         memset(&vbr->bios_tabsz_big, 0, 28);
00263     }
00264 #ifdef NUTDEBUG
00265     PhatDbgVbr(stdout, "Volume Boot Record", vbr);
00266 #endif
00267 
00268     /*
00269      * Verify the VBR signature.
00270      */
00271     if (vol->vol_buf[sbn].sect_data[510] != 0x55 || vol->vol_buf[sbn].sect_data[511] != 0xAA) {
00272         PhatVolUnmount(dev);
00273         errno = ENODEV;
00274         return -1;
00275     }
00276 
00277     /*
00278      * Make sure we got a valid media type.
00279      */
00280     if (vbr->bios_media != 0xF0 && vbr->bios_media < 0xF8) {
00281         PhatVolUnmount(dev);
00282         errno = ENODEV;
00283         return -1;
00284     }
00285 
00286     /*
00287      * Examine the informations found in the boot record.
00288      */
00289     /* Bytes per sector. */
00290     vol->vol_sectsz = vbr->bios_sectsz;
00291     if (vol->vol_sectsz < 512 || vol->vol_sectsz & 0xFF) {
00292         PhatVolUnmount(dev);
00293         errno = ENODEV;
00294         return -1;
00295     }
00296     /* Sectors per cluster. */
00297     if ((vol->vol_clustsz = vbr->bios_clustsz) == 0) {
00298         PhatVolUnmount(dev);
00299         errno = ENODEV;
00300         return -1;
00301     }
00302     /* Allocation table size and position. */
00303     if (vbr->bios_tabsz) {
00304         vol->vol_tabsz = vbr->bios_tabsz;
00305     } else {
00306         vol->vol_tabsz = vbr->bios_tabsz_big;
00307     }
00308     vol->vol_tab_sect[0] = vbr->bios_rsvd_sects;
00309     if (vbr->bios_ntabs > 1) {
00310         vol->vol_tab_sect[1] = vol->vol_tab_sect[0] + vol->vol_tabsz;
00311     }
00312     /* Root directory size and position. */
00313     vol->vol_rootsz = (vbr->bios_rootsz * sizeof(PHATDIRENT) +  /* */
00314                        vol->vol_sectsz - 1) / vol->vol_sectsz;
00315     vol->vol_root_sect = vbr->bios_rsvd_sects + /* */
00316         vbr->bios_ntabs * vol->vol_tabsz;
00317     if (vol->vol_type == 32) {
00318         vol->vol_root_clust = vbr->bios_root_clust;
00319     }
00320     /* First data sector and number of data clusters. */
00321     vol->vol_data_sect = vol->vol_root_sect + vol->vol_rootsz;
00322     if (vbr->bios_volsz) {
00323         vol->vol_last_clust = vbr->bios_volsz - vol->vol_data_sect;
00324     } else {
00325         vol->vol_last_clust = vbr->bios_volsz_big - vol->vol_data_sect;
00326     }
00327     vol->vol_last_clust /= vol->vol_clustsz;
00328     /* First cluster number is 2. */
00329     vol->vol_last_clust += 2;
00330 
00331     /* 
00332      * Having calculated the total number of clusters allows us to 
00333      * distinguish between PHAT12 and PHAT16. 
00334      */
00335     if (vol->vol_type == 0) {
00336         if (vol->vol_last_clust > 4086) {
00337             vol->vol_type = 16;
00338         }
00339         else {
00340             vol->vol_type = 12;
00341         }
00342     }
00343 #ifdef NUTDEBUG
00344     printf("\n%lu cluster -> PHAT%d\n", vol->vol_last_clust, vol->vol_type);
00345 #endif
00346 
00347     dev->dev_icb = blkmnt;
00348 
00349     /* Initialize mutual exclusion semaphores. */
00350     NutEventPost(&vol->vol_fsmutex);
00351     NutEventPost(&vol->vol_iomutex);
00352 
00353     vol->vol_numfree = PhatCountFreeClusters(dev);
00354 
00355     return 0;
00356 }
00357 
00368 int PhatVolUnmount(NUTDEVICE * dev)
00369 {
00370     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00371 
00372     if (vol) {
00373 #if PHAT_SECTOR_BUFFERS
00374         int sbn;
00375 
00376         for (sbn = 0; sbn < PHAT_SECTOR_BUFFERS; sbn++) {
00377             if (vol->vol_buf[sbn].sect_data) {
00378                 free(vol->vol_buf[sbn].sect_data);
00379             }
00380         }
00381 #endif
00382         free(vol);
00383     }
00384     return 0;
00385 }
00386 
00387 /*
00388  * \brief Get first sector of a specified cluster.
00389  *
00390  * \param nfp   File descriptor.
00391  * \param clust Specified cluster.
00392  */
00393 uint32_t PhatClusterSector(NUTFILE * nfp, uint32_t clust)
00394 {
00395     NUTDEVICE *dev = nfp->nf_dev;
00396     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00397 
00398     /*
00399      * If the file descriptor specifies the root directory, then the first
00400      * sector is located after the reserved sectors and the allocation table.
00401      */
00402     if (IsFixedRootDir(nfp)) {
00403         return vol->vol_root_sect;
00404     }
00405 
00406     /*
00407      * For all other files/directories the sector is located in the data
00408      * area of the volume.
00409      */
00410     if (clust >= 2) {
00411         clust -= 2;
00412     }
00413     return vol->vol_data_sect + clust * vol->vol_clustsz;
00414 }
00415 

© 2000-2007 by egnite Software GmbH - visit http://www.ethernut.de/