How to check if a file is in given directory - c

I tried to search that in many words, but for some reason I am solely given references to questions like "How to check if file or directory exists".
Instead, I would like to check if a given file is located in a given directory.
The problem is that the file, the directory or both can and sometimes have to be passed as a relative path, instead of absolute path.
Is there any windows/unix function that checks on that?

here is an example of using the stat() function regardless if the 'filename' is a full path or just the file name
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#if 0
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* Inode number */
mode_t st_mode; /* File type and mode */
nlink_t st_nlink; /* Number of hard links */
uid_t st_uid; /* User ID of owner */
gid_t st_gid; /* Group ID of owner */
dev_t st_rdev; /* Device ID (if special file) */
off_t st_size; /* Total size, in bytes */
blksize_t st_blksize; /* Block size for filesystem I/O */
blkcnt_t st_blocks; /* Number of 512B blocks allocated */
/* Since Linux 2.6, the kernel supports nanosecond
precision for the following timestamp fields.
For the details before Linux 2.6, see NOTES. */
struct timespec st_atim; /* Time of last access */
struct timespec st_mtim; /* Time of last modification */
struct timespec st_ctim; /* Time of last status change */
#define st_atime st_atim.tv_sec /* Backward compatibility */
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
};
#endif
bool doesFileExistInDir( char *path, char *filename )
{
struct stat myStat;
int statStatus;
char pathname[ strlen(path) + strlen( filename ) + 1];
if( !strchr( filename, '/' ) )
{
pathname[0] = '\0';
strcat( pathname, path );
// strcat( pathname, "/" );
strcat( pathname, filename );
}
else
{
strcpy( pathname, filename );
}
if( (statStatus = stat( pathname, &myStat )) != 0 )
{
// then file not accessible -or- directory not readable -or- file does not exist
perror( "stat failed" );
return false;
}
return true;
}

This function can be used to determine if dirname is the directory of filename.
int file_is_in_directory (char *filename, char *dirname) /* [!] Windows-specific */
{
char filename_full[MAX_PATH] = {'\0'};
char dirname_full[MAX_PATH] = {'\0'};
char* file = NULL;
GetFullPathNameA(filename, MAX_PATH, filename_full, NULL); /* [!] Check rval */
GetFullPathNameA(dirname, MAX_PATH, dirname_full, NULL); /* [!] Check rval */
if(!strncmp(dirname_full, filename_full, strlen(dirname_full)))
{
return 1; /* File is located in directory */
}
return 0; /* File not contained */
}

Related

Reading txt files in a choosen directory

