xlhtml/cole/cole.c

1224 lines
30 KiB
C

/*
cole - A free C OLE library.
Copyright 1998, 1999 Roberto Arturo Tena Sanchez
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
Arturo Tena <arturo@directmail.org>
*/
#if !(defined( __BORLANDC__ ) || defined( __WIN32__ ))
#include "config.h"
#include "cole.h"
#else
#include "cole.h.in"
#endif
#include "internal.h"
#include <stdlib.h>
/**
* cole_perror:
* @s: string to print before the error message. It can be NULL.
* @colerrno: error value of which a message will be printed.
*
* Prints a message on the standard error output, describing the error
* @colerrno, preceding it with the string @s, a semicolon and a space.
* It handles COLE_EERRNO value too, calling perror(3).
*/
void
cole_perror (const char *s, COLERRNO colerrno)
{
if (s != NULL) fprintf (stderr, "%s: ", s);
switch (colerrno) {
case COLE_EMEMORY:
case COLE_ECLOSEFILE:
case COLE_EWRITE:
case COLE_EREMOVE:
case COLE_ETMPNAM:
case COLE_ESEEK:
case COLE_EERRNO:
perror ("cole");
break;
case COLE_EOPENFILE:
fprintf (stderr, "cole - Cannot open the file\n");
exit(1);
break;
case COLE_ENOFILESYSTEM:
fprintf (stderr, "cole - The file is not a OLE2 file\n");
break;
case COLE_EINVALIDFILESYSTEM:
fprintf (stderr, "cole - The file has a short OLE2 header or it is not really an OLE2 file.\n");
break;
case COLE_EISNOTDIR:
fprintf (stderr, "cole - The OLE2 entry is not a substorage object\n");
break;
case COLE_EISNOTFILE:
fprintf (stderr, "cole - The substorage object is not valid\n");
break;
case COLE_EFILENOTFOUND:
fprintf (stderr, "cole - OLE2 object not found\n");
break;
case COLE_EOF:
fprintf (stderr, "cole - End of stream object has been reached\n");
break;
case COLE_EMEMBERISNOTDIR:
fprintf (stderr, "cole - The OLE2 object searched for is not "
"a substorage object\n");
break;
case COLE_EBROKENFILENAME:
fprintf (stderr, "cole - Illegal OLE object name\n");
break;
case COLE_EFILENAMEISNOTFILE:
fprintf (stderr, "cole - The OLE2 object is not a stream\n");
break;
case COLE_EFSEEKDELTA:
fprintf (stderr, "cole - The seek offset is an illegal value\n");
break;
case COLE_EFSEEKFLAG:
fprintf (stderr, "cole - The Seek Flag is not valid\n");
break;
case COLE_EREAD:
fprintf (stderr, "cole - Short read length returned...the file is probably corrupted\n");
break;
case COLE_EUNKNOWN:
fprintf (stderr, "cole - An unknown error ocurred in the cole libary (might be a bug)\n");
break;
default:
fprintf (stderr, "cole - An unknown error %d ocurred in the cole libabry (might be a bug)\n",
colerrno);
break;
}
}
/**
* cole_mount:
* @filename: name of the file with the filesystem.
* @colerrno: error value (COLE_EMEMORY, COLE_EOPENFILE, COLE_ENOFILESYSTEM,
* COLE_EINVALIDFILESYSTEM, COLE_EUNKNOWN).
*
* Mounts the filesystem which is in @filename.
*
* Returns: a filesystem in success, or NULL in other case.
*/
COLEFS *
cole_mount (char *filename, COLERRNO *colerrno)
{
COLEFS * ret;
ret = (COLEFS *)malloc (sizeof (COLEFS));
if (ret == NULL) {
if (colerrno != NULL) *colerrno = COLE_EMEMORY;
return NULL;
}
switch (__OLEdecode (filename, &ret->tree, &ret->root, &ret->BDepot,
&ret->SDepot, &ret->sbfile, &ret->sbfilename,
&ret->file, 0)) {
case 0:
/* success */
break;
case 10:
if (colerrno != NULL) *colerrno = COLE_EMEMORY;
free (ret);
return NULL;
case 7:
case 4:
if (colerrno != NULL) *colerrno = COLE_EOPENFILE;
free (ret);
return NULL;
case 8:
case 9:
if (colerrno != NULL) *colerrno = COLE_ENOFILESYSTEM;
free (ret);
return NULL;
case 5:
if (colerrno != NULL) *colerrno = COLE_EINVALIDFILESYSTEM;
free (ret);
return NULL;
default:
if (colerrno != NULL) *colerrno = COLE_EUNKNOWN;
free (ret);
return NULL;
}
return ret;
}
/**
* cole_umount:
* @colefilesystem: filesystem to umount.
* @colerrno: error value (COLE_ECLOSEFILE, COLE_EREMOVE).
*
* Umounts the filesystem @colefilesystem.
*
* Returns: zero in success, no zero in other case.
*/
int
cole_umount (COLEFS *colefilesystem, COLERRNO *colerrno)
{
int ret;
ret = 0;
free (colefilesystem->BDepot);
free (colefilesystem->tree);
if (fclose (colefilesystem->file) && !ret) {
if (colerrno != NULL) *colerrno = COLE_ECLOSEFILE;
ret = 1;
}
if (colefilesystem->SDepot != NULL) {
free (colefilesystem->SDepot);
/* may no exist SDepot because there are not small files */
/* assert (colefilesystem->sbfile != NULL); */
/* assert (colefilesystem->sbfilename != NULL); */
if (fclose (colefilesystem->sbfile) && !ret) {
if (colerrno != NULL) *colerrno = COLE_ECLOSEFILE;
ret = 1;
}
#if defined(__WIN32__) || (__BORLANDC__)
if (remove (colefilesystem->sbfilename) && !ret) {
if (colerrno != NULL) *colerrno = COLE_EREMOVE;
ret = 1;
}
#endif
free (colefilesystem->sbfilename);
}
free (colefilesystem);
return ret;
}
/**
* cole_print_tree:
* @colefilesystem: filesystem of which the tree will be printed.
* @colerrno: error value (errors from call cole_recurse_tree()).
*
* Prints on the standard output the tree of files and directories contained
* in @colefilesystem.
* Currently this call always success.
*
* Returns: zero in success, no zero in other case.
*/
static COLE_RECURSE_DIR_FUNC __cole_print_tree_indir;
static COLE_RECURSE_DIR_FUNC __cole_print_tree_outdir;
static COLE_RECURSE_DIR_FUNC __cole_print_tree_inroot;
static COLE_RECURSE_DIRENT_FUNC __cole_print_tree_indirentry;
int cole_print_tree (COLEFS *colefilesystem, COLERRNO *colerrno)
{
long level;
level = 1;
if (cole_recurse_tree (colefilesystem, &level,
__cole_print_tree_inroot,
__cole_print_tree_indirentry,
__cole_print_tree_indir,
__cole_print_tree_outdir, NULL, colerrno)) {
return 1;
}
return 0;
}
static int
__cole_print_tree_indir(COLEDIR *cd, void *info, COLERRNO *colerrno)
{
/*
* ATTENTION: if you modify this function so it modifies colerrno:
* Modify colerrno comment in the functions that call it,
* ie. cole_print_tree().
*/
(*((long*)info))++;
return 0;
}
static int
__cole_print_tree_outdir(COLEDIR *cd, void *info, COLERRNO *colerrno)
{
/*
* ATTENTION: if you modify this function so it modifies colerrno:
* Modify colerrno comment in the functions that call it,
* ie. cole_print_tree().
*/
(*((long*)info))--;
return 0;
}
static int
__cole_print_tree_inroot(COLEDIR *cd, void *info, COLERRNO *colerrno)
{
/*
* ATTENTION: if you modify this function so it modifies colerrno:
* Modify colerrno comment in the functions that call it,
* ie. cole_print_tree().
*/
char *entry_name;
printf ("DIR ");
printf (" %7zu", cole_dir_getsize (cd));
printf (" %08lx-%08lx %08lx-%08lx",
cole_dir_getdays1 (cd),
cole_dir_getsec1 (cd),
cole_dir_getdays2 (cd),
cole_dir_getsec2 (cd));
entry_name = cole_dir_getname (cd);
if (!isprint ((int)entry_name[0]))
printf (" '\\x%02x%s'\n", entry_name[0], entry_name+1);
else
printf (" '%s'\n", entry_name);
return 0;
}
static int
__cole_print_tree_indirentry(COLEDIRENT *cde, void *info, COLERRNO *colerrno)
{
/*
* ATTENTION: if you modify this function so it modifies colerrno:
* Modify colerrno comment in the functions that call it,
* ie. cole_print_tree().
*/
char *entry_name;
long level;
long i;
level = *((long*)info);
for (i = 0; i < level; i++) {
if (i == level - 1)
printf ("\\--");
else
printf ("| ");
}
if (cole_direntry_isdir (cde))
printf ("DIR ");
else if (cole_direntry_isfile (cde))
printf ("FILE");
else
printf ("????");
printf (" %7zu", cole_direntry_getsize (cde));
printf (" %08lx-%08lx %08lx-%08lx",
cole_direntry_getdays1 (cde),
cole_direntry_getsec1 (cde),
cole_direntry_getdays2 (cde),
cole_direntry_getsec2 (cde));
entry_name = cole_direntry_getname (cde);
if (!isprint ((int)entry_name[0]))
printf (" '\\x%02x%s'\n", entry_name[0], entry_name+1);
else
printf (" '%s'\n", entry_name);
return 0;
}
/**
* cole_opendir_rootdir:
* @colefilesystem: filesystem of which the root directory will be opened.
* @colerrno: error value (COLE_EMEMORY).
*
* Opens the root directory of the filesystem @colefilesystem as directory.
*
* Returns: a directory in success, or NULL in other case.
*/
COLEDIR *
cole_opendir_rootdir (COLEFS *colefilesystem, COLERRNO *colerrno)
{
COLEDIR *ret;
ret = (COLEDIR *)malloc (sizeof (COLEDIR));
if (ret == NULL) {
if (colerrno != NULL) *colerrno = COLE_EMEMORY;
return NULL;
}
ret->fs = colefilesystem;
ret->entry = ret->fs->root;
ret->visited_entry.dir = ret;
ret->visited_entry.entry = ret->fs->tree[ ret->entry ].dir;
return ret;
}
/**
* cole_opendir_direntry:
* @coledirentry: directory entry to be opened as directory.
* @colerrno: error value (COLE_EISNOTDIR, COLE_EMEMORY).
*
* Opens a directory entry as directory.
*
* Returns: a directory in success, or NULL in other case.
*/
COLEDIR *
cole_opendir_direntry (COLEDIRENT *coledirentry, COLERRNO *colerrno)
{
COLEDIR *ret;
if (!cole_direntry_isdir (coledirentry)) {
if (colerrno != NULL) *colerrno = COLE_EISNOTDIR;
return NULL;
}
ret = (COLEDIR *)malloc (sizeof (COLEDIR));
if (ret == NULL) {
if (colerrno != NULL) *colerrno = COLE_EMEMORY;
return NULL;
}
ret->fs = coledirentry->dir->fs;
ret->entry = coledirentry->entry;
ret->visited_entry.dir = ret;
ret->visited_entry.entry = ret->fs->tree[ ret->entry ].dir;
return ret;
}
/**
* cole_closedir:
* @coledir: directory to be closed.
* @colerrno: error value ().
*
* Closes the directory @coledir.
* Currently this call always success.
*
* Returns: zero in success, no zero in other case.
*/
int
cole_closedir (COLEDIR *coledir, COLERRNO *colerrno)
{
free (coledir);
return 0;
}
COLEDIRENT *
cole_visiteddirentry (COLEDIR *coledir)
{
if (coledir->visited_entry.entry == 0xffffffffUL)
return NULL;
return &coledir->visited_entry;
}
COLEDIRENT *
cole_nextdirentry (COLEDIR *coledir)
{
if (coledir->visited_entry.entry == 0xffffffffUL)
return NULL;
coledir->visited_entry.entry =
coledir->fs->tree [ coledir->visited_entry.entry ].next;
if (coledir->visited_entry.entry == 0xffffffffUL)
return NULL;
return &coledir->visited_entry;
}
/**
* cole_direntry_isdir:
* @coledirentry: directory entry to be tested.
*
* Tests if the directory entry @coledirentry is a directory.
*
* Returns: no zero if it is a directory, zero in other case.
*/
int
cole_direntry_isdir (COLEDIRENT *coledirentry)
{
return coledirentry->dir->fs->tree[ coledirentry->entry ].type ==
_COLE_TYPE_DIR;
}
/**
* cole_direntry_isfile:
* @coledirentry: directory entry to be tested.
*
* Tests if the directory entry @coledirentry is a file.
*
* Returns: no zero if it is a directory, zero in other case.
*/
int
cole_direntry_isfile (COLEDIRENT *coledirentry)
{
return coledirentry->dir->fs->tree[ coledirentry->entry ].type ==
_COLE_TYPE_FILE;
}
char *
cole_direntry_getname (COLEDIRENT *coledirentry)
{
return coledirentry->dir->fs->tree[ coledirentry->entry ].name;
}
size_t
cole_direntry_getsize (COLEDIRENT *coledirentry)
{
/* FIXME is it cast needed? */
return coledirentry->dir->fs->tree[ coledirentry->entry ].size;
}
long
cole_direntry_getsec1 (COLEDIRENT *coledirentry)
{
/* seconds1 is U32, long is at least U32 in all plattforms, isn't it? */
return coledirentry->dir->fs->tree[ coledirentry->entry ].seconds1;
}
long
cole_direntry_getsec2 (COLEDIRENT *coledirentry)
{
/* seconds2 is U32, long is at least U32 in all plattforms, isn't it? */
return coledirentry->dir->fs->tree[ coledirentry->entry ].seconds2;
}
long
cole_direntry_getdays1 (COLEDIRENT *coledirentry)
{
/* days1 is U32, long is at least U32 in all plattforms, isn't it? */
return coledirentry->dir->fs->tree[ coledirentry->entry ].days1;
}
long
cole_direntry_getdays2 (COLEDIRENT *coledirentry)
{
/* days2 is U32, long is at least U32 in all plattforms, isn't it? */
return coledirentry->dir->fs->tree[ coledirentry->entry ].days2;
}
char *
cole_dir_getname (COLEDIR *coledir)
{
return coledir->fs->tree[ coledir->entry ].name;
}
size_t
cole_dir_getsize (COLEDIR *coledir)
{
/* FIXME is it cast needed? */
return coledir->fs->tree[ coledir->entry ].size;
}
long
cole_dir_getsec1 (COLEDIR *coledir)
{
/* seconds1 is U32, long is at least U32 in all plattforms, isn't it? */
return coledir->fs->tree[ coledir->entry ].seconds1;
}
long
cole_dir_getsec2 (COLEDIR *coledir)
{
/* seconds2 is U32, long is at least U32 in all plattforms, isn't it? */
return coledir->fs->tree[ coledir->entry ].seconds2;
}
long
cole_dir_getdays1 (COLEDIR *coledir)
{
/* days1 is U32, long is at least U32 in all plattforms, isn't it? */
return coledir->fs->tree[ coledir->entry ].days1;
}
long
cole_dir_getdays2 (COLEDIR *coledir)
{
/* days2 is U32, long is at least U32 in all plattforms, isn't it? */
return coledir->fs->tree[ coledir->entry ].days2;
}
/**
* cole_fopen:
* @colefilesystem: filesystem in which @filename is in.
* @filename: name of the file to open.
* @colerrno: error value (COLE_EFILENOTFOUND, errors from calls
* cole_opendir_rootdir(), cole_fopen_direntry() and
* cole_locate_filename()).
*
* Opens the file with the name @filename in the filesystem @colefilesystem.
* Currently, @filename must begin with a '/' character, it means @filename is
* the absolute filename.
*
* Returns: a file in success, or NULL in other case.
*/
struct _cole_fopen_info {
COLEFILE *file;
int succ;
COLERRNO colerrno;
};
static COLE_LOCATE_ACTION_FUNC _cole_fopen_action;
COLEFILE *
cole_fopen (COLEFS *colefilesystem, char *filename, COLERRNO *colerrno)
{
struct _cole_fopen_info info;
if (cole_locate_filename (colefilesystem, filename, &info,
_cole_fopen_action, colerrno)) {
/* couldn't locate the filename */
/* colerrno is set */
return NULL;
}
if (info.succ)
return info.file;
if (colerrno != NULL) *colerrno = info.colerrno;
return NULL;
}
static void
_cole_fopen_action (COLEDIRENT *cde, void *_info)
{
struct _cole_fopen_info *info;
info = (struct _cole_fopen_info *)_info;
if (!cole_direntry_isfile(cde)) {
info->colerrno = COLE_EFILENAMEISNOTFILE;
info->succ = 0;
return;
}
info->file = cole_fopen_direntry (cde, &info->colerrno);
if (info->file == NULL) {
/* colerrno is set */
info->succ = 0;
return;
}
info->succ = 1;
}
/**
* cole_fopen_direntry:
* @coledirentry: directory entry to be opened as file.
* @colerrno: error value (COLE_EISNOTFILE, COLE_EMEMORY, COLE_ETMPNAM,
* COLE_EOPENFILE, COLE_EINVALIDFILESYSTEM, COLE_EREAD,
* COLE_EWRITE, COLE_EUNKNOWN).
*
* Opens a directory entry as file.
*
* Returns: a file in success, or NULL in other case.
*/
COLEFILE *
cole_fopen_direntry (COLEDIRENT *coledirentry, COLERRNO *colerrno)
{
COLEFILE *ret;
if (!cole_direntry_isfile (coledirentry)) {
if (colerrno != NULL) *colerrno = COLE_EISNOTFILE;
return NULL;
}
ret = (COLEFILE *)malloc (sizeof (COLEFILE));
if (ret == NULL) {
if (colerrno != NULL) *colerrno = COLE_EMEMORY;
return NULL;
}
ret->fs = coledirentry->dir->fs;
ret->entry = coledirentry->entry;
switch (__cole_extract_file (&ret->file, &ret->filename,
ret->fs->tree[ ret->entry ].size,
ret->fs->tree[ ret->entry ].start,
ret->fs->BDepot, ret->fs->SDepot,
ret->fs->sbfile, ret->fs->file)) {
case 0:
/* success */
break;
case 1:
if (colerrno != NULL) *colerrno = COLE_EMEMORY;
free (ret);
return NULL;
case 2:
if (colerrno != NULL) *colerrno = COLE_ETMPNAM;
free (ret);
return NULL;
case 3:
if (colerrno != NULL) *colerrno = COLE_EOPENFILE;
free (ret);
return NULL;
case 4:
if (colerrno != NULL) *colerrno = COLE_EINVALIDFILESYSTEM;
free (ret);
return NULL;
case 5:
if (colerrno != NULL) *colerrno = COLE_EREAD;
free (ret);
return NULL;
case 6:
if (colerrno != NULL) *colerrno = COLE_EWRITE;
free (ret);
return NULL;
default:
if (colerrno != NULL) *colerrno = COLE_EUNKNOWN;
free (ret);
return NULL;
}
/* because the original fopen(3) leaves the file pointer
in the beginning */
rewind (ret->file);
ret->pos = 0;
ret->filesize = ret->fs->tree[ ret->entry ].size;
return ret;
}
/**
* cole_fclose:
* @colefile: file to be closed.
* @colerrno: error value (COLE_ECLOSEFILE, CLOSE_EREMOVE).
*
* Closes the file @colefile.
*
* Returns: zero in sucess, no zero in other case.
*/
int
cole_fclose (COLEFILE *colefile, COLERRNO *colerrno)
{
int ret;
ret = 0;
if (fclose (colefile->file) && !ret) {
if (colerrno != NULL) *colerrno = COLE_ECLOSEFILE;
ret = 1;
}
if (remove (colefile->filename) && !ret) {
if (colerrno != NULL) *colerrno = COLE_EREMOVE;
ret = 1;
}
free (colefile->filename);
free (colefile);
return ret;
}
/**
* cole_fread:
* @colefile: file to be read.
* @ptr: memory location where the bytes will be stored.
* @size: how many bytes will be read.
* @colerrno: error value (COLE_EOF, COLE_EREAD, COLE_ESEEK).
*
* Reads @size bytes from @colefile and store them in the location given
* by @ptr. If not success, the file position indicator is not changed.
*
* Returns: in sucess the number of bytes actually readed (maximum @size)
* or zero in other case.
*/
size_t
cole_fread (COLEFILE *colefile, void *ptr, size_t size, COLERRNO *colerrno)
{
size_t bytes_read, bytes_to_read;
long tbytes;
/* Check to see if going past end... */
if ((colefile->pos + size) > colefile->filesize)
tbytes = colefile->filesize - colefile->pos;
else
tbytes = size;
if (tbytes <= 0)
return 0;
bytes_to_read = (size_t)tbytes;
bytes_read = fread (ptr, 1, bytes_to_read, colefile->file);
/* assert (size && (colefile->pos + bytes_read > colefile->pos)); */
colefile->pos += bytes_read;
/* assert (!feof (colefile->file)
&& ftell (colefile->file) == colefile->pos); */
if (bytes_read != size) {
/* Linux man page says that fread returns a `short item count
(or zero)' when an error of end of file ocurrs. A short count
OR zero? We are hopping that fread always returns zero. */
if (feof (colefile->file)) {
if (colerrno != NULL) *colerrno = COLE_EOF;
return 0;
} else if (ferror (colefile->file)) {
if (colerrno != NULL) *colerrno = COLE_EREAD;
return 0;
}
}
/* assert (size != 0 && bytes_read != 0); */
/* assert (bytes_read <= size); */
return bytes_read;
}
/**
* cole_ftell:
* @colefile: file of which the file position indicator will be get.
*
* Get the current value of the file position indicator for the file
* @colefile.
*
* Returns: The file position.
*/
size_t
cole_ftell (COLEFILE *colefile)
{
return colefile->pos;
}
/**
* cole_fseek:
* @colefile: file of which its file position indicator will be set.
* @delta: number of bytes that the file position indicator will be moved.
* @direction: from where start to count the @delta bytes.
* @colerrno: error value (COLE_EFSEEKDELTA).
*
* Sets the value of the file position indicator for the file @colefile
* @delta bytes from the beginning of the file, forward from the current
* position, backward from the current position, or from the end of the
* file, if @direction is COLE_SEEK_SET, COLE_SEEK_BACKWARD,
* COLE_SEEK_FORWARD or COLE_SEEK_END, respectively.
* The file position indicator will always be <= @colefile->filesize.
* If you @delta is such that the previous line would not true, cole_fseek
* fails.
*
* Returns: zero in success, no zero in other case.
*/
int
cole_fseek (COLEFILE *colefile, size_t delta, COLE_SEEK_FLAG direction,
COLERRNO *colerrno)
{
if ((int)delta < 0) {
if (colerrno != NULL) *colerrno = COLE_EFSEEKDELTA;
return 1;
}
switch (direction) {
case COLE_SEEK_SET:
if (delta <= colefile->filesize) {
colefile->pos = delta;
} else {
if (colerrno != NULL) *colerrno = COLE_EFSEEKDELTA;
return 1;
}
break;
case COLE_SEEK_END:
if (delta <= colefile->filesize) {
colefile->pos = colefile->filesize - delta;
} else {
if (colerrno != NULL) *colerrno = COLE_EFSEEKDELTA;
return 1;
}
break;
case COLE_SEEK_BACKWARD:
if (delta <= colefile->pos) {
colefile->pos = colefile->pos - delta;
} else {
if (colerrno != NULL) *colerrno = COLE_EFSEEKDELTA;
return 1;
}
break;
case COLE_SEEK_FORWARD:
if (delta <= colefile->filesize - colefile->pos) {
colefile->pos = colefile->pos + delta;
} else {
if (colerrno != NULL) *colerrno = COLE_EFSEEKDELTA;
return 1;
}
break;
default:
if (colerrno != NULL) *colerrno = COLE_EFSEEKFLAG;
return 1;
}
fseek(colefile->file,colefile->pos,SEEK_SET);
}
/**
* cole_frewind:
* @colefile: file of which its file position indicator will be rewind.
* @colerrno: error value (error from call cole_fseek()).
*
* Sets the value of the file position indicator for the file @colefile
* in the beginning of the file.
*
* Returns: zero in success, no zero in other case.
*/
int
cole_frewind (COLEFILE *colefile, COLERRNO *colerrno)
{
if (cole_fseek (colefile, 0, COLE_SEEK_SET, colerrno))
return 1;
return 0;
}
/**
* cole_fsize:
* @colefile: file of which its size will be returned.
*
* Returns the size in bytes of the file @colefile.
*/
size_t
cole_fsize (COLEFILE *colefile)
{
return colefile->filesize;
}
/**
* cole_feof:
* @colefile: file to be tested.
*
* Tests if the end of file has been reached in @colefile.
*
* Returns: no zero if the end of file has been reached, zero in other case.
*/
int
cole_feof (COLEFILE *colefile)
{
/* assert ((colefile->pos == colefile->fs->tree[ colefile->entry ].size)
&& feof (colefile->file)); */
return (colefile->pos == colefile->filesize);
}
/**
* cole_recurse_tree:
* @colefilesystem: filesystem to recurse.
* @info: arbitrary pointer passed to the functions.
* @inroot: pointer to the function that is called when start visiting root
* directory. It can be NULL.
* @indirentry: pointer to the function that is called when start visiting any
* directory entry (file or directory). It can be NULL.
* @indir: pointer to the function that is called when start visiting a
* directory. It can be NULL.
* @outdir: pointer to the function that is called when end visiting a
* directory. It can be NULL.
* @visitdir: pointer to the function that is called to know if visit a
* directory. It can be NULL.
* @colerrno: error value (errors from calls cole_opendir_rootdir(),
* cole_opendir_direntry(), cole_closedir() and
* inroot, indirentry, indir, and outdir functions).
*
* Recurse the filesystem @colefilesystem, calling the functions pointed by
* @inroot, @indirentry, @indir and @outdirectory when start visiting
* root directory, start visiting any directory entry (file or directory),
* start visiting a directory or end visiting a directory, respectively.
* If @visitdir returns no zero or it's NULL, the directory is visited,
* otherwise is not visited.
* @info is a arbitrary pointer which is passed to the functions pointed by
* @inroot, @indirentry, @indir and @outdirectory: it may be used to share
* arbitrary information between them.
*
* Returns: zero if recursed all the tree, no zero in other case.
*/
static int
__cole_recurse_tree (COLEDIR *_cd, long level, void *info,
COLE_RECURSE_DIR_FUNC *inroot,
COLE_RECURSE_DIRENT_FUNC *indirentry,
COLE_RECURSE_DIR_FUNC *indir,
COLE_RECURSE_DIR_FUNC *outdir,
COLE_RECURSE_VISIT_DIR_FUNC *visitdir,
COLERRNO *colerrno);
int
cole_recurse_tree (COLEFS *colefilesystem, void *info,
COLE_RECURSE_DIR_FUNC *inroot,
COLE_RECURSE_DIRENT_FUNC *indirentry,
COLE_RECURSE_DIR_FUNC *indir,
COLE_RECURSE_DIR_FUNC *outdir,
COLE_RECURSE_VISIT_DIR_FUNC *visitdir,
COLERRNO *colerrno)
{
COLEDIR * cd;
cd = cole_opendir_rootdir (colefilesystem, colerrno);
if (cd == NULL)
return 1;
if (__cole_recurse_tree (cd, 1, info, inroot, indirentry, indir,
outdir, visitdir, colerrno)) {
cole_closedir (cd, NULL);
/* colerrno is set */
return 1;
}
if (cole_closedir (cd, colerrno)) {
/* colerrno is set */
return 1;
}
return 0;
}
static int
__cole_recurse_tree (COLEDIR *_cd, long level, void *info,
COLE_RECURSE_DIR_FUNC *inroot,
COLE_RECURSE_DIRENT_FUNC *indirentry,
COLE_RECURSE_DIR_FUNC *indir,
COLE_RECURSE_DIR_FUNC *outdir,
COLE_RECURSE_VISIT_DIR_FUNC *visitdir,
COLERRNO *colerrno)
{
/*
* ATTENTION: if you modify __cole_recurse_tree() so it modifies colerrno
* besides in calling inroot, indirentry, indir, outdir, cole_opendir_direntry
* or cole_closedir:
* Modify colerrno comment in the functions that call it,
* ie. cole_recurse_tree().
*/
/* ATTENTION: This is a recursive function */
COLEDIRENT * cde;
COLEDIR * cd;
if (level == 1) {
/* The following lines are only executed on Root Entry */
if (inroot != NULL) {
if ( (*inroot) (_cd, info, colerrno) ) {
/* colerrno is set */
return 1;
}
}
}
/* Iterate through childrens */
for (cde = cole_visiteddirentry (_cd); cde != NULL;
cde = cole_nextdirentry (_cd)) {
if (indirentry != NULL) {
if ( (*indirentry) (cde, info, colerrno) ) {
/* colerrno is set */
return 1;
}
}
/* RECURSIVE CALL */
if (cole_direntry_isdir (cde)) {
cd = cole_opendir_direntry (cde, colerrno);
if (cd == NULL) {
/* colerrno is set */
return 1;
}
if (indir != NULL) {
if ( (*indir) (cd, info, colerrno) ) {
/* colerrno is set */
cole_closedir (cd, NULL);
return 1;
}
}
if ( (visitdir == NULL) ||
((*visitdir)(cd, info)) ) {
if (__cole_recurse_tree (cd, level + 1, info,
inroot, indirentry,
indir, outdir,
visitdir, colerrno)) {
/* colerrno is set */
cole_closedir (cd, NULL);
return 1;
}
}
if (outdir != NULL) {
if ( (*outdir) (cd, info, colerrno) ) {
/* colerrno is set */
cole_closedir (cd, NULL);
return 1;
}
}
if (cole_closedir (cd, colerrno)) {
/* colerrno is set */
return 1;
}
}
}
return 0;
}
/**
* cole_locate_filename:
* @colefilesystem: filesystem where to locate @filename.
* @filename: name of the file or directory to be located.
* @info: arbitrary pointer passed to @action.
* @action: pointer to the function that is called when founding @filename.
* @colerrno: error value (COLE_EUNKNOWN, COLE_EMEMBERISNOTDIR,
* COLE_EFILENOTFOUND, COLE_EBROKENFILENAME, errors
* from call cole_recurse_tree()).
*
* Locate the @filename in the filesystem @colefilesystem, calling @action when
* it's found. @info is arbitrary pointer passed to @action.
* Currently, @filename must begin with a '/' character, it means @filename is
* the absolute filename.
*
* Returns: zero in success, 1 in other case.
*/
struct __cole_locate_filenameinfo {
COLE_LOCATE_ACTION_FUNC *action;
void *info;
char *filename;
char *current;
int visitdir;
};
static COLE_RECURSE_DIRENT_FUNC __cole_locate_filename_indirentry;
static COLE_RECURSE_VISIT_DIR_FUNC __cole_locate_filename_visitdir;
int
cole_locate_filename (COLEFS *colefilesystem, char *filename,
void *info,
COLE_LOCATE_ACTION_FUNC *action,
COLERRNO *colerrno)
{
struct __cole_locate_filenameinfo _info;
COLERRNO _colerrno;
/* FIXME allow no absolute paths */
if (filename[0] != '/') {
if (colerrno != NULL) *colerrno = COLE_EBROKENFILENAME;
return 1;
}
_info.action = action;
_info.info = info;
_info.filename = filename;
_info.current = filename + 1;
if (cole_recurse_tree (colefilesystem, &_info, NULL,
__cole_locate_filename_indirentry, NULL, NULL,
__cole_locate_filename_visitdir,
&_colerrno)) {
if (_colerrno == COLE_ELAST+1) {
/* file was found */
return 0;
}
if (colerrno != NULL) *colerrno = _colerrno;
return 1;
}
if (colerrno != NULL) *colerrno = COLE_EFILENOTFOUND;
return 1;
}
static int
__cole_locate_filename_visitdir (COLEDIR *cd, void *info)
{
return ((struct __cole_locate_filenameinfo *)info)->visitdir;
}
static int
__cole_locate_filename_indirentry (COLEDIRENT *cde, void *_info,
COLERRNO *colerrno)
{
char *entry_name;
struct __cole_locate_filenameinfo *info;
char *pcurrent;
char *pentry_name;
info = (struct __cole_locate_filenameinfo *)_info;
entry_name = cole_direntry_getname (cde);
for (pcurrent = info->current, pentry_name = entry_name;
*pcurrent && *pentry_name && *pcurrent != '/';
pcurrent++, pentry_name++) {
if (*pcurrent != *pentry_name) {
info->visitdir = 0; /* don't visit this directory */
return 0; /* don't break recurse */
}
}
switch (*pentry_name) {
case 0:
switch (*pcurrent) {
case '/':
if (!cole_direntry_isdir (cde)) {
if (colerrno != NULL)
*colerrno = COLE_EMEMBERISNOTDIR;
return 1; /* break recurse */
}
pcurrent++; /* jump the '/' character */
info->current = pcurrent;
/* check if it's the last component of filename */
if (!(*info->current)) {
/* last component of filename reached */
if (info->action != NULL) {
(*(info->action)) (cde, info->info);
}
if (colerrno != NULL) *colerrno = COLE_ELAST+1;
return 1; /* break recurse */
}
info->visitdir = 1; /* visit this directory */
return 0; /* don't break recurse */
case 0:
/* last component of filename reached */
if (info->action != NULL) {
(*(info->action)) (cde, info->info);
}
if (colerrno != NULL) *colerrno = COLE_ELAST+1;
return 1; /* break recurse */
default:
info->visitdir = 0; /* don't visit this directory */
return 0; /* don't break recurse */
}
default:
switch (*pcurrent) {
case 0:
info->visitdir = 0; /* don't visit this directory */
return 0; /* don't break recurse */
case '/':
info->visitdir = 0; /* don't visit this directory */
return 0; /* don't break recurse */
default:
if (colerrno != NULL) *colerrno = COLE_EUNKNOWN;
return 1; /* break recurse */
}
}
}