Encryption using GPGME in C - c

I am currently working on a project that requires file encryption using GPGME. I have found this sandbox code and am trying to get it going to help understand the subject. I am getting held up on line 46 with the gpgme_get_key() function and it is not allowing the code to continue. I am having a hard time finding documentation on what might be going wrong. I think that the problem is coming from that a key is not properly being generated.
#include <gpgme.h>
#include <gpg-error.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <locale.h>
#include <unistd.h>
//define INSERT_FAILURE
int bang(const gpgme_error_t err)
{
fprintf(stderr, "%s: %s\n", gpgme_strerror(err), gpgme_strsource(err));
return err;
}
int bang_(const char *e)
{
fprintf(stderr, "%s\n", e);
return 1;
}
int main(void)
{
gpgme_check_version(NULL);
gpgme_error_t err;
gpgme_data_t plain, cipher;
gpgme_ctx_t ctx;
gpgme_key_t recp[2] = {NULL, NULL};
gpgme_encrypt_flags_t flags = GPGME_ENCRYPT_ALWAYS_TRUST;
char *plaintext = "foo bar\0";
char *fp = "845B80B9AD12DB400CE534F6837EED10F97A36A1";
char *result_file = "./result.gpg";
char *verify_file = "./result";
size_t max_buflen = 2048, buflen;
char *buf = malloc(max_buflen * sizeof(char));
FILE *fh = NULL;
fprintf(stderr, "Got to line: %d\n", __LINE__);
err = gpgme_new(&ctx);
if (err)
return bang(err);
fprintf(stderr, "Got to line: %d\n", __LINE__);
gpgme_set_armor(ctx, 1);
fprintf(stderr, "Got to line: %d\n", __LINE__);
err = gpgme_get_key(ctx, fp, &recp[0], 0);
if (err)
return bang(err);
fprintf(stderr, "Got to line: %d\n", __LINE__);
err = gpgme_data_new_from_mem(&plain, plaintext, strlen(plaintext), 0); //look at
if (err)
return bang(err);
fprintf(stderr, "Got to line: %d\n", __LINE__);
err = gpgme_data_new(&cipher);
if (err)
return bang(err);
fprintf(stderr, "Got to line: %d\n", __LINE__);
err = gpgme_op_encrypt(ctx, recp, flags, plain, cipher);
if (err)
return bang(err);
gpgme_data_seek(cipher, 0, SEEK_SET);
buflen = gpgme_data_read(cipher, buf, max_buflen);
if (1 > buflen || buflen == max_buflen)
return bang_("Failed to read ciphertext");
fh = fopen(result_file, "w");
if (!fh)
bang_("failed to open result_file");
fwrite(buf, sizeof(char), buflen, fh);
fclose(fh);
fh = NULL;
memset(buf, 0, max_buflen);
snprintf(buf, max_buflen - 1, "gpg --output %s -d %s", verify_file, result_file);
system(buf);
memset(buf, 0, max_buflen);
fh = fopen(verify_file, "rb");
if (!fh)
return bang_("failed to open verify_file");
buflen = fread(buf, sizeof(char), max_buflen, fh);
fclose(fh);
if (buflen < 1 || buflen == max_buflen)
return bang_("Failed to read result file");
#ifdef INSERT_FAILURE
buf[buflen - 1] = '\0';
#endif
if (strncmp(buf, plaintext, strlen(plaintext)) != 0)
return bang_("Decrypted text is different from original plaintext");
return 0;
}

Related

C: Segmentation Fault (core dumped) for processing file