#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
int main (void)
{
DIR *dp;
struct dirent *ep;
dp = opendir ("./");
if (dp != NULL)
{
while (ep = readdir (dp))
puts (ep->d_name);
(void) closedir (dp);
}
else
perror ("Couldn't open the directory");
return 0;
}
This code gives me all things in that directory. It works like "ls" command. For example let's say i have one folder which is name is "folder" and one .txt file which is name is "input" (names are could be different btw) , in that directory. I want to decide if it is folder or txt file.If it is txt file how can i read it?
]You can use scandir() function to open and scan the entries in a directory.
The example comes from man 3 scandir
#define _SVID_SOURCE
/* print files in current directory in reverse order */
#include <dirent.h>
int
main(void)
{
struct dirent **namelist;
int n;
n = scandir(".", &namelist, NULL, alphasort);
if (n < 0)
perror("scandir");
else {
while (n--) {
printf("%s\n", namelist[n]->d_name);
free(namelist[n]);
}
free(namelist);
}
}
Note the struct dirent:
struct dirent {
ino_t d_ino; /* inode number */
off_t d_off; /* offset to the next dirent */
unsigned short d_reclen; /* length of this record */
unsigned char d_type; /* type of file; not supported
by all file system types */
char d_name[256]; /* filename */
};
you can check if current entry is a regular file, directory or others by d_type field.
Available file types are :
#define DT_UNKNOWN 0
#define DT_FIFO 1
#define DT_CHR 2
#define DT_DIR 4 // directory type
#define DT_BLK 6
#define DT_REG 8 // regular file, txt file is a regular file
#define DT_LNK 10
#define DT_SOCK 12
#define DT_WHT 14
After checking the name and type of file, you can safely open it with open()(system call) or fopen()(glib function) and read the contents by read()(if you opened file via open() or fread()(fopen() counterpart).
DON'T forget to close file after read.
Besides, if you just want to check the existence and accessibility of a directory, access() is handle.
The code below tests if the dir exist.
int exist_dir (const char *dir)
{
DIR *dirptr;
if (access(dir, F_OK) != -1) {
// file exists
if ((dirptr = opendir(dir)) != NULL) {
// do something here
closedir (dirptr);
} else {
// dir exists, but not a directory
return -1;
}
} else {
// dir does not exist
return -1;
}
return 0;
}
All information about a file except the contents can be get by calling function stat. stat has signature
int stat(const char *pathname, struct stat *buf);
and returns information about the file in the buffer pointed to by buf.
struct stat encodes information of file type and file permission in the field st_mode.
Some additional macros are defined to test the file type:
S_ISREG(m) is it a regular file?
S_ISDIR(m) directory?
S_ISCHR(m) character device?
S_ISBLK(m) block device?
S_ISFIFO(m) FIFO (named pipe)?
S_ISLNK(m) symbolic link? (Not in POSIX.1-1996.)
S_ISSOCK(m) socket? (Not in POSIX.1-1996.)
Here is a piece of sample code:
stat(pathname, &sb);
if (S_ISREG(sb.st_mode)) {
/* Handle regular file */
}
As for reading, concatenate directory path and filename to get file path, using function sprintf, like this:
sprintf(file_path, "%s/%s", dir_path, file_name);

How can I know text file is empty or not?(in C)

I'm trying to detect text file is empty or not in C.
(values are initialized in NULL)
Whenever read first in value(using fscanf), it always returns file has zero,
even if it has value "0" or "empty".
How can I know the target text file is empty or not?
(it should be distinguished even it has "0" in first letter)
If the file was successfully open for read, as per fopen(filename, "r"), you can verify if it is empty before any read operation this way:
int is_empty_file(FILE *fp) {
int c = getc(fp);
if (c == EOF)
return 1;
ungetc(c, fp);
return 0;
}
ungetc() is guaranteed to work for at least one character. The above function will return 1 if the file is empty or if it cannot be read, due to an I/O error. You can tell which by testing ferr(fp) or feof(fp).
If the file is a stream associated to a device or a terminal, the test code will block until at least one byte can be read, or end of file is signaled.
If the file is a regular file, you could also use a system specific API to determine the file size, such as stat, lstat, fstat (on Posix systems).
If you're under Linux, you can use stat or fstat:
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *path, struct stat *buf);
Will give you this information:
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */
mode_t st_mode; /* protection */
nlink_t st_nlink; /* number of hard links */
uid_t st_uid; /* user ID of owner */
gid_t st_gid; /* group ID of owner */
dev_t st_rdev; /* device ID (if special file) */
off_t st_size; /* total size, in bytes */
blksize_t st_blksize; /* blocksize for file system I/O */
blkcnt_t st_blocks; /* number of 512B blocks allocated */
time_t st_atime; /* time of last access */
time_t st_mtime; /* time of last modification */
time_t st_ctime; /* time of last status change */
};
To check for the size using stat:
struct stat info;
if(stat(filepath, &info) < 0) {
/* error */
}
if(info.st_size == 0) {
/* file is empty */
}
Or using fstat:
int fd = open(filepath, O_RDONLY);
struct stat info;
if(fstat(fd, &info) < 0) {
/* error */
}
if(info.st_size == 0) {
/* file is empty */
}
you can do using ftell
#include <stdio.h>
int get_file_size (char *filename) {
FILE *fp;
int len;
fp = fopen(filename, "r");
if( fp == NULL ) {
perror ("Error opening file");
return(-1);
}
fseek(fp, 0, SEEK_END);
len = ftell(fp);
fclose(fp);
return(len);
}

