#include #include #include #include #include static int is_valid(const char *path) { int len = strnlen(path, PATH_MAX); /* Only allow for absolute paths for now */ if (len < PATH_MAX && path[len] == '\0' && strncmp(path, "/", 1) == 0) return true; return false; } /* * Name must be dynamically allocated and not NULL */ static struct path_part * path_alloc(const char *name) { struct path_part *p = kzalloc(sizeof(struct path_part)); p->name = name; return p; } /* * This is the main parser routine. * It is designed to be called in a loop until it returns NULL, * indicating the end of the path. * * It will return a copy of the current part of the path. * * So for a path like: /home/foo/bar, each call to this routine * will return: "home", "foo", "bar" and NULL (signaling the end * of the path). It uses the double pointer argument as its own * cursor. * * - This makes no distinction if what it receives is an absolute * or relative path. It just extracts the components. * - The caller is responsible for checking if the path is * absolute or relative. * * - It makes no distinction between files or directories, this only * parses a path. * * - Double slashes like /home//foo are ignored and the entries returned * will be "home" and "foo". */ static char * get_path_part(char **path) { char *name; char *cur = *path; int i = 0; size_t pathlen = strlen(cur); /* We reached the end of the full path */ if (!pathlen) return NULL; /* Ignore any leading slashes */ while (cur[i] == '/' && i < pathlen) i++; /* There are no more components, just leading slash(es) */ if (i >= pathlen) return NULL; /* Advance cursor to the first non-slash character */ *path = cur += i; /* * Reset the index and advance it accordingly to the * new cursor position. */ for (i = 0; cur[i] != '/' && cur[i] != '\0'; i++); name = kzalloc(i + 1); /* Size of the current component + null */ strncpy(name, cur, i); /* kzalloc'ed, null terminator already there, but just in case...*/ name[i] = '\0'; /* * Advance path to the next component * * The last for loop incremented 'i' to either the next '/' in the path * or to the null terminator of the full path. * * Just point the caller's cursor to that location. Next call here will * either return NULL or begin with a '/' */ *path += (i + 1); /* Move the path cursor to the next component */ return name; } /* * If last is not NULL, we are parsing a relative path * so we should just extend the current path. * * Relative paths not implemented yet... last should ALWAYS * be NULL */ static struct path_part * construct_path( struct path_part *last, char *p) { char *cur = p; /* Used to walk through the path */ char *name = kzalloc(2); /* Alloc space for '/' */ name[0] = '/'; name[1] = '\0'; /* Root path component has NULL as its name */ struct path_part *root = path_alloc(name); struct path_part *ptr_next = root; /* Reset the name pointer before starting to parse the path */ name = NULL; /* check (last == NULL); */ while ((name = get_path_part(&cur))) { ptr_next->next = path_alloc(name); /* Gotta check if path_aloc() failed*/ ptr_next = ptr_next->next; } /* Ensure we null terminate the component's linked list */ ptr_next->next = NULL; return root; err_out: return NULL; } static struct path_root * root_init(void) { struct path_root *r = kzalloc(sizeof(struct path_root)); /* * We just have support for one disk by now, and the root * shouldn't be tied to a specific disk. I want a Unix-like * namespace */ r->disk_id = 0; r->head = NULL; return r; } void free_root(struct path_root *r) { if (r) kfree(r); } /* * This should account for a relative path. * By now it only deals with absolute paths (see is_valid()) */ struct path_root * parse_path(char *path) { struct path_root *root; if (!is_valid(path)) return NULL; root = root_init(); root->head = construct_path(NULL, path); if (!root->head) { free_root(root); return NULL; } return root; }