In C, when executing my program, I get a segmentation fault (core dumped error) and have no clue why. The program takes a .class file and converts it to binary. I suspect the issue is with the temporary file. This is on a Linux/Raspberry system.
The code:
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/unistd.h>
#include <limits.h>
static unsigned int numFiles = 0;
static unsigned long numBytes = 0;
FILE* rawf;
char* raw_file_name_end = ".raw_ujc";
char * rawfilename;
static void byte(unsigned char v){
if(numBytes) printf(", ");
printf((numBytes & 0x0F) ? "0x%02X" : "\n\t0x%02X", v);
fwrite(&v,sizeof(v),1,rawf);
numBytes++;
}
int main(int argc, char** argv){
const char* self = argv[0];
int c;
const char* classCvt = 0;
long len;
if(argc == 1){
fprintf(stderr, "USAGE: %s [-c <path_to_classCvt>] <file 1> [<file 2> [ <file 3> [...]]] > result.c\n", self);
return -1;
}
argv++;
argc--;
if(argv[0][0] == '-' && argv[0][1] == 'c' && !argv[0][2]){
classCvt = argv[1];
argv += 2;
argc -= 2;
}
printf("\nService optimized bytecode = {\n\t");
while(argc--){
char* filename = *argv;
rawfilename = malloc(sizeof(char) * (strlen(filename)-strlen(".class")) + sizeof(char) * strlen(raw_file_name_end)+1);
strncpy(rawfilename,filename,(strlen(filename)-strlen(".class")));
strcat(rawfilename,raw_file_name_end);
fprintf(stderr, "rawfilename after alloc: %s \n", rawfilename);
if(classCvt){
char* t;
static char template[] = "/tmp/myfileXXXXXX";
char fname[PATH_MAX];
strcpy(fname, template); /* Copy template */
filename = mkstemp(fname);
if(!filename){
fprintf(stderr, "%s: failed to create a tempfile: %d\n", self, errno);
return -10;
}
t = malloc(strlen(filename) + strlen(classCvt) + strlen(*argv) + 32);
if(!t){
fprintf(stderr, "%s: failed to alloc a small string. This is unlikely\n", self);
free(t);
return -11;
}
sprintf(t, "%s < %s > %s", classCvt, *argv, filename);
if(system(t)){
fprintf(stderr, "%s: system() fail: %d\n", self, errno);
free(t);
return -12;
}
free(t);
unlink(fname);
}
FILE* f = fopen(filename, "r");
rawf = fopen(rawfilename, "wb");
if(!f){
fprintf(stderr, "%s: failed to open '%s': %d\n", self, *argv, errno);
fclose(f);
return -2;
}
if(!f){
fprintf(stderr, "%s: failed to open '%s': %d\n", self, *argv, errno);
fclose(f);
return -2;
}
if(fseek(f, 0, SEEK_END)){
fprintf(stderr, "%s: failed to seek(1) in '%s': %d\n", self, *argv, errno);
fclose(f);
return -3;
}
len = ftell(f);
if(len < 0){
fprintf(stderr, "%s: failed to tell in '%s': %d\n", self, *argv, errno);
fclose(f);
return -4;
}
if(fseek(f, 0, SEEK_SET)){
fprintf(stderr, "%s: failed to seek(2) in '%s': %d\n", self, *argv, errno);
fclose(f);
return -5;
}
if(len > 0x00FFFFFFUL){
fprintf(stderr, "%s: file '%s' is %lu bytes, while maximum allowable size is %lu.\n", self, *argv, len, 0x00FFFFFFUL);
fclose(f);
return -6;
}
byte(len >> 16);
byte(len >> 8);
byte(len);
while((c = fgetc(f)) != EOF){
byte(c);
}
numFiles++;
fclose(f);
fclose(rawf);
if(filename != *argv){
unlink(filename);
free(filename);
}
argv++;
}
byte(0);
byte(0);
byte(0);
printf("\n};\n");
fprintf(stderr, "%s: processed %u files, producing %lu (0x%lX) bytes of output\n", self, numFiles, numBytes, numBytes);
fprintf(stderr, "rawfilename at end: %s \n", rawfilename);
free(rawfilename);
return 0;
}
The segfault happens after the print of:
"
rawfilename after alloc: ./../files//Test_Network.raw_ujc
Segmentation fault (core dumped)
"

C: Can not decrypt message Openssl

