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 
00101 #include <fs/fs.h>
00102 
00103 #include <dirent.h>
00104 
00105 #include <dev/blockdev.h>
00106 
00107 #include <sys/event.h>
00108 
00109 #include <fs/phatfs.h>
00110 #include <fs/phatvol.h>
00111 #include <fs/phatio.h>
00112 #include <fs/phatutil.h>
00113 #include <fs/phatdir.h>
00114 
00115 #include <stdlib.h>
00116 #include <errno.h>
00117 #include <string.h>
00118 #include <fcntl.h>
00119 
00120 #if 0
00121 /* Use for local debugging. */
00122 #define NUTDEBUG
00123 #include <stdio.h>
00124 #include <fs/phatdbg.h>
00125 #endif
00126 
00127 #ifndef SEEK_SET
00128 #  define SEEK_SET        0     /* Seek from beginning of file.  */
00129 #  define SEEK_CUR        1     /* Seek from current position.  */
00130 #  define SEEK_END        2     /* Set file pointer to EOF plus "offset" */
00131 #endif
00132 
00137 
00148 static uint32_t SearchFreeCluster(NUTDEVICE * dev, uint32_t first, uint32_t last)
00149 {
00150     int rc = -1;
00151     uint32_t clust;
00152     uint32_t link = 1;
00153     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00154 
00155     if (vol->vol_type == 32) {
00156         for (clust = first; clust < last; clust++) {
00157             if ((rc = Phat32GetClusterLink(dev, clust, &link)) < 0 || link == 0) {
00158                 break;
00159             }
00160         }
00161     } else if (vol->vol_type == 16) {
00162         for (clust = first; clust < last; clust++) {
00163             if ((rc = Phat16GetClusterLink(dev, clust, &link)) < 0 || link == 0) {
00164                 break;
00165             }
00166         }
00167     } else {
00168         for (clust = first; clust < last; clust++) {
00169             if ((rc = Phat12GetClusterLink(dev, clust, &link)) < 0 || link == 0) {
00170                 break;
00171             }
00172         }
00173     }
00174 
00175     if (rc || link) {
00176         return 0;
00177     }
00178     return clust;
00179 }
00180 
00189 static uint32_t AllocCluster(NUTDEVICE * dev)
00190 {
00191     uint32_t clust;
00192     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00193 
00194     /*
00195      * If the hint for the next free cluster is invalid, start from the beginning,
00196      */
00197     if (vol->vol_nxtfree < 2 || vol->vol_nxtfree >= vol->vol_last_clust) {
00198         vol->vol_nxtfree = 2;
00199     }
00200     if ((clust = SearchFreeCluster(dev, vol->vol_nxtfree, vol->vol_last_clust)) < 2) {
00201         if ((clust = SearchFreeCluster(dev, 2, vol->vol_nxtfree)) < 2) {
00202             vol->vol_nxtfree = 0;
00203             errno = ENOSPC;
00204             return 0;
00205         }
00206     }
00207     vol->vol_nxtfree = clust;
00208 
00209     return clust;
00210 }
00211 
00220 uint32_t AllocFirstCluster(NUTFILE * nfp)
00221 {
00222     uint32_t clust;
00223     NUTDEVICE *dev = nfp->nf_dev;
00224     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00225     PHATFILE *fcb = nfp->nf_fcb;
00226 
00227     if ((clust = AllocCluster(dev)) < 2) {
00228         return 0;
00229     }
00230 
00231     /* Set the pointer to the first cluster in out directory entry. */
00232     fcb->f_dirent.dent_clusthi = (uint16_t) (clust >> 16);
00233     fcb->f_dirent.dent_clust = (uint16_t) clust;
00234     fcb->f_de_dirty = 1;
00235 
00236     /* The first cluster entry will be set to EOC. */
00237     if (vol->vol_type == 32) {
00238         if (Phat32SetClusterLink(dev, clust, PHAT32CMASK)) {
00239             return 0;
00240         }
00241     } else if (vol->vol_type == 16) {
00242         if (Phat16SetClusterLink(dev, clust, PHAT16CMASK)) {
00243             return 0;
00244         }
00245     } else if (Phat12SetClusterLink(dev, clust, PHAT12CMASK)) {
00246         return 0;
00247     }
00248     vol->vol_numfree--;
00249 
00250     return clust;
00251 }
00252 
00261 static uint32_t AllocNextCluster(NUTFILE * nfp)
00262 {
00263     uint32_t clust;
00264     NUTDEVICE *dev = nfp->nf_dev;
00265     PHATFILE *fcb = nfp->nf_fcb;
00266     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00267 
00268     /* Allocate a free cluster. */
00269     if ((clust = AllocCluster(dev)) < 2) {
00270         return 0;
00271     }
00272 
00273     /* Link the previous cluster to the new one and set
00274      * the entry of the new one to EOC.
00275      */
00276     if (vol->vol_type == 32) {
00277         if (Phat32SetClusterLink(dev, fcb->f_clust, clust)) {
00278             return 0;
00279         }
00280         if (Phat32SetClusterLink(dev, clust, PHAT32CMASK)) {
00281             return 0;
00282         }
00283     } else if (vol->vol_type == 16) {
00284         if (Phat16SetClusterLink(dev, fcb->f_clust, clust)) {
00285             return 0;
00286         }
00287         if (Phat16SetClusterLink(dev, clust, PHAT16CMASK)) {
00288             return 0;
00289         }
00290     } else if (Phat12SetClusterLink(dev, fcb->f_clust, clust)) {
00291         return 0;
00292     } else if (Phat12SetClusterLink(dev, clust, PHAT12CMASK)) {
00293         return 0;
00294     }
00295     vol->vol_numfree--;
00296 
00297     return clust;
00298 }
00299 
00307 static int PhatFileFlush(NUTFILE * nfp)
00308 {
00309     int rc;
00310     NUTDEVICE *dev = nfp->nf_dev;
00311     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00312 
00313     /* Update the file's directory entry. */
00314     if ((rc = PhatDirEntryUpdate(nfp)) == 0) {
00315         /* Gain mutex access. */
00316         NutEventWait(&vol->vol_iomutex, 0);
00317         /* Flush sector buffers. */
00318         rc = PhatSectorFlush(nfp->nf_dev, -1);
00319         /* Release mutex access. */
00320         NutEventPost(&vol->vol_iomutex);
00321     }
00322     return rc;
00323 }
00324 
00332 int PhatFileClose(NUTFILE * nfp)
00333 {
00334     int rc;
00335 
00336     if (nfp == NULL || nfp == NUTFILE_EOF) {
00337         errno = EBADF;
00338         return -1;
00339     }
00340 #ifdef NUTDEBUG
00341     PhatDbgFileInfo(stdout, "Close file", (PHATFILE *) nfp->nf_fcb);
00342 #endif
00343     rc = PhatFileFlush(nfp);
00344     if (nfp->nf_fcb) {
00345         free(nfp->nf_fcb);
00346     }
00347     free(nfp);
00348 
00349     return rc;
00350 }
00351 
00368 NUTFILE *PhatFileOpen(NUTDEVICE * dev, CONST char *path, int mode, int acc)
00369 {
00370     NUTFILE *nfp = NUTFILE_EOF;
00371     NUTFILE *ndp = NUTFILE_EOF;
00372     PHATFILE *ffcb;
00373     PHATFILE *dfcb;
00374     PHATFIND *srch;
00375     CONST char *fname;
00376 
00377     /* Open the parent directory and return the basename. */
00378     if ((ndp = PhatDirOpenParent(dev, path, &fname)) == NUTFILE_EOF) {
00379         return NUTFILE_EOF;
00380     }
00381 
00382     /*
00383      * We successfully opened the directory. If no file name had been specified,
00384      * then the caller wants to open the directory itself. In this case, simply
00385      * return the NUTFILE for it.
00386      */
00387     dfcb = ndp->nf_fcb;
00388     if (*fname == 0) {
00389         dfcb->f_mode = mode;
00390         return ndp;
00391     }
00392 
00393     /*
00394      * Allocate a file information and a temporary search structure.
00395      */
00396     nfp = malloc(sizeof(NUTFILE));
00397     ffcb = malloc(sizeof(PHATFILE));
00398     srch = malloc(sizeof(PHATFIND));
00399     if (nfp == NULL || ffcb == NULL || srch == NULL) {
00400         PhatFileClose(ndp);
00401         if (nfp) {
00402             free(nfp);
00403         }
00404         if (ffcb) {
00405             free(ffcb);
00406         }
00407         if (srch) {
00408             free(srch);
00409         }
00410         return NUTFILE_EOF;
00411     }
00412 
00413     memset(ffcb, 0, sizeof(PHATFILE));
00414     nfp->nf_next = 0;
00415     nfp->nf_dev = dev;
00416     nfp->nf_fcb = ffcb;
00417 
00418     /*
00419      * Check if the specified file already exists.
00420      *
00421      * Note, that directories are handled differently in PhatDirCreate(),
00422      * where the first cluster is initialized with zeros.
00423      */
00424     if (PhatDirEntryFind(ndp, fname, PHAT_FATTR_FILEMASK, srch)) {
00425         /* 
00426          * File doesn't exist. Does the opening mode allow to create 
00427          * a new file? 
00428          */
00429         if ((mode & _O_CREAT) == 0) {
00430             free(srch);
00431             PhatFileClose(ndp);
00432             PhatFileClose(nfp);
00433             errno = ENOENT;
00434             return NUTFILE_EOF;
00435         }
00436         /* Create a new directory entry. */
00437         if (PhatDirEntryCreate(ndp, fname, acc, &ffcb->f_dirent)) {
00438             free(srch);
00439             PhatFileClose(ndp);
00440             PhatFileClose(nfp);
00441             return NUTFILE_EOF;
00442         }
00443         ffcb->f_de_dirty = 1;
00444 #ifdef NUTDEBUG
00445         PhatDbgFileInfo(stdout, "New entry", ffcb);
00446 #endif
00447     } else {
00448         /*
00449          * We return an error, if the file exists and _O_EXCL has been
00450          * set with _O_CREAT.
00451          */
00452         if ((mode & (_O_CREAT | _O_EXCL)) == (_O_CREAT | _O_EXCL)) {
00453             free(srch);
00454             PhatFileClose(ndp);
00455             PhatFileClose(nfp);
00456             errno = EEXIST;
00457             return NUTFILE_EOF;
00458         }
00459 #ifdef NUTDEBUG
00460         PhatDbgFileInfo(stdout, "Existing entry", ffcb);
00461 #endif
00462         /*
00463          * Truncate an existing file.
00464          */
00465         if (mode & _O_TRUNC) {
00466             /*
00467              * Relase all clusters allocated by this entry.
00468              */
00469             if (PhatDirReleaseChain(dev, &srch->phfind_ent)) {
00470                 PhatFileClose(ndp);
00471                 PhatFileClose(nfp);
00472                 free(srch);
00473                 return NUTFILE_EOF;
00474             }
00475             memset(ffcb, 0, sizeof(PHATFILE));
00476             memcpy(ffcb->f_dirent.dent_name, srch->phfind_ent.dent_name, sizeof(ffcb->f_dirent.dent_name));
00477             ffcb->f_dirent.dent_attr = srch->phfind_ent.dent_attr;
00478             ffcb->f_dirent.dent_rsvdnt = srch->phfind_ent.dent_rsvdnt;
00479             ffcb->f_dirent.dent_ctsecs = srch->phfind_ent.dent_ctsecs;
00480             ffcb->f_dirent.dent_ctime = srch->phfind_ent.dent_ctime;
00481             ffcb->f_dirent.dent_cdate = srch->phfind_ent.dent_cdate;
00482             ffcb->f_de_dirty = 1;
00483         }
00484         else {
00485             ffcb->f_dirent = srch->phfind_ent;
00486         }
00487     }
00488     free(srch);
00489 
00490     /* Store position of our directory entry. */
00491     ffcb->f_de_sect = PhatClusterSector(ndp, dfcb->f_clust) + dfcb->f_clust_pos;
00492     ffcb->f_de_offs = dfcb->f_sect_pos - 32;
00493     /* Store first cluster of parent. */
00494     ffcb->f_pde_clusthi = dfcb->f_dirent.dent_clusthi;
00495     ffcb->f_pde_clust = dfcb->f_dirent.dent_clust;
00496     /* Set the current cluster. */
00497     ffcb->f_clust = ffcb->f_dirent.dent_clusthi;
00498     ffcb->f_clust <<= 16;
00499     ffcb->f_clust += ffcb->f_dirent.dent_clust;
00500     /* Store the opening mode. */
00501     ffcb->f_mode = mode;
00502 
00503     /* Close the directory. */
00504     PhatFileClose(ndp);
00505 
00506     /*
00507      * Append to an existing file.
00508      */
00509     if ((mode & _O_APPEND) != 0 && ffcb->f_dirent.dent_fsize) {
00510         if (PhatFilePosSet(nfp, ffcb->f_dirent.dent_fsize)) {
00511             PhatFileClose(nfp);
00512             return NUTFILE_EOF;
00513         }
00514     }
00515 
00516 #ifdef NUTDEBUG
00517     PhatDbgFileInfo(stdout, "File opened", ffcb);
00518 #endif
00519     return nfp;
00520 }
00521 
00534 int PhatFileWrite(NUTFILE * nfp, CONST void *buffer, int len)
00535 {
00536     int rc;
00537     int step;
00538     uint32_t clust;
00539     int sbn;
00540     uint8_t *buf = (uint8_t *) buffer;
00541     NUTDEVICE *dev = nfp->nf_dev;
00542     PHATFILE *fcb = nfp->nf_fcb;
00543     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00544 
00545     /*
00546      * Refuse to write to files with RDONLY attribute set.
00547      */
00548     if (fcb->f_dirent.dent_attr & PHAT_FATTR_RDONLY) {
00549         errno = EACCES;
00550         return -1;
00551     }
00552 
00553     /*
00554      * Flush file if buffer is a NULL pointer.
00555      */
00556     if (buf == NULL || len == 0) {
00557         return PhatFileFlush(nfp);
00558     }
00559 
00560     /*
00561      * In case of normal files, check for sufficient space.
00562      */
00563     if ((fcb->f_dirent.dent_attr & PHAT_FATTR_DIR) == 0) {
00564         /* Bytes per cluster. */
00565         uint32_t num = vol->vol_sectsz * vol->vol_clustsz;
00566         /* Number of clusters already used. */
00567         uint32_t cur = (fcb->f_dirent.dent_fsize + num - 1) / num;
00568 
00569         /* Number of clusters used after writing. */
00570         num = (fcb->f_pos + len + num - 1) / num;
00571         /* If additional clusters are required, are they available? */
00572         if (num > cur && num - cur > vol->vol_numfree) {
00573             errno = ENOSPC;
00574             return -1;
00575         }
00576 
00577         /* If the file is empty, allocate the first cluster. */
00578         if (fcb->f_dirent.dent_fsize == 0) {
00579             if ((clust = AllocFirstCluster(nfp)) < 2) {
00580                 return -1;
00581             }
00582             fcb->f_clust_prv = clust;
00583             fcb->f_clust = clust;
00584         }
00585     }
00586 
00587 
00588     /*
00589      * Write the data.
00590      */
00591     for (rc = 0, step = 0; rc < len; rc += step) {
00592         /* Did we reach the end of a sector? */
00593         if (fcb->f_sect_pos >= vol->vol_sectsz) {
00594             /* Move to the next sector within the cluster. */
00595             if (IsFixedRootDir(nfp)) {
00596                 if (fcb->f_clust_pos + 1 >= vol->vol_rootsz) {
00597                     /* End of root directory, abort writing. */
00598                     break;
00599                 }
00600                 fcb->f_clust_pos++;
00601             }
00602             else {
00603                 /* Did we reach the last sector of this cluster? */
00604                 if (fcb->f_clust_pos  + 1 >= vol->vol_clustsz) {
00605                     /* Move to the next cluster. */
00606                     if (vol->vol_type == 32) {
00607                         if (Phat32GetClusterLink(dev, fcb->f_clust, &clust)) {
00608                             rc = -1;
00609                             break;
00610                         }
00611                         if (clust >= (PHATEOC & PHAT32CMASK)) {
00612                             if ((clust = AllocNextCluster(nfp)) < 2) {
00613                                 rc = -1;
00614                                 break;
00615                             }
00616                         }
00617                     } else if (vol->vol_type == 16) {
00618                         if (Phat16GetClusterLink(dev, fcb->f_clust, &clust)) {
00619                             rc = -1;
00620                             break;
00621                         }
00622                         if (clust >= (PHATEOC & PHAT16CMASK)) {
00623                             if ((clust = AllocNextCluster(nfp)) < 2) {
00624                                 rc = -1;
00625                                 break;
00626                             }
00627                         }
00628                     } else if (Phat12GetClusterLink(dev, fcb->f_clust, &clust)) {
00629                         rc = -1;
00630                         break;
00631                     } else if (clust >= (PHATEOC & PHAT12CMASK)) {
00632                         if ((clust = AllocNextCluster(nfp)) < 2) {
00633                             rc = -1;
00634                             break;
00635                         }
00636                     }
00637                     fcb->f_clust_pos = 0;
00638                     fcb->f_clust_prv = fcb->f_clust;
00639                     fcb->f_clust = clust;
00640                 }
00641                 else {
00642                     fcb->f_clust_pos++;
00643                 }
00644             }
00645             fcb->f_sect_pos = 0;
00646         }
00647 
00648         /* Load the sector we want to write to. */
00649         if ((sbn = PhatSectorLoad(nfp->nf_dev, PhatClusterSector(nfp, fcb->f_clust) + fcb->f_clust_pos)) < 0) {
00650             rc = -1;
00651             break;
00652         }
00653         /* The number of bytes we write to this sector. */
00654         step = (int) (vol->vol_sectsz - fcb->f_sect_pos);
00655         if (step > len - rc) {
00656             step = len - rc;
00657         }
00658         /* Copy data to this sector. */
00659         memcpy(&vol->vol_buf[sbn].sect_data[fcb->f_sect_pos], &buf[rc], step);
00660         vol->vol_buf[sbn].sect_dirty = 1;
00661         /* Advance file pointers. */
00662         fcb->f_pos += step;
00663         fcb->f_sect_pos += step;
00664     }
00665 
00666     if (rc > 0) {
00667         /*
00668          * Update directory entry. Note that directory entries of directories
00669          * are never updated in a PHAT file system.
00670          */
00671         if ((fcb->f_dirent.dent_attr & PHAT_FATTR_DIR) == 0) {
00672             GetDosTimeStamp(&fcb->f_dirent.dent_mtime, &fcb->f_dirent.dent_mdate);
00673             fcb->f_dirent.dent_adate = fcb->f_dirent.dent_mdate;
00674             fcb->f_dirent.dent_attr |= PHAT_FATTR_ARCHIV;
00675             if(fcb->f_dirent.dent_fsize < fcb->f_pos) {
00676                 fcb->f_dirent.dent_fsize = fcb->f_pos;
00677             }
00678             fcb->f_de_dirty = 1;
00679         }
00680     }
00681     return rc;
00682 }
00683 
00684 #ifdef __HARVARD_ARCH__
00685 
00702 int PhatFileWrite_P(NUTFILE * nfp, PGM_P buffer, int len)
00703 {
00704     return -1;
00705 }
00706 #endif
00707 
00719 int PhatFileRead(NUTFILE * nfp, void *buffer, int size)
00720 {
00721     int rc;
00722     int step;
00723     int sbn;
00724     uint8_t *buf = (uint8_t *) buffer;
00725     NUTDEVICE *dev = nfp->nf_dev;
00726     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00727     PHATFILE *fcb = nfp->nf_fcb;
00728 
00729     /*
00730      * Ignore input flush.
00731      */
00732     if (buf == NULL || size == 0) {
00733         return 0;
00734     }
00735 
00736     /* Respect the end of normal files. */
00737     if ((fcb->f_dirent.dent_attr & PHAT_FATTR_DIR) == 0) {
00738         if (fcb->f_pos + size >= fcb->f_dirent.dent_fsize) {
00739             size = fcb->f_dirent.dent_fsize - fcb->f_pos;
00740         }
00741     }
00742     for (rc = 0, step = 0; rc < size; rc += step) {
00743         /* Did we reach the end of a sector? */
00744         if (fcb->f_sect_pos >= vol->vol_sectsz) {
00745             /* Move to the next sector. */
00746             if (IsFixedRootDir(nfp)) {
00747                 if (fcb->f_clust_pos + 1 >= vol->vol_rootsz) {
00748                     /* End of root directory, abort reading. */
00749                     break;
00750                 }
00751                 fcb->f_clust_pos++;
00752             }
00753             else {
00754                 /* Did we reach the last sector of this cluster? */
00755                 if (fcb->f_clust_pos + 1 >= vol->vol_clustsz) {
00756                     /* Move to the next cluster. */
00757                     uint32_t clust;
00758 
00759                     if (vol->vol_type == 32) {
00760                         if (Phat32GetClusterLink(dev, fcb->f_clust, &clust)) {
00761                             break;
00762                         }
00763                         if (clust >= (PHATEOC & PHAT32CMASK)) {
00764                             break;
00765                         }
00766                     } else if (vol->vol_type == 16) {
00767                         if (Phat16GetClusterLink(dev, fcb->f_clust, &clust)) {
00768                             break;
00769                         }
00770                         if (clust >= (PHATEOC & PHAT16CMASK)) {
00771                             break;
00772                         }
00773                     } else if (Phat12GetClusterLink(dev, fcb->f_clust, &clust)) {
00774                         break;
00775                     }
00776                     else if (clust >= (PHATEOC & PHAT12CMASK)) {
00777                         break;
00778                     }
00779                     fcb->f_clust_pos = 0;
00780                     fcb->f_clust_prv = fcb->f_clust;
00781                     fcb->f_clust = clust;
00782                 }
00783                 else {
00784                     fcb->f_clust_pos++;
00785                 }
00786             }
00787             fcb->f_sect_pos = 0;
00788         }
00789 
00790         /* Make sure that the required sector is loaded. */
00791         if ((sbn = PhatSectorLoad(nfp->nf_dev, PhatClusterSector(nfp, fcb->f_clust) + fcb->f_clust_pos)) < 0) {
00792             rc = -1;
00793             break;
00794         }
00795         step = (int) (vol->vol_sectsz - fcb->f_sect_pos);
00796         if (step > size - rc) {
00797             step = size - rc;
00798         }
00799         memcpy(&buf[rc], &vol->vol_buf[sbn].sect_data[fcb->f_sect_pos], step);
00800         fcb->f_pos += step;
00801         fcb->f_sect_pos += step;
00802     }
00803     return rc;
00804 }
00805 
00817 static long PhatFileSize(NUTFILE *nfp)
00818 {
00819     PHATFILE *fcb = nfp->nf_fcb;
00820 
00821     return fcb->f_dirent.dent_fsize;
00822 }
00823 
00824 static int PhatFileSeek(NUTFILE * nfp, long *pos, int whence)
00825 {
00826     int rc = 0;
00827     long npos = *pos;
00828     PHATFILE *fcb = nfp->nf_fcb;
00829 
00830     switch (whence) {
00831     case SEEK_CUR:
00832         npos += fcb->f_pos;
00833         break;
00834     case SEEK_END:
00835         npos += PhatFileSize(nfp);
00836         break;
00837     }
00838 
00839     if (npos < 0 || npos > PhatFileSize(nfp)) {
00840         rc = EINVAL;
00841     } else {
00842         rc = PhatFilePosSet(nfp, npos);
00843         *pos = fcb->f_pos;
00844     }
00845     return rc;
00846 }
00847 
00852 static int PhatIOCtl(NUTDEVICE * dev, int req, void *conf)
00853 {
00854     int rc = -1;
00855 
00856     switch (req) {
00857     case FS_STATUS:
00858         {
00859             FSCP_STATUS *par = (FSCP_STATUS *) conf;
00860 
00861             rc = PhatDirEntryStatus(dev, par->par_path, par->par_stp);
00862         }
00863         break;
00864     case FS_DIR_CREATE:
00865         rc = PhatDirCreate(dev, (char *) conf);
00866         break;
00867     case FS_DIR_REMOVE:
00868         rc = PhatDirRemove(dev, (char *) conf);
00869         break;
00870     case FS_DIR_OPEN:
00871         /* Open a directory for reading entries. */
00872         {
00873             DIR *dir = (DIR *) conf;
00874 
00875             if ((dir->dd_fd = PhatDirOpen(dev, dir->dd_buf)) != NUTFILE_EOF) {
00876                 rc = 0;
00877             }
00878         }
00879         break;
00880     case FS_DIR_CLOSE:
00881         rc = PhatFileClose(((DIR *) conf)->dd_fd);
00882         break;
00883     case FS_DIR_READ:
00884         rc = PhatDirRead((DIR *) conf);
00885         break;
00886     case FS_FILE_STATUS:
00887         /* TODO */
00888         break;
00889     case FS_FILE_DELETE:
00890         rc = PhatDirDelEntry(dev, (char *) conf, PHAT_FATTR_FILEMASK & ~PHAT_FATTR_DIR);
00891         break;
00892     case FS_FILE_SEEK:
00893         PhatFileSeek((NUTFILE *) ((IOCTL_ARG3 *) conf)->arg1,  /* */
00894                      (long *) ((IOCTL_ARG3 *) conf)->arg2,      /* */
00895                      (int) ((IOCTL_ARG3 *) conf)->arg3);
00896         break;
00897     case FS_RENAME:
00898         /* Rename an existing file or directory. */
00899         {
00900             FSCP_RENAME *par = (FSCP_RENAME *) conf;
00901 
00902             rc = PhatDirRenameEntry(dev, par->par_old, par->par_new);
00903         }
00904         break;
00905 
00906     case FS_VOL_MOUNT:
00907         {
00908             /* Mount a volume. */
00909             FSCP_VOL_MOUNT *par = (FSCP_VOL_MOUNT *) conf;
00910 
00911             rc = PhatVolMount(dev, par->fscp_bmnt, par->fscp_part_type);
00912             if (rc) {
00913                 /* Release resources on failures. */
00914                 PhatVolUnmount(dev);
00915             }
00916         }
00917         break;
00918     case FS_VOL_UNMOUNT:
00919         /* Unmount a volume. */
00920         rc = PhatVolUnmount(dev);
00921         break;
00922     }
00923     return rc;
00924 }
00925 
00935 static int PhatInit(NUTDEVICE * dev)
00936 {
00937     /* Nothing to do. */
00938     return 0;
00939 }
00940 
00944 static NUTFILE *PhatApiFileOpen(NUTDEVICE * dev, CONST char *path, int mode, int acc)
00945 {
00946     NUTFILE *rc;
00947     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00948 
00949     /* Make sure the volume is mounted. */
00950     if (vol == NULL) {
00951         errno = ENOENT;
00952         return NUTFILE_EOF;
00953     }
00954 
00955     /* Lock filesystem access. */
00956     NutEventWait(&vol->vol_fsmutex, 0);
00957     /* Call worker routine. */
00958     rc = PhatFileOpen(dev, path, mode, acc);
00959     /* Release filesystem lock. */
00960     NutEventPost(&vol->vol_fsmutex);
00961 
00962     return rc;
00963 }
00964 
00968 static int PhatApiFileClose(NUTFILE * nfp)
00969 {
00970     int rc;
00971     NUTDEVICE *dev = nfp->nf_dev;
00972     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00973 
00974     /* Lock filesystem access. */
00975     NutEventWait(&vol->vol_fsmutex, 0);
00976     /* Call worker routine. */
00977     rc = PhatFileClose(nfp);
00978     /* Release filesystem lock. */
00979     NutEventPost(&vol->vol_fsmutex);
00980 
00981     return rc;
00982 }
00983 
00987 static int PhatApiFileWrite(NUTFILE * nfp, CONST void *buffer, int len)
00988 {
00989     int rc;
00990     NUTDEVICE *dev = nfp->nf_dev;
00991     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00992 
00993     /* Lock filesystem access. */
00994     NutEventWait(&vol->vol_fsmutex, 0);
00995     /* Call worker routine. */
00996     rc = PhatFileWrite(nfp, buffer, len);
00997     /* Release filesystem lock. */
00998     NutEventPost(&vol->vol_fsmutex);
00999 
01000     return rc;
01001 }
01002 
01003 #ifdef __HARVARD_ARCH__
01004 
01007 static int PhatApiFileWrite_P(NUTFILE * nfp, PGM_P buffer, int len)
01008 {
01009     int rc;
01010     NUTDEVICE *dev = nfp->nf_dev;
01011     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
01012 
01013     /* Lock filesystem access. */
01014     NutEventWait(&vol->vol_fsmutex, 0);
01015     /* Call worker routine. */
01016     rc = PhatFileWrite_P(nfp, buffer, len);
01017     /* Release filesystem lock. */
01018     NutEventPost(&vol->vol_fsmutex);
01019 
01020     return rc;
01021 }
01022 #endif
01023 
01027 static int PhatApiFileRead(NUTFILE * nfp, void *buffer, int size)
01028 {
01029     int rc;
01030     NUTDEVICE *dev = nfp->nf_dev;
01031     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
01032 
01033     /* Lock filesystem access. */
01034     NutEventWait(&vol->vol_fsmutex, 0);
01035     /* Call worker routine. */
01036     rc = PhatFileRead(nfp, buffer, size);
01037     /* Release filesystem lock. */
01038     NutEventPost(&vol->vol_fsmutex);
01039 
01040     return rc;
01041 }
01042 
01046 static int PhatApiIOCtl(NUTDEVICE * dev, int req, void *conf)
01047 {
01048     int rc;
01049     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
01050 
01051     /* Lock filesystem access. */
01052     if (req != FS_VOL_MOUNT && vol) {
01053         NutEventWait(&vol->vol_fsmutex, 0);
01054     }
01055     /* Call worker routine. */
01056     rc = PhatIOCtl(dev, req, conf);
01057     /* Release filesystem lock. */
01058     if (req != FS_VOL_MOUNT && req != FS_VOL_UNMOUNT && vol) {
01059         NutEventPost(&vol->vol_fsmutex);
01060     }
01061     return rc;
01062 }
01063 
01076 NUTDEVICE devPhat0 = {
01077     0,                          
01078     {'P', 'H', 'A', 'T', '0', 0, 0, 0, 0}
01079     ,                           
01080     IFTYP_FS,                   
01081     0,                          
01082     0,                          
01083     0,                          
01084     0,                          
01085     PhatInit,                   
01086     PhatApiIOCtl,               
01087     PhatApiFileRead,            
01088     PhatApiFileWrite,           
01089 #ifdef __HARVARD_ARCH__
01090     PhatApiFileWrite_P,         
01091 #endif
01092     PhatApiFileOpen,            
01093     PhatApiFileClose,           
01094     PhatFileSize                
01095 };
01096 
01097 NUTDEVICE devPhat1 = {
01098     0,                          
01099     {'P', 'H', 'A', 'T', '1', 0, 0, 0, 0}
01100     ,                           
01101     IFTYP_FS,                   
01102     0,                          
01103     0,                          
01104     0,                          
01105     0,                          
01106     PhatInit,                   
01107     PhatApiIOCtl,               
01108     PhatApiFileRead,            
01109     PhatApiFileWrite,           
01110 #ifdef __HARVARD_ARCH__
01111     PhatApiFileWrite_P,         
01112 #endif
01113     PhatApiFileOpen,            
01114     PhatApiFileClose,           
01115     PhatFileSize                
01116 };
01117 

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