Unique String generator - c

I want to make a program (network server-client).
One of the specification for this program is next:
The server will receive the sent packages and save it into a file, with a unique name (generated by the server at the moment the transfer starts.
Ex __tf_"unique_random_string".txt
I made a function that returns a pointer to a "unique" string created.
The problem is: If i stop the server and then start it again it will generate the same names.
Ex:this file names were generated and then i stopped the server.
__ft_apqfwk.txt
__ft_arzowk.txt
__ft_cdyggx.txt
I start it again and i try to generate 3 file names. Them will be the same.
Sorry for my english. I'm still learning it.
My function to generate this "unique string" is:
char *create_random_name(void)
{
const char charset[] = "abcdefghijklmnopqrstuvwxyz";
char *file_name;
int i=0;
int key;
if((file_name = malloc(16 * sizeof ( char )) ) == NULL)
{
printf("Failed to alloc memory space\n");
return NULL;
}
strcpy(file_name,"__ft_");
for(i=5 ; i<11 ; i++)
{
key = rand() % (int)(sizeof(charset)-1);
file_name[i]=charset[key];
}
strcat(file_name,".txt");
file_name[15] = '\0';
return file_name;
}

One option is saving to a file the names that have been used, and using them as a checklist. You also want to seed rand with something like srand(time(NULL)).
another is ignoring the randomisation, and just going in order, e.g. aaa, aab aac...aba ,abb etc. Again, save where your cycle is up to on a file.

Your question seems a little bit unclear but if you want to generate a unique string there are a couple of things you can consider:
Get System timestamp ( yyyy-MM-dd-HH-mm-ss-fff-tt)
Use Random function to generate a random number
Combine this with your function and I am sure you will get a unique string.
Hope it helps !

If it's available, you could avoid manually generating random names that might collide and let the system do it for you (and handle collision resolution by creating a new name) by using mkstemps. This is also safer because it opens the file for you, removing the risk of a random name being generated, verified to be unique, then trying to open it and discovering another thread/process raced in and created it.
char name[] = "/path/to/put/files/in/__ft_XXXXXX.txt";
int fd = mkstemps(name, strlen(".txt"));
if (fd == -1) { ... handle error ... }
After mkstemps succeeds, name will hold the path to the file (it's mutated in place, replacing the XXXXXX string), and fd will be an open file descriptor to that newly created file; if you need a FILE*, use fdopen to convert to a stdio type.

Before calling rand(),--- once and only once---, call srand(time()) to initialize the random number generator.
Before settling on any specific file name, call stat() to assure that file name does not already exist.

Related

GetModuleHandleW / A - not working. Returning null every call excluding empty string

#include <Windows.h>
int main(){
printf("Enter name of program. \n");
char prog[300];
scanf("%s", prog);
HMODULE hModule = GetModuleHandleW((LPCWSTR)prog);
if (hModule){
IMAGE_DOS_HEADER* pIDH = (IMAGE_DOS_HEADER*)hModule;
IMAGE_NT_HEADERS* pNTH =(IMAGE_NT_HEADERS*)((BYTE*)pIDH + pIDH->e_lfanew);
IMAGE_OPTIONAL_HEADER pOPH = (IMAGE_OPTIONAL_HEADER)pNTH->OptionalHeader;
IMAGE_DATA_DIRECTORY* pIDD = (IMAGE_DATA_DIRECTORY*)pOPH.DataDirectory;
printf("%x", pIDD->VirtualAddress);
}
else {
printf("Error");
}
return 0;
}
That's my basic script for now only to check if I get into the IMAGE_DATA_DIRECTORY.
My goal is to print every dll and all of it's imported functions of a certain running process - GetModuleHandleA / W.
Every call its returning null - printing "Error" as I checked, excluding the empty call in which it prints '0' for some reason..
Besides the obvious (LPCWSTR)prog casting bug, GetModuleHandle is never going to work because it only handles modules in the current process.
Call CreateToolhelp32Snapshot to get a list of all processes and then call CreateToolhelp32Snapshot again to get the modules of a specific process. Note that you cannot read the DOS/NT headers of a remote process directly, you would have to use ReadProcessMemory.
DataDirectory is an array, you have to specify the directory you are interested in (resource, import, export etc.).

FatFS: f_findfirst returns a string that does not correspond to the file found

I am using the FatFs library to create and manage a file system on an SD card. The goal is to identify a file containing the firmware for the bootloader to update (or not) the device.
The procedure im following is the follwing:
DIR directory;
FILINFO filinfo;
f_findfirst(&directory, &filinfo, "", "firmware_");
To my understanding, the first file that starts with "firmware_" should be identified and the information stored in filinfo . This does work, but when I try to extract the name from filinfo.fname the name that has been extracted is the follwing: "\0IRMWA~1.BIN".
I don't know the reason why the naming of the file is extracted in this format. The idea would be to later take the second part of the file: "firmware_01_01_01" and perform a char to int conversion to process the version number, but I cannot extract the full string of the file name.
I had a similar problem. Here is my code. Hope you find this helpful
#define FW_FOLDER "fw"
#define FW_PATH "0:/" FW_FOLDER
#define FW_BIN "*.bin"
FRESULT res;
DIR dir;
FILINFO fno;
static char fw_path[128];
// Find first item
res = f_findfirst(&dir, &fno, FW_PATH, FW_BIN);
// Create directory (optional)
if (res == FR_NO_PATH)
{
printf("Creating %s directory!\n", FW_FOLDER);
f_mkdir(FW_FOLDER);
}
// Repeat until proper item is found
while (res == FR_OK)
{
// Make sure file name is valid
if (fno.fname[0] == 0)
break;
// Debugging
printf("Scanning: %s\n", fno.fname);
// Make sure it is not a directory
if (!(fno.fattrib & AM_DIR))
{
// Success!
printf("Found: %s\n", fno.fname);
// Construct file path
sprintf(fw_path, "%s/%s", FW_PATH, fno.fname);
break;
}
// Move to the next one
res = f_findnext(&dir, &fno);
}
// Close directory
f_closedir(&dir);
And yes, you need to enable FF_USE_FIND == 1 in fatfs library. And if you decide to use 2 for FF_USE_FIND you have to check altname as part of fno.
Also, I had to update file validation eventually to this snippet
// Make sure file name is alpha numeric
if (!isalnum(fat_fno.fname[0]))
break;
Always read the documentation.
Description
After the directory specified by path could be opened, it starts to
search the directory for items with the name specified by pattern. If
the first item is found, the information about the object is stored
into the file information structure fno.
The matching pattern can contain wildcard characters (? and *). A ?
matches an any character and an * matches an any string in length of
zero or longer. When support of long file name is enabled, only
fname[] is tested at FF_USE_FIND == 1 and also altname[] is tested at
FF_USE_FIND == 2. In this revision, there are some differences listed
below between FatFs and standard systems in matching condition.
- "*.*" never matches any name without extension while it matches any name with or without extension at the standard systems.
- Any pattern terminated with a period never matches any name while it matches the name without extensiton at the standard systems.
- DBCS extended characters are compared in case-sensitive at LFN with ANSI/OEM API.
>
QuickInfo
This is a wrapper function of f_opendir and f_readdir function.
Available when FF_USE_FIND >= 1 and FF_FS_MINIMIZE <= 1. Examples
/* Search a directory for objects and display it */
void find_image_file (void) {
FRESULT fr; /* Return value */
DIR dj; /* Directory search object */
FILINFO fno; /* File information */
fr = f_findfirst(&dj, &fno, "", "dsc*.jpg"); /* Start to search for photo files */
while (fr == FR_OK && fno.fname[0]) { /* Repeat while an item is found */
printf("%s\n", fno.fname); /* Display the object name */
fr = f_findnext(&dj, &fno); /* Search for next item */
}
f_closedir(&dj);
}
Then you will learn that you need to use:
wildcards
you need to check the function return value
if the first char of the filename is zero - it means that the no file was found
I was using Long File Name (LFN) which had been activated in the ffconf.h file (the options file that comes with FatFs). The problem was that I was using filinfo.fname which refers to the 8.3 file name structure (short naming scheme).
If LFN is activated, the fields lfname and lfsize within the FILINFO struct are active. These two fields are a pointer to a char array as well as the size. Both fields must be initialized before using them like follows:
static char lfn[_MAX_LFN + 1]
//MAX_LFN is defined in ffconf.h and is 255, maximum value for LFN
filinfo.lfname = lfn;
filinfo.lfsize = sizeof lfn;
f_findfirst(&directory, &filinfo, "", "firmware_*.bin");
(...)
The documentation that also shows an example can be read here.
When LFN feature is enabled, lfname and lfsize in the file information structure must be initialized with valid value prior to use the f_readdir function. The lfname is a pointer to the string buffer to return the long file name. The lfsize is the size of the string buffer in unit of TCHAR.
lfname and lfsize would work the same for f_findfirst as with f_readdir.
This is a wrapper function of f_opendir and f_readdir

Remove file from directory - ext-like file system implementation

I have an issue. I'm currently trying to implement an ext-ish file system. I've done the inode operations such as read and write. I've created a structure that represents both a regular file and a directory. I have a problem when trying to remove a certain file from the directory.
char
dirremove(struct dirent *dir, struct dirent *file)
{
dirent_t n = {.mode = NODDIR, .inumber = remdirnod,
.r = 0, .w = 0};
strcpy(n.nm, dir->nm);
dirent_t t;
dir->r = 0;
char r = 1;
while (!dirread(dir, &t))
{
int tt = dir->r;
dir->r = 0;
dirent_t ff[3];
filread(ff, dir, 3 * entrysiz);
dir->r = tt;
if (!strcmp(t.nm, ""))
return 1;
if (!(!strcmp(t.nm, file->nm) && !(r = 0)))
assert(!dirappend(&n, &t));
}
assert(n.w == dir->w - entrysiz);
dir->w = n.w;
dir->r = n.r;
copyinode(dir->inumber, remdirnod);
return r;
}
This is the function called from the rm command. It takes the directory object (where the file is stored) and the file object to be deleted. I know this solution is not the best in terms of speed and memory usage but I'm still a beginner in this area, so don't hate me a lot, please :).
The function is designed to do the following. It has to read all files and check if the current is the one to be deleted. If not, the file is added to a new directory (empty in the beginning) which will replace the old one at the end of the function. The "new" directory is an entry saved entirely for this purpose, so there isn't a chance that all inodes are already used.
The test that I've done is to create a file (works fine), then remove it, then create it again and remove it. Everything works perfectly except for the second execution of the dirremove function. The directory has its dot and dot-dot directories by default so it goes through them first. The result is that the first deletion is successful. Everything works perfectly. But the second time things go wrong somewhere.
int tt = dir->r;
dir->r = 0;
dirent_t ff[3];
filread(ff, dir, 3 * entrysize;
dir->r = tt;
I added the ff array that should read the whole content of the directory and this would help me figure out if the correct files are there. On the first and second iteration, all files (".", ".." and "some-other-file") are there but at the iteration which should hold the object of the file that's to be removed the third file suddenly goes all zeroes.
I've debugged this for several hours but it continues to fail the same way.
Probably I didn't explain the failure the best way, but there are a lot of things that I forgot to say, so if I missed something please don't ignore the question and just ask about it.

How do I continuously generate a name for a file which is increasing ? For example: book1.txt, book2.txt etc

So I am trying to write a begginers program in which it is necessary to create a series of files, depending on the users choosing option, and where the first file created should be name by for example "book1.txt" and second one "book2.txt" etc...
FILE *fnew;
int num; //i do have a lot of code before to get the 'num' value from where I want, don't bother it;
char filename[]= "bookX.txt";
filename[4]=num+1;
fnew = fopen(filename,"w");
fclose(fnew);
You can use sprintf to build the filename:
sprintf(filename, "book%03d.txt", num);
This will create files named booknnn.txt, where nnn is the number in question padded with 0's, ex. book001.txt, book002.txt.

Reading and selecting files using dirent.h in C

I'm new into programming microcontrollers, and I have a problem.
I'm trying to make a device that plays music from USB. I can read from USB, but I have no idea how to choose a certain file. I'm using dirent.
My code so far:
while (true) {
USBHostMSD msd("usb");
//setup PWM hardware for a Class D style audio output
PWMout.period(1.0/400000.0);
// wait until connected to a USB device
while(!msd.connect()) {
Thread::wait(500);
}
FILE *wave_file;
lcd.cls();
lcd.locate(0,3);
DIR *dir;
struct dirent *ent;
int i=0;
int stevilo_datotek =0;
dir = opendir ("/usb/");
if (dir != NULL)
{
while ((ent = readdir (dir)) != NULL)
{
lcd.printf ("%s\n", ent->d_name[0]);
}
}
Now this code displays what's on USB. How can I navigate through files on USB using the buttons on the device? I'd like to know if there's a way to assign certain song a certain number so I can navigate. I've studied dirent.h file for so long, and I can't find where dirent saves the file order (if it does).
You may be confusing the purpose of dirent.h In short it may be difficult to see the forest for the trees.
You can read the information (ent->d_name, note that ent->d_name is a pointer to an array of chars, often called a 'string') into a data structure (like an array or a list), then use that struct with code that detects button presses to move an index into the array information either up or down (to a greater or lesser index, make sure to check that your index doesn't go outside the range or your structure). Or you can create code where your while loop waits on a button press and only reads the file name then (using seekdir to go backwards).
UPDATE (to response to comment):
Keep in mind that filesystems are tree structures like so:
/ (root) +--- dir1 ----------------------------+- dir1.1
---- dir2 (empty) -- file1.1
---- dir3 ---- dir3.1 +--- file3.1
---- file1 ---- file3.2
---- file2
You have to decide how to handle that, are you going to only support one directory (make them put all their music files in one place), allow them to navigate directories, or look through all directories selecting only files you know how to play?
There is no inherit order to the files (or sub-directories) and in some systems files can be added or deleted at any time.
Here is a very simple-minded example of one way to keep the list of directory entries:
char *names[400]; // make space for 400 names
int ix;
ix = 0;
if (dir != NULL)
{
while ((ent = readdir (dir)) != NULL)
{
lcd.printf ("%s\n", ent->d_name[0]);
// allocate memory to store the name
names[ix] = (char*) malloc(strlen(ent->d_name)); // strlen from string.h
// malloc from stdlib.h
// copy the name from the directory entry
strcpy(names[ix], ent->d_name); // strcpy from string.h
ix++;
if (ix >= 400)
{
// do something because your array isn't big enough
}
}
}
Now you have your names in the array 'names' and can address them by index. The value 'ix-1' is your last name, 0 is your first name. Your button presses can increment/decrement the index into your name array which identifies the name you want. Keep in mind that some of those names might be directory names rather than file names.
Admittedly this is simply-minded, you might want to allocation the array rather than use a fixed value (in fact you have to if you want to pass the 'names' array to a calling function), there are "secure" versions of strcpy (meant to help prevent memory overflow corruption), etc. but it should give you an idea about how you can keep the names in memory.

Resources