Write function for storing filetype and a few other bits
This commit is contained in:
parent
c8e73f8e13
commit
b5f571be5d
3 changed files with 223 additions and 135 deletions
|
@ -34,22 +34,35 @@
|
||||||
#define HAGGIS_H
|
#define HAGGIS_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
typedef uint64_t u64;
|
|
||||||
typedef uint32_t u32;
|
|
||||||
typedef uint16_t u16;
|
|
||||||
typedef uint8_t u8;
|
typedef uint8_t u8;
|
||||||
|
|
||||||
u64 le_bytes_to_u64(u8 arr[8]);
|
union u16 {
|
||||||
u32 le_bytes_to_u32(u8 arr[4]);
|
uint16_t val;
|
||||||
u16 le_bytes_to_u16(u8 arr[2]);
|
u8 bytes[2];
|
||||||
void u64_to_le_bytes(u64 num, u8 arr[8]);
|
};
|
||||||
void u32_to_le_bytes(u32 num, u8 arr[4]);
|
|
||||||
void u16_to_le_bytes(u16 num, u8 arr[2]);
|
union u32 {
|
||||||
|
uint32_t val;
|
||||||
|
u8 bytes[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
union u64 {
|
||||||
|
uint64_t val;
|
||||||
|
u8 bytes[8];
|
||||||
|
};
|
||||||
|
|
||||||
|
int load_u16(FILE *stream, union u16 num);
|
||||||
|
int store_u16(FILE *stream, union u16 num);
|
||||||
|
int load_u32(FILE *stream, union u32 num);
|
||||||
|
int store_u32(FILE *stream, union u32 num);
|
||||||
|
int load_u64(FILE *stream, union u64 num);
|
||||||
|
int store_u64(FILE *stream, union u64 num);
|
||||||
|
|
||||||
struct haggis_device {
|
struct haggis_device {
|
||||||
uint32_t major;
|
union u32 major;
|
||||||
uint32_t minor;
|
union u32 minor;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum haggis_algorithm {
|
enum haggis_algorithm {
|
||||||
|
@ -60,9 +73,9 @@ enum haggis_algorithm {
|
||||||
};
|
};
|
||||||
|
|
||||||
union haggis_sum {
|
union haggis_sum {
|
||||||
char md5[16];
|
u8 md5[16];
|
||||||
char sha1[20];
|
u8 sha1[20];
|
||||||
char sha256[32];
|
u8 sha256[32];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct haggis_checksum {
|
struct haggis_checksum {
|
||||||
|
@ -70,10 +83,15 @@ struct haggis_checksum {
|
||||||
union haggis_sum *sum;
|
union haggis_sum *sum;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct haggis_normal {
|
struct haggis_file {
|
||||||
uint64_t len;
|
union u64 len;
|
||||||
struct haggis_checksum *cksum;
|
struct haggis_checksum *cksum;
|
||||||
unsigned char *data[];
|
u8 *data[];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct haggis_filename {
|
||||||
|
union u16 len;
|
||||||
|
u8 name[4096];
|
||||||
};
|
};
|
||||||
|
|
||||||
enum haggis_typeflag {
|
enum haggis_typeflag {
|
||||||
|
@ -88,8 +106,8 @@ enum haggis_typeflag {
|
||||||
};
|
};
|
||||||
|
|
||||||
union haggis_ft {
|
union haggis_ft {
|
||||||
struct haggis_normal *file;
|
struct haggis_file *file;
|
||||||
char target[4096];
|
struct haggis_filename *target;
|
||||||
struct haggis_device *dev;
|
struct haggis_device *dev;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -99,10 +117,10 @@ struct haggis_filetype {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct haggis_node {
|
struct haggis_node {
|
||||||
uint32_t uid;
|
union u32 uid;
|
||||||
uint32_t gid;
|
union u32 gid;
|
||||||
uint64_t mtime;
|
union u64 mtime;
|
||||||
uint16_t mode;
|
union u16 mode;
|
||||||
struct haggis_filetype *filetype;
|
struct haggis_filetype *filetype;
|
||||||
char *name[];
|
char *name[];
|
||||||
};
|
};
|
||||||
|
|
191
src/bytes.c
191
src/bytes.c
|
@ -1,3 +1,35 @@
|
||||||
|
/* _,.---._ .-._ .--.-. ,--.--------.
|
||||||
|
* _,..---._ ,-.' , - `. /==/ \ .-._/==/ //==/, - , -\
|
||||||
|
* /==/, - \ /==/_, , - \|==|, \/ /, |==\ -\\==\.-. - ,-./
|
||||||
|
* |==| _ _\==| .=. |==|- \| | \==\- \`--`\==\- \
|
||||||
|
* |==| .=. |==|_ : ;=: - |==| , | -| `--`-' \==\_ \
|
||||||
|
* |==|,| | -|==| , '=' |==| - _ | |==|- |
|
||||||
|
* |==| '=' /\==\ - ,_ /|==| /\ , | |==|, |
|
||||||
|
* |==|-, _`/ '.='. - .' /==/, | |- | /==/ -/
|
||||||
|
* `-.`.____.' `--`--'' `--`./ `--` `--`--`
|
||||||
|
* _ __ ,---. .-._ .=-.-. _,.----.
|
||||||
|
* .-`.' ,`..--.' \ /==/ \ .-._ /==/_ /.' .' - \
|
||||||
|
* /==/, - \==\-/\ \ |==|, \/ /, /==|, |/==/ , ,-'
|
||||||
|
* |==| _ .=. /==/-|_\ | |==|- \| ||==| ||==|- | .
|
||||||
|
* |==| , '=',\==\, - \ |==| , | -||==|- ||==|_ `-' \
|
||||||
|
* |==|- '..'/==/ - ,| |==| - _ ||==| ,||==| _ , |
|
||||||
|
* |==|, | /==/- /\ - \|==| /\ , ||==|- |\==\. /
|
||||||
|
* /==/ - | \==\ _.\=\.-'/==/, | |- |/==/. / `-.`.___.-'
|
||||||
|
* `--`---' `--` `--`./ `--``--`-`
|
||||||
|
*
|
||||||
|
* @(#)Copyright (c) 2023, Nathan D. Fisher.
|
||||||
|
*
|
||||||
|
* This is free software. It comes with NO WARRANTY.
|
||||||
|
* Permission to use, modify and distribute this source code
|
||||||
|
* is granted subject to the following conditions.
|
||||||
|
* 1/ that the above copyright notice and this notice
|
||||||
|
* are preserved in all copies and that due credit be given
|
||||||
|
* to the author.
|
||||||
|
* 2/ that any changes to this code are clearly commented
|
||||||
|
* as such so that the author does not get blamed for bugs
|
||||||
|
* other than his own.
|
||||||
|
*/
|
||||||
|
|
||||||
#include <endian.h>
|
#include <endian.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
@ -5,121 +37,92 @@
|
||||||
#include "haggis.h"
|
#include "haggis.h"
|
||||||
|
|
||||||
#if __BYTE_ORDER__ == __LITTLE_ENDIAN
|
#if __BYTE_ORDER__ == __LITTLE_ENDIAN
|
||||||
u64 le_bytes_to_u64(u8 arr[8]) {
|
int load_u16(FILE *stream, union u16 num) {
|
||||||
return (u64)arr[7] << 56 |
|
return fread(num.bytes, 1, 2, stream);
|
||||||
(u64)arr[6] << 48 |
|
|
||||||
(u64)arr[5] << 40 |
|
|
||||||
(u64)arr[4] << 32 |
|
|
||||||
(u64)arr[3] << 24 |
|
|
||||||
(u64)arr[2] << 16 |
|
|
||||||
(u64)arr[1] << 8 |
|
|
||||||
(u64)arr[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 le_bytes_to_u32(u8 arr[4]) {
|
int store_u16(FILE *stream, union u16 num) {
|
||||||
return (u32)arr[3] << 24 |
|
return fwrite(num.bytes, 1, 2, stream);
|
||||||
(u32)arr[2] << 16 |
|
|
||||||
(u32)arr[1] << 8 |
|
|
||||||
(u32)arr[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 le_bytes_to_u16(u8 arr[2]) {
|
int load_u32(FILE *stream, union u32 num) {
|
||||||
return (u32)arr[1] << 8 | (u32)arr[0];
|
return fread(num.bytes, 1, 4, stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
void u64_to_le_bytes(u64 num, u8 arr[8]) {
|
int store_u32(FILE *stream, union u32 num) {
|
||||||
u64 eighth = (num & 0xFF00000000000000) >> 56;
|
return fwrite(num.bytes, 1, 4, stream);
|
||||||
u64 seventh = (num & 0xFF000000000000) >> 48;
|
|
||||||
u64 sixth = (num & 0xFF0000000000) >> 40;
|
|
||||||
u64 fifth = (num & 0xFF00000000) >> 32;
|
|
||||||
u64 fourth = (num & 0xFF000000) >> 24;
|
|
||||||
u64 third = (num & 0xFF0000) >> 16;
|
|
||||||
u64 second = (num & 0xFF00) >> 8;
|
|
||||||
u64 first = num & 0xFF;
|
|
||||||
arr[0] = (u8)first;
|
|
||||||
arr[1] = (u8)second;
|
|
||||||
arr[2] = (u8)third;
|
|
||||||
arr[3] = (u8)fourth;
|
|
||||||
arr[4] = (u8)fifth;
|
|
||||||
arr[5] = (u8)sixth;
|
|
||||||
arr[6] = (u8)seventh;
|
|
||||||
arr[7] = (u8)eighth;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void u32_to_le_bytes(u32 num, u8 arr[4]) {
|
int load_u64(FILE *stream, union u64 num) {
|
||||||
u32 fourth = (num & 0xFF000000) >> 24;
|
return fread(num.bytes, 1, 8, stream);
|
||||||
u32 third = (num & 0xFF0000) >> 16;
|
|
||||||
u32 second = (num & 0xFF00) >> 8;
|
|
||||||
u32 first = num & 0xFF;
|
|
||||||
arr[0] = (u8)first;
|
|
||||||
arr[1] = (u8)second;
|
|
||||||
arr[2] = (u8)third;
|
|
||||||
arr[3] = (u8)fourth;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void u16_to_le_bytes(u16 num, u8 arr[2]) {
|
int store_u64(FILE *stream, union u64 num) {
|
||||||
u16 second = (num & 0xFF00) >> 8;
|
return fwrite(num.bytes, 1, 8, stream);
|
||||||
u16 first = num & 0xFF;
|
|
||||||
arr[0] = (u8)first;
|
|
||||||
arr[1] = (u8)second;
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
u64 le_bytes_to_u64(u8 arr[8]) {
|
int load_u16(FILE *stream, union u16 num) {
|
||||||
return (u64)arr[0] << 56 |
|
u8 buf[2];
|
||||||
(u64)arr[1] << 48 |
|
int res = fread(buf, 1, 2, stream);
|
||||||
(u64)arr[2] << 40 |
|
if (res != 2)
|
||||||
(u64)arr[3] << 32 |
|
return res;
|
||||||
(u64)arr[4] << 24 |
|
num.bytes[0] = buf[1];
|
||||||
(u64)arr[5] << 16 |
|
num.bytes[1] = buf[0];
|
||||||
(u64)arr[6] << 8 |
|
return res;
|
||||||
(u64)arr[7];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 le_bytes_to_u32(u8 arr[4]) {
|
int store_u16(FILE * stream, union u16 num) {
|
||||||
return (u32)arr[0] << 24 |
|
u8 buf[2];
|
||||||
(u32)arr[1] << 16 |
|
buf[0] = num.bytes[1];
|
||||||
(u32)arr[2] << 8 |
|
buf[1] = num.bytes[0];
|
||||||
(u32)arr[3];
|
return fwrite(buf, 1, 2, stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 le_bytes_to_u16(u8 arr[2]) {
|
int load_u32(FILE *stream, union u32 num) {
|
||||||
return (u32)arr[0] << 8 | (u32)arr[1];
|
u8 buf[4];
|
||||||
|
int res = fread(buf, 1, 4, stream);
|
||||||
|
if (res != 4)
|
||||||
|
return res;
|
||||||
|
num.bytes[0] = buf[3];
|
||||||
|
num.bytes[1] = buf[2];
|
||||||
|
num.bytes[2] = buf[1];
|
||||||
|
num.bytes[3] = buf[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
void u64_to_le_bytes(u64 num, u8 arr[8]) {
|
int store_u32(FILE *stream, union u32 num) {
|
||||||
u64 first = (num & 0xFF00000000000000) >> 56;
|
u8 buf[4];
|
||||||
u64 second = (num & 0xFF000000000000) >> 48;
|
buf[0] = num.bytes[3];
|
||||||
u64 third = (num & 0xFF0000000000) >> 40;
|
buf[1] = num.bytes[2];
|
||||||
u64 fourth = (num & 0xFF00000000) >> 32;
|
buf[2] = num.bytes[1];
|
||||||
u64 fifth = (num & 0xFF000000) >> 24;
|
buf[3] = num.bytes[0];
|
||||||
u64 sixth = (num & 0xFF0000) >> 16;
|
return fwrite(buf, 1, 2, stream);
|
||||||
u64 seventh = (num & 0xFF00) >> 8;
|
|
||||||
u64 eighth = num & 0xFF;
|
|
||||||
arr[0] = (u8)first;
|
|
||||||
arr[1] = (u8)second;
|
|
||||||
arr[2] = (u8)third;
|
|
||||||
arr[3] = (u8)fourth;
|
|
||||||
arr[4] = (u8)fifth;
|
|
||||||
arr[5] = (u8)sixth;
|
|
||||||
arr[6] = (u8)seventh;
|
|
||||||
arr[7] = (u8)eighth;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void u32_to_le_bytes(u32 num, u8 arr[4]) {
|
int load_u64(FILE *stream, union u64 num) {
|
||||||
u32 first = (num & 0xFF000000) >> 24;
|
u8 buf[8];
|
||||||
u32 second = (num & 0xFF0000) >> 16;
|
int res = fread(buf, 1, 8, stream);
|
||||||
u32 third = (num & 0xFF00) >> 8;
|
if (res != 8)
|
||||||
u32 fourth = num & 0xFF;
|
return res;
|
||||||
arr[0] = (u8)first;
|
num.bytes[0] = buf[7];
|
||||||
arr[1] = (u8)second;
|
num.bytes[1] = buf[6];
|
||||||
arr[2] = (u8)third;
|
num.bytes[2] = buf[5];
|
||||||
arr[3] = (u8)fourth;
|
num.bytes[3] = buf[4];
|
||||||
|
num.bytes[4] = buf[3];
|
||||||
|
num.bytes[5] = buf[2];
|
||||||
|
num.bytes[6] = buf[1];
|
||||||
|
num.bytes[7] = buf[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
void u16_to_le_bytes(u16 num, u8 arr[2]) {
|
int store_u64(FILE *stream, union u64 num) {
|
||||||
u16 first = (num & 0xFF00) >> 8;
|
u8 buf[8];
|
||||||
u16 second = num & 0xFF;
|
buf[0] = num.bytes[7];
|
||||||
arr[0] = (u8)first;
|
buf[1] = num.bytes[6];
|
||||||
arr[1] = (u8)second;
|
buf[2] = num.bytes[5];
|
||||||
|
buf[3] = num.bytes[4];
|
||||||
|
buf[4] = num.bytes[3];
|
||||||
|
buf[5] = num.butes[2];
|
||||||
|
buf[6] = num.bytes[1];
|
||||||
|
buf[7] = num.bytes[0];
|
||||||
|
return fwrite(buf, 1, 2, stream);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
103
src/haggis.c
103
src/haggis.c
|
@ -30,6 +30,7 @@
|
||||||
* other than his own.
|
* other than his own.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
@ -53,26 +54,18 @@ int haggis_check_header(FILE *stream) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int haggis_store_device(FILE *stream, struct haggis_device *dev) {
|
int haggis_store_device(FILE *stream, struct haggis_device *dev) {
|
||||||
u8 major[4];
|
if (fwrite(dev->major.bytes, 1, 4, stream) != 4)
|
||||||
u8 minor[4];
|
|
||||||
u32_to_le_bytes(dev->major, major);
|
|
||||||
u32_to_le_bytes(dev->minor, minor);
|
|
||||||
if (fwrite(major, 1, 4, stream) != 4)
|
|
||||||
return 1;
|
return 1;
|
||||||
if (fwrite(minor, 1, 4, stream) != 4)
|
if (fwrite(dev->minor.bytes, 1, 4, stream) != 4)
|
||||||
return 1;
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int haggis_load_device(FILE *stream, struct haggis_device *dev) {
|
int haggis_load_device(FILE *stream, struct haggis_device *dev) {
|
||||||
u8 major[4];
|
if (fread(dev->major.bytes, 1, 4, stream) != 4)
|
||||||
u8 minor[4];
|
|
||||||
if (fread(major, 1, 4, stream) != 4)
|
|
||||||
return 1;
|
return 1;
|
||||||
if (fread(minor, 1, 4, stream) != 4)
|
if (fread(dev->minor.bytes, 1, 4, stream) != 4)
|
||||||
return 1;
|
return 1;
|
||||||
dev->major = le_bytes_to_u32(major);
|
|
||||||
dev->minor = le_bytes_to_u32(minor);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,7 +103,6 @@ int haggis_store_cksum(FILE *stream, struct haggis_checksum *cksum) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int haggis_load_cksum(FILE *stream, struct haggis_checksum *cksum) {
|
int haggis_load_cksum(FILE *stream, struct haggis_checksum *cksum) {
|
||||||
// todo
|
|
||||||
char flag;
|
char flag;
|
||||||
if (fread(&flag, 1, 1, stream) != 1)
|
if (fread(&flag, 1, 1, stream) != 1)
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -137,18 +129,94 @@ int haggis_load_cksum(FILE *stream, struct haggis_checksum *cksum) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int haggis_store_file(FILE *stream, struct haggis_normal *file) {
|
int haggis_validate_cksum(struct haggis_file *file) {
|
||||||
// todo
|
// todo
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int haggis_load_file(FILE *stream, struct haggis_normal *file) {
|
int haggis_store_file(FILE *stream, struct haggis_file *file) {
|
||||||
// todo
|
if (store_u64(stream, file->len) != 8)
|
||||||
|
return 1;
|
||||||
|
if (haggis_store_cksum(stream, file->cksum) != 0)
|
||||||
|
return 1;
|
||||||
|
int res = fwrite(file->data, 1, (size_t)file->len.val, stream);
|
||||||
|
if (res != (size_t)file->len.val)
|
||||||
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int haggis_load_file(FILE *stream, struct haggis_file *file) {
|
||||||
|
if (load_u64(stream, file->len) != 8)
|
||||||
|
return 1;
|
||||||
|
if (haggis_load_cksum(stream, file->cksum) != 0)
|
||||||
|
return 1;
|
||||||
|
int res = fread(file->data, 1, (size_t)file->len.val, stream);
|
||||||
|
if (res != (size_t)file->len.val)
|
||||||
|
return 1;
|
||||||
|
return haggis_validate_cksum(file);
|
||||||
|
}
|
||||||
|
|
||||||
int haggis_store_filetype(FILE *stream, struct haggis_filetype *filetype) {
|
int haggis_store_filetype(FILE *stream, struct haggis_filetype *filetype) {
|
||||||
// todo
|
size_t len;
|
||||||
|
u8 flag;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
switch (filetype->tag) {
|
||||||
|
case normal:
|
||||||
|
flag = 0;
|
||||||
|
if (fwrite(&flag, 1, 1, stream) != 1)
|
||||||
|
return 1;
|
||||||
|
if (haggis_store_file(stream, filetype->f_type->file) != 0)
|
||||||
|
return 1;
|
||||||
|
break;
|
||||||
|
case hardlink:
|
||||||
|
flag = 1;
|
||||||
|
if (fwrite(&flag, 1, 1, stream) != 1)
|
||||||
|
return 1;
|
||||||
|
len = (size_t)filetype->f_type->target->len.val;
|
||||||
|
res = fwrite(filetype->f_type->target->name, 1, len, stream);
|
||||||
|
if (res != (size_t)len)
|
||||||
|
return 1;
|
||||||
|
break;
|
||||||
|
case softlink:
|
||||||
|
flag = 2;
|
||||||
|
if (fwrite(&flag, 1, 1, stream) != 1)
|
||||||
|
return 1;
|
||||||
|
len = (size_t)filetype->f_type->target->len.val;
|
||||||
|
res = fwrite(filetype->f_type->target->name, 1, len, stream);
|
||||||
|
if (res != (size_t)len)
|
||||||
|
return 1;
|
||||||
|
break;
|
||||||
|
case directory:
|
||||||
|
flag = 3;
|
||||||
|
if (fwrite(&flag, 1, 1, stream) != 1)
|
||||||
|
return 1;
|
||||||
|
break;
|
||||||
|
case character:
|
||||||
|
flag = 4;
|
||||||
|
if (fwrite(&flag, 1, 1, stream) != 1)
|
||||||
|
return 1;
|
||||||
|
if (haggis_store_device(stream, filetype->f_type->dev) != 0)
|
||||||
|
return 1;
|
||||||
|
break;
|
||||||
|
case block:
|
||||||
|
flag = 5;
|
||||||
|
if (fwrite(&flag, 1, 1, stream) != 1)
|
||||||
|
return 1;
|
||||||
|
if (haggis_store_device(stream, filetype->f_type->dev) != 0)
|
||||||
|
return 1;
|
||||||
|
break;
|
||||||
|
case fifo:
|
||||||
|
flag = 6;
|
||||||
|
if (fwrite(&flag, 1, 1, stream) != 1)
|
||||||
|
return 1;
|
||||||
|
break;
|
||||||
|
case eof:
|
||||||
|
flag = 7;
|
||||||
|
if (fwrite(&flag, 1, 1, stream) != 1)
|
||||||
|
return 1;
|
||||||
|
break;
|
||||||
|
};
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,4 +234,3 @@ int haggis_load_node(FILE *stream, struct haggis_node *node) {
|
||||||
// todo
|
// todo
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue