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