phatfs.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 
00088 #include <fs/fs.h>
00089 
00090 #include <dirent.h>
00091 
00092 #include <dev/blockdev.h>
00093 
00094 #include <sys/event.h>
00095 
00096 #include <fs/phatfs.h>
00097 #include <fs/phatvol.h>
00098 #include <fs/phatio.h>
00099 #include <fs/phatutil.h>
00100 #include <fs/phatdir.h>
00101 
00102 #include <stdlib.h>
00103 #include <errno.h>
00104 #include <string.h>
00105 #include <fcntl.h>
00106 
00107 #if 0
00108 /* Use for local debugging. */
00109 #define NUTDEBUG
00110 #include <stdio.h>
00111 #include <fs/phatdbg.h>
00112 #endif
00113 
00114 #ifndef SEEK_SET
00115 #  define SEEK_SET        0     /* Seek from beginning of file.  */
00116 #  define SEEK_CUR        1     /* Seek from current position.  */
00117 #  define SEEK_END        2     /* Set file pointer to EOF plus "offset" */
00118 #endif
00119 
00124 
00135 static u_long SearchFreeCluster(NUTDEVICE * dev, u_long first, u_long last)
00136 {
00137     int rc = -1;
00138     u_long clust;
00139     u_long link = 1;
00140     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00141 
00142     if (vol->vol_type == 32) {
00143         for (clust = first; clust < last; clust++) {
00144             if ((rc = Phat32GetClusterLink(dev, clust, &link)) < 0 || link == 0) {
00145                 break;
00146             }
00147         }
00148     } else if (vol->vol_type == 16) {
00149         for (clust = first; clust < last; clust++) {
00150             if ((rc = Phat16GetClusterLink(dev, clust, &link)) < 0 || link == 0) {
00151                 break;
00152             }
00153         }
00154     } else {
00155         for (clust = first; clust < last; clust++) {
00156             if ((rc = Phat12GetClusterLink(dev, clust, &link)) < 0 || link == 0) {
00157                 break;
00158             }
00159         }
00160     }
00161 
00162     if (rc || link) {
00163         return 0;
00164     }
00165     return clust;
00166 }
00167 
00176 static u_long AllocCluster(NUTDEVICE * dev)
00177 {
00178     u_long clust;
00179     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00180 
00181     /*
00182      * If the hint for the next free cluster is invalid, start from the beginning,
00183      */
00184     if (vol->vol_nxtfree < 2 || vol->vol_nxtfree >= vol->vol_last_clust) {
00185         vol->vol_nxtfree = 2;
00186     }
00187     if ((clust = SearchFreeCluster(dev, vol->vol_nxtfree, vol->vol_last_clust)) < 2) {
00188         if ((clust = SearchFreeCluster(dev, 2, vol->vol_nxtfree)) < 2) {
00189             vol->vol_nxtfree = 0;
00190             errno = ENOSPC;
00191             return 0;
00192         }
00193     }
00194     vol->vol_nxtfree = clust;
00195 
00196     return clust;
00197 }
00198 
00207 u_long AllocFirstCluster(NUTFILE * nfp)
00208 {
00209     u_long clust;
00210     NUTDEVICE *dev = nfp->nf_dev;
00211     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00212     PHATFILE *fcb = nfp->nf_fcb;
00213 
00214     if ((clust = AllocCluster(dev)) < 2) {
00215         return 0;
00216     }
00217 
00218     /* Set the pointer to the first cluster in out directory entry. */
00219     fcb->f_dirent.dent_clusthi = (u_short) (clust >> 16);
00220     fcb->f_dirent.dent_clust = (u_short) clust;
00221     fcb->f_de_dirty = 1;
00222 
00223     /* The first cluster entry will be set to EOC. */
00224     if (vol->vol_type == 32) {
00225         if (Phat32SetClusterLink(dev, clust, PHAT32CMASK)) {
00226             return 0;
00227         }
00228     } else if (vol->vol_type == 16) {
00229         if (Phat16SetClusterLink(dev, clust, PHAT16CMASK)) {
00230             return 0;
00231         }
00232     } else if (Phat12SetClusterLink(dev, clust, PHAT12CMASK)) {
00233         return 0;
00234     }
00235     vol->vol_numfree--;
00236 
00237     return clust;
00238 }
00239 
00248 static u_long AllocNextCluster(NUTFILE * nfp)
00249 {
00250     u_long clust;
00251     NUTDEVICE *dev = nfp->nf_dev;
00252     PHATFILE *fcb = nfp->nf_fcb;
00253     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00254 
00255     /* Allocate a free cluster. */
00256     if ((clust = AllocCluster(dev)) < 2) {
00257         return 0;
00258     }
00259 
00260     /* Link the previous cluster to the new one and set
00261      * the entry of the new one to EOC.
00262      */
00263     if (vol->vol_type == 32) {
00264         if (Phat32SetClusterLink(dev, fcb->f_clust, clust)) {
00265             return 0;
00266         }
00267         if (Phat32SetClusterLink(dev, clust, PHAT32CMASK)) {
00268             return 0;
00269         }
00270     } else if (vol->vol_type == 16) {
00271         if (Phat16SetClusterLink(dev, fcb->f_clust, clust)) {
00272             return 0;
00273         }
00274         if (Phat16SetClusterLink(dev, clust, PHAT16CMASK)) {
00275             return 0;
00276         }
00277     } else if (Phat12SetClusterLink(dev, fcb->f_clust, clust)) {
00278         return 0;
00279     } else if (Phat12SetClusterLink(dev, clust, PHAT12CMASK)) {
00280         return 0;
00281     }
00282     vol->vol_numfree--;
00283 
00284     return clust;
00285 }
00286 
00294 static int PhatFileFlush(NUTFILE * nfp)
00295 {
00296     int rc;
00297     NUTDEVICE *dev = nfp->nf_dev;
00298     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00299 
00300     /* Update the file's directory entry. */
00301     if ((rc = PhatDirEntryUpdate(nfp)) == 0) {
00302         /* Gain mutex access. */
00303         NutEventWait(&vol->vol_iomutex, 0);
00304         /* Flush sector buffers. */
00305         rc = PhatSectorFlush(nfp->nf_dev, -1);
00306         /* Release mutex access. */
00307         NutEventPost(&vol->vol_iomutex);
00308     }
00309     return rc;
00310 }
00311 
00319 int PhatFileClose(NUTFILE * nfp)
00320 {
00321     int rc;
00322 
00323     if (nfp == NULL || nfp == NUTFILE_EOF) {
00324         errno = EBADF;
00325         return -1;
00326     }
00327 #ifdef NUTDEBUG
00328     PhatDbgFileInfo(stdout, "Close file", (PHATFILE *) nfp->nf_fcb);
00329 #endif
00330     rc = PhatFileFlush(nfp);
00331     if (nfp->nf_fcb) {
00332         free(nfp->nf_fcb);
00333     }
00334     free(nfp);
00335 
00336     return rc;
00337 }
00338 
00355 NUTFILE *PhatFileOpen(NUTDEVICE * dev, CONST char *path, int mode, int acc)
00356 {
00357     NUTFILE *nfp = NUTFILE_EOF;
00358     NUTFILE *ndp = NUTFILE_EOF;
00359     PHATFILE *ffcb;
00360     PHATFILE *dfcb;
00361     PHATFIND *srch;
00362     CONST char *fname;
00363 
00364     /* Open the parent directory and return the basename. */
00365     if ((ndp = PhatDirOpenParent(dev, path, &fname)) == NUTFILE_EOF) {
00366         return NUTFILE_EOF;
00367     }
00368 
00369     /*
00370      * We successfully opened the directory. If no file name had been specified,
00371      * then the caller wants to open the directory itself. In this case, simply
00372      * return the NUTFILE for it.
00373      */
00374     dfcb = ndp->nf_fcb;
00375     if (*fname == 0) {
00376         dfcb->f_mode = mode;
00377         return ndp;
00378     }
00379 
00380     /*
00381      * Allocate a file information and a temporary search structure.
00382      */
00383     nfp = malloc(sizeof(NUTFILE));
00384     ffcb = malloc(sizeof(PHATFILE));
00385     srch = malloc(sizeof(PHATFIND));
00386     if (nfp == NULL || ffcb == NULL || srch == NULL) {
00387         PhatFileClose(ndp);
00388         if (nfp) {
00389             free(nfp);
00390         }
00391         if (ffcb) {
00392             free(ffcb);
00393         }
00394         if (srch) {
00395             free(srch);
00396         }
00397         return NUTFILE_EOF;
00398     }
00399 
00400     memset(ffcb, 0, sizeof(PHATFILE));
00401     nfp->nf_next = 0;
00402     nfp->nf_dev = dev;
00403     nfp->nf_fcb = ffcb;
00404 
00405     /*
00406      * Check if the specified file already exists.
00407      *
00408      * Note, that directories are handled differently in PhatDirCreate(),
00409      * where the first cluster is initialized with zeros.
00410      */
00411     if (PhatDirEntryFind(ndp, fname, PHAT_FATTR_FILEMASK, srch)) {
00412         /* 
00413          * File doesn't exist. Does the opening mode allow to create 
00414          * a new file? 
00415          */
00416         if ((mode & _O_CREAT) == 0) {
00417             free(srch);
00418             PhatFileClose(ndp);
00419             PhatFileClose(nfp);
00420             errno = ENOENT;
00421             return NUTFILE_EOF;
00422         }
00423         /* Create a new directory entry. */
00424         if (PhatDirEntryCreate(ndp, fname, acc, &ffcb->f_dirent)) {
00425             free(srch);
00426             PhatFileClose(ndp);
00427             PhatFileClose(nfp);
00428             return NUTFILE_EOF;
00429         }
00430         ffcb->f_de_dirty = 1;
00431 #ifdef NUTDEBUG
00432         PhatDbgFileInfo(stdout, "New entry", ffcb);
00433 #endif
00434     } else {
00435         /*
00436          * We return an error, if the file exists and _O_EXCL has been
00437          * set with _O_CREAT.
00438          */
00439         if ((mode & (_O_CREAT | _O_EXCL)) == (_O_CREAT | _O_EXCL)) {
00440             free(srch);
00441             PhatFileClose(ndp);
00442             PhatFileClose(nfp);
00443             errno = EEXIST;
00444             return NUTFILE_EOF;
00445         }
00446 #ifdef NUTDEBUG
00447         PhatDbgFileInfo(stdout, "Existing entry", ffcb);
00448 #endif
00449         /*
00450          * Truncate an existing file.
00451          */
00452         if (mode & _O_TRUNC) {
00453             /*
00454              * Relase all clusters allocated by this entry.
00455              */
00456             if (PhatDirReleaseChain(dev, &srch->phfind_ent)) {
00457                 PhatFileClose(ndp);
00458                 PhatFileClose(nfp);
00459                 free(srch);
00460                 return NUTFILE_EOF;
00461             }
00462             memset(ffcb, 0, sizeof(PHATFILE));
00463             memcpy(ffcb->f_dirent.dent_name, srch->phfind_ent.dent_name, sizeof(ffcb->f_dirent.dent_name));
00464             ffcb->f_dirent.dent_attr = srch->phfind_ent.dent_attr;
00465             ffcb->f_dirent.dent_rsvdnt = srch->phfind_ent.dent_rsvdnt;
00466             ffcb->f_dirent.dent_ctsecs = srch->phfind_ent.dent_ctsecs;
00467             ffcb->f_dirent.dent_ctime = srch->phfind_ent.dent_ctime;
00468             ffcb->f_dirent.dent_cdate = srch->phfind_ent.dent_cdate;
00469             ffcb->f_de_dirty = 1;
00470         }
00471         else {
00472             ffcb->f_dirent = srch->phfind_ent;
00473             /*
00474              * Append to an existing file.
00475              */
00476             if ((mode & _O_APPEND) != 0 && ffcb->f_dirent.dent_fsize) {
00477                 if (PhatFilePosSet(nfp, ffcb->f_dirent.dent_fsize)) {
00478                     PhatFileClose(ndp);
00479                     PhatFileClose(nfp);
00480                     free(srch);
00481                     return NUTFILE_EOF;
00482                 }
00483             }
00484         }
00485     }
00486     free(srch);
00487 
00488     /* Store position of our directory entry. */
00489     ffcb->f_de_sect = PhatClusterSector(ndp, dfcb->f_clust) + dfcb->f_clust_pos;
00490     ffcb->f_de_offs = dfcb->f_sect_pos - 32;
00491     /* Store first cluster of parent. */
00492     ffcb->f_pde_clusthi = dfcb->f_dirent.dent_clusthi;
00493     ffcb->f_pde_clust = dfcb->f_dirent.dent_clust;
00494     /* Set the current cluster. */
00495     ffcb->f_clust = ffcb->f_dirent.dent_clusthi;
00496     ffcb->f_clust <<= 16;
00497     ffcb->f_clust += ffcb->f_dirent.dent_clust;
00498     /* Store the opening mode. */
00499     ffcb->f_mode = mode;
00500 
00501     /* Close the directory. */
00502     PhatFileClose(ndp);
00503 
00504 #ifdef NUTDEBUG
00505     PhatDbgFileInfo(stdout, "File opened", ffcb);
00506 #endif
00507     return nfp;
00508 }
00509 
00522 int PhatFileWrite(NUTFILE * nfp, CONST void *buffer, int len)
00523 {
00524     int rc;
00525     int step;
00526     u_long clust;
00527     int sbn;
00528     u_char *buf = (u_char *) buffer;
00529     NUTDEVICE *dev = nfp->nf_dev;
00530     PHATFILE *fcb = nfp->nf_fcb;
00531     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00532 
00533     /*
00534      * Refuse to write to files with RDONLY attribute set.
00535      */
00536     if (fcb->f_dirent.dent_attr & PHAT_FATTR_RDONLY) {
00537         errno = EACCES;
00538         return -1;
00539     }
00540 
00541     /*
00542      * Flush file if buffer is a NULL pointer.
00543      */
00544     if (buf == NULL || len == 0) {
00545         return PhatFileFlush(nfp);
00546     }
00547 
00548     /*
00549      * In case of normal files, check for sufficient space.
00550      */
00551     if ((fcb->f_dirent.dent_attr & PHAT_FATTR_DIR) == 0) {
00552         /* Bytes per cluster. */
00553         u_long num = vol->vol_sectsz * vol->vol_clustsz;
00554         /* Number of clusters already used. */
00555         u_long cur = (fcb->f_dirent.dent_fsize + num - 1) / num;
00556 
00557         /* Number of clusters used after writing. */
00558         num = (fcb->f_pos + len + num - 1) / num;
00559         /* If additional clusters are required, are they available? */
00560         if (num > cur && num - cur > vol->vol_numfree) {
00561             errno = ENOSPC;
00562             return -1;
00563         }
00564 
00565         /* If the file is empty, allocate the first cluster. */
00566         if (fcb->f_dirent.dent_fsize == 0) {
00567             if ((clust = AllocFirstCluster(nfp)) < 2) {
00568                 return -1;
00569             }
00570             fcb->f_clust_prv = clust;
00571             fcb->f_clust = clust;
00572         }
00573     }
00574 
00575 
00576     /*
00577      * Write the data.
00578      */
00579     for (rc = 0, step = 0; rc < len; rc += step) {
00580         /* Did we reach the end of a sector? */
00581         if (fcb->f_sect_pos >= vol->vol_sectsz) {
00582             /* Move to the next sector within the cluster. */
00583             if (IsFixedRootDir(nfp)) {
00584                 if (fcb->f_clust_pos + 1 >= vol->vol_rootsz) {
00585                     /* End of root directory, abort writing. */
00586                     break;
00587                 }
00588                 fcb->f_clust_pos++;
00589             }
00590             else {
00591                 /* Did we reach the last sector of this cluster? */
00592                 if (fcb->f_clust_pos  + 1 >= vol->vol_clustsz) {
00593                     /* Move to the next cluster. */
00594                     if (vol->vol_type == 32) {
00595                         if (Phat32GetClusterLink(dev, fcb->f_clust, &clust)) {
00596                             rc = -1;
00597                             break;
00598                         }
00599                         if (clust >= (PHATEOC & PHAT32CMASK)) {
00600                             if ((clust = AllocNextCluster(nfp)) < 2) {
00601                                 rc = -1;
00602                                 break;
00603                             }
00604                         }
00605                     } else if (vol->vol_type == 16) {
00606                         if (Phat16GetClusterLink(dev, fcb->f_clust, &clust)) {
00607                             rc = -1;
00608                             break;
00609                         }
00610                         if (clust >= (PHATEOC & PHAT16CMASK)) {
00611                             if ((clust = AllocNextCluster(nfp)) < 2) {
00612                                 rc = -1;
00613                                 break;
00614                             }
00615                         }
00616                     } else if (Phat12GetClusterLink(dev, fcb->f_clust, &clust)) {
00617                         rc = -1;
00618                         break;
00619                     } else if (clust >= (PHATEOC & PHAT12CMASK)) {
00620                         if ((clust = AllocNextCluster(nfp)) < 2) {
00621                             rc = -1;
00622                             break;
00623                         }
00624                     }
00625                     fcb->f_clust_pos = 0;
00626                     fcb->f_clust_prv = fcb->f_clust;
00627                     fcb->f_clust = clust;
00628                 }
00629                 else {
00630                     fcb->f_clust_pos++;
00631                 }
00632             }
00633             fcb->f_sect_pos = 0;
00634         }
00635 
00636         /* Load the sector we want to write to. */
00637         if ((sbn = PhatSectorLoad(nfp->nf_dev, PhatClusterSector(nfp, fcb->f_clust) + fcb->f_clust_pos)) < 0) {
00638             rc = -1;
00639             break;
00640         }
00641         /* The number of bytes we write to this sector. */
00642         step = (int) (vol->vol_sectsz - fcb->f_sect_pos);
00643         if (step > len - rc) {
00644             step = len - rc;
00645         }
00646         /* Copy data to this sector. */
00647         memcpy(&vol->vol_buf[sbn].sect_data[fcb->f_sect_pos], &buf[rc], step);
00648         vol->vol_buf[sbn].sect_dirty = 1;
00649         /* Advance file pointers. */
00650         fcb->f_pos += step;
00651         fcb->f_sect_pos += step;
00652     }
00653 
00654     if (rc > 0) {
00655         /*
00656          * Update directory entry. Note that directory entries of directories
00657          * are never updated in a PHAT file system.
00658          */
00659         if ((fcb->f_dirent.dent_attr & PHAT_FATTR_DIR) == 0) {
00660             GetDosTimeStamp(&fcb->f_dirent.dent_mtime, &fcb->f_dirent.dent_mdate);
00661             fcb->f_dirent.dent_adate = fcb->f_dirent.dent_mdate;
00662             fcb->f_dirent.dent_attr |= PHAT_FATTR_ARCHIV;
00663             if(fcb->f_dirent.dent_fsize < fcb->f_pos) {
00664                 fcb->f_dirent.dent_fsize = fcb->f_pos;
00665             }
00666             fcb->f_de_dirty = 1;
00667         }
00668     }
00669     return rc;
00670 }
00671 
00672 #ifdef __HARVARD_ARCH__
00673 
00690 int PhatFileWrite_P(NUTFILE * nfp, PGM_P buffer, int len)
00691 {
00692     return -1;
00693 }
00694 #endif
00695 
00707 int PhatFileRead(NUTFILE * nfp, void *buffer, int size)
00708 {
00709     int rc;
00710     int step;
00711     int sbn;
00712     u_char *buf = (u_char *) buffer;
00713     NUTDEVICE *dev = nfp->nf_dev;
00714     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00715     PHATFILE *fcb = nfp->nf_fcb;
00716 
00717     /*
00718      * Ignore input flush.
00719      */
00720     if (buf == NULL || size == 0) {
00721         return 0;
00722     }
00723 
00724     /* Respect the end of normal files. */
00725     if ((fcb->f_dirent.dent_attr & PHAT_FATTR_DIR) == 0) {
00726         if (fcb->f_pos + size >= fcb->f_dirent.dent_fsize) {
00727             size = fcb->f_dirent.dent_fsize - fcb->f_pos;
00728         }
00729     }
00730     for (rc = 0, step = 0; rc < size; rc += step) {
00731         /* Did we reach the end of a sector? */
00732         if (fcb->f_sect_pos >= vol->vol_sectsz) {
00733             /* Move to the next sector. */
00734             if (IsFixedRootDir(nfp)) {
00735                 if (fcb->f_clust_pos + 1 >= vol->vol_rootsz) {
00736                     /* End of root directory, abort reading. */
00737                     break;
00738                 }
00739                 fcb->f_clust_pos++;
00740             }
00741             else {
00742                 /* Did we reach the last sector of this cluster? */
00743                 if (fcb->f_clust_pos + 1 >= vol->vol_clustsz) {
00744                     /* Move to the next cluster. */
00745                     u_long clust;
00746 
00747                     if (vol->vol_type == 32) {
00748                         if (Phat32GetClusterLink(dev, fcb->f_clust, &clust)) {
00749                             break;
00750                         }
00751                         if (clust >= (PHATEOC & PHAT32CMASK)) {
00752                             break;
00753                         }
00754                     } else if (vol->vol_type == 16) {
00755                         if (Phat16GetClusterLink(dev, fcb->f_clust, &clust)) {
00756                             break;
00757                         }
00758                         if (clust >= (PHATEOC & PHAT16CMASK)) {
00759                             break;
00760                         }
00761                     } else if (Phat12GetClusterLink(dev, fcb->f_clust, &clust)) {
00762                         break;
00763                     }
00764                     else if (clust >= (PHATEOC & PHAT12CMASK)) {
00765                         break;
00766                     }
00767                     fcb->f_clust_pos = 0;
00768                     fcb->f_clust_prv = fcb->f_clust;
00769                     fcb->f_clust = clust;
00770                 }
00771                 else {
00772                     fcb->f_clust_pos++;
00773                 }
00774             }
00775             fcb->f_sect_pos = 0;
00776         }
00777 
00778         /* Make sure that the required sector is loaded. */
00779         if ((sbn = PhatSectorLoad(nfp->nf_dev, PhatClusterSector(nfp, fcb->f_clust) + fcb->f_clust_pos)) < 0) {
00780             rc = -1;
00781             break;
00782         }
00783         step = (int) (vol->vol_sectsz - fcb->f_sect_pos);
00784         if (step > size - rc) {
00785             step = size - rc;
00786         }
00787         memcpy(&buf[rc], &vol->vol_buf[sbn].sect_data[fcb->f_sect_pos], step);
00788         fcb->f_pos += step;
00789         fcb->f_sect_pos += step;
00790     }
00791     return rc;
00792 }
00793 
00805 static long PhatFileSize(NUTFILE *nfp)
00806 {
00807     PHATFILE *fcb = nfp->nf_fcb;
00808 
00809     return fcb->f_dirent.dent_fsize;
00810 }
00811 
00812 static int PhatFileSeek(NUTFILE * nfp, long *pos, int whence)
00813 {
00814     int rc = 0;
00815     long npos = *pos;
00816     PHATFILE *fcb = nfp->nf_fcb;
00817 
00818     switch (whence) {
00819     case SEEK_CUR:
00820         npos += fcb->f_pos;
00821         break;
00822     case SEEK_END:
00823         npos += PhatFileSize(nfp);
00824         break;
00825     }
00826 
00827     if (npos < 0 || npos > PhatFileSize(nfp)) {
00828         rc = EINVAL;
00829     } else {
00830         rc = PhatFilePosSet(nfp, npos);
00831         *pos = fcb->f_pos;
00832     }
00833     return rc;
00834 }
00835 
00840 static int PhatIOCtl(NUTDEVICE * dev, int req, void *conf)
00841 {
00842     int rc = -1;
00843 
00844     switch (req) {
00845     case FS_STATUS:
00846         {
00847             FSCP_STATUS *par = (FSCP_STATUS *) conf;
00848 
00849             rc = PhatDirEntryStatus(dev, par->par_path, par->par_stp);
00850         }
00851         break;
00852     case FS_DIR_CREATE:
00853         rc = PhatDirCreate(dev, (char *) conf);
00854         break;
00855     case FS_DIR_REMOVE:
00856         rc = PhatDirRemove(dev, (char *) conf);
00857         break;
00858     case FS_DIR_OPEN:
00859         /* Open a directory for reading entries. */
00860         {
00861             DIR *dir = (DIR *) conf;
00862 
00863             if ((dir->dd_fd = PhatDirOpen(dev, dir->dd_buf)) != NUTFILE_EOF) {
00864                 rc = 0;
00865             }
00866         }
00867         break;
00868     case FS_DIR_CLOSE:
00869         rc = PhatFileClose(((DIR *) conf)->dd_fd);
00870         break;
00871     case FS_DIR_READ:
00872         rc = PhatDirRead((DIR *) conf);
00873         break;
00874     case FS_FILE_STATUS:
00875         /* TODO */
00876         break;
00877     case FS_FILE_DELETE:
00878         rc = PhatDirDelEntry(dev, (char *) conf, PHAT_FATTR_FILEMASK & ~PHAT_FATTR_DIR);
00879         break;
00880     case FS_FILE_SEEK:
00881         PhatFileSeek((NUTFILE *) ((IOCTL_ARG3 *) conf)->arg1,  /* */
00882                      (long *) ((IOCTL_ARG3 *) conf)->arg2,      /* */
00883                      (int) ((IOCTL_ARG3 *) conf)->arg3);
00884         break;
00885     case FS_RENAME:
00886         /* Rename an existing file or directory. */
00887         {
00888             FSCP_RENAME *par = (FSCP_RENAME *) conf;
00889 
00890             rc = PhatDirRenameEntry(dev, par->par_old, par->par_new);
00891         }
00892         break;
00893 
00894     case FS_VOL_MOUNT:
00895         {
00896             /* Mount a volume. */
00897             FSCP_VOL_MOUNT *par = (FSCP_VOL_MOUNT *) conf;
00898 
00899             rc = PhatVolMount(dev, par->fscp_bmnt, par->fscp_part_type);
00900             if (rc) {
00901                 /* Release resources on failures. */
00902                 PhatVolUnmount(dev);
00903             }
00904         }
00905         break;
00906     case FS_VOL_UNMOUNT:
00907         /* Unmount a volume. */
00908         rc = PhatVolUnmount(dev);
00909         break;
00910     }
00911     return rc;
00912 }
00913 
00923 static int PhatInit(NUTDEVICE * dev)
00924 {
00925     /* Nothing to do. */
00926     return 0;
00927 }
00928 
00932 static NUTFILE *PhatApiFileOpen(NUTDEVICE * dev, CONST char *path, int mode, int acc)
00933 {
00934     NUTFILE *rc;
00935     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00936 
00937     /* Lock filesystem access. */
00938     NutEventWait(&vol->vol_fsmutex, 0);
00939     /* Call worker routine. */
00940     rc = PhatFileOpen(dev, path, mode, acc);
00941     /* Release filesystem lock. */
00942     NutEventPost(&vol->vol_fsmutex);
00943 
00944     return rc;
00945 }
00946 
00950 static int PhatApiFileClose(NUTFILE * nfp)
00951 {
00952     int rc;
00953     NUTDEVICE *dev = nfp->nf_dev;
00954     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00955 
00956     /* Lock filesystem access. */
00957     NutEventWait(&vol->vol_fsmutex, 0);
00958     /* Call worker routine. */
00959     rc = PhatFileClose(nfp);
00960     /* Release filesystem lock. */
00961     NutEventPost(&vol->vol_fsmutex);
00962 
00963     return rc;
00964 }
00965 
00969 static int PhatApiFileWrite(NUTFILE * nfp, CONST void *buffer, int len)
00970 {
00971     int rc;
00972     NUTDEVICE *dev = nfp->nf_dev;
00973     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00974 
00975     /* Lock filesystem access. */
00976     NutEventWait(&vol->vol_fsmutex, 0);
00977     /* Call worker routine. */
00978     rc = PhatFileWrite(nfp, buffer, len);
00979     /* Release filesystem lock. */
00980     NutEventPost(&vol->vol_fsmutex);
00981 
00982     return rc;
00983 }
00984 
00985 #ifdef __HARVARD_ARCH__
00986 
00989 static int PhatApiFileWrite_P(NUTFILE * nfp, PGM_P buffer, int len)
00990 {
00991     int rc;
00992     NUTDEVICE *dev = nfp->nf_dev;
00993     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00994 
00995     /* Lock filesystem access. */
00996     NutEventWait(&vol->vol_fsmutex, 0);
00997     /* Call worker routine. */
00998     rc = PhatFileWrite_P(nfp, buffer, len);
00999     /* Release filesystem lock. */
01000     NutEventPost(&vol->vol_fsmutex);
01001 
01002     return rc;
01003 }
01004 #endif
01005 
01009 static int PhatApiFileRead(NUTFILE * nfp, void *buffer, int size)
01010 {
01011     int rc;
01012     NUTDEVICE *dev = nfp->nf_dev;
01013     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
01014 
01015     /* Lock filesystem access. */
01016     NutEventWait(&vol->vol_fsmutex, 0);
01017     /* Call worker routine. */
01018     rc = PhatFileRead(nfp, buffer, size);
01019     /* Release filesystem lock. */
01020     NutEventPost(&vol->vol_fsmutex);
01021 
01022     return rc;
01023 }
01024 
01028 static int PhatApiIOCtl(NUTDEVICE * dev, int req, void *conf)
01029 {
01030     int rc;
01031     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
01032 
01033     /* Lock filesystem access. */
01034     if (req != FS_VOL_MOUNT && vol) {
01035         NutEventWait(&vol->vol_fsmutex, 0);
01036     }
01037     /* Call worker routine. */
01038     rc = PhatIOCtl(dev, req, conf);
01039     /* Release filesystem lock. */
01040     if (req != FS_VOL_MOUNT && req != FS_VOL_UNMOUNT && vol) {
01041         NutEventPost(&vol->vol_fsmutex);
01042     }
01043     return rc;
01044 }
01045 
01058 NUTDEVICE devPhat0 = {
01059     0,                          
01060     {'P', 'H', 'A', 'T', '0', 0, 0, 0, 0}
01061     ,                           
01062     IFTYP_FS,                   
01063     0,                          
01064     0,                          
01065     0,                          
01066     0,                          
01067     PhatInit,                   
01068     PhatApiIOCtl,               
01069     PhatApiFileRead,            
01070     PhatApiFileWrite,           
01071 #ifdef __HARVARD_ARCH__
01072     PhatApiFileWrite_P,         
01073 #endif
01074     PhatApiFileOpen,            
01075     PhatApiFileClose,           
01076     PhatFileSize                
01077 };
01078 
01079 NUTDEVICE devPhat1 = {
01080     0,                          
01081     {'P', 'H', 'A', 'T', '1', 0, 0, 0, 0}
01082     ,                           
01083     IFTYP_FS,                   
01084     0,                          
01085     0,                          
01086     0,                          
01087     0,                          
01088     PhatInit,                   
01089     PhatApiIOCtl,               
01090     PhatApiFileRead,            
01091     PhatApiFileWrite,           
01092 #ifdef __HARVARD_ARCH__
01093     PhatApiFileWrite_P,         
01094 #endif
01095     PhatApiFileOpen,            
01096     PhatApiFileClose,           
01097     PhatFileSize                
01098 };
01099 

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