swad-core/swad_file.c

692 lines
24 KiB
C
Raw Normal View History

2014-12-01 23:55:08 +01:00
// swad_file.c: files
/*
SWAD (Shared Workspace At a Distance),
is a web platform developed at the University of Granada (Spain),
and used to support university teaching.
This file is part of SWAD core.
Copyright (C) 1999-2023 Antonio Ca<EFBFBD>as Vargas
2014-12-01 23:55:08 +01:00
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*****************************************************************************/
/********************************* Headers ***********************************/
/*****************************************************************************/
#include <ctype.h> // For isprint, isspace, etc.
#include <dirent.h> // For scandir, etc.
#include <errno.h> // For errno
#include <linux/limits.h> // For PATH_MAX
2019-12-29 12:39:00 +01:00
#include <stddef.h> // For NULL
2014-12-01 23:55:08 +01:00
#include <stdio.h> // For FILE,fprintf
2019-11-11 11:20:31 +01:00
#include <stdlib.h> // For exit, system, free, etc.
2014-12-01 23:55:08 +01:00
#include <string.h> // For string functions
#include <sys/stat.h> // For mkdir
#include <sys/types.h> // For mkdir
#include <unistd.h> // For unlink
#include "swad_config.h"
2019-03-20 13:05:09 +01:00
#include "swad_database.h"
#include "swad_error.h"
2014-12-01 23:55:08 +01:00
#include "swad_global.h"
#include "swad_file.h"
#include "swad_file_database.h"
#include "swad_parameter.h"
2014-12-01 23:55:08 +01:00
#include "swad_string.h"
/*****************************************************************************/
/************** External global variables from others modules ****************/
/*****************************************************************************/
extern struct Globals Gbl;
/*****************************************************************************/
/***************************** Private constants *****************************/
/*****************************************************************************/
#define Fil_NUM_BYTES_PER_CHUNK 4096
2016-04-01 01:59:27 +02:00
static struct
{
char FileName[PATH_MAX + 1];
} Fil_HTMLOutput;
/*****************************************************************************/
/************************* Private global variables **************************/
/*****************************************************************************/
static FILE *Fil_QueryFile = NULL; // Temporary file to save stdin
static FILE *Fil_Out = NULL; // Temporary file to save output to be written to stdout
/*****************************************************************************/
/***************************** Get query file ********************************/
/*****************************************************************************/
FILE *Fil_GetQueryFile (void)
{
return Fil_QueryFile;
}
/*****************************************************************************/
/*************************** Set/Get output file *****************************/
/*****************************************************************************/
void Fil_SetOutputFileToStdout (void)
{
Fil_Out = stdout;
}
FILE *Fil_GetOutputFile (void)
{
return Fil_Out;
}
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2014-12-21 14:47:04 +01:00
/******** Create HTML output file for the web page sent by this CGI **********/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2014-12-21 14:47:04 +01:00
void Fil_CreateFileForHTMLOutput (void)
2014-12-01 23:55:08 +01:00
{
2014-12-21 14:47:04 +01:00
/***** Check if exists the directory for HTML output. If not exists, create it *****/
2019-03-20 01:36:36 +01:00
Fil_CreateDirIfNotExists (Cfg_PATH_OUT_PRIVATE);
2014-12-01 23:55:08 +01:00
/***** Create a unique name for the file *****/
snprintf (Fil_HTMLOutput.FileName,sizeof (Fil_HTMLOutput.FileName),
"%s/%s.html",Cfg_PATH_OUT_PRIVATE,Cry_GetUniqueNameEncrypted ());
2014-12-01 23:55:08 +01:00
/***** Open file for writing and reading *****/
if ((Fil_Out = fopen (Fil_HTMLOutput.FileName,"w+t")) == NULL)
2014-12-01 23:55:08 +01:00
{
Fil_SetOutputFileToStdout ();
Err_ShowErrorAndExit ("Can not create output file.");
2014-12-01 23:55:08 +01:00
}
}
/*****************************************************************************/
2014-12-21 14:47:04 +01:00
/****************** Close and remove the HTML output file ********************/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2014-12-21 14:47:04 +01:00
void Fil_CloseAndRemoveFileForHTMLOutput (void)
2014-12-01 23:55:08 +01:00
{
if (Fil_Out)
2014-12-01 23:55:08 +01:00
{
fclose (Fil_Out);
unlink (Fil_HTMLOutput.FileName);
2014-12-01 23:55:08 +01:00
}
Fil_SetOutputFileToStdout ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/********** Open temporary file and write on it reading from stdin ***********/
/*****************************************************************************/
bool Fil_ReadStdinIntoTmpFile (void)
{
extern const char *Txt_UPLOAD_FILE_File_too_large_maximum_X_MiB_NO_HTML;
extern const char *Txt_UPLOAD_FILE_Upload_time_too_long_maximum_X_minutes_NO_HTML;
unsigned long long TmpFileSize;
bool FileIsTooBig = false;
bool TimeExceeded = false;
if ((Fil_QueryFile = tmpfile ()) == NULL)
2014-12-01 23:55:08 +01:00
{
Fil_EndOfReadingStdin ();
Err_ShowErrorAndExit ("Can not create temporary file.");
2014-12-01 23:55:08 +01:00
}
for (TmpFileSize = 0;
!feof (stdin) && !FileIsTooBig && !TimeExceeded;
TmpFileSize++)
if (TmpFileSize < Fil_MAX_FILE_SIZE)
{
2017-01-28 15:58:46 +01:00
if (!(TmpFileSize % (64ULL * 1024ULL))) // Check timeout from time to time
if (time (NULL) - Dat_GetStartExecutionTimeUTC () >= Cfg_TIME_TO_ABORT_FILE_UPLOAD)
2014-12-01 23:55:08 +01:00
TimeExceeded = true;
fputc (fgetc (stdin),Fil_QueryFile);
2014-12-01 23:55:08 +01:00
}
else
FileIsTooBig = true;
if (FileIsTooBig || TimeExceeded)
{
Fil_EndOfReadingStdin (); // If stdin were not fully read, there will be problems with buffers
2019-02-17 01:14:55 +01:00
/* Begin HTTP response */
2019-02-17 01:14:55 +01:00
fprintf (stdout,"Content-type: text/plain; charset=windows-1252\n");
/* Status code and message */
fprintf (stdout,"Status: 501 Not Implemented\r\n\r\n");
2014-12-01 23:55:08 +01:00
if (FileIsTooBig)
2019-02-17 01:14:55 +01:00
fprintf (stdout,Txt_UPLOAD_FILE_File_too_large_maximum_X_MiB_NO_HTML,
(unsigned long) (Fil_MAX_FILE_SIZE / (1024ULL * 1024ULL)));
2014-12-01 23:55:08 +01:00
else
2019-02-17 01:14:55 +01:00
fprintf (stdout,Txt_UPLOAD_FILE_Upload_time_too_long_maximum_X_minutes_NO_HTML,
(unsigned long) (Cfg_TIME_TO_ABORT_FILE_UPLOAD / 60UL));
fprintf (stdout,"\n");
2014-12-01 23:55:08 +01:00
/* Don't write HTML at all */
Gbl.Layout.HTMLStartWritten =
2015-11-27 21:24:24 +01:00
Gbl.Layout.DivsEndWritten =
2014-12-01 23:55:08 +01:00
Gbl.Layout.HTMLEndWritten = true;
return false;
}
rewind (Fil_QueryFile);
2014-12-01 23:55:08 +01:00
return true;
}
/*****************************************************************************/
/************ End the reading of all characters coming from stdin ************/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
void Fil_EndOfReadingStdin (void)
{
while (!feof (stdin))
fgetc (stdin);
}
/*****************************************************************************/
/******** Start the reception of data from a file *********/
/******** once the rest of parameters from the form have been readed *********/
/*****************************************************************************/
/*
-----------------------------7d113610948
Content-Disposition: form-data; name="Param1"
2000-2001
-----------------------------7d113610948
Content-Disposition: form-data; name="Param2"
Estructura de los computadores II
-----------------------------7d113610948
Content-Disposition: form-data; name="Param3"
../swad/fichas.htm
-----------------------------7d113610948
Content-Disposition: form-data; name="Param4"
../public_html/docencia/ecii/ecii-log.html
-----------------------------7d113610948
Content-Disposition: form-data; name="Param5"
L384261
-----------------------------7d113610948
Content-Disposition: form-data; name="Param6"
13282
-----------------------------7d113610948
Content-Disposition: form-data; name="Param7"
/~acanas/docencia/fotos
-----------------------------7d113610948
Content-Disposition: form-data; name="Archivo"; filename="D:\Usr\Antonio\Docencia\Estruct\Notas\Notas 2000-2001.ec\fotos\R157550.jpg"
Content-Type: image/pjpeg
000000 FFD8FFE0 00104A46 49460001 01010048 <EFBFBD><EFBFBD><EFBFBD>JFIF<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>H
000010 00480000 FFDB0043 00030202 03020203 <EFBFBD>H<EFBFBD><EFBFBD><EFBFBD>۷C<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
000020 03030304 03030405 08050504 04050A07 <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
etc, etc.
*/
struct Par_Param *Fil_StartReceptionOfFile (const char *ParFile,
char *FileName,char *MIMEType)
2014-12-01 23:55:08 +01:00
{
struct Par_Param *Par;
FILE *QueryFile = Fil_GetQueryFile ();
2014-12-01 23:55:08 +01:00
2016-04-01 12:47:32 +02:00
/***** Set default values *****/
FileName[0] = 0;
2016-04-01 09:46:09 +02:00
/***** Get parameter *****/
Par_GetPar (Par_PARAM_SINGLE,ParFile,NULL,Fil_MAX_FILE_SIZE,&Par);
2016-04-01 09:46:09 +02:00
2016-04-01 01:59:27 +02:00
/***** Get filename *****/
2016-04-01 09:46:09 +02:00
/* Check if filename exists */
if (Par->FileName.Start == 0 ||
Par->FileName.Length == 0)
2016-04-01 12:47:32 +02:00
{
FileName[0] = MIMEType[0] = '\0';
return Par;
2016-04-01 12:47:32 +02:00
}
if (Par->FileName.Length > PATH_MAX)
Err_ShowErrorAndExit ("Error while getting filename.");
2016-04-01 09:46:09 +02:00
/* Copy filename */
fseek (QueryFile,Par->FileName.Start,SEEK_SET);
if (fread (FileName,sizeof (char),Par->FileName.Length,QueryFile) !=
Par->FileName.Length)
Err_ShowErrorAndExit ("Error while getting filename.");
FileName[Par->FileName.Length] = '\0';
2016-04-01 01:59:27 +02:00
/***** Get MIME type *****/
/* Check if MIME type exists */
if (Par->ContentType.Start == 0 ||
Par->ContentType.Length == 0 ||
Par->ContentType.Length > Brw_MAX_BYTES_MIME_TYPE)
Err_ShowErrorAndExit ("Error while getting content type.");
2016-04-01 01:59:27 +02:00
/* Copy MIME type */
fseek (QueryFile,Par->ContentType.Start,SEEK_SET);
if (fread (MIMEType,sizeof (char),Par->ContentType.Length,QueryFile) !=
Par->ContentType.Length)
Err_ShowErrorAndExit ("Error while getting content type.");
MIMEType[Par->ContentType.Length] = '\0';
2016-04-01 01:59:27 +02:00
return Par;
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/****************** End the reception of data of a file **********************/
/*****************************************************************************/
bool Fil_EndReceptionOfFile (char *FileNameDataTmp,struct Par_Param *Param)
2014-12-01 23:55:08 +01:00
{
FILE *FileDataTmp;
unsigned char Bytes[Fil_NUM_BYTES_PER_CHUNK];
2016-04-01 01:59:27 +02:00
size_t RemainingBytesToCopy;
size_t BytesToCopy;
FILE *QueryFile = Fil_GetQueryFile ();
2014-12-01 23:55:08 +01:00
2016-04-01 01:59:27 +02:00
/***** Open destination file *****/
2014-12-01 23:55:08 +01:00
if ((FileDataTmp = fopen (FileNameDataTmp,"wb")) == NULL)
Err_ShowErrorAndExit ("Can not open temporary file.");
2014-12-01 23:55:08 +01:00
2016-04-01 01:59:27 +02:00
/***** Copy file *****/
/* Go to start of source */
if (Param->Value.Start == 0)
Err_ShowErrorAndExit ("Error while copying file.");
fseek (QueryFile,Param->Value.Start,SEEK_SET);
2014-12-01 23:55:08 +01:00
/* Copy part of query file to FileDataTmp */
for (RemainingBytesToCopy = Param->Value.Length;
2016-04-01 01:59:27 +02:00
RemainingBytesToCopy != 0;
RemainingBytesToCopy -= BytesToCopy)
2014-12-01 23:55:08 +01:00
{
BytesToCopy = (RemainingBytesToCopy >= Fil_NUM_BYTES_PER_CHUNK) ? Fil_NUM_BYTES_PER_CHUNK :
RemainingBytesToCopy;
if (fread (Bytes,1,BytesToCopy,QueryFile) != BytesToCopy)
2016-04-01 01:59:27 +02:00
{
fclose (FileDataTmp);
return false;
}
2019-11-06 19:45:20 +01:00
if (fwrite (Bytes,sizeof (Bytes[0]),BytesToCopy,FileDataTmp) != BytesToCopy)
2016-04-01 01:59:27 +02:00
{
fclose (FileDataTmp);
return false;
}
2014-12-01 23:55:08 +01:00
}
2016-04-01 01:59:27 +02:00
/***** Close destination file *****/
fclose (FileDataTmp);
return true;
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/************* Create names and new file to update a existing file ***********/
/*****************************************************************************/
// CurrentName does not change
// OldName is created
// NewName is created
2017-01-16 01:51:01 +01:00
void Fil_CreateUpdateFile (const char CurrentName[PATH_MAX + 1],
const char *ExtensionOldName,
char OldName[PATH_MAX + 1],
char NewName[PATH_MAX + 1],
FILE **NewFile)
2014-12-01 23:55:08 +01:00
{
2016-03-28 19:30:37 +02:00
size_t LengthFileRoot = Str_GetLengthRootFileName (CurrentName);
2019-02-17 01:14:55 +01:00
char ErrorMsg[128 + PATH_MAX];
2014-12-01 23:55:08 +01:00
Str_Copy (NewName,CurrentName,PATH_MAX);
2017-01-17 03:10:43 +01:00
NewName[LengthFileRoot] = '\0';
snprintf (OldName,PATH_MAX + 1,"%s%s",NewName,ExtensionOldName);
Str_Concat (NewName,".new",PATH_MAX);
2014-12-01 23:55:08 +01:00
/* The new file shouldn't exist. If it exists is due to any error when running this CGI formerly
and the file was not renamed successfully. In this case, remove it! */
if (Fil_CheckIfPathExists (NewName))
unlink (NewName);
/* Open the new file */
if ((*NewFile = fopen (NewName,"wb")) == NULL)
{
2019-02-17 01:14:55 +01:00
snprintf (ErrorMsg,sizeof (ErrorMsg),
"Can not create file <strong>%s</strong>.",NewName);
Err_ShowErrorAndExit (ErrorMsg);
2014-12-01 23:55:08 +01:00
}
}
/*****************************************************************************/
/****************** Close and rename files related to an update **************/
/*****************************************************************************/
2019-02-17 01:14:55 +01:00
void Fil_CloseUpdateFile (const char CurrentName[PATH_MAX + 1],
const char OldName[PATH_MAX + 1],
const char NewName[PATH_MAX + 1],
FILE *NewFile)
2014-12-01 23:55:08 +01:00
{
2019-02-17 01:14:55 +01:00
char ErrorMsg[128 + 2 * PATH_MAX];
2014-12-01 23:55:08 +01:00
/* Close file */
fclose (NewFile);
/* Rename the old file and the new file */
if (rename (CurrentName,OldName)) // mv CurrentName OldName Ej: mv file.html file.old
{
2019-02-17 01:14:55 +01:00
snprintf (ErrorMsg,sizeof (ErrorMsg),
2018-10-16 21:56:01 +02:00
"Can not rename the file <strong>%s</strong> as <strong>%s</strong>.",
CurrentName,OldName);
Err_ShowErrorAndExit (ErrorMsg);
2014-12-01 23:55:08 +01:00
}
if (rename (NewName,CurrentName)) // mv NewName CurrentName Ej: mv file.new file.html
{
2019-02-17 01:14:55 +01:00
snprintf (ErrorMsg,sizeof (ErrorMsg),
2018-10-16 21:56:01 +02:00
"Can not rename the file <strong>%s</strong> as <strong>%s</strong>.",
NewName,CurrentName);
Err_ShowErrorAndExit (ErrorMsg);
2014-12-01 23:55:08 +01:00
}
}
/*****************************************************************************/
/***************** Check if existe a file or directory ***********************/
/*****************************************************************************/
/* Return true if exists and false if not exists */
bool Fil_CheckIfPathExists (const char *Path)
{
2019-03-20 13:05:09 +01:00
// Important: access with a link returns
// if exists the file pointed by the link, not the link itself
2014-12-01 23:55:08 +01:00
return access (Path,F_OK) ? false :
true;
}
/*****************************************************************************/
/********** Check if a directory exists. If not exists, create it! ***********/
/*****************************************************************************/
void Fil_CreateDirIfNotExists (const char *Path)
2014-12-01 23:55:08 +01:00
{
2019-02-17 01:14:55 +01:00
char ErrorMsg[128 + PATH_MAX];
2014-12-01 23:55:08 +01:00
if (!Fil_CheckIfPathExists (Path))
if (mkdir (Path,(mode_t) 0xFFF) != 0)
{
2019-02-17 01:14:55 +01:00
snprintf (ErrorMsg,sizeof (ErrorMsg),
"Can not create folder <strong>%s</strong>.",Path);
Err_ShowErrorAndExit (ErrorMsg);
2014-12-01 23:55:08 +01:00
}
}
2016-10-06 22:18:33 +02:00
/*****************************************************************************/
/************************ Remove a directory recursively *********************/
/*****************************************************************************/
// If the tree of directories and files exists, remove it
void Fil_RemoveTree (const char *Path)
2016-10-06 22:18:33 +02:00
{
struct stat FileStatus;
struct dirent **FileList;
int NumFile,NumFiles;
2017-01-28 15:58:46 +01:00
char PathFileRel[PATH_MAX + 1];
2016-10-06 22:18:33 +02:00
bool Error;
2019-02-17 01:14:55 +01:00
char ErrorMsg[128 + PATH_MAX];
2016-10-06 22:18:33 +02:00
if (Fil_CheckIfPathExists (Path))
{
2016-12-29 22:00:35 +01:00
if (lstat (Path,&FileStatus)) // On success ==> 0 is returned
Err_ShowErrorAndExit ("Can not get information about a file or folder.");
2016-12-29 22:00:35 +01:00
else if (S_ISDIR (FileStatus.st_mode)) // It's a directory
2016-10-06 22:18:33 +02:00
{
if (rmdir (Path))
{
Error = false;
if (errno == ENOTEMPTY)
{
/***** Remove each directory and file under this directory *****/
/* Scan the directory */
if ((NumFiles = scandir (Path,&FileList,NULL,NULL)) >= 0)
{
/* Remove recursively all directories and files */
2016-10-06 22:18:33 +02:00
for (NumFile = 0;
NumFile < NumFiles;
NumFile++)
{
if (strcmp (FileList[NumFile]->d_name,".") &&
strcmp (FileList[NumFile]->d_name,"..")) // Skip directories "." and ".."
{
snprintf (PathFileRel,sizeof (PathFileRel),"%s/%s",
2018-10-18 02:02:32 +02:00
Path,FileList[NumFile]->d_name);
2016-10-06 22:18:33 +02:00
Fil_RemoveTree (PathFileRel);
}
2019-11-06 19:45:20 +01:00
free (FileList[NumFile]);
2016-10-06 22:18:33 +02:00
}
2019-11-06 19:45:20 +01:00
free (FileList);
2016-10-06 22:18:33 +02:00
}
else
Err_ShowErrorAndExit ("Error while scanning directory.");
2016-10-06 22:18:33 +02:00
/***** Remove of new the directory, now empty *****/
if (rmdir (Path))
Error = true;
}
else
Error = true;
if (Error)
{
2019-02-17 01:14:55 +01:00
snprintf (ErrorMsg,sizeof (ErrorMsg),
"Can not remove folder %s.",Path);
Err_ShowErrorAndExit (ErrorMsg);
2016-10-06 22:18:33 +02:00
}
}
}
else // It's a file
if (unlink (Path))
Err_ShowErrorAndExit ("Can not remove file.");
2016-10-06 22:18:33 +02:00
}
}
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/********************* Remove old temporary directories **********************/
/*****************************************************************************/
2019-03-20 13:05:09 +01:00
void Fil_RemoveOldTmpFiles (const char *Path,time_t TimeToRemove,
bool RemoveDirectory)
2014-12-01 23:55:08 +01:00
{
struct dirent **FileList;
2015-12-21 13:36:39 +01:00
int NumFile;
int NumFiles;
2017-01-28 15:58:46 +01:00
char Path2[PATH_MAX + 1];
2014-12-01 23:55:08 +01:00
struct stat FileStatus;
2019-02-21 17:34:53 +01:00
/***** Check this path (file or directory)
because it could have already been deleted *****/
2019-03-20 13:05:09 +01:00
// Important: don't use access here to check if path exists
// because access with a link returns if exists
// the file pointed by the link, not the link itself
if (!lstat (Path,&FileStatus)) // On success ==> 0 is returned
{
if (S_ISDIR (FileStatus.st_mode)) // It's a directory
{
/***** Scan the directory and delete recursively *****/
if ((NumFiles = scandir (Path,&FileList,NULL,NULL)) >= 0) // No error
2014-12-01 23:55:08 +01:00
{
2019-03-20 13:05:09 +01:00
/* Loop over files */
for (NumFile = 0;
NumFile < NumFiles;
NumFile++)
2015-12-21 13:36:39 +01:00
{
2019-03-20 13:05:09 +01:00
if (strcmp (FileList[NumFile]->d_name,".") &&
strcmp (FileList[NumFile]->d_name,"..")) // Skip directories "." and ".."
2019-02-21 17:34:53 +01:00
{
snprintf (Path2,sizeof (Path2),"%s/%s",
2019-03-20 13:05:09 +01:00
Path,FileList[NumFile]->d_name);
Fil_RemoveOldTmpFiles (Path2,TimeToRemove,true); // Recursive call
2019-02-21 17:34:53 +01:00
}
2019-11-06 19:45:20 +01:00
free (FileList[NumFile]);
2015-12-21 13:36:39 +01:00
}
2019-11-06 19:45:20 +01:00
free (FileList);
2019-03-20 13:05:09 +01:00
if (RemoveDirectory)
/* Remove the directory itself */
if (FileStatus.st_mtime < Dat_GetStartExecutionTimeUTC () - TimeToRemove)
2019-03-20 13:05:09 +01:00
rmdir (Path);
2019-02-21 17:48:44 +01:00
}
2019-03-20 13:05:09 +01:00
else
Err_ShowErrorAndExit ("Error while scanning directory.");
2019-03-20 13:05:09 +01:00
}
else // Not a directory
if (FileStatus.st_mtime < Dat_GetStartExecutionTimeUTC () - TimeToRemove)
2019-03-20 13:05:09 +01:00
unlink (Path);
}
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/**************************** Fast copy of files *****************************/
/*****************************************************************************/
void Fil_FastCopyOfFiles (const char *PathSrc,const char *PathTgt)
{
2016-03-30 01:28:58 +02:00
FILE *FileSrc;
FILE *FileTgt;
2014-12-01 23:55:08 +01:00
/***** Open source file *****/
if ((FileSrc = fopen (PathSrc,"rb")) == NULL)
Err_ShowErrorAndExit ("Can not open source file.");
2014-12-01 23:55:08 +01:00
/***** Open destination file *****/
if ((FileTgt = fopen (PathTgt,"wb")) == NULL)
Err_ShowErrorAndExit ("Can not open target file.");
2014-12-01 23:55:08 +01:00
/***** Copy source file into destination file *****/
Fil_FastCopyOfOpenFiles (FileSrc,FileTgt);
/***** Close the files *****/
fclose (FileTgt);
fclose (FileSrc);
}
/*****************************************************************************/
/************************* Fast copy of open files ***************************/
/*****************************************************************************/
void Fil_FastCopyOfOpenFiles (FILE *FileSrc,FILE *FileTgt)
{
unsigned char Bytes[Fil_NUM_BYTES_PER_CHUNK];
2014-12-01 23:55:08 +01:00
size_t NumBytesRead;
while ((NumBytesRead = fread (Bytes,sizeof (Bytes[0]),
(size_t) Fil_NUM_BYTES_PER_CHUNK,FileSrc)))
2019-11-06 19:45:20 +01:00
fwrite (Bytes,sizeof (Bytes[0]),NumBytesRead,FileTgt);
2014-12-01 23:55:08 +01:00
}
2016-06-30 18:14:09 +02:00
/*****************************************************************************/
/********** Write a quantity of bytes as bytes, KiB, MiB, GiB or TiB *********/
/*****************************************************************************/
#define Ki 1024.0
#define Mi 1048576.0
#define Gi 1073741824.0
#define Ti 1099511627776.0
void Fil_WriteFileSizeBrief (double SizeInBytes,
2017-01-15 22:58:26 +01:00
char FileSizeStr[Fil_MAX_BYTES_FILE_SIZE_STRING + 1])
2016-06-30 18:14:09 +02:00
{
if (SizeInBytes < Ki)
snprintf (FileSizeStr,Fil_MAX_BYTES_FILE_SIZE_STRING + 1,"%.0f&nbsp;B",
2018-10-18 02:02:32 +02:00
SizeInBytes);
2016-06-30 18:14:09 +02:00
else if (SizeInBytes < Mi)
snprintf (FileSizeStr,Fil_MAX_BYTES_FILE_SIZE_STRING + 1,"%.0f&nbsp;KiB",
2018-10-18 02:02:32 +02:00
SizeInBytes / Ki);
2016-06-30 18:14:09 +02:00
else if (SizeInBytes < Gi)
snprintf (FileSizeStr,Fil_MAX_BYTES_FILE_SIZE_STRING + 1,"%.0f&nbsp;MiB",
2018-10-18 02:02:32 +02:00
SizeInBytes / Mi);
2016-06-30 18:14:09 +02:00
else if (SizeInBytes < Ti)
snprintf (FileSizeStr,Fil_MAX_BYTES_FILE_SIZE_STRING + 1,"%.0f&nbsp;GiB",
2018-10-18 02:02:32 +02:00
SizeInBytes / Gi);
2016-06-30 18:14:09 +02:00
else
snprintf (FileSizeStr,Fil_MAX_BYTES_FILE_SIZE_STRING + 1,"%.0f&nbsp;TiB",
2018-10-18 02:02:32 +02:00
SizeInBytes / Ti);
2016-06-30 18:14:09 +02:00
}
void Fil_WriteFileSizeFull (double SizeInBytes,
2017-01-15 22:58:26 +01:00
char FileSizeStr[Fil_MAX_BYTES_FILE_SIZE_STRING + 1])
2016-06-30 18:14:09 +02:00
{
if (SizeInBytes < Ki)
snprintf (FileSizeStr,Fil_MAX_BYTES_FILE_SIZE_STRING + 1,"%.0f&nbsp;B",
2018-10-18 02:02:32 +02:00
SizeInBytes);
2016-06-30 18:14:09 +02:00
else if (SizeInBytes < Mi)
snprintf (FileSizeStr,Fil_MAX_BYTES_FILE_SIZE_STRING + 1,"%.1f&nbsp;KiB",
2018-10-18 02:02:32 +02:00
SizeInBytes / Ki);
2016-06-30 18:14:09 +02:00
else if (SizeInBytes < Gi)
snprintf (FileSizeStr,Fil_MAX_BYTES_FILE_SIZE_STRING + 1,"%.1f&nbsp;MiB",
2018-10-18 02:02:32 +02:00
SizeInBytes / Mi);
2016-06-30 18:14:09 +02:00
else if (SizeInBytes < Ti)
snprintf (FileSizeStr,Fil_MAX_BYTES_FILE_SIZE_STRING + 1,"%.1f&nbsp;GiB",
2018-10-18 02:02:32 +02:00
SizeInBytes / Gi);
2016-06-30 18:14:09 +02:00
else
snprintf (FileSizeStr,Fil_MAX_BYTES_FILE_SIZE_STRING + 1,"%.1f&nbsp;TiB",
2018-10-18 02:02:32 +02:00
SizeInBytes / Ti);
2016-06-30 18:14:09 +02:00
}
/*****************************************************************************/
/********* Add public directory used to link private path to cache ***********/
/*****************************************************************************/
void Fil_AddPublicDirToCache (const char *FullPathPriv,
const char TmpPubDir[PATH_MAX + 1])
{
if (Gbl.Session.IsOpen)
{
/* Delete possible old entry */
Fil_DB_RemovePublicDirFromCache (FullPathPriv);
/* Insert new entry */
Fil_DB_AddPublicDirToCache (FullPathPriv,TmpPubDir);
}
}
/*****************************************************************************/
/******** Get public directory used to link private path from cache **********/
/*****************************************************************************/
bool Fil_GetPublicDirFromCache (const char *FullPathPriv,
char TmpPubDir[PATH_MAX + 1])
{
bool Cached;
bool TmpPubDirExists;
/***** Reset temporary directory *****/
TmpPubDir[0] = '\0';
if (Gbl.Session.IsOpen)
{
/***** Get temporary directory from cache *****/
Fil_DB_GetPublicDirFromCache (FullPathPriv,TmpPubDir);
Cached = (TmpPubDir[0] != '\0');
/***** Check if temporary public directory exists *****/
if (Cached)
{
/* If not exists (it could be deleted if its lifetime has expired)
==> remove from cache */
TmpPubDirExists = Fil_CheckIfPathExists (TmpPubDir);
if (!TmpPubDirExists)
Fil_DB_RemovePublicDirFromCache (FullPathPriv);
return TmpPubDirExists;
}
}
return false;
}