Stat Structure Segmentation Fault

struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */
mode_t st_mode; /* protection */
nlink_t st_nlink; /* number of hard links */
uid_t st_uid; /* user ID of owner */
gid_t st_gid; /* group ID of owner */
dev_t st_rdev; /* device ID (if special file) */
off_t st_size; /* total size, in bytes */
blksize_t st_blksize; /* blocksize for file system I/O */
blkcnt_t st_blocks; /* number of 512B blocks allocated */
time_t st_atime; /* time of last access */
time_t st_mtime; /* time of last modification */
time_t st_ctime; /* time of last status change */
}
I am working with the stat struct in C and I want to output each of the fields. When I try to output st_atime, st_mtime, and st_ctime I am using the following lines:
printf("Last file change: %s\n", ctime(sb.st_ctime));
printf("Last file access time: %s\n", ctime(sb.st_atime));
printf("Last file mod time: %s\n", ctime(sb.st_mtime));
For some reason, I am getting a Segmentation Fault(Core Dump) error. My declaration for the stat struct is:
struct stat sb;
#include <stdio.h>
#include <sys/stat.h>
char file[128];
int main(int argc, char *argv[]){
struct stat sb;
sprintf(file, "%s", argv[1]);
if(stat(file, &sb) == 0)
{
printf("Last change: %s\n", ctime(sb.st_ctime));
printf("Last File access: %s\n", ctime(sb.st_atime));
printf("Last file mod: %s\n", ctime(sb.st_mtime));
}
else
{
printf("File name does not exist!\n");
}
return 0;
}
EDIT:
To use the function ctime you should include time.h library using
#include <time.h>
The function ctime receives a pointer to a time_t.
char* ctime (const time_t * timer);
You are passing the time_t itself. You should pass the address of your struct or change the time to time_t * in your struct. This approach is dangerous depending where you are declaring your struct.
printf("Last file change: %s\n", ctime(&(sb.st_ctime)));
or change the declaration to
time_t* st_ctime; /* time of last status change */
You should pass reference to ctime according to its documentation so I suggest to use:
printf("Last file change: %s\n", ctime(&sb.st_ctime));
printf("Last file access time: %s\n", ctime(&sb.st_atime));
printf("Last file mod time: %s\n", ctime(&sb.st_mtime));

Adding Argument to a char device

