swad-core/swad_file.c

660 lines
23 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.
2018-04-24 13:21:53 +02:00
Copyright (C) 1999-2018 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
#include <linux/stddef.h> // For NULL
#include <stdio.h> // For FILE,fprintf
#include <stdlib.h> // For exit, system, malloc, calloc, free, etc.
#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"
#include "swad_global.h"
#include "swad_file.h"
#include "swad_string.h"
/*****************************************************************************/
/************** External global variables from others modules ****************/
/*****************************************************************************/
extern struct Globals Gbl;
/*****************************************************************************/
/***************************** Private constants *****************************/
/*****************************************************************************/
2016-04-01 01:59:27 +02:00
#define NUM_BYTES_PER_CHUNK 4096
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/******************************* Private types *******************************/
/*****************************************************************************/
/*****************************************************************************/
/***************************** Private variables *****************************/
/*****************************************************************************/
/*****************************************************************************/
/***************************** Private prototypes ****************************/
/*****************************************************************************/
/*****************************************************************************/
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
{
2017-01-28 15:58:46 +01:00
char PathHTMLOutputPriv[PATH_MAX + 1];
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 *****/
sprintf (PathHTMLOutputPriv,"%s/%s",Cfg_PATH_SWAD_PRIVATE,Cfg_FOLDER_OUT);
Fil_CreateDirIfNotExists (PathHTMLOutputPriv);
2014-12-01 23:55:08 +01:00
/***** Remove old files *****/
2014-12-21 14:47:04 +01:00
Fil_RemoveOldTmpFiles (PathHTMLOutputPriv,Cfg_TIME_TO_DELETE_HTML_OUTPUT,false);
2014-12-01 23:55:08 +01:00
/***** Create a unique name for the file *****/
2014-12-21 14:47:04 +01:00
sprintf (Gbl.HTMLOutput.FileName,"%s/%s.html",
PathHTMLOutputPriv,Gbl.UniqueNameEncrypted);
2014-12-01 23:55:08 +01:00
/***** Open file for writing and reading *****/
2014-12-21 14:47:04 +01:00
if ((Gbl.F.Out = fopen (Gbl.HTMLOutput.FileName,"w+t")) == NULL)
2014-12-01 23:55:08 +01:00
{
Gbl.F.Out = stdout;
Lay_ShowErrorAndExit ("Can not create output file.");
}
}
/*****************************************************************************/
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 (Gbl.F.Out)
{
fclose (Gbl.F.Out);
2014-12-21 14:47:04 +01:00
unlink (Gbl.HTMLOutput.FileName);
2014-12-01 23:55:08 +01:00
}
Gbl.F.Out = stdout;
}
/*****************************************************************************/
/********** Open temporary file and write on it reading from stdin ***********/
/*****************************************************************************/
2017-05-10 10:25:01 +02:00
// On error, Gbl.Alert.Txt will contain feedback
2014-12-01 23:55:08 +01:00
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 ((Gbl.F.Tmp = tmpfile ()) == NULL)
{
Fil_EndOfReadingStdin ();
Lay_ShowErrorAndExit ("Can not create temporary file.");
}
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
2015-10-27 19:00:21 +01:00
if (time (NULL) - Gbl.StartExecutionTimeUTC >= Cfg_TIME_TO_ABORT_FILE_UPLOAD)
2014-12-01 23:55:08 +01:00
TimeExceeded = true;
fputc (fgetc (stdin),Gbl.F.Tmp);
}
else
FileIsTooBig = true;
if (FileIsTooBig || TimeExceeded)
{
Fil_EndOfReadingStdin (); // If stdin were not fully read, there will be problems with buffers
if (FileIsTooBig)
2018-10-16 23:08:04 +02:00
snprintf (Gbl.Alert.Txt,sizeof (Gbl.Alert.Txt),
2018-10-16 21:56:01 +02:00
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
2018-10-16 23:08:04 +02:00
snprintf (Gbl.Alert.Txt,sizeof (Gbl.Alert.Txt),
2018-10-16 21:56:01 +02:00
Txt_UPLOAD_FILE_Upload_time_too_long_maximum_X_minutes_NO_HTML,
(unsigned long) (Cfg_TIME_TO_ABORT_FILE_UPLOAD / 60UL));
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;
/* Start HTTP response */
2014-12-21 14:47:04 +01:00
fprintf (stdout,"Content-type: text/plain; charset=windows-1252\n");
2014-12-01 23:55:08 +01:00
/* Status code and message */
fprintf (stdout,"Status: 501 Not Implemented\r\n\r\n"
"%s\n",
2017-05-10 10:25:01 +02:00
Gbl.Alert.Txt);
2014-12-01 23:55:08 +01:00
return false;
}
rewind (Gbl.F.Tmp);
return true;
}
/*****************************************************************************/
/********** End the reading of all the characters coming from stdin **********/
/*****************************************************************************/
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.
*/
2016-04-04 12:13:37 +02:00
struct Param *Fil_StartReceptionOfFile (const char *ParamFile,
char *FileName,char *MIMEType)
2014-12-01 23:55:08 +01:00
{
2016-03-31 22:30:07 +02:00
struct Param *Param;
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 *****/
2016-04-04 12:13:37 +02:00
Par_GetParameter (Par_PARAM_SINGLE,ParamFile,NULL,Fil_MAX_FILE_SIZE,&Param);
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 (Param->FileName.Start == 0 ||
2016-04-01 12:47:32 +02:00
Param->FileName.Length == 0)
{
FileName[0] = MIMEType[0] = '\0';
return Param;
}
if (Param->FileName.Length > PATH_MAX)
2016-04-01 09:46:09 +02:00
Lay_ShowErrorAndExit ("Error while getting filename.");
/* Copy filename */
fseek (Gbl.F.Tmp,Param->FileName.Start,SEEK_SET);
if (fread (FileName,sizeof (char),Param->FileName.Length,Gbl.F.Tmp) !=
Param->FileName.Length)
Lay_ShowErrorAndExit ("Error while getting filename.");
2016-04-13 10:17:20 +02:00
FileName[Param->FileName.Length] = '\0';
2016-04-01 01:59:27 +02:00
/***** Get MIME type *****/
/* Check if MIME type exists */
if (Param->ContentType.Start == 0 ||
Param->ContentType.Length == 0 ||
Param->ContentType.Length > Brw_MAX_BYTES_MIME_TYPE)
Lay_ShowErrorAndExit ("Error while getting content type.");
/* Copy MIME type */
fseek (Gbl.F.Tmp,Param->ContentType.Start,SEEK_SET);
if (fread (MIMEType,sizeof (char),Param->ContentType.Length,Gbl.F.Tmp) !=
Param->ContentType.Length)
Lay_ShowErrorAndExit ("Error while getting content type.");
2016-04-07 01:16:34 +02:00
MIMEType[Param->ContentType.Length] = '\0';
2016-04-01 01:59:27 +02:00
return Param;
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/****************** End the reception of data of a file **********************/
/*****************************************************************************/
2016-04-01 01:59:27 +02:00
bool Fil_EndReceptionOfFile (char *FileNameDataTmp,struct Param *Param)
2014-12-01 23:55:08 +01:00
{
extern const char *Txt_UPLOAD_FILE_File_too_large_maximum_X_MiB_NO_HTML;
FILE *FileDataTmp;
2016-04-01 01:59:27 +02:00
unsigned char Bytes[NUM_BYTES_PER_CHUNK];
size_t RemainingBytesToCopy;
size_t BytesToCopy;
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)
Lay_ShowErrorAndExit ("Can not open temporary file.");
2016-04-01 01:59:27 +02:00
/***** Copy file *****/
/* Go to start of source */
if (Param->Value.Start == 0)
Lay_ShowErrorAndExit ("Error while copying file.");
fseek (Gbl.F.Tmp,Param->Value.Start,SEEK_SET);
2014-12-01 23:55:08 +01:00
2016-04-01 01:59:27 +02:00
/* Copy part of Gbl.F.Tmp to FileDataTmp */
for (RemainingBytesToCopy = Param->Value.Length;
RemainingBytesToCopy != 0;
RemainingBytesToCopy -= BytesToCopy)
2014-12-01 23:55:08 +01:00
{
2016-04-01 01:59:27 +02:00
BytesToCopy = (RemainingBytesToCopy >= NUM_BYTES_PER_CHUNK) ? NUM_BYTES_PER_CHUNK :
RemainingBytesToCopy;
if (fread ((void *) Bytes,1,BytesToCopy,Gbl.F.Tmp) != BytesToCopy)
{
fclose (FileDataTmp);
return false;
}
if (fwrite ((void *) Bytes,sizeof (Bytes[0]),BytesToCopy,FileDataTmp) != BytesToCopy)
{
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);
2014-12-01 23:55:08 +01:00
2017-01-17 03:10:43 +01:00
Str_Copy (NewName,CurrentName,
PATH_MAX);
NewName[LengthFileRoot] = '\0';
2014-12-01 23:55:08 +01:00
sprintf (OldName,"%s%s",NewName,ExtensionOldName);
2017-01-17 03:33:05 +01:00
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)
{
2018-10-16 23:08:04 +02:00
snprintf (Gbl.Alert.Txt,sizeof (Gbl.Alert.Txt),
2018-10-16 21:56:01 +02:00
"Can not create file <strong>%s</strong>.",
NewName);
2017-05-10 10:25:01 +02:00
Lay_ShowErrorAndExit (Gbl.Alert.Txt);
2014-12-01 23:55:08 +01:00
}
}
/*****************************************************************************/
/****************** Close and rename files related to an update **************/
/*****************************************************************************/
void Fil_CloseUpdateFile (const char *CurrentName,const char *OldName,const char *NewName,FILE *NewFile)
{
/* 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
{
2018-10-16 23:08:04 +02:00
snprintf (Gbl.Alert.Txt,sizeof (Gbl.Alert.Txt),
2018-10-16 21:56:01 +02:00
"Can not rename the file <strong>%s</strong> as <strong>%s</strong>.",
CurrentName,OldName);
2017-05-10 10:25:01 +02:00
Lay_ShowErrorAndExit (Gbl.Alert.Txt);
2014-12-01 23:55:08 +01:00
}
if (rename (NewName,CurrentName)) // mv NewName CurrentName Ej: mv file.new file.html
{
2018-10-16 23:08:04 +02:00
snprintf (Gbl.Alert.Txt,sizeof (Gbl.Alert.Txt),
2018-10-16 21:56:01 +02:00
"Can not rename the file <strong>%s</strong> as <strong>%s</strong>.",
NewName,CurrentName);
2017-05-10 10:25:01 +02:00
Lay_ShowErrorAndExit (Gbl.Alert.Txt);
2014-12-01 23:55:08 +01:00
}
}
/*****************************************************************************/
/*********************** Rename a file or directory **************************/
/*****************************************************************************/
bool Fil_RenameFileOrDir (const char *PathOld,const char *PathNew)
{
extern const char *Txt_There_is_already_a_non_empty_folder_named_X;
extern const char *Txt_There_is_already_a_file_named_X;
/* Rename the file or directory */
2016-04-03 01:24:20 +02:00
if (rename (PathOld,PathNew)) // Fail
2014-12-01 23:55:08 +01:00
{
switch (errno)
{
case ENOTEMPTY:
case EEXIST:
2018-10-16 23:08:04 +02:00
snprintf (Gbl.Alert.Txt,sizeof (Gbl.Alert.Txt),
2018-10-16 21:56:01 +02:00
Txt_There_is_already_a_non_empty_folder_named_X,
PathNew);
2014-12-01 23:55:08 +01:00
break;
case ENOTDIR:
2018-10-16 23:08:04 +02:00
snprintf (Gbl.Alert.Txt,sizeof (Gbl.Alert.Txt),
2018-10-16 21:56:01 +02:00
Txt_There_is_already_a_file_named_X,
PathNew);
2014-12-01 23:55:08 +01:00
break;
case EACCES:
Lay_ShowErrorAndExit ("Write is forbidden.");
break;
default:
Lay_ShowErrorAndExit ("Can not rename file or folder.");
break;
}
return false;
}
2016-04-03 01:24:20 +02:00
else // Success
return true;
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)
{
return access (Path,F_OK) ? false :
true;
}
/*****************************************************************************/
/********** Check if a directory exists. If not exists, create it! ***********/
/*****************************************************************************/
void Fil_CreateDirIfNotExists (const char *Path)
{
if (!Fil_CheckIfPathExists (Path))
if (mkdir (Path,(mode_t) 0xFFF) != 0)
{
2018-10-16 23:08:04 +02:00
snprintf (Gbl.Alert.Txt,sizeof (Gbl.Alert.Txt),
2018-10-16 21:56:01 +02:00
"Can not create folder <strong>%s</strong>.",
Path);
2017-05-10 10:25:01 +02:00
Lay_ShowErrorAndExit (Gbl.Alert.Txt);
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)
{
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;
if (Fil_CheckIfPathExists (Path))
{
2016-12-29 22:00:35 +01:00
if (lstat (Path,&FileStatus)) // On success ==> 0 is returned
Lay_ShowErrorAndExit ("Can not get information about a file or folder.");
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 the directories and files */
for (NumFile = 0;
NumFile < NumFiles;
NumFile++)
{
if (strcmp (FileList[NumFile]->d_name,".") &&
strcmp (FileList[NumFile]->d_name,"..")) // Skip directories "." and ".."
{
sprintf (PathFileRel,"%s/%s",Path,FileList[NumFile]->d_name);
Fil_RemoveTree (PathFileRel);
}
free ((void *) FileList[NumFile]);
}
free ((void *) FileList);
}
else
Lay_ShowErrorAndExit ("Error while scanning directory.");
/***** Remove of new the directory, now empty *****/
if (rmdir (Path))
Error = true;
}
else
Error = true;
if (Error)
{
2018-10-16 23:08:04 +02:00
snprintf (Gbl.Alert.Txt,sizeof (Gbl.Alert.Txt),
2018-10-16 21:56:01 +02:00
"Can not remove folder %s.",
Path);
2017-05-10 10:25:01 +02:00
Lay_ShowErrorAndExit (Gbl.Alert.Txt);
2016-10-06 22:18:33 +02:00
}
}
}
else // It's a file
if (unlink (Path))
Lay_ShowErrorAndExit ("Can not remove file.");
}
}
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/********************* Remove old temporary directories **********************/
/*****************************************************************************/
void Fil_RemoveOldTmpFiles (const char *Path,time_t TimeToRemove,bool RemoveDirectory)
{
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;
2016-12-29 22:00:35 +01:00
if (lstat (Path,&FileStatus)) // On success ==> 0 is returned
Lay_ShowErrorAndExit ("Can not get information about a file or folder.");
else if (S_ISDIR (FileStatus.st_mode)) // It's a directory
2014-12-01 23:55:08 +01:00
{
/***** Scan the directory *****/
2015-12-21 13:36:39 +01:00
if ((NumFiles = scandir (Path,&FileList,NULL,NULL)) >= 0) // No error
{
/* Loop over files */
for (NumFile = 0;
NumFile < NumFiles;
NumFile++)
2014-12-01 23:55:08 +01:00
{
2015-12-21 13:36:39 +01:00
if (strcmp (FileList[NumFile]->d_name,".") &&
strcmp (FileList[NumFile]->d_name,"..")) // Skip directories "." and ".."
{
sprintf (Path2,"%s/%s",Path,FileList[NumFile]->d_name);
Fil_RemoveOldTmpFiles (Path2,TimeToRemove,true); // Recursive call
}
free ((void *) FileList[NumFile]);
2014-12-01 23:55:08 +01:00
}
2015-12-21 13:36:39 +01:00
free ((void *) FileList);
if (RemoveDirectory)
/* Remove the directory itself */
if (FileStatus.st_mtime < Gbl.StartExecutionTimeUTC - TimeToRemove)
rmdir (Path);
}
else
Lay_ShowErrorAndExit ("Error while scanning directory.");
2014-12-01 23:55:08 +01:00
}
else
2015-12-21 13:36:39 +01:00
if (FileStatus.st_mtime < Gbl.StartExecutionTimeUTC - TimeToRemove)
2014-12-01 23:55:08 +01:00
unlink (Path);
}
/*****************************************************************************/
/**************************** 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)
Lay_ShowErrorAndExit ("Can not open source file.");
/***** Open destination file *****/
if ((FileTgt = fopen (PathTgt,"wb")) == NULL)
Lay_ShowErrorAndExit ("Can not open target file.");
/***** 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)
{
2016-04-01 01:59:27 +02:00
unsigned char Bytes[NUM_BYTES_PER_CHUNK];
2014-12-01 23:55:08 +01:00
size_t NumBytesRead;
2016-04-01 01:59:27 +02:00
while ((NumBytesRead = fread ((void *) Bytes,sizeof (Bytes[0]),(size_t) NUM_BYTES_PER_CHUNK,FileSrc)))
2014-12-01 23:55:08 +01:00
fwrite ((void *) Bytes,sizeof (Bytes[0]),NumBytesRead,FileTgt);
}
/*****************************************************************************/
/**************************** Close XML file *********************************/
/*****************************************************************************/
void Fil_CloseXMLFile (void)
{
if (Gbl.F.XML)
{
fclose (Gbl.F.XML);
Gbl.F.XML = NULL; // To indicate that it is not open
}
}
2016-06-30 18:14:09 +02:00
2016-10-03 14:12:01 +02:00
/*****************************************************************************/
/***************************** Close report file *****************************/
/*****************************************************************************/
void Fil_CloseReportFile (void)
{
if (Gbl.F.Rep)
{
fclose (Gbl.F.Rep);
Gbl.F.Rep = NULL; // To indicate that it is not open
}
}
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)
sprintf (FileSizeStr,"%.0f&nbsp;B" ,SizeInBytes);
else if (SizeInBytes < Mi)
sprintf (FileSizeStr,"%.0f&nbsp;KiB",SizeInBytes / Ki);
else if (SizeInBytes < Gi)
sprintf (FileSizeStr,"%.0f&nbsp;MiB",SizeInBytes / Mi);
else if (SizeInBytes < Ti)
sprintf (FileSizeStr,"%.0f&nbsp;GiB",SizeInBytes / Gi);
else
sprintf (FileSizeStr,"%.0f&nbsp;TiB",SizeInBytes / Ti);
}
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)
sprintf (FileSizeStr,"%.0f&nbsp;B" ,SizeInBytes);
else if (SizeInBytes < Mi)
sprintf (FileSizeStr,"%.1f&nbsp;KiB",SizeInBytes / Ki);
else if (SizeInBytes < Gi)
sprintf (FileSizeStr,"%.1f&nbsp;MiB",SizeInBytes / Mi);
else if (SizeInBytes < Ti)
sprintf (FileSizeStr,"%.1f&nbsp;GiB",SizeInBytes / Gi);
else
sprintf (FileSizeStr,"%.1f&nbsp;TiB",SizeInBytes / Ti);
}