in lsvmutils/vfat.c [1324:1521]
int _PutFile(
VFAT* vfat,
BOOLEAN isDir,
const char* path,
void* data,
UINTN size)
{
int rc = -1;
VFATDirectoryEntry ent;
char dirname[VFAT_PATH_SIZE];
char basename[VFAT_PATH_SIZE];
void* dirData = NULL;
UINTN dirSize;
UINT32 dirClustno;
UINT32 clustno = 0;
const VFATDirectoryEntry dot =
{
{ '.', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' }, /* name */
ATTR_ARCHIVE | ATTR_DIRECTORY, /* attr */
0, /* res */
0, /* crtTimeTenth */
1709, /* crtTime */
18706, /* crtDate */
18706, /* lstAccDate */
0, /* fstClusHI */
22131, /* wrtTime */
18706, /* wrtDate */
0, /* fstClusLO */
0, /* fileSize */
};
const VFATDirectoryEntry dotdot =
{
{ '.', '.', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' }, /* name */
ATTR_ARCHIVE | ATTR_DIRECTORY, /* attr */
0, /* res */
0, /* crtTimeTenth */
1709, /* crtTime */
18706, /* crtDate */
18706, /* lstAccDate */
0, /* fstClusHI */
22131, /* wrtTime */
18706, /* wrtDate */
0, /* fstClusLO */
0, /* fileSize */
};
/* Check parameters */
if (!vfat || !path || !data)
GOTO(done);
/* If a directory, then copy "." and ".." entries */
if (isDir)
{
Memset(data, 0, size);
Memcpy(data, &dot, sizeof(dot));
Memcpy((UINT8*)data + sizeof(dot), &dotdot, sizeof(dotdot));
}
/* Fail if file already exists */
if (VFATStatFile(vfat, path, &ent) == 0)
GOTO(done);
/* Reject non-absolute paths */
if (path[0] != '/')
GOTO(done);
/* Get the base name from the path (final component) */
if (_GetBaseName(basename, path) == NULL)
GOTO(done);
/* Get the directory name from the path (excludes final component) */
if (_GetDirName(dirname, path) == NULL)
GOTO(done);
/* Load directory into memory */
if (_LoadDir(vfat, dirname, &dirData, &dirSize, &dirClustno) != 0)
GOTO(done);
/* If creating directory file, update the parent directory cluster */
if (isDir)
{
VFATDirectoryEntry* p = (VFATDirectoryEntry*)data;
p[1].fstClusHI = (dirClustno & 0xFFFF0000) << 16;
p[1].fstClusLO = (dirClustno & 0x0000FFFF);
}
/* Inject directory entry */
{
/* Used hardcoded dates and times */
VFATDirectoryEntry entry =
{
{ '\0' }, /* name */
0, /* attr */
0, /* res */
100, /* crtTimeTenth */
1884, /* crtTime */
18706, /* crtDate */
18706, /* lstAccDate */
0, /* fstClusHI */
1884, /* wrtTime */
18706, /* wrtDate */
0, /* fstClusLO */
0, /* fileSize */
};
/* Set VFATDirectoryEntry.attr */
{
entry.attr = ATTR_ARCHIVE;
if (isDir)
entry.attr |= ATTR_DIRECTORY;
}
/* Set VFATDirectoryEntry.name */
{
char shortname[12];
InternShortname(shortname, basename);
Memcpy(entry.name, shortname, sizeof(entry.name));
}
/* Set VFATDirectoryEntry.fileSize */
if (!isDir)
entry.fileSize = size;
/* Allocate FAT chain for this new file (update in-memory FAT copy) */
{
UINTN r = (size + vfat->ClusterSize - 1) / vfat->ClusterSize;
if (_AllocateFATChain(vfat, r, &clustno) != 0)
GOTO(done);
}
/* If creating directory file, update the directory cluster */
if (isDir)
{
VFATDirectoryEntry* p = (VFATDirectoryEntry*)data;
p[0].fstClusHI = (clustno & 0xFFFF0000) << 16;
p[0].fstClusLO = (clustno & 0x0000FFFF);
}
/* Update directory entry cluster number */
entry.fstClusHI = (clustno & 0xFFFF0000) << 16;
entry.fstClusLO = (clustno & 0x0000FFFF);
/* Inject entry into directory file memory */
{
VFATDirectoryEntry* p = (VFATDirectoryEntry*)dirData;
for (; p->name[0]; p++)
{
/* Use this entry if deleted */
if (p->name[0] == 0xE5)
break;
/* Skip long-name entries */
if (p->attr == ATTR_LONG_NAME)
continue;
}
/* If no more room for a directory entry */
if ((void*)(p + 1) >= (dirData + dirSize))
GOTO(done);
/* Update the entry */
Memcpy(p, &entry, sizeof(*p));
}
}
/* Flush file to disk */
if (_FlushFile(vfat, data, size, clustno) != 0)
GOTO(done);
/* If this is the root directory, then refresh the cache */
if (dirClustno == vfat->rootdirClustno)
{
if (vfat->rootdir.size != dirSize)
goto done;
Memcpy(vfat->rootdir.data, dirData, dirSize);
}
/* Flush directory to disk */
if (_FlushFile(vfat, dirData, dirSize, dirClustno) != 0)
GOTO(done);
/* Flush FAT to disk */
if (_FlushFAT(vfat))
GOTO(done);
rc = 0;
done:
if (dirData)
Free(dirData);
return rc;
}