Listing all commits in a branch using libgit2 - c

How can I walk through all the commits of a branch using libgit2?
I have already the following bit of code, but it doesn't compile.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <git2.h>
int main(int argc, char *argv[]){
git_repository *repo;
git_repository_open(&repo, ".");
git_odb *obj_db;
obj_db = git_repository_database(repo);
git_object commit;
git_revparse_single(&commit, repo, "HEAD");
git_repository_free(repo);
return 0;
}
GCC reports:
log.c: In function ‘main’:
log.c:11:9: warning: assignment makes pointer from integer without a cast [enabled by default]
log.c:13:13: error: storage size of ‘commit’ isn’t known
I compiled with the -lgit2 flag. Is there a fast possibility to walk through all the commits, beginning from the root-commit?
Update
The new code looks like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <git2.h>
int main(int argc, char *argv[]){
git_repository *repo;
git_repository_open(&repo, ".");
git_odb *obj_db;
obj_db = git_repository_database(repo);
git_object *commit;
git_revparse_single(&commit, repo, "HEAD");
git_repository_free(repo);
return 0;
}
I get the following error messages:
log.c:11: undefined reference to `git_repository_database'
log.c:14: undefined reference to `git_revparse_single'

Finally, I created a working version using libgit2. Carlos Martín Nieto pointed in the right direction, the following example works great with libgit2 0.16. It took me some time to study the general.c I found in the libgit2-examples repository on github. git revwalk was exactly what I was looking for.
I noted that git adds an newline at the end of my commit messages, probably because I'm always using nano to write them, so I don't printf out the last character in my example code.
If anyone reads this and has the same problem as I had, here's the working code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <git2.h>
#define REPO ".git"
int main(void){
git_repository *repo;
if(git_repository_open(&repo, REPO) != GIT_SUCCESS){
fprintf(stderr, "Failed opening repository: '%s'\n", REPO);
return 1;
}
// Read HEAD on master
char head_filepath[512];
FILE *head_fileptr;
char head_rev[41];
strcpy(head_filepath, REPO);
if(strrchr(REPO, '/') != (REPO+strlen(REPO)))
strcat(head_filepath, "/refs/heads/master");
else
strcat(head_filepath, "refs/heads/master");
if((head_fileptr = fopen(head_filepath, "r")) == NULL){
fprintf(stderr, "Error opening '%s'\n", head_filepath);
return 1;
}
if(fread(head_rev, 40, 1, head_fileptr) != 1){
fprintf(stderr, "Error reading from '%s'\n", head_filepath);
fclose(head_fileptr);
return 1;
}
fclose(head_fileptr);
git_oid oid;
git_revwalk *walker;
git_commit *commit;
if(git_oid_fromstr(&oid, head_rev) != GIT_SUCCESS){
fprintf(stderr, "Invalid git object: '%s'\n", head_rev);
return 1;
}
git_revwalk_new(&walker, repo);
git_revwalk_sorting(walker, GIT_SORT_TOPOLOGICAL);
git_revwalk_push(walker, &oid);
const char *commit_message;
const git_signature *commit_author;
while(git_revwalk_next(&oid, walker) == GIT_SUCCESS) {
if(git_commit_lookup(&commit, repo, &oid)){
fprintf(stderr, "Failed to lookup the next object\n");
return 1;
}
commit_message = git_commit_message(commit);
commit_author = git_commit_committer(commit);
// Don't print the \n in the commit_message
printf("'%.*s' by %s <%s>\n", strlen(commit_message)-1, commit_message, commit_author->name, commit_author->email);
git_commit_free(commit);
}
git_revwalk_free(walker);
return 0;
}
Thanks!

I have already the following bit of code, but it doesn't compile
A git_commit is an opaque type, which means that your compiler doesn't know what it is, only that it exists. Thus you cannot allocate a git_commit on the stack. The library will allocate it on the heap for you.
You must use a pointer in your code and pass a pointer to that to the library's functions, as you can see in its documentation and the examples it links to.
Is there a fast possibility to walk through all the commits, beginning from the root-commit?
Those revwalk tests, demonstrating different walking strategies, may provide you with some help.