I am writing a character device that will be given a processes pid and return the parent process id, start time, and number of siblings. I am using this site: http://tldp.org/LDP/lkmpg/2.6/html/x892.html#AEN972 as a guide.
I would like to add an argument into the read call of the character driver but it is not letting me do that. My code looks like this:
/*
* chardev.c - Create an input/output character device
*/
#include <linux/kernel.h> /* We're doing kernel work */
#include <linux/module.h> /* Specifically, a module */
#include <linux/fs.h>
#include <asm/uaccess.h> /* for get_user and put_user */
#include "chardev.h"
#define SUCCESS 0
#define DEVICE_NAME "char_dev"
#define BUF_LEN 80
struct procinfo {
pid_t pid;
pid_t ppid;
struct timespec start_time;
int num_sib;
};
/*
* Is the device open right now? Used to prevent
* concurent access into the same device
*/
static int Device_Open = 0;
/*
* The message the device will give when asked
*/
static char Message[BUF_LEN];
/*
* How far did the process reading the message get?
* Useful if the message is larger than the size of the
* buffer we get to fill in device_read.
*/
static char *Message_Ptr;
/*
* This is called whenever a process attempts to open the device file
*/
static int device_open(struct inode *inode, struct file *file)
{
#ifdef DEBUG
printk(KERN_INFO "device_open(%p)\n", file);
#endif
/*
* We don't want to talk to two processes at the same time
*/
if (Device_Open)
return -EBUSY;
Device_Open++;
/*
* Initialize the message
*/
Message_Ptr = Message;
try_module_get(THIS_MODULE);
return SUCCESS;
}
static int device_release(struct inode *inode, struct file *file)
{
#ifdef DEBUG
printk(KERN_INFO "device_release(%p,%p)\n", inode, file);
#endif
/*
* We're now ready for our next caller
*/
Device_Open--;
module_put(THIS_MODULE);
return SUCCESS;
}
/*
* This function is called whenever a process which has already opened the
* device file attempts to read from it.
*/
static ssize_t device_read(struct file *file, /* see include/linux/fs.h */
char __user * buffer, /* buffer to be
* filled with data */
pid_t pid,
size_t length, /* length of the buffer */
loff_t * offset)
{
/*
* Number of bytes actually written to the buffer
*/
int bytes_read = 0;
#ifdef DEBUG
printk(KERN_INFO "device_read(%p,%p,%d)\n", file, buffer, length);
#endif
/*
* If we're at the end of the message, return 0
* (which signifies end of file)
*/
if (*Message_Ptr == 0)
return 0;
/*
* Actually put the data into the buffer
*/
while (length && *Message_Ptr) {
/*
* Because the buffer is in the user data segment,
* not the kernel data segment, assignment wouldn't
* work. Instead, we have to use put_user which
* copies data from the kernel data segment to the
* user data segment.
*/
put_user(*(Message_Ptr++), buffer++);
length--;
bytes_read++;
}
#ifdef DEBUG
printk(KERN_INFO "Read %d bytes, %d left\n", bytes_read, length);
#endif
/*
* Read functions are supposed to return the number
* of bytes actually inserted into the buffer
*/
return bytes_read;
}
/*
* This function is called when somebody tries to
* write into our device file.
*/
static ssize_t
device_write(struct file *file,
const char __user * buffer, size_t length, loff_t * offset)
{
int i;
#ifdef DEBUG
printk(KERN_INFO "device_write(%p,%s,%d)", file, buffer, length);
#endif
for (i = 0; i < length && i < BUF_LEN; i++)
get_user(Message[i], buffer + i);
Message_Ptr = Message;
/*
* Again, return the number of input characters used
*/
return i;
}
/*
* This function is called whenever a process tries to do an ioctl on our
* device file. We get two extra parameters (additional to the inode and file
* structures, which all device functions get): the number of the ioctl called
* and the parameter given to the ioctl function.
*
* If the ioctl is write or read/write (meaning output is returned to the
* calling process), the ioctl call returns the output of this function.
*
*/
long device_ioctl(struct file *file, /* see include/linux/fs.h */
unsigned int ioctl_num, /* number and param for ioctl */
unsigned long ioctl_param)
{
int i;
char *temp;
char ch;
/*
* Switch according to the ioctl called
*/
switch (ioctl_num) {
case IOCTL_SET_MSG:
/*
* Receive a pointer to a message (in user space) and set that
* to be the device's message. Get the parameter given to
* ioctl by the process.
*/
temp = (char *)ioctl_param;
/*
* Find the length of the message
*/
get_user(ch, temp);
for (i = 0; ch && i < BUF_LEN; i++, temp++)
get_user(ch, temp);
device_write(file, (char *)ioctl_param, i, 0);
break;
case IOCTL_GET_MSG:
/*
* Give the current message to the calling process -
* the parameter we got is a pointer, fill it.
*/
i = device_read(file, (char *)ioctl_param, 99, 0);
/*
* Put a zero at the end of the buffer, so it will be
* properly terminated
*/
put_user('\0', (char *)ioctl_param + i);
break;
case IOCTL_GET_NTH_BYTE:
/*
* This ioctl is both input (ioctl_param) and
* output (the return value of this function)
*/
return Message[ioctl_param];
break;
}
return SUCCESS;
}
/* Module Declarations */
/*
* This structure will hold the functions to be called
* when a process does something to the device we
* created. Since a pointer to this structure is kept in
* the devices table, it can't be local to
* init_module. NULL is for unimplemented functions.
*/
struct file_operations Fops = {
.read = device_read,
.write = device_write,
.unlocked_ioctl = device_ioctl,
.open = device_open,
.release = device_release, /* a.k.a. close */
};
/*
* Initialize the module - Register the character device
*/
int init_module()
{
int ret_val;
/*
* Register the character device (atleast try)
*/
ret_val = register_chrdev(MAJOR_NUM, DEVICE_NAME, &Fops);
/*
* Negative values signify an error
*/
if (ret_val < 0) {
printk(KERN_ALERT "%s failed with %d\n",
"Sorry, registering the character device ", ret_val);
return ret_val;
}
printk(KERN_INFO "%s The major device number is %d.\n",
"Registeration is a success", MAJOR_NUM);
printk(KERN_INFO "If you want to talk to the device driver,\n");
printk(KERN_INFO "you'll have to create a device file. \n");
printk(KERN_INFO "We suggest you use:\n");
printk(KERN_INFO "mknod %s c %d 0\n", DEVICE_FILE_NAME, MAJOR_NUM);
printk(KERN_INFO "The device file name is important, because\n");
printk(KERN_INFO "the ioctl program assumes that's the\n");
printk(KERN_INFO "file you'll use.\n");
return 0;
}
/*
* Cleanup - unregister the appropriate file from /proc
*/
void cleanup_module()
{
unregister_chrdev(MAJOR_NUM, DEVICE_NAME);
#if 0
int ret;
/*
* Unregister the device
*/
ret = unregister_chrdev(MAJOR_NUM, DEVICE_NAME);
/*
* If there's an error, report it
*/
if (ret < 0)
printk(KERN_ALERT "Error: unregister_chrdev: %d\n", ret);
#endif
}

