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 
00083 #include <dev/blockdev.h>
00084 
00085 #include <sys/event.h>
00086 
00087 #include <fs/dospart.h>
00088 #include <fs/phatio.h>
00089 #include <fs/phatutil.h>
00090 #include <fs/phatvol.h>
00091 
00092 #include <errno.h>
00093 #include <stdlib.h>
00094 #include <string.h>
00095 
00096 
00097 #if 0
00098 /* Use for local debugging. */
00099 #define NUTDEBUG
00100 #include <stdio.h>
00101 #include <fs/phatdbg.h>
00102 #endif
00103 
00108 
00116 static u_long PhatCountFreeClusters(NUTDEVICE * dev)
00117 {
00118     u_long rc = 0;
00119     u_long i = 2;
00120     u_long link;
00121     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00122 
00123     if (vol->vol_type == 32) {
00124         while (i < vol->vol_last_clust) {
00125             if (Phat32GetClusterLink(dev, i, &link)) {
00126                 break;
00127             }
00128             if (link == 0) {
00129                 rc++;
00130             }
00131             i++;
00132         }
00133     } else if (vol->vol_type == 16) {
00134         while (i < vol->vol_last_clust) {
00135             if (Phat16GetClusterLink(dev, i, &link)) {
00136                 break;
00137             }
00138             if (link == 0) {
00139                 rc++;
00140             }
00141             i++;
00142         }
00143     } else {
00144         while (i < vol->vol_last_clust) {
00145             if (Phat12GetClusterLink(dev, i, &link)) {
00146                 break;
00147             }
00148             if (link == 0) {
00149                 rc++;
00150             }
00151             i++;
00152         }
00153     }
00154     return rc;
00155 }
00156 
00179 int PhatVolMount(NUTDEVICE * dev, NUTFILE * blkmnt, u_char part_type)
00180 {
00181     PHATVOL *vol;
00182     PHATVBR *vbr;
00183     BLKPAR_INFO pari;
00184     int sbn;
00185     NUTDEVICE *blkdev = blkmnt->nf_dev;
00186 
00187     /*
00188      * Allocate the volume information structure 
00189      */
00190     if ((dev->dev_dcb = malloc(sizeof(PHATVOL))) == 0) {
00191         return -1;
00192     }
00193     vol = (PHATVOL *) memset(dev->dev_dcb, 0, sizeof(PHATVOL));
00194 
00195     /*
00196      * Determine the PHAT type.
00197      */
00198     switch (part_type) {
00199     case PTYPE_FAT32:
00200     case PTYPE_FAT32_LBA:
00201         vol->vol_type = 32;
00202         break;
00203     case PTYPE_FAT16:
00204     case PTYPE_FAT16_BIG:
00205     case PTYPE_FAT16_LBA:
00206         vol->vol_type = 16;
00207         break;
00208     case PTYPE_FAT12:
00209         vol->vol_type = 12;
00210         break;
00211     }
00212 
00213     /*
00214      * Query information from the block device driver.
00215      */
00216     pari.par_nfp = blkmnt;
00217     if ((*blkdev->dev_ioctl) (blkdev, NUTBLKDEV_INFO, &pari)) {
00218         free(vol);
00219         errno = ENODEV;
00220         return -1;
00221     }
00222 #if PHAT_SECTOR_BUFFERS
00223     for (sbn = 0; sbn < PHAT_SECTOR_BUFFERS; sbn++) {
00224         if ((vol->vol_buf[sbn].sect_data = malloc(pari.par_blksz)) == NULL) {
00225             PhatVolUnmount(dev);
00226             return -1;
00227         }
00228         vol->vol_buf[sbn].sect_num = (u_long)-1;
00229     }
00230 #else
00231     vol->vol_buf[0].sect_data = pari.par_blkbp;
00232 #endif
00233     sbn = 0;
00234 
00235     /*
00236      * We use PhatSectorRead() instead of PhatSectorLoad() for our 
00237      * very first read to properly initialize the caching status.
00238      */
00239     if (PhatSectorRead(blkmnt, 0, vol->vol_buf[sbn].sect_data)) {
00240         PhatVolUnmount(dev);
00241         return -1;
00242     }
00243     vol->vol_buf[sbn].sect_num = 0;
00244     vbr = (PHATVBR *) vol->vol_buf[sbn].sect_data;
00245 
00246     /*
00247      * PHAT32 doesn't have a fixed root directory. At this point
00248      * we reliably know wether we got PHAT32 or not. After having
00249      * determined the total number of clusters later, we can check
00250      * for PHAT12 or PHAT16.
00251      */
00252     if (vol->vol_type == 0 && vbr->bios_rootsz == 0) {
00253         vol->vol_type = 32;
00254     }
00255 
00256     /* Convert to PHAT12/PHAT16 layout. */
00257     if (vol->vol_type != 32) {
00258         memcpy(&vbr->boot_drive, &vbr->bios_tabsz_big, 26);
00259         memset(&vbr->bios_tabsz_big, 0, 28);
00260     }
00261 #ifdef NUTDEBUG
00262     PhatDbgVbr(stdout, "Volume Boot Record", vbr);
00263 #endif
00264 
00265     /*
00266      * Verify the VBR signature.
00267      */
00268     if (vol->vol_buf[sbn].sect_data[510] != 0x55 || vol->vol_buf[sbn].sect_data[511] != 0xAA) {
00269         PhatVolUnmount(dev);
00270         errno = ENODEV;
00271         return -1;
00272     }
00273 
00274     /*
00275      * Make sure we got a valid media type.
00276      */
00277     if (vbr->bios_media != 0xF0 && vbr->bios_media < 0xF8) {
00278         PhatVolUnmount(dev);
00279         errno = ENODEV;
00280         return -1;
00281     }
00282 
00283     /*
00284      * Examine the informations found in the boot record.
00285      */
00286     /* Bytes per sector. */
00287     vol->vol_sectsz = vbr->bios_sectsz;
00288     if (vol->vol_sectsz < 512 || vol->vol_sectsz & 0xFF) {
00289         PhatVolUnmount(dev);
00290         errno = ENODEV;
00291         return -1;
00292     }
00293     /* Sectors per cluster. */
00294     if ((vol->vol_clustsz = vbr->bios_clustsz) == 0) {
00295         PhatVolUnmount(dev);
00296         errno = ENODEV;
00297         return -1;
00298     }
00299     /* Allocation table size and position. */
00300     if (vbr->bios_tabsz) {
00301         vol->vol_tabsz = vbr->bios_tabsz;
00302     } else {
00303         vol->vol_tabsz = vbr->bios_tabsz_big;
00304     }
00305     vol->vol_tab_sect[0] = vbr->bios_rsvd_sects;
00306     if (vbr->bios_ntabs > 1) {
00307         vol->vol_tab_sect[1] = vol->vol_tab_sect[0] + vol->vol_tabsz;
00308     }
00309     /* Root directory size and position. */
00310     vol->vol_rootsz = (vbr->bios_rootsz * sizeof(PHATDIRENT) +  /* */
00311                        vol->vol_sectsz - 1) / vol->vol_sectsz;
00312     vol->vol_root_sect = vbr->bios_rsvd_sects + /* */
00313         vbr->bios_ntabs * vol->vol_tabsz;
00314     if (vol->vol_type == 32) {
00315         vol->vol_root_clust = vbr->bios_root_clust;
00316     }
00317     /* First data sector and number of data clusters. */
00318     vol->vol_data_sect = vol->vol_root_sect + vol->vol_rootsz;
00319     if (vbr->bios_volsz) {
00320         vol->vol_last_clust = vbr->bios_volsz - vol->vol_data_sect;
00321     } else {
00322         vol->vol_last_clust = vbr->bios_volsz_big - vol->vol_data_sect;
00323     }
00324     vol->vol_last_clust /= vol->vol_clustsz;
00325     /* First cluster number is 2. */
00326     vol->vol_last_clust += 2;
00327 
00328     /* 
00329      * Having calculated the total number of clusters allows us to 
00330      * distinguish between PHAT12 and PHAT16. 
00331      */
00332     if (vol->vol_type == 0) {
00333         if (vol->vol_last_clust > 4086) {
00334             vol->vol_type = 16;
00335         }
00336         else {
00337             vol->vol_type = 12;
00338         }
00339     }
00340 #ifdef NUTDEBUG
00341     printf("\n%lu cluster -> PHAT%d\n", vol->vol_last_clust, vol->vol_type);
00342 #endif
00343 
00344     dev->dev_icb = blkmnt;
00345 
00346     /* Initialize mutual exclusion semaphores. */
00347     NutEventPost(&vol->vol_fsmutex);
00348     NutEventPost(&vol->vol_iomutex);
00349 
00350     vol->vol_numfree = PhatCountFreeClusters(dev);
00351 
00352     return 0;
00353 }
00354 
00365 int PhatVolUnmount(NUTDEVICE * dev)
00366 {
00367     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00368 
00369     if (vol) {
00370 #if PHAT_SECTOR_BUFFERS
00371         int sbn;
00372 
00373         for (sbn = 0; sbn < PHAT_SECTOR_BUFFERS; sbn++) {
00374             if (vol->vol_buf[sbn].sect_data) {
00375                 free(vol->vol_buf[sbn].sect_data);
00376             }
00377         }
00378 #endif
00379         free(vol);
00380     }
00381     return 0;
00382 }
00383 
00384 /*
00385  * \brief Get first sector of a specified cluster.
00386  *
00387  * \param nfp   File descriptor.
00388  * \param clust Specified cluster.
00389  */
00390 u_long PhatClusterSector(NUTFILE * nfp, u_long clust)
00391 {
00392     NUTDEVICE *dev = nfp->nf_dev;
00393     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00394 
00395     /*
00396      * If the file descriptor specifies the root directory, then the first
00397      * sector is located after the reserved sectors and the allocation table.
00398      */
00399     if (IsFixedRootDir(nfp)) {
00400         return vol->vol_root_sect;
00401     }
00402 
00403     /*
00404      * For all other files/directories the sector is located in the data
00405      * area of the volume.
00406      */
00407     if (clust >= 2) {
00408         clust -= 2;
00409     }
00410     return vol->vol_data_sect + clust * vol->vol_clustsz;
00411 }
00412 

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