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 
00082 #include <fs/fs.h>
00083 
00084 #include <dirent.h>
00085 
00086 #include <dev/blockdev.h>
00087 
00088 #include <sys/event.h>
00089 
00090 #include <fs/phatfs.h>
00091 #include <fs/phatvol.h>
00092 #include <fs/phatio.h>
00093 #include <fs/phatutil.h>
00094 #include <fs/phatdir.h>
00095 
00096 #include <stdlib.h>
00097 #include <errno.h>
00098 #include <string.h>
00099 #include <fcntl.h>
00100 
00101 #if 0
00102 /* Use for local debugging. */
00103 #define NUTDEBUG
00104 #include <stdio.h>
00105 #include <fs/phatdbg.h>
00106 #endif
00107 
00108 #ifndef SEEK_SET
00109 #  define SEEK_SET        0     /* Seek from beginning of file.  */
00110 #  define SEEK_CUR        1     /* Seek from current position.  */
00111 #  define SEEK_END        2     /* Set file pointer to EOF plus "offset" */
00112 #endif
00113 
00118 
00129 static u_long SearchFreeCluster(NUTDEVICE * dev, u_long first, u_long last)
00130 {
00131     int rc = -1;
00132     u_long clust;
00133     u_long link = 1;
00134     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00135 
00136     if (vol->vol_type == 32) {
00137         for (clust = first; clust < last; clust++) {
00138             if ((rc = Phat32GetClusterLink(dev, clust, &link)) < 0 || link == 0) {
00139                 break;
00140             }
00141         }
00142     } else if (vol->vol_type == 16) {
00143         for (clust = first; clust < last; clust++) {
00144             if ((rc = Phat16GetClusterLink(dev, clust, &link)) < 0 || link == 0) {
00145                 break;
00146             }
00147         }
00148     } else {
00149         for (clust = first; clust < last; clust++) {
00150             if ((rc = Phat12GetClusterLink(dev, clust, &link)) < 0 || link == 0) {
00151                 break;
00152             }
00153         }
00154     }
00155 
00156     if (rc || link) {
00157         return 0;
00158     }
00159     return clust;
00160 }
00161 
00170 static u_long AllocCluster(NUTDEVICE * dev)
00171 {
00172     u_long clust;
00173     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00174 
00175     /*
00176      * If the hint for the next free cluster is invalid, start from the beginning,
00177      */
00178     if (vol->vol_nxtfree < 2 || vol->vol_nxtfree >= vol->vol_last_clust) {
00179         vol->vol_nxtfree = 2;
00180     }
00181     if ((clust = SearchFreeCluster(dev, vol->vol_nxtfree, vol->vol_last_clust)) < 2) {
00182         if ((clust = SearchFreeCluster(dev, 2, vol->vol_nxtfree)) < 2) {
00183             vol->vol_nxtfree = 0;
00184             errno = ENOSPC;
00185             return 0;
00186         }
00187     }
00188     vol->vol_nxtfree = clust;
00189 
00190     return clust;
00191 }
00192 
00201 u_long AllocFirstCluster(NUTFILE * nfp)
00202 {
00203     u_long clust;
00204     NUTDEVICE *dev = nfp->nf_dev;
00205     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00206     PHATFILE *fcb = nfp->nf_fcb;
00207 
00208     if ((clust = AllocCluster(dev)) < 2) {
00209         return 0;
00210     }
00211 
00212     /* Set the pointer to the first cluster in out directory entry. */
00213     fcb->f_dirent.dent_clusthi = (u_short) (clust >> 16);
00214     fcb->f_dirent.dent_clust = (u_short) clust;
00215     fcb->f_de_dirty = 1;
00216 
00217     /* The first cluster entry will be set to EOC. */
00218     if (vol->vol_type == 32) {
00219         if (Phat32SetClusterLink(dev, clust, PHAT32CMASK)) {
00220             return 0;
00221         }
00222     } else if (vol->vol_type == 16) {
00223         if (Phat16SetClusterLink(dev, clust, PHAT16CMASK)) {
00224             return 0;
00225         }
00226     } else if (Phat12SetClusterLink(dev, clust, PHAT12CMASK)) {
00227         return 0;
00228     }
00229     vol->vol_numfree--;
00230 
00231     return clust;
00232 }
00233 
00242 static u_long AllocNextCluster(NUTFILE * nfp)
00243 {
00244     u_long clust;
00245     NUTDEVICE *dev = nfp->nf_dev;
00246     PHATFILE *fcb = nfp->nf_fcb;
00247     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00248 
00249     /* Allocate a free cluster. */
00250     if ((clust = AllocCluster(dev)) < 2) {
00251         return 0;
00252     }
00253 
00254     /* Link the previous cluster to the new one and set
00255      * the entry of the new one to EOC.
00256      */
00257     if (vol->vol_type == 32) {
00258         if (Phat32SetClusterLink(dev, fcb->f_clust, clust)) {
00259             return 0;
00260         }
00261         if (Phat32SetClusterLink(dev, clust, PHAT32CMASK)) {
00262             return 0;
00263         }
00264     } else if (vol->vol_type == 16) {
00265         if (Phat16SetClusterLink(dev, fcb->f_clust, clust)) {
00266             return 0;
00267         }
00268         if (Phat16SetClusterLink(dev, clust, PHAT16CMASK)) {
00269             return 0;
00270         }
00271     } else if (Phat12SetClusterLink(dev, fcb->f_clust, clust)) {
00272         return 0;
00273     } else if (Phat12SetClusterLink(dev, clust, PHAT12CMASK)) {
00274         return 0;
00275     }
00276     vol->vol_numfree--;
00277 
00278     return clust;
00279 }
00280 
00288 static int PhatFileFlush(NUTFILE * nfp)
00289 {
00290     int rc;
00291     NUTDEVICE *dev = nfp->nf_dev;
00292     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00293 
00294     /* Update the file's directory entry. */
00295     if ((rc = PhatDirEntryUpdate(nfp)) == 0) {
00296         /* Gain mutex access. */
00297         NutEventWait(&vol->vol_iomutex, 0);
00298         /* Flush sector buffers. */
00299         rc = PhatSectorFlush(nfp->nf_dev, -1);
00300         /* Release mutex access. */
00301         NutEventPost(&vol->vol_iomutex);
00302     }
00303     return rc;
00304 }
00305 
00313 int PhatFileClose(NUTFILE * nfp)
00314 {
00315     int rc;
00316 
00317     if (nfp == NULL || nfp == NUTFILE_EOF) {
00318         errno = EBADF;
00319         return -1;
00320     }
00321 #ifdef NUTDEBUG
00322     PhatDbgFileInfo(stdout, "Close file", (PHATFILE *) nfp->nf_fcb);
00323 #endif
00324     rc = PhatFileFlush(nfp);
00325     if (nfp->nf_fcb) {
00326         free(nfp->nf_fcb);
00327     }
00328     free(nfp);
00329 
00330     return rc;
00331 }
00332 
00347 NUTFILE *PhatFileOpen(NUTDEVICE * dev, CONST char *path, int mode, int acc)
00348 {
00349     NUTFILE *nfp = NUTFILE_EOF;
00350     NUTFILE *ndp = NUTFILE_EOF;
00351     PHATFILE *ffcb;
00352     PHATFILE *dfcb;
00353     PHATFIND *srch;
00354     CONST char *fname;
00355 
00356     /* Open the parent directory and return the basename. */
00357     if ((ndp = PhatDirOpenParent(dev, path, &fname)) == NUTFILE_EOF) {
00358         return NUTFILE_EOF;
00359     }
00360 
00361     /*
00362      * We successfully opened the directory. If no file name had been specified,
00363      * then the caller wants to open the directory itself. In this case, simply
00364      * return the NUTFILE for it.
00365      */
00366     dfcb = ndp->nf_fcb;
00367     if (*fname == 0) {
00368         dfcb->f_mode = mode;
00369         return ndp;
00370     }
00371 
00372     /*
00373      * Allocate a file information and a temporary search structure.
00374      */
00375     nfp = malloc(sizeof(NUTFILE));
00376     ffcb = malloc(sizeof(PHATFILE));
00377     srch = malloc(sizeof(PHATFIND));
00378     if (nfp == NULL || ffcb == NULL || srch == NULL) {
00379         PhatFileClose(ndp);
00380         if (nfp) {
00381             free(nfp);
00382         }
00383         if (ffcb) {
00384             free(ffcb);
00385         }
00386         if (srch) {
00387             free(srch);
00388         }
00389         return NUTFILE_EOF;
00390     }
00391 
00392     memset(ffcb, 0, sizeof(PHATFILE));
00393     nfp->nf_next = 0;
00394     nfp->nf_dev = dev;
00395     nfp->nf_fcb = ffcb;
00396 
00397     /*
00398      * Check if the specified file already exists.
00399      *
00400      * Note, that directories are handled differently in PhatDirCreate(),
00401      * where the first cluster is initialized with zeros.
00402      */
00403     if (PhatDirEntryFind(ndp, fname, PHAT_FATTR_FILEMASK, srch)) {
00404         /* 
00405          * File doesn't exist. Does the opening mode allow to create 
00406          * a new file? 
00407          */
00408         if ((mode & _O_CREAT) == 0) {
00409             free(srch);
00410             PhatFileClose(ndp);
00411             PhatFileClose(nfp);
00412             errno = ENOENT;
00413             return NUTFILE_EOF;
00414         }
00415         /* Create a new directory entry. */
00416         if (PhatDirEntryCreate(ndp, fname, acc, &ffcb->f_dirent)) {
00417             free(srch);
00418             PhatFileClose(ndp);
00419             PhatFileClose(nfp);
00420             return NUTFILE_EOF;
00421         }
00422         ffcb->f_de_dirty = 1;
00423 #ifdef NUTDEBUG
00424         PhatDbgFileInfo(stdout, "New entry", ffcb);
00425 #endif
00426     } else {
00427         /*
00428          * We return an error, if the file exists and _O_EXCL has been
00429          * set with _O_CREAT.
00430          */
00431         if ((mode & (_O_CREAT | _O_EXCL)) == (_O_CREAT | _O_EXCL)) {
00432             free(srch);
00433             PhatFileClose(ndp);
00434             PhatFileClose(nfp);
00435             errno = EEXIST;
00436             return NUTFILE_EOF;
00437         }
00438 #ifdef NUTDEBUG
00439         PhatDbgFileInfo(stdout, "Existing entry", ffcb);
00440 #endif
00441         /*
00442          * Truncate an existing file.
00443          */
00444         if (mode & _O_TRUNC) {
00445             /*
00446              * Relase all clusters allocated by this entry.
00447              */
00448             if (PhatDirReleaseChain(dev, &srch->phfind_ent)) {
00449                 PhatFileClose(ndp);
00450                 PhatFileClose(nfp);
00451                 free(srch);
00452                 return NUTFILE_EOF;
00453             }
00454             memset(ffcb, 0, sizeof(PHATFILE));
00455             memcpy(ffcb->f_dirent.dent_name, srch->phfind_ent.dent_name, sizeof(ffcb->f_dirent.dent_name));
00456             ffcb->f_dirent.dent_attr = srch->phfind_ent.dent_attr;
00457             ffcb->f_dirent.dent_rsvdnt = srch->phfind_ent.dent_rsvdnt;
00458             ffcb->f_dirent.dent_ctsecs = srch->phfind_ent.dent_ctsecs;
00459             ffcb->f_dirent.dent_ctime = srch->phfind_ent.dent_ctime;
00460             ffcb->f_dirent.dent_cdate = srch->phfind_ent.dent_cdate;
00461             ffcb->f_de_dirty = 1;
00462         }
00463         /*
00464          * Append to an existing file.
00465          */
00466         else {
00467             ffcb->f_dirent = srch->phfind_ent;
00468             if (ffcb->f_dirent.dent_fsize) {
00469                 PhatFilePosSet(nfp, ffcb->f_dirent.dent_fsize + 1);
00470             }
00471         }
00472     }
00473     free(srch);
00474 
00475     /* Store position of our directory entry. */
00476     ffcb->f_de_sect = PhatClusterSector(ndp, dfcb->f_clust) + dfcb->f_clust_pos;
00477     ffcb->f_de_offs = dfcb->f_sect_pos - 32;
00478     /* Store first cluster of parent. */
00479     ffcb->f_pde_clusthi = dfcb->f_dirent.dent_clusthi;
00480     ffcb->f_pde_clust = dfcb->f_dirent.dent_clust;
00481     /* Set the current cluster. */
00482     ffcb->f_clust = ffcb->f_dirent.dent_clusthi;
00483     ffcb->f_clust <<= 16;
00484     ffcb->f_clust += ffcb->f_dirent.dent_clust;
00485     /* Store the opening mode. */
00486     ffcb->f_mode = mode;
00487 
00488     /* Close the directory. */
00489     PhatFileClose(ndp);
00490 
00491 #ifdef NUTDEBUG
00492     PhatDbgFileInfo(stdout, "File opened", ffcb);
00493 #endif
00494     return nfp;
00495 }
00496 
00509 int PhatFileWrite(NUTFILE * nfp, CONST void *buffer, int len)
00510 {
00511     int rc;
00512     int step;
00513     u_long clust;
00514     int sbn;
00515     u_char *buf = (u_char *) buffer;
00516     NUTDEVICE *dev = nfp->nf_dev;
00517     PHATFILE *fcb = nfp->nf_fcb;
00518     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00519 
00520     /*
00521      * Refuse to write to files with RDONLY attribute set.
00522      */
00523     if (fcb->f_dirent.dent_attr & PHAT_FATTR_RDONLY) {
00524         errno = EACCES;
00525         return -1;
00526     }
00527 
00528     /*
00529      * Flush file if buffer is a NULL pointer.
00530      */
00531     if (buf == NULL || len == 0) {
00532         return PhatFileFlush(nfp);
00533     }
00534 
00535     /*
00536      * In case of normal files, check for sufficient space.
00537      */
00538     if ((fcb->f_dirent.dent_attr & PHAT_FATTR_DIR) == 0) {
00539         /* Bytes per cluster. */
00540         u_long num = vol->vol_sectsz * vol->vol_clustsz;
00541         /* Number of clusters already used. */
00542         u_long cur = (fcb->f_dirent.dent_fsize + num - 1) / num;
00543 
00544         /* Number of clusters used after writing. */
00545         num = (fcb->f_pos + len + num - 1) / num;
00546         /* If additional clusters are required, are they available? */
00547         if (num > cur && num - cur > vol->vol_numfree) {
00548             errno = ENOSPC;
00549             return -1;
00550         }
00551 
00552         /* If the file is empty, allocate the first cluster. */
00553         if (fcb->f_dirent.dent_fsize == 0) {
00554             if ((clust = AllocFirstCluster(nfp)) < 2) {
00555                 return -1;
00556             }
00557             fcb->f_clust_prv = clust;
00558             fcb->f_clust = clust;
00559         }
00560     }
00561 
00562 
00563     /*
00564      * Write the data.
00565      */
00566     for (rc = 0, step = 0; rc < len; rc += step) {
00567         /* Did we reach the end of a sector? */
00568         if (fcb->f_sect_pos >= vol->vol_sectsz) {
00569             /* Move to the next sector within the cluster. */
00570             if (IsFixedRootDir(nfp)) {
00571                 if (fcb->f_clust_pos + 1 >= vol->vol_rootsz) {
00572                     /* End of root directory, abort writing. */
00573                     break;
00574                 }
00575                 fcb->f_clust_pos++;
00576             }
00577             else {
00578                 /* Did we reach the last sector of this cluster? */
00579                 if (fcb->f_clust_pos  + 1 >= vol->vol_clustsz) {
00580                     /* Move to the next cluster. */
00581                     if (vol->vol_type == 32) {
00582                         if (Phat32GetClusterLink(dev, fcb->f_clust, &clust)) {
00583                             rc = -1;
00584                             break;
00585                         }
00586                         if (clust >= (PHATEOC & PHAT32CMASK)) {
00587                             if ((clust = AllocNextCluster(nfp)) < 2) {
00588                                 rc = -1;
00589                                 break;
00590                             }
00591                         }
00592                     } else if (vol->vol_type == 16) {
00593                         if (Phat16GetClusterLink(dev, fcb->f_clust, &clust)) {
00594                             rc = -1;
00595                             break;
00596                         }
00597                         if (clust >= (PHATEOC & PHAT16CMASK)) {
00598                             if ((clust = AllocNextCluster(nfp)) < 2) {
00599                                 rc = -1;
00600                                 break;
00601                             }
00602                         }
00603                     } else if (Phat12GetClusterLink(dev, fcb->f_clust, &clust)) {
00604                         rc = -1;
00605                         break;
00606                     } else if (clust >= (PHATEOC & PHAT12CMASK)) {
00607                         if ((clust = AllocNextCluster(nfp)) < 2) {
00608                             rc = -1;
00609                             break;
00610                         }
00611                     }
00612                     fcb->f_clust_pos = 0;
00613                     fcb->f_clust_prv = fcb->f_clust;
00614                     fcb->f_clust = clust;
00615                 }
00616                 else {
00617                     fcb->f_clust_pos++;
00618                 }
00619             }
00620             fcb->f_sect_pos = 0;
00621         }
00622 
00623         /* Load the sector we want to write to. */
00624         if ((sbn = PhatSectorLoad(nfp->nf_dev, PhatClusterSector(nfp, fcb->f_clust) + fcb->f_clust_pos)) < 0) {
00625             rc = -1;
00626             break;
00627         }
00628         /* The number of bytes we write to this sector. */
00629         step = (int) (vol->vol_sectsz - fcb->f_sect_pos);
00630         if (step > len - rc) {
00631             step = len - rc;
00632         }
00633         /* Copy data to this sector. */
00634         memcpy(&vol->vol_buf[sbn].sect_data[fcb->f_sect_pos], &buf[rc], step);
00635         vol->vol_buf[sbn].sect_dirty = 1;
00636         /* Advance file pointers. */
00637         fcb->f_pos += step;
00638         fcb->f_sect_pos += step;
00639     }
00640 
00641     if (rc > 0) {
00642         /*
00643          * Update directory entry. Note that directory entries of directories
00644          * are never updated in a PHAT file system.
00645          */
00646         if ((fcb->f_dirent.dent_attr & PHAT_FATTR_DIR) == 0) {
00647             GetDosTimeStamp(&fcb->f_dirent.dent_mtime, &fcb->f_dirent.dent_mdate);
00648             fcb->f_dirent.dent_adate = fcb->f_dirent.dent_mdate;
00649             fcb->f_dirent.dent_attr |= PHAT_FATTR_ARCHIV;
00650             fcb->f_dirent.dent_fsize += rc;
00651             fcb->f_de_dirty = 1;
00652         }
00653     }
00654     return rc;
00655 }
00656 
00657 #ifdef __HARVARD_ARCH__
00658 
00675 int PhatFileWrite_P(NUTFILE * nfp, PGM_P buffer, int len)
00676 {
00677     return -1;
00678 }
00679 #endif
00680 
00692 int PhatFileRead(NUTFILE * nfp, void *buffer, int size)
00693 {
00694     int rc;
00695     int step;
00696     int sbn;
00697     u_char *buf = (u_char *) buffer;
00698     NUTDEVICE *dev = nfp->nf_dev;
00699     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00700     PHATFILE *fcb = nfp->nf_fcb;
00701 
00702     /*
00703      * Ignore input flush.
00704      */
00705     if (buf == NULL || size == 0) {
00706         return 0;
00707     }
00708 
00709     /* Respect the end of normal files. */
00710     if ((fcb->f_dirent.dent_attr & PHAT_FATTR_DIR) == 0) {
00711         if (fcb->f_pos + size >= fcb->f_dirent.dent_fsize) {
00712             size = fcb->f_dirent.dent_fsize - fcb->f_pos;
00713         }
00714     }
00715     for (rc = 0, step = 0; rc < size; rc += step) {
00716         /* Did we reach the end of a sector? */
00717         if (fcb->f_sect_pos >= vol->vol_sectsz) {
00718             /* Move to the next sector. */
00719             if (IsFixedRootDir(nfp)) {
00720                 if (fcb->f_clust_pos + 1 >= vol->vol_rootsz) {
00721                     /* End of root directory, abort reading. */
00722                     break;
00723                 }
00724                 fcb->f_clust_pos++;
00725             }
00726             else {
00727                 /* Did we reach the last sector of this cluster? */
00728                 if (fcb->f_clust_pos + 1 >= vol->vol_clustsz) {
00729                     /* Move to the next cluster. */
00730                     u_long clust;
00731 
00732                     if (vol->vol_type == 32) {
00733                         if (Phat32GetClusterLink(dev, fcb->f_clust, &clust)) {
00734                             break;
00735                         }
00736                         if (clust >= (PHATEOC & PHAT32CMASK)) {
00737                             break;
00738                         }
00739                     } else if (vol->vol_type == 16) {
00740                         if (Phat16GetClusterLink(dev, fcb->f_clust, &clust)) {
00741                             break;
00742                         }
00743                         if (clust >= (PHATEOC & PHAT16CMASK)) {
00744                             break;
00745                         }
00746                     } else if (Phat12GetClusterLink(dev, fcb->f_clust, &clust)) {
00747                         break;
00748                     }
00749                     else if (clust >= (PHATEOC & PHAT12CMASK)) {
00750                         break;
00751                     }
00752                     fcb->f_clust_pos = 0;
00753                     fcb->f_clust_prv = fcb->f_clust;
00754                     fcb->f_clust = clust;
00755                 }
00756                 else {
00757                     fcb->f_clust_pos++;
00758                 }
00759             }
00760             fcb->f_sect_pos = 0;
00761         }
00762 
00763         /* Make sure that the required sector is loaded. */
00764         if ((sbn = PhatSectorLoad(nfp->nf_dev, PhatClusterSector(nfp, fcb->f_clust) + fcb->f_clust_pos)) < 0) {
00765             rc = -1;
00766             break;
00767         }
00768         step = (int) (vol->vol_sectsz - fcb->f_sect_pos);
00769         if (step > size - rc) {
00770             step = size - rc;
00771         }
00772         memcpy(&buf[rc], &vol->vol_buf[sbn].sect_data[fcb->f_sect_pos], step);
00773         fcb->f_pos += step;
00774         fcb->f_sect_pos += step;
00775     }
00776     return rc;
00777 }
00778 
00790 static long PhatFileSize(NUTFILE *nfp)
00791 {
00792     PHATFILE *fcb = nfp->nf_fcb;
00793 
00794     return fcb->f_dirent.dent_fsize;
00795 }
00796 
00797 static int PhatFileSeek(NUTFILE * nfp, long *pos, int whence)
00798 {
00799     int rc = 0;
00800     long npos = *pos;
00801     PHATFILE *fcb = nfp->nf_fcb;
00802 
00803     switch (whence) {
00804     case SEEK_CUR:
00805         npos += fcb->f_pos;
00806         break;
00807     case SEEK_END:
00808         npos += PhatFileSize(nfp);
00809         break;
00810     }
00811 
00812     if (npos < 0 || npos > PhatFileSize(nfp)) {
00813         rc = EINVAL;
00814     } else {
00815         rc = PhatFilePosSet(nfp, npos);
00816         *pos = fcb->f_pos;
00817     }
00818     return rc;
00819 }
00820 
00825 static int PhatIOCtl(NUTDEVICE * dev, int req, void *conf)
00826 {
00827     int rc = -1;
00828 
00829     switch (req) {
00830     case FS_STATUS:
00831         {
00832             FSCP_STATUS *par = (FSCP_STATUS *) conf;
00833 
00834             rc = PhatDirEntryStatus(dev, par->par_path, par->par_stp);
00835         }
00836         break;
00837     case FS_DIR_CREATE:
00838         rc = PhatDirCreate(dev, (char *) conf);
00839         break;
00840     case FS_DIR_REMOVE:
00841         rc = PhatDirRemove(dev, (char *) conf);
00842         break;
00843     case FS_DIR_OPEN:
00844         /* Open a directory for reading entries. */
00845         {
00846             DIR *dir = (DIR *) conf;
00847 
00848             if ((dir->dd_fd = PhatDirOpen(dev, dir->dd_buf)) != NUTFILE_EOF) {
00849                 rc = 0;
00850             }
00851         }
00852         break;
00853     case FS_DIR_CLOSE:
00854         rc = PhatFileClose(((DIR *) conf)->dd_fd);
00855         break;
00856     case FS_DIR_READ:
00857         rc = PhatDirRead((DIR *) conf);
00858         break;
00859     case FS_FILE_STATUS:
00860         /* TODO */
00861         break;
00862     case FS_FILE_DELETE:
00863         rc = PhatDirDelEntry(dev, (char *) conf, PHAT_FATTR_FILEMASK & ~PHAT_FATTR_DIR);
00864         break;
00865     case FS_FILE_SEEK:
00866         PhatFileSeek((NUTFILE *) ((IOCTL_ARG3 *) conf)->arg1,  /* */
00867                      (long *) ((IOCTL_ARG3 *) conf)->arg2,      /* */
00868                      (int) ((IOCTL_ARG3 *) conf)->arg3);
00869         break;
00870     case FS_RENAME:
00871         /* Rename an existing file or directory. */
00872         {
00873             FSCP_RENAME *par = (FSCP_RENAME *) conf;
00874 
00875             rc = PhatDirRenameEntry(dev, par->par_old, par->par_new);
00876         }
00877         break;
00878 
00879     case FS_VOL_MOUNT:
00880         {
00881             /* Mount a volume. */
00882             FSCP_VOL_MOUNT *par = (FSCP_VOL_MOUNT *) conf;
00883 
00884             rc = PhatVolMount(dev, par->fscp_bmnt, par->fscp_part_type);
00885             if (rc) {
00886                 /* Release resources on failures. */
00887                 PhatVolUnmount(dev);
00888             }
00889         }
00890         break;
00891     case FS_VOL_UNMOUNT:
00892         /* Unmount a volume. */
00893         rc = PhatVolUnmount(dev);
00894         break;
00895     }
00896     return rc;
00897 }
00898 
00908 static int PhatInit(NUTDEVICE * dev)
00909 {
00910     /* Nothing to do. */
00911     return 0;
00912 }
00913 
00917 static NUTFILE *PhatApiFileOpen(NUTDEVICE * dev, CONST char *path, int mode, int acc)
00918 {
00919     NUTFILE *rc;
00920     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00921 
00922     /* Lock filesystem access. */
00923     NutEventWait(&vol->vol_fsmutex, 0);
00924     /* Call worker routine. */
00925     rc = PhatFileOpen(dev, path, mode, acc);
00926     /* Release filesystem lock. */
00927     NutEventPost(&vol->vol_fsmutex);
00928 
00929     return rc;
00930 }
00931 
00935 static int PhatApiFileClose(NUTFILE * nfp)
00936 {
00937     int rc;
00938     NUTDEVICE *dev = nfp->nf_dev;
00939     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00940 
00941     /* Lock filesystem access. */
00942     NutEventWait(&vol->vol_fsmutex, 0);
00943     /* Call worker routine. */
00944     rc = PhatFileClose(nfp);
00945     /* Release filesystem lock. */
00946     NutEventPost(&vol->vol_fsmutex);
00947 
00948     return rc;
00949 }
00950 
00954 static int PhatApiFileWrite(NUTFILE * nfp, CONST void *buffer, int len)
00955 {
00956     int rc;
00957     NUTDEVICE *dev = nfp->nf_dev;
00958     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00959 
00960     /* Lock filesystem access. */
00961     NutEventWait(&vol->vol_fsmutex, 0);
00962     /* Call worker routine. */
00963     rc = PhatFileWrite(nfp, buffer, len);
00964     /* Release filesystem lock. */
00965     NutEventPost(&vol->vol_fsmutex);
00966 
00967     return rc;
00968 }
00969 
00970 #ifdef __HARVARD_ARCH__
00971 
00974 static int PhatApiFileWrite_P(NUTFILE * nfp, PGM_P 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_P(nfp, buffer, len);
00984     /* Release filesystem lock. */
00985     NutEventPost(&vol->vol_fsmutex);
00986 
00987     return rc;
00988 }
00989 #endif
00990 
00994 static int PhatApiFileRead(NUTFILE * nfp, void *buffer, int size)
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 = PhatFileRead(nfp, buffer, size);
01004     /* Release filesystem lock. */
01005     NutEventPost(&vol->vol_fsmutex);
01006 
01007     return rc;
01008 }
01009 
01013 static int PhatApiIOCtl(NUTDEVICE * dev, int req, void *conf)
01014 {
01015     int rc;
01016     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
01017 
01018     /* Lock filesystem access. */
01019     if (req != FS_VOL_MOUNT && vol) {
01020         NutEventWait(&vol->vol_fsmutex, 0);
01021     }
01022     /* Call worker routine. */
01023     rc = PhatIOCtl(dev, req, conf);
01024     /* Release filesystem lock. */
01025     if (req != FS_VOL_MOUNT && req != FS_VOL_UNMOUNT && vol) {
01026         NutEventPost(&vol->vol_fsmutex);
01027     }
01028     return rc;
01029 }
01030 
01043 NUTDEVICE devPhat0 = {
01044     0,                          
01045     {'P', 'H', 'A', 'T', '0', 0, 0, 0, 0}
01046     ,                           
01047     IFTYP_FS,                   
01048     0,                          
01049     0,                          
01050     0,                          
01051     0,                          
01052     PhatInit,                   
01053     PhatApiIOCtl,               
01054     PhatApiFileRead,            
01055     PhatApiFileWrite,           
01056 #ifdef __HARVARD_ARCH__
01057     PhatApiFileWrite_P,         
01058 #endif
01059     PhatApiFileOpen,            
01060     PhatApiFileClose,           
01061     PhatFileSize                
01062 };
01063 
01064 NUTDEVICE devPhat1 = {
01065     0,                          
01066     {'P', 'H', 'A', 'T', '1', 0, 0, 0, 0}
01067     ,                           
01068     IFTYP_FS,                   
01069     0,                          
01070     0,                          
01071     0,                          
01072     0,                          
01073     PhatInit,                   
01074     PhatApiIOCtl,               
01075     PhatApiFileRead,            
01076     PhatApiFileWrite,           
01077 #ifdef __HARVARD_ARCH__
01078     PhatApiFileWrite_P,         
01079 #endif
01080     PhatApiFileOpen,            
01081     PhatApiFileClose,           
01082     PhatFileSize                
01083 };
01084 

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