How to display st_atime and st_mtime

I want to display my two attributes from the structure stat
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */
mode_t st_mode; /* protection */
nlink_t st_nlink; /* number of hard links */
uid_t st_uid; /* user ID of owner */
gid_t st_gid; /* group ID of owner */
dev_t st_rdev; /* device ID (if special file) */
off_t st_size; /* total size, in bytes */
blksize_t st_blksize; /* blocksize for file system I/O */
blkcnt_t st_blocks; /* number of 512B blocks allocated */
time_t st_atime; /* time of last access */
time_t st_mtime; /* time of last modification */
time_t st_ctime; /* time of last status change */
};
Here is my code that i try to display the last time access and the last time of last modification of folder/file
struct tm *time;
char buffer[200];
time = localtime(file_info.st_atime);
strftime(buffer, sizeof(buffer), "%d.%m.%Y %H:%M:%S", time);
printf("%s\n", buffer);
time = localtime(file_info.st_mtime);
strftime(buffer, sizeof(buffer), "%d.%m.%Y %H:%M:%S", time);
printf("%s\n", buffer);
I want to display like human readble time and date like 15.03.1952 23:11:34 of a folder/file info that has been last modifed or access in linux
This deviates a bit from your code in terms of style, but perhaps it's helpful?
#include <time.h>
#include <stdio.h>
#include <sys/stat.h>
#include <stdlib.h>
char* formatdate(char* str, time_t val)
{
strftime(str, 36, "%d.%m.%Y %H:%M:%S", localtime(&val));
return str;
}
int main()
{
int errno;
const char* filename;
filename = "stat.c";
errno = 0;
struct stat *file_info = malloc(sizeof(struct stat));
if (lstat(filename, file_info) != 0) {
perror("Error");
exit(1);
}
char date[36];
printf("Access: %s\n", formatdate(date, file_info->st_atime));
printf("Modify: %s\n", formatdate(date, file_info->st_mtime));
printf("Change: %s\n", formatdate(date, file_info->st_ctime));
free(file_info);
return 0;
}
char buffer[200];
printf("Access : %s\n", formatdate(buffer, file_info.st_atime));
printf("Modify : %s\n", formatdate(buffer, file_info.st_mtime));
printf("\n\n");
char *formatdate(char *buff, time_t val)
{
strftime(buff,200, "%d.%m.%Y %H:%M:%S", localtime(&val));
return buff;
}
And this is the answer that i was looking for thanks again.
Try this: printf("%s", asctime(localtime(&buffer.st_mtime)));

Resources