gonzui


Format: Advanced Search

t2ex/t2ex_source/t2ex/fs/fimp/src/fimp_fat.cbare sourcepermlink (0.46 seconds)

Search this content:

    1: /*
    2:  *----------------------------------------------------------------------
    3:  *    T2EX Software Package
    4:  *
    5:  *    Copyright 2012 by Ken Sakamura.
    6:  *    This software is distributed under the latest version of T-License 2.x.
    7:  *----------------------------------------------------------------------
    8:  *
    9:  *    Released by T-Engine Forum(http://www.t-engine.org/) at 2012/12/12.
   10:  *    Modified by T-Engine Forum at 2014/01/08.
   11:  *    Modified by TRON Forum(http://www.tron.org/) at 2015/06/04.
   12:  *
   13:  *----------------------------------------------------------------------
   14:  */
   15: /*
   16:  * This software package is available for use, modification, 
   17:  * and redistribution in accordance with the terms of the attached 
   18:  * T-License 2.x.
   19:  * If you want to redistribute the source code, you need to attach 
   20:  * the T-License 2.x document.
   21:  * There's no obligation to publish the content, and no obligation 
   22:  * to disclose it to the TRON Forum if you have modified the 
   23:  * software package.
   24:  * You can also distribute the modified source code. In this case, 
   25:  * please register the modification to T-Kernel traceability service.
   26:  * People can know the history of modifications by the service, 
   27:  * and can be sure that the version you have inherited some 
   28:  * modification of a particular version or not.
   29:  *
   30:  *    http://trace.tron.org/tk/?lang=en
   31:  *    http://trace.tron.org/tk/?lang=ja
   32:  *
   33:  * As per the provisions of the T-License 2.x, TRON Forum ensures that 
   34:  * the portion of the software that is copyrighted by Ken Sakamura or 
   35:  * the TRON Forum does not infringe the copyrights of a third party.
   36:  * However, it does not make any warranty other than this.
   37:  * DISCLAIMER: TRON Forum and Ken Sakamura shall not be held
   38:  * responsible for any consequences or damages caused directly or
   39:  * indirectly by the use of this software package.
   40:  *
   41:  * The source codes in bsd_source.tar.gz in this software package are 
   42:  * derived from NetBSD or OpenBSD and not covered under T-License 2.x.
   43:  * They need to be changed or redistributed according to the 
   44:  * representation of each source header.
   45:  */
   46: 
   47: /*
   48:  *  @(#)fimp_fat.c
   49:  *
   50:  */
   51: 
   52: #include "fimp_fat.h"
   53: #include "fimp_fat_local.h"
   54: 
   55: /*
   56:  *  Configuration information
   57:  */
   58: LOCAL   INT       MaxOpenF              = DEFAULT_MaxOpenF;
   59: LOCAL   INT       TaskPriority          = DEFAULT_TaskPriority;
   60: LOCAL   INT       TaskStackSize         = DEFAULT_TaskStackSize;
   61: LOCAL   INT       CacheFATMemorySize    = DEFAULT_CacheFATMemorySize;
   62: LOCAL   INT       CacheFATRatio         = DEFAULT_CacheFATRatio;
   63: LOCAL   INT       CacheRootMemorySize   = DEFAULT_CacheRootMemorySize;
   64: LOCAL   INT       CacheRootRatio                = DEFAULT_CacheRootRatio;
   65: LOCAL   INT       CacheDataMemorySize   = DEFAULT_CacheDataMemorySize;
   66: LOCAL   INT       CacheDataRatio                = DEFAULT_CacheDataRatio;
   67: LOCAL   INT       LastAccess            = DEFAULT_LastAccess;
   68: 
   69: /*
   70:  *  FAT FIMP entry
   71:  */
   72: LOCAL   ER        fatfs_service(fimp_t *req);
   73: LOCAL   ER        fatfs_registfn(fimpinf_t *fimpinf, void *exinf);
   74: LOCAL   ER        fatfs_unregistfn(fimpinf_t *fimpinf);
   75: LOCAL   ER        fatfs_attachfn(coninf_t *coninf, void *exinf);
   76: LOCAL   ER        fatfs_detachfn(coninf_t *coninf);
   77: LOCAL   ER        fatfs_breakfn(coninf_t *coninf, ID tskid, BOOL set);
   78: 
   79: EXPORT  const    fs_fimp_t  fimp_fatfs_entry = {
   80:         fatfs_service,                         /* reqfn     */
   81:         fatfs_registfn,                                /* registfn */
   82:         fatfs_unregistfn,                      /* unregistfn      */
   83:         fatfs_attachfn,                                /* attachfn */
   84:         fatfs_detachfn,                                /* detachfn */
   85:         NULL,                                  /* startupfn */
   86:         NULL,                                  /* cleanupfn */
   87:         fatfs_breakfn,                         /* breakfn   */
   88:         FIMP_FLAG_64BIT | FIMP_FLAG_USEABORT,  /* flags */
   89:         0,                                     /* priority     */
   90: };
   91: 
   92: /* Task status table [0 .. MaxTskId - 1] */
   93: LOCAL   TaskSts   *tskStsTab;
   94: 
   95: /* Check flags or mode */
   96: #define isSET(flags, value)     (((UW)(flags) & (UW)(value)) != 0)
   97: #define isFAT_SUBDIR(typ)       isSET(typ, FAT_SUBDIR)
   98: #define isFAT_VOLUME(typ)       isSET(typ, FAT_VOLUME)
   99: #define isFAT_RDONLY(typ)       isSET(typ, FAT_RDONLY)
  100: #define isNOT_RDONLY(md)        (((UW)(md) & O_ACCMODE) != O_RDONLY)
  101: #define isDEV_RDONLY(flg)       isSET(flg, DEV_FLAG_READONLY)
  102: 
  103: /* Check dirent */
  104: #define isDE_TERM(de)           ((de)->de_fname[0] == DE_B0_END)
  105: #define isDE_FREE(de)           ((de)->de_fname[0] == DE_B0_FREE)
  106: #define isDE_LFN(de)            ((de)->de_ftype == FAT_LONGNAME)
  107: #define isDE_VOL(de)            isFAT_VOLUME((de)->de_ftype)
  108: 
  109: /* Check break done */
  110: #define CHK_BREAK_AND_SET_ERR(fs, perr)         \
  111:         { if (((FS*)(fs))->fs_tsksts->c.break_done != 0) {*(perr) = EX_INTR;} }
  112: 
  113: /* Set second error */
  114: #define SetErr2(er,er2)         {if ((er) >= E_OK) (er) = (er2);}
  115: 
  116: /* Directory entry size */
  117: #define DIRENTSZ        (sizeof(FAT_DIRENT))
  118: 
  119: /* FAT12, 16 Root directory */
  120: #define ROOTENT         (fs->ff_rootent)
  121: #define ROOTSZ          (ROOTENT * DIRENTSZ)
  122: 
  123: /* Cluster number <-> Block number */
  124: #define CNtoBN(cn)      (fs->ff_clstart + (((cn) - 2) * fs->ff_ratio))
  125: #define BNtoCN(bn)      ((((bn) - fs->ff_clstart) / fs->ff_ratio) + 2)
  126: 
  127: /* Number of dirent per sector / cluster */
  128: #define DEpSEC          ((fs->ff_clsz / fs->ff_ratio) / DIRENTSZ)
  129: #define DEpCL           (fs->ff_clsz / DIRENTSZ)
  130: 
  131: /* Byte <-> Number of cluster */
  132: #define BYTEtoCL(b)     (((b) + (fs->ff_clsz - 1)) / fs->ff_clsz)
  133: 
  134: /* Check rootdir inode */
  135: #define IsRootINODE(fs, inode)  \
  136:                 (((INODE*)(inode))->ino_ino == ((FS*)(fs))->fs_rootino)
  137: 
  138: /* Disk sector(block) size */
  139: #define DSECSZ(fs)      ((fs)->ff_c.fs_diskinfo.blocksize)
  140: 
  141: /* Byte offset corresponding to 'offset' byte of 'secno' in 'page' */
  142: #define OFFSETinPAGE(fs, page, secno, offset)   \
  143:         ( ((secno) - (page)->dcp_secno) * DSECSZ(fs) + (offset) % DSECSZ(fs) )
  144: 
  145: /* is FAT32 ? */
  146: #define isFAT32(fstype)         ((fstype) == FAT32)
  147: 
  148: /* Generic pointer */
  149: typedef union {
  150:         UB     *b;
  151:         UH     *h;
  152:         UW     *w;
  153: } GPTR;
  154: 
  155: /* FAT_DIRENT_LFN : fragmented file name offset & count */
  156: LOCAL   const     struct {
  157:         UB     ofs;
  158:         UB     cnt;
  159: } LDE_NMPOS[3] = {
  160:         {offsetof(FAT_DIRENT_LFN, lde_fname1), 10},
  161:         {offsetof(FAT_DIRENT_LFN, lde_fname2), 12},
  162:         {offsetof(FAT_DIRENT_LFN, lde_fname3), 4}
  163: };
  164: 
  165: /* Special directory entry name */
  166: LOCAL   const     UB  nmDOT[BASE_EXTLEN + 1]   = ".          ";
  167: LOCAL   const     UB  nmDOT2[BASE_EXTLEN + 1] = "..         ";
  168: 
  169: /* "root" path name */
  170: LOCAL   const     UB  inode_root_path[] = "/";
  171: 
  172: /*----------------------------------------------------------------------------
  173:         Misc functions
  174: ----------------------------------------------------------------------------*/
  175: 
  176: /*
  177:  *  Get directory "ino"
  178:  */
  179: Inline  UD       dirINO(FATFS *fs, UW fclno)
  180: {
  181:         return (fclno == fs->ff_rootcl) ? CLSTART : CNtoBN(fclno) * DEpSEC;
  182: }
  183: 
  184: /*
  185:  *  Get file "ino"
  186:  */
  187: Inline  UD       fileINO(FATFS *fs, UW clno, UW offset)
  188: {
  189:         return (CNtoBN(clno) * DEpSEC) + offset;
  190: }
  191: 
  192: /*
  193:  *  Get  file "ino" of FAT12/16 root directory
  194:  */
  195: Inline  UD       rootINO(FATFS *fs, UW offset)
  196: {
  197:         return ((fs->ff_rootsc * DEpSEC) + offset);
  198: }
  199: 
  200: /*
  201:  *  Get directory start cluster number
  202:  */
  203: Inline  UW       dirCLNO(FATFS *fs, UD ino)
  204: {
  205:         return ((ino == CLSTART) ? fs->ff_rootcl : BNtoCN(ino / DEpSEC));
  206: }
  207: 
  208: /*
  209:  *  Get directory entry cluster number
  210:  */
  211: LOCAL   UW        dirent_to_fcl(FATFS *fs, FAT_DIRENT *dirent)
  212: {
  213:         UW     fcl;
  214: 
  215:         fcl = (UW)CEH(dirent->de_clno_lo);
  216:         if (isFAT32(fs->ff_fstype)) {
  217:                 fcl |= (UW)CEH(dirent->de_clno_hi) << DE_SHIFT_CLNO_HI;
  218:         }
  219:         if (fcl == 0 && isFAT_SUBDIR(dirent->de_ftype)) {
  220:                 fcl = fs->ff_rootcl;
  221:         }
  222:         return fcl;
  223: }
  224: 
  225: /*
  226:  *  Set directory entry cluster number
  227:  */
  228: LOCAL   void      fcl_to_dirent(FATFS *fs, FAT_DIRENT *dirent, UW fcl)
  229: {
  230:         /* Modify start cluster = 0 */
  231:         if (fcl == fs->ff_rootcl) fcl = 0;
  232: 
  233:         dirent->de_clno_lo = CEH((UH)fcl);
  234:         dirent->de_clno_hi = isFAT32(fs->ff_fstype) ?
  235:                                 (CEH((UH)(fcl >> DE_SHIFT_CLNO_HI))) : 0;
  236: }
  237: 
  238: /*----------------------------------------------------------------------------
  239:         Disk device operations
  240: ----------------------------------------------------------------------------*/
  241: 
  242: /*
  243:  *  Disk read
  244:  */
  245: LOCAL   ER        fatDiskRead(FATFS *fs, D start, void *buf, W size)
  246: {
  247:         W      asize;
  248:         ER     err;
  249: 
  250:         err = tk_srea_dev_d(fs->ff_c.fs_devid, start, buf, size, &asize);
  251:         return (err >= E_OK && asize != size) ? EX_IO : err;
  252: }
  253: 
  254: /*
  255:  *  Disk write
  256:  */
  257: LOCAL   ER        fatDiskWrite(FATFS *fs, D start, void *buf, W size)
  258: {
  259:         W      asize;
  260:         ER     err;
  261: 
  262:         err = tk_swri_dev_d(fs->ff_c.fs_devid, start, buf, size, &asize);
  263:         return (err >= E_OK && asize != size) ? EX_IO : err;
  264: }
  265: 
  266: /*
  267:  *  Disk open
  268:  */
  269: LOCAL   ER        fatDiskOpen(const coninf_t *coninf, FATFS *fs)
  270: {
  271:         ER     err;
  272:         UINT   omode;
  273:         W      sz;
  274: #define OPEN_MODE(n)    ((n) | TD_WEXCL | TD_NOLOCK)
  275: 
  276:         /* Check device name */
  277:         if (coninf->devnm[0] == '\0') {
  278:                 err = EX_INVAL;
  279:                 goto exit0;
  280:         }
  281: 
  282:         /* Open device */
  283:         if (isDEV_RDONLY(coninf->dflags)) {
  284:                 omode = OPEN_MODE(TD_READ);
  285:                 fs->ff_c.fs_rdonly = TRUE;
  286:         } else {
  287:                 omode = OPEN_MODE(TD_UPDATE);
  288:                 fs->ff_c.fs_rdonly = FALSE;
  289:         }
  290:         err = tk_opn_dev((UB*)coninf->devnm, omode);
  291:         if (err == E_RONLY) {
  292:                 /* Try read-only open */
  293:                 fs->ff_c.fs_rdonly = TRUE;
  294:                 err = tk_opn_dev((UB *)coninf->devnm, OPEN_MODE(TD_READ));
  295:         }
  296:         if (err < E_OK) goto exit0;
  297:         fs->ff_c.fs_devid = err;
  298: 
  299:         /* Get disk info */
  300:         err = tk_srea_dev(fs->ff_c.fs_devid, DN_DISKINFO,
  301:                                 &fs->ff_c.fs_diskinfo, sizeof(DiskInfo), &sz);
  302:         if (err < E_OK) goto exit0;
  303: 
  304:         if (DSECSZ(fs) == 0) {
  305:                 err = EX_NXIO;                        /* Media does not exist */
  306:         } else if (fs->ff_c.fs_diskinfo.protect != 0) {
  307:                 fs->ff_c.fs_rdonly = TRUE;    /* Media is protected */
  308:         }
  309: exit0:
  310:         return err;
  311: }
  312: 
  313: /*
  314:  *  Disk close
  315:  */
  316: LOCAL   void      fatDiskClose(const coninf_t *coninf, FATFS *fs)
  317: {
  318:         (void)tk_cls_dev(fs->ff_c.fs_devid, 0);
  319: }
  320: 
  321: /*
  322:  *  Disk device number
  323:  */
  324: LOCAL   ER        fatGetDeviceNumber(UB *devnm, W *devnum)
  325: {
  326:         ID     devid;
  327: 
  328:         devid = tk_ref_dev(devnm, NULL);
  329:         if (devid >= E_OK) {
  330:                 *devnum = (W)devid;
  331:         }
  332:         return devid;
  333: }
  334: 
  335: /*----------------------------------------------------------------------------
  336:         Disk cache operations
  337: ----------------------------------------------------------------------------*/
  338: 
  339: /*
  340:  *  Sync a disk cache page
  341:  */
  342: LOCAL   ER        fatDCacheSyncPage(FATFS *fs, DCachePage *page, VW info)
  343: {
  344:         ER     err;
  345: 
  346:         err = E_OK;
  347:         if (info == 0 || page->dcp_info == 0 || page->dcp_info == info) {
  348:                 if (page->dcp_update != FALSE) {
  349:                         err = fatDiskWrite(fs, page->dcp_secno,
  350:                                         page->dcp_buf, page->dcp_seclen);
  351:                         page->dcp_update = FALSE;
  352:                         page->dcp_dcinf->dci_updatecnt--;
  353:                 }
  354:                 page->dcp_info = 0;
  355:         }
  356:         return err;
  357: }
  358: 
  359: /*
  360:  *  Initialize disk cache information
  361:  */
  362: LOCAL   ER        fatDCacheInfoInit(FATFS *fs, DCacheInfo *dcinf, D secno,
  363:                                                 D seclen, UW memsz, UW ratio)
  364: {
  365:         DCachePage     *page;
  366:         UB             *buf;
  367:         UW             pagememsz;
  368:         W              i;
  369:         ER             err;
  370: 
  371:         err = E_OK;
  372: 
  373:         /* Calcurate cache page size */
  374:         if (ratio != 1 && (ratio % 2) != 0) {
  375:                 err = EX_INVAL;
  376:                 goto exit0;
  377:         }
  378:         pagememsz = ratio * DSECSZ(fs);
  379: 
  380:         dcinf->dci_secno = secno;
  381:         dcinf->dci_endsec = secno + seclen;
  382:         dcinf->dci_ratio = ratio;
  383:         dcinf->dci_pagelen = memsz / pagememsz;
  384:         if (dcinf->dci_pagelen == 0) {
  385:                 err = EX_INVAL;
  386:                 goto exit0;
  387:         }
  388: 
  389:         /* Allocate CachePage structure */
  390:         buf = (UB *)fimp_calloc(dcinf->dci_pagelen, sizeof(DCachePage));
  391:         if (buf == NULL) {
  392:                 err = EX_NOMEM;
  393:                 goto exit0;
  394:         }
  395:         dcinf->dci_pages = (DCachePage *)buf;
  396: 
  397:         /* Allocate Cache buffer */
  398:         buf = (UB *)fimp_malloc(dcinf->dci_pagelen * pagememsz);
  399:         if (buf == NULL) {
  400:                 fimp_free(dcinf->dci_pages);
  401:                 dcinf->dci_pages = NULL;
  402:                 err = EX_NOMEM;
  403:                 goto exit0;
  404:         }
  405:         dcinf->dci_bufs = buf;
  406: 
  407:         /* Initialize queues */
  408:         for (i = 0; i < DCI_NHSQUE; i++) {
  409:                 QueInit(&dcinf->dci_hsque[i]);
  410:         }
  411:         QueInit(&dcinf->dci_freeque);
  412:         QueInit(&dcinf->dci_useque);
  413:         QueInit(&dcinf->dci_actque);
  414: 
  415:         /* Initialize CachePages */
  416:         for (i = 0; i < dcinf->dci_pagelen; i++) {
  417:                 page = &dcinf->dci_pages[i];
  418:                 page->dcp_dcinf = dcinf;
  419:                 page->dcp_secno = SECVOID;
  420:                 //page->dcp_seclen = 0;
  421:                 //page->dcp_accnt = 0;
  422:                 //page->dcp_update = FALSE;
  423:                 //page->dcp_info = 0;
  424:                 page->dcp_buf = &dcinf->dci_bufs[pagememsz * i];
  425:                 /* Insert to freeque */
  426:                 QueInsert(&page->dcp_q, &dcinf->dci_freeque);
  427:         }
  428: exit0:
  429:         return err;
  430: }
  431: 
  432: /*
  433:  *  Cleanup disk cache information
  434:  */
  435: LOCAL   void      fatDCacheInfoCleanup(FATFS *fs, DCacheInfo *dcinf)
  436: {
  437:         QUEUE  *q;
  438: 
  439:         /* Sync active pages */
  440:         for (q = dcinf->dci_actque.next;
  441:                                 q != &dcinf->dci_actque; q = q->next) {
  442:                 (void)fatDCacheSyncPage(fs, PageFromActque(q), 0);
  443:         }
  444: 
  445:         /* Sync use pages */
  446:         for (q = dcinf->dci_useque.next;
  447:                                 q != &dcinf->dci_useque; q = q->next) {
  448:                 (void)fatDCacheSyncPage(fs, PageFromUseque(q), 0);
  449:         }
  450: 
  451:         /* Free cache */
  452:         fimp_free(dcinf->dci_pages);
  453:         fimp_free(dcinf->dci_bufs);
  454:         memset(dcinf, 0, sizeof(DCacheInfo));
  455: }
  456: 
  457: /*
  458:  *  Read disk cache
  459:  */
  460: LOCAL   ER        fatDCacheRead(FATFS *fs, DCachePage ** pagep)
  461: {
  462:         ER             err;
  463:         DCachePage     *page;
  464: 
  465:         page = *pagep;
  466:         err = E_OK;
  467: 
  468:         if (page->dcp_read == FALSE) {
  469:                 err = fatDiskRead(fs, page->dcp_secno, page->dcp_buf,
  470:                                                         page->dcp_seclen);
  471:                 if (err < E_OK) {
  472:                         /* Remove from actque and hsque, insert to freeque */
  473:                         QueRemove(&page->dcp_uq);
  474:                         QueRemove(&page->dcp_q);
  475:                         QueInsert(&page->dcp_q, &page->dcp_dcinf->dci_freeque);
  476:                         *pagep = NULL;
  477:                 } else {
  478:                         page->dcp_read = TRUE;
  479:                 }
  480:         }
  481:         return err;
  482: }
  483: 
  484: /*
  485:  *  Search disk cache use page
  486:  */
  487: LOCAL   ER        fatDCacheSearchUsedPage(FATFS *fs, DCacheInfo *dcinf, D sec,
  488:                                                 DCachePage ** pagep)
  489: {
  490:         DCachePage     *page;
  491:         QUEUE          *q, *hsq;
  492:         D              secno;
  493:         ER             err;
  494: 
  495:         page = NULL;
  496: 
  497:         /* Check sector number */
  498:         if (sec < dcinf->dci_secno || sec >= dcinf->dci_endsec) {
  499:                 err = EX_INVAL;
  500:                 goto exit0;
  501:         }
  502: 
  503:         /* Search used and active page using hsque (hash queue) */
  504:         secno = sec - ((sec - dcinf->dci_secno) % dcinf->dci_ratio);
  505:         hsq = &dcinf->dci_hsque[(secno / dcinf->dci_ratio) & DCI_HSQUEMSK];
  506: 
  507:         err = E_OK;
  508:         if (isQueEmpty(hsq) == FALSE) {
  509:                 for (q = hsq->next; q != hsq; q = q->next) {
  510:                         if (PageFromHsque(q)->dcp_secno != secno) continue;
  511:                         /* Found */
  512:                         page = PageFromHsque(q);
  513:                         if (page->dcp_accnt++ == 0) {
  514:                                 /* Move from useque to actque */
  515:                                 QueRemove(&page->dcp_uq);
  516:                                 QueInsert(&page->dcp_uq, &dcinf->dci_actque);
  517:                         }
  518:                         break;
  519:                 }
  520:         }
  521: exit0:
  522:         *pagep = page;
  523:         return err;
  524: }
  525: 
  526: /*
  527:  *  Search disk cache page with/ithout read
  528:  */
  529: LOCAL   ER        fatDCacheSearchPage(FATFS *fs, DCacheInfo *dcinf, D sec,
  530:                                         DCachePage ** pagep, BOOL read)
  531: {
  532:         DCachePage     *page;
  533:         D              secno;
  534:         UW             seclen;
  535:         ER             err;
  536: 
  537:         /* Search used / active page */
  538:         err = fatDCacheSearchUsedPage(fs, dcinf, sec, &page);
  539:         if (err < E_OK || page != NULL) goto exit0;    /* OK or error */
  540: 
  541:         /* Not found, get new page */
  542:         if (isQueEmpty(&dcinf->dci_freeque) == FALSE) {
  543:                 /* Get a page from freeque */
  544:                 page = PageFromFreeque(dcinf->dci_freeque.next);
  545:                 QueRemove(&page->dcp_q);      /* Remove from freeque */
  546: 
  547:         } else if (isQueEmpty(&dcinf->dci_useque) == FALSE) {
  548:                 /* No free page, use oldest used page at the top of useque.
  549:                    Do not use active page in actque. */
  550:                 page = PageFromUseque(dcinf->dci_useque.next);
  551:                 err = fatDCacheSyncPage(fs, page, 0);
  552:                 if (err >= E_OK) {
  553:                         /* Remove from both useque and hsque */
  554:                         QueRemove(&page->dcp_uq);
  555:                         QueRemove(&page->dcp_q);
  556:                 }
  557:         } else {
  558:                 /* All pages are used */
  559:                 err = EX_NOMEM;
  560:                 goto exit0;
  561:         }
  562: 
  563:         /* Initialize page info */
  564:         page->dcp_accnt = 1;
  565:         page->dcp_read = FALSE;
  566:         page->dcp_update = FALSE;
  567:         page->dcp_info = 0;
  568:         secno = sec - ((sec - dcinf->dci_secno) % dcinf->dci_ratio);
  569:         seclen = dcinf->dci_ratio;
  570:         if (secno + seclen > dcinf->dci_endsec) {
  571:                 seclen = dcinf->dci_endsec - secno;
  572:         }
  573:         page->dcp_secno = secno;
  574:         page->dcp_seclen = seclen;
  575:         /* Insert page to both actque and hsque */
  576:         QueInsert(&page->dcp_uq, &dcinf->dci_actque);
  577:         QueInsert(&page->dcp_q,
  578:                 &dcinf->dci_hsque[(secno / dcinf->dci_ratio) & DCI_HSQUEMSK]);
  579: exit0:
  580:         *pagep = page;
  581:         if (err >= E_OK && read != FALSE) {
  582:                 /* Read from disk */
  583:                 err = fatDCacheRead(fs, pagep);
  584:         }
  585:         return err;
  586: }
  587: 
  588: /*
  589:  *  Disk cache get info
  590:  */
  591: LOCAL   void      fatDCacheGetDcinf(FATFS *fs, D sec, DCacheInfo ** dcinf)
  592: {
  593:         if (   sec >= fs->ff_dc_fat.dci_secno &&
  594:                 sec <  fs->ff_dc_fat.dci_endsec) {
  595:                 /* For FAT */
  596:                 *dcinf = &fs->ff_dc_fat;
  597: 
  598:         } else if (! isFAT32(fs->ff_fstype) &&
  599:                 sec >= fs->ff_dc_rootdir.dci_secno &&
  600:                 sec <  fs->ff_dc_rootdir.dci_endsec) {
  601:                 /* For Root directory */
  602:                 *dcinf = &fs->ff_dc_rootdir;
  603: 
  604:         } else if (sec >= fs->ff_dc_data.dci_secno &&
  605:                     sec <  fs->ff_dc_data.dci_endsec) {
  606:                 /* For Data */
  607:                 *dcinf = &fs->ff_dc_data;
  608: 
  609:         } else {
  610:                 /* For FSInfo, reserved serctors */
  611:                 *dcinf = &fs->ff_dc_other;
  612:         }
  613: }
  614: 
  615: /*
  616:  *  Disk cache start
  617:  */
  618: LOCAL   ER        fatDCacheStart(FATFS *fs, D sec, DCachePage ** page)
  619: {
  620:         DCacheInfo     *dcinf;
  621: 
  622:         *page = NULL;
  623:         fatDCacheGetDcinf(fs, sec, &dcinf);
  624:         return fatDCacheSearchPage(fs, dcinf, sec, page, TRUE);
  625: }
  626: 
  627: /*
  628:  *  Disk cache end
  629:  */
  630: LOCAL   ER        fatDCacheEnd(FATFS *fs, DCachePage *page)
  631: {
  632:         ER     err;
  633: 
  634:         err = E_OK;
  635: 
  636:         if (--page->dcp_accnt <= 0) {
  637: #if     FAT_SYNC_WITH_CACHEEND
  638:                 err = fatDCacheSyncPage(fs, page, 0);
  639: #endif
  640:                 page->dcp_info = 0;
  641:                 page->dcp_accnt = 0;
  642: 
  643:                 /* Move from actque to useque */
  644:                 QueRemove(&page->dcp_uq);
  645:                 QueInsert(&page->dcp_uq, &page->dcp_dcinf->dci_useque);
  646:         }
  647:         return err;
  648: }
  649: 
  650: /*
  651:  *  Disk cache update
  652:  */
  653: LOCAL   ER        fatDCacheUpdate(FATFS *fs, DCachePage *page, VW info)
  654: {
  655:         if (page->dcp_update == FALSE) {
  656:                 page->dcp_dcinf->dci_updatecnt++;
  657:                 page->dcp_update = TRUE;
  658:         }
  659:         page->dcp_read = TRUE;
  660:         page->dcp_info = info;
  661:         return E_OK;
  662: }
  663: 
  664: /*
  665:  *  Disk cache sync info
  666:  */
  667: LOCAL   ER        fatDCacheSyncInfo(FATFS *fs, DCacheInfo *dcinf, VW info)
  668: {
  669:         QUEUE  *q;
  670:         ER     err, err2;
  671: 
  672:         err = E_OK;
  673:         CHK_BREAK_AND_SET_ERR(fs, &err);
  674:         if (err < E_OK) goto exit0;
  675: 
  676:         /* Sync pages in actque */
  677:         for (q = dcinf->dci_actque.next; q != &dcinf->dci_actque &&
  678:                 dcinf->dci_updatecnt > 0 && err != EX_INTR; q = q->next) {
  679:                 err2 = fatDCacheSyncPage(fs, PageFromActque(q), info);
  680:                 SetErr2(err, err2);
  681:                 CHK_BREAK_AND_SET_ERR(fs, &err);
  682:         }
  683: 
  684:         /* Sync pages in useque */
  685:         for (q = dcinf->dci_useque.next; q != &dcinf->dci_useque &&
  686:                 dcinf->dci_updatecnt > 0 && err != EX_INTR; q = q->next) {
  687:                 err2 = fatDCacheSyncPage(fs, PageFromUseque(q), info);
  688:                 SetErr2(err, err2);
  689:                 CHK_BREAK_AND_SET_ERR(fs, &err);
  690:         }
  691: exit0:
  692:         return err;
  693: }
  694: 
  695: /*
  696:  *  Disk cache sync FS
  697:  */
  698: LOCAL   ER        fatDCacheSyncFS(FATFS *fs, VW info)
  699: {
  700:         ER     err, err2;
  701: 
  702:         err = E_OK;
  703:         if (fs->ff_c.fs_rdonly != FALSE) goto exit0;
  704: 
  705:         /* Cache for fsinfo, reserved sectors */
  706:         err2 = fatDCacheSyncInfo(fs, &fs->ff_dc_other, info);
  707:         SetErr2(err, err2);
  708: 
  709:         /* Cache for FAT */
  710:         err2 = fatDCacheSyncInfo(fs, &fs->ff_dc_fat, info);
  711:         SetErr2(err, err2);
  712: 
  713:         /* Cache for root directory */
  714:         if (! isFAT32(fs->ff_fstype)) {
  715:                 err2 = fatDCacheSyncInfo(fs, &fs->ff_dc_rootdir, info);
  716:                 SetErr2(err, err2);
  717:         }
  718: 
  719:         /* Cache for file data */
  720:         err2 = fatDCacheSyncInfo(fs, &fs->ff_dc_data, info);
  721:         SetErr2(err, err2);
  722: exit0:
  723:         return err;
  724: }
  725: 
  726: /*
  727:  *  Initialize disk caches
  728:  */
  729: LOCAL   ER        fatDCacheInit(FATFS *fs)
  730: {
  731:         ER     err;
  732: 
  733:         /* Cache for FAT */
  734:         err = fatDCacheInfoInit(fs, &fs->ff_dc_fat, fs->ff_fat, fs->ff_fatsz,
  735:                         CacheFATMemorySize, CacheFATRatio);
  736:         if (err < E_OK) goto exit0;
  737: 
  738:         /* Cache for root direcotry */
  739:         if (! isFAT32(fs->ff_fstype)) {
  740:                 err = fatDCacheInfoInit(fs, &fs->ff_dc_rootdir, fs->ff_rootsc,
  741:                                 ROOTSZ / DSECSZ(fs),
  742:                                 CacheRootMemorySize, CacheRootRatio);
  743:                 if (err < E_OK) goto exit0;
  744:         }
  745: 
  746:         /* Cache for file data */
  747:         err = fatDCacheInfoInit(fs, &fs->ff_dc_data, fs->ff_clstart,
  748:                         CNtoBN(fs->ff_lastcl + 1) - fs->ff_clstart,
  749:                         CacheDataMemorySize,
  750:                         (CacheDataRatio == 0) ? fs->ff_ratio : CacheDataRatio);
  751:         if (err < E_OK) goto exit0;
  752: 
  753:         /* Cache for fsinfo, reserved sectors */
  754:         err = fatDCacheInfoInit(fs, &fs->ff_dc_other, 1, fs->ff_fat - 1,
  755:                         DSECSZ(fs) * 2, 1);
  756: exit0:
  757:         return err;
  758: }
  759: 
  760: /*
  761:  *  Cleanup disk caches
  762:  */
  763: LOCAL   void      fatDCacheCleanup(FATFS *fs)
  764: {
  765:         /* FSInfo, reserved sectors */
  766:         fatDCacheInfoCleanup(fs, &fs->ff_dc_other);
  767: 
  768:         /* FAT */
  769:         fatDCacheInfoCleanup(fs, &fs->ff_dc_fat);
  770: 
  771:         /* Root directory */
  772:         if (! isFAT32(fs->ff_fstype)) {
  773:                 fatDCacheInfoCleanup(fs, &fs->ff_dc_rootdir);
  774:         }
  775: 
  776:         /* Data */
  777:         fatDCacheInfoCleanup(fs, &fs->ff_dc_data);
  778: }
  779: 
  780: /*
  781:  *  Fsync if the file have O_SYNC flag.
  782:  */
  783: LOCAL   ER        fatFDSync(FD *fd)
  784: {
  785:         return isSET(fd->fd_omode, O_SYNC) ?
  786:                 fatDCacheSyncFS((FATFS*)fd->fd_fs, (VW)fd->fd_inode) : E_OK;
  787: }
  788: 
  789: /*----------------------------------------------------------------------------
  790:         Disk map operations
  791: ----------------------------------------------------------------------------*/
  792: 
  793: /*
  794:  *  End disk map
  795:  */
  796: LOCAL   ER        fatMapEnd(MapInfo *map)
  797: {
  798:         return (map->m_page == NULL) ? E_OK :
  799:                                 fatDCacheEnd(map->m_fs, map->m_page);
  800: }
  801: 
  802: /*
  803:  *  Unmap disk map
  804:  */
  805: LOCAL   void      fatUnmapDisk(MapInfo *map)
  806: {
  807:         memset(map, 0, sizeof(MapInfo));
  808: }
  809: 
  810: /*
  811:  *  Get the sector and cache page of specified offset
  812:  *      map->m_page : result cache page
  813:  */
  814: LOCAL   ER        fatMapGetCache(MapInfo *map, D offset, UW *bufofs, BOOL isread)
  815: {
  816:         FATFS  *fs;
  817:         D      sec;
  818:         UW     off, toff, secsz;
  819:         CLAD   *clp, *cle;
  820:         ER     err;
  821: 
  822:         fs = map->m_fs;
  823:         secsz = DSECSZ(fs);
  824: 
  825:         /* Calcurate sector / cluster offset */ 
  826:         off = offset / (isSET(map->m_flags, MAP_C) ? fs->ff_clsz : secsz);
  827: 
  828:         /* Search cluster / sector at offset byte */
  829:         clp = map->m_clad;
  830:         cle = clp + map->m_clen;
  831: 
  832:         /* Use last offset for fast search */
  833:         if ((toff = map->m_lastoff) <= off) {
  834:                 clp += map->m_lastix;
  835:         } else {
  836:                 toff = 0;
  837:         }
  838: 
  839:         for ( ; clp < cle && (toff += clp->ca_len) <= off; clp++);
  840:         if (clp >= cle) {
  841:                 err = EX_INVAL;
  842:                 goto exit0;
  843:         }
  844: 
  845:         map->m_btop = CLVOID;                          /* Invalidate data ix */
  846:         map->m_bend = 0;
  847:         map->m_lastix = clp - map->m_clad;             /* Save last info */
  848:         map->m_lastoff = toff - clp->ca_len;
  849:         sec = clp->ca_no + (off - map->m_lastoff);     /* Sector number */
  850: 
  851:         if (isSET(map->m_flags, MAP_C)) {
  852:                 /* Convert sector to cluster number */
  853:                 sec = CNtoBN(sec);
  854:                 /* Add sector offset within cluster */
  855:                 sec += offset / secsz - (off * fs->ff_ratio);
  856:         }
  857: 
  858:         /* Get mapped page */
  859:         if (map->m_page == NULL ||
  860:                 sec < map->m_page->dcp_secno ||
  861:                 sec >= map->m_page->dcp_secno + map->m_page->dcp_seclen) {
  862:                 if (map->m_page != NULL) {
  863:                         err = fatDCacheEnd(fs, map->m_page);
  864:                         if (err < E_OK) goto exit0;
  865:                 }
  866:                 /* Search mapped page of the sector */
  867:                 err = fatDCacheSearchPage(fs, map->m_dcinf, sec,
  868:                                                 &map->m_page, isread);
  869:                 if (err < E_OK) goto exit0;
  870:         }
  871: 
  872:         /* Set cache page offset bytes */
  873:         *bufofs = (sec - map->m_page->dcp_secno) * secsz + (offset % secsz);
  874:         return E_OK;
  875: exit0:
  876:         return err;
  877: }
  878: 
  879: /*
  880:  *  Get disk map information for read
  881:  */
  882: LOCAL   ER        fatMapRead(MapInfo *map, D *offset, UB **sp, UW *len, UB **ep)
  883: {
  884:         FATFS  *fs;
  885:         UW     bufofs, sz;
  886:         ER     err;
  887: 
  888:         fs = map->m_fs;
  889:         err = fatMapGetCache(map, *offset, &bufofs, TRUE);
  890:         if (err < E_OK) goto exit0;
  891: 
  892:         sz = map->m_bpp - bufofs;              /* Remain size */
  893:         *offset += sz;                         /* Next offset */
  894:         *sp = &map->m_page->dcp_buf[bufofs];   /* Map start pointer */
  895:         if (sz > *len) sz = *len;              /* Map length */
  896:         *len -= sz;                            /* Remain length */
  897:         *ep = *sp + sz;                                /* Map end pointer */
  898: exit0:
  899:         return err;
  900: }
  901: 
  902: /*
  903:  *  Read N bytes from disk map
  904:  */
  905: LOCAL   ER        fatMapReadBytes(MapInfo *map, D offset, UB *buf, UW len)
  906: {
  907:         FATFS  *fs;
  908:         UW     bufofs, dofs, sz;
  909:         ER     err;
  910: 
  911:         err = E_OK;
  912:         fs = map->m_fs;
  913:         for (dofs = 0; len > 0; len -= sz, dofs += sz) {
  914:                 err = fatMapGetCache(map, offset, &bufofs, TRUE);
  915:                 if (err < E_OK) break;
  916: 
  917:                 sz = map->m_bpp - bufofs;
  918:                 if (sz > len) sz = len;
  919: 
  920:                 memcpy(&buf[dofs], &map->m_page->dcp_buf[bufofs], sz);
  921:                 offset += sz;
  922:         }
  923:         if (len > 0) {
  924:                 CHK_BREAK_AND_SET_ERR(fs, &err);
  925:         }
  926:         return err;
  927: }
  928: 
  929: /*
  930:  *  Write N bytes to disk map (write 0 when buf == NULL)
  931:  */
  932: LOCAL   ER        fatMapWriteBytes(MapInfo *map, D offset, const UB *buf, D len)
  933: {
  934:         FATFS          *fs;
  935:         DCachePage     *page;
  936:         UW             bufofs, dofs, sz;
  937:         ER             err;
  938: 
  939:         err = E_OK;
  940:         fs = map->m_fs;
  941:         for (dofs = 0; len > 0; len -= sz, dofs += sz) {
  942:                 err = fatMapGetCache(map, offset, &bufofs, FALSE);
  943:                 if (err < E_OK) break;
  944: 
  945:                 page = map->m_page;
  946:                 if (bufofs != 0 || len < map->m_bpp) {
  947:                         err = fatDCacheRead(fs, &page);
  948:                         if (err < E_OK) break;
  949:                 }
  950:                 sz = map->m_bpp - bufofs;
  951:                 if (sz > len) sz = len;
  952: 
  953:                 if (buf == NULL) {
  954:                         memset(&page->dcp_buf[bufofs], 0, sz);
  955:                 } else {
  956:                         memcpy(&page->dcp_buf[bufofs], &buf[dofs], sz);
  957:                 }
  958: 
  959:                 offset += sz;
  960:                 err = fatDCacheUpdate(fs, page, map->m_info);
  961:                 if (err < E_OK) break;
  962:         }
  963:         if (len > 0) {
  964:                 CHK_BREAK_AND_SET_ERR(fs, &err);
  965:         }
  966:         return err;
  967: }
  968: 
  969: /*
  970:  *  Map disk cluster or sector
  971:  */
  972: LOCAL   ER        fatMapDisk(FATFS *fs, CLAD *clad, W len, MapInfo *map,
  973:                                                         W flags, VW info)
  974: {
  975:         DCacheInfo     *dcinf;
  976:         D              sec, sa, ea;
  977:         W              i, secsz;
  978:         UW             cnt;
  979:         ER             err, err2;
  980: 
  981:         /* Clear map */
  982:         memset(map, 0, sizeof(MapInfo));
  983: 
  984:         /* Initialize cache information */
  985:         if (isSET(flags, MAP_C)) {
  986:                 sec = CNtoBN(clad[0].ca_no);
  987:                 fatDCacheGetDcinf(fs, sec, &dcinf);
  988:                 sa = BNtoCN(dcinf->dci_secno);
  989:                 ea = BNtoCN(dcinf->dci_endsec);
  990:         } else {
  991:                 sec = clad[0].ca_no;
  992:                 fatDCacheGetDcinf(fs, sec, &dcinf);
  993:                 sa = dcinf->dci_secno;
  994:                 ea = dcinf->dci_endsec - 1;
  995:         }
  996: 
  997:         /* Check clad[] */
  998:         err = E_OK;
  999:         for (i = 0; i < len; i++) {
 1000:                 if (sa > clad[i].ca_no ||
 1001:                         ea < (clad[i].ca_no + clad[i].ca_len - 1)) {
 1002:                         err = EX_INVAL;
 1003:                         break;
 1004:                 }
 1005:         }
 1006:         if (err < E_OK) goto exit0;
 1007: 
 1008:         /* Initialize map inromation */
 1009:         map->m_fs = fs;
 1010:         map->m_dcinf = dcinf;
 1011:         map->m_flags = flags;
 1012:         map->m_info = info;
 1013:         map->m_clad = clad;
 1014:         map->m_clen = len;
 1015:         //map->m_lastoff = 0;
 1016:         //map->m_lastix = 0;
 1017:         //map->m_page = NULL;
 1018:         secsz = DSECSZ(fs);
 1019:         map->m_bpp = dcinf->dci_ratio * secsz;
 1020:         map->m_btop = CLVOID;
 1021: 
 1022:         /* Clear Map area */
 1023:         if (isSET(flags, MAP_CLR)) {
 1024:                 for (cnt = 0, i = 0; i < len; i++) {
 1025:                         cnt += clad[i].ca_len;
 1026:                 }
 1027:                 if (cnt > 0) {
 1028:                         err = fatMapWriteBytes(map, 0, NULL, (D)cnt *
 1029:                                 (isSET(flags, MAP_C) ? fs->ff_clsz : secsz));
 1030:                         err2 = fatMapEnd(map);
 1031:                         SetErr2(err, err2);
 1032:                 }
 1033:         } else if (isSET(flags, MAP_READ)) {
 1034:                 /* Read first cache page */
 1035:                 err = fatDCacheSearchPage(fs, dcinf, sec, &map->m_page, TRUE);
 1036:         }
 1037: exit0:
 1038:         return err;
 1039: }
 1040: 
 1041: /*
 1042:  *  Initialize FAT sector map
 1043:  */
 1044: LOCAL   ER        fatMapFATInit(FATFS *fs)
 1045: {
 1046:         fs->ff_fatmap_s[0].ca_no = fs->ff_fat;
 1047:         fs->ff_fatmap_s[0].ca_len = fs->ff_fatsz;
 1048: 
 1049:         return fatMapDisk(fs, fs->ff_fatmap_s, NUM_FATMAP_S,
 1050:                                         &fs->ff_fatmap, MAP_S, 0);
 1051: }
 1052: 
 1053: /*
 1054:  *  Cleanup FAT sector map
 1055:  */
 1056: LOCAL   void      fatMapFATCleanup(FATFS *fs)
 1057: {
 1058:         fatUnmapDisk(&fs->ff_fatmap);
 1059: }
 1060: 
 1061: /*----------------------------------------------------------------------------
 1062:         FAT inode queue operations
 1063: ----------------------------------------------------------------------------*/
 1064: 
 1065: /*
 1066:  *  Initilization of file reference node connection queue
 1067:  */
 1068: LOCAL   void      fatInodeQueInit(FS *fs)
 1069: {
 1070:         W      i;
 1071: 
 1072:         for (i = 0; i < FS_NIQUE; i++) {
 1073:                 QueInit(&fs->fs_ique[i]);
 1074:         }
 1075: }
 1076: 
 1077: /*
 1078:  *  Check file reference node in connection queue.
 1079:  */
 1080: LOCAL   ER        fatInodeCheckEmpty(FS *fs, INODE *ignorenode)
 1081: {
 1082:         QUEUE  *q;
 1083:         W      i;
 1084: 
 1085:         for (i = 0; i < FS_NIQUE; i++) {
 1086:                 if (isQueEmpty(&fs->fs_ique[i]) != FALSE) continue;
 1087:                 for (q = fs->fs_ique[i].next;
 1088:                                 q != &fs->fs_ique[i]; q = q->next) {
 1089:                         if ((INODE *)q != ignorenode) {
 1090:                                 return EX_BUSY;
 1091:                         }
 1092:                 }
 1093:         }
 1094:         return E_OK;
 1095: }
 1096: 
 1097: /*
 1098:  *  Regist file reference node in connection queue.
 1099:  */
 1100: LOCAL   void      fatInodeRegister(FS *fs, INODE *inode, UB omode)
 1101: {
 1102:         /* Stop the root directory and standard input-output */
 1103:         if (inode != NULL) {
 1104:                 /* Update of the number of references */
 1105:                 if (isNOT_RDONLY(omode)) {
 1106:                         inode->ino_wrefcnt++;
 1107:                 }
 1108:                 if (inode->ino_refcnt++ <= 0) {
 1109:                         /* Insert into queue at 1st time */
 1110:                         QueInsert(&inode->ino_q,
 1111:                                 &fs->fs_ique[(UW)inode->ino_ino & FS_IQUEMSK]);
 1112:                 }
 1113:         }
 1114: }
 1115: 
 1116: /*
 1117:  *  Delete file reference node
 1118:  */
 1119: LOCAL   void      fatInodeFree(FS *fs, INODE *inode)
 1120: {
 1121:         /* Stop root directory and standard input-output */
 1122:         if (inode != NULL) {
 1123:                 /* Delete if there is no reference */
 1124:                 if (inode->ino_refcnt <= 0) {
 1125:                         if (inode->ino_path != NULL &&
 1126:                                 inode->ino_path != inode_root_path) {
 1127:                                 fimp_free(inode->ino_path);
 1128:                         }
 1129:                         if (inode->ino_info != NULL) {
 1130:                                 fimp_free(inode->ino_info);
 1131:                         }
 1132:                         if (inode != (INODE*)&((FATFS*)fs)->ff_rootnode) {
 1133:                                 fimp_free(inode);
 1134:                         } else {
 1135:                                 memset(inode, 0, sizeof(INODE));
 1136:                         }
 1137:                 }
 1138:         }
 1139: }
 1140: 
 1141: /*
 1142:  *  Release file reference node from connection queue
 1143:  */
 1144: LOCAL   void      fatInodeRelease(FS *fs, INODE *inode, UB omode)
 1145: {
 1146:         /* Stop root directory and standard input-output */
 1147:         if (inode != NULL) {
 1148:                 /* Stop writing reference */
 1149:                 if (isNOT_RDONLY(omode)) {
 1150:                         if (--inode->ino_wrefcnt <= 0) {
 1151:                                 (void)fatDCacheSyncFS((FATFS *)fs, (VW)inode);
 1152:                         }
 1153:                 }
 1154:                 /* Stop reference */
 1155:                 if (--inode->ino_refcnt <= 0) {
 1156:                         /* Delete from queue */
 1157:                         QueRemove(&inode->ino_q);
 1158: 
 1159:                         /* Release of file reference node */
 1160:                         fatInodeFree(fs, inode);
 1161:                 }
 1162:         }
 1163: }
 1164: 
 1165: /*
 1166:  *  Search of file reference node
 1167:  */
 1168: LOCAL   INODE     *fatInodeSearch(FS *fs, UD ino)
 1169: {
 1170:         QUEUE  *iq, *q;
 1171: 
 1172:         /* Search */
 1173:         iq = &fs->fs_ique[(UW)ino & FS_IQUEMSK];
 1174:         for (q = iq->next; q != iq; q = q->next) {
 1175:                 if (((INODE *)q)->ino_ino == ino) return (INODE *)q;
 1176:         }
 1177:         return NULL;
 1178: }
 1179: 
 1180: /*
 1181:  *  Queue transfer of file reference node
 1182:  */
 1183: LOCAL   void      fatInodeChangeQue(FS *fs, INODE *inode)
 1184: {
 1185:         if (inode->ino_refcnt > 0) {
 1186:                 /* Queue remove */
 1187:                 QueRemove(&inode->ino_q);
 1188:                 QueInsert(&inode->ino_q,
 1189:                         &fs->fs_ique[(UW)inode->ino_ino & FS_IQUEMSK]);
 1190:         }
 1191: }
 1192: 
 1193: /*----------------------------------------------------------------------------
 1194:         File descriptor operations
 1195: ----------------------------------------------------------------------------*/
 1196: 
 1197: /*
 1198:  *  Search file descriptor
 1199:  */
 1200: LOCAL   ER        fatSearchFileDesc(FS *fs, FD **fdp, W fildes)
 1201: {
 1202:         FD     *fd;
 1203: 
 1204:         if (fs->fs_uxinfo.uxi_fdtbl != NULL) {
 1205:                 if (fildes >= 0 && fildes < MaxOpenF) {
 1206:                         fd = fs->fs_uxinfo.uxi_fdtbl[fildes];
 1207:                         if (fd != NULL && fd->fd_fs == fs) {
 1208:                                 *fdp = fd;
 1209:                                 return E_OK;
 1210:                         }
 1211:                 }
 1212:         }
 1213:         *fdp = NULL;
 1214:         return EX_BADF;
 1215: }
 1216: 
 1217: /*
 1218:  *  Create new file descriptor
 1219:  */
 1220: LOCAL   ER        fatNewFileDesc(FS *fs, FD **fdp, W *fdno)
 1221: {
 1222:         FD     *fd;
 1223:         W      i;
 1224:         ER     err;
 1225: 
 1226:         if (fs->fs_uxinfo.uxi_fdtbl == NULL) {
 1227:                 err = EX_NOBUFS;
 1228:                 goto exit0;
 1229:         }
 1230: 
 1231:         for (i = 0; i < MaxOpenF && fs->fs_uxinfo.uxi_fdtbl[i] != NULL; i++);
 1232: 
 1233:         if (i >= MaxOpenF) {
 1234:                 err = EX_NFILE;
 1235:         } else {
 1236:                 fd = (FD *)fimp_calloc(1, sizeof(FD));
 1237:                 if (fd == NULL) {
 1238:                         err = EX_NOMEM;
 1239:                 } else {
 1240:                         fd->fd_fs = fs;
 1241:                         fd->fd_inode = NULL;
 1242:                         fd->fd_fpos = 0;
 1243:                         fd->fd_refcnt = 1;
 1244: 
 1245:                         /* Registration of file descriptor */
 1246:                         fs->fs_uxinfo.uxi_fdtbl[i] = fd;
 1247: 
 1248:                         *fdp = fd;
 1249:                         *fdno = i;
 1250:                         err = E_OK;
 1251:                 }
 1252:         }
 1253: exit0:
 1254:         return err;
 1255: }
 1256: 
 1257: /*
 1258:  *  Delete file descriptor
 1259:  */
 1260: LOCAL   void      fatDelFileDesc(FS *fs, FD *fd, W fdno)
 1261: {
 1262:         fs->fs_uxinfo.uxi_fdtbl[fdno] = NULL;
 1263: 
 1264:         if (--fd->fd_refcnt <= 0) {
 1265:                 /* Release file reference node */
 1266:                 fatInodeRelease(fd->fd_fs, fd->fd_inode, fd->fd_omode);
 1267:                 fimp_free(fd);
 1268:         }
 1269: }
 1270: 
 1271: /*----------------------------------------------------------------------------
 1272:         Cluster operations
 1273: ----------------------------------------------------------------------------*/
 1274: 
 1275: /*
 1276:  *  Allocate or expand cluster address buffer
 1277:  */
 1278: LOCAL   ER        alloc_clbuf(CLAD **clbufp, UH *maxcl)
 1279: {
 1280:         CLAD   *clbuf;
 1281:         UH     ncl;
 1282:         VP     tmp;
 1283: 
 1284:         if ((clbuf = *clbufp) == NULL) {
 1285:                 /* Initial allocation */
 1286:                 clbuf = (CLAD *)fimp_malloc(sizeof(CLAD) * MAX_CLEN);
 1287:                 ncl = 1;
 1288:         } else {
 1289:                 /* Expand buffer */
 1290:                 ncl = *maxcl + 1;
 1291:                 tmp = fimp_realloc(clbuf, sizeof(CLAD) * ncl * MAX_CLEN);
 1292:                 if (tmp == NULL) {
 1293:                         fimp_free(clbuf);
 1294:                 }
 1295:                 clbuf = tmp;
 1296:         }
 1297:         *clbufp = clbuf;
 1298:         if (clbuf == NULL) {
 1299:                 *maxcl = 0;
 1300:                 return EX_NOMEM;
 1301:         }
 1302:         *maxcl = ncl;
 1303:         return E_OK;
 1304: }
 1305: 
 1306: /*
 1307:  *  Get next cluster number
 1308:  */
 1309: LOCAL   ER        fatGetCluster(MapInfo *map, UW clno, UW *ncl)
 1310: {
 1311:         UW     cl, bufofs, n;
 1312:         ER     err;
 1313: 
 1314:         cl = CLEND;
 1315:         err = E_OK;
 1316: 
 1317:         switch (map->m_fs->ff_fstype) {
 1318:         case FAT12:
 1319:         {
 1320:                 UB    buf[2];
 1321: 
 1322:                 err = fatMapReadBytes(map, clno + clno / 2, buf, 2);
 1323:                 if (err < E_OK) break;
 1324: 
 1325:                 cl = CEH(GetMisalignH(buf));
 1326:                 if ((clno & 1) != 0) cl >>= 4;
 1327:                 cl &= FAT12_MASK_VALID_CLST;
 1328:                 if (cl >= FAT12_EOC) cl = CLEND;
 1329:         }
 1330:                 break;
 1331: 
 1332:         case FAT16:
 1333:                 if (clno >= map->m_btop && clno < map->m_bend) {
 1334:                         /* Use last page cache */
 1335:                         n = clno - map->m_btop;
 1336:                 } else {
 1337:                         err = fatMapGetCache(map, clno * sizeof(UH),
 1338:                                                         &bufofs, TRUE);
 1339:                         if (err < E_OK) break;
 1340:                         map->m_btop = clno - (n = bufofs / sizeof(UH));
 1341:                         map->m_bend = map->m_btop + (map->m_bpp / sizeof(UH));
 1342:                 }
 1343:                 cl = CEH(((UH *)map->m_page->dcp_buf)[n]);
 1344:                 if (cl >= FAT16_EOC) cl = CLEND;
 1345:                 break;
 1346: 
 1347:         case FAT32:
 1348:         default:
 1349:                 if (clno >= map->m_btop && clno < map->m_bend) {
 1350:                         /* Use last page cache */
 1351:                         n = clno - map->m_btop;
 1352:                 } else {
 1353:                         err = fatMapGetCache(map, clno * sizeof(UW),
 1354:                                                         &bufofs, TRUE);
 1355:                         if (err < E_OK) break;
 1356:                         map->m_btop = clno - (n = bufofs / sizeof(UW));
 1357:                         map->m_bend = map->m_btop + (map->m_bpp / sizeof(UW));
 1358:                 }
 1359:                 cl = CEW(((UW *)map->m_page->dcp_buf)[n]);
 1360:                 cl &= FAT32_MASK_VALID_CLST;
 1361:                 if (cl >= FAT32_EOC) cl = CLEND;
 1362:                 break;
 1363:         }
 1364:         *ncl = cl;
 1365: 
 1366:         /* Check validity */
 1367:         if (err >= E_OK) {
 1368:                 if (cl < CLSTART || cl > map->m_fs->ff_lastcl) {
 1369:                         if (cl != CLEND) err = EX_IO;
 1370:                         /* Note, return EX_IO when cl == 0 */
 1371:                 }
 1372:         }
 1373:         return err;
 1374: }
 1375: 
 1376: /*
 1377:  *  Set cluster number
 1378:  */
 1379: LOCAL   ER        fatSetCluster(MapInfo *map, UW clno, UW new, UW *old)
 1380: {
 1381:         FATFS          *fs;
 1382:         UW             offset, cl, bufofs, n;
 1383:         ER             err;
 1384:         GPTR           dp;
 1385: 
 1386:         err = E_OK;
 1387:         fs = map->m_fs;
 1388:         switch (fs->ff_fstype) {
 1389:         case FAT12:
 1390:         {
 1391:                 UB    buf[2];
 1392: 
 1393:                 offset = clno + (clno / 2);
 1394:                 err = fatMapReadBytes(map, offset, buf, 2);
 1395:                 if (err < E_OK) break;
 1396: 
 1397:                 cl = CEH(GetMisalignH(buf));
 1398:                 new &= FAT12_MASK_VALID_CLST;
 1399:                 if ((clno & 1) != 0) {
 1400:                         new = (new << 4) | (cl & 0x0F);
 1401:                         cl >>= 4;
 1402:                 } else {
 1403:                         new |= (cl & 0xF000);
 1404:                 }
 1405:                 if (old != NULL) {
 1406:                         cl &= FAT12_MASK_VALID_CLST;
 1407:                         *old = (cl >= FAT12_EOC) ? CLEND : cl;
 1408:                 }
 1409:                 SetMisalignH(buf, (UH)CEH(new));
 1410:                 err = fatMapWriteBytes(map, offset, buf, 2);
 1411:                 break;
 1412:         }
 1413: 
 1414:         case FAT16:
 1415:                 if (clno >= map->m_btop && clno < map->m_bend) {
 1416:                         /* Use last page cache */
 1417:                         n = clno - map->m_btop;
 1418:                 } else {
 1419:                         err = fatMapGetCache(map, clno * sizeof(UH),
 1420:                                                         &bufofs, TRUE);
 1421:                         if (err < E_OK) break;
 1422:                         map->m_btop = clno - (n = bufofs / sizeof(UH));
 1423:                         map->m_bend = map->m_btop + (map->m_bpp / sizeof(UH));
 1424:                 }
 1425:                 dp.b = &map->m_page->dcp_buf[n * sizeof(UH)];
 1426:                 if (old != NULL) {
 1427:                         cl = CEH(*dp.h);
 1428:                         *old = (cl >= FAT16_EOC) ? CLEND : cl;
 1429:                 }
 1430:                 *dp.h = CEH(new);
 1431:                 err = fatDCacheUpdate(fs, map->m_page, map->m_info);
 1432:                 break;
 1433: 
 1434:         case FAT32:
 1435:         default:
 1436:                 if (clno >= map->m_btop && clno < map->m_bend) {
 1437:                         /* Use last page cache */
 1438:                         n = clno - map->m_btop;
 1439:                 } else {
 1440:                         err = fatMapGetCache(map, clno * sizeof(UW),
 1441:                                                         &bufofs, TRUE);
 1442:                         if (err < E_OK) break;
 1443:                         map->m_btop = clno - (n = bufofs / sizeof(UW));
 1444:                         map->m_bend = map->m_btop + (map->m_bpp / sizeof(UW));
 1445:                 }
 1446:                 dp.b = &map->m_page->dcp_buf[n * sizeof(UW)];
 1447:                 if (old != NULL) {
 1448:                         cl = CEW(*dp.w) & FAT32_MASK_VALID_CLST;
 1449:                         *old = (cl >= FAT32_EOC) ? CLEND : cl;
 1450:                 }
 1451:                 new &= FAT32_MASK_VALID_CLST;
 1452:                 *dp.w = CEW(new);
 1453:                 err = fatDCacheUpdate(fs, map->m_page, map->m_info);
 1454:                 break;
 1455:         }
 1456:         return err;
 1457: }
 1458: 
 1459: /*
 1460:  *  Get cluster list - from "clno" + "offset" bytes to the end.
 1461:  *      If "offset" is OFSNEXT, start from next of "clno".
 1462:  */
 1463: LOCAL   ER        fatGetClusterList(FATFS *fs, CLAD clad[], W cllen,
 1464:                                                 UW clno, UW offset, W *len)
 1465: {
 1466:         MapInfo        *map;
 1467:         UW     ncl, pos;
 1468:         W      n;
 1469:         ER     err;
 1470: 
 1471:         if (clno < CLSTART || clno > fs->ff_lastcl) {
 1472:                 err = EX_INVAL;
 1473:                 goto exit0;
 1474:         }
 1475: 
 1476:         pos = fs->ff_clsz;
 1477:         if (offset == OFSNEXT) {
 1478:                 offset = 0;
 1479:                 n = -1;
 1480:         } else {
 1481:                 n = (pos > offset) ? 0 : -1;
 1482:         }
 1483: 
 1484:         clad[0].ca_no = clno;
 1485:         clad[0].ca_len = 1;
 1486: 
 1487:         map = &fs->ff_fatmap;
 1488: 
 1489:         for (err = E_OK; err >= E_OK; clno = ncl) {
 1490:                 err = fatGetCluster(map, clno, &ncl);
 1491:                 if (err < E_OK || ncl == CLEND) break;
 1492: 
 1493:                 if (offset == 0 || (pos += fs->ff_clsz) > offset) {
 1494:                         if (ncl == clno + 1 && n >= 0) {
 1495:                                 clad[n].ca_len++;   /* continuous cluster */
 1496:                         } else {
 1497:                                 if (n + 1 >= cllen) break;
 1498:                                 clad[++n].ca_no = ncl;
 1499:                                 clad[n].ca_len = 1;
 1500:                         }
 1501:                 }
 1502:                 CHK_BREAK_AND_SET_ERR(fs, &err);
 1503:         }
 1504:         if (err >= E_OK) {
 1505:                 *len = n + 1;
 1506:         }
 1507:         (void)fatMapEnd(map);
 1508: exit0:
 1509:         return err;
 1510: }
 1511: 
 1512: /*
 1513:  *  Get a cluster just before "clno" started from "stcl"
 1514:  */
 1515: LOCAL   ER        fatGetPrevCluster(FATFS *fs, CLAD *clad, UW stcl, UW clno)
 1516: {
 1517:         MapInfo        *map;
 1518:         UW     ncl, cl;
 1519:         W      len;
 1520:         ER     err;
 1521: 
 1522:         if (stcl < CLSTART || stcl > fs->ff_lastcl) {
 1523:                 err = EX_INVAL;
 1524:                 goto exit0;
 1525:         }
 1526:         err = E_OK;
 1527:         if (stcl == CLEND || stcl == clno) goto exit0;
 1528: 
 1529:         map = &fs->ff_fatmap;
 1530: 
 1531:         for (cl = stcl, len = 1; ; stcl = ncl) {
 1532:                 err = fatGetCluster(map, stcl, &ncl);
 1533:                 if (err < E_OK) break;
 1534:                 if (ncl == CLEND) {
 1535:                         len = 0;
 1536:                         break;
 1537:                 }
 1538:                 if (ncl == clno) break;
 1539:                 if (ncl == stcl + 1) {
 1540:                         len++;                       /* continuous cluster */
 1541:                 } else {
 1542:                         cl = ncl;
 1543:                         len = 1;
 1544:                 }
 1545:         }
 1546:         if (err >= E_OK) {
 1547:                 clad->ca_no = cl;
 1548:                 clad->ca_len = (UW)len;
 1549:         }
 1550:         (void)fatMapEnd(map);
 1551: exit0:
 1552:         return err;
 1553: }
 1554: 
 1555: /*
 1556:  *  Get the number of clusters
 1557:  */
 1558: LOCAL   ER        fatGetClusterCount(FATFS *fs, UW clno, FATNODE *inode, W *num)
 1559: {
 1560:         MapInfo        *map;
 1561:         W      n;
 1562:         UW     ncl;
 1563:         ER     err;
 1564: 
 1565:         if (clno < CLSTART || clno > fs->ff_lastcl) {
 1566:                 err = EX_INVAL;
 1567:                 goto exit0;
 1568:         }
 1569: 
 1570:         map = &fs->ff_fatmap;
 1571: 
 1572:         for (n = 1; ; n++, clno = ncl) {
 1573:                 err = fatGetCluster(map, clno, &ncl);
 1574:                 if (err < E_OK || ncl == CLEND) break;
 1575:         }
 1576:         if (err >= E_OK) {
 1577:                 if (inode != NULL) {
 1578:                         /* Set directory file size */
 1579:                         inode->fino_filsz = n * fs->ff_clsz;
 1580:                         if (inode->fino_filsz > FILE_SIZE_MAX) {
 1581:                                 inode->fino_filsz = FILE_SIZE_MAX;
 1582:                         }
 1583:                 }
 1584:                 if (num != NULL) {
 1585:                         *num = n;
 1586:                 }
 1587:         }
 1588:         (void)fatMapEnd(map);
 1589: exit0:
 1590:         return err;
 1591: }
 1592: 
 1593: /*
 1594:  *  Search successive empty cluster of maximum "nbyte" follwing "clno".
 1595:  *      When not found, re-search from the top to "clno".
 1596:  */
 1597: LOCAL   ER        fatGetNewCluster(FATFS *fs, CLAD *clad, UW clno, D nbyte)
 1598: {
 1599:         MapInfo        *map;
 1600:         UW     reqlen, ccl, ncl, stcl, encl;
 1601:         W      n;
 1602:         ER     err;
 1603: 
 1604:         stcl = (clno < CLSTART || clno > fs->ff_lastcl) ? CLSTART : clno;
 1605:         encl = fs->ff_lastcl + 1;
 1606:         reqlen = (nbyte + fs->ff_clsz - 1) / fs->ff_clsz;
 1607: 
 1608:         clad->ca_no = CLVOID;
 1609:         clad->ca_len = 0;
 1610: 
 1611:         map = &fs->ff_fatmap;
 1612: 
 1613:         for (err = E_OK; ; ) {
 1614:                 /* Search first free cluster */
 1615:                 ncl = CLVOID;
 1616:                 for (ccl = stcl; ccl < encl; ccl++) {
 1617:                         err = fatGetCluster(map, ccl, &ncl);
 1618:                         if (err < E_OK) {    /* if ncl == 0, EX_IO */
 1619:                                 if (ncl == 0) err = E_OK;
 1620:                                 break;
 1621:                         }
 1622:                         CHK_BREAK_AND_SET_ERR(fs, &err);
 1623:                         if (err < E_OK) break;
 1624:                 }
 1625:                 if (err < E_OK) break;
 1626: 
 1627:                 if (ncl == 0) {
 1628:                         /* Count free clusters up to reqlen */
 1629:                         clad->ca_no = ccl;
 1630:                         n = 1;
 1631:                         if (reqlen > 1) {
 1632:                                 while(++ccl < encl) {
 1633:                                         err = fatGetCluster(map, ccl, &ncl);
 1634:                                         if (ncl != 0) break;
 1635:                                         err = E_OK;        /* if ncl==0, EX_IO */
 1636:                                         if (++n >= reqlen) break;
 1637:                                         CHK_BREAK_AND_SET_ERR(fs, &err);
 1638:                                         if (err < E_OK) break;
 1639:                                 }
 1640:                         }
 1641:                         if (err >= E_OK) clad->ca_len = n;
 1642:                         break;                       /* Found */
 1643:                 }
 1644:                 if (stcl == CLSTART) break;   /* Re-search done */
 1645: 
 1646:                 /* Re-search from top */
 1647:                 stcl = CLSTART;
 1648:                 encl = clno;
 1649:         }
 1650:         (void)fatMapEnd(map);
 1651:         return err;
 1652: }
 1653: 
 1654: /*
 1655:  *  Counts the total number of empty clusters
 1656:  */
 1657: LOCAL   ER        fatCountFreeCluster(FATFS *fs, UW *freecl)
 1658: {
 1659:         MapInfo        *map;
 1660:         D      offset;
 1661:         UW     free, totalcl, len, rem, dt;
 1662:         ER     err;
 1663:         UB     *ep;
 1664:         GPTR   dp;
 1665: 
 1666:         /* FAT map */
 1667:         map = &fs->ff_fatmap;
 1668: 
 1669:         /* Count free clusters */
 1670:         free = 0;
 1671:         offset = 0;
 1672:         totalcl = fs->ff_lastcl + 1;
 1673: 
 1674:         /* !! Do not use fatGetCluster() in order to count faster */
 1675:         switch (fs->ff_fstype) {
 1676:         case FAT12:
 1677:                 for (len = (totalcl * 3 + 1) / 2, rem = 0; len > 0; ) {
 1678:                         err = fatMapRead(map, &offset, &dp.b, &len, &ep);
 1679:                         if (err < E_OK) break;
 1680:                         while (dp.b + 3 <= ep) {
 1681:                                 switch(rem) {
 1682:                                 case 0:     dt = *dp.b++;
 1683:                                 case 1:     dt |= *dp.b++ << 8;
 1684:                                 case 2:     dt |= *dp.b++ << 16;
 1685:                                 }
 1686:                                 if (dt == 0) free += 2;
 1687:                                 else if ((dt & 0x000FFF) == 0) free++;
 1688:                                 else if ((dt & 0xFFF000) == 0) free++;
 1689:                                 rem = 0;
 1690:                         }
 1691:                         rem = ep - dp.b;
 1692:                         if (rem == 0) continue;
 1693:                         dt = *dp.b++;
 1694:                         if (rem <= 1) continue;
 1695:                         dt |= *dp.b++ << 8;
 1696:                         if (len <= 0 && (dt & 0x000FFF) == 0) free++;
 1697:                 }
 1698:                 break;
 1699: 
 1700:         case FAT16:
 1701:                 for (len = totalcl * sizeof(UH); len > 0; ) {
 1702:                         err = fatMapRead(map, &offset, &dp.b, &len, &ep);
 1703:                         if (err < E_OK) break;
 1704:                         while (dp.b < ep) {
 1705:                                 if (*dp.h++ == 0) free++;
 1706:                         }
 1707:                 }
 1708:                 break;
 1709: 
 1710:         case FAT32:
 1711:         default:
 1712:                 for (len = totalcl * sizeof(UW); len > 0; ) {
 1713:                         err = fatMapRead(map, &offset, &dp.b, &len, &ep);
 1714:                         if (err < E_OK) break;
 1715:                         while (dp.b < ep) {
 1716:                                 if (*dp.w++ == 0) free++;
 1717:                         }
 1718:                 }
 1719:                 break;
 1720:         }
 1721:         if (err >= E_OK) {
 1722:                 *freecl = free;
 1723:         }
 1724:         (void)fatMapEnd(map);
 1725:         return err;
 1726: }
 1727: 
 1728: /*
 1729:  *  Make cluster list specified by "clad" and bind at the end of "clno" list
 1730:  */
 1731: LOCAL   ER        fatChainCluster(FATFS *fs, UW clno, CLAD *clad, VW info)
 1732: {
 1733:         MapInfo        *map;
 1734:         UW     ccl, ncl, endcl;
 1735:         VW     oldinfo;
 1736:         ER     err;
 1737: 
 1738:         endcl = clad->ca_no + clad->ca_len - 1;
 1739:         if (clno < CLSTART || clno > fs->ff_lastcl ||
 1740:                         clad->ca_no < CLSTART || endcl > fs->ff_lastcl) {
 1741:                 err = EX_INVAL;
 1742:                 goto exit0;
 1743:         }
 1744: 
 1745:         /* Save map info (used for update) */
 1746:         map = &fs->ff_fatmap;
 1747:         oldinfo = map->m_info;
 1748:         map->m_info = info;
 1749: 
 1750:         /* Create cluster list */
 1751:         err = E_OK;
 1752:         for (ccl = clad->ca_no; ccl < endcl && err >= E_OK; ccl++) {
 1753:                 err = fatSetCluster(map, ccl, ccl + 1, NULL);
 1754:         }
 1755:         if (err < E_OK) goto exit1;
 1756: 
 1757:         /* Termination */
 1758:         err = fatSetCluster(map, ccl, CLEND, NULL);
 1759:         if (err < E_OK) goto exit1;
 1760: 
 1761:         /* Bind 'clad' list to the end of the 'clno' list */
 1762:         for (ccl = clno; ccl != clad->ca_no; ccl = ncl) {
 1763:                 err = fatGetCluster(map, ccl, &ncl);
 1764:                 if (err < E_OK) break;
 1765:                 if (ncl == CLEND) {
 1766:                         err = fatSetCluster(map, ccl, clad->ca_no, NULL);
 1767:                         break;
 1768:                 }
 1769:         }
 1770: 
 1771:         /* Update the number of empty clusters */
 1772:         if (err >= E_OK) {
 1773:                 fs->ff_freecl -= clad->ca_len;
 1774:                 fs->ff_nextfree = clad->ca_no + clad->ca_len;
 1775:         }
 1776: exit1:
 1777:         (void)fatMapEnd(map);
 1778: 
 1779:         /* Recover map info */
 1780:         map->m_info = oldinfo;
 1781: exit0:
 1782:         return err;
 1783: }
 1784: 
 1785: /*
 1786:  *  Delete cluster list from "clno" to the end.
 1787:  *      If "next" is TRUE, set CLEND instead of zero at "clno".
 1788:  */
 1789: LOCAL   ER        fatUnchainCluster(FATFS *fs, UW clno, BOOL next, VW info)
 1790: {
 1791:         MapInfo        *map;
 1792:         UW     clofs, ncl;
 1793:         W      cnt;
 1794:         VW     oldinfo;
 1795:         ER     err;
 1796: 
 1797:         /* Save map info (used for update) */
 1798:         map = &fs->ff_fatmap;
 1799:         oldinfo = map->m_info;
 1800:         map->m_info = info;
 1801: 
 1802:         for (cnt = 0, ncl = clno; ncl != CLEND;) {
 1803:                 /* Check of cluster number */
 1804:                 if (ncl < CLSTART || ncl > fs->ff_lastcl) {
 1805:                         err = EX_IO;
 1806:                         break;
 1807:                 }
 1808:                 /* Map of FAT area */
 1809:                 clofs = ncl;
 1810:                 if (ncl == clno && next != FALSE) {
 1811:                         /* New termination */
 1812:                         err = fatSetCluster(map, clofs, CLEND, &ncl);
 1813:                 } else {
 1814:                         /* Deletion of Cluster */
 1815:                         err = fatSetCluster(map, clofs, 0, &ncl);
 1816:                         cnt++;
 1817:                 }
 1818:                 if (err < E_OK) break;
 1819:         }
 1820:         if (err >= E_OK) {
 1821:                 /* File system information update */
 1822:                 fs->ff_freecl += cnt;
 1823:                 /* Do not update next free cluster */
 1824:                 //fs->ff_nextfree = CLSTART;
 1825:         }
 1826:         (void)fatMapEnd(map);
 1827: 
 1828:         /* Recover map info */
 1829:         map->m_info = oldinfo;
 1830:         return err;
 1831: }
 1832: 
 1833: /*
 1834:  *  Extend cluster list
 1835:  */
 1836: LOCAL   ER        fatExtendClusterList(FATFS *fs, CLAD *clad, FATNODE *inode)
 1837: {
 1838:         UW     clno;
 1839:         CLAD   *clbuf, *clp;
 1840:         ER     err;
 1841: 
 1842:         clbuf = inode->fino_c.ino_info;
 1843:         clp = NULL;
 1844: 
 1845:         /* Cluster's linkage location search */
 1846:         if (clbuf != NULL && inode->fino_cllen > 0) {
 1847:                 /* Linkage location */
 1848:                 clp = &clbuf[inode->fino_cllen - 1];
 1849:                 clno = clp->ca_no + clp->ca_len - 1;
 1850:         } else if (inode->fino_fclno == 0) {
 1851:                 /* File start cluster */
 1852:                 inode->fino_fclno = clad->ca_no;
 1853:                 clno = clad->ca_no;
 1854:         } else {
 1855:                 /* Started search of linkage location  */
 1856:                 clno = inode->fino_fclno;
 1857:         }
 1858: 
 1859:         /* Binding of cluster list  */
 1860:         err = fatChainCluster(fs, clno, clad, (VW)inode);
 1861:         if (err < E_OK) goto exit0;
 1862: 
 1863:         if (clbuf == NULL) goto exit0;
 1864: 
 1865:         /* Update cluster buffer */
 1866:         if (clp != NULL && clad->ca_no == clno + 1) {
 1867:                 /* Update the number of successive clusters */
 1868:                 clp->ca_len += clad->ca_len;
 1869:         } else {
 1870:                 /* When cluster buffer is full, expand cluster buffer */
 1871:                 if (inode->fino_maxcl <= inode->fino_cllen) {
 1872:                         err = alloc_clbuf(&clbuf, &inode->fino_maxcl);
 1873:                         inode->fino_c.ino_info = clbuf;
 1874:                         if (err < E_OK) goto exit0;
 1875:                 }
 1876:                 /* Append new cluster */
 1877:                 clbuf[inode->fino_cllen] = *clad;
 1878:                 inode->fino_cllen++;
 1879:         }
 1880: exit0:
 1881:         return err;
 1882: }
 1883: 
 1884: /*
 1885:  *  Append a new cluster list
 1886:  */
 1887: LOCAL   ER        fatApdNewCluster(FATFS *fs, CLAD *clad, D size, FATNODE *inode)
 1888: {
 1889:         ER     err;
 1890: 
 1891:         /* Get empty cluster */
 1892:         err = fatGetNewCluster(fs, clad, fs->ff_nextfree, size);
 1893:         if (err >= E_OK) {
 1894:                 /* Cluster expansion */
 1895:                 err = fatExtendClusterList(fs, clad, inode);
 1896:         }
 1897:         return err;
 1898: }
 1899: 
 1900: /*
 1901:  *  Truncate cluster list
 1902:  */
 1903: LOCAL   ER        fatTruncClusterList(FATFS *fs, D newsz, FATNODE *inode)
 1904: {
 1905:         UW     clno, ofs;
 1906:         W      len;
 1907:         CLAD   *clbuf, clad;
 1908:         ER     err;
 1909: 
 1910:         err = E_OK;
 1911: 
 1912:         /* Location of detachment */
 1913:         ofs = (newsz > 0) ? newsz - 1 : 0;
 1914: 
 1915:         clbuf = (CLAD *)inode->fino_c.ino_info;
 1916:         if (clbuf != NULL) {
 1917:                 /* Empty file - do nothing */
 1918:                 if (inode->fino_cllen == 0) goto exit0;
 1919: 
 1920:                 /* Offset cluster */
 1921:                 ofs /= fs->ff_clsz;
 1922: 
 1923:                 /* Location of detachment */
 1924:                 for (len = 0; len < (W)inode->fino_cllen; len++) {
 1925:                         if (ofs < clbuf[len].ca_len) break;
 1926:                         ofs -= clbuf[len].ca_len;
 1927:                 }
 1928:                 if (len >= (W)inode->fino_cllen) len--;
 1929:                 clno = clbuf[len].ca_no + ofs;
 1930:         } else {
 1931:                 /* Empty file - do nothing */
 1932:                 if (inode->fino_fclno == 0) goto exit0;
 1933: 
 1934:                 /* Get cluster list */
 1935:                 err = fatGetClusterList(fs, &clad, 1, inode->fino_fclno,
 1936:                                                                 ofs, &len);
 1937:                 if (err < E_OK) goto exit0;
 1938: 
 1939:                 /* Location of detachment */
 1940:                 clno = clad.ca_no;
 1941:         }
 1942: 
 1943:         /* Delete cluster list */
 1944:         err = fatUnchainCluster(fs, clno, (newsz > 0)? TRUE : FALSE, (VW)inode);
 1945:         if (err < E_OK) goto exit0;
 1946: 
 1947:         /* File size update */
 1948:         if ((inode->fino_filsz = newsz) > 0) {
 1949:                 if (clbuf != NULL) {  /* Cluster buffer update */
 1950:                         clbuf[len].ca_len = ofs + 1; /* len + CLEND */
 1951:                         inode->fino_cllen = (UW)len + 1;
 1952:                 }
 1953:         } else {
 1954:                 inode->fino_fclno = 0;
 1955:                 inode->fino_cllen = 0;
 1956:         }
 1957: exit0:
 1958:         return err;
 1959: }
 1960: 
 1961: /*
 1962:  *  Make cluster list of the inode
 1963:  */
 1964: LOCAL   ER        fatMakeClusterList(FATFS *fs, FATNODE *inode)
 1965: {
 1966:         UW     clno, cllen;
 1967:         UH     maxcl;
 1968:         W      len;
 1969:         CLAD   *clbuf,*clp;
 1970:         ER     err;
 1971: 
 1972:         err = E_OK;
 1973: 
 1974:         /* Confirmation of cluster list */
 1975:         if (inode->fino_c.ino_info != NULL ||
 1976:                 (IsRootINODE(fs, inode) && ! isFAT32(fs->ff_fstype))) {
 1977:                 goto exit0;
 1978:         }
 1979: 
 1980:         /* Allocate buffer */
 1981:         cllen = 0;
 1982:         clbuf = NULL;
 1983:         err = alloc_clbuf(&clbuf, &maxcl);
 1984:         if (err < E_OK) goto exit1;
 1985: 
 1986:         /* Empty file */
 1987:         if ((clno = inode->fino_fclno) == 0 &&
 1988:                                         inode->fino_filsz == 0) goto exit1;
 1989: 
 1990:         /* Started cluster */
 1991:         for ( ; ; ) {
 1992:                 /* Location for storing cluster list */
 1993:                 clp = &clbuf[cllen];
 1994: 
 1995:                 /* Get cluster list */
 1996:                 err = fatGetClusterList(fs, clp, MAX_CLEN, clno,
 1997:                                         (cllen == 0) ? 0 : OFSNEXT, &len);
 1998:                 if (err < E_OK) break;
 1999: 
 2000:                 cllen += (UW)len;
 2001: 
 2002:                 /* Clsuter list termination */
 2003:                 if (len < MAX_CLEN) break;
 2004: 
 2005:                 /* Started cluster */
 2006:                 clno = clbuf[cllen - 1].ca_no + clbuf[cllen - 1].ca_len - 1;
 2007: 
 2008:                 /* Addition of buffer size */
 2009:                 err = alloc_clbuf(&clbuf, &maxcl);
 2010:                 if (err < E_OK) break;
 2011:         }
 2012: exit1:
 2013:         if (err < E_OK) {
 2014:                 if (clbuf != NULL) {
 2015:                         fimp_free(clbuf);
 2016:                 }
 2017:                 clbuf = NULL;
 2018:                 maxcl = cllen = 0;
 2019:         }
 2020:         inode->fino_c.ino_info = clbuf;
 2021:         inode->fino_maxcl = maxcl;
 2022:         inode->fino_cllen = cllen;
 2023: exit0:
 2024:         return err;
 2025: }
 2026: 
 2027: /*
 2028:  *  Get & copy cluster list
 2029:  *      from the offset byte "offset" of file "inode" to "nbyte" byte.
 2030:  */
 2031: LOCAL   ER        fatCopyClusterList(FATFS *fs, CLAD clad[], D offset,
 2032:                                         D nbyte, FATNODE *inode, W *lenp)
 2033: {
 2034:         CLAD   *clp, *cle;
 2035:         UW     cllen, clofs, clend, len;
 2036:         W      n;
 2037:         ER     err;
 2038: 
 2039:         err = E_OK;
 2040: 
 2041:         /* Make cluster list of inode */
 2042:         if (inode->fino_c.ino_info == NULL) {
 2043:                 err = fatMakeClusterList(fs, inode);
 2044:                 if (err < E_OK) goto exit0;
 2045:         }
 2046: 
 2047:         /* Cluster offset */
 2048:         clofs = offset / fs->ff_clsz;
 2049:         clend = (nbyte <= 0) ? 0 :
 2050:                         (offset + nbyte + (fs->ff_clsz - 1)) / fs->ff_clsz;
 2051: 
 2052:         /* Copy cluster list */
 2053:         clp = (CLAD *)inode->fino_c.ino_info;
 2054:         cle = clp + (W)inode->fino_cllen;
 2055: 
 2056:         for (cllen = 0, n = 0; n < MAX_CLEN && clp < cle; clp++) {
 2057:                 cllen += (len = clp->ca_len);
 2058:                 if (len <= clofs) {
 2059:                         /* Skip to the offset location */
 2060:                         clofs -= len;
 2061:                 } else {
 2062:                         /* Copy cluster list */
 2063:                         clad[n].ca_no = clp->ca_no + clofs;
 2064:                         clad[n++].ca_len = len - clofs;
 2065:                         if (clend > 0 && cllen >= clend) {
 2066:                                 /* Adjust last cluster length */
 2067:                                 clad[n - 1].ca_len -= cllen - clend;
 2068:                                 break;
 2069:                         }
 2070:                         clofs = 0;
 2071:                 }
 2072:         }
 2073:         *lenp = n;
 2074: exit0:
 2075:         return err;
 2076: }
 2077: 
 2078: /*----------------------------------------------------------------------------
 2079:         File name operations
 2080: ----------------------------------------------------------------------------*/
 2081: 
 2082: /*
 2083:  *  Get UTF16 file name from short file name (SFN)
 2084:  */
 2085: LOCAL   W fatGetSFN(UB sfname[BASE_EXTLEN], UB smallcaps,
 2086:                                                 UH utf16nm[BASE_EXTLEN + 2])
 2087: {
 2088:         UB     c, nm[BASE_EXTLEN + 2];
 2089:         W      i, n, sflg;
 2090: 
 2091:         /* Normalize file name */
 2092:         sflg = SMALL_BASE;
 2093:         for (i = n = 0; n < BASE_EXTLEN; n++) {
 2094:                 if ((c = sfname[n]) == ' ') {
 2095:                         if (n == BASELEN) break;     /* No ext name */
 2096:                 } else {
 2097:                         if (n == BASELEN) {
 2098:                                 nm[i++] = '.';
 2099:                                 sflg = SMALL_EXT;
 2100:                         }
 2101:                         nm[i++] = isSET(smallcaps, sflg) ? AsciiToLOW(c) : c;
 2102:                 }
 2103:         }
 2104:         nm[i] = '\0';
 2105: 
 2106:         if (nm[0] == DE_B0_KANJI_ESC) nm[0] = DE_B0_FREE;
 2107: 
 2108:         /* Convert to UTF16 */
 2109:         for (i = n = 0; nm[i] != '\0'; n++) {
 2110: #ifdef  FAT_ASCII_FN_ONLY
 2111:                 utf16nm[n] = (nm[i] <= ASCII_MAX) ? (UH)nm[i] : (UH)'_';
 2112:                 i++;
 2113: #else   /* FAT_ASCII_FN_ONLY */
 2114:                 UW    unicode;
 2115:                 i += fatEncLocalToUnicode(&nm[i], &unicode);
 2116:                 if (UnicodeIsNormal(unicode)) {
 2117:                         utf16nm[n] = (UH)unicode;
 2118:                 } else if (UnicodeIsSurrogate(unicode)) {
 2119:                         utf16nm[n++] = UnicodeToUtf16UpSurrogate(unicode);
 2120:                         utf16nm[n] = UnicodeToUtf16LowSurrogate(unicode);
 2121:                 } else {
 2122:                         utf16nm[n] = (UH)'_';
 2123:                 }
 2124: #endif  /* FAT_ASCII_FN_ONLY */
 2125:         }
 2126:         utf16nm[n] = (UH)'\0';
 2127:         return n;
 2128: }
 2129: 
 2130: /*
 2131:  *  Set short file name (SFN) from UTF8 long file name (LFN)
 2132:  */
 2133: LOCAL   W fatSetSFN(const UB *utf8nm, W utf8len,
 2134:                         UB sfname[BASE_EXTLEN], UB *smallcaps, W gen)
 2135: {
 2136:         W      n, i, kind, stat;
 2137:         UW     unicode, cbit;
 2138:         UB     *e_utf8nm, *cp;
 2139: 
 2140:         /* Initailize */
 2141:         memset(sfname, ' ', BASE_EXTLEN);
 2142:         *smallcaps = 0x0;
 2143:         e_utf8nm = (UB*)utf8nm + utf8len;
 2144: 
 2145:         cbit = 0;
 2146:         stat = FAT_SAME_NAME;
 2147: 
 2148:         /* Special for "." and ".." */
 2149:         if (utf8nm[0] == '.') {
 2150:                 if (utf8len == 1) {
 2151:                         sfname[0] = '.';
 2152:                         goto exit0;
 2153:                 }
 2154:                 if (utf8nm[1] == '.' && utf8len == 2) {
 2155:                         sfname[0] = sfname[1] = '.';
 2156:                         goto exit0;
 2157:                 }
 2158:                 /* ".xxxxxxxx" */
 2159:                 sfname[0] = '_';
 2160:                 cbit |= 1 << 0;
 2161:                 stat = FAT_CHG_WITH_N;
 2162:         }
 2163: 
 2164:         /* Set basename */
 2165:         for (kind = n = 0; n < BASELEN &&
 2166:                                 utf8nm < e_utf8nm && *utf8nm != '.'; ) {
 2167:                 /* In case of multi-byte character, cbit is set first only */
 2168:                 cbit |= 1 << n;
 2169:                 utf8nm += fatEncUtf8ToUnicode(utf8nm, &unicode);
 2170:                 if (UnicodeIsAscii(unicode)) {
 2171:                         if (AsciiIsSFN(unicode)) {
 2172:                                 /* Valid ASCII */
 2173:                                 sfname[n++] = AsciiToUP(unicode);
 2174:                                 kind |= 1 << getAsciiKind(unicode);
 2175:                                 continue;
 2176:                         }
 2177: #ifndef FAT_ASCII_FN_ONLY
 2178:                 } else if (! UnicodeIsInvalid(unicode)) {
 2179:                         W    cnt;
 2180:                         UB   buf[ENC_CHAR_MAX];
 2181: 
 2182:                         cnt = fatEncUnicodeToLocal(unicode, buf);
 2183:                         if (cnt > 0) {
 2184:                                 /* Non ASCII */
 2185:                                 if (n + cnt > BASELEN) {
 2186:                                         n = BASELEN;
 2187:                                         stat = FAT_CHG_WITH_N;
 2188:                                         break;
 2189:                                 }
 2190:                                 for (i = 0; i < cnt; i++) {
 2191:                                         sfname[n++] = buf[i];
 2192:                                 }
 2193:                                 kind |= 1 << ASCII_CON;     /* MultiByte */
 2194:                                 continue;
 2195:                         }
 2196: #endif  /* ~ FAT_ASCII_FN_ONLY */
 2197:                 }
 2198:                 /* Invalid character */
 2199:                 sfname[n++] = '_';
 2200:                 stat = FAT_CHG_WITH_N;
 2201:         }
 2202: 
 2203:         if (stat != FAT_CHG_WITH_N) {
 2204:                 /* Check characters */
 2205:                 if ((kind & (1 << ASCII_LOW)) != 0) {
 2206:                         if ((kind & (1 << ASCII_UP)) != 0) {
 2207:                                 /* Both lower and upper case */
 2208:                                 stat = FAT_CHG_WITHOUT_N;
 2209:                         } else if ((kind & (1 << ASCII_CON)) == 0) {
 2210:                                 /* ASCII Lower case only */
 2211:                                 *smallcaps |= SMALL_BASE;
 2212:                         }
 2213:                 }
 2214:         }
 2215: 
 2216:         /* Process remain chacters */
 2217:         if (utf8nm < e_utf8nm) {
 2218:                 if (*utf8nm != '.') { /* Basename too long */
 2219:                         stat = FAT_CHG_WITH_N;
 2220:                 }
 2221:                 /* Search last '.' position */
 2222:                 for (cp = e_utf8nm; --cp >= utf8nm; ) {
 2223:                         if (*cp == '.') break;
 2224:                 }
 2225:                 utf8nm = (cp < utf8nm) ? e_utf8nm : cp + 1;
 2226: 
 2227:                 /* Set extension name */
 2228:                 for (n = BASELEN, kind = 0;
 2229:                                  n < BASE_EXTLEN && utf8nm < e_utf8nm; ) {
 2230:                         utf8nm += fatEncUtf8ToUnicode(utf8nm, &unicode);
 2231:                         if (UnicodeIsAscii(unicode)) {
 2232:                                 if (AsciiIsSFN(unicode)) {
 2233:                                         /* Valid ASCII */
 2234:                                         sfname[n++] = AsciiToUP(unicode);
 2235:                                         kind |= 1 << getAsciiKind(unicode);
 2236:                                         continue;
 2237:                                 }
 2238: #ifndef FAT_ASCII_FN_ONLY
 2239:                         } else if (! UnicodeIsInvalid(unicode)) {
 2240:                                 W   cnt;
 2241:                                 UB  buf[ENC_CHAR_MAX];
 2242: 
 2243:                                 cnt = fatEncUnicodeToLocal(unicode, buf);
 2244:                                 if (cnt > 0) {
 2245:                                         /* Non ASCII */
 2246:                                         if (n + cnt > BASE_EXTLEN) {
 2247:                                                 n = BASE_EXTLEN;
 2248:                                                 stat = FAT_CHG_WITH_N;
 2249:                                                 break;
 2250:                                         }
 2251:                                         for (i = 0; i < cnt; i++) {
 2252:                                                 sfname[n++] = buf[i];
 2253:                                         }
 2254:                                         kind |= 1 << ASCII_CON;    /* MultiByte */
 2255:                                         continue;
 2256:                                 }
 2257: #endif  /* ~ FAT_ASCII_FN_ONLY */
 2258:                         }
 2259:                         /* Invalid character */
 2260:                         sfname[n++] = '_';
 2261:                         stat = FAT_CHG_WITH_N;
 2262:                 }
 2263:                 if (utf8nm < e_utf8nm) {      /* Extension too long */
 2264:                         stat = FAT_CHG_WITH_N;
 2265: 
 2266:                 } else if (stat != FAT_CHG_WITH_N) {
 2267:                         /* Check characters */
 2268:                         if ((kind & (1 << ASCII_LOW)) != 0) {
 2269:                                 if ((kind & (1 << ASCII_UP)) != 0) {
 2270:                                         /* Both lower and upper case */
 2271:                                         stat = FAT_CHG_WITHOUT_N;
 2272:                                 } else if ((kind & (1 << ASCII_CON)) == 0) {
 2273:                                         /* ASCII Lower case only */
 2274:                                         *smallcaps |= SMALL_EXT;
 2275:                                 }
 2276:                         }
 2277:                 }
 2278:         }
 2279: 
 2280:         if (sfname[0] == DE_B0_FREE) sfname[0] = DE_B0_KANJI_ESC;
 2281: 
 2282:         if (stat != FAT_SAME_NAME) {
 2283:                 *smallcaps = 0x0;
 2284: 
 2285:                 /* Append generation number : ~n */
 2286:                 if (stat == FAT_CHG_WITH_N && gen > 0) {
 2287:                         UB   numstr[BASELEN];
 2288: 
 2289:                         /* Create gen number string */
 2290:                         for (i = BASELEN; --i > 0 && gen > 0; gen /= 10) {
 2291:                                 numstr[i] = '0' + (gen % 10);
 2292:                         }
 2293: 
 2294:                         /* Calcurate '~' position */
 2295:                         while (i > 0 && ! isSET(cbit, 1 << i)) i--;
 2296: 
 2297:                         /* Set generation number : ~n */
 2298:                         sfname[i] = '~';
 2299:                         while (++i < BASELEN) sfname[i] = numstr[i];
 2300:                 }
 2301:         }
 2302: exit0:
 2303:         return stat;
 2304: }
 2305: 
 2306: /*
 2307:  *  Get long file name (UTF16) from the LFN directory entry
 2308:  */
 2309: LOCAL   W fatGetLFN(FAT_DIRENT_LFN *lde, W *ldenum, W *chksum,
 2310:                                                         UH *utf16nm)
 2311: {
 2312:         W      i, num;
 2313:         UB     *cp, *ep;
 2314: 
 2315:         if ((num = lde->lde_index & LFN_CNT) > LFN_MAXENT) goto exit0;
 2316: 
 2317:         if (*chksum == CKSVOID) {      /* 1st time, last LFN entry */
 2318:                 if (! isSET(lde->lde_index, LFN_LAST)) goto exit0;
 2319:                 *chksum = lde->lde_checksum;
 2320:                 utf16nm[num * LFN_CHARS] = (UH)'\0';
 2321:         } else {
 2322:                 if (num != *ldenum ||
 2323:                         lde->lde_checksum != *chksum) goto exit0;
 2324:         }
 2325:         *ldenum = --num;       /* Next lde number */
 2326: 
 2327:         /* Copy LFN */
 2328:         for (utf16nm += num * LFN_CHARS, i = 0; i < 3; i++) {
 2329:                 cp = (UB*)lde + LDE_NMPOS[i].ofs;
 2330:                 ep = cp + LDE_NMPOS[i].cnt;
 2331:                 for ( ; cp < ep; cp += 2) {
 2332:                         *utf16nm++ = CEH(GetMisalignH(cp));
 2333:                 }
 2334:         }
 2335:         return 0;
 2336: exit0:
 2337:         return -1;     /* Invalid entry */
 2338: }
 2339: 
 2340: /*
 2341:  *  Check long file name (LFN) with the directory entry.
 2342:  *      utf16nm is upper case character.
 2343:  */
 2344: LOCAL   W fatChkLFN(UH *utf16nm, W utf16len, FAT_DIRENT_LFN *lde,
 2345:                                                         W chksum, UH *realnm)
 2346: {
 2347:         UB     *cp, *ep;
 2348:         W      n, i, cks;
 2349:         UH     utf16;
 2350: 
 2351:         cks = CKSVOID;
 2352: 
 2353:         /* Get character position */
 2354:         n = (W)(((lde->lde_index & LFN_CNT) - 1) * LFN_CHARS);
 2355:         if ((utf16len -= n) <= 0) goto exit0;  /* Length differs */
 2356: 
 2357:         /* Check checksum */
 2358:         if (isSET(lde->lde_index, LFN_LAST)) {
 2359:                 if (utf16len > (W)LFN_CHARS) goto exit0; /* Length differs */
 2360:                 chksum = (W)lde->lde_checksum;
 2361:         } else {
 2362:                 if (chksum != lde->lde_checksum) goto exit0;
 2363:         }
 2364: 
 2365:         /* Compare the fragment of file name */
 2366:         for (utf16nm += n, i = 0; i < 3; i++) {
 2367:                 cp = (UB*)lde + LDE_NMPOS[i].ofs;
 2368:                 ep = cp + LDE_NMPOS[i].cnt;
 2369:                 for ( ; cp < ep; cp += 2) {
 2370:                         utf16 = CEH(GetMisalignH(cp));
 2371:                         if (--utf16len < 0) {
 2372:                                 if (utf16 != 0) goto exit0;
 2373:                                 if (realnm != NULL) realnm[n] = (UH)'\0';
 2374:                                 goto exit1;
 2375:                         }
 2376:                         if (*utf16nm++ != (CharIsAscii(utf16) ?
 2377:                                 AsciiToUP(utf16) : utf16)) goto exit0;
 2378:                         if (realnm != NULL) realnm[n++] = utf16;
 2379:                 }
 2380:         }
 2381: exit1:
 2382:         cks = chksum;
 2383: exit0:
 2384:         return cks;
 2385: }
 2386: 
 2387: /*
 2388:  *  Set long file name (LFN) : returns 0 if final entry
 2389:  */
 2390: LOCAL   void      fatSetLFN(UH *utf16nm, W utf16len, FAT_DIRENT_LFN *lde,
 2391:                                                 W lfnidx, UB chksum)
 2392: {
 2393:         UB     *cp, *ep;
 2394:         UH     *utf16end;
 2395:         W      i;
 2396: 
 2397:         /* Initialize the entry */
 2398:         memset(lde, 0xFF, sizeof(FAT_DIRENT_LFN));
 2399:         lde->lde_index = (UB)lfnidx;
 2400:         lde->lde_ftype = FAT_LONGNAME;
 2401:         lde->lde_smallcaps = 0;
 2402:         lde->lde_checksum = chksum;
 2403:         lde->lde_clno = 0;
 2404: 
 2405:         /* Store the file name fragment */
 2406:         utf16end = utf16nm + utf16len;
 2407:         utf16nm += (lfnidx - 1) * LFN_CHARS;
 2408: 
 2409:         for (i = 0; i < 3; i++) {
 2410:                 cp = (UB*)lde + LDE_NMPOS[i].ofs;
 2411:                 ep = cp + LDE_NMPOS[i].cnt;
 2412:                 for ( ; cp < ep && utf16nm < utf16end; cp += 2, utf16nm++) {
 2413:                         SetMisalignH(cp, *utf16nm);
 2414:                 }
 2415:                 if (utf16nm < utf16end) continue;
 2416: 
 2417:                 /* Last entry, set terminator(0x0000) */
 2418:                 if (cp < ep) cp[0] = cp[1] = 0;
 2419:                 else if (i < 2) continue;     /* for set terminator next */
 2420:                 lde->lde_index |= LFN_LAST;
 2421:                 break;
 2422:         }
 2423: }
 2424: 
 2425: /*----------------------------------------------------------------------------
 2426:         Directory operations
 2427: ----------------------------------------------------------------------------*/
 2428: 
 2429: /*
 2430:  *  Check-sum calculation of file name
 2431:  */
 2432: LOCAL   UB        fatCalcChksum(UB *name)
 2433: {
 2434:         W      i;
 2435:         UB     s;
 2436: 
 2437:         for (s = 0, i = BASE_EXTLEN; --i >= 0; s += *name++) {
 2438:                 s = (s << 7) | (s >> 1);      /* rotate right shift */
 2439:         }
 2440:         return s;
 2441: }
 2442: 
 2443: /*
 2444:  *  Read current dirent entry
 2445:  */
 2446: LOCAL   ER        fatReadCurDIR(FATFS *fs, DIRINF *dir)
 2447: {
 2448:         W      d_ofs;
 2449:         UW     ofs;
 2450:         ER     err;
 2451: 
 2452:         if ((d_ofs = dir->di_dirent_ofs) == OFSVOID) return EX_INVAL;
 2453: 
 2454:         if (d_ofs >= dir->di_map.m_btop && d_ofs < dir->di_map.m_bend) {
 2455:                 /* The dirent exists in the last cache page, then use it */
 2456:                 ofs = (d_ofs - dir->di_map.m_btop) * DIRENTSZ;
 2457:         } else {
 2458:                 err = fatMapGetCache(&dir->di_map, d_ofs * DIRENTSZ, &ofs,TRUE);
 2459:                 if (err < E_OK) return err;
 2460:                 /* Save last dirent_ofs of the top of cache page */
 2461:                 dir->di_map.m_btop = d_ofs - (ofs / DIRENTSZ);
 2462:                 dir->di_map.m_bend = dir->di_map.m_btop +
 2463:                         ( ((fs->ff_clsz < dir->di_map.m_bpp) ?
 2464:                                 fs->ff_clsz : dir->di_map.m_bpp) / DIRENTSZ );
 2465:         }
 2466:         dir->di_dirent = (FAT_DIRENT *)&dir->di_map.m_page->dcp_buf[ofs];
 2467:         return E_OK;
 2468: }
 2469: 
 2470: /*
 2471:  *  Write current directory entry
 2472:  */
 2473: LOCAL   ER        fatWriteCurDIR(FATFS *fs, DIRINF *dir, VW info)
 2474: {
 2475:         if (dir->di_map.m_page == NULL || dir->di_access != AC_WRITE ||
 2476:                         dir->di_dirent_ofs == OFSVOID) return EX_INVAL;
 2477: 
 2478:         return fatDCacheUpdate(fs, dir->di_map.m_page,
 2479:                                 (info == 0) ? dir->di_map.m_info : info);
 2480: }
 2481: 
 2482: /*
 2483:  *  Open the directory that specifies cluster "dircl" as  the top.
 2484:  */
 2485: LOCAL   ER        fatOpenDIR(FATFS *fs, DIRINF *dir, UW dircl, W offset,
 2486:                                 UW mode, FATNODE *inode)
 2487: {
 2488:         UW     dirofs;
 2489:         W      cllen;
 2490:         div_t  dv;
 2491:         ER     err;
 2492: 
 2493:         /* Initialization of directory */
 2494:         memset(dir, 0, sizeof(DIRINF));
 2495:         dir->di_dircl = dircl;         /* Directory top cluster */
 2496:         dir->di_access = mode;         /* Accesss mode */
 2497:         dir->di_dirent_ofs = OFSVOID;
 2498: 
 2499:         dirofs = 0;
 2500:         dv.quot = dv.rem = 0;
 2501:         err = E_OK;
 2502: 
 2503:         if (offset >= 0) {
 2504:                 dv = div((dircl > 0)? (offset % fs->ff_clsz):offset, DIRENTSZ);
 2505:                 if (dv.rem != 0) {
 2506:                         err = EX_INVAL;
 2507:                         goto exit0;
 2508:                 }
 2509:                 /* Directory present location */
 2510:                 dir->di_offset = (UW)offset;
 2511:                 dirofs = (UW)offset;
 2512:         }
 2513: 
 2514:         if (inode == NULL) {
 2515:                 inode = (FATNODE *)fatInodeSearch((FS*)fs, dirINO(fs, dircl));
 2516:         }
 2517:         dir->di_inode = inode;
 2518: 
 2519:         if (dircl > 0) {       /* FAT32 or Subdirectory */
 2520:                 /* Get next cluster list */
 2521:                 if (inode != NULL && inode->fino_c.ino_info != NULL) {
 2522:                         err = fatCopyClusterList(fs, dir->di_clno,
 2523:                                                 dirofs, 0, inode, &cllen);
 2524:                 } else {
 2525:                         err = fatGetClusterList(fs, dir->di_clno, MAX_CLEN,
 2526:                                                         dircl, dirofs, &cllen);
 2527:                 }
 2528:                 if (err < E_OK) goto exit0;
 2529: 
 2530:                 /* Confirmation of offset */
 2531:                 if (cllen == 0) {
 2532:                         if (offset < 0) {
 2533:                                 err = EX_INVAL;
 2534:                                 goto exit0;
 2535:                         }
 2536:                         offset = OFSVOID;
 2537:                         goto exit1;
 2538:                 }
 2539: 
 2540:                 /* Map clusters */
 2541:                 dir->di_len = cllen;
 2542:                 err = fatMapDisk(fs, dir->di_clno, cllen, &dir->di_map,
 2543:                                                 MAP_C | MAP_READ, (VW)inode);
 2544:                 if (err < E_OK) goto exit0;
 2545: 
 2546:                 /* fatMapEnd() is called by fatCloseDIR() */
 2547:                 while (--cllen >= 0) {
 2548:                         dir->di_nent += dir->di_clno[cllen].ca_len;
 2549:                 }
 2550:                 dir->di_nent *= DEpCL;
 2551: 
 2552:         } else {       /* FAT12, FAT16 root directory */
 2553:                 /* Confirmation of offset */
 2554:                 if (dirofs >= ROOTSZ) {
 2555:                         offset = OFSVOID;
 2556:                         goto exit1;
 2557:                 }
 2558: 
 2559:                 /* FAT12, FAT16 Root map */
 2560:                 dir->di_secno[0].ca_no = fs->ff_rootsc;
 2561:                 dir->di_secno[0].ca_len = ROOTSZ / DSECSZ(fs);
 2562: 
 2563:                 err = fatMapDisk(fs, dir->di_secno, ROOT_SLEN, &dir->di_map,
 2564:                                         MAP_S | MAP_READ, (VW)inode);
 2565:                 if (err < E_OK) goto exit0;
 2566: 
 2567:                 /* fatMapEnd() is called by fatCloseDIR() */
 2568:                 dir->di_nent = ROOTENT;       /* The number of directory entries */
 2569:         }
 2570: exit1:
 2571:         /* Entry present location */
 2572:         if (offset >= 0) {
 2573:                 if (dv.quot >= (W)dir->di_nent) {
 2574:                         err = EX_INVAL;
 2575:                 } else {
 2576:                         dir->di_dirent_ofs = dv.quot;
 2577:                         err = fatReadCurDIR(fs, dir);
 2578:                 }
 2579:         }
 2580: exit0:
 2581:         return err;
 2582: }
 2583: 
 2584: /*
 2585:  *  Close opened directory
 2586:  */
 2587: LOCAL   ER        fatCloseDIR(FATFS *fs, DIRINF *dir, ER err)
 2588: {
 2589:         (void)fs;
 2590: 
 2591:         if (dir->di_dirent_ofs != OFSVOID) {
 2592:                 if (err < E_OK) {     /* When any error, do not update */
 2593:                         dir->di_access = AC_RDONLY;
 2594:                 }
 2595:                 (void)fatMapEnd(&dir->di_map);
 2596:                 fatUnmapDisk(&dir->di_map);
 2597:                 dir->di_dirent_ofs = OFSVOID;
 2598:                 dir->di_dirent = NULL;
 2599:         }
 2600:         return err;
 2601: }
 2602: 
 2603: /*
 2604:  *  Directory map next directory entries
 2605:  */
 2606: LOCAL   ER        fatMapNextDIR(FATFS *fs, DIRINF *dir, UW mode)
 2607: {
 2608:         UW     clno;
 2609:         W      n;
 2610:         ER     err;
 2611: 
 2612:         /* Directory close */
 2613:         (void)fatCloseDIR(fs, dir, E_OK);
 2614: 
 2615:         err = E_OK;
 2616:         if (dir->di_dircl == 0) goto exit0;
 2617: 
 2618:         /* Get last cluster number */
 2619:         clno = dir->di_clno[dir->di_len - 1].ca_no +
 2620:                                 dir->di_clno[dir->di_len - 1].ca_len - 1;
 2621:         /* Get next cluster list */
 2622:         err = fatGetClusterList(fs, dir->di_clno, MAX_CLEN, clno, OFSNEXT,
 2623:                                                                 &dir->di_len);
 2624:         if (err < E_OK) goto exit0;
 2625: 
 2626:         if ((n = dir->di_len) > 0) {
 2627:                 /* Map clusters */
 2628:                 err = fatMapDisk(fs, dir->di_clno, n, &dir->di_map,
 2629:                                         MAP_C | MAP_READ, (VW)dir->di_inode);
 2630:                 if (err < E_OK) goto exit0;
 2631: 
 2632:                 /* Set number of directory entries */
 2633:                 for (dir->di_nent = 0; --n >= 0; ) {
 2634:                         dir->di_nent += dir->di_clno[n].ca_len;
 2635:                 }
 2636:                 dir->di_nent *= DEpCL;
 2637: 
 2638:                 /* Read first directory entry */
 2639:                 dir->di_access = mode;
 2640:                 dir->di_dirent_ofs = 0;
 2641:                 err = fatReadCurDIR(fs, dir);
 2642:         }
 2643: exit0:
 2644:         return err;
 2645: }
 2646: 
 2647: /*
 2648:  *  Directory map previous directory entry
 2649:  */
 2650: LOCAL   ER        fatMapPrevDIR(FATFS *fs, DIRINF *dir, UW mode)
 2651: {
 2652:         ER     err;
 2653: 
 2654:         /* Directory close */
 2655:         (void)fatCloseDIR(fs, dir, E_OK);
 2656: 
 2657:         /* Get a previous cluster */
 2658:         err = fatGetPrevCluster(fs, &dir->di_clno[0], dir->di_dircl,
 2659:                                                 dir->di_clno[0].ca_no);
 2660:         if (err < E_OK) goto exit0;
 2661: 
 2662:         if (dir->di_clno[0].ca_len == 0) {
 2663:                 err = EX_INVAL;
 2664:                 goto exit0;
 2665:         }
 2666: 
 2667:         /* Map a cluster */
 2668:         dir->di_len = 1;
 2669:         err = fatMapDisk(fs, dir->di_clno, 1, &dir->di_map,
 2670:                                         MAP_C | MAP_READ, (VW)dir->di_inode);
 2671:         if (err < E_OK) goto exit0;
 2672: 
 2673:         /* Set number of directory entries */
 2674:         dir->di_nent = dir->di_clno[0].ca_len * DEpCL;
 2675: 
 2676:         /* Read last directory entry in the cluster */
 2677:         dir->di_access = mode;
 2678:         dir->di_dirent_ofs = dir->di_nent - 1;
 2679:         err = fatReadCurDIR(fs, dir);
 2680: exit0:
 2681:         return err;
 2682: }
 2683: 
 2684: /*
 2685:  *  Get the next directory entry
 2686:  */
 2687: LOCAL   ER        fatNextDIR(FATFS *fs, DIRINF *dir, UW mode)
 2688: {
 2689:         ER     err;
 2690: 
 2691:         if (dir->di_dirent == NULL) {          /* Top */
 2692:                 dir->di_dirent_ofs = 0;
 2693:                 dir->di_offset = 0;
 2694:                 return fatReadCurDIR(fs, dir);
 2695:         }
 2696: 
 2697:         /* Next entry */
 2698:         dir->di_dirent_ofs++;
 2699: 
 2700:         if (dir->di_dirent_ofs >= dir->di_nent) {
 2701:                 /* Map next cluster & read directory entry */
 2702:                 err = fatMapNextDIR(fs, dir, mode);
 2703:         } else {
 2704:                 /* Already mapped, read directory entry */
 2705:                 err = fatReadCurDIR(fs, dir);
 2706:         }
 2707:         if (err >= E_OK) {
 2708:                 if (dir->di_dirent != NULL) {
 2709:                         dir->di_offset += DIRENTSZ;
 2710:                 }
 2711:                 /* di_dirent == NULL when last entry */
 2712:         }
 2713:         return err;
 2714: }
 2715: 
 2716: /*
 2717:  *  Get the directory entry just before
 2718:  */
 2719: LOCAL   ER        fatPrevDIR(FATFS *fs, DIRINF *dir, UW mode)
 2720: {
 2721:         ER     err;
 2722: 
 2723:         if (dir->di_dirent == NULL) {  /* End */
 2724:                 err = EX_INVAL;               /* Not occur */
 2725:                 //dir->di_dirent_ofs = dir->di_nent - 1;
 2726:                 //dir->di_offset = dir->di_nent * DIRENTSZ;
 2727:         } else {                       /* Previous */
 2728:                 if (dir->di_dirent_ofs <= 0) {
 2729:                         if (dir->di_offset > 0) {
 2730:                                 /* Map the previous cluster */
 2731:                                 err = fatMapPrevDIR(fs, dir, mode);
 2732:                                 if (err >= E_OK) {
 2733:                                         dir->di_offset -= DIRENTSZ;
 2734:                                 }
 2735:                         } else {
 2736:                                 err = EX_INVAL;
 2737:                         }
 2738:                 } else {
 2739:                         dir->di_dirent_ofs--;
 2740:                         err = fatReadCurDIR(fs, dir);
 2741:                         if (err >= E_OK) {
 2742:                                 dir->di_offset -= DIRENTSZ;
 2743:                         }
 2744:                 }
 2745:         }
 2746:         return err;
 2747: }
 2748: 
 2749: /*
 2750:  *  Set the terminated mark next to directory's present location.
 2751:  */
 2752: LOCAL   ER        fatSetEndDIR(FATFS *fs, DIRINF *dir)
 2753: {
 2754:         MapInfo                map;
 2755:         UW             clno;
 2756:         W              len, bufofs;
 2757:         CLAD           clad;
 2758:         FAT_DIRENT     *de;
 2759:         ER             err, err2;
 2760: 
 2761:         if (dir->di_dirent == NULL) {
 2762:                 err = EX_INVAL;
 2763:                 goto exit0;
 2764:         }
 2765: 
 2766:         if (dir->di_dirent_ofs + 1 >= dir->di_nent) {
 2767: 
 2768:                 if (dir->di_dircl == 0) {     /* FAT12, 16 root */
 2769:                         err = E_OK;
 2770:                         goto exit0;          /* do nothing */
 2771:                 }
 2772: 
 2773:                 /* Get a next cluster */
 2774:                 clno = dir->di_clno[dir->di_len - 1].ca_no
 2775:                         + dir->di_clno[dir->di_len - 1].ca_len - 1;
 2776:                 err = fatGetClusterList(fs, &clad, 1, clno, OFSNEXT, &len);
 2777:                 if (err < E_OK) goto exit0;
 2778: 
 2779:                 if (len <= 0) goto exit0;     /* Last entry, do nothing */
 2780: 
 2781:                 /* Map a cluster */
 2782:                 err = fatMapDisk(fs, &clad, 1, &map,
 2783:                                         MAP_C | MAP_READ, (VW)dir->di_inode);
 2784:                 if (err >= E_OK) {
 2785:                         /* Set terminated entry */
 2786:                         bufofs = OFFSETinPAGE(fs, map.m_page,
 2787:                                                 CNtoBN(clad.ca_no), 0);
 2788:                         de = (FAT_DIRENT*)&map.m_page->dcp_buf[bufofs];
 2789:                         de->de_fname[0] = DE_B0_END;
 2790:                         err = fatDCacheUpdate(fs,map.m_page, (VW)dir->di_inode);
 2791:                         (void)fatMapEnd(&map);
 2792:                 }
 2793:                 fatUnmapDisk(&map);
 2794:         } else {
 2795:                 dir->di_dirent_ofs++;
 2796:                 err = fatReadCurDIR(fs, dir);
 2797:                 if (err >= E_OK) {
 2798:                         /* Set terminated entry */
 2799:                         dir->di_dirent->de_fname[0] = DE_B0_END;
 2800:                         err = fatWriteCurDIR(fs, dir, 0);
 2801: 
 2802:                         dir->di_dirent_ofs--;
 2803:                         err2 = fatReadCurDIR(fs, dir);
 2804:                         SetErr2(err, err2);
 2805:                 }
 2806:         }
 2807: exit0:
 2808:         return err;
 2809: }
 2810: 
 2811: /*
 2812:  *  Search the directory entry corresponding with the file started
 2813:  *      cluster "fclno".
 2814:  */
 2815: LOCAL   ER        fatSearchDIR_cl(FATFS *fs, DIRINF *dir, UW fclno, UW mode)
 2816: {
 2817:         FAT_DIRENT     *dirent;
 2818:         ER             err;
 2819: 
 2820:         for (;;) {
 2821:                 /* Get next directory entry */
 2822:                 err = fatNextDIR(fs, dir, mode);
 2823:                 if (err < E_OK) break;
 2824: 
 2825:                 dirent = dir->di_dirent;
 2826:                 if (dirent == NULL ||         /* Last entry */
 2827:                         isDE_TERM(dirent)) { /* Terminated entry */
 2828:                         dir->di_dirent = NULL;
 2829:                         err = EX_NOENT;
 2830:                         break;
 2831:                 }
 2832:                 if (isDE_FREE(dirent) ||      /* Free entry */
 2833:                         isDE_LFN(dirent)) {  /* LFN entry */
 2834:                         continue;
 2835:                 }
 2836:                 if (isFAT_SUBDIR(dirent->de_ftype)) {
 2837:                         /* Directory, comparison of the started cluster */
 2838:                         if (dirent_to_fcl(fs, dirent) == fclno) break;
 2839:                 }
 2840:         }
 2841:         return err;
 2842: }
 2843: 
 2844: /*
 2845:  *  Search the directory entry whose file name is identical with "utf8nm".
 2846:  */
 2847: LOCAL   ER        fatSearchDIR_nm(FATFS *fs, DIRINF *dir, UB *utf8nm, W len,
 2848:                                                 UW mode, UH *realname)
 2849: {
 2850:         FAT_DIRENT     *dirent;
 2851:         UB             sfname[BASE_EXTLEN];
 2852:         W              utf16len, enc, cks;
 2853:         UB             smallcaps;
 2854:         ER             err;
 2855: 
 2856:         /* Convert UTF8 name to UTF16 name (result in ff_nmwk) */
 2857:         utf16len = fatEncUtf8strToUtf16str(utf8nm, len,
 2858:                                         fs->ff_nmwk, LFN_MAXBUF, TRUE);
 2859:         if (utf16len <= 0) {
 2860:                 err = EX_INVAL;
 2861:                 goto exit0;
 2862:         }
 2863:         if (utf16len > LFN_MAXLEN) {
 2864:                 err = EX_NAMETOOLONG;
 2865:                 goto exit0;
 2866:         }
 2867: 
 2868:         /* Set SFN from UTF8 long name */
 2869:         enc = fatSetSFN(utf8nm, len, sfname, &smallcaps, 0);
 2870: 
 2871:         /* Search directory entry */
 2872:         for (cks = CKSVOID; ; ) {
 2873: 
 2874:                 /* Get next directory entry */
 2875:                 err = fatNextDIR(fs, dir, mode);
 2876:                 if (err < E_OK) break;
 2877: 
 2878:                 dirent = dir->di_dirent;
 2879:                 if (dirent == NULL ||         /* Last entry */
 2880:                         isDE_TERM(dirent)) { /* Terminated entry */
 2881:                         dir->di_dirent = NULL;
 2882:                         err = EX_NOENT;
 2883:                         break;
 2884:                 }
 2885:                 if (isDE_FREE(dirent)) {      /* Free entry */
 2886:                         goto next0;
 2887:                 }
 2888:                 if (isDE_LFN(dirent)) {       /* LFN entry */
 2889:                         /* Check LFN and calcurate chksum */
 2890:                         cks = fatChkLFN(fs->ff_nmwk, utf16len,
 2891:                                 (FAT_DIRENT_LFN *)dirent, cks, realname);
 2892:                         goto next1;
 2893:                 }
 2894:                 if (isDE_VOL(dirent)) {       /* Volume label */
 2895:                         goto next0;
 2896:                 }
 2897: 
 2898:                 /* SFN entry */
 2899:                 if (fatCalcChksum(dirent->de_fname) == cks) {
 2900:                         /* Checksum is matched, LFN found */
 2901:                         break;
 2902:                 }
 2903:                 if (enc != FAT_CHG_WITH_N &&
 2904:                         memcmp((B*)dirent->de_fname,
 2905:                                         (B*)sfname, BASE_EXTLEN) == 0) {
 2906:                         /* sfname is matched, SFN found */
 2907:                         if (realname != NULL) {
 2908:                                 (void)fatGetSFN(dirent->de_fname,
 2909:                                         dirent->de_smallcaps, realname);
 2910:                         }
 2911:                         break;
 2912:                 }
 2913: next0:
 2914:                 cks = CKSVOID;                /* Initilize LFN search */
 2915: next1:
 2916:                 CHK_BREAK_AND_SET_ERR(fs, &err);
 2917:                 if (err < E_OK) break;
 2918:         }
 2919: exit0:
 2920:         return err;
 2921: }
 2922: 
 2923: /*
 2924:  *  Get file number from directory entry
 2925:  */
 2926: LOCAL   UD        fatGetInoDIR(FATFS *fs, DIRINF *dir)
 2927: {
 2928:         W      i, ofs, offset;
 2929: 
 2930:         if (isFAT_SUBDIR(dir->di_dirent->de_ftype)) {  /* Directory */
 2931:                 return dirINO(fs, dirent_to_fcl(fs, dir->di_dirent));
 2932:         }
 2933: 
 2934:         if (dir->di_dircl > 0) {                       /* File */
 2935:                 for (i = 0, ofs = dir->di_dirent_ofs; ;) {
 2936:                         offset = ofs;
 2937:                         ofs -= (W)(dir->di_clno[i].ca_len * DEpCL);
 2938:                         if (++i >= dir->di_len || ofs <= 0) break;
 2939:                 }
 2940:                 return fileINO(fs, dir->di_clno[i - 1].ca_no, offset);
 2941:         }
 2942:         /* FAT12,16 root directory */
 2943:         return rootINO(fs, dir->di_dirent_ofs);
 2944: }
 2945: 
 2946: /*
 2947:  *  Get root directory file reference node
 2948:  */
 2949: LOCAL   ER        fatGetRootINODE(FATFS *fs, FATNODE ** inodep)
 2950: {
 2951:         FATNODE        *inode;
 2952:         ER     err;
 2953: 
 2954:         err = E_OK;
 2955: 
 2956:         inode = &fs->ff_rootnode;
 2957:         if (inode->fino_ftype != FAT_SUBDIR) {
 2958:                 inode->fino_c.ino_ino = fs->ff_c.fs_rootino;
 2959:                 inode->fino_c.ino_path = (UB*)inode_root_path;
 2960:                 inode->fino_c.ino_type = DT_DIR;
 2961:                 inode->fino_d_ronly = TRUE;
 2962:                 inode->fino_fclno = fs->ff_rootcl;
 2963:                 inode->fino_ftype = FAT_SUBDIR;
 2964: 
 2965:                 if (! isFAT32(fs->ff_fstype)) {
 2966:                         inode->fino_filsz = ROOTSZ;
 2967:                 } else {
 2968:                         err = fatGetClusterCount(fs, inode->fino_fclno,
 2969:                                                                 inode, NULL);
 2970:                         if (err < E_OK) inode = NULL;
 2971:                 }
 2972:         }
 2973:         *inodep = inode;
 2974:         return err;
 2975: }
 2976: 
 2977: /*
 2978:  *  Get file reference node
 2979:  */
 2980: LOCAL   ER        fatGetINODE(FATFS *fs, DIRINF *dir, UB dtype,
 2981:                                         UB *abspath, W len, FATNODE ** inodep)
 2982: {
 2983:         FATNODE                *inode;
 2984:         UD             ino;
 2985:         UB             *path;
 2986:         FAT_DIRENT     *dirent;
 2987:         ER             err;
 2988: 
 2989:         err = E_OK;
 2990:         if ((dirent = dir->di_dirent) != NULL) {       /* Exist */
 2991:                 ino = fatGetInoDIR(fs, dir);
 2992:                 inode = (FATNODE *)fatInodeSearch((FS *)fs, ino);
 2993:         } else {                                       /* Not exist */
 2994:                 inode = NULL;
 2995:                 ino = NOEXS_INO;
 2996:         }
 2997:         if (inode == NULL) {   /* Create new inode */
 2998:                 inode = fimp_calloc(1, sizeof(FATNODE));
 2999:                 if (inode == NULL) {
 3000:                         err = EX_NOMEM;
 3001:                         goto exit0;
 3002:                 }
 3003:                 if (dirent != NULL) { /* Exists */
 3004:                         inode->fino_dirofs = dir->di_offset;
 3005:                         inode->fino_fclno = dirent_to_fcl(fs, dirent);
 3006:                         inode->fino_ftype = dirent->de_ftype;
 3007: 
 3008:                         if (isFAT_SUBDIR(dirent->de_ftype)) {
 3009:                                 inode->fino_c.ino_type = DT_DIR;
 3010:                                 /* Size of directory */
 3011:                                 err = fatGetClusterCount(fs, inode->fino_fclno,
 3012:                                                                 inode, NULL);
 3013:                                 if (err < E_OK) {
 3014:                                         fimp_free(inode);
 3015:                                         goto exit0;
 3016:                                 }
 3017:                         } else {     /* Usual file size */
 3018:                                 inode->fino_c.ino_type = DT_REG;
 3019:                                 inode->fino_filsz = (D)
 3020:                                                 ((UW)CEW(dirent->de_fsize));
 3021:                         }
 3022:                 }
 3023:                 inode->fino_dircl = dir->di_dircl;
 3024:                 inode->fino_d_ronly = isFAT_RDONLY(dtype) ? TRUE : FALSE;
 3025:                 inode->fino_c.ino_ino = ino;
 3026:         }
 3027: 
 3028:         /* Set abs path name when directory */
 3029:         if (inode->fino_c.ino_type == DT_DIR &&
 3030:                                         inode->fino_c.ino_path == NULL) {
 3031:                 path = fimp_malloc(len + 1);
 3032:                 if (path == NULL) {
 3033:                         fimp_free(inode);
 3034:                         err = EX_NOMEM;
 3035:                         goto exit0;
 3036:                 }
 3037:                 inode->fino_c.ino_path = path;
 3038:                 while (--len >= 0) {
 3039:                         *path++ = *abspath++;
 3040:                 }
 3041:                 *path = '\0';
 3042:         }
 3043:         if (inode != NULL) {
 3044:                 *inodep = inode;
 3045:         }
 3046: exit0:
 3047:         return err;
 3048: }
 3049: 
 3050: /*----------------------------------------------------------------------------
 3051:         Time operations
 3052: ----------------------------------------------------------------------------*/
 3053: 
 3054: /*
 3055:  *  Get date & time
 3056:  */
 3057: LOCAL   void      fatGetDateTime(FAT_DIRENT *dirent, struct stat64_us *sb)
 3058: {
 3059:         struct tm      mtim, atim;
 3060: 
 3061:         memset(&mtim, 0, sizeof(struct tm));
 3062:         mtim.tm_sec = (CEH(dirent->de_mtime) & FAT_TIME_MASK_SEC) << 1;
 3063:         mtim.tm_min = (CEH(dirent->de_mtime) & FAT_TIME_MASK_MIN) >>
 3064:                                                 FAT_TIME_SHIFT_MIN;
 3065:         mtim.tm_hour = (CEH(dirent->de_mtime) & FAT_TIME_MASK_HOUR) >>
 3066:                                                 FAT_TIME_SHIFT_HOUR;
 3067:         mtim.tm_mday = CEH(dirent->de_mdate) & FAT_TIME_MASK_SEC;
 3068:         mtim.tm_mon = ((CEH(dirent->de_mdate) & FAT_DATE_MASK_MON) >>
 3069:                                                 FAT_DATE_SHIFT_MON) - 1;
 3070:         mtim.tm_year = ((CEH(dirent->de_mdate) & FAT_DATE_MAS_YEAR) >>
 3071:                                 FAT_DATE_SHIFT_YEAR) + FATYEAR_TO_TMYEAR;
 3072: 
 3073:         memset(&atim, 0, sizeof(struct tm));
 3074:         atim.tm_mday = CEH(dirent->de_adate) & FAT_TIME_MASK_SEC;
 3075:         atim.tm_mon = ((CEH(dirent->de_adate) & FAT_DATE_MASK_MON) >>
 3076:                                 FAT_DATE_SHIFT_MON) -1;
 3077:         atim.tm_year = ((CEH(dirent->de_adate) & FAT_DATE_MAS_YEAR) >>
 3078:                                 FAT_DATE_SHIFT_YEAR) + FATYEAR_TO_TMYEAR;
 3079: 
 3080:         /* There is no "last status change time" in FAT file system.
 3081:                 Then, use "last modified time" as "last status change time".
 3082:                 Note: Create date/time in FAT is not used.    */
 3083: 
 3084:         (void)dt_mktime_us(&mtim, NULL, &sb->st_mtime_u);
 3085:         (void)dt_mktime_us(&mtim, NULL, &sb->st_ctime_u);
 3086:         (void)dt_mktime_us(&atim, NULL, &sb->st_atime_u);
 3087: }
 3088: 
 3089: /*
 3090:  *  Set date & time
 3091:  */
 3092: LOCAL   ER        fatSetDateTime(UH *date, UH *time, const SYSTIM_U *stime_u)
 3093: {
 3094:         SYSTIM_U       tim_u;
 3095:         struct tm      tm;
 3096:         UH             de_date, de_time;
 3097:         ER             err;
 3098: 
 3099:         if (stime_u == NULL) { /* Set system time */
 3100:                 (void)tk_get_tim_u(&tim_u, 0);
 3101:         } else {
 3102:                 tim_u = *stime_u;
 3103:         }
 3104:         err = dt_localtime_us(tim_u, NULL, &tm);
 3105:         if (err >= E_OK) {
 3106:                 /* Convert into calendar format */
 3107:                 de_date = (UH)(       ((tm.tm_year - FATYEAR_TO_TMYEAR) <<
 3108:                                                         FAT_DATE_SHIFT_YEAR) |
 3109:                                 ((tm.tm_mon + 1) << FAT_DATE_SHIFT_MON) |
 3110:                                 tm.tm_mday );
 3111:                 de_time = (UH)(       (tm.tm_hour << FAT_TIME_SHIFT_HOUR) |
 3112:                                 (tm.tm_min << FAT_TIME_SHIFT_MIN) |
 3113:                                 (tm.tm_sec >> 1));
 3114:                 *date = CEH(de_date);
 3115:                 *time = CEH(de_time);
 3116:         }
 3117:         return err;
 3118: }
 3119: 
 3120: /*----------------------------------------------------------------------------
 3121:         File operarions
 3122: ----------------------------------------------------------------------------*/
 3123: 
 3124: /*
 3125:  *  Check if the SFN exists in the directory.
 3126:  */
 3127: LOCAL   ER        fatCheckDirent(FATFS *fs, UW dircl, UB *sfname, UW nent)
 3128: {
 3129:         DIRINF         dir;
 3130:         FAT_DIRENT     *dirent;
 3131:         UB             nm[BASE_EXTLEN];
 3132:         W              i, exist, existall, gnpos;
 3133:         ER             err;
 3134: 
 3135:         /* Directory open */
 3136:         err = fatOpenDIR(fs, &dir, dircl, OFSVOID, AC_RDONLY, NULL);
 3137:         if (err < E_OK) goto exit0;
 3138: 
 3139:         /* Last digit position of generation number */
 3140:         for (gnpos = BASELEN; sfname[--gnpos] == ' '; );
 3141: 
 3142:         /* Directory search */
 3143:         existall = (1 << nent) - 1;            /* All exist pattern */
 3144:         for (exist = 0; exist != existall; ) {
 3145: 
 3146:                 /* Get next directory entry */
 3147:                 err = fatNextDIR(fs, &dir, AC_RDONLY);
 3148:                 if (err < E_OK) break;
 3149: 
 3150:                 dirent = dir.di_dirent;
 3151:                 if (dirent == NULL ||         /* Last entry */
 3152:                         isDE_TERM(dirent) ) {        /* Terminated entry */
 3153:                         break;
 3154:                 }
 3155:                 if (isDE_FREE(dirent) ||      /* Free entry */
 3156:                         isDE_LFN(dirent)  || /* LFN entry */
 3157:                         isDE_VOL(dirent) ) { /* Volume label */
 3158:                         continue;
 3159:                 }
 3160: 
 3161:                 /* SFN entry, check name by increasing generation number */
 3162:                 memcpy(nm, sfname, BASE_EXTLEN);
 3163:                 for (i = 0; i < nent; i++, nm[gnpos] += 1) {
 3164:                         if (isSET(exist, (1 << i)) ||
 3165:                                 memcmp(dirent->de_fname, nm, BASE_EXTLEN) != 0)
 3166:                                         continue;
 3167:                         exist |= (1 << i);   /* Exists */
 3168:                         break;
 3169:                 }
 3170:         }
 3171: 
 3172:         /* Directory close */
 3173:         err = fatCloseDIR(fs, &dir, err);
 3174:         if (err < E_OK) goto exit0;
 3175: 
 3176:         err = E_OK;
 3177:         if (exist != existall) {
 3178:                 for (i = 0; i < nent && isSET(exist, 1); i++, exist >>= 1);
 3179:                 sfname[gnpos] += i;   /* Set unique generation number */
 3180:                 err = E_OK + 1;
 3181:         }
 3182: exit0:
 3183:         return err;
 3184: }
 3185: 
 3186: /*
 3187:  *  Search the "nent" (>= 1) pieces of empty entries successive from
 3188:  *  the directory "dircl".
 3189:  *    1. Use entries after the termination entry.
 3190:  *    2. Use successive free entry.
 3191:  *    3. Expands directory.
 3192:  */
 3193: LOCAL   ER        fatSearchFreeDirent(FATFS *fs, UW dircl, UW nent, W *ofs)
 3194: {
 3195:         DIRINF         dir;
 3196:         FAT_DIRENT     *dirent;
 3197:         W              end, free, offset, freeofs, num, nbyte;
 3198:         FATNODE                *inode;
 3199:         BOOL           found;
 3200:         CLAD           clad;
 3201:         MapInfo                map;
 3202:         ER             err;
 3203: 
 3204:         /* Directory open */
 3205:         err = fatOpenDIR(fs, &dir, dircl, 0, AC_WRITE, NULL);
 3206:         if (err < E_OK) goto exit0;
 3207: 
 3208:         for (end = free = 0, freeofs = OFSVOID, found = FALSE;;) {
 3209:                 offset = (W)dir.di_offset;
 3210: 
 3211:                 dirent = dir.di_dirent;
 3212:                 if (dirent == NULL) {                 /* Last entry */
 3213:                         if (freeofs != OFSVOID) {
 3214:                                 offset = freeofs;
 3215:                                 found = TRUE;
 3216:                         }
 3217:                         break;
 3218:                 }
 3219:                 if (end > 0 || isDE_TERM(dirent)) {   /* Terminated entry */
 3220:                         if (++end >= nent) {
 3221:                                 err = fatSetEndDIR(fs, &dir);
 3222:                                 if (err >= E_OK) found = TRUE;
 3223:                                 break;
 3224:                         }
 3225:                 } else if (isDE_FREE(dirent) && freeofs == OFSVOID) {
 3226:                         /* Free entry */
 3227:                         if (++free >= nent) {
 3228:                                 freeofs = offset;
 3229: #ifdef  USE_1ST_FREEENT
 3230:                                 found = TRUE;
 3231:                                 break;
 3232: #endif
 3233:                         }
 3234:                 } else {
 3235:                         /* Reset of the number of successive free entries */
 3236:                         free = 0;
 3237:                 }
 3238:                 /* Get next directory entry */
 3239:                 err = fatNextDIR(fs, &dir, AC_WRITE);
 3240:                 if (err < E_OK) break;
 3241:         }
 3242: 
 3243:         /* Directory close */
 3244:         err = fatCloseDIR(fs, &dir, err);
 3245:         if (err < E_OK) goto exit0;
 3246: 
 3247:         if (found != FALSE) goto exit1;
 3248: 
 3249:         /* Not found */
 3250:         inode = dir.di_inode;
 3251:         if (dircl > 0) {       /* FAT32 or sub directory */
 3252:                 nbyte = ((W)nent - end) * DIRENTSZ;
 3253: 
 3254:                 /* Empty cluster search. Note nbyte <= ff_clsz */
 3255:                 err = fatGetNewCluster(fs, &clad, fs->ff_nextfree, nbyte);
 3256:                 if (err < E_OK) goto exit0;
 3257: 
 3258:                 /* Directory size */
 3259:                 err = fatGetClusterCount(fs, dircl, NULL, &num);
 3260:                 if (err < E_OK) goto exit0;
 3261: 
 3262:                 if (((num + clad.ca_len) * fs->ff_clsz) > DIR_SIZE_MAX) {
 3263:                         err = EX_FBIG;
 3264:                         goto exit0;
 3265:                 }
 3266: 
 3267:                 /* Directory expansion */
 3268:                 if (inode != NULL) {
 3269:                         err = fatExtendClusterList(fs, &clad, inode);
 3270:                         if (err < E_OK) goto exit0;
 3271: 
 3272:                         inode->fino_filsz += (fs->ff_clsz * clad.ca_len);
 3273:                         if (inode->fino_filsz > FILE_SIZE_MAX) {
 3274:                                 inode->fino_filsz = FILE_SIZE_MAX;
 3275:                         }
 3276:                 } else {
 3277:                         err = fatChainCluster(fs, dircl, &clad, NULL);
 3278:                 }
 3279: 
 3280:                 /* Zero clear */
 3281:                 err = fatMapDisk(fs, &clad, 1, &map, MAP_C | MAP_CLR,(VW)inode);
 3282:                 fatUnmapDisk(&map);
 3283: 
 3284:                 /* Entry location */
 3285:                 offset += nbyte;
 3286: 
 3287:         } else {       /* FAT12, FAT16 root directory */
 3288:                 /* Note: !! do not support arrangement of root directory
 3289:                         entries to make successive free entries !! */
 3290:                 err = EX_NOSPC;
 3291:                 goto exit0;
 3292:         }
 3293: exit1:
 3294:         *ofs = offset;
 3295: exit0:
 3296:         return err;
 3297: }
 3298: 
 3299: /*
 3300:  *  File initialization
 3301:  */
 3302: LOCAL   ER        fatInitDirent(FATFS *fs, FAT_DIRENT *dirent, FATNODE *inode)
 3303: {
 3304:         UH             date, time;
 3305:         MapInfo                map;
 3306:         CLAD           clad;
 3307:         FAT_DIRENT     *de;
 3308:         ER             err;
 3309: 
 3310:         /* File time */
 3311:         err = fatSetDateTime(&date, &time, NULL);
 3312:         if (err < E_OK) goto exit0;
 3313: 
 3314:         /* Entry initialization */
 3315:         memset(dirent, 0, sizeof(FAT_DIRENT));
 3316:         dirent->de_ftype = inode->fino_ftype | FAT_ARCHIV;
 3317:         //dirent->de_smallcaps = 0;
 3318:         dirent->de_adate = date;
 3319:         dirent->de_ctime = time;
 3320:         dirent->de_cdate = date;
 3321:         dirent->de_mdate = date;
 3322:         dirent->de_mtime = time;
 3323: 
 3324:         /* Directory */
 3325:         if (! isFAT_SUBDIR(inode->fino_ftype)) goto exit0;
 3326: 
 3327:         /* Append new cluster */
 3328:         err = fatApdNewCluster(fs, &clad, fs->ff_clsz, inode);
 3329:         if (err < E_OK) goto exit0;
 3330: 
 3331:         inode->fino_filsz = fs->ff_clsz;
 3332:         inode->fino_fclno = clad.ca_no;
 3333:         fcl_to_dirent(fs, dirent, inode->fino_fclno);
 3334: 
 3335:         /* Map and initialization of cluster */
 3336:         err = fatMapDisk(fs, &clad, 1, &map, MAP_C | MAP_CLR, (VW)inode);
 3337:         if (err < E_OK) goto exit1;
 3338: 
 3339:         /* Create "." entry  */
 3340:         de = (FAT_DIRENT *)&map.m_page->dcp_buf[
 3341:                         OFFSETinPAGE(fs, map.m_page, CNtoBN(clad.ca_no), 0)];
 3342:         memcpy(de->de_fname, nmDOT, BASE_EXTLEN);
 3343:         de->de_ftype = FAT_SUBDIR;
 3344:         de->de_smallcaps = 0;
 3345:         de->de_rsv[0] = 0;
 3346:         de->de_adate = date;
 3347:         de->de_ctime = time;
 3348:         de->de_cdate = date;
 3349:         de->de_mtime = time;
 3350:         de->de_mdate = date;
 3351:         de->de_fsize = 0;
 3352:         fcl_to_dirent(fs, de, inode->fino_fclno);
 3353: 
 3354:         /* Create ".." entry  */
 3355:         de++;
 3356:         memcpy(de->de_fname, nmDOT2, BASE_EXTLEN);
 3357:         de->de_ftype = FAT_SUBDIR;
 3358:         de->de_smallcaps = 0;
 3359:         de->de_rsv[0] = 0;
 3360:         de->de_adate = date;
 3361:         de->de_ctime = time;
 3362:         de->de_cdate = date;
 3363:         de->de_mtime = time;
 3364:         de->de_mdate = date;
 3365:         de->de_fsize = 0;
 3366:         fcl_to_dirent(fs, de, inode->fino_dircl);
 3367: 
 3368:         err = fatDCacheUpdate(fs, map.m_page, (VW)inode);
 3369:         (void)fatMapEnd(&map);
 3370: exit1:
 3371:         fatUnmapDisk(&map);
 3372: exit0:
 3373:         return err;
 3374: }
 3375: 
 3376: /*
 3377:  *  Copy a directory entry
 3378:  */
 3379: LOCAL   ER        fatCopyDirent(FATFS *fs, FAT_DIRENT *from, FAT_DIRENT *to,
 3380:                                                 FATNODE *inode)
 3381: {
 3382:         DIRINF dir;
 3383:         ER     err;
 3384: 
 3385:         err = E_OK;
 3386: 
 3387:         /* Initilization of entry */
 3388:         memset(to, 0, sizeof(FAT_DIRENT));
 3389:         to->de_ftype = from->de_ftype | FAT_ARCHIV;
 3390:         to->de_adate = from->de_adate;
 3391:         to->de_ctime = from->de_ctime;
 3392:         to->de_cdate = from->de_cdate;
 3393:         to->de_mtime = from->de_mtime;
 3394:         to->de_mdate = from->de_mdate;
 3395:         to->de_clno_hi = from->de_clno_hi;
 3396:         to->de_clno_lo = from->de_clno_lo;
 3397:         to->de_fsize = from->de_fsize;
 3398: 
 3399:         /* Directory */
 3400:         if (! isFAT_SUBDIR(inode->fino_ftype)) goto exit0;
 3401: 
 3402:         /* Directory open */
 3403:         err = fatOpenDIR(fs, &dir, inode->fino_fclno, OFSVOID, AC_WRITE, inode);
 3404:         if (err < E_OK) goto exit0;
 3405: 
 3406:         /*  ".." entry search */
 3407:         err = fatSearchDIR_nm(fs, &dir, (UB*)nmDOT2, 2, AC_WRITE, NULL);
 3408:         if (err >= E_OK) {
 3409:                 fcl_to_dirent(fs, dir.di_dirent, inode->fino_dircl);
 3410:                 err = fatWriteCurDIR(fs, &dir, 0);
 3411:         }
 3412: 
 3413:         /* Directory close */
 3414:         err = fatCloseDIR(fs, &dir, err);
 3415: exit0:
 3416:         return err;
 3417: }
 3418: 
 3419: /*
 3420:  *  Update file system information
 3421:  */
 3422: LOCAL   ER        fatUpdateFileSystem(FATFS *fs)
 3423: {
 3424:         FAT_FSINFO     *fsi;
 3425:         DCachePage     *page;
 3426:         ER             err;
 3427: 
 3428:         err = E_OK;
 3429: 
 3430:         /* Confirm file system information */
 3431:         if (fs->ff_fsinfo > 0) {
 3432: 
 3433:                 /* Map the file system information sector */
 3434:                 err = fatDCacheStart(fs, fs->ff_fsinfo, &page);
 3435:                 if (err < E_OK) goto exit0;
 3436: 
 3437:                 fsi = (FAT_FSINFO *)&page->dcp_buf[
 3438:                         OFFSETinPAGE(fs, page, fs->ff_fsinfo, 0)];
 3439: 
 3440:                 /* Update file system information only when changed */
 3441:                 if ( fsi->fsi_freecl != CEW(fs->ff_freecl) ||
 3442:                         fsi->fsi_nextfree != CEW(fs->ff_nextfree) ) {
 3443: 
 3444:                         /* Update the free cluster count */
 3445:                         fsi->fsi_freecl = CEW(fs->ff_freecl);
 3446: 
 3447:                         /* Record the start position to search free clusters */
 3448:                         fsi->fsi_nextfree = CEW(fs->ff_nextfree);
 3449: 
 3450:                         (void)fatDCacheUpdate(fs, page, 0);
 3451:                         err = fatDCacheEnd(fs, page);
 3452:                 }
 3453:         }
 3454: exit0:
 3455:         return err;
 3456: }
 3457: 
 3458: /*
 3459:  *  Update directory entry to the file "inode" content.
 3460:  */
 3461: LOCAL   ER        fatUpdateFile(FATFS *fs, FATNODE *inode)
 3462: {
 3463:         DIRINF dir;
 3464:         UH     date, time;
 3465:         ER     err;
 3466: 
 3467:         /* File time */
 3468:         err = fatSetDateTime(&date, &time, NULL);
 3469:         if (err < E_OK) goto exit0;
 3470: 
 3471:         /* Directory open */
 3472:         err = fatOpenDIR(fs, &dir, inode->fino_dircl,
 3473:                                 (W)inode->fino_dirofs, AC_WRITE, NULL);
 3474:         if (err < E_OK) goto exit0;
 3475: 
 3476:         if (dir.di_dirent == NULL) {
 3477:                 err = EX_NOENT;
 3478:         } else {
 3479:                 dir.di_dirent->de_fsize = (W)CEW(inode->fino_filsz);
 3480:                 dir.di_dirent->de_ftype |= FAT_ARCHIV;
 3481:                 fcl_to_dirent(fs, dir.di_dirent, inode->fino_fclno);
 3482:                 dir.di_dirent->de_mdate = date;
 3483:                 dir.di_dirent->de_mtime = time;
 3484:                 err = fatWriteCurDIR(fs, &dir, (VW)inode);
 3485:         }
 3486:         /* Directory close */
 3487:         err = fatCloseDIR(fs, &dir, err);
 3488:         if (err >= E_OK) {
 3489:                 /* Update the file system information : ignore error */
 3490:                 (void)fatUpdateFileSystem(fs);
 3491:         }
 3492: exit0:
 3493:         return err;
 3494: }
 3495: 
 3496: /*
 3497:  *  Get parent directory
 3498:  */
 3499: LOCAL   ER        fatGetParentDirectory(FATFS *fs, W *dircl, FATNODE *inode)
 3500: {
 3501:         ER     err;
 3502:         DIRINF dir;
 3503: 
 3504:         /* Directory open */
 3505:         err = fatOpenDIR(fs, &dir, *dircl, OFSVOID, AC_RDONLY, inode);
 3506:         if (err < E_OK) return err;
 3507: 
 3508:         /* Search of directory ".."  */
 3509:         err = fatSearchDIR_nm(fs, &dir, (UB*)nmDOT2, 2, AC_RDONLY, NULL);
 3510:         if (err >= E_OK) {
 3511:                 /* Parent directory started cluster */
 3512:                 *dircl = (W)dirent_to_fcl(fs, dir.di_dirent);
 3513:         }
 3514:         /* Directory close */
 3515:         return fatCloseDIR(fs, &dir, err);
 3516: }
 3517: 
 3518: /*
 3519:  *  Update the directory entry of the parent diretory of the file "inode".
 3520:  */
 3521: LOCAL   ER        fatUpdateDirectory(FATFS *fs, FATNODE *inode)
 3522: {
 3523:         DIRINF dir;
 3524:         FATNODE        *din;
 3525:         W      dircl;
 3526:         UH     date, time;
 3527:         ER     err;
 3528: 
 3529:         dircl = 0;
 3530: 
 3531:         /* Root directory */
 3532:         if (inode->fino_dircl == fs->ff_rootcl) goto exit0;
 3533: 
 3534:         /* File reference node search */
 3535:         din = (FATNODE *)fatInodeSearch((FS*)fs, dirINO(fs, inode->fino_dircl));
 3536: 
 3537:         /* File modification time */
 3538:         err = fatSetDateTime(&date, &time, NULL);
 3539:         if (err < E_OK) goto exit0;
 3540: 
 3541:         /* Get Parent directory started cluster */
 3542:         dircl = inode->fino_dircl;
 3543:         err = fatGetParentDirectory(fs, &dircl, din);
 3544:         if (err < E_OK) goto exit0;
 3545: 
 3546:         /* Parent directory open */
 3547:         err = fatOpenDIR(fs, &dir, (UW)dircl, OFSVOID, AC_WRITE, NULL);
 3548:         if (err < E_OK) goto exit0;
 3549: 
 3550:         /* Search of directory entry  */
 3551:         err = fatSearchDIR_cl(fs, &dir, inode->fino_dircl, AC_WRITE);
 3552:         if (err >= E_OK) {
 3553:                 dir.di_dirent->de_mdate = date;
 3554:                 dir.di_dirent->de_mtime = time;
 3555:                 err = fatWriteCurDIR(fs, &dir, (VW)inode);
 3556:         }
 3557:         /* Parent directory close */
 3558:         err = fatCloseDIR(fs, &dir, err);
 3559: exit0:
 3560:         /* Update the file system information : ignore error */
 3561:         (void)fatUpdateFileSystem(fs);
 3562:         return E_OK;
 3563: }
 3564: 
 3565: /*
 3566:  *  Check if directory "to" is not the subdirectory of directory "from".
 3567:  */
 3568: LOCAL   ER        fatCheckSubDirectory(FATFS *fs, FATNODE *from, FATNODE *to)
 3569: {
 3570:         W      dircl;
 3571:         ER     err;
 3572: 
 3573:         err = E_OK;
 3574: 
 3575:         if (isFAT_SUBDIR(from->fino_ftype)) {
 3576:                 for (dircl = to->fino_dircl; ;) {
 3577:                         /* Error by the consistence of subdirectory */
 3578:                         if (dircl == from->fino_fclno) {
 3579:                                 err = EX_INVAL;
 3580:                                 break;
 3581:                         }
 3582:                         /* Root directory */
 3583:                         if (dircl == fs->ff_rootcl) break;
 3584: 
 3585:                         /* Get Parent directory started cluster */
 3586:                         err = fatGetParentDirectory(fs, &dircl, NULL);
 3587:                         if (err < E_OK) break;
 3588:                 }
 3589:         }
 3590:         return err;
 3591: }
 3592: 
 3593: /*
 3594:  *  Create a new file from the file "inode" directory and the file type.
 3595:  *  If copy file "rename" is designated, copy "rename" to new file.
 3596:  */
 3597: LOCAL   ER        fatCreateFile(FATFS *fs, FATNODE *inode, UB *utf8nm,
 3598:                                                         FAT_DIRENT *rename)
 3599: {
 3600:         UB             sfname[BASE_EXTLEN];
 3601:         W              utf8len, utf16len, ofs;
 3602:         W              gen, idx, nent, enc;
 3603:         UB             smallcaps, chksum;
 3604:         DIRINF         dir;
 3605:         FAT_DIRENT     *dirent;
 3606:         ER             err;
 3607: 
 3608:         err = E_OK;
 3609: 
 3610:         /* Remove trailing ' ' and '.' of pathname */
 3611:         utf8len = strlen((B*)utf8nm);
 3612:         while (utf8nm[utf8len - 1] == ' ' ||
 3613:                                 utf8nm[utf8len - 1] == '.') utf8len--;
 3614: 
 3615:         /* Convert to UTF16 LFN */
 3616:         utf16len = fatEncUtf8strToUtf16str(utf8nm, utf8len,
 3617:                                         fs->ff_nmbf, LFN_MAXBUF, FALSE);
 3618:         if (utf16len <= 0) {
 3619:                 err = EX_INVAL;
 3620:                 goto exit1;
 3621:         }
 3622:         if (utf16len > LFN_MAXLEN) {
 3623:                 err = EX_NAMETOOLONG;
 3624:                 goto exit1;
 3625:         }
 3626: 
 3627:         /* Generate SFN which is unique in the directory */
 3628:         smallcaps = 0x00;
 3629:         for (nent = 1, gen = 1; ; ) {
 3630: 
 3631:                 /* Generation numbered file name conversion */
 3632:                 enc = fatSetSFN(utf8nm, utf8len, sfname, &smallcaps, gen);
 3633:                 if (enc == FAT_SAME_NAME) break;      /* LFN not required */
 3634: 
 3635:                 smallcaps = 0x00;
 3636: 
 3637:                 /* Check file name increasing last digit of generation number
 3638:                         from '1' to '9' */
 3639:                 err = fatCheckDirent(fs, inode->fino_dircl, sfname,
 3640:                                         (enc == FAT_CHG_WITH_N) ? 9 : 1);
 3641:                 if (err < E_OK) break;
 3642:                 if (err > E_OK) {     /* Check OK */
 3643:                         nent += (utf16len + LFN_CHARS - 1) / LFN_CHARS;
 3644:                         break;
 3645:                 }
 3646:                 /* Check again with new generation number : ..N1 */
 3647:                 gen += 10;
 3648:         }
 3649: 
 3650:         /* Get empty directory entry */
 3651:         err = fatSearchFreeDirent(fs, inode->fino_dircl, (UW)nent, &ofs);
 3652:         if (err < E_OK) goto exit1;
 3653: 
 3654:         /* Entry location */
 3655:         inode->fino_dirofs = (UW)ofs;
 3656: 
 3657:         /* Directory open */
 3658:         err = fatOpenDIR(fs, &dir, inode->fino_dircl, (W)inode->fino_dirofs,
 3659:                                                 AC_WRITE, NULL);
 3660:         if (err < E_OK) goto exit1;
 3661: 
 3662:         if (dir.di_dirent == NULL) {
 3663:                 err = EX_NOENT;
 3664:                 goto exit2;
 3665:         }
 3666: 
 3667:         /* Set SFN entry */
 3668:         dirent = dir.di_dirent;
 3669:         if (rename != NULL) {  /* Entry copy */
 3670:                 err = fatCopyDirent(fs, rename, dirent, inode);
 3671:         } else {               /* Entry initialization */
 3672:                 err = fatInitDirent(fs, dirent, inode);
 3673:         }
 3674:         if (err < E_OK) goto exit2;
 3675: 
 3676:         dirent->de_smallcaps = smallcaps;
 3677:         memcpy(dirent->de_fname, sfname, BASE_EXTLEN);
 3678:         inode->fino_c.ino_ino = fatGetInoDIR(fs, &dir);
 3679:         inode->fino_c.ino_type =
 3680:                         isFAT_SUBDIR(inode->fino_ftype) ? DT_DIR : DT_REG;
 3681:         err = fatWriteCurDIR(fs, &dir, (VW)inode);
 3682:         if (err < E_OK) goto exit2;
 3683: 
 3684:         /* Set LFN entry */
 3685:         if (nent > 1)  {
 3686:                 /* Checksum */
 3687:                 chksum = fatCalcChksum(sfname);
 3688: 
 3689:                 for (idx = 1; idx < nent; idx++) {
 3690:                         /* Previous */
 3691:                         err = fatPrevDIR(fs, &dir, AC_WRITE);
 3692:                         if (err < E_OK) break;
 3693: 
 3694:                         fatSetLFN(fs->ff_nmbf, utf16len,
 3695:                                 (FAT_DIRENT_LFN *)dir.di_dirent, idx, chksum);
 3696:                         err = fatWriteCurDIR(fs, &dir, (VW)inode);
 3697:                         if (err < E_OK) break;
 3698:                 }
 3699:         }
 3700: exit2:
 3701:         /* Directory close */
 3702:         err = fatCloseDIR(fs, &dir, err);
 3703: exit1:
 3704:         return err;
 3705: }
 3706: 
 3707: /*
 3708:  *  Deletion of file
 3709:  */
 3710: LOCAL   ER        fatRemoveFile(FATFS *fs, FATNODE *inode)
 3711: {
 3712:         DIRINF dir;
 3713:         ER     err;
 3714: 
 3715:         /* Directory open */
 3716:         err = fatOpenDIR(fs, &dir, inode->fino_dircl, (W)inode->fino_dirofs,
 3717:                                                 AC_WRITE, NULL);
 3718:         if (err < E_OK) goto exit0;
 3719: 
 3720:         if (dir.di_dirent == NULL) {
 3721:                 err = EX_NOENT;
 3722:                 goto exit0;
 3723:         }
 3724: 
 3725:         /* Delete directory entry */
 3726:         dir.di_dirent->de_fname[0] = DE_B0_FREE;
 3727:         err = fatWriteCurDIR(fs, &dir, (VW)inode);
 3728:         if (err < E_OK) goto exit0;
 3729: 
 3730:         /* Deletion of LFN entry */
 3731:         for (;;) {
 3732:                 if (dir.di_offset == 0) break;        /* Top entry */
 3733: 
 3734:                 /* Previous */
 3735:                 err = fatPrevDIR(fs, &dir, AC_WRITE);
 3736:                 if (err < E_OK) break;
 3737: 
 3738:                 if (! isDE_LFN(dir.di_dirent)) break;
 3739: 
 3740:                 /* Delete LFN entry */
 3741:                 dir.di_dirent->de_fname[0] = DE_B0_FREE;
 3742:                 err = fatWriteCurDIR(fs, &dir, (VW)inode);
 3743:                 if (err < E_OK) break;
 3744:         }
 3745: 
 3746:         /* Directory close */
 3747:         err = fatCloseDIR(fs, &dir, err);
 3748:         if (err >= E_OK) {
 3749:                 /* Delete clusters */
 3750:                 err = fatTruncClusterList(fs, 0, inode);
 3751:         }
 3752: exit0:
 3753:         return err;
 3754: }
 3755: 
 3756: /*
 3757:  *  Extension of file size
 3758:  */
 3759: LOCAL   ER        fatExtendFile(FATFS *fs, FATNODE *inode, D size)
 3760: {
 3761:         CLAD   clad[MAX_CLEN];
 3762:         MapInfo        map;
 3763:         D      fsz, incsz;
 3764:         W      cllen, ofs, i;
 3765:         UW     clsz;
 3766:         ER     err;
 3767: 
 3768:         err = E_OK;
 3769: 
 3770:         /* File size */
 3771:         fsz = (UW)inode->fino_filsz;
 3772:         if (fsz >= size) goto exit0;
 3773: 
 3774:         /* Check free clusters */
 3775:         if (BYTEtoCL(size) - BYTEtoCL(fsz) > fs->ff_freecl) {
 3776:                 err = EX_NOSPC;
 3777:                 goto exit0;
 3778:         }
 3779: 
 3780:         /* Extend file size */
 3781:         for (ofs = fsz % fs->ff_clsz; (incsz = size - fsz) > 0; ofs = 0) {
 3782: 
 3783:                 /* Get next cluster list */
 3784:                 err = fatCopyClusterList(fs, clad, fsz, incsz, inode, &cllen);
 3785:                 if (err < E_OK) goto exit0;
 3786: 
 3787:                 /* Note; if ofs > 0, cllen == 1, and clad[0].ca_len = 1 */
 3788: 
 3789:                 if (cllen <= 0) {     /* Append new cluster */
 3790:                         err = fatApdNewCluster(fs, &clad[0], incsz, inode);
 3791:                         if (err < E_OK) goto exit0;
 3792:                         cllen = 1;
 3793:                 }
 3794: 
 3795:                 /* Zero clear */
 3796:                 err = fatMapDisk(fs, clad, cllen, &map, MAP_C |
 3797:                                         ((ofs > 0) ? 0 : MAP_CLR), (VW)inode);
 3798:                 if (err >= E_OK && ofs > 0) {
 3799:                         /* Clear a cluster after ofs : 1st time only */
 3800:                         err = fatMapWriteBytes(&map, ofs, NULL,
 3801:                                         (incsz < fs->ff_clsz - ofs) ?
 3802:                                                 incsz : fs->ff_clsz - ofs);
 3803:                         (void)fatMapEnd(&map);
 3804:                 }
 3805:                 fatUnmapDisk(&map);
 3806:                 if (err < E_OK) break;
 3807: 
 3808:                 /* Calc new file cluster size */
 3809:                 for (clsz = 0, i = 0; i < cllen; i++) clsz += clad[i].ca_len;
 3810:                 fsz += clsz * fs->ff_clsz - ofs;
 3811:         }
 3812: 
 3813:         /* File update */
 3814:         inode->fino_filsz = size;
 3815:         err = fatUpdateFile(fs, inode);
 3816: exit0:
 3817:         return err;
 3818: }
 3819: 
 3820: /*
 3821:  *  Reduction of file size
 3822:  */
 3823: LOCAL   ER        fatTruncateFile(FATFS *fs, FATNODE *inode, D size)
 3824: {
 3825:         ER     err;
 3826: 
 3827:         err = E_OK;
 3828:         if (size < inode->fino_filsz) {
 3829:                 /* File reduction */
 3830:                 err = fatTruncClusterList(fs, size, inode);
 3831:                 if (err >= E_OK) {
 3832:                         /* File update */
 3833:                         err = fatUpdateFile(fs, inode);
 3834:                 }
 3835:         }
 3836:         return err;
 3837: }
 3838: 
 3839: /*
 3840:  *  Check if the directory "inode" includes the active entry or not.
 3841:  */
 3842: LOCAL   ER        fatChkEmptyDirectory(FATFS *fs, FATNODE *inode)
 3843: {
 3844:         DIRINF         dir;
 3845:         FAT_DIRENT     *dirent;
 3846:         ER             err;
 3847: 
 3848:         /* Directory open */
 3849:         err = fatOpenDIR(fs, &dir, inode->fino_fclno, OFSVOID,
 3850:                                                         AC_RDONLY, inode);
 3851:         if (err < E_OK) goto exit0;
 3852: 
 3853:         for (;;) {
 3854:                 /* Ge next dirent */
 3855:                 err = fatNextDIR(fs, &dir, AC_RDONLY);
 3856:                 if (err < E_OK) break;
 3857: 
 3858:                 dirent = dir.di_dirent;
 3859:                 if (dirent == NULL ||         /* Last entry */
 3860:                         isDE_TERM(dirent)) { /* Terminated entry */
 3861:                         break;
 3862:                 }
 3863:                 if (isDE_FREE(dirent) ||      /* Free entry */
 3864:                         isDE_LFN(dirent) ||  /* LFN entry */
 3865:                         isDE_VOL(dirent) ) { /* VOLUME label */
 3866:                         continue;
 3867:                 }
 3868:                 /* SFN entry, ignore "." or ".." entry */
 3869:                 if (memcmp(dirent->de_fname, nmDOT, BASE_EXTLEN) != 0 &&
 3870:                     memcmp(dirent->de_fname, nmDOT2, BASE_EXTLEN) != 0) {
 3871:                         err = EX_NOTEMPTY;
 3872:                         break;                       /* Active entry */
 3873:                 }
 3874:         }
 3875: 
 3876:         /* Directory close */
 3877:         err = fatCloseDIR(fs, &dir, err);
 3878: exit0:
 3879:         return err;
 3880: }
 3881: 
 3882: /*
 3883:  *  Get file information
 3884:  */
 3885: LOCAL   ER        fatGetAttr64us(FATFS *fs, FATNODE *inode,
 3886:                                                 struct stat64_us *sb)
 3887: {
 3888:         ER     err;
 3889:         UB     ftyp;
 3890: 
 3891:         err = E_OK;
 3892:         memset(sb, 0, sizeof(struct stat64_us));
 3893: 
 3894:         /* Device ID */
 3895:         sb->st_dev = (dev_t)fs->ff_c.fs_devnum;
 3896: 
 3897:         /* File number:
 3898:                 Note: It may not be unique, because it ignores upper word */
 3899:         sb->st_ino = (ino_t)inode->fino_c.ino_ino;
 3900: 
 3901:         /* File mode */
 3902:         ftyp = inode->fino_ftype;
 3903:         sb->st_mode = DEFAULT_FILMODE;
 3904:         if (! isFAT_RDONLY(ftyp)) {
 3905:                 sb->st_mode |= FILMODE_WRITE;
 3906:         }
 3907:         sb->st_mode |= isFAT_SUBDIR(ftyp) ? S_IFDIR : S_IFREG;
 3908: 
 3909:         /* The number of links */
 3910:         sb->st_nlink = 1;
 3911: 
 3912:         /* user ID : sb->st_uid = 0 */
 3913:         /* group ID : sb->st_gid = 0 */
 3914: 
 3915:         /* File size */
 3916:         sb->st_size = inode->fino_filsz;
 3917: 
 3918:         /* File time */
 3919:         if (! IsRootINODE(fs, inode)) {
 3920:                 DIRINF dir;
 3921: 
 3922:                 err = fatOpenDIR(fs, &dir, inode->fino_dircl,
 3923:                                 (W)inode->fino_dirofs, AC_RDONLY, NULL);
 3924:                 if (err >= E_OK) {
 3925:                         if (dir.di_dirent == NULL) {
 3926:                                 err = EX_NOENT;
 3927:                         } else {
 3928:                                 fatGetDateTime(dir.di_dirent, sb);
 3929:                         }
 3930:                         /* Directory close */
 3931:                         err = fatCloseDIR(fs, &dir, err);
 3932:                 }
 3933:         }
 3934: 
 3935:         /* Device ID : sb->st_rdev = 0 */
 3936: 
 3937:         /* A file system-specific preferred I/O block size */
 3938:         sb->st_blksize = fs->ff_clsz;
 3939: 
 3940:         /* Number of blocks allocated */
 3941:         if (inode->fino_fclno > 0) {
 3942:                 W     num = 0;
 3943: 
 3944:                 if (isFAT_SUBDIR(ftyp)) {
 3945:                         err = fatGetClusterCount(fs, inode->fino_fclno,
 3946:                                                                 NULL, &num);
 3947:                 } else {
 3948:                         num = BYTEtoCL(inode->fino_filsz);
 3949:                 }
 3950:                 sb->st_blocks = (blkcnt_t)num;
 3951:         }
 3952:         return err;
 3953: }
 3954: 
 3955: /*
 3956:  *  Confirmation of the disk partition information
 3957:  */
 3958: LOCAL   ER        fatCheckPartitionID(FATFS *fs, FATFSType *fstype)
 3959: {
 3960:         DiskPartInfo   inf;
 3961:         ER             err;
 3962: 
 3963:         *fstype = 0;           /* Unknown */
 3964: 
 3965:         /* Reading of partition information */
 3966:         err = fatDiskRead(fs, DN_DISKPARTINFO, (B*)&inf, sizeof(inf));
 3967:         if (err < E_OK) {
 3968:                 if (err == E_NOSPT || err == E_PAR) err = E_OK;
 3969:         } else {
 3970:                 switch (inf.systemid) {
 3971:                 case DSID_DOS1:       /* 0x01: FAT12 */
 3972:                         //*fstype = 0;       /* judged by the number of clusters */
 3973:                         break;
 3974:                 case DSID_DOS2:       /* 0x04: FAT16 */
 3975:                         //*fstype = 0;       /* judged by the number of clusters */
 3976:                         break;
 3977:                 case DSID_DOS3:       /* 0x06: FAT16 */
 3978:                         //*fstype = 0;       /* judged by the number of clusters */
 3979:                         break;
 3980:                 case DSID_DOS3L:      /* 0x0e: FAT16 */
 3981:                         //*fstype = 0;       /* judged by the number of clusters */
 3982:                         break;
 3983:                 case DSID_WIN95:      /* 0x0b: FAT32 */
 3984:                         *fstype = FAT32;
 3985:                         break;
 3986:                 case DSID_WIN95L:     /* 0x0c: FAT32 */
 3987:                         *fstype = FAT32;
 3988:                         break;
 3989:                 default:
 3990:                         err = EX_NOTSUP;
 3991:                         break;
 3992:                 }
 3993:         }
 3994:         return err;
 3995: }
 3996: 
 3997: /*
 3998:  *  Confirmation of file system
 3999:  */
 4000: LOCAL   ER        fatCheckFileSystem(FATFS *fs)
 4001: {
 4002:         FAT_BOOTSEC    *boot;
 4003:         FAT_FSINFO     *fsi;
 4004:         FATFSType      fstype;
 4005:         UB             *blkbuf;
 4006:         UW             dsksz, secsz, rsvsc, nfat;
 4007:         UH             fsinfo;
 4008:         ER             err;
 4009: 
 4010:         /* Allocate block read buffer */
 4011:         if ((blkbuf = fimp_malloc(DSECSZ(fs))) == NULL) {
 4012:                 err = EX_NOMEM;
 4013:                 goto exit0;
 4014:         }
 4015: 
 4016:         /* Confirmation of the disk parttion information */
 4017:         err = fatCheckPartitionID(fs, &fstype);
 4018:         if (err < E_OK) goto exit1;
 4019: 
 4020:         /* Check boot sector */
 4021:         boot = (FAT_BOOTSEC *)blkbuf;
 4022:         err = fatDiskRead(fs, 0, boot, BPB_READ_SIZE);
 4023:         if (err < E_OK) goto exit1;
 4024: 
 4025:         /* Confirmation of boot sector */
 4026:         err = EX_NOTSUP;
 4027:         if (   (((UB *)boot)[BPB_TAILSIGN_OFS1] != BPB_TAILSIGN_VAL1) ||
 4028:                 (((UB *)boot)[BPB_TAILSIGN_OFS2] != BPB_TAILSIGN_VAL2)) {
 4029:                 goto exit1;
 4030:         }
 4031: 
 4032:         /* File system information */
 4033:         secsz = CEH(GetMisalignH(boot->bo_scsz));
 4034:         fs->ff_ratio = boot->bo_clsz;
 4035:         fs->ff_clsz = (UH)(secsz * fs->ff_ratio);
 4036:         rsvsc = CEH(GetMisalignH(boot->bo_rsvsc));
 4037:         nfat = boot->bo_nfat;
 4038:         fs->ff_fatsz = CEH(boot->bo_fatsz);
 4039:         if (fs->ff_fatsz == 0) {
 4040:                 fs->ff_fatsz = ((UW)CEH(boot-> bo_fatsz_hi) << BPB_SHIFT_FATSZ)
 4041:                                 | (UW)CEH(boot->bo_fatsz_lo);
 4042:         }
 4043:         dsksz = CEH(GetMisalignH(boot->bo_dsksz));
 4044:         if (dsksz == 0) {
 4045:                 dsksz = ((UW)CEH(boot->bo_dsksz_hi) << BPB_SHIFT_DSKSZ) |
 4046:                                 (UW)CEH(boot->bo_dsksz_lo);
 4047:         }
 4048: 
 4049:         if (secsz <= 0 || (W)secsz != DSECSZ(fs) ||
 4050:             fs->ff_ratio <= 0 || (W)dsksz > fs->ff_c.fs_diskinfo.blockcont) {
 4051:                 goto exit1;
 4052:         }
 4053: 
 4054:         fs->ff_rootent = CEH(GetMisalignH(boot->bo_rootent));
 4055:         fs->ff_fat = rsvsc;
 4056: 
 4057: CHK_AGAIN:
 4058:         /* FAT 32 root directory is also inside the cluster area */
 4059:         if (isFAT32(fstype)) {
 4060:                 fs->ff_rootcl = ((UW)CEH(boot->bo_root_hi) <<
 4061:                                 BPB_SHIFT_ROOT_HI) | (UW)CEH(boot->bo_root_lo);
 4062:                 if ((boot->bo_extflg & FAT_NoFATMirror) != 0) {
 4063:                         fs->ff_fat += (boot->bo_extflg & FAT_ActiveFAT) *
 4064:                                                 fs->ff_fatsz;
 4065:                         fs->ff_nfat = 1;
 4066:                 } else {
 4067:                         fs->ff_nfat = (UB)nfat;
 4068:                 }
 4069:                 fsinfo = CEH(boot->bo_fsinfo);
 4070:         }
 4071:         /* FAT12, 16 root directories are outside the cluster area */
 4072:         else {
 4073:                 fs->ff_rootcl = 0;
 4074:                 fs->ff_nfat = (UB)nfat;
 4075:                 fsinfo = 0;
 4076:         }
 4077: 
 4078:         /* Root directory and cluster area */
 4079:         if (isFAT32(fstype)) {
 4080:                 fs->ff_rootsc = 0;    /* FAT32 is meaningless */
 4081:                 fs->ff_clstart = rsvsc + (fs->ff_fatsz * nfat);
 4082:         } else {
 4083:                 fs->ff_rootsc = rsvsc + (fs->ff_fatsz * nfat);
 4084:                 fs->ff_clstart = (UW)(fs->ff_rootsc +
 4085:                                         (ROOTSZ + secsz - 1) / secsz);
 4086:         }
 4087: 
 4088:         /* Last cluster number */
 4089:         fs->ff_lastcl = ((dsksz - fs->ff_clstart) / fs->ff_ratio) + 1;
 4090: 
 4091:         /* Re-judgment of file system */
 4092:         if (fstype == 0) {
 4093:                 if (fs->ff_lastcl < FAT12_EOC) {
 4094:                         fstype = FAT12;
 4095:                 } else if (fs->ff_lastcl < FAT16_EOC) {
 4096:                         fstype = FAT16;
 4097:                 } else {
 4098:                         fstype = FAT32;
 4099:                         goto CHK_AGAIN;
 4100:                 }
 4101:         }
 4102: 
 4103:         fs->ff_fstype = fstype;
 4104:         fs->ff_fsinfo = 0;             /* Invalid */
 4105: 
 4106:         /* Check file system information (only FAT32) */
 4107:         if (fsinfo > 0) {
 4108:                 /* Map of file system information sector */
 4109:                 fsi = (FAT_FSINFO *)blkbuf;
 4110:                 err = fatDiskRead(fs, fsinfo, fsi, FSINFO_READ_SIZE);
 4111:                 if (err < E_OK) goto exit1;
 4112: 
 4113:                 /* Check signature */
 4114:                 if (  fsi->fsi_leadsig == CEW(FSINFO_LEADSIGN_VAL) &&
 4115:                         fsi->fsi_structsig == CEW(FSINFO_STRUCTSIGN_VAL) &&
 4116:                         fsi->fsi_trailsig == CEW(FSINFO_TAILSIGN_VAL)) {
 4117:                         fs->ff_fsinfo = fsinfo;              /* Active */
 4118: 
 4119:                         /* Note: Do not use the free cluster count
 4120:                                 (fsi->fsi_freecl), but update it. */
 4121: 
 4122:                         /* Use the next free cluster number */ 
 4123:                         fs->ff_nextfree = fsi->fsi_nextfree;
 4124:                 }
 4125:         }
 4126:         err = E_OK;
 4127: exit1:
 4128:         fimp_free(blkbuf);
 4129: exit0:
 4130:         return err;
 4131: }
 4132: 
 4133: /*
 4134:  *  Reset current directory to root directory
 4135:  */
 4136: LOCAL   void      fatResetCurdir(FS *fs)
 4137: {
 4138:         CDINF  *curdir;
 4139:         INODE  *rootinode;
 4140: 
 4141:         curdir = &fs->fs_uxinfo.uxi_curdir;
 4142: 
 4143:         if (! IsRootINODE(fs, curdir->cd_inode)) {
 4144:                 /* Set root as curdir */
 4145:                 (void)fatGetRootINODE((FATFS *)fs, (FATNODE **)&rootinode);
 4146:                 fatInodeRegister(fs, rootinode, O_RDONLY);
 4147:                 /* Regist curdir->cd_inode for release after current
 4148:                                 proccessing using this inode has done. */
 4149:                 fs->fs_uxinfo.uxi_relino = curdir->cd_inode;
 4150:                 curdir->cd_inode = rootinode;
 4151:         }
 4152: }
 4153: 
 4154: /*
 4155:  *  Check inode is busy or not
 4156:  */
 4157: LOCAL   BOOL      fatCheckIsInodeBusy(FS *fs, INODE *inode)
 4158: {
 4159:         if (inode->ino_refcnt <= 0) return FALSE;
 4160: 
 4161:         if (inode == fs->fs_uxinfo.uxi_curdir.cd_inode &&
 4162:                                                 inode->ino_refcnt == 1) {
 4163:                 /* Reset current directory to make inode free */
 4164:                 fatResetCurdir(fs);
 4165:                 return FALSE;
 4166:         }
 4167:         return TRUE;           /* Busy */
 4168: }
 4169: 
 4170: /*
 4171:  *  Update access date
 4172:  */
 4173: LOCAL   ER        fatUpdateAccessDate(FATFS *fs, FATNODE *inode)
 4174: {
 4175:         DIRINF dir;
 4176:         UH     date, time;
 4177:         ER     err;
 4178: 
 4179:         err = E_OK;
 4180:         if (LastAccess != FALSE && fs->ff_c.fs_rdonly == FALSE &&
 4181:                                                 ! IsRootINODE(fs, inode)) {
 4182:                 /* Get date & time */
 4183:                 err = fatSetDateTime(&date, &time, NULL);
 4184:                 if (err < E_OK) goto exit0;
 4185: 
 4186:                 /* Directpory open */
 4187:                 err = fatOpenDIR(fs, &dir, inode->fino_dircl,
 4188:                                 (W)inode->fino_dirofs, AC_WRITE, NULL);
 4189:                 if (err < E_OK) goto exit0;
 4190: 
 4191:                 /* File access date */
 4192:                 if (dir.di_dirent != NULL && dir.di_dirent->de_adate != date){
 4193:                         dir.di_dirent->de_adate = date;
 4194:                         err = fatWriteCurDIR(fs, &dir, (VW)inode);
 4195:                 }
 4196: 
 4197:                 /* Directory close */
 4198:                 err = fatCloseDIR(fs, &dir, err);
 4199:         }
 4200: exit0:
 4201:         return err;
 4202: }
 4203: 
 4204: /*----------------------------------------------------------------------------
 4205:         FATFS API functions
 4206: ----------------------------------------------------------------------------*/
 4207: 
 4208: /*
 4209:  *  Analize path name and get inode
 4210:  */
 4211: LOCAL   ER        fat_lookup(FATFS *fs, LPINF *lp, const B *r_path)
 4212: {
 4213:         CDINF  *curdir;
 4214:         FATNODE        *inode;
 4215:         DIRINF dir;
 4216:         UB     *path, *cpath, *npath;
 4217:         UW     len, dcl;
 4218:         UB     dtp;
 4219:         ER     err;
 4220: 
 4221:         err = E_OK;
 4222:         cpath = path = (UB*)&r_path[fs->ff_c.fs_conlen];
 4223: 
 4224:         /* Check root directory */
 4225:         if (path[0] == '\0') {         /* Root directory */
 4226:                 (void)fatGetRootINODE(fs, &inode);
 4227:                 goto exit1;
 4228:         }
 4229: 
 4230:         /* Check current directory */
 4231:         curdir = &fs->ff_c.fs_uxinfo.uxi_curdir;
 4232:         len = strlen((B*)curdir->cd_inode->ino_path);
 4233: 
 4234:         if (fat_strncasecmp(curdir->cd_inode->ino_path, path, len) == 0
 4235:                         && (path[len] == '\0' || path[len] == '/')) {
 4236:                 /* Under current directory */
 4237:                 if (path[len] == '\0') {
 4238:                         /* Current directory */
 4239:                         if ((cpath = (UB*)strrchr((B*)path, '/')) != NULL) cpath++;
 4240:                         else cpath = path;
 4241:                         inode = (FATNODE*)curdir->cd_inode;
 4242:                         goto exit1;
 4243:                 }
 4244:                 /* Search from current directory */
 4245:                 dcl = dirCLNO(fs, curdir->cd_inode->ino_ino);
 4246:                 cpath += len + 1;
 4247:         } else {
 4248:                 /* Search from top */
 4249:                 dcl = fs->ff_rootcl;
 4250:                 cpath += 1;
 4251:         }
 4252: 
 4253:         /* Search parent directory */
 4254:         dtp = FAT_SUBDIR;
 4255:         dir.di_dirent = NULL;
 4256:         for ( ; (npath = (UB*)strchr((B*)cpath, '/')) != NULL; cpath = npath + 1) {
 4257: 
 4258:                 /* Open directory */
 4259:                 err = fatOpenDIR(fs, &dir, dcl, OFSVOID, AC_RDONLY, NULL);
 4260:                 if (err < E_OK) break;
 4261: 
 4262:                 /* Search name */
 4263:                 err = fatSearchDIR_nm(fs, &dir, cpath,
 4264:                                         npath - cpath, AC_RDONLY, NULL);
 4265:                 if (err >= E_OK) {
 4266:                         if (isFAT_SUBDIR(dir.di_dirent->de_ftype)) {
 4267:                                 /* Parent directory */
 4268:                                 dcl = dirent_to_fcl(fs, dir.di_dirent);
 4269:                                 dtp = dir.di_dirent->de_ftype;
 4270:                         } else {
 4271:                                 dir.di_dirent = NULL;
 4272:                                 err = EX_NOTDIR;
 4273:                         }
 4274:                 }
 4275:                 /* Close directory */
 4276:                 err = fatCloseDIR(fs, &dir, err);
 4277: 
 4278:                 CHK_BREAK_AND_SET_ERR(fs, &err);
 4279:                 if (err < E_OK) break;
 4280:         }
 4281:         if (err < E_OK) goto exit0;
 4282: 
 4283:         if (dir.di_dirent != NULL) {
 4284:                 err = fatGetINODE(fs, &dir, dtp, path, cpath - path -1, &inode);
 4285:                 if (err >= E_OK && curdir->cd_inode != (INODE*)inode) {
 4286:                         /* Set parent directory as a current directory */
 4287:                         fatInodeRegister((FS*)fs, (INODE*)inode, O_RDONLY);
 4288:                         fatInodeRelease((FS*)fs, curdir->cd_inode, O_RDONLY);
 4289:                         curdir->cd_inode = (INODE*)inode;
 4290:                 }
 4291:                 CHK_BREAK_AND_SET_ERR(fs, &err);
 4292:         }
 4293:         if (err < E_OK) goto exit0;
 4294: 
 4295:         /* Open parent directory */
 4296:         err = fatOpenDIR(fs, &dir, dcl, OFSVOID, AC_RDONLY, NULL);
 4297:         if (err < E_OK) goto exit0;
 4298: 
 4299:         /* Search file */
 4300:         inode = NULL;
 4301:         err = fatSearchDIR_nm(fs, &dir, cpath, strlen((B*)cpath), AC_RDONLY, NULL);
 4302:         if (err >= E_OK || err == EX_NOENT) {
 4303:                 err = fatGetINODE(fs, &dir, dtp, path, strlen((B*)path), &inode);
 4304:         }
 4305: 
 4306:         /* Close parent directory */
 4307:         err = fatCloseDIR(fs, &dir, err);
 4308:         if (err < E_OK) {
 4309:                 /* Free memory that is allocated by fatGetINODE() */
 4310:                 if (inode != NULL && inode->fino_c.ino_refcnt == 0) {
 4311:                         fatInodeFree((FS*)fs, (INODE*)inode);
 4312:                 }
 4313:         } else {
 4314: exit1:          /* Set result */
 4315:                 lp->lp_inode = (INODE*)inode;
 4316:                 lp->lp_path = cpath;
 4317:         }
 4318:         CHK_BREAK_AND_SET_ERR(fs, &err);
 4319: exit0:
 4320:         return err;
 4321: }
 4322: 
 4323: /*
 4324:  *  Truncate or extend size of file specified by path name
 4325:  */
 4326: LOCAL   ER        fat_truncate64(FATFS *fs, FATNODE *inode, D size)
 4327: {
 4328:         ER     err;
 4329: 
 4330:         if (isFAT_RDONLY(inode->fino_ftype)) {
 4331:                 err = EX_ACCES;
 4332:         } else if (size > FILE_SIZE_MAX) {
 4333:                 err = EX_FBIG;
 4334:         } else if (size < 0) {
 4335:                 err = EX_INVAL;
 4336:         } else if (size > inode->fino_filsz) {
 4337:                 err = fatExtendFile(fs, inode, size);
 4338:         } else {
 4339:                 err = fatTruncateFile(fs, inode, size);
 4340:         }
 4341:         return err;
 4342: }
 4343: 
 4344: /*
 4345:  *  Truncate or extend size of file specified by descriptor
 4346:  */
 4347: LOCAL   ER        fat_ftruncate64(FD *fd, D size)
 4348: {
 4349:         return fat_truncate64((FATFS*)fd->fd_fs, (FATNODE*)fd->fd_inode, size);
 4350: }
 4351: 
 4352: /*
 4353:  *  Change access and modification time of file specified by path name
 4354:  */
 4355: LOCAL   ER        fat_utimes_us(FATFS *fs, FATNODE *inode,
 4356:                                                 const SYSTIM_U times_u[2])
 4357: {
 4358:         DIRINF dir;
 4359:         UH     date[2], time[2];
 4360:         ER     err;
 4361: 
 4362:         err = E_OK;
 4363: 
 4364:         if (IsRootINODE(fs, inode)) goto exit0;
 4365: 
 4366:         /* Set date & time */
 4367:         err = fatSetDateTime(&date[0], &time[0], &times_u[0]);
 4368:         if (err >= E_OK) {
 4369:                 err = fatSetDateTime(&date[1], &time[1], &times_u[1]);
 4370:         }
 4371:         if (err < E_OK) goto exit0;
 4372: 
 4373:         /* Open directory */
 4374:         err = fatOpenDIR(fs, &dir, inode->fino_dircl,
 4375:                                 (W)inode->fino_dirofs, AC_WRITE, NULL);
 4376:         if (err >= E_OK) {
 4377:                 if (dir.di_dirent == NULL) {
 4378:                         err = EX_NOENT;
 4379:                 } else {
 4380:                         /* Set times */
 4381:                         dir.di_dirent->de_adate = date[0];
 4382:                         dir.di_dirent->de_mdate = date[1];
 4383:                         dir.di_dirent->de_mtime = time[1];
 4384:                         err = fatWriteCurDIR(fs, &dir, (VW)inode);
 4385:                 }
 4386:                 /* Directory close */
 4387:                 err = fatCloseDIR(fs, &dir, err);
 4388:         }
 4389: exit0:
 4390:         return err;
 4391: }
 4392: 
 4393: /*
 4394:  *  Change mode of file specified by path name
 4395:  */
 4396: LOCAL   ER        fat_chmod(FATFS *fs, FATNODE *inode, mode_t mode)
 4397: {
 4398:         DIRINF dir;
 4399:         ER     err;
 4400: 
 4401:         if (IsRootINODE(fs, inode)) {
 4402:                 err = isSET(mode, FILMODE_WRITE) ? E_OK : EX_INVAL;
 4403:         } else {
 4404:                 /* Open directory */
 4405:                 err = fatOpenDIR(fs, &dir, inode->fino_dircl,
 4406:                                 (W)inode->fino_dirofs, AC_WRITE, NULL);
 4407:                 if (err >= E_OK) {
 4408:                         if (dir.di_dirent == NULL) {
 4409:                                 err = EX_NOENT;
 4410:                         } else {
 4411:                                 /* Change file mode */
 4412:                                 if (isSET(mode, FILMODE_WRITE)) {
 4413:                                         dir.di_dirent->de_ftype &= ~FAT_RDONLY;
 4414:                                 } else {
 4415:                                         dir.di_dirent->de_ftype |= FAT_RDONLY;
 4416:                                 }
 4417:                                 err = fatWriteCurDIR(fs, &dir, (VW) inode);
 4418:                                 inode->fino_ftype = dir.di_dirent->de_ftype;
 4419:                         }
 4420:                         /* Close directory */
 4421:                         err = fatCloseDIR(fs, &dir, err);
 4422:                 }
 4423:         }
 4424:         return err;
 4425: }
 4426: 
 4427: /*
 4428:  *  Change mode of file specified by descriptor
 4429:  */
 4430: LOCAL   ER        fat_fchmod(FD *fd, mode_t mode)
 4431: {
 4432:         return fat_chmod((FATFS*)fd->fd_fs, (FATNODE*)fd->fd_inode, mode);
 4433: }
 4434: 
 4435: /*
 4436:  *  Rename file name
 4437:  */
 4438: LOCAL   ER        fat_rename(FATFS *fs, FATNODE *from,
 4439:                                                 FATNODE *to, const UB *fname)
 4440: {
 4441:         DIRINF         dir;
 4442:         FAT_DIRENT     de;
 4443:         UW             dircl, dirofs;
 4444:         ER             err;
 4445: 
 4446:         /* Check readonly */
 4447:         if (from->fino_d_ronly || to->fino_d_ronly) {
 4448:                 err = EX_ACCES;
 4449:                 goto exit0;
 4450:         }
 4451: 
 4452:         /* Check directory "to" is not the subdirectory of "from" */
 4453:         err = fatCheckSubDirectory(fs, from, to);
 4454:         if (err < E_OK) goto exit0;
 4455: 
 4456:         /* Check rename of directory */
 4457:         if (isFAT_SUBDIR(from->fino_ftype) && isFAT_RDONLY(from->fino_ftype)
 4458:                                 && to->fino_dircl != from->fino_dircl) {
 4459:                 err = EX_ACCES;
 4460:                 goto exit0;
 4461:         }
 4462: 
 4463:         /* Open "from" directory */
 4464:         err = fatOpenDIR(fs, &dir, from->fino_dircl,
 4465:                                 (W)from->fino_dirofs, AC_RDONLY, NULL);
 4466:         if (err >= E_OK) {
 4467:                 /* Save "from" entry save */
 4468:                 memcpy(&de, dir.di_dirent, DIRENTSZ);
 4469: 
 4470:                 /* Close "from" directory */
 4471:                 err = fatCloseDIR(fs, &dir, E_OK);
 4472:         }
 4473:         if (err < E_OK) goto exit0;
 4474: 
 4475:         if (to->fino_c.ino_ino != NOEXS_INO) { /* "to" exists */
 4476: 
 4477:                 if (isFAT_SUBDIR(to->fino_ftype)) {
 4478:                         /* Rename directory, check "to" is empty */
 4479:                         err = fatChkEmptyDirectory(fs, to);
 4480:                         if (err == EX_NOTEMPTY) err = EX_EXIST;
 4481:                 }
 4482:                 if (err < E_OK) goto exit0;
 4483: 
 4484:                 /* Open "to" directory */
 4485:                 err = fatOpenDIR(fs, &dir, to->fino_dircl,
 4486:                                         (W)to->fino_dirofs, AC_WRITE, NULL);
 4487:                 if (err < E_OK) goto exit0;
 4488: 
 4489:                 if (dir.di_dirent == NULL) {
 4490:                         err = EX_NOENT;
 4491:                 } else {
 4492:                         /* Copy directory entry except name */
 4493:                         dir.di_dirent->de_ftype = de.de_ftype | FAT_ARCHIV;
 4494:                         dir.di_dirent->de_ctime = de.de_ctime;
 4495:                         dir.di_dirent->de_cdate = de.de_cdate;
 4496:                         dir.di_dirent->de_adate = de.de_adate;
 4497:                         dir.di_dirent->de_clno_hi = de.de_clno_hi;
 4498:                         dir.di_dirent->de_mtime = de.de_mtime;
 4499:                         dir.di_dirent->de_mdate = de.de_mdate;
 4500:                         dir.di_dirent->de_clno_lo = de.de_clno_lo;
 4501:                         dir.di_dirent->de_fsize = de.de_fsize;
 4502: 
 4503:                         err = fatWriteCurDIR(fs, &dir, (VW)to);
 4504:                 }
 4505:                 /* Close "to" directory */
 4506:                 err = fatCloseDIR(fs, &dir, err);
 4507:                 if (err < E_OK) goto exit0;
 4508: 
 4509:                 /* Delete original "to" file and "from" directory entry */
 4510:                 dircl = to->fino_dircl;
 4511:                 dirofs = to->fino_dirofs;
 4512:                 to->fino_dircl = from->fino_dircl;
 4513:                 to->fino_dirofs = from->fino_dirofs;
 4514: 
 4515:                 err = fatRemoveFile(fs, to);
 4516:                 if (err < E_OK) goto exit0;
 4517: 
 4518:                 /* Update "from" directory */
 4519:                 err = fatUpdateDirectory(fs, to);
 4520:                 if (err < E_OK) goto exit0;
 4521: 
 4522:                 /* Transfer file reference node */
 4523:                 if (! isFAT_SUBDIR(to->fino_ftype)) {
 4524:                         from->fino_c.ino_ino = to->fino_c.ino_ino;
 4525:                 }
 4526:                 from->fino_dircl = dircl;
 4527:                 from->fino_dirofs = dirofs;
 4528: 
 4529:         } else {       /* "to" does not exist */
 4530:                 dircl = from->fino_dircl;
 4531:                 dirofs = from->fino_dirofs;
 4532:                 from->fino_dircl = to->fino_dircl;
 4533: 
 4534:                 /* Create new file in "to" directory */
 4535:                 err = fatCreateFile(fs, from, (UB*)fname, &de);
 4536:                 if (err < E_OK) goto exit0;
 4537: 
 4538:                 /* Delete original "from" file */
 4539:                 to->fino_dircl = dircl;
 4540:                 to->fino_dirofs = dirofs;
 4541: 
 4542:                 err = fatRemoveFile(fs, to);
 4543:                 if (err < E_OK) goto exit0;
 4544: 
 4545:                 /* Update "to" directory */
 4546:                 err = fatUpdateDirectory(fs, from);
 4547:                 if (err < E_OK) goto exit0;
 4548: 
 4549:                 /* Update "from" directory */
 4550:                 if (from->fino_dircl != to->fino_dircl) {
 4551:                         err = fatUpdateDirectory(fs, to);
 4552:                 }
 4553:         }
 4554:         if (err >= E_OK) {
 4555:                 /* Change inode queue entry */
 4556:                 fatInodeChangeQue((FS *)fs, (INODE *)from);
 4557:         }
 4558: exit0:
 4559:         return err;
 4560: }
 4561: 
 4562: /*
 4563:  *  Delete directory entry and file itself
 4564:  */
 4565: LOCAL   ER        fat_unlink(FATFS *fs, FATNODE *inode)
 4566: {
 4567:         ER     err;
 4568: 
 4569:         if (inode->fino_d_ronly != FALSE) {
 4570:                 err = EX_ACCES;
 4571:         } else {
 4572:                 /* Delete file */
 4573:                 err = fatRemoveFile(fs, inode);
 4574:                 if (err >= E_OK) {
 4575:                         err = fatUpdateDirectory(fs, inode);
 4576:                 }
 4577:         }
 4578:         return err;
 4579: }
 4580: 
 4581: /*
 4582:  *  Create directory
 4583:  */
 4584: LOCAL   ER        fat_mkdir(FATFS *fs, FATNODE *inode,
 4585:                                                 const UB *fname, mode_t mode)
 4586: {
 4587:         ER     err;
 4588: 
 4589:         if (inode->fino_d_ronly != FALSE) {
 4590:                 err = EX_ACCES;
 4591:         } else {
 4592:                 /* Set file type */
 4593:                 inode->fino_ftype = FAT_SUBDIR;
 4594:                 if (! isSET(mode, FILMODE_WRITE)) {
 4595:                         inode->fino_ftype |= FAT_RDONLY;
 4596:                 }
 4597: 
 4598:                 /* Create new directory */
 4599:                 err = fatCreateFile(fs, inode, (UB*)fname, NULL);
 4600:                 if (err >= E_OK) {
 4601:                         err = fatUpdateDirectory(fs, inode);
 4602:                 }
 4603:         }
 4604:         return err;
 4605: }
 4606: 
 4607: /*
 4608:  *  Delete directory
 4609:  */
 4610: LOCAL   ER        fat_rmdir(FATFS *fs, CDINF *curdir, FATNODE *inode)
 4611: {
 4612:         ER     err;
 4613: 
 4614:         if (inode->fino_d_ronly != FALSE) {
 4615:                 err = EX_ACCES;
 4616:                 goto exit0;
 4617:         }
 4618: 
 4619:         if (inode == (FATNODE*)curdir->cd_inode) {
 4620:                 /* Reset current directory */
 4621:                 fatResetCurdir((FS*)fs);
 4622:         }
 4623: 
 4624:         /* Check directory is empty */
 4625:         err = fatChkEmptyDirectory(fs, inode);
 4626:         if (err >= E_OK) {
 4627:                 err = fatRemoveFile(fs, inode);
 4628:                 if (err >= E_OK) {
 4629:                         err = fatUpdateDirectory(fs, inode);
 4630:                 }
 4631:         }
 4632: exit0:
 4633:         return err;
 4634: }
 4635: 
 4636: /*
 4637:  *  Get file status - stat64_us
 4638:  */
 4639: LOCAL   ER        fat_stat64_us(FATFS *fs, FATNODE *inode, struct stat64_us *sb)
 4640: {
 4641:         return fatGetAttr64us(fs, inode, sb);
 4642: }
 4643: 
 4644: /*
 4645:  *  Get file status - fstat64_us
 4646:  */
 4647: LOCAL   ER        fat_fstat64_us(FD *fd, struct stat64_us *sb)
 4648: {
 4649:         return fatGetAttr64us((FATFS*)fd->fd_fs, (FATNODE*)fd->fd_inode, sb);
 4650: }
 4651: 
 4652: /*
 4653:  *  Read file data
 4654:  */
 4655: LOCAL   ER        fat_read64(FD *fd, UB *buf, UW len, UW *alen, D *aoffset)
 4656: {
 4657:         FATFS  *fs;
 4658:         FATNODE        *inode;
 4659:         CLAD   clad[MAX_CLEN];
 4660:         D      offset;
 4661:         UW     actual, ofs, sz;
 4662:         W      cllen, i;
 4663:         MapInfo        map;
 4664:         ER     err;
 4665: 
 4666:         fs = (FATFS *)fd->fd_fs;
 4667:         inode = (FATNODE *)fd->fd_inode;
 4668:         offset = fd->fd_fpos;
 4669:         err = E_OK;
 4670: 
 4671:         *alen = 0;
 4672:         *aoffset = offset;
 4673: 
 4674:         /* Check read offset */
 4675:         if (offset >= inode->fino_filsz) {
 4676:                 if (offset > inode->fino_filsz) {
 4677:                         err = EX_OVERFLOW;
 4678:                 }
 4679:                 goto exit0;
 4680:         }
 4681: 
 4682:         /* Check read size */
 4683:         if (offset + len > inode->fino_filsz) {
 4684:                 len = inode->fino_filsz - offset;
 4685:         }
 4686: 
 4687:         /* Read offset within 1st cluster */
 4688:         ofs = offset % fs->ff_clsz;
 4689: 
 4690:         for (actual = 0; len > 0; actual += sz, len -= sz, ofs = 0) {
 4691: 
 4692:                 /* Get next cluster list */
 4693:                 err = fatCopyClusterList(fs, clad, offset + actual,
 4694:                                                         len, inode, &cllen);
 4695:                 if (err < E_OK) break;
 4696: 
 4697:                 /* Map area size */
 4698:                 for (sz = 0, i = 0; i < cllen; i++) {
 4699:                         sz += clad[i].ca_len;
 4700:                 }
 4701:                 sz *= fs->ff_clsz;
 4702: 
 4703:                 /* Read size */
 4704:                 if ((sz -= ofs) > len) sz = len;
 4705: 
 4706:                 /* Map data area */
 4707:                 err = fatMapDisk(fs, clad, cllen, &map, MAP_C, (VW)inode);
 4708:                 if (err < E_OK) break;
 4709: 
 4710:                 /* Read data */
 4711:                 err = fatMapReadBytes(&map, ofs, &buf[actual], sz);
 4712: 
 4713:                 (void)fatMapEnd(&map);
 4714:                 fatUnmapDisk(&map);
 4715:                 if (err < E_OK) break;
 4716:         }
 4717:         if (err == EX_INTR && actual > 0) err = E_OK;
 4718: 
 4719:         /* Update access date */
 4720:         if (err >= E_OK) {
 4721:                 err = fatUpdateAccessDate(fs, inode);
 4722:         }
 4723: 
 4724:         if (err >= E_OK) {
 4725:                 *aoffset = (fd->fd_fpos += actual);
 4726:                 *alen = actual;
 4727:         }
 4728: exit0:
 4729:         return err;
 4730: }
 4731: 
 4732: /*
 4733:  *  Write file data
 4734:  */
 4735: LOCAL   ER        fat_write64(FD *fd, const UB *buf, UW len,
 4736:                                                 UW *alen, D *aoffset)
 4737: {
 4738:         FATFS  *fs;
 4739:         FATNODE        *inode;
 4740:         CLAD   clad[MAX_CLEN];
 4741:         D      offset;
 4742:         UW     actual, gapsz, ofs, sz, gsz, dsz;
 4743:         W      i, cllen;
 4744:         MapInfo        map;
 4745:         ER     err;
 4746: 
 4747:         fs = (FATFS *)fd->fd_fs;
 4748:         inode = (FATNODE *)fd->fd_inode;
 4749:         err = E_OK;
 4750: 
 4751:         /* If O_APPEND, force offset to end of file */
 4752:         if ((fd->fd_omode & O_APPEND) != 0) {
 4753:                 fd->fd_fpos = inode->fino_filsz;
 4754:         }
 4755:         offset = fd->fd_fpos;
 4756: 
 4757:         *alen = 0;
 4758:         *aoffset = offset;
 4759: 
 4760:         if (len <= 0) goto exit0;
 4761: 
 4762:         /* Check gap area */
 4763:         gapsz = 0;
 4764:         if (offset > inode->fino_filsz) {
 4765:                 gapsz = offset - inode->fino_filsz;
 4766:                 offset -= gapsz;
 4767:         }
 4768: 
 4769:         /* Check writing size */
 4770:         len += gapsz;
 4771:         if (offset + len > FILE_SIZE_MAX) {
 4772:                 err = EX_FBIG;
 4773:                 goto exit0;
 4774:         }
 4775: 
 4776:         /* Write offset within 1st cluster */
 4777:         ofs = offset % fs->ff_clsz;
 4778: 
 4779:         for (actual = 0; len > 0; len -= sz, offset += sz, gapsz -= gsz,
 4780:                                                 actual += dsz, ofs = 0) {
 4781: 
 4782:                 /* Get next cluster list */
 4783:                 err = fatCopyClusterList(fs, clad, offset, len, inode, &cllen);
 4784:                 if (err >= E_OK && cllen == 0) {
 4785:                         /* Append new cluster */
 4786:                         err = fatApdNewCluster(fs, &clad[0], (W)len, inode);
 4787:                         if (err >= E_OK) cllen = 1;
 4788:                 }
 4789:                 if (err < E_OK) break;
 4790: 
 4791:                 /* Map area size */
 4792:                 for (sz = i = 0; i < cllen; i++) {
 4793:                         sz += clad[i].ca_len;
 4794:                 }
 4795:                 sz *= fs->ff_clsz;
 4796: 
 4797:                 /* Write total size : gap + data */
 4798:                 if ((sz -= ofs) > len) sz = len;
 4799: 
 4800:                 /* Write gap size */
 4801:                 if ((gsz = gapsz) > sz) gsz = sz;
 4802: 
 4803:                 /* Write data size */
 4804:                 dsz = sz - gsz;
 4805: 
 4806:                 /* Map data area */
 4807:                 err = fatMapDisk(fs, clad, cllen, &map, MAP_C, (VW)inode);
 4808:                 if (err < E_OK) break;
 4809: 
 4810:                 /* Write gap - zero clear */
 4811:                 if (gsz > 0) {
 4812:                         err = fatMapWriteBytes(&map, ofs, NULL, gsz);
 4813:                 }
 4814: 
 4815:                 /* Write data */
 4816:                 if (err >= E_OK && dsz > 0) {
 4817:                         err = fatMapWriteBytes(&map, ofs + gsz,
 4818:                                                         &buf[actual], dsz);
 4819:                 }
 4820:                 (void)fatMapEnd(&map);
 4821:                 fatUnmapDisk(&map);
 4822:                 if (err < E_OK) break;
 4823:         }
 4824: 
 4825:         if (err == EX_INTR && actual > 0) err = E_OK;
 4826: 
 4827:         /* Update file size */
 4828:         if (inode->fino_filsz < fd->fd_fpos + actual) {
 4829:                 inode->fino_filsz = fd->fd_fpos + actual;
 4830:         }
 4831: 
 4832:         /* Update */
 4833:         err = fatUpdateFile(fs, inode);
 4834:         if (err >= E_OK) {
 4835:                 *aoffset = (fd->fd_fpos += actual);
 4836:                 *alen = actual;
 4837:         }
 4838: exit0:
 4839:         return err;
 4840: }
 4841: 
 4842: /*
 4843:  *  Set a direcory entry to buffer
 4844:  */
 4845: LOCAL   ER        set_dirent(FATFS *fs, UD ino, void *nm,
 4846:                                 struct dirent *ent, W *alen, W bflen)
 4847: {
 4848:         W      nmlen, nmsz;
 4849:         struct dirent  *e;
 4850: 
 4851:         /* Check buffer length */
 4852:         bflen -= *alen;
 4853:         nmsz  = bflen - offsetof(struct dirent, d_name) - 1;
 4854:         if (nmsz <= 0) goto nospace;                   /* No space */
 4855:         if (nmsz > NAME_MAX) nmsz = NAME_MAX;
 4856: 
 4857:         /* Get actual name length */
 4858:         e = (struct dirent *)((UB*)ent + *alen);
 4859:         if (ino <= CLSTART) {  /* Special for root "." and ".." */
 4860:                 nmlen = strlen((B*)nm);
 4861:                 if (nmlen <= nmsz) strcpy(e->d_name, (B*)nm);
 4862:         } else {
 4863:                 nmlen = fatEncUtf16strToUtf8str((UH*)nm,
 4864:                                 fat_strlen16((UH*)nm), (UB*)e->d_name, nmsz + 1);
 4865:         }
 4866:         if (bflen < RECLEN_DIRENT(nmlen)) goto nospace;        /* No space */
 4867: 
 4868:         /* Set entry:
 4869:                 Note: d_ino may not be unique, because it ignores upper word */
 4870:         e->d_ino = (ino_t)ino;
 4871:         e->d_reclen = RECLEN_DIRENT(nmlen);
 4872:         *alen += e->d_reclen;
 4873:         return E_OK + 1;
 4874: nospace:
 4875:         return (nmsz == NAME_MAX) ? EX_NAMETOOLONG :
 4876:                                 ((*alen == 0) ? EX_INVAL : E_OK);
 4877: }
 4878: 
 4879: /*
 4880:  *  Get direcory entries
 4881:  */
 4882: LOCAL   ER        fat_getdents(FD *fd, struct dirent *ent, W *len, W *retofs)
 4883: {
 4884:         FATFS          *fs;
 4885:         FATNODE                *inode;
 4886:         DIRINF         dir;
 4887:         FAT_DIRENT     *dirent;
 4888:         W              ofs, ofsbias, ldenum, cks, bflen, alen;
 4889:         ER             err;
 4890: 
 4891: /*
 4892:  *  Special specification : Get only one entry when buffer size is just
 4893:  *    same as the sizeof(struct dirent).
 4894:  */
 4895: #define GetOnlyOneEnt   (bflen == sizeof(struct dirent))
 4896: 
 4897:         fs = (FATFS *)fd->fd_fs;
 4898:         inode = (FATNODE *)fd->fd_inode;
 4899:         ofs = (W)fd->fd_fpos;
 4900: 
 4901:         bflen = *len;
 4902:         *len = alen = 0;
 4903:         ofsbias = 0;
 4904:         err = E_OK;
 4905: 
 4906:         /* Check offset */
 4907:         if ((ofs % DIRENTSZ) != 0) {
 4908:                 err = EX_NOENT;
 4909:                 goto exit0;
 4910:         }
 4911: 
 4912:         /* Special handling for "." and ".." of root directory */
 4913:         if (IsRootINODE(fs, inode)) {
 4914:                 /* Root of "." directory */
 4915:                 if (ofs == 0) {
 4916:                         err = set_dirent(fs, CLSTART, ".", ent, &alen, bflen);
 4917:                         if (err <= E_OK) goto exit1;
 4918:                         ofs = DIRENTSZ;
 4919:                         if (GetOnlyOneEnt) goto exit1;
 4920:                 }
 4921:                 /* Root of ".." entry  */
 4922:                 if (ofs == DIRENTSZ) {
 4923:                         err = set_dirent(fs, 0, "..", ent, &alen, bflen);
 4924:                         if (err <= 0) goto exit1;
 4925:                         ofs = DIRENTSZ * 2;
 4926:                         if (GetOnlyOneEnt) goto exit1;
 4927:                 }
 4928:                 ofs -= (ofsbias = DIRENTSZ * 2);
 4929:         }
 4930: 
 4931:         /* Open directory */
 4932:         err = fatOpenDIR(fs, &dir, inode->fino_fclno, ofs, AC_RDONLY, inode);
 4933:         if (err < E_OK) goto exit0;
 4934: 
 4935:         /* Get directory entries */
 4936:         for (ldenum = 0, cks = CKSVOID; err >= E_OK;
 4937:                                 err = fatNextDIR(fs, &dir, AC_RDONLY) ) {
 4938:                 /* Check directory entry */
 4939:                 dirent = dir.di_dirent;
 4940:                 if (dirent == NULL ||         /* Last entry */
 4941:                         isDE_TERM(dirent)) { /* Terminated entry */
 4942:                         break;
 4943:                 }
 4944:                 if (isDE_FREE(dirent)) {      /* Free entry */
 4945:                         ;
 4946:                 } else if (isDE_LFN(dirent)) {        /* LFN entry */
 4947:                         if (fatGetLFN((FAT_DIRENT_LFN *)dirent,
 4948:                                 &ldenum, &cks, fs->ff_nmbf) >= 0) continue;
 4949: 
 4950:                 } else if (isDE_VOL(dirent)) {        /* Volume label */
 4951:                         ;
 4952:                 } else if (cks == fatCalcChksum(dirent->de_fname) ||
 4953:                                                         cks == CKSVOID ) {
 4954:                         /* SFN entry, check checksum  */
 4955:                         if (cks == CKSVOID) {
 4956:                                 /* Get SFN */
 4957:                                 (void)fatGetSFN(dirent->de_fname,
 4958:                                         dirent->de_smallcaps, fs->ff_nmbf);
 4959:                         }
 4960:                         /* Set entry */
 4961:                         err = set_dirent(fs, fatGetInoDIR(fs, &dir),
 4962:                                         fs->ff_nmbf, ent, &alen, bflen);
 4963:                         if (err <= E_OK) break;
 4964: 
 4965:                         ofs = dir.di_offset + DIRENTSZ;
 4966:                         if (GetOnlyOneEnt) break;
 4967:                 }
 4968:                 cks = CKSVOID;
 4969:                 ldenum = 0;
 4970:         }
 4971: 
 4972:         /* Close directory */
 4973:         err = fatCloseDIR(fs, &dir, err);
 4974:         if (err >= E_OK) {
 4975:                 /* Update access date */
 4976:                 err = fatUpdateAccessDate(fs, inode);
 4977:         }
 4978: exit1:
 4979:         if (err >= E_OK) {
 4980:                 *retofs = fd->fd_fpos = ofs + ofsbias;
 4981:                 *len = alen;
 4982:         }
 4983: exit0:
 4984:         return err;
 4985: }
 4986: 
 4987: /*
 4988:  *  Open file/directory
 4989:  */
 4990: LOCAL   ER        fat_open(FD *fd, const UB *fname, W oflag, mode_t mode)
 4991: {
 4992:         FATFS  *fs;
 4993:         FATNODE        *inode;
 4994:         ER     err;
 4995: 
 4996:         fs = (FATFS *)fd->fd_fs;
 4997:         inode = (FATNODE *)fd->fd_inode;
 4998:         err = E_OK;
 4999: 
 5000:         fd->fd_omode = (UB)oflag;                      /* Open mode */
 5001: 
 5002:         if (inode->fino_c.ino_ino == NOEXS_INO) {      /* Create open */
 5003: 
 5004:                 /* Check writable */
 5005:                 if (inode->fino_d_ronly != FALSE) {
 5006:                         err = EX_ACCES;
 5007:                         goto exit0;
 5008:                 }
 5009:                 /* File type */
 5010:                 if (! isSET(mode, FILMODE_WRITE)) {
 5011:                         inode->fino_ftype = FAT_RDONLY;
 5012:                 }
 5013:                 /* Create a file */
 5014:                 err = fatCreateFile(fs, inode, (UB*)fname, NULL);
 5015:                 if (err < E_OK) goto exit0;
 5016: 
 5017:                 err = fatUpdateDirectory(fs, inode);
 5018: 
 5019:         } else {       /* Normal open */
 5020:                 /* Check writable */
 5021:                 if (isFAT_RDONLY(inode->fino_ftype) &&
 5022:                                         isNOT_RDONLY(fd->fd_omode)) {
 5023:                         err = EX_ACCES;
 5024:                         goto exit0;
 5025:                 }
 5026: 
 5027:                 /* If O_TRUNC, delete file data */
 5028:                 if (isSET(oflag, O_TRUNC) &&
 5029:                                         ! isFAT_SUBDIR(inode->fino_ftype)) {
 5030:                         /* Check writable */
 5031:                         if (isFAT_RDONLY(inode->fino_ftype)) {
 5032:                                 err = EX_ACCES;
 5033:                                 goto exit0;
 5034:                         }
 5035:                         /* Check open mode */
 5036:                         if (isNOT_RDONLY(fd->fd_omode)) {
 5037:                                 /* Delete file data */
 5038:                                 err = fatTruncateFile(fs, inode, 0);
 5039:                         }
 5040:                 }
 5041:         }
 5042:         if (err >= E_OK) {
 5043:                 /* Make cluster list of inode */
 5044:                 err = fatMakeClusterList(fs, inode);
 5045:         }
 5046: exit0:
 5047:         return err;
 5048: }
 5049: 
 5050: /*
 5051:  *  Close file/directory
 5052:  */
 5053: LOCAL   ER        fat_close(FD *fd)
 5054: {
 5055:         /* do nothing */
 5056:         (void)fd;
 5057:         return E_OK;
 5058: }
 5059: 
 5060: /*
 5061:  *  Get file sysatem status - statvfs
 5062:  */
 5063: LOCAL   ER        fat_statvfs(FATFS *fs, struct statvfs *buf)
 5064: {
 5065:         buf->f_bsize = DSECSZ(fs);
 5066:         buf->f_frsize = fs->ff_clsz;
 5067:         buf->f_blocks = fs->ff_lastcl;
 5068:         buf->f_bfree = fs->ff_freecl;
 5069:         buf->f_bavail = buf->f_bfree;
 5070:         buf->f_files = 0;              /* Not support */
 5071:         buf->f_ffree = 0;              /* Not support */
 5072:         buf->f_favail = buf->f_ffree;
 5073:         buf->f_fsid = 0;               /* Not support */
 5074:         buf->f_flag = ST_NOSUID;
 5075:         if (fs->ff_c.fs_rdonly != FALSE) {
 5076:                 buf->f_flag |= ST_RDONLY;
 5077:         }
 5078:         if (fs->ff_c.fs_diskinfo.removable != 0) {
 5079:                 buf->f_flag |= ST_REMOVABLE;
 5080:         }
 5081:         buf->f_namemax = LFN_MAXLEN;
 5082:         return E_OK;
 5083: }
 5084: 
 5085: /*
 5086:  *  ioctl function
 5087:  */
 5088: LOCAL   ER        fat_ioctl(FD *fd, UW dcmd, void *data)
 5089: {
 5090:         /* No I/O control function supported  */
 5091: 
 5092:         (void)fd;
 5093:         (void)dcmd;
 5094:         (void)data;
 5095:         return EX_NOTSUP;
 5096: }
 5097: 
 5098: /*
 5099:  *  Change current diretory
 5100:  */
 5101: LOCAL   ER        fat_fchdir(FD *fd, UB *utf8nm, W utf8len)
 5102: {
 5103:         FATFS  *fs;
 5104: #ifndef FAT_CURDIR_CASE_NOCARE
 5105:         DIRINF dir;
 5106:         UB     *npath, *cpath;
 5107:         UW     len, dcl;
 5108: #endif  /* ~ FAT_CURDIR_CASE_NOCARE */
 5109:         UB     *path, *e_utf8nm;
 5110:         ER     err;
 5111: 
 5112:         fs = (FATFS *)fd->fd_fs;
 5113: 
 5114:         /* Check inode's path name */
 5115:         path = ((FATNODE *)fd->fd_inode)->fino_c.ino_path;
 5116:         if (path == NULL) {
 5117:                 err = EX_INVAL;
 5118:                 goto exit0;
 5119:         }
 5120:         if (path[0] != '/') {
 5121:                 err = EX_IO;
 5122:                 goto exit0;
 5123:         }
 5124: 
 5125:         /* Set connection name */
 5126:         e_utf8nm = utf8nm + utf8len;
 5127:         *utf8nm++ = '/';
 5128:         (void)strcpy((B*)utf8nm, fs->ff_c.fs_coninf->connm);
 5129:         if (path[1] == '\0') goto exit0;       /* root directory */
 5130: 
 5131:         utf8nm += strlen((B*)utf8nm);
 5132: 
 5133: #ifdef  FAT_CURDIR_CASE_NOCARE
 5134: 
 5135:         if (utf8nm + strlen(path) >= e_utf8nm) {
 5136:                 err = EX_NAMETOOLONG;
 5137:         } else {
 5138:                 strcpy((B*)utf8nm, path);
 5139:                 err = E_OK;
 5140:         }
 5141: 
 5142: #else   /* FAT_CURDIR_CASE_NOCARE */
 5143: 
 5144:         /* Convert inode's path name to real "case-sensitve" path name */
 5145:         cpath = &path[1];
 5146:         for (dcl = fs->ff_rootcl; ; cpath = npath + 1) {
 5147: 
 5148:                 if ((npath = (UB*)strchr((B*)cpath, '/')) == NULL) {
 5149:                         len = strlen((B*)cpath);
 5150:                 } else {
 5151:                         len = npath - cpath;
 5152:                 }
 5153: 
 5154:                 err = fatOpenDIR(fs, &dir, dcl, OFSVOID, AC_RDONLY, NULL);
 5155:                 if (err < E_OK) break;
 5156: 
 5157:                 err = fatSearchDIR_nm(fs, &dir, cpath, len,
 5158:                                                 AC_RDONLY, fs->ff_nmbf);
 5159:                 if (err >= E_OK) {
 5160:                         if (isFAT_SUBDIR(dir.di_dirent->de_ftype)) {
 5161:                                 *utf8nm++ = '/';
 5162:                                 len = fatEncUtf16strToUtf8str(
 5163:                                         fs->ff_nmbf, fat_strlen16(fs->ff_nmbf),
 5164:                                         utf8nm, e_utf8nm - utf8nm);
 5165:                                 if ((utf8nm += len) >= e_utf8nm) {
 5166:                                         err = EX_NAMETOOLONG;
 5167:                                 }
 5168:                                 /* Go parent directory */
 5169:                                 dcl = dirent_to_fcl(fs, dir.di_dirent);
 5170:                         } else {
 5171:                                 dir.di_dirent = NULL;
 5172:                                 err = EX_NOTDIR;
 5173:                         }
 5174:                 }
 5175:                 /* Close directory */
 5176:                 err = fatCloseDIR(fs, &dir, err);
 5177: 
 5178:                 CHK_BREAK_AND_SET_ERR(fs, &err);
 5179:                 if (err < E_OK) break;
 5180:                 if (npath == NULL) break;
 5181:         }
 5182: #endif  /* FAT_CURDIR_CASE_NOCARE */
 5183: exit0:
 5184:         return err;
 5185: }
 5186: 
 5187: /*----------------------------------------------------------------------------
 5188:         FATFS FIMP services
 5189: ----------------------------------------------------------------------------*/
 5190: 
 5191: /*
 5192:  *  FATFS FIMP service - FIMP_OPEN
 5193:  */
 5194: LOCAL   ER        fatfs_open(FS *fs, fimp_t *req)
 5195: {
 5196:         LPINF  lp;
 5197:         FD     *fd;
 5198:         W      oflag, fdno;
 5199:         mode_t mode;
 5200:         ER     err;
 5201: 
 5202:         /* Analize path */
 5203:         err = fat_lookup((FATFS*)fs, &lp, req->r_open.path);
 5204:         if (err < E_OK) goto exit0;
 5205: 
 5206:         mode = 0;
 5207:         oflag = (W)req->r_open.oflags;
 5208: 
 5209:         /* Check the file system writing access */
 5210:         if (isNOT_RDONLY(oflag) && fs->fs_rdonly != FALSE) {
 5211:                 err = EX_ROFS;
 5212:         } else if (lp.lp_inode->ino_ino != NOEXS_INO) {
 5213:                 /* Existent file */
 5214:                 if (isSET(oflag, O_CREAT) && isSET(oflag, O_EXCL)) {
 5215:                         err = EX_EXIST;
 5216:                 } else if (lp.lp_inode->ino_type == DT_DIR) {
 5217:                         if (isNOT_RDONLY(oflag)) {
 5218:                                 /* Directory is reading open */
 5219:                                 err = EX_ISDIR;
 5220:                         } else if (isSET(oflag, O_TRUNC)) {
 5221:                                 /* Directory is not truncated */
 5222:                                 err = EX_ISDIR;
 5223:                         }
 5224:                 } else if (lp.lp_inode->ino_type == DT_REG &&
 5225:                                         isSET(oflag, O_DIRECTORY)) {
 5226:                         err = EX_NOTDIR;
 5227:                 }
 5228:         } else {
 5229:                 /* Nonnexisitent file */
 5230:                 if (! isSET(oflag, O_CREAT)) {
 5231:                         err = EX_NOENT;
 5232:                 } else if (fs->fs_rdonly != FALSE) {
 5233:                         /* Writing access of file system */
 5234:                         err = EX_ROFS;
 5235:                 } else {
 5236:                         /* File creation mode */
 5237:                         mode = req->r_open.mode & ~(fs->fs_uxinfo.uxi_cmask);
 5238:                 }
 5239:         }
 5240:         if (err < E_OK) goto exit1;
 5241: 
 5242:         /* Creation of file descriptor */
 5243:         err = fatNewFileDesc(fs, &fd, &fdno);
 5244:         if (err < E_OK) goto exit1;
 5245: 
 5246:         /* Open */
 5247:         fd->fd_inode = lp.lp_inode;
 5248:         err = fat_open(fd, lp.lp_path, oflag, mode);
 5249:         if (err < E_OK) goto exit2;
 5250: 
 5251:         err = fatDCacheSyncFS((FATFS*)fs, 0);
 5252:         if (err >= E_OK) {
 5253:                 /* Registration of file ref. node */
 5254:                 fatInodeRegister(fs, lp.lp_inode, fd->fd_omode);
 5255:                 *req->r_open.fid = (fid_t)fdno;
 5256:         }
 5257: exit2:
 5258:         if (err < E_OK) {
 5259:                 fd->fd_inode = NULL;
 5260:                 fatDelFileDesc(fs, fd, fdno);
 5261:         }
 5262: exit1:
 5263:         if (err < E_OK) {
 5264:                 fatInodeFree(fs, lp.lp_inode);
 5265:         }
 5266: exit0:
 5267:         return err;
 5268: }
 5269: 
 5270: /*
 5271:  *  FATFS FIMP service - FIMP_CLOSE
 5272:  */
 5273: LOCAL   ER        fatfs_close(FS *fs, fimp_t *req)
 5274: {
 5275:         FD     *fd;
 5276:         ER     err;
 5277: 
 5278:         err = fatSearchFileDesc(fs, &fd, (W)req->r_close.fid);
 5279:         if (err >= E_OK) {
 5280:                 if (fd->fd_refcnt <= 1) {
 5281:                         fd->fd_omode = req->r_close.oflags;
 5282:                         err = fat_close(fd);
 5283:                 }
 5284:                 if (err >= E_OK) {
 5285:                         err = fatFDSync(fd);
 5286:                         fatDelFileDesc(fs, fd, (W)req->r_close.fid);
 5287:                 }
 5288:         }
 5289:         return err;
 5290: }
 5291: 
 5292: /*
 5293:  *  FATFS FIMP service - FIMP_READ64
 5294:  */
 5295: LOCAL   ER        fatfs_read64(FS *fs, fimp_t *req)
 5296: {
 5297:         FD     *fd;
 5298:         ER     err;
 5299:         UW     alen;
 5300: 
 5301:         err = fatSearchFileDesc(fs, &fd, (W)req->r_read64.fid);
 5302:         if (err >= E_OK) {
 5303:                 if (fd->fd_inode == NULL) {
 5304:                         err = EX_BADF;
 5305:                 } else if (fd->fd_inode->ino_type != DT_REG) {
 5306:                         err = EX_ISDIR;
 5307:                 } else {
 5308:                         fd->fd_fpos = (D)*(req->r_read64.off);
 5309:                         fd->fd_omode = (W)req->r_read64.oflags;
 5310:                         err = fat_read64(fd, (UB*)req->r_read64.buf,
 5311:                                         (UW)*req->r_read64.len, (UW*)&alen,
 5312:                                                 (D*)req->r_read64.retoff);
 5313:                         if (err >= E_OK) {
 5314:                                 *req->r_read64.len = alen;
 5315:                                 err = fatFDSync(fd);
 5316:                         }
 5317:                 }
 5318:         }
 5319:         return err;
 5320: }
 5321: 
 5322: /*
 5323:  *  FATFS FIMP service - FIMP_WRITE64
 5324:  */
 5325: LOCAL   ER        fatfs_write64(FS *fs, fimp_t *req)
 5326: {
 5327:         FD     *fd;
 5328:         ER     err;
 5329:         UW     alen;
 5330: 
 5331:         err = fatSearchFileDesc(fs, &fd, (W)req->r_write64.fid);
 5332:         if (err >= E_OK) {
 5333:                 if (fd->fd_inode == NULL) {
 5334:                         err = EX_BADF;
 5335:                 } else if (fd->fd_inode->ino_type != DT_REG) {
 5336:                         err = EX_ISDIR;
 5337:                 } else {
 5338:                         fd->fd_fpos = (D)*(req->r_write64.off);
 5339:                         fd->fd_omode = (W)req->r_write64.oflags;
 5340:                         err = fat_write64(fd, (const UB*)req->r_write64.buf,
 5341:                                         (UW)*req->r_write64.len, (UW*)&alen,
 5342:                                                 (D*)req->r_write64.retoff);
 5343:                         if (err >= E_OK) {
 5344:                                 *req->r_write64.len = alen;
 5345:                                 err = fatFDSync(fd);
 5346:                         }
 5347:                 }
 5348:         }
 5349:         return err;
 5350: }
 5351: 
 5352: /*
 5353:  *  FATFS FIMP service - FIMP_IOCTL
 5354:  */
 5355: LOCAL   ER        fatfs_ioctl(FS *fs, fimp_t *req)
 5356: {
 5357:         FD     *fd;
 5358:         ER     err;
 5359: 
 5360:         err = fatSearchFileDesc(fs, &fd, (W)req->r_ioctl.fid);
 5361:         if (err >= E_OK) {
 5362:                 fd->fd_omode = (W)req->r_ioctl.oflags;
 5363:                 *req->r_ioctl.retval = (INT)
 5364:                         fat_ioctl(fd, (UW)req->r_ioctl.dcmd,req->r_ioctl.arg);
 5365:         }
 5366:         return err;
 5367: }
 5368: 
 5369: /*
 5370:  *  FATFS FIMP service - FIMP_FSYNC
 5371:  */
 5372: LOCAL   ER        fatfs_fsync(FS *fs, fimp_t *req)
 5373: {
 5374:         FD     *fd;
 5375:         ER     err;
 5376: 
 5377:         err = fatSearchFileDesc(fs, &fd, (W)req->r_fsync.fid);
 5378:         if (err >= E_OK) {
 5379:                 fd->fd_omode = (W)req->r_fsync.oflags;
 5380:                 err = fatDCacheSyncFS((FATFS*)fs, (VW)fd->fd_inode);
 5381:         }
 5382:         return err;
 5383: }
 5384: 
 5385: /*
 5386:  *  FATFS FIMP service - FIMP_TRUNCATE64
 5387:  */
 5388: LOCAL   ER        fatfs_truncate64(FS *fs, fimp_t *req)
 5389: {
 5390:         LPINF  lp;
 5391:         ER     err;
 5392: 
 5393:         err = fat_lookup((FATFS*)fs, &lp, req->r_truncate64.path);
 5394:         if (err >= E_OK) {
 5395:                 if (fs->fs_rdonly != FALSE) {
 5396:                         err = EX_ROFS;
 5397:                 } else {
 5398:                         err = fat_truncate64((FATFS*)fs, (FATNODE*)lp.lp_inode,
 5399:                                                 (D)req->r_truncate64.len);
 5400:                         if (err >= E_OK) {
 5401:                                 err = fatDCacheSyncFS((FATFS*)fs, 0);
 5402:                         }
 5403:                 }
 5404:                 fatInodeFree(fs, lp.lp_inode);
 5405:         }
 5406:         return err;
 5407: }
 5408: 
 5409: /*
 5410:  *  FATFS FIMP service - FIMP_FTRUNCATE64
 5411:  */
 5412: LOCAL   ER        fatfs_ftruncate64(FS *fs, fimp_t *req)
 5413: {
 5414:         ER     err;
 5415:         FD     *fd;
 5416: 
 5417:         err = fatSearchFileDesc(fs, &fd, (W)req->r_ftruncate64.fid);
 5418:         if (err >= E_OK) {
 5419:                 err = fat_ftruncate64(fd, (D)req->r_ftruncate64.len);
 5420:                 if (err >= E_OK) {
 5421:                         err = fatFDSync(fd);
 5422:                 }
 5423:         }
 5424:         return err;
 5425: }
 5426: 
 5427: /*
 5428:  *  FATFS FIMP service - FIMP_UNLINK
 5429:  */
 5430: LOCAL   ER        fatfs_unlink(FS *fs, fimp_t *req)
 5431: {
 5432:         LPINF  lp;
 5433:         ER     err;
 5434: 
 5435:         err = fat_lookup((FATFS*)fs, &lp, req->r_unlink.path);
 5436:         if (err >= E_OK) {
 5437:                 if (lp.lp_inode->ino_ino == NOEXS_INO) {
 5438:                         err = EX_NOENT;
 5439:                 } else if (lp.lp_inode->ino_refcnt > 0) {
 5440:                         err = EX_BUSY;
 5441:                 } else if (fs->fs_rdonly != FALSE) {
 5442:                         err = EX_ROFS;
 5443:                 } else {
 5444:                         err = fat_unlink((FATFS*)fs, (FATNODE*)lp.lp_inode);
 5445:                         if (err >= E_OK) {
 5446:                                 err = fatDCacheSyncFS((FATFS*)fs, 0);
 5447:                         }
 5448:                 }
 5449:                 fatInodeFree(fs, lp.lp_inode);
 5450:         }
 5451:         return err;
 5452: }
 5453: 
 5454: /*
 5455:  *  FATFS FIMP service - FIMP_RENAME
 5456:  */
 5457: LOCAL   ER        fatfs_rename(FS *fs, fimp_t *req)
 5458: {
 5459:         LPINF  olp, nlp;
 5460:         INODE  *from, *to;
 5461:         ER     err;
 5462: 
 5463:         err = fat_lookup((FATFS*)fs, &olp, req->r_rename.oldpath);
 5464:         if (err < E_OK) goto exit0;
 5465: 
 5466:         from = olp.lp_inode;
 5467:         if (from->ino_ino == NOEXS_INO) {
 5468:                 err = EX_NOENT;
 5469:                 goto exit1;
 5470:         }
 5471:         if (IsRootINODE(fs, from)) {
 5472:                 err = EX_ACCES;
 5473:                 goto exit1;
 5474:         }
 5475: 
 5476:         err = fat_lookup((FATFS*)fs, &nlp, req->r_rename.newpath);
 5477:         if (err < E_OK) goto exit1;
 5478: 
 5479:         to = nlp.lp_inode;
 5480:         if (IsRootINODE(fs, to)) {
 5481:                 err = EX_ACCES;
 5482:                 goto exit2;
 5483:         }
 5484: 
 5485:         /* Existence of "to" */
 5486:         if (to->ino_ino != NOEXS_INO) {
 5487:                 /* Check of the number of "to" references */
 5488:                 if (fatCheckIsInodeBusy(fs, to) != FALSE) {
 5489:                         err = EX_BUSY;
 5490:                         goto exit2;
 5491:                 }
 5492:                 /* Check of the accordance of file type */
 5493:                 if (from->ino_type != to->ino_type) {
 5494:                         err = (to->ino_type == DT_DIR) ? EX_ISDIR : EX_NOTDIR;
 5495:                         goto exit2;
 5496:                 }
 5497:                 /* Stop if it is an same file */
 5498:                 if (from->ino_ino == to->ino_ino) {
 5499:                         goto exit2;
 5500:                 }
 5501:         }
 5502:         if (fs->fs_rdonly != FALSE) {
 5503:                 err = EX_ROFS;
 5504:                 goto exit2;
 5505:         }
 5506:         err = fat_rename((FATFS*)fs, (FATNODE*)from, (FATNODE*)to, nlp.lp_path);
 5507:         if (err >= E_OK) {
 5508:                 err = fatDCacheSyncFS((FATFS*)fs, 0);
 5509:         }
 5510: exit2:
 5511:         fatInodeFree(fs, to);
 5512: exit1:
 5513:         fatInodeFree(fs, from);
 5514: exit0:
 5515:         return err;
 5516: }
 5517: 
 5518: /*
 5519:  *  FATFS FIMP service - FIMP_CHMOD
 5520:  */
 5521: LOCAL   ER        fatfs_chmod(FS *fs, fimp_t *req)
 5522: {
 5523:         LPINF  lp;
 5524:         ER     err;
 5525: 
 5526:         err = fat_lookup((FATFS*)fs, &lp, req->r_chmod.path);
 5527:         if (err >= E_OK) {
 5528:                 if (lp.lp_inode->ino_ino == NOEXS_INO) {
 5529:                         err = EX_NOENT;
 5530:                 } else if (fs->fs_rdonly != FALSE) {
 5531:                         err = EX_ROFS;
 5532:                 } else {
 5533:                         err = fat_chmod((FATFS*)fs, (FATNODE*)lp.lp_inode,
 5534:                                                         req->r_chmod.mode);
 5535:                         if (err >= E_OK) {
 5536:                                 err = fatDCacheSyncFS((FATFS*)fs, 0);
 5537:                         }
 5538:                 }
 5539:                 fatInodeFree(fs, lp.lp_inode);
 5540:         }
 5541:         return err;
 5542: }
 5543: 
 5544: /*
 5545:  *  FATFS FIMP service - FIMP_FCHMOD
 5546:  */
 5547: LOCAL   ER        fatfs_fchmod(FS *fs, fimp_t *req)
 5548: {
 5549:         FD     *fd;
 5550:         ER     err;
 5551: 
 5552:         err = fatSearchFileDesc(fs, &fd, (W)req->r_fchmod.fid);
 5553:         if (err >= E_OK) {
 5554:                 if (fs->fs_rdonly != FALSE) {
 5555:                         err = EX_ROFS;
 5556:                 } else {
 5557:                         err = fat_fchmod(fd, req->r_fchmod.mode);
 5558:                         if (err >= E_OK) {
 5559:                                 err = fatFDSync(fd);
 5560:                         }
 5561:                 }
 5562:         }
 5563:         return err;
 5564: }
 5565: 
 5566: /*
 5567:  *  FATFS FIMP service - FIMP_MKDIR
 5568:  */
 5569: LOCAL   ER        fatfs_mkdir(FS *fs, fimp_t *req)
 5570: {
 5571:         LPINF  lp;
 5572:         ER     err;
 5573: 
 5574:         err = fat_lookup((FATFS*)fs, &lp, req->r_mkdir.path);
 5575:         if (err >= E_OK) {
 5576:                 if (lp.lp_inode->ino_ino != NOEXS_INO) {
 5577:                         err = EX_EXIST;
 5578:                 } else if (fs->fs_rdonly != FALSE) {
 5579:                         err = EX_ROFS;
 5580:                 } else {
 5581:                         err = fat_mkdir((FATFS*)fs, (FATNODE*)lp.lp_inode,
 5582:                                         lp.lp_path, req->r_mkdir.mode);
 5583:                         if (err >= E_OK) {
 5584:                                 err = fatDCacheSyncFS((FATFS*)fs, 0);
 5585:                         }
 5586:                 }
 5587:                 fatInodeFree(fs, lp.lp_inode);
 5588:         }
 5589:         return err;
 5590: }
 5591: 
 5592: /*
 5593:  *  FATFS FIMP service - FIMP_RMDIR
 5594:  */
 5595: LOCAL   ER        fatfs_rmdir(FS *fs, fimp_t *req)
 5596: {
 5597:         LPINF  lp;
 5598:         ER     err;
 5599: 
 5600:         err = fat_lookup((FATFS*)fs, &lp, req->r_rmdir.path);
 5601:         if (err >= E_OK) {
 5602:                 if (lp.lp_inode->ino_ino == NOEXS_INO) {
 5603:                         err = EX_NOENT;
 5604:                 } else if (IsRootINODE(fs, lp.lp_inode)) {
 5605:                         err = EX_ACCES;
 5606:                 } else if (fatCheckIsInodeBusy(fs, lp.lp_inode) != FALSE) {
 5607:                         err = EX_BUSY;
 5608:                 } else if (fs->fs_rdonly != FALSE) {
 5609:                         err = EX_ROFS;
 5610:                 } else {
 5611:                         err = fat_rmdir((FATFS*)fs, &fs->fs_uxinfo.uxi_curdir,
 5612:                                                 (FATNODE*)lp.lp_inode);
 5613:                         if (err >= E_OK) {
 5614:                                 err = fatDCacheSyncFS((FATFS*)fs, 0);
 5615:                         }
 5616:                 }
 5617:                 fatInodeFree(fs, lp.lp_inode);
 5618:         }
 5619:         return err;
 5620: }
 5621: 
 5622: /*
 5623:  *  FATFS FIMP service - FIMP_CHDIR
 5624:  */
 5625: LOCAL   ER        fatfs_chdir(FS *fs, fimp_t *req)
 5626: {
 5627:         (void)fs;
 5628:         (void)req;
 5629:         /* Nothing to do */
 5630:         return E_OK;
 5631: }
 5632: 
 5633: /*
 5634:  *  FATFS FIMP service - FIMP_FCHDIR
 5635:  */
 5636: LOCAL   ER        fatfs_fchdir(FS *fs, fimp_t *req)
 5637: {
 5638:         FD     *fd;
 5639:         ER     err;
 5640: 
 5641:         err = fatSearchFileDesc(fs, &fd, (W)req->r_fchdir.fid);
 5642:         if (err >= E_OK) {
 5643:                 err = fat_fchdir(fd, (UB*)req->r_fchdir.buf,
 5644:                                                 (W)req->r_fchdir.len);
 5645:                 if (err >= E_OK) {
 5646:                         err = fatFDSync(fd);
 5647:                 }
 5648:         }
 5649:         return err;
 5650: }
 5651: 
 5652: /*
 5653:  *  FATFS FIMP service - FIMP_READDIR
 5654:  */
 5655: LOCAL   ER        fatfs_getdents(FS *fs, fimp_t *req)
 5656: {
 5657:         FD     *fd;
 5658:         W      retofs;
 5659:         ER     err;
 5660: 
 5661:         err = fatSearchFileDesc(fs, &fd, (W)req->r_getdents.fid);
 5662:         if (err >= E_OK) {
 5663:                 fd->fd_fpos = (D)*(req->r_getdents.off);
 5664:                 fd->fd_omode = (W)req->r_getdents.oflags;
 5665:                 err = fat_getdents(fd, req->r_getdents.buf,
 5666:                                         (W*)req->r_getdents.len, &retofs);
 5667:                 if (err >= E_OK) {
 5668:                         err = fatFDSync(fd);
 5669:                         if (err >= E_OK) {
 5670:                                 *(req->r_getdents.retoff) = (off64_t)retofs;
 5671:                         }
 5672:                 }
 5673:         }
 5674:         return err;
 5675: }
 5676: 
 5677: /*
 5678:  *  FATFS FIMP service - FIMP_FSTATVFS
 5679:  */
 5680: LOCAL   ER        fatfs_fstatvfs(FS *fs, fimp_t *req)
 5681: {
 5682:         return fat_statvfs((FATFS*)fs, req->r_fstatvfs.buf);
 5683: }
 5684: 
 5685: /*
 5686:  *  FATFS FIMP service - FIMP_STATVFS
 5687:  */
 5688: LOCAL   ER        fatfs_statvfs(FS *fs, fimp_t *req)
 5689: {
 5690:         LPINF  lp;
 5691:         ER     err;
 5692: 
 5693:         err = fat_lookup((FATFS*)fs, &lp, req->r_statvfs.path);
 5694:         if (err >= E_OK) {
 5695:                 if (lp.lp_inode->ino_ino == NOEXS_INO) {
 5696:                         err = EX_NOENT;
 5697:                 } else {
 5698:                         err = fat_statvfs((FATFS*)fs, req->r_statvfs.buf);
 5699:                         //if (err >= E_OK) {
 5700:                         //   err = fatDCacheSyncFS((FATFS*)fs, 0);
 5701:                         //}
 5702:                 }
 5703:                 fatInodeFree(fs, lp.lp_inode);
 5704:         }
 5705:         return err;
 5706: }
 5707: 
 5708: /*
 5709:  *  FATFS FIMP service - FIMP_SYNC
 5710:  */
 5711: LOCAL   ER        fatfs_sync(FS *fs, fimp_t *req)
 5712: {
 5713:         (void)req;
 5714:         return fatDCacheSyncFS((FATFS*)fs, 0);
 5715: }
 5716: 
 5717: /*
 5718:  *  FATFS FIMP service - FIMP_UTIMES_US
 5719:  */
 5720: LOCAL   ER        fatfs_utimes_us(FS *fs, fimp_t *req)
 5721: {
 5722:         LPINF  lp;
 5723:         ER     err;
 5724: 
 5725:         err = fat_lookup((FATFS*)fs, &lp, req->r_utimes_us.path);
 5726:         if (err >= E_OK) {
 5727:                 if (lp.lp_inode->ino_ino == NOEXS_INO) {
 5728:                         err = EX_NOENT;
 5729:                 } else if (fs->fs_rdonly != FALSE) {
 5730:                         err = EX_ROFS;
 5731:                 } else {
 5732:                         err = fat_utimes_us((FATFS*)fs, (FATNODE*)lp.lp_inode,
 5733:                                                 req->r_utimes_us.times_u);
 5734:                         if (err >= E_OK) {
 5735:                                 err = fatDCacheSyncFS((FATFS*)fs, 0);
 5736:                         }
 5737:                 }
 5738:                 fatInodeFree(fs, lp.lp_inode);
 5739:         }
 5740:         return err;
 5741: }
 5742: 
 5743: /*
 5744:  *  FATFS FIMP service - FIMP_FCNTL64
 5745:  */
 5746: LOCAL   ER        fatfs_fcntl64(FS *fs, fimp_t *req)
 5747: {
 5748:         (void)fs;
 5749:         (void)req;
 5750:         return EX_NOTSUP;
 5751: }
 5752: 
 5753: /*
 5754:  *  FATFS FIMP service - FIMP_FSTAT64_US
 5755:  */
 5756: LOCAL   ER        fatfs_fstat64_us(FS *fs, fimp_t *req)
 5757: {
 5758:         FD     *fd;
 5759:         ER     err;
 5760: 
 5761:         err = fatSearchFileDesc(fs, &fd, (W)req->r_fstat64_us.fid);
 5762:         if (err >= E_OK) {
 5763:                 err = fat_fstat64_us(fd, req->r_fstat64_us.buf);
 5764:                 if (err >= E_OK) {
 5765:                         err = fatFDSync(fd);
 5766:                 }
 5767:         }
 5768:         return err;
 5769: }
 5770: 
 5771: /*
 5772:  *  FATFS FIMP service - FIMP_STAT64_US
 5773:  */
 5774: LOCAL   ER        fatfs_stat64_us(FS *fs, fimp_t *req)
 5775: {
 5776:         LPINF  lp;
 5777:         ER     err;
 5778: 
 5779:         err = fat_lookup((FATFS*)fs, &lp, req->r_stat64_us.path);
 5780:         if (err >= E_OK) {
 5781:                 if (lp.lp_inode->ino_ino == NOEXS_INO) {
 5782:                         err = EX_NOENT;
 5783:                 } else {
 5784:                         err = fat_stat64_us((FATFS*)fs, (FATNODE*)lp.lp_inode,
 5785:                                                         req->r_stat64_us.buf);
 5786:                         //if (err >= E_OK) {
 5787:                         //   err = fatDCacheSyncFS((FATFS*)fs, 0);
 5788:                         //}
 5789:                 }
 5790:                 fatInodeFree(fs, lp.lp_inode);
 5791:         }
 5792:         return err;
 5793: }
 5794: 
 5795: /*----------------------------------------------------------------------------
 5796:         FAT uxinfo operations
 5797: ----------------------------------------------------------------------------*/
 5798: 
 5799: /*
 5800:  *  Initialize UXINFO
 5801:  */
 5802: LOCAL   ER        fatUxinfoInit(FATFS *fs)
 5803: {
 5804:         UXINFO *uxinfo;
 5805:         FATNODE        *rootinode;
 5806:         UB     *buf;
 5807:         ER     err;
 5808: 
 5809:         uxinfo = &fs->ff_c.fs_uxinfo;
 5810:         rootinode = NULL;
 5811: 
 5812:         /* Current directory takeover */
 5813:         fatInodeQueInit(&fs->ff_c);
 5814:         err = fatGetRootINODE(fs, &rootinode);
 5815:         if (err < E_OK) goto exit0;
 5816: 
 5817:         /* Twice */
 5818:         fatInodeRegister((FS *)fs, (INODE *)rootinode, O_RDONLY);
 5819:         fatInodeRegister((FS *)fs, (INODE *)rootinode, O_RDONLY);
 5820:         uxinfo->uxi_curdir.cd_inode = (INODE *)rootinode;
 5821: 
 5822:         /* File creation mode takeover */
 5823:         uxinfo->uxi_cmask = 0;
 5824: 
 5825:         /* Released inode */
 5826:         uxinfo->uxi_relino = NULL;
 5827: 
 5828:         /* Creation of file descriptor table  */
 5829:         buf = (UB *)fimp_calloc(MaxOpenF, sizeof(FD *));
 5830:         if (buf == NULL) {
 5831:                 err = EX_NOMEM;
 5832:                 fatInodeRelease((FS *)fs,
 5833:                                 uxinfo->uxi_curdir.cd_inode, O_RDONLY);
 5834:                 uxinfo->uxi_curdir.cd_inode = NULL;
 5835:                 goto exit0;
 5836:         }
 5837:         uxinfo->uxi_fdtbl = (FD **)buf;
 5838: exit0:
 5839:         return err;
 5840: }
 5841: 
 5842: /*
 5843:  *  Cleanup UXINFO
 5844:  */
 5845: LOCAL   void      fatUxinfoCleanup(FATFS *fs)
 5846: {
 5847:         UXINFO *uxinfo;
 5848:         FATNODE        *rootinode;
 5849:         FD     *fd;
 5850:         W      i;
 5851: 
 5852:         uxinfo = &fs->ff_c.fs_uxinfo;
 5853:         rootinode = NULL;
 5854: 
 5855:         /* Opened files releasee */
 5856:         if (uxinfo->uxi_fdtbl != NULL) {
 5857:                 /* All files close */
 5858:                 for (i = 0; i < MaxOpenF; i++) {
 5859:                         fd = uxinfo->uxi_fdtbl[i];
 5860:                         if (fd != NULL) {
 5861:                                 struct fimp_close   req;
 5862:                                 req.fid = i;
 5863:                                 (void)fatfs_close((FS *)fs, (fimp_t *)&req);
 5864:                         }
 5865:                 }
 5866:                 /* Deletion of file descriptor table */
 5867:                 fimp_free(uxinfo->uxi_fdtbl);
 5868:                 uxinfo->uxi_fdtbl = NULL;
 5869:         }
 5870: 
 5871:         /* Release current directory */
 5872:         if (uxinfo->uxi_curdir.cd_inode != NULL) {
 5873:                 fatInodeRelease((FS *)fs,
 5874:                                 uxinfo->uxi_curdir.cd_inode, O_RDONLY);
 5875:                 uxinfo->uxi_curdir.cd_inode = NULL;
 5876:         }
 5877: 
 5878:         /* Release rootdir inode */
 5879:         (void)fatGetRootINODE(fs, &rootinode);
 5880:         fatInodeRelease((FS *)fs, (INODE *)rootinode, O_RDONLY);
 5881: }
 5882: 
 5883: /*----------------------------------------------------------------------------
 5884:         FIMP various functions
 5885: ----------------------------------------------------------------------------*/
 5886: 
 5887: /*
 5888:  *  Error code conversion
 5889:  */
 5890: LOCAL   ER        toEXER(ER err)
 5891: {
 5892:         if (err < E_OK && MERCD(err) != EC_ERRNO) {
 5893:                 switch (MERCD(err)) {
 5894:                 case MERCD(E_SYS):    err = EX_IO;               break;
 5895:                 case MERCD(E_NOCOP):  err = EX_IO;             break;
 5896:                 case MERCD(E_NOSPT):  err = EX_NOTSUP; break;
 5897:                 case MERCD(E_RSFN):   err = EX_IO;              break;
 5898:                 case MERCD(E_RSATR):  err = EX_INVAL;          break;
 5899:                 case MERCD(E_PAR):    err = EX_INVAL;            break;
 5900:                 case MERCD(E_ID):     err = EX_INVAL;             break;
 5901:                 case MERCD(E_CTX):    err = EX_IO;               break;
 5902:                 case MERCD(E_MACV):   err = EX_FAULT;           break;
 5903:                 case MERCD(E_OACV):   err = EX_ACCES;           break;
 5904:                 case MERCD(E_ILUSE):  err = EX_INVAL;          break;
 5905:                 case MERCD(E_NOMEM):  err = EX_NOMEM;          break;
 5906:                 case MERCD(E_LIMIT):  err = EX_NOSPC;          break;
 5907:                 case MERCD(E_OBJ):    err = EX_INVAL;            break;
 5908:                 case MERCD(E_NOEXS):  err = EX_INVAL;          break;
 5909:                 case MERCD(E_QOVR):   err = EX_IO;              break;
 5910:                 case MERCD(E_RLWAI):  err = EX_INVAL;          break;
 5911:                 case MERCD(E_TMOUT):  err = EX_IO;             break;
 5912:                 case MERCD(E_DLT):    err = EX_IO;               break;
 5913:                 case MERCD(E_DISWAI): err = EX_INTR;          break;
 5914:                 case MERCD(E_IO):     err = EX_IO;                break;
 5915:                 case MERCD(E_NOMDA):  err = EX_NODEV;          break;
 5916:                 case MERCD(E_BUSY):   err = EX_BUSY;            break;
 5917:                 case MERCD(E_ABORT):  err = EX_INTR;           break;
 5918:                 case MERCD(E_RONLY):  err = EX_ROFS;           break;
 5919:                 default:                                      break;
 5920:                 }
 5921:         }
 5922:         return err;
 5923: }
 5924: 
 5925: /*
 5926:  *  Get request information
 5927:  */
 5928: LOCAL   void      *fatGetReqInf(fimp_t *req, UW *func)
 5929: {
 5930: static const    UW functab[] = {
 5931:                 (UW)((B*)fatfs_open + 0x01),  /* +0x01: Breakable      */
 5932:                 (UW)((B*)fatfs_close + 0x01),
 5933:                 (UW)fatfs_ioctl,
 5934:                 (UW)fatfs_getdents,
 5935:                 (UW)((B*)fatfs_chdir + 0x01),
 5936:                 (UW)((B*)fatfs_fchdir + 0x01),
 5937:                 (UW)((B*)fatfs_fsync + 0x01),
 5938:                 (UW)fatfs_unlink,
 5939:                 (UW)fatfs_rename,
 5940:                 (UW)fatfs_chmod,
 5941:                 (UW)fatfs_fchmod,
 5942:                 (UW)fatfs_mkdir,
 5943:                 (UW)fatfs_rmdir,
 5944:                 (UW)((B*)fatfs_statvfs + 0x01),
 5945:                 (UW)((B*)fatfs_fstatvfs + 0x01),
 5946:                 (UW)((B*)fatfs_sync + 0x01),
 5947:                 (UW)((B*)fatfs_read64 + 0x01),
 5948:                 (UW)((B*)fatfs_write64 + 0x01),
 5949:                 (UW)((B*)fatfs_truncate64 + 0x01),
 5950:                 (UW)((B*)fatfs_ftruncate64 + 0x01),
 5951:                 (UW)fatfs_fcntl64,
 5952:                 (UW)fatfs_stat64_us,
 5953:                 (UW)fatfs_fstat64_us,
 5954:                 (UW)fatfs_utimes_us,
 5955: };
 5956:         INT    i;
 5957: 
 5958:         if (req->com.coninf != NULL) {
 5959:                 if ((i = req->com.r_code) >= 0 && i <= FIMP_COMMAND_MAX) {
 5960:                         *func = functab[i];
 5961:                         return req->com.coninf->consd;
 5962:                 }
 5963:         }
 5964:         *func = 0;
 5965:         return NULL;
 5966: }
 5967: 
 5968: /*
 5969:  *  FIMP request function execute task
 5970:  */
 5971: LOCAL   void      FileSystemTask(INT stacd)
 5972: {
 5973:         FS     *fs;
 5974:         BOOL   fin;
 5975:         CMDPKT *pkt;
 5976:         RNO    rdvno;
 5977:         UW     func;
 5978:         ER     err;
 5979: 
 5980:         fs = (FS *)stacd;
 5981:         for (fin = FALSE; fin == FALSE; ) {
 5982:                 /* accept request */
 5983:                 if (tk_acp_por(fs->fs_porid, 1, &rdvno,
 5984:                                         &pkt, TMO_FEVR) < E_OK) continue;
 5985: 
 5986:                 /* Set task space */
 5987:                 err = SetTaskSpace(pkt->cp_tskid);
 5988:                 if (err < E_OK) goto reply;
 5989: 
 5990:                 if (pkt->cp_req == NULL) {    /* terminate own task */
 5991:                         fin = TRUE;
 5992:                         err = E_OK;
 5993:                         goto reply;
 5994:                 }
 5995: 
 5996:                 /* Check request */
 5997:                 if (fatGetReqInf(pkt->cp_req, &func) != fs) {
 5998:                         err = EX_IO;
 5999:                         goto reply;
 6000:                 }
 6001: 
 6002:                 /* Here, check break_done flag again, note that
 6003:                    break_enb flag has been set in fatfs_service */
 6004:                 fs->fs_tsksts = &tskStsTab[pkt->cp_tskid];
 6005:                 if (fs->fs_tsksts->c.break_done != 0) {
 6006:                         err = EX_INTR;
 6007:                         goto reply;
 6008:                 }
 6009: 
 6010:                 /* Call service function */
 6011:                 err = ((fatfs_api_t)(func & ~0x01))(fs, pkt->cp_req);
 6012: 
 6013:                 if (fs->fs_uxinfo.uxi_relino != NULL) {
 6014:                         /* Release inode registered in fatResetCurdir() */
 6015:                         fatInodeRelease(fs, fs->fs_uxinfo.uxi_relino, O_RDONLY);
 6016:                         fs->fs_uxinfo.uxi_relino = NULL;
 6017:                 }
 6018: reply:
 6019:                 /* Reply response */
 6020:                 pkt->cp_err = err;
 6021:                 (void)tk_rpl_rdv(rdvno, &pkt, sizeof(pkt));
 6022:         }
 6023:         /* Exit and delete own task */
 6024:         tk_exd_tsk();
 6025: }
 6026: 
 6027: /*
 6028:  *  Call rendezvous
 6029:  */
 6030: LOCAL   ER        CallFileSystemTask(FATFS *fs, CMDPKT *ppkt)
 6031: {
 6032:         ER     err;
 6033: 
 6034:         ppkt->cp_err = E_OK;
 6035:         err = tk_cal_por(fs->ff_c.fs_porid, 1, &ppkt,
 6036:                                                 sizeof(CMDPKT *), TMO_FEVR);
 6037:         return (err < E_OK) ? err : ppkt->cp_err;
 6038: }
 6039: 
 6040: /*
 6041:  *  Create objects
 6042:  */
 6043: LOCAL   ER        fatCreateObjects(FATFS *fs)
 6044: {
 6045:         T_CPOR cpor;
 6046:         T_CTSK ctsk;
 6047:         ER     err;
 6048: 
 6049:         /* Creation of rendezvous port */
 6050:         SetOBJNAME(cpor.exinf, "bfat");
 6051:         cpor.poratr = TA_TPRI;
 6052:         cpor.maxcmsz = sizeof(CMDPKT *);
 6053:         cpor.maxrmsz = sizeof(CMDPKT *);
 6054:         err = tk_cre_por(&cpor);
 6055:         if (err >= E_OK) {
 6056:                 fs->ff_c.fs_porid = (ID)err;
 6057: 
 6058:                 /* Creation of file system task */
 6059:                 SetOBJNAME(ctsk.exinf, "bfat");
 6060:                 ctsk.tskatr = TA_HLNG | TA_RNG0;
 6061:                 ctsk.task = (void*)FileSystemTask;
 6062:                 ctsk.itskpri = TaskPriority;
 6063:                 ctsk.stksz = TaskStackSize;
 6064:                 err = tk_cre_tsk(&ctsk);
 6065:                 if (err >= E_OK) {
 6066:                         fs->ff_c.fs_tskid = (ID)err;
 6067:                         err = tk_sta_tsk(fs->ff_c.fs_tskid, (INT)fs);
 6068:                         if (err < E_OK) {
 6069:                                 (void)tk_del_tsk(fs->ff_c.fs_tskid);
 6070:                         }
 6071:                 }
 6072:                 if (err < E_OK) {
 6073:                         (void)tk_del_por(fs->ff_c.fs_porid);
 6074:                 }
 6075:         }
 6076:         return err;
 6077: }
 6078: 
 6079: /*
 6080:  *  Delete objects
 6081:  */
 6082: LOCAL   void      fatDeleteObjects(FATFS *fs)
 6083: {
 6084:         CMDPKT pkt;
 6085: 
 6086:         /* Delete task */
 6087:         pkt.cp_tskid = tk_get_tid();
 6088:         pkt.cp_req = NULL;
 6089: 
 6090:         (void)CallFileSystemTask(fs, &pkt);
 6091: 
 6092:         /* Delete rendezvous */
 6093:         (void)tk_del_por(fs->ff_c.fs_porid);
 6094: }
 6095: 
 6096: /*
 6097:  *  FATFS FIMP service function
 6098:  */
 6099: LOCAL   ER        fatfs_service(fimp_t *req)
 6100: {
 6101:         FATFS          *fs;
 6102:         UW             func;
 6103:         TaskSts                *tsksts;
 6104:         ER             err;
 6105:         CMDPKT         pkt;
 6106: 
 6107:         /* Check request */
 6108:         fs = (FATFS*)fatGetReqInf(req, &func);
 6109:         if (fs == NULL) {
 6110:                 err = EX_NOTSUP;
 6111:         } else {
 6112:                 err = E_OK;
 6113:                 pkt.cp_tskid = tk_get_tid();
 6114:                 tsksts = &tskStsTab[pkt.cp_tskid];
 6115: 
 6116:                 /* Check break flag */
 6117:                 if ((func & 0x01) != 0) {
 6118:                         tsksts->c.break_enb = 1;
 6119:                         if (tsksts->c.break_done != 0) {
 6120:                                 err = EX_INTR;
 6121:                         } else if (tsksts->c.break_req != 0) {
 6122:                                 err = EX_INTR;
 6123:                         }
 6124:                 }
 6125: 
 6126:                 /* Call FileSystemTask */
 6127:                 if (err >= E_OK) {
 6128:                         pkt.cp_req = req;
 6129:                         err = CallFileSystemTask(fs, &pkt);
 6130:                 }
 6131: 
 6132:                 tsksts->c.break_enb = 0;
 6133:                 if (tsksts->c.break_done != 0) {
 6134:                         tsksts->c.break_done = 0;
 6135:                 }
 6136:         }
 6137:         return toEXER(err);
 6138: }
 6139: 
 6140: /*
 6141:  *  Get system configuration parameter
 6142:  */
 6143: LOCAL   void      fatGetConfiguration(UB *name, INT *par)
 6144: {
 6145:         INT    val;
 6146: 
 6147:         if (tk_get_cfn(name, &val, 1) >= 1) *par = val;
 6148: }
 6149: 
 6150: /*
 6151:  *  FATFS FIMP registration function
 6152:  */
 6153: LOCAL   ER        fatfs_registfn(fimpinf_t *fimpinf, void *exinf)
 6154: {
 6155:         FAT_FSInfo     *fpi;
 6156: 
 6157:         (void)exinf;
 6158: 
 6159:         /* Alloc FAT FIMP informationn queue */
 6160:         if ((fpi = fimp_calloc(1, sizeof(FAT_FSInfo))) == NULL) {
 6161:                 return EX_NOMEM;
 6162:         }
 6163: 
 6164:         /* Set task status tbale : allocated by upper fs */
 6165:         tskStsTab = (TaskSts*)fimpinf->fimpsd;
 6166: 
 6167:         QueInit(&fpi->fpi_attachque);
 6168:         fimpinf->fimpsd = (void *)fpi;
 6169: 
 6170:         /* Get FAT FS configuration parameters : global */
 6171:         fatGetConfiguration(SYSCONF_MaxOpenF, &MaxOpenF);
 6172:         fatGetConfiguration(SYSCONF_TaskStackSize, &TaskStackSize);
 6173:         fatGetConfiguration(SYSCONF_CacheFATMemorySize, &CacheFATMemorySize);
 6174:         fatGetConfiguration(SYSCONF_CacheFATRatio, &CacheFATRatio);
 6175:         fatGetConfiguration(SYSCONF_CacheRootMemorySize, &CacheRootMemorySize);
 6176:         fatGetConfiguration(SYSCONF_CacheRootRatio, &CacheRootRatio);
 6177:         fatGetConfiguration(SYSCONF_CacheDataMemorySize, &CacheDataMemorySize);
 6178:         fatGetConfiguration(SYSCONF_CacheDataRatio, &CacheDataRatio);
 6179:         fatGetConfiguration(SYSCONF_LastAccess, &LastAccess);
 6180: 
 6181:         return E_OK;
 6182: }
 6183: 
 6184: /*
 6185:  *  FATFS FIMP unregistration function
 6186:  */
 6187: LOCAL   ER        fatfs_unregistfn(fimpinf_t *fimpinf)
 6188: {
 6189:         /* Free FIMP Information memory */
 6190:         fimp_free(fimpinf->fimpsd);
 6191:         fimpinf->fimpsd = NULL;
 6192:         return E_OK;
 6193: }
 6194: 
 6195: /*
 6196:  *  FATFS FIMP attach function
 6197:  */
 6198: LOCAL   ER        fatfs_attachfn(coninf_t *coninf, void *exinf)
 6199: {
 6200:         FAT_FSInfo     *fpi;
 6201:         FATFS          *fs;
 6202:         ER             err;
 6203: 
 6204:         (void)exinf;
 6205: 
 6206:         fpi = (FAT_FSInfo *)coninf->fimpinf->fimpsd;
 6207: 
 6208:         /* Alloc FAT Information memory */
 6209:         if ((fs = fimp_calloc(1, sizeof(FATFS))) == NULL) {
 6210:                 err = EX_NOMEM;
 6211:                 goto exit0;
 6212:         }
 6213: 
 6214:         /* Open device */
 6215:         err = fatDiskOpen(coninf, fs);
 6216:         if (err < E_OK) goto exit1;
 6217: 
 6218:         /* Check boot sector and calc number of free cluster */
 6219:         err = fatCheckFileSystem(fs);
 6220:         if (err < E_OK) goto exit2;
 6221: 
 6222:         /* Initialize Disk cache */
 6223:         err = fatDCacheInit(fs);
 6224:         if (err < E_OK) goto exit2;
 6225: 
 6226:         /* Initialize FAT map */
 6227:         err = fatMapFATInit(fs);
 6228:         if (err < E_OK) goto exit3;
 6229: 
 6230:         /* Count of the number of empty clusters */
 6231:         err = fatCountFreeCluster(fs, &fs->ff_freecl);
 6232:         if (err < E_OK) goto exit4;
 6233: 
 6234:         /* Get file number of root directory */
 6235:         fs->ff_c.fs_rootino = dirINO(fs, fs->ff_rootcl);
 6236: 
 6237:         /* Get device number */
 6238:         err = fatGetDeviceNumber(coninf->devnm, &fs->ff_c.fs_devnum);
 6239:         if (err < E_OK) goto exit4;
 6240: 
 6241:         /* Initialize uxinfo */
 6242:         err = fatUxinfoInit(fs);
 6243:         if (err < E_OK) goto exit5;
 6244: 
 6245:         /* Create kernel objects */
 6246:         err = fatCreateObjects(fs);
 6247: 
 6248: exit5:
 6249:         if (err < E_OK) {
 6250:                 fatUxinfoCleanup(fs);
 6251:         }
 6252: exit4:
 6253:         if (err < E_OK) {
 6254:                 fatMapFATCleanup(fs);
 6255:         }
 6256: exit3:
 6257:         if (err < E_OK) {
 6258:                 fatDCacheCleanup(fs);
 6259:         }
 6260: exit2:
 6261:         if (err < E_OK) {
 6262:                 fatDiskClose(coninf, fs);
 6263:         }
 6264: 
 6265:         if (err >= E_OK) {
 6266:                 /* Set dflags */
 6267:                 if (fs->ff_c.fs_diskinfo.protect != 0) {
 6268:                         coninf->dflags |= DEV_FLAG_READONLY;
 6269:                 }
 6270:                 if (fs->ff_c.fs_diskinfo.removable != 0) {
 6271:                         coninf->dflags |= DEV_FLAG_REMOVABLE;
 6272:                 }
 6273:                 coninf->consd = (void *)fs;
 6274:                 fs->ff_c.fs_coninf = coninf;
 6275:                 fs->ff_c.fs_conlen = strlen(coninf->connm) + 1;
 6276:                                                 /* + 1 : '/' <connm>  */
 6277:                 /* Insert FAT attach queue */
 6278:                 QueInsert(&fs->ff_c.fs_q, &fpi->fpi_attachque);
 6279:         }
 6280: exit1:
 6281:         if (err < E_OK) {
 6282:                 fimp_free(fs);
 6283:         }
 6284: exit0:
 6285:         return toEXER(err);
 6286: }
 6287: 
 6288: /*
 6289:  *  FATFS FIMP detach function
 6290:  */
 6291: LOCAL   ER        fatfs_detachfn(coninf_t *coninf)
 6292: {
 6293:         FATFS  *fs;
 6294:         FATNODE        *rootinode;
 6295:         ER     err;
 6296: 
 6297:         fs = (FATFS *)coninf->consd;
 6298:         rootinode = NULL;
 6299: 
 6300:         (void)fatGetRootINODE(fs, &rootinode);
 6301:         fatInodeRegister((FS *)fs, (INODE *)rootinode, O_RDONLY);
 6302:         fatInodeRelease((FS *)fs, (INODE *)
 6303:                         fs->ff_c.fs_uxinfo.uxi_curdir.cd_inode, O_RDONLY);
 6304:         fs->ff_c.fs_uxinfo.uxi_curdir.cd_inode = (INODE *)rootinode;
 6305: 
 6306:         err = fatInodeCheckEmpty(&fs->ff_c, (INODE *)rootinode);
 6307:         if (err >= E_OK) {
 6308:                 /* Remove from queue */
 6309:                 QueRemove(&fs->ff_c.fs_q);
 6310: 
 6311:                 /* Cleanup */
 6312:                 fatUxinfoCleanup(fs);
 6313:                 fatDeleteObjects(fs);
 6314:                 fatMapFATCleanup(fs);
 6315:                 fatDCacheCleanup(fs);
 6316:                 fatDiskClose(coninf, fs);
 6317:                 fimp_free(fs);
 6318:                 coninf->consd = NULL;
 6319:         }
 6320:         return err;
 6321: }
 6322: 
 6323: /*
 6324:  *  FATFS FIMP break function
 6325:  */
 6326: LOCAL   ER        fatfs_breakfn(coninf_t *coninf, ID tskid, BOOL set)
 6327: {
 6328:         FATFS  *fs;
 6329:         TaskSts        *tsksts;
 6330: 
 6331:         fs = (FATFS *)coninf->consd;
 6332:         tsksts = &tskStsTab[tskid];
 6333: 
 6334:         /* Disable dispatch to ensure atomic operations
 6335:                                         when called in task context */
 6336:         tk_dis_dsp();
 6337:         if (set != FALSE) {
 6338:                 if (tsksts->c.break_enb != 0) {
 6339:                         /* Already enabled, do break and set done flag */
 6340:                         tsksts->c.break_done = 1;
 6341:                 } else {
 6342:                         /* Not yet enabled, set req flag */
 6343:                         tsksts->c.break_req = 1;
 6344:                 }
 6345:         } else {
 6346:                 /* Clear break req, done and enb flag */
 6347:                 tsksts->w = 0;
 6348:         }
 6349:         tk_ena_dsp();
 6350: 
 6351:         return E_OK;
 6352: }
 6353: