* add directories to index, will make things easier to deal with
* reflect read-only status in generated volume
This commit is contained in:
parent
82fc4ff101
commit
1c1f5b9ebc
|
@ -604,14 +604,14 @@ bool ImportFile(const char* path, const char* in)
|
|||
return false;
|
||||
}
|
||||
|
||||
u8 buf[0x200];
|
||||
for (u32 i = 0; i < len; i += 0x200)
|
||||
u8 buf[0x1000];
|
||||
for (u32 i = 0; i < len; i += 0x1000)
|
||||
{
|
||||
u32 blocklen;
|
||||
if ((i + 0x200) > len)
|
||||
if ((i + 0x1000) > len)
|
||||
blocklen = len - i;
|
||||
else
|
||||
blocklen = 0x200;
|
||||
blocklen = 0x1000;
|
||||
|
||||
u32 nwrite;
|
||||
fread(buf, blocklen, 1, fin);
|
||||
|
@ -643,14 +643,14 @@ bool ExportFile(const char* path, const char* out)
|
|||
return false;
|
||||
}
|
||||
|
||||
u8 buf[0x200];
|
||||
for (u32 i = 0; i < len; i += 0x200)
|
||||
u8 buf[0x1000];
|
||||
for (u32 i = 0; i < len; i += 0x1000)
|
||||
{
|
||||
u32 blocklen;
|
||||
if ((i + 0x200) > len)
|
||||
if ((i + 0x1000) > len)
|
||||
blocklen = len - i;
|
||||
else
|
||||
blocklen = 0x200;
|
||||
blocklen = 0x1000;
|
||||
|
||||
u32 nread;
|
||||
f_read(&file, buf, blocklen, &nread);
|
||||
|
|
|
@ -115,7 +115,8 @@ UINT FATStorage::FF_WriteStorage(BYTE* buf, LBA_t sector, UINT num)
|
|||
|
||||
void FATStorage::LoadIndex()
|
||||
{
|
||||
Index.clear();
|
||||
DirIndex.clear();
|
||||
FileIndex.clear();
|
||||
|
||||
FILE* f = Platform::OpenLocalFile(IndexPath.c_str(), "r");
|
||||
if (!f) return;
|
||||
|
@ -126,29 +127,58 @@ void FATStorage::LoadIndex()
|
|||
if (fgets(linebuf, 1536, f) == nullptr)
|
||||
break;
|
||||
|
||||
u64 fsize;
|
||||
s64 lastmodified;
|
||||
u32 lastmod_internal;
|
||||
char fpath[1536] = {0};
|
||||
int ret = sscanf(linebuf, "FILE %" PRIu64 " %" PRId64 " %u %[^\t\r\n]", &fsize, &lastmodified, &lastmod_internal, fpath);
|
||||
if (ret < 4) continue;
|
||||
|
||||
for (int i = 0; i < 1536 && fpath[i] != '\0'; i++)
|
||||
if (linebuf[0] == 'D')
|
||||
{
|
||||
if (fpath[i] == '\\')
|
||||
fpath[i] = '/';
|
||||
u32 readonly;
|
||||
char fpath[1536] = {0};
|
||||
int ret = sscanf(linebuf, "DIR %u %[^\t\r\n]",
|
||||
&readonly, fpath);
|
||||
if (ret < 2) continue;
|
||||
|
||||
for (int i = 0; i < 1536 && fpath[i] != '\0'; i++)
|
||||
{
|
||||
if (fpath[i] == '\\')
|
||||
fpath[i] = '/';
|
||||
}
|
||||
|
||||
DirIndexEntry entry;
|
||||
entry.Path = fpath;
|
||||
entry.IsReadOnly = readonly!=0;
|
||||
|
||||
DirIndex[entry.Path] = entry;
|
||||
}
|
||||
else if (linebuf[0] == 'F')
|
||||
{
|
||||
u32 readonly;
|
||||
u64 fsize;
|
||||
s64 lastmodified;
|
||||
u32 lastmod_internal;
|
||||
char fpath[1536] = {0};
|
||||
int ret = sscanf(linebuf, "FILE %u %" PRIu64 " %" PRId64 " %u %[^\t\r\n]",
|
||||
&readonly, &fsize, &lastmodified, &lastmod_internal, fpath);
|
||||
if (ret < 5) continue;
|
||||
|
||||
IndexEntry entry;
|
||||
entry.Path = fpath;
|
||||
entry.Size = fsize;
|
||||
entry.LastModified = lastmodified;
|
||||
entry.LastModifiedInternal = lastmod_internal;
|
||||
for (int i = 0; i < 1536 && fpath[i] != '\0'; i++)
|
||||
{
|
||||
if (fpath[i] == '\\')
|
||||
fpath[i] = '/';
|
||||
}
|
||||
|
||||
Index[entry.Path] = entry;
|
||||
FileIndexEntry entry;
|
||||
entry.Path = fpath;
|
||||
entry.IsReadOnly = readonly!=0;
|
||||
entry.Size = fsize;
|
||||
entry.LastModified = lastmodified;
|
||||
entry.LastModifiedInternal = lastmod_internal;
|
||||
|
||||
FileIndex[entry.Path] = entry;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
// TODO: ensure the indexes are sane
|
||||
// ie. ensure that we don't have files existing in inexistant directories
|
||||
}
|
||||
|
||||
void FATStorage::SaveIndex()
|
||||
|
@ -156,15 +186,92 @@ void FATStorage::SaveIndex()
|
|||
FILE* f = Platform::OpenLocalFile(IndexPath.c_str(), "w");
|
||||
if (!f) return;
|
||||
|
||||
for (const auto& [key, val] : Index)
|
||||
for (const auto& [key, val] : DirIndex)
|
||||
{
|
||||
fprintf(f, "FILE %" PRIu64 " %" PRId64 " %u %s\r\n", val.Size, val.LastModified, val.LastModifiedInternal, val.Path.c_str());
|
||||
fprintf(f, "DIR %u %s\r\n",
|
||||
val.IsReadOnly?1:0, val.Path.c_str());
|
||||
}
|
||||
|
||||
for (const auto& [key, val] : FileIndex)
|
||||
{
|
||||
fprintf(f, "FILE %u %" PRIu64 " %" PRId64 " %u %s\r\n",
|
||||
val.IsReadOnly?1:0, val.Size, val.LastModified, val.LastModifiedInternal, val.Path.c_str());
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
|
||||
bool FATStorage::ExportFile(std::string path, std::string out)
|
||||
{
|
||||
FIL file;
|
||||
FILE* fout;
|
||||
FRESULT res;
|
||||
|
||||
res = f_open(&file, path.c_str(), FA_OPEN_EXISTING | FA_READ);
|
||||
if (res != FR_OK)
|
||||
return false;
|
||||
|
||||
u32 len = f_size(&file);
|
||||
|
||||
fout = fopen(out.c_str(), "wb");
|
||||
if (!fout)
|
||||
{
|
||||
f_close(&file);
|
||||
return false;
|
||||
}
|
||||
|
||||
u8 buf[0x1000];
|
||||
for (u32 i = 0; i < len; i += 0x1000)
|
||||
{
|
||||
u32 blocklen;
|
||||
if ((i + 0x1000) > len)
|
||||
blocklen = len - i;
|
||||
else
|
||||
blocklen = 0x1000;
|
||||
|
||||
u32 nread;
|
||||
f_read(&file, buf, blocklen, &nread);
|
||||
fwrite(buf, blocklen, 1, fout);
|
||||
}
|
||||
|
||||
fclose(fout);
|
||||
f_close(&file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FATStorage::ExportChanges(std::string sourcedir)
|
||||
{
|
||||
// reflect changes in the FAT volume to the host filesystem
|
||||
// * delete directories and files that exist in the index but not in the volume
|
||||
// * copy files to the host FS if they exist within the index and their size or
|
||||
// internal last-modified time is different
|
||||
// * index and copy directories and files that exist in the volume but not in
|
||||
// the index
|
||||
|
||||
std::vector<std::string> deletelist;
|
||||
std::vector<std::string> exportlist;
|
||||
|
||||
for (const auto& [key, val] : FileIndex)
|
||||
{
|
||||
std::string innerpath = "0:/" + val.Path;
|
||||
FILINFO finfo;
|
||||
FRESULT res = f_stat(innerpath.c_str(), &finfo);
|
||||
if (res == FR_OK)
|
||||
{
|
||||
u32 lastmod = (finfo.fdate << 16) | finfo.ftime;
|
||||
if ((val.Size != finfo.fsize) || (val.LastModifiedInternal != lastmod))
|
||||
exportlist.push_back(key);
|
||||
}
|
||||
else if (res == FR_NO_FILE || res == FR_NO_PATH)
|
||||
{
|
||||
deletelist.push_back(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool FATStorage::CanFitFile(u32 len)
|
||||
{
|
||||
FATFS* fs;
|
||||
|
@ -181,16 +288,19 @@ bool FATStorage::CanFitFile(u32 len)
|
|||
return (freeclusters >= len);
|
||||
}
|
||||
|
||||
int FATStorage::CleanupDirectory(std::string path, int level)
|
||||
bool FATStorage::DeleteDirectory(std::string path, int level)
|
||||
{
|
||||
if (level >= 32) return 44203;
|
||||
if (level >= 32) return false;
|
||||
if (path.length() < 1) return false;
|
||||
|
||||
fDIR dir;
|
||||
FILINFO info;
|
||||
FRESULT res;
|
||||
printf("CHECKING %s (level %d) FOR SHIT\n", path.c_str(), level);
|
||||
res = f_opendir(&dir, path.c_str());
|
||||
if (res != FR_OK) return 0;
|
||||
printf("PURGING %s (level %d)\n", path.c_str(), level);
|
||||
std::string fullpath = "0:/" + path;
|
||||
f_chmod(fullpath.c_str(), 0, AM_RDO);
|
||||
res = f_opendir(&dir, fullpath.c_str());
|
||||
if (res != FR_OK) return false;
|
||||
|
||||
std::vector<std::string> deletelist;
|
||||
std::vector<std::string> subdirlist;
|
||||
|
@ -203,17 +313,14 @@ printf("CHECKING %s (level %d) FOR SHIT\n", path.c_str(), level);
|
|||
if (!info.fname[0]) break;
|
||||
|
||||
std::string fullpath = path + info.fname;
|
||||
printf("- FOUND: %s\n", fullpath.c_str());
|
||||
|
||||
if (info.fattrib & AM_DIR)
|
||||
{
|
||||
subdirlist.push_back(fullpath);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Index.count(fullpath) < 1)
|
||||
deletelist.push_back(fullpath);
|
||||
else
|
||||
survivors++;
|
||||
deletelist.push_back(fullpath);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -223,23 +330,85 @@ printf("- FOUND: %s\n", fullpath.c_str());
|
|||
{
|
||||
std::string fullpath = "0:/" + entry;
|
||||
printf("- PURGING file %s\n", fullpath.c_str());
|
||||
f_unlink(fullpath.c_str());
|
||||
f_chmod(fullpath.c_str(), 0, AM_RDO);
|
||||
res = f_unlink(fullpath.c_str());
|
||||
if (res != FR_OK) return false;
|
||||
}
|
||||
|
||||
for (auto& entry : subdirlist)
|
||||
{
|
||||
int res = CleanupDirectory(entry+"/", level+1);
|
||||
if (res < 1)
|
||||
{
|
||||
std::string fullpath = "0:/" + entry;
|
||||
printf("- PURGING subdir %s\n", fullpath.c_str());
|
||||
f_unlink(fullpath.c_str());
|
||||
}
|
||||
else
|
||||
survivors++;
|
||||
if (!DeleteDirectory(entry+"/", level+1)) return false;
|
||||
|
||||
std::string fullpath = "0:/" + entry;
|
||||
printf("- PURGING subdir %s\n", fullpath.c_str());
|
||||
f_chmod(fullpath.c_str(), 0, AM_RDO);
|
||||
res = f_unlink(fullpath.c_str());
|
||||
if (res != FR_OK) return false;
|
||||
}
|
||||
|
||||
return survivors;
|
||||
res = f_unlink(fullpath.c_str());
|
||||
if (res != FR_OK) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FATStorage::CleanupDirectory(std::string path, int level)
|
||||
{
|
||||
if (level >= 32) return;
|
||||
|
||||
fDIR dir;
|
||||
FILINFO info;
|
||||
FRESULT res;
|
||||
printf("CHECKING %s (level %d) FOR SHIT\n", path.c_str(), level);
|
||||
std::string fullpath = "0:/" + path;
|
||||
res = f_opendir(&dir, fullpath.c_str());
|
||||
if (res != FR_OK) return;
|
||||
|
||||
std::vector<std::string> filedeletelist;
|
||||
std::vector<std::string> dirdeletelist;
|
||||
std::vector<std::string> subdirlist;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
res = f_readdir(&dir, &info);
|
||||
if (res != FR_OK) break;
|
||||
if (!info.fname[0]) break;
|
||||
|
||||
std::string fullpath = path + info.fname;
|
||||
printf("- FOUND: %s\n", fullpath.c_str());
|
||||
if (info.fattrib & AM_DIR)
|
||||
{
|
||||
if (DirIndex.count(fullpath) < 1)
|
||||
dirdeletelist.push_back(fullpath);
|
||||
else
|
||||
subdirlist.push_back(fullpath);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FileIndex.count(fullpath) < 1)
|
||||
filedeletelist.push_back(fullpath);
|
||||
}
|
||||
}
|
||||
|
||||
f_closedir(&dir);
|
||||
|
||||
for (auto& entry : filedeletelist)
|
||||
{
|
||||
std::string fullpath = "0:/" + entry;
|
||||
printf("- PURGING file %s\n", fullpath.c_str());
|
||||
f_chmod(fullpath.c_str(), 0, AM_RDO);
|
||||
f_unlink(fullpath.c_str());
|
||||
}
|
||||
|
||||
for (auto& entry : dirdeletelist)
|
||||
{
|
||||
DeleteDirectory(entry+"/", level+1);
|
||||
}
|
||||
|
||||
for (auto& entry : subdirlist)
|
||||
{
|
||||
CleanupDirectory(entry+"/", level+1);
|
||||
}
|
||||
}
|
||||
|
||||
bool FATStorage::ImportFile(std::string path, std::string in)
|
||||
|
@ -299,13 +468,13 @@ bool FATStorage::BuildSubdirectory(const char* sourcedir, const char* path, int
|
|||
|
||||
if (level == 0)
|
||||
{
|
||||
// remove whatever isn't in the index, as well as empty directories
|
||||
// remove whatever isn't in the index
|
||||
CleanupDirectory("", 0);
|
||||
|
||||
int srclen = strlen(sourcedir);
|
||||
|
||||
// iterate through the host directory:
|
||||
// * directories will be added as needed
|
||||
// * directories will be added if they aren't in the index
|
||||
// * files will be added if they aren't in the index, or if the size or last-modified-date don't match
|
||||
for (auto& entry : fs::recursive_directory_iterator(sourcedir))
|
||||
{
|
||||
|
@ -321,13 +490,27 @@ bool FATStorage::BuildSubdirectory(const char* sourcedir, const char* path, int
|
|||
innerpath[i] = '/';
|
||||
}
|
||||
|
||||
bool readonly = (entry.status().permissions() & fs::perms::owner_write) == fs::perms::none;
|
||||
|
||||
//std::chrono::duration<s64> bourf(lastmodified_raw);
|
||||
//printf("DORP: %016llX\n", bourf.count());
|
||||
|
||||
if (entry.is_directory())
|
||||
{
|
||||
innerpath = "0:/" + innerpath;
|
||||
f_mkdir(innerpath.c_str());
|
||||
if (DirIndex.count(innerpath) < 1)
|
||||
{
|
||||
DirIndexEntry ientry;
|
||||
ientry.Path = innerpath;
|
||||
ientry.IsReadOnly = readonly;
|
||||
|
||||
innerpath = "0:/" + innerpath;
|
||||
if (f_mkdir(innerpath.c_str()) == FR_OK)
|
||||
{
|
||||
DirIndex[ientry.Path] = ientry;
|
||||
|
||||
printf("IMPORTING DIR %s (FROM %s), %d\n", innerpath.c_str(), fullpath.c_str(), readonly);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (entry.is_regular_file())
|
||||
{
|
||||
|
@ -337,23 +520,24 @@ bool FATStorage::BuildSubdirectory(const char* sourcedir, const char* path, int
|
|||
s64 lastmodified_raw = std::chrono::duration_cast<std::chrono::seconds>(lastmodified.time_since_epoch()).count();
|
||||
|
||||
bool import = false;
|
||||
if (Index.count(innerpath) < 1)
|
||||
if (FileIndex.count(innerpath) < 1)
|
||||
{
|
||||
import = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
IndexEntry& chk = Index[innerpath];
|
||||
FileIndexEntry& chk = FileIndex[innerpath];
|
||||
if (chk.Size != filesize) import = true;
|
||||
if (chk.LastModified != lastmodified_raw) import = true;
|
||||
}
|
||||
|
||||
if (import)
|
||||
{
|
||||
IndexEntry entry;
|
||||
entry.Path = innerpath;
|
||||
entry.Size = filesize;
|
||||
entry.LastModified = lastmodified_raw;
|
||||
FileIndexEntry ientry;
|
||||
ientry.Path = innerpath;
|
||||
ientry.IsReadOnly = readonly;
|
||||
ientry.Size = filesize;
|
||||
ientry.LastModified = lastmodified_raw;
|
||||
|
||||
innerpath = "0:/" + innerpath;
|
||||
if (ImportFile(innerpath, fullpath))
|
||||
|
@ -361,15 +545,16 @@ bool FATStorage::BuildSubdirectory(const char* sourcedir, const char* path, int
|
|||
FILINFO finfo;
|
||||
f_stat(innerpath.c_str(), &finfo);
|
||||
|
||||
entry.LastModifiedInternal = (finfo.fdate << 16) | finfo.ftime;
|
||||
ientry.LastModifiedInternal = (finfo.fdate << 16) | finfo.ftime;
|
||||
|
||||
Index[entry.Path] = entry;
|
||||
FileIndex[ientry.Path] = ientry;
|
||||
|
||||
printf("IMPORTING FILE %s (FROM %s)\n", innerpath.c_str(), fullpath.c_str());
|
||||
printf("IMPORTING FILE %s (FROM %s), %d\n", innerpath.c_str(), fullpath.c_str(), readonly);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
f_chmod(innerpath.c_str(), readonly?AM_RDO:0, AM_RDO);
|
||||
}
|
||||
|
||||
SaveIndex();
|
||||
|
|
|
@ -49,8 +49,12 @@ private:
|
|||
void LoadIndex();
|
||||
void SaveIndex();
|
||||
|
||||
bool ExportFile(std::string path, std::string out);
|
||||
void ExportChanges(std::string sourcedir);
|
||||
|
||||
bool CanFitFile(u32 len);
|
||||
int CleanupDirectory(std::string path, int level);
|
||||
bool DeleteDirectory(std::string path, int level);
|
||||
void CleanupDirectory(std::string path, int level);
|
||||
bool ImportFile(std::string path, std::string in);
|
||||
bool BuildSubdirectory(const char* sourcedir, const char* path, int level);
|
||||
bool Build(const char* sourcedir, u64 size, const char* filename);
|
||||
|
@ -58,13 +62,22 @@ private:
|
|||
typedef struct
|
||||
{
|
||||
std::string Path;
|
||||
bool IsReadOnly;
|
||||
|
||||
} DirIndexEntry;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
std::string Path;
|
||||
bool IsReadOnly;
|
||||
u64 Size;
|
||||
s64 LastModified;
|
||||
u32 LastModifiedInternal;
|
||||
|
||||
} IndexEntry;
|
||||
} FileIndexEntry;
|
||||
|
||||
std::map<std::string, IndexEntry> Index;
|
||||
std::map<std::string, DirIndexEntry> DirIndex;
|
||||
std::map<std::string, FileIndexEntry> FileIndex;
|
||||
};
|
||||
|
||||
#endif // FATSTORAGE_H
|
||||
|
|
Loading…
Reference in New Issue