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 
00098 #include <fs/fs.h>
00099 #include <fs/phatfs.h>
00100 #include <fs/phatvol.h>
00101 #include <fs/phatio.h>
00102 #include <fs/phatutil.h>
00103 #include <fs/phatdir.h>
00104 
00105 #include <stdlib.h>
00106 #include <string.h>
00107 #include <ctype.h>
00108 #include <fcntl.h>
00109 #include <errno.h>
00110 #include <time.h>
00111 
00112 #if 0
00113 /* Use for local debugging. */
00114 #define NUTDEBUG
00115 #include <stdio.h>
00116 #include <fs/phatdbg.h>
00117 #endif
00118 
00123 
00125 #define PHAT_MAXDIRENT   65536
00126 
00133 static INLINE u_char GenShortNameChecksum(char *sfn)
00134 {
00135     u_char rc = 0;
00136     int i;
00137 
00138     for (i = 0; i < 11; i++) {
00139         rc = ((rc >> 1) | ((rc & 1) << 7)) + (u_char)(sfn[i]);
00140     }
00141     return rc;
00142 }
00143 
00155 static int GenShortName(NUTFILE * ndp, CONST char *lfn, char *sfn)
00156 {
00157     int rc = -1;
00158     int i;
00159     int got;
00160     PHATDIRENT *entry;
00161     char *xp;
00162 
00163     /* Fill the buffer with spaces. */
00164     memset(sfn, ' ', 11);
00165 
00166     /* Get the position of the last dot in the long name. */
00167     xp = strrchr(lfn, '.');
00168 
00169     /* Now collect up to 8 characters for the basename and 3 characters
00170      * for the extension. */
00171     for (i = 0; i < 11 && *lfn; lfn++) {
00172         if (*lfn == '.') {
00173             /* We reached the first dot. The basename ends here. */
00174             if (lfn == xp) {
00175                 /* This is also the last dot. Start copying the extension. */
00176                 lfn++;
00177                 if (*lfn) {
00178                     sfn[8] = toupper(*lfn);
00179                 }
00180                 i = 9;
00181             }
00182         }
00183         else if (i == 8) {
00184             /* First 8 characters collected. */
00185             if (xp == NULL) {
00186                 /* No dot, no extension. */
00187                 break;
00188             }
00189             lfn = xp + 1;
00190             if (*lfn) {
00191                 sfn[i++] = toupper(*lfn);
00192             }
00193         }
00194         else if (*lfn != ' ') {
00195             if (strrchr("+,;=[]", *lfn)) {
00196                 sfn[i++] = '_';
00197             }
00198             else {
00199                 sfn[i++] = toupper(*lfn);
00200             }
00201         }
00202     }
00203 
00204     /*
00205      * Select a unique short name by verifying existing entries in the 
00206      * specified directory.
00207      */
00208     if ((entry = malloc(sizeof(PHATDIRENT))) != NULL) {
00209         xp = sfn;
00210         for (i = 0; i < 6 && *xp != ' '; i++) {
00211             xp++;
00212         }
00213         /*
00214          * We try up to 99 unique short names only, but this should be
00215          * sufficient for our tiny system - hopefully.
00216          */
00217         for (i = 1; i <= 99 && rc; i++) {
00218             if (i == 10) {
00219                 xp--;
00220             }
00221             *xp = '~';
00222             if (i > 9) {
00223                 *(xp + 1) = '0' + i / 10;
00224                 *(xp + 2) = '0' + i % 10;
00225             }
00226             else {
00227                 *(xp + 1) = '0' + i;
00228             }
00229             PhatFilePosRewind((PHATFILE *)ndp->nf_fcb);
00230             for (;;) {
00231                 /* Read next entry. */
00232                 if ((got = PhatFileRead(ndp, entry, sizeof(PHATDIRENT))) != sizeof(PHATDIRENT)) {
00233                     if (got) {
00234                         /* Read error, stop searching. */
00235                         i = 9;
00236                     }
00237                     else {
00238                         /* End of directory reached, entry is unique. */
00239                         rc = 0;
00240                     }
00241                     break;
00242                 }
00243                 if ((entry->dent_attr & PHAT_FATTR_VOLID) == 0) {
00244                     if (entry->dent_name[0] == 0) {
00245                         /* End of directory reached, entry is unique. */
00246                         rc = 0;
00247                         break;
00248                     }
00249                     if (memcmp(sfn, (char *)entry->dent_name, 11) == 0) {
00250                         /* Entry exists, try next one. */
00251                         break;
00252                     }
00253                 }
00254             }
00255         }
00256         free(entry);
00257     }
00258     return rc;
00259 }
00260 
00270 static int PhatDirEntryAlloc(NUTFILE * ndp, CONST char *fname, PHATDIRENT * entry)
00271 {
00272     int rc;
00273     int pos = 0;
00274     int got;
00275     u_char sect;
00276     u_char *temp;
00277     NUTDEVICE *dev = ndp->nf_dev;
00278     PHATFILE *dfcb = ndp->nf_fcb;
00279     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00280     PHATDIRENT *dent;
00281     PHATXDIRENT *xdent;
00282     int nwant = 1;
00283     int ngot = 0;
00284     int npos = 0;
00285     int i;
00286     int ci;
00287     u_char cks = 0;
00288 
00289     /* Convert the dotted name to a space filled one. */
00290     if ((rc = MakePhatName(fname, entry->dent_name)) == 1) {
00291         /* Reject name with wildcards. */
00292         errno = EINVAL;
00293         return -1;
00294     }
00295     if (rc == 0) {
00296         char vname[16];
00297 
00298         MakeVisibleName(entry->dent_name, vname);
00299         if (strcmp(fname, vname)) {
00300             rc = 1;
00301         }
00302     }
00303     if (rc) {
00304         if (GenShortName(ndp, fname, (char *)entry->dent_name)) {
00305             errno = EINVAL;
00306             return -1;
00307         }
00308         nwant = (strlen(fname) + 12) / 13 + 1;
00309         cks = GenShortNameChecksum((char *)entry->dent_name);
00310     }
00311 
00312     /* Allocate a temporary entry buffer. */
00313     if ((dent = malloc(sizeof(PHATDIRENT))) == NULL) {
00314         return -1;
00315     }
00316 
00317     /*
00318      * Find free entries, starting from the beginning.
00319      */
00320     PhatFilePosRewind(dfcb);
00321     rc = -1;
00322     for (;;) {
00323         /* Memorize the current position and try to read the next entry. */
00324         npos = dfcb->f_pos;
00325         if ((got = PhatFileRead(ndp, dent, sizeof(PHATDIRENT))) < 0) {
00326             /* Read failed. */
00327             break;
00328         }
00329         if (got != sizeof(PHATDIRENT)) {
00330             /*
00331              * End of directory reached. Try to expand it. 
00332              */
00333             if (IsFixedRootDir(ndp) ||  /* */
00334                 dfcb->f_pos >= PHAT_MAXDIRENT * sizeof(PHATDIRENT)) {
00335                 /* Failed. Either PHAT12/16 root dir or max. size reached. */
00336                 errno = EFBIG;
00337                 break;
00338             }
00339 
00340             /* Fill a new cluster with zeros. */
00341             if ((temp = malloc(vol->vol_sectsz)) == NULL) {
00342                 break;
00343             }
00344             memset(temp, 0, vol->vol_sectsz);
00345             for (sect = vol->vol_clustsz; sect; sect--) {
00346                 if (PhatFileWrite(ndp, temp, vol->vol_sectsz) < 0) {
00347                     /* Write failed. */
00348                     break;
00349                 }
00350             }
00351             free(temp);
00352             /* End of directory reached and expanded by a new cluster. */
00353             if (sect == 0) {
00354                 if (ngot == 0) {
00355                     pos = npos;
00356                 }
00357                 rc = 0;
00358             }
00359             break;
00360         }
00361         if (dent->dent_name[0] == PHAT_REM_DIRENT || dent->dent_name[0] == 0) {
00362             /* Empty entry found. */
00363             if (ngot == 0) {
00364                 pos = npos;
00365             }
00366             ngot++;
00367             if (ngot >= nwant) {
00368                 rc = 0;
00369                 break;
00370             }
00371         }
00372         else {
00373             ngot = 0;
00374         }
00375     }
00376     free(dent);
00377 
00378     if (rc == 0) {
00379         /* Return to the memorized position and write the new entry. */
00380         PhatFilePosSet(ndp, pos);
00381         if ((xdent = malloc(sizeof(PHATXDIRENT))) == NULL) {
00382             return -1;
00383         }
00384         for (ngot = nwant - 1; ngot; ngot--) {
00385             memset(xdent, 0xFF, sizeof(PHATXDIRENT));
00386             xdent->xdent_seq = ngot;
00387             if (ngot == nwant - 1) {
00388                 xdent->xdent_seq |= 0x40;
00389             }
00390             xdent->xdent_attr = PHAT_FATTR_LFN;
00391             xdent->xdent_cks = cks;
00392             xdent->xdent_clust = 0;
00393             xdent->xdent_rsvd = 0;
00394             /* Simplified unicode conversion, ignores double byte characters. */
00395             ci = (ngot - 1) * 13;
00396             for (i = 0; i < 13; i++) {
00397                 if (ci + i <= strlen(fname)) {
00398                     if (i < 5) {
00399                         xdent->xdent_uname_1_5[i] = fname[ci + i];
00400                     }
00401                     else if (i < 11) {
00402                         xdent->xdent_uname_6_11[i - 5] = fname[ci + i];
00403                     }
00404                     else {
00405                         xdent->xdent_uname_12_13[i - 11] = fname[ci + i];
00406                     }
00407                 }
00408             }
00409             if (PhatFileWrite(ndp, xdent, sizeof(PHATXDIRENT)) < 0) {
00410                 /* Write error. */
00411                 rc = -1;
00412                 break;
00413             }
00414         }
00415         if (PhatFileWrite(ndp, entry, sizeof(PHATDIRENT)) < 0) {
00416             /* Write error. */
00417             rc = -1;
00418         }
00419         free(xdent);
00420     }
00421     return rc;
00422 }
00423 
00436 static int PhatDirEntryRelease(NUTFILE * ndp, u_long pos, int lfncnt)
00437 {
00438     u_char ch = PHAT_REM_DIRENT;
00439     int i;
00440 
00441     for (i = lfncnt; i; i--) {
00442         PhatFilePosSet(ndp, pos - i * sizeof(PHATXDIRENT));
00443         if (PhatFileWrite(ndp, &ch, 1) < 0) {
00444             return -1;
00445         }
00446     }
00447     PhatFilePosSet(ndp, pos);
00448     if (PhatFileWrite(ndp, &ch, 1) < 0) {
00449         return -1;
00450     }
00451     return 0;
00452 }
00453 
00464 int PhatDirEntryCreate(NUTFILE * ndp, CONST char *name, int acc, PHATDIRENT * dirent)
00465 {
00466     dirent->dent_attr = (u_char) acc;
00467     GetDosTimeStamp(&dirent->dent_ctime, &dirent->dent_cdate);
00468     dirent->dent_adate = dirent->dent_cdate;
00469     dirent->dent_mtime = dirent->dent_ctime;
00470     dirent->dent_mdate = dirent->dent_cdate;
00471 
00472     if (PhatDirEntryAlloc(ndp, name, dirent)) {
00473         return -1;
00474     }
00475 #ifdef NUTDEBUG
00476     PhatDbgFileInfo(stdout, "New Dir Entry", ndp->nf_fcb);
00477 #endif
00478     return 0;
00479 }
00480 
00488 int PhatDirEntryUpdate(NUTFILE * nfp)
00489 {
00490     int sbn;
00491     NUTDEVICE *dev = nfp->nf_dev;
00492     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00493     PHATFILE *fcb = nfp->nf_fcb;
00494 
00495     if (fcb->f_de_dirty) {
00496         /*
00497          * The file may specify the root directory, in which case
00498          * the updated is skipped.
00499          */
00500         if (fcb->f_de_sect) {
00501 #ifdef NUTDEBUG
00502             PhatDbgDirEntry(stdout, "PhatDirEntryUpdate", &fcb->f_dirent);
00503 #endif
00504             if ((sbn = PhatSectorLoad(dev, fcb->f_de_sect)) < 0) {
00505                 return -1;
00506             }
00507             memcpy(vol->vol_buf[sbn].sect_data + fcb->f_de_offs, &fcb->f_dirent, sizeof(PHATDIRENT));
00508             vol->vol_buf[sbn].sect_dirty = 1;
00509         }
00510         fcb->f_de_dirty = 0;
00511     }
00512     return 0;
00513 }
00514 
00523 static int PhatDirEntryRead(NUTFILE * ndp, PHATFIND * srch)
00524 {
00525     PHATDIRENT *entry = &srch->phfind_ent;
00526     PHATFILE *fcb = ndp->nf_fcb;
00527     PHATXDIRENT *xentry;
00528     char *lfn = NULL;
00529     int lfnpos = 0;
00530     int nxtseq = 0;
00531     int lfncnt = 0;
00532     int i;
00533 
00534     for (;;) {
00535         /* Read next entry. */
00536         if (PhatFileRead(ndp, entry, sizeof(PHATDIRENT)) != sizeof(PHATDIRENT)) {
00537             break;
00538         }
00539         /* Skip removed entries. */
00540         if (entry->dent_name[0] == PHAT_REM_DIRENT) {
00541             if (lfn) {
00542                 free(lfn);
00543                 lfn = NULL;
00544             }
00545         }
00546         /* Process long filename entries. */
00547         else if (entry->dent_attr == PHAT_FATTR_LFN) {
00548             xentry = (PHATXDIRENT *)entry;
00549             lfnpos = (xentry->xdent_seq & 0x3F);
00550             /* Make sure we are in sequence. */
00551             if ((nxtseq == 0 && (xentry->xdent_seq & 0x40) != 0) || nxtseq == lfnpos) {
00552                 nxtseq = --lfnpos;
00553                 lfnpos *= 13;
00554                 if (lfnpos + 13 > PHAT_MAX_NAMELEN) {
00555                     errno = EINVAL;
00556                     break;
00557                 }
00558                 if (xentry->xdent_seq & 0x40) {
00559                     if (lfn == NULL) {
00560                         lfn = malloc(PHAT_MAX_NAMELEN + 1);
00561                     }
00562                     lfn[lfnpos + 13] = 0;
00563                     lfncnt = 0;
00564                 }
00565                 lfncnt++;
00566                 /* Simplified unicode conversion, ignores double byte characters. */
00567                 for (i = 0; i < 5; i++) {
00568                     lfn[lfnpos + i] = (char)xentry->xdent_uname_1_5[i];
00569                 }
00570                 for (i = 0; i < 6; i++) {
00571                     lfn[lfnpos + 5 + i] = (char)xentry->xdent_uname_6_11[i];
00572                 }
00573                 for (i = 0; i < 2; i++) {
00574                     lfn[lfnpos + 11 + i] = (char)xentry->xdent_uname_12_13[i];
00575                 }
00576             }
00577         }
00578 
00579         /* Skip volume IDs. */
00580         else if ((entry->dent_attr & PHAT_FATTR_VOLID) == 0) {
00581             /* Stop searching if last entry reached. */
00582             if (entry->dent_name[0] == 0) {
00583                 break;
00584             }
00585             /* Valid entry found. Return success. */
00586             srch->phfind_pos = fcb->f_pos - sizeof(PHATDIRENT);
00587             if (lfn && lfnpos == 0) {
00588                 strcpy(srch->phfind_name, lfn);
00589                 srch->phfind_xcnt = lfncnt;
00590             }
00591             else {
00592                 MakeVisibleName(entry->dent_name, srch->phfind_name);
00593                 srch->phfind_xcnt = 0;
00594             }
00595             if (lfn) {
00596                 free(lfn);
00597             }
00598             nxtseq = 0;
00599             lfncnt = 0;
00600             return 0;
00601         }
00602         else if (lfn) {
00603             free(lfn);
00604             lfn = NULL;
00605             nxtseq = 0;
00606             lfncnt = 0;
00607         }
00608     }
00609     if (lfn) {
00610         free(lfn);
00611     }
00612     return -1;
00613 }
00614 
00627 int PhatDirEntryFind(NUTFILE * ndp, CONST char *spec, u_long attmsk, PHATFIND * srch)
00628 {
00629     int rc;
00630     PHATFIND *temps;
00631 
00632     /* Allocate a temporary structure to store the search result. */
00633     if ((temps = malloc(sizeof(PHATFIND))) == NULL) {
00634         return -1;
00635     }
00636 
00637     /*
00638      * Loop until the specified entry was found or until we reach the
00639      * end of the directory.
00640      */
00641     PhatFilePosRewind((PHATFILE *)ndp->nf_fcb);
00642     while ((rc = PhatDirEntryRead(ndp, temps)) == 0) {
00643         if ((temps->phfind_ent.dent_attr | attmsk) == attmsk) {
00644             if (strcasecmp(temps->phfind_name, spec) == 0) {
00645                 /* Specified entry found. */
00646                 if (srch) {
00647                     *srch = *temps;
00648                 }
00649                 break;
00650             }
00651         }
00652     }
00653     free(temps);
00654 
00655     return rc;
00656 }
00657 
00668 NUTFILE *PhatDirOpenParent(NUTDEVICE * dev, CONST char *path, CONST char **basename)
00669 {
00670     NUTFILE *rc = NUTFILE_EOF;
00671     char *parent;
00672 
00673     if ((parent = GetParentPath(path, basename)) != NULL) {
00674         rc = PhatDirOpen(dev, parent);
00675         free(parent);
00676     }
00677     return rc;
00678 }
00679 
00689 int PhatDirRenameEntry(NUTDEVICE * dev, CONST char *old_path, CONST char *new_path)
00690 {
00691     int rc = -1;
00692     CONST char *fname;
00693     NUTFILE *old_ndp;
00694     NUTFILE *new_ndp;
00695     PHATFIND *srch;
00696 
00697     /*
00698      * Open directory of the old file.
00699      */
00700     if ((old_ndp = PhatDirOpenParent(dev, old_path, &fname)) == NUTFILE_EOF) {
00701         return -1;
00702     }
00703 
00704     if ((srch = malloc(sizeof(PHATFIND))) != NULL) {
00705         if ((rc = PhatDirEntryFind(old_ndp, fname, PHAT_FATTR_FILEMASK, srch)) == 0) {
00706             rc = -1;
00707             if ((new_ndp = PhatDirOpenParent(dev, new_path, &fname)) != NUTFILE_EOF) {
00708                 if (PhatDirEntryFind(new_ndp, fname, PHAT_FATTR_FILEMASK, NULL) == 0) {
00709                     errno = EEXIST;
00710                 } else {
00711                     if ((rc = PhatDirEntryAlloc(new_ndp, fname, &srch->phfind_ent)) == 0) {
00712                         rc = PhatDirEntryRelease(old_ndp, srch->phfind_pos, srch->phfind_xcnt);
00713                     }
00714                 }
00715                 PhatFileClose(new_ndp);
00716             }
00717         }
00718         else {
00719             errno = ENOENT;
00720         }
00721         free(srch);
00722     }
00723     PhatFileClose(old_ndp);
00724 
00725     return rc;
00726 }
00727 
00736 int PhatDirReleaseChain(NUTDEVICE * dev, PHATDIRENT *dent)
00737 {
00738     int rc = 0;
00739     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00740     u_long clust;
00741 
00742     /* Do not remove clusters of files with RDONLY attribute. */
00743     if (dent->dent_attr & PHAT_FATTR_RDONLY) {
00744         errno = EACCES;
00745         return -1;
00746     }
00747 
00748     /* Get the first cluster of this file. The directory entry stores this
00749        value in two positions. */
00750     clust = dent->dent_clusthi;
00751     clust <<= 16;
00752     clust |= dent->dent_clust;
00753 
00754     /* The data area starts at cluster 2. With empty files the first cluster 
00755        is set to zero. A value of one is suspicious and will be ignored. */
00756     if (clust >= 2) {
00757         /* Call the format specific release routine. */
00758         if (vol->vol_type == 32) {
00759             rc = Phat32ReleaseChain(dev, clust);
00760         } else if (vol->vol_type == 16) {
00761             rc = Phat16ReleaseChain(dev, clust);
00762         } else {
00763             rc = Phat12ReleaseChain(dev, clust);
00764         }
00765     }
00766     return rc;
00767 }
00768 
00780 int PhatDirDelEntry(NUTDEVICE * dev, CONST char *path, u_long flags)
00781 {
00782     int rc = -1;
00783     PHATFIND *srch;
00784     NUTFILE *ndp;
00785     CONST char *fname;
00786 
00787     /* Open the parent directory. */
00788     if ((ndp = PhatDirOpenParent(dev, path, &fname)) != NUTFILE_EOF) {
00789         if ((srch = malloc(sizeof(PHATFIND))) != NULL) {
00790             /* Find the specified file name. */
00791             if (PhatDirEntryFind(ndp, fname, flags, srch) == 0) {
00792                 if (PhatDirReleaseChain(dev, &srch->phfind_ent) == 0) {
00793                     rc = PhatDirEntryRelease(ndp, srch->phfind_pos, srch->phfind_xcnt);
00794                 }
00795             }
00796             else {
00797                 errno = ENOENT;
00798             }
00799             free(srch);
00800         }
00801         PhatFileClose(ndp);
00802     }
00803     return rc;
00804 }
00805 
00814 NUTFILE *PhatDirOpen(NUTDEVICE * dev, CONST char *dpath)
00815 {
00816     NUTFILE *ndp;
00817     PHATFILE *dfcb;
00818     PHATFIND *srch;
00819     char *comp;
00820     char *cp;
00821     int sz;
00822     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00823 
00824     /* Make sure the volume is mounted. */
00825     if (vol == NULL) {
00826         errno = ENODEV;
00827         return NUTFILE_EOF;
00828     }
00829 
00830     /* Allocate the structure to return. */
00831     if ((ndp = malloc(sizeof(NUTFILE))) == NULL) {
00832         return NUTFILE_EOF;
00833     }
00834     if ((ndp->nf_fcb = malloc(sizeof(PHATFILE))) == NULL) {
00835         free(ndp);
00836         return NUTFILE_EOF;
00837     }
00838     memset(ndp->nf_fcb, 0, sizeof(PHATFILE));
00839     ndp->nf_next = NULL;
00840     ndp->nf_dev = dev;
00841 
00842     dfcb = ndp->nf_fcb;
00843     dfcb->f_dirent.dent_attr = PHAT_FATTR_DIR;
00844     dfcb->f_mode = _O_RDONLY;
00845 
00846     /* We start at the root directory. */
00847     dfcb->f_clust = vol->vol_root_clust;
00848     dfcb->f_dirent.dent_clusthi = (u_short) (vol->vol_root_clust >> 16);
00849     dfcb->f_dirent.dent_clust = (u_short) vol->vol_root_clust;
00850 
00851     if (*dpath == '/') {
00852         dpath++;
00853     }
00854     if (*dpath) {
00855         /*
00856          * We are looking for a subdirectory.
00857          */
00858         if ((comp = malloc(PHAT_MAX_NAMELEN + 1)) == NULL) {
00859             free(dfcb);
00860             free(ndp);
00861             return NUTFILE_EOF;
00862         }
00863         if ((srch = malloc(sizeof(PHATFIND))) == NULL) {
00864             free(comp);
00865             free(dfcb);
00866             free(ndp);
00867             return NUTFILE_EOF;
00868         }
00869 
00870         /*
00871          * Walk down the path.
00872          */
00873         while (*dpath) {
00874             /* Fetch the next component from the path. */
00875             cp = comp;
00876             sz = 0;
00877             while (*dpath) {
00878                 if (*dpath == '/') {
00879                     dpath++;
00880                     break;
00881                 }
00882                 if (++sz > PHAT_MAX_NAMELEN) {
00883                     break;
00884                 }
00885                 *cp++ = *dpath++;
00886             }
00887             *cp = 0;
00888 
00889             /* Search component's entry in the current directory. */
00890             if (sz > PHAT_MAX_NAMELEN || PhatDirEntryFind(ndp, comp, PHAT_FATTR_FILEMASK, srch)) {
00891                 errno = ENOENT;
00892                 free(dfcb);
00893                 free(ndp);
00894                 ndp = NUTFILE_EOF;
00895                 break;
00896             }
00897 
00898             /*
00899              * Next component found. Mimic the open by updating the existing
00900              * file control block structure.
00901              */
00902             dfcb->f_de_sect = PhatClusterSector(ndp, dfcb->f_clust) + dfcb->f_clust_pos;
00903             dfcb->f_de_offs = dfcb->f_sect_pos - 32;
00904 
00905             /* Set the cluster of our directory entry. */
00906             dfcb->f_pde_clusthi = dfcb->f_dirent.dent_clusthi;
00907             dfcb->f_pde_clust = dfcb->f_dirent.dent_clust;
00908 
00909             dfcb->f_dirent = srch->phfind_ent;
00910 #ifdef NUTDEBUG
00911             PhatDbgFileInfo(stdout, "Component", dfcb);
00912 #endif
00913 
00914             /*
00915              * Handle root directory.
00916              */
00917             if (dfcb->f_dirent.dent_attr & PHAT_FATTR_DIR) {
00918                 if (dfcb->f_dirent.dent_clust == 0 && dfcb->f_dirent.dent_clusthi == 0) {
00919                     if (vol->vol_type != 32) {
00920                         dfcb->f_de_sect = 0;
00921                     }
00922                     dfcb->f_dirent.dent_clusthi = (u_short) (vol->vol_root_clust >> 16);
00923                     dfcb->f_dirent.dent_clust = (u_short) vol->vol_root_clust;
00924                 }
00925             }
00926 
00927             /*
00928              * Reset position.
00929              */
00930             PhatFilePosRewind(dfcb);
00931             dfcb->f_clust_prv = 0;
00932             dfcb->f_mode = _O_RDONLY;
00933         }
00934         free(srch);
00935         free(comp);
00936     }
00937     return ndp;
00938 }
00939 
00947 int PhatDirRead(DIR * dir)
00948 {
00949     PHATFIND *srch;
00950     struct dirent *ent;
00951 
00952     if ((srch = malloc(sizeof(PHATFIND))) == NULL) {
00953         return -1;
00954     }
00955     if (PhatDirEntryRead(dir->dd_fd, srch)) {
00956         free(srch);
00957         return -1;
00958     }
00959 #ifdef NUTDEBUG
00960     PhatDbgDirEntry(stdout, "Read entry", &srch->phfind_ent);
00961 #endif
00962 
00963     ent = (struct dirent *) dir->dd_buf;
00964     memset(dir->dd_buf, 0, sizeof(struct dirent));
00965     ent->d_namlen = (u_char) strlen(srch->phfind_name);
00966     strcpy(ent->d_name, srch->phfind_name);
00967     if (srch->phfind_ent.dent_attr & PHAT_FATTR_DIR) {
00968         ent->d_type = 1;
00969     }
00970     free(srch);
00971 
00972     return 0;
00973 }
00974 
00986 int PhatDirCreate(NUTDEVICE * dev, char *path)
00987 {
00988     NUTFILE *ndp;
00989     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00990     PHATFILE *dfcb;
00991     PHATDIRENT *entry;
00992     u_char *buf;
00993     u_long sect;
00994     u_long clust;
00995 
00996     /*
00997      * Create the new directory like a normal file with a special attribute.
00998      */
00999     if ((ndp = PhatFileOpen(dev, path, _O_CREAT | _O_RDWR | _O_EXCL, PHAT_FATTR_DIR)) == NUTFILE_EOF) {
01000         return -1;
01001     }
01002     dfcb = ndp->nf_fcb;
01003 
01004     /*
01005      * Allocate a first cluster and initialize it with zeros.
01006      */
01007     if ((clust = AllocFirstCluster(ndp)) < 2) {
01008         PhatFileClose(ndp);
01009         return -1;
01010     }
01011     dfcb->f_clust_prv = clust;
01012     dfcb->f_clust = clust;
01013     if ((buf = malloc(vol->vol_sectsz)) == NULL) {
01014         PhatFileClose(ndp);
01015         return -1;
01016     }
01017     memset(buf, 0, vol->vol_sectsz);
01018     for (sect = vol->vol_clustsz; sect; sect--) {
01019         if (PhatFileWrite(ndp, buf, vol->vol_sectsz) < 0) {
01020             /* Write failed. */
01021             free(buf);
01022             PhatFileClose(ndp);
01023             return -1;
01024         }
01025     }
01026     free(buf);
01027 
01028     /*
01029      * Write the dot entry.
01030      */
01031     entry = malloc(sizeof(PHATDIRENT));
01032     *entry = dfcb->f_dirent;
01033     memset(entry->dent_name, ' ', sizeof(entry->dent_name));
01034     entry->dent_name[0] = '.';
01035     PhatFilePosRewind(dfcb);
01036     if (PhatFileWrite(ndp, entry, sizeof(PHATDIRENT)) != sizeof(PHATDIRENT)) {
01037         PhatFileClose(ndp);
01038         free(entry);
01039         return -1;
01040     }
01041 
01042     /*
01043      * Write the double dot entry. If it points to the root cluster,
01044      * then the cluster number in the directory entry must be zero.
01045      */
01046     if ((u_short) vol->vol_root_clust == dfcb->f_pde_clust &&   /* */
01047         vol->vol_root_clust >> 16 == dfcb->f_pde_clusthi) {
01048         entry->dent_clust = 0;
01049         entry->dent_clusthi = 0;
01050     } else {
01051         entry->dent_clust = dfcb->f_pde_clust;
01052         entry->dent_clusthi = dfcb->f_pde_clusthi;
01053     }
01054     entry->dent_name[1] = '.';
01055     if (PhatFileWrite(ndp, entry, sizeof(PHATDIRENT)) != sizeof(PHATDIRENT)) {
01056         PhatFileClose(ndp);
01057         free(entry);
01058         return -1;
01059     }
01060     free(entry);
01061 
01062     return PhatFileClose(ndp);
01063 }
01064 
01073 int PhatDirRemove(NUTDEVICE * dev, char *path)
01074 {
01075     int rc = -1;
01076     PHATDIRENT *entry;
01077     NUTFILE *ndp;
01078 
01079     /* Never remove the root directory */
01080     if (path[0] == '/' && path[1] == 0) {
01081         errno = EBUSY;
01082         return -1;
01083     }
01084 
01085     if ((entry = malloc(sizeof(PHATDIRENT))) == NULL) {
01086         return -1;
01087     }
01088 
01089     /*
01090      * Make sure, that the directory we want to remove is empty. The dot 
01091      * and double dot entries are ignored.
01092      */
01093     if ((ndp = PhatFileOpen(dev, path, _O_RDONLY, 0)) != NUTFILE_EOF) {
01094         rc = 0;
01095         for (;;) {
01096             rc = PhatFileRead(ndp, entry, sizeof(PHATDIRENT));
01097             if (rc < 0) {
01098                 break;
01099             }
01100             /* Check for end of directory. */
01101             if (rc < sizeof(PHATDIRENT) || entry->dent_name[0] == 0) {
01102                 rc = 0;
01103                 break;
01104             }
01105             /* Skip removed entries. */
01106             if (entry->dent_name[0] == PHAT_REM_DIRENT) {
01107                 continue;
01108             }
01109             /* Ignore entries which are not files. */
01110             if ((entry->dent_attr | PHAT_FATTR_FILEMASK) != PHAT_FATTR_FILEMASK) {
01111                 continue;
01112             }
01113             /* Ignore dot and double dot entries. */
01114             if (entry->dent_name[0] == '.' &&   /* */
01115                 (entry->dent_name[1] == '.' || entry->dent_name[1] == ' ')) {
01116                 if (memcmp("         ", &entry->dent_name[2], 9) == 0) {
01117                     continue;
01118                 }
01119             }
01120             errno = ENOTEMPTY;
01121             rc = -1;
01122             break;
01123         }
01124         PhatFileClose(ndp);
01125     }
01126     free(entry);
01127 
01128     /* If the empty check was successful, then remove the entry. */
01129     if (rc == 0) {
01130         rc = PhatDirDelEntry(dev, path, PHAT_FATTR_DIR);
01131     }
01132     return rc;
01133 }
01134 
01144 int PhatDirEntryStatus(NUTDEVICE * dev, CONST char *path, struct stat *stp)
01145 {
01146     int rc;
01147     CONST char *fname;
01148     NUTFILE *ndp;
01149     PHATFIND *srch;
01150     u_int val;
01151 
01152     /* Open parent directory. */
01153     if ((ndp = PhatDirOpenParent(dev, path, &fname)) == NUTFILE_EOF) {
01154         return -1;
01155     }
01156 
01157     if ((srch = malloc(sizeof(PHATFIND))) == NULL) {
01158         PhatFileClose(ndp);
01159         return -1;
01160     }
01161     if ((rc = PhatDirEntryFind(ndp, fname, PHAT_FATTR_FILEMASK, srch)) == 0) {
01162         struct _tm t;
01163 
01164         memset(&t, 0, sizeof(struct _tm));
01165         val = srch->phfind_ent.dent_mtime;
01166         t.tm_sec = (val & 0x1F) << 1;
01167         t.tm_min = (val >> 5) & 0x3F;
01168         t.tm_hour = (val >> 11) & 0x1F;
01169         val = srch->phfind_ent.dent_mdate;
01170         t.tm_mday = val & 0x1F;
01171         t.tm_mon = ((val >> 5) & 0x0F);
01172         if (t.tm_mon) {
01173             t.tm_mon--;
01174         }
01175         t.tm_year = ((val >> 9) & 0x7F) + 80;
01176         t.tm_isdst = _daylight; 
01177         stp->st_mtime = mktime(&t);
01178 
01179         stp->st_ino = 0;
01180         stp->st_mode = (srch->phfind_ent.dent_attr & PHAT_FATTR_DIR) != 0;
01181         stp->st_nlink = 0;
01182         stp->st_size = srch->phfind_ent.dent_fsize;
01183     }
01184     free(srch);
01185     PhatFileClose(ndp);
01186 
01187     return rc;
01188 }
01189 

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