I'm new with cryptography, so I decided to create simple program that would open a file encrypt data, put it in etest.txt, then open this file decrypt it and put it indetest.txt. I know it sounds really weired but its for educational purposes. so here is my code.
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <stdio.h>
#include <string.h>
int main(void) {
size_t pri_len; // Length of private key
size_t pub_len; // Length of public key
char *pri_key; // Private key
char *pub_key; // Public key
char *msg = malloc(256); // Message to encrypt
char *encrypt = NULL; // Encrypted message
char *decrypt = NULL; // Decrypted message
char *err; // Buffer for any error messages
// Generate key pair
RSA *keypair = RSA_generate_key(2048, 3, NULL, NULL);
FILE *in = fopen("test.txt", "rb");
FILE *out = fopen("etest.txt", "wb");
if(in == NULL)
{
printf("in Error is %d (%s).\n", errno, strerror(errno));
}
if(out == NULL)
{
printf("out Error is %d (%s).\n", errno, strerror(errno));
}
encrypt = malloc(RSA_size(keypair));
for(;;)
{
//213 because of padding
memset(msg, '\0', 256);
memset(encrypt, '\0', 256);
fread(msg, 213, 1, in);
if((RSA_public_encrypt(strlen(msg), (unsigned char*)msg, (unsigned char*)encrypt,
keypair, RSA_PKCS1_OAEP_PADDING)) == -1) {
ERR_load_crypto_strings();
ERR_error_string(ERR_get_error(), err);
fprintf(stderr, "Error encrypting message: %s\n", err);
}
if(fwrite(encrypt, 256, 1, out) != 1)
{
printf("fwrite Error is %d (%s).\n", errno, strerror(errno));
}
if(feof(in))
{
break;
}
}
fclose(in);
fclose(out);
in = fopen("etest.txt", "rb");
out = fopen("dtest.txt", "wb");
if(in == NULL)
{
printf("in Error is %d (%s).\n", errno, strerror(errno));
}
if(out == NULL)
{
printf("out Error is %d (%s).\n", errno, strerror(errno));
}
decrypt = malloc(RSA_size(keypair));
for(;;)
{
//I use malloc because if i didnt it would from file and if it filled the msg and if this function would execute second time it would not overwrite the whole buffer and would cause problem
memset(decrypt, '\0', 256);
memset(msg, '\0', 256);
fread(msg, 256, 1, in);
if(RSA_private_decrypt(256, (unsigned char*)msg, (unsigned char*)decrypt,
keypair, RSA_PKCS1_OAEP_PADDING) == -1) {
ERR_load_crypto_strings();
ERR_error_string(ERR_get_error(), err);
fprintf(stderr, "Error decrypting message: %s\n", err);
}
fwrite(decrypt, 256, 1, out);
if(feof(in))
{
break;
}
}
fclose(in);
fclose(out);
RSA_free(keypair);
return 0;
}
When I run code it gives me back error saying:Error decrypting message: error:0407A079:rsa routines:RSA_padding_check_PKCS1_OAEP:oaep decoding error but if i delete this codememset(msg, '\0', 256); it shows that everything works fine but it causes problems because msg buffer is overwritten with first few bytes that second fread() function overwrote.
Sorry if my questions sound silly. Hope you can help. thanks.
Your are using fwrite(decrypt, 256, 1, out); which is wrong.size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) Second parameter is the size in bytes of each element to be read And the third one is number of elements, each one with a size of size bytes.

Passing data and retrieving data via same struct using threads