Adding to Pentax's answer above. If you just want to 'walk' the head, instead of doing all that work to get the old to the head to initialize the walker with:
git_revwalk_push(walker, &oid);
One could simply use:
git_revwalk_push_head(walker);

Related

Opening multiple directories in C

I am trying to make a program that creates a directory in which multiple directories are created, then in each directory I am creating a file. I cannot seem to open those "multiple directories" so that I can put my file there. I tried using name3 as a parameter, and I also tried creating a const char* with name3's value and nothing worked.
error: malloc.c:2379: sysmalloc: Assertion `(old_top == initial_top (av) && old_size == 0) || ((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) && ((unsigned long) old_end & (pagesize - 1)) == 0)' failed. Aborted (core dumped)
here is my code
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
int make_directory(char * name) {
int checker=mkdir(name, S_IRWXU | S_IRWXG | S_IRWXO);
return checker;
}
char** getNames() {
char** names=malloc(10*sizeof(char*));
for(int i=0;i<10;i++) {
if(i==9) {
names[i]=malloc(3*sizeof(char));
names[i][0]='1';
names[i][1]='0';
names[i][2]='\0';
} else {
names[i]=malloc(2*sizeof(char));
names[i][0]=49+i;
names[i][1]='\0';
}
}
return names;
}
int makeTenDirs() {
char **names=getNames();
char *name2;
for(int i=0;i<10;i++) {
name2=NULL;
name2=getcwd(NULL,0);
strncat(name2,"/input/dir",11);
strncat(name2,names[i],1);
int s=make_directory(name2);
}
name2=NULL;
name2=getcwd(NULL,0);
strncat(name2,"/input/dir",11);
strncat(name2,names[0],1);
strncat(name2,"0",2);
int s=make_directory(name2);
}
int main() {
char **names=getNames();
FILE *file;
DIR *dir;
DIR *dir2;
struct dirent *dent;
char * name1="./input";
char *name3;
int proceed=make_directory("./input");
if(proceed==-1) {
printf("Error making the directory\n");
}
makeTenDirs();
dir=opendir("./input");
if(dir!=NULL) {
name3=getcwd(NULL,0);
while((dent=readdir(dir))!=NULL){
if(strcmp(dent->d_name,"..")!=0 && strcmp(dent->d_name,".")!=0) {
name3=getcwd(NULL,0);
strncat(name3,"/input/",8);
strncat(name3,dent->d_name,10);
printf("%s\n",name3);
dir2=opendir(name3);
if(dir2!=NULL) {
printf("alo");
}
}
}
}
closedir(dir);
free(names);
return 0;
}
Any tips on how to open the directories (and maybe put the files in them)?
Below is a working implementation. I cleaned up all the warnings (you had some unused variables, makeTenDirs was not returning a value). Always look at and fix the warnings, use -Wall -Wextra flags to enable them. As I thought before, you were invoking undefined behavior by overwriting the buffers of name2 and name3. The way you were using getcwd it was allocating exactly enough space for name2 and name3. As soon as you strcat to that, you overwrite the buffer, invoking UB. At that point, the program can behave in completely unpredictable ways, including appearing to work. You hope your program crashes when there's UB so you're alerted to the problem. Below, I've used a 2nd operating mode of getcwd that doesn't internally malloc memory and instead keeps everything in automatic memory (on the stack). This relieves you of having to manage memory manually. I've included comments that hopefully explain everything, let me know if you have questions.
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <linux/limits.h> // for PATH_MAX
int make_directory(char * name) {
int checker=mkdir(name, S_IRWXU | S_IRWXG | S_IRWXO);
return checker;
}
char** getNames() {
char** names=malloc(10*sizeof(char*));
for(int i=0;i<10;i++) {
if(i==9) {
names[i]=malloc(3*sizeof(char));
names[i][0]='1';
names[i][1]='0';
names[i][2]='\0';
} else {
names[i]=malloc(2*sizeof(char));
names[i][0]='1'+i;
names[i][1]='\0';
}
}
return names;
}
int makeTenDirs(char** names) {
// This is where your problems began. As I suggested before and confirmed
// when I actually ran the code, `getcwd(NULL, 0)` returns a pointer to
// dynamically allocated memory that's just big enough to hold the path.
// As soon as you strcat to that, you overflow the buffer causing
// undefined behavior. It crashed for me 2nd time through the loop, not
// immediately when the UB occurred. Your results could be entirely different,
// that is the essence of UB. To fix it, I will declare an automatic array
// of PATH_MAX large (4096 I believe). That should make this fixed size array
// able to handle any path on your _linux_ box (this code will not be portable
// to windows). Alternatively, you could do what you did before, just be sure
// to realloc the name2 memory _before_ strcat'ing so there's enough room for
// "/input/dir"
char name2[PATH_MAX];
// only acceptable place for one character variable names are loop index
// variables, and you'll even get some argument on that. Give your variables
// descriptive names (although, I'd probably just make this function void, not
// much utility in the return value here, which you didn't even return!)
int directoryMade = 0;
for(int i=0;i<10;i++) {
// This returns NULL if the `sizeof name` (==PATH_MAX == 4096) is too
// small to hold the path. That shouldn't be the case since no paths
// on the system should exceed PATH_MAX, but it's always a good idea
// to check for errors, that's what a lot of your C code should be
// doing, so get in the habit. Also, realize your old way created
// a memory leak each time since each call to getcwd would malloc more
// memory, and you overwrite the pointer to the previous block with the
// pointer to the new block. Now nothing is pointing at the previous
// block so you can't free it --> memory leak.
if (getcwd(name2, sizeof name2) == NULL)
{
perror("Path exceeded buffer length");
exit(-1);
}
// should be plenty of space to strcat now
strncat(name2,"/input/dir",11);
strncat(name2,names[i],1);
// not much utility b/c it keeps getting overwritten. You could check it each time
// and return if there's an error
directoryMade=make_directory(name2);
}
if (getcwd(name2, sizeof name2) == NULL)
{
perror("Path exceeded buffer length");
exit(-1);
}
strncat(name2,"/input/dir",11);
strncat(name2,names[0],1);
strncat(name2,"0",2);
directoryMade=make_directory(name2);
return directoryMade;
}
int main() {
char **names=getNames();
DIR *dir;
DIR *dir2;
struct dirent *dent;
int proceed=make_directory("./input");
if(proceed==-1) {
// you print an error here, but continue on anyway
// as if there was no error
printf("Error making the directory\n");
}
makeTenDirs(names); // you already fetched names, use them!
dir=opendir("./input");
if(dir!=NULL) {
// same problem here. name3 holds _exactly_ how much space it
// needs when you allow getcwd to malloc memory for it. As before,
// you can make name3 an array in automatic storage, or realloc it
// before strcat'ing
char name3[PATH_MAX];
// check for NULL return here too. Not showing it because I'm getting lazy
getcwd(name3, sizeof name3);
while((dent=readdir(dir))!=NULL){
if(strcmp(dent->d_name,"..")!=0 && strcmp(dent->d_name,".")!=0) {
// check for NULL return
getcwd(name3, sizeof name3);
strncat(name3,"/input/",8);
strncat(name3,dent->d_name,10);
printf("%s\n",name3);
dir2=opendir(name3);
if(dir2!=NULL) {
// printf is line-buffered, so this won't print right away unless
// you put a newline on it (or fflush(stdout);)
printf("alo\n");
// close this dir too?
closedir(dir2);
}
}
}
}
closedir(dir);
// this is NOT a complete free. You have a double pointer. You need to loop and
// free each of names[0], names[1], .. names[9], _then_ free(names). I'll leave
// that as an exercise. In general, you should have a matching number of malloc's
// and free's.
free(names);
return 0;
}

How to use ioctl with FS_IOC_FIEMAP

My problem is to deal with sparse file reads and understand where the extents of the file are to perform some logic around it.
Since, there is no direct API call to figure these stuff out, I decided to use ioctl api to do this. I got the idea from how cp command deals with problems of copying over sparse files by going through their code and ended up seeing this.
https://github.com/coreutils/coreutils/blob/df88fce71651afb2c3456967a142db0ae4bf9906/src/extent-scan.c#L112
So, I tried to do the same thing in my sample program running in user space and it errors out with "Invalid argument". I am not sure what I am missing or if this is even possible from userspace. I am running on ubuntu 14.04 on an ext4 file system. Could this be a problem with device driver supporting these request modes underneath?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include "fiemap.h" //This is from https://github.com/coreutils/coreutils/blob/df88fce71651afb2c3456967a142db0ae4bf9906/src/fiemap.h
int main(int argc, char* argv[]) {
int input_fd;
if(argc != 2){
printf ("Usage: ioctl file1");
return 1;
}
/* Create input file descriptor */
input_fd = open (argv [1], O_RDWR);
if (input_fd < 0) {
perror ("open");
return 2;
}
union { struct fiemap f; char c[4096]; } fiemap_buf;
struct fiemap *fiemap = &fiemap_buf.f;
int s = ioctl(input_fd, FS_IOC_FIEMAP, fiemap);
if (s == 0) {
printf("ioctl success\n");
} else {
printf("ioctl failure\n");
char * errmsg = strerror(errno);
printf("error: %d %s\n", errno, errmsg);
}
/* Close file descriptors */
close (input_fd);
return s;
}
As you're not properly setting the fiemap_buf.f parameters before invoking ioctl(), it is likely that the EINVAL is coming from the fiemap invalid contents than from the FS_IOC_FIEMAP request identifier support itself.
For instance, the ioctl_fiemap() (from kernel) will evaluate the fiemap.fm_extent_count in order to determine if it is greater than FIEMAP_MAX_EXTENTS and return -EINVAL in that case. Since no memory reset nor parameterization is being performed on fiemap, this is very likely the root cause of the problem.
Note that from the coreutils code you referenced, it performs the correct parameterization of fiemap before calling ioctl():
fiemap->fm_start = scan->scan_start;
fiemap->fm_flags = scan->fm_flags;
fiemap->fm_extent_count = count;
fiemap->fm_length = FIEMAP_MAX_OFFSET - scan->scan_start;
Note fiemap is not recommended as you have to be sure to pass FIEMAP_FLAG_SYNC which has side effects. The lseek(), SEEK_DATA and SEEK_HOLE interface is the recommended one, though note that will, depending on file system, represent unwritten extents (allocated zeros) as holes.

Read values of config file error

I have the following Config.cfg file and I want to read the values of Device
[BBDD]
user=**
password=***
database=***
IPServidor=*
port=3***
[Device]
dev=8
Temperatura=5=1001
Humedad=7=1002
Link=8=1003
Volt=9=1004
[Device]
dev=10
Temperatura=5=1012
Humedad=7=1013
Link=8=1014
Volt=9=1015
So I try with libconfig library. I wrote the following code but it returns me nothing. Am I missing something? Or is there any problem with libconfig? I tried also with glib but because of the same keyword Device I cannot use it.
#include <stdio.h> // standard input / output functions
#include <string.h> // string function definitions
#include <stdlib.h>
#include <libconfig.h>
#include <glib.h>
int main()
{
config_t cfg; //returns all parameters in this structure
config_setting_t *setting;
const char *str1, *str2;
int tmp;
config_init(&cfg);
if(config_read_file(&cfg, "Config.cfg"))
{
fprintf(stderr, "%s=%d\n", config_error_file(&cfg),config_error_line(&cfg),config_error_text(&cfg));
config_destroy(&cfg);
return(EXIT_FAILURE);
}
//Read the parameter group
setting = config_lookup(&cfg, "Device");
if (setting!= NULL)
{
//Read the string
if(config_setting_lookup_string(setting, "dev", &str1))
{
printf("\n Device: &s", str1);
}
else
printf("\n No 'Device' setting in configuration file");
printf("\n");
}
config_destroy(&cfg);
}
I tried both with Device and [Device] as keyword and also config_setting_lookup_string and config_setting_lookup_int to return the values of dev but nothing happens. My command returns me a simple
Process returned 0. execution time: 0.115sec
Your configuration doesn't seem to be a valid libconfig configuration file.
Check the libconfig documentation.

Regarding checking for file or directory

I have a very simple program here, but it seems to be returning
a "true" value to the query S_ISDIR() even when the directory
entry is not a directory. Can any one pleeas help me. I am using QNX Neurtion RTOS
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <errno.h>
int main(int argc, char *argv[]) {
DIR *dir;
struct dirent *entry;
struct stat eStat;
char *root;
int i;
root = argv[1];
while((entry = readdir(dir)) != NULL) {
lstat(entry->d_name, &eStat);
if(S_ISDIR(eStat.st_mode))
printf("found directory %s\n", entry->d_name);
else
printf("not a dir\n");
}
return 0;
}
sample output:
found directory .
found directory ..
found directory NCURSES-Programming-HOWTO-html.tar.gz
found directory ncurses_programs
found directory ncurses.html
Following information may be helpful.
lstat for file is failing with errno set to 2. I am not sure why, can any one know this.
Just a guess; since you're not checking for an error after your lstat call, the eStat buffer could be containing the result of the last successful call. Try checking if lstat returns -1.
readdir() on Linux is fundamentally different, so I can't fully test on my system. See the sample programs at link text and link text. Modifying the lstat sample code, this seems to work for me:
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
int main( int argc, char **argv )
{
int ecode = 0;
int n;
struct stat sbuf;
for( n = 1; n < argc; ++n ) {
if( lstat( argv[n], &sbuf ) == -1 ) {
perror( argv[n] );
ecode++;
} else if( S_ISDIR( sbuf.st_mode ) ) {
printf( "%s is a dir\n", argv[n] );
} else {
printf( "%s is not a dir\n", argv[n] );
}
}
}
I don't know if that helps any. Note that the readdir() sample code uses opendir() as schot suggested. But I can't explain why your readdir() seems to work regardless.
My compiler says: "warning: 'dir' is used uninitialized in this function" You may want to add dir = opendir(root); after you initialize root. And don't forget to add some error checking.
I doubt this causes your problem, jcomeau_ictx is probably right. If lstat returns -1 it sets errno to a value that signifies the type of error. Look at its man page and the man page for strerror
Even though this question was asked long time ago, and I found it because this quesion. but the answers here didn't really solve the problem, so I decided to post the answer which I wrote on another post, such that if anyone had the same problem and used google to find this page, there is a clear answer.
The real reason of S_ISDIR not working as expected is dp->d_name contains only the name of the file, you need to pass the full path of the file to lstat().

fopen in C on solaris

I've been trying to get this code to work for hours! All I need to do is open a file to see if it is real and readable. I'm new to C so I'm sure there is something stupid I'm missing. Here is the code (shorthand, but copied):
#include <stdio.h>
main() {
char fpath[200];
char file = "/test/file.this";
sprintf(fpath,"~cs4352/projects/proj0%s",file);
FILE *fp = fopen(fpath,"r");
if(fp==NULL) {
printf("There is no file on the server");
exit(1);
}
fclose(fp);
//do more stuff
}
I have also verified that the path is correctly specifying a real file that I have read permissions to. Any other ideas?
Edit 1: I do know that the fpath ends up as "~cs4352/projects/proj0/test/file.this"
Edit 2: I have also tried the using the absolute file path. In both cases, I can verify that the paths are properly built via ls.
Edit 3: There errno is 2... I'm currently trying to track what that means in google.
Edit 4: Ok, errno of 2 is "There is no such file or directory". I am getting this when the reference path in fopen is "/home/courses1/cs4352/projects/proj0/index.html" which I verified does exist and I have read rights to it. As for the C code listed below, there may be a few semantic/newbie errors in it, but gcc does not give me any compile time warnings, and the code works exactly as it should except that it says that it keeps spitting errno of 2. In other words, I know that all the strings/char array are working properly, but the only thing that could be an issue is the fopen() call.
Solution: Ok, the access() procedure is what helped me the most (and what i am still using as it is less code, not to mention the more elegant way of doing it). The problem actually came from something that I didn't explain to you all (because I didn't see it until I used access()). To derrive the file, I was splitting strings using strtok() and was only splitting on " \n", but because this is a UNIX system, I needed to add "\r" to it as well. Once I fixed that, everything fell into place, and I'm sure that the fopen() function would work as well, but I have not tested it.
Thank you all for your helpful suggestions, and especially to Paul Beckingham for finding this wonderful solution.
Cheers!
The "~" is expanded by the shell, and is not expanded by fopen.
To test the existence and readability of a file, consider using the POSIX.1 "access" function:
#include <unistd.h>
if (access ("/path/to/file", F_OK | R_OK) == 0)
{
// file exists and is readable
}
First, file needs to be declared as char* or const char*, not simply char as you've written. But this might just be a typo, the compiler should at least give a warning there.
Secondly, use an absolute path (or a path relative to the current directory), not shell syntax with ~. The substitution of ~cs4352 by the respective home directory is usually done by the shell, but you are directly opening the file. So you are trying to open a file in a ~cs4352 subdirectory of your current working directory, which I guess is not what you want.
Other people have probably produced the equivalent (every modern shell, for example), but here's some code that will expand a filename with ~ or ~user notation.
#if __STDC_VERSION__ >= 199901L
#define _XOPEN_SOURCE 600
#else
#define _XOPEN_SOURCE 500
#endif
#include <assert.h>
#include <limits.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
char *relfname(const char *name, char *buffer, size_t bufsiz)
{
assert(name != 0 && buffer != 0 && bufsiz != 0);
if (name[0] != '~')
strncpy(buffer, name, bufsiz);
else
{
const char *copy;
struct passwd *usr = 0;
if (name[1] == '/' || name[1] == '\0')
{
usr = getpwuid(getuid());
copy = &name[1];
}
else
{
char username[PATH_MAX];
copy = strchr(name, '/');
if (copy == 0)
copy = name + strlen(name);
strncpy(username, &name[1], copy - &name[1]);
username[copy - &name[1]] = '\0';
usr = getpwnam(username);
}
if (usr == 0)
return(0);
snprintf(buffer, bufsiz, "%s%s", usr->pw_dir, copy);
}
buffer[bufsiz-1] = '\0';
return buffer;
}
#ifdef TEST
static struct { const char *name; int result; } files[] =
{
{ "/etc/passwd", 1 },
{ "~/.profile", 1 },
{ "~root/.profile", 1 },
{ "~nonexistent/.profile", 0 },
};
#define DIM(x) (sizeof(x)/sizeof(*(x)))
int main(void)
{
int i;
int fail = 0;
for (i = 0; i < DIM(files); i++)
{
char buffer[PATH_MAX];
char *name = relfname(files[i].name, buffer, sizeof(buffer));
if (name == 0 && files[i].result != 0)
{
fail++;
printf("!! FAIL !! %s\n", files[i].name);
}
else if (name != 0 && files[i].result == 0)
{
fail++;
printf("!! FAIL !! %s --> %s (unexpectedly)\n", files[i].name, name);
}
else if (name == 0)
printf("** PASS ** %s (no match)\n", files[i].name);
else
printf("** PASS ** %s -> %s\n", files[i].name, name);
}
return((fail == 0) ? EXIT_SUCCESS : EXIT_FAILURE);
}
#endif
You could try examining errno for more information on why you're not getting a valid FILE*.
BTW-- in unix the global value errno is set by some library and system calls when they need to return more information than just "it didn't work". It is only guaranteed to be good immediately after the relevant call.
char file = "/test/file.this";
You probably want
char *file = "/test/file.this";
Are you sure you do not mean
~/cs4352/projects/proj0%s"
for your home directory?
To sum up:
Use char *file=/test/file.this";
Don't expect fopen() to do shell substitution on ~ because it won't. Use the full path or use a relative path and make sure the current directory is approrpriate.
error 2 means the file wasn't found. It wasn't found because of item #2 on this list.
For extra credit, using sprintf() like this to write into a buffer that's allocated on the stack is a dangerous habit. Look up and use snprintf(), at the very least.
As someone else here mentioned, using access() would be a better way to do what you're attempting here.

Resources