Nut/OS  4.10.3
API Reference
phatdir.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 
00108 #include <fs/fs.h>
00109 #include <fs/phatfs.h>
00110 #include <fs/phatvol.h>
00111 #include <fs/phatio.h>
00112 #include <fs/phatutil.h>
00113 #include <fs/phatdir.h>
00114 
00115 #include <stdlib.h>
00116 #include <string.h>
00117 #include <ctype.h>
00118 #include <fcntl.h>
00119 #include <errno.h>
00120 #include <time.h>
00121 #include <memdebug.h>
00122 
00123 #if 0
00124 /* Use for local debugging. */
00125 #define NUTDEBUG
00126 #include <stdio.h>
00127 #include <fs/phatdbg.h>
00128 #endif
00129 
00134 
00136 #define PHAT_MAXDIRENT   65536
00137 
00144 static INLINE uint8_t GenShortNameChecksum(char *sfn)
00145 {
00146     uint8_t rc = 0;
00147     int i;
00148 
00149     for (i = 0; i < 11; i++) {
00150         rc = ((rc >> 1) | ((rc & 1) << 7)) + (uint8_t)(sfn[i]);
00151     }
00152     return rc;
00153 }
00154 
00166 static int GenShortName(NUTFILE * ndp, CONST char *lfn, char *sfn)
00167 {
00168     int rc = -1;
00169     int i;
00170     int got;
00171     PHATDIRENT *entry;
00172     char *xp;
00173 
00174     /* Fill the buffer with spaces. */
00175     memset(sfn, ' ', 11);
00176 
00177     /* Get the position of the last dot in the long name. */
00178     xp = strrchr(lfn, '.');
00179 
00180     /* Now collect up to 8 characters for the basename and 3 characters
00181      * for the extension. */
00182     for (i = 0; i < 11 && *lfn; lfn++) {
00183         if (*lfn == '.') {
00184             /* We reached the first dot. The basename ends here. */
00185             if (lfn == xp) {
00186                 /* This is also the last dot. Start copying the extension. */
00187                 lfn++;
00188                 if (*lfn) {
00189                     sfn[8] = toupper((unsigned char)*lfn);
00190                 }
00191                 i = 9;
00192             }
00193         }
00194         else if (i == 8) {
00195             /* First 8 characters collected. */
00196             if (xp == NULL) {
00197                 /* No dot, no extension. */
00198                 break;
00199             }
00200             lfn = xp + 1;
00201             if (*lfn) {
00202                 sfn[i++] = toupper((unsigned char)*lfn);
00203             }
00204         }
00205         else if (*lfn != ' ') {
00206             if (strrchr("+,;=[]", *lfn)) {
00207                 sfn[i++] = '_';
00208             }
00209             else {
00210                 sfn[i++] = toupper((unsigned char)*lfn);
00211             }
00212         }
00213     }
00214 
00215     /*
00216      * Select a unique short name by verifying existing entries in the
00217      * specified directory.
00218      */
00219     if ((entry = malloc(sizeof(PHATDIRENT))) != NULL) {
00220         xp = sfn;
00221         for (i = 0; i < 6 && *xp != ' '; i++) {
00222             xp++;
00223         }
00224         /*
00225          * We try up to 99 unique short names only, but this should be
00226          * sufficient for our tiny system - hopefully.
00227          */
00228         for (i = 1; i <= 99 && rc; i++) {
00229             if (i == 10) {
00230                 xp--;
00231             }
00232             *xp = '~';
00233             if (i > 9) {
00234                 *(xp + 1) = '0' + i / 10;
00235                 *(xp + 2) = '0' + i % 10;
00236             }
00237             else {
00238                 *(xp + 1) = '0' + i;
00239             }
00240             PhatFilePosRewind((PHATFILE *)ndp->nf_fcb);
00241             for (;;) {
00242                 /* Read next entry. */
00243                 if ((got = PhatFileRead(ndp, entry, sizeof(PHATDIRENT))) != sizeof(PHATDIRENT)) {
00244                     if (got) {
00245                         /* Read error, stop searching. */
00246                         i = 9;
00247                     }
00248                     else {
00249                         /* End of directory reached, entry is unique. */
00250                         rc = 0;
00251                     }
00252                     break;
00253                 }
00254                 if ((entry->dent_attr & PHAT_FATTR_VOLID) == 0) {
00255                     if (entry->dent_name[0] == 0) {
00256                         /* End of directory reached, entry is unique. */
00257                         rc = 0;
00258                         break;
00259                     }
00260                     if (memcmp(sfn, (char *)entry->dent_name, 11) == 0) {
00261                         /* Entry exists, try next one. */
00262                         break;
00263                     }
00264                 }
00265             }
00266         }
00267         free(entry);
00268     }
00269     return rc;
00270 }
00271 
00281 static int PhatDirEntryAlloc(NUTFILE * ndp, CONST char *fname, PHATDIRENT * entry)
00282 {
00283     int rc;
00284     int pos = 0;
00285     int got;
00286     uint8_t sect;
00287     uint8_t *temp;
00288     NUTDEVICE *dev = ndp->nf_dev;
00289     PHATFILE *dfcb = ndp->nf_fcb;
00290     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00291     PHATDIRENT *dent;
00292     PHATXDIRENT *xdent;
00293     int nwant = 1;
00294     int ngot = 0;
00295     int npos = 0;
00296     int i;
00297     int ci;
00298     uint8_t cks = 0;
00299 
00300     /* Convert the dotted name to a space filled one. */
00301     if ((rc = MakePhatName(fname, entry->dent_name)) == 1) {
00302         /* Reject name with wildcards. */
00303         errno = EINVAL;
00304         return -1;
00305     }
00306     if (rc == 0) {
00307         char vname[16];
00308 
00309         MakeVisibleName(entry->dent_name, vname);
00310         if (strcmp(fname, vname)) {
00311             rc = 1;
00312         }
00313     }
00314     if (rc) {
00315         if (GenShortName(ndp, fname, (char *)entry->dent_name)) {
00316             errno = EINVAL;
00317             return -1;
00318         }
00319         nwant = (strlen(fname) + 12) / 13 + 1;
00320         cks = GenShortNameChecksum((char *)entry->dent_name);
00321     }
00322 
00323     /* Allocate a temporary entry buffer. */
00324     if ((dent = malloc(sizeof(PHATDIRENT))) == NULL) {
00325         return -1;
00326     }
00327 
00328     /*
00329      * Find free entries, starting from the beginning.
00330      */
00331     PhatFilePosRewind(dfcb);
00332     rc = -1;
00333     for (;;) {
00334         /* Memorize the current position and try to read the next entry. */
00335         npos = dfcb->f_pos;
00336         if ((got = PhatFileRead(ndp, dent, sizeof(PHATDIRENT))) < 0) {
00337             /* Read failed. */
00338             break;
00339         }
00340         if (got != sizeof(PHATDIRENT)) {
00341             /*
00342              * End of directory reached. Try to expand it.
00343              */
00344             if (IsFixedRootDir(ndp) ||  /* */
00345                 dfcb->f_pos >= PHAT_MAXDIRENT * sizeof(PHATDIRENT)) {
00346                 /* Failed. Either PHAT12/16 root dir or max. size reached. */
00347                 errno = EFBIG;
00348                 break;
00349             }
00350 
00351             /* Fill a new cluster with zeros. */
00352             if ((temp = malloc(vol->vol_sectsz)) == NULL) {
00353                 break;
00354             }
00355             memset(temp, 0, vol->vol_sectsz);
00356             for (sect = vol->vol_clustsz; sect; sect--) {
00357                 if (PhatFileWrite(ndp, temp, vol->vol_sectsz) < 0) {
00358                     /* Write failed. */
00359                     break;
00360                 }
00361             }
00362             free(temp);
00363             /* End of directory reached and expanded by a new cluster. */
00364             if (sect == 0) {
00365                 if (ngot == 0) {
00366                     pos = npos;
00367                 }
00368                 rc = 0;
00369             }
00370             break;
00371         }
00372         if (dent->dent_name[0] == PHAT_REM_DIRENT || dent->dent_name[0] == 0) {
00373             /* Empty entry found. */
00374             if (ngot == 0) {
00375                 pos = npos;
00376             }
00377             ngot++;
00378             if (ngot >= nwant) {
00379                 rc = 0;
00380                 break;
00381             }
00382         }
00383         else {
00384             ngot = 0;
00385         }
00386     }
00387     free(dent);
00388 
00389     if (rc == 0) {
00390         /* Return to the memorized position and write the new entry. */
00391         PhatFilePosSet(ndp, pos);
00392         if ((xdent = malloc(sizeof(PHATXDIRENT))) == NULL) {
00393             return -1;
00394         }
00395         for (ngot = nwant - 1; ngot; ngot--) {
00396             memset(xdent, 0xFF, sizeof(PHATXDIRENT));
00397             xdent->xdent_seq = ngot;
00398             if (ngot == nwant - 1) {
00399                 xdent->xdent_seq |= 0x40;
00400             }
00401             xdent->xdent_attr = PHAT_FATTR_LFN;
00402             xdent->xdent_cks = cks;
00403             xdent->xdent_clust = 0;
00404             xdent->xdent_rsvd = 0;
00405             /* Simplified unicode conversion, ignores double byte characters. */
00406             ci = (ngot - 1) * 13;
00407             for (i = 0; i < 13; i++) {
00408                 if (ci + i <= strlen(fname)) {
00409                     if (i < 5) {
00410                         xdent->xdent_uname_1_5[i] = fname[ci + i];
00411                     }
00412                     else if (i < 11) {
00413                         xdent->xdent_uname_6_11[i - 5] = fname[ci + i];
00414                     }
00415                     else {
00416                         xdent->xdent_uname_12_13[i - 11] = fname[ci + i];
00417                     }
00418                 }
00419             }
00420             if (PhatFileWrite(ndp, xdent, sizeof(PHATXDIRENT)) < 0) {
00421                 /* Write error. */
00422                 rc = -1;
00423                 break;
00424             }
00425         }
00426         if (PhatFileWrite(ndp, entry, sizeof(PHATDIRENT)) < 0) {
00427             /* Write error. */
00428             rc = -1;
00429         }
00430         free(xdent);
00431     }
00432     return rc;
00433 }
00434 
00447 static int PhatDirEntryRelease(NUTFILE * ndp, uint32_t pos, int lfncnt)
00448 {
00449     uint8_t ch = PHAT_REM_DIRENT;
00450     int i;
00451 
00452     for (i = lfncnt; i; i--) {
00453         PhatFilePosSet(ndp, pos - i * sizeof(PHATXDIRENT));
00454         if (PhatFileWrite(ndp, &ch, 1) < 0) {
00455             return -1;
00456         }
00457     }
00458     PhatFilePosSet(ndp, pos);
00459     if (PhatFileWrite(ndp, &ch, 1) < 0) {
00460         return -1;
00461     }
00462     return 0;
00463 }
00464 
00475 int PhatDirEntryCreate(NUTFILE * ndp, CONST char *name, int acc, PHATDIRENT * dirent)
00476 {
00477     dirent->dent_attr = (uint8_t) acc;
00478     GetDosTimeStamp(&dirent->dent_ctime, &dirent->dent_cdate);
00479     dirent->dent_adate = dirent->dent_cdate;
00480     dirent->dent_mtime = dirent->dent_ctime;
00481     dirent->dent_mdate = dirent->dent_cdate;
00482 
00483     if (PhatDirEntryAlloc(ndp, name, dirent)) {
00484         return -1;
00485     }
00486 #ifdef NUTDEBUG
00487     PhatDbgFileInfo(stdout, "New Dir Entry", ndp->nf_fcb);
00488 #endif
00489     return 0;
00490 }
00491 
00499 int PhatDirEntryUpdate(NUTFILE * nfp)
00500 {
00501     int sbn;
00502     NUTDEVICE *dev = nfp->nf_dev;
00503     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00504     PHATFILE *fcb = nfp->nf_fcb;
00505 
00506     if (fcb->f_de_dirty) {
00507         /*
00508          * The file may specify the root directory, in which case
00509          * the updated is skipped.
00510          */
00511         if (fcb->f_de_sect) {
00512 #ifdef NUTDEBUG
00513             PhatDbgDirEntry(stdout, "PhatDirEntryUpdate", &fcb->f_dirent);
00514 #endif
00515             if ((sbn = PhatSectorLoad(dev, fcb->f_de_sect)) < 0) {
00516                 return -1;
00517             }
00518             memcpy(vol->vol_buf[sbn].sect_data + fcb->f_de_offs, &fcb->f_dirent, sizeof(PHATDIRENT));
00519             vol->vol_buf[sbn].sect_dirty = 1;
00520         }
00521         fcb->f_de_dirty = 0;
00522     }
00523     return 0;
00524 }
00525 
00534 static int PhatDirEntryRead(NUTFILE * ndp, PHATFIND * srch)
00535 {
00536     PHATDIRENT *entry = &srch->phfind_ent;
00537     PHATFILE *fcb = ndp->nf_fcb;
00538     PHATXDIRENT *xentry;
00539     char *lfn = NULL;
00540     int lfnpos = 0;
00541     int nxtseq = 0;
00542     int lfncnt = 0;
00543     int i;
00544 
00545     for (;;) {
00546         /* Read next entry. */
00547         if (PhatFileRead(ndp, entry, sizeof(PHATDIRENT)) != sizeof(PHATDIRENT)) {
00548             break;
00549         }
00550         /* Skip removed entries. */
00551         if (entry->dent_name[0] == PHAT_REM_DIRENT) {
00552             if (lfn) {
00553                 free(lfn);
00554                 lfn = NULL;
00555             }
00556         }
00557         /* Process long filename entries. */
00558         else if (entry->dent_attr == PHAT_FATTR_LFN) {
00559             xentry = (PHATXDIRENT *)entry;
00560             lfnpos = (xentry->xdent_seq & 0x3F);
00561             /* Make sure we are in sequence. */
00562             if ((nxtseq == 0 && (xentry->xdent_seq & 0x40) != 0) || nxtseq == lfnpos) {
00563                 nxtseq = --lfnpos;
00564                 lfnpos *= 13;
00565                 if (lfnpos + 13 > PHAT_MAX_NAMELEN) {
00566                     errno = EINVAL;
00567                     break;
00568                 }
00569                 if (xentry->xdent_seq & 0x40) {
00570                     if (lfn == NULL) {
00571                         lfn = malloc(PHAT_MAX_NAMELEN + 1);
00572                     }
00573                     lfn[lfnpos + 13] = 0;
00574                     lfncnt = 0;
00575                 }
00576                 lfncnt++;
00577                 /* Simplified unicode conversion, ignores double byte characters. */
00578                 for (i = 0; i < 5; i++) {
00579                     lfn[lfnpos + i] = (char)xentry->xdent_uname_1_5[i];
00580                 }
00581                 for (i = 0; i < 6; i++) {
00582                     lfn[lfnpos + 5 + i] = (char)xentry->xdent_uname_6_11[i];
00583                 }
00584                 for (i = 0; i < 2; i++) {
00585                     lfn[lfnpos + 11 + i] = (char)xentry->xdent_uname_12_13[i];
00586                 }
00587             }
00588         }
00589 
00590         /* Skip volume IDs. */
00591         else if ((entry->dent_attr & PHAT_FATTR_VOLID) == 0) {
00592             /* Stop searching if last entry reached. */
00593             if (entry->dent_name[0] == 0) {
00594                 break;
00595             }
00596             /* Valid entry found. Return success. */
00597             srch->phfind_pos = fcb->f_pos - sizeof(PHATDIRENT);
00598             if (lfn && lfnpos == 0) {
00599                 strcpy(srch->phfind_name, lfn);
00600                 srch->phfind_xcnt = lfncnt;
00601             }
00602             else {
00603                 MakeVisibleName(entry->dent_name, srch->phfind_name);
00604                 srch->phfind_xcnt = 0;
00605             }
00606             if (lfn) {
00607                 free(lfn);
00608             }
00609             nxtseq = 0;
00610             lfncnt = 0;
00611             return 0;
00612         }
00613         else if (lfn) {
00614             free(lfn);
00615             lfn = NULL;
00616             nxtseq = 0;
00617             lfncnt = 0;
00618         }
00619     }
00620     if (lfn) {
00621         free(lfn);
00622     }
00623     return -1;
00624 }
00625 
00638 int PhatDirEntryFind(NUTFILE * ndp, CONST char *spec, uint32_t attmsk, PHATFIND * srch)
00639 {
00640     int rc;
00641     PHATFIND *temps;
00642 
00643     /* Allocate a temporary structure to store the search result. */
00644     if ((temps = malloc(sizeof(PHATFIND))) == NULL) {
00645         return -1;
00646     }
00647 
00648     /*
00649      * Loop until the specified entry was found or until we reach the
00650      * end of the directory.
00651      */
00652     PhatFilePosRewind((PHATFILE *)ndp->nf_fcb);
00653     while ((rc = PhatDirEntryRead(ndp, temps)) == 0) {
00654         if ((temps->phfind_ent.dent_attr | attmsk) == attmsk) {
00655             if (strcasecmp(temps->phfind_name, spec) == 0) {
00656                 /* Specified entry found. */
00657                 if (srch) {
00658                     *srch = *temps;
00659                 }
00660                 break;
00661             }
00662         }
00663     }
00664     free(temps);
00665 
00666     return rc;
00667 }
00668 
00679 NUTFILE *PhatDirOpenParent(NUTDEVICE * dev, CONST char *path, CONST char **basename)
00680 {
00681     NUTFILE *rc = NUTFILE_EOF;
00682     char *parent;
00683 
00684     if ((parent = GetParentPath(path, basename)) != NULL) {
00685         rc = PhatDirOpen(dev, parent);
00686         free(parent);
00687     }
00688     return rc;
00689 }
00690 
00700 int PhatDirRenameEntry(NUTDEVICE * dev, CONST char *old_path, CONST char *new_path)
00701 {
00702     int rc = -1;
00703     CONST char *fname;
00704     NUTFILE *old_ndp;
00705     NUTFILE *new_ndp;
00706     PHATFIND *srch;
00707 
00708     /*
00709      * Open directory of the old file.
00710      */
00711     if ((old_ndp = PhatDirOpenParent(dev, old_path, &fname)) == NUTFILE_EOF) {
00712         return -1;
00713     }
00714 
00715     if ((srch = malloc(sizeof(PHATFIND))) != NULL) {
00716         if ((rc = PhatDirEntryFind(old_ndp, fname, PHAT_FATTR_FILEMASK, srch)) == 0) {
00717             rc = -1;
00718             if ((new_ndp = PhatDirOpenParent(dev, new_path, &fname)) != NUTFILE_EOF) {
00719                 if (PhatDirEntryFind(new_ndp, fname, PHAT_FATTR_FILEMASK, NULL) == 0) {
00720                     errno = EEXIST;
00721                 } else {
00722                     if ((rc = PhatDirEntryAlloc(new_ndp, fname, &srch->phfind_ent)) == 0) {
00723                         rc = PhatDirEntryRelease(old_ndp, srch->phfind_pos, srch->phfind_xcnt);
00724                     }
00725                 }
00726                 PhatFileClose(new_ndp);
00727             }
00728         }
00729         else {
00730             errno = ENOENT;
00731         }
00732         free(srch);
00733     }
00734     PhatFileClose(old_ndp);
00735 
00736     return rc;
00737 }
00738 
00747 int PhatDirReleaseChain(NUTDEVICE * dev, PHATDIRENT *dent)
00748 {
00749     int rc = 0;
00750     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00751     uint32_t clust;
00752 
00753     /* Do not remove clusters of files with RDONLY attribute. */
00754     if (dent->dent_attr & PHAT_FATTR_RDONLY) {
00755         errno = EACCES;
00756         return -1;
00757     }
00758 
00759     /* Get the first cluster of this file. The directory entry stores this
00760        value in two positions. */
00761     clust = dent->dent_clusthi;
00762     clust <<= 16;
00763     clust |= dent->dent_clust;
00764 
00765     /* The data area starts at cluster 2. With empty files the first cluster
00766        is set to zero. A value of one is suspicious and will be ignored. */
00767     if (clust >= 2) {
00768         /* Call the format specific release routine. */
00769         if (vol->vol_type == 32) {
00770             rc = Phat32ReleaseChain(dev, clust);
00771         } else if (vol->vol_type == 16) {
00772             rc = Phat16ReleaseChain(dev, clust);
00773         } else {
00774             rc = Phat12ReleaseChain(dev, clust);
00775         }
00776     }
00777     return rc;
00778 }
00779 
00791 int PhatDirDelEntry(NUTDEVICE * dev, CONST char *path, uint32_t flags)
00792 {
00793     int rc = -1;
00794     PHATFIND *srch;
00795     NUTFILE *ndp;
00796     CONST char *fname;
00797 
00798     /* Open the parent directory. */
00799     if ((ndp = PhatDirOpenParent(dev, path, &fname)) != NUTFILE_EOF) {
00800         if ((srch = malloc(sizeof(PHATFIND))) != NULL) {
00801             /* Find the specified file name. */
00802             if (PhatDirEntryFind(ndp, fname, flags, srch) == 0) {
00803                 if (PhatDirReleaseChain(dev, &srch->phfind_ent) == 0) {
00804                     rc = PhatDirEntryRelease(ndp, srch->phfind_pos, srch->phfind_xcnt);
00805                 }
00806             }
00807             else {
00808                 errno = ENOENT;
00809             }
00810             free(srch);
00811         }
00812         PhatFileClose(ndp);
00813     }
00814     return rc;
00815 }
00816 
00825 NUTFILE *PhatDirOpen(NUTDEVICE * dev, CONST char *dpath)
00826 {
00827     NUTFILE *ndp;
00828     PHATFILE *dfcb;
00829     PHATFIND *srch;
00830     char *comp;
00831     char *cp;
00832     int sz;
00833     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00834 
00835     /* Make sure the volume is mounted. */
00836     if (vol == NULL) {
00837         errno = ENODEV;
00838         return NUTFILE_EOF;
00839     }
00840 
00841     /* Allocate the structure to return. */
00842     if ((ndp = malloc(sizeof(NUTFILE))) == NULL) {
00843         return NUTFILE_EOF;
00844     }
00845     if ((ndp->nf_fcb = malloc(sizeof(PHATFILE))) == NULL) {
00846         free(ndp);
00847         return NUTFILE_EOF;
00848     }
00849     memset(ndp->nf_fcb, 0, sizeof(PHATFILE));
00850     ndp->nf_next = NULL;
00851     ndp->nf_dev = dev;
00852 
00853     dfcb = ndp->nf_fcb;
00854     dfcb->f_dirent.dent_attr = PHAT_FATTR_DIR;
00855     dfcb->f_mode = _O_RDONLY;
00856 
00857     /* We start at the root directory. */
00858     dfcb->f_clust = vol->vol_root_clust;
00859     dfcb->f_dirent.dent_clusthi = (uint16_t) (vol->vol_root_clust >> 16);
00860     dfcb->f_dirent.dent_clust = (uint16_t) vol->vol_root_clust;
00861 
00862     if (*dpath == '/') {
00863         dpath++;
00864     }
00865     if (*dpath) {
00866         /*
00867          * We are looking for a subdirectory.
00868          */
00869         if ((comp = malloc(PHAT_MAX_NAMELEN + 1)) == NULL) {
00870             free(dfcb);
00871             free(ndp);
00872             return NUTFILE_EOF;
00873         }
00874         if ((srch = malloc(sizeof(PHATFIND))) == NULL) {
00875             free(comp);
00876             free(dfcb);
00877             free(ndp);
00878             return NUTFILE_EOF;
00879         }
00880 
00881         /*
00882          * Walk down the path.
00883          */
00884         while (*dpath) {
00885             /* Fetch the next component from the path. */
00886             cp = comp;
00887             sz = 0;
00888             while (*dpath) {
00889                 if (*dpath == '/') {
00890                     dpath++;
00891                     break;
00892                 }
00893                 if (++sz > PHAT_MAX_NAMELEN) {
00894                     break;
00895                 }
00896                 *cp++ = *dpath++;
00897             }
00898             *cp = 0;
00899 
00900             /* Search component's entry in the current directory. */
00901             if (sz > PHAT_MAX_NAMELEN || PhatDirEntryFind(ndp, comp, PHAT_FATTR_FILEMASK, srch)) {
00902                 errno = ENOENT;
00903                 free(dfcb);
00904                 free(ndp);
00905                 ndp = NUTFILE_EOF;
00906                 break;
00907             }
00908 
00909             /*
00910              * Next component found. Mimic the open by updating the existing
00911              * file control block structure.
00912              */
00913             dfcb->f_de_sect = PhatClusterSector(ndp, dfcb->f_clust) + dfcb->f_clust_pos;
00914             dfcb->f_de_offs = dfcb->f_sect_pos - 32;
00915 
00916             /* Set the cluster of our directory entry. */
00917             dfcb->f_pde_clusthi = dfcb->f_dirent.dent_clusthi;
00918             dfcb->f_pde_clust = dfcb->f_dirent.dent_clust;
00919 
00920             dfcb->f_dirent = srch->phfind_ent;
00921 #ifdef NUTDEBUG
00922             PhatDbgFileInfo(stdout, "Component", dfcb);
00923 #endif
00924 
00925             /*
00926              * Handle root directory.
00927              */
00928             if (dfcb->f_dirent.dent_attr & PHAT_FATTR_DIR) {
00929                 if (dfcb->f_dirent.dent_clust == 0 && dfcb->f_dirent.dent_clusthi == 0) {
00930                     if (vol->vol_type != 32) {
00931                         dfcb->f_de_sect = 0;
00932                     }
00933                     dfcb->f_dirent.dent_clusthi = (uint16_t) (vol->vol_root_clust >> 16);
00934                     dfcb->f_dirent.dent_clust = (uint16_t) vol->vol_root_clust;
00935                 }
00936             }
00937 
00938             /*
00939              * Reset position.
00940              */
00941             PhatFilePosRewind(dfcb);
00942             dfcb->f_clust_prv = 0;
00943             dfcb->f_mode = _O_RDONLY;
00944         }
00945         free(srch);
00946         free(comp);
00947     }
00948     return ndp;
00949 }
00950 
00958 int PhatDirRead(DIR * dir)
00959 {
00960     PHATFIND *srch;
00961     struct dirent *ent;
00962 
00963     if ((srch = malloc(sizeof(PHATFIND))) == NULL) {
00964         return -1;
00965     }
00966     if (PhatDirEntryRead(dir->dd_fd, srch)) {
00967         free(srch);
00968         return -1;
00969     }
00970 #ifdef NUTDEBUG
00971     PhatDbgDirEntry(stdout, "Read entry", &srch->phfind_ent);
00972 #endif
00973 
00974     ent = (struct dirent *) dir->dd_buf;
00975     memset(dir->dd_buf, 0, sizeof(struct dirent));
00976     ent->d_namlen = (uint8_t) strlen(srch->phfind_name);
00977     strcpy(ent->d_name, srch->phfind_name);
00978     if (srch->phfind_ent.dent_attr & PHAT_FATTR_DIR) {
00979         ent->d_type = 1;
00980     }
00981     free(srch);
00982 
00983     return 0;
00984 }
00985 
00997 int PhatDirCreate(NUTDEVICE * dev, char *path)
00998 {
00999     NUTFILE *ndp;
01000     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
01001     PHATFILE *dfcb;
01002     PHATDIRENT *entry;
01003     uint8_t *buf;
01004     uint32_t sect;
01005     uint32_t clust;
01006 
01007     /*
01008      * Create the new directory like a normal file with a special attribute.
01009      */
01010     if ((ndp = PhatFileOpen(dev, path, _O_CREAT | _O_RDWR | _O_EXCL, PHAT_FATTR_DIR)) == NUTFILE_EOF) {
01011         return -1;
01012     }
01013     dfcb = ndp->nf_fcb;
01014 
01015     /*
01016      * Allocate a first cluster and initialize it with zeros.
01017      */
01018     if ((clust = AllocFirstCluster(ndp)) < 2) {
01019         PhatFileClose(ndp);
01020         return -1;
01021     }
01022     dfcb->f_clust_prv = clust;
01023     dfcb->f_clust = clust;
01024     if ((buf = malloc(vol->vol_sectsz)) == NULL) {
01025         PhatFileClose(ndp);
01026         return -1;
01027     }
01028     memset(buf, 0, vol->vol_sectsz);
01029     for (sect = vol->vol_clustsz; sect; sect--) {
01030         if (PhatFileWrite(ndp, buf, vol->vol_sectsz) < 0) {
01031             /* Write failed. */
01032             free(buf);
01033             PhatFileClose(ndp);
01034             return -1;
01035         }
01036     }
01037     free(buf);
01038 
01039     /*
01040      * Write the dot entry.
01041      */
01042     entry = malloc(sizeof(PHATDIRENT));
01043     *entry = dfcb->f_dirent;
01044     memset(entry->dent_name, ' ', sizeof(entry->dent_name));
01045     entry->dent_name[0] = '.';
01046     PhatFilePosRewind(dfcb);
01047     if (PhatFileWrite(ndp, entry, sizeof(PHATDIRENT)) != sizeof(PHATDIRENT)) {
01048         PhatFileClose(ndp);
01049         free(entry);
01050         return -1;
01051     }
01052 
01053     /*
01054      * Write the double dot entry. If it points to the root cluster,
01055      * then the cluster number in the directory entry must be zero.
01056      */
01057     if ((uint16_t) vol->vol_root_clust == dfcb->f_pde_clust &&   /* */
01058         vol->vol_root_clust >> 16 == dfcb->f_pde_clusthi) {
01059         entry->dent_clust = 0;
01060         entry->dent_clusthi = 0;
01061     } else {
01062         entry->dent_clust = dfcb->f_pde_clust;
01063         entry->dent_clusthi = dfcb->f_pde_clusthi;
01064     }
01065     entry->dent_name[1] = '.';
01066     if (PhatFileWrite(ndp, entry, sizeof(PHATDIRENT)) != sizeof(PHATDIRENT)) {
01067         PhatFileClose(ndp);
01068         free(entry);
01069         return -1;
01070     }
01071     free(entry);
01072 
01073     return PhatFileClose(ndp);
01074 }
01075 
01084 int PhatDirRemove(NUTDEVICE * dev, char *path)
01085 {
01086     int rc = -1;
01087     PHATDIRENT *entry;
01088     NUTFILE *ndp;
01089 
01090     /* Never remove the root directory */
01091     if (path[0] == '/' && path[1] == 0) {
01092         errno = EBUSY;
01093         return -1;
01094     }
01095 
01096     if ((entry = malloc(sizeof(PHATDIRENT))) == NULL) {
01097         return -1;
01098     }
01099 
01100     /*
01101      * Make sure, that the directory we want to remove is empty. The dot
01102      * and double dot entries are ignored.
01103      */
01104     if ((ndp = PhatFileOpen(dev, path, _O_RDONLY, 0)) != NUTFILE_EOF) {
01105         rc = 0;
01106         for (;;) {
01107             rc = PhatFileRead(ndp, entry, sizeof(PHATDIRENT));
01108             if (rc < 0) {
01109                 break;
01110             }
01111             /* Check for end of directory. */
01112             if (rc < sizeof(PHATDIRENT) || entry->dent_name[0] == 0) {
01113                 rc = 0;
01114                 break;
01115             }
01116             /* Skip removed entries. */
01117             if (entry->dent_name[0] == PHAT_REM_DIRENT) {
01118                 continue;
01119             }
01120             /* Ignore entries which are not files. */
01121             if ((entry->dent_attr | PHAT_FATTR_FILEMASK) != PHAT_FATTR_FILEMASK) {
01122                 continue;
01123             }
01124             /* Ignore dot and double dot entries. */
01125             if (entry->dent_name[0] == '.' &&   /* */
01126                 (entry->dent_name[1] == '.' || entry->dent_name[1] == ' ')) {
01127                 if (memcmp("         ", &entry->dent_name[2], 9) == 0) {
01128                     continue;
01129                 }
01130             }
01131             errno = ENOTEMPTY;
01132             rc = -1;
01133             break;
01134         }
01135         PhatFileClose(ndp);
01136     }
01137     free(entry);
01138 
01139     /* If the empty check was successful, then remove the entry. */
01140     if (rc == 0) {
01141         rc = PhatDirDelEntry(dev, path, PHAT_FATTR_DIR);
01142     }
01143     return rc;
01144 }
01145 
01155 int PhatDirEntryStatus(NUTDEVICE * dev, CONST char *path, struct stat *stp)
01156 {
01157     int rc;
01158     CONST char *fname;
01159     NUTFILE *ndp;
01160     PHATFIND *srch;
01161     unsigned int val;
01162 
01163     /* Open parent directory. */
01164     if ((ndp = PhatDirOpenParent(dev, path, &fname)) == NUTFILE_EOF) {
01165         return -1;
01166     }
01167 
01168     if ((srch = malloc(sizeof(PHATFIND))) == NULL) {
01169         PhatFileClose(ndp);
01170         return -1;
01171     }
01172     if ((rc = PhatDirEntryFind(ndp, fname, PHAT_FATTR_FILEMASK, srch)) == 0) {
01173         struct _tm t;
01174 
01175         memset(&t, 0, sizeof(struct _tm));
01176         val = srch->phfind_ent.dent_mtime;
01177         t.tm_sec = (val & 0x1F) << 1;
01178         t.tm_min = (val >> 5) & 0x3F;
01179         t.tm_hour = (val >> 11) & 0x1F;
01180         val = srch->phfind_ent.dent_mdate;
01181         t.tm_mday = val & 0x1F;
01182         t.tm_mon = ((val >> 5) & 0x0F);
01183         if (t.tm_mon) {
01184             t.tm_mon--;
01185         }
01186         t.tm_year = ((val >> 9) & 0x7F) + 80;
01187         t.tm_isdst = _daylight;
01188         stp->st_mtime = mktime(&t);
01189 
01190         stp->st_ino = 0;
01191         stp->st_mode = (srch->phfind_ent.dent_attr & PHAT_FATTR_DIR) != 0;
01192         stp->st_nlink = 0;
01193         stp->st_size = srch->phfind_ent.dent_fsize;
01194     }
01195     free(srch);
01196     PhatFileClose(ndp);
01197 
01198     return rc;
01199 }
01200