EAPI Eina_Iterator *eina_file_direct_ls(const char *dir) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_MALLOC;
/**
+ * @brief Sanitize file path.
+ *
+ * @param path The path to sanitize
+ *
+ * @return an allocated string with the sanitized path.
+ *
+ * This function take care of adding the current working directory if it's a
+ * relative path and also remove all '..' and '//' reference in the original
+ * path.
+ *
+ * @since 1.1
+ */
+EAPI char *eina_file_path_sanitize(const char *path);
+
+/**
* @brief Get a read-only handler to a file.
*
* @param name Filename to open
return EINA_TRUE;
}
+static void
+slprintf(char *str, size_t size, const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+
+ vsnprintf(str, size, format, ap);
+ str[size - 1] = 0;
+
+ va_end(ap);
+}
+
+static char*
+_eina_file_escape(const char* path, int* length)
+{
+ char *result = strdup(path ? path : "");
+ char *p = result;
+ char *q = result;
+ int len;
+
+ if (!result)
+ return NULL;
+
+ if (length) len = *length;
+ else len = strlen(result);
+
+ while ((p = strchr(p, '/')))
+ {
+ // remove double `/'
+ if (p[1] == '/')
+ {
+ memmove(p, p + 1, --len - (p - result));
+ result[len] = '\0';
+ }
+ else
+ if (p[1] == '.'
+ && p[2] == '.')
+ {
+ // remove `/../'
+ if (p[3] == '/')
+ {
+ char tmp;
+
+ len -= p + 3 - q;
+ memmove(q, p + 3, len - (q - result));
+ result[len] = '\0';
+ p = q;
+
+ /* Update q correctly. */
+ tmp = *p;
+ *p = '\0';
+ q = strrchr(result, '/');
+ if (!q) q = result;
+ *p = tmp;
+ }
+ else
+ // remove '/..$'
+ if (p[3] == '\0')
+ {
+ len -= p + 2 - q;
+ result[len] = '\0';
+ q = p;
+ ++p;
+ }
+ else
+ {
+ q = p;
+ ++p;
+ }
+ }
+ else
+ {
+ q = p;
+ ++p;
+ }
+ }
+
+ if (length)
+ *length = len;
+ return result;
+}
+
Eina_Bool
eina_file_init(void)
{
* API *
*============================================================================*/
+EAPI char *
+eina_file_path_sanitize(const char *path)
+{
+ char *result = NULL;
+ int len;
+
+ if (!path) return NULL;
+
+ len = strlen(path);
+
+ if (*path != '/')
+ {
+ char cwd[PATH_MAX];
+ char *tmp = NULL;
+
+ tmp = getcwd(cwd, PATH_MAX);
+ if (!tmp) return NULL;
+
+ len += strlen(cwd) + 2;
+ tmp = alloca(sizeof (char) * len);
+
+ slprintf(tmp, len, "%s/%s", cwd, path);
+
+ result = tmp;
+ }
+
+ return _eina_file_escape(result ? result : path, &len);
+}
+
EAPI Eina_Bool
eina_file_dir_list(const char *dir,
Eina_Bool recursive,
}
EAPI Eina_File *
-eina_file_open(const char *filename, Eina_Bool shared)
+eina_file_open(const char *path, Eina_Bool shared)
{
Eina_File *file;
Eina_File *n;
+ char *filename;
struct stat file_stat;
- int fd;
+ int fd = -1;
int flags;
- EINA_SAFETY_ON_NULL_RETURN_VAL(filename, NULL);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
- /*
- FIXME: always open absolute path
- (need to fix filename according to current directory)
- */
+ filename = eina_file_path_sanitize(path);
+ if (!filename) return NULL;
if (shared)
#ifdef HAVE_SHMOPEN
fd = shm_open(filename, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO);
#else
- return NULL;
+ goto on_error;
#endif
else
fd = open(filename, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO);
- if (fd < 0) return NULL;
+ if (fd < 0) goto on_error;
#ifdef HAVE_EXECVP
flags = fcntl(fd, F_GETFD);
eina_lock_release(&_eina_file_lock_cache);
+ free(filename);
+
return n;
on_error:
- close(fd);
+ free(filename);
+ if (fd >= 0) close(fd);
return NULL;
}