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

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