Accidently creating gigantic file with write - c

this is the code I am using:
#include <stdio.h>
#include <stdlib.h>
void main(){
test = creat("TEST",0751);
close(test);
test = open("TEST",2);
write(test, "123456789101112131415",21);
lseek(test,-2,2);
read(test,swap_array,2);
write(test,swap_array,2);
lseek(test,-6, 1);
write(test,"xx",2);
}
This creates an 8gb file containing instead of inserting "xx" in between the numbers as I intend. What is wrong with the code as I have it?

You have failed to include the appropriate header files. You should include, at a minimum:
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
Additionally, this will give you access to the symbolic constants required to make your code maintainable.
Here is a working version of your program:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main() {
char swap_array[2];
int test = creat("TEST",0751);
close(test);
test = open("TEST",O_RDWR);
write(test, "123456789101112131415",21);
lseek(test,-2,SEEK_END);
read(test,swap_array,2);
write(test,swap_array,2);
lseek(test,-6, SEEK_CUR);
write(test,"xx",2);
return 0;
}

You probably aren't including the headers, so there's probably no prototype for lseek() in scope, so the 2 in the middle argument is an int, but lseek() expects (a long) an off_t, and you're on a 64-bit machine where sizeof(int) != sizeof(long) so the two 2's are misinterpreted by the system call (maybe treating them as the offset and for whatever reason what's left on the stack is interpreted as SEEK_SET or otherwise jumps to a large offset).
Basically, you're probably passing inaccurately typed information to the system call because you haven't included the correct headers. Classically (before POSIX interfered), the middle 2 would be 2L because the l in lseek() stood for 'long' — prior to that, there was a seek() which took a plain int (in the days of 16-bit int types) — to ensure that a long is passed as lseek()
requires. These days, lseek() requires an off_t; using the prototype is crucial to ensure that what you write is interpreted correctly as an off_t.
There's a lot of UB lurking in that description, but the fact that you're not using SEEK_SET etc raises warning flags. Also, why is the file executable? That doesn't look like executable code you're writing.
This variant of the code is more careful (and doesn't create an 8 GiB file on Mac OS X 10.11.6 with GCC 6.2.0).
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#define MODE_0751 (S_IRWXU | S_IRGRP | S_IXGRP | S_IXOTH)
int main(void)
{
// All error checking omitted
char swap_array[2];
int test = creat("TEST", MODE_0751);
close(test);
test = open("TEST", O_RDWR);
write(test, "123456789101112131415", 21);
lseek(test, -2L, SEEK_END);
read(test, swap_array, 2);
write(test, swap_array, 2);
lseek(test, -6L, SEEK_CUR);
write(test, "xx", 2);
close(test);
return 0;
}
I use the L's out of (very) old habit, but they're optional. The various 2's could be replaced by sizeof(swap_array) (and sizeof("xx")-1). I learned C long enough ago that the octal permissions were the only way of doing business; the S_IRWXU and related names were years in the future. I find a 4-digit or 5-digit octal number more readable than a string of S_Iwxyz names.
Make sure you compile your code with options set so that prototypes are required before you can use functions. For example, I use:
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes \
> -Wstrict-prototypes -Wold-style-definition mx19.c -o mx19
$

Related

Does getcwd() ignore the size of the buffer and copy it?

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main() {
char wd[10];
if(getcwd(wd,BUFSIZ) == NULL){ //BUFSIZ = 8192
perror("getcwd");
exit(1);
}
printf("wd = %s\n",wd);
}
This C code works well in Ubuntu Linux 20.
The size of buffer wd is 10 but if I print the wd, it can output a string that is over size 10.
I think that the function uses the pointer of wd regardless of size, so it can work well but it can also print dummy string. Is it right?
//Edit :
printf("wd2 = %s\n",wd2); -> printf("wd = %s\n",wd);
You lie to getcwd about buffer size.
getcwd does not magically know the buffer size. Buffers which know their own size is not a C language feature. That's why getcwd needs the size parameter!
So, getcwd happily writes beyond end of array.
In C, this is Undefined Behavior. Anything can happen, and "anything" includes what you observe here.
Alright, let's get you straightened out:
You can't declare wd as char[10] and then try and read 8192 bytes into it -- won't work,
You can't declare wd and then try and output wd2 -- won't work, and your compiler should be screaming errors at you,
\\n is a literal "\n" (two \\ are a literal '\') not a newline '\n',
#include <limits.h> and #define _GNU_SOURCE to make PATH_MAX available -- which is the maximum length a pathname can be on your system (if any) -- then read that many bytes with getcwd().
Putting it altogether, you can do:
#define _GNU_SOURCE /* needed for PATH_MAX */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h> /* needed for PATH_MAX */
int main (void) {
char wd[PATH_MAX]; /* define your buffer with size PATH_MAX */
if (getcwd (wd, PATH_MAX) == NULL) { /* get the same number of bytes */
perror("getcwd");
exit(1);
}
printf ("wd = %s\n", wd); /* output the results using same variable */
}
Compile
With the source in getcwd.c and ALWAYS compiling with FULL WARNINGS ENABLED, you can do:
$ gcc -Wall -Wextra -pedantic -Wshadow -std=c11 -Ofast -o bin/getcwd getcwd.c
(note: I have a bin directory in my current directory that I put executables in to keep from cluttering my source directory)
Don't accept code until it compiles without warning. Add -Werror to treat warnings as errors so you can't cheat.
Example Use/Output
Running the program yields:
$ ./bin/getcwd
wd = /home/david/dev/src-c/tmp/debug
Let me know if you have further questions.

How do I fix "'struct _IO_FILE' has no member named '_file'"?

I have a version of a program that used to compile to a *.o file, but now it does not, and gives a compiler error.
I have tried to compile my code with gcc compiler on Linux, and the compile fails.
#include <stdio.h>
int isatty();
long isatty_(lio_number)
long *lio_number;
{
int file_desc;
if ((*lio_number)==5)
{
file_desc = stdin->_file;
return isatty(file_desc);
}
else
return 0;
}
I expect the command gcc -c isatty.c to yield isatty.o but it does not. Instead, I get this message:
isatty.c: In function ‘isatty_’:
isatty.c:11: error: ‘struct _IO_FILE’ has no member named ‘_file’
Never use any members of the FILE structure.
Use fileno(stdin) instead of stdin->_file.
The member _file is a MinGW-specific name for the file descriptor, while fileno is a widely-supported POSIX-compliant function.
Along with that, you may want to #include <unistd.h> instead of defining isatty explicitly.
If you're limited to writing your code this way for some reason, don't expect it to be portable. Otherwise, this should work:
#include <stdio.h>
#include <unistd.h>
long isatty_(long *lio_number)
{
int file_desc;
if (*lio_number == 5)
{
file_desc = fileno(stdin);
return isatty(file_desc);
}
else
{
return 0;
}
}
What this changes is that it includes unistd.h which provides a declaration for isatty, it includes the types of the arguments within the function definition, and it uses fileno(stdin) instead of stdin->_file, of which the former is much more portable. It also improves the formatting so others can read your code if they need to.
Modernize the code. The original seems to be targeting some ancient Unix. This should work on more recent POSIX-compliant systems, since virtually every such system should provide the fileno() function. Changing the code to standard C is also a good idea.
So use fileno(), include <unistd.h> instead of forward declaring isatty(), and use standard C function parameter declarations:
#include <stdio.h>
#include <unistd.h>
long isatty_(long *lio_number)
{
if (*lio_number == 5)
{
return isatty(fileno(stdin));
}
return 0;
}

Use of undeclared identifier 'O_DIRECT'

Apple LLVM version 10.0.0 (clang-1000.10.44.4)
Target: x86_64-apple-darwin18.0.0
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#define _GNU_SOURCE
#define __USE_GNU 1
#include <fcntl.h>
int main()
{
int fd = open("./test.txt", O_WRONLY|O_DIRECT);
close(fd);
return 0;
}
I use clang -o out test.c and get the following result:
test.c:14:39: error: use of undeclared identifier 'O_DIRECT'
int fd = open("./test.txt", O_WRONLY|O_DIRECT);
How can I solve the problem?
Thank you.
With this snippet it is impossible to tell what you are trying to do, but in general do not use nonstandard stuff in applications intended to be portable.
The portable way to accomplish your task is probably fsync.
To sum up
For LINUX, the O_DIRECT flag has to be included. For Mac OSX, O_DIRECT is not available. Instead, fcntl(fd, F_NOCACHE, 1) looks to be the canonical solution where fd is the file descriptor of the file. For Windows, there is a flag called FILE_FLAG_NO_BUFFERING as the counterpart in Windows of O_DIRECT
Reference here

stat.h file access file descriptors open() Hacking The Art of Exploitation

I am working out of the 2nd edition of Jon Erickson's "Hacking: The Art of Exploitation" using a VM (virutalbox) to run the LiveCD it came with (Ubuntu 7.04). In section 0x281 "File Access", the author explains accessing files through file descriptors, as well as the open() close() read() and write() functions, using an example on pages 82-84.
The code for the simplenote.c is as follows:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
void usage(char *prog_name,char *filename){
printf("Usage: %s < data to add to %s>\n",prog_name,filename);
exit(0);
}
void fatal(char *);
void *ec_malloc(unsigned int );
int main(int argc,char *argv[]){
int fd; //file descriptor
char *buffer,*datafile;
buffer = (char *)ec_malloc(100);
datafile = (char *)ec_malloc(20);
strcpy(datafile,"/tmp/notes");
if(argc < 2)
usage(argv[0],datafile);
strcpy(buffer,argv[1]);
printf("[DEBUG] buffer # %p:\'%s'\n",buffer,buffer);
printf("[DEBUG] datafile # %p:\'%s'\n",datafile,datafile);
strncat(buffer,"\n",1);//Add a newline on the end.
fd = open(datafile,O_WRONLY|O_CREAT|O_APPEND,S_IRUSR|S_IWUSR);
if(fd == -1)
fatal("in main() while opening file");
printf("[DEBUG] file descriptor is %d\n",fd);
//Writing data
if(write(fd,buffer,strlen(buffer)) == -1)
fatal("in main() while writing buffer to file");
//Closing file
if(close(fd) == -1)
fatal("in main() while closing file");
printf("Note has been saved.\n");
free(buffer);
free(datafile);
}
//A function to display an error message and then exit
void fatal(char *message){
char error_message[100];
strcpy(error_message,"[!!]Fatal Error");
strncat(error_message,message,83);
perror(error_message);
exit(-1);
}
//An error-checked malloc() wrapper function
void *ec_malloc(unsigned int size){
void *ptr;
ptr = malloc(size);
if(ptr == NULL)
fatal("in ec_malloc() on memory allocation");
return ptr;
}
However, when I type the following instructions stated in the book into my terminal window, it returns the following error message:
reader#hacking:~/booksrc $ gcc -o simplenote simplenote.c
In file included from /usr/include/sys/stat.h:105, from simplenote.c:6:
/usr/include/bits/stat.h:70: error: field 'st_atim' has incomplete type
/usr/include/bits/stat.h:71: error: field 'st_mtim' has incomplete type
/usr/include/bits/stat.h:72: error: field 'st_ctim' has incomplete type
simplenote.c: In function 'main':
simplenote.c:35: error: 'O-WRONLY' undeclared (first use in this function)
simplenote.c:35: error: (Each undeclared identifier is reported only once
simplenote.c:35: error: for each function it appears in.)
simplenote.c:35: error: 'O_CREAT' undeclared (first use in this function)
simplenote.c:35: error: 'O_APPEND' undeclared (first use in this function)
Here is sys/stat.h line 105:
#include <bits/stat.h>
And here is bits/stat.h lines 63-83:
#ifdef __USE_MISC
/* Nanosecond resolution timestamps are stored in a format
equivalent to 'struct timespec'. This is the type used
whenever possible but the Unix namespace rules do not allow the
identifier 'timespec' to appear in the <sys/stat.h> header.
Therefore we have to handle the use of this header in strictly
standard-compliant sources special. */
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
#else
__time_t st_atime; /* Time of last access. */
unsigned long int st_atimensec; /* Nscecs of last access. */
__time_t st_mtime; /* Time of last modification. */
unsigned long int st_mtimensec; /* Nsecs of last modification. */
__time_t st_ctime; /* Time of last status change. */
unsigned long int st_ctimensec; /* Nsecs of last status change. */
#endif
I suppose this might be of some use for the first set of issues:
C++ system file bits/stat.h suddenly breaks with "error: field ‘st_atim’ has incomplete type"
/usr/include/time.h
cat time.h
doesn't do anything in my terminal window.
And here is the simplenote.c main function lines 1-6, 34-35:
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
// Opening the file
fd = open(datafile, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR);
I'm guessing the open function problems stem from fcntl.h ?
I seem to keep running into issues because of faulty code the author provided. I don't want to constantly depend on the stackoverflow community for help, so what suggestions do you have for a novice about examining and fixing these problems in the future?
Thanks.
Transferring a selection of comments into a semi-coherent answer.
You should probably explicitly enable POSIX definitions. Add -D_XOPEN_SOURCE=700 to the command line, or #define _XOPEN_SOURCE 700 before the first #include and see if that solves anything. You should not be running into the problem though; the header should be self-contained.
Oh, but Ubuntu 7.04 is archaic…you may need to use 600 instead of 700. When was it released (when was the book published)? If it was 2009 or before, you probably need the older version (600). It's still surprising that you're seeing the error. The command line you specify doesn't contain the options that normally cause trouble (-ansi -pedantic, for example, or -std=c99 -pedantic). You could try using -std=gnu99 too; it might work better.
You had a similar problem recently (gcc -o stdlib.h syntax error c Hacking the Art of Exploitation). Did you get that resolved? It sounds as if the compilation system on the Live CD is not self-coherent, or the way you're able to use it means that it is not behaving self-coherently. Are you sure the compilation system works? It appears to be semi-defunct. Is it using the wrong headers, somehow?
I was able to resolve the previous problem by inserting #include <stdint.h> before #include <stdlib.h>
I will try the -D_XOPEN_SOURCE=600 and get back to you. Something must be wrong with the compilation system.
Well, you might need to include <time.h> (or possibly <sys/time.h>) before <sys/stat.h>, but the <sys/stat.h> header is broken if that works. And the <stdlib.h> header is broken if you have to include <stdint.h> before including it. I suppose Ubuntu 7.04 could be so old that you're supposed to #include <sys/types.h> before many of these headers, but that's still not an excuse for <stdlib.h>; that should be self-contained. POSIX 1997 required #include <sys/types.h> before <sys/stat.h>; POSIX 2004 did not. And I don't think Ubuntu 7.04 is quite that old.
Note, though, that the st_atim member is new; it was added to POSIX 2008 (and hence is in POSIX 2013). It was just st_atime before (and st_atime is now a macro for st_atim.tv_sec).
Including the -D_XOPEN_SOURCE=600 dealt with the bits stat issue. Ubuntu 7.04 was released in 2007 and the 2nd edition of the book that I am using came out in 2008. Also, not sure if this is of use, but in another previous example that included both <stdio.h> and <string.h> (as opposed to only <stdio.h>), the code would run fine without any intervention.
Interesting…it is going to make life interesting for you, in a way that life should not need to be interesting. (Chinese curses like "May you live in interesting times" spring to mind.) Use the -DXOPEN_SOURCE=600 option in all your compilations and keep your fingers crossed; that may well resolve most of your problems. Consider using -std=gnu99 as well, or instead. With luck, either or both of those should get you around most problems.
In case someone else is having the same issue with this book, I downloaded the iso file from hacking-live-1.0.iso.
Created a bootable usb and all works just fine without corrupted headers or anything.

C warning: implicit declaration of function ‘fchmod’

I have a function, createFile that uses fchmod:
int createFile(char *pFileName) {
int ret;
if ((ret = open(pFileName, O_RDWR | O_CREAT | O_TRUNC)) < 0)
errorAndQuit(2);
fchmod(ret, S_IRUSR | S_IWUSR);
return ret;
}
At the top of my file, I have the following includes:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
When compiling: the compiler spits out:
warning: implicit declaration of function ‘fchmod’
I'm including all of the correct files, yet getting this warning. The program runs fine, even with the warning.
By a happy coincidence, your question is directly answered by the feature_test_macros(7) manpage:
Specification of feature test macro requirements in manual pages
When a function requires that a feature test macro is
defined, the manual page SYNOPSIS typically includes a note
of the following form (this example from the chmod(2) manual
page):
#include <sys/stat.h>
int chmod(const char *path, mode_t mode);
int fchmod(int fd, mode_t mode);
Feature Test Macro Requirements for glibc (see
feature_test_macros(7)):
fchmod(): _BSD_SOURCE || _XOPEN_SOURCE >= 500
The || means that in order to obtain the declaration of
fchmod(2) from <sys/stat.h>, either of the following macro
definitions must be made before including any header files:
#define _BSD_SOURCE
#define _XOPEN_SOURCE 500 /* or any value > 500 */
Alternatively, equivalent definitions can be included in the
compilation command:
cc -D_BSD_SOURCE
cc -D_XOPEN_SOURCE=500 # Or any value > 500
You didn't specify what compiler or platform you're using, but on my recent Linux installation, fchmod() is defined in but guarded by a couple of #ifdefs (__USD_BSD and __USE_XOPEN_EXTENDED).
You aren't supposed to set those directly, but rather via the _FOO_SOURCE macros in . Try defining _XOPEN_SOURCE_EXTENDED or just _GNU_SOURCE and recompiling (and note that these macros enable nonstandard functionality and use of the functionality they enable may limit the portability of your code).
I have faced this error while building uml.
Just add this line in the file where this error is thrown:
#include "sys/stat.h"
I believe it will take care about adding the macros defined in the above answers.

Resources