Changeset 5ed41a6 in rtems


Ignore:
Timestamp:
Mar 14, 2017, 10:41:18 AM (2 years ago)
Author:
Sebastian Huber <sebastian.huber@…>
Branches:
4.11
Children:
49eb6061
Parents:
58e8131
git-author:
Sebastian Huber <sebastian.huber@…> (03/14/17 10:41:18)
git-committer:
Sebastian Huber <sebastian.huber@…> (03/21/17 15:15:04)
Message:

dosfs: Fix msdos_add_file()

Make sure that long file names work accross cluster boundaries.

Close #2929.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • cpukit/libfs/src/dosfs/msdos_misc.c

    r58e8131 r5ed41a6  
    117117 */
    118118static void
    119 msdos_short_name_hex(char* sfn, int num)
     119msdos_short_name_hex(char* sfn, uint32_t num)
    120120{
    121121    static const char* hex = "0123456789ABCDEF";
     
    10201020    char                                 *entry,
    10211021    fat_dir_pos_t                        *dir_pos,
    1022     uint32_t                             *dir_offset,
     1022    uint32_t                              dir_offset,
    10231023    const uint32_t                        dir_entry,
    10241024    const fat_pos_t                      *lfn_start
     
    10361036                        fat_fd,
    10371037                        F_CLU_NUM,
    1038                         *dir_offset * bts2rd,
     1038                        dir_offset * bts2rd,
    10391039                        &dir_pos->sname.cln);
    10401040    if (rc == RC_OK) {
     
    13011301    char                                 *name_dir_entry,
    13021302    fat_dir_pos_t                        *dir_pos,
    1303     uint32_t                             *dir_offset,
    1304     uint32_t                             *empty_space_offset,
    1305     uint32_t                             *empty_space_entry,
    1306     uint32_t                             *empty_space_count)
     1303    uint32_t                             *empty_file_offset,
     1304    uint32_t                             *empty_entry_count)
    13071305{
    13081306    int               rc                = RC_OK;
     
    13201318    ssize_t           filename_size_remaining = name_len_for_compare;
    13211319    rtems_dosfs_convert_control *converter = fs_info->converter;
     1320    uint32_t          dir_offset = 0;
    13221321
    13231322    /*
     
    13291328    lfn_start.cln = lfn_start.ofs = FAT_FILE_SHORT_NAME;
    13301329
    1331     while (   (bytes_read = fat_file_read (&fs_info->fat, fat_fd, (*dir_offset * bts2rd),
     1330    while (   (bytes_read = fat_file_read (&fs_info->fat, fat_fd, (dir_offset * bts2rd),
    13321331                                             bts2rd, fs_info->cl_buf)) != FAT_EOF
    13331332           && rc == RC_OK)
     
    13351334        bool remainder_empty = false;
    13361335#if MSDOS_FIND_PRINT
    1337         printf ("MSFS:[2] dir_offset:%li\n", *dir_offset);
     1336        printf ("MSFS:[2] dir_offset:%li\n", dir_offset);
    13381337#endif
    13391338
     
    13601359#if MSDOS_FIND_PRINT
    13611360            printf ("MSFS:[3] re:%i ee:%i do:%li de:%li(%ld)\n",
    1362                     remainder_empty, entry_empty, *dir_offset,
     1361                    remainder_empty, entry_empty, dir_offset,
    13631362                    dir_entry, (dir_entry / MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE));
    13641363#endif
     
    13661365             * Remember where the we are, ie the start, so we can come back
    13671366             * to here and write the long file name if this is the start of
    1368              * a series of empty entries. If empty_space_count is 0 then
     1367             * a series of empty entries. If empty_entry_count is 0 then
    13691368             * we are currently not inside an empty series of entries. It
    13701369             * is a count of empty entries.
    13711370             */
    1372             if (*empty_space_count == 0)
     1371            if (*empty_entry_count == 0)
    13731372            {
    1374                 *empty_space_entry = dir_entry;
    1375                 *empty_space_offset = *dir_offset;
     1373                *empty_file_offset = dir_offset * bts2rd + dir_entry;
    13761374            }
    13771375
     
    13971395                    && rc == RC_OK )
    13981396                {
    1399                     *empty_space_count +=
     1397                    *empty_entry_count +=
    14001398                    entries_per_block - (dir_entry / MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
    14011399                    empty_space_found = true;
    14021400#if MSDOS_FIND_PRINT
    1403                     printf ( "MSFS:[3.2] esf:%i esc%"PRIu32"\n", empty_space_found, *empty_space_count );
     1401                    printf ( "MSFS:[3.2] esf:%i esc%"PRIu32"\n", empty_space_found, *empty_entry_count );
    14041402#endif
    14051403                }
     
    14131411                     * Remainder is not empty so is this entry empty ?
    14141412                     */
    1415                     (*empty_space_count)++;
    1416 
    1417                     if (*empty_space_count == (fat_entries + 1))
     1413                    (*empty_entry_count)++;
     1414
     1415                    if (*empty_entry_count == (fat_entries + 1))
    14181416                        empty_space_found = true;
    14191417                }
    14201418#if MSDOS_FIND_PRINT
    14211419                printf ("MSFS:[4.1] esc:%li esf:%i\n",
    1422                         *empty_space_count, empty_space_found);
     1420                        *empty_entry_count, empty_space_found);
    14231421#endif
    14241422            }
     
    14331431                if (create_node && !empty_space_found)
    14341432                {
    1435                     *empty_space_entry = 0;
    1436                     *empty_space_count = 0;
     1433                    *empty_file_offset = 0;
     1434                    *empty_entry_count = 0;
    14371435                }
    14381436
     
    14811479                         * Get the checksum of the short entry.
    14821480                         */
    1483                         lfn_start.cln = *dir_offset;
     1481                        lfn_start.cln = dir_offset;
    14841482                        lfn_start.ofs = dir_entry;
    14851483                        lfn_entry = fat_entries;
     
    16221620            break;
    16231621
    1624         (*dir_offset)++;
     1622        dir_offset++;
    16251623    }
    16261624    if ( ! filename_matched ) {
     
    16321630
    16331631#if MSDOS_FIND_PRINT
    1634         printf ( "MSFS:[8.1] WRITE do:%"PRIu32" esc:%"PRIu32" eso:%"PRIu32" ese:%"PRIu32"\n",
    1635                  *dir_offset, *empty_space_count, *empty_space_offset, *empty_space_entry );
     1632        printf ( "MSFS:[8.1] WRITE do:%"PRIu32" esc:%"PRIu32" efo:%"PRIu32"\n",
     1633                 dir_offset, *empty_entry_count, *empty_file_offset );
    16361634#endif
    16371635    }
    16381636
    16391637    return rc;
     1638}
     1639
     1640static int
     1641msdos_get_pos(
     1642    msdos_fs_info_t *fs_info,
     1643    fat_file_fd_t   *fat_fd,
     1644    uint32_t         bts2rd,
     1645    uint32_t         file_offset,
     1646    fat_pos_t       *pos
     1647)
     1648{
     1649    pos->ofs = file_offset & (bts2rd - 1);
     1650    return fat_file_ioctl(&fs_info->fat, fat_fd, F_CLU_NUM,
     1651                          file_offset, &pos->cln);
    16401652}
    16411653
     
    16501662    const char                           *name_dir_entry,
    16511663    fat_dir_pos_t                        *dir_pos,
    1652     const uint32_t                        dir_offset,
    1653     uint32_t                              empty_space_offset,
    1654     uint32_t                              empty_space_entry,
    1655     const uint32_t                        empty_space_count
    1656 
     1664    uint32_t                              empty_file_offset,
     1665    const uint32_t                        empty_entry_count
    16571666)
    16581667{
    1659     int              ret                = 0;
    1660     ssize_t          bytes_written      = 0;
    1661     uint8_t          lfn_checksum       = 0;
    1662     bool             read_cluster       = false;
    1663     int              lfn_entry          = 0;
    1664     fat_pos_t        lfn_start;
    1665     uint32_t         dir_entry;
     1668    int              ret;
     1669    ssize_t          bytes_written;
     1670    uint8_t          lfn_checksum;
     1671    int              lfn_entry;
     1672    uint8_t         *entry;
     1673    uint32_t         short_file_offset;
     1674    uint32_t         length;
    16661675
    16671676    /*
    1668      * If a long file name calculate the checksum of the short file name
    1669      * data to place in each long file name entry. First set the short
    1670      * file name to the slot of the SFN entry. This will mean no clashes
    1671      * in this directory.
     1677     * If there is not enough space available then extend the file.
    16721678     */
     1679    if (empty_entry_count < fat_entries + 1)
     1680    {
     1681        uint32_t unused;
     1682
     1683        empty_file_offset = fat_fd->fat_file_size -
     1684            empty_entry_count * MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE;
     1685
     1686        ret = fat_file_extend(&fs_info->fat,
     1687                              fat_fd,
     1688                              true,
     1689                              fat_fd->fat_file_size + fs_info->fat.vol.bpc,
     1690                              &unused);
     1691        if (ret != RC_OK)
     1692            return ret;
     1693    }
     1694
    16731695    if (name_type == MSDOS_NAME_LONG)
    16741696    {
    1675         int      slot = (((empty_space_offset * bts2rd) + empty_space_entry) /
    1676                         MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE) + fat_entries + 1;
     1697        uint32_t slot;
     1698
     1699        /*
     1700         * If a long file name calculate the checksum of the short file name
     1701         * data to place in each long file name entry. First set the short
     1702         * file name to the slot of the SFN entry. This will mean no clashes
     1703         * in this directory.
     1704         */
     1705        slot = (empty_file_offset /
     1706            MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE) + fat_entries + 1;
    16771707        msdos_short_name_hex(MSDOS_DIR_NAME(name_dir_entry), slot);
    1678     }
    1679 
    1680     if (fat_entries)
    1681     {
     1708
    16821709        lfn_checksum = msdos_lfn_checksum(name_dir_entry);
    1683     }
    1684 
    1685     /*
    1686      * If there is no space available then extend the file. The
    1687      * empty_space_count is a count of empty entries in the currently
    1688      * read cluster so if 0 there is no space. Note, dir_offset will
    1689      * be at the next cluster so we can just make empty_space_offset
    1690      * that value.
    1691      */
    1692     if (empty_space_count == 0)
    1693     {
    1694         read_cluster = true;
    1695         empty_space_offset = dir_offset;
    1696         empty_space_entry = 0;
    1697     }
    1698 
    1699     /*
    1700      * Have we read past the empty block ? If so go back and read it again.
    1701      */
    1702     if (dir_offset != empty_space_offset)
    1703         read_cluster = true;
     1710
     1711        short_file_offset = empty_file_offset + fat_entries
     1712            * MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE;
     1713
     1714        /* Get position of first long file name entry */
     1715        ret = msdos_get_pos(fs_info, fat_fd, bts2rd, empty_file_offset,
     1716                            &dir_pos->lname);
     1717        if (ret != RC_OK)
     1718            return ret;
     1719    } else {
     1720        lfn_checksum = 0;
     1721        short_file_offset = empty_file_offset;
     1722        dir_pos->lname.cln = FAT_FILE_SHORT_NAME;
     1723        dir_pos->lname.ofs = FAT_FILE_SHORT_NAME;
     1724    }
     1725
     1726    /* Get position of short file name entry */
     1727    ret = msdos_get_pos(fs_info, fat_fd, bts2rd, short_file_offset,
     1728                        &dir_pos->sname);
    17041729
    17051730    /*
    17061731     * Handle the entry writes.
    17071732     */
    1708     lfn_start.cln = lfn_start.ofs = FAT_FILE_SHORT_NAME;
    1709     lfn_entry = 0;
     1733    entry = fs_info->cl_buf;
    17101734
    17111735#if MSDOS_FIND_PRINT
    1712     printf ("MSFS:[9] read_cluster:%d eso:%ld ese:%ld\n",
    1713             read_cluster, empty_space_offset, empty_space_entry);
    1714 #endif
    1715 
    1716     /*
    1717      * The one more is the short entry.
    1718      */
    1719     while (lfn_entry < (fat_entries + 1))
    1720     {
    1721         int length = 0;
    1722 
    1723         if (read_cluster)
     1736    printf ("MSFS:[9] read_cluster:%d efo:%ld ese:%ld\n",
     1737            read_cluster, empty_file_offset, empty_space_entry);
     1738#endif
     1739
     1740    /* Long file name entries */
     1741    for (lfn_entry = 0; lfn_entry < fat_entries; ++lfn_entry) {
     1742        uint8_t       *p;
     1743        const uint8_t *n;
     1744        int            i;
     1745        uint8_t        fill = 0;
     1746
     1747        /*
     1748         * Clear the entry before loading the data.
     1749         */
     1750        memset (entry, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
     1751
     1752        *MSDOS_DIR_LFN_CHECKSUM(entry) = lfn_checksum;
     1753
     1754        p = entry + 1;
     1755        n = (const uint8_t *) name_converted +
     1756            (fat_entries - lfn_entry - 1) * MSDOS_LFN_ENTRY_SIZE;
     1757
     1758#if MSDOS_FIND_PRINT
     1759        printf ("MSFS:[11] ");
     1760#endif
     1761        for (i = 0; i < MSDOS_LFN_LEN_PER_ENTRY; ++i)
    17241762        {
    1725             uint32_t new_length;
     1763            if (!(*n == 0 && *(n+1) == 0))
     1764            {
     1765                *p = *n;
     1766                *(p+1) = *(n+1);
     1767            }
     1768            else
     1769            {
     1770                p [0] = fill;
     1771                p [1] = fill;
     1772                fill = 0xff;
     1773            }
     1774            n += MSDOS_NAME_LFN_BYTES_PER_CHAR;
    17261775#if MSDOS_FIND_PRINT
    1727             printf ("MSFS:[9.1] eso:%li\n", empty_space_offset);
    1728 #endif
    1729             ret = fat_file_read(&fs_info->fat, fat_fd,
    1730                                 (empty_space_offset * bts2rd), bts2rd,
    1731                                 fs_info->cl_buf);
    1732 
    1733             if (ret != bts2rd)
     1776            printf ( "'%c''%c'", *p, *(p+1) );
     1777#endif
     1778
     1779            switch (i)
    17341780            {
    1735                 if (ret != FAT_EOF)
    1736                     rtems_set_errno_and_return_minus_one(EIO);
    1737 
    1738 #if MSDOS_FIND_PRINT
    1739                 printf ("MSFS:[9.2] extending file:%li\n", empty_space_offset);
    1740 #endif
    1741                 ret = fat_file_extend (&fs_info->fat, fat_fd, false,
    1742                                        empty_space_offset * bts2rd, &new_length);
    1743 
    1744                 if (ret != RC_OK)
    1745                     return ret;
    1746 
    1747 #if MSDOS_FIND_PRINT
    1748                 printf ("MSFS:[9.3] extended: %"PRIu32" <-> %"PRIu32"\n", new_length, empty_space_offset * bts2rd);
    1749 #endif
    1750                 if (new_length != (empty_space_offset * bts2rd))
    1751                     rtems_set_errno_and_return_minus_one(EIO);
    1752 
    1753                 memset(fs_info->cl_buf, 0, bts2rd);
    1754 
    1755                 bytes_written = fat_file_write(&fs_info->fat, fat_fd,
    1756                                                empty_space_offset * bts2rd,
    1757                                                bts2rd, fs_info->cl_buf);
    1758 #if MSDOS_FIND_PRINT
    1759                 printf ("MSFS:[9.4] clear write: %d\n", ret);
    1760 #endif
    1761                 if (bytes_written == -1)
    1762                     return -1;
    1763                 else if (bytes_written != bts2rd)
    1764                     rtems_set_errno_and_return_minus_one(EIO);
     1781                case 4:
     1782                    p += 5;
     1783                    break;
     1784                case 10:
     1785                    p += 4;
     1786                    break;
     1787                default:
     1788                    p += 2;
     1789                    break;
    17651790            }
    17661791        }
    1767 
    17681792#if MSDOS_FIND_PRINT
    1769         printf ("MSFS:[10] eso:%li\n", empty_space_offset);
    1770 #endif
    1771 
    1772         for (dir_entry = empty_space_entry;
    1773              dir_entry < bts2rd;
    1774              dir_entry += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
    1775         {
    1776             char*       entry = (char*) fs_info->cl_buf + dir_entry;
    1777             char*       p;
    1778             const char* n;
    1779             int         i;
    1780             char        fill = 0;
    1781 
    1782             length += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE;
    1783             lfn_entry++;
    1784 
    1785 #if MSDOS_FIND_PRINT
    1786             printf ("MSFS:[10] de:%li(%li) length:%i lfn_entry:%i\n",
    1787                     dir_entry, (dir_entry / MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE),
    1788                     length, lfn_entry);
    1789 #endif
    1790             /*
    1791              * Time to write the short file name entry.
    1792              */
    1793             if (lfn_entry == (fat_entries + 1))
    1794             {
    1795                 /* get current cluster number */
    1796                 ret = fat_file_ioctl(&fs_info->fat, fat_fd, F_CLU_NUM,
    1797                                     empty_space_offset * bts2rd,
    1798                                     &dir_pos->sname.cln);
    1799                 if (ret != RC_OK)
    1800                     return ret;
    1801 
    1802                 dir_pos->sname.ofs = dir_entry;
    1803 
    1804                 if (lfn_start.cln != FAT_FILE_SHORT_NAME)
    1805                 {
    1806                     ret = fat_file_ioctl(&fs_info->fat, fat_fd, F_CLU_NUM,
    1807                                         lfn_start.cln * bts2rd,
    1808                                         &lfn_start.cln);
    1809                     if (ret != RC_OK)
    1810                         return ret;
    1811                 }
    1812 
    1813                 dir_pos->lname.cln = lfn_start.cln;
    1814                 dir_pos->lname.ofs = lfn_start.ofs;
    1815 
    1816                 /* write new node entry */
    1817                 memcpy (entry, (uint8_t *) name_dir_entry,
    1818                         MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
    1819                 break;
    1820             }
    1821 
    1822             /*
    1823              * This is a long file name and we need to write
    1824              * a long file name entry. See if this is the
    1825              * first entry written and if so remember the
    1826              * the location of the long file name.
    1827              */
    1828             if (lfn_start.cln == FAT_FILE_SHORT_NAME)
    1829             {
    1830                 lfn_start.cln = empty_space_offset;
    1831                 lfn_start.ofs = dir_entry;
    1832             }
    1833 
    1834             /*
    1835              * Clear the entry before loading the data.
    1836              */
    1837             memset (entry, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
    1838 
    1839             *MSDOS_DIR_LFN_CHECKSUM(entry) = lfn_checksum;
    1840 
    1841             p = entry + 1;
    1842             n = name_converted + (fat_entries - lfn_entry) * MSDOS_LFN_ENTRY_SIZE;
    1843 
    1844 #if MSDOS_FIND_PRINT
    1845             printf ("MSFS:[11] ");
    1846 #endif
    1847             for (i = 0; i < MSDOS_LFN_LEN_PER_ENTRY; ++i)
    1848             {
    1849                 if (!(*n == 0 && *(n+1) == 0))
    1850                 {
    1851                     *p = *n;
    1852                     *(p+1) = *(n+1);
    1853                 }
    1854                 else
    1855                 {
    1856                     p [0] = fill;
    1857                     p [1] = fill;
    1858                     fill = 0xff;
    1859                 }
    1860                 n += MSDOS_NAME_LFN_BYTES_PER_CHAR;
    1861 #if MSDOS_FIND_PRINT
    1862                 printf ( "'%c''%c'", *p, *(p+1) );
    1863 #endif
    1864 
    1865                 switch (i)
    1866                 {
    1867                     case 4:
    1868                         p += 5;
    1869                         break;
    1870                     case 10:
    1871                         p += 4;
    1872                         break;
    1873                     default:
    1874                         p += 2;
    1875                         break;
    1876                 }
    1877             }
    1878 #if MSDOS_FIND_PRINT
    1879             printf ( "\n" );
    1880 #endif
    1881             *MSDOS_DIR_ENTRY_TYPE(entry) = (fat_entries - lfn_entry) + 1;
    1882             if (lfn_entry == 1)
    1883                 *MSDOS_DIR_ENTRY_TYPE(entry) |= MSDOS_LAST_LONG_ENTRY;
    1884             *MSDOS_DIR_ATTR(entry) |= MSDOS_ATTR_LFN;
    1885         }
    1886 
    1887         bytes_written = fat_file_write(&fs_info->fat, fat_fd,
    1888                                        (empty_space_offset * bts2rd) + empty_space_entry,
    1889                                        length, fs_info->cl_buf + empty_space_entry);
    1890         if (bytes_written == -1)
    1891             return -1;
    1892         else if (bytes_written != length)
    1893             rtems_set_errno_and_return_minus_one(EIO);
    1894 
    1895         empty_space_offset++;
    1896         empty_space_entry = 0;
    1897         read_cluster = true;
    1898     }
    1899     return ret;
     1793        printf ( "\n" );
     1794#endif
     1795        *MSDOS_DIR_ENTRY_TYPE(entry) = fat_entries - lfn_entry;
     1796        if (lfn_entry == 0)
     1797            *MSDOS_DIR_ENTRY_TYPE(entry) |= MSDOS_LAST_LONG_ENTRY;
     1798        *MSDOS_DIR_ATTR(entry) |= MSDOS_ATTR_LFN;
     1799
     1800        entry += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE;
     1801    }
     1802
     1803    /* Short file name entry */
     1804    memcpy(entry, name_dir_entry, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
     1805
     1806    length = (fat_entries + 1) * MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE;
     1807    bytes_written = fat_file_write(&fs_info->fat, fat_fd,
     1808                                   empty_file_offset,
     1809                                   length, fs_info->cl_buf);
     1810    if (bytes_written == (ssize_t) length)
     1811        return 0;
     1812    else if (bytes_written == -1)
     1813        return -1;
     1814    else
     1815        rtems_set_errno_and_return_minus_one(EIO);
    19001816}
    19011817
     
    19161832    ssize_t                            name_len_for_compare;
    19171833    uint32_t                           bts2rd                     = 0;
    1918     uint32_t                           empty_space_offset         = 0;
    1919     uint32_t                           empty_space_entry          = 0;
    1920     uint32_t                           empty_space_count          = 0;
    1921     uint32_t                           dir_offset                 = 0;
     1834    uint32_t                           empty_file_offset          = 0;
     1835    uint32_t                           empty_entry_count          = 0;
    19221836    unsigned int                       fat_entries;
    19231837    rtems_dosfs_convert_control       *converter = fs_info->converter;
     
    19931907          name_dir_entry,
    19941908          dir_pos,
    1995           &dir_offset,
    1996           &empty_space_offset,
    1997           &empty_space_entry,
    1998           &empty_space_count);
     1909          &empty_file_offset,
     1910          &empty_entry_count);
    19991911    }
    20001912    /* Create a non-existing file/directory if requested */
     
    20451957                name_dir_entry,
    20461958                dir_pos,
    2047                 dir_offset,
    2048                 empty_space_offset,
    2049                 empty_space_entry,
    2050                 empty_space_count
     1959                empty_file_offset,
     1960                empty_entry_count
    20511961            );
    20521962    }
Note: See TracChangeset for help on using the changeset viewer.