phatutil.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 
00069 #include <fs/phatfs.h>
00070 #include <fs/phatvol.h>
00071 #include <fs/phatdir.h>
00072 #include <fs/phatutil.h>
00073 
00074 #include <stdlib.h>
00075 #include <string.h>
00076 #include <time.h>
00077 #include <ctype.h>
00078 #include <errno.h>
00079 
00080 #if 0
00081 /* Use for local debugging. */
00082 #define NUTDEBUG
00083 #include <stdio.h>
00084 #include <fs/phatdbg.h>
00085 #endif
00086 
00091 
00098 void GetDosTimeStamp(uint16_t * dostim, uint16_t * dosdat)
00099 {
00100     time_t now;
00101     struct _tm *gmt;
00102 
00103     time(&now);
00104     gmt = localtime(&now);
00105 
00106     if (dosdat) {
00107         *dosdat = (uint16_t) (gmt->tm_mday | ((gmt->tm_mon + 1) << 5) | ((gmt->tm_year - 80) << 9));
00108     }
00109     if (dostim) {
00110         *dostim = (uint16_t) ((gmt->tm_sec / 2) | (gmt->tm_min << 5) | (gmt->tm_hour << 11));
00111     }
00112 }
00113 
00123 int MakePhatName(CONST char *src, uint8_t * dst)
00124 {
00125     int rc = 0;
00126     int i;
00127 
00128     /* Fill destination with spaces. */
00129     memset(dst, ' ', 11);
00130 
00131     /* Skip leading dots. */
00132     for (i = 0; src[i] == '.'; i++);
00133     /* Handle the special entries dot and double dot. */
00134     if (src[i] == 0 && (i == 1 || i == 2)) {
00135         while (i--) {
00136             *dst++ = '.';
00137         }
00138         return 0;
00139     }
00140 
00141     /* Convert the special token of removed entries. */
00142     if (*src == (char)PHAT_REM_DIRENT) {
00143         dst[0] = PHAT_REM_NAMENT;
00144         src++;
00145     } else {
00146         dst[0] = toupper(*src);
00147         src++;
00148     }
00149 
00150     /* Copy the rest of the base name upto the dot, 8 characters max. */
00151     for (i = 1; i < 8 && *src && *src != '.'; i++, src++) {
00152         dst[i] = toupper(*src);
00153     }
00154 
00155     /* More characters? */
00156     if (*src) {
00157         /* If we didn't reach a dot, then the base name is too long. */
00158         if (*src != '.') {
00159             return -1;
00160         }
00161         /* Skip the dot and copy the extension. */
00162         src++;
00163         for (i = 8; i < 11 && *src; i++, src++) {
00164             dst[i] = toupper(*src);
00165         }
00166         /* If more characters are available, then the extension is too long. */
00167         if (*src) {
00168             return -1;
00169         }
00170     }
00171 
00172     /* Finally check our result. */
00173     for (i = 0; i < 11; i++) {
00174         /* Reject control codes. */
00175         if (dst[i] < ' ') {
00176             return -1;
00177         }
00178         /* Reject illegal characters. */
00179         if (strchr("\"+,./:;<=>[\\]^", dst[i])) {
00180             return -1;
00181         }
00182         /* Wildcard found. */
00183         if (dst[i] == '?') {
00184             rc = 1;
00185         } else if (dst[i] == '*') {
00186             rc = 1;
00187             /* Stars in the name will fill the remaining name or
00188                extension part with '?'. */
00189             if (i < 8) {
00190                 memset(&dst[i], '?', 8 - i);
00191             } else {
00192                 memset(&dst[i], '?', 11 - i);
00193             }
00194         }
00195     }
00196     return rc;
00197 }
00198 
00208 void MakeVisibleName(CONST uint8_t * src, char *dst)
00209 {
00210     int i;
00211 
00212     /* Replace the 0x05 cludge. */
00213     if (src[0] == PHAT_REM_NAMENT) {
00214         *dst++ = PHAT_REM_DIRENT;
00215     } else {
00216         *dst++ = src[0];
00217     }
00218 
00219     /* Copy the base name part up to the first space. */
00220     for (i = 1; i < 8 && src[i] != ' '; i++) {
00221         *dst++ = src[i];
00222     }
00223 
00224     /* Add the extension up to the first space. */
00225     for (i = 8; i < 11 && src[i] != ' '; i++) {
00226         if (i == 8) {
00227             *dst++ = '.';
00228         }
00229         *dst++ = src[i];
00230     }
00231     *dst = 0;
00232 }
00233 
00245 char *GetParentPath(CONST char *path, CONST char **comp)
00246 {
00247     char *parent;
00248     int len;
00249 
00250     if ((*comp = strrchr(path, '/')) == NULL) {
00251         errno = EINVAL;
00252         return NULL;
00253     }
00254 
00255     (*comp)++;
00256     len = strlen(path) - strlen(*comp);
00257     if (len < 2) {
00258         len = 2;
00259     }
00260     if ((parent = malloc(len)) == NULL) {
00261         return NULL;
00262     }
00263     memcpy(parent, (void *)path, len - 1);
00264     parent[len - 1] = 0;
00265 
00266     return parent;
00267 }
00268 
00276 int IsFixedRootDir(NUTFILE * ndp)
00277 {
00278     NUTDEVICE *dev = ndp->nf_dev;
00279     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00280     PHATFILE *fcb;
00281 
00282     /* PHAT32 root directories are expandable. */
00283     if (vol->vol_type == 32) {
00284         return 0;
00285     }
00286 
00287     /* Root directory cluster number is 0 per definition. */
00288     fcb = ndp->nf_fcb;
00289     if (fcb->f_de_sect || fcb->f_dirent.dent_clusthi || fcb->f_dirent.dent_clust) {
00290         return 0;
00291     }
00292     return 1;
00293 }
00294 
00300 void PhatFilePosRewind(PHATFILE * fcb)
00301 {
00302     /* Reset current pointer into the file. */
00303     fcb->f_pos = 0;
00304     /* Reset current cluster to the first cluster. */
00305     fcb->f_clust = fcb->f_dirent.dent_clusthi;
00306     fcb->f_clust <<= 16;
00307     fcb->f_clust += fcb->f_dirent.dent_clust;
00308     /* Reset position (sector number) within the cluster. */
00309     fcb->f_clust_pos = 0;
00310     /* Reset current position into the current sector. */
00311     fcb->f_sect_pos = 0;
00312 }
00313 
00325 int PhatFilePosSet(NUTFILE * nfp, uint32_t pos)
00326 {
00327     uint32_t dist;
00328     uint32_t step;
00329     uint32_t clust;
00330     PHATFILE *fcb = nfp->nf_fcb;
00331     NUTDEVICE *dev = nfp->nf_dev;
00332     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00333 
00334     /* Simple case, rewind the file. */
00335     if (pos == 0) {
00336         PhatFilePosRewind(fcb);
00337         return 0;
00338     }
00339 
00340     /* We do not support seeking beyond the file size plus one. */
00341     if ((fcb->f_dirent.dent_attr & PHAT_FATTR_DIR) == 0 && pos > fcb->f_dirent.dent_fsize) {
00342         return -1;
00343     }
00344 
00345     /*
00346      * If the requested position is in front of the currect position,
00347      * then we start from the beginning.
00348      * TODO: Should check if we still are in the current cluster.
00349      */
00350     if (pos < fcb->f_pos) {
00351         PhatFilePosRewind(fcb);
00352         dist = pos;
00353     } else {
00354         dist = pos - fcb->f_pos;
00355     }
00356 
00357     for (;;) {
00358         if (fcb->f_sect_pos >= vol->vol_sectsz) {
00359             if (IsFixedRootDir(nfp)) {
00360                 if (fcb->f_clust_pos + 1 >= vol->vol_rootsz) {
00361                     /* End of root directory, abort reading. */
00362                     break;
00363                 }
00364                 fcb->f_clust_pos++;
00365             }
00366             else {
00367 
00368                 /* 
00369                 * We reached the end of the current sector. Move to the 
00370                 * next sector of the current cluster.
00371                 */
00372                 if (fcb->f_clust_pos + 1 >= vol->vol_clustsz) {
00373                     /*
00374                     * We reached the end of the current cluster. Move to 
00375                     * the next cluster.
00376                     */
00377                     if (vol->vol_type == 32) {
00378                         if (Phat32GetClusterLink(dev, fcb->f_clust, &clust)) {
00379                             break;
00380                         }
00381                         if (clust >= (PHATEOC & PHAT32CMASK)) {
00382                             break;
00383                         }
00384                     } else if (vol->vol_type == 16) {
00385                         if (Phat16GetClusterLink(dev, fcb->f_clust, &clust)) {
00386                             break;
00387                         }
00388                         if (clust >= (PHATEOC & PHAT16CMASK)) {
00389                             break;
00390                         }
00391                     } else if (Phat12GetClusterLink(dev, fcb->f_clust, &clust)) {
00392                         break;
00393                     }
00394                     else if (clust >= (PHATEOC & PHAT12CMASK)) {
00395                         break;
00396                     }
00397                     fcb->f_clust_pos = 0;
00398                     fcb->f_clust_prv = fcb->f_clust;
00399                     fcb->f_clust = clust;
00400                 } else {
00401                     fcb->f_clust_pos++;
00402                 }
00403             }
00404             fcb->f_sect_pos = 0;
00405         }
00406         if (dist == 0) {
00407             break;
00408         }
00409 
00410         /* Calculate the number of bytes available in the current sector. */
00411         step = vol->vol_sectsz - fcb->f_sect_pos;
00412         if (step > dist) {
00413             step = dist;
00414         }
00415         fcb->f_sect_pos += step;
00416         fcb->f_pos += step;
00417         dist -= step;
00418     }
00419     return fcb->f_pos == pos ? 0 : -1;
00420 }
00421 

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