Handle Spaces in File Path Unix programmatically - c

I'm trying to open files at random from my disk. Problem Is Most have Spaces in their path and won't
open unless I add backslashes on the fly, which is proving more difficult than I thought. While doing research I saw
how does unix handle full path name with space and arguments?
which say's that you can use backslashes or quotes but that was referring to passing arguments to the shell. Is it possible to do something like...
static int removeSpaces(char **inBuf, char **outBuf)
{
/* Declarations */
int rtrn;
char *pos;
/* Null terminate incoming buffer */
if((pos=strchr(*inBuf, '\n')) != NULL)
{
*pos = '\0';
}
rtrn = asprintf(outBuf, "\"%s\"", *inBuf);
if(rtrn < 0)
{
printf("Memory Error\n");
return -1;
}
return 0;
}
int main(void)
{
int rtrn;
char *file, *parsed;
rtrn = getFile(&file);
if(rtrn < 0)
{
printf("Can't Get File\n");
return -1;
}
rtrn = removeSpaces(&file, &parsed);
if(rtrn < 0)
{
printf("Can't Get File\n");
return -1;
}
printf("Parsed: %s\n", parsed);
fd = open(parsed, O_RDONLY);
if(fd < 0)
{
perror("Can't Open File\n");
return -1;
}
return 0;
}
I currently get no such file or directory, but i was wondering can I pass quoted file paths to open() or fopen(), or is that only the case with passing file paths to the shell. I'm asking because I saw very little information on the web specific to unix and unix-like systems, most was about windows (at least what i saw), and what i did find for unix was about the shell and not system calls.

Related

simulating '<' operator in a c programme

I am recreating a complete shell. For that I must simulate <. To do this, I have to use the function dup2().
I made this but it didn't work and I donc't understand why :
void simple_redirection_left(char *buffer, int index, global *glob)
{
char *file_name = &buffer[index + 1];
int fd = 0;
file_name = clean_file_name(file_name);
if (file_name[0] == '\0') {
my_putstr(1, "Missing name for redirect.\n");
return;
}
if ((fd = open(file_name, O_RDONLY)) == -1) {
printf("Error: file not found.\n");
return;
}
dup2(fd, STDIN_FILENO);
}
I first execute the binary on the left of the < in a fork() and then call the function above.
Did someone know why it didn't work ?
Thanks in advance for your answers.

How can I detect that I open()ed a directory in C, without using stat()?

I've written a simplified "cat" function in C. It is working fine, except when one of my argument is the name of a directory.
As it is an assignement, I'm only allowed to use "open", "read" and "close" functions in my code.
When "-1" is returned by function open(file, O_RDONLY), I call function ft_display_error to display error messages such as "No such file or directory".
Yet it doesn't work when "file" is a directory: in this case open will not return "-1". It will go on some kind of infinite loop.
void ft_display_file(char *file)
{
int fd;
char buf[BUF_SIZE + 1];
int ret;
fd = open(file, O_RDONLY);
if (fd == -1)
ft_display_error(file);
else
{
ret = read(fd, buf, BUF_SIZE);
while(ret)
{
buf[ret] = 0;
write(1, buf, ret);
ret = read(fd, buf, BUF_SIZE);
}
}
close(fd);
}
int main(int ac, char **av)
{
int i;
i = 1;
while (i < ac)
{
ft_display_file(av[i]);
i++;
}
}
Instead, I would like my program to identify that my argument is a directory, and then display the following message "cat: file: Is a directory.
Opening a directory for reading with open is the low level way of accessing its contents. Not very useful for you, but it doesn't allow to test for a directory.
If you cannot use stat (which is the best option) there seems to be another trick:
According to the documentation of open
The open() function shall fail if:
...
EISDIR
The named file is a directory and oflag includes O_WRONLY or O_RDWR.
So first try to open your file with O_RDWR (read-write) and if it fails, check if errno is equal to EISDIR
Code (untested)
fd = open(file, O_RDWR);
if ((fd == -1) && (errno == EISDIR))
{
// this is a directory
}

not able to read iio file from userspace

