diff --git a/cinera/cinera.c b/cinera/cinera.c index de2bfd1..6f79ba1 100644 --- a/cinera/cinera.c +++ b/cinera/cinera.c @@ -14,21 +14,12 @@ typedef struct version CINERA_APP_VERSION = { .Major = 0, .Minor = 5, - .Patch = 39 + .Patch = 40 }; // TODO(matt): Copy in the DB 3 stuff from cinera_working.c #define CINERA_DB_VERSION 3 -typedef unsigned int bool; -#define TRUE 1 -#define FALSE 0 - -#define DEBUG 0 -#define DEBUG_MEM 0 -#define BINARY_SEARCH 1 -bool PROFILING = 0; - #include // NOTE(matt): varargs #include // NOTE(matt): printf, sprintf, vsprintf, fprintf, perror #include // NOTE(matt): calloc, malloc, free @@ -45,6 +36,14 @@ bool PROFILING = 0; #include // NOTE(matt): inotify #include // NOTE(matt): sleep() +typedef unsigned int bool; +#define TRUE 1 +#define FALSE 0 + +#define DEBUG 0 +#define DEBUG_MEM 0 + +bool PROFILING = 0; clock_t TIMING_START; #define START_TIMING_BLOCK(...) if(PROFILING) { printf(__VA_ARGS__); TIMING_START = clock(); } #define END_TIMING_BLOCK() if(PROFILING) { printf("\e[1;34m%ld\e[0m\n", clock() - TIMING_START);} @@ -86,9 +85,11 @@ enum enum { - MODE_ONESHOT = 1 << 0, - MODE_EXAMINE = 1 << 1, - MODE_NOCACHE = 1 << 2, + MODE_FORCEINTEGRATION = 1 << 0, + MODE_ONESHOT = 1 << 1, + MODE_EXAMINE = 1 << 2, + MODE_NOCACHE = 1 << 3, + MODE_NOPRIVACY = 1 << 4, } modes; enum @@ -107,6 +108,7 @@ enum RC_UNFOUND, RC_INVALID_REFERENCE, RC_INVALID_TEMPLATE, + RC_PRIVATE_VIDEO, RC_NOOP, RC_RIP, RC_SUCCESS @@ -128,7 +130,6 @@ typedef struct int LogLevel; int Mode; int UpdateInterval; - bool ForceIntegration; // Advisedly universal, although could be per-project char *RootDir; // Absolute @@ -166,6 +167,7 @@ typedef struct // NOTE(matt): Globals config Config = {}; arena MemoryArena; +time_t LastPrivacyCheck; time_t LastQuoteFetch; // @@ -2120,6 +2122,10 @@ PrintUsage(char *BinaryLocation, config *DefaultConfig) " Display (examine) index file and exit\n" " -f\n" " Force integration with an incomplete template\n" + " -g\n" + " Ignore video privacy status\n" + " NOTE: For use with projects whose videos are known to all be public,\n" + " to save us having to check their privacy status\n" " -w\n" " Force quote cache rebuild \e[1;30m(memory aid: \"wget\")\e[0m\n" "\n" @@ -2257,7 +2263,7 @@ NextTagSearch: FoundIndex = TRUE; goto RecordTag; case TAG_INCLUDES: - if(!Config.ForceIntegration && FoundIncludes == TRUE) + if(!(Config.Mode & MODE_FORCEINTEGRATION) && FoundIncludes == TRUE) { CopyStringToBuffer(&Errors, "Template contains more than one tag\n", ThisTagName); HaveErrors = TRUE; @@ -2265,7 +2271,7 @@ NextTagSearch: FoundIncludes = TRUE; goto RecordTag; case TAG_MENUS: - if(!Config.ForceIntegration && FoundMenus == TRUE) + if(!(Config.Mode & MODE_FORCEINTEGRATION) && FoundMenus == TRUE) { CopyStringToBuffer(&Errors, "Template contains more than one tag\n", Tags[i].Tag); HaveErrors = TRUE; @@ -2273,7 +2279,7 @@ NextTagSearch: FoundMenus = TRUE; goto RecordTag; case TAG_PLAYER: - if(!Config.ForceIntegration && FoundPlayer == TRUE) + if(!(Config.Mode & MODE_FORCEINTEGRATION) && FoundPlayer == TRUE) { CopyStringToBuffer(&Errors, "Template contains more than one tag\n", Tags[i].Tag); HaveErrors = TRUE; @@ -2281,12 +2287,12 @@ NextTagSearch: FoundPlayer = TRUE; goto RecordTag; case TAG_SCRIPT: - if(!Config.ForceIntegration && FoundPlayer == FALSE) + if(!(Config.Mode & MODE_FORCEINTEGRATION) && (FoundMenus == FALSE || FoundPlayer == FALSE)) { - CopyStringToBuffer(&Errors, " must come after \n", Tags[i].Tag); + CopyStringToBuffer(&Errors, " must come after and \n", Tags[i].Tag); HaveErrors = TRUE; } - if(!Config.ForceIntegration && FoundScript == TRUE) + if(!(Config.Mode & MODE_FORCEINTEGRATION) && FoundScript == TRUE) { CopyStringToBuffer(&Errors, "Template contains more than one tag\n", Tags[i].Tag); HaveErrors = TRUE; @@ -2323,7 +2329,7 @@ RecordTag: (*Template)->Metadata.Validity |= PAGE_PLAYER; } - if(!Config.ForceIntegration) + if(!(Config.Mode & MODE_FORCEINTEGRATION)) { if(TemplateType == TEMPLATE_INDEX && !((*Template)->Metadata.Validity & PAGE_INDEX)) { @@ -2434,6 +2440,7 @@ ReadFileIntoBuffer(file_buffer *File, int BufferPadding) fread(File->Buffer.Location, File->FileSize, 1, File->Handle); File->Buffer.Location[File->FileSize] = '\0'; fclose(File->Handle); + File->Buffer.ID = File->Path; return RC_SUCCESS; } @@ -2542,6 +2549,87 @@ ExamineIndex(index *Index) return RC_SUCCESS; } +enum +{ + C_SEEK_FORWARDS, + C_SEEK_BACKWARDS +} seek_directions; + +enum +{ + C_SEEK_START, // First character of string + C_SEEK_BEFORE, // Character before first character + C_SEEK_END, // Last character of string + C_SEEK_AFTER // Character after last character +} seek_positions; + +int +SeekBufferForString(buffer *Buffer, char *String, + int Direction, /* seek_directions */ + int Position /* seek_positions */) +{ + // TODO(matt): Optimise? Some means of analysing the String to increment + // the pointer in bigger strides + + // Perhaps count up runs of consecutive chars and seek for the char with + // the longest run, in strides of that run-length + + char *InitialLocation = Buffer->Ptr; + if(Direction == C_SEEK_FORWARDS) + { + while(Buffer->Ptr - Buffer->Location < Buffer->Size - StringLength(String) + && StringsDifferT(String, Buffer->Ptr, 0)) + { + ++Buffer->Ptr; + } + } + else + { + while(Buffer->Ptr > Buffer->Location + && StringsDifferT(String, Buffer->Ptr, 0)) + { + --Buffer->Ptr; + } + } + + if(StringsDifferT(String, Buffer->Ptr, 0)) + { + Buffer->Ptr = InitialLocation; + return RC_UNFOUND; + } + + switch(Position) + { + case C_SEEK_START: + break; + case C_SEEK_BEFORE: + if(Buffer->Ptr > Buffer->Location) + { + --Buffer->Ptr; + break; + } + else + { + return RC_ERROR_SEEK; // Ptr remains at string start + } + case C_SEEK_END: + Buffer->Ptr += StringLength(String) - 1; + break; + case C_SEEK_AFTER: + if(Buffer->Size >= Buffer->Ptr - Buffer->Location + StringLength(String)) + { + Buffer->Ptr += StringLength(String); + break; + } + else + { + return RC_ERROR_SEEK; // Ptr remains at string start + // NOTE(matt): Should it, however, be left at the end of the string? + } + } + return RC_SUCCESS; +} + #define HMMLCleanup() \ DeclaimBuffer(&FilterState); \ DeclaimBuffer(&CreditsMenu); \ @@ -2552,8 +2640,80 @@ ExamineIndex(index *Index) DeclaimBuffer(&QuoteMenu); \ hmml_free(&HMML); +void +ClearTerminalRow(int Length) +{ + fprintf(stderr, "\r"); + for(int i = 0; i < Length; ++i) + { + fprintf(stderr, " "); + } + fprintf(stderr, "\r"); +} + +bool +VideoIsPrivate(char *VideoID) +{ + // NOTE(matt): Currently only supports YouTube + char Message[128]; + CopyString(Message, "\e[0;35mChecking\e[0m privacy status of: https://youtube.com/watch?v=%s", VideoID); + fprintf(stderr, Message); + int MessageLength = StringLength(Message); + buffer VideoAPIResponse; + ClaimBuffer(&VideoAPIResponse, "VideoAPIResponse", Kilobytes(1)); + + CURL *curl = curl_easy_init(); + if(curl) { + LastPrivacyCheck = time(0); +#define APIKey "AIzaSyAdV2U8ivPk8PHMaPMId0gynksw_gdzr9k" + char URL[1024] = {0}; + CopyString(URL, "https://www.googleapis.com/youtube/v3/videos?key=%s&part=status&id=%s", APIKey, VideoID); + CURLcode CurlReturnCode; + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &VideoAPIResponse.Ptr); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlIntoBuffer); + curl_easy_setopt(curl, CURLOPT_URL, URL); + if((CurlReturnCode = curl_easy_perform(curl))) + { + fprintf(stderr, "%s\n", curl_easy_strerror(CurlReturnCode)); + } + curl_easy_cleanup(curl); + + VideoAPIResponse.Ptr = VideoAPIResponse.Location; + SeekBufferForString(&VideoAPIResponse, "{", C_SEEK_FORWARDS, C_SEEK_AFTER); + SeekBufferForString(&VideoAPIResponse, "\"totalResults\": ", C_SEEK_FORWARDS, C_SEEK_AFTER); + if(*VideoAPIResponse.Ptr == '0') + { + DeclaimBuffer(&VideoAPIResponse); + // printf("Private video: https://youtube.com/watch?v=%s\n", VideoID); + ClearTerminalRow(MessageLength); + return TRUE; + } + SeekBufferForString(&VideoAPIResponse, "{", C_SEEK_FORWARDS, C_SEEK_AFTER); + SeekBufferForString(&VideoAPIResponse, "\"privacyStatus\": \"", C_SEEK_FORWARDS, C_SEEK_AFTER); + char Status[16]; + CopyStringNoFormatT(Status, VideoAPIResponse.Ptr, '\"'); + if(!StringsDiffer(Status, "public")) + { + DeclaimBuffer(&VideoAPIResponse); + ClearTerminalRow(MessageLength); + return FALSE; + } + } + DeclaimBuffer(&VideoAPIResponse); + // printf("Unlisted video: https://youtube.com/watch?v=%s\n", VideoID); + ClearTerminalRow(MessageLength); + return TRUE; +} + +typedef struct +{ + index_metadata Prev, This, Next; + bool PrevIsFirst, NextIsFinal; + short int PrevIndex, ThisIndex, NextIndex; +} neighbourhood; + int -HMMLToBuffers(buffers *CollationBuffers, template **BespokeTemplate, char *Filename, link_insertion_offsets *LinkOffsets, neighbours *Neighbours) +HMMLToBuffers(buffers *CollationBuffers, template **BespokeTemplate, char *Filename, neighbourhood *N) { RewindBuffer(&CollationBuffers->IncludesPlayer); RewindBuffer(&CollationBuffers->Menus); @@ -2750,12 +2910,12 @@ HMMLToBuffers(buffers *CollationBuffers, template **BespokeTemplate, char *Filen return RC_ERROR_HMML; } - if(LinkOffsets) + if(N) { - LinkOffsets->PrevStart = 0; - LinkOffsets->NextStart = 0; - LinkOffsets->PrevEnd = 0; - LinkOffsets->NextEnd = 0; + N->This.LinkOffsets.PrevStart = 0; + N->This.LinkOffsets.PrevEnd = 0; + N->This.LinkOffsets.NextStart = 0; + N->This.LinkOffsets.NextEnd = 0; } #if DEBUG @@ -2828,21 +2988,21 @@ HMMLToBuffers(buffers *CollationBuffers, template **BespokeTemplate, char *Filen "
\n" "
\n", HMML.metadata.id, StringsDiffer(Config.Theme, "") ? Config.Theme : HMML.metadata.project); - if(LinkOffsets) + if(N) { - LinkOffsets->PrevStart = (CollationBuffers->Player.Ptr - CollationBuffers->Player.Location); - if(Neighbours->Prev.BaseFilename || Neighbours->Next.BaseFilename) + N->This.LinkOffsets.PrevStart = (CollationBuffers->Player.Ptr - CollationBuffers->Player.Location); + if(N->Prev.Size || N->Next.Size) { - if(Neighbours->Prev.BaseFilename) + if(N->Prev.Size) { // TODO(matt): Once we have a more rigorous notion of "Day Numbers", perhaps also use them here buffer PreviousPlayerURL; ClaimBuffer(&PreviousPlayerURL, "PreviousPlayerURL", MAX_BASE_URL_LENGTH + 1 + MAX_RELATIVE_PAGE_LOCATION_LENGTH + 1 + MAX_PLAYER_URL_PREFIX_LENGTH + MAX_BASE_FILENAME_LENGTH); - ConstructPlayerURL(&PreviousPlayerURL, Neighbours->Prev.BaseFilename); + ConstructPlayerURL(&PreviousPlayerURL, N->Prev.BaseFilename); CopyStringToBuffer(&CollationBuffers->Player, "
Previous: '%s'
\n", PreviousPlayerURL.Location, - Neighbours->Prev.Title); + N->Prev.Title); DeclaimBuffer(&PreviousPlayerURL); } @@ -2852,7 +3012,7 @@ HMMLToBuffers(buffers *CollationBuffers, template **BespokeTemplate, char *Filen "
Welcome to %s
\n", CollationBuffers->ProjectName); } } - LinkOffsets->PrevEnd = (CollationBuffers->Player.Ptr - CollationBuffers->Player.Location - LinkOffsets->PrevStart); + N->This.LinkOffsets.PrevEnd = (CollationBuffers->Player.Ptr - CollationBuffers->Player.Location - N->This.LinkOffsets.PrevStart); } CopyStringToBuffer(&CollationBuffers->Player, @@ -2868,7 +3028,21 @@ HMMLToBuffers(buffers *CollationBuffers, template **BespokeTemplate, char *Filen return RC_ERROR_HMML; } - if(Config.Edition != EDITION_SINGLE) + bool PrivateVideo = FALSE; + if(Config.Edition != EDITION_SINGLE && N->This.Size == 0 && !(Config.Mode & MODE_NOPRIVACY)) + { + if(VideoIsPrivate(HMML.metadata.id)) + { + // TODO(matt): Actually generate these guys, just putting them in a secret location + N->This.LinkOffsets.PrevStart = 0; + N->This.LinkOffsets.PrevEnd = 0; + PrivateVideo = TRUE; + HMMLCleanup(); + return RC_PRIVATE_VIDEO; + } + } + + if(Config.Edition != EDITION_SINGLE && !PrivateVideo) { RewindBuffer(&CollationBuffers->Search); CopyStringToBuffer(&CollationBuffers->Search, "name: \"%s\"\n" @@ -2902,7 +3076,7 @@ HMMLToBuffers(buffers *CollationBuffers, template **BespokeTemplate, char *Filen } PreviousTimecode = TimecodeToSeconds(Anno->time); - if(Config.Edition != EDITION_SINGLE) + if(Config.Edition != EDITION_SINGLE && !PrivateVideo) { CopyStringToBuffer(&CollationBuffers->Search, "\"%d\": \"", TimecodeToSeconds(Anno->time)); CopyStringToBufferJSONSafe(&CollationBuffers->Search, Anno->text); @@ -3418,9 +3592,10 @@ AppendedIdentifier: DeclaimBuffer(&Annotation); } - if(Config.Edition != EDITION_SINGLE) + if(Config.Edition != EDITION_SINGLE && !PrivateVideo) { CopyStringToBuffer(&CollationBuffers->Search, "---\n"); + N->This.Size = CollationBuffers->Search.Ptr - CollationBuffers->Search.Location; } #if DEBUG @@ -3932,21 +4107,21 @@ AppendedIdentifier: CopyStringToBuffer(&CollationBuffers->Player, "
\n"); - if(LinkOffsets) + if(N) { - LinkOffsets->NextStart = (CollationBuffers->Player.Ptr - CollationBuffers->Player.Location - (LinkOffsets->PrevStart + LinkOffsets->PrevEnd)); - if(Neighbours->Prev.BaseFilename || Neighbours->Next.BaseFilename) + N->This.LinkOffsets.NextStart = (CollationBuffers->Player.Ptr - CollationBuffers->Player.Location - (N->This.LinkOffsets.PrevStart + N->This.LinkOffsets.PrevEnd)); + if(N->Prev.Size || N->Next.Size) { - if(Neighbours->Next.BaseFilename) + if(N->Next.Size > 0) { // TODO(matt): Once we have a more rigorous notion of "Day Numbers", perhaps also use them here buffer NextPlayerURL; ClaimBuffer(&NextPlayerURL, "NextPlayerURL", MAX_BASE_URL_LENGTH + 1 + MAX_RELATIVE_PAGE_LOCATION_LENGTH + 1 + MAX_PLAYER_URL_PREFIX_LENGTH + MAX_BASE_FILENAME_LENGTH); - ConstructPlayerURL(&NextPlayerURL, Neighbours->Next.BaseFilename); + ConstructPlayerURL(&NextPlayerURL, N->Next.BaseFilename); CopyStringToBuffer(&CollationBuffers->Player, "
Next: '%s'
\n", NextPlayerURL.Location, - Neighbours->Next.Title); + N->Next.Title); DeclaimBuffer(&NextPlayerURL); } @@ -3956,7 +4131,7 @@ AppendedIdentifier: "
You have arrived at the (current) end of %s
\n", CollationBuffers->ProjectName); } } - LinkOffsets->NextEnd = (CollationBuffers->Player.Ptr - CollationBuffers->Player.Location - (LinkOffsets->PrevStart + LinkOffsets->PrevEnd + LinkOffsets->NextStart)); + N->This.LinkOffsets.NextEnd = (CollationBuffers->Player.Ptr - CollationBuffers->Player.Location - (N->This.LinkOffsets.PrevStart + N->This.LinkOffsets.PrevEnd + N->This.LinkOffsets.NextStart)); } CopyStringToBuffer(&CollationBuffers->Player, @@ -4079,7 +4254,7 @@ AppendedIdentifier: } int -BuffersToHTML(buffers *CollationBuffers, template *Template, char *OutputPath, int PageType, int *PlayerOffset) +BuffersToHTML(buffers *CollationBuffers, template *Template, char *OutputPath, int PageType, unsigned int *PlayerOffset) { #if DEBUG printf("\n\n --- Buffer Collation ---\n" @@ -4095,7 +4270,7 @@ BuffersToHTML(buffers *CollationBuffers, template *Template, char *OutputPath, i if(Template->Metadata.Filename && StringsDiffer(Template->Metadata.Filename, "")) { if((Template->Metadata.Filename && StringsDiffer(Template->Metadata.Filename, "")) - && ((Template->Metadata.Validity & PageType) || Config.ForceIntegration)) + && ((Template->Metadata.Validity & PageType) || Config.Mode & MODE_FORCEINTEGRATION)) { buffer Output; Output.Size = Template->Buffer.Size + (Kilobytes(512)); @@ -4182,7 +4357,7 @@ BuffersToHTML(buffers *CollationBuffers, template *Template, char *OutputPath, i CopyBuffer(&Output, &CollationBuffers->Menus); break; case TAG_PLAYER: - if(NeedPlayerOffset) { *PlayerOffset = (Output.Ptr - Output.Location); NeedPlayerOffset = !NeedPlayerOffset; } + if(NeedPlayerOffset) { *PlayerOffset += (Output.Ptr - Output.Location); NeedPlayerOffset = !NeedPlayerOffset; } CopyBuffer(&Output, &CollationBuffers->Player); break; case TAG_SCRIPT: @@ -4272,7 +4447,7 @@ BuffersToHTML(buffers *CollationBuffers, template *Template, char *OutputPath, i CopyStringToBuffer(&Master, "\n" " "); - if(PlayerOffset) { *PlayerOffset = Master.Ptr - Master.Location; } + if(PlayerOffset) { *PlayerOffset += Master.Ptr - Master.Location; } CopyBuffer(&Master, &CollationBuffers->Player); CopyStringToBuffer(&Master, "\n" @@ -4305,93 +4480,12 @@ BuffersToHTML(buffers *CollationBuffers, template *Template, char *OutputPath, i } } -enum -{ - C_SEEK_FORWARDS, - C_SEEK_BACKWARDS -} seek_directions; - -enum -{ - C_SEEK_START, // First character of string - C_SEEK_BEFORE, // Character before first character - C_SEEK_END, // Last character of string - C_SEEK_AFTER // Character after last character -} seek_positions; - int -SeekBufferForString(buffer *Buffer, char *String, - int Direction, /* seek_directions */ - int Position /* seek_positions */) -{ - // TODO(matt): Optimise? Some means of analysing the String to increment - // the pointer in bigger strides - - // Perhaps count up runs of consecutive chars and seek for the char with - // the longest run, in strides of that run-length - - char *InitialLocation = Buffer->Ptr; - if(Direction == C_SEEK_FORWARDS) - { - while(Buffer->Ptr - Buffer->Location < Buffer->Size - StringLength(String) - && StringsDifferT(String, Buffer->Ptr, 0)) - { - ++Buffer->Ptr; - } - } - else - { - while(Buffer->Ptr > Buffer->Location - && StringsDifferT(String, Buffer->Ptr, 0)) - { - --Buffer->Ptr; - } - } - - if(StringsDifferT(String, Buffer->Ptr, 0)) - { - Buffer->Ptr = InitialLocation; - return RC_UNFOUND; - } - - switch(Position) - { - case C_SEEK_START: - break; - case C_SEEK_BEFORE: - if(Buffer->Ptr > Buffer->Location) - { - --Buffer->Ptr; - break; - } - else - { - return RC_ERROR_SEEK; // Ptr remains at string start - } - case C_SEEK_END: - Buffer->Ptr += StringLength(String) - 1; - break; - case C_SEEK_AFTER: - if(Buffer->Size >= Buffer->Ptr - Buffer->Location + StringLength(String)) - { - Buffer->Ptr += StringLength(String); - break; - } - else - { - return RC_ERROR_SEEK; // Ptr remains at string start - // NOTE(matt): Should it, however, be left at the end of the string? - } - } - return RC_SUCCESS; -} - -int -BinarySearchForMetadataEntry(index *Index, index_metadata **Test, char *SearchTerm) +BinarySearchForMetadataEntry(index *Index, index_metadata **Entry, char *SearchTerm) { int Lower = 0; index_metadata *LowerEntry = (index_metadata*)(Index->Metadata.Buffer.Ptr + sizeof(index_metadata) * Lower); - if(StringsDiffer(SearchTerm, LowerEntry->BaseFilename) < 0 ) { return Lower; } + if(StringsDiffer(SearchTerm, LowerEntry->BaseFilename) < 0 ) { return -1; } int Upper = Index->Header.EntryCount - 1; int Pivot = Upper - ((Upper - Lower) >> 1); @@ -4403,9 +4497,9 @@ BinarySearchForMetadataEntry(index *Index, index_metadata **Test, char *SearchTe PivotEntry = (index_metadata*)(Index->Metadata.Buffer.Ptr + sizeof(index_metadata) * Pivot); UpperEntry = (index_metadata*)(Index->Metadata.Buffer.Ptr + sizeof(index_metadata) * Upper); - if(!StringsDiffer(SearchTerm, LowerEntry->BaseFilename)) { *Test = LowerEntry; return Lower; } - if(!StringsDiffer(SearchTerm, PivotEntry->BaseFilename)) { *Test = PivotEntry; return Pivot; } - if(!StringsDiffer(SearchTerm, UpperEntry->BaseFilename)) { *Test = UpperEntry; return Upper; } + if(!StringsDiffer(SearchTerm, LowerEntry->BaseFilename)) { *Entry = LowerEntry; return Lower; } + if(!StringsDiffer(SearchTerm, PivotEntry->BaseFilename)) { *Entry = PivotEntry; return Pivot; } + if(!StringsDiffer(SearchTerm, UpperEntry->BaseFilename)) { *Entry = UpperEntry; return Upper; } if((StringsDiffer(SearchTerm, PivotEntry->BaseFilename) < 0)) { Upper = Pivot; } else { Lower = Pivot; } @@ -4440,8 +4534,167 @@ AccumulateIndexEntryInsertionOffset(index *Index, int EntryIndex) return Result; } +void +ClearEntry(index_metadata *Entry) +{ + Entry->LinkOffsets.PrevStart = 0; + Entry->LinkOffsets.NextStart = 0; + Entry->LinkOffsets.PrevEnd = 0; + Entry->LinkOffsets.NextEnd = 0; + Entry->Size = 0; + Clear(Entry->BaseFilename, sizeof(Entry->BaseFilename)); + Clear(Entry->Title, sizeof(Entry->Title)); +} + +enum +{ + EDIT_DELETION, + EDIT_ADDITION, + EDIT_REINSERTION +} index_edits; + +void +GetNeighbourhood(index *Index, neighbourhood *N, int IndexEditType, bool *ThisIsPrev) +{ + index_metadata Entry = { 0 }; + int EntryIndex; + int IncomingIndex = N->ThisIndex; + + if(IndexEditType == EDIT_DELETION) + { + bool FoundThis = FALSE; + for(EntryIndex = IncomingIndex + 1; EntryIndex < Index->Header.EntryCount; ++EntryIndex) + { + Entry = *(index_metadata *)(Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * EntryIndex); + if(Entry.Size > 0) + { + FoundThis = TRUE; + break; + } + } + + if(!FoundThis) + { + for(EntryIndex = IncomingIndex - 1; EntryIndex >= 0; --EntryIndex) + { + Entry = *(index_metadata *)(Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * EntryIndex); + if(Entry.Size > 0) + { + FoundThis = TRUE; + *ThisIsPrev = TRUE; + break; + } + } + } + + if(FoundThis) + { + N->ThisIndex = EntryIndex; + N->This.Size = Entry.Size; + N->This.LinkOffsets.PrevStart = Entry.LinkOffsets.PrevStart; + N->This.LinkOffsets.PrevEnd = Entry.LinkOffsets.PrevEnd; + N->This.LinkOffsets.NextStart = Entry.LinkOffsets.NextStart; + N->This.LinkOffsets.NextEnd = Entry.LinkOffsets.NextEnd; + CopyString(N->This.BaseFilename, Entry.BaseFilename); + CopyString(N->This.Title, Entry.Title); + } + else + { + return; // NOTE(matt): We were evidently the last public entry, until now + } + } + + N->PrevIsFirst = TRUE; + N->NextIsFinal = TRUE; + + if(IndexEditType == EDIT_DELETION && *ThisIsPrev == FALSE) + { + EntryIndex = IncomingIndex - 1; + } + else + { + EntryIndex = N->ThisIndex - 1; + } + bool FoundPrev = FALSE; + for(; EntryIndex >= 0; --EntryIndex) + { + Entry = *(index_metadata*)(Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * EntryIndex); + if(Entry.Size > 0) + { + if(!FoundPrev) + { + N->PrevIndex = EntryIndex; + N->Prev.Size = Entry.Size; + N->Prev.LinkOffsets.PrevStart = Entry.LinkOffsets.PrevStart; + N->Prev.LinkOffsets.PrevEnd = Entry.LinkOffsets.PrevEnd; + N->Prev.LinkOffsets.NextStart = Entry.LinkOffsets.NextStart; + N->Prev.LinkOffsets.NextEnd = Entry.LinkOffsets.NextEnd; + CopyString(N->Prev.BaseFilename, Entry.BaseFilename); + CopyString(N->Prev.Title, Entry.Title); + FoundPrev = TRUE; + } + else + { + N->PrevIsFirst = FALSE; + break; + } + } + } + + switch(IndexEditType) + { + case EDIT_DELETION: + if(*ThisIsPrev == TRUE) { EntryIndex = Index->Header.EntryCount; break; } // NOTE(matt): No need to enter the loop, else fallthrough + case EDIT_REINSERTION: + EntryIndex = N->ThisIndex + 1; + break; + case EDIT_ADDITION: + EntryIndex = N->ThisIndex; + break; + } + bool FoundNext = FALSE; + for(; EntryIndex < Index->Header.EntryCount; + ++EntryIndex) + { + Entry = *(index_metadata*)(Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * EntryIndex); + if(Entry.Size > 0) + { + if(!FoundNext) + { + N->NextIndex = EntryIndex; + N->Next.Size = Entry.Size; + N->Next.LinkOffsets.PrevStart = Entry.LinkOffsets.PrevStart; + N->Next.LinkOffsets.PrevEnd = Entry.LinkOffsets.PrevEnd; + N->Next.LinkOffsets.NextStart = Entry.LinkOffsets.NextStart; + N->Next.LinkOffsets.NextEnd = Entry.LinkOffsets.NextEnd; + CopyString(N->Next.BaseFilename, Entry.BaseFilename); + CopyString(N->Next.Title, Entry.Title); + FoundNext = TRUE; + } + else + { + N->NextIsFinal = FALSE; + break; + } + } + } + + switch(IndexEditType) + { + case EDIT_REINSERTION: + break; + case EDIT_DELETION: + if(*ThisIsPrev == FALSE) { --N->ThisIndex; } + if(FoundNext) { --N->NextIndex; } + break; + case EDIT_ADDITION: + if(FoundNext) { ++N->NextIndex; } + break; + } +} + int -InsertIntoIndex(index *Index, int *EntryIndex, buffers *CollationBuffers, template **BespokeTemplate, char *BaseFilename) +InsertIntoIndex(index *Index, neighbourhood *N, buffers *CollationBuffers, template **BespokeTemplate, char *BaseFilename, bool RecheckingPrivacy) { int IndexMetadataFileReadCode = ReadFileIntoBuffer(&Index->Metadata, 0); switch(IndexMetadataFileReadCode) @@ -4463,15 +4716,12 @@ InsertIntoIndex(index *Index, int *EntryIndex, buffers *CollationBuffers, templa break; } - int MetadataInsertionOffset = -1; int IndexEntryInsertionStart = -1; int IndexEntryInsertionEnd = -1; Index->Header.EntryCount = 0; - bool Found = FALSE; + ClearEntry(&Index->Entry); + bool Reinserting = FALSE; - neighbours Neighbours = { 0 }; - index_metadata *This = { 0 }; - index_metadata *Next = { 0 }; if(IndexMetadataFileReadCode == RC_SUCCESS && IndexFileReadCode == RC_SUCCESS) { // TODO(matt): Index validation? @@ -4486,110 +4736,44 @@ InsertIntoIndex(index *Index, int *EntryIndex, buffers *CollationBuffers, templa Index->Header.CurrentHMMLVersion.Minor = hmml_version.Minor; Index->Header.CurrentHMMLVersion.Patch = hmml_version.Patch; - Index->Metadata.Buffer.Ptr += sizeof(Index->Header); + Index->Metadata.Buffer.Ptr += sizeof(index_header); Index->File.Buffer.Ptr += StringLength("---\n"); -#if BINARY_SEARCH -START_TIMING_BLOCK(" InsertIntoIndex(%s) BinarySearch: ", BaseFilename); - index_metadata *Prev = { 0 }; - *EntryIndex = BinarySearchForMetadataEntry(Index, &This, BaseFilename); - if(This) + index_metadata *Entry = { 0 }; + N->ThisIndex = BinarySearchForMetadataEntry(Index, &Entry, BaseFilename); + if(Entry) { // Reinsert - Found = TRUE; - MetadataInsertionOffset = sizeof(index_header) + sizeof(index_metadata) * *EntryIndex; - IndexEntryInsertionStart = AccumulateIndexEntryInsertionOffset(Index, *EntryIndex); - IndexEntryInsertionEnd = IndexEntryInsertionStart + This->Size; - if(*EntryIndex > 0) - { - Prev = (index_metadata*)(Index->Metadata.Buffer.Ptr + sizeof(index_metadata) * (*EntryIndex - 1)); - Neighbours.Prev.BaseFilename = Prev->BaseFilename; - Neighbours.Prev.Title = Prev->Title; - } - if(*EntryIndex < Index->Header.EntryCount - 1) - { - Next = (index_metadata*)(Index->Metadata.Buffer.Ptr + sizeof(index_metadata) * (*EntryIndex + 1)); - Neighbours.Next.BaseFilename = Next->BaseFilename; - Neighbours.Next.Title = Next->Title; - } + Reinserting = TRUE; + N->This.Size = Entry->Size; + N->This.LinkOffsets.PrevStart = Entry->LinkOffsets.PrevStart; + N->This.LinkOffsets.PrevEnd = Entry->LinkOffsets.PrevEnd; + N->This.LinkOffsets.NextStart = Entry->LinkOffsets.NextStart; + N->This.LinkOffsets.NextEnd = Entry->LinkOffsets.NextEnd; + + IndexEntryInsertionStart = AccumulateIndexEntryInsertionOffset(Index, N->ThisIndex); + IndexEntryInsertionEnd = IndexEntryInsertionStart + N->This.Size; } else { - This = (index_metadata*)(Index->Metadata.Buffer.Ptr + sizeof(index_metadata) * *EntryIndex); - if(StringsDiffer(BaseFilename, This->BaseFilename) < 0) + if(N->ThisIndex == -1) { ++N->ThisIndex; } // NOTE(matt): BinarySearchForMetadataEntry returns -1 if search term precedes the set + Entry = (index_metadata*)(Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * N->ThisIndex); + if(StringsDiffer(BaseFilename, Entry->BaseFilename) < 0) { // Insert - MetadataInsertionOffset = sizeof(index_header) + sizeof(index_metadata) * *EntryIndex; - IndexEntryInsertionStart = AccumulateIndexEntryInsertionOffset(Index, *EntryIndex); - if(*EntryIndex > 0) - { - Prev = (index_metadata*)(Index->Metadata.Buffer.Ptr + sizeof(index_metadata) * (*EntryIndex - 1)); - Neighbours.Prev.BaseFilename = Prev->BaseFilename; - Neighbours.Prev.Title = Prev->Title; - } - Neighbours.Next.BaseFilename = This->BaseFilename; - Neighbours.Next.Title = This->Title; + IndexEntryInsertionStart = AccumulateIndexEntryInsertionOffset(Index, N->ThisIndex); + } else { // Append - if(*EntryIndex > 0) - { - Neighbours.Prev.BaseFilename = This->BaseFilename; - Neighbours.Prev.Title = This->Title; - } - ++*EntryIndex; + ++N->ThisIndex; } } -#else -START_TIMING_BLOCK(" InsertIntoIndex(%s) LinearSearch: ", BaseFilename); - char *IndexEntryStart; - IndexEntryStart = Index->File.Buffer.Ptr; - for(*EntryIndex = 0; *EntryIndex < Index->Header.EntryCount; ++*EntryIndex) - { - This = (index_metadata *)Index->Metadata.Buffer.Ptr; - if(!StringsDiffer(This->BaseFilename, BaseFilename)) - { - // Reinsert - if(*EntryIndex < (Index->Header.EntryCount - 1)) - { - Next = (index_metadata *)(Index->Metadata.Buffer.Ptr + sizeof(Index->Entry)); - Neighbours.Next.BaseFilename = Next->BaseFilename; - Neighbours.Next.Title = Next->Title; - } - - MetadataInsertionOffset = Index->Metadata.Buffer.Ptr - Index->Metadata.Buffer.Location; - IndexEntryInsertionStart = IndexEntryStart - Index->File.Buffer.Location; - IndexEntryInsertionEnd = IndexEntryInsertionStart + This->Size; - Found = TRUE; - break; - } - else if(StringsDiffer(This->BaseFilename, BaseFilename) > 0) - { - // Insert - Neighbours.Next.BaseFilename = This->BaseFilename; - Neighbours.Next.Title = This->Title; - - MetadataInsertionOffset = Index->Metadata.Buffer.Ptr - Index->Metadata.Buffer.Location; - IndexEntryInsertionStart = IndexEntryStart - Index->File.Buffer.Location; - break; - } - else - { - Index->Metadata.Buffer.Ptr += sizeof(Index->Entry); - - IndexEntryStart += This->Size; - Index->File.Buffer.Ptr = IndexEntryStart; - - Neighbours.Prev.BaseFilename = This->BaseFilename; - Neighbours.Prev.Title = This->Title; - } - } -#endif + GetNeighbourhood(Index, N, Reinserting ? EDIT_REINSERTION : EDIT_ADDITION, 0); } else { -START_TIMING_BLOCK(" InsertIntoIndex(%s) NoSearch: ", BaseFilename); // NOTE(matt): Initialising new index_header Index->Header.CurrentDBVersion = CINERA_DB_VERSION; Index->Header.CurrentAppVersion = CINERA_APP_VERSION; @@ -4631,11 +4815,12 @@ START_TIMING_BLOCK(" InsertIntoIndex(%s) NoSearch: ", BaseFilename); } closedir(OutputDirectoryHandle); } -END_TIMING_BLOCK(); char InputFile[StringLength(BaseFilename) + StringLength(".hmml")]; CopyString(InputFile, "%s.hmml", BaseFilename); - switch(HMMLToBuffers(CollationBuffers, BespokeTemplate, InputFile, &Index->Entry.LinkOffsets, &Neighbours)) + bool VideoIsPrivate = FALSE; + + switch(HMMLToBuffers(CollationBuffers, BespokeTemplate, InputFile, N)) { // TODO(matt): Actually sort out the fatality of these cases, once we are always-on case RC_ERROR_FILE: @@ -4646,81 +4831,126 @@ END_TIMING_BLOCK(); case RC_ERROR_QUOTE: case RC_INVALID_REFERENCE: return RC_ERROR_HMML; + case RC_PRIVATE_VIDEO: + VideoIsPrivate = TRUE; case RC_SUCCESS: break; }; - Index->Entry.Size = CollationBuffers->Search.Ptr - CollationBuffers->Search.Location; - ClearCopyStringNoFormat(Index->Entry.BaseFilename, sizeof(Index->Entry.BaseFilename), BaseFilename); - ClearCopyStringNoFormat(Index->Entry.Title, sizeof(Index->Entry.Title), CollationBuffers->Title); + 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; } if(!(Index->File.Handle = fopen(Index->File.Path, "w"))) { FreeBuffer(&Index->File.Buffer); return RC_ERROR_FILE; } - if(!Found) { ++Index->Header.EntryCount; } + if(!Reinserting) { ++Index->Header.EntryCount; } - fwrite(&Index->Header, sizeof(Index->Header), 1, Index->Metadata.Handle); + 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); + Index->Metadata.Buffer.Ptr = Index->Metadata.Buffer.Location + sizeof(index_header); } - if(Found) + 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 - fwrite(Index->Metadata.Buffer.Ptr, MetadataInsertionOffset - sizeof(Index->Header), 1, Index->Metadata.Handle); - fwrite(&Index->Entry, sizeof(Index->Entry), 1, Index->Metadata.Handle); - fwrite(Index->Metadata.Buffer.Ptr - sizeof(Index->Header) + MetadataInsertionOffset + sizeof(Index->Entry), Index->Metadata.FileSize - MetadataInsertionOffset - sizeof(Index->Entry), 1, Index->Metadata.Handle); + Index->Metadata.Buffer.Ptr = Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * N->ThisIndex; + *(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, Index->Entry.Size, 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); - LogError(LOG_NOTICE, "Reinserted %s - %s", BaseFilename, CollationBuffers->Title); - fprintf(stderr, "\e[1;33mReinserted\e[0m %s - %s\n", BaseFilename, CollationBuffers->Title); + if(VideoIsPrivate) + { + if(!RecheckingPrivacy) + { + LogError(LOG_NOTICE, "Privately Reinserted %s", BaseFilename); + fprintf(stderr, "\e[0;34mPrivately Reinserted\e[0m %s\n", BaseFilename); + } + } + else + { + LogError(LOG_NOTICE, "Reinserted %s - %s", BaseFilename, CollationBuffers->Title); + fprintf(stderr, "\e[1;33mReinserted\e[0m %s - %s\n", BaseFilename, CollationBuffers->Title); + } } - else if(MetadataInsertionOffset >= 0 && IndexEntryInsertionStart >= 0) + else if(IndexEntryInsertionStart >= 0) { // Insert new - fwrite(Index->Metadata.Buffer.Ptr, MetadataInsertionOffset - sizeof(Index->Header), 1, Index->Metadata.Handle); - fwrite(&Index->Entry, sizeof(Index->Entry), 1, Index->Metadata.Handle); - fwrite(Index->Metadata.Buffer.Ptr - sizeof(Index->Header) + MetadataInsertionOffset, Index->Metadata.FileSize - MetadataInsertionOffset, 1, Index->Metadata.Handle); + 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, Index->Entry.Size, 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); - LogError(LOG_NOTICE, "Inserted %s - %s", BaseFilename, CollationBuffers->Title); - fprintf(stderr, "\e[1;32mInserted\e[0m %s - %s\n", BaseFilename, CollationBuffers->Title); + if(VideoIsPrivate) + { + if(!RecheckingPrivacy) + { + LogError(LOG_NOTICE, "Privately Inserted %s", BaseFilename); + fprintf(stderr, "\e[0;34mPrivately Inserted\e[0m %s\n", BaseFilename); + } + } + else + { + LogError(LOG_NOTICE, "Inserted %s - %s", BaseFilename, CollationBuffers->Title); + fprintf(stderr, "\e[1;32mInserted\e[0m %s - %s\n", BaseFilename, CollationBuffers->Title); + } } else { // Append new if(IndexMetadataFileReadCode == RC_SUCCESS) { - fwrite(Index->Metadata.Buffer.Ptr, Index->Metadata.FileSize - sizeof(Index->Header), 1, Index->Metadata.Handle); + 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); } else { fprintf(Index->File.Handle, "---\n"); } - fwrite(&Index->Entry, sizeof(Index->Entry), 1, Index->Metadata.Handle); - fwrite(CollationBuffers->Search.Location, Index->Entry.Size, 1, Index->File.Handle); - LogError(LOG_NOTICE, "Appended %s - %s", BaseFilename, CollationBuffers->Title); - fprintf(stderr, "\e[1;32mAppended\e[0m %s - %s\n", BaseFilename, CollationBuffers->Title); + fwrite(&N->This, sizeof(index_metadata), 1, Index->Metadata.Handle); + fwrite(CollationBuffers->Search.Location, N->This.Size, 1, Index->File.Handle); + if(VideoIsPrivate) + { + if(!RecheckingPrivacy) + { + LogError(LOG_NOTICE, "Privately Appended %s", 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->File.Handle); + FreeBuffer(&Index->Metadata.Buffer); FreeBuffer(&Index->File.Buffer); - return Found ? RC_SUCCESS : RC_UNFOUND; + // 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; } void @@ -4741,14 +4971,17 @@ ConstructDirectoryPath(buffer *DirectoryPath, int PageType, char *PageLocation, { CopyStringToBuffer(DirectoryPath, "/%s", PageLocation); } - if(StringsDiffer(Config.PlayerURLPrefix, "")) + if(BaseFilename) { - char *Ptr = BaseFilename + StringLength(Config.ProjectID); - CopyStringToBuffer(DirectoryPath, "/%s%s", Config.PlayerURLPrefix, Ptr); - } - else - { - CopyStringToBuffer(DirectoryPath, "/%s", BaseFilename); + if(StringsDiffer(Config.PlayerURLPrefix, "")) + { + char *Ptr = BaseFilename + StringLength(Config.ProjectID); + CopyStringToBuffer(DirectoryPath, "/%s%s", Config.PlayerURLPrefix, Ptr); + } + else + { + CopyStringToBuffer(DirectoryPath, "/%s", BaseFilename); + } } break; } @@ -4902,201 +5135,187 @@ int DeleteNeighbourLinks(file_buffer *File, index_metadata *Metadata) FreeBuffer(&File->Buffer); return RC_SUCCESS; } - else - { - return RC_ERROR_FILE; - } + else { return RC_ERROR_FILE; } } -int LinkNeighbours(index *Index, int EntryIndex, char *BaseFilename, int LinkType) +int 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, "DeleteFromIndex(): %s", strerror(errno)); + LogError(LOG_ERROR, "LinkNeighbours(): %s", strerror(errno)); return RC_ERROR_MEMORY; case RC_SUCCESS: break; } Index->Header = *(index_header *)Index->Metadata.Buffer.Ptr; - Index->Metadata.Buffer.Ptr += sizeof(Index->Header); - index_metadata *Prev = { 0 }; - index_metadata *This = { 0 }; - index_metadata *Next = { 0 }; -#if BINARY_SEARCH -START_TIMING_BLOCK(" LinkNeighbours(%s) [passing in EntryIndex]: ", BaseFilename); - This = (index_metadata *)Index->Metadata.Buffer.Ptr; - if(Index->Header.EntryCount != 1) + if(N->PrevIndex == -1 && N->NextIndex == -1) { - This = (index_metadata*)(Index->Metadata.Buffer.Ptr + sizeof(index_metadata) * EntryIndex); - if(EntryIndex > 0) - { - Prev = (index_metadata*)(Index->Metadata.Buffer.Ptr + sizeof(index_metadata) * (EntryIndex - 1)); - } - if(EntryIndex < Index->Header.EntryCount - 1) - { - Next = (index_metadata*)(Index->Metadata.Buffer.Ptr + sizeof(index_metadata) * (EntryIndex + 1)); - } + buffer LonePlayerPagePath; + ClaimBuffer(&LonePlayerPagePath, "LonePlayerPagePath", MAX_BASE_URL_LENGTH + 1 + MAX_RELATIVE_PAGE_LOCATION_LENGTH + 1 + MAX_PLAYER_URL_PREFIX_LENGTH + MAX_BASE_FILENAME_LENGTH + 1 + 10); + ConstructDirectoryPath(&LonePlayerPagePath, PAGE_PLAYER, Config.PlayerLocation, N->This.BaseFilename); + CopyStringToBuffer(&LonePlayerPagePath, "/index.html"); + + file_buffer LonePlayerPage; + CopyStringNoFormat(LonePlayerPage.Path, LonePlayerPagePath.Location); + + DeleteNeighbourLinks(&LonePlayerPage, &N->This); + 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 -START_TIMING_BLOCK(" LinkNeighbours(%s) LinearSearch: ", BaseFilename); - switch(LinkType) + else { - case LINK_INCLUDE: + if(N->PrevIndex >= 0) + { + buffer PreviousPlayerPagePath; + ClaimBuffer(&PreviousPlayerPagePath, "PreviousPlayerPagePath", MAX_BASE_URL_LENGTH + 1 + MAX_RELATIVE_PAGE_LOCATION_LENGTH + 1 + MAX_PLAYER_URL_PREFIX_LENGTH + MAX_BASE_FILENAME_LENGTH + 1 + 10); + ConstructDirectoryPath(&PreviousPlayerPagePath, PAGE_PLAYER, Config.PlayerLocation, N->Prev.BaseFilename); + CopyStringToBuffer(&PreviousPlayerPagePath, "/index.html"); + + file_buffer PreviousPlayerPage; + CopyStringNoFormat(PreviousPlayerPage.Path, PreviousPlayerPagePath.Location); + + switch(LinkType) { - for(EntryIndex = 0; EntryIndex < Index->Header.EntryCount; ++EntryIndex) - { - This = (index_metadata *)Index->Metadata.Buffer.Ptr; - if(!StringsDiffer(This->BaseFilename, BaseFilename)) + case LINK_EXCLUDE: { - if(EntryIndex < (Index->Header.EntryCount - 1)) - { - Next = (index_metadata *)(Index->Metadata.Buffer.Ptr + sizeof(index_metadata)); - } - break; - } - Prev = This; - Index->Metadata.Buffer.Ptr += sizeof(index_metadata); - } - } break; - case LINK_EXCLUDE: - { - This = (index_metadata *)Index->Metadata.Buffer.Ptr; - if(Index->Header.EntryCount != 1) - { - Index->Metadata.Buffer.Ptr += sizeof(index_metadata); - Next = (index_metadata *)Index->Metadata.Buffer.Ptr; + buffer ThisPlayerPagePath; + ClaimBuffer(&ThisPlayerPagePath, "ThisPlayerPagePath", MAX_BASE_URL_LENGTH + 1 + MAX_RELATIVE_PAGE_LOCATION_LENGTH + 1 + MAX_PLAYER_URL_PREFIX_LENGTH + MAX_BASE_FILENAME_LENGTH + 1 + 10); + ConstructDirectoryPath(&ThisPlayerPagePath, PAGE_PLAYER, Config.PlayerLocation, N->This.BaseFilename); + CopyStringToBuffer(&ThisPlayerPagePath, "/index.html"); - for(EntryIndex = 1; EntryIndex < Index->Header.EntryCount; ++EntryIndex) + file_buffer ThisPlayerPage; + CopyStringNoFormat(ThisPlayerPage.Path, ThisPlayerPagePath.Location); + + InsertNeighbourLink(&ThisPlayerPage, &N->This, &N->Prev, LINK_PREV, Index->Header.ProjectName, N->NextIndex == -1 ? TRUE : FALSE); + + 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: { - Prev = This; - This = Next; - if(EntryIndex < (Index->Header.EntryCount - 1)) - { - Index->Metadata.Buffer.Ptr += sizeof(index_metadata); - Next = (index_metadata *)Index->Metadata.Buffer.Ptr; - } - else { Next = 0; } - if(StringsDiffer(BaseFilename, This->BaseFilename) < 0) - { - break; - } + 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.Ptr = N->Prev; } - } - } break; - } -#endif -END_TIMING_BLOCK(); + } - if(!Prev && !Next) - { - buffer ThisPlayerPagePath; - ClaimBuffer(&ThisPlayerPagePath, "ThisPlayerPagePath", MAX_BASE_URL_LENGTH + 1 + MAX_RELATIVE_PAGE_LOCATION_LENGTH + 1 + MAX_PLAYER_URL_PREFIX_LENGTH + MAX_BASE_FILENAME_LENGTH + 1 + 10); - ConstructDirectoryPath(&ThisPlayerPagePath, PAGE_PLAYER, Config.PlayerLocation, This->BaseFilename); - CopyStringToBuffer(&ThisPlayerPagePath, "/index.html"); - - file_buffer ThisPlayerPage; - CopyStringNoFormat(ThisPlayerPage.Path, ThisPlayerPagePath.Location); - - DeleteNeighbourLinks(&ThisPlayerPage, This); - - DeclaimBuffer(&ThisPlayerPagePath); - - Index->Metadata.Handle = fopen(Index->Metadata.Path, "w"); - fwrite(Index->Metadata.Buffer.Location, ((char *)This - Index->Metadata.Buffer.Location), 1, Index->Metadata.Handle); - fwrite(This, sizeof(index_metadata), 1, Index->Metadata.Handle); - fwrite(Index->Metadata.Buffer.Location + ((char *)This - Index->Metadata.Buffer.Location) + sizeof(index_metadata), - Index->Metadata.FileSize - (((char *)This - Index->Metadata.Buffer.Location) + sizeof(index_metadata)), - 1, Index->Metadata.Handle); - fclose(Index->Metadata.Handle); - } - - if(Prev) - { - buffer PreviousPlayerPagePath; - ClaimBuffer(&PreviousPlayerPagePath, "PreviousPlayerPagePath", MAX_BASE_URL_LENGTH + 1 + MAX_RELATIVE_PAGE_LOCATION_LENGTH + 1 + MAX_PLAYER_URL_PREFIX_LENGTH + MAX_BASE_FILENAME_LENGTH + 1 + 10); - ConstructDirectoryPath(&PreviousPlayerPagePath, PAGE_PLAYER, Config.PlayerLocation, Prev->BaseFilename); - CopyStringToBuffer(&PreviousPlayerPagePath, "/index.html"); - - file_buffer PreviousPlayerPage; - CopyStringNoFormat(PreviousPlayerPage.Path, PreviousPlayerPagePath.Location); - - switch(LinkType) - { - case LINK_EXCLUDE: - { - buffer ThisPlayerPagePath; - ClaimBuffer(&ThisPlayerPagePath, "ThisPlayerPagePath", MAX_BASE_URL_LENGTH + 1 + MAX_RELATIVE_PAGE_LOCATION_LENGTH + 1 + MAX_PLAYER_URL_PREFIX_LENGTH + MAX_BASE_FILENAME_LENGTH + 1 + 10); - ConstructDirectoryPath(&ThisPlayerPagePath, PAGE_PLAYER, Config.PlayerLocation, This->BaseFilename); - CopyStringToBuffer(&ThisPlayerPagePath, "/index.html"); - - file_buffer ThisPlayerPage; - CopyStringNoFormat(ThisPlayerPage.Path, ThisPlayerPagePath.Location); - - InsertNeighbourLink(&ThisPlayerPage, This, Prev, LINK_PREV, Index->Header.ProjectName, Next ? FALSE : TRUE); - - DeclaimBuffer(&ThisPlayerPagePath); - - Index->Metadata.Handle = fopen(Index->Metadata.Path, "w"); - fwrite(Index->Metadata.Buffer.Location, ((char* )This - Index->Metadata.Buffer.Location), 1, Index->Metadata.Handle); - fwrite(This, sizeof(index_metadata), 1, Index->Metadata.Handle); - fwrite(Index->Metadata.Buffer.Location + ((char* )This - Index->Metadata.Buffer.Location) + sizeof(index_metadata), - Index->Metadata.FileSize - (((char* )This - Index->Metadata.Buffer.Location) + sizeof(index_metadata)), - 1, Index->Metadata.Handle); - fclose(Index->Metadata.Handle); - - if(EntryIndex == Index->Header.EntryCount) { break; } - } - case LINK_INCLUDE: - { - InsertNeighbourLink(&PreviousPlayerPage, Prev, This, LINK_NEXT, Index->Header.ProjectName, EntryIndex == 1 ? TRUE : FALSE); - } break; + DeclaimBuffer(&PreviousPlayerPagePath); } - DeclaimBuffer(&PreviousPlayerPagePath); + if(N->NextIndex >= 0) + { + buffer NextPlayerPagePath; + ClaimBuffer(&NextPlayerPagePath, "NextPlayerPagePath", MAX_BASE_URL_LENGTH + 1 + MAX_RELATIVE_PAGE_LOCATION_LENGTH + 1 + MAX_PLAYER_URL_PREFIX_LENGTH + MAX_BASE_FILENAME_LENGTH + 1 + 10); + ConstructDirectoryPath(&NextPlayerPagePath, PAGE_PLAYER, Config.PlayerLocation, N->Next.BaseFilename); + CopyStringToBuffer(&NextPlayerPagePath, "/index.html"); - Index->Metadata.Handle = fopen(Index->Metadata.Path, "w"); - fwrite(Index->Metadata.Buffer.Location, ((char *)Prev - Index->Metadata.Buffer.Location), 1, Index->Metadata.Handle); - fwrite(Prev, sizeof(index_metadata), 1, Index->Metadata.Handle); - fwrite(Index->Metadata.Buffer.Location + ((char *)Prev - Index->Metadata.Buffer.Location) + sizeof(index_metadata), - Index->Metadata.FileSize - (((char *)Prev - Index->Metadata.Buffer.Location) + sizeof(index_metadata)), - 1, Index->Metadata.Handle); - fclose(Index->Metadata.Handle); + file_buffer NextPlayerPage; + CopyStringNoFormat(NextPlayerPage.Path, NextPlayerPagePath.Location); + + switch(LinkType) + { + case LINK_EXCLUDE: + { + buffer ThisPlayerPagePath; + ClaimBuffer(&ThisPlayerPagePath, "ThisPlayerPagePath", MAX_BASE_URL_LENGTH + 1 + MAX_RELATIVE_PAGE_LOCATION_LENGTH + 1 + MAX_PLAYER_URL_PREFIX_LENGTH + MAX_BASE_FILENAME_LENGTH + 1 + 10); + ConstructDirectoryPath(&ThisPlayerPagePath, PAGE_PLAYER, Config.PlayerLocation, N->This.BaseFilename); + CopyStringToBuffer(&ThisPlayerPagePath, "/index.html"); + + file_buffer ThisPlayerPage; + CopyStringNoFormat(ThisPlayerPage.Path, ThisPlayerPagePath.Location); + + InsertNeighbourLink(&ThisPlayerPage, &N->This, &N->Next, LINK_NEXT, Index->Header.ProjectName, N->PrevIndex == -1 ? TRUE : FALSE); + + 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: + { + InsertNeighbourLink(&NextPlayerPage, &N->Next, &N->This, LINK_PREV, Index->Header.ProjectName, N->NextIsFinal); + Index->Metadata.Buffer.Ptr = Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * N->NextIndex; + *(index_metadata *)Index->Metadata.Buffer.Ptr = N->Next; + } + } + + DeclaimBuffer(&NextPlayerPagePath); + + } } - if(Next && LinkType == LINK_INCLUDE) - { - buffer NextPlayerPagePath; - ClaimBuffer(&NextPlayerPagePath, "NextPlayerPagePath", MAX_BASE_URL_LENGTH + 1 + MAX_RELATIVE_PAGE_LOCATION_LENGTH + 1 + MAX_PLAYER_URL_PREFIX_LENGTH + MAX_BASE_FILENAME_LENGTH + 1 + 10); - ConstructDirectoryPath(&NextPlayerPagePath, PAGE_PLAYER, Config.PlayerLocation, Next->BaseFilename); - CopyStringToBuffer(&NextPlayerPagePath, "/index.html"); - - file_buffer NextPlayerPage; - CopyStringNoFormat(NextPlayerPage.Path, NextPlayerPagePath.Location); - - InsertNeighbourLink(&NextPlayerPage, Next, This, LINK_PREV, Index->Header.ProjectName, EntryIndex == (Index->Header.EntryCount - 2) ? TRUE : FALSE); - - DeclaimBuffer(&NextPlayerPagePath); - - Index->Metadata.Handle = fopen(Index->Metadata.Path, "w"); - fwrite(Index->Metadata.Buffer.Location, ((char* )Next - Index->Metadata.Buffer.Location), 1, Index->Metadata.Handle); - fwrite(Next, sizeof(index_metadata), 1, Index->Metadata.Handle); - fwrite(Index->Metadata.Buffer.Location + ((char* )Next - Index->Metadata.Buffer.Location) + sizeof(index_metadata), - Index->Metadata.FileSize - (((char* )Next - Index->Metadata.Buffer.Location) + sizeof(index_metadata)), - 1, Index->Metadata.Handle); - fclose(Index->Metadata.Handle); - } + Index->Metadata.Handle = fopen(Index->Metadata.Path, "w"); + fwrite(Index->Metadata.Buffer.Location, Index->Metadata.FileSize, 1, Index->Metadata.Handle); + fclose(Index->Metadata.Handle); FreeBuffer(&Index->Metadata.Buffer); return RC_SUCCESS; } +void +DeleteIndexPageFromFilesystem() // NOTE(matt): Do we need to handle relocating, like the PlayerPage function? +{ + buffer IndexDirectory; + ClaimBuffer(&IndexDirectory, "IndexDirectory", 1024); + ConstructDirectoryPath(&IndexDirectory, PAGE_INDEX, Config.IndexLocation, ""); + char IndexPagePath[1024]; + CopyString(IndexPagePath, "%s/index.html", IndexDirectory.Location); + remove(IndexPagePath); + remove(IndexDirectory.Location); + DeclaimBuffer(&IndexDirectory); +} + int -DeleteFromIndex(index *Index, int *EntryIndex, char *BaseFilename) +DeletePlayerPageFromFilesystem(char *BaseFilename, char *PlayerLocation, bool Relocating) +{ + // NOTE(matt): Once we have the notion of an output filename format, we'll need to use that here + buffer OutputDirectoryPath; + ClaimBuffer(&OutputDirectoryPath, "OutputDirectoryPath", 1024); + ConstructDirectoryPath(&OutputDirectoryPath, PAGE_PLAYER, PlayerLocation, BaseFilename); + DIR *PlayerDir; + + if((PlayerDir = opendir(OutputDirectoryPath.Location))) // There is a directory for the Player, which there probably should be if not for manual intervention + { + char PlayerPagePath[256]; + CopyString(PlayerPagePath, "%s/index.html", OutputDirectoryPath.Location); + FILE *PlayerPage; + if((PlayerPage = fopen(PlayerPagePath, "r"))) + { + fclose(PlayerPage); + remove(PlayerPagePath); + } + + closedir(PlayerDir); + if((remove(OutputDirectoryPath.Location) == -1)) + { + LogError(LOG_NOTICE, "Mostly deleted %s. Unable to remove directory %s: %s", BaseFilename, OutputDirectoryPath.Location, strerror(errno)); + fprintf(stderr, "\e[1;30mMostly deleted\e[0m %s. \e[1;31mUnable to remove directory\e[0m %s: %s", BaseFilename, OutputDirectoryPath.Location, strerror(errno)); + } + else + { + if(!Relocating) + { + LogError(LOG_INFORMATIONAL, "Deleted %s", BaseFilename); + fprintf(stderr, "\e[1;30mDeleted\e[0m %s\n", BaseFilename); + } + + } + } + DeclaimBuffer(&OutputDirectoryPath); + return RC_SUCCESS; +} + +int +DeleteFromIndex(index *Index, neighbourhood *N, char *BaseFilename) { // TODO(matt): LogError() switch(ReadFileIntoBuffer(&Index->Metadata, 0)) @@ -5124,74 +5343,33 @@ DeleteFromIndex(index *Index, int *EntryIndex, char *BaseFilename) Index->Header = *(index_header *)Index->Metadata.Buffer.Ptr; Index->Metadata.Buffer.Ptr += sizeof(Index->Header); - bool Found = FALSE; - int DeleteMetadataFrom = -1; - int DeleteFileFrom = -1; - int DeleteFileTo = -1; - -#if BINARY_SEARCH -START_TIMING_BLOCK(" DeleteFromIndex(%s) BinarySearch: ", BaseFilename); - index_metadata *This = { 0 }; - *EntryIndex = BinarySearchForMetadataEntry(Index, &This, BaseFilename); - if(This) + index_metadata *Entry = { 0 }; + int EntryIndex = BinarySearchForMetadataEntry(Index, &Entry, BaseFilename); + if(Entry) { - Found = TRUE; - DeleteMetadataFrom = (char *)This - Index->Metadata.Buffer.Location; - DeleteFileFrom = AccumulateIndexEntryInsertionOffset(Index, *EntryIndex); - DeleteFileTo = DeleteFileFrom + This->Size; + int DeleteFileFrom = AccumulateIndexEntryInsertionOffset(Index, EntryIndex); + int DeleteFileTo = DeleteFileFrom + Entry->Size; + bool ThisIsPrev = FALSE; + N->ThisIndex = EntryIndex; + GetNeighbourhood(Index, N, EDIT_DELETION, &ThisIsPrev); --Index->Header.EntryCount; - } -#else -START_TIMING_BLOCK(" DeleteFromIndex(%s) LinearSearch: ", BaseFilename); - int SizeAcc = 0; - for(*EntryIndex = 0; *EntryIndex < Index->Header.EntryCount; ++*EntryIndex, Index->Metadata.Buffer.Ptr += sizeof(index_metadata)) - { - index_metadata This = *(index_metadata *)Index->Metadata.Buffer.Ptr; - if(!StringsDiffer(This.BaseFilename, BaseFilename)) - { - Found = TRUE; - --Index->Header.EntryCount; - DeleteMetadataFrom = Index->Metadata.Buffer.Ptr - Index->Metadata.Buffer.Location; - DeleteFileFrom = StringLength("---\n") + SizeAcc; - DeleteFileTo = DeleteFileFrom + This.Size; - break; - } - SizeAcc += This.Size; - } -#endif -END_TIMING_BLOCK(); - - if(Found) - { if(Index->Header.EntryCount == 0) { - buffer IndexDirectory; - ClaimBuffer(&IndexDirectory, "IndexDirectory", 1024); - ConstructDirectoryPath(&IndexDirectory, PAGE_INDEX, Config.IndexLocation, ""); - char IndexPagePath[1024]; - CopyString(IndexPagePath, "%s/index.html", IndexDirectory.Location); - remove(IndexPagePath); - remove(IndexDirectory.Location); - DeclaimBuffer(&IndexDirectory); + DeleteIndexPageFromFilesystem(); remove(Index->Metadata.Path); remove(Index->File.Path); } else { - if(*EntryIndex == Index->Header.EntryCount) // NOTE(matt): LinkNeighbours() requires this - { - --*EntryIndex; - } - if(!(Index->Metadata.Handle = fopen(Index->Metadata.Path, "w"))) { FreeBuffer(&Index->Metadata.Buffer); return RC_ERROR_FILE; } if(!(Index->File.Handle = fopen(Index->File.Path, "w"))) { FreeBuffer(&Index->File.Buffer); return RC_ERROR_FILE; } fwrite(&Index->Header, sizeof(Index->Header), 1, Index->Metadata.Handle); - Index->Metadata.Buffer.Ptr = Index->Metadata.Buffer.Location + sizeof(Index->Header); - - fwrite(Index->Metadata.Buffer.Ptr, DeleteMetadataFrom - sizeof(Index->Header), 1, Index->Metadata.Handle); - fwrite(Index->Metadata.Buffer.Ptr + DeleteMetadataFrom - sizeof(Index->Header) + sizeof(Index->Entry), Index->Metadata.FileSize - DeleteMetadataFrom - sizeof(Index->Entry), 1, Index->Metadata.Handle); + fwrite(Index->Metadata.Buffer.Location + sizeof(index_header), sizeof(index_metadata) * EntryIndex, 1, Index->Metadata.Handle); + fwrite(Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * (EntryIndex + 1), + Index->Metadata.FileSize - sizeof(index_header) - sizeof(index_metadata) * (EntryIndex + 1), + 1, Index->Metadata.Handle); fclose(Index->Metadata.Handle); fwrite(Index->File.Buffer.Location, DeleteFileFrom, 1, Index->File.Handle); @@ -5202,7 +5380,7 @@ END_TIMING_BLOCK(); FreeBuffer(&Index->Metadata.Buffer); FreeBuffer(&Index->File.Buffer); - return Found ? RC_SUCCESS : RC_NOOP; + return Entry ? RC_SUCCESS : RC_NOOP; } int @@ -5253,14 +5431,13 @@ IndexToBuffer(index *Index, buffers *CollationBuffers) // NOTE(matt): This guy m Theme, Theme); - buffer URLPrefix; - ClaimBuffer(&URLPrefix, "URLPrefix", 1024); - ConstructURLPrefix(&URLPrefix, INCLUDE_JS, PAGE_INDEX); - buffer PlayerURL; ClaimBuffer(&PlayerURL, "PlayerURL", MAX_BASE_URL_LENGTH + 1 + MAX_RELATIVE_PAGE_LOCATION_LENGTH + 1 + MAX_PLAYER_URL_PREFIX_LENGTH + MAX_BASE_FILENAME_LENGTH); ConstructPlayerURL(&PlayerURL, ""); + buffer URLPrefix; + ClaimBuffer(&URLPrefix, "URLPrefix", 1024); + ConstructURLPrefix(&URLPrefix, INCLUDE_JS, PAGE_INDEX); char Script[532 + StringLength(URLPrefix.Location) + (StringLength(Config.ProjectID) * 2)]; CopyString(Script, " \n" @@ -5291,6 +5468,7 @@ IndexToBuffer(index *Index, buffers *CollationBuffers) // NOTE(matt): This guy m FreeBuffer(&Index->Metadata.Buffer); return(RC_ERROR_MEMORY); } + CollationBuffers->Index.ID = "Index"; CollationBuffers->Index.Ptr = CollationBuffers->Index.Location; CopyStringToBuffer(&CollationBuffers->Index, queryContainer); @@ -5304,51 +5482,56 @@ IndexToBuffer(index *Index, buffers *CollationBuffers) // NOTE(matt): This guy m char Number[16]; char Text[1024]; // NOTE(matt): Surely this will be big enough index_metadata *This; + bool IndexRequired = FALSE; for(int EntryIndex = 0; EntryIndex < Index->Header.EntryCount; ++EntryIndex, Index->Metadata.Buffer.Ptr += sizeof(index_metadata)) { This = (index_metadata *)Index->Metadata.Buffer.Ptr; - CopyString(Number, This->BaseFilename + ProjectIDLength); - if(ProjectInfo[ProjectIndex].NumberingScheme == NS_LINEAR) + if(This->Size > 0) { - for(int i = 0; Number[i]; ++i) + IndexRequired = TRUE; + CopyString(Number, This->BaseFilename + ProjectIDLength); + if(ProjectInfo[ProjectIndex].NumberingScheme == NS_LINEAR) { - if(Number[i] == '_') + for(int i = 0; Number[i]; ++i) { - Number[i] = '.'; + if(Number[i] == '_') + { + Number[i] = '.'; + } } } - } - ConstructPlayerURL(&PlayerURL, This->BaseFilename); + ConstructPlayerURL(&PlayerURL, This->BaseFilename); - if(ProjectUnit) - { - CopyStringToBuffer(&CollationBuffers->Index, - "
\n" - " ", PlayerURL.Location); + if(ProjectUnit) + { + CopyStringToBuffer(&CollationBuffers->Index, + " \n"); - } - else - { - CopyStringToBuffer(&CollationBuffers->Index, - " \n"); + } + else + { + CopyStringToBuffer(&CollationBuffers->Index, + " \n"); + CopyStringToBufferHTMLSafe(&CollationBuffers->Index, This->Title); + CopyStringToBuffer(&CollationBuffers->Index, + "\n" + "
\n"); + } } } @@ -5357,7 +5540,8 @@ IndexToBuffer(index *Index, buffers *CollationBuffers) // NOTE(matt): This guy m CopyStringToBuffer(&CollationBuffers->Index, Script); FreeBuffer(&Index->Metadata.Buffer); - return RC_SUCCESS; + if(!IndexRequired) { return RC_NOOP; } + else { return RC_SUCCESS; } } else { @@ -5398,7 +5582,7 @@ StripSurroundingSlashes(char *String) // NOTE(matt): For relative paths } int -GeneratePlayerPage(index *Index, int EntryIndex, buffers *CollationBuffers, template *PlayerTemplate, char *BaseFilename) +GeneratePlayerPage(index *Index, neighbourhood *N, buffers *CollationBuffers, template *PlayerTemplate, char *BaseFilename) { buffer OutputDirectoryPath; ClaimBuffer(&OutputDirectoryPath, "OutputDirectoryPath", 1024); @@ -5430,35 +5614,14 @@ GeneratePlayerPage(index *Index, int EntryIndex, buffers *CollationBuffers, temp break; } } - int PlayerOffset = 0; // NOTE(matt): Could just straight up pass the LinkOffsets.PrevStart directly... - BuffersToHTML(CollationBuffers, PlayerTemplate, PlayerPagePath, PAGE_PLAYER, &PlayerOffset); - Index->Entry.LinkOffsets.PrevStart += PlayerOffset; + BuffersToHTML(CollationBuffers, PlayerTemplate, PlayerPagePath, PAGE_PLAYER, &N->This.LinkOffsets.PrevStart); ReadFileIntoBuffer(&Index->Metadata, 0); - Index->Metadata.Buffer.Ptr += sizeof(index_header); - int MetadataInsertionOffset = 0; -#if BINARY_SEARCH -START_TIMING_BLOCK(" GeneratePlayerPage(%s) [passing in EntryIndex]: ", BaseFilename); - MetadataInsertionOffset = sizeof(index_header) + sizeof(index_metadata) * EntryIndex; -#else -START_TIMING_BLOCK(" GeneratePlayerPage(%s) LinearSearch: ", BaseFilename); - for(EntryIndex = 0; EntryIndex < Index->Header.EntryCount; ++EntryIndex) - { - index_metadata This = *(index_metadata *)Index->Metadata.Buffer.Ptr; - if(!StringsDiffer(This.BaseFilename, Index->Entry.BaseFilename)) - { - MetadataInsertionOffset = (Index->Metadata.Buffer.Ptr - Index->Metadata.Buffer.Location); - break; - } - Index->Metadata.Buffer.Ptr += sizeof(index_metadata); - } -#endif -END_TIMING_BLOCK(); if(!(Index->Metadata.Handle = fopen(Index->Metadata.Path, "w"))) { FreeBuffer(&Index->Metadata.Buffer); return RC_ERROR_FILE; } - fwrite(Index->Metadata.Buffer.Location, MetadataInsertionOffset, 1, Index->Metadata.Handle); - fwrite(&Index->Entry, sizeof(Index->Entry), 1, Index->Metadata.Handle); - fwrite(Index->Metadata.Buffer.Location + MetadataInsertionOffset + sizeof(Index->Entry), Index->Metadata.FileSize - MetadataInsertionOffset - sizeof(Index->Entry), 1, Index->Metadata.Handle); + Index->Metadata.Buffer.Ptr = Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * N->ThisIndex; + *(index_metadata *)Index->Metadata.Buffer.Ptr = N->This; + fwrite(Index->Metadata.Buffer.Location, Index->Metadata.FileSize, 1, Index->Metadata.Handle); fclose(Index->Metadata.Handle); FreeBuffer(&Index->Metadata.Buffer); @@ -5491,65 +5654,102 @@ GenerateIndexPage(index *Index, buffers *CollationBuffers, template *IndexTempla char IndexPagePath[1024]; CopyString(IndexPagePath, "%s/index.html", OutputDirectoryPath.Location); DeclaimBuffer(&OutputDirectoryPath); - IndexToBuffer(Index, CollationBuffers); - BuffersToHTML(CollationBuffers, IndexTemplate, IndexPagePath, PAGE_INDEX, 0); + switch(IndexToBuffer(Index, CollationBuffers)) + { + case RC_SUCCESS: + { + BuffersToHTML(CollationBuffers, IndexTemplate, IndexPagePath, PAGE_INDEX, 0); + break; + } + case RC_NOOP: + { + DeleteIndexPageFromFilesystem(); + break; + } + } FreeBuffer(&CollationBuffers->Index); return RC_SUCCESS; } int -DeletePlayerPageFromFilesystem(char *BaseFilename, char *PlayerLocation, bool Relocating) +DeleteEntry(index *Index, neighbourhood *Neighbourhood, char *BaseFilename) { - // NOTE(matt): Once we have the notion of an output filename format, we'll need to use that here - buffer OutputDirectoryPath; - ClaimBuffer(&OutputDirectoryPath, "OutputDirectoryPath", 1024); - ConstructDirectoryPath(&OutputDirectoryPath, PAGE_PLAYER, PlayerLocation, BaseFilename); - DIR *PlayerDir; - - if((PlayerDir = opendir(OutputDirectoryPath.Location))) // There is a directory for the Player, which there probably should be if not for manual intervention + if(DeleteFromIndex(Index, Neighbourhood, BaseFilename) == RC_SUCCESS) { - char PlayerPagePath[256]; - CopyString(PlayerPagePath, "%s/index.html", OutputDirectoryPath.Location); - FILE *PlayerPage; - if((PlayerPage = fopen(PlayerPagePath, "r"))) + if(Neighbourhood->This.Size > 0) { - fclose(PlayerPage); - remove(PlayerPagePath); + LinkNeighbours(Index, Neighbourhood, BaseFilename, LINK_EXCLUDE); } - - closedir(PlayerDir); - if((remove(OutputDirectoryPath.Location) == -1)) - { - LogError(LOG_NOTICE, "Mostly deleted %s. Unable to remove directory %s: %s", BaseFilename, OutputDirectoryPath.Location, strerror(errno)); - fprintf(stderr, "\e[1;30mMostly deleted\e[0m %s. \e[1;31mUnable to remove directory\e[0m %s: %s", BaseFilename, OutputDirectoryPath.Location, strerror(errno)); - } - else - { - if(!Relocating) - { - LogError(LOG_INFORMATIONAL, "Deleted %s", BaseFilename); - fprintf(stderr, "\e[1;30mDeleted\e[0m %s\n", BaseFilename); - } - - } - } - DeclaimBuffer(&OutputDirectoryPath); - return RC_SUCCESS; -} - -int -DeleteEntry(index *Index, char *BaseFilename) -{ - int EntryIndex = 0; - if(DeleteFromIndex(Index, &EntryIndex, BaseFilename) == RC_SUCCESS) - { - LinkNeighbours(Index, EntryIndex, BaseFilename, LINK_EXCLUDE); DeletePlayerPageFromFilesystem(BaseFilename, Config.PlayerLocation, FALSE); return RC_SUCCESS; } return RC_NOOP; } +void +InsertEntry(index *Index, neighbourhood *Neighbourhood, buffers *CollationBuffers, template *PlayerTemplate, template *BespokeTemplate, char *BaseFilename, bool *Inserted, bool RecheckingPrivacy) +{ + switch(InsertIntoIndex(Index, Neighbourhood, CollationBuffers, &BespokeTemplate, BaseFilename, RecheckingPrivacy)) + { + case RC_UNFOUND: + LinkNeighbours(Index, Neighbourhood, BaseFilename, LINK_INCLUDE); + *Inserted = TRUE; + case RC_SUCCESS: + { + if(BespokeTemplate->Metadata.Filename && StringsDiffer(BespokeTemplate->Metadata.Filename, "")) + { + GeneratePlayerPage(Index, Neighbourhood, CollationBuffers, BespokeTemplate, BaseFilename); + DeclaimTemplate(BespokeTemplate); + } + else + { + GeneratePlayerPage(Index, Neighbourhood, CollationBuffers, PlayerTemplate, BaseFilename); + } + *Inserted = TRUE; + } break; + } +} + +int +RecheckPrivacy(index *Index, buffers *CollationBuffers, template *IndexTemplate, template *PlayerTemplate, template *BespokeTemplate) +{ + if(ReadFileIntoBuffer(&Index->Metadata, 0) == RC_SUCCESS) + { + Index->Header = *(index_header*)Index->Metadata.Buffer.Ptr; + index_metadata Entry = { 0 }; + int PrivateEntryIndex = 0; + index_metadata PrivateEntries[Index->Header.EntryCount]; + bool Inserted = FALSE; + for(int IndexEntry = 0; IndexEntry < Index->Header.EntryCount; ++IndexEntry) + { + Entry = *(index_metadata *)(Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * IndexEntry); + if(Entry.Size == 0) + { + PrivateEntries[PrivateEntryIndex] = Entry; + ++PrivateEntryIndex; + } + } + FreeBuffer(&Index->Metadata.Buffer); + + for(int i = 0; i < PrivateEntryIndex; ++i) + { + neighbourhood Neighbourhood = { 0 }; + Neighbourhood.PrevIndex = -1; + Neighbourhood.ThisIndex = -1; + Neighbourhood.NextIndex = -1; + InsertEntry(Index, &Neighbourhood, CollationBuffers, PlayerTemplate, BespokeTemplate, PrivateEntries[i].BaseFilename, &Inserted, TRUE); + } + + if(Inserted) + { + GenerateIndexPage(Index, CollationBuffers, IndexTemplate); + } + + LastPrivacyCheck = time(0); + } + return RC_SUCCESS; +} + int MonitorDirectory(index *Index, buffers *CollationBuffers, template *IndexTemplate, template *PlayerTemplate, template *BespokeTemplate, int inotifyInstance, int WatchDescriptor) { @@ -5561,62 +5761,52 @@ MonitorDirectory(index *Index, buffers *CollationBuffers, template *IndexTemplat #endif buffer Events; - if(ClaimBuffer(&Events, "inotify Events", Kilobytes(1)) == RC_ARENA_FULL) { return RC_ARENA_FULL; }; + if(ClaimBuffer(&Events, "inotify Events", Kilobytes(4)) == RC_ARENA_FULL) { return RC_ARENA_FULL; }; struct inotify_event *Event; - int BytesRead = read(inotifyInstance, Events.Location, Events.Size); + int BytesRead = read(inotifyInstance, Events.Location, Events.Size); // TODO(matt): Handle error EINVAL if(inotifyInstance < 0) { perror("MonitorDirectory()"); } + bool Deleted = FALSE; + bool Inserted = FALSE; + for(Events.Ptr = Events.Location; Events.Ptr < Events.Location + BytesRead && Events.Ptr - Events.Location < Events.Size; Events.Ptr += sizeof(struct inotify_event) + Event->len) { Event = (struct inotify_event *)Events.Ptr; - char *Ptr; - Ptr = Event->name; + char *Ptr = Event->name; Ptr += (StringLength(Event->name) - StringLength(".hmml")); if(!(StringsDiffer(Ptr, ".hmml"))) { *Ptr = '\0'; - char BaseFilename[256]; - CopyString(BaseFilename, Event->name); - *Ptr = '.'; + neighbourhood Neighbourhood = { 0 }; + Neighbourhood.PrevIndex = -1; + Neighbourhood.ThisIndex = -1; + Neighbourhood.NextIndex = -1; // TODO(matt): Maybe handle IN_ALL_EVENTS if(Event->mask & IN_DELETE || Event->mask & IN_MOVED_FROM) { - if(DeleteEntry(Index, BaseFilename) == RC_SUCCESS) + if(DeleteEntry(Index, &Neighbourhood, Event->name) == RC_SUCCESS) { - GenerateIndexPage(Index, CollationBuffers, IndexTemplate); + Deleted = TRUE; } } else { - int EntryIndex = 0; - switch(InsertIntoIndex(Index, &EntryIndex, CollationBuffers, &BespokeTemplate, BaseFilename)) - { - case RC_SUCCESS: - case RC_UNFOUND: - LinkNeighbours(Index, EntryIndex, BaseFilename, LINK_INCLUDE); - { - if(BespokeTemplate->Metadata.Filename && StringsDiffer(BespokeTemplate->Metadata.Filename, "")) - { - GeneratePlayerPage(Index, EntryIndex, CollationBuffers, BespokeTemplate, BaseFilename); - DeclaimTemplate(BespokeTemplate); - } - else - { - GeneratePlayerPage(Index, EntryIndex, CollationBuffers, PlayerTemplate, BaseFilename); - } - GenerateIndexPage(Index, CollationBuffers, IndexTemplate); - } break; - } + InsertEntry(Index, &Neighbourhood, CollationBuffers, PlayerTemplate, BespokeTemplate, Event->name, &Inserted, 0); } } } + if(Deleted || Inserted) + { + GenerateIndexPage(Index, CollationBuffers, IndexTemplate); + } + DeclaimBuffer(&Events); - return RC_NOOP; + return RC_SUCCESS; } int @@ -5815,6 +6005,22 @@ typedef struct char ID[32]; } index_entry; // Metadata, unless we actually want to bolster this? +void +RemoveChildDirectories(buffer FullPath, char *ParentDirectory) +{ + char *Ptr = FullPath.Location + StringLength(ParentDirectory); + RemoveDirectory(FullPath.Location); + while(FullPath.Ptr > Ptr) + { + if(*FullPath.Ptr == '/') + { + *FullPath.Ptr = '\0'; + RemoveDirectory(FullPath.Location); + } + --FullPath.Ptr; + } +} + int DeleteDeadIndexEntries(index *Index) { @@ -5842,65 +6048,82 @@ DeleteDeadIndexEntries(index *Index) exit(RC_ERROR_FATAL); } + bool NewPlayerLocation = FALSE; + bool NewIndexLocation = FALSE; if(StringsDiffer(Index->Header.PlayerLocation, Config.PlayerLocation)) { - buffer PlayerDirectory; - ClaimBuffer(&PlayerDirectory, "PlayerDirectory", 1024); + buffer OldPlayerDirectory; + ClaimBuffer(&OldPlayerDirectory, "OldPlayerDirectory", 1024); + ConstructDirectoryPath(&OldPlayerDirectory, PAGE_PLAYER, Index->Header.PlayerLocation, 0); + buffer NewPlayerDirectory; + ClaimBuffer(&NewPlayerDirectory, "NewPlayerDirectory", 1024); + ConstructDirectoryPath(&NewPlayerDirectory, PAGE_PLAYER, Config.PlayerLocation, 0); printf("\e[1;33mRelocating Player Page%s from %s to %s\e[0m\n", Index->Header.EntryCount > 1 ? "s" : "", - (StringsDiffer(Index->Header.PlayerLocation, "") ? Index->Header.PlayerLocation : (StringsDiffer(Config.BaseDir, ".") ? Config.BaseDir : "\"Base Directory\"")), - (StringsDiffer(Config.PlayerLocation, "") ? Config.PlayerLocation : (StringsDiffer(Config.BaseDir, ".") ? Config.BaseDir : "\"Base Directory\""))); - Index->Metadata.Buffer.Ptr = Index->Metadata.Buffer.Location + sizeof(Index->Header); + OldPlayerDirectory.Location, + NewPlayerDirectory.Location); + DeclaimBuffer(&NewPlayerDirectory); + for(int EntryIndex = 0; EntryIndex < Index->Header.EntryCount; ++EntryIndex) { - index_metadata This = *(index_metadata *)Index->Metadata.Buffer.Ptr; - ConstructDirectoryPath(&PlayerDirectory, PAGE_PLAYER, Index->Header.PlayerLocation, This.BaseFilename); + index_metadata This = *(index_metadata *)(Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * EntryIndex); + ConstructDirectoryPath(&OldPlayerDirectory, PAGE_PLAYER, Index->Header.PlayerLocation, This.BaseFilename); DeletePlayerPageFromFilesystem(This.BaseFilename, Index->Header.PlayerLocation, TRUE); - Index->Metadata.Buffer.Ptr += sizeof(This); } - DeclaimBuffer(&PlayerDirectory); - RemoveDirectoryRecursively(Index->Header.PlayerLocation); + + ConstructDirectoryPath(&OldPlayerDirectory, PAGE_PLAYER, Index->Header.PlayerLocation, 0); + + if(StringLength(Index->Header.PlayerLocation) > 0) + { + RemoveChildDirectories(OldPlayerDirectory, Config.BaseDir); + } + + DeclaimBuffer(&OldPlayerDirectory); + ClearCopyStringNoFormat(Index->Header.PlayerLocation, sizeof(Index->Header.PlayerLocation), Config.PlayerLocation); - if(!(Index->Metadata.Handle = fopen(Index->Metadata.Path, "w"))) { FreeBuffer(&Index->Metadata.Buffer); return RC_ERROR_FILE; } - fwrite(&Index->Header, sizeof(Index->Header), 1, Index->Metadata.Handle); - Index->Metadata.Buffer.Ptr = Index->Metadata.Buffer.Location + sizeof(Index->Header); - fwrite(Index->Metadata.Buffer.Ptr, Index->Metadata.FileSize - sizeof(Index->Header), 1, Index->Metadata.Handle); - Index->Metadata.Buffer.Ptr = Index->Metadata.Buffer.Location; - fclose(Index->Metadata.Handle); + NewPlayerLocation = TRUE; } if(StringsDiffer(Index->Header.IndexLocation, Config.IndexLocation)) { + buffer OldIndexDirectory; + ClaimBuffer(&OldIndexDirectory, "OldIndexDirectory", 1024); + ConstructDirectoryPath(&OldIndexDirectory, PAGE_INDEX, Index->Header.IndexLocation, 0); + buffer NewIndexDirectory; + ClaimBuffer(&NewIndexDirectory, "NewIndexDirectory", 1024); + ConstructDirectoryPath(&NewIndexDirectory, PAGE_INDEX, Config.IndexLocation, 0); printf("\e[1;33mRelocating Index Page from %s to %s\e[0m\n", - (StringsDiffer(Index->Header.IndexLocation, "") ? Index->Header.IndexLocation : (StringsDiffer(Config.BaseDir, ".") ? Config.BaseDir : "\"Base Directory\"")), - (StringsDiffer(Config.IndexLocation, "") ? Config.IndexLocation : (StringsDiffer(Config.BaseDir, ".") ? Config.BaseDir : "\"Base Directory\""))); - buffer IndexDirectory; - ClaimBuffer(&IndexDirectory, "IndexDirectory", 1024); - ConstructDirectoryPath(&IndexDirectory, PAGE_INDEX, Index->Header.IndexLocation, ""); + OldIndexDirectory.Location, + NewIndexDirectory.Location); + DeclaimBuffer(&NewIndexDirectory); + char IndexPagePath[2048] = { 0 }; - CopyString(IndexPagePath, "%s/index.html", IndexDirectory.Location); + CopyString(IndexPagePath, "%s/index.html", OldIndexDirectory.Location); remove(IndexPagePath); - RemoveDirectoryRecursively(IndexDirectory.Location); - DeclaimBuffer(&IndexDirectory); + if(StringLength(Index->Header.IndexLocation) > 0) + { + RemoveChildDirectories(OldIndexDirectory, Config.BaseDir); + } + DeclaimBuffer(&OldIndexDirectory); ClearCopyStringNoFormat(Index->Header.IndexLocation, sizeof(Index->Header.IndexLocation), Config.IndexLocation); - if(!(Index->Metadata.Handle = fopen(Index->Metadata.Path, "w"))) { FreeBuffer(&Index->Metadata.Buffer); return RC_ERROR_FILE; } - fwrite(&Index->Header, sizeof(Index->Header), 1, Index->Metadata.Handle); - Index->Metadata.Buffer.Ptr = Index->Metadata.Buffer.Location + sizeof(Index->Header); - fwrite(Index->Metadata.Buffer.Ptr, Index->Metadata.FileSize - sizeof(Index->Header), 1, Index->Metadata.Handle); - Index->Metadata.Buffer.Ptr = Index->Metadata.Buffer.Location; - fclose(Index->Metadata.Handle); + NewIndexLocation = TRUE; } - Index->Metadata.Buffer.Ptr = Index->Metadata.Buffer.Location + sizeof(Index->Header); + if(NewPlayerLocation || NewIndexLocation) + { + if(!(Index->Metadata.Handle = fopen(Index->Metadata.Path, "w"))) { FreeBuffer(&Index->Metadata.Buffer); return RC_ERROR_FILE; } + *(index_header *)Index->Metadata.Buffer.Location = Index->Header; + fwrite(Index->Metadata.Buffer.Location, Index->Metadata.FileSize, 1, Index->Metadata.Handle); + fclose(Index->Metadata.Handle); + } index_entry Entries[Index->Header.EntryCount]; for(int EntryIndex = 0; EntryIndex < Index->Header.EntryCount; ++EntryIndex) { - index_metadata This = *(index_metadata *)Index->Metadata.Buffer.Ptr; + index_metadata This = *(index_metadata *)(Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * EntryIndex); CopyStringNoFormat(Entries[EntryIndex].ID, This.BaseFilename); Entries[EntryIndex].Present = FALSE; - Index->Metadata.Buffer.Ptr += sizeof(This); } DIR *ProjectDirHandle; @@ -5939,7 +6162,11 @@ DeleteDeadIndexEntries(index *Index) if(Entries[i].Present == FALSE) { Deleted = TRUE; - DeleteEntry(Index, Entries[i].ID); + neighbourhood Neighbourhood = { 0 }; + Neighbourhood.PrevIndex = -1; + Neighbourhood.ThisIndex = -1; + Neighbourhood.NextIndex = -1; + DeleteEntry(Index, &Neighbourhood, Entries[i].ID); } } @@ -5974,25 +6201,10 @@ SyncIndexWithInput(index *Index, buffers *CollationBuffers, template *IndexTempl if(!(StringsDiffer(Ptr, ".hmml"))) { *Ptr = '\0'; - int EntryIndex = 0; - switch(InsertIntoIndex(Index, &EntryIndex, CollationBuffers, &BespokeTemplate, ProjectFiles->d_name)) - { - case RC_UNFOUND: - LinkNeighbours(Index, EntryIndex, ProjectFiles->d_name, LINK_INCLUDE); - case RC_SUCCESS: - { - if(BespokeTemplate->Metadata.Filename && StringsDiffer(BespokeTemplate->Metadata.Filename, "")) - { - GeneratePlayerPage(Index, EntryIndex, CollationBuffers, BespokeTemplate, ProjectFiles->d_name); - DeclaimTemplate(BespokeTemplate); - } - else - { - GeneratePlayerPage(Index, EntryIndex, CollationBuffers, PlayerTemplate, ProjectFiles->d_name); - } - Inserted = TRUE; - } - } + neighbourhood Neighbourhood = { 0 }; + Neighbourhood.PrevIndex = -1; + Neighbourhood.NextIndex = -1; + InsertEntry(Index, &Neighbourhood, CollationBuffers, PlayerTemplate, BespokeTemplate, ProjectFiles->d_name, &Inserted, 0); } } closedir(ProjectDirHandle); @@ -6021,10 +6233,6 @@ PrintVersions() int main(int ArgC, char **Args) { -#if 0 - printf("%lu\n", sizeof(index_metadata)); - exit(1); -#endif // TODO(matt): Read all defaults from the config config DefaultConfig = { .RootDir = ".", @@ -6045,7 +6253,6 @@ main(int ArgC, char **Args) .Mode = 0, .OutLocation = "out.html", .OutIntegratedLocation = "out_integrated.html", - .ForceIntegration = FALSE, .ProjectDir = ".", .ProjectID = "", .Theme = "", @@ -6071,7 +6278,7 @@ main(int ArgC, char **Args) } char CommandLineArg; - while((CommandLineArg = getopt(ArgC, Args, "a:b:B:c:d:efhi:j:l:m:n:o:p:qr:R:s:t:u:vwx:y:")) != -1) + while((CommandLineArg = getopt(ArgC, Args, "a:b:B:c:d:efghi:j:l:m:n:o:p:qr:R:s:t:u:vwx:y:")) != -1) { switch(CommandLineArg) { @@ -6094,7 +6301,10 @@ main(int ArgC, char **Args) Config.Mode |= MODE_EXAMINE; break; case 'f': - Config.ForceIntegration = TRUE; + Config.Mode |= MODE_FORCEINTEGRATION; + break; + case 'g': + Config.Mode |= MODE_NOPRIVACY; break; case 'i': Config.ImagesDir = StripSurroundingSlashes(optarg); @@ -6354,6 +6564,12 @@ main(int ArgC, char **Args) /* NOTE(matt): Here, I think, is where we'll split into sub-projects (...really?...) */ " Player Page(s): \e[1;30m(-a)\e[0m\t\t%s\n" " Player Page Prefix: \e[1;30m(hardcoded)\e[0m\t%s\n" + "\n" + "Modes\n" + " Force template integration: \e[1;30m(-f)\e[0m\t%s\n" + " Ignore video privacy status: \e[1;30m(-g)\e[0m\t%s\n" + " Quit after sync: \e[1;30m(-q)\e[0m\t\t%s\n" + " Force quote cache rebuild: \e[1;30m(-w)\e[0m\t%s\n" "\n", Config.CacheDir, @@ -6378,7 +6594,12 @@ main(int ArgC, char **Args) StringsDiffer(Config.BaseURL, "") ? Config.BaseURL : "[empty]", StringsDiffer(Config.IndexLocation, "") ? Config.IndexLocation : "(same as base)", StringsDiffer(Config.PlayerLocation, "") ? Config.PlayerLocation : "(directly descended from base)", - StringsDiffer(Config.PlayerURLPrefix, "") ? Config.PlayerURLPrefix : Config.ProjectID); + StringsDiffer(Config.PlayerURLPrefix, "") ? Config.PlayerURLPrefix : Config.ProjectID, + + Config.Mode & MODE_FORCEINTEGRATION ? "on" : "off", + Config.Mode & MODE_NOPRIVACY ? "on" : "off", + Config.Mode & MODE_ONESHOT ? "on" : "off", + Config.Mode & MODE_NOCACHE ? "on" : "off"); if((StringsDiffer(Config.IndexLocation, "") || StringsDiffer(Config.PlayerLocation, "")) && StringLength(Config.BaseURL) == 0) @@ -6406,7 +6627,7 @@ main(int ArgC, char **Args) // NOTE(matt): Do we want to also watch IN_DELETE_SELF events? int WatchDescriptor = inotify_add_watch(inotifyInstance, Config.ProjectDir, IN_CLOSE_WRITE | IN_DELETE | IN_MOVED_FROM | IN_MOVED_TO); - while(MonitorDirectory(&Index, &CollationBuffers, IndexTemplate, PlayerTemplate, BespokeTemplate, inotifyInstance, WatchDescriptor) != RC_ERROR_FATAL) + while(MonitorDirectory(&Index, &CollationBuffers, IndexTemplate, PlayerTemplate, BespokeTemplate, inotifyInstance, WatchDescriptor) != RC_ARENA_FULL) { // TODO(matt): Refetch the quotes and rebuild player pages if needed // @@ -6417,6 +6638,11 @@ main(int ArgC, char **Args) // The most ideal solution is possibly that we store quote numbers in the Metadata->Entry, listen for and handle a // 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. + // + if(!(Config.Mode & MODE_NOPRIVACY) && time(0) - LastPrivacyCheck > 60 * 60 * 4) + { + RecheckPrivacy(&Index, &CollationBuffers, IndexTemplate, PlayerTemplate, BespokeTemplate); + } sleep(Config.UpdateInterval); } } @@ -6439,7 +6665,7 @@ NextFile: if(!(StringsDiffer(Ptr, ".hmml"))) { CopyString(Config.SingleHMMLFilePath, Args[FileIndex]); - switch(HMMLToBuffers(&CollationBuffers, &BespokeTemplate, Args[FileIndex], 0, 0)) + switch(HMMLToBuffers(&CollationBuffers, &BespokeTemplate, Args[FileIndex], 0)) { // TODO(matt): Actually sort out the fatality of these cases, once we are always-on case RC_ERROR_FILE: