@@ -151,7 +151,8 @@ int UTIL_requireUserConfirmation(const char* prompt, const char* abortMsg,
151
151
/*-*************************************
152
152
* Constants
153
153
***************************************/
154
- #define LIST_SIZE_INCREASE (8*1024)
154
+ #define KB * (1 << 10)
155
+ #define LIST_SIZE_INCREASE (8 KB)
155
156
#define MAX_FILE_OF_FILE_NAMES_SIZE (1<<20)*50
156
157
157
158
@@ -448,6 +449,26 @@ int UTIL_isFIFOStat(const stat_t* statbuf)
448
449
return 0 ;
449
450
}
450
451
452
+ /* process substitution */
453
+ int UTIL_isFileDescriptorPipe (const char * filename )
454
+ {
455
+ UTIL_TRACE_CALL ("UTIL_isFileDescriptorPipe(%s)" , filename );
456
+ /* Check if the filename is a /dev/fd/ path which indicates a file descriptor */
457
+ if (filename [0 ] == '/' && strncmp (filename , "/dev/fd/" , 8 ) == 0 ) {
458
+ UTIL_TRACE_RET (1 );
459
+ return 1 ;
460
+ }
461
+
462
+ /* Check for alternative process substitution formats on different systems */
463
+ if (filename [0 ] == '/' && strncmp (filename , "/proc/self/fd/" , 14 ) == 0 ) {
464
+ UTIL_TRACE_RET (1 );
465
+ return 1 ;
466
+ }
467
+
468
+ UTIL_TRACE_RET (0 );
469
+ return 0 ; /* Not recognized as a file descriptor pipe */
470
+ }
471
+
451
472
/* UTIL_isBlockDevStat : distinguish named pipes */
452
473
int UTIL_isBlockDevStat (const stat_t * statbuf )
453
474
{
@@ -614,101 +635,157 @@ U64 UTIL_getTotalFileSize(const char* const * fileNamesTable, unsigned nbFiles)
614
635
}
615
636
616
637
617
- /* condition : @file must be valid, and not have reached its end.
618
- * @return : length of line written into @buf, ended with `\0` instead of '\n',
619
- * or 0, if there is no new line */
620
- static size_t readLineFromFile (char * buf , size_t len , FILE * file )
638
+ /* Read the entire content of a file into a buffer with progressive resizing */
639
+ static char * UTIL_readFileContent (FILE * inFile , size_t * totalReadPtr )
621
640
{
622
- assert (!feof (file ));
623
- if ( fgets (buf , (int ) len , file ) == NULL ) return 0 ;
624
- { size_t linelen = strlen (buf );
625
- if (strlen (buf )== 0 ) return 0 ;
626
- if (buf [linelen - 1 ] == '\n' ) linelen -- ;
627
- buf [linelen ] = '\0' ;
628
- return linelen + 1 ;
641
+ size_t bufSize = 64 KB ; /* Start with a reasonable buffer size */
642
+ size_t totalRead = 0 ;
643
+ size_t bytesRead = 0 ;
644
+ char * buf = (char * )malloc (bufSize );
645
+ if (buf == NULL ) return NULL ;
646
+
647
+
648
+ /* Read the file incrementally */
649
+ while ((bytesRead = fread (buf + totalRead , 1 , bufSize - totalRead - 1 , inFile )) > 0 ) {
650
+ totalRead += bytesRead ;
651
+
652
+ /* If buffer is nearly full, expand it */
653
+ if (bufSize - totalRead < 1 KB ) {
654
+ if (bufSize >= MAX_FILE_OF_FILE_NAMES_SIZE ) {
655
+ /* Too large, abort */
656
+ free (buf );
657
+ return NULL ;
658
+ }
659
+
660
+ { size_t newBufSize = bufSize * 2 ;
661
+ if (newBufSize > MAX_FILE_OF_FILE_NAMES_SIZE )
662
+ newBufSize = MAX_FILE_OF_FILE_NAMES_SIZE ;
663
+
664
+ { char * newBuf = (char * )realloc (buf , newBufSize );
665
+ if (newBuf == NULL ) {
666
+ free (buf );
667
+ return NULL ;
668
+ }
669
+
670
+ buf = newBuf ;
671
+ bufSize = newBufSize ;
672
+ } } }
629
673
}
674
+
675
+ /* Add null terminator to the end */
676
+ buf [totalRead ] = '\0' ;
677
+ * totalReadPtr = totalRead ;
678
+
679
+ return buf ;
630
680
}
631
681
632
- /* Conditions :
633
- * size of @inputFileName file must be < @dstCapacity
634
- * @dst must be initialized
635
- * @return : nb of lines
636
- * or -1 if there's an error
637
- */
638
- static int
639
- readLinesFromFile (void * dst , size_t dstCapacity ,
640
- const char * inputFileName )
682
+ /* Process a buffer containing multiple lines and count the number of lines */
683
+ static size_t UTIL_processLines (char * buffer , size_t bufferSize )
641
684
{
642
- int nbFiles = 0 ;
643
- size_t pos = 0 ;
644
- char * const buf = (char * )dst ;
645
- FILE * const inputFile = fopen (inputFileName , "r" );
685
+ size_t lineCount = 0 ;
686
+ size_t i = 0 ;
646
687
647
- assert (dst != NULL );
688
+ /* Convert newlines to null terminators and count lines */
689
+ while (i < bufferSize ) {
690
+ if (buffer [i ] == '\n' ) {
691
+ buffer [i ] = '\0' ; /* Replace newlines with null terminators */
692
+ lineCount ++ ;
693
+ }
694
+ i ++ ;
695
+ }
648
696
649
- if (! inputFile ) {
650
- if ( g_utilDisplayLevel >= 1 ) perror ( "zstd:util:readLinesFromFile" );
651
- return -1 ;
697
+ /* Count the last line if it doesn't end with a newline */
698
+ if ( bufferSize > 0 && ( i == 0 || buffer [ i - 1 ] != '\0' )) {
699
+ lineCount ++ ;
652
700
}
653
701
654
- while ( !feof (inputFile ) ) {
655
- size_t const lineLength = readLineFromFile (buf + pos , dstCapacity - pos , inputFile );
656
- if (lineLength == 0 ) break ;
657
- assert (pos + lineLength <= dstCapacity ); /* '=' for inputFile not terminated with '\n' */
658
- pos += lineLength ;
659
- ++ nbFiles ;
702
+ return lineCount ;
703
+ }
704
+
705
+ /* Create an array of pointers to the lines in a buffer */
706
+ static const char * * UTIL_createLinePointers (char * buffer , size_t numLines , size_t bufferSize )
707
+ {
708
+ size_t lineIndex = 0 ;
709
+ size_t pos = 0 ;
710
+ void * const bufferPtrs = malloc (numLines * sizeof (const char * * ));
711
+ const char * * const linePointers = (const char * * )bufferPtrs ;
712
+ if (bufferPtrs == NULL ) return NULL ;
713
+
714
+ while (lineIndex < numLines && pos < bufferSize ) {
715
+ size_t len = 0 ;
716
+ linePointers [lineIndex ++ ] = buffer + pos ;
717
+
718
+ /* Find the next null terminator, being careful not to go past the buffer */
719
+ while ((pos + len < bufferSize ) && buffer [pos + len ] != '\0' ) {
720
+ len ++ ;
721
+ }
722
+
723
+ /* Move past this string and its null terminator */
724
+ pos += len ;
725
+ if (pos < bufferSize ) pos ++ ; /* Skip the null terminator if we're not at buffer end */
660
726
}
661
727
662
- CONTROL ( fclose (inputFile ) == 0 );
728
+ /* Verify we processed the expected number of lines */
729
+ if (lineIndex != numLines ) {
730
+ /* Something went wrong - we didn't find as many lines as expected */
731
+ free (bufferPtrs );
732
+ return NULL ;
733
+ }
663
734
664
- return nbFiles ;
735
+ return linePointers ;
665
736
}
666
737
667
- /*Note: buf is not freed in case function successfully created table because filesTable->fileNames[0] = buf*/
668
738
FileNamesTable *
669
- UTIL_createFileNamesTable_fromFileName (const char * inputFileName )
739
+ UTIL_createFileNamesTable_fromFileList (const char * fileList )
670
740
{
671
- size_t nbFiles = 0 ;
672
- char * buf ;
673
- size_t bufSize ;
674
741
stat_t statbuf ;
742
+ char * buffer = NULL ;
743
+ size_t numLines = 0 ;
744
+ size_t bufferSize = 0 ;
675
745
676
- if (!UTIL_stat (inputFileName , & statbuf ) || !UTIL_isRegularFileStat (& statbuf ))
746
+ /* Check if the input is a valid file */
747
+ if (!UTIL_stat (fileList , & statbuf )) {
677
748
return NULL ;
678
-
679
- { U64 const inputFileSize = UTIL_getFileSizeStat (& statbuf );
680
- if (inputFileSize > MAX_FILE_OF_FILE_NAMES_SIZE )
681
- return NULL ;
682
- bufSize = (size_t )(inputFileSize + 1 ); /* (+1) to add '\0' at the end of last filename */
683
749
}
684
750
685
- buf = (char * ) malloc (bufSize );
686
- CONTROL ( buf != NULL );
751
+ /* Check if the input is a supported type */
752
+ if (!UTIL_isRegularFileStat (& statbuf ) &&
753
+ !UTIL_isFIFOStat (& statbuf ) &&
754
+ !UTIL_isFileDescriptorPipe (fileList )) {
755
+ return NULL ;
756
+ }
687
757
688
- { int const ret_nbFiles = readLinesFromFile (buf , bufSize , inputFileName );
758
+ /* Open the input file */
759
+ { FILE * const inFile = fopen (fileList , "rb" );
760
+ if (inFile == NULL ) return NULL ;
689
761
690
- if (ret_nbFiles <= 0 ) {
691
- free (buf );
692
- return NULL ;
693
- }
694
- nbFiles = (size_t )ret_nbFiles ;
762
+ /* Read the file content */
763
+ buffer = UTIL_readFileContent (inFile , & bufferSize );
764
+ fclose (inFile );
695
765
}
696
766
697
- { const char * * filenamesTable = (const char * * ) malloc (nbFiles * sizeof (* filenamesTable ));
698
- CONTROL (filenamesTable != NULL );
767
+ if (buffer == NULL ) return NULL ;
699
768
700
- { size_t fnb , pos = 0 ;
701
- for (fnb = 0 ; fnb < nbFiles ; fnb ++ ) {
702
- filenamesTable [fnb ] = buf + pos ;
703
- pos += strlen (buf + pos )+ 1 ; /* +1 for the finishing `\0` */
704
- }
705
- assert (pos <= bufSize );
769
+ /* Process lines */
770
+ numLines = UTIL_processLines (buffer , bufferSize );
771
+ if (numLines == 0 ) {
772
+ free (buffer );
773
+ return NULL ;
774
+ }
775
+
776
+ /* Create line pointers */
777
+ { const char * * linePointers = UTIL_createLinePointers (buffer , numLines , bufferSize );
778
+ if (linePointers == NULL ) {
779
+ free (buffer );
780
+ return NULL ;
706
781
}
707
782
708
- return UTIL_assembleFileNamesTable (filenamesTable , nbFiles , buf );
783
+ /* Create the final table */
784
+ return UTIL_assembleFileNamesTable (linePointers , numLines , buffer );
709
785
}
710
786
}
711
787
788
+
712
789
static FileNamesTable *
713
790
UTIL_assembleFileNamesTable2 (const char * * filenames , size_t tableSize , size_t tableCapacity , char * buf )
714
791
{
0 commit comments