I need to read a file from a separate thread, to avoid hiccups in the flow of my opengl program. I already do that for loading textures and blending them using global variables, that works fine.
However now I need some separate threads to read small data files.
I have created a struct, which basically contains 2 args and 1 result.
It seems I can't do that or I got it wrong somewhere (or in many places)
Here is the sample code of my non proof of concept:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#define content_file "/home/tias/content.txt" //this file contains "foobar!!"
typedef struct {
int* reading; // 0 = not reading , 1 = reading , 2 = finished reading
char* content; // content of the file
char* file; // file to read
} struct_file_content;
struct_file_content first_file;
void *thread_read_file ( void* data ) {
struct_file_content *thisdata = (struct_file_content*) data;
long length;
int i = 0;
char readchar;
char * thiscontent = 0;
int reading_finished = 2;
int *ptr_to_reading_finished = (int*)malloc(sizeof(int));
ptr_to_reading_finished = &reading_finished;
fprintf(stdout,"thread_Read_file called with file: %s and reading: %u\n",(*thisdata).file,*(*thisdata).reading);
FILE * f = fopen ((*thisdata).file, "r");
if (f) {
fseek (f, 0, SEEK_END);
length = ftell (f);
fseek (f, 0, SEEK_SET);
if (length > 39) {
fprintf(stderr,"file %s is too big\n",(*thisdata).file);
exit (1);
}
thiscontent = (char*) malloc (length*sizeof(char));
if ( thiscontent ) {
fread (thiscontent, 1, length, f);
}
fclose (f);
thisdata->content = thiscontent;
} else {
fprintf (stderr, "cannot read file %s\n",(*thisdata).file);
exit (1);
}
sleep(1);
thisdata->reading = ptr_to_reading_finished;
fprintf(stdout,"finished reading: %u\n",*(*thisdata).reading);
fprintf(stdout,"content: %s\n",thiscontent);
pthread_exit(NULL);
return NULL;
}
main()
{
pthread_t thread1;
int filename_length = strlen(content_file);
int rfinish = 2;
int rbegin = 1;
first_file.reading = (int*) malloc(sizeof(int));
first_file.file = (char*) malloc((filename_length+1)*sizeof(char));
first_file.reading = &rbegin;
strcpy(first_file.file,content_file);
pthread_create( &thread1, NULL, thread_read_file, (void*) &first_file);
while ( *(first_file.reading) != 2 ) {
fprintf(stdout,"still reading, reading: %u\n",*(first_file.reading));
sleep(1);
}
fprintf(stdout,"exited control loop with file: %s, reading: %u, content: %s\n",first_file.file, *(first_file.reading), first_file.content);
}
Here's the result:
~/repository/thread/test$ ./tt
still reading, reading: 1
thread_Read_file called with file: /home/tias/content.txt and reading: 1
still reading, reading: 1
still reading, reading: 1
still reading, reading: 1
finished reading: 2
content: foobar!!
still reading, reading: 0
still reading, reading: 0
I was expecting reading = 2 to get out of the loop, instead it is 0.
Any idea on what I have to modify to make it work?
I have read about mutex and so, may be it is the way?
I had found my solution elegant and not working, your help is greatly appreciated.
typedef struct {
int* reading; // 0 = not reading , 1 = reading , 2 = finished reading
char* content; // content of the file
char* file; // file to read
} struct_file_content;
Why is reading a pointer type? It is used in the code as a flag, there is absolutely no need to make it a pointer, especially given that you dynamically allocate memory for this structure field. It complicates the design and is unnecessary. Go ahead and make that an int, not a pointer:
typedef struct {
int reading; // 0 = not reading , 1 = reading , 2 = finished reading
char *content; // content of the file
char *file; // file to read
} struct_file_content;
This simplifies the code in main() used to set up first_file:
first_file.reading = 1;
first_file.content = NULL;
first_file.file = content_file;
Note that there is no need to have first_file.file be dynamically allocated memory, since you know the file name (and size) at compile time. Keep things simple.
Next, you ignore a possible error return value from pthread_create(3). It returns non-zero in case of failure, and you should check for that. Something like this will do:
pthread_t thread1;
int thread_res = pthread_create(&thread1, NULL, thread_read_file, &first_file);
if (thread_res != 0) {
fprintf(stderr, "pthread_create(3) error: %s\n", strerror(thread_res));
exit(EXIT_FAILURE);
}
The code to wait for reading to finish is buggy and racy, you need to either synchronize access to the reading field of struct_file_content with a mutex, or properly wait for the thread to terminate before accessing the first_file again. Since the code does nothing but wait for the thread, pthread_join(3) is a much more reasonable choice here. You'd do something like:
int join_res = pthread_join(thread1, NULL);
if (join_res != 0) {
fprintf(stderr, "pthread_join(3) error: %s\n", strerror(join_res));
exit(EXIT_FAILURE);
}
Inside thread_read_file(), you probably want pthread_exit(3) when handling errors instead of exit(2), since the latter will terminate the entire process, not just the local thread. You also need to handle malloc(3) errors.
Here's the code with all of these issues addressed:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#define content_file "/home/tias/content.txt" //this file contains "foobar!!"
typedef struct {
int reading; // 0 = not reading , 1 = reading , 2 = finished reading
char *content; // content of the file
char *file; // file to read
} struct_file_content;
struct_file_content first_file;
void *thread_read_file(void *data) {
struct_file_content *thisdata = data;
long length;
char *thiscontent = NULL;
fprintf(stdout,"thread_Read_file called with file: %s and reading: %u\n", thisdata->file, thisdata->reading);
FILE *f = fopen (thisdata->file, "r");
if (f) {
fseek(f, 0, SEEK_END);
length = ftell(f);
fseek (f, 0, SEEK_SET);
if (length > 39) {
fprintf(stderr,"file %s is too big\n", thisdata->file);
pthread_exit(NULL);
}
thiscontent = malloc(length);
if (thiscontent) {
fread(thiscontent, 1, length, f);
} else {
perror("malloc(3) error");
pthread_exit(NULL);
}
fclose(f);
thisdata->content = thiscontent;
} else {
fprintf(stderr, "cannot open file %s\n", thisdata->file);
pthread_exit(NULL);
}
thisdata->reading = 2;
fprintf(stdout, "finished reading: %u\n", thisdata->reading);
fprintf(stdout, "content: %s\n", thiscontent);
return NULL;
}
int main(void) {
first_file.reading = 1;
first_file.content = NULL;
first_file.file = content_file;
pthread_t thread1;
int thread_res = pthread_create(&thread1, NULL, thread_read_file, &first_file);
if (thread_res != 0) {
fprintf(stderr, "pthread_create(3) error: %s\n", strerror(thread_res));
exit(EXIT_FAILURE);
}
int join_res = pthread_join(thread1, NULL);
if (join_res != 0) {
fprintf(stderr, "pthread_join(3) error: %s\n", strerror(join_res));
exit(EXIT_FAILURE);
}
fprintf(stdout, "Read file %s, reading: %u, content: %s\n", first_file.file, first_file.reading, first_file.content);
return 0;
}
UPDATE
From the comments, it seems like you want to do some additional processing and periodically test (at your convenience) whether the thread is done reading. Your approach of using a flag to test for termination is mostly correct, but you should synchronize access to the reading field of struct_file_content to make sure that you always get consistent values. As such, I suggest adding a mutex to struct_file_content that is used to control concurrent access to the reading field. You should lock the mutex every time you need to read or update reading.
So, the structure definition becomes:
typedef struct {
pthread_mutex_t read_mutex; // synchronize access to reading flag
int reading; // 0 = not reading , 1 = reading , 2 = finished reading
char *content; // content of the file
char *file; // file to read
} struct_file_content;
Then, as part of initializing struct_file_content, you need to remember to initialize the mutex. Here's how you'd do it in main():
int mutex_err = pthread_mutex_init(&first_file.read_mutex, NULL);
if (mutex_err != 0) {
fprintf(stderr, "pthread_mutex_init(3) error: %s\n", strerror(mutex_err));
exit(EXIT_FAILURE);
}
first_file.reading = 1;
first_file.content = NULL;
first_file.file = content_file;
Now, the loop in main() simply locks the mutex, checks the status of the reading field (breaking out if it is equal to 2), and unlocks the mutex. Something like:
int read_done = 0;
while (!read_done) {
mutex_err = pthread_mutex_lock(&first_file.read_mutex);
if (mutex_err != 0) {
fprintf(stderr, "pthread_mutex_lock(3) error: %s\n", strerror(mutex_err));
exit(EXIT_FAILURE);
}
/* Reading is finished when first_file.reading == 2 */
read_done = (first_file.reading == 2);
if (first_file.reading != 2)
printf("Still reading, reading: %u\n", first_file.reading);
mutex_err = pthread_mutex_unlock(&first_file.read_mutex);
if (mutex_err != 0) {
fprintf(stderr, "pthread_mutex_unlock(3) error: %s\n", strerror(mutex_err));
}
}
Of course, you also need to update the thread function to lock the mutex before modifying reading:
void *thread_read_file(void *data) {
struct_file_content *thisdata = data;
int mutex_res;
long length;
char *thiscontent = NULL;
mutex_res = pthread_mutex_lock(&thisdata->read_mutex);
if (mutex_res != 0) {
fprintf(stderr, "thread_read_file() failed to acquire mutex: %s\n", strerror(mutex_res));
pthread_exit(NULL);
}
fprintf(stdout, "thread_read_file() called with file: %s and reading: %u\n", thisdata->file, thisdata->reading);
mutex_res = pthread_mutex_unlock(&thisdata->read_mutex);
if (mutex_res != 0) {
fprintf(stderr, "thread_read_file() failed to release mutex: %s\n", strerror(mutex_res));
pthread_exit(NULL);
}
FILE *f = fopen(thisdata->file, "r");
if (f) {
fseek(f, 0, SEEK_END);
length = ftell(f);
fseek (f, 0, SEEK_SET);
if (length > 39) {
fprintf(stderr, "file %s is too big\n", thisdata->file);
pthread_exit(NULL);
}
thiscontent = malloc(length);
if (thiscontent) {
fread(thiscontent, 1, length, f);
} else {
perror("malloc(3) error");
pthread_exit(NULL);
}
fclose(f);
thisdata->content = thiscontent;
} else {
fprintf(stderr, "cannot open file %s\n", thisdata->file);
pthread_exit(NULL);
}
mutex_res = pthread_mutex_lock(&thisdata->read_mutex);
if (mutex_res != 0) {
fprintf(stderr, "thread_read_file() failed to acquire mutex: %s\n", strerror(mutex_res));
pthread_exit(NULL);
}
thisdata->reading = 2;
fprintf(stdout, "finished reading: %u\n", thisdata->reading);
mutex_res = pthread_mutex_unlock(&thisdata->read_mutex);
if (mutex_res != 0) {
fprintf(stderr, "thread_read_file() failed to release mutex: %s\n", strerror(mutex_res));
pthread_exit(NULL);
}
fprintf(stdout, "content: %s\n", thiscontent);
return NULL;
}
That should be enough. Here's the full code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#define content_file "/home/tias/content.txt" //this file contains "foobar!!"
typedef struct {
pthread_mutex_t read_mutex; // synchronize access to reading flag
int reading; // 0 = not reading , 1 = reading , 2 = finished reading
char *content; // content of the file
char *file; // file to read
} struct_file_content;
struct_file_content first_file;
void *thread_read_file(void *data) {
struct_file_content *thisdata = data;
int mutex_res;
long length;
char *thiscontent = NULL;
mutex_res = pthread_mutex_lock(&thisdata->read_mutex);
if (mutex_res != 0) {
fprintf(stderr, "thread_read_file() failed to acquire mutex: %s\n", strerror(mutex_res));
pthread_exit(NULL);
}
fprintf(stdout, "thread_read_file() called with file: %s and reading: %u\n", thisdata->file, thisdata->reading);
mutex_res = pthread_mutex_unlock(&thisdata->read_mutex);
if (mutex_res != 0) {
fprintf(stderr, "thread_read_file() failed to release mutex: %s\n", strerror(mutex_res));
pthread_exit(NULL);
}
FILE *f = fopen(thisdata->file, "r");
if (f) {
fseek(f, 0, SEEK_END);
length = ftell(f);
fseek (f, 0, SEEK_SET);
if (length > 39) {
fprintf(stderr, "file %s is too big\n", thisdata->file);
pthread_exit(NULL);
}
thiscontent = malloc(length);
if (thiscontent) {
fread(thiscontent, 1, length, f);
} else {
perror("malloc(3) error");
pthread_exit(NULL);
}
fclose(f);
thisdata->content = thiscontent;
} else {
fprintf(stderr, "cannot open file %s\n", thisdata->file);
pthread_exit(NULL);
}
mutex_res = pthread_mutex_lock(&thisdata->read_mutex);
if (mutex_res != 0) {
fprintf(stderr, "thread_read_file() failed to acquire mutex: %s\n", strerror(mutex_res));
pthread_exit(NULL);
}
thisdata->reading = 2;
fprintf(stdout, "finished reading: %u\n", thisdata->reading);
mutex_res = pthread_mutex_unlock(&thisdata->read_mutex);
if (mutex_res != 0) {
fprintf(stderr, "thread_read_file() failed to release mutex: %s\n", strerror(mutex_res));
pthread_exit(NULL);
}
fprintf(stdout, "content: %s\n", thiscontent);
return NULL;
}
int main(void) {
int mutex_err = pthread_mutex_init(&first_file.read_mutex, NULL);
if (mutex_err != 0) {
fprintf(stderr, "pthread_mutex_init(3) error: %s\n", strerror(mutex_err));
exit(EXIT_FAILURE);
}
first_file.reading = 1;
first_file.content = NULL;
first_file.file = content_file;
pthread_t thread1;
int thread_res = pthread_create(&thread1, NULL, thread_read_file, &first_file);
if (thread_res != 0) {
fprintf(stderr, "pthread_create(3) error: %s\n", strerror(thread_res));
exit(EXIT_FAILURE);
}
int read_done = 0;
while (!read_done) {
mutex_err = pthread_mutex_lock(&first_file.read_mutex);
if (mutex_err != 0) {
fprintf(stderr, "pthread_mutex_lock(3) error: %s\n", strerror(mutex_err));
exit(EXIT_FAILURE);
}
/* Reading is finished when first_file.reading == 2 */
read_done = (first_file.reading == 2);
if (first_file.reading != 2)
printf("Still reading, reading: %u\n", first_file.reading);
mutex_err = pthread_mutex_unlock(&first_file.read_mutex);
if (mutex_err != 0) {
fprintf(stderr, "pthread_mutex_unlock(3) error: %s\n", strerror(mutex_err));
}
}
/* Here we don't need to lock because the thread has finished and no other thread is
* using this struct
*/
fprintf(stdout, "Read file %s, reading: %u, content: %s\n", first_file.file, first_file.reading, first_file.content);
free(first_file.content);
mutex_err = pthread_mutex_destroy(&first_file.read_mutex);
if (mutex_err != 0) {
fprintf(stderr, "Warning: Error destroying mutex: %s\n", strerror(mutex_err));
}
return 0;
}
Note that I added cleanup code in the end of main(). Even though it is not necessary (because the program is about to terminate), it is there to make sure you don't forget what kind of cleanup needs to be done once a thread terminates.

