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