C - Read struct in file - c

Hi I want to read some information in a struct that i wrote in file with fwrite but there's a problem I can't extract these information. I got 2 file
tttfs.h :
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
typedef struct _disk disk;
typedef struct _block block;
struct _block{
uint8_t *unBlock;
};
struct _disk{
int id;
block *diskBlock;
};
tfs_create.c :
#include "tttfs.h"
uint8_t little[4];
int tttfs_create(int size, char *name);
void inttolitend(uint32_t x, uint8_t* lit_int);
int main(){
tttfs_create(7, "disk.tfs");
int f = 0;
if((f=open("disk.tfs",O_RDONLY)) < -1) //I took this from an example.
return 1;
disk *d = malloc(sizeof(disk)); //Create a disk
d->diskBlock = malloc(1024); //The block where I want to write the information from the file.
lseek(f,0,SEEK_SET);//I want to read from the beginning
read(f,d->diskBlock,1024); //I write all the information from the beginning to 1024th byte of my file
int i;
for(i=0; i<4; i++){
printf("%d\n", (uint8_t)&d->diskBlock[i]);//print my result.
}
}
int tttfs_create(int size, char *name){
FILE *f = NULL;
if ((f = fopen(name, "wb"))!=NULL) /** si ouverture ok **/
{
disk *d = malloc(sizeof(disk));
d->diskBlock = malloc(sizeof(block) * size);
d->id = 1;
int i;
for(i = 0; i<size; i++){
d->diskBlock[i].unBlock = malloc(sizeof(uint8_t) * 1024);
}
inttolitend(size, little);
for(i = 0; i<4; i++){
d->diskBlock[0].unBlock[i] = little[i];
}
for(i = 0; i<size; i++){
fwrite(&d->diskBlock[i],sizeof(block),1,f);
}
}
else
printf("Erreur\n\n");
return 0;
}
void inttolitend(uint32_t x, uint8_t* lit_int){
lit_int[3] = (uint8_t)x / (256*256*256);
lit_int[2] = (uint8_t)(x % (256*256*256)) / (256*256);
lit_int[1] = (uint8_t)((x % (256*256*256)) % (256*256)) / 256;
lit_int[0] = (uint8_t)((x % (256*256*256)) % (256*256)) % 256;
}
With this I create a disk with 7 block and I write all 7 block in my file. In my first block I wrote the size of my disk (7) in little endian. So block[0] = 00, block[1] = 00, block[2] = 01, block[3] = 11 or something like that.
But when I print my result I get :
0
8
16
24
Not what I expected I try without readand i got the same result. So my programm didn't write the information from the disk. Or there's a problem when I write my block in the disk ?

i can not be so sure what you want exactly but this should work
#define BLOCK_BUFF_SIZE (1024*sizeof(block))
int tttfs_create(int size, char *name);
int tttfs_load(char *fname, disk *pdisk)
void inttolitend(uint32_t x, uint8_t* lit_int);
int tttfs_load(char *fname, disk *pdisk){
int fd;
unsigned int n;
int i;
fd = open("disk.tfs",_O_RDONLY);
if(fd==-1){
perror("tttfs_load.open");
return -1;
}
n=lseek (fd,0,SEEK_END);
lseek(fd,0,SEEK_SET);
if(n==(unsigned int)-1){
close(fd);
return -1;
}
if(n){
n/=(BLOCK_BUFF_SIZE);
pdisk->diskBlock=malloc(n*sizeof(block));
for(i=0;i<n;i++){
pdisk->diskBlock[i].unBlock=malloc(BLOCK_BUFF_SIZE);
read(fd,pdisk->diskBlock[i].unBlock,BLOCK_BUFF_SIZE);
}
}
close(fd);
return n;
}
int main(){
unsigned int n;
disk d;
int i;
tttfs_create(7, "disk.tfs");
n=tttfs_load("disk.tfs",&d);
if(!n || n==(-1)) return -1;
for(i=0; i<4; i++){
printf("%d\n", (uint8_t)(d.diskBlock->unBlock[i]));//print my result.
}
}
int tttfs_create(int size, char *name){
FILE *f = NULL;
disk d;
int i;
if (!(f = fopen(name, "wb"))) {
perror("tttfs_create:open()");
return 0;
}
d.diskBlock = malloc(sizeof(block) * size);
d.id = 1;
for(i = 0; i<size; i++){
d.diskBlock[i].unBlock = malloc(BLOCK_BUFF_SIZE);
}
inttolitend(size, (uint8_t*)(d.diskBlock->unBlock));
for(i=0;i<size;i++){
fwrite(d.diskBlock[i].unBlock ,BLOCK_BUFF_SIZE,1,f);
}
return 1;
}
void inttolitend(uint32_t x, uint8_t* lit_int){
lit_int[3] = ((x<<24) & 0xff);
lit_int[2] = ((x<<16) & 0xff);
lit_int[1] = ((x<<8) & 0xff);
lit_int[0] = ((x<<0) & 0xff);
}

