* Rename a file or subdirectory. * * \param[in] dirFile Directory for the new path. * \param[in] newPath New path name for the file/directory. * * \return true for success, false for failure. * Reasons for failure include \a dirFile is not open or is not a directory * file, newPath is invalid or already exists, or an I/O error occurs. */
| 1715 | * file, newPath is invalid or already exists, or an I/O error occurs. |
| 1716 | */ |
| 1717 | bool SdBaseFile::rename(SdBaseFile * const dirFile, const char * const newPath) { |
| 1718 | if (ENABLED(SDCARD_READONLY)) return false; |
| 1719 | |
| 1720 | uint32_t dirCluster = 0; |
| 1721 | |
| 1722 | // must be an open file or subdirectory |
| 1723 | if (!(isFile() || isSubDir())) return false; |
| 1724 | |
| 1725 | // can't move file |
| 1726 | if (vol_ != dirFile->vol_) return false; |
| 1727 | |
| 1728 | // sync() and cache directory entry |
| 1729 | sync(); |
| 1730 | dir_t *d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); |
| 1731 | if (!d) return false; |
| 1732 | |
| 1733 | // save directory entry |
| 1734 | dir_t entry; |
| 1735 | memcpy(&entry, d, sizeof(entry)); |
| 1736 | |
| 1737 | // mark entry deleted |
| 1738 | d->name[0] = DIR_NAME_DELETED; |
| 1739 | |
| 1740 | // make directory entry for new path |
| 1741 | SdBaseFile file; |
| 1742 | if (isFile()) { |
| 1743 | if (!file.open(dirFile, newPath, O_CREAT | O_EXCL | O_WRITE)) { |
| 1744 | goto restore; |
| 1745 | } |
| 1746 | } |
| 1747 | else { |
| 1748 | // don't create missing path prefix components |
| 1749 | if (!file.mkdir(dirFile, newPath, false)) { |
| 1750 | goto restore; |
| 1751 | } |
| 1752 | // save cluster containing new dot dot |
| 1753 | dirCluster = file.firstCluster_; |
| 1754 | } |
| 1755 | // change to new directory entry |
| 1756 | dirBlock_ = file.dirBlock_; |
| 1757 | dirIndex_ = file.dirIndex_; |
| 1758 | |
| 1759 | // mark closed to avoid possible destructor close call |
| 1760 | file.type_ = FAT_FILE_TYPE_CLOSED; |
| 1761 | |
| 1762 | // cache new directory entry |
| 1763 | d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); |
| 1764 | if (!d) return false; |
| 1765 | |
| 1766 | // copy all but name field to new directory entry |
| 1767 | memcpy(&d->attributes, &entry.attributes, sizeof(entry) - sizeof(d->name)); |
| 1768 | |
| 1769 | // update dot dot if directory |
| 1770 | if (dirCluster) { |
| 1771 | // get new dot dot |
| 1772 | uint32_t block = vol_->clusterStartBlock(dirCluster); |
| 1773 | if (!vol_->cacheRawBlock(block, SdVolume::CACHE_FOR_READ)) return false; |
| 1774 | memcpy(&entry, &vol_->cache()->dir[1], sizeof(entry)); |
no test coverage detected