cinera: Lock database and config files
This commit aims to help Cinera instances coordinate themselves by throwing an error upon being instructed to use a database or config file currently in use by another instance.
This commit is contained in:
parent
1cf703e346
commit
f60cf3087f
314
cinera/cinera.c
314
cinera/cinera.c
|
@ -23,15 +23,22 @@ typedef struct
|
||||||
version CINERA_APP_VERSION = {
|
version CINERA_APP_VERSION = {
|
||||||
.Major = 0,
|
.Major = 0,
|
||||||
.Minor = 10,
|
.Minor = 10,
|
||||||
.Patch = 12
|
.Patch = 13
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define __USE_XOPEN2K8 // NOTE(matt): O_NOFOLLOW
|
||||||
|
#include <fcntl.h> // NOTE(matt): open()
|
||||||
|
#undef __USE_XOPEN2K8
|
||||||
|
|
||||||
#include <stdarg.h> // NOTE(matt): varargs
|
#include <stdarg.h> // NOTE(matt): varargs
|
||||||
|
#define __USE_POSIX // NOTE(matt): fileno()
|
||||||
#include <stdio.h> // NOTE(matt): printf, sprintf, vsprintf, fprintf, perror
|
#include <stdio.h> // NOTE(matt): printf, sprintf, vsprintf, fprintf, perror
|
||||||
|
#undef __USE_POSIX
|
||||||
#include <stdlib.h> // NOTE(matt): calloc, malloc, free
|
#include <stdlib.h> // NOTE(matt): calloc, malloc, free
|
||||||
#include <getopt.h> // NOTE(matt): getopts
|
#include <getopt.h> // NOTE(matt): getopts
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <sys/file.h> // NOTE(matt): flock
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
@ -41,10 +48,6 @@ version CINERA_APP_VERSION = {
|
||||||
#include <sys/ioctl.h> // NOTE(matt): ioctl and TIOCGWINSZ
|
#include <sys/ioctl.h> // NOTE(matt): ioctl and TIOCGWINSZ
|
||||||
#include <wordexp.h>
|
#include <wordexp.h>
|
||||||
|
|
||||||
#define __USE_XOPEN2K8 // NOTE(matt): O_NOFOLLOW
|
|
||||||
#include <fcntl.h> // NOTE(matt): open()
|
|
||||||
#undef __USE_XOPEN2K8
|
|
||||||
|
|
||||||
#define __USE_XOPEN2K // NOTE(matt): readlink()
|
#define __USE_XOPEN2K // NOTE(matt): readlink()
|
||||||
#include <unistd.h> // NOTE(matt): sleep()
|
#include <unistd.h> // NOTE(matt): sleep()
|
||||||
#undef __USE_XOPEN2K
|
#undef __USE_XOPEN2K
|
||||||
|
@ -67,6 +70,7 @@ version CINERA_APP_VERSION = {
|
||||||
typedef uint64_t bool;
|
typedef uint64_t bool;
|
||||||
#define TRUE 1
|
#define TRUE 1
|
||||||
#define FALSE 0
|
#define FALSE 0
|
||||||
|
#define NA 0
|
||||||
|
|
||||||
#define SECONDS_PER_HOUR 3600
|
#define SECONDS_PER_HOUR 3600
|
||||||
#define SECONDS_PER_MINUTE 60
|
#define SECONDS_PER_MINUTE 60
|
||||||
|
@ -279,6 +283,7 @@ typedef enum
|
||||||
RC_ERROR_DIRECTORY,
|
RC_ERROR_DIRECTORY,
|
||||||
RC_ERROR_FATAL,
|
RC_ERROR_FATAL,
|
||||||
RC_ERROR_FILE,
|
RC_ERROR_FILE,
|
||||||
|
RC_ERROR_FILE_LOCKED,
|
||||||
RC_ERROR_HMML,
|
RC_ERROR_HMML,
|
||||||
RC_ERROR_MAX_REFS,
|
RC_ERROR_MAX_REFS,
|
||||||
RC_ERROR_MEMORY,
|
RC_ERROR_MEMORY,
|
||||||
|
@ -464,6 +469,7 @@ typedef struct
|
||||||
buffer Buffer;
|
buffer Buffer;
|
||||||
char *Path;
|
char *Path;
|
||||||
FILE *Handle;
|
FILE *Handle;
|
||||||
|
bool Locking;
|
||||||
} file;
|
} file;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -1064,7 +1070,7 @@ ExtendString0(char **Dest, string Src)
|
||||||
}
|
}
|
||||||
|
|
||||||
file
|
file
|
||||||
InitFile(string *Directory, string *Filename, extension_id Extension)
|
InitFile(string *Directory, string *Filename, extension_id Extension, bool Locking)
|
||||||
{
|
{
|
||||||
file Result = {};
|
file Result = {};
|
||||||
if(Directory)
|
if(Directory)
|
||||||
|
@ -1079,6 +1085,36 @@ InitFile(string *Directory, string *Filename, extension_id Extension)
|
||||||
{
|
{
|
||||||
ExtendString0(&Result.Path, ExtensionStrings[Extension]);
|
ExtendString0(&Result.Path, ExtensionStrings[Extension]);
|
||||||
}
|
}
|
||||||
|
Result.Locking = Locking;
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CloseFile(file *F, bool CloseLocking)
|
||||||
|
{
|
||||||
|
if(F->Handle)
|
||||||
|
{
|
||||||
|
fclose(F->Handle);
|
||||||
|
F->Handle = 0;
|
||||||
|
if(F->Locking && !CloseLocking)
|
||||||
|
{
|
||||||
|
F->Handle = fopen(F->Path, "r");
|
||||||
|
flock(fileno(F->Handle), LOCK_EX | LOCK_NB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
TryLock(file *F) // USAGE: File shall already be open, if possible
|
||||||
|
{
|
||||||
|
bool Result = TRUE;
|
||||||
|
if(F->Locking && F->Handle)
|
||||||
|
{
|
||||||
|
if(flock(fileno(F->Handle), LOCK_EX | LOCK_NB) == -1)
|
||||||
|
{
|
||||||
|
Result = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1088,7 +1124,9 @@ ReadFileIntoBuffer(file *F)
|
||||||
rc Result = RC_ERROR_FILE;
|
rc Result = RC_ERROR_FILE;
|
||||||
if(F->Path)
|
if(F->Path)
|
||||||
{
|
{
|
||||||
if((F->Handle = fopen(F->Path, "r")))
|
if(F->Handle || (F->Handle = fopen(F->Path, "r")))
|
||||||
|
{
|
||||||
|
if(TryLock(F))
|
||||||
{
|
{
|
||||||
fseek(F->Handle, 0, SEEK_END);
|
fseek(F->Handle, 0, SEEK_END);
|
||||||
F->Buffer.Size = ftell(F->Handle);
|
F->Buffer.Size = ftell(F->Handle);
|
||||||
|
@ -1096,13 +1134,13 @@ ReadFileIntoBuffer(file *F)
|
||||||
F->Buffer.Ptr = F->Buffer.Location;
|
F->Buffer.Ptr = F->Buffer.Location;
|
||||||
fseek(F->Handle, 0, SEEK_SET);
|
fseek(F->Handle, 0, SEEK_SET);
|
||||||
fread(F->Buffer.Location, F->Buffer.Size, 1, F->Handle);
|
fread(F->Buffer.Location, F->Buffer.Size, 1, F->Handle);
|
||||||
fclose(F->Handle);
|
CloseFile(F, FALSE);
|
||||||
F->Handle = 0;
|
|
||||||
Result = RC_SUCCESS;
|
Result = RC_SUCCESS;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
perror(F->Path);
|
Result = RC_ERROR_FILE_LOCKED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Result;
|
return Result;
|
||||||
|
@ -1914,16 +1952,6 @@ ConfigErrorUnset(config_identifier_id FieldID)
|
||||||
"Unset %s\n", ConfigIdentifiers[FieldID].String);
|
"Unset %s\n", ConfigIdentifiers[FieldID].String);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
ConfigFileIncludeError(string *Filename, uint64_t LineNumber, string Path)
|
|
||||||
{
|
|
||||||
ErrorFilenameAndLineNumber(Filename, LineNumber, S_WARNING, ED_CONFIG);
|
|
||||||
fprintf(stderr,
|
|
||||||
"Included file could not be opened (%s): ", strerror(errno));
|
|
||||||
PrintStringC(CS_MAGENTA_BOLD, Path);
|
|
||||||
fprintf(stderr, "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ConfigErrorSizing(string *Filename, uint64_t LineNumber, config_identifier_id FieldID, string *Received, uint64_t MaxSize)
|
ConfigErrorSizing(string *Filename, uint64_t LineNumber, config_identifier_id FieldID, string *Received, uint64_t MaxSize)
|
||||||
{
|
{
|
||||||
|
@ -1933,6 +1961,27 @@ ConfigErrorSizing(string *Filename, uint64_t LineNumber, config_identifier_id Fi
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ConfigErrorLockedConfigLocation(string *Filename, uint64_t LineNumber, string *Received)
|
||||||
|
{
|
||||||
|
ErrorFilenameAndLineNumber(Filename, LineNumber, Filename ? S_WARNING : S_ERROR, ED_CONFIG);
|
||||||
|
fprintf(stderr, "%s file %s%.*s%s is in use by another Cinera instance\n", Filename ? "Included" : "Config", ColourStrings[CS_MAGENTA_BOLD], (int)Received->Length, Received->Base, ColourStrings[CS_END]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ConfigErrorUnopenableConfigLocation(string *Filename, uint64_t LineNumber, string *Received)
|
||||||
|
{
|
||||||
|
ErrorFilenameAndLineNumber(Filename, LineNumber, Filename ? S_WARNING : S_ERROR, ED_CONFIG);
|
||||||
|
fprintf(stderr, "%s file %s%.*s%s could not be opened: %s\n", Filename ? "Included" : "Config", ColourStrings[CS_MAGENTA_BOLD], (int)Received->Length, Received->Base, ColourStrings[CS_END], strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ConfigErrorLockedDBLocation(string *Filename, uint64_t LineNumber, string *Received)
|
||||||
|
{
|
||||||
|
ErrorFilenameAndLineNumber(Filename, LineNumber, S_ERROR, ED_CONFIG);
|
||||||
|
fprintf(stderr, "File at db_location %s%.*s%s is in use by another Cinera instance\n", ColourStrings[CS_MAGENTA_BOLD], (int)Received->Length, Received->Base, ColourStrings[CS_END]);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ConfigErrorInt(string *Filename, uint64_t LineNumber, severity Severity, char *Message, uint64_t Number)
|
ConfigErrorInt(string *Filename, uint64_t LineNumber, severity Severity, char *Message, uint64_t Number)
|
||||||
{
|
{
|
||||||
|
@ -2740,6 +2789,7 @@ typedef struct
|
||||||
{
|
{
|
||||||
file File;
|
file File;
|
||||||
file_signposted Metadata;
|
file_signposted Metadata;
|
||||||
|
bool Ready;
|
||||||
|
|
||||||
db_header5 Header;
|
db_header5 Header;
|
||||||
db_block_projects5 ProjectsBlock;
|
db_block_projects5 ProjectsBlock;
|
||||||
|
@ -3024,17 +3074,23 @@ ClearTemplateMetadata(template *Template)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FreeFile(file *F)
|
FreeFileBufferAndPath(file *F)
|
||||||
{
|
{
|
||||||
FreeBuffer(&F->Buffer);
|
FreeBuffer(&F->Buffer);
|
||||||
Free(F->Path);
|
Free(F->Path);
|
||||||
F->Handle = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FreeSignpostedFile(file_signposted *F)
|
FreeFile(file *F, bool CloseLocking)
|
||||||
{
|
{
|
||||||
FreeFile(&F->File);
|
CloseFile(F, CloseLocking);
|
||||||
|
FreeFileBufferAndPath(F);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
FreeSignpostedFile(file_signposted *F, bool CloseLocking)
|
||||||
|
{
|
||||||
|
FreeFile(&F->File, CloseLocking);
|
||||||
file_signposts Zero = {};
|
file_signposts Zero = {};
|
||||||
F->Signposts = Zero;
|
F->Signposts = Zero;
|
||||||
}
|
}
|
||||||
|
@ -3042,7 +3098,7 @@ FreeSignpostedFile(file_signposted *F)
|
||||||
void
|
void
|
||||||
FreeTemplate(template *Template)
|
FreeTemplate(template *Template)
|
||||||
{
|
{
|
||||||
FreeFile(&Template->File);
|
FreeFile(&Template->File, NA);
|
||||||
ClearTemplateMetadata(Template);
|
ClearTemplateMetadata(Template);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3152,8 +3208,6 @@ typedef enum
|
||||||
WT_CONFIG,
|
WT_CONFIG,
|
||||||
} watch_type;
|
} watch_type;
|
||||||
|
|
||||||
#include "cinera_config.c"
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
watch_type Type;
|
watch_type Type;
|
||||||
|
@ -3161,6 +3215,7 @@ typedef struct
|
||||||
extension_id Extension;
|
extension_id Extension;
|
||||||
project *Project;
|
project *Project;
|
||||||
asset *Asset;
|
asset *Asset;
|
||||||
|
FILE *Handle;
|
||||||
} watch_file;
|
} watch_file;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -3178,6 +3233,8 @@ typedef struct
|
||||||
uint32_t DefaultEventsMask;
|
uint32_t DefaultEventsMask;
|
||||||
} watch_handles;
|
} watch_handles;
|
||||||
|
|
||||||
|
#include "cinera_config.c"
|
||||||
|
|
||||||
#define AFD 1
|
#define AFD 1
|
||||||
#define AFE 0
|
#define AFE 0
|
||||||
|
|
||||||
|
@ -4281,17 +4338,17 @@ InitTemplate(template *Template, string Location, template_type Type)
|
||||||
Template->Metadata.Type = Type;
|
Template->Metadata.Type = Type;
|
||||||
if(Type == TEMPLATE_GLOBAL_SEARCH)
|
if(Type == TEMPLATE_GLOBAL_SEARCH)
|
||||||
{
|
{
|
||||||
Template->File = InitFile(&Config->GlobalTemplatesDir, &Config->GlobalSearchTemplatePath, EXT_NULL);
|
Template->File = InitFile(&Config->GlobalTemplatesDir, &Config->GlobalSearchTemplatePath, EXT_NULL, FALSE);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(Location.Base[0] == '/')
|
if(Location.Base[0] == '/')
|
||||||
{
|
{
|
||||||
Template->File = InitFile(0, &Location, EXT_NULL);
|
Template->File = InitFile(0, &Location, EXT_NULL, FALSE);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Template->File = InitFile(Type == TEMPLATE_BESPOKE ? &CurrentProject->HMMLDir : &CurrentProject->TemplatesDir, &Location, EXT_NULL);
|
Template->File = InitFile(Type == TEMPLATE_BESPOKE ? &CurrentProject->HMMLDir : &CurrentProject->TemplatesDir, &Location, EXT_NULL, FALSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fprintf(stderr, "%sPacking%s template: %s\n", ColourStrings[CS_ONGOING], ColourStrings[CS_END], Template->File.Path);
|
fprintf(stderr, "%sPacking%s template: %s\n", ColourStrings[CS_ONGOING], ColourStrings[CS_END], Template->File.Path);
|
||||||
|
@ -4516,7 +4573,7 @@ ConstructAssetPath(file *AssetFile, string Filename, asset_type Type)
|
||||||
void
|
void
|
||||||
CycleFile(file *File)
|
CycleFile(file *File)
|
||||||
{
|
{
|
||||||
fclose(File->Handle);
|
CloseFile(File, FALSE);
|
||||||
// TODO(matt): Rather than freeing the buffer, why not just realloc it to fit the new file? Couldn't that work easily?
|
// TODO(matt): Rather than freeing the buffer, why not just realloc it to fit the new file? Couldn't that work easily?
|
||||||
// The reason we Free / Reread is to save us having to shuffle the buffer contents around, basically
|
// The reason we Free / Reread is to save us having to shuffle the buffer contents around, basically
|
||||||
// If we switch the whole database over to use linked lists - the database being the only file we actually cycle
|
// If we switch the whole database over to use linked lists - the database being the only file we actually cycle
|
||||||
|
@ -4541,7 +4598,7 @@ CycleSignpostedFile(file_signposted *File)
|
||||||
// NOTE(matt) This file_signposted struct is totally hardcoded to the Metadata file, but may suffice for now
|
// NOTE(matt) This file_signposted struct is totally hardcoded to the Metadata file, but may suffice for now
|
||||||
//
|
//
|
||||||
// TODO(matt): This is probably insufficient. We likely need to offset the pointers any time we add stuff to the database
|
// TODO(matt): This is probably insufficient. We likely need to offset the pointers any time we add stuff to the database
|
||||||
fclose(File->File.Handle);
|
CloseFile(&File->File, FALSE);
|
||||||
// TODO(matt): Rather than freeing the buffer, why not just realloc it to fit the new file? Couldn't that work easily?
|
// TODO(matt): Rather than freeing the buffer, why not just realloc it to fit the new file? Couldn't that work easily?
|
||||||
// The reason we Free / Reread is to save us having to shuffle the buffer contents around, basically
|
// The reason we Free / Reread is to save us having to shuffle the buffer contents around, basically
|
||||||
// If we switch the whole database over to use linked lists - the database being the only file we actually cycle
|
// If we switch the whole database over to use linked lists - the database being the only file we actually cycle
|
||||||
|
@ -4834,9 +4891,7 @@ SnipeChecksumAndCloseFile(file *HTMLFile, db_asset *Asset, int LandmarksInFile,
|
||||||
|
|
||||||
HTMLFile->Handle = fopen(HTMLFile->Path, "w");
|
HTMLFile->Handle = fopen(HTMLFile->Path, "w");
|
||||||
fwrite(HTMLFile->Buffer.Location, HTMLFile->Buffer.Size, 1, HTMLFile->Handle);
|
fwrite(HTMLFile->Buffer.Location, HTMLFile->Buffer.Size, 1, HTMLFile->Handle);
|
||||||
fclose(HTMLFile->Handle);
|
FreeFile(HTMLFile, NA);
|
||||||
HTMLFile->Handle = 0;
|
|
||||||
FreeFile(HTMLFile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(matt): Bounds-check the Metadata.File.Buffer
|
// TODO(matt): Bounds-check the Metadata.File.Buffer
|
||||||
|
@ -5136,13 +5191,25 @@ AccumulateFileEditSize(file_signposted *File, int64_t Bytes)
|
||||||
File->Signposts.Edit.Size += Bytes;
|
File->Signposts.Edit.Size += Bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FILE *
|
||||||
|
OpenFileForWriting(file *F)
|
||||||
|
{
|
||||||
|
if(F->Locking && F->Handle)
|
||||||
|
{
|
||||||
|
fclose(F->Handle);
|
||||||
|
}
|
||||||
|
F->Handle = fopen(F->Path, "w");
|
||||||
|
TryLock(F);
|
||||||
|
return F->Handle;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(matt): Consider enforcing an order of these blocks, basically putting the easy-to-skip ones first...
|
// TODO(matt): Consider enforcing an order of these blocks, basically putting the easy-to-skip ones first...
|
||||||
void *
|
void *
|
||||||
InitBlock(block_id ID)
|
InitBlock(block_id ID)
|
||||||
{
|
{
|
||||||
db_header *Header = (db_header *)DB.Metadata.File.Buffer.Location;
|
db_header *Header = (db_header *)DB.Metadata.File.Buffer.Location;
|
||||||
++Header->BlockCount;
|
++Header->BlockCount;
|
||||||
DB.Metadata.File.Handle = fopen(DB.Metadata.File.Path, "w");
|
OpenFileForWriting(&DB.Metadata.File);
|
||||||
fwrite(DB.Metadata.File.Buffer.Location, DB.Metadata.File.Buffer.Size, 1, DB.Metadata.File.Handle);
|
fwrite(DB.Metadata.File.Buffer.Location, DB.Metadata.File.Buffer.Size, 1, DB.Metadata.File.Handle);
|
||||||
|
|
||||||
SetFileEditPosition(&DB.Metadata);
|
SetFileEditPosition(&DB.Metadata);
|
||||||
|
@ -5419,9 +5486,10 @@ IsSymlink(char *Filepath)
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
watch_file *
|
||||||
PushWatchFileUniquely(watch_handle *Handle, string Filepath, extension_id Extension, watch_type Type, project *Project, asset *Asset)
|
PushWatchFileUniquely(watch_handle *Handle, string Filepath, extension_id Extension, watch_type Type, project *Project, asset *Asset)
|
||||||
{
|
{
|
||||||
|
watch_file *Result = 0;
|
||||||
bool Required = TRUE;
|
bool Required = TRUE;
|
||||||
for(int i = 0; i < Handle->Files.ItemCount; ++i)
|
for(int i = 0; i < Handle->Files.ItemCount; ++i)
|
||||||
{
|
{
|
||||||
|
@ -5432,14 +5500,16 @@ PushWatchFileUniquely(watch_handle *Handle, string Filepath, extension_id Extens
|
||||||
{
|
{
|
||||||
if(This->Extension == Extension)
|
if(This->Extension == Extension)
|
||||||
{
|
{
|
||||||
|
Result = This;
|
||||||
Required = FALSE;
|
Required = FALSE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(StringsMatch(This->Path, Filepath))
|
else if(StringsMatch(This->Path, Filepath))
|
||||||
{
|
{
|
||||||
Required = FALSE;
|
Result = This;
|
||||||
EraseCurrentStringFromBook(&WatchHandles.Paths);
|
EraseCurrentStringFromBook(&WatchHandles.Paths);
|
||||||
|
Required = FALSE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5459,7 +5529,9 @@ PushWatchFileUniquely(watch_handle *Handle, string Filepath, extension_id Extens
|
||||||
New->Type = Type;
|
New->Type = Type;
|
||||||
New->Project = Project;
|
New->Project = Project;
|
||||||
New->Asset = Asset;
|
New->Asset = Asset;
|
||||||
|
Result = New;
|
||||||
}
|
}
|
||||||
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -5535,9 +5607,10 @@ GetNearestExistingPath(string Path)
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
watch_file *
|
||||||
PushWatchHandle(string Path, extension_id Extension, watch_type Type, project *Project, asset *Asset)
|
PushWatchHandle(string Path, extension_id Extension, watch_type Type, project *Project, asset *Asset)
|
||||||
{
|
{
|
||||||
|
watch_file *Result = 0;
|
||||||
// NOTE(matt): This function influences RemoveAndFreeAllButFirstWatchFile(). If we change to write different strings into
|
// NOTE(matt): This function influences RemoveAndFreeAllButFirstWatchFile(). If we change to write different strings into
|
||||||
// the W->Paths memory_book, we must reflect that change over to RemoveAndFreeAllButFirstWatchFile()
|
// the W->Paths memory_book, we must reflect that change over to RemoveAndFreeAllButFirstWatchFile()
|
||||||
|
|
||||||
|
@ -5675,7 +5748,8 @@ PushWatchHandle(string Path, extension_id Extension, watch_type Type, project *P
|
||||||
//PrintWatchHandles();
|
//PrintWatchHandles();
|
||||||
}
|
}
|
||||||
|
|
||||||
PushWatchFileUniquely(Watch, Filename, Extension, Type, Project, Asset);
|
Result = PushWatchFileUniquely(Watch, Filename, Extension, Type, Project, Asset);
|
||||||
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -5795,6 +5869,17 @@ UpdateNeighbourhoodPointers(neighbourhood *N, file_signposts *S)
|
||||||
N->Next = S->Next.Ptr;
|
N->Next = S->Next.Ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
WriteEntireDatabase(neighbourhood *N)
|
||||||
|
{
|
||||||
|
// NOTE(matt): This may suffice when the only changes are to existing fixed-size variables,
|
||||||
|
// e.g. ProjectsBlock->GlobalSearchDir
|
||||||
|
OpenFileForWriting(&DB.Metadata.File);
|
||||||
|
fwrite(DB.Metadata.File.Buffer.Location, DB.Metadata.File.Buffer.Size, 1, DB.Metadata.File.Handle);
|
||||||
|
CycleSignpostedFile(&DB.Metadata);
|
||||||
|
UpdateNeighbourhoodPointers(N, &DB.Metadata.Signposts);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
UpdateAssetInDB(asset *Asset)
|
UpdateAssetInDB(asset *Asset)
|
||||||
{
|
{
|
||||||
|
@ -5854,7 +5939,7 @@ UpdateAssetInDB(asset *Asset)
|
||||||
|
|
||||||
FreeString(&Message);
|
FreeString(&Message);
|
||||||
|
|
||||||
DB.Metadata.File.Handle = fopen(DB.Metadata.File.Path, "w");
|
OpenFileForWriting(&DB.Metadata.File);
|
||||||
fwrite(DB.Metadata.File.Buffer.Location, DB.Metadata.File.Buffer.Size, 1, DB.Metadata.File.Handle);
|
fwrite(DB.Metadata.File.Buffer.Location, DB.Metadata.File.Buffer.Size, 1, DB.Metadata.File.Handle);
|
||||||
SetFileEditPosition(&DB.Metadata);
|
SetFileEditPosition(&DB.Metadata);
|
||||||
|
|
||||||
|
@ -5865,7 +5950,7 @@ UpdateAssetInDB(asset *Asset)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Append new asset, not bothering to insertion sort because there likely won't be many
|
// Append new asset, not bothering to insertion sort because there likely won't be many
|
||||||
DB.Metadata.File.Handle = fopen(DB.Metadata.File.Path, "w");
|
OpenFileForWriting(&DB.Metadata.File);
|
||||||
char *InsertionPoint = LocateEndOfAssetsBlock(AssetsBlock);
|
char *InsertionPoint = LocateEndOfAssetsBlock(AssetsBlock);
|
||||||
|
|
||||||
AssetIndexInDB = AssetsBlock->Count;
|
AssetIndexInDB = AssetsBlock->Count;
|
||||||
|
@ -5994,7 +6079,7 @@ UpdateAsset(asset *Asset, bool Defer)
|
||||||
{
|
{
|
||||||
AssetIndexInDB = UpdateAssetInDB(Asset);
|
AssetIndexInDB = UpdateAssetInDB(Asset);
|
||||||
}
|
}
|
||||||
FreeFile(&File);
|
FreeFile(&File, NA);
|
||||||
return AssetIndexInDB;
|
return AssetIndexInDB;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6068,7 +6153,7 @@ PlaceAsset(string Filename, asset_type Type, uint64_t Variants, bool Associated,
|
||||||
printf("%sNonexistent%s %s asset: %s\n", ColourStrings[CS_WARNING], ColourStrings[CS_END], AssetTypeNames[Type], File.Path);
|
printf("%sNonexistent%s %s asset: %s\n", ColourStrings[CS_WARNING], ColourStrings[CS_END], AssetTypeNames[Type], File.Path);
|
||||||
}
|
}
|
||||||
|
|
||||||
FreeFile(&File);
|
FreeFile(&File, NA);
|
||||||
return This;
|
return This;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7601,7 +7686,7 @@ GenerateTopicColours(neighbourhood *N, string Topic)
|
||||||
printf(" Freed Topics (%ld)\n", Topics.Buffer.Size);
|
printf(" Freed Topics (%ld)\n", Topics.Buffer.Size);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
fclose(Topics.Handle);
|
CloseFile(&Topics, NA);
|
||||||
|
|
||||||
asset *Asset = GetPlaceInBook(&Assets, ASSET_CSS_TOPICS);
|
asset *Asset = GetPlaceInBook(&Assets, ASSET_CSS_TOPICS);
|
||||||
if(Asset->Known)
|
if(Asset->Known)
|
||||||
|
@ -7623,7 +7708,7 @@ GenerateTopicColours(neighbourhood *N, string Topic)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FreeFile(&Topics);
|
FreeFile(&Topics, NA);
|
||||||
}
|
}
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
@ -9115,7 +9200,7 @@ void
|
||||||
ExamineDB(void)
|
ExamineDB(void)
|
||||||
{
|
{
|
||||||
DB.Metadata.File.Buffer.ID = BID_DATABASE;
|
DB.Metadata.File.Buffer.ID = BID_DATABASE;
|
||||||
DB.Metadata.File = InitFile(0, &Config->DatabaseLocation, EXT_NULL);
|
DB.Metadata.File = InitFile(0, &Config->DatabaseLocation, EXT_NULL, TRUE);
|
||||||
ReadFileIntoBuffer(&DB.Metadata.File); // NOTE(matt): Could we actually catch errors (permissions?) here and bail?
|
ReadFileIntoBuffer(&DB.Metadata.File); // NOTE(matt): Could we actually catch errors (permissions?) here and bail?
|
||||||
|
|
||||||
if(DB.Metadata.File.Buffer.Location)
|
if(DB.Metadata.File.Buffer.Location)
|
||||||
|
@ -9146,7 +9231,7 @@ ExamineDB(void)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Unable to open database file %s: %s\n", DB.Metadata.File.Path, strerror(errno));
|
fprintf(stderr, "Unable to open database file %s: %s\n", DB.Metadata.File.Path, strerror(errno));
|
||||||
}
|
}
|
||||||
FreeFile(&DB.Metadata.File);
|
FreeFile(&DB.Metadata.File, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define HMMLCleanup() \
|
#define HMMLCleanup() \
|
||||||
|
@ -9323,7 +9408,7 @@ DeleteSearchPageFromFilesystem(string BaseDir, string SearchLocation, string Pro
|
||||||
|
|
||||||
remove(DB.File.Path);
|
remove(DB.File.Path);
|
||||||
// TODO(matt): Consider the correctness of this.
|
// TODO(matt): Consider the correctness of this.
|
||||||
FreeFile(&DB.File);
|
FreeFile(&DB.File, NA);
|
||||||
|
|
||||||
char *SearchDirectory = ConstructDirectoryPath(&BaseDir, &SearchLocation, 0);
|
char *SearchDirectory = ConstructDirectoryPath(&BaseDir, &SearchLocation, 0);
|
||||||
remove(SearchDirectory);
|
remove(SearchDirectory);
|
||||||
|
@ -11866,7 +11951,7 @@ InitIndexFile(project *P)
|
||||||
|
|
||||||
DB.File.Handle = fopen(DB.File.Path, "w");
|
DB.File.Handle = fopen(DB.File.Path, "w");
|
||||||
fprintf(DB.File.Handle, "---\n");
|
fprintf(DB.File.Handle, "---\n");
|
||||||
fclose(DB.File.Handle);
|
CloseFile(&DB.File, NA);
|
||||||
ReadFileIntoBuffer(&DB.File);
|
ReadFileIntoBuffer(&DB.File);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12243,10 +12328,7 @@ RenumberEntries(neighbourhood *N, db_header_project *P, int64_t IndexOfFirstEntr
|
||||||
Cursor += fwrite(Cursor, 1, DB.File.Buffer.Size - (Cursor - DB.File.Buffer.Location), DB.File.Handle);
|
Cursor += fwrite(Cursor, 1, DB.File.Buffer.Size - (Cursor - DB.File.Buffer.Location), DB.File.Handle);
|
||||||
CycleFile(&DB.File);
|
CycleFile(&DB.File);
|
||||||
|
|
||||||
if(!(DB.Metadata.File.Handle = fopen(DB.Metadata.File.Path, "w"))) { return; }
|
WriteEntireDatabase(N);
|
||||||
fwrite(DB.Metadata.File.Buffer.Location, 1, DB.Metadata.File.Buffer.Size, DB.Metadata.File.Handle);
|
|
||||||
CycleSignpostedFile(&DB.Metadata);
|
|
||||||
UpdateNeighbourhoodPointers(N, &DB.Metadata.Signposts);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
db_entry *
|
db_entry *
|
||||||
|
@ -12328,7 +12410,7 @@ InsertIntoDB(neighbourhood *N, buffers *CollationBuffers, template *BespokeTempl
|
||||||
fwrite(DB.File.Buffer.Location, EntryInsertionStart, 1, DB.File.Handle);
|
fwrite(DB.File.Buffer.Location, EntryInsertionStart, 1, DB.File.Handle);
|
||||||
fwrite(CollationBuffers->SearchEntry.Location, N->This->Size, 1, DB.File.Handle);
|
fwrite(CollationBuffers->SearchEntry.Location, N->This->Size, 1, DB.File.Handle);
|
||||||
fwrite(DB.File.Buffer.Location + EntryInsertionEnd, DB.File.Buffer.Size - EntryInsertionEnd, 1, DB.File.Handle);
|
fwrite(DB.File.Buffer.Location + EntryInsertionEnd, DB.File.Buffer.Size - EntryInsertionEnd, 1, DB.File.Handle);
|
||||||
fclose(DB.File.Handle);
|
CloseFile(&DB.File, NA);
|
||||||
|
|
||||||
if(N->This->Size == EntryInsertionEnd - EntryInsertionStart)
|
if(N->This->Size == EntryInsertionEnd - EntryInsertionStart)
|
||||||
{
|
{
|
||||||
|
@ -12350,7 +12432,7 @@ InsertIntoDB(neighbourhood *N, buffers *CollationBuffers, template *BespokeTempl
|
||||||
Ptr += sizeof(*N->Project) + sizeof(db_entry) * N->ThisIndex;
|
Ptr += sizeof(*N->Project) + sizeof(db_entry) * N->ThisIndex;
|
||||||
uint64_t BytesIntoFile = Ptr - DB.Metadata.File.Buffer.Location;
|
uint64_t BytesIntoFile = Ptr - DB.Metadata.File.Buffer.Location;
|
||||||
|
|
||||||
if(!(DB.Metadata.File.Handle = fopen(DB.Metadata.File.Path, "w"))) { return 0; }
|
if(!(OpenFileForWriting(&DB.Metadata.File))) { return 0; }
|
||||||
fwrite(DB.Metadata.File.Buffer.Location, BytesIntoFile, 1, DB.Metadata.File.Handle);
|
fwrite(DB.Metadata.File.Buffer.Location, BytesIntoFile, 1, DB.Metadata.File.Handle);
|
||||||
SetFileEditPosition(&DB.Metadata);
|
SetFileEditPosition(&DB.Metadata);
|
||||||
|
|
||||||
|
@ -12401,7 +12483,7 @@ WritePastAssetsHeader(void)
|
||||||
DB.Metadata.File.Buffer.Ptr = DB.Metadata.Signposts.AssetsBlock.Ptr;
|
DB.Metadata.File.Buffer.Ptr = DB.Metadata.Signposts.AssetsBlock.Ptr;
|
||||||
DB.Metadata.File.Buffer.Ptr += sizeof(db_block_assets);
|
DB.Metadata.File.Buffer.Ptr += sizeof(db_block_assets);
|
||||||
|
|
||||||
DB.Metadata.File.Handle = fopen(DB.Metadata.File.Path, "w");
|
OpenFileForWriting(&DB.Metadata.File);
|
||||||
fwrite(DB.Metadata.File.Buffer.Location, DB.Metadata.File.Buffer.Ptr - DB.Metadata.File.Buffer.Location, 1, DB.Metadata.File.Handle);
|
fwrite(DB.Metadata.File.Buffer.Location, DB.Metadata.File.Buffer.Ptr - DB.Metadata.File.Buffer.Location, 1, DB.Metadata.File.Handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13197,7 +13279,7 @@ InsertNeighbourLink(db_header_project *P, db_entry *From, db_entry *To, enum8(li
|
||||||
|
|
||||||
if(To) { DeclaimBuffer(&ToPlayerURL); }
|
if(To) { DeclaimBuffer(&ToPlayerURL); }
|
||||||
DeclaimBuffer(&Link);
|
DeclaimBuffer(&Link);
|
||||||
fclose(HTML.Handle);
|
CloseFile(&HTML, NA);
|
||||||
HTML.Handle = 0;
|
HTML.Handle = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13205,7 +13287,7 @@ InsertNeighbourLink(db_header_project *P, db_entry *From, db_entry *To, enum8(li
|
||||||
{
|
{
|
||||||
Result = RC_ERROR_FILE;
|
Result = RC_ERROR_FILE;
|
||||||
}
|
}
|
||||||
FreeFile(&HTML);
|
FreeFile(&HTML, NA);
|
||||||
MEM_TEST_END("InsertNeighbourLink()");
|
MEM_TEST_END("InsertNeighbourLink()");
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
@ -13236,14 +13318,14 @@ DeleteNeighbourLinks(neighbourhood *N)
|
||||||
ReadPlayerPageIntoBuffer(&HTML, Wrap0i(N->Project->BaseDir), Wrap0i(N->Project->PlayerLocation), Wrap0i(Entry->OutputLocation));
|
ReadPlayerPageIntoBuffer(&HTML, Wrap0i(N->Project->BaseDir), Wrap0i(N->Project->PlayerLocation), Wrap0i(Entry->OutputLocation));
|
||||||
if(HTML.Buffer.Location)
|
if(HTML.Buffer.Location)
|
||||||
{
|
{
|
||||||
if(!(HTML.Handle = fopen(HTML.Path, "w"))) { FreeFile(&HTML); return RC_ERROR_FILE; };
|
if(!(HTML.Handle = fopen(HTML.Path, "w"))) { FreeFile(&HTML, NA); return RC_ERROR_FILE; };
|
||||||
fwrite(HTML.Buffer.Location, Entry->LinkOffsets.PrevStart, 1, HTML.Handle);
|
fwrite(HTML.Buffer.Location, Entry->LinkOffsets.PrevStart, 1, HTML.Handle);
|
||||||
fwrite(HTML.Buffer.Location + Entry->LinkOffsets.PrevStart + Entry->LinkOffsets.PrevEnd, Entry->LinkOffsets.NextStart, 1, HTML.Handle);
|
fwrite(HTML.Buffer.Location + Entry->LinkOffsets.PrevStart + Entry->LinkOffsets.PrevEnd, Entry->LinkOffsets.NextStart, 1, HTML.Handle);
|
||||||
fwrite(HTML.Buffer.Location + Entry->LinkOffsets.PrevStart + Entry->LinkOffsets.PrevEnd + Entry->LinkOffsets.NextStart + Entry->LinkOffsets.NextEnd,
|
fwrite(HTML.Buffer.Location + Entry->LinkOffsets.PrevStart + Entry->LinkOffsets.PrevEnd + Entry->LinkOffsets.NextStart + Entry->LinkOffsets.NextEnd,
|
||||||
HTML.Buffer.Size - (Entry->LinkOffsets.PrevStart + Entry->LinkOffsets.PrevEnd + Entry->LinkOffsets.NextStart + Entry->LinkOffsets.NextEnd),
|
HTML.Buffer.Size - (Entry->LinkOffsets.PrevStart + Entry->LinkOffsets.PrevEnd + Entry->LinkOffsets.NextStart + Entry->LinkOffsets.NextEnd),
|
||||||
1,
|
1,
|
||||||
HTML.Handle);
|
HTML.Handle);
|
||||||
fclose(HTML.Handle);
|
CloseFile(&HTML, NA);
|
||||||
Entry->LinkOffsets.PrevEnd = 0;
|
Entry->LinkOffsets.PrevEnd = 0;
|
||||||
Entry->LinkOffsets.NextEnd = 0;
|
Entry->LinkOffsets.NextEnd = 0;
|
||||||
if(N->Prev && N->PrevIndex >= 0)
|
if(N->Prev && N->PrevIndex >= 0)
|
||||||
|
@ -13262,7 +13344,7 @@ DeleteNeighbourLinks(neighbourhood *N)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FreeFile(&HTML);
|
FreeFile(&HTML, NA);
|
||||||
return RC_SUCCESS;
|
return RC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13331,7 +13413,7 @@ MarkNextAsFirst(neighbourhood *N)
|
||||||
N->Next->LinkOffsets.PrevEnd = Link.Ptr - Link.Location;
|
N->Next->LinkOffsets.PrevEnd = Link.Ptr - Link.Location;
|
||||||
|
|
||||||
DeclaimBuffer(&Link);
|
DeclaimBuffer(&Link);
|
||||||
fclose(HTML.Handle);
|
CloseFile(&HTML, NA);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -13339,7 +13421,7 @@ MarkNextAsFirst(neighbourhood *N)
|
||||||
N->Next->LinkOffsets = Blank;
|
N->Next->LinkOffsets = Blank;
|
||||||
}
|
}
|
||||||
|
|
||||||
FreeFile(&HTML);
|
FreeFile(&HTML, NA);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -13369,7 +13451,7 @@ MarkPrevAsFinal(neighbourhood *N)
|
||||||
N->Prev->LinkOffsets.NextEnd = Link.Ptr - Link.Location;
|
N->Prev->LinkOffsets.NextEnd = Link.Ptr - Link.Location;
|
||||||
|
|
||||||
DeclaimBuffer(&Link);
|
DeclaimBuffer(&Link);
|
||||||
fclose(HTML.Handle);
|
CloseFile(&HTML, NA);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -13377,7 +13459,7 @@ MarkPrevAsFinal(neighbourhood *N)
|
||||||
N->Prev->LinkOffsets = Blank;
|
N->Prev->LinkOffsets = Blank;
|
||||||
}
|
}
|
||||||
|
|
||||||
FreeFile(&HTML);
|
FreeFile(&HTML, NA);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -13534,7 +13616,7 @@ DeleteFromDB(neighbourhood *N, string BaseFilename, db_entry *Deceased)
|
||||||
}
|
}
|
||||||
N->Project->EntryCount = NewEntryCount;
|
N->Project->EntryCount = NewEntryCount;
|
||||||
|
|
||||||
if(!(DB.Metadata.File.Handle = fopen(DB.Metadata.File.Path, "w"))) { FreeBuffer(&DB.Metadata.File.Buffer); return RC_ERROR_FILE; }
|
if(!(OpenFileForWriting(&DB.Metadata.File))) { FreeBuffer(&DB.Metadata.File.Buffer); return RC_ERROR_FILE; }
|
||||||
|
|
||||||
char *Ptr = (char *)N->This;
|
char *Ptr = (char *)N->This;
|
||||||
uint64_t BytesIntoFile = Ptr - DB.Metadata.File.Buffer.Location;
|
uint64_t BytesIntoFile = Ptr - DB.Metadata.File.Buffer.Location;
|
||||||
|
@ -14560,7 +14642,7 @@ SetCurrentProject(project *P, neighbourhood *N)
|
||||||
{
|
{
|
||||||
if(CurrentProject != P)
|
if(CurrentProject != P)
|
||||||
{
|
{
|
||||||
FreeFile(&DB.File);
|
FreeFile(&DB.File, NA);
|
||||||
|
|
||||||
if(CurrentProject)
|
if(CurrentProject)
|
||||||
{
|
{
|
||||||
|
@ -14608,7 +14690,6 @@ RecheckPrivacyRecursively(project *P, neighbourhood *N, buffers *CollationBuffer
|
||||||
DeleteStaleAssets();
|
DeleteStaleAssets();
|
||||||
UpdateNeighbourhoodPointers(N, &DB.Metadata.Signposts);
|
UpdateNeighbourhoodPointers(N, &DB.Metadata.Signposts);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; i < P->Child.ItemCount; ++i)
|
for(int i = 0; i < P->Child.ItemCount; ++i)
|
||||||
|
@ -14723,7 +14804,7 @@ UpgradeDB(int OriginalDBVersion)
|
||||||
ClearCopyStringNoFormat(DB.AssetsBlock.JSDir, sizeof(DB.AssetsBlock.JSDir), Config->JSDir);
|
ClearCopyStringNoFormat(DB.AssetsBlock.JSDir, sizeof(DB.AssetsBlock.JSDir), Config->JSDir);
|
||||||
++DB.Header.BlockCount;
|
++DB.Header.BlockCount;
|
||||||
|
|
||||||
DB.Metadata.File.Handle = fopen(DB.Metadata.File.Path, "w");
|
OpenFileForWriting(&DB.Metadata.File);
|
||||||
fwrite(&DB.Header, sizeof(DB.Header), 1, DB.Metadata.File.Handle);
|
fwrite(&DB.Header, sizeof(DB.Header), 1, DB.Metadata.File.Handle);
|
||||||
|
|
||||||
DB.Metadata.Signposts.ProjectsBlock.Byte = ftell(DB.Metadata.File.Handle);
|
DB.Metadata.Signposts.ProjectsBlock.Byte = ftell(DB.Metadata.File.Handle);
|
||||||
|
@ -14829,7 +14910,7 @@ DeleteDeadDBEntries(neighbourhood *N, bool *Modified)
|
||||||
|
|
||||||
Free(NewSearchDirectory);
|
Free(NewSearchDirectory);
|
||||||
|
|
||||||
FreeFile(&DB.File);
|
FreeFile(&DB.File, NA);
|
||||||
DB.File.Path = ConstructIndexFilePath(CurrentProject->BaseDir, CurrentProject->SearchLocation, CurrentProject->ID);
|
DB.File.Path = ConstructIndexFilePath(CurrentProject->BaseDir, CurrentProject->SearchLocation, CurrentProject->ID);
|
||||||
ReadFileIntoBuffer(&DB.File); // NOTE(matt): Could we actually catch errors (permissions?) here and bail?
|
ReadFileIntoBuffer(&DB.File); // NOTE(matt): Could we actually catch errors (permissions?) here and bail?
|
||||||
|
|
||||||
|
@ -14847,7 +14928,7 @@ DeleteDeadDBEntries(neighbourhood *N, bool *Modified)
|
||||||
if(StringsDiffer(CurrentProject->BaseDir, Wrap0i(N->Project->BaseDir)))
|
if(StringsDiffer(CurrentProject->BaseDir, Wrap0i(N->Project->BaseDir)))
|
||||||
{
|
{
|
||||||
ClearCopyStringNoFormat(N->Project->BaseDir, sizeof(N->Project->BaseDir), CurrentProject->BaseDir);
|
ClearCopyStringNoFormat(N->Project->BaseDir, sizeof(N->Project->BaseDir), CurrentProject->BaseDir);
|
||||||
DB.Metadata.File.Handle = fopen(DB.Metadata.File.Path, "w");
|
OpenFileForWriting(&DB.Metadata.File);
|
||||||
WriteFromByteToEnd(&DB.Metadata.File, 0);
|
WriteFromByteToEnd(&DB.Metadata.File, 0);
|
||||||
CycleSignpostedFile(&DB.Metadata);
|
CycleSignpostedFile(&DB.Metadata);
|
||||||
UpdateNeighbourhoodPointers(N, &DB.Metadata.Signposts);
|
UpdateNeighbourhoodPointers(N, &DB.Metadata.Signposts);
|
||||||
|
@ -14857,7 +14938,7 @@ DeleteDeadDBEntries(neighbourhood *N, bool *Modified)
|
||||||
if(StringsDiffer(CurrentProject->BaseURL, Wrap0i(N->Project->BaseURL)))
|
if(StringsDiffer(CurrentProject->BaseURL, Wrap0i(N->Project->BaseURL)))
|
||||||
{
|
{
|
||||||
ClearCopyStringNoFormat(N->Project->BaseURL, sizeof(N->Project->BaseURL), CurrentProject->BaseURL);
|
ClearCopyStringNoFormat(N->Project->BaseURL, sizeof(N->Project->BaseURL), CurrentProject->BaseURL);
|
||||||
DB.Metadata.File.Handle = fopen(DB.Metadata.File.Path, "w");
|
OpenFileForWriting(&DB.Metadata.File);
|
||||||
WriteFromByteToEnd(&DB.Metadata.File, 0);
|
WriteFromByteToEnd(&DB.Metadata.File, 0);
|
||||||
CycleSignpostedFile(&DB.Metadata);
|
CycleSignpostedFile(&DB.Metadata);
|
||||||
UpdateNeighbourhoodPointers(N, &DB.Metadata.Signposts);
|
UpdateNeighbourhoodPointers(N, &DB.Metadata.Signposts);
|
||||||
|
@ -14866,7 +14947,7 @@ DeleteDeadDBEntries(neighbourhood *N, bool *Modified)
|
||||||
|
|
||||||
if(HasNewPlayerLocation || HasNewSearchLocation)
|
if(HasNewPlayerLocation || HasNewSearchLocation)
|
||||||
{
|
{
|
||||||
if(!(DB.Metadata.File.Handle = fopen(DB.Metadata.File.Path, "w"))) { FreeBuffer(&DB.Metadata.File.Buffer); return RC_ERROR_FILE; }
|
if(!(OpenFileForWriting(&DB.Metadata.File))) { FreeBuffer(&DB.Metadata.File.Buffer); return RC_ERROR_FILE; }
|
||||||
ClearCopyStringNoFormat(N->Project->BaseDir, sizeof(N->Project->BaseDir), CurrentProject->BaseDir);
|
ClearCopyStringNoFormat(N->Project->BaseDir, sizeof(N->Project->BaseDir), CurrentProject->BaseDir);
|
||||||
ClearCopyStringNoFormat(N->Project->BaseURL, sizeof(N->Project->BaseURL), CurrentProject->BaseURL);
|
ClearCopyStringNoFormat(N->Project->BaseURL, sizeof(N->Project->BaseURL), CurrentProject->BaseURL);
|
||||||
fwrite(DB.Metadata.File.Buffer.Location, DB.Metadata.File.Buffer.Size, 1, DB.Metadata.File.Handle);
|
fwrite(DB.Metadata.File.Buffer.Location, DB.Metadata.File.Buffer.Size, 1, DB.Metadata.File.Handle);
|
||||||
|
@ -14942,7 +15023,7 @@ SyncDBWithInput(neighbourhood *N, buffers *CollationBuffers, template *BespokeTe
|
||||||
if(StringsDiffer(CurrentProject->Title, Wrap0i(N->Project->Title)))
|
if(StringsDiffer(CurrentProject->Title, Wrap0i(N->Project->Title)))
|
||||||
{
|
{
|
||||||
ClearCopyStringNoFormat(N->Project->Title, sizeof(N->Project->Title), CurrentProject->Title);
|
ClearCopyStringNoFormat(N->Project->Title, sizeof(N->Project->Title), CurrentProject->Title);
|
||||||
DB.Metadata.File.Handle = fopen(DB.Metadata.File.Path, "w");
|
OpenFileForWriting(&DB.Metadata.File);
|
||||||
WriteFromByteToEnd(&DB.Metadata.File, 0);
|
WriteFromByteToEnd(&DB.Metadata.File, 0);
|
||||||
CycleSignpostedFile(&DB.Metadata);
|
CycleSignpostedFile(&DB.Metadata);
|
||||||
UpdateNeighbourhoodPointers(N, &DB.Metadata.Signposts);
|
UpdateNeighbourhoodPointers(N, &DB.Metadata.Signposts);
|
||||||
|
@ -14952,7 +15033,7 @@ SyncDBWithInput(neighbourhood *N, buffers *CollationBuffers, template *BespokeTe
|
||||||
if(StringsDiffer(CurrentProject->Theme, Wrap0i(N->Project->Theme)))
|
if(StringsDiffer(CurrentProject->Theme, Wrap0i(N->Project->Theme)))
|
||||||
{
|
{
|
||||||
ClearCopyStringNoFormat(N->Project->Theme, sizeof(N->Project->Theme), CurrentProject->Theme);
|
ClearCopyStringNoFormat(N->Project->Theme, sizeof(N->Project->Theme), CurrentProject->Theme);
|
||||||
DB.Metadata.File.Handle = fopen(DB.Metadata.File.Path, "w");
|
OpenFileForWriting(&DB.Metadata.File);
|
||||||
WriteFromByteToEnd(&DB.Metadata.File, 0);
|
WriteFromByteToEnd(&DB.Metadata.File, 0);
|
||||||
CycleSignpostedFile(&DB.Metadata);
|
CycleSignpostedFile(&DB.Metadata);
|
||||||
UpdateNeighbourhoodPointers(N, &DB.Metadata.Signposts);
|
UpdateNeighbourhoodPointers(N, &DB.Metadata.Signposts);
|
||||||
|
@ -14962,7 +15043,7 @@ SyncDBWithInput(neighbourhood *N, buffers *CollationBuffers, template *BespokeTe
|
||||||
if(StringsDiffer(CurrentProject->Numbering.Unit, Wrap0i(N->Project->Unit)))
|
if(StringsDiffer(CurrentProject->Numbering.Unit, Wrap0i(N->Project->Unit)))
|
||||||
{
|
{
|
||||||
ClearCopyStringNoFormat(N->Project->Unit, sizeof(N->Project->Unit), CurrentProject->Numbering.Unit);
|
ClearCopyStringNoFormat(N->Project->Unit, sizeof(N->Project->Unit), CurrentProject->Numbering.Unit);
|
||||||
DB.Metadata.File.Handle = fopen(DB.Metadata.File.Path, "w");
|
OpenFileForWriting(&DB.Metadata.File);
|
||||||
WriteFromByteToEnd(&DB.Metadata.File, 0);
|
WriteFromByteToEnd(&DB.Metadata.File, 0);
|
||||||
CycleSignpostedFile(&DB.Metadata);
|
CycleSignpostedFile(&DB.Metadata);
|
||||||
UpdateNeighbourhoodPointers(N, &DB.Metadata.Signposts);
|
UpdateNeighbourhoodPointers(N, &DB.Metadata.Signposts);
|
||||||
|
@ -15082,16 +15163,6 @@ InitAccumulator(project_generations *G)
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
WriteEntireDatabase()
|
|
||||||
{
|
|
||||||
// NOTE(matt): This may suffice when the only changes are to existing fixed-size variables,
|
|
||||||
// e.g. ProjectsBlock->GlobalSearchDir
|
|
||||||
DB.Metadata.File.Handle = fopen(DB.Metadata.File.Path, "w");
|
|
||||||
fwrite(DB.Metadata.File.Buffer.Location, DB.Metadata.File.Buffer.Size, 1, DB.Metadata.File.Handle);
|
|
||||||
fclose(DB.Metadata.File.Handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
rc
|
rc
|
||||||
InitDB(void)
|
InitDB(void)
|
||||||
{
|
{
|
||||||
|
@ -15101,9 +15172,15 @@ InitDB(void)
|
||||||
// need a separate InitIndex() function that we can call when looping over the projects after ParseConfig()
|
// need a separate InitIndex() function that we can call when looping over the projects after ParseConfig()
|
||||||
|
|
||||||
DB.Metadata.File.Buffer.ID = BID_DATABASE;
|
DB.Metadata.File.Buffer.ID = BID_DATABASE;
|
||||||
DB.Metadata.File = InitFile(0, &Config->DatabaseLocation, EXT_NULL);
|
DB.Metadata.File = InitFile(0, &Config->DatabaseLocation, EXT_NULL, TRUE);
|
||||||
ReadFileIntoBuffer(&DB.Metadata.File); // NOTE(matt): Could we actually catch errors (permissions?) here and bail?
|
if(ReadFileIntoBuffer(&DB.Metadata.File) == RC_ERROR_FILE_LOCKED) // NOTE(matt): Could we actually catch errors (permissions?) here and bail?
|
||||||
|
{
|
||||||
|
ConfigErrorLockedDBLocation(0, 0, &Config->DatabaseLocation);
|
||||||
|
CloseFile(&DB.Metadata.File, TRUE);
|
||||||
|
Result = RC_ERROR_FILE_LOCKED;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if(DB.Metadata.File.Buffer.Location)
|
if(DB.Metadata.File.Buffer.Location)
|
||||||
{
|
{
|
||||||
// TODO(matt): Handle this gracefully (it'll be an invalid file)
|
// TODO(matt): Handle this gracefully (it'll be an invalid file)
|
||||||
|
@ -15169,12 +15246,12 @@ InitDB(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DB.Metadata.File.Handle = fopen(DB.Metadata.File.Path, "w");
|
if(OpenFileForWriting(&DB.Metadata.File))
|
||||||
if(DB.Metadata.File.Handle)
|
|
||||||
{
|
{
|
||||||
fwrite(B->Location, B->Size, 1, DB.Metadata.File.Handle);
|
fwrite(B->Location, B->Size, 1, DB.Metadata.File.Handle);
|
||||||
SetFileEditPosition(&DB.Metadata);
|
SetFileEditPosition(&DB.Metadata);
|
||||||
CycleSignpostedFile(&DB.Metadata);
|
CycleSignpostedFile(&DB.Metadata);
|
||||||
|
DB.Ready = TRUE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -15233,9 +15310,7 @@ InitDB(void)
|
||||||
|
|
||||||
if(Result == RC_SUCCESS)
|
if(Result == RC_SUCCESS)
|
||||||
{
|
{
|
||||||
|
if(OpenFileForWriting(&DB.Metadata.File))
|
||||||
DB.Metadata.File.Handle = fopen(DB.Metadata.File.Path, "w");
|
|
||||||
if(DB.Metadata.File.Handle)
|
|
||||||
{
|
{
|
||||||
fwrite(&DB.Header, sizeof(DB.Header), 1, DB.Metadata.File.Handle);
|
fwrite(&DB.Header, sizeof(DB.Header), 1, DB.Metadata.File.Handle);
|
||||||
|
|
||||||
|
@ -15245,10 +15320,11 @@ InitDB(void)
|
||||||
DB.Metadata.Signposts.AssetsBlock.Byte = ftell(DB.Metadata.File.Handle);
|
DB.Metadata.Signposts.AssetsBlock.Byte = ftell(DB.Metadata.File.Handle);
|
||||||
fwrite(&DB.AssetsBlock, sizeof(DB.AssetsBlock), 1, DB.Metadata.File.Handle);
|
fwrite(&DB.AssetsBlock, sizeof(DB.AssetsBlock), 1, DB.Metadata.File.Handle);
|
||||||
|
|
||||||
fclose(DB.Metadata.File.Handle);
|
CloseFile(&DB.Metadata.File, FALSE);
|
||||||
ReadFileIntoBuffer(&DB.Metadata.File);
|
ReadFileIntoBuffer(&DB.Metadata.File);
|
||||||
DB.Metadata.Signposts.ProjectsBlock.Ptr = DB.Metadata.File.Buffer.Location + DB.Metadata.Signposts.ProjectsBlock.Byte;
|
DB.Metadata.Signposts.ProjectsBlock.Ptr = DB.Metadata.File.Buffer.Location + DB.Metadata.Signposts.ProjectsBlock.Byte;
|
||||||
DB.Metadata.Signposts.AssetsBlock.Ptr = DB.Metadata.File.Buffer.Location + DB.Metadata.Signposts.AssetsBlock.Byte;
|
DB.Metadata.Signposts.AssetsBlock.Ptr = DB.Metadata.File.Buffer.Location + DB.Metadata.Signposts.AssetsBlock.Byte;
|
||||||
|
DB.Ready = TRUE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -15262,11 +15338,12 @@ InitDB(void)
|
||||||
#if 0
|
#if 0
|
||||||
DB.File.Handle = fopen(DB.File.Path, "w");
|
DB.File.Handle = fopen(DB.File.Path, "w");
|
||||||
fprintf(DB.File.Handle, "---\n");
|
fprintf(DB.File.Handle, "---\n");
|
||||||
fclose(DB.File.Handle);
|
CloseFile(&DB.File, NA);
|
||||||
ReadFileIntoBuffer(&DB.File);
|
ReadFileIntoBuffer(&DB.File);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15407,7 +15484,7 @@ InsertProjectIntoDB_TopLevel(project_generations *G, db_block_projects **Block,
|
||||||
{
|
{
|
||||||
uint64_t Byte = 0;
|
uint64_t Byte = 0;
|
||||||
|
|
||||||
DB.Metadata.File.Handle = fopen(DB.Metadata.File.Path, "w");
|
OpenFileForWriting(&DB.Metadata.File);
|
||||||
WriteFromByteToPointer(&DB.Metadata.File, &Byte, *Block);
|
WriteFromByteToPointer(&DB.Metadata.File, &Byte, *Block);
|
||||||
|
|
||||||
db_block_projects NewBlock = **Block;
|
db_block_projects NewBlock = **Block;
|
||||||
|
@ -15431,7 +15508,7 @@ InsertProjectIntoDB(project_generations *G, db_header_project **Parent, db_heade
|
||||||
{
|
{
|
||||||
uint64_t Byte = 0;
|
uint64_t Byte = 0;
|
||||||
|
|
||||||
DB.Metadata.File.Handle = fopen(DB.Metadata.File.Path, "w");
|
OpenFileForWriting(&DB.Metadata.File);
|
||||||
WriteFromByteToPointer(&DB.Metadata.File, &Byte, *Parent);
|
WriteFromByteToPointer(&DB.Metadata.File, &Byte, *Parent);
|
||||||
|
|
||||||
db_header_project NewParent = **Parent;
|
db_header_project NewParent = **Parent;
|
||||||
|
@ -15633,7 +15710,7 @@ DeleteProject_TopLevel(db_block_projects **Parent, db_header_project **Child, pr
|
||||||
uint64_t PPos = (char *)*Parent - DB.Metadata.File.Buffer.Location;
|
uint64_t PPos = (char *)*Parent - DB.Metadata.File.Buffer.Location;
|
||||||
uint64_t CPos = (char *)*Child - DB.Metadata.File.Buffer.Location;
|
uint64_t CPos = (char *)*Child - DB.Metadata.File.Buffer.Location;
|
||||||
|
|
||||||
DB.Metadata.File.Handle = fopen(DB.Metadata.File.Path, "w");
|
OpenFileForWriting(&DB.Metadata.File);
|
||||||
uint64_t Byte = 0;
|
uint64_t Byte = 0;
|
||||||
|
|
||||||
WriteFromByteToPointer(&DB.Metadata.File, &Byte, *Parent);
|
WriteFromByteToPointer(&DB.Metadata.File, &Byte, *Parent);
|
||||||
|
@ -15663,7 +15740,7 @@ DeleteProject(db_header_project **Parent, db_header_project **Child, project_gen
|
||||||
uint64_t CPos = (char *)*Child - DB.Metadata.File.Buffer.Location;
|
uint64_t CPos = (char *)*Child - DB.Metadata.File.Buffer.Location;
|
||||||
//db_project_index Index = GetCurrentProjectIndex(G);
|
//db_project_index Index = GetCurrentProjectIndex(G);
|
||||||
|
|
||||||
DB.Metadata.File.Handle = fopen(DB.Metadata.File.Path, "w");
|
OpenFileForWriting(&DB.Metadata.File);
|
||||||
uint64_t Byte = 0;
|
uint64_t Byte = 0;
|
||||||
|
|
||||||
WriteFromByteToPointer(&DB.Metadata.File, &Byte, *Parent);
|
WriteFromByteToPointer(&DB.Metadata.File, &Byte, *Parent);
|
||||||
|
@ -15723,7 +15800,7 @@ ReorganiseProjectsInterior(project_generations *G, project *CChild, uint64_t Chi
|
||||||
project_generations ThisAcc = InitAccumulator(G);
|
project_generations ThisAcc = InitAccumulator(G);
|
||||||
AccumulateProjectIndices(&ThisAcc, This);
|
AccumulateProjectIndices(&ThisAcc, This);
|
||||||
|
|
||||||
DB.Metadata.File.Handle = fopen(DB.Metadata.File.Path, "w");
|
OpenFileForWriting(&DB.Metadata.File);
|
||||||
uint64_t Byte = 0;
|
uint64_t Byte = 0;
|
||||||
|
|
||||||
WriteFromByteToPointer(&DB.Metadata.File, &Byte, SChild);
|
WriteFromByteToPointer(&DB.Metadata.File, &Byte, SChild);
|
||||||
|
@ -16036,13 +16113,13 @@ SyncGlobalPagesWithInput(neighbourhood *N, buffers *CollationBuffers)
|
||||||
if(StringsDiffer(StoredGlobalSearchDir, Config->GlobalSearchDir))
|
if(StringsDiffer(StoredGlobalSearchDir, Config->GlobalSearchDir))
|
||||||
{
|
{
|
||||||
ClearCopyStringNoFormat(ProjectsBlock->GlobalSearchDir, sizeof(ProjectsBlock->GlobalSearchDir), Config->GlobalSearchDir);
|
ClearCopyStringNoFormat(ProjectsBlock->GlobalSearchDir, sizeof(ProjectsBlock->GlobalSearchDir), Config->GlobalSearchDir);
|
||||||
WriteEntireDatabase();
|
WriteEntireDatabase(N);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(StringsDiffer(StoredGlobalSearchURL, Config->GlobalSearchURL))
|
if(StringsDiffer(StoredGlobalSearchURL, Config->GlobalSearchURL))
|
||||||
{
|
{
|
||||||
ClearCopyStringNoFormat(ProjectsBlock->GlobalSearchURL, sizeof(ProjectsBlock->GlobalSearchURL), Config->GlobalSearchURL);
|
ClearCopyStringNoFormat(ProjectsBlock->GlobalSearchURL, sizeof(ProjectsBlock->GlobalSearchURL), Config->GlobalSearchURL);
|
||||||
WriteEntireDatabase();
|
WriteEntireDatabase(N);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!ProjectsBlock->GlobalSearchDir[0])
|
if(!ProjectsBlock->GlobalSearchDir[0])
|
||||||
|
@ -16350,6 +16427,15 @@ RemoveAndFreeWatchHandles(watch_handles *W)
|
||||||
{
|
{
|
||||||
watch_handle *This = GetPlaceInBook(&W->Handles, i);
|
watch_handle *This = GetPlaceInBook(&W->Handles, i);
|
||||||
inotify_rm_watch(inotifyInstance, This->Descriptor);
|
inotify_rm_watch(inotifyInstance, This->Descriptor);
|
||||||
|
for(int j = 0; j < This->Files.ItemCount; ++j)
|
||||||
|
{
|
||||||
|
watch_file *File = GetPlaceInBook(&This->Files, j);
|
||||||
|
if(File->Handle)
|
||||||
|
{
|
||||||
|
fclose(File->Handle);
|
||||||
|
File->Handle = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
FreeBook(&This->Files);
|
FreeBook(&This->Files);
|
||||||
}
|
}
|
||||||
FreeAndReinitialiseBook(&W->Handles);
|
FreeAndReinitialiseBook(&W->Handles);
|
||||||
|
@ -16359,8 +16445,9 @@ RemoveAndFreeWatchHandles(watch_handles *W)
|
||||||
void
|
void
|
||||||
DiscardAllAndFreeConfig(void)
|
DiscardAllAndFreeConfig(void)
|
||||||
{
|
{
|
||||||
FreeSignpostedFile(&DB.Metadata); // NOTE(matt): This seems fine
|
FreeSignpostedFile(&DB.Metadata, TRUE); // NOTE(matt): This seems fine
|
||||||
FreeFile(&DB.File); // NOTE(matt): This seems fine
|
FreeFile(&DB.File, NA); // NOTE(matt): This seems fine
|
||||||
|
DB.Ready = FALSE;
|
||||||
FreeAssets(&Assets); // NOTE(matt): This seems fine
|
FreeAssets(&Assets); // NOTE(matt): This seems fine
|
||||||
RemoveAndFreeWatchHandles(&WatchHandles);
|
RemoveAndFreeWatchHandles(&WatchHandles);
|
||||||
CurrentProject = 0; // NOTE(matt): This is fine
|
CurrentProject = 0; // NOTE(matt): This is fine
|
||||||
|
@ -16572,6 +16659,8 @@ MonitorFilesystem(neighbourhood *N, buffers *CollationBuffers, template *Bespoke
|
||||||
switch(WatchFile->Type)
|
switch(WatchFile->Type)
|
||||||
{
|
{
|
||||||
case WT_HMML:
|
case WT_HMML:
|
||||||
|
{
|
||||||
|
if(DB.Ready)
|
||||||
{
|
{
|
||||||
SetCurrentProject(WatchFile->Project, N);
|
SetCurrentProject(WatchFile->Project, N);
|
||||||
string BaseFilename = GetBaseFilename(Wrap0(Event->name), WatchFile->Extension);
|
string BaseFilename = GetBaseFilename(Wrap0(Event->name), WatchFile->Extension);
|
||||||
|
@ -16583,14 +16672,18 @@ MonitorFilesystem(neighbourhood *N, buffers *CollationBuffers, template *Bespoke
|
||||||
{
|
{
|
||||||
Inserted |= (InsertEntry(N, CollationBuffers, BespokeTemplate, BaseFilename, 0) == RC_SUCCESS);
|
Inserted |= (InsertEntry(N, CollationBuffers, BespokeTemplate, BaseFilename, 0) == RC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
case WT_ASSET:
|
case WT_ASSET:
|
||||||
|
{
|
||||||
|
if(DB.Ready)
|
||||||
{
|
{
|
||||||
UpdateAsset(WatchFile->Asset, FALSE);
|
UpdateAsset(WatchFile->Asset, FALSE);
|
||||||
UpdateNeighbourhoodPointers(N, &DB.Metadata.Signposts);
|
UpdateNeighbourhoodPointers(N, &DB.Metadata.Signposts);
|
||||||
#if DEBUG_LANDMARKS
|
#if DEBUG_LANDMARKS
|
||||||
UpdatedAsset = TRUE;
|
UpdatedAsset = TRUE;
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
case WT_CONFIG:
|
case WT_CONFIG:
|
||||||
{
|
{
|
||||||
|
@ -16749,7 +16842,6 @@ main(int ArgC, char **Args)
|
||||||
PushWatchHandle(ConfigPathL, EXT_NULL, WT_CONFIG, 0, 0);
|
PushWatchHandle(ConfigPathL, EXT_NULL, WT_CONFIG, 0, 0);
|
||||||
|
|
||||||
Config = ParseConfig(ConfigPathL, &TokensList);
|
Config = ParseConfig(ConfigPathL, &TokensList);
|
||||||
rc Succeeding = RC_SUCCESS;
|
|
||||||
if(Config)
|
if(Config)
|
||||||
{
|
{
|
||||||
if(Mode & MODE_EXAMINE)
|
if(Mode & MODE_EXAMINE)
|
||||||
|
@ -16766,7 +16858,7 @@ main(int ArgC, char **Args)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* */ MEM_TEST_MID("main()");
|
/* */ MEM_TEST_MID("main()");
|
||||||
/* +MEM */ Succeeding = InitAll(&Neighbourhood, &CollationBuffers, &BespokeTemplate);
|
/* +MEM */ InitAll(&Neighbourhood, &CollationBuffers, &BespokeTemplate);
|
||||||
/* */ MEM_TEST_MID("main()");
|
/* */ MEM_TEST_MID("main()");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16782,8 +16874,6 @@ main(int ArgC, char **Args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Succeeding == RC_SUCCESS)
|
|
||||||
{
|
|
||||||
if(inotifyInstance != -1)
|
if(inotifyInstance != -1)
|
||||||
{
|
{
|
||||||
while(GlobalRunning && MonitorFilesystem(&Neighbourhood, &CollationBuffers, &BespokeTemplate, ConfigPathL, &TokensList) != RC_ARENA_FULL)
|
while(GlobalRunning && MonitorFilesystem(&Neighbourhood, &CollationBuffers, &BespokeTemplate, ConfigPathL, &TokensList) != RC_ARENA_FULL)
|
||||||
|
@ -16798,7 +16888,7 @@ main(int ArgC, char **Args)
|
||||||
// REST PUT request from insobot when a quote changes (unless we're supposed to poll insobot for them?), and rebuild
|
// REST PUT request from insobot when a quote changes (unless we're supposed to poll insobot for them?), and rebuild
|
||||||
// the player page(s) accordingly.
|
// the player page(s) accordingly.
|
||||||
//
|
//
|
||||||
if(!(Mode & MODE_DRYRUN) && Config && Config->RespectingPrivacy && time(0) - LastPrivacyCheck > Config->PrivacyCheckInterval)
|
if(!(Mode & MODE_DRYRUN) && DB.Ready && Config && Config->RespectingPrivacy && time(0) - LastPrivacyCheck > Config->PrivacyCheckInterval)
|
||||||
{
|
{
|
||||||
RecheckPrivacy(&Neighbourhood, &CollationBuffers, &BespokeTemplate);
|
RecheckPrivacy(&Neighbourhood, &CollationBuffers, &BespokeTemplate);
|
||||||
}
|
}
|
||||||
|
@ -16812,9 +16902,7 @@ main(int ArgC, char **Args)
|
||||||
}
|
}
|
||||||
|
|
||||||
DiscardAllAndFreeConfig();
|
DiscardAllAndFreeConfig();
|
||||||
RemoveAndFreeWatchHandles(&WatchHandles);
|
|
||||||
MEM_TEST_END("main()");
|
MEM_TEST_END("main()");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Exit();
|
Exit();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,12 +8,6 @@ exit
|
||||||
|
|
||||||
// config
|
// config
|
||||||
//
|
//
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
|
|
||||||
#define ArgCountPointer(...) (sizeof((void *[]){__VA_ARGS__})/sizeof(void *))
|
#define ArgCountPointer(...) (sizeof((void *[]){__VA_ARGS__})/sizeof(void *))
|
||||||
|
|
||||||
#define DigitsInInt(I) DigitsInInt_(I, sizeof(*I))
|
#define DigitsInInt(I) DigitsInInt_(I, sizeof(*I))
|
||||||
|
@ -348,6 +342,15 @@ PushTokens(memory_book *TokensList)
|
||||||
return This;
|
return This;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PopTokens(memory_book *TokensList)
|
||||||
|
{
|
||||||
|
--TokensList->ItemCount;
|
||||||
|
tokens *This = GetPlaceInBook(TokensList, TokensList->ItemCount);
|
||||||
|
FreeBook(&This->Token);
|
||||||
|
This->CurrentLine = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FreeTokensList(memory_book *TokensList)
|
FreeTokensList(memory_book *TokensList)
|
||||||
{
|
{
|
||||||
|
@ -357,7 +360,8 @@ FreeTokensList(memory_book *TokensList)
|
||||||
This->CurrentIndex = 0;
|
This->CurrentIndex = 0;
|
||||||
This->CurrentLine = 0;
|
This->CurrentLine = 0;
|
||||||
FreeBook(&This->Token);
|
FreeBook(&This->Token);
|
||||||
FreeFile(&This->File);
|
FreeFileBufferAndPath(&This->File); // NOTE(matt): Not closing file because the next time we touch this handle is in
|
||||||
|
// RemoveAndFreeWatchHandles() where we will close it
|
||||||
}
|
}
|
||||||
TokensList->ItemCount = 0;
|
TokensList->ItemCount = 0;
|
||||||
}
|
}
|
||||||
|
@ -588,22 +592,36 @@ typedef struct
|
||||||
} config;
|
} config;
|
||||||
|
|
||||||
char *ExpandPath(string Path, string *RelativeToFile); // NOTE(matt): Forward declared. Consider reorganising the code?
|
char *ExpandPath(string Path, string *RelativeToFile); // NOTE(matt): Forward declared. Consider reorganising the code?
|
||||||
void PushWatchHandle(string Path, extension_id Extension, watch_type Type, project *Project, asset *Asset); // NOTE(matt): Forward declared. Consider reorganising the code?
|
watch_file *PushWatchHandle(string Path, extension_id Extension, watch_type Type, project *Project, asset *Asset); // NOTE(matt): Forward declared. Consider reorganising the code?
|
||||||
|
|
||||||
tokens *
|
tokens *
|
||||||
Tokenise(memory_book *TokensList, string Path)
|
Tokenise(memory_book *TokensList, string Path, string *Filename, uint64_t LineNumber)
|
||||||
{
|
{
|
||||||
tokens *Result = 0;
|
tokens *Result = 0;
|
||||||
char *Path0 = MakeString0("l", &Path);
|
watch_file *WatchFile = PushWatchHandle(Path, EXT_NULL, WT_CONFIG, 0, 0);
|
||||||
FILE *Handle = 0;
|
|
||||||
PushWatchHandle(Path, EXT_NULL, WT_CONFIG, 0, 0);
|
|
||||||
if((Handle = fopen(Path0, "r")))
|
|
||||||
{
|
|
||||||
fclose(Handle);
|
|
||||||
|
|
||||||
Result = PushTokens(TokensList);
|
Result = PushTokens(TokensList);
|
||||||
Result->File = InitFile(0, &Path, EXT_NULL);
|
Result->File = InitFile(0, &Path, EXT_NULL, TRUE);
|
||||||
ReadFileIntoBuffer(&Result->File);
|
switch(ReadFileIntoBuffer(&Result->File))
|
||||||
|
{
|
||||||
|
case RC_ERROR_FILE_LOCKED:
|
||||||
|
{
|
||||||
|
ConfigErrorLockedConfigLocation(Filename, LineNumber, &Path);
|
||||||
|
FreeFile(&Result->File, TRUE);
|
||||||
|
PopTokens(TokensList);
|
||||||
|
Result = 0;
|
||||||
|
} break;
|
||||||
|
case RC_ERROR_FILE:
|
||||||
|
{
|
||||||
|
ConfigErrorUnopenableConfigLocation(Filename, LineNumber, &Path);
|
||||||
|
FreeFile(&Result->File, TRUE);
|
||||||
|
PopTokens(TokensList);
|
||||||
|
Result = 0;
|
||||||
|
} break;
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
WatchFile->Handle = Result->File.Handle;
|
||||||
|
|
||||||
buffer *B = &Result->File.Buffer;
|
buffer *B = &Result->File.Buffer;
|
||||||
SkipWhitespace(Result, B);
|
SkipWhitespace(Result, B);
|
||||||
while(B->Ptr - B->Location < B->Size)
|
while(B->Ptr - B->Location < B->Size)
|
||||||
|
@ -770,12 +788,8 @@ Tokenise(memory_book *TokensList, string Path)
|
||||||
Advance(B, Advancement);
|
Advance(B, Advancement);
|
||||||
SkipWhitespace(Result, B);
|
SkipWhitespace(Result, B);
|
||||||
}
|
}
|
||||||
|
} break;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
ConfigError(0, 0, S_WARNING, "Unable to open config file: ", &Path);
|
|
||||||
}
|
|
||||||
Free(Path0);
|
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2341,7 +2355,8 @@ ScopeTokens(scope_tree *Tree, memory_book *TokensList, tokens *T, memory_book *T
|
||||||
}
|
}
|
||||||
if(!I)
|
if(!I)
|
||||||
{
|
{
|
||||||
I = Tokenise(TokensList, IncludePathL);
|
token *This = GetPlaceInBook(&T->Token, IncludePathTokenIndex);
|
||||||
|
I = Tokenise(TokensList, IncludePathL, &Filepath, This->LineNumber);
|
||||||
}
|
}
|
||||||
if(I)
|
if(I)
|
||||||
{
|
{
|
||||||
|
@ -2352,11 +2367,6 @@ ScopeTokens(scope_tree *Tree, memory_book *TokensList, tokens *T, memory_book *T
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
token *This = GetPlaceInBook(&T->Token, IncludePathTokenIndex);
|
|
||||||
ConfigFileIncludeError(&Filepath, This->LineNumber, Wrap0(IncludePath));
|
|
||||||
}
|
|
||||||
Free(IncludePath);
|
Free(IncludePath);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -4977,7 +4987,7 @@ ParseConfig(string Path, memory_book *TokensList)
|
||||||
MEM_LOOP_POST("InitTypeSpecs")
|
MEM_LOOP_POST("InitTypeSpecs")
|
||||||
#endif
|
#endif
|
||||||
config *Result = 0;
|
config *Result = 0;
|
||||||
tokens *T = Tokenise(TokensList, Path);
|
tokens *T = Tokenise(TokensList, Path, NA, NA);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
MEM_LOOP_PRE_FREE("Tokenise")
|
MEM_LOOP_PRE_FREE("Tokenise")
|
||||||
|
@ -4993,7 +5003,7 @@ ParseConfig(string Path, memory_book *TokensList)
|
||||||
scope_tree *ScopeTree = InitRootScopeTree();
|
scope_tree *ScopeTree = InitRootScopeTree();
|
||||||
SetTypeSpec(ScopeTree, &TypeSpecs);
|
SetTypeSpec(ScopeTree, &TypeSpecs);
|
||||||
SetDefaults(ScopeTree, &TypeSpecs);
|
SetDefaults(ScopeTree, &TypeSpecs);
|
||||||
ScopeTree = ScopeTokens(ScopeTree, TokensList, T, &TypeSpecs, 0);
|
ScopeTree = ScopeTokens(ScopeTree, TokensList, T, &TypeSpecs, NA);
|
||||||
|
|
||||||
// TODO(matt): Mem testing
|
// TODO(matt): Mem testing
|
||||||
//
|
//
|
||||||
|
|
Loading…
Reference in New Issue