Related

Get value at memory address of a process and modify it

I was trying to emulate what Cheat Engine does on mac os in getting the memory address from values and modifying it. I have done this so far:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <libproc.h>
#include <mach/mach_init.h>
// Get array of all process ids
uint32_t* get_pids(uint16_t* size) {
uint32_t number_of_pids = proc_listpids(1, 0, NULL, 0);
uint32_t* buffer = malloc(sizeof(uint32_t) * number_of_pids);
uint8_t return_code = proc_listpids(1, 0, buffer, sizeof(buffer) * number_of_pids);
uint16_t sum = 0;
for(int i = 0; i < number_of_pids; i++) {
if(buffer[i] != 0) {
sum++;
}
}
uint32_t* final = malloc(sizeof(uint32_t) * sum);
for(int i = 0, t = 0; i < number_of_pids; i++) {
if(buffer[i]) {
final[t++] = buffer[i];
}
}
*size = sum;
return final;
}
int main() {
uint16_t size;
uint32_t* pids = get_pids(&size);
uint16_t maxpathlength = 1024;
uint16_t path_size = maxpathlength * 4;
char path_buffer[path_size];
uint32_t pid = 0;
for(int i = 0; i < size; i++) {
memset(path_buffer, '\0', sizeof(path_buffer));
uint8_t return_code = proc_pidpath(pids[i], path_buffer, path_size);
if(strstr(path_buffer, "Geometry Dash")) {
pid = pids[i];
}
//printf("PID: %d, Process: %s\n", pids[i], path_buffer);
}
mach_port_name_t port = 0;
if(task_for_pid(mach_task_self(), pid, &port)) {
printf("Run as root!\n");
}
printf("%d\n", port);
return 0;
}
So I got there and now have the mach port of the target pid however I am not sure where to go from here as I have found practically 0 good documentation on the mach_vm methods and anything I try fails. How should I go about doing this?

Unable to sequentially process a file > 250kb using Windows file mapping with n-sized chunks

I am trying to make a software that takes a txt file and xor every 4 byte with a pre-defined number.
I am doing this mapping the file in memory and opening chunks of the file with MapViewOfFile of size n.
The algorithm I'm attaching works well for txt files of less than 250 kb. But for file > 250kb it only xor some parts of the file and I cannot understand why and how to fix this.
Can someone help me?
#include "stdafx.h"
#include "Windows.h"
#include <stdio.h>
#include <stdint.h>
#include <iso646.h>
#include <math.h>
unsigned int strToUl(char *s)
{
int size = 4;
unsigned int ul = 0;
memcpy(&ul, (unsigned int *)s, size);
return ul;
}
char *ulToStr(unsigned int *ul)
{
int size = 4;
char *tch = (char *)calloc(size, sizeof(char *));
memcpy(tch, (char *)ul, size);
return tch;
}
unsigned int uixor(unsigned int n, unsigned int seed)
{
srand(seed);
unsigned int mask = rand();
char ch[5] = { 0 };
strcpy_s(ch, 5, ulToStr(&n));
for (int j = 0; j < 5; j++)
{
ch[j] = ch[j] ^ mask;
}
return strToUl(ch);
}
BOOL mapWriteChunk(PHANDLE phFile, DWORD dwFileSize, int start, int buffsize, uint32_t xork)
{
DWORD offset = start;// / 4;// / sizeof(DWORD);
SYSTEM_INFO SysInfo;
GetSystemInfo(&SysInfo);
DWORD dwSysGran = SysInfo.dwAllocationGranularity;
DWORD dwFileMapStart = (offset/dwSysGran) * dwSysGran;
DWORD dwMapViewSize = (offset % dwSysGran) + buffsize;
DWORD dwFileMapSize = offset + buffsize;
unsigned int *ulMVBuffer = (unsigned int *)MapViewOfFile(*phFile, FILE_MAP_ALL_ACCESS, 0, dwFileMapStart, 0);
if (ulMVBuffer == NULL)
{
printf("ulMVBuffer = NULL\n");
}
int iViewDelta = offset - dwFileMapStart;
for (int i = 0; i < buffsize; i++)
{
unsigned int *u = (unsigned int *)ulMVBuffer + (iViewDelta + i);
unsigned int u1 = *u;
unsigned int u2 = uixor(u1, xork);
*u = u2;
printf("write on %d -> ", iViewDelta);
}
UnmapViewOfFile(ulMVBuffer);
return TRUE;
}
int main()
{
char name[] = "test.txt";
OFSTRUCT tOfStrIn;
tOfStrIn.cBytes = sizeof tOfStrIn;
HANDLE hFile = (HANDLE)OpenFile(name, &tOfStrIn, OF_READWRITE);
DWORD dwFileSize = GetFileSize(hFile, NULL);
HANDLE hFileMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, dwFileSize, NULL);
if (hFileMap == NULL)
{
printf("hFileMap = NULL\n");
}
int pos = 0;
int chunk = 4;
int bSize = dwFileSize / sizeof(DWORD);
int rseed = 10;
for (pos = 0; pos < bSize; pos+=chunk)
{
mapWriteChunk(&hFileMap, dwFileSize, pos, chunk, rseed);
}
CloseHandle(hFile);
CloseHandle(hFileMap);
system("PAUSE");
return 0;
}
Ok, I figured out the problem and I'm writing here so anyone who have the same problem, know what's wrong.
Talk is cheap, I show you the code (and then I'll explain):
char *ulMVBuffer = (char *)MapViewOfFile(phFile, FILE_MAP_ALL_ACCESS, 0, dwFileMapStart, 0);
if (ulMVBuffer == NULL)
{
printf("ulMVBuffer = NULL\n");
}
int iViewDelta = offset - dwFileMapStart;
unsigned int mask = myrand(xork);
for(int i = 0; i < buffsize; i++)
{
unsigned int c = ulMVBuffer[iViewDelta + i] ^ mask;
ulMVBuffer[iViewDelta + i] = c;
}
So you have to map the memory using a char pointer and then, when you use the XOR operator like that:
unsigned int c = ulMVBuffer[iViewDelta + i] ^ mask;
You obtain the XOR to be applied to a group of 4 bytes and not only on 1 byte, because - as far as I understood playing around - the XOR between a char (1 byte) and a unsigned int (4 bytes) forces the operator to pick 3 more bytes from the memory and use it for the bitwise operation.
This wasn't working using a pointer to unsigned int because, I guess, it stored the bytes from the memory in a different fashion (maybe OS or machine dependent?) and so you were able to XOR only 1 byte every 4 and not groups of 4 bytes all together.
If anyone has a better understanding to this or wants to add more to this solution, I will be more than happy to read it!

Difference in behavior between clang and gcc?

I'm writing a C function to simulate a cache given an address trace. The function works as expected when compiled on my mac using gcc (really clang). gcc --version on my mac returns this:
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 8.1.0 (clang-802.0.42)
When I compile the same program on linux using gcc, the returns are way off, and eC & hC in my program (cache eviction counter and hit counter) are in the hundreds of thousands, when they should be below 10. When typing gcc --version on the linux machine, it returns this:
gcc (Ubuntu 4.9.3-8ubuntu2~14.04) 4.9.3
Here is the program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <limits.h>
#include <getopt.h>
#include "cachelab.h"
typedef struct{
int v;
int t;
int LRU;
} block;
typedef struct{
block *blocks;
} set;
typedef struct{
set *sets;
} cache;
void simulate(int s, int E, int b, char* file, int* hC, int* mC, int* eC)
{
int numSets = (1 << s);
char operation;
int address;
int size;
int curTag;
int curSet;
int maxLRU = 0;
int curLRU = 0;
int check = 0;
cache c;
set *sets = malloc(sizeof(set) * numSets);
c.sets = sets;
int i = 0;
while(i < numSets)
{
c.sets[i].blocks = malloc(sizeof(block) * E);
for (int j = 0; j < E; j++)
{
c.sets[i].blocks[j].v = 0;
c.sets[i].blocks[j].t = INT_MIN;
c.sets[i].blocks[j].LRU = 0;
}
i++;
}
FILE *f = fopen(file, "r");
while(fscanf(f," %c %x,%d", &operation, &address, &size) != EOF)
{
check = 0;
curTag = ((unsigned int) address) >> (s+b);
curSet = (address >> b) & ((1 << s) - 1);
for (int i = 0; i < E; i++)
{
c.sets[curSet].blocks[i].LRU++;
if(c.sets[curSet].blocks[i].LRU >= maxLRU)
{
maxLRU = c.sets[curSet].blocks[i].LRU;
curLRU = i;
}
if(curTag == c.sets[curSet].blocks[i].t)
{
*hC = *hC + 1;
if (operation == 'M')
{
*hC = *hC + 1;
}
c.sets[curSet].blocks[i].LRU = 0;
check = 1;
}
}
if(check == 0)
{
for(int i = 0; i < E; i++)
{
if(c.sets[curSet].blocks[i].v == 0)
{
*mC = *mC + 1;
if (operation == 'M')
{
*hC = *hC + 1;
}
c.sets[curSet].blocks[i].v = 1;
c.sets[curSet].blocks[i].LRU = 0;
c.sets[curSet].blocks[i].t = curTag;
check = 1;
break;
}
}
}
if(check == 0)
{
*eC = *eC + 1;
*mC = *mC + 1;
if (operation == 'M')
{
*hC = *hC + 1;
}
c.sets[curSet].blocks[curLRU].t = curTag;
c.sets[curSet].blocks[curLRU].v = 1;
c.sets[curSet].blocks[curLRU].LRU = 0;
}
}
}
int main(int argc, char** argv)
{
int hitCount, missCount, evictionCount;
int s, E, b;
char *file;
char opt;
while((opt = getopt(argc,argv,"v:h:s:E:b:t:")) != -1)
{
switch(opt){
case 'v':
break;
case 'h':
break;
case 's':
s = atoi(optarg);
break;
case 'E':
E = atoi(optarg);
break;
case 'b':
b = atoi(optarg);
break;
case 't':
file = optarg;
break;
default:
exit(1);
}
}
simulate(s, E, b, file, &hitCount, &missCount, &evictionCount);
printSummary(hitCount, missCount, evictionCount);
return 0;
}
EDIT:
I understand that this is due to a difference between clang and gcc. Does anyone have any information about how I can go about fixing this discrepancy?
Here is cachelab.c:
/*
* cachelab.c - Cache Lab helper functions
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "cachelab.h"
#include <time.h>
trans_func_t func_list[MAX_TRANS_FUNCS];
int func_counter = 0;
/*
* printSummary - Summarize the cache simulation statistics. Student cache simulators
* must call this function in order to be properly autograded.
*/
void printSummary(int hits, int misses, int evictions)
{
printf("hits:%d misses:%d evictions:%d\n", hits, misses, evictions);
FILE* output_fp = fopen(".csim_results", "w");
assert(output_fp);
fprintf(output_fp, "%d %d %d\n", hits, misses, evictions);
fclose(output_fp);
}
/*
* initMatrix - Initialize the given matrix
*/
void initMatrix(int M, int N, int A[N][M], int B[M][N])
{
int i, j;
srand(time(NULL));
for (i = 0; i < N; i++){
for (j = 0; j < M; j++){
// A[i][j] = i+j; /* The matrix created this way is symmetric */
A[i][j]=rand();
B[j][i]=rand();
}
}
}
void randMatrix(int M, int N, int A[N][M]) {
int i, j;
srand(time(NULL));
for (i = 0; i < N; i++){
for (j = 0; j < M; j++){
// A[i][j] = i+j; /* The matrix created this way is symmetric */
A[i][j]=rand();
}
}
}
/*
* correctTrans - baseline transpose function used to evaluate correctness
*/
void correctTrans(int M, int N, int A[N][M], int B[M][N])
{
int i, j, tmp;
for (i = 0; i < N; i++){
for (j = 0; j < M; j++){
tmp = A[i][j];
B[j][i] = tmp;
}
}
}
/*
* registerTransFunction - Add the given trans function into your list
* of functions to be tested
*/
void registerTransFunction(void (*trans)(int M, int N, int[N][M], int[M][N]),
char* desc)
{
func_list[func_counter].func_ptr = trans;
func_list[func_counter].description = desc;
func_list[func_counter].correct = 0;
func_list[func_counter].num_hits = 0;
func_list[func_counter].num_misses = 0;
func_list[func_counter].num_evictions =0;
func_counter++;
}
You forgot to initialize the counters and flags so they start at undefined values. The following lines:
int hitCount, missCount, evictionCount;
int s, E, b;
should be:
int hitCount = 0, missCount = 0, evictionCount = 0;
int s = 0, E = 0, b = 0;
It just happens that the initial values happen to be lower on the mac so you're not getting correct results on the mac either (at least not guaranteed since the initial value is undefined).

C - Segmentation fault : 11

Hi I have to do a simulation of disk for my university.
I got 2 file :
tttfs.h :
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
typedef struct _disk disk;
typedef struct _block block;
struct _block{
uint8_t *unBlock;
};
struct _disk{
int id;
block *diskBlock;
};
tfs_create.c :
#include "tttfs.h"
uint8_t little[4];
int tttfs_create(int size, char *name);
void inttolitend(uint32_t x, uint8_t* lit_int);
int main(){
tttfs_create(7, "disk.tfs");
}
int tttfs_create(int size, char *name){
FILE *f = NULL;
if ((f = fopen(name, "wb"))!=NULL)
{
disk *d = malloc(sizeof(disk));
d->diskBlock = malloc(1024);
d->id = 1;
int i;
for(i = 0; i<size; i++){
printf("%d\n", i);
d->diskBlock[i].unBlock = malloc(1024); //I got the segmentation fault here
}
inttolitend(size, little);
for(i = 0; i<4; i++){
d->diskBlock[0].unBlock[i] = little[i];
}
for(i = 0; i<size; i++){
fwrite(&d->diskBlock[i],1024,1,f);
}
}
else
printf("Erreur\n\n");
return 0;
}
void inttolitend(uint32_t x, uint8_t* lit_int){
lit_int[3] = (uint8_t)x / (256*256*256);
lit_int[2] = (uint8_t)(x % (256*256*256)) / (256*256);
lit_int[1] = (uint8_t)((x % (256*256*256)) % (256*256)) / 256;
lit_int[0] = (uint8_t)((x % (256*256*256)) % (256*256)) % 256;
}
I want to write in a file a number of block (here 7), so I do malloc on size of my disk struct and then I do a malloc on diskBlock to make a table d->diskBlock[0].unBlock = malloc(1024); but not for more. how could I do a block[size] with my struct ? (I'm not good in c)
I think you should change this line
d->diskBlock = malloc(1024);
to
d->diskBlock = malloc(sizeof(block) * size);
And, this
d->diskBlock[i].unBlock = malloc(1024);
to
d->diskBlock[i].unBlock = malloc(sizeof(uint8_t) * 4);

How to undo changes to an array after passing to a function

Is there any way to undo the actions or get the original array after I changed the array as shown below.
#include <stdio.h>
void function(int array[]){
array[2] = 20;
//do some extra work
return;
}
int main(void){
int array[5] = {1,2,3,4,5};
function(array);
// code which has to use original array
return 0;
}
You can pack two 32 bit integers (old / new) into a 64 bit integer, example:
#include <stdio.h>
#include <stdint.h>
void function(int64_t array[])
{
array[2] = (array[2] << 32) | 20;
}
void printarr(int64_t array[], size_t n)
{
size_t i;
for (i = 0; i < n; i++) {
printf("%d ", (int32_t)(array[i]));
}
printf("\n");
}
int main(void)
{
int64_t array[] = {1, 2, 3, 4, 5};
size_t i, n = sizeof(array) / sizeof(array[0]);
function(array);
puts("After function:");
printarr(array, n);
for (i = 0; i < n; i++) {
if (array[i] >> 32 != 0) /* Changed */
array[i] = array[i] >> 32; /* Undo */
}
puts("Original values:");
printarr(array, n);
return 0;
}
Output:
After function:
1 2 20 4 5
Original values:
1 2 3 4 5
Note:
Of course you can pack two 16 bit integers in a 32 bit integer if you are using short values in order to save some space.
To be portable use PRId32 format (defined in <inttyes.h>) for printf and int32_t:
printf("%"PRId32" ", (int32_t)x);
Another method:
If those changes are made sequentially over positive integers you can change the sign (to identify a change) and store only the changes using realloc:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int *value;
size_t length;
} t_undo;
void function(t_undo *undo, int array[], int index, int value)
{
undo->value = realloc(undo->value, sizeof(int) * (undo->length + 1));
/* check realloc */
undo->value[undo->length++] = array[index];
array[index] = -value;
}
void printarr(int array[], size_t n)
{
size_t i;
for (i = 0; i < n; i++) {
printf("%d ", abs(array[i]));
}
printf("\n");
}
int main(void)
{
t_undo *undo;
int array[] = {1, 2, 3, 4, 5};
size_t i, j = 0, n = sizeof(array) / sizeof(array[0]);
undo = malloc(sizeof(*undo));
/* check malloc */
undo->value = NULL;
undo->length = 0;
function(undo, array, 2, 20);
puts("After function:");
printarr(array, n);
for (i = 0; i < n; i++) {
if (array[i] < 0) /* Changed */
array[i] = undo->value[j++]; /* Undo */
}
puts("Original values:");
printarr(array, n);
free(undo->value);
free(undo);
return 0;
}
Making it short: No. You cannot have your operations reverted - Not in a simple way anyway. What you probably want is to have a local copy of your data in your function(). You could do this by creating a new array and copy it to your first one:
int array[5] = whatever;
int array_copy[5];
memcpy(array_copy, array, 5*sizeof(int));
function(array_copy);
//You have your array now unchanged
If you really don't wanna do that, there's another way of enclosing your array into a struct and let the compiler synthesize a copy operation for you. However there's a serious downside for this one since for big such struct you may end up wasting your stack.
struct MyArray {
int array[5];
};
void function(struct MyArray m) {
//This will create a local copy of m
int i;
for (i = 0; i < 5; i++) {
m.array[i] = i + 1;
}
}
void initialize(struct MyArray* m) {
int i;
assert(m != NULL);
for (i = 0; i < 5; i++) {
m->array[i] = i;
}
}
int main(int argc, char *argv[]) {
struct MyArray m;
int i;
initialize(&m);
function(m);
//Your m here will be untouched
return 0;
}
#include <stdio.h>
void function(int array[]){
array[2] = 20;
}
void save(const char *filename, const void *data, size_t size);
void undo(const char *filename);
int main(void){
int array[5] = {1,2,3,4,5};
save("save_2", &array[2], sizeof(int));//array[2] save to file
function(array);
undo("save_2");//restore
save("save_all", array, sizeof(array));
function(array);
undo("save_all");
// code which has to use original array
for(int i=0;i<5;++i)
printf("%d\n", array[i]);
remove("save_2");
remove("save_all");
return 0;
}
void save(const char *filename, const void *data, size_t size){
FILE *fp = fopen(filename, "wb");
fwrite(&data, sizeof(void *), 1, fp);
fwrite(&size, sizeof(size_t), 1, fp);
fwrite(data, size, 1, fp);
fclose(fp);、
}
void undo(const char *filename){
FILE *fp = fopen(filename, "rb");
void *data;
size_t size;
fread(&data, sizeof(void*), 1, fp);
fread(&size, sizeof(size_t), 1, fp);
fread(data, size, 1, fp);
fclose(fp);
}

Resources