fat_out.c
上传用户:yj_qqy
上传日期:2017-01-28
资源大小:2911k
文件大小:17k
源码类别:

uCOS

开发平台:

C/C++

  1. /*
  2. **********************************************************************
  3. *                          Micrium, Inc.
  4. *                      949 Crestview Circle
  5. *                     Weston,  FL 33327-1848
  6. *
  7. *                            uC/FS
  8. *
  9. *             (c) Copyright 2001 - 2003, Micrium, Inc.
  10. *                      All rights reserved.
  11. *
  12. ***********************************************************************
  13. ----------------------------------------------------------------------
  14. File        : fat_out.c
  15. Purpose     : FAT12/FAT16/FAT32 Filesystem file write routines
  16. ----------------------------------------------------------------------
  17. Known problems or limitations with current version
  18. ----------------------------------------------------------------------
  19. None.
  20. ---------------------------END-OF-HEADER------------------------------
  21. */
  22. /*********************************************************************
  23. *
  24. *             #include Section
  25. *
  26. **********************************************************************
  27. */
  28. #include "fs_conf.h"
  29. #include "fs_port.h"
  30. #ifndef FS_FARCHARPTR
  31.   #define FS_FARCHARPTR char *
  32. #endif
  33. #ifndef FS_FAT_FWRITE_UPDATE_DIR
  34.   #define FS_FAT_FWRITE_UPDATE_DIR 1
  35. #endif
  36. #include "fs_dev.h"
  37. #include "fs_api.h"
  38. #include "fs_fsl.h"
  39. #include "fs_int.h"
  40. #include "fs_os.h"
  41. #include "fs_lbl.h"
  42. #include "fs_fat.h"
  43. #include "fs_clib.h"
  44. /*********************************************************************
  45. *
  46. *             Local functions
  47. *
  48. **********************************************************************
  49. */
  50. /*********************************************************************
  51. *
  52. *             _FS_fat_write_dentry
  53. *
  54.   Description:
  55.   FS internal function. Write a directory entry.
  56.   Parameters:
  57.   Idx         - Index of device in the device information table 
  58.                 referred by FS__pDevInfo.
  59.   Unit        - Unit number.
  60.   FirstClust  - First cluster of the file, which's directory entry 
  61.                 will be written.
  62.   pDirEntry   - Pointer to an FS__fat_dentry_type structure, which 
  63.                 contains the new directory entry.
  64.   DirSec      - Sector, which contains the directory entry.
  65.   pBuffer     - Pointer to a buffer, which contains the sector with 
  66.                 the old directory entry.
  67.  
  68.   Return value:
  69.   ==1         - Directory entry has been written.
  70.   ==0         - An error has occured.
  71. */
  72. static int _FS_fat_write_dentry(int Idx, FS_u32 Unit, FS_u32 FirstClust, FS__fat_dentry_type *pDirEntry, 
  73.                                 FS_u32 DirSec, char *pBuffer) {
  74.   FS__fat_dentry_type *s;
  75.   FS_u32 value;
  76.   int err;
  77.   if (DirSec == 0) {
  78.     return 0;  /* Not a valid directory sector */
  79.   }
  80.   if (pBuffer == 0) {
  81.     return 0;  /* No buffer */
  82.   }
  83.   /* Scan for the directory entry with FirstClust in the directory sector */
  84.   s = (FS__fat_dentry_type*)pBuffer;
  85.   while (1) {
  86.     if (s >= (FS__fat_dentry_type*)(pBuffer + FS_FAT_SEC_SIZE)) {
  87.       break;  /* End of sector reached */
  88.     }
  89.     value = (FS_u32)s->data[26] + 0x100UL * s->data[27] + 0x10000UL * s->data[20] + 0x1000000UL * s->data[21];
  90.     if (value == FirstClust) {
  91.       break;  /* Entry found */
  92.     }
  93.     s++;
  94.   }
  95.   if (s < (FS__fat_dentry_type*)(pBuffer + FS_FAT_SEC_SIZE)) {
  96.     if (pDirEntry) {
  97.       FS__CLIB_memcpy(s, pDirEntry, sizeof(FS__fat_dentry_type));
  98.       err = FS__lb_write(FS__pDevInfo[Idx].devdriver, Unit, DirSec, (void*)pBuffer);
  99.       if (err < 0) {
  100.         return 0;
  101.       }
  102.     }
  103.     return 1;
  104.   }
  105.   return 0;
  106. }
  107. /*********************************************************************
  108. *
  109. *             _FS_fat_read_dentry
  110. *
  111.   Description:
  112.   FS internal function. Read a directory entry.
  113.   Parameters:
  114.   Idx         - Index of device in the device information table 
  115.                 referred by FS__pDevInfo.
  116.   Unit        - Unit number.
  117.   FirstClust  - First cluster of the file, which's directory entry 
  118.                 will be read.
  119.   DirStart    - Start of directory, where to read the entry.
  120.   pDirEntry   - Pointer to an FS__fat_dentry_type structure, which is 
  121.                 used to read the directory entry.
  122.   pDirSec     - Pointer to an FS_u32, which is used to store the sector
  123.                 number, in which the directory entry has been read.
  124.   pBuffer     - Pointer to a buffer, which is used for reading the
  125.                 directory.
  126.  
  127.   Return value:
  128.   ==1         - Directory entry has been read.
  129.   ==0         - An error has occured.
  130. */
  131. static int _FS_fat_read_dentry(int Idx, FS_u32 Unit, FS_u32 FirstClust, 
  132.                               FS_u32 DirStart, FS__fat_dentry_type *pDirEntry, FS_u32 *pDirSec, char *pBuffer) {
  133.   FS_u32 i;
  134.   FS_u32 dsize;
  135.   FS_u32 value;
  136.   FS__fat_dentry_type *s;
  137.   int err;
  138.   if (pBuffer == 0) {
  139.     return 0;
  140.   }
  141.   dsize  =  FS__fat_dir_size(Idx, Unit, DirStart);
  142.   /* Read the directory */
  143.   for (i = 0; i < dsize; i++) {
  144.     *pDirSec = FS__fat_dir_realsec(Idx, Unit, DirStart, i);
  145.     if (*pDirSec == 0) {
  146.       return 0;  /* Unable to translate relative directory sector to absolute setor */
  147.     }
  148.     err = FS__lb_read(FS__pDevInfo[Idx].devdriver, Unit, *pDirSec, (void*)pBuffer);
  149.     if (err < 0) {
  150.       return 0;
  151.     }
  152.     /* Scan for entry with FirstClus in the sector */
  153.     s = (FS__fat_dentry_type*)pBuffer;
  154.     while (1) {
  155.       if (s >= (FS__fat_dentry_type*)(pBuffer + FS_FAT_SEC_SIZE)) {
  156.         break;  /* End of sector reached */
  157.       }
  158.       value = (FS_u32)s->data[26] + 0x100UL * s->data[27] + 0x10000UL * s->data[20] + 0x1000000UL * s->data[21];
  159.       if (value == FirstClust) {
  160.         break;  /* Entry found */
  161.       }
  162.       s++;
  163.     }
  164.     if (s < (FS__fat_dentry_type*)(pBuffer + FS_FAT_SEC_SIZE)) {
  165.       if (pDirEntry) {
  166.         /* Read the complete directory entry from the buffer */
  167.         FS__CLIB_memcpy(pDirEntry, s, sizeof(FS__fat_dentry_type));
  168.       }
  169.       return 1;
  170.     }
  171.   }
  172.   return 0;
  173. }
  174. /*********************************************************************
  175. *
  176. *             Global functions
  177. *
  178. **********************************************************************
  179. */
  180. /*********************************************************************
  181. *
  182. *             FS__fat_fwrite
  183. *
  184.   Description:
  185.   FS internal function. Write data to a file.
  186.   Parameters:
  187.   pData       - Pointer to data, which will be written to the file. 
  188.   Size        - Size of an element to be transferred to a file.
  189.   N           - Number of elements to be transferred to the file.
  190.   pFile       - Pointer to a FS_FILE data structure.
  191.   
  192.   Return value:
  193.   Number of elements written.
  194. */
  195. FS_size_t FS__fat_fwrite(const void *pData, FS_size_t Size, FS_size_t N, FS_FILE *pFile) {
  196.   FS_size_t todo;
  197.   FS_u32 dstart;
  198.   FS_u32 dsize;
  199.   FS_u32 bytesperclus;
  200.   FS_u32 datastart;
  201.   FS_u32 fatsize;
  202.   FS_u32 fileclustnum;
  203.   FS_u32 diskclustnum;
  204.   FS_u32 prevclust;
  205.   FS_i32 last;
  206.   FS_i32 i;
  207.   FS_i32 j;
  208. #if (FS_FAT_FWRITE_UPDATE_DIR)
  209.   FS__fat_dentry_type s;
  210.   FS_u32 dsec = 0;
  211.   FS_u16 val;
  212. #endif /* FS_FAT_FWRITE_UPDATE_DIR */
  213.   int err;
  214.   int lexp;
  215.   char *buffer;
  216.   if (!pFile) {
  217.       return 0;
  218.   }
  219.   /* Check if media is OK */
  220.   err = FS__lb_status(FS__pDevInfo[pFile->dev_index].devdriver, pFile->fileid_lo);
  221.   if (err == FS_LBL_MEDIACHANGED) {
  222.     pFile->error = FS_ERR_DISKCHANGED;
  223.     return 0;
  224.   }
  225.   else if (err < 0) {
  226.     pFile->error = FS_ERR_WRITEERROR;
  227.     return 0;
  228.   }
  229.   buffer = FS__fat_malloc(FS_FAT_SEC_SIZE);
  230.   if (!buffer) {
  231.     return 0;
  232.   }
  233.   fatsize = FS__FAT_aBPBUnit[pFile->dev_index][pFile->fileid_lo].FATSz16;
  234.   if (fatsize == 0) {
  235.     /* FAT32 */
  236.     fatsize = FS__FAT_aBPBUnit[pFile->dev_index][pFile->fileid_lo].FATSz32;
  237.   }
  238.   todo = N * Size;  /* Number of bytes to be written */
  239.   if (!todo) {
  240.     FS__fat_free(buffer);
  241.     return 0;
  242.   }
  243.   /* Alloc new clusters if required */
  244.   bytesperclus = (FS_u32)FS__FAT_aBPBUnit[pFile->dev_index][pFile->fileid_lo].SecPerClus *
  245.                  ((FS_u32)FS__FAT_aBPBUnit[pFile->dev_index][pFile->fileid_lo].BytesPerSec);
  246.   /* Calculate number of clusters required */
  247.   i = (pFile->filepos + todo) / bytesperclus;
  248.   if ((pFile->filepos + todo) % bytesperclus) {
  249.     i++;
  250.   }
  251.   /* Calculate clusters already allocated */
  252.   j = pFile->size / bytesperclus;
  253.   lexp = (pFile->size % bytesperclus);
  254.   lexp = lexp || (pFile->size == 0);
  255.   if (lexp) {
  256.     j++;
  257.   }
  258.   i -= j;
  259.   if (i > 0) {
  260.     /* Alloc new clusters */
  261.     last = pFile->EOFClust;
  262.     if (last < 0) {
  263.       /* Position of EOF is unknown, so we scan the whole file to find it */
  264.       last = FS__fat_FAT_find_eof(pFile->dev_index, pFile->fileid_lo, pFile->fileid_hi, 0);
  265.     }
  266.     if (last < 0) {
  267.       /* No EOF found */
  268.       FS__fat_free(buffer);
  269.       return 0;
  270.     }
  271.     while (i) {
  272.       last = FS__fat_FAT_alloc(pFile->dev_index, pFile->fileid_lo, last);  /* Allocate new cluster */
  273.       pFile->EOFClust = last;
  274.       if (last < 0) {
  275.         /* Cluster allocation failed */
  276.         pFile->size += (N * Size - todo);
  277.         pFile->error = FS_ERR_DISKFULL;
  278.         FS__fat_free(buffer);
  279.         return ((N * Size - todo) / Size);
  280.       }
  281.       i--;
  282.     }
  283.   }
  284.   /* Get absolute postion of data area on the media */
  285.   dstart    = (FS_u32)FS__FAT_aBPBUnit[pFile->dev_index][pFile->fileid_lo].RsvdSecCnt + 
  286.               FS__FAT_aBPBUnit[pFile->dev_index][pFile->fileid_lo].NumFATs * fatsize;
  287.   dsize     = ((FS_u32)((FS_u32)FS__FAT_aBPBUnit[pFile->dev_index][pFile->fileid_lo].RootEntCnt) * FS_FAT_DENTRY_SIZE) / FS_FAT_SEC_SIZE;
  288.   datastart = dstart + dsize;
  289.   /* Write data to clusters */
  290.   prevclust = 0;
  291.   while (todo) {  /* Write data loop */
  292.     /* Translate file ppinter position to cluster position*/
  293.     fileclustnum = pFile->filepos / bytesperclus;
  294.     /* 
  295.        Translate the file relative cluster position to an absolute cluster
  296.        position on the media. To avoid scanning the whole FAT of the file,
  297.        we remember the current cluster position in the FS_FILE data structure.
  298.     */
  299.     if (prevclust == 0) {
  300.       diskclustnum = pFile->CurClust;
  301.       if (diskclustnum == 0) {
  302.         /* No known current cluster position, we have to scan from the file's start cluster */
  303.         diskclustnum = FS__fat_diskclust(pFile->dev_index, pFile->fileid_lo, pFile->fileid_hi, fileclustnum);
  304.       }
  305.     } 
  306.     else {
  307.       /* Get next cluster of the file starting at the current cluster */
  308.       diskclustnum = FS__fat_diskclust(pFile->dev_index, pFile->fileid_lo, prevclust, 1);
  309.     }
  310.     prevclust        = diskclustnum;
  311.     pFile->CurClust  = diskclustnum;
  312.     if (diskclustnum == 0) {
  313.       /* Translation to absolute cluster failed */
  314.       pFile->error = FS_ERR_WRITEERROR;
  315.       FS__fat_free(buffer);
  316.       return ((N * Size - todo) / Size);
  317.     }
  318.     diskclustnum -= 2;
  319.     j = (pFile->filepos % bytesperclus) / FS_FAT_SEC_SIZE;
  320.     while (1) {  /* Cluster loop */
  321.       if (!todo) {
  322.         break;  /* Nothing more to write */
  323.       }
  324.       if (j >= FS__FAT_aBPBUnit[pFile->dev_index][pFile->fileid_lo].SecPerClus) {
  325.         break; /* End of cluster reached */
  326.       }
  327.       i = pFile->filepos % FS_FAT_SEC_SIZE;
  328.       /* 
  329.          We only have to read the sector from the media, if we do not
  330.          modify the whole sector. That is the case if
  331.          a) Writing starts not at the first byte of the sector
  332.          b) Less data than the sector contains is written
  333.       */
  334.       lexp = (i != 0);
  335.       lexp = lexp || (todo < FS_FAT_SEC_SIZE);
  336.       if (lexp) {
  337.         /* We have to read the old sector */
  338.         err = FS__lb_read(FS__pDevInfo[pFile->dev_index].devdriver, pFile->fileid_lo,
  339.                       datastart +
  340.                       diskclustnum * FS__FAT_aBPBUnit[pFile->dev_index][pFile->fileid_lo].SecPerClus + j,
  341.                       (void*)buffer);
  342.         if (err < 0) {
  343.           pFile->error = FS_ERR_WRITEERROR;
  344.           FS__fat_free(buffer);
  345.           return ((N * Size - todo) / Size);
  346.         }
  347.       }
  348.       while (1) {  /* Sector loop */
  349.         if (!todo) {
  350.           break;  /* Nothing more to write */
  351.         }
  352.         if (i >= FS_FAT_SEC_SIZE) {
  353.           break;  /* End of sector reached */
  354.         }
  355.         buffer[i] = *((FS_FARCHARPTR)(((FS_FARCHARPTR)pData) + N * Size - todo));
  356.         i++;
  357.         pFile->filepos++;
  358.         if (pFile->filepos > pFile->size) {
  359.           pFile->size = pFile->filepos;
  360.         }
  361.         todo--;
  362.       }  /* Sector loop */
  363.       /* Write the modified sector */
  364.       err = FS__lb_write(FS__pDevInfo[pFile->dev_index].devdriver, pFile->fileid_lo,
  365.                     datastart +
  366.                     diskclustnum * FS__FAT_aBPBUnit[pFile->dev_index][pFile->fileid_lo].SecPerClus + j,
  367.                     (void*)buffer);
  368.       if (err < 0) {
  369.         pFile->error = FS_ERR_WRITEERROR;
  370.         FS__fat_free(buffer);
  371.         return ((N * Size - todo) / Size);
  372.       }
  373.       j++;
  374.     }  /* Cluster loop */
  375.   } /* Write data loop */
  376.   if (i >= FS_FAT_SEC_SIZE) {
  377.     if (j >= FS__FAT_aBPBUnit[pFile->dev_index][pFile->fileid_lo].SecPerClus) {
  378.       /* File pointer is already in the next cluster */
  379.       pFile->CurClust = FS__fat_diskclust(pFile->dev_index, pFile->fileid_lo, prevclust, 1);
  380.     }
  381.   }
  382. #if (FS_FAT_FWRITE_UPDATE_DIR)
  383.   /* Modify directory entry */
  384.   err = _FS_fat_read_dentry(pFile->dev_index, pFile->fileid_lo, pFile->fileid_hi, pFile->fileid_ex, &s, &dsec, buffer);
  385.   if (err == 0) {
  386.     pFile->error = FS_ERR_WRITEERROR;
  387.     FS__fat_free(buffer);
  388.     return ((N * Size - todo) / Size);
  389.   }
  390.   s.data[28] = (unsigned char)(pFile->size & 0xff);   /* FileSize */
  391.   s.data[29] = (unsigned char)((pFile->size / 0x100UL) & 0xff);   
  392.   s.data[30] = (unsigned char)((pFile->size / 0x10000UL) & 0xff);
  393.   s.data[31] = (unsigned char)((pFile->size / 0x1000000UL) & 0xff);
  394.   val = FS_X_OS_GetTime();
  395.   s.data[22] = (unsigned char)(val & 0xff);
  396.   s.data[23] = (unsigned char)((val / 0x100) & 0xff);
  397.   val = FS_X_OS_GetDate();
  398.   s.data[24] = (unsigned char)(val & 0xff);
  399.   s.data[25] = (unsigned char)((val / 0x100) & 0xff);
  400.   err = _FS_fat_write_dentry(pFile->dev_index, pFile->fileid_lo, pFile->fileid_hi, &s, dsec, buffer);
  401.   if (err == 0) {
  402.     pFile->error = FS_ERR_WRITEERROR;
  403.   }
  404. #endif /* FS_FAT_FWRITE_UPDATE_DIR */
  405.   FS__fat_free(buffer);
  406.   return ((N * Size - todo) / Size);
  407. }
  408. /*********************************************************************
  409. *
  410. *             FS__fat_fclose
  411. *
  412.   Description:
  413.   FS internal function. Close a file referred by pFile.
  414.   Parameters:
  415.   pFile       - Pointer to a FS_FILE data structure. 
  416.   
  417.   Return value:
  418.   None.
  419. */
  420. void FS__fat_fclose(FS_FILE *pFile) {
  421. #if (FS_FAT_FWRITE_UPDATE_DIR==0)
  422.   FS__fat_dentry_type s;
  423.   char *buffer;
  424.   FS_u32 dsec;
  425.   FS_u16 val;
  426. #endif /* FS_FAT_FWRITE_UPDATE_DIR */
  427.   int err;
  428.   if (!pFile) {
  429.       return;
  430.   }
  431.   /* Check if media is OK */
  432.   err = FS__lb_status(FS__pDevInfo[pFile->dev_index].devdriver, pFile->fileid_lo);
  433.   if (err == FS_LBL_MEDIACHANGED) {
  434.     pFile->error = FS_ERR_DISKCHANGED;
  435.     FS__lb_ioctl(FS__pDevInfo[pFile->dev_index].devdriver, pFile->fileid_lo, FS_CMD_DEC_BUSYCNT, 0, (void*)0);  /* Turn off busy signal */
  436.     pFile->inuse = 0;
  437.     return;
  438.   }
  439.   else if (err < 0) {
  440.     pFile->error = FS_ERR_CLOSE;
  441.     FS__lb_ioctl(FS__pDevInfo[pFile->dev_index].devdriver, pFile->fileid_lo, FS_CMD_DEC_BUSYCNT, 0, (void*)0);  /* Turn off busy signal */
  442.     pFile->inuse = 0;
  443.     return;
  444.   }
  445. #if (FS_FAT_FWRITE_UPDATE_DIR==0)
  446.   /* Modify directory entry */
  447.   buffer = FS__fat_malloc(FS_FAT_SEC_SIZE);
  448.   if (!buffer) {
  449.     pFile->inuse = 0;
  450.     pFile->error = FS_ERR_CLOSE;
  451.     return;
  452.   }
  453.   err = _FS_fat_read_dentry(pFile->dev_index, pFile->fileid_lo, pFile->fileid_hi, pFile->fileid_ex, &s, &dsec, buffer);
  454.   if (err == 0) {
  455.     pFile->inuse = 0;
  456.     pFile->error = FS_ERR_CLOSE;
  457.     FS__fat_free(buffer);
  458.     return;
  459.   }
  460.   s.data[28] = (unsigned char)(pFile->size & 0xff);   /* FileSize */
  461.   s.data[29] = (unsigned char)((pFile->size / 0x100UL) & 0xff);   
  462.   s.data[30] = (unsigned char)((pFile->size / 0x10000UL) & 0xff);
  463.   s.data[31] = (unsigned char)((pFile->size / 0x1000000UL) & 0xff);
  464.   val = FS_X_OS_GetTime();
  465.   s.data[22] = (unsigned char)(val & 0xff);
  466.   s.data[23] = (unsigned char)((val / 0x100) & 0xff);
  467.   val = FS_X_OS_GetDate();
  468.   s.data[24] = (unsigned char)(val & 0xff);
  469.   s.data[25] = (unsigned char)((val / 0x100) & 0xff);
  470.   err = _FS_fat_write_dentry(pFile->dev_index, pFile->fileid_lo, pFile->fileid_hi, &s, dsec, buffer);
  471.   if (err == 0) {
  472.     pFile->error = FS_ERR_CLOSE;
  473.   }
  474.   FS__fat_free(buffer);
  475. #endif /* FS_FAT_FWRITE_UPDATE_DIR */
  476.   err = FS__lb_ioctl(FS__pDevInfo[pFile->dev_index].devdriver, pFile->fileid_lo, FS_CMD_FLUSH_CACHE, 2, (void*)0);
  477.   if (err < 0) {
  478.     pFile->error = FS_ERR_WRITEERROR;
  479.   }
  480.   pFile->inuse = 0;
  481.   FS__lb_ioctl(FS__pDevInfo[pFile->dev_index].devdriver, pFile->fileid_lo, FS_CMD_DEC_BUSYCNT, 0, (void*)0);  /* Turn off busy signal */
  482. }