swad-core/swad_zip.c

620 lines
23 KiB
C
Raw Normal View History

2014-12-01 23:55:08 +01:00
// swad_zip.c: compress files in file browsers
/*
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.
2019-01-07 21:52:19 +01:00
Copyright (C) 1999-2019 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 3 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 <dirent.h> // For scandir, etc.
2015-04-14 19:38:00 +02:00
#include <errno.h> // For errno
2014-12-01 23:55:08 +01:00
#include <linux/limits.h> // For PATH_MAX
#include <stdlib.h> // For system...
2017-01-15 22:58:26 +01:00
#include <string.h> // For string functions...
2014-12-01 23:55:08 +01:00
#include <sys/stat.h> // For mkdir...
#include <sys/types.h> // For mkdir...
#include <unistd.h> // For chdir...
2017-06-10 21:38:10 +02:00
#include "swad_box.h"
2014-12-01 23:55:08 +01:00
#include "swad_config.h"
2019-10-23 19:05:05 +02:00
#include "swad_file_browser.h"
2018-11-09 20:47:39 +01:00
#include "swad_form.h"
2014-12-01 23:55:08 +01:00
#include "swad_global.h"
2019-10-23 19:05:05 +02:00
#include "swad_HTML.h"
2014-12-01 23:55:08 +01:00
#include "swad_ID.h"
#include "swad_parameter.h"
#include "swad_string.h"
#include "swad_theme.h"
/*****************************************************************************/
/****************************** Public constants *****************************/
/*****************************************************************************/
/*****************************************************************************/
/***************************** Internal constants ****************************/
/*****************************************************************************/
2017-01-28 15:58:46 +01:00
#define ZIP_MiB (1024ULL * 1024ULL)
#define ZIP_MAX_SIZE_UNCOMPRESSED (1024ULL * ZIP_MiB)
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/****************************** Internal types *******************************/
/*****************************************************************************/
/*****************************************************************************/
/************** External global variables from others modules ****************/
/*****************************************************************************/
extern struct Globals Gbl;
/*****************************************************************************/
/************************* Internal global variables *************************/
/*****************************************************************************/
/*****************************************************************************/
/***************************** Internal prototypes ***************************/
/*****************************************************************************/
2016-11-22 13:26:34 +01:00
static void ZIP_PutLinkToCreateZIPAsgWrkParams (void);
2015-04-02 18:39:49 +02:00
2016-11-22 13:15:12 +01:00
static void ZIP_CreateTmpDirForCompression (void);
static void ZIP_CreateDirCompressionUsr (struct UsrData *UsrDat);
2014-12-01 23:55:08 +01:00
static void ZIP_CompressFolderIntoZIP (void);
static unsigned long long ZIP_CloneDir (const char *Path,const char *PathClone,const char *PathInTree);
static void ZIP_ShowLinkToDownloadZIP (const char *FileName,const char *URL,
off_t FileSize,unsigned long long UncompressedSize);
/*****************************************************************************/
2016-11-22 13:26:34 +01:00
/*********** Put link to create ZIP file of assignments and works ************/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2016-11-22 13:26:34 +01:00
void ZIP_PutLinkToCreateZIPAsgWrk (void)
2014-12-01 23:55:08 +01:00
{
extern const char *Txt_Create_ZIP_file;
2019-01-12 03:00:59 +01:00
Lay_PutContextualLinkIconText (ActAdmAsgWrkCrs,NULL,
ZIP_PutLinkToCreateZIPAsgWrkParams,
"download.svg",
Txt_Create_ZIP_file);
2015-04-02 18:39:49 +02:00
}
2016-11-22 13:26:34 +01:00
static void ZIP_PutLinkToCreateZIPAsgWrkParams (void)
2015-04-02 18:39:49 +02:00
{
2019-11-15 03:34:48 +01:00
Usr_PutHiddenParSelectedUsrsCods (&Gbl.Usrs.Selected);
2019-04-25 02:58:42 +02:00
Brw_PutHiddenParamFullTreeIfSelected ();
2014-12-01 23:55:08 +01:00
Par_PutHiddenParamChar ("CreateZIP",'Y');
}
/*****************************************************************************/
/****************** Get whether to create ZIP file from form *****************/
/*****************************************************************************/
bool ZIP_GetCreateZIPFromForm (void)
{
2017-01-28 20:32:50 +01:00
return Par_GetParToBool ("CreateZIP");
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/*************** Create the zip file with assignments and works **************/
/*************** and put a link to download it **************/
/*****************************************************************************/
void ZIP_CreateZIPAsgWrk (void)
{
extern const char *Txt_works_ZIP_FILE_NAME;
2016-11-22 13:15:12 +01:00
struct UsrData UsrDat;
const char *Ptr;
2018-10-04 21:57:25 +02:00
char StrZip[128 + PATH_MAX];
char Path[PATH_MAX + 1 +
NAME_MAX + 1 +
NAME_MAX + 1];
2014-12-01 23:55:08 +01:00
int Result;
2017-01-28 15:58:46 +01:00
char FileNameZIP[NAME_MAX + 1];
char PathFileZIP[PATH_MAX + 1];
2014-12-01 23:55:08 +01:00
struct stat FileStatus;
2017-01-28 15:58:46 +01:00
char URLWithSpaces[PATH_MAX + 1];
char URL[PATH_MAX + 1];
2014-12-01 23:55:08 +01:00
2016-11-22 13:15:12 +01:00
/***** Create zip file
with the assignments and works
of the selected users *****/
/* Create temporary directory
for the compression of assignments and works */
ZIP_CreateTmpDirForCompression ();
/* Initialize structure with user's data */
Usr_UsrDataConstructor (&UsrDat);
/* Create temporary directory for each selected user
inside the directory used for compression */
2019-03-11 13:33:34 +01:00
Ptr = Gbl.Usrs.Selected.List[Rol_UNK];
2016-11-22 13:15:12 +01:00
while (*Ptr)
{
Par_GetNextStrUntilSeparParamMult (&Ptr,UsrDat.EncryptedUsrCod,
2017-03-07 01:56:41 +01:00
Cry_BYTES_ENCRYPTED_STR_SHA256_BASE64);
2016-11-22 13:15:12 +01:00
Usr_GetUsrCodFromEncryptedUsrCod (&UsrDat);
2019-03-19 13:22:14 +01:00
if (Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&UsrDat,Usr_DONT_GET_PREFS)) // Get user's data from database
2017-06-09 15:04:02 +02:00
if (Usr_CheckIfUsrBelongsToCurrentCrs (&UsrDat))
2016-11-22 13:15:12 +01:00
ZIP_CreateDirCompressionUsr (&UsrDat);
}
/* Free memory used for user's data */
Usr_UsrDataDestructor (&UsrDat);
2014-12-01 23:55:08 +01:00
/***** Create a temporary public directory
used to download the zip file *****/
Brw_CreateDirDownloadTmp ();
/***** Relative path of the directory with the works to compress *****/
2018-10-16 23:08:04 +02:00
snprintf (Path,sizeof (Path),
2019-03-20 01:36:36 +01:00
"%s/%s",
Cfg_PATH_ZIP_PRIVATE,
2018-10-16 23:08:04 +02:00
Gbl.FileBrowser.ZIP.TmpDir);
2014-12-01 23:55:08 +01:00
/***** Change to directory of the assignments and works
in order to start the path in the zip file from there *****/
if (chdir (Path))
Lay_ShowErrorAndExit ("Can not change to temporary folder for compression.");
/***** Create public zip file with the assignment and works *****/
2018-10-16 23:08:04 +02:00
snprintf (FileNameZIP,sizeof (FileNameZIP),
"%s.zip",
Txt_works_ZIP_FILE_NAME);
snprintf (PathFileZIP,sizeof (PathFileZIP),
2019-03-20 14:36:26 +01:00
"%s/%s/%s/%s",
2019-03-20 01:36:36 +01:00
Cfg_PATH_FILE_BROWSER_TMP_PUBLIC,
2019-03-20 14:36:26 +01:00
Gbl.FileBrowser.TmpPubDir.L,
Gbl.FileBrowser.TmpPubDir.R,
2018-10-16 23:08:04 +02:00
FileNameZIP);
snprintf (StrZip,sizeof (StrZip),
"nice -n 19 zip -q -r '%s' *",
PathFileZIP);
2014-12-01 23:55:08 +01:00
Result = system (StrZip);
/***** Return to the CGI directory *****/
if (chdir (Cfg_PATH_CGI_BIN))
Lay_ShowErrorAndExit ("Can not change to cgi-bin folder.");
/***** If the zip command has been sucessful, write the link to zip file *****/
if (Result == 0)
{
/***** Get file size *****/
2016-12-29 22:00:35 +01:00
if (lstat (PathFileZIP,&FileStatus)) // On success ==> 0 is returned
2019-02-21 17:34:53 +01:00
Lay_ShowErrorAndExit ("Can not get information about a file or folder.");
2016-12-29 22:00:35 +01:00
else
{
/***** Create URL pointing to ZIP file *****/
2018-10-16 23:08:04 +02:00
snprintf (URLWithSpaces,sizeof (URLWithSpaces),
2019-03-20 14:36:26 +01:00
"%s/%s/%s/%s",
2019-03-20 01:36:36 +01:00
Cfg_URL_FILE_BROWSER_TMP_PUBLIC,
2019-03-20 14:36:26 +01:00
Gbl.FileBrowser.TmpPubDir.L,
Gbl.FileBrowser.TmpPubDir.R,
2018-10-16 23:08:04 +02:00
FileNameZIP);
2016-12-29 22:00:35 +01:00
Str_CopyStrChangingSpaces (URLWithSpaces,URL,PATH_MAX); // In HTML, URL must have no spaces
/****** Link to download file *****/
ZIP_ShowLinkToDownloadZIP (FileNameZIP,URL,FileStatus.st_size,0);
}
2014-12-01 23:55:08 +01:00
}
else
Lay_ShowErrorAndExit ("Can not compress files into zip file.");
/***** Remove the directory of compression *****/
2016-10-06 22:18:33 +02:00
Fil_RemoveTree (Path);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/********* Create temporary directory to put the works to compress ***********/
/*****************************************************************************/
2016-11-22 13:15:12 +01:00
static void ZIP_CreateTmpDirForCompression (void)
2014-12-01 23:55:08 +01:00
{
2017-01-28 15:58:46 +01:00
char PathDirTmp[PATH_MAX + 1];
2014-12-01 23:55:08 +01:00
/***** If the private directory does not exist, create it *****/
2019-03-20 01:36:36 +01:00
Fil_CreateDirIfNotExists (Cfg_PATH_ZIP_PRIVATE);
2014-12-01 23:55:08 +01:00
/***** Create a new temporary directory *****/
2017-01-17 03:10:43 +01:00
Str_Copy (Gbl.FileBrowser.ZIP.TmpDir,Gbl.UniqueNameEncrypted,
NAME_MAX);
2018-10-16 23:08:04 +02:00
snprintf (PathDirTmp,sizeof (PathDirTmp),
"%s/%s",
2019-03-20 01:36:36 +01:00
Cfg_PATH_ZIP_PRIVATE,Gbl.FileBrowser.ZIP.TmpDir);
2014-12-01 23:55:08 +01:00
if (mkdir (PathDirTmp,(mode_t) 0xFFF))
Lay_ShowErrorAndExit ("Can not create temporary folder for compression.");
}
/*****************************************************************************/
/**************** Create link to a user's works zone ******************/
/**************** in the temporary directory of compression ******************/
/*****************************************************************************/
2016-11-22 13:15:12 +01:00
static void ZIP_CreateDirCompressionUsr (struct UsrData *UsrDat)
2014-12-01 23:55:08 +01:00
{
2017-03-06 10:27:02 +01:00
char FullNameAndUsrID[NAME_MAX + 1];
2018-10-04 21:57:25 +02:00
char PathFolderUsrInsideCrs[128 + PATH_MAX + NAME_MAX];
2017-01-15 22:58:26 +01:00
char LinkTmpUsr[PATH_MAX + 1];
char Link[PATH_MAX + 1];
2015-04-14 19:38:00 +02:00
unsigned NumTry;
bool Success;
2014-12-01 23:55:08 +01:00
/***** Create a link in the tree of compression
with a name that identifies the owner
of the assignments and works *****/
2016-06-03 10:37:00 +02:00
/* Create link name for this user */
2017-01-17 03:10:43 +01:00
Str_Copy (FullNameAndUsrID,UsrDat->Surname1,
2017-03-06 10:27:02 +01:00
NAME_MAX);
2016-06-03 10:37:00 +02:00
if (UsrDat->Surname1[0] &&
UsrDat->Surname2[0])
2017-01-17 03:33:05 +01:00
Str_Concat (FullNameAndUsrID,"_", // Separation between surname 1 and surname 2
2017-03-06 10:27:02 +01:00
NAME_MAX);
2017-01-17 03:33:05 +01:00
Str_Concat (FullNameAndUsrID,UsrDat->Surname2,
2017-03-06 10:27:02 +01:00
NAME_MAX);
2016-06-03 10:37:00 +02:00
if ((UsrDat->Surname1[0] ||
UsrDat->Surname2[0]) &&
UsrDat->FirstName[0])
2017-01-17 03:33:05 +01:00
Str_Concat (FullNameAndUsrID,"_", // Separation between surnames and first name
2017-03-06 10:27:02 +01:00
NAME_MAX);
2017-01-17 03:33:05 +01:00
Str_Concat (FullNameAndUsrID,UsrDat->FirstName,
2017-03-06 10:27:02 +01:00
NAME_MAX);
2016-06-03 10:37:00 +02:00
if ((UsrDat->Surname1[0] ||
UsrDat->Surname2[0] ||
UsrDat->FirstName[0]) &&
UsrDat->IDs.Num)
2017-01-17 03:33:05 +01:00
Str_Concat (FullNameAndUsrID,"-", // Separation between name and ID
2017-03-06 10:27:02 +01:00
NAME_MAX);
2016-06-03 10:37:00 +02:00
if (UsrDat->IDs.Num) // If this user has at least one ID
2017-01-17 03:33:05 +01:00
Str_Concat (FullNameAndUsrID,UsrDat->IDs.List[0].ID,
2017-03-06 10:27:02 +01:00
NAME_MAX); // First user's ID
2015-04-14 20:01:37 +02:00
Str_ConvertToValidFileName (FullNameAndUsrID);
2014-12-01 23:55:08 +01:00
2016-06-03 10:37:00 +02:00
/* Create path to folder and link */
2018-10-16 23:08:04 +02:00
snprintf (PathFolderUsrInsideCrs,sizeof (PathFolderUsrInsideCrs),
"%s/usr/%02u/%ld",
2019-04-04 10:45:15 +02:00
Gbl.Crs.PathPriv,
2018-10-16 23:08:04 +02:00
(unsigned) (UsrDat->UsrCod % 100),
UsrDat->UsrCod);
snprintf (LinkTmpUsr,sizeof (LinkTmpUsr),
2019-03-20 01:36:36 +01:00
"%s/%s/%s",
Cfg_PATH_ZIP_PRIVATE,
2018-10-16 23:08:04 +02:00
Gbl.FileBrowser.ZIP.TmpDir,
FullNameAndUsrID);
2015-04-14 19:38:00 +02:00
/* Try to create a link named LinkTmpUsr to PathFolderUsrInsideCrs */
if (symlink (PathFolderUsrInsideCrs,LinkTmpUsr) != 0)
{
for (Success = false, NumTry = 2;
!Success && errno == EEXIST && NumTry<=1000;
NumTry++)
{
// Link exists ==> a former user share the same name and ID
// (probably a unique user has created two or more accounts)
2018-10-16 23:08:04 +02:00
snprintf (Link,sizeof (Link),
"%s-%u",
LinkTmpUsr,NumTry);
2015-04-14 19:38:00 +02:00
if (symlink (PathFolderUsrInsideCrs,Link) == 0)
Success = true;
}
if (!Success)
Lay_ShowErrorAndExit ("Can not create temporary link for compression.");
}
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/********************* Compress a folder into ZIP file ***********************/
/*****************************************************************************/
void ZIP_CompressFileTree (void)
{
/***** Get parameters related to file browser *****/
Brw_GetParAndInitFileBrowser ();
/***** Compress folder into ZIP *****/
ZIP_CompressFolderIntoZIP ();
/***** Show again file browser *****/
Brw_ShowAgainFileBrowserOrWorks ();
}
/*****************************************************************************/
/*************** Create the zip file with assignments and works **************/
/*************** and put a link to download it **************/
/*****************************************************************************/
static void ZIP_CompressFolderIntoZIP (void)
{
extern const char *Txt_ROOT_FOLDER_EXTERNAL_NAMES[Brw_NUM_TYPES_FILE_BROWSER];
extern const char *Txt_The_folder_is_empty;
extern const char *Txt_The_contents_of_the_folder_are_too_big;
unsigned long long UncompressedSize;
2018-10-04 21:57:25 +02:00
char StrZip[128 + PATH_MAX];
char Path[PATH_MAX + 1 +
PATH_MAX + 1];
char PathCompression[PATH_MAX + 1 +
NAME_MAX + 1 +
NAME_MAX + 1];
2014-12-01 23:55:08 +01:00
int Result;
2017-01-28 15:58:46 +01:00
char FileNameZIP[NAME_MAX + 1];
char PathFileZIP[PATH_MAX + 1];
2014-12-01 23:55:08 +01:00
struct stat FileStatus;
2017-01-28 15:58:46 +01:00
char URLWithSpaces[PATH_MAX + 1];
char URL[PATH_MAX + 1];
2014-12-01 23:55:08 +01:00
/***** Create temporary private directory
for the compression of folder *****/
ZIP_CreateTmpDirForCompression ();
/***** Create a temporary public directory
used to download the zip file *****/
Brw_CreateDirDownloadTmp ();
/***** Create a copy of the directory to compress *****/
2018-10-16 23:08:04 +02:00
snprintf (Path,sizeof (Path),
"%s/%s",
Gbl.FileBrowser.Priv.PathAboveRootFolder,
2019-04-25 14:39:51 +02:00
Gbl.FileBrowser.FilFolLnk.Full);
2018-10-16 23:08:04 +02:00
snprintf (PathCompression,sizeof (PathCompression),
2019-03-20 01:36:36 +01:00
"%s/%s",
Cfg_PATH_ZIP_PRIVATE,
2018-10-16 23:08:04 +02:00
Gbl.FileBrowser.ZIP.TmpDir); // Example: /var/www/swad/zip/<temporary_dir>
2014-12-01 23:55:08 +01:00
2019-04-25 14:39:51 +02:00
UncompressedSize = ZIP_CloneDir (Path,PathCompression,Gbl.FileBrowser.FilFolLnk.Full);
2014-12-01 23:55:08 +01:00
if (UncompressedSize == 0) // Nothing to compress
2019-02-16 19:29:27 +01:00
Ale_ShowAlert (Ale_WARNING,Txt_The_folder_is_empty);
2014-12-01 23:55:08 +01:00
else if (UncompressedSize > ZIP_MAX_SIZE_UNCOMPRESSED) // Uncompressed size is too big
2019-02-16 19:29:27 +01:00
Ale_ShowAlert (Ale_WARNING,Txt_The_contents_of_the_folder_are_too_big);
2014-12-01 23:55:08 +01:00
else
{
/***** Change to directory of the clone folder
in order to start the path in the zip file from there *****/
if (chdir (PathCompression))
Lay_ShowErrorAndExit ("Can not change to temporary folder for compression.");
/***** Create public zip file with the assignment and works *****/
2018-10-16 23:08:04 +02:00
snprintf (FileNameZIP,sizeof (FileNameZIP),
"%s.zip",
2019-04-25 14:39:51 +02:00
strcmp (Gbl.FileBrowser.FilFolLnk.Name,".") ? Gbl.FileBrowser.FilFolLnk.Name :
2018-10-16 23:08:04 +02:00
Txt_ROOT_FOLDER_EXTERNAL_NAMES[Gbl.FileBrowser.Type]);
snprintf (PathFileZIP,sizeof (PathFileZIP),
2019-03-20 14:36:26 +01:00
"%s/%s/%s/%s",
2019-03-20 01:36:36 +01:00
Cfg_PATH_FILE_BROWSER_TMP_PUBLIC,
2019-03-20 14:36:26 +01:00
Gbl.FileBrowser.TmpPubDir.L,
Gbl.FileBrowser.TmpPubDir.R,
2018-10-16 23:08:04 +02:00
FileNameZIP);
snprintf (StrZip,sizeof (StrZip),
"nice -n 19 zip -q -5 -r '%s' *",
PathFileZIP);
2014-12-01 23:55:08 +01:00
Result = system (StrZip);
/***** Return to the CGI directory *****/
if (chdir (Cfg_PATH_CGI_BIN))
Lay_ShowErrorAndExit ("Can not change to cgi-bin folder.");
/***** If the zip command has been sucessful, write the link to zip file *****/
if (Result == 0)
{
/***** Get file size *****/
2016-12-29 22:00:35 +01:00
if (lstat (PathFileZIP,&FileStatus)) // On success ==> 0 is returned
2019-02-21 17:34:53 +01:00
Lay_ShowErrorAndExit ("Can not get information about a file or folder.");
2016-12-29 22:00:35 +01:00
else
{
/***** Create URL pointing to ZIP file *****/
2018-10-16 23:08:04 +02:00
snprintf (URLWithSpaces,sizeof (URLWithSpaces),
2019-03-20 14:36:26 +01:00
"%s/%s/%s/%s",
2019-03-20 01:36:36 +01:00
Cfg_URL_FILE_BROWSER_TMP_PUBLIC,
2019-03-20 14:36:26 +01:00
Gbl.FileBrowser.TmpPubDir.L,
Gbl.FileBrowser.TmpPubDir.R,
2018-10-16 23:08:04 +02:00
FileNameZIP);
2016-12-29 22:00:35 +01:00
Str_CopyStrChangingSpaces (URLWithSpaces,URL,PATH_MAX); // In HTML, URL must have no spaces
/****** Link to download file *****/
ZIP_ShowLinkToDownloadZIP (FileNameZIP,URL,FileStatus.st_size,UncompressedSize);
}
2014-12-01 23:55:08 +01:00
}
else
Lay_ShowErrorAndExit ("Can not compress files into zip file.");
}
/***** Remove the directory of compression *****/
2016-10-06 22:18:33 +02:00
Fil_RemoveTree (PathCompression);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/*************** Clone a directory recursively to compress it ****************/
/*****************************************************************************/
/* Example:
*
* Example starting directory with document files: /var/www/swad/crs/1000/descarga/lectures/lecture_1
* We want to compress all files inside lecture_1 into a ZIP file
* Path = /var/www/swad/crs/1000/descarga/lectures/lecture_1
* PathClone = /var/www/swad/zip/<unique_dir>
* PathInTree = "descarga/lectures/lecture_1"
* Example directory inside starting directory with document files: /var/www/swad/crs/1000/descarga/lectures/lecture_1/slides
* Path = /var/www/swad/crs/1000/descarga/lectures/lecture_1/slides
* PathClone: /var/www/swad/zip/<unique_dir>/slides
* PathInTree = "descarga/lectures/lecture_1/slides
*/
// Return: full size of directory contents
static unsigned long long ZIP_CloneDir (const char *Path,const char *PathClone,const char *PathInTree)
{
2015-12-21 14:43:52 +01:00
struct dirent **FileList;
int NumFile;
int NumFiles;
2017-01-28 15:58:46 +01:00
char PathFile[PATH_MAX + 1];
char PathFileClone[PATH_MAX + 1];
char PathFileInTree[PATH_MAX + 1];
2014-12-01 23:55:08 +01:00
struct stat FileStatus;
Brw_FileType_t FileType;
bool Hidden;
2017-10-08 00:51:49 +02:00
bool SeeDocsZone = Gbl.FileBrowser.Type == Brw_SHOW_DOC_INS ||
Gbl.FileBrowser.Type == Brw_SHOW_DOC_CTR ||
Gbl.FileBrowser.Type == Brw_SHOW_DOC_DEG ||
Gbl.FileBrowser.Type == Brw_SHOW_DOC_CRS ||
Gbl.FileBrowser.Type == Brw_SHOW_DOC_GRP;
bool SeeMarks = Gbl.FileBrowser.Type == Brw_SHOW_MRK_CRS ||
Gbl.FileBrowser.Type == Brw_SHOW_MRK_GRP;
2014-12-01 23:55:08 +01:00
unsigned long long FullSize = 0;
/***** Scan directory *****/
2015-12-21 14:43:52 +01:00
if ((NumFiles = scandir (Path,&FileList,NULL,alphasort)) >= 0) // No error
{
/***** List files *****/
for (NumFile = 0;
NumFile < NumFiles;
NumFile++)
if (strcmp (FileList[NumFile]->d_name,".") &&
strcmp (FileList[NumFile]->d_name,"..")) // Skip directories "." and ".."
{
2018-10-16 23:08:04 +02:00
snprintf (PathFileInTree,sizeof (PathFileInTree),
"%s/%s",
PathInTree,FileList[NumFile]->d_name);
snprintf (PathFile,sizeof (PathFile),
"%s/%s",
Path,FileList[NumFile]->d_name);
snprintf (PathFileClone,sizeof (PathFileClone),
"%s/%s",
PathClone,FileList[NumFile]->d_name);
2015-12-21 14:43:52 +01:00
2016-12-29 22:00:35 +01:00
FileType = Brw_IS_UNKNOWN;
if (lstat (PathFile,&FileStatus)) // On success ==> 0 is returned
2019-02-21 17:34:53 +01:00
Lay_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
2015-12-21 14:43:52 +01:00
FileType = Brw_IS_FOLDER;
else if (S_ISREG (FileStatus.st_mode)) // It's a regular file
FileType = Str_FileIs (FileList[NumFile]->d_name,"url") ? Brw_IS_LINK : // It's a link (URL inside a .url file)
Brw_IS_FILE; // It's a file
Hidden = (SeeDocsZone || SeeMarks) ? Brw_CheckIfFileOrFolderIsSetAsHiddenInDB (FileType,PathFileInTree) :
false;
if (!Hidden) // If file/folder is not hidden
2014-12-01 23:55:08 +01:00
{
2015-12-21 14:43:52 +01:00
if (FileType == Brw_IS_FOLDER) // It's a directory
{
FullSize += (unsigned long long) FileStatus.st_size;
/***** Create clone of subdirectory *****/
if (mkdir (PathFileClone,(mode_t) 0xFFF))
Lay_ShowErrorAndExit ("Can not create temporary subfolder for compression.");
/***** Clone subtree starting at this this directory *****/
FullSize += ZIP_CloneDir (PathFile,PathFileClone,PathFileInTree);
}
else if (FileType == Brw_IS_FILE ||
FileType == Brw_IS_LINK) // It's a regular file
{
FullSize += (unsigned long long) FileStatus.st_size;
/***** Create a symbolic link (clone) to original file *****/
if (symlink (PathFile,PathFileClone) != 0)
Lay_ShowErrorAndExit ("Can not create temporary link for compression.");
/***** Update number of my views of this file *****/
2016-01-04 01:02:07 +01:00
Brw_UpdateMyFileViews (Brw_GetFilCodByPath (PathFileInTree,false)); // Any file, public or not
2015-12-21 14:43:52 +01:00
}
2014-12-01 23:55:08 +01:00
}
2015-12-21 14:43:52 +01:00
}
}
else
Lay_ShowErrorAndExit ("Error while scanning directory.");
2014-12-01 23:55:08 +01:00
return FullSize;
}
/*****************************************************************************/
/********************* Show link to download a ZIP file **********************/
/*****************************************************************************/
static void ZIP_ShowLinkToDownloadZIP (const char *FileName,const char *URL,
off_t FileSize,unsigned long long UncompressedSize)
{
2019-02-22 21:47:50 +01:00
extern const char *The_ClassFormInBox[The_NUM_THEMES];
2014-12-01 23:55:08 +01:00
extern const char *Txt_ZIP_file;
extern const char *Txt_Download;
extern const char *Txt_Filename;
extern const char *Txt_File_size;
extern const char *Txt_FILE_uncompressed;
2017-01-15 18:02:52 +01:00
char FileSizeStr[Fil_MAX_BYTES_FILE_SIZE_STRING + 1];
2014-12-01 23:55:08 +01:00
2019-10-26 02:19:42 +02:00
/***** Begin box and table *****/
2017-06-10 21:38:10 +02:00
Box_StartBoxTableShadow (NULL,NULL,NULL,NULL,2);
2014-12-01 23:55:08 +01:00
/***** Link to download the file *****/
2019-10-23 19:05:05 +02:00
HTM_TR_Begin (NULL);
HTM_TD_Begin ("colspan=\"2\" class=\"FILENAME_TXT CM\"");
2019-10-28 20:38:29 +01:00
HTM_A_Begin ("href=\"%s\" class=\"FILENAME_TXT\" title=\"%s\" target=\"_blank\"",
URL,FileName);
2019-10-30 00:42:01 +01:00
HTM_IMG (CfG_URL_ICON_FILEXT_PUBLIC "32x32","zip32x32.gif",Txt_ZIP_file,
2019-10-30 22:31:03 +01:00
"class=\"ICO40x40\"");
2019-11-11 10:59:24 +01:00
HTM_TxtF ("&nbsp;%s&nbsp;",FileName);
2019-10-29 21:41:54 +01:00
Ico_PutIcon ("download.svg",Txt_Download,"ICO40x40");
2019-10-28 13:56:04 +01:00
HTM_A_End ();
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
HTM_TR_End ();
2014-12-01 23:55:08 +01:00
/***** Filename *****/
2019-10-23 19:05:05 +02:00
HTM_TR_Begin (NULL);
2019-10-07 21:15:14 +02:00
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"%s RM\"",The_ClassFormInBox[Gbl.Prefs.Theme]);
2019-11-11 10:59:24 +01:00
HTM_TxtF ("%s:",Txt_Filename);
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2019-10-07 21:15:14 +02:00
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"DAT LM\"");
2019-10-28 20:38:29 +01:00
HTM_A_Begin ("href=\"%s\" class=\"DAT\" title=\"%s\" target=\"_blank\"",
URL,FileName);
2019-11-10 12:36:37 +01:00
HTM_Txt (FileName);
2019-10-28 13:56:04 +01:00
HTM_A_End ();
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2019-10-07 21:15:14 +02:00
2019-10-23 19:05:05 +02:00
HTM_TR_End ();
2014-12-01 23:55:08 +01:00
/***** Write the file size *****/
2016-06-30 18:14:09 +02:00
Fil_WriteFileSizeFull ((double) FileSize,FileSizeStr);
2019-10-23 19:05:05 +02:00
HTM_TR_Begin (NULL);
2019-10-07 21:15:14 +02:00
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"%s RM\"",The_ClassFormInBox[Gbl.Prefs.Theme]);
2019-11-11 10:59:24 +01:00
HTM_TxtF ("%s:",Txt_File_size);
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2019-10-07 21:15:14 +02:00
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"DAT LM\"");
2019-11-10 12:36:37 +01:00
HTM_Txt (FileSizeStr);
2014-12-01 23:55:08 +01:00
if (UncompressedSize)
{
2016-06-30 18:14:09 +02:00
Fil_WriteFileSizeFull ((double) UncompressedSize,FileSizeStr);
2019-11-11 00:15:44 +01:00
HTM_TxtF (" (%s %s)",FileSizeStr,Txt_FILE_uncompressed);
2014-12-01 23:55:08 +01:00
}
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2019-10-07 21:15:14 +02:00
2019-10-23 19:05:05 +02:00
HTM_TR_End ();
2014-12-01 23:55:08 +01:00
2017-06-12 14:16:33 +02:00
/***** End table and box *****/
2017-06-10 21:38:10 +02:00
Box_EndBoxTable ();
2014-12-01 23:55:08 +01:00
}