Commit e77d2086 authored by Matt Mascarenhas's avatar Matt Mascarenhas

cinera.c: Remove spurious file I/O

Don't \-escape anything in the index

Document server's security header (recommended) requirements
parent be37ea23
...@@ -11,9 +11,9 @@ deployment ...@@ -11,9 +11,9 @@ deployment
4. `cp hmml.a hmmlib.h ../cinera/` 4. `cp hmml.a hmmlib.h ../cinera/`
5. `cd ../cinera/` 5. `cd ../cinera/`
Note: For each parser update, remember to make and copy it into place Note: For each parser update, remember to make and copy it into place.
### Install Dependencies ### Install the dependency
1. curl 1. curl
...@@ -21,6 +21,20 @@ Note: For each parser update, remember to make and copy it into place ...@@ -21,6 +21,20 @@ Note: For each parser update, remember to make and copy it into place
1. `$SHELL cinera.c` 1. `$SHELL cinera.c`
### Configure the server
If you enforce a strict Content Security Policy and X-Frame-Options in your
server configuration as recommended by [Security
Headers](https://securityheaders.com/), you may enable _Cinera_ to function by
making two small tweaks:
add_header Content-Security-Policy "default-src … https://www.youtube.com https://s.ytimg.com";
add_header X-Frame-Options "ALLOW-FROM https://www.youtube.com";
Note: For more information about these and other security headers, see Scott
Helme's articles [Content Security Policy - An Introduction](https://scotthelme.co.uk/content-security-policy-an-introduction/)
and [Hardening your HTTP response headers](https://scotthelme.co.uk/hardening-your-http-response-headers/#x-frame-options).
### Run ### Run
#### Single Edition operation #### Single Edition operation
...@@ -28,14 +42,14 @@ Note: For each parser update, remember to make and copy it into place ...@@ -28,14 +42,14 @@ Note: For each parser update, remember to make and copy it into place
cinera test.hmml cinera test.hmml
This simply generates an HTML file (and updates `cinera_topics.css` if needed) This simply generates an HTML file (and updates `cinera_topics.css` if needed)
from `test.hmml` and outputs to `out.html` from `test.hmml` and outputs to `out.html` (configurable with -o).
#### Project Edition operation #### Project Edition operation
cinera -p ProjectID cinera -p ProjectID
Setting the ProjectID with the `-p` flag triggers Project Edition. In this Setting the ProjectID with the `-p` flag triggers Project Edition. In this
edition `cinera` monitors the Project Input Directory for new, edited and edition _Cinera_ monitors the Project Input Directory for new, edited and
deleted .hmml files, and generates one table of contents / search page and a deleted .hmml files, and generates one table of contents / search page and a
player page each for valid sets of annotations (or removes them, if needed). player page each for valid sets of annotations (or removes them, if needed).
...@@ -93,7 +107,12 @@ directory. Typical operation will involve setting these flags: ...@@ -93,7 +107,12 @@ directory. Typical operation will involve setting these flags:
hold up to 255 characters 12 to 15 may hold up to 1023 characters_ hold up to 255 characters 12 to 15 may hold up to 1023 characters_
Feel free to play with templates to your heart's content. If you do anything Feel free to play with templates to your heart's content. If you do anything
invalid, `cinera` will tell you what's wrong. invalid, _Cinera_ will tell you what's wrong.
Note: There is currently an issue sizing the annotation marker container if your
HTML document contains `<!DOCTYPE html>`. To work around this for now, please do
not declare a DOCTYPE and instead let the page be displayed in [quirks
mode](https://www.w3.org/International/articles/serving-xhtml/#quirks).
#### Arguments #### Arguments
...@@ -123,6 +142,7 @@ invalid, `cinera` will tell you what's wrong. ...@@ -123,6 +142,7 @@ invalid, `cinera` will tell you what's wrong.
-m <default medium> -m <default medium>
Override default default medium ("programming") Override default default medium ("programming")
Known project defaults: Known project defaults:
bitwise: programming
book: research book: research
pcalc: programming pcalc: programming
riscy: programming riscy: programming
...@@ -179,6 +199,10 @@ invalid, `cinera` will tell you what's wrong. ...@@ -179,6 +199,10 @@ invalid, `cinera` will tell you what's wrong.
Display (examine) index file and exit Display (examine) index file and exit
-f -f
Force integration with an incomplete template Force integration with an incomplete template
-g
Ignore video privacy status
NOTE: For use with projects whose videos are known to all be public,
to save us having to check their privacy status
-w -w
Force quote cache rebuild (memory aid: "wget") Force quote cache rebuild (memory aid: "wget")
......
...@@ -16,7 +16,7 @@ typedef struct ...@@ -16,7 +16,7 @@ typedef struct
version CINERA_APP_VERSION = { version CINERA_APP_VERSION = {
.Major = 0, .Major = 0,
.Minor = 5, .Minor = 5,
.Patch = 46 .Patch = 47
}; };
// TODO(matt): Copy in the DB 3 stuff from cinera_working.c // TODO(matt): Copy in the DB 3 stuff from cinera_working.c
...@@ -207,7 +207,7 @@ typedef struct ...@@ -207,7 +207,7 @@ typedef struct
char BaseURL[MAX_BASE_URL_LENGTH + 1]; char BaseURL[MAX_BASE_URL_LENGTH + 1];
char IndexLocation[MAX_RELATIVE_PAGE_LOCATION_LENGTH + 1]; char IndexLocation[MAX_RELATIVE_PAGE_LOCATION_LENGTH + 1];
char PlayerLocation[MAX_RELATIVE_PAGE_LOCATION_LENGTH + 1]; char PlayerLocation[MAX_RELATIVE_PAGE_LOCATION_LENGTH + 1];
char PlayerURLPrefix[MAX_PLAYER_URL_PREFIX_LENGTH + 1]; char PlayerURLPrefix[MAX_PLAYER_URL_PREFIX_LENGTH + 1]; // TODO(matt): Replace this with the OutputPath, when we add that
} index_header; } index_header;
typedef struct typedef struct
...@@ -417,8 +417,8 @@ typedef struct ...@@ -417,8 +417,8 @@ typedef struct
credential_info Credentials[] = credential_info Credentials[] =
{ {
{ "/a_waterman", "Andrew Waterman", "https://www.linkedin.com/in/andrew-waterman-76805788", "", ""}, { "a_waterman", "Andrew Waterman", "https://www.linkedin.com/in/andrew-waterman-76805788", "", ""},
{ "/y_lee", "Yunsup Lee", "https://www.linkedin.com/in/yunsup-lee-385b692b/", "", ""}, { "y_lee", "Yunsup Lee", "https://www.linkedin.com/in/yunsup-lee-385b692b/", "", ""},
{ "AndrewJDR", "Andrew Johnson", "", "", ""}, { "AndrewJDR", "Andrew Johnson", "", "", ""},
{ "AsafGartner", "Asaf Gartner", "", "", ""}, { "AsafGartner", "Asaf Gartner", "", "", ""},
{ "BretHudson", "Bret Hudson", "http://www.brethudson.com/", "cinera_sprite_patreon.png", "https://www.patreon.com/indieFunction"}, { "BretHudson", "Bret Hudson", "http://www.brethudson.com/", "cinera_sprite_patreon.png", "https://www.patreon.com/indieFunction"},
...@@ -726,48 +726,37 @@ CopyStringToBufferHTMLSafeBreakingOnSlash_(int LineNumber, buffer *Dest, char *S ...@@ -726,48 +726,37 @@ CopyStringToBufferHTMLSafeBreakingOnSlash_(int LineNumber, buffer *Dest, char *S
} }
} }
#define CopyStringToBufferJSONSafe(Dest, String) CopyStringToBufferJSONSafe_(__LINE__, Dest, String) #define CopyBuffer(Dest, Src) CopyBuffer_(__LINE__, Dest, Src)
void void
CopyStringToBufferJSONSafe_(int LineNumber, buffer *Dest, char *String) CopyBuffer_(int LineNumber, buffer *Dest, buffer *Src)
{ {
char *Start = String; Src->Ptr = Src->Location;
int Length = StringLength(String); while(*Src->Ptr)
while(*String)
{ {
switch(*String) *Dest->Ptr++ = *Src->Ptr++;
{
case '\\':
case '\"':
*Dest->Ptr++ = '\\';
++Length;
default:
*Dest->Ptr++ = *String++;
break;
}
} }
if(Dest->Ptr - Dest->Location >= Dest->Size) if(Dest->Ptr - Dest->Location >= Dest->Size)
{ {
fprintf(stderr, "CopyStringToBufferJSONSafe(%s) call on line %d cannot accommodate %d(+1)-character JSON-sanitised string:\n" fprintf(stderr, "CopyBuffer(%s) call on line %d cannot accommodate %d(+1)-character %s\n", Dest->ID, LineNumber, StringLength(Src->Location), Src->ID);
"%s\n", Dest->ID, LineNumber, Length, Start);
__asm__("int3"); __asm__("int3");
} }
*Dest->Ptr = '\0';
} }
#define CopyBuffer(Dest, Src) CopyBuffer_(__LINE__, Dest, Src) #define CopyBufferSized(Dest, Src, Size) CopyBufferSized_(__LINE__, Dest, Src, Size)
void void
CopyBuffer_(int LineNumber, buffer *Dest, buffer *Src) CopyBufferSized_(int LineNumber, buffer *Dest, buffer *Src, int Size)
{ {
Src->Ptr = Src->Location; Src->Ptr = Src->Location;
while(*Src->Ptr) while(Src->Ptr - Src->Location < Size)
{ {
*Dest->Ptr++ = *Src->Ptr++; *Dest->Ptr++ = *Src->Ptr++;
} }
if(Dest->Ptr - Dest->Location >= Dest->Size) if(Dest->Ptr - Dest->Location >= Dest->Size)
{ {
fprintf(stderr, "CopyBuffer(%s) call on line %d cannot accommodate %d(+1)-character %s\n", Dest->ID, LineNumber, StringLength(Src->Location), Src->ID); fprintf(stderr, "CopyBufferNoNull(%s) call on line %d cannot accommodate %d(+1)-character %s\n", Dest->ID, LineNumber, StringLength(Src->Location), Src->ID);
__asm__("int3"); __asm__("int3");
} }
*Dest->Ptr = '\0';
} }
int int
...@@ -2628,7 +2617,7 @@ MediumExists(char *Medium) ...@@ -2628,7 +2617,7 @@ MediumExists(char *Medium)
int int
ReadFileIntoBuffer(file_buffer *File, int BufferPadding) ReadFileIntoBuffer(file_buffer *File, int BufferPadding)
{ {
if(!(File->Handle = fopen(File->Path, "r"))) if(!(File->Handle = fopen(File->Path, "r"))) // TODO(matt): Fuller error handling
{ {
return RC_ERROR_FILE; return RC_ERROR_FILE;
} }
...@@ -2954,6 +2943,7 @@ HMMLToBuffers(buffers *CollationBuffers, template **BespokeTemplate, char *Filen ...@@ -2954,6 +2943,7 @@ HMMLToBuffers(buffers *CollationBuffers, template **BespokeTemplate, char *Filen
RewindBuffer(&CollationBuffers->Player); RewindBuffer(&CollationBuffers->Player);
RewindBuffer(&CollationBuffers->ScriptPlayer); RewindBuffer(&CollationBuffers->ScriptPlayer);
RewindBuffer(&CollationBuffers->IncludesIndex); RewindBuffer(&CollationBuffers->IncludesIndex);
RewindBuffer(&CollationBuffers->Search);
*CollationBuffers->Custom0 = '\0'; *CollationBuffers->Custom0 = '\0';
*CollationBuffers->Custom1 = '\0'; *CollationBuffers->Custom1 = '\0';
*CollationBuffers->Custom2 = '\0'; *CollationBuffers->Custom2 = '\0';
...@@ -3274,7 +3264,6 @@ HMMLToBuffers(buffers *CollationBuffers, template **BespokeTemplate, char *Filen ...@@ -3274,7 +3264,6 @@ HMMLToBuffers(buffers *CollationBuffers, template **BespokeTemplate, char *Filen
if(Config.Edition != EDITION_SINGLE && !PrivateVideo) if(Config.Edition != EDITION_SINGLE && !PrivateVideo)
{ {
RewindBuffer(&CollationBuffers->Search);
CopyStringToBuffer(&CollationBuffers->Search, "name: \""); CopyStringToBuffer(&CollationBuffers->Search, "name: \"");
if(StringsDiffer(Config.PlayerURLPrefix, "")) if(StringsDiffer(Config.PlayerURLPrefix, ""))
{ {
...@@ -3288,7 +3277,7 @@ HMMLToBuffers(buffers *CollationBuffers, template **BespokeTemplate, char *Filen ...@@ -3288,7 +3277,7 @@ HMMLToBuffers(buffers *CollationBuffers, template **BespokeTemplate, char *Filen
CopyStringToBuffer(&CollationBuffers->Search, "\"\n" CopyStringToBuffer(&CollationBuffers->Search, "\"\n"
"title: \""); "title: \"");
CopyStringToBufferJSONSafe(&CollationBuffers->Search, HMML.metadata.title); CopyStringToBufferNoFormat(&CollationBuffers->Search, HMML.metadata.title);
CopyStringToBuffer(&CollationBuffers->Search, "\"\n" CopyStringToBuffer(&CollationBuffers->Search, "\"\n"
"markers:\n"); "markers:\n");
} }
...@@ -3681,12 +3670,12 @@ AppendedIdentifier: ...@@ -3681,12 +3670,12 @@ AppendedIdentifier:
if(Anno->is_quote && !Anno->text[0]) if(Anno->is_quote && !Anno->text[0])
{ {
CopyStringToBuffer(&CollationBuffers->Search, "\u201C"); CopyStringToBuffer(&CollationBuffers->Search, "\u201C");
CopyStringToBufferJSONSafe(&CollationBuffers->Search, QuoteInfo.Text); CopyStringToBufferNoFormat(&CollationBuffers->Search, QuoteInfo.Text);
CopyStringToBuffer(&CollationBuffers->Search, "\u201D"); CopyStringToBuffer(&CollationBuffers->Search, "\u201D");
} }
else else
{ {
CopyStringToBufferJSONSafe(&CollationBuffers->Search, Anno->text); CopyStringToBufferNoFormat(&CollationBuffers->Search, Anno->text);
} }
CopyStringToBuffer(&CollationBuffers->Search, "\"\n"); CopyStringToBuffer(&CollationBuffers->Search, "\"\n");
} }
...@@ -4833,55 +4822,36 @@ GetNeighbourhood(index *Index, neighbourhood *N, int IndexEditType, bool *ThisIs ...@@ -4833,55 +4822,36 @@ GetNeighbourhood(index *Index, neighbourhood *N, int IndexEditType, bool *ThisIs
int int
InsertIntoIndex(index *Index, neighbourhood *N, buffers *CollationBuffers, template **BespokeTemplate, char *BaseFilename, bool RecheckingPrivacy) InsertIntoIndex(index *Index, neighbourhood *N, buffers *CollationBuffers, template **BespokeTemplate, char *BaseFilename, bool RecheckingPrivacy)
{ {
int IndexMetadataFileReadCode = ReadFileIntoBuffer(&Index->Metadata, 0);
switch(IndexMetadataFileReadCode)
{
case RC_ERROR_MEMORY:
return RC_ERROR_MEMORY;
case RC_ERROR_FILE:
case RC_SUCCESS:
break;
}
int IndexFileReadCode = ReadFileIntoBuffer(&Index->File, 0);
switch(IndexFileReadCode)
{
case RC_ERROR_MEMORY:
return RC_ERROR_MEMORY;
case RC_ERROR_FILE:
case RC_SUCCESS:
break;
}
int IndexEntryInsertionStart = -1; int IndexEntryInsertionStart = -1;
int IndexEntryInsertionEnd = -1; int IndexEntryInsertionEnd = -1;
Index->Header.EntryCount = 0; Index->Header.EntryCount = 0;
ClearEntry(&Index->Entry); ClearEntry(&Index->Entry);
bool Reinserting = FALSE; bool Reinserting = FALSE;
if(IndexMetadataFileReadCode == RC_SUCCESS && IndexFileReadCode == RC_SUCCESS) index_metadata *Entry = { 0 };
if(Index->Metadata.FileSize > 0 && Index->File.FileSize > 0)
{ {
// TODO(matt): Index validation? // TODO(matt): Index validation?
// Maybe at least if(!StringsDiffer(..., "name: \""); // Maybe at least if(!StringsDiffer(..., "name: \"");
// and check that we won't crash through the end of the file when skipping to the next entry // and check that we won't crash through the end of the file when skipping to the next entry
Index->Metadata.Buffer.Ptr = Index->Metadata.Buffer.Location; Index->Header = *(index_header *)Index->Metadata.Buffer.Location;
Index->Header = *(index_header *)Index->Metadata.Buffer.Ptr;
Index->Header.CurrentDBVersion = CINERA_DB_VERSION; Index->Header.CurrentDBVersion = CINERA_DB_VERSION;
Index->Header.CurrentAppVersion = CINERA_APP_VERSION; Index->Header.CurrentAppVersion = CINERA_APP_VERSION;
Index->Header.CurrentHMMLVersion.Major = hmml_version.Major; Index->Header.CurrentHMMLVersion.Major = hmml_version.Major;
Index->Header.CurrentHMMLVersion.Minor = hmml_version.Minor; Index->Header.CurrentHMMLVersion.Minor = hmml_version.Minor;
Index->Header.CurrentHMMLVersion.Patch = hmml_version.Patch; Index->Header.CurrentHMMLVersion.Patch = hmml_version.Patch;
Index->Metadata.Buffer.Ptr += sizeof(index_header); *(index_header *)Index->Metadata.Buffer.Location = Index->Header;
Index->File.Buffer.Ptr += StringLength("---\n"); Index->Metadata.Buffer.Ptr = Index->Metadata.Buffer.Location + sizeof(Index->Header);
Index->File.Buffer.Ptr = Index->File.Buffer.Location + StringLength("---\n");
index_metadata *Entry = { 0 };
N->ThisIndex = BinarySearchForMetadataEntry(Index, &Entry, BaseFilename); N->ThisIndex = BinarySearchForMetadataEntry(Index, &Entry, BaseFilename);
if(Entry) if(Entry)
{ {
// Reinsert // Reinsert
Reinserting = TRUE; Reinserting = TRUE;
N->This.Size = Entry->Size;
N->This.LinkOffsets.PrevStart = Entry->LinkOffsets.PrevStart; N->This.LinkOffsets.PrevStart = Entry->LinkOffsets.PrevStart;
N->This.LinkOffsets.PrevEnd = Entry->LinkOffsets.PrevEnd; N->This.LinkOffsets.PrevEnd = Entry->LinkOffsets.PrevEnd;
N->This.LinkOffsets.NextStart = Entry->LinkOffsets.NextStart; N->This.LinkOffsets.NextStart = Entry->LinkOffsets.NextStart;
...@@ -4911,17 +4881,11 @@ InsertIntoIndex(index *Index, neighbourhood *N, buffers *CollationBuffers, templ ...@@ -4911,17 +4881,11 @@ InsertIntoIndex(index *Index, neighbourhood *N, buffers *CollationBuffers, templ
else else
{ {
// NOTE(matt): Initialising new index_header // NOTE(matt): Initialising new index_header
Index->Header.CurrentDBVersion = CINERA_DB_VERSION; Index->Header.InitialDBVersion = Index->Header.CurrentDBVersion = CINERA_DB_VERSION;
Index->Header.CurrentAppVersion = CINERA_APP_VERSION; Index->Header.InitialAppVersion = Index->Header.CurrentAppVersion = CINERA_APP_VERSION;
Index->Header.CurrentHMMLVersion.Major = hmml_version.Major; Index->Header.InitialHMMLVersion.Major = Index->Header.CurrentHMMLVersion.Major = hmml_version.Major;
Index->Header.CurrentHMMLVersion.Minor = hmml_version.Minor; Index->Header.InitialHMMLVersion.Minor = Index->Header.CurrentHMMLVersion.Minor = hmml_version.Minor;
Index->Header.CurrentHMMLVersion.Patch = hmml_version.Patch; Index->Header.InitialHMMLVersion.Patch = Index->Header.CurrentHMMLVersion.Patch = hmml_version.Patch;
Index->Header.InitialDBVersion = CINERA_DB_VERSION;
Index->Header.InitialAppVersion = CINERA_APP_VERSION;
Index->Header.InitialHMMLVersion.Major = hmml_version.Major;
Index->Header.InitialHMMLVersion.Minor = hmml_version.Minor;
Index->Header.InitialHMMLVersion.Patch = hmml_version.Patch;
CopyStringNoFormat(Index->Header.ProjectID, sizeof(Index->Header.ProjectID), Config.ProjectID); CopyStringNoFormat(Index->Header.ProjectID, sizeof(Index->Header.ProjectID), Config.ProjectID);
...@@ -4958,7 +4922,7 @@ InsertIntoIndex(index *Index, neighbourhood *N, buffers *CollationBuffers, templ ...@@ -4958,7 +4922,7 @@ InsertIntoIndex(index *Index, neighbourhood *N, buffers *CollationBuffers, templ
switch(HMMLToBuffers(CollationBuffers, BespokeTemplate, InputFile, N)) switch(HMMLToBuffers(CollationBuffers, BespokeTemplate, InputFile, N))
{ {
// TODO(matt): Actually sort out the fatality of these cases, once we are always-on // TODO(matt): Actually sort out the fatality of these cases
case RC_ERROR_FILE: case RC_ERROR_FILE:
case RC_ERROR_FATAL: case RC_ERROR_FATAL:
return RC_ERROR_FATAL; return RC_ERROR_FATAL;
...@@ -4971,75 +4935,69 @@ InsertIntoIndex(index *Index, neighbourhood *N, buffers *CollationBuffers, templ ...@@ -4971,75 +4935,69 @@ InsertIntoIndex(index *Index, neighbourhood *N, buffers *CollationBuffers, templ
VideoIsPrivate = TRUE; VideoIsPrivate = TRUE;
case RC_SUCCESS: case RC_SUCCESS:
break; break;
};
ClearCopyStringNoFormat(N->This.BaseFilename, sizeof(N->This.BaseFilename), BaseFilename);
if(N->This.Size > 0)
{
ClearCopyStringNoFormat(N->This.Title, sizeof(N->This.Title), CollationBuffers->Title);
} }
if(!(Index->Metadata.Handle = fopen(Index->Metadata.Path, "w"))) { FreeBuffer(&Index->Metadata.Buffer); return RC_ERROR_FILE; } ClearCopyStringNoFormat(N->This.BaseFilename, sizeof(N->This.BaseFilename), BaseFilename);
if(!(Index->File.Handle = fopen(Index->File.Path, "w"))) { FreeBuffer(&Index->File.Buffer); return RC_ERROR_FILE; } if(N->This.Size > 0) { ClearCopyStringNoFormat(N->This.Title, sizeof(N->This.Title), CollationBuffers->Title); }
if(!Reinserting) { ++Index->Header.EntryCount; }
fwrite(&Index->Header, sizeof(index_header), 1, Index->Metadata.Handle);
if(IndexMetadataFileReadCode == RC_SUCCESS)
{
Index->Metadata.Buffer.Ptr = Index->Metadata.Buffer.Location + sizeof(index_header);
}
if(Reinserting) if(Reinserting)
{ {
// NOTE(matt): We hit this during the start-up sync and when copying in a .hmml file over an already existing one, but
// would need to fool about with the inotify event processing to get to this branch in the case that saving
// a file triggers an IN_DELETE followed by an IN_CLOSE_WRITE event
//
// We will almost definitely need to handle our inotify events differently once we are outputting the player
// pages of private videos to "secret locations", because we will need to preserve the randomly generated
// location stored in the .metadata
// Reinsert // Reinsert
Index->Metadata.Buffer.Ptr = Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * N->ThisIndex; if(!VideoIsPrivate)
*(index_metadata *)Index->Metadata.Buffer.Ptr = N->This;
fwrite(Index->Metadata.Buffer.Location + sizeof(index_header), Index->Metadata.FileSize - sizeof(index_header), 1, Index->Metadata.Handle);
fwrite(Index->File.Buffer.Location, IndexEntryInsertionStart, 1, Index->File.Handle);
fwrite(CollationBuffers->Search.Location, N->This.Size, 1, Index->File.Handle);
fwrite(Index->File.Buffer.Location + IndexEntryInsertionEnd, Index->File.FileSize - IndexEntryInsertionEnd, 1, Index->File.Handle);
if(VideoIsPrivate)
{ {
if(!RecheckingPrivacy) if(!(Index->File.Handle = fopen(Index->File.Path, "w"))) { return RC_ERROR_FILE; }
fwrite(Index->File.Buffer.Location, IndexEntryInsertionStart, 1, Index->File.Handle);
fwrite(CollationBuffers->Search.Location, N->This.Size, 1, Index->File.Handle);
fwrite(Index->File.Buffer.Location + IndexEntryInsertionEnd, Index->File.FileSize - IndexEntryInsertionEnd, 1, Index->File.Handle);
fclose(Index->File.Handle);
if(N->This.Size == IndexEntryInsertionEnd - IndexEntryInsertionStart)
{ {
LogError(LOG_NOTICE, "Privately Reinserted %s", BaseFilename); Index->File.Buffer.Ptr = Index->File.Buffer.Location + IndexEntryInsertionStart;
fprintf(stderr, "\e[0;34mPrivately Reinserted\e[0m %s\n", BaseFilename); CopyBufferSized(&Index->File.Buffer, &CollationBuffers->Search, N->This.Size);
}
else
{
FreeBuffer(&Index->File.Buffer);
ReadFileIntoBuffer(&Index->File, 0);
} }
}
else
{
LogError(LOG_NOTICE, "Reinserted %s - %s", BaseFilename, CollationBuffers->Title); LogError(LOG_NOTICE, "Reinserted %s - %s", BaseFilename, CollationBuffers->Title);
fprintf(stderr, "\e[1;33mReinserted\e[0m %s - %s\n", BaseFilename, CollationBuffers->Title); fprintf(stderr, "\e[1;33mReinserted\e[0m %s - %s\n", BaseFilename, CollationBuffers->Title);
} }
else if(!RecheckingPrivacy)
{
LogError(LOG_NOTICE, "Privately Reinserted %s", BaseFilename);
fprintf(stderr, "\e[0;34mPrivately Reinserted\e[0m %s\n", BaseFilename);
}
} }
else if(IndexEntryInsertionStart >= 0) else
{ {
// Insert new ++Index->Header.EntryCount;
fwrite(Index->Metadata.Buffer.Location + sizeof(index_header), sizeof(index_metadata) * N->ThisIndex, 1, Index->Metadata.Handle);
fwrite(&N->This, sizeof(index_metadata), 1, Index->Metadata.Handle); if(!(Index->Metadata.Handle = fopen(Index->Metadata.Path, "w"))) { return RC_ERROR_FILE; }
fwrite(Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * N->ThisIndex, fwrite(&Index->Header, sizeof(index_header), 1, Index->Metadata.Handle);
Index->Metadata.FileSize - sizeof(index_header) - sizeof(index_metadata) * N->ThisIndex,
1, Index->Metadata.Handle);
fwrite(Index->File.Buffer.Location, IndexEntryInsertionStart, 1, Index->File.Handle); if(!(Index->File.Handle = fopen(Index->File.Path, "w"))) { return RC_ERROR_FILE; }
fwrite(CollationBuffers->Search.Location, N->This.Size, 1, Index->File.Handle);
fwrite(Index->File.Buffer.Location + IndexEntryInsertionStart, Index->File.FileSize - IndexEntryInsertionStart, 1, Index->File.Handle);
if(VideoIsPrivate) if(IndexEntryInsertionStart >= 0)
{ {
if(!RecheckingPrivacy) // Insert new
fwrite(Index->Metadata.Buffer.Location + sizeof(index_header), sizeof(index_metadata) * N->ThisIndex, 1, Index->Metadata.Handle);
fwrite(&N->This, sizeof(index_metadata), 1, Index->Metadata.Handle);
fwrite(Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * N->ThisIndex,
Index->Metadata.FileSize - sizeof(index_header) - sizeof(index_metadata) * N->ThisIndex,
1, Index->Metadata.Handle);
fwrite(Index->File.Buffer.Location, IndexEntryInsertionStart, 1, Index->File.Handle);
fwrite(CollationBuffers->Search.Location, N->This.Size, 1, Index->File.Handle);
fwrite(Index->File.Buffer.Location + IndexEntryInsertionStart, Index->File.FileSize - IndexEntryInsertionStart, 1, Index->File.Handle);
if(!VideoIsPrivate)
{
LogError(LOG_NOTICE, "Inserted %s - %s", BaseFilename, CollationBuffers->Title);
fprintf(stderr, "\e[1;32mInserted\e[0m %s - %s\n", BaseFilename, CollationBuffers->Title);
}
else if(!RecheckingPrivacy)
{ {
LogError(LOG_NOTICE, "Privately Inserted %s", BaseFilename); LogError(LOG_NOTICE, "Privately Inserted %s", BaseFilename);
fprintf(stderr, "\e[0;34mPrivately Inserted\e[0m %s\n", BaseFilename); fprintf(stderr, "\e[0;34mPrivately Inserted\e[0m %s\n", BaseFilename);
...@@ -5047,46 +5005,42 @@ InsertIntoIndex(index *Index, neighbourhood *N, buffers *CollationBuffers, templ ...@@ -5047,46 +5005,42 @@ InsertIntoIndex(index *Index, neighbourhood *N, buffers *CollationBuffers, templ
} }
else else
{ {
LogError(LOG_NOTICE, "Inserted %s - %s", BaseFilename, CollationBuffers->Title); // Append new
fprintf(stderr, "\e[1;32mInserted\e[0m %s - %s\n", BaseFilename, CollationBuffers->Title); if(Index->Metadata.FileSize > 0)
} {
} fwrite(Index->Metadata.Buffer.Location + sizeof(index_header), Index->Metadata.FileSize - sizeof(index_header), 1, Index->Metadata.Handle);
else fwrite(Index->File.Buffer.Location, Index->File.FileSize, 1, Index->File.Handle);
{ }
// Append new else
if(IndexMetadataFileReadCode == RC_SUCCESS) {
{ fprintf(Index->File.Handle, "---\n");
fwrite(Index->Metadata.Buffer.Location + sizeof(index_header), Index->Metadata.FileSize - sizeof(index_header), 1, Index->Metadata.Handle); }
fwrite(Index->File.Buffer.Location, Index->File.FileSize, 1, Index->File.Handle); fwrite(&N->This, sizeof(index_metadata), 1, Index->Metadata.Handle);
} fwrite(CollationBuffers->Search.Location, N->This.Size, 1, Index->File.Handle);
else
{ if(!VideoIsPrivate)
fprintf(Index->File.Handle, "---\n"); {
} LogError(LOG_NOTICE, "Appended %s - %s", BaseFilename, CollationBuffers->Title);
fwrite(&N->This, sizeof(index_metadata), 1, Index->Metadata.Handle); fprintf(stderr, "\e[1;32mAppended\e[0m %s - %s\n", BaseFilename, CollationBuffers->Title);
fwrite(CollationBuffers->Search.Location, N->This.Size, 1, Index->File.Handle); }
if(VideoIsPrivate) else if(!RecheckingPrivacy)
{
if(!RecheckingPrivacy)
{ {
LogError(LOG_NOTICE, "Privately Appended %s", BaseFilename); LogError(LOG_NOTICE, "Privately Appended %s", BaseFilename);
fprintf(stderr, "\e[0;34mPrivately Appended\e[0m %s\n", BaseFilename); fprintf(stderr, "\e[0;34mPrivately Appended\e[0m %s\n", BaseFilename);
} }
} }
else
{
LogError(LOG_NOTICE, "Appended %s - %s", BaseFilename, CollationBuffers->Title);
fprintf(stderr, "\e[1;32mAppended\e[0m %s - %s\n", BaseFilename, CollationBuffers->Title);
}
}
fclose(Index->Metadata.Handle); fclose(Index->Metadata.Handle);
fclose(Index->File.Handle); FreeBuffer(&Index->Metadata.Buffer);
ReadFileIntoBuffer(&Index->Metadata, 0);
fclose(Index->File.Handle);
FreeBuffer(&Index->File.Buffer);
ReadFileIntoBuffer(&Index->File, 0);
}
FreeBuffer(&Index->Metadata.Buffer);
FreeBuffer(&Index->File.Buffer);
// TODO(matt): Remove VideoIsPrivate in favour of generating a player page in a random location // TODO(matt): Remove VideoIsPrivate in favour of generating a player page in a random location
return VideoIsPrivate ? RC_PRIVATE_VIDEO : Reinserting ? RC_SUCCESS : RC_UNFOUND; return VideoIsPrivate ? RC_PRIVATE_VIDEO : RC_SUCCESS;
} }
void void
...@@ -5279,19 +5233,6 @@ DeleteNeighbourLinks(file_buffer *File, index_metadata *Metadata) ...@@ -5279,19 +5233,6 @@ DeleteNeighbourLinks(file_buffer *File, index_metadata *Metadata)
int int
LinkNeighbours(index *Index, neighbourhood *N, char *BaseFilename, int LinkType) LinkNeighbours(index *Index, neighbourhood *N, char *BaseFilename, int LinkType)
{ {
switch(ReadFileIntoBuffer(&Index->Metadata, 0))
{
case RC_ERROR_FILE:
return RC_ERROR_FILE;
case RC_ERROR_MEMORY:
LogError(LOG_ERROR, "LinkNeighbours(): %s", strerror(errno));
return RC_ERROR_MEMORY;
case RC_SUCCESS:
break;
}
Index->Header = *(index_header *)Index->Metadata.Buffer.Ptr;
if(N->PrevIndex == -1 && N->NextIndex == -1) if(N->PrevIndex == -1 && N->NextIndex == -1)
{ {
buffer LonePlayerPagePath; buffer LonePlayerPagePath;
...@@ -5304,9 +5245,6 @@ LinkNeighbours(index *Index, neighbourhood *N, char *BaseFilename, int LinkType) ...@@ -5304,9 +5245,6 @@ LinkNeighbours(index *Index, neighbourhood *N, char *BaseFilename, int LinkType)
DeleteNeighbourLinks(&LonePlayerPage, &N->This); DeleteNeighbourLinks(&LonePlayerPage, &N->This);
DeclaimBuffer(&LonePlayerPagePath); DeclaimBuffer(&LonePlayerPagePath);
Index->Metadata.Buffer.Ptr = Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * N->ThisIndex;
*(index_metadata *)Index->Metadata.Buffer.Ptr = N->This;
} }
else else
{ {
...@@ -5335,15 +5273,11 @@ LinkNeighbours(index *Index, neighbourhood *N, char *BaseFilename, int LinkType) ...@@ -5335,15 +5273,11 @@ LinkNeighbours(index *Index, neighbourhood *N, char *BaseFilename, int LinkType)
InsertNeighbourLink(&ThisPlayerPage, &N->This, &N->Prev, LINK_PREV, Index->Header.ProjectName, N->NextIndex == -1 ? TRUE : FALSE); InsertNeighbourLink(&ThisPlayerPage, &N->This, &N->Prev, LINK_PREV, Index->Header.ProjectName, N->NextIndex == -1 ? TRUE : FALSE);
DeclaimBuffer(&ThisPlayerPagePath); DeclaimBuffer(&ThisPlayerPagePath);
Index->Metadata.Buffer.Ptr = Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * N->ThisIndex;
*(index_metadata *)Index->Metadata.Buffer.Ptr = N->This;
} }
case LINK_INCLUDE: case LINK_INCLUDE:
{ {
InsertNeighbourLink(&PreviousPlayerPage, &N->Prev, &N->This, LINK_NEXT, Index->Header.ProjectName, N->PrevIsFirst); InsertNeighbourLink(&PreviousPlayerPage, &N->Prev, &N->This, LINK_NEXT, Index->Header.ProjectName, N->PrevIsFirst);
Index->Metadata.Buffer.Ptr = Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * N->PrevIndex; *(index_metadata *)(Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * N->PrevIndex) = N->Prev;
*(index_metadata *)Index->Metadata.Buffer.Ptr = N->Prev;
} }
} }
...@@ -5375,28 +5309,17 @@ LinkNeighbours(index *Index, neighbourhood *N, char *BaseFilename, int LinkType) ...@@ -5375,28 +5309,17 @@ LinkNeighbours(index *Index, neighbourhood *N, char *BaseFilename, int LinkType)
InsertNeighbourLink(&ThisPlayerPage, &N->This, &N->Next, LINK_NEXT, Index->Header.ProjectName, N->PrevIndex == -1 ? TRUE : FALSE); InsertNeighbourLink(&ThisPlayerPage, &N->This, &N->Next, LINK_NEXT, Index->Header.ProjectName, N->PrevIndex == -1 ? TRUE : FALSE);
DeclaimBuffer(&ThisPlayerPagePath); DeclaimBuffer(&ThisPlayerPagePath);
Index->Metadata.Buffer.Ptr = Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * N->ThisIndex;
*(index_metadata *)Index->Metadata.Buffer.Ptr = N->This;