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

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