return remove(path);
}
-/** FIO_openSrcFile() :
- * condition : `srcFileName` must be non-NULL. `prefs` may be NULL.
- * @result : FILE* to `srcFileName`, or NULL if it fails */
static FILE* FIO_openSrcFile(const FIO_prefs_t* const prefs, const char* srcFileName, stat_t* statbuf)
{
int allowBlockDevices = prefs != NULL ? prefs->allowBlockDevices : 0;
assert(srcFileName != NULL);
assert(statbuf != NULL);
- if (!strcmp (srcFileName, stdinmark)) {
+
+ if (!strcmp(srcFileName, stdinmark)) {
DISPLAYLEVEL(4,"Using stdin for input \n");
SET_BINARY_MODE(stdin);
return stdin;
return NULL;
}
+ /* Accept regular files, FIFOs, and process substitution file descriptors */
if (!UTIL_isRegularFileStat(statbuf)
&& !UTIL_isFIFOStat(statbuf)
+ && !UTIL_isFileDescriptorPipe(srcFileName) /* Process substitution support */
&& !(allowBlockDevices && UTIL_isBlockDevStat(statbuf))
) {
DISPLAYLEVEL(1, "zstd: %s is not a regular file -- ignored \n",
return 0;
}
+/* process substitution */
+int UTIL_isFileDescriptorPipe(const char* filename)
+{
+ UTIL_TRACE_CALL("UTIL_isFileDescriptorPipe(%s)", filename);
+ /* Check if the filename is a /dev/fd/ path which indicates a file descriptor */
+ if (filename[0] == '/' && strncmp(filename, "/dev/fd/", 8) == 0) {
+ UTIL_TRACE_RET(1);
+ return 1;
+ }
+
+ /* Check for alternative process substitution formats on different systems */
+ if (filename[0] == '/' && strncmp(filename, "/proc/self/fd/", 14) == 0) {
+ UTIL_TRACE_RET(1);
+ return 1;
+ }
+
+ UTIL_TRACE_RET(0);
+ return 0; /* Not recognized as a file descriptor pipe */
+}
+
/* UTIL_isBlockDevStat : distinguish named pipes */
int UTIL_isBlockDevStat(const stat_t* statbuf)
{
}
-/* condition : @file must be valid, and not have reached its end.
- * @return : length of line written into @buf, ended with `\0` instead of '\n',
- * or 0, if there is no new line */
-static size_t readLineFromFile(char* buf, size_t len, FILE* file)
-{
- assert(!feof(file));
- if ( fgets(buf, (int) len, file) == NULL ) return 0;
- { size_t linelen = strlen(buf);
- if (strlen(buf)==0) return 0;
- if (buf[linelen-1] == '\n') linelen--;
- buf[linelen] = '\0';
- return linelen+1;
- }
-}
-
-/* Conditions :
- * size of @inputFileName file must be < @dstCapacity
- * @dst must be initialized
- * @return : nb of lines
- * or -1 if there's an error
- */
-static int
-readLinesFromFile(void* dst, size_t dstCapacity,
- const char* inputFileName)
+/*Note: buf is not freed in case function successfully created table because filesTable->fileNames[0] = buf*/
+FileNamesTable*
+UTIL_createFileNamesTable_fromFileName(const char* inputFileName)
{
- int nbFiles = 0;
- size_t pos = 0;
- char* const buf = (char*)dst;
- FILE* const inputFile = fopen(inputFileName, "r");
-
- assert(dst != NULL);
+ size_t nbFiles = 0;
+ char* buf = NULL;
+ size_t bufSize = 0;
+ size_t totalRead = 0;
+ size_t bytesRead = 0;
+
+ /* Check if the input is a regular file or a file descriptor */
+ { stat_t statbuf;
+ if (!UTIL_stat(inputFileName, &statbuf)) {
+ return NULL;
+ }
- if(!inputFile) {
- if (g_utilDisplayLevel >= 1) perror("zstd:util:readLinesFromFile");
- return -1;
+ if (!UTIL_isRegularFileStat(&statbuf) &&
+ !UTIL_isFIFOStat(&statbuf) &&
+ !UTIL_isFileDescriptorPipe(inputFileName)) {
+ return NULL;
+ }
}
- while ( !feof(inputFile) ) {
- size_t const lineLength = readLineFromFile(buf+pos, dstCapacity-pos, inputFile);
- if (lineLength == 0) break;
- assert(pos + lineLength <= dstCapacity); /* '=' for inputFile not terminated with '\n' */
- pos += lineLength;
- ++nbFiles;
- }
+ /* Open the input file */
+ { FILE* const inFile = fopen(inputFileName, "rb");
+ if (inFile == NULL) return NULL;
- CONTROL( fclose(inputFile) == 0 );
+ /* Start with a reasonable buffer size */
+ bufSize = 64 * 1024;
+ buf = (char*)malloc(bufSize);
+ if (buf == NULL) {
+ fclose(inFile);
+ return NULL;
+ }
- return nbFiles;
-}
+ /* Read the file incrementally */
+ while ((bytesRead = fread(buf + totalRead, 1, bufSize - totalRead - 1, inFile)) > 0) {
+ totalRead += bytesRead;
+
+ /* If buffer is nearly full, expand it */
+ if (bufSize - totalRead < 1024) {
+ size_t newBufSize;
+ if (bufSize >= MAX_FILE_OF_FILE_NAMES_SIZE) {
+ /* Too large, abort */
+ free(buf);
+ fclose(inFile);
+ return NULL;
+ }
-/*Note: buf is not freed in case function successfully created table because filesTable->fileNames[0] = buf*/
-FileNamesTable*
-UTIL_createFileNamesTable_fromFileName(const char* inputFileName)
-{
- size_t nbFiles = 0;
- char* buf;
- size_t bufSize;
- stat_t statbuf;
+ newBufSize = bufSize * 2;
+ if (newBufSize > MAX_FILE_OF_FILE_NAMES_SIZE)
+ newBufSize = MAX_FILE_OF_FILE_NAMES_SIZE;
- if (!UTIL_stat(inputFileName, &statbuf) || !UTIL_isRegularFileStat(&statbuf))
- return NULL;
+ { char* newBuf = (char*)realloc(buf, newBufSize);
+ if (newBuf == NULL) {
+ free(buf);
+ fclose(inFile);
+ return NULL;
+ }
- { U64 const inputFileSize = UTIL_getFileSizeStat(&statbuf);
- if(inputFileSize > MAX_FILE_OF_FILE_NAMES_SIZE)
- return NULL;
- bufSize = (size_t)(inputFileSize + 1); /* (+1) to add '\0' at the end of last filename */
+ buf = newBuf;
+ }
+ bufSize = newBufSize;
+ }
+ }
+
+ fclose(inFile);
}
- buf = (char*) malloc(bufSize);
- CONTROL( buf != NULL );
+ /* Add null terminator to the end */
+ buf[totalRead] = '\0';
- { int const ret_nbFiles = readLinesFromFile(buf, bufSize, inputFileName);
+ /* Count and process the lines */
+ {
+ size_t lineCount = 0;
+ size_t i = 0;
+
+ /* Convert newlines to null terminators and count lines */
+ while (i < totalRead) {
+ if (buf[i] == '\n') {
+ buf[i] = '\0'; /* Replace newlines with null terminators */
+ lineCount++;
+ }
+ i++;
+ }
- if (ret_nbFiles <= 0) {
- free(buf);
- return NULL;
+ /* Count the last line if it doesn't end with a newline */
+ if (totalRead > 0 && buf[totalRead-1] != '\0') {
+ lineCount++;
}
- nbFiles = (size_t)ret_nbFiles;
+
+ nbFiles = lineCount;
}
- { const char** filenamesTable = (const char**) malloc(nbFiles * sizeof(*filenamesTable));
- CONTROL(filenamesTable != NULL);
+ if (nbFiles == 0) {
+ free(buf);
+ return NULL;
+ }
+
+ /* Create the file names table */
+ { const char** filenamesTable = (const char**)malloc(nbFiles * sizeof(*filenamesTable));
+ if (filenamesTable == NULL) {
+ free(buf);
+ return NULL;
+ }
- { size_t fnb, pos = 0;
+ {
+ size_t fnb, pos = 0;
for (fnb = 0; fnb < nbFiles; fnb++) {
filenamesTable[fnb] = buf+pos;
pos += strlen(buf+pos)+1; /* +1 for the finishing `\0` */
}
- assert(pos <= bufSize);
+ assert(pos <= bufSize);
}
return UTIL_assembleFileNamesTable(filenamesTable, nbFiles, buf);