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

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