Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
dadigang
Ventoy
Commits
43e8ec57
Commit
43e8ec57
authored
Feb 26, 2021
by
longpanda
Browse files
Experimental Linux GUI based on web browser
parent
7279ba9b
Changes
158
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
19368 additions
and
0 deletions
+19368
-0
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_misc.h
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_misc.h
+63
-0
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_opts.h
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_opts.h
+90
-0
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_string.c
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_string.c
+514
-0
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_string.h
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_string.h
+20
-0
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_table.c
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_table.c
+478
-0
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_table.h
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_table.h
+20
-0
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_types.h
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_types.h
+69
-0
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_write.c
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_write.c
+373
-0
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_write.h
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_write.h
+14
-0
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/version.txt
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/version.txt
+1
-0
LinuxGUI/Ventoy2Disk/Lib/libhttp/buildlib.sh
LinuxGUI/Ventoy2Disk/Lib/libhttp/buildlib.sh
+46
-0
LinuxGUI/Ventoy2Disk/Lib/libhttp/include/civetweb.c
LinuxGUI/Ventoy2Disk/Lib/libhttp/include/civetweb.c
+13145
-0
LinuxGUI/Ventoy2Disk/Lib/libhttp/include/civetweb.h
LinuxGUI/Ventoy2Disk/Lib/libhttp/include/civetweb.h
+1024
-0
LinuxGUI/Ventoy2Disk/Lib/libhttp/include/handle_form.inl
LinuxGUI/Ventoy2Disk/Lib/libhttp/include/handle_form.inl
+793
-0
LinuxGUI/Ventoy2Disk/Lib/libhttp/include/md5.inl
LinuxGUI/Ventoy2Disk/Lib/libhttp/include/md5.inl
+468
-0
LinuxGUI/Ventoy2Disk/Lib/libhttp/include/mod_duktape.inl
LinuxGUI/Ventoy2Disk/Lib/libhttp/include/mod_duktape.inl
+250
-0
LinuxGUI/Ventoy2Disk/Lib/libhttp/include/mod_lua.inl
LinuxGUI/Ventoy2Disk/Lib/libhttp/include/mod_lua.inl
+1840
-0
LinuxGUI/Ventoy2Disk/Lib/libhttp/include/timer.inl
LinuxGUI/Ventoy2Disk/Lib/libhttp/include/timer.inl
+150
-0
LinuxGUI/Ventoy2Disk/Lib/libhttp/libhttp-1.8.tar.gz
LinuxGUI/Ventoy2Disk/Lib/libhttp/libhttp-1.8.tar.gz
+0
-0
LinuxGUI/Ventoy2Disk/Lib/xz-embedded/COPYING
LinuxGUI/Ventoy2Disk/Lib/xz-embedded/COPYING
+10
-0
No files found.
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_misc.h
0 → 100644
View file @
43e8ec57
#ifndef __FAT_MISC_H__
#define __FAT_MISC_H__
#include "fat_defs.h"
#include "fat_opts.h"
//-----------------------------------------------------------------------------
// Defines
//-----------------------------------------------------------------------------
#define MAX_LONGFILENAME_ENTRIES 20
#define MAX_LFN_ENTRY_LENGTH 13
//-----------------------------------------------------------------------------
// Macros
//-----------------------------------------------------------------------------
#define GET_32BIT_WORD(buffer, location) ( ((uint32)buffer[location+3]<<24) + ((uint32)buffer[location+2]<<16) + ((uint32)buffer[location+1]<<8) + (uint32)buffer[location+0] )
#define GET_16BIT_WORD(buffer, location) ( ((uint16)buffer[location+1]<<8) + (uint16)buffer[location+0] )
#define SET_32BIT_WORD(buffer, location, value) { buffer[location+0] = (uint8)((value)&0xFF); \
buffer[location+1] = (uint8)((value>>8)&0xFF); \
buffer[location+2] = (uint8)((value>>16)&0xFF); \
buffer[location+3] = (uint8)((value>>24)&0xFF); }
#define SET_16BIT_WORD(buffer, location, value) { buffer[location+0] = (uint8)((value)&0xFF); \
buffer[location+1] = (uint8)((value>>8)&0xFF); }
//-----------------------------------------------------------------------------
// Structures
//-----------------------------------------------------------------------------
struct
lfn_cache
{
#if FATFS_INC_LFN_SUPPORT
// Long File Name Structure (max 260 LFN length)
uint8
String
[
MAX_LONGFILENAME_ENTRIES
][
MAX_LFN_ENTRY_LENGTH
];
uint8
Null
;
#endif
uint8
no_of_strings
;
};
//-----------------------------------------------------------------------------
// Prototypes
//-----------------------------------------------------------------------------
void
fatfs_lfn_cache_init
(
struct
lfn_cache
*
lfn
,
int
wipeTable
);
void
fatfs_lfn_cache_entry
(
struct
lfn_cache
*
lfn
,
uint8
*
entryBuffer
);
char
*
fatfs_lfn_cache_get
(
struct
lfn_cache
*
lfn
);
int
fatfs_entry_lfn_text
(
struct
fat_dir_entry
*
entry
);
int
fatfs_entry_lfn_invalid
(
struct
fat_dir_entry
*
entry
);
int
fatfs_entry_lfn_exists
(
struct
lfn_cache
*
lfn
,
struct
fat_dir_entry
*
entry
);
int
fatfs_entry_sfn_only
(
struct
fat_dir_entry
*
entry
);
int
fatfs_entry_is_dir
(
struct
fat_dir_entry
*
entry
);
int
fatfs_entry_is_file
(
struct
fat_dir_entry
*
entry
);
int
fatfs_lfn_entries_required
(
char
*
filename
);
void
fatfs_filename_to_lfn
(
char
*
filename
,
uint8
*
buffer
,
int
entry
,
uint8
sfnChk
);
void
fatfs_sfn_create_entry
(
char
*
shortfilename
,
uint32
size
,
uint32
startCluster
,
struct
fat_dir_entry
*
entry
,
int
dir
);
int
fatfs_lfn_create_sfn
(
char
*
sfn_output
,
char
*
filename
);
int
fatfs_lfn_generate_tail
(
char
*
sfn_output
,
char
*
sfn_input
,
uint32
tailNum
);
void
fatfs_convert_from_fat_time
(
uint16
fat_time
,
int
*
hours
,
int
*
minutes
,
int
*
seconds
);
void
fatfs_convert_from_fat_date
(
uint16
fat_date
,
int
*
day
,
int
*
month
,
int
*
year
);
uint16
fatfs_convert_to_fat_time
(
int
hours
,
int
minutes
,
int
seconds
);
uint16
fatfs_convert_to_fat_date
(
int
day
,
int
month
,
int
year
);
void
fatfs_print_sector
(
uint32
sector
,
uint8
*
data
);
#endif
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_opts.h
0 → 100644
View file @
43e8ec57
#ifndef __FAT_OPTS_H__
#define __FAT_OPTS_H__
#ifdef FATFS_USE_CUSTOM_OPTS_FILE
#include "fat_custom.h"
#endif
//-------------------------------------------------------------
// Configuration
//-------------------------------------------------------------
// Is the processor little endian (1) or big endian (0)
#ifndef FATFS_IS_LITTLE_ENDIAN
#define FATFS_IS_LITTLE_ENDIAN 1
#endif
// Max filename Length
#ifndef FATFS_MAX_LONG_FILENAME
#define FATFS_MAX_LONG_FILENAME 260
#endif
// Max open files (reduce to lower memory requirements)
#ifndef FATFS_MAX_OPEN_FILES
#define FATFS_MAX_OPEN_FILES 2
#endif
// Number of sectors per FAT_BUFFER (min 1)
#ifndef FAT_BUFFER_SECTORS
#define FAT_BUFFER_SECTORS 1
#endif
// Max FAT sectors to buffer (min 1)
// (mem used is FAT_BUFFERS * FAT_BUFFER_SECTORS * FAT_SECTOR_SIZE)
#ifndef FAT_BUFFERS
#define FAT_BUFFERS 1
#endif
// Size of cluster chain cache (can be undefined)
// Mem used = FAT_CLUSTER_CACHE_ENTRIES * 4 * 2
// Improves access speed considerably
//#define FAT_CLUSTER_CACHE_ENTRIES 128
// Include support for writing files (1 / 0)?
#ifndef FATFS_INC_WRITE_SUPPORT
#define FATFS_INC_WRITE_SUPPORT 1
#endif
// Support long filenames (1 / 0)?
// (if not (0) only 8.3 format is supported)
#ifndef FATFS_INC_LFN_SUPPORT
#define FATFS_INC_LFN_SUPPORT 1
#endif
// Support directory listing (1 / 0)?
#ifndef FATFS_DIR_LIST_SUPPORT
#define FATFS_DIR_LIST_SUPPORT 1
#endif
// Support time/date (1 / 0)?
#ifndef FATFS_INC_TIME_DATE_SUPPORT
#define FATFS_INC_TIME_DATE_SUPPORT 0
#endif
// Include support for formatting disks (1 / 0)?
#ifndef FATFS_INC_FORMAT_SUPPORT
#define FATFS_INC_FORMAT_SUPPORT 1
#endif
// Sector size used
#define FAT_SECTOR_SIZE 512
// Printf output (directory listing / debug)
#ifndef FAT_PRINTF
// Don't include stdio, but there is a printf function available
#ifdef FAT_PRINTF_NOINC_STDIO
extern
int
printf
(
const
char
*
ctrl1
,
...
);
#define FAT_PRINTF(a) printf a
// Include stdio to use printf
#else
#include <stdio.h>
#define FAT_PRINTF(a) printf a
#endif
#endif
// Time/Date support requires time.h
#if FATFS_INC_TIME_DATE_SUPPORT
#include <time.h>
#endif
#endif
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_string.c
0 → 100644
View file @
43e8ec57
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// FAT16/32 File IO Library
// V2.6
// Ultra-Embedded.com
// Copyright 2003 - 2012
//
// Email: admin@ultra-embedded.com
//
// License: GPL
// If you would like a version with a more permissive license for use in
// closed source commercial applications please contact me for details.
//-----------------------------------------------------------------------------
//
// This file is part of FAT File IO Library.
//
// FAT File IO Library is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// FAT File IO Library 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with FAT File IO Library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
#include <string.h>
#include <assert.h>
#include "fat_string.h"
//-----------------------------------------------------------------------------
// fatfs_total_path_levels: Take a filename and path and count the sub levels
// of folders. E.g. C:\folder\file.zip = 1 level
// Acceptable input formats are:
// c:\folder\file.zip
// /dev/etc/samba.conf
// Returns: -1 = Error, 0 or more = Ok
//-----------------------------------------------------------------------------
int
fatfs_total_path_levels
(
char
*
path
)
{
int
levels
=
0
;
char
expectedchar
;
if
(
!
path
)
return
-
1
;
// Acceptable formats:
// c:\folder\file.zip
// /dev/etc/samba.conf
if
(
*
path
==
'/'
)
{
expectedchar
=
'/'
;
path
++
;
}
else
if
(
path
[
1
]
==
':'
||
path
[
2
]
==
'\\'
)
{
expectedchar
=
'\\'
;
path
+=
3
;
}
else
return
-
1
;
// Count levels in path string
while
(
*
path
)
{
// Fast forward through actual subdir text to next slash
for
(;
*
path
;
)
{
// If slash detected escape from for loop
if
(
*
path
==
expectedchar
)
{
path
++
;
break
;
}
path
++
;
}
// Increase number of subdirs founds
levels
++
;
}
// Subtract the file itself
return
levels
-
1
;
}
//-----------------------------------------------------------------------------
// fatfs_get_substring: Get a substring from 'path' which contains the folder
// (or file) at the specified level.
// E.g. C:\folder\file.zip : Level 0 = C:\folder, Level 1 = file.zip
// Returns: -1 = Error, 0 = Ok
//-----------------------------------------------------------------------------
int
fatfs_get_substring
(
char
*
path
,
int
levelreq
,
char
*
output
,
int
max_len
)
{
int
i
;
int
pathlen
=
0
;
int
levels
=
0
;
int
copypnt
=
0
;
char
expectedchar
;
if
(
!
path
||
max_len
<=
0
)
return
-
1
;
// Acceptable formats:
// c:\folder\file.zip
// /dev/etc/samba.conf
if
(
*
path
==
'/'
)
{
expectedchar
=
'/'
;
path
++
;
}
else
if
(
path
[
1
]
==
':'
||
path
[
2
]
==
'\\'
)
{
expectedchar
=
'\\'
;
path
+=
3
;
}
else
return
-
1
;
// Get string length of path
pathlen
=
(
int
)
strlen
(
path
);
// Loop through the number of times as characters in 'path'
for
(
i
=
0
;
i
<
pathlen
;
i
++
)
{
// If a '\' is found then increase level
if
(
*
path
==
expectedchar
)
levels
++
;
// If correct level and the character is not a '\' or '/' then copy text to 'output'
if
(
(
levels
==
levelreq
)
&&
(
*
path
!=
expectedchar
)
&&
(
copypnt
<
(
max_len
-
1
)))
output
[
copypnt
++
]
=
*
path
;
// Increment through path string
path
++
;
}
// Null Terminate
output
[
copypnt
]
=
'\0'
;
// If a string was copied return 0 else return 1
if
(
output
[
0
]
!=
'\0'
)
return
0
;
// OK
else
return
-
1
;
// Error
}
//-----------------------------------------------------------------------------
// fatfs_split_path: Full path contains the passed in string.
// Returned is the path string and file Name string
// E.g. C:\folder\file.zip -> path = C:\folder filename = file.zip
// E.g. C:\file.zip -> path = [blank] filename = file.zip
//-----------------------------------------------------------------------------
int
fatfs_split_path
(
char
*
full_path
,
char
*
path
,
int
max_path
,
char
*
filename
,
int
max_filename
)
{
int
strindex
;
// Count the levels to the filepath
int
levels
=
fatfs_total_path_levels
(
full_path
);
if
(
levels
==
-
1
)
return
-
1
;
// Get filename part of string
if
(
fatfs_get_substring
(
full_path
,
levels
,
filename
,
max_filename
)
!=
0
)
return
-
1
;
// If root file
if
(
levels
==
0
)
path
[
0
]
=
'\0'
;
else
{
strindex
=
(
int
)
strlen
(
full_path
)
-
(
int
)
strlen
(
filename
);
if
(
strindex
>
max_path
)
strindex
=
max_path
;
memcpy
(
path
,
full_path
,
strindex
);
path
[
strindex
-
1
]
=
'\0'
;
}
return
0
;
}
//-----------------------------------------------------------------------------
// FileString_StrCmpNoCase: Compare two strings case with case sensitivity
//-----------------------------------------------------------------------------
static
int
FileString_StrCmpNoCase
(
char
*
s1
,
char
*
s2
,
int
n
)
{
int
diff
;
char
a
,
b
;
while
(
n
--
)
{
a
=
*
s1
;
b
=
*
s2
;
// Make lower case if uppercase
if
((
a
>=
'A'
)
&&
(
a
<=
'Z'
))
a
+=
32
;
if
((
b
>=
'A'
)
&&
(
b
<=
'Z'
))
b
+=
32
;
diff
=
a
-
b
;
// If different
if
(
diff
)
return
diff
;
// If run out of strings
if
(
(
*
s1
==
0
)
||
(
*
s2
==
0
)
)
break
;
s1
++
;
s2
++
;
}
return
0
;
}
//-----------------------------------------------------------------------------
// FileString_GetExtension: Get index to extension within filename
// Returns -1 if not found or index otherwise
//-----------------------------------------------------------------------------
static
int
FileString_GetExtension
(
char
*
str
)
{
int
dotPos
=
-
1
;
char
*
strSrc
=
str
;
// Find last '.' in string (if at all)
while
(
*
strSrc
)
{
if
(
*
strSrc
==
'.'
)
dotPos
=
(
int
)(
strSrc
-
str
);
strSrc
++
;
}
return
dotPos
;
}
//-----------------------------------------------------------------------------
// FileString_TrimLength: Get length of string excluding trailing spaces
// Returns -1 if not found or index otherwise
//-----------------------------------------------------------------------------
static
int
FileString_TrimLength
(
char
*
str
,
int
strLen
)
{
int
length
=
strLen
;
char
*
strSrc
=
str
+
strLen
-
1
;
// Find last non white space
while
(
strLen
!=
0
)
{
if
(
*
strSrc
==
' '
)
length
=
(
int
)(
strSrc
-
str
);
else
break
;
strSrc
--
;
strLen
--
;
}
return
length
;
}
//-----------------------------------------------------------------------------
// fatfs_compare_names: Compare two filenames (without copying or changing origonals)
// Returns 1 if match, 0 if not
//-----------------------------------------------------------------------------
int
fatfs_compare_names
(
char
*
strA
,
char
*
strB
)
{
char
*
ext1
=
NULL
;
char
*
ext2
=
NULL
;
int
ext1Pos
,
ext2Pos
;
int
file1Len
,
file2Len
;
// Get both files extension
ext1Pos
=
FileString_GetExtension
(
strA
);
ext2Pos
=
FileString_GetExtension
(
strB
);
// NOTE: Extension position can be different for matching
// filename if trailing space are present before it!
// Check that if one has an extension, so does the other
if
((
ext1Pos
==-
1
)
&&
(
ext2Pos
!=-
1
))
return
0
;
if
((
ext2Pos
==-
1
)
&&
(
ext1Pos
!=-
1
))
return
0
;
// If they both have extensions, compare them
if
(
ext1Pos
!=-
1
)
{
// Set pointer to start of extension
ext1
=
strA
+
ext1Pos
+
1
;
ext2
=
strB
+
ext2Pos
+
1
;
// Verify that the file extension lengths match!
if
(
strlen
(
ext1
)
!=
strlen
(
ext2
))
return
0
;
// If they dont match
if
(
FileString_StrCmpNoCase
(
ext1
,
ext2
,
(
int
)
strlen
(
ext1
))
!=
0
)
return
0
;
// Filelength is upto extensions
file1Len
=
ext1Pos
;
file2Len
=
ext2Pos
;
}
// No extensions
else
{
// Filelength is actual filelength
file1Len
=
(
int
)
strlen
(
strA
);
file2Len
=
(
int
)
strlen
(
strB
);
}
// Find length without trailing spaces (before ext)
file1Len
=
FileString_TrimLength
(
strA
,
file1Len
);
file2Len
=
FileString_TrimLength
(
strB
,
file2Len
);
// Check the file lengths match
if
(
file1Len
!=
file2Len
)
return
0
;
// Compare main part of filenames
if
(
FileString_StrCmpNoCase
(
strA
,
strB
,
file1Len
)
!=
0
)
return
0
;
else
return
1
;
}
//-----------------------------------------------------------------------------
// fatfs_string_ends_with_slash: Does the string end with a slash (\ or /)
//-----------------------------------------------------------------------------
int
fatfs_string_ends_with_slash
(
char
*
path
)
{
if
(
path
)
{
while
(
*
path
)
{
// Last character?
if
(
!
(
*
(
path
+
1
)))
{
if
(
*
path
==
'\\'
||
*
path
==
'/'
)
return
1
;
}
path
++
;
}
}
return
0
;
}
//-----------------------------------------------------------------------------
// fatfs_get_sfn_display_name: Get display name for SFN entry
//-----------------------------------------------------------------------------
int
fatfs_get_sfn_display_name
(
char
*
out
,
char
*
in
)
{
int
len
=
0
;
while
(
*
in
&&
len
<=
11
)
{
char
a
=
*
in
++
;
if
(
a
==
' '
)
continue
;
// Make lower case if uppercase
else
if
((
a
>=
'A'
)
&&
(
a
<=
'Z'
))
a
+=
32
;
*
out
++
=
a
;
len
++
;
}
*
out
=
'\0'
;
return
1
;
}
//-----------------------------------------------------------------------------
// fatfs_get_extension: Get extension of filename passed in 'filename'.
// Returned extension is always lower case.
// Returns: 1 if ok, 0 if not.
//-----------------------------------------------------------------------------
int
fatfs_get_extension
(
char
*
filename
,
char
*
out
,
int
maxlen
)
{
int
len
=
0
;
// Get files extension offset
int
ext_pos
=
FileString_GetExtension
(
filename
);
if
(
ext_pos
>
0
&&
out
&&
maxlen
)
{
filename
+=
ext_pos
+
1
;
while
(
*
filename
&&
len
<
(
maxlen
-
1
))
{
char
a
=
*
filename
++
;
// Make lowercase if uppercase
if
((
a
>=
'A'
)
&&
(
a
<=
'Z'
))
a
+=
32
;
*
out
++
=
a
;
len
++
;
}
*
out
=
'\0'
;
return
1
;
}
return
0
;
}
//-----------------------------------------------------------------------------
// fatfs_create_path_string: Append path & filename to create file path string.
// Returns: 1 if ok, 0 if not.
//-----------------------------------------------------------------------------
int
fatfs_create_path_string
(
char
*
path
,
char
*
filename
,
char
*
out
,
int
maxlen
)
{
int
len
=
0
;
char
last
=
0
;
char
seperator
=
'/'
;
if
(
path
&&
filename
&&
out
&&
maxlen
>
0
)
{
while
(
*
path
&&
len
<
(
maxlen
-
2
))
{
last
=
*
path
++
;
if
(
last
==
'\\'
)
seperator
=
'\\'
;
*
out
++
=
last
;
len
++
;
}
// Add a seperator if trailing one not found
if
(
last
!=
'\\'
&&
last
!=
'/'
)
*
out
++
=
seperator
;
while
(
*
filename
&&
len
<
(
maxlen
-
1
))
{
*
out
++
=
*
filename
++
;
len
++
;
}
*
out
=
'\0'
;
return
1
;
}
return
0
;
}
//-----------------------------------------------------------------------------
// Test Bench
//-----------------------------------------------------------------------------
#ifdef FAT_STRING_TESTBENCH
void
main
(
void
)
{
char
output
[
255
];
char
output2
[
255
];
assert
(
fatfs_total_path_levels
(
"C:
\\
folder
\\
file.zip"
)
==
1
);
assert
(
fatfs_total_path_levels
(
"C:
\\
file.zip"
)
==
0
);
assert
(
fatfs_total_path_levels
(
"C:
\\
folder
\\
folder2
\\
file.zip"
)
==
2
);
assert
(
fatfs_total_path_levels
(
"C:
\\
"
)
==
-
1
);
assert
(
fatfs_total_path_levels
(
""
)
==
-
1
);
assert
(
fatfs_total_path_levels
(
"/dev/etc/file.zip"
)
==
2
);
assert
(
fatfs_total_path_levels
(
"/dev/file.zip"
)
==
1
);
assert
(
fatfs_get_substring
(
"C:
\\
folder
\\
file.zip"
,
0
,
output
,
sizeof
(
output
))
==
0
);
assert
(
strcmp
(
output
,
"folder"
)
==
0
);
assert
(
fatfs_get_substring
(
"C:
\\
folder
\\
file.zip"
,
1
,
output
,
sizeof
(
output
))
==
0
);
assert
(
strcmp
(
output
,
"file.zip"
)
==
0
);
assert
(
fatfs_get_substring
(
"/dev/etc/file.zip"
,
0
,
output
,
sizeof
(
output
))
==
0
);
assert
(
strcmp
(
output
,
"dev"
)
==
0
);
assert
(
fatfs_get_substring
(
"/dev/etc/file.zip"
,
1
,
output
,
sizeof
(
output
))
==
0
);
assert
(
strcmp
(
output
,
"etc"
)
==
0
);
assert
(
fatfs_get_substring
(
"/dev/etc/file.zip"
,
2
,
output
,
sizeof
(
output
))
==
0
);
assert
(
strcmp
(
output
,
"file.zip"
)
==
0
);
assert
(
fatfs_split_path
(
"C:
\\
folder
\\
file.zip"
,
output
,
sizeof
(
output
),
output2
,
sizeof
(
output2
))
==
0
);
assert
(
strcmp
(
output
,
"C:
\\
folder"
)
==
0
);
assert
(
strcmp
(
output2
,
"file.zip"
)
==
0
);
assert
(
fatfs_split_path
(
"C:
\\
file.zip"
,
output
,
sizeof
(
output
),
output2
,
sizeof
(
output2
))
==
0
);
assert
(
output
[
0
]
==
0
);
assert
(
strcmp
(
output2
,
"file.zip"
)
==
0
);
assert
(
fatfs_split_path
(
"/dev/etc/file.zip"
,
output
,
sizeof
(
output
),
output2
,
sizeof
(
output2
))
==
0
);
assert
(
strcmp
(
output
,
"/dev/etc"
)
==
0
);
assert
(
strcmp
(
output2
,
"file.zip"
)
==
0
);
assert
(
FileString_GetExtension
(
"C:
\\
file.zip"
)
==
strlen
(
"C:
\\
file"
));
assert
(
FileString_GetExtension
(
"C:
\\
file.zip.ext"
)
==
strlen
(
"C:
\\
file.zip"
));
assert
(
FileString_GetExtension
(
"C:
\\
file.zip."
)
==
strlen
(
"C:
\\
file.zip"
));
assert
(
FileString_TrimLength
(
"C:
\\
file.zip"
,
strlen
(
"C:
\\
file.zip"
))
==
strlen
(
"C:
\\
file.zip"
));
assert
(
FileString_TrimLength
(
"C:
\\
file.zip "
,
strlen
(
"C:
\\
file.zip "
))
==
strlen
(
"C:
\\
file.zip"
));
assert
(
FileString_TrimLength
(
" "
,
strlen
(
" "
))
==
0
);
assert
(
fatfs_compare_names
(
"C:
\\
file.ext"
,
"C:
\\
file.ext"
)
==
1
);
assert
(
fatfs_compare_names
(
"C:
\\
file2.ext"
,
"C:
\\
file.ext"
)
==
0
);
assert
(
fatfs_compare_names
(
"C:
\\
file .ext"
,
"C:
\\
file.ext"
)
==
1
);
assert
(
fatfs_compare_names
(
"C:
\\
file .ext"
,
"C:
\\
file2.ext"
)
==
0
);
assert
(
fatfs_string_ends_with_slash
(
"C:
\\
folder"
)
==
0
);
assert
(
fatfs_string_ends_with_slash
(
"C:
\\
folder
\\
"
)
==
1
);
assert
(
fatfs_string_ends_with_slash
(
"/path"
)
==
0
);
assert
(
fatfs_string_ends_with_slash
(
"/path/a"
)
==
0
);
assert
(
fatfs_string_ends_with_slash
(
"/path/"
)
==
1
);
assert
(
fatfs_get_extension
(
"/mypath/file.wav"
,
output
,
4
)
==
1
);
assert
(
strcmp
(
output
,
"wav"
)
==
0
);
assert
(
fatfs_get_extension
(
"/mypath/file.WAV"
,
output
,
4
)
==
1
);
assert
(
strcmp
(
output
,
"wav"
)
==
0
);
assert
(
fatfs_get_extension
(
"/mypath/file.zip"
,
output
,
4
)
==
1
);
assert
(
strcmp
(
output
,
"ext"
)
!=
0
);
assert
(
fatfs_create_path_string
(
"/mydir1"
,
"myfile.txt"
,
output
,
sizeof
(
output
))
==
1
);
assert
(
strcmp
(
output
,
"/mydir1/myfile.txt"
)
==
0
);
assert
(
fatfs_create_path_string
(
"/mydir2/"
,
"myfile2.txt"
,
output
,
sizeof
(
output
))
==
1
);
assert
(
strcmp
(
output
,
"/mydir2/myfile2.txt"
)
==
0
);
assert
(
fatfs_create_path_string
(
"C:
\\
mydir3"
,
"myfile3.txt"
,
output
,
sizeof
(
output
))
==
1
);
assert
(
strcmp
(
output
,
"C:
\\
mydir3
\\
myfile3.txt"
)
==
0
);
}
#endif
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_string.h
0 → 100644
View file @
43e8ec57
#ifndef __FILESTRING_H__
#define __FILESTRING_H__
//-----------------------------------------------------------------------------
// Prototypes
//-----------------------------------------------------------------------------
int
fatfs_total_path_levels
(
char
*
path
);
int
fatfs_get_substring
(
char
*
Path
,
int
levelreq
,
char
*
output
,
int
max_len
);
int
fatfs_split_path
(
char
*
FullPath
,
char
*
Path
,
int
max_path
,
char
*
FileName
,
int
max_filename
);
int
fatfs_compare_names
(
char
*
strA
,
char
*
strB
);
int
fatfs_string_ends_with_slash
(
char
*
path
);
int
fatfs_get_sfn_display_name
(
char
*
out
,
char
*
in
);
int
fatfs_get_extension
(
char
*
filename
,
char
*
out
,
int
maxlen
);
int
fatfs_create_path_string
(
char
*
path
,
char
*
filename
,
char
*
out
,
int
maxlen
);
#ifndef NULL
#define NULL 0
#endif
#endif
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_table.c
0 → 100644
View file @
43e8ec57
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// FAT16/32 File IO Library
// V2.6
// Ultra-Embedded.com
// Copyright 2003 - 2012
//
// Email: admin@ultra-embedded.com
//
// License: GPL
// If you would like a version with a more permissive license for use in
// closed source commercial applications please contact me for details.
//-----------------------------------------------------------------------------
//
// This file is part of FAT File IO Library.
//
// FAT File IO Library is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// FAT File IO Library 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with FAT File IO Library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
#include <string.h>
#include "fat_defs.h"
#include "fat_access.h"
#include "fat_table.h"
#ifndef FAT_BUFFERS
#define FAT_BUFFERS 1
#endif
#ifndef FAT_BUFFER_SECTORS
#define FAT_BUFFER_SECTORS 1
#endif
#if FAT_BUFFERS < 1 || FAT_BUFFER_SECTORS < 1
#error "FAT_BUFFERS & FAT_BUFFER_SECTORS must be at least 1"
#endif
//-----------------------------------------------------------------------------
// FAT Sector Buffer
//-----------------------------------------------------------------------------
#define FAT32_GET_32BIT_WORD(pbuf, location) ( GET_32BIT_WORD(pbuf->ptr, location) )
#define FAT32_SET_32BIT_WORD(pbuf, location, value) { SET_32BIT_WORD(pbuf->ptr, location, value); pbuf->dirty = 1; }
#define FAT16_GET_16BIT_WORD(pbuf, location) ( GET_16BIT_WORD(pbuf->ptr, location) )
#define FAT16_SET_16BIT_WORD(pbuf, location, value) { SET_16BIT_WORD(pbuf->ptr, location, value); pbuf->dirty = 1; }
//-----------------------------------------------------------------------------
// fatfs_fat_init:
//-----------------------------------------------------------------------------
void
fatfs_fat_init
(
struct
fatfs
*
fs
)
{
int
i
;
// FAT buffer chain head
fs
->
fat_buffer_head
=
NULL
;
for
(
i
=
0
;
i
<
FAT_BUFFERS
;
i
++
)
{
// Initialise buffers to invalid
fs
->
fat_buffers
[
i
].
address
=
FAT32_INVALID_CLUSTER
;
fs
->
fat_buffers
[
i
].
dirty
=
0
;
memset
(
fs
->
fat_buffers
[
i
].
sector
,
0x00
,
sizeof
(
fs
->
fat_buffers
[
i
].
sector
));
fs
->
fat_buffers
[
i
].
ptr
=
NULL
;
// Add to head of queue
fs
->
fat_buffers
[
i
].
next
=
fs
->
fat_buffer_head
;
fs
->
fat_buffer_head
=
&
fs
->
fat_buffers
[
i
];
}
}
//-----------------------------------------------------------------------------
// fatfs_fat_writeback: Writeback 'dirty' FAT sectors to disk
//-----------------------------------------------------------------------------
static
int
fatfs_fat_writeback
(
struct
fatfs
*
fs
,
struct
fat_buffer
*
pcur
)
{
if
(
pcur
)
{
// Writeback sector if changed
if
(
pcur
->
dirty
)
{
if
(
fs
->
disk_io
.
write_media
)
{
uint32
sectors
=
FAT_BUFFER_SECTORS
;
uint32
offset
=
pcur
->
address
-
fs
->
fat_begin_lba
;
// Limit to sectors used for the FAT
if
((
offset
+
FAT_BUFFER_SECTORS
)
<=
fs
->
fat_sectors
)
sectors
=
FAT_BUFFER_SECTORS
;
else
sectors
=
fs
->
fat_sectors
-
offset
;
if
(
!
fs
->
disk_io
.
write_media
(
pcur
->
address
,
pcur
->
sector
,
sectors
))
return
0
;
}
pcur
->
dirty
=
0
;
}
return
1
;
}
else
return
0
;
}
//-----------------------------------------------------------------------------
// fatfs_fat_read_sector: Read a FAT sector
//-----------------------------------------------------------------------------
static
struct
fat_buffer
*
fatfs_fat_read_sector
(
struct
fatfs
*
fs
,
uint32
sector
)
{
struct
fat_buffer
*
last
=
NULL
;
struct
fat_buffer
*
pcur
=
fs
->
fat_buffer_head
;
// Itterate through sector buffer list
while
(
pcur
)
{
// Sector within this buffer?
if
((
sector
>=
pcur
->
address
)
&&
(
sector
<
(
pcur
->
address
+
FAT_BUFFER_SECTORS
)))
break
;
// End of list?
if
(
pcur
->
next
==
NULL
)
{
// Remove buffer from list
if
(
last
)
last
->
next
=
NULL
;
// We the first and last buffer in the chain?
else
fs
->
fat_buffer_head
=
NULL
;
}
last
=
pcur
;
pcur
=
pcur
->
next
;
}
// We found the sector already in FAT buffer chain
if
(
pcur
)
{
pcur
->
ptr
=
(
uint8
*
)(
pcur
->
sector
+
((
sector
-
pcur
->
address
)
*
FAT_SECTOR_SIZE
));
return
pcur
;
}
// Else, we removed the last item from the list
pcur
=
last
;
// Add to start of sector buffer list (now newest sector)
pcur
->
next
=
fs
->
fat_buffer_head
;
fs
->
fat_buffer_head
=
pcur
;
// Writeback sector if changed
if
(
pcur
->
dirty
)
if
(
!
fatfs_fat_writeback
(
fs
,
pcur
))
return
0
;
// Address is now new sector
pcur
->
address
=
sector
;
// Read next sector
if
(
!
fs
->
disk_io
.
read_media
(
pcur
->
address
,
pcur
->
sector
,
FAT_BUFFER_SECTORS
))
{
// Read failed, invalidate buffer address
pcur
->
address
=
FAT32_INVALID_CLUSTER
;
return
NULL
;
}
pcur
->
ptr
=
pcur
->
sector
;
return
pcur
;
}
//-----------------------------------------------------------------------------
// fatfs_fat_purge: Purge 'dirty' FAT sectors to disk
//-----------------------------------------------------------------------------
int
fatfs_fat_purge
(
struct
fatfs
*
fs
)
{
struct
fat_buffer
*
pcur
=
fs
->
fat_buffer_head
;
// Itterate through sector buffer list
while
(
pcur
)
{
// Writeback sector if changed
if
(
pcur
->
dirty
)
if
(
!
fatfs_fat_writeback
(
fs
,
pcur
))
return
0
;
pcur
=
pcur
->
next
;
}
return
1
;
}
//-----------------------------------------------------------------------------
// General FAT Table Operations
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// fatfs_find_next_cluster: Return cluster number of next cluster in chain by
// reading FAT table and traversing it. Return 0xffffffff for end of chain.
//-----------------------------------------------------------------------------
uint32
fatfs_find_next_cluster
(
struct
fatfs
*
fs
,
uint32
current_cluster
)
{
uint32
fat_sector_offset
,
position
;
uint32
nextcluster
;
struct
fat_buffer
*
pbuf
;
// Why is '..' labelled with cluster 0 when it should be 2 ??
if
(
current_cluster
==
0
)
current_cluster
=
2
;
// Find which sector of FAT table to read
if
(
fs
->
fat_type
==
FAT_TYPE_16
)
fat_sector_offset
=
current_cluster
/
256
;
else
fat_sector_offset
=
current_cluster
/
128
;
// Read FAT sector into buffer
pbuf
=
fatfs_fat_read_sector
(
fs
,
fs
->
fat_begin_lba
+
fat_sector_offset
);
if
(
!
pbuf
)
return
(
FAT32_LAST_CLUSTER
);
if
(
fs
->
fat_type
==
FAT_TYPE_16
)
{
// Find 32 bit entry of current sector relating to cluster number
position
=
(
current_cluster
-
(
fat_sector_offset
*
256
))
*
2
;
// Read Next Clusters value from Sector Buffer
nextcluster
=
FAT16_GET_16BIT_WORD
(
pbuf
,
(
uint16
)
position
);
// If end of chain found
if
(
nextcluster
>=
0xFFF8
&&
nextcluster
<=
0xFFFF
)
return
(
FAT32_LAST_CLUSTER
);
}
else
{
// Find 32 bit entry of current sector relating to cluster number
position
=
(
current_cluster
-
(
fat_sector_offset
*
128
))
*
4
;
// Read Next Clusters value from Sector Buffer
nextcluster
=
FAT32_GET_32BIT_WORD
(
pbuf
,
(
uint16
)
position
);
// Mask out MS 4 bits (its 28bit addressing)
nextcluster
=
nextcluster
&
0x0FFFFFFF
;
// If end of chain found
if
(
nextcluster
>=
0x0FFFFFF8
&&
nextcluster
<=
0x0FFFFFFF
)
return
(
FAT32_LAST_CLUSTER
);
}
// Else return next cluster
return
(
nextcluster
);
}
//-----------------------------------------------------------------------------
// fatfs_set_fs_info_next_free_cluster: Write the next free cluster to the FSINFO table
//-----------------------------------------------------------------------------
void
fatfs_set_fs_info_next_free_cluster
(
struct
fatfs
*
fs
,
uint32
newValue
)
{
if
(
fs
->
fat_type
==
FAT_TYPE_16
)
;
else
{
// Load sector to change it
struct
fat_buffer
*
pbuf
=
fatfs_fat_read_sector
(
fs
,
fs
->
lba_begin
+
fs
->
fs_info_sector
);
if
(
!
pbuf
)
return
;
// Change
FAT32_SET_32BIT_WORD
(
pbuf
,
492
,
newValue
);
fs
->
next_free_cluster
=
newValue
;
// Write back FSINFO sector to disk
if
(
fs
->
disk_io
.
write_media
)
fs
->
disk_io
.
write_media
(
pbuf
->
address
,
pbuf
->
sector
,
1
);
// Invalidate cache entry
pbuf
->
address
=
FAT32_INVALID_CLUSTER
;
pbuf
->
dirty
=
0
;
}
}
//-----------------------------------------------------------------------------
// fatfs_find_blank_cluster: Find a free cluster entry by reading the FAT
//-----------------------------------------------------------------------------
#if FATFS_INC_WRITE_SUPPORT
int
fatfs_find_blank_cluster
(
struct
fatfs
*
fs
,
uint32
start_cluster
,
uint32
*
free_cluster
)
{
uint32
fat_sector_offset
,
position
;
uint32
nextcluster
;
uint32
current_cluster
=
start_cluster
;
struct
fat_buffer
*
pbuf
;
do
{
// Find which sector of FAT table to read
if
(
fs
->
fat_type
==
FAT_TYPE_16
)
fat_sector_offset
=
current_cluster
/
256
;
else
fat_sector_offset
=
current_cluster
/
128
;
if
(
fat_sector_offset
<
fs
->
fat_sectors
)
{
// Read FAT sector into buffer
pbuf
=
fatfs_fat_read_sector
(
fs
,
fs
->
fat_begin_lba
+
fat_sector_offset
);
if
(
!
pbuf
)
return
0
;
if
(
fs
->
fat_type
==
FAT_TYPE_16
)
{
// Find 32 bit entry of current sector relating to cluster number
position
=
(
current_cluster
-
(
fat_sector_offset
*
256
))
*
2
;
// Read Next Clusters value from Sector Buffer
nextcluster
=
FAT16_GET_16BIT_WORD
(
pbuf
,
(
uint16
)
position
);
}
else
{
// Find 32 bit entry of current sector relating to cluster number
position
=
(
current_cluster
-
(
fat_sector_offset
*
128
))
*
4
;
// Read Next Clusters value from Sector Buffer
nextcluster
=
FAT32_GET_32BIT_WORD
(
pbuf
,
(
uint16
)
position
);
// Mask out MS 4 bits (its 28bit addressing)
nextcluster
=
nextcluster
&
0x0FFFFFFF
;
}
if
(
nextcluster
!=
0
)
current_cluster
++
;
}
else
// Otherwise, run out of FAT sectors to check...
return
0
;
}
while
(
nextcluster
!=
0x0
);
// Found blank entry
*
free_cluster
=
current_cluster
;
return
1
;
}
#endif
//-----------------------------------------------------------------------------
// fatfs_fat_set_cluster: Set a cluster link in the chain. NOTE: Immediate
// write (slow).
//-----------------------------------------------------------------------------
#if FATFS_INC_WRITE_SUPPORT
int
fatfs_fat_set_cluster
(
struct
fatfs
*
fs
,
uint32
cluster
,
uint32
next_cluster
)
{
struct
fat_buffer
*
pbuf
;
uint32
fat_sector_offset
,
position
;
// Find which sector of FAT table to read
if
(
fs
->
fat_type
==
FAT_TYPE_16
)
fat_sector_offset
=
cluster
/
256
;
else
fat_sector_offset
=
cluster
/
128
;
// Read FAT sector into buffer
pbuf
=
fatfs_fat_read_sector
(
fs
,
fs
->
fat_begin_lba
+
fat_sector_offset
);
if
(
!
pbuf
)
return
0
;
if
(
fs
->
fat_type
==
FAT_TYPE_16
)
{
// Find 16 bit entry of current sector relating to cluster number
position
=
(
cluster
-
(
fat_sector_offset
*
256
))
*
2
;
// Write Next Clusters value to Sector Buffer
FAT16_SET_16BIT_WORD
(
pbuf
,
(
uint16
)
position
,
((
uint16
)
next_cluster
));
}
else
{
// Find 32 bit entry of current sector relating to cluster number
position
=
(
cluster
-
(
fat_sector_offset
*
128
))
*
4
;
// Write Next Clusters value to Sector Buffer
FAT32_SET_32BIT_WORD
(
pbuf
,
(
uint16
)
position
,
next_cluster
);
}
return
1
;
}
#endif
//-----------------------------------------------------------------------------
// fatfs_free_cluster_chain: Follow a chain marking each element as free
//-----------------------------------------------------------------------------
#if FATFS_INC_WRITE_SUPPORT
int
fatfs_free_cluster_chain
(
struct
fatfs
*
fs
,
uint32
start_cluster
)
{
uint32
last_cluster
;
uint32
next_cluster
=
start_cluster
;
// Loop until end of chain
while
(
(
next_cluster
!=
FAT32_LAST_CLUSTER
)
&&
(
next_cluster
!=
0x00000000
)
)
{
last_cluster
=
next_cluster
;
// Find next link
next_cluster
=
fatfs_find_next_cluster
(
fs
,
next_cluster
);
// Clear last link
fatfs_fat_set_cluster
(
fs
,
last_cluster
,
0x00000000
);
}
return
1
;
}
#endif
//-----------------------------------------------------------------------------
// fatfs_fat_add_cluster_to_chain: Follow a chain marking and then add a new entry
// to the current tail.
//-----------------------------------------------------------------------------
#if FATFS_INC_WRITE_SUPPORT
int
fatfs_fat_add_cluster_to_chain
(
struct
fatfs
*
fs
,
uint32
start_cluster
,
uint32
newEntry
)
{
uint32
last_cluster
=
FAT32_LAST_CLUSTER
;
uint32
next_cluster
=
start_cluster
;
if
(
start_cluster
==
FAT32_LAST_CLUSTER
)
return
0
;
// Loop until end of chain
while
(
next_cluster
!=
FAT32_LAST_CLUSTER
)
{
last_cluster
=
next_cluster
;
// Find next link
next_cluster
=
fatfs_find_next_cluster
(
fs
,
next_cluster
);
if
(
!
next_cluster
)
return
0
;
}
// Add link in for new cluster
fatfs_fat_set_cluster
(
fs
,
last_cluster
,
newEntry
);
// Mark new cluster as end of chain
fatfs_fat_set_cluster
(
fs
,
newEntry
,
FAT32_LAST_CLUSTER
);
return
1
;
}
#endif
//-----------------------------------------------------------------------------
// fatfs_count_free_clusters:
//-----------------------------------------------------------------------------
uint32
fatfs_count_free_clusters
(
struct
fatfs
*
fs
)
{
uint32
i
,
j
;
uint32
count
=
0
;
struct
fat_buffer
*
pbuf
;
for
(
i
=
0
;
i
<
fs
->
fat_sectors
;
i
++
)
{
// Read FAT sector into buffer
pbuf
=
fatfs_fat_read_sector
(
fs
,
fs
->
fat_begin_lba
+
i
);
if
(
!
pbuf
)
break
;
for
(
j
=
0
;
j
<
FAT_SECTOR_SIZE
;
)
{
if
(
fs
->
fat_type
==
FAT_TYPE_16
)
{
if
(
FAT16_GET_16BIT_WORD
(
pbuf
,
(
uint16
)
j
)
==
0
)
count
++
;
j
+=
2
;
}
else
{
if
(
FAT32_GET_32BIT_WORD
(
pbuf
,
(
uint16
)
j
)
==
0
)
count
++
;
j
+=
4
;
}
}
}
return
count
;
}
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_table.h
0 → 100644
View file @
43e8ec57
#ifndef __FAT_TABLE_H__
#define __FAT_TABLE_H__
#include "fat_opts.h"
#include "fat_misc.h"
//-----------------------------------------------------------------------------
// Prototypes
//-----------------------------------------------------------------------------
void
fatfs_fat_init
(
struct
fatfs
*
fs
);
int
fatfs_fat_purge
(
struct
fatfs
*
fs
);
uint32
fatfs_find_next_cluster
(
struct
fatfs
*
fs
,
uint32
current_cluster
);
void
fatfs_set_fs_info_next_free_cluster
(
struct
fatfs
*
fs
,
uint32
newValue
);
int
fatfs_find_blank_cluster
(
struct
fatfs
*
fs
,
uint32
start_cluster
,
uint32
*
free_cluster
);
int
fatfs_fat_set_cluster
(
struct
fatfs
*
fs
,
uint32
cluster
,
uint32
next_cluster
);
int
fatfs_fat_add_cluster_to_chain
(
struct
fatfs
*
fs
,
uint32
start_cluster
,
uint32
newEntry
);
int
fatfs_free_cluster_chain
(
struct
fatfs
*
fs
,
uint32
start_cluster
);
uint32
fatfs_count_free_clusters
(
struct
fatfs
*
fs
);
#endif
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_types.h
0 → 100644
View file @
43e8ec57
#ifndef __FAT_TYPES_H__
#define __FAT_TYPES_H__
// Detect 64-bit compilation on GCC
#if defined(__GNUC__) && defined(__SIZEOF_LONG__)
#if __SIZEOF_LONG__ == 8
#define FATFS_DEF_UINT32_AS_INT
#endif
#endif
//-------------------------------------------------------------
// System specific types
//-------------------------------------------------------------
#ifndef FATFS_NO_DEF_TYPES
typedef
unsigned
char
uint8
;
typedef
unsigned
short
uint16
;
// If compiling on a 64-bit machine, use int as 32-bits
#ifdef FATFS_DEF_UINT32_AS_INT
typedef
unsigned
int
uint32
;
// Else for 32-bit machines & embedded systems, use long...
#else
typedef
unsigned
long
uint32
;
#endif
#endif
#ifndef NULL
#define NULL 0
#endif
//-------------------------------------------------------------
// Endian Macros
//-------------------------------------------------------------
// FAT is little endian so big endian systems need to swap words
// Little Endian - No swap required
#if FATFS_IS_LITTLE_ENDIAN == 1
#define FAT_HTONS(n) (n)
#define FAT_HTONL(n) (n)
// Big Endian - Swap required
#else
#define FAT_HTONS(n) ((((uint16)((n) & 0xff)) << 8) | (((n) & 0xff00) >> 8))
#define FAT_HTONL(n) (((((uint32)(n) & 0xFF)) << 24) | \
((((uint32)(n) & 0xFF00)) << 8) | \
((((uint32)(n) & 0xFF0000)) >> 8) | \
((((uint32)(n) & 0xFF000000)) >> 24))
#endif
//-------------------------------------------------------------
// Structure Packing Compile Options
//-------------------------------------------------------------
#ifdef __GNUC__
#define STRUCT_PACK
#define STRUCT_PACK_BEGIN
#define STRUCT_PACK_END
#define STRUCT_PACKED __attribute__ ((packed))
#else
// Other compilers may require other methods of packing structures
#define STRUCT_PACK
#define STRUCT_PACK_BEGIN
#define STRUCT_PACK_END
#define STRUCT_PACKED
#endif
#endif
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_write.c
0 → 100644
View file @
43e8ec57
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// FAT16/32 File IO Library
// V2.6
// Ultra-Embedded.com
// Copyright 2003 - 2012
//
// Email: admin@ultra-embedded.com
//
// License: GPL
// If you would like a version with a more permissive license for use in
// closed source commercial applications please contact me for details.
//-----------------------------------------------------------------------------
//
// This file is part of FAT File IO Library.
//
// FAT File IO Library is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// FAT File IO Library 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with FAT File IO Library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
#include <string.h>
#include "fat_defs.h"
#include "fat_access.h"
#include "fat_table.h"
#include "fat_write.h"
#include "fat_string.h"
#include "fat_misc.h"
#if FATFS_INC_WRITE_SUPPORT
//-----------------------------------------------------------------------------
// fatfs_add_free_space: Allocate another cluster of free space to the end
// of a files cluster chain.
//-----------------------------------------------------------------------------
int
fatfs_add_free_space
(
struct
fatfs
*
fs
,
uint32
*
startCluster
,
uint32
clusters
)
{
uint32
i
;
uint32
nextcluster
;
uint32
start
=
*
startCluster
;
// Set the next free cluster hint to unknown
if
(
fs
->
next_free_cluster
!=
FAT32_LAST_CLUSTER
)
fatfs_set_fs_info_next_free_cluster
(
fs
,
FAT32_LAST_CLUSTER
);
for
(
i
=
0
;
i
<
clusters
;
i
++
)
{
// Start looking for free clusters from the beginning
if
(
fatfs_find_blank_cluster
(
fs
,
fs
->
rootdir_first_cluster
,
&
nextcluster
))
{
// Point last to this
fatfs_fat_set_cluster
(
fs
,
start
,
nextcluster
);
// Point this to end of file
fatfs_fat_set_cluster
(
fs
,
nextcluster
,
FAT32_LAST_CLUSTER
);
// Adjust argument reference
start
=
nextcluster
;
if
(
i
==
0
)
*
startCluster
=
nextcluster
;
}
else
return
0
;
}
return
1
;
}
//-----------------------------------------------------------------------------
// fatfs_allocate_free_space: Add an ammount of free space to a file either from
// 'startCluster' if newFile = false, or allocating a new start to the chain if
// newFile = true.
//-----------------------------------------------------------------------------
int
fatfs_allocate_free_space
(
struct
fatfs
*
fs
,
int
newFile
,
uint32
*
startCluster
,
uint32
size
)
{
uint32
clusterSize
;
uint32
clusterCount
;
uint32
nextcluster
;
if
(
size
==
0
)
return
0
;
// Set the next free cluster hint to unknown
if
(
fs
->
next_free_cluster
!=
FAT32_LAST_CLUSTER
)
fatfs_set_fs_info_next_free_cluster
(
fs
,
FAT32_LAST_CLUSTER
);
// Work out size and clusters
clusterSize
=
fs
->
sectors_per_cluster
*
FAT_SECTOR_SIZE
;
clusterCount
=
(
size
/
clusterSize
);
// If any left over
if
(
size
-
(
clusterSize
*
clusterCount
))
clusterCount
++
;
// Allocated first link in the chain if a new file
if
(
newFile
)
{
if
(
!
fatfs_find_blank_cluster
(
fs
,
fs
->
rootdir_first_cluster
,
&
nextcluster
))
return
0
;
// If this is all that is needed then all done
if
(
clusterCount
==
1
)
{
fatfs_fat_set_cluster
(
fs
,
nextcluster
,
FAT32_LAST_CLUSTER
);
*
startCluster
=
nextcluster
;
return
1
;
}
}
// Allocate from end of current chain (startCluster is end of chain)
else
nextcluster
=
*
startCluster
;
if
(
!
fatfs_add_free_space
(
fs
,
&
nextcluster
,
clusterCount
))
return
0
;
return
1
;
}
//-----------------------------------------------------------------------------
// fatfs_find_free_dir_offset: Find a free space in the directory for a new entry
// which takes up 'entryCount' blocks (or allocate some more)
//-----------------------------------------------------------------------------
static
int
fatfs_find_free_dir_offset
(
struct
fatfs
*
fs
,
uint32
dirCluster
,
int
entryCount
,
uint32
*
pSector
,
uint8
*
pOffset
)
{
struct
fat_dir_entry
*
directoryEntry
;
uint8
item
=
0
;
uint16
recordoffset
=
0
;
uint8
i
=
0
;
int
x
=
0
;
int
possible_spaces
=
0
;
int
start_recorded
=
0
;
// No entries required?
if
(
entryCount
==
0
)
return
0
;
// Main cluster following loop
while
(
1
)
{
// Read sector
if
(
fatfs_sector_reader
(
fs
,
dirCluster
,
x
++
,
0
))
{
// Analyse Sector
for
(
item
=
0
;
item
<
FAT_DIR_ENTRIES_PER_SECTOR
;
item
++
)
{
// Create the multiplier for sector access
recordoffset
=
FAT_DIR_ENTRY_SIZE
*
item
;
// Overlay directory entry over buffer
directoryEntry
=
(
struct
fat_dir_entry
*
)(
fs
->
currentsector
.
sector
+
recordoffset
);
// LFN Entry
if
(
fatfs_entry_lfn_text
(
directoryEntry
))
{
// First entry?
if
(
possible_spaces
==
0
)
{
// Store start
*
pSector
=
x
-
1
;
*
pOffset
=
item
;
start_recorded
=
1
;
}
// Increment the count in-case the file turns
// out to be deleted...
possible_spaces
++
;
}
// SFN Entry
else
{
// Has file been deleted?
if
(
fs
->
currentsector
.
sector
[
recordoffset
]
==
FILE_HEADER_DELETED
)
{
// First entry?
if
(
possible_spaces
==
0
)
{
// Store start
*
pSector
=
x
-
1
;
*
pOffset
=
item
;
start_recorded
=
1
;
}
possible_spaces
++
;
// We have found enough space?
if
(
possible_spaces
>=
entryCount
)
return
1
;
// Else continue counting until we find a valid entry!
}
// Is the file entry empty?
else
if
(
fs
->
currentsector
.
sector
[
recordoffset
]
==
FILE_HEADER_BLANK
)
{
// First entry?
if
(
possible_spaces
==
0
)
{
// Store start
*
pSector
=
x
-
1
;
*
pOffset
=
item
;
start_recorded
=
1
;
}
// Increment the blank entries count
possible_spaces
++
;
// We have found enough space?
if
(
possible_spaces
>=
entryCount
)
return
1
;
}
// File entry is valid
else
{
// Reset all flags
possible_spaces
=
0
;
start_recorded
=
0
;
}
}
}
// End of for
}
// End of if
// Run out of free space in the directory, allocate some more
else
{
uint32
newCluster
;
// Get a new cluster for directory
if
(
!
fatfs_find_blank_cluster
(
fs
,
fs
->
rootdir_first_cluster
,
&
newCluster
))
return
0
;
// Add cluster to end of directory tree
if
(
!
fatfs_fat_add_cluster_to_chain
(
fs
,
dirCluster
,
newCluster
))
return
0
;
// Erase new directory cluster
memset
(
fs
->
currentsector
.
sector
,
0x00
,
FAT_SECTOR_SIZE
);
for
(
i
=
0
;
i
<
fs
->
sectors_per_cluster
;
i
++
)
{
if
(
!
fatfs_write_sector
(
fs
,
newCluster
,
i
,
0
))
return
0
;
}
// If non of the name fitted on previous sectors
if
(
!
start_recorded
)
{
// Store start
*
pSector
=
(
x
-
1
);
*
pOffset
=
0
;
start_recorded
=
1
;
}
return
1
;
}
}
// End of while loop
return
0
;
}
//-----------------------------------------------------------------------------
// fatfs_add_file_entry: Add a directory entry to a location found by FindFreeOffset
//-----------------------------------------------------------------------------
int
fatfs_add_file_entry
(
struct
fatfs
*
fs
,
uint32
dirCluster
,
char
*
filename
,
char
*
shortfilename
,
uint32
startCluster
,
uint32
size
,
int
dir
)
{
uint8
item
=
0
;
uint16
recordoffset
=
0
;
uint8
i
=
0
;
uint32
x
=
0
;
int
entryCount
;
struct
fat_dir_entry
shortEntry
;
int
dirtySector
=
0
;
uint32
dirSector
=
0
;
uint8
dirOffset
=
0
;
int
foundEnd
=
0
;
uint8
checksum
;
uint8
*
pSname
;
// No write access?
if
(
!
fs
->
disk_io
.
write_media
)
return
0
;
#if FATFS_INC_LFN_SUPPORT
// How many LFN entries are required?
// NOTE: We always request one LFN even if it would fit in a SFN!
entryCount
=
fatfs_lfn_entries_required
(
filename
);
if
(
!
entryCount
)
return
0
;
#else
entryCount
=
0
;
#endif
// Find space in the directory for this filename (or allocate some more)
// NOTE: We need to find space for at least the LFN + SFN (or just the SFN if LFNs not supported).
if
(
!
fatfs_find_free_dir_offset
(
fs
,
dirCluster
,
entryCount
+
1
,
&
dirSector
,
&
dirOffset
))
return
0
;
// Generate checksum of short filename
pSname
=
(
uint8
*
)
shortfilename
;
checksum
=
0
;
for
(
i
=
11
;
i
!=
0
;
i
--
)
checksum
=
((
checksum
&
1
)
?
0x80
:
0
)
+
(
checksum
>>
1
)
+
*
pSname
++
;
// Start from current sector where space was found!
x
=
dirSector
;
// Main cluster following loop
while
(
1
)
{
// Read sector
if
(
fatfs_sector_reader
(
fs
,
dirCluster
,
x
++
,
0
))
{
// Analyse Sector
for
(
item
=
0
;
item
<
FAT_DIR_ENTRIES_PER_SECTOR
;
item
++
)
{
// Create the multiplier for sector access
recordoffset
=
FAT_DIR_ENTRY_SIZE
*
item
;
// If the start position for the entry has been found
if
(
foundEnd
==
0
)
if
(
(
dirSector
==
(
x
-
1
))
&&
(
dirOffset
==
item
)
)
foundEnd
=
1
;
// Start adding filename
if
(
foundEnd
)
{
if
(
entryCount
==
0
)
{
// Short filename
fatfs_sfn_create_entry
(
shortfilename
,
size
,
startCluster
,
&
shortEntry
,
dir
);
#if FATFS_INC_TIME_DATE_SUPPORT
// Update create, access & modify time & date
fatfs_update_timestamps
(
&
shortEntry
,
1
,
1
,
1
);
#endif
memcpy
(
&
fs
->
currentsector
.
sector
[
recordoffset
],
&
shortEntry
,
sizeof
(
shortEntry
));
// Writeback
return
fs
->
disk_io
.
write_media
(
fs
->
currentsector
.
address
,
fs
->
currentsector
.
sector
,
1
);
}
#if FATFS_INC_LFN_SUPPORT
else
{
entryCount
--
;
// Copy entry to directory buffer
fatfs_filename_to_lfn
(
filename
,
&
fs
->
currentsector
.
sector
[
recordoffset
],
entryCount
,
checksum
);
dirtySector
=
1
;
}
#endif
}
}
// End of if
// Write back to disk before loading another sector
if
(
dirtySector
)
{
if
(
!
fs
->
disk_io
.
write_media
(
fs
->
currentsector
.
address
,
fs
->
currentsector
.
sector
,
1
))
return
0
;
dirtySector
=
0
;
}
}
else
return
0
;
}
// End of while loop
return
0
;
}
#endif
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/fat_write.h
0 → 100644
View file @
43e8ec57
#ifndef __FAT_WRITE_H__
#define __FAT_WRITE_H__
#include "fat_defs.h"
#include "fat_opts.h"
//-----------------------------------------------------------------------------
// Prototypes
//-----------------------------------------------------------------------------
int
fatfs_add_file_entry
(
struct
fatfs
*
fs
,
uint32
dirCluster
,
char
*
filename
,
char
*
shortfilename
,
uint32
startCluster
,
uint32
size
,
int
dir
);
int
fatfs_add_free_space
(
struct
fatfs
*
fs
,
uint32
*
startCluster
,
uint32
clusters
);
int
fatfs_allocate_free_space
(
struct
fatfs
*
fs
,
int
newFile
,
uint32
*
startCluster
,
uint32
size
);
#endif
LinuxGUI/Ventoy2Disk/Lib/fat_io_lib/release/version.txt
0 → 100644
View file @
43e8ec57
2.6.11
LinuxGUI/Ventoy2Disk/Lib/libhttp/buildlib.sh
0 → 100644
View file @
43e8ec57
#!/bin/sh
# https://github.com/lammertb/libhttp/archive/v1.8.tar.gz
# rm -rf include
# rm -rf lib
# mkdir include
# mkdir lib
# rm -rf libhttp-1.8
# tar xf libhttp-1.8.tar.gz
# cd libhttp-1.8
# cp -a include/civetweb.h ../include/
# cd ..
# rm -rf libhttp-1.8
# tar xf libhttp-1.8.tar.gz
# cd libhttp-1.8
# make lib COPT="-DNDEBUG -DNO_CGI -DNO_CACHING -DNO_SSL -DSQLITE_DISABLE_LFS -DSSL_ALREADY_INITIALIZED"
# cp -a libcivetweb.a ../lib/libcivetweb_64.a
# cd ..
# rm -rf libhttp-1.8
# tar xf libhttp-1.8.tar.gz
# cd libhttp-1.8
# make lib COPT="-m32 -DNDEBUG -DNO_CGI -DNO_CACHING -DNO_SSL -DSQLITE_DISABLE_LFS -DSSL_ALREADY_INITIALIZED"
# cp -a libcivetweb.a ../lib/libcivetweb_32.a
# cd ..
# rm -rf libhttp-1.8
# tar xf libhttp-1.8.tar.gz
# cd libhttp-1.8
# make lib CC=aarch64-linux-gnu-gcc COPT="-DNDEBUG -DNO_CGI -DNO_CACHING -DNO_SSL -DSQLITE_DISABLE_LFS -DSSL_ALREADY_INITIALIZED"
# cp -a libcivetweb.a ../lib/libcivetweb_aa64.a
# cd ..
# rm -rf libhttp-1.8
LinuxGUI/Ventoy2Disk/Lib/libhttp/include/civetweb.c
0 → 100644
View file @
43e8ec57
This source diff could not be displayed because it is too large. You can
view the blob
instead.
LinuxGUI/Ventoy2Disk/Lib/libhttp/include/civetweb.h
0 → 100644
View file @
43e8ec57
/* Copyright (c) 2013-2016 the Civetweb developers
* Copyright (c) 2004-2013 Sergey Lyubka
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef CIVETWEB_HEADER_INCLUDED
#define CIVETWEB_HEADER_INCLUDED
#define CIVETWEB_VERSION "1.8"
#ifndef CIVETWEB_API
#if defined(_WIN32)
#if defined(CIVETWEB_DLL_EXPORTS)
#define CIVETWEB_API __declspec(dllexport)
#elif defined(CIVETWEB_DLL_IMPORTS)
#define CIVETWEB_API __declspec(dllimport)
#else
#define CIVETWEB_API
#endif
#elif __GNUC__ >= 4
#define CIVETWEB_API __attribute__((visibility("default")))
#else
#define CIVETWEB_API
#endif
#endif
#include <stdio.h>
#include <stddef.h>
#ifdef __cplusplus
extern
"C"
{
#endif
/* __cplusplus */
struct
mg_context
;
/* Handle for the HTTP service itself */
struct
mg_connection
;
/* Handle for the individual connection */
/* This structure contains information about the HTTP request. */
struct
mg_request_info
{
const
char
*
request_method
;
/* "GET", "POST", etc */
const
char
*
request_uri
;
/* URL-decoded URI (absolute or relative,
* as in the request) */
const
char
*
local_uri
;
/* URL-decoded URI (relative). Can be NULL
* if the request_uri does not address a
* resource at the server host. */
const
char
*
uri
;
/* Deprecated: use local_uri instead */
const
char
*
http_version
;
/* E.g. "1.0", "1.1" */
const
char
*
query_string
;
/* URL part after '?', not including '?', or
NULL */
const
char
*
remote_user
;
/* Authenticated user, or NULL if no auth
used */
char
remote_addr
[
48
];
/* Client's IP address as a string. */
#if defined(MG_LEGACY_INTERFACE)
long
remote_ip
;
/* Client's IP address. Deprecated: use remote_addr instead
*/
#endif
long
long
content_length
;
/* Length (in bytes) of the request body,
can be -1 if no length was given. */
int
remote_port
;
/* Client's port */
int
is_ssl
;
/* 1 if SSL-ed, 0 if not */
void
*
user_data
;
/* User data pointer passed to mg_start() */
void
*
conn_data
;
/* Connection-specific user data */
int
num_headers
;
/* Number of HTTP headers */
struct
mg_header
{
const
char
*
name
;
/* HTTP header name */
const
char
*
value
;
/* HTTP header value */
}
http_headers
[
64
];
/* Maximum 64 headers */
};
/* This structure needs to be passed to mg_start(), to let civetweb know
which callbacks to invoke. For a detailed description, see
https://github.com/civetweb/civetweb/blob/master/docs/UserManual.md */
struct
mg_callbacks
{
/* Called when civetweb has received new HTTP request.
If the callback returns one, it must process the request
by sending valid HTTP headers and a body. Civetweb will not do
any further processing. Otherwise it must return zero.
Note that since V1.7 the "begin_request" function is called
before an authorization check. If an authorization check is
required, use a request_handler instead.
Return value:
0: civetweb will process the request itself. In this case,
the callback must not send any data to the client.
1-999: callback already processed the request. Civetweb will
not send any data after the callback returned. The
return code is stored as a HTTP status code for the
access log. */
int
(
*
begin_request
)(
struct
mg_connection
*
);
/* Called when civetweb has finished processing request. */
void
(
*
end_request
)(
const
struct
mg_connection
*
,
int
reply_status_code
);
/* Called when civetweb is about to log a message. If callback returns
non-zero, civetweb does not log anything. */
int
(
*
log_message
)(
const
struct
mg_connection
*
,
const
char
*
message
);
/* Called when civetweb is about to log access. If callback returns
non-zero, civetweb does not log anything. */
int
(
*
log_access
)(
const
struct
mg_connection
*
,
const
char
*
message
);
/* Called when civetweb initializes SSL library.
Parameters:
user_data: parameter user_data passed when starting the server.
Return value:
0: civetweb will set up the SSL certificate.
1: civetweb assumes the callback already set up the certificate.
-1: initializing ssl fails. */
int
(
*
init_ssl
)(
void
*
ssl_context
,
void
*
user_data
);
#if defined(MG_LEGACY_INTERFACE)
/* Called when websocket request is received, before websocket handshake.
Return value:
0: civetweb proceeds with websocket handshake.
1: connection is closed immediately.
This callback is deprecated: Use mg_set_websocket_handler instead. */
int
(
*
websocket_connect
)(
const
struct
mg_connection
*
);
/* Called when websocket handshake is successfully completed, and
connection is ready for data exchange.
This callback is deprecated: Use mg_set_websocket_handler instead. */
void
(
*
websocket_ready
)(
struct
mg_connection
*
);
/* Called when data frame has been received from the client.
Parameters:
bits: first byte of the websocket frame, see websocket RFC at
http://tools.ietf.org/html/rfc6455, section 5.2
data, data_len: payload, with mask (if any) already applied.
Return value:
1: keep this websocket connection open.
0: close this websocket connection.
This callback is deprecated: Use mg_set_websocket_handler instead. */
int
(
*
websocket_data
)(
struct
mg_connection
*
,
int
bits
,
char
*
data
,
size_t
data_len
);
#endif
/* MG_LEGACY_INTERFACE */
/* Called when civetweb is closing a connection. The per-context mutex is
locked when this is invoked. This is primarily useful for noting when
a websocket is closing and removing it from any application-maintained
list of clients.
Using this callback for websocket connections is deprecated: Use
mg_set_websocket_handler instead. */
void
(
*
connection_close
)(
const
struct
mg_connection
*
);
/* Called when civetweb tries to open a file. Used to intercept file open
calls, and serve file data from memory instead.
Parameters:
path: Full path to the file to open.
data_len: Placeholder for the file size, if file is served from
memory.
Return value:
NULL: do not serve file from memory, proceed with normal file open.
non-NULL: pointer to the file contents in memory. data_len must be
initilized with the size of the memory block. */
const
char
*
(
*
open_file
)(
const
struct
mg_connection
*
,
const
char
*
path
,
size_t
*
data_len
);
/* Called when civetweb is about to serve Lua server page, if
Lua support is enabled.
Parameters:
lua_context: "lua_State *" pointer. */
void
(
*
init_lua
)(
const
struct
mg_connection
*
,
void
*
lua_context
);
#if defined(MG_LEGACY_INTERFACE)
/* Called when civetweb has uploaded a file to a temporary directory as a
result of mg_upload() call.
Note that mg_upload is deprecated. Use mg_handle_form_request instead.
Parameters:
file_name: full path name to the uploaded file. */
void
(
*
upload
)(
struct
mg_connection
*
,
const
char
*
file_name
);
#endif
/* Called when civetweb is about to send HTTP error to the client.
Implementing this callback allows to create custom error pages.
Parameters:
status: HTTP error status code.
Return value:
1: run civetweb error handler.
0: callback already handled the error. */
int
(
*
http_error
)(
struct
mg_connection
*
,
int
status
);
/* Called after civetweb context has been created, before requests
are processed.
Parameters:
ctx: context handle */
void
(
*
init_context
)(
const
struct
mg_context
*
ctx
);
/* Called when a new worker thread is initialized.
Parameters:
ctx: context handle
thread_type:
0 indicates the master thread
1 indicates a worker thread handling client connections
2 indicates an internal helper thread (timer thread)
*/
void
(
*
init_thread
)(
const
struct
mg_context
*
ctx
,
int
thread_type
);
/* Called when civetweb context is deleted.
Parameters:
ctx: context handle */
void
(
*
exit_context
)(
const
struct
mg_context
*
ctx
);
};
/* Start web server.
Parameters:
callbacks: mg_callbacks structure with user-defined callbacks.
options: NULL terminated list of option_name, option_value pairs that
specify Civetweb configuration parameters.
Side-effects: on UNIX, ignores SIGCHLD and SIGPIPE signals. If custom
processing is required for these, signal handlers must be set up
after calling mg_start().
Example:
const char *options[] = {
"document_root", "/var/www",
"listening_ports", "80,443s",
NULL
};
struct mg_context *ctx = mg_start(&my_func, NULL, options);
Refer to https://github.com/civetweb/civetweb/blob/master/docs/UserManual.md
for the list of valid option and their possible values.
Return:
web server context, or NULL on error. */
CIVETWEB_API
struct
mg_context
*
mg_start
(
const
struct
mg_callbacks
*
callbacks
,
void
*
user_data
,
const
char
**
configuration_options
);
/* Stop the web server.
Must be called last, when an application wants to stop the web server and
release all associated resources. This function blocks until all Civetweb
threads are stopped. Context pointer becomes invalid. */
CIVETWEB_API
void
mg_stop
(
struct
mg_context
*
);
/* mg_request_handler
Called when a new request comes in. This callback is URI based
and configured with mg_set_request_handler().
Parameters:
conn: current connection information.
cbdata: the callback data configured with mg_set_request_handler().
Returns:
0: the handler could not handle the request, so fall through.
1 - 999: the handler processed the request. The return code is
stored as a HTTP status code for the access log. */
typedef
int
(
*
mg_request_handler
)(
struct
mg_connection
*
conn
,
void
*
cbdata
);
/* mg_set_request_handler
Sets or removes a URI mapping for a request handler.
This function uses mg_lock_context internally.
URI's are ordered and prefixed URI's are supported. For example,
consider two URIs: /a/b and /a
/a matches /a
/a/b matches /a/b
/a/c matches /a
Parameters:
ctx: server context
uri: the URI (exact or pattern) for the handler
handler: the callback handler to use when the URI is requested.
If NULL, an already registered handler for this URI will be
removed.
The URI used to remove a handler must match exactly the one used
to
register it (not only a pattern match).
cbdata: the callback data to give to the handler when it is called. */
CIVETWEB_API
void
mg_set_request_handler
(
struct
mg_context
*
ctx
,
const
char
*
uri
,
mg_request_handler
handler
,
void
*
cbdata
);
/* Callback types for websocket handlers in C/C++.
mg_websocket_connect_handler
Is called when the client intends to establish a websocket connection,
before websocket handshake.
Return value:
0: civetweb proceeds with websocket handshake.
1: connection is closed immediately.
mg_websocket_ready_handler
Is called when websocket handshake is successfully completed, and
connection is ready for data exchange.
mg_websocket_data_handler
Is called when a data frame has been received from the client.
Parameters:
bits: first byte of the websocket frame, see websocket RFC at
http://tools.ietf.org/html/rfc6455, section 5.2
data, data_len: payload, with mask (if any) already applied.
Return value:
1: keep this websocket connection open.
0: close this websocket connection.
mg_connection_close_handler
Is called, when the connection is closed.*/
typedef
int
(
*
mg_websocket_connect_handler
)(
const
struct
mg_connection
*
,
void
*
);
typedef
void
(
*
mg_websocket_ready_handler
)(
struct
mg_connection
*
,
void
*
);
typedef
int
(
*
mg_websocket_data_handler
)(
struct
mg_connection
*
,
int
,
char
*
,
size_t
,
void
*
);
typedef
void
(
*
mg_websocket_close_handler
)(
const
struct
mg_connection
*
,
void
*
);
/* mg_set_websocket_handler
Set or remove handler functions for websocket connections.
This function works similar to mg_set_request_handler - see there. */
CIVETWEB_API
void
mg_set_websocket_handler
(
struct
mg_context
*
ctx
,
const
char
*
uri
,
mg_websocket_connect_handler
connect_handler
,
mg_websocket_ready_handler
ready_handler
,
mg_websocket_data_handler
data_handler
,
mg_websocket_close_handler
close_handler
,
void
*
cbdata
);
/* mg_authorization_handler
Some description here
Parameters:
conn: current connection information.
cbdata: the callback data configured with mg_set_request_handler().
Returns:
0: access denied
1: access granted
*/
typedef
int
(
*
mg_authorization_handler
)(
struct
mg_connection
*
conn
,
void
*
cbdata
);
/* mg_set_auth_handler
Sets or removes a URI mapping for an authorization handler.
This function works similar to mg_set_request_handler - see there. */
CIVETWEB_API
void
mg_set_auth_handler
(
struct
mg_context
*
ctx
,
const
char
*
uri
,
mg_authorization_handler
handler
,
void
*
cbdata
);
/* Get the value of particular configuration parameter.
The value returned is read-only. Civetweb does not allow changing
configuration at run time.
If given parameter name is not valid, NULL is returned. For valid
names, return value is guaranteed to be non-NULL. If parameter is not
set, zero-length string is returned. */
CIVETWEB_API
const
char
*
mg_get_option
(
const
struct
mg_context
*
ctx
,
const
char
*
name
);
/* Get context from connection. */
CIVETWEB_API
struct
mg_context
*
mg_get_context
(
const
struct
mg_connection
*
conn
);
/* Get user data passed to mg_start from context. */
CIVETWEB_API
void
*
mg_get_user_data
(
const
struct
mg_context
*
ctx
);
/* Set user data for the current connection. */
CIVETWEB_API
void
mg_set_user_connection_data
(
struct
mg_connection
*
conn
,
void
*
data
);
/* Get user data set for the current connection. */
CIVETWEB_API
void
*
mg_get_user_connection_data
(
const
struct
mg_connection
*
conn
);
#if defined(MG_LEGACY_INTERFACE)
/* Return array of strings that represent valid configuration options.
For each option, option name and default value is returned, i.e. the
number of entries in the array equals to number_of_options x 2.
Array is NULL terminated. */
/* Deprecated: Use mg_get_valid_options instead. */
CIVETWEB_API
const
char
**
mg_get_valid_option_names
(
void
);
#endif
struct
mg_option
{
const
char
*
name
;
int
type
;
const
char
*
default_value
;
};
enum
{
CONFIG_TYPE_UNKNOWN
=
0x0
,
CONFIG_TYPE_NUMBER
=
0x1
,
CONFIG_TYPE_STRING
=
0x2
,
CONFIG_TYPE_FILE
=
0x3
,
CONFIG_TYPE_DIRECTORY
=
0x4
,
CONFIG_TYPE_BOOLEAN
=
0x5
,
CONFIG_TYPE_EXT_PATTERN
=
0x6
};
/* Return array of struct mg_option, representing all valid configuration
options of civetweb.c.
The array is terminated by a NULL name option. */
CIVETWEB_API
const
struct
mg_option
*
mg_get_valid_options
(
void
);
struct
mg_server_ports
{
int
protocol
;
/* 1 = IPv4, 2 = IPv6, 3 = both */
int
port
;
/* port number */
int
is_ssl
;
/* https port: 0 = no, 1 = yes */
int
is_redirect
;
/* redirect all requests: 0 = no, 1 = yes */
int
_reserved1
;
int
_reserved2
;
int
_reserved3
;
int
_reserved4
;
};
/* Get the list of ports that civetweb is listening on.
The parameter size is the size of the ports array in elements.
The caller is responsibility to allocate the required memory.
This function returns the number of struct mg_server_ports elements
filled in, or <0 in case of an error. */
CIVETWEB_API
int
mg_get_server_ports
(
const
struct
mg_context
*
ctx
,
int
size
,
struct
mg_server_ports
*
ports
);
/* Deprecated: Use mg_get_server_ports instead. */
CIVETWEB_API
size_t
mg_get_ports
(
const
struct
mg_context
*
ctx
,
size_t
size
,
int
*
ports
,
int
*
ssl
);
/* Add, edit or delete the entry in the passwords file.
This function allows an application to manipulate .htpasswd files on the
fly by adding, deleting and changing user records. This is one of the
several ways of implementing authentication on the server side. For another,
cookie-based way please refer to the examples/chat in the source tree.
If password is not NULL, entry is added (or modified if already exists).
If password is NULL, entry is deleted.
Return:
1 on success, 0 on error. */
CIVETWEB_API
int
mg_modify_passwords_file
(
const
char
*
passwords_file_name
,
const
char
*
domain
,
const
char
*
user
,
const
char
*
password
);
/* Return information associated with the request. */
CIVETWEB_API
const
struct
mg_request_info
*
mg_get_request_info
(
const
struct
mg_connection
*
);
/* Send data to the client.
Return:
0 when the connection has been closed
-1 on error
>0 number of bytes written on success */
CIVETWEB_API
int
mg_write
(
struct
mg_connection
*
,
const
void
*
buf
,
size_t
len
);
/* Send data to a websocket client wrapped in a websocket frame. Uses
mg_lock_connection to ensure that the transmission is not interrupted,
i.e., when the application is proactively communicating and responding to
a request simultaneously.
Send data to a websocket client wrapped in a websocket frame.
This function is available when civetweb is compiled with -DUSE_WEBSOCKET
Return:
0 when the connection has been closed
-1 on error
>0 number of bytes written on success */
CIVETWEB_API
int
mg_websocket_write
(
struct
mg_connection
*
conn
,
int
opcode
,
const
char
*
data
,
size_t
data_len
);
/* Send data to a websocket server wrapped in a masked websocket frame. Uses
mg_lock_connection to ensure that the transmission is not interrupted,
i.e., when the application is proactively communicating and responding to
a request simultaneously.
Send data to a websocket server wrapped in a masked websocket frame.
This function is available when civetweb is compiled with -DUSE_WEBSOCKET
Return:
0 when the connection has been closed
-1 on error
>0 number of bytes written on success */
CIVETWEB_API
int
mg_websocket_client_write
(
struct
mg_connection
*
conn
,
int
opcode
,
const
char
*
data
,
size_t
data_len
);
/* Blocks until unique access is obtained to this connection. Intended for use
with websockets only.
Invoke this before mg_write or mg_printf when communicating with a
websocket if your code has server-initiated communication as well as
communication in direct response to a message. */
CIVETWEB_API
void
mg_lock_connection
(
struct
mg_connection
*
conn
);
CIVETWEB_API
void
mg_unlock_connection
(
struct
mg_connection
*
conn
);
#if defined(MG_LEGACY_INTERFACE)
#define mg_lock mg_lock_connection
#define mg_unlock mg_unlock_connection
#endif
/* Lock server context. This lock may be used to protect resources
that are shared between different connection/worker threads. */
CIVETWEB_API
void
mg_lock_context
(
struct
mg_context
*
ctx
);
CIVETWEB_API
void
mg_unlock_context
(
struct
mg_context
*
ctx
);
/* Opcodes, from http://tools.ietf.org/html/rfc6455 */
enum
{
WEBSOCKET_OPCODE_CONTINUATION
=
0x0
,
WEBSOCKET_OPCODE_TEXT
=
0x1
,
WEBSOCKET_OPCODE_BINARY
=
0x2
,
WEBSOCKET_OPCODE_CONNECTION_CLOSE
=
0x8
,
WEBSOCKET_OPCODE_PING
=
0x9
,
WEBSOCKET_OPCODE_PONG
=
0xa
};
/* Macros for enabling compiler-specific checks for printf-like arguments. */
#undef PRINTF_FORMAT_STRING
#if defined(_MSC_VER) && _MSC_VER >= 1400
#include <sal.h>
#if defined(_MSC_VER) && _MSC_VER > 1400
#define PRINTF_FORMAT_STRING(s) _Printf_format_string_ s
#else
#define PRINTF_FORMAT_STRING(s) __format_string s
#endif
#else
#define PRINTF_FORMAT_STRING(s) s
#endif
#ifdef __GNUC__
#define PRINTF_ARGS(x, y) __attribute__((format(printf, x, y)))
#else
#define PRINTF_ARGS(x, y)
#endif
/* Send data to the client using printf() semantics.
Works exactly like mg_write(), but allows to do message formatting. */
CIVETWEB_API
int
mg_printf
(
struct
mg_connection
*
,
PRINTF_FORMAT_STRING
(
const
char
*
fmt
),
...)
PRINTF_ARGS
(
2
,
3
);
/* Send contents of the entire file together with HTTP headers. */
CIVETWEB_API
void
mg_send_file
(
struct
mg_connection
*
conn
,
const
char
*
path
);
/* Send contents of the entire file together with HTTP headers.
Parameters:
conn: Current connection information.
path: Full path to the file to send.
mime_type: Content-Type for file. NULL will cause the type to be
looked up by the file extension.
*/
CIVETWEB_API
void
mg_send_mime_file
(
struct
mg_connection
*
conn
,
const
char
*
path
,
const
char
*
mime_type
);
/* Store body data into a file. */
CIVETWEB_API
long
long
mg_store_body
(
struct
mg_connection
*
conn
,
const
char
*
path
);
/* Read entire request body and stor it in a file "path".
Return:
< 0 Error
>= 0 Number of bytes stored in file "path".
*/
/* Read data from the remote end, return number of bytes read.
Return:
0 connection has been closed by peer. No more data could be read.
< 0 read error. No more data could be read from the connection.
> 0 number of bytes read into the buffer. */
CIVETWEB_API
int
mg_read
(
struct
mg_connection
*
,
void
*
buf
,
size_t
len
);
/* Get the value of particular HTTP header.
This is a helper function. It traverses request_info->http_headers array,
and if the header is present in the array, returns its value. If it is
not present, NULL is returned. */
CIVETWEB_API
const
char
*
mg_get_header
(
const
struct
mg_connection
*
,
const
char
*
name
);
/* Get a value of particular form variable.
Parameters:
data: pointer to form-uri-encoded buffer. This could be either POST data,
or request_info.query_string.
data_len: length of the encoded data.
var_name: variable name to decode from the buffer
dst: destination buffer for the decoded variable
dst_len: length of the destination buffer
Return:
On success, length of the decoded variable.
On error:
-1 (variable not found).
-2 (destination buffer is NULL, zero length or too small to hold the
decoded variable).
Destination buffer is guaranteed to be '\0' - terminated if it is not
NULL or zero length. */
CIVETWEB_API
int
mg_get_var
(
const
char
*
data
,
size_t
data_len
,
const
char
*
var_name
,
char
*
dst
,
size_t
dst_len
);
/* Get a value of particular form variable.
Parameters:
data: pointer to form-uri-encoded buffer. This could be either POST data,
or request_info.query_string.
data_len: length of the encoded data.
var_name: variable name to decode from the buffer
dst: destination buffer for the decoded variable
dst_len: length of the destination buffer
occurrence: which occurrence of the variable, 0 is the first, 1 the
second...
this makes it possible to parse a query like
b=x&a=y&a=z which will have occurrence values b:0, a:0 and a:1
Return:
On success, length of the decoded variable.
On error:
-1 (variable not found).
-2 (destination buffer is NULL, zero length or too small to hold the
decoded variable).
Destination buffer is guaranteed to be '\0' - terminated if it is not
NULL or zero length. */
CIVETWEB_API
int
mg_get_var2
(
const
char
*
data
,
size_t
data_len
,
const
char
*
var_name
,
char
*
dst
,
size_t
dst_len
,
size_t
occurrence
);
/* Fetch value of certain cookie variable into the destination buffer.
Destination buffer is guaranteed to be '\0' - terminated. In case of
failure, dst[0] == '\0'. Note that RFC allows many occurrences of the same
parameter. This function returns only first occurrence.
Return:
On success, value length.
On error:
-1 (either "Cookie:" header is not present at all or the requested
parameter is not found).
-2 (destination buffer is NULL, zero length or too small to hold the
value). */
CIVETWEB_API
int
mg_get_cookie
(
const
char
*
cookie
,
const
char
*
var_name
,
char
*
buf
,
size_t
buf_len
);
/* Download data from the remote web server.
host: host name to connect to, e.g. "foo.com", or "10.12.40.1".
port: port number, e.g. 80.
use_ssl: wether to use SSL connection.
error_buffer, error_buffer_size: error message placeholder.
request_fmt,...: HTTP request.
Return:
On success, valid pointer to the new connection, suitable for mg_read().
On error, NULL. error_buffer contains error message.
Example:
char ebuf[100];
struct mg_connection *conn;
conn = mg_download("google.com", 80, 0, ebuf, sizeof(ebuf),
"%s", "GET / HTTP/1.0\r\nHost: google.com\r\n\r\n");
*/
CIVETWEB_API
struct
mg_connection
*
mg_download
(
const
char
*
host
,
int
port
,
int
use_ssl
,
char
*
error_buffer
,
size_t
error_buffer_size
,
PRINTF_FORMAT_STRING
(
const
char
*
request_fmt
),
...)
PRINTF_ARGS
(
6
,
7
);
/* Close the connection opened by mg_download(). */
CIVETWEB_API
void
mg_close_connection
(
struct
mg_connection
*
conn
);
#if defined(MG_LEGACY_INTERFACE)
/* File upload functionality. Each uploaded file gets saved into a temporary
file and MG_UPLOAD event is sent.
Return number of uploaded files.
Deprecated: Use mg_handle_form_request instead. */
CIVETWEB_API
int
mg_upload
(
struct
mg_connection
*
conn
,
const
char
*
destination_dir
);
#endif
/* This structure contains callback functions for handling form fields.
It is used as an argument to mg_handle_form_request. */
struct
mg_form_data_handler
{
/* This callback function is called, if a new field has been found.
* The return value of this callback is used to define how the field
* should be processed.
*
* Parameters:
* key: Name of the field ("name" property of the HTML input field).
* filename: Name of a file to upload, at the client computer.
* Only set for input fields of type "file", otherwise NULL.
* path: Output parameter: File name (incl. path) to store the file
* at the server computer. Only used if FORM_FIELD_STORAGE_STORE
* is returned by this callback. Existing files will be
* overwritten.
* pathlen: Length of the buffer for path.
* user_data: Value of the member user_data of mg_form_data_handler
*
* Return value:
* The callback must return the intended storage for this field
* (See FORM_FIELD_STORAGE_*).
*/
int
(
*
field_found
)(
const
char
*
key
,
const
char
*
filename
,
char
*
path
,
size_t
pathlen
,
void
*
user_data
);
/* If the "field_found" callback returned FORM_FIELD_STORAGE_GET,
* this callback will receive the field data.
*
* Parameters:
* key: Name of the field ("name" property of the HTML input field).
* value: Value of the input field.
* user_data: Value of the member user_data of mg_form_data_handler
*
* Return value:
* TODO: Needs to be defined.
*/
int
(
*
field_get
)(
const
char
*
key
,
const
char
*
value
,
size_t
valuelen
,
void
*
user_data
);
/* If the "field_found" callback returned FORM_FIELD_STORAGE_STORE,
* the data will be stored into a file. If the file has been written
* successfully, this callback will be called. This callback will
* not be called for only partially uploaded files. The
* mg_handle_form_request function will either store the file completely
* and call this callback, or it will remove any partial content and
* not call this callback function.
*
* Parameters:
* path: Path of the file stored at the server.
* file_size: Size of the stored file in bytes.
* user_data: Value of the member user_data of mg_form_data_handler
*
* Return value:
* TODO: Needs to be defined.
*/
int
(
*
field_store
)(
const
char
*
path
,
long
long
file_size
,
void
*
user_data
);
/* User supplied argument, passed to all callback functions. */
void
*
user_data
;
};
/* Return values definition for the "field_found" callback in
* mg_form_data_handler. */
enum
{
/* Skip this field (neither get nor store it). Continue with the
* next field. */
FORM_FIELD_STORAGE_SKIP
=
0x0
,
/* Get the field value. */
FORM_FIELD_STORAGE_GET
=
0x1
,
/* Store the field value into a file. */
FORM_FIELD_STORAGE_STORE
=
0x2
,
/* Stop parsing this request. Skip the remaining fields. */
FORM_FIELD_STORAGE_ABORT
=
0x10
};
/* Process form data.
* Returns the number of fields handled, or < 0 in case of an error.
* Note: It is possible that several fields are already handled successfully
* (e.g., stored into files), before the request handling is stopped with an
* error. In this case a number < 0 is returned as well.
* In any case, it is the duty of the caller to remove files once they are
* no longer required. */
CIVETWEB_API
int
mg_handle_form_request
(
struct
mg_connection
*
conn
,
struct
mg_form_data_handler
*
fdh
);
/* Convenience function -- create detached thread.
Return: 0 on success, non-0 on error. */
typedef
void
*
(
*
mg_thread_func_t
)(
void
*
);
CIVETWEB_API
int
mg_start_thread
(
mg_thread_func_t
f
,
void
*
p
);
/* Return builtin mime type for the given file name.
For unrecognized extensions, "text/plain" is returned. */
CIVETWEB_API
const
char
*
mg_get_builtin_mime_type
(
const
char
*
file_name
);
/* Get text representation of HTTP status code. */
CIVETWEB_API
const
char
*
mg_get_response_code_text
(
struct
mg_connection
*
conn
,
int
response_code
);
/* Return CivetWeb version. */
CIVETWEB_API
const
char
*
mg_version
(
void
);
/* URL-decode input buffer into destination buffer.
0-terminate the destination buffer.
form-url-encoded data differs from URI encoding in a way that it
uses '+' as character for space, see RFC 1866 section 8.2.1
http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt
Return: length of the decoded data, or -1 if dst buffer is too small. */
CIVETWEB_API
int
mg_url_decode
(
const
char
*
src
,
int
src_len
,
char
*
dst
,
int
dst_len
,
int
is_form_url_encoded
);
/* URL-encode input buffer into destination buffer.
returns the length of the resulting buffer or -1
is the buffer is too small. */
CIVETWEB_API
int
mg_url_encode
(
const
char
*
src
,
char
*
dst
,
size_t
dst_len
);
/* MD5 hash given strings.
Buffer 'buf' must be 33 bytes long. Varargs is a NULL terminated list of
ASCIIz strings. When function returns, buf will contain human-readable
MD5 hash. Example:
char buf[33];
mg_md5(buf, "aa", "bb", NULL); */
CIVETWEB_API
char
*
mg_md5
(
char
buf
[
33
],
...);
/* Print error message to the opened error log stream.
This utilizes the provided logging configuration.
conn: connection
fmt: format string without the line return
...: variable argument list
Example:
mg_cry(conn,"i like %s", "logging"); */
CIVETWEB_API
void
mg_cry
(
const
struct
mg_connection
*
conn
,
PRINTF_FORMAT_STRING
(
const
char
*
fmt
),
...)
PRINTF_ARGS
(
2
,
3
);
/* utility methods to compare two buffers, case incensitive. */
CIVETWEB_API
int
mg_strcasecmp
(
const
char
*
s1
,
const
char
*
s2
);
CIVETWEB_API
int
mg_strncasecmp
(
const
char
*
s1
,
const
char
*
s2
,
size_t
len
);
/* Connect to a websocket as a client
Parameters:
host: host to connect to, i.e. "echo.websocket.org" or "192.168.1.1" or
"localhost"
port: server port
use_ssl: make a secure connection to server
error_buffer, error_buffer_size: buffer for an error message
path: server path you are trying to connect to, i.e. if connection to
localhost/app, path should be "/app"
origin: value of the Origin HTTP header
data_func: callback that should be used when data is received from the
server
user_data: user supplied argument
Return:
On success, valid mg_connection object.
On error, NULL. Se error_buffer for details.
*/
CIVETWEB_API
struct
mg_connection
*
mg_connect_websocket_client
(
const
char
*
host
,
int
port
,
int
use_ssl
,
char
*
error_buffer
,
size_t
error_buffer_size
,
const
char
*
path
,
const
char
*
origin
,
mg_websocket_data_handler
data_func
,
mg_websocket_close_handler
close_func
,
void
*
user_data
);
/* Connect to a TCP server as a client (can be used to connect to a HTTP server)
Parameters:
host: host to connect to, i.e. "www.wikipedia.org" or "192.168.1.1" or
"localhost"
port: server port
use_ssl: make a secure connection to server
error_buffer, error_buffer_size: buffer for an error message
Return:
On success, valid mg_connection object.
On error, NULL. Se error_buffer for details.
*/
CIVETWEB_API
struct
mg_connection
*
mg_connect_client
(
const
char
*
host
,
int
port
,
int
use_ssl
,
char
*
error_buffer
,
size_t
error_buffer_size
);
struct
mg_client_options
{
const
char
*
host
;
int
port
;
const
char
*
client_cert
;
const
char
*
server_cert
;
/* TODO: add more data */
};
CIVETWEB_API
struct
mg_connection
*
mg_connect_client_secure
(
const
struct
mg_client_options
*
client_options
,
char
*
error_buffer
,
size_t
error_buffer_size
);
enum
{
TIMEOUT_INFINITE
=
-
1
};
/* Wait for a response from the server
Parameters:
conn: connection
ebuf, ebuf_len: error message placeholder.
timeout: time to wait for a response in milliseconds (if < 0 then wait
forever)
Return:
On success, >= 0
On error/timeout, < 0
*/
CIVETWEB_API
int
mg_get_response
(
struct
mg_connection
*
conn
,
char
*
ebuf
,
size_t
ebuf_len
,
int
timeout
);
/* Check which features where set when civetweb has been compiled.
Parameters:
feature: specifies which feature should be checked
1 serve files (NO_FILES not set)
2 support HTTPS (NO_SSL not set)
4 support CGI (NO_CGI not set)
8 support IPv6 (USE_IPV6 set)
16 support WebSocket (USE_WEBSOCKET set)
32 support Lua scripts and Lua server pages (USE_LUA is set)
64 support server side JavaScript (USE_DUKTAPE is set)
128 support caching (NO_CACHING not set)
The result is undefined for all other feature values.
Return:
If feature is available > 0
If feature is not available = 0
*/
CIVETWEB_API
unsigned
mg_check_feature
(
unsigned
feature
);
#ifdef __cplusplus
}
#endif
/* __cplusplus */
#endif
/* CIVETWEB_HEADER_INCLUDED */
LinuxGUI/Ventoy2Disk/Lib/libhttp/include/handle_form.inl
0 → 100644
View file @
43e8ec57
/* Copyright (c) 2016 the Civetweb developers
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
static int
url_encoded_field_found(const struct mg_connection *conn,
const char *key,
size_t key_len,
const char *filename,
size_t filename_len,
char *path,
size_t path_len,
struct mg_form_data_handler *fdh)
{
char key_dec[1024];
char filename_dec[1024];
int key_dec_len;
int filename_dec_len;
int ret;
key_dec_len =
mg_url_decode(key, (int)key_len, key_dec, (int)sizeof(key_dec), 1);
if (((size_t)key_dec_len >= (size_t)sizeof(key_dec)) || (key_dec_len < 0)) {
return FORM_FIELD_STORAGE_SKIP;
}
if (filename) {
filename_dec_len = mg_url_decode(filename,
(int)filename_len,
filename_dec,
(int)sizeof(filename_dec),
1);
if (((size_t)filename_dec_len >= (size_t)sizeof(filename_dec))
|| (filename_dec_len < 0)) {
/* Log error message and skip this field. */
mg_cry(conn, "%s: Cannot decode filename", __func__);
return FORM_FIELD_STORAGE_SKIP;
}
} else {
filename_dec[0] = 0;
}
ret =
fdh->field_found(key_dec, filename_dec, path, path_len, fdh->user_data);
if ((ret & 0xF) == FORM_FIELD_STORAGE_GET) {
if (fdh->field_get == NULL) {
mg_cry(conn, "%s: Function \"Get\" not available", __func__);
return FORM_FIELD_STORAGE_SKIP;
}
}
if ((ret & 0xF) == FORM_FIELD_STORAGE_STORE) {
if (fdh->field_store == NULL) {
mg_cry(conn, "%s: Function \"Store\" not available", __func__);
return FORM_FIELD_STORAGE_SKIP;
}
}
return ret;
}
static int
url_encoded_field_get(const struct mg_connection *conn,
const char *key,
size_t key_len,
const char *value,
size_t value_len,
struct mg_form_data_handler *fdh)
{
char key_dec[1024];
char *value_dec = mg_malloc(value_len + 1);
int value_dec_len;
if (!value_dec) {
/* Log error message and stop parsing the form data. */
mg_cry(conn,
"%s: Not enough memory (required: %lu)",
__func__,
(unsigned long)(value_len + 1));
return FORM_FIELD_STORAGE_ABORT;
}
mg_url_decode(key, (int)key_len, key_dec, (int)sizeof(key_dec), 1);
value_dec_len =
mg_url_decode(value, (int)value_len, value_dec, (int)value_len + 1, 1);
return fdh->field_get(key_dec,
value_dec,
(size_t)value_dec_len,
fdh->user_data);
}
static int
field_stored(const struct mg_connection *conn,
const char *path,
long long file_size,
struct mg_form_data_handler *fdh)
{
/* Equivalent to "upload" callback of "mg_upload". */
(void)conn; /* we do not need mg_cry here, so conn is currently unused */
return fdh->field_store(path, file_size, fdh->user_data);
}
static const char *
search_boundary(const char *buf,
size_t buf_len,
const char *boundary,
size_t boundary_len)
{
/* We must do a binary search here, not a string search, since the buffer
* may contain '\x00' bytes, if binary data is transferred. */
int clen = (int)buf_len - (int)boundary_len - 4;
int i;
for (i = 0; i <= clen; i++) {
if (!memcmp(buf + i, "\r\n--", 4)) {
if (!memcmp(buf + i + 4, boundary, boundary_len)) {
return buf + i;
}
}
}
return NULL;
}
int
mg_handle_form_request(struct mg_connection *conn,
struct mg_form_data_handler *fdh)
{
const char *content_type;
char path[512];
char buf[1024];
int field_storage;
int buf_fill = 0;
int r;
int field_count = 0;
struct file fstore = STRUCT_FILE_INITIALIZER;
int64_t file_size = 0; /* init here, to a avoid a false positive
"uninitialized variable used" warning */
int has_body_data =
(conn->request_info.content_length > 0) || (conn->is_chunked);
/* There are three ways to encode data from a HTML form:
* 1) method: GET (default)
* The form data is in the HTTP query string.
* 2) method: POST, enctype: "application/x-www-form-urlencoded"
* The form data is in the request body.
* The body is url encoded (the default encoding for POST).
* 3) method: POST, enctype: "multipart/form-data".
* The form data is in the request body of a multipart message.
* This is the typical way to handle file upload from a form.
*/
if (!has_body_data) {
const char *data;
if (strcmp(conn->request_info.request_method, "GET")) {
/* No body data, but not a GET request.
* This is not a valid form request. */
return -1;
}
/* GET request: form data is in the query string. */
/* The entire data has already been loaded, so there is no nead to
* call mg_read. We just need to split the query string into key-value
* pairs. */
data = conn->request_info.query_string;
if (!data) {
/* No query string. */
return -1;
}
/* Split data in a=1&b=xy&c=3&c=4 ... */
while (*data) {
const char *val = strchr(data, '=');
const char *next;
ptrdiff_t keylen, vallen;
if (!val) {
break;
}
keylen = val - data;
/* In every "field_found" callback we ask what to do with the
* data ("field_storage"). This could be:
* FORM_FIELD_STORAGE_SKIP (0) ... ignore the value of this field
* FORM_FIELD_STORAGE_GET (1) ... read the data and call the get
* callback function
* FORM_FIELD_STORAGE_STORE (2) ... store the data in a file
* FORM_FIELD_STORAGE_READ (3) ... let the user read the data
* (for parsing long data on the fly)
* (currently not implemented)
* FORM_FIELD_STORAGE_ABORT (flag) ... stop parsing
*/
memset(path, 0, sizeof(path));
field_count++;
field_storage = url_encoded_field_found(conn,
data,
(size_t)keylen,
NULL,
0,
path,
sizeof(path) - 1,
fdh);
val++;
next = strchr(val, '&');
if (next) {
vallen = next - val;
next++;
} else {
vallen = (ptrdiff_t)strlen(val);
next = val + vallen;
}
if (field_storage == FORM_FIELD_STORAGE_GET) {
/* Call callback */
url_encoded_field_get(
conn, data, (size_t)keylen, val, (size_t)vallen, fdh);
}
if (field_storage == FORM_FIELD_STORAGE_STORE) {
/* Store the content to a file */
if (mg_fopen(conn, path, "wb", &fstore) == 0) {
fstore.fp = NULL;
}
file_size = 0;
if (fstore.fp != NULL) {
size_t n =
(size_t)fwrite(val, 1, (size_t)vallen, fstore.fp);
if ((n != (size_t)vallen) || (ferror(fstore.fp))) {
mg_cry(conn,
"%s: Cannot write file %s",
__func__,
path);
fclose(fstore.fp);
fstore.fp = NULL;
remove_bad_file(conn, path);
}
file_size += (int64_t)n;
if (fstore.fp) {
r = fclose(fstore.fp);
if (r == 0) {
/* stored successfully */
field_stored(conn, path, file_size, fdh);
} else {
mg_cry(conn,
"%s: Error saving file %s",
__func__,
path);
remove_bad_file(conn, path);
}
fstore.fp = NULL;
}
} else {
mg_cry(conn, "%s: Cannot create file %s", __func__, path);
}
}
/* if (field_storage == FORM_FIELD_STORAGE_READ) { */
/* The idea of "field_storage=read" is to let the API user read
* data chunk by chunk and to some data processing on the fly.
* This should avoid the need to store data in the server:
* It should neither be stored in memory, like
* "field_storage=get" does, nor in a file like
* "field_storage=store".
* However, for a "GET" request this does not make any much
* sense, since the data is already stored in memory, as it is
* part of the query string.
*/
/* } */
if ((field_storage & FORM_FIELD_STORAGE_ABORT)
== FORM_FIELD_STORAGE_ABORT) {
/* Stop parsing the request */
break;
}
/* Proceed to next entry */
data = next;
}
return field_count;
}
content_type = mg_get_header(conn, "Content-Type");
if (!content_type
|| !mg_strcasecmp(content_type, "APPLICATION/X-WWW-FORM-URLENCODED")
|| !mg_strcasecmp(content_type, "APPLICATION/WWW-FORM-URLENCODED")) {
/* The form data is in the request body data, encoded in key/value
* pairs. */
int all_data_read = 0;
/* Read body data and split it in keys and values.
* The encoding is like in the "GET" case above: a=1&b&c=3&c=4.
* Here we use "POST", and read the data from the request body.
* The data read on the fly, so it is not required to buffer the
* entire request in memory before processing it. */
for (;;) {
const char *val;
const char *next;
ptrdiff_t keylen, vallen;
ptrdiff_t used;
int end_of_key_value_pair_found = 0;
int get_block;
if ((size_t)buf_fill < (sizeof(buf) - 1)) {
size_t to_read = sizeof(buf) - 1 - (size_t)buf_fill;
r = mg_read(conn, buf + (size_t)buf_fill, to_read);
if (r < 0) {
/* read error */
return -1;
}
if (r != (int)to_read) {
/* TODO: Create a function to get "all_data_read" from
* the conn object. All data is read if the Content-Length
* has been reached, or if chunked encoding is used and
* the end marker has been read, or if the connection has
* been closed. */
all_data_read = 1;
}
buf_fill += r;
buf[buf_fill] = 0;
if (buf_fill < 1) {
break;
}
}
val = strchr(buf, '=');
if (!val) {
break;
}
keylen = val - buf;
val++;
/* Call callback */
memset(path, 0, sizeof(path));
field_count++;
field_storage = url_encoded_field_found(conn,
buf,
(size_t)keylen,
NULL,
0,
path,
sizeof(path) - 1,
fdh);
if ((field_storage & FORM_FIELD_STORAGE_ABORT)
== FORM_FIELD_STORAGE_ABORT) {
/* Stop parsing the request */
break;
}
if (field_storage == FORM_FIELD_STORAGE_STORE) {
if (mg_fopen(conn, path, "wb", &fstore) == 0) {
fstore.fp = NULL;
}
file_size = 0;
if (!fstore.fp) {
mg_cry(conn, "%s: Cannot create file %s", __func__, path);
}
}
get_block = 0;
/* Loop to read values larger than sizeof(buf)-keylen-2 */
do {
next = strchr(val, '&');
if (next) {
vallen = next - val;
next++;
end_of_key_value_pair_found = 1;
} else {
vallen = (ptrdiff_t)strlen(val);
next = val + vallen;
}
if (field_storage == FORM_FIELD_STORAGE_GET) {
#if 0
if (!end_of_key_value_pair_found && !all_data_read) {
/* This callback will deliver partial contents */
}
#else
(void)all_data_read; /* avoid warning */
#endif
/* Call callback */
url_encoded_field_get(conn,
((get_block > 0) ? NULL : buf),
((get_block > 0) ? 0
: (size_t)keylen),
val,
(size_t)vallen,
fdh);
get_block++;
}
if (fstore.fp) {
size_t n =
(size_t)fwrite(val, 1, (size_t)vallen, fstore.fp);
if ((n != (size_t)vallen) || (ferror(fstore.fp))) {
mg_cry(conn,
"%s: Cannot write file %s",
__func__,
path);
fclose(fstore.fp);
fstore.fp = NULL;
remove_bad_file(conn, path);
}
file_size += (int64_t)n;
}
if (!end_of_key_value_pair_found) {
used = next - buf;
memmove(buf,
buf + (size_t)used,
sizeof(buf) - (size_t)used);
buf_fill -= (int)used;
if ((size_t)buf_fill < (sizeof(buf) - 1)) {
size_t to_read = sizeof(buf) - 1 - (size_t)buf_fill;
r = mg_read(conn, buf + (size_t)buf_fill, to_read);
if (r < 0) {
/* read error */
return -1;
}
if (r != (int)to_read) {
/* TODO: Create a function to get "all_data_read"
* from the conn object. All data is read if the
* Content-Length has been reached, or if chunked
* encoding is used and the end marker has been
* read, or if the connection has been closed. */
all_data_read = 1;
}
buf_fill += r;
buf[buf_fill] = 0;
if (buf_fill < 1) {
break;
}
val = buf;
}
}
} while (!end_of_key_value_pair_found);
if (fstore.fp) {
r = fclose(fstore.fp);
if (r == 0) {
/* stored successfully */
field_stored(conn, path, file_size, fdh);
} else {
mg_cry(conn, "%s: Error saving file %s", __func__, path);
remove_bad_file(conn, path);
}
fstore.fp = NULL;
}
/* Proceed to next entry */
used = next - buf;
memmove(buf, buf + (size_t)used, sizeof(buf) - (size_t)used);
buf_fill -= (int)used;
}
return field_count;
}
if (!mg_strncasecmp(content_type, "MULTIPART/FORM-DATA;", 20)) {
/* The form data is in the request body data, encoded as multipart
* content (see https://www.ietf.org/rfc/rfc1867.txt,
* https://www.ietf.org/rfc/rfc2388.txt). */
const char *boundary;
size_t bl;
ptrdiff_t used;
struct mg_request_info part_header;
char *hbuf, *hend, *fbeg, *fend, *nbeg, *nend;
const char *content_disp;
const char *next;
memset(&part_header, 0, sizeof(part_header));
/* Skip all spaces between MULTIPART/FORM-DATA; and BOUNDARY= */
bl = 20;
while (content_type[bl] == ' ') {
bl++;
}
/* There has to be a BOUNDARY definition in the Content-Type header */
if (mg_strncasecmp(content_type + bl, "BOUNDARY=", 9)) {
/* Malformed request */
return -1;
}
boundary = content_type + bl + 9;
bl = strlen(boundary);
if (bl + 800 > sizeof(buf)) {
/* Sanity check: The algorithm can not work if bl >= sizeof(buf),
* and it will not work effectively, if the buf is only a few byte
* larger than bl, or it buf can not hold the multipart header
* plus the boundary.
* Check some reasonable number here, that should be fulfilled by
* any reasonable request from every browser. If it is not
* fulfilled, it might be a hand-made request, intended to
* interfere with the algorithm. */
return -1;
}
for (;;) {
size_t towrite, n;
int get_block;
r = mg_read(conn,
buf + (size_t)buf_fill,
sizeof(buf) - 1 - (size_t)buf_fill);
if (r < 0) {
/* read error */
return -1;
}
buf_fill += r;
buf[buf_fill] = 0;
if (buf_fill < 1) {
/* No data */
return -1;
}
if (buf[0] != '-' || buf[1] != '-') {
/* Malformed request */
return -1;
}
if (strncmp(buf + 2, boundary, bl)) {
/* Malformed request */
return -1;
}
if (buf[bl + 2] != '\r' || buf[bl + 3] != '\n') {
/* Every part must end with \r\n, if there is another part.
* The end of the request has an extra -- */
if (((size_t)buf_fill != (size_t)(bl + 6))
|| (strncmp(buf + bl + 2, "--\r\n", 4))) {
/* Malformed request */
return -1;
}
/* End of the request */
break;
}
/* Next, we need to get the part header: Read until \r\n\r\n */
hbuf = buf + bl + 4;
hend = strstr(hbuf, "\r\n\r\n");
if (!hend) {
/* Malformed request */
return -1;
}
parse_http_headers(&hbuf, &part_header);
if ((hend + 2) != hbuf) {
/* Malformed request */
return -1;
}
/* Skip \r\n\r\n */
hend += 4;
/* According to the RFC, every part has to have a header field like:
* Content-Disposition: form-data; name="..." */
content_disp = get_header(&part_header, "Content-Disposition");
if (!content_disp) {
/* Malformed request */
return -1;
}
/* Get the mandatory name="..." part of the Content-Disposition
* header. */
nbeg = strstr(content_disp, "name=\"");
if (!nbeg) {
/* Malformed request */
return -1;
}
nbeg += 6;
nend = strchr(nbeg, '\"');
if (!nend) {
/* Malformed request */
return -1;
}
/* Get the optional filename="..." part of the Content-Disposition
* header. */
fbeg = strstr(content_disp, "filename=\"");
if (fbeg) {
fbeg += 10;
fend = strchr(fbeg, '\"');
if (!fend) {
/* Malformed request (the filename field is optional, but if
* it exists, it needs to be terminated correctly). */
return -1;
}
/* TODO: check Content-Type */
/* Content-Type: application/octet-stream */
} else {
fend = fbeg;
}
memset(path, 0, sizeof(path));
field_count++;
field_storage = url_encoded_field_found(conn,
nbeg,
(size_t)(nend - nbeg),
fbeg,
(size_t)(fend - fbeg),
path,
sizeof(path) - 1,
fdh);
/* If the boundary is already in the buffer, get the address,
* otherwise next will be NULL. */
next = search_boundary(hbuf,
(size_t)((buf - hbuf) + buf_fill),
boundary,
bl);
if (field_storage == FORM_FIELD_STORAGE_STORE) {
/* Store the content to a file */
if (mg_fopen(conn, path, "wb", &fstore) == 0) {
fstore.fp = NULL;
}
file_size = 0;
if (!fstore.fp) {
mg_cry(conn, "%s: Cannot create file %s", __func__, path);
}
}
get_block = 0;
while (!next) {
/* Set "towrite" to the number of bytes available
* in the buffer */
towrite = (size_t)(buf - hend + buf_fill);
/* Subtract the boundary length, to deal with
* cases the boundary is only partially stored
* in the buffer. */
towrite -= bl + 4;
if (field_storage == FORM_FIELD_STORAGE_GET) {
url_encoded_field_get(conn,
((get_block > 0) ? NULL : nbeg),
((get_block > 0)
? 0
: (size_t)(nend - nbeg)),
hend,
towrite,
fdh);
get_block++;
}
if (field_storage == FORM_FIELD_STORAGE_STORE) {
if (fstore.fp) {
/* Store the content of the buffer. */
n = (size_t)fwrite(hend, 1, towrite, fstore.fp);
if ((n != towrite) || (ferror(fstore.fp))) {
mg_cry(conn,
"%s: Cannot write file %s",
__func__,
path);
fclose(fstore.fp);
fstore.fp = NULL;
remove_bad_file(conn, path);
}
file_size += (int64_t)n;
}
}
memmove(buf, hend + towrite, bl + 4);
buf_fill = (int)(bl + 4);
hend = buf;
/* Read new data */
r = mg_read(conn,
buf + (size_t)buf_fill,
sizeof(buf) - 1 - (size_t)buf_fill);
if (r < 0) {
/* read error */
return -1;
}
buf_fill += r;
buf[buf_fill] = 0;
if (buf_fill < 1) {
/* No data */
return -1;
}
/* Find boundary */
next = search_boundary(buf, (size_t)buf_fill, boundary, bl);
}
towrite = (size_t)(next - hend);
if (field_storage == FORM_FIELD_STORAGE_GET) {
/* Call callback */
url_encoded_field_get(conn,
((get_block > 0) ? NULL : nbeg),
((get_block > 0) ? 0
: (size_t)(nend - nbeg)),
hend,
towrite,
fdh);
}
if (field_storage == FORM_FIELD_STORAGE_STORE) {
if (fstore.fp) {
n = (size_t)fwrite(hend, 1, towrite, fstore.fp);
if ((n != towrite) || (ferror(fstore.fp))) {
mg_cry(conn,
"%s: Cannot write file %s",
__func__,
path);
fclose(fstore.fp);
fstore.fp = NULL;
remove_bad_file(conn, path);
}
file_size += (int64_t)n;
}
}
if (field_storage == FORM_FIELD_STORAGE_STORE) {
if (fstore.fp) {
r = fclose(fstore.fp);
if (r == 0) {
/* stored successfully */
field_stored(conn, path, file_size, fdh);
} else {
mg_cry(conn,
"%s: Error saving file %s",
__func__,
path);
remove_bad_file(conn, path);
}
fstore.fp = NULL;
}
}
if ((field_storage & FORM_FIELD_STORAGE_ABORT)
== FORM_FIELD_STORAGE_ABORT) {
/* Stop parsing the request */
break;
}
/* Remove from the buffer */
used = next - buf + 2;
memmove(buf, buf + (size_t)used, sizeof(buf) - (size_t)used);
buf_fill -= (int)used;
}
/* All parts handled */
return field_count;
}
/* Unknown Content-Type */
return -1;
}
LinuxGUI/Ventoy2Disk/Lib/libhttp/include/md5.inl
0 → 100644
View file @
43e8ec57
/*
* This an amalgamation of md5.c and md5.h into a single file
* with all static declaration to reduce linker conflicts
* in Civetweb.
*
* The MD5_STATIC declaration was added to facilitate static
* inclusion.
* No Face Press, LLC
*/
/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */
/*
Independent implementation of MD5 (RFC 1321).
This code implements the MD5 Algorithm defined in RFC 1321, whose
text is available at
http://www.ietf.org/rfc/rfc1321.txt
The code is derived from the text of the RFC, including the test suite
(section A.5) but excluding the rest of Appendix A. It does not include
any code or documentation that is identified in the RFC as being
copyrighted.
The original and principal author of md5.h is L. Peter Deutsch
<ghost@aladdin.com>. Other authors are noted in the change history
that follows (in reverse chronological order):
2002-04-13 lpd Removed support for non-ANSI compilers; removed
references to Ghostscript; clarified derivation from RFC 1321;
now handles byte order either statically or dynamically.
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
added conditionalization for C++ compilation from Martin
Purschke <purschke@bnl.gov>.
1999-05-03 lpd Original version.
*/
#ifndef md5_INCLUDED
#define md5_INCLUDED
/*
* This package supports both compile-time and run-time determination of CPU
* byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
* compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
* defined as non-zero, the code will be compiled to run only on big-endian
* CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
* run on either big- or little-endian CPUs, but will run slightly less
* efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
*/
typedef unsigned char md5_byte_t; /* 8-bit byte */
typedef unsigned int md5_word_t; /* 32-bit word */
/* Define the state of the MD5 Algorithm. */
typedef struct md5_state_s {
md5_word_t count[2]; /* message length in bits, lsw first */
md5_word_t abcd[4]; /* digest buffer */
md5_byte_t buf[64]; /* accumulate block */
} md5_state_t;
#ifdef __cplusplus
extern "C" {
#endif
/* Initialize the algorithm. */
MD5_STATIC void md5_init(md5_state_t *pms);
/* Append a string to the message. */
MD5_STATIC void
md5_append(md5_state_t *pms, const md5_byte_t *data, size_t nbytes);
/* Finish the message and return the digest. */
MD5_STATIC void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
#ifdef __cplusplus
} /* end extern "C" */
#endif
#endif /* md5_INCLUDED */
/*
Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
L. Peter Deutsch
ghost@aladdin.com
*/
/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */
/*
Independent implementation of MD5 (RFC 1321).
This code implements the MD5 Algorithm defined in RFC 1321, whose
text is available at
http://www.ietf.org/rfc/rfc1321.txt
The code is derived from the text of the RFC, including the test suite
(section A.5) but excluding the rest of Appendix A. It does not include
any code or documentation that is identified in the RFC as being
copyrighted.
The original and principal author of md5.c is L. Peter Deutsch
<ghost@aladdin.com>. Other authors are noted in the change history
that follows (in reverse chronological order):
2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
either statically or dynamically; added missing #include <string.h>
in library.
2002-03-11 lpd Corrected argument list for main(), and added int return
type, in test program and T value program.
2002-02-21 lpd Added missing #include <stdio.h> in test program.
2000-07-03 lpd Patched to eliminate warnings about "constant is
unsigned in ANSI C, signed in traditional"; made test program
self-checking.
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
1999-05-03 lpd Original version.
*/
#ifndef MD5_STATIC
#include <string.h>
#endif
#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
#ifdef ARCH_IS_BIG_ENDIAN
#define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
#else
#define BYTE_ORDER (0)
#endif
#define T_MASK ((md5_word_t)~0)
#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
#define T3 (0x242070db)
#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
#define T6 (0x4787c62a)
#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
#define T9 (0x698098d8)
#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
#define T13 (0x6b901122)
#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
#define T16 (0x49b40821)
#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
#define T19 (0x265e5a51)
#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
#define T22 (0x02441453)
#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
#define T25 (0x21e1cde6)
#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
#define T28 (0x455a14ed)
#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
#define T31 (0x676f02d9)
#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
#define T35 (0x6d9d6122)
#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
#define T38 (0x4bdecfa9)
#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
#define T41 (0x289b7ec6)
#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
#define T44 (0x04881d05)
#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
#define T47 (0x1fa27cf8)
#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
#define T50 (0x432aff97)
#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
#define T53 (0x655b59c3)
#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
#define T57 (0x6fa87e4f)
#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
#define T60 (0x4e0811a1)
#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
#define T63 (0x2ad7d2bb)
#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
static void
md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
{
md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2],
d = pms->abcd[3];
md5_word_t t;
#if BYTE_ORDER > 0
/* Define storage only for big-endian CPUs. */
md5_word_t X[16];
#else
/* Define storage for little-endian or both types of CPUs. */
md5_word_t xbuf[16];
const md5_word_t *X;
#endif
{
#if BYTE_ORDER == 0
/*
* Determine dynamically whether this is a big-endian or
* little-endian machine, since we can use a more efficient
* algorithm on the latter.
*/
static const int w = 1;
if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
#endif
#if BYTE_ORDER <= 0 /* little-endian */
{
/*
* On little-endian machines, we can process properly aligned
* data without copying it.
*/
if (!((data - (const md5_byte_t *)0) & 3)) {
/* data are properly aligned, a direct assignment is possible */
/* cast through a (void *) should avoid a compiler warning,
see
https://github.com/bel2125/civetweb/issues/94#issuecomment-98112861
*/
X = (const md5_word_t *)(const void *)data;
} else {
/* not aligned */
memcpy(xbuf, data, 64);
X = xbuf;
}
}
#endif
#if BYTE_ORDER == 0
else /* dynamic big-endian */
#endif
#if BYTE_ORDER >= 0 /* big-endian */
{
/*
* On big-endian machines, we must arrange the bytes in the
* right order.
*/
const md5_byte_t *xp = data;
int i;
#if BYTE_ORDER == 0
X = xbuf; /* (dynamic only) */
#else
#define xbuf X /* (static only) */
#endif
for (i = 0; i < 16; ++i, xp += 4)
xbuf[i] = (md5_word_t)(xp[0]) + (md5_word_t)(xp[1] << 8)
+ (md5_word_t)(xp[2] << 16)
+ (md5_word_t)(xp[3] << 24);
}
#endif
}
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
/* Round 1. */
/* Let [abcd k s i] denote the operation
a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
#define SET(a, b, c, d, k, s, Ti) \
t = a + F(b, c, d) + X[k] + Ti; \
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 0, 7, T1);
SET(d, a, b, c, 1, 12, T2);
SET(c, d, a, b, 2, 17, T3);
SET(b, c, d, a, 3, 22, T4);
SET(a, b, c, d, 4, 7, T5);
SET(d, a, b, c, 5, 12, T6);
SET(c, d, a, b, 6, 17, T7);
SET(b, c, d, a, 7, 22, T8);
SET(a, b, c, d, 8, 7, T9);
SET(d, a, b, c, 9, 12, T10);
SET(c, d, a, b, 10, 17, T11);
SET(b, c, d, a, 11, 22, T12);
SET(a, b, c, d, 12, 7, T13);
SET(d, a, b, c, 13, 12, T14);
SET(c, d, a, b, 14, 17, T15);
SET(b, c, d, a, 15, 22, T16);
#undef SET
/* Round 2. */
/* Let [abcd k s i] denote the operation
a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
#define SET(a, b, c, d, k, s, Ti) \
t = a + G(b, c, d) + X[k] + Ti; \
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 1, 5, T17);
SET(d, a, b, c, 6, 9, T18);
SET(c, d, a, b, 11, 14, T19);
SET(b, c, d, a, 0, 20, T20);
SET(a, b, c, d, 5, 5, T21);
SET(d, a, b, c, 10, 9, T22);
SET(c, d, a, b, 15, 14, T23);
SET(b, c, d, a, 4, 20, T24);
SET(a, b, c, d, 9, 5, T25);
SET(d, a, b, c, 14, 9, T26);
SET(c, d, a, b, 3, 14, T27);
SET(b, c, d, a, 8, 20, T28);
SET(a, b, c, d, 13, 5, T29);
SET(d, a, b, c, 2, 9, T30);
SET(c, d, a, b, 7, 14, T31);
SET(b, c, d, a, 12, 20, T32);
#undef SET
/* Round 3. */
/* Let [abcd k s t] denote the operation
a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define SET(a, b, c, d, k, s, Ti) \
t = a + H(b, c, d) + X[k] + Ti; \
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 5, 4, T33);
SET(d, a, b, c, 8, 11, T34);
SET(c, d, a, b, 11, 16, T35);
SET(b, c, d, a, 14, 23, T36);
SET(a, b, c, d, 1, 4, T37);
SET(d, a, b, c, 4, 11, T38);
SET(c, d, a, b, 7, 16, T39);
SET(b, c, d, a, 10, 23, T40);
SET(a, b, c, d, 13, 4, T41);
SET(d, a, b, c, 0, 11, T42);
SET(c, d, a, b, 3, 16, T43);
SET(b, c, d, a, 6, 23, T44);
SET(a, b, c, d, 9, 4, T45);
SET(d, a, b, c, 12, 11, T46);
SET(c, d, a, b, 15, 16, T47);
SET(b, c, d, a, 2, 23, T48);
#undef SET
/* Round 4. */
/* Let [abcd k s t] denote the operation
a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
#define SET(a, b, c, d, k, s, Ti) \
t = a + I(b, c, d) + X[k] + Ti; \
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 0, 6, T49);
SET(d, a, b, c, 7, 10, T50);
SET(c, d, a, b, 14, 15, T51);
SET(b, c, d, a, 5, 21, T52);
SET(a, b, c, d, 12, 6, T53);
SET(d, a, b, c, 3, 10, T54);
SET(c, d, a, b, 10, 15, T55);
SET(b, c, d, a, 1, 21, T56);
SET(a, b, c, d, 8, 6, T57);
SET(d, a, b, c, 15, 10, T58);
SET(c, d, a, b, 6, 15, T59);
SET(b, c, d, a, 13, 21, T60);
SET(a, b, c, d, 4, 6, T61);
SET(d, a, b, c, 11, 10, T62);
SET(c, d, a, b, 2, 15, T63);
SET(b, c, d, a, 9, 21, T64);
#undef SET
/* Then perform the following additions. (That is increment each
of the four registers by the value it had before this block
was started.) */
pms->abcd[0] += a;
pms->abcd[1] += b;
pms->abcd[2] += c;
pms->abcd[3] += d;
}
MD5_STATIC void
md5_init(md5_state_t *pms)
{
pms->count[0] = pms->count[1] = 0;
pms->abcd[0] = 0x67452301;
pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
pms->abcd[3] = 0x10325476;
}
MD5_STATIC void
md5_append(md5_state_t *pms, const md5_byte_t *data, size_t nbytes)
{
const md5_byte_t *p = data;
size_t left = nbytes;
size_t offset = (pms->count[0] >> 3) & 63;
md5_word_t nbits = (md5_word_t)(nbytes << 3);
if (nbytes <= 0)
return;
/* Update the message length. */
pms->count[1] += (md5_word_t)(nbytes >> 29);
pms->count[0] += nbits;
if (pms->count[0] < nbits)
pms->count[1]++;
/* Process an initial partial block. */
if (offset) {
size_t copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
memcpy(pms->buf + offset, p, copy);
if (offset + copy < 64)
return;
p += copy;
left -= copy;
md5_process(pms, pms->buf);
}
/* Process full blocks. */
for (; left >= 64; p += 64, left -= 64)
md5_process(pms, p);
/* Process a final partial block. */
if (left)
memcpy(pms->buf, p, left);
}
MD5_STATIC void
md5_finish(md5_state_t *pms, md5_byte_t digest[16])
{
static const md5_byte_t pad[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
md5_byte_t data[8];
int i;
/* Save the length before padding. */
for (i = 0; i < 8; ++i)
data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
/* Pad to 56 bytes mod 64. */
md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
/* Append the length. */
md5_append(pms, data, 8);
for (i = 0; i < 16; ++i)
digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
}
LinuxGUI/Ventoy2Disk/Lib/libhttp/include/mod_duktape.inl
0 → 100644
View file @
43e8ec57
/* This file is part of the CivetWeb web server.
* See https://github.com/civetweb/civetweb/
* (C) 2015 by the CivetWeb authors, MIT license.
*/
#include "duktape.h"
/* TODO: the mg context should be added to duktape as well */
/* Alternative: redefine a new, clean API from scratch (instead of using mg),
* or at least do not add problematic functions. */
/* For evaluation purposes, currently only "send" is supported.
* All other ~50 functions will be added later. */
/* Note: This is only experimental support, so the API may still change. */
static const char *civetweb_conn_id = "\xFF"
"civetweb_conn";
static const char *civetweb_ctx_id = "\xFF"
"civetweb_ctx";
static void *
mg_duk_mem_alloc(void *udata, duk_size_t size)
{
return mg_malloc(size);
}
static void *
mg_duk_mem_realloc(void *udata, void *ptr, duk_size_t newsize)
{
return mg_realloc(ptr, newsize);
}
static void
mg_duk_mem_free(void *udata, void *ptr)
{
mg_free(ptr);
}
static void
mg_duk_fatal_handler(duk_context *ctx, duk_errcode_t code, const char *msg)
{
/* Script is called "protected" (duk_peval_file), so script errors should
* never yield in a call to this function. Maybe calls prior to executing
* the script could raise a fatal error. */
struct mg_connection *conn;
duk_push_global_stash(ctx);
duk_get_prop_string(ctx, -1, civetweb_conn_id);
conn = (struct mg_connection *)duk_to_pointer(ctx, -1);
mg_cry(conn, "%s", msg);
}
static duk_ret_t
duk_itf_write(duk_context *ctx)
{
struct mg_connection *conn;
duk_double_t ret;
duk_size_t len = 0;
const char *val = duk_require_lstring(ctx, -1, &len);
/*
duk_push_global_stash(ctx);
duk_get_prop_string(ctx, -1, civetweb_conn_id);
conn = (struct mg_connection *)duk_to_pointer(ctx, -1);
*/
duk_push_current_function(ctx);
duk_get_prop_string(ctx, -1, civetweb_conn_id);
conn = (struct mg_connection *)duk_to_pointer(ctx, -1);
if (!conn) {
duk_error(ctx,
DUK_ERR_INTERNAL_ERROR,
"function not available without connection object");
/* probably never reached, but satisfies static code analysis */
return DUK_RET_INTERNAL_ERROR;
}
ret = mg_write(conn, val, len);
duk_push_number(ctx, ret);
return 1;
}
static duk_ret_t
duk_itf_read(duk_context *ctx)
{
struct mg_connection *conn;
char buf[1024];
int len;
duk_push_global_stash(ctx);
duk_get_prop_string(ctx, -1, civetweb_conn_id);
conn = (struct mg_connection *)duk_to_pointer(ctx, -1);
if (!conn) {
duk_error(ctx,
DUK_ERR_INTERNAL_ERROR,
"function not available without connection object");
/* probably never reached, but satisfies static code analysis */
return DUK_RET_INTERNAL_ERROR;
}
len = mg_read(conn, buf, sizeof(buf));
duk_push_lstring(ctx, buf, len);
return 1;
}
static duk_ret_t
duk_itf_getoption(duk_context *ctx)
{
struct mg_context *cv_ctx;
const char *ret;
duk_size_t len = 0;
const char *val = duk_require_lstring(ctx, -1, &len);
duk_push_current_function(ctx);
duk_get_prop_string(ctx, -1, civetweb_ctx_id);
cv_ctx = (struct mg_context *)duk_to_pointer(ctx, -1);
if (!cv_ctx) {
duk_error(ctx,
DUK_ERR_INTERNAL_ERROR,
"function not available without connection object");
/* probably never reached, but satisfies static code analysis */
return DUK_RET_INTERNAL_ERROR;
}
ret = mg_get_option(cv_ctx, val);
if (ret) {
duk_push_string(ctx, ret);
} else {
duk_push_null(ctx);
}
return 1;
}
static void
mg_exec_duktape_script(struct mg_connection *conn, const char *script_name)
{
int i;
duk_context *ctx = NULL;
conn->must_close = 1;
/* Create Duktape interpreter state */
ctx = duk_create_heap(mg_duk_mem_alloc,
mg_duk_mem_realloc,
mg_duk_mem_free,
NULL,
mg_duk_fatal_handler);
if (!ctx) {
mg_cry(conn, "Failed to create a Duktape heap.");
goto exec_duktape_finished;
}
/* Add "conn" object */
duk_push_global_object(ctx);
duk_push_object(ctx); /* create a new table/object ("conn") */
duk_push_c_function(ctx, duk_itf_write, 1 /* 1 = nargs */);
duk_push_pointer(ctx, (void *)conn);
duk_put_prop_string(ctx, -2, civetweb_conn_id);
duk_put_prop_string(ctx, -2, "write"); /* add function conn.write */
duk_push_c_function(ctx, duk_itf_read, 0 /* 0 = nargs */);
duk_push_pointer(ctx, (void *)conn);
duk_put_prop_string(ctx, -2, civetweb_conn_id);
duk_put_prop_string(ctx, -2, "read"); /* add function conn.read */
duk_push_string(ctx, conn->request_info.request_method);
duk_put_prop_string(ctx, -2, "request_method"); /* add string conn.r... */
duk_push_string(ctx, conn->request_info.request_uri);
duk_put_prop_string(ctx, -2, "request_uri");
duk_push_string(ctx, conn->request_info.local_uri);
duk_put_prop_string(ctx, -2, "uri");
duk_push_string(ctx, conn->request_info.http_version);
duk_put_prop_string(ctx, -2, "http_version");
duk_push_string(ctx, conn->request_info.query_string);
duk_put_prop_string(ctx, -2, "query_string");
duk_push_string(ctx, conn->request_info.remote_addr);
duk_put_prop_string(ctx, -2, "remote_addr");
duk_push_int(ctx, conn->request_info.remote_port);
duk_put_prop_string(ctx, -2, "remote_port");
duk_push_int(ctx, ntohs(conn->client.lsa.sin.sin_port));
duk_put_prop_string(ctx, -2, "server_port");
duk_push_object(ctx); /* subfolder "conn.http_headers" */
for (i = 0; i < conn->request_info.num_headers; i++) {
duk_push_string(ctx, conn->request_info.http_headers[i].value);
duk_put_prop_string(ctx, -2, conn->request_info.http_headers[i].name);
}
duk_put_prop_string(ctx, -2, "http_headers");
duk_put_prop_string(ctx, -2, "conn"); /* call the table "conn" */
/* Add "civetweb" object */
duk_push_global_object(ctx);
duk_push_object(ctx); /* create a new table/object ("conn") */
duk_push_string(ctx, CIVETWEB_VERSION);
duk_put_prop_string(ctx, -2, "version");
duk_push_string(ctx, script_name);
duk_put_prop_string(ctx, -2, "script_name");
if (conn->ctx != NULL) {
duk_push_c_function(ctx, duk_itf_getoption, 1 /* 1 = nargs */);
duk_push_pointer(ctx, (void *)(conn->ctx));
duk_put_prop_string(ctx, -2, civetweb_ctx_id);
duk_put_prop_string(ctx, -2, "getoption"); /* add function conn.write */
if (conn->ctx->systemName != NULL) {
duk_push_string(ctx, conn->ctx->systemName);
duk_put_prop_string(ctx, -2, "system");
}
}
duk_put_prop_string(ctx, -2, "civetweb"); /* call the table "civetweb" */
duk_push_global_stash(ctx);
duk_push_pointer(ctx, (void *)conn);
duk_put_prop_string(ctx, -2, civetweb_conn_id);
if (duk_peval_file(ctx, script_name) != 0) {
mg_cry(conn, "%s", duk_safe_to_string(ctx, -1));
goto exec_duktape_finished;
}
duk_pop(ctx); /* ignore result */
exec_duktape_finished:
duk_destroy_heap(ctx);
}
LinuxGUI/Ventoy2Disk/Lib/libhttp/include/mod_lua.inl
0 → 100644
View file @
43e8ec57
#include "civetweb_lua.h"
#include "civetweb_private_lua.h"
#ifdef _WIN32
static void *
mmap(void *addr, int64_t len, int prot, int flags, int fd, int offset)
{
/* TODO (low): This is an incomplete implementation of mmap for windows.
* Currently it is sufficient, but there are a lot of unused parameters.
* Better use a function "mg_map" which only has the required parameters,
* and implement it using mmap in Linux and CreateFileMapping in Windows.
* Noone should expect a full mmap for Windows here.
*/
HANDLE fh = (HANDLE)_get_osfhandle(fd);
HANDLE mh = CreateFileMapping(fh, 0, PAGE_READONLY, 0, 0, 0);
void *p = MapViewOfFile(mh, FILE_MAP_READ, 0, 0, (size_t)len);
CloseHandle(mh);
/* unused parameters */
(void)addr;
(void)prot;
(void)flags;
(void)offset;
return p;
}
static void
munmap(void *addr, int64_t length)
{
/* unused parameters */
(void)length;
UnmapViewOfFile(addr);
}
#define MAP_FAILED (NULL)
#define MAP_PRIVATE (0)
#define PROT_READ (0)
#else
#include <sys/mman.h>
#endif
static const char *LUASOCKET = "luasocket";
static const char lua_regkey_ctx = 1;
static const char lua_regkey_connlist = 2;
/* Forward declarations */
static void handle_request(struct mg_connection *);
static int handle_lsp_request(struct mg_connection *,
const char *,
struct file *,
struct lua_State *);
static void
reg_string(struct lua_State *L, const char *name, const char *val)
{
if (name != NULL && val != NULL) {
lua_pushstring(L, name);
lua_pushstring(L, val);
lua_rawset(L, -3);
}
}
static void
reg_int(struct lua_State *L, const char *name, int val)
{
if (name != NULL) {
lua_pushstring(L, name);
lua_pushinteger(L, val);
lua_rawset(L, -3);
}
}
static void
reg_boolean(struct lua_State *L, const char *name, int val)
{
if (name != NULL) {
lua_pushstring(L, name);
lua_pushboolean(L, val != 0);
lua_rawset(L, -3);
}
}
static void
reg_conn_function(struct lua_State *L,
const char *name,
lua_CFunction func,
struct mg_connection *conn)
{
if (name != NULL && func != NULL && conn != NULL) {
lua_pushstring(L, name);
lua_pushlightuserdata(L, conn);
lua_pushcclosure(L, func, 1);
lua_rawset(L, -3);
}
}
static void
reg_function(struct lua_State *L, const char *name, lua_CFunction func)
{
if (name != NULL && func != NULL) {
lua_pushstring(L, name);
lua_pushcclosure(L, func, 0);
lua_rawset(L, -3);
}
}
static void
lua_cry(struct mg_connection *conn,
int err,
lua_State *L,
const char *lua_title,
const char *lua_operation)
{
switch (err) {
case LUA_OK:
case LUA_YIELD:
break;
case LUA_ERRRUN:
mg_cry(conn,
"%s: %s failed: runtime error: %s",
lua_title,
lua_operation,
lua_tostring(L, -1));
break;
case LUA_ERRSYNTAX:
mg_cry(conn,
"%s: %s failed: syntax error: %s",
lua_title,
lua_operation,
lua_tostring(L, -1));
break;
case LUA_ERRMEM:
mg_cry(conn, "%s: %s failed: out of memory", lua_title, lua_operation);
break;
case LUA_ERRGCMM:
mg_cry(conn,
"%s: %s failed: error during garbage collection",
lua_title,
lua_operation);
break;
case LUA_ERRERR:
mg_cry(conn,
"%s: %s failed: error in error handling: %s",
lua_title,
lua_operation,
lua_tostring(L, -1));
break;
default:
mg_cry(conn, "%s: %s failed: error %i", lua_title, lua_operation, err);
break;
}
}
static int
lsp_sock_close(lua_State *L)
{
int num_args = lua_gettop(L);
if ((num_args == 1) && lua_istable(L, -1)) {
lua_getfield(L, -1, "sock");
closesocket((SOCKET)lua_tonumber(L, -1));
} else {
return luaL_error(L, "invalid :close() call");
}
return 1;
}
static int
lsp_sock_recv(lua_State *L)
{
int num_args = lua_gettop(L);
char buf[2000];
int n;
if ((num_args == 1) && lua_istable(L, -1)) {
lua_getfield(L, -1, "sock");
n = recv((SOCKET)lua_tonumber(L, -1), buf, sizeof(buf), 0);
if (n <= 0) {
lua_pushnil(L);
} else {
lua_pushlstring(L, buf, n);
}
} else {
return luaL_error(L, "invalid :close() call");
}
return 1;
}
static int
lsp_sock_send(lua_State *L)
{
int num_args = lua_gettop(L);
const char *buf;
size_t len, sent = 0;
int n = 0, sock;
if ((num_args == 2) && lua_istable(L, -2) && lua_isstring(L, -1)) {
buf = lua_tolstring(L, -1, &len);
lua_getfield(L, -2, "sock");
sock = (int)lua_tonumber(L, -1);
while (sent < len) {
if ((n = send(sock, buf + sent, (int)(len - sent), 0)) <= 0) {
break;
}
sent += n;
}
lua_pushnumber(L, n);
} else {
return luaL_error(L, "invalid :close() call");
}
return 1;
}
static const struct luaL_Reg luasocket_methods[] = {{"close", lsp_sock_close},
{"send", lsp_sock_send},
{"recv", lsp_sock_recv},
{NULL, NULL}};
static int
lsp_connect(lua_State *L)
{
int num_args = lua_gettop(L);
char ebuf[100];
SOCKET sock;
union usa sa;
int ok;
if ((num_args == 3) && lua_isstring(L, -3) && lua_isnumber(L, -2)
&& lua_isnumber(L, -1)) {
ok = connect_socket(NULL,
lua_tostring(L, -3),
(int)lua_tonumber(L, -2),
(int)lua_tonumber(L, -1),
ebuf,
sizeof(ebuf),
&sock,
&sa);
if (!ok) {
return luaL_error(L, ebuf);
} else {
lua_newtable(L);
reg_int(L, "sock", (int)sock);
reg_string(L, "host", lua_tostring(L, -4));
luaL_getmetatable(L, LUASOCKET);
lua_setmetatable(L, -2);
/* TODO (high): The metatable misses a _gc method to free the
* sock object -> currently lsp_connect is a resource leak. */
}
} else {
return luaL_error(
L, "connect(host,port,is_ssl): invalid parameter given.");
}
return 1;
}
static int
lsp_error(lua_State *L)
{
lua_getglobal(L, "mg");
lua_getfield(L, -1, "onerror");
lua_pushvalue(L, -3);
lua_pcall(L, 1, 0, 0);
return 0;
}
/* Silently stop processing chunks. */
static void
lsp_abort(lua_State *L)
{
int top = lua_gettop(L);
lua_getglobal(L, "mg");
lua_pushnil(L);
lua_setfield(L, -2, "onerror");
lua_settop(L, top);
lua_pushstring(L, "aborting");
lua_error(L);
}
struct lsp_var_reader_data {
const char *begin;
unsigned len;
unsigned state;
};
static const char *
lsp_var_reader(lua_State *L, void *ud, size_t *sz)
{
struct lsp_var_reader_data *reader = (struct lsp_var_reader_data *)ud;
const char *ret;
(void)(L); /* unused */
switch (reader->state) {
case 0:
ret = "mg.write(";
*sz = strlen(ret);
break;
case 1:
ret = reader->begin;
*sz = reader->len;
break;
case 2:
ret = ")";
*sz = strlen(ret);
break;
default:
ret = 0;
*sz = 0;
}
reader->state++;
return ret;
}
static int
lsp(struct mg_connection *conn,
const char *path,
const char *p,
int64_t len,
lua_State *L)
{
int i, j, pos = 0, lines = 1, lualines = 0, is_var, lua_ok;
char chunkname[MG_BUF_LEN];
struct lsp_var_reader_data data;
for (i = 0; i < len; i++) {
if (p[i] == '\n')
lines++;
if ((i + 1) < len && p[i] == '<' && p[i + 1] == '?') {
/* <?= ?> means a variable is enclosed and its value should be
* printed */
is_var = ((i + 2) < len && p[i + 2] == '=');
if (is_var)
j = i + 2;
else
j = i + 1;
while (j < len) {
if (p[j] == '\n')
lualines++;
if ((j + 1) < len && p[j] == '?' && p[j + 1] == '>') {
mg_write(conn, p + pos, i - pos);
mg_snprintf(conn,
NULL, /* name only used for debugging */
chunkname,
sizeof(chunkname),
"@%s+%i",
path,
lines);
lua_pushlightuserdata(L, conn);
lua_pushcclosure(L, lsp_error, 1);
if (is_var) {
data.begin = p + (i + 3);
data.len = j - (i + 3);
data.state = 0;
lua_ok = mg_lua_load(
L, lsp_var_reader, &data, chunkname, NULL);
} else {
lua_ok = luaL_loadbuffer(L,
p + (i + 2),
j - (i + 2),
chunkname);
}
if (lua_ok) {
/* Syntax error or OOM. Error message is pushed on
* stack. */
lua_pcall(L, 1, 0, 0);
} else {
/* Success loading chunk. Call it. */
lua_pcall(L, 0, 0, 1);
}
pos = j + 2;
i = pos - 1;
break;
}
j++;
}
if (lualines > 0) {
lines += lualines;
lualines = 0;
}
}
}
if (i > pos) {
mg_write(conn, p + pos, i - pos);
}
return 0;
}
/* mg.write: Send data to the client */
static int
lsp_write(lua_State *L)
{
struct mg_connection *conn =
(struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
int num_args = lua_gettop(L);
const char *str;
size_t size;
int i;
for (i = 1; i <= num_args; i++) {
if (lua_isstring(L, i)) {
str = lua_tolstring(L, i, &size);
mg_write(conn, str, size);
}
}
return 0;
}
/* mg.read: Read data from the client (e.g., from a POST request) */
static int
lsp_read(lua_State *L)
{
struct mg_connection *conn =
(struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
char buf[1024];
int len = mg_read(conn, buf, sizeof(buf));
if (len <= 0)
return 0;
lua_pushlstring(L, buf, len);
return 1;
}
/* mg.keep_alive: Allow Lua pages to use the http keep-alive mechanism */
static int
lsp_keep_alive(lua_State *L)
{
struct mg_connection *conn =
(struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
int num_args = lua_gettop(L);
/* This function may be called with one parameter (boolean) to set the
keep_alive state.
Or without a parameter to just query the current keep_alive state. */
if ((num_args == 1) && lua_isboolean(L, 1)) {
conn->must_close = !lua_toboolean(L, 1);
} else if (num_args != 0) {
/* Syntax error */
return luaL_error(L, "invalid keep_alive() call");
}
/* Return the current "keep_alive" state. This may be false, even it
* keep_alive(true) has been called. */
lua_pushboolean(L, should_keep_alive(conn));
return 1;
}
/* mg.include: Include another .lp file */
static int
lsp_include(lua_State *L)
{
struct mg_connection *conn =
(struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
int num_args = lua_gettop(L);
struct file file = STRUCT_FILE_INITIALIZER;
const char *filename = (num_args == 1) ? lua_tostring(L, 1) : NULL;
if (filename) {
if (handle_lsp_request(conn, filename, &file, L)) {
/* handle_lsp_request returned an error code, meaning an error
occured in
the included page and mg.onerror returned non-zero. Stop processing.
*/
lsp_abort(L);
}
} else {
/* Syntax error */
return luaL_error(L, "invalid include() call");
}
return 0;
}
/* mg.cry: Log an error. Default value for mg.onerror. */
static int
lsp_cry(lua_State *L)
{
struct mg_connection *conn =
(struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
int num_args = lua_gettop(L);
const char *text = (num_args == 1) ? lua_tostring(L, 1) : NULL;
if (text) {
mg_cry(conn, "%s", lua_tostring(L, -1));
} else {
/* Syntax error */
return luaL_error(L, "invalid cry() call");
}
return 0;
}
/* mg.redirect: Redirect the request (internally). */
static int
lsp_redirect(lua_State *L)
{
struct mg_connection *conn =
(struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
int num_args = lua_gettop(L);
const char *target = (num_args == 1) ? lua_tostring(L, 1) : NULL;
if (target) {
conn->request_info.local_uri = target;
handle_request(conn);
lsp_abort(L);
} else {
/* Syntax error */
return luaL_error(L, "invalid redirect() call");
}
return 0;
}
/* mg.send_file */
static int
lsp_send_file(lua_State *L)
{
struct mg_connection *conn =
(struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
int num_args = lua_gettop(L);
const char *filename = (num_args == 1) ? lua_tostring(L, 1) : NULL;
if (filename) {
mg_send_file(conn, filename);
} else {
/* Syntax error */
return luaL_error(L, "invalid send_file() call");
}
return 0;
}
/* mg.get_time */
static int
lsp_get_time(lua_State *L)
{
int num_args = lua_gettop(L);
int monotonic = (num_args > 0) ? lua_toboolean(L, 1) : 0;
struct timespec ts;
double d;
clock_gettime(monotonic ? CLOCK_MONOTONIC : CLOCK_REALTIME, &ts);
d = (double)ts.tv_sec + ((double)ts.tv_nsec * 1.0E-9);
lua_pushnumber(L, d);
return 1;
}
/* mg.get_var */
static int
lsp_get_var(lua_State *L)
{
int num_args = lua_gettop(L);
const char *data, *var_name;
size_t data_len, occurrence;
int ret;
char dst[512];
if (num_args >= 2 && num_args <= 3) {
data = lua_tolstring(L, 1, &data_len);
var_name = lua_tostring(L, 2);
occurrence = (num_args > 2) ? (long)lua_tonumber(L, 3) : 0;
ret =
mg_get_var2(data, data_len, var_name, dst, sizeof(dst), occurrence);
if (ret >= 0) {
/* Variable found: return value to Lua */
lua_pushstring(L, dst);
} else {
/* Variable not found (TODO (mid): may be string too long) */
lua_pushnil(L);
}
} else {
/* Syntax error */
return luaL_error(L, "invalid get_var() call");
}
return 1;
}
/* mg.get_mime_type */
static int
lsp_get_mime_type(lua_State *L)
{
int num_args = lua_gettop(L);
struct vec mime_type = {0, 0};
struct mg_context *ctx;
const char *text;
lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
lua_gettable(L, LUA_REGISTRYINDEX);
ctx = (struct mg_context *)lua_touserdata(L, -1);
if (num_args == 1) {
text = lua_tostring(L, 1);
if (text) {
if (ctx) {
get_mime_type(ctx, text, &mime_type);
lua_pushlstring(L, mime_type.ptr, mime_type.len);
} else {
text = mg_get_builtin_mime_type(text);
lua_pushstring(L, text);
}
} else {
/* Syntax error */
return luaL_error(L, "invalid argument for get_mime_type() call");
}
} else {
/* Syntax error */
return luaL_error(L, "invalid get_mime_type() call");
}
return 1;
}
/* mg.get_cookie */
static int
lsp_get_cookie(lua_State *L)
{
int num_args = lua_gettop(L);
const char *cookie;
const char *var_name;
int ret;
char dst[512];
if (num_args == 2) {
cookie = lua_tostring(L, 1);
var_name = lua_tostring(L, 2);
if (cookie != NULL && var_name != NULL) {
ret = mg_get_cookie(cookie, var_name, dst, sizeof(dst));
} else {
ret = -1;
}
if (ret >= 0) {
lua_pushlstring(L, dst, ret);
} else {
lua_pushnil(L);
}
} else {
/* Syntax error */
return luaL_error(L, "invalid get_cookie() call");
}
return 1;
}
/* mg.md5 */
static int
lsp_md5(lua_State *L)
{
int num_args = lua_gettop(L);
const char *text;
md5_byte_t hash[16];
md5_state_t ctx;
size_t text_len;
char buf[40];
if (num_args == 1) {
text = lua_tolstring(L, 1, &text_len);
if (text) {
md5_init(&ctx);
md5_append(&ctx, (const md5_byte_t *)text, text_len);
md5_finish(&ctx, hash);
bin2str(buf, hash, sizeof(hash));
lua_pushstring(L, buf);
} else {
lua_pushnil(L);
}
} else {
/* Syntax error */
return luaL_error(L, "invalid md5() call");
}
return 1;
}
/* mg.url_encode */
static int
lsp_url_encode(lua_State *L)
{
int num_args = lua_gettop(L);
const char *text;
size_t text_len;
char dst[512];
if (num_args == 1) {
text = lua_tolstring(L, 1, &text_len);
if (text) {
mg_url_encode(text, dst, sizeof(dst));
lua_pushstring(L, dst);
} else {
lua_pushnil(L);
}
} else {
/* Syntax error */
return luaL_error(L, "invalid url_encode() call");
}
return 1;
}
/* mg.url_decode */
static int
lsp_url_decode(lua_State *L)
{
int num_args = lua_gettop(L);
const char *text;
size_t text_len;
int is_form;
char dst[512];
if (num_args == 1 || (num_args == 2 && lua_isboolean(L, 2))) {
text = lua_tolstring(L, 1, &text_len);
is_form = (num_args == 2) ? lua_isboolean(L, 2) : 0;
if (text) {
mg_url_decode(text, text_len, dst, (int)sizeof(dst), is_form);
lua_pushstring(L, dst);
} else {
lua_pushnil(L);
}
} else {
/* Syntax error */
return luaL_error(L, "invalid url_decode() call");
}
return 1;
}
/* mg.base64_encode */
static int
lsp_base64_encode(lua_State *L)
{
int num_args = lua_gettop(L);
const char *text;
size_t text_len;
char *dst;
if (num_args == 1) {
text = lua_tolstring(L, 1, &text_len);
if (text) {
dst = (char *)mg_malloc(text_len * 8 / 6 + 4);
if (dst) {
base64_encode((const unsigned char *)text, (int)text_len, dst);
lua_pushstring(L, dst);
mg_free(dst);
} else {
return luaL_error(L, "out of memory in base64_encode() call");
}
} else {
lua_pushnil(L);
}
} else {
/* Syntax error */
return luaL_error(L, "invalid base64_encode() call");
}
return 1;
}
/* mg.base64_encode */
static int
lsp_base64_decode(lua_State *L)
{
int num_args = lua_gettop(L);
const char *text;
size_t text_len, dst_len;
int ret;
char *dst;
if (num_args == 1) {
text = lua_tolstring(L, 1, &text_len);
if (text) {
dst = (char *)mg_malloc(text_len);
if (dst) {
ret = base64_decode((const unsigned char *)text,
(int)text_len,
dst,
&dst_len);
if (ret != -1) {
mg_free(dst);
return luaL_error(
L, "illegal character in lsp_base64_decode() call");
} else {
lua_pushlstring(L, dst, dst_len);
mg_free(dst);
}
} else {
return luaL_error(L,
"out of memory in lsp_base64_decode() call");
}
} else {
lua_pushnil(L);
}
} else {
/* Syntax error */
return luaL_error(L, "invalid lsp_base64_decode() call");
}
return 1;
}
/* mg.get_response_code_text */
static int
lsp_get_response_code_text(lua_State *L)
{
int num_args = lua_gettop(L);
int type1;
double code;
const char *text;
if (num_args == 1) {
type1 = lua_type(L, 1);
if (type1 == LUA_TNUMBER) {
/* If the first argument is a number,
convert it to the corresponding text. */
code = lua_tonumber(L, 1);
text = mg_get_response_code_text(NULL, (int)code);
if (text)
lua_pushstring(L, text);
return text ? 1 : 0;
}
}
/* Syntax error */
return luaL_error(L, "invalid get_response_code_text() call");
}
/* mg.random - might be better than math.random on some systems */
static int
lsp_random(lua_State *L)
{
int num_args = lua_gettop(L);
if (num_args == 0) {
/* The civetweb internal random number generator will generate
* a 64 bit random number. */
uint64_t r = get_random();
/* Lua "number" is a IEEE 754 double precission float:
* https://en.wikipedia.org/wiki/Double-precision_floating-point_format
* Thus, mask with 2^53-1 to get an integer with the maximum
* precission available. */
r &= ((((uint64_t)1) << 53) - 1);
lua_pushnumber(L, (double)r);
return 1;
}
/* Syntax error */
return luaL_error(L, "invalid random() call");
}
union {
void *p;
void (*f)(unsigned char uuid[16]);
} pf_uuid_generate;
/* mg.uuid */
static int
lsp_uuid(lua_State *L)
{
union {
unsigned char uuid_array[16];
struct uuid_struct_type {
uint32_t data1;
uint16_t data2;
uint16_t data3;
uint8_t data4[8];
} uuid_struct;
} uuid;
char uuid_str[40];
int num_args = lua_gettop(L);
memset(&uuid, 0, sizeof(uuid));
memset(uuid_str, 0, sizeof(uuid_str));
if (num_args == 0) {
pf_uuid_generate.f(uuid.uuid_array);
sprintf(uuid_str,
"{%08lX-%04X-%04X-%02X%02X-"
"%02X%02X%02X%02X%02X%02X}",
(unsigned long)uuid.uuid_struct.data1,
(unsigned)uuid.uuid_struct.data2,
(unsigned)uuid.uuid_struct.data3,
(unsigned)uuid.uuid_struct.data4[0],
(unsigned)uuid.uuid_struct.data4[1],
(unsigned)uuid.uuid_struct.data4[2],
(unsigned)uuid.uuid_struct.data4[3],
(unsigned)uuid.uuid_struct.data4[4],
(unsigned)uuid.uuid_struct.data4[5],
(unsigned)uuid.uuid_struct.data4[6],
(unsigned)uuid.uuid_struct.data4[7]);
lua_pushstring(L, uuid_str);
return 1;
}
/* Syntax error */
return luaL_error(L, "invalid random() call");
}
#ifdef USE_WEBSOCKET
struct lua_websock_data {
lua_State *state;
char *script;
unsigned references;
struct mg_connection *conn[MAX_WORKER_THREADS];
pthread_mutex_t ws_mutex;
};
#endif
/* mg.write for websockets */
static int
lwebsock_write(lua_State *L)
{
#ifdef USE_WEBSOCKET
int num_args = lua_gettop(L);
struct lua_websock_data *ws;
const char *str;
size_t size;
int opcode = -1;
unsigned i;
struct mg_connection *client = NULL;
lua_pushlightuserdata(L, (void *)&lua_regkey_connlist);
lua_gettable(L, LUA_REGISTRYINDEX);
ws = (struct lua_websock_data *)lua_touserdata(L, -1);
(void)pthread_mutex_lock(&(ws->ws_mutex));
if (num_args == 1) {
/* just one text: send it to all client */
if (lua_isstring(L, 1)) {
opcode = WEBSOCKET_OPCODE_TEXT;
}
} else if (num_args == 2) {
if (lua_isnumber(L, 1)) {
/* opcode number and message text */
opcode = (int)lua_tointeger(L, 1);
} else if (lua_isstring(L, 1)) {
/* opcode string and message text */
str = lua_tostring(L, 1);
if (!mg_strncasecmp(str, "text", 4))
opcode = WEBSOCKET_OPCODE_TEXT;
else if (!mg_strncasecmp(str, "bin", 3))
opcode = WEBSOCKET_OPCODE_BINARY;
else if (!mg_strncasecmp(str, "close", 5))
opcode = WEBSOCKET_OPCODE_CONNECTION_CLOSE;
else if (!mg_strncasecmp(str, "ping", 4))
opcode = WEBSOCKET_OPCODE_PING;
else if (!mg_strncasecmp(str, "pong", 4))
opcode = WEBSOCKET_OPCODE_PONG;
else if (!mg_strncasecmp(str, "cont", 4))
opcode = WEBSOCKET_OPCODE_CONTINUATION;
} else if (lua_isuserdata(L, 1)) {
/* client id and message text */
client = (struct mg_connection *)lua_touserdata(L, 1);
opcode = WEBSOCKET_OPCODE_TEXT;
}
} else if (num_args == 3) {
if (lua_isuserdata(L, 1)) {
client = (struct mg_connection *)lua_touserdata(L, 1);
if (lua_isnumber(L, 2)) {
/* client id, opcode number and message text */
opcode = (int)lua_tointeger(L, 2);
} else if (lua_isstring(L, 2)) {
/* client id, opcode string and message text */
str = lua_tostring(L, 2);
if (!mg_strncasecmp(str, "text", 4))
opcode = WEBSOCKET_OPCODE_TEXT;
else if (!mg_strncasecmp(str, "bin", 3))
opcode = WEBSOCKET_OPCODE_BINARY;
else if (!mg_strncasecmp(str, "close", 5))
opcode = WEBSOCKET_OPCODE_CONNECTION_CLOSE;
else if (!mg_strncasecmp(str, "ping", 4))
opcode = WEBSOCKET_OPCODE_PING;
else if (!mg_strncasecmp(str, "pong", 4))
opcode = WEBSOCKET_OPCODE_PONG;
else if (!mg_strncasecmp(str, "cont", 4))
opcode = WEBSOCKET_OPCODE_CONTINUATION;
}
}
}
if (opcode >= 0 && opcode < 16 && lua_isstring(L, num_args)) {
str = lua_tolstring(L, num_args, &size);
if (client) {
for (i = 0; i < ws->references; i++) {
if (client == ws->conn[i]) {
mg_websocket_write(ws->conn[i], opcode, str, size);
}
}
} else {
for (i = 0; i < ws->references; i++) {
mg_websocket_write(ws->conn[i], opcode, str, size);
}
}
} else {
(void)pthread_mutex_unlock(&(ws->ws_mutex));
return luaL_error(L, "invalid websocket write() call");
}
(void)pthread_mutex_unlock(&(ws->ws_mutex));
#else
(void)(L); /* unused */
#endif
return 0;
}
struct laction_arg {
lua_State *state;
const char *script;
pthread_mutex_t *pmutex;
char txt[1];
};
static int
lua_action(struct laction_arg *arg)
{
int err, ok;
struct mg_context *ctx;
(void)pthread_mutex_lock(arg->pmutex);
lua_pushlightuserdata(arg->state, (void *)&lua_regkey_ctx);
lua_gettable(arg->state, LUA_REGISTRYINDEX);
ctx = (struct mg_context *)lua_touserdata(arg->state, -1);
err = luaL_loadstring(arg->state, arg->txt);
if (err != 0) {
lua_cry(fc(ctx), err, arg->state, arg->script, "timer");
(void)pthread_mutex_unlock(arg->pmutex);
mg_free(arg);
return 0;
}
err = lua_pcall(arg->state, 0, 1, 0);
if (err != 0) {
lua_cry(fc(ctx), err, arg->state, arg->script, "timer");
(void)pthread_mutex_unlock(arg->pmutex);
mg_free(arg);
return 0;
}
ok = lua_type(arg->state, -1);
if (lua_isboolean(arg->state, -1)) {
ok = lua_toboolean(arg->state, -1);
} else {
ok = 0;
}
lua_pop(arg->state, 1);
(void)pthread_mutex_unlock(arg->pmutex);
if (!ok) {
mg_free(arg);
}
return ok;
}
static int
lua_action_free(struct laction_arg *arg)
{
if (lua_action(arg)) {
mg_free(arg);
}
return 0;
}
static int
lwebsocket_set_timer(lua_State *L, int is_periodic)
{
#if defined(USE_TIMERS) && defined(USE_WEBSOCKET)
int num_args = lua_gettop(L);
struct lua_websock_data *ws;
int type1, type2, ok = 0;
double timediff;
struct mg_context *ctx;
struct laction_arg *arg;
const char *txt;
size_t txt_len;
lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
lua_gettable(L, LUA_REGISTRYINDEX);
ctx = (struct mg_context *)lua_touserdata(L, -1);
lua_pushlightuserdata(L, (void *)&lua_regkey_connlist);
lua_gettable(L, LUA_REGISTRYINDEX);
ws = (struct lua_websock_data *)lua_touserdata(L, -1);
if (num_args < 2) {
return luaL_error(L,
"not enough arguments for set_timer/interval() call");
}
type1 = lua_type(L, 1);
type2 = lua_type(L, 2);
if (type1 == LUA_TSTRING && type2 == LUA_TNUMBER && num_args == 2) {
timediff = (double)lua_tonumber(L, 2);
txt = lua_tostring(L, 1);
txt_len = strlen(txt);
arg = (struct laction_arg *)mg_malloc(sizeof(struct laction_arg)
+ txt_len + 10);
arg->state = L;
arg->script = ws->script;
arg->pmutex = &(ws->ws_mutex);
memcpy(arg->txt, "return(", 7);
memcpy(arg->txt + 7, txt, txt_len);
arg->txt[txt_len + 7] = ')';
arg->txt[txt_len + 8] = 0;
ok =
(0
== timer_add(ctx,
timediff,
is_periodic,
1,
(taction)(is_periodic ? lua_action : lua_action_free),
(void *)arg));
} else if (type1 == LUA_TFUNCTION && type2 == LUA_TNUMBER) {
/* TODO (mid): not implemented yet */
return luaL_error(L, "invalid arguments for set_timer/interval() call");
} else {
return luaL_error(L, "invalid arguments for set_timer/interval() call");
}
lua_pushboolean(L, ok);
return 1;
#else
(void)(L); /* unused */
(void)(is_periodic); /* unused */
return 0;
#endif
}
/* mg.set_timeout for websockets */
static int
lwebsocket_set_timeout(lua_State *L)
{
return lwebsocket_set_timer(L, 0);
}
/* mg.set_interval for websockets */
static int
lwebsocket_set_interval(lua_State *L)
{
return lwebsocket_set_timer(L, 1);
}
enum {
LUA_ENV_TYPE_LUA_SERVER_PAGE = 0,
LUA_ENV_TYPE_PLAIN_LUA_PAGE = 1,
LUA_ENV_TYPE_LUA_WEBSOCKET = 2,
};
static void
prepare_lua_request_info(struct mg_connection *conn, lua_State *L)
{
const char *s;
int i;
/* Export mg.request_info */
lua_pushstring(L, "request_info");
lua_newtable(L);
reg_string(L, "request_method", conn->request_info.request_method);
reg_string(L, "request_uri", conn->request_info.request_uri);
reg_string(L, "uri", conn->request_info.local_uri);
reg_string(L, "http_version", conn->request_info.http_version);
reg_string(L, "query_string", conn->request_info.query_string);
#if defined(MG_LEGACY_INTERFACE)
reg_int(L, "remote_ip", conn->request_info.remote_ip); /* remote_ip is
deprecated, use
remote_addr
instead */
#endif
reg_string(L, "remote_addr", conn->request_info.remote_addr);
/* TODO (high): ip version */
reg_int(L, "remote_port", conn->request_info.remote_port);
reg_int(L, "num_headers", conn->request_info.num_headers);
reg_int(L, "server_port", ntohs(conn->client.lsa.sin.sin_port));
if (conn->request_info.content_length >= 0) {
/* reg_int64: content_length */
lua_pushstring(L, "content_length");
lua_pushnumber(
L,
(lua_Number)conn->request_info
.content_length); /* lua_Number may be used as 52 bit integer */
lua_rawset(L, -3);
}
if ((s = mg_get_header(conn, "Content-Type")) != NULL) {
reg_string(L, "content_type", s);
}
if (conn->request_info.remote_user != NULL) {
reg_string(L, "remote_user", conn->request_info.remote_user);
reg_string(L, "auth_type", "Digest");
}
reg_boolean(L, "https", conn->ssl != NULL);
if (conn->status_code > 0) {
/* Lua error handler should show the status code */
reg_int(L, "status", conn->status_code);
}
lua_pushstring(L, "http_headers");
lua_newtable(L);
for (i = 0; i < conn->request_info.num_headers; i++) {
reg_string(L,
conn->request_info.http_headers[i].name,
conn->request_info.http_headers[i].value);
}
lua_rawset(L, -3);
lua_rawset(L, -3);
}
void
civetweb_open_lua_libs(lua_State *L)
{
{
extern void luaL_openlibs(lua_State *);
luaL_openlibs(L);
}
#ifdef USE_LUA_SQLITE3
{
extern int luaopen_lsqlite3(lua_State *);
luaopen_lsqlite3(L);
}
#endif
#ifdef USE_LUA_LUAXML
{
extern int luaopen_LuaXML_lib(lua_State *);
luaopen_LuaXML_lib(L);
}
#endif
#ifdef USE_LUA_FILE_SYSTEM
{
extern int luaopen_lfs(lua_State *);
luaopen_lfs(L);
}
#endif
#ifdef USE_LUA_BINARY
{
/* TODO (low): Test if this could be used as a replacement for bit32.
* Check again with Lua 5.3 later. */
extern int luaopen_binary(lua_State *);
luaL_requiref(L, "binary", luaopen_binary, 1);
lua_pop(L, 1);
}
#endif
}
static void
prepare_lua_environment(struct mg_context *ctx,
struct mg_connection *conn,
struct lua_websock_data *ws_conn_list,
lua_State *L,
const char *script_name,
int lua_env_type)
{
civetweb_open_lua_libs(L);
#if LUA_VERSION_NUM == 502
/* Keep the "connect" method for compatibility,
* but do not backport it to Lua 5.1.
* TODO: Redesign the interface.
*/
luaL_newmetatable(L, LUASOCKET);
lua_pushliteral(L, "__index");
luaL_newlib(L, luasocket_methods);
lua_rawset(L, -3);
lua_pop(L, 1);
lua_register(L, "connect", lsp_connect);
#endif
/* Store context in the registry */
if (ctx != NULL) {
lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
lua_pushlightuserdata(L, (void *)ctx);
lua_settable(L, LUA_REGISTRYINDEX);
}
if (ws_conn_list != NULL) {
lua_pushlightuserdata(L, (void *)&lua_regkey_connlist);
lua_pushlightuserdata(L, (void *)ws_conn_list);
lua_settable(L, LUA_REGISTRYINDEX);
}
/* Register mg module */
lua_newtable(L);
switch (lua_env_type) {
case LUA_ENV_TYPE_LUA_SERVER_PAGE:
reg_string(L, "lua_type", "page");
break;
case LUA_ENV_TYPE_PLAIN_LUA_PAGE:
reg_string(L, "lua_type", "script");
break;
case LUA_ENV_TYPE_LUA_WEBSOCKET:
reg_string(L, "lua_type", "websocket");
break;
}
if (lua_env_type == LUA_ENV_TYPE_LUA_SERVER_PAGE
|| lua_env_type == LUA_ENV_TYPE_PLAIN_LUA_PAGE) {
reg_conn_function(L, "cry", lsp_cry, conn);
reg_conn_function(L, "read", lsp_read, conn);
reg_conn_function(L, "write", lsp_write, conn);
reg_conn_function(L, "keep_alive", lsp_keep_alive, conn);
reg_conn_function(L, "send_file", lsp_send_file, conn);
}
if (lua_env_type == LUA_ENV_TYPE_LUA_SERVER_PAGE) {
reg_conn_function(L, "include", lsp_include, conn);
reg_conn_function(L, "redirect", lsp_redirect, conn);
}
if (lua_env_type == LUA_ENV_TYPE_LUA_WEBSOCKET) {
reg_function(L, "write", lwebsock_write);
#ifdef USE_TIMERS
reg_function(L, "set_timeout", lwebsocket_set_timeout);
reg_function(L, "set_interval", lwebsocket_set_interval);
#endif
/* reg_conn_function(L, "send_file", lsp_send_file, conn); */
}
reg_function(L, "time", lsp_get_time);
reg_function(L, "get_var", lsp_get_var);
reg_function(L, "get_mime_type", lsp_get_mime_type);
reg_function(L, "get_cookie", lsp_get_cookie);
reg_function(L, "md5", lsp_md5);
reg_function(L, "url_encode", lsp_url_encode);
reg_function(L, "url_decode", lsp_url_decode);
reg_function(L, "base64_encode", lsp_base64_encode);
reg_function(L, "base64_decode", lsp_base64_decode);
reg_function(L, "get_response_code_text", lsp_get_response_code_text);
reg_function(L, "random", lsp_random);
if (pf_uuid_generate.f) {
reg_function(L, "uuid", lsp_uuid);
}
reg_string(L, "version", CIVETWEB_VERSION);
reg_string(L, "script_name", script_name);
if (ctx != NULL) {
reg_string(L, "document_root", ctx->config[DOCUMENT_ROOT]);
reg_string(L, "auth_domain", ctx->config[AUTHENTICATION_DOMAIN]);
#if defined(USE_WEBSOCKET)
reg_string(L, "websocket_root", ctx->config[WEBSOCKET_ROOT]);
#endif
if (ctx->systemName != NULL) {
reg_string(L, "system", ctx->systemName);
}
}
/* Export connection specific info */
if (conn != NULL) {
prepare_lua_request_info(conn, L);
}
lua_setglobal(L, "mg");
/* Register default mg.onerror function */
IGNORE_UNUSED_RESULT(
luaL_dostring(L,
"mg.onerror = function(e) mg.write('\\nLua error:\\n', "
"debug.traceback(e, 1)) end"));
if (ctx != NULL) {
/* Preload */
if (ctx->config[LUA_PRELOAD_FILE] != NULL) {
IGNORE_UNUSED_RESULT(luaL_dofile(L, ctx->config[LUA_PRELOAD_FILE]));
}
if (ctx->callbacks.init_lua != NULL) {
ctx->callbacks.init_lua(conn, L);
}
}
}
static int
lua_error_handler(lua_State *L)
{
const char *error_msg = lua_isstring(L, -1) ? lua_tostring(L, -1) : "?\n";
lua_getglobal(L, "mg");
if (!lua_isnil(L, -1)) {
lua_getfield(L, -1, "write"); /* call mg.write() */
lua_pushstring(L, error_msg);
lua_pushliteral(L, "\n");
lua_call(L, 2, 0);
IGNORE_UNUSED_RESULT(
luaL_dostring(L, "mg.write(debug.traceback(), '\\n')"));
} else {
printf("Lua error: [%s]\n", error_msg);
IGNORE_UNUSED_RESULT(
luaL_dostring(L, "print(debug.traceback(), '\\n')"));
}
/* TODO(lsm, low): leave the stack balanced */
return 0;
}
static void *
lua_allocator(void *ud, void *ptr, size_t osize, size_t nsize)
{
(void)ud;
(void)osize; /* not used */
if (nsize == 0) {
mg_free(ptr);
return NULL;
}
return mg_realloc(ptr, nsize);
}
static void
mg_exec_lua_script(struct mg_connection *conn,
const char *path,
const void **exports)
{
int i;
lua_State *L;
/* Assume the script does not support keep_alive. The script may change this
* by calling mg.keep_alive(true). */
conn->must_close = 1;
/* Execute a plain Lua script. */
if (path != NULL && (L = lua_newstate(lua_allocator, NULL)) != NULL) {
prepare_lua_environment(
conn->ctx, conn, NULL, L, path, LUA_ENV_TYPE_PLAIN_LUA_PAGE);
lua_pushcclosure(L, &lua_error_handler, 0);
if (exports != NULL) {
#if LUA_VERSION_NUM > 501
lua_pushglobaltable(L);
for (i = 0; exports[i] != NULL && exports[i + 1] != NULL; i += 2) {
lua_CFunction func;
lua_pushstring(L, (const char *)(exports[i]));
*(const void **)(&func) = exports[i + 1];
lua_pushcclosure(L, func, 0);
lua_rawset(L, -3);
}
#else
for (i = 0; exports[i] != NULL && exports[i + 1] != NULL; i += 2) {
lua_CFunction func;
const char *name = (const char *)(exports[i]);
*(const void **)(&func) = exports[i + 1];
lua_register(L, name, func);
}
#endif
}
if (luaL_loadfile(L, path) != 0) {
lua_error_handler(L);
}
lua_pcall(L, 0, 0, -2);
lua_close(L);
}
}
static int
handle_lsp_request(struct mg_connection *conn,
const char *path,
struct file *filep,
struct lua_State *ls)
{
void *p = NULL;
lua_State *L = NULL;
int error = 1;
struct file filesize = STRUCT_FILE_INITIALIZER;
/* Assume the script does not support keep_alive. The script may change this
* by calling mg.keep_alive(true). */
conn->must_close = 1;
/* We need both mg_stat to get file size, and mg_fopen to get fd */
if (!mg_stat(conn, path, &filesize)) {
/* File not found */
if (ls == NULL) {
send_http_error(conn, 500, "Error: File %s not found", path);
} else {
luaL_error(ls, "File [%s] not found", path);
}
goto cleanup_handle_lsp_request;
}
if (!mg_fopen(conn, path, "r", filep)) {
/* File not found or not accessible */
if (ls == NULL) {
send_http_error(conn,
500,
"Error: Cannot open script file %s",
path);
} else {
luaL_error(ls, "Cannot [%s] not found", path);
}
goto cleanup_handle_lsp_request;
}
/* TODO: Operations mg_fopen and mg_stat should do what their names
* indicate. They should not fill in different members of the same
* struct file.
* See Github issue #225 */
filep->size = filesize.size;
if (filep->membuf == NULL
&& (p = mmap(NULL,
(size_t)filep->size,
PROT_READ,
MAP_PRIVATE,
fileno(filep->fp),
0)) == MAP_FAILED) {
/* mmap failed */
if (ls == NULL) {
send_http_error(
conn,
500,
"Error: Cannot open script\nFile %s can not be mapped",
path);
} else {
luaL_error(ls,
"mmap(%s, %zu, %d): %s",
path,
(size_t)filep->size,
fileno(filep->fp),
strerror(errno));
}
goto cleanup_handle_lsp_request;
}
if (ls != NULL) {
L = ls;
} else {
L = lua_newstate(lua_allocator, NULL);
if (L == NULL) {
send_http_error(
conn,
500,
"%s",
"Error: Cannot execute script\nlua_newstate failed");
goto cleanup_handle_lsp_request;
}
prepare_lua_environment(
conn->ctx, conn, NULL, L, path, LUA_ENV_TYPE_LUA_SERVER_PAGE);
}
/* Lua state is ready to use */
/* We're not sending HTTP headers here, Lua page must do it. */
error = lsp(conn,
path,
(filep->membuf == NULL) ? (const char *)p
: (const char *)filep->membuf,
filep->size,
L);
cleanup_handle_lsp_request:
if (L != NULL && ls == NULL)
lua_close(L);
if (p != NULL)
munmap(p, filep->size);
mg_fclose(filep);
return error;
}
#ifdef USE_WEBSOCKET
struct mg_shared_lua_websocket_list {
struct lua_websock_data ws;
struct mg_shared_lua_websocket_list *next;
};
static void *
lua_websocket_new(const char *script, struct mg_connection *conn)
{
struct mg_shared_lua_websocket_list **shared_websock_list =
&(conn->ctx->shared_lua_websockets);
struct lua_websock_data *ws;
int err, ok = 0;
assert(conn->lua_websocket_state == NULL);
/* lock list (mg_context global) */
mg_lock_context(conn->ctx);
while (*shared_websock_list) {
/* check if ws already in list */
if (0 == strcmp(script, (*shared_websock_list)->ws.script)) {
break;
}
shared_websock_list = &((*shared_websock_list)->next);
}
if (*shared_websock_list == NULL) {
/* add ws to list */
*shared_websock_list = (struct mg_shared_lua_websocket_list *)
mg_calloc(sizeof(struct mg_shared_lua_websocket_list), 1);
if (*shared_websock_list == NULL) {
mg_unlock_context(conn->ctx);
mg_cry(conn, "Cannot create shared websocket struct, OOM");
return NULL;
}
/* init ws list element */
ws = &(*shared_websock_list)->ws;
ws->script = mg_strdup(script); /* TODO (low): handle OOM */
pthread_mutex_init(&(ws->ws_mutex), &pthread_mutex_attr);
(void)pthread_mutex_lock(&(ws->ws_mutex));
ws->state = lua_newstate(lua_allocator, NULL);
ws->conn[0] = conn;
ws->references = 1;
prepare_lua_environment(
conn->ctx, NULL, ws, ws->state, script, LUA_ENV_TYPE_LUA_WEBSOCKET);
err = luaL_loadfile(ws->state, script);
if (err != 0) {
lua_cry(conn, err, ws->state, script, "load");
}
err = lua_pcall(ws->state, 0, 0, 0);
if (err != 0) {
lua_cry(conn, err, ws->state, script, "init");
}
} else {
/* inc ref count */
ws = &(*shared_websock_list)->ws;
(void)pthread_mutex_lock(&(ws->ws_mutex));
(*shared_websock_list)->ws.conn[(ws->references)++] = conn;
}
mg_unlock_context(conn->ctx);
/* call add */
lua_getglobal(ws->state, "open");
lua_newtable(ws->state);
prepare_lua_request_info(conn, ws->state);
lua_pushstring(ws->state, "client");
lua_pushlightuserdata(ws->state, (void *)conn);
lua_rawset(ws->state, -3);
err = lua_pcall(ws->state, 1, 1, 0);
if (err != 0) {
lua_cry(conn, err, ws->state, script, "open handler");
} else {
if (lua_isboolean(ws->state, -1)) {
ok = lua_toboolean(ws->state, -1);
}
lua_pop(ws->state, 1);
}
if (!ok) {
/* Remove from ws connection list. */
/* TODO (mid): Check if list entry and Lua state needs to be deleted
* (see websocket_close). */
(*shared_websock_list)->ws.conn[--(ws->references)] = 0;
}
(void)pthread_mutex_unlock(&(ws->ws_mutex));
return ok ? (void *)ws : NULL;
}
static int
lua_websocket_data(struct mg_connection *conn,
int bits,
char *data,
size_t data_len,
void *ws_arg)
{
struct lua_websock_data *ws = (struct lua_websock_data *)(ws_arg);
int err, ok = 0;
assert(ws != NULL);
assert(ws->state != NULL);
(void)pthread_mutex_lock(&(ws->ws_mutex));
lua_getglobal(ws->state, "data");
lua_newtable(ws->state);
lua_pushstring(ws->state, "client");
lua_pushlightuserdata(ws->state, (void *)conn);
lua_rawset(ws->state, -3);
lua_pushstring(ws->state, "bits"); /* TODO: dont use "bits" but fields with
a meaning according to
http://tools.ietf.org/html/rfc6455,
section 5.2 */
lua_pushnumber(ws->state, bits);
lua_rawset(ws->state, -3);
lua_pushstring(ws->state, "data");
lua_pushlstring(ws->state, data, data_len);
lua_rawset(ws->state, -3);
err = lua_pcall(ws->state, 1, 1, 0);
if (err != 0) {
lua_cry(conn, err, ws->state, ws->script, "data handler");
} else {
if (lua_isboolean(ws->state, -1)) {
ok = lua_toboolean(ws->state, -1);
}
lua_pop(ws->state, 1);
}
(void)pthread_mutex_unlock(&(ws->ws_mutex));
return ok;
}
static int
lua_websocket_ready(struct mg_connection *conn, void *ws_arg)
{
struct lua_websock_data *ws = (struct lua_websock_data *)(ws_arg);
int err, ok = 0;
assert(ws != NULL);
assert(ws->state != NULL);
(void)pthread_mutex_lock(&(ws->ws_mutex));
lua_getglobal(ws->state, "ready");
lua_newtable(ws->state);
lua_pushstring(ws->state, "client");
lua_pushlightuserdata(ws->state, (void *)conn);
lua_rawset(ws->state, -3);
err = lua_pcall(ws->state, 1, 1, 0);
if (err != 0) {
lua_cry(conn, err, ws->state, ws->script, "ready handler");
} else {
if (lua_isboolean(ws->state, -1)) {
ok = lua_toboolean(ws->state, -1);
}
lua_pop(ws->state, 1);
}
(void)pthread_mutex_unlock(&(ws->ws_mutex));
return ok;
}
static void
lua_websocket_close(struct mg_connection *conn, void *ws_arg)
{
struct lua_websock_data *ws = (struct lua_websock_data *)(ws_arg);
struct mg_shared_lua_websocket_list **shared_websock_list =
&(conn->ctx->shared_lua_websockets);
int err = 0;
unsigned i;
assert(ws != NULL);
assert(ws->state != NULL);
(void)pthread_mutex_lock(&(ws->ws_mutex));
lua_getglobal(ws->state, "close");
lua_newtable(ws->state);
lua_pushstring(ws->state, "client");
lua_pushlightuserdata(ws->state, (void *)conn);
lua_rawset(ws->state, -3);
err = lua_pcall(ws->state, 1, 0, 0);
if (err != 0) {
lua_cry(conn, err, ws->state, ws->script, "close handler");
}
for (i = 0; i < ws->references; i++) {
if (ws->conn[i] == conn) {
ws->references--;
ws->conn[i] = ws->conn[ws->references];
}
}
/* TODO: Delete lua_websock_data and remove it from the websocket list.
This must only be done, when all connections are closed, and all
asynchronous operations and timers are completed/expired. */
(void)shared_websock_list; /* shared_websock_list unused (see open TODO) */
(void)pthread_mutex_unlock(&(ws->ws_mutex));
}
#endif
static void
lua_init_optional_libraries(void)
{
#if !defined(_WIN32)
void *dll_handle = dlopen("libuuid.so", RTLD_LAZY);
pf_uuid_generate.p = dlsym(dll_handle, "uuid_generate");
#else
pf_uuid_generate.p = 0;
#endif
}
LinuxGUI/Ventoy2Disk/Lib/libhttp/include/timer.inl
0 → 100644
View file @
43e8ec57
#if !defined(MAX_TIMERS)
#define MAX_TIMERS MAX_WORKER_THREADS
#endif
typedef int (*taction)(void *arg);
struct ttimer {
double time;
double period;
taction action;
void *arg;
};
struct ttimers {
pthread_t threadid; /* Timer thread ID */
pthread_mutex_t mutex; /* Protects timer lists */
struct ttimer timers[MAX_TIMERS]; /* List of timers */
unsigned timer_count; /* Current size of timer list */
};
static int
timer_add(struct mg_context *ctx,
double next_time,
double period,
int is_relative,
taction action,
void *arg)
{
unsigned u, v;
int error = 0;
struct timespec now;
if (ctx->stop_flag) {
return 0;
}
if (is_relative) {
clock_gettime(CLOCK_MONOTONIC, &now);
next_time += now.tv_sec;
next_time += now.tv_nsec * 1.0E-9;
}
pthread_mutex_lock(&ctx->timers->mutex);
if (ctx->timers->timer_count == MAX_TIMERS) {
error = 1;
} else {
for (u = 0; u < ctx->timers->timer_count; u++) {
if (ctx->timers->timers[u].time < next_time) {
for (v = ctx->timers->timer_count; v > u; v--) {
ctx->timers->timers[v] = ctx->timers->timers[v - 1];
}
break;
}
}
ctx->timers->timers[u].time = next_time;
ctx->timers->timers[u].period = period;
ctx->timers->timers[u].action = action;
ctx->timers->timers[u].arg = arg;
ctx->timers->timer_count++;
}
pthread_mutex_unlock(&ctx->timers->mutex);
return error;
}
static void
timer_thread_run(void *thread_func_param)
{
struct mg_context *ctx = (struct mg_context *)thread_func_param;
struct timespec now;
double d;
unsigned u;
int re_schedule;
struct ttimer t;
mg_set_thread_name("timer");
if (ctx->callbacks.init_thread) {
/* Timer thread */
ctx->callbacks.init_thread(ctx, 2);
}
#if defined(HAVE_CLOCK_NANOSLEEP) /* Linux with librt */
/* TODO */
while (clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &request, &request)
== EINTR) { /*nop*/
;
}
#else
clock_gettime(CLOCK_MONOTONIC, &now);
d = (double)now.tv_sec + (double)now.tv_nsec * 1.0E-9;
while (ctx->stop_flag == 0) {
pthread_mutex_lock(&ctx->timers->mutex);
if (ctx->timers->timer_count > 0 && d >= ctx->timers->timers[0].time) {
t = ctx->timers->timers[0];
for (u = 1; u < ctx->timers->timer_count; u++) {
ctx->timers->timers[u - 1] = ctx->timers->timers[u];
}
ctx->timers->timer_count--;
pthread_mutex_unlock(&ctx->timers->mutex);
re_schedule = t.action(t.arg);
if (re_schedule && (t.period > 0)) {
timer_add(ctx, t.time + t.period, t.period, 0, t.action, t.arg);
}
continue;
} else {
pthread_mutex_unlock(&ctx->timers->mutex);
}
mg_sleep(1);
clock_gettime(CLOCK_MONOTONIC, &now);
d = (double)now.tv_sec + (double)now.tv_nsec * 1.0E-9;
}
#endif
}
#ifdef _WIN32
static unsigned __stdcall timer_thread(void *thread_func_param)
{
timer_thread_run(thread_func_param);
return 0;
}
#else
static void *
timer_thread(void *thread_func_param)
{
timer_thread_run(thread_func_param);
return NULL;
}
#endif /* _WIN32 */
static int
timers_init(struct mg_context *ctx)
{
ctx->timers = (struct ttimers *)mg_calloc(sizeof(struct ttimers), 1);
(void)pthread_mutex_init(&ctx->timers->mutex, NULL);
/* Start timer thread */
mg_start_thread_with_id(timer_thread, ctx, &ctx->timers->threadid);
return 0;
}
static void
timers_exit(struct mg_context *ctx)
{
if (ctx->timers) {
(void)pthread_mutex_destroy(&ctx->timers->mutex);
mg_free(ctx->timers);
}
}
LinuxGUI/Ventoy2Disk/Lib/libhttp/libhttp-1.8.tar.gz
0 → 100644
View file @
43e8ec57
File added
LinuxGUI/Ventoy2Disk/Lib/xz-embedded/COPYING
0 → 100644
View file @
43e8ec57
Licensing of XZ Embedded
========================
All the files in this package have been written by Lasse Collin
and/or Igor Pavlov. All these files have been put into the
public domain. You can do whatever you want with these files.
As usual, this software is provided "as is", without any warranty.
Prev
1
2
3
4
5
6
7
8
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment