Add checksums (used as a timestamp) to VFS.
Deprecate mj_makeEmptyFileVFS in favor of mj_addBufferVFS. PiperOrigin-RevId: 608915388 Change-Id: Id9e9b042799bc1bf547f0795ae6f386447d53cdd
This commit is contained in:
committed by
Copybara-Service
parent
042760eba8
commit
a4a621f6e3
@@ -105,7 +105,9 @@ mjResource* mju_openResource(const char* name, char* error, size_t error_sz) {
|
||||
memcpy(&fb->mtime, &file_stat.st_mtime, sizeof(time_t));
|
||||
} else {
|
||||
memset(&fb->mtime, 0, sizeof(time_t));
|
||||
resource->timestamp[0] = '\0';
|
||||
}
|
||||
strftime(resource->timestamp, 512, "%Y-%m-%d-%H:%M:%S", localtime(&(fb->mtime)));
|
||||
return resource;
|
||||
}
|
||||
|
||||
@@ -185,24 +187,20 @@ static int mju_isModifiedFile(const char* name, const file_buffer* fb) {
|
||||
if (stat(name, &file_stat) == 0) {
|
||||
return difftime(fb->mtime, file_stat.st_mtime) < 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return -2;
|
||||
return 1; // modified (default)
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Returns > 0 if resource has been modified since last read, 0 if not, and < 0
|
||||
// if inconclusive
|
||||
int mju_isModifiedResource(const mjResource* resource) {
|
||||
if (resource == NULL) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
// return 0 if the resource's timestamp matches the provided timestamp
|
||||
// return > 0 if the the resource is younger than the given timestamp
|
||||
// return < 0 if the resource is older than the given timestamp
|
||||
int mju_isModifiedResource(const mjResource* resource, const char* timestamp) {
|
||||
// provider is not OS filesystem
|
||||
if (resource->provider) {
|
||||
if (resource->provider->modified) {
|
||||
return resource->provider->modified(resource);
|
||||
return resource->provider->modified(resource, timestamp);
|
||||
}
|
||||
return 1; // default (modified)
|
||||
}
|
||||
|
||||
@@ -35,12 +35,13 @@ MJAPI void mju_closeResource(mjResource* resource);
|
||||
// return negative value if error
|
||||
MJAPI int mju_readResource(mjResource* resource, const void** buffer);
|
||||
|
||||
// sets for a resource with a name partitioned as {dir}{filename}, the dir and ndir pointers
|
||||
// set for a resource with a name partitioned as {dir}{filename}, the dir and ndir pointers
|
||||
MJAPI void mju_getResourceDir(mjResource* resource, const char** dir, int* ndir);
|
||||
|
||||
// Returns > 0 if resource has been modified since last read, 0 if not, and < 0
|
||||
// if inconclusive
|
||||
MJAPI int mju_isModifiedResource(const mjResource* resource);
|
||||
// return 0 if the resource's timestamp matches the provided timestamp
|
||||
// return > 0 if the the resource is younger than the given timestamp
|
||||
// return < 0 if the resource is older than the given timestamp
|
||||
MJAPI int mju_isModifiedResource(const mjResource* resource, const char* timestamp);
|
||||
|
||||
// get the length of the dirname portion of a given path
|
||||
int mju_dirnamelen(const char* path);
|
||||
|
||||
+90
-2
@@ -15,7 +15,9 @@
|
||||
#include "engine/engine_vfs.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "engine/engine_array_safety.h"
|
||||
#include "engine/engine_resource.h"
|
||||
@@ -55,6 +57,38 @@ static void vfs_strippath(char* newname, const char* oldname) {
|
||||
|
||||
|
||||
|
||||
// copies data into a buffer and produces a hash of the data
|
||||
static uint64_t vfs_memcpy(void* dest, const void* restrict src, size_t n) {
|
||||
uint64_t hash = 0xcbf29ce484222325; // magic number
|
||||
uint64_t prime = 0x100000001b3; // magic prime
|
||||
const uint8_t* bytes = (uint8_t*) src;
|
||||
uint8_t* buffer = (uint8_t*) dest;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
buffer[i] = bytes[i];
|
||||
|
||||
// do FNV-1 hash
|
||||
hash |= bytes[i];
|
||||
hash *= prime;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// VFS hash function implemented using the FNV-1 hash
|
||||
static uint64_t vfs_hash(const void* restrict buffer, size_t n) {
|
||||
uint64_t hash = 0xcbf29ce484222325; // magic number
|
||||
uint64_t prime = 0x100000001b3; // magic prime
|
||||
const uint8_t* bytes = (uint8_t*) buffer;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
hash |= bytes[i];
|
||||
hash *= prime;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// initialize to empty (no deallocation)
|
||||
void mj_defaultVFS(mjVFS* vfs) {
|
||||
memset(vfs, 0, sizeof(mjVFS));
|
||||
@@ -95,7 +129,9 @@ int mj_addFileVFS(mjVFS* vfs, const char* directory, const char* filename) {
|
||||
if (!vfs->filedata[vfs->nfile]) {
|
||||
return -1;
|
||||
}
|
||||
// assign size and count
|
||||
|
||||
// assign size, count, and checksum
|
||||
vfs->filestamp[vfs->nfile] = vfs_hash(vfs->filedata[vfs->nfile], filesize);
|
||||
vfs->filesize[vfs->nfile] = filesize;
|
||||
vfs->nfile++;
|
||||
|
||||
@@ -136,6 +172,7 @@ int mj_makeEmptyFileVFS(mjVFS* vfs, const char* filename, int filesize) {
|
||||
mjERROR("could not allocate memory");
|
||||
}
|
||||
memset(vfs->filedata[vfs->nfile], 0, filesize);
|
||||
vfs->filestamp[vfs->nfile] = 0;
|
||||
|
||||
// assign size and count
|
||||
vfs->filesize[vfs->nfile] = filesize;
|
||||
@@ -146,6 +183,51 @@ int mj_makeEmptyFileVFS(mjVFS* vfs, const char* filename, int filesize) {
|
||||
|
||||
|
||||
|
||||
// add file from buffer into VFS
|
||||
int mj_addBufferVFS(mjVFS* vfs, const char* name, const void* buffer, int nbuffer) {
|
||||
if (!vfs || !buffer || !name) {
|
||||
mjERROR("null pointer");
|
||||
}
|
||||
|
||||
if (vfs->nfile >= mjMAXVFS-1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// check buffer size
|
||||
if (nbuffer <= 0) {
|
||||
mjERROR("expects positive buffer size");
|
||||
}
|
||||
|
||||
// strip path
|
||||
char newname[mjMAXVFSNAME];
|
||||
vfs_strippath(newname, name);
|
||||
|
||||
// check for repeated name
|
||||
for (int i=0; i < vfs->nfile; i++) {
|
||||
if (strncmp(newname, vfs->filename[i], mjMAXVFSNAME) == 0) {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
// assign name
|
||||
mjSTRNCPY(vfs->filename[vfs->nfile], newname);
|
||||
|
||||
// allocate and clear
|
||||
vfs->filedata[vfs->nfile] = mju_malloc(nbuffer);
|
||||
if (!vfs->filedata[vfs->nfile]) {
|
||||
mjERROR("could not allocate memory");
|
||||
}
|
||||
vfs->filestamp[vfs->nfile] = vfs_memcpy(vfs->filedata[vfs->nfile], buffer, nbuffer);
|
||||
|
||||
// assign size and count
|
||||
vfs->filesize[vfs->nfile] = nbuffer;
|
||||
vfs->nfile++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// return file index in VFS, or -1 if not found in VFS
|
||||
int mj_findFileVFS(const mjVFS* vfs, const char* filename) {
|
||||
// strip path
|
||||
@@ -216,7 +298,13 @@ static int vfs_open_callback(mjResource* resource) {
|
||||
}
|
||||
|
||||
const mjVFS* vfs = (const mjVFS*) resource->data;
|
||||
return mj_findFileVFS(vfs, resource->name) >= 0;
|
||||
int i = mj_findFileVFS(vfs, resource->name);
|
||||
resource->timestamp[0] = '\0';
|
||||
if (i >= 0 && vfs->filestamp[i]) {
|
||||
mju_encodeBase64(resource->timestamp, (uint8_t*) &vfs->filestamp[i],
|
||||
sizeof(uint64_t));
|
||||
}
|
||||
return i >= 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#ifndef MUJOCO_SRC_ENGINE_ENGINE_VFS_H_
|
||||
#define MUJOCO_SRC_ENGINE_ENGINE_VFS_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <mujoco/mjexport.h>
|
||||
#include <mujoco/mjmodel.h>
|
||||
#include <mujoco/mjplugin.h>
|
||||
@@ -29,9 +31,12 @@ MJAPI void mj_defaultVFS(mjVFS* vfs);
|
||||
// add file to VFS, return 0: success, 1: full, 2: repeated name, -1: not found on disk
|
||||
MJAPI int mj_addFileVFS(mjVFS* vfs, const char* directory, const char* filename);
|
||||
|
||||
// make empty file in VFS, return 0: success, 1: full, 2: repeated name
|
||||
// deprecated: use mj_copyBufferVFS
|
||||
MJAPI int mj_makeEmptyFileVFS(mjVFS* vfs, const char* filename, int filesize);
|
||||
|
||||
// add file from buffer into VFS, return 0: success, 1: full, 2: repeated name, -1: failed to load
|
||||
MJAPI int mj_copyBufferVFS(mjVFS* vfs, const char* filename, const void* buffer, int nbuffer);
|
||||
|
||||
// return file index in VFS, or -1 if not found in VFS
|
||||
MJAPI int mj_findFileVFS(const mjVFS* vfs, const char* filename);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user