I am trying to read following file from C code.
file: /sys/bus/iio/devices/iio\:device0/in_voltage7_raw
but file pointer I am getting is -1.
Using cat command it is able to read the file.
But I am trying to read the same from my code as follows:
nos_int32 nos_adc_read_port (ADC_PORT_DB *p_port, nos_int32 *data)
{
char file_name[VALUE_MAX];
int value;
char buffer[BUFFER_LENGTH];
char intBuffer[INT_BUFFER_LENGTH];
int fd;
sprintf(file_name, "/sys/bus/iio/devices/iio\\:device0/in_voltage7_raw");
fd = open(file_name, O_RDONLY);
if (fd == -1) {
return(-1);
}
if (read(fd, buffer, BUFFER_LENGTH) == -1) {
return(-1);
}
close(fd);
memcpy(intBuffer, buffer, BUFFER_LENGTH);
intBuffer[INT_BUFFER_LENGTH-1] = '\0';
value = atoi(intBuffer);
*data = value;
return(0);
}
After the line:
fd = open(file_name, O_RDONLY);
value of fd is -1. How can it be solved?
Most command line shells use some characters for special actions and if you're trying to use them as their actual character, you need to prefix them with a backslash to escape them. In this case, your shell needs you to escape the colon when accessing that filename.
In C you don't have this issue so you can put in your code the filename as it truly is, such as:
"/sys/bus/iio/devices/iio:device0/in_voltage7_raw"

Creating my own redirect and duplicate pipe functions

I am making a small shell and I am having some problems with two of my functions.
They are kind of out of context but I hope you can understand what I am trying to do so I don't have to post my whole code.
My dupPipe function:
I want to duplicate a pipe to a std I/O file descriptor and close both of the pipe ends. It looks like this: int dupPipe(int pip[2], int end, int destinfd);. Where end tells which pipe to duplicate, either READ_END or WRITE_END and destinfd tells which std I/O file descriptor to replace.
My Redirect function:
It's supposed to redirect a std I/O file descriptor to a file.
It looks like this, int redirect(char *file, int flag, int destinfd);.
Where flag indicate if the file should be read from or written to and destinfd is the std I/O file descriptor I want to redirect.
What I have done:
int dupPipe(int pip[2], int end, int destinfd)
{
if(end == READ_END)
{
dup2(pip[0], destinfd);
close(pip[0]);
}
else if(end == WRITE_END)
{
dup2(pip[1], destinfd);
close(pip[1]);
}
return destinfd;
}
Second function:
int redirect(char *filename, int flags, int destinfd)
{
if(flags == 0)
{
return destinfd;
}
else if(flags == 1)
{
FILE *f = fopen(filename, "w");
if(! f)
{
perror(filename);
return -1;
}
}
else if(flags == 2)
{
FILE *f = fopen(filename, "r");
if(! f)
{
perror(filename);
return -1;
}
}
return destinfd;
}
I appreciate any help given, what have I done wrong or haven't done with the function that I wrote wanted to? Thanks.
The redirect function doesn't appear to be doing what you want. You're opening a file using fopen, but you're not linking it to destinfd in any way. You probably want to use open instead, then use dup2 to move the file descriptor to where you want.
int redirect(char *filename, int flags, int destinfd)
{
int newfd;
if(flags == 0) {
return -1;
} else if(flags == 1) {
newfd = open(filename, O_WRONLY);
if (newfd == -1) {
perror("open for write failed");
return -1;
}
} else if(flags == 2) {
newfd = open(filename, O_RDONLY);
if (newfd == -1) {
perror("open for read failed");
return -1;
}
} else {
return -1;
}
if (dup2(newfd, destinfd) == -1) {
perror("dup2 failed");
close(newfd);
return -1;
}
close(newfd);
return destinfd;
}

How to decide if a file descriptor is attached to a file or socket in Linux

Using C language in Linux, how to decide if a file descriptor is attached to a file or socket?
Use getsockopt to get SO_TYPE on the file descriptor. If it is not a socket, it will return -1 with the error ENOTSOCK:
int fd = /* ... */;
bool is_socket;
int socket_type;
socklen_t length = sizeof(socket_type);
if(getsockopt(fd, SOL_SOCKET, SO_TYPE, &socket_type, &length) != -1) {
is_socket = true;
} else {
if(errno == ENOTSOCK) {
is_socket = false;
} else {
abort(); /* genuine error */
}
}
/* whether it is a socket will be stored in is_socket */
Alternatively, you can use fstat and the S_ISSOCK macro.
int main(int argc, char *argv[])
{
int fds[2];
fds[0] = 0; //stdin
fds[1] = socket(AF_INET,SOCK_STREAM, 0);
for (int i = 0; i < 2; ++i)
{
struct stat statbuf;
if (fstat(fds[i], &statbuf) == -1)
{
perror("fstat");
exit(1);
}
if (S_ISSOCK(statbuf.st_mode))
printf("%d is a socket\n", fds[i]);
else
printf("%d is NOT a socket\n", fds[i]);
}
return(0);
}
According to socket(7) man page:
Seeking, or calling pread(2) or pwrite(2) with a nonzero position is not supported on sockets.
So, another option would be to do one of those unsupported operations and see if you get an error. If you managed to seek, then FD is probably a file (or a device). Otherwise it may be a socket. Or a pipe.

Resources