Linux, reading the tape device

I'm using plain C and trying to read data from stream device (single tape)
size_t res=0;
size_t total=0;
char data[512];
FILE *f = fopen("/dev/st0","r");
if(!f)
{
perror ("Error:");
printf( "Value: %d\n", errno );
return;
}
while((res=fread(data,1, sizeof data,f))>0)
{
total+=res;
}
fclose(f);
printf("read: %ld bytes\n", total);
It doesn't work this way, so I assume there should be some specific way to do it.
I didn't find something useful in google. May be source code of mt tool can help, but again it doesn't read/write to tape.
The result is
read: 0 bytes
To read the first sizeof(data) bytes (if any) from the device specified do like so:
#define _POSIX_SOURCE /* for ferror */
#include <stdio.h>
#define DEVICENAME "/dev/st0"
int main(void)
{
int result = EXIT_SUCCESS; /* Be optimistic. */
size_t total = 0;
char data[1024];
FILE * f = fopen(DEVICENAME, "r");
if (NULL == f)
{
fprintf(stderr, "Failed to open '%s'.\n", DEVICENAME);
result = EXIT_FAILURE;
}
else
{
total = fread(data, 1, sizeof(data), f);
if (ferror(f))
{
fprintf(stderr, "Error reading from '%s'.\n", DEVICENAME);
result = EXIT_FAILURE;
}
fclose(f);
}
printf("Read %zd bytes from '%s'.\n", total, DEVICENAME);
return result;
}

Error in lseek when I am trying to create holes in file

I have written the below program to create a file containing holes but I am getting an error in lseek() as below:
Error in lseek <22> : Invalid argument
I just want to write "1" at first and "2" at 100th offset. I have tried it with SEEK_END also, but no success
#include<stdio.h>
#include<errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
int main(void) {
int fd = -1;
int rc = -1;
char *buff = "1";
char *buff_end = "2";
char *err;
fd = open("hole_file", O_CREAT | O_RDWR | O_TRUNC, 0644);
if (fd == -1) {
printf("\n Error in open() !!!");
return (-1);
}
rc = write(fd, buff, sizeof(buff));
if (rc == -1) {
printf("\n Error in writing at start location <%d>", errno);
close(fd);
unlink("hole_file");
return (-1);
}
rc = lseek(fd, SEEK_CUR, 100);
if (rc == -1) {
err = strerror(errno);
printf("\n Error in lseek <%d> : %s\n", errno, err);
close(fd);
unlink("hole_file");
return (-1);
}
rc = write(fd, buff_end, sizeof(buff_end));
if (rc == -1) {
printf("\n Error in writing at 100th offset <%d>", errno);
close(fd);
unlink("hole_file");
return (-1);
}
close(fd);
return (0);
}
You've swapped the arguments.
lseek(fd, SEEK_CUR, 100)
should be
lseek(fd, 100, SEEK_CUR)
After
rc = write(fd, buff, sizeof(buff));
you have the pointer at end of file, you can't use SEEK_CUR, you must use SEEK_SET, and you put the lseek flag at wrong position in parameter list:
rc = lseek(fd, 100, SEEK_SET);

Resources