diff options
author | Daniel Caujolle-Bert <f1rmb@users.sourceforge.net> | 2001-07-10 21:07:55 +0000 |
---|---|---|
committer | Daniel Caujolle-Bert <f1rmb@users.sourceforge.net> | 2001-07-10 21:07:55 +0000 |
commit | 4cc9fd313df701f722a81ad4bb551155415ce5cc (patch) | |
tree | cafd04a6191675accbc2d168192eee7169a6056b /src/input/input_file.c | |
parent | 9125c00c6d1242b911cbf68cdd25114cd9972c8f (diff) | |
download | xine-lib-4cc9fd313df701f722a81ad4bb551155415ce5cc.tar.gz xine-lib-4cc9fd313df701f722a81ad4bb551155415ce5cc.tar.bz2 |
Fixed get_dir in input plugins. Fixed a strange header inclusion bug
in libw32dll/wine.
CVS patchset: 264
CVS date: 2001/07/10 21:07:55
Diffstat (limited to 'src/input/input_file.c')
-rw-r--r-- | src/input/input_file.c | 506 |
1 files changed, 405 insertions, 101 deletions
diff --git a/src/input/input_file.c b/src/input/input_file.c index 6a6bbfba9..182c34d5f 100644 --- a/src/input/input_file.c +++ b/src/input/input_file.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: input_file.c,v 1.15 2001/07/01 23:37:04 guenter Exp $ + * $Id: input_file.c,v 1.16 2001/07/10 21:07:55 f1rmb Exp $ */ #ifdef HAVE_CONFIG_H @@ -43,6 +43,8 @@ extern int errno; static uint32_t xine_debug; +#define MAXFILES 65535 + #ifndef S_ISLNK #define S_ISLNK(mode) 0 #endif @@ -77,6 +79,151 @@ typedef struct { } file_input_plugin_t; + +/* *************************************************************************** + * PRIVATES FUNCTIONS + */ + +/* + * Sorting function, it comes from GNU fileutils package. + */ +#define S_N 0x0 +#define S_I 0x4 +#define S_F 0x8 +#define S_Z 0xC +#define CMP 2 +#define LEN 3 +#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9) +static int strverscmp(const char *s1, const char *s2) { + const unsigned char *p1 = (const unsigned char *) s1; + const unsigned char *p2 = (const unsigned char *) s2; + unsigned char c1, c2; + int state; + int diff; + static const unsigned int next_state[] = { + S_N, S_I, S_Z, S_N, + S_N, S_I, S_I, S_I, + S_N, S_F, S_F, S_F, + S_N, S_F, S_Z, S_Z + }; + static const int result_type[] = { + CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP, + CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, + CMP, -1, -1, CMP, 1, LEN, LEN, CMP, + 1, LEN, LEN, CMP, CMP, CMP, CMP, CMP, + CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP, + CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, + CMP, 1, 1, CMP, -1, CMP, CMP, CMP, + -1, CMP, CMP, CMP + }; + + if(p1 == p2) + return 0; + + c1 = *p1++; + c2 = *p2++; + + state = S_N | ((c1 == '0') + (ISDIGIT(c1) != 0)); + + while((diff = c1 - c2) == 0 && c1 != '\0') { + state = next_state[state]; + c1 = *p1++; + c2 = *p2++; + state |= (c1 == '0') + (ISDIGIT(c1) != 0); + } + + state = result_type[state << 2 | ((c2 == '0') + (ISDIGIT(c2) != 0))]; + + switch(state) { + case CMP: + return diff; + + case LEN: + while(ISDIGIT(*p1++)) + if(!ISDIGIT(*p2++)) + return 1; + + return ISDIGIT(*p2) ? -1 : diff; + + default: + return state; + } +} + +/* + * Wrapper to strverscmp() for qsort() calls, which sort mrl_t type array. + */ +static int _sortfiles_default(const mrl_t *s1, const mrl_t *s2) { + return(strverscmp(s1->mrl, s2->mrl)); +} + +/* + * Return the type (OR'ed) of the given file *fully named* + */ +static uint32_t get_file_type(char *filepathname, char *origin) { + struct stat pstat; + int mode; + uint32_t file_type = 0; + char buf[PATH_MAX + NAME_MAX + 1]; + + if((lstat(filepathname, &pstat)) < 0) { + sprintf(buf, "%s/%s", origin, filepathname); + if((lstat(buf, &pstat)) < 0) { + printf("lstat failed for %s{%s}\n", filepathname, origin); + file_type |= mrl_unknown; + return file_type; + } + } + + file_type |= mrl_file; + + mode = pstat.st_mode; + + if(S_ISLNK(mode)) + file_type |= mrl_file_symlink; + else if(S_ISDIR(mode)) + file_type |= mrl_file_directory; + else if(S_ISCHR(mode)) + file_type |= mrl_file_chardev; + else if(S_ISBLK(mode)) + file_type |= mrl_file_blockdev; + else if(S_ISFIFO(mode)) + file_type |= mrl_file_fifo; + else if(S_ISSOCK(mode)) + file_type |= mrl_file_sock; + else { + if(S_ISREG(mode)) { + file_type |= mrl_file_normal; + } + if(mode & S_IXUGO) + file_type |= mrl_file_exec; + } + + if(filepathname[strlen(filepathname) - 1] == '~') + file_type |= mrl_file_backup; + + return file_type; +} + +/* + * Return the file size of the given file *fully named* + */ +static off_t get_file_size(char *filepathname, char *origin) { + struct stat pstat; + char buf[PATH_MAX + NAME_MAX + 1]; + + if((lstat(filepathname, &pstat)) < 0) { + sprintf(buf, "%s/%s", origin, filepathname); + if((lstat(buf, &pstat)) < 0) + return (off_t) 0; + } + + return pstat.st_size; +} +/* + * END OF PRIVATES + *****************************************************************************/ + /* * */ @@ -186,18 +333,33 @@ static uint32_t file_plugin_get_blocksize (input_plugin_t *this_gen) { } /* + * Return 1 is filepathname is a directory, otherwise 0 + */ +static int is_a_dir(char *filepathname) { + struct stat pstat; + + stat(filepathname, &pstat); + + return (S_ISDIR(pstat.st_mode)); +} + +/* * */ static mrl_t **file_plugin_get_dir (input_plugin_t *this_gen, char *filename, int *nFiles) { file_input_plugin_t *this = (file_input_plugin_t *) this_gen; - char current_dir[PATH_MAX + 1]; - char *fullpathname = NULL; struct dirent *pdirent; DIR *pdir; - mode_t mode; - struct stat pstat; - int num_files = 0; + mrl_t *hide_files, *dir_files, *norm_files; + char current_dir[PATH_MAX + 1]; + char current_dir_slashed[PATH_MAX + 1]; + char fullfilename[PATH_MAX + NAME_MAX + 1]; + int num_hide_files = 0; + int num_dir_files = 0; + int num_norm_files = 0; + int num_files = -1; + int (*func) () = _sortfiles_default; *nFiles = 0; memset(¤t_dir, 0, strlen(current_dir)); @@ -213,126 +375,268 @@ static mrl_t **file_plugin_get_dir (input_plugin_t *this_gen, else snprintf(current_dir, PATH_MAX, "%s", pwd); } - else + else { + + /* Remove exceed '/' */ + while((filename[strlen(filename) - 1] == '/') && strlen(filename) > 1) + filename[strlen(filename) - 1] = '\0'; + snprintf(current_dir, PATH_MAX, "%s", filename); + } + + if(strcasecmp(current_dir, "/")) + sprintf(current_dir_slashed, "%s/", current_dir); + else + sprintf(current_dir_slashed, "/"); + /* * Ooch! */ - if((pdir = opendir(current_dir)) == NULL) { - return NULL; - } - + if((pdir = opendir(current_dir)) == NULL) + return NULL; + + dir_files = (mrl_t *) xmalloc(sizeof(mrl_t) * MAXFILES); + hide_files = (mrl_t *) xmalloc(sizeof(mrl_t) * MAXFILES); + norm_files = (mrl_t *) xmalloc(sizeof(mrl_t) * MAXFILES); + while((pdirent = readdir(pdir)) != NULL) { - /* - * full pathname creation - */ - if(!fullpathname) { - fullpathname = (char *) - malloc((strlen(current_dir) + strlen(pdirent->d_name) + 2)); - } - else { - fullpathname = (char *) - realloc(fullpathname, - (strlen(current_dir) + strlen(pdirent->d_name) + 2)); - } - - sprintf(fullpathname, "%s/%s", current_dir, pdirent->d_name); - /* - * stat the file - */ - if(lstat(fullpathname, &pstat) < 0) { - fprintf(stderr, "lstat() failed: %s\n", strerror(errno)); - free(fullpathname); - return NULL; - } + memset(&fullfilename, 0, strlen(fullfilename)); + sprintf(fullfilename, "%s/%s", current_dir, pdirent->d_name); - /* - * alloc enought memory in private plugin structure to - * store found mrls. - */ - if(num_files >= this->mrls_allocated_entries - || this->mrls_allocated_entries == 0) { - - if((this->mrls[num_files] = (mrl_t *) malloc(sizeof(mrl_t))) == NULL) { - fprintf(stderr, "malloc() failed: %s\n", strerror(errno)); - return NULL; + if(is_a_dir(fullfilename)) { + + dir_files[num_dir_files].mrl = (char *) + xmalloc(strlen(current_dir_slashed) + 1 + strlen(pdirent->d_name) + 1); + + dir_files[num_dir_files].origin = strdup(current_dir); + sprintf(dir_files[num_dir_files].mrl, "%s%s", + current_dir_slashed, pdirent->d_name); + dir_files[num_dir_files].link = NULL; + dir_files[num_dir_files].type = get_file_type(fullfilename, current_dir); + dir_files[num_dir_files].size = get_file_size(fullfilename, current_dir); + + /* The file is a link, follow it */ + if(dir_files[num_dir_files].type & mrl_file_symlink) { + char linkbuf[PATH_MAX + NAME_MAX + 1]; + int linksize; + + memset(&linkbuf, 0, PATH_MAX + NAME_MAX); + linksize = readlink(fullfilename, linkbuf, PATH_MAX + NAME_MAX); + + if(linksize < 0) { + fprintf(stderr, "%s(%d): readlink() failed: %s\n", + __FUNCTION__, __LINE__, strerror(errno)); + } + else { + dir_files[num_dir_files].link = (char *) xmalloc(linksize + 1); + strncpy(dir_files[num_dir_files].link, linkbuf, linksize); + dir_files[num_dir_files].type |= get_file_type(dir_files[num_dir_files].link, current_dir); + } } - - this->mrls[num_files]->mrl = (char *) malloc(strlen(fullpathname) + 1); - - } + + num_dir_files++; + } /* Hmmmm, an hidden file ? */ + else if((strlen(pdirent->d_name) > 1) + && (pdirent->d_name[0] == '.' && pdirent->d_name[1] != '.')) { + + hide_files[num_hide_files].mrl = (char *) + xmalloc(strlen(current_dir_slashed) + 1 + strlen(pdirent->d_name) + 1); + + hide_files[num_hide_files].origin = strdup(current_dir); + sprintf(hide_files[num_hide_files].mrl, "%s%s", + current_dir_slashed, pdirent->d_name); + hide_files[num_hide_files].link = NULL; + hide_files[num_hide_files].type = get_file_type(fullfilename, current_dir); + hide_files[num_hide_files].size = get_file_size(fullfilename, current_dir); + + /* The file is a link, follow it */ + if(hide_files[num_hide_files].type & mrl_file_symlink) { + char linkbuf[PATH_MAX + NAME_MAX + 1]; + int linksize; + + memset(&linkbuf, 0, PATH_MAX + NAME_MAX); + linksize = readlink(fullfilename, linkbuf, PATH_MAX + NAME_MAX); + + if(linksize < 0) { + fprintf(stderr, "%s(%d): readlink() failed: %s\n", + __FUNCTION__, __LINE__, strerror(errno)); + } + else { + hide_files[num_hide_files].link = (char *) + xmalloc(linksize + 1); + strncpy(hide_files[num_hide_files].link, linkbuf, linksize); + hide_files[num_hide_files].type |= get_file_type(hide_files[num_hide_files].link, current_dir); + } + } + + num_hide_files++; + } /* So a *normal* one. */ else { - printf("realloc\n"); - this->mrls[num_files]->mrl = (char *) - realloc(this->mrls[num_files]->mrl, strlen(fullpathname) + 1); - } - - sprintf(this->mrls[num_files]->mrl, "%s", fullpathname); - - this->mrls[num_files]->size = pstat.st_size; - /* - * Ok, now check file type - */ - mode = pstat.st_mode; - - if(S_ISLNK(mode)) { - this->mrls[num_files]->type = mrl_symbolic_link; - /* - * So follow the link - */ - { - char *linkbuf; + norm_files[num_norm_files].mrl = (char *) + xmalloc(strlen(current_dir_slashed) + 1 + strlen(pdirent->d_name) + 1); + + norm_files[num_norm_files].origin = strdup(current_dir); + sprintf(norm_files[num_norm_files].mrl, "%s%s", + current_dir_slashed, pdirent->d_name); + norm_files[num_norm_files].link = NULL; + norm_files[num_norm_files].type = get_file_type(fullfilename, current_dir); + norm_files[num_norm_files].size = get_file_size(fullfilename, current_dir); + + /* The file is a link, follow it */ + if(norm_files[num_norm_files].type & mrl_file_symlink) { + char linkbuf[PATH_MAX + NAME_MAX + 1]; int linksize; - linkbuf = (char *) alloca(PATH_MAX + 2); - memset(linkbuf, 0, sizeof(linkbuf)); - linksize = readlink(fullpathname, linkbuf, PATH_MAX + 1); + memset(&linkbuf, 0, PATH_MAX + NAME_MAX); + linksize = readlink(fullfilename, linkbuf, PATH_MAX + NAME_MAX); if(linksize < 0) { - fprintf(stderr, "readlink() failed: %s\n", strerror(errno)); + fprintf(stderr, "%s(%d): readlink() failed: %s\n", + __FUNCTION__, __LINE__, strerror(errno)); } else { - this->mrls[num_files]->mrl = (char *) - realloc(this->mrls[num_files]->mrl, (linksize + 1)); - memset(this->mrls[num_files]->mrl, 0, linksize + 1); - strncpy(this->mrls[num_files]->mrl, linkbuf, linksize); + norm_files[num_norm_files].link = (char *) + xmalloc(linksize + 1); + strncpy(norm_files[num_norm_files].link, linkbuf, linksize); + norm_files[num_norm_files].type |= get_file_type(norm_files[num_norm_files].link, current_dir); } } + + num_norm_files++; } - else if(S_ISDIR(mode)) - this->mrls[num_files]->type = mrl_directory; - else if(S_ISCHR(mode)) - this->mrls[num_files]->type = mrl_chardev; - else if(S_ISBLK(mode)) - this->mrls[num_files]->type = mrl_blockdev; - else if(S_ISFIFO(mode)) - this->mrls[num_files]->type = mrl_fifo; - else if(S_ISSOCK(mode)) - this->mrls[num_files]->type = mrl_sock; - else { - this->mrls[num_files]->type = mrl_normal; - if(mode & S_IXUGO) - this->mrls[num_files]->type |= mrl_type_exec; - } - + num_files++; } - + closedir(pdir); + + /* + * Ok, there are some files here, so sort + * them then store them into global mrls array. + */ + if(num_files > 0) { + int i; - *nFiles = num_files; + num_files = 0; + + /* + * Sort arrays + */ + if(num_dir_files) + qsort(dir_files, num_dir_files, sizeof(mrl_t), func); + + if(num_hide_files) + qsort(hide_files, num_hide_files, sizeof(mrl_t), func); + + if(num_norm_files) + qsort(norm_files, num_norm_files, sizeof(mrl_t), func); + + /* + * Add directories entries + */ + for(i = 0; i < num_dir_files; i++) { + + if(num_files >= this->mrls_allocated_entries + || this->mrls_allocated_entries == 0) { + this->mrls[num_files] = (mrl_t *) xmalloc(sizeof(mrl_t)); + } + else + memset(this->mrls[num_files], 0, sizeof(mrl_t)); + + MRL_DUPLICATE(&dir_files[i], this->mrls[num_files]); + num_files++; + } + + /* + * Add hidden files entries + */ + for(i = 0; i < num_hide_files; i++) { + + if(num_files >= this->mrls_allocated_entries + || this->mrls_allocated_entries == 0) { + this->mrls[num_files] = (mrl_t *) xmalloc(sizeof(mrl_t)); + } + else + memset(this->mrls[num_files], 0, sizeof(mrl_t)); + + MRL_DUPLICATE(&hide_files[i], this->mrls[num_files]); + + num_files++; + } + + /* + * Add other files entries + */ + for(i = 0; i < num_norm_files; i++) { + + if(num_files >= this->mrls_allocated_entries + || this->mrls_allocated_entries == 0) { + this->mrls[num_files] = (mrl_t *) xmalloc(sizeof(mrl_t)); + } + else + memset(this->mrls[num_files], 0, sizeof(mrl_t)); + + MRL_DUPLICATE(&norm_files[i], this->mrls[num_files]); + + num_files++; + } + + /* Some cleanups before leaving */ + for(i = num_dir_files; i == 0; i--) + MRL_ZERO(&dir_files[i]); + free(dir_files); + + for(i = num_hide_files; i == 0; i--) + MRL_ZERO(&hide_files[i]); + free(hide_files); + + for(i = num_norm_files; i == 0; i--) + MRL_ZERO(&norm_files[i]); + free(norm_files); + + } + else + return NULL; + + /* + * Inform caller about files found number. + */ + *nFiles = num_files; + + /* + * Freeing exceeded mrls if exists. + */ if(num_files > this->mrls_allocated_entries) this->mrls_allocated_entries = num_files; - - if(fullpathname) - free(fullpathname); + else if(this->mrls_allocated_entries > num_files) { + while(this->mrls_allocated_entries > num_files) { + MRL_ZERO(this->mrls[this->mrls_allocated_entries - 1]); + free(this->mrls[this->mrls_allocated_entries--]); + } + } + /* + * This is useful to let UI know where it should stops ;-). + */ this->mrls[num_files] = NULL; - + + /* + * Some debugging info + */ + /* + { + int j = 0; + while(this->mrls[j]) { + printf("mrl[%d] = '%s'\n", j, this->mrls[j]->mrl); + j++; + } + } + */ + return this->mrls; } @@ -404,7 +708,7 @@ input_plugin_t *init_input_plugin (int iface, config_values_t *config) { return NULL; } - this = (file_input_plugin_t *) malloc (sizeof (file_input_plugin_t)); + this = (file_input_plugin_t *) xmalloc (sizeof (file_input_plugin_t)); this->input_plugin.interface_version = INPUT_PLUGIN_IFACE_VERSION; this->input_plugin.get_capabilities = file_plugin_get_capabilities; @@ -423,14 +727,14 @@ input_plugin_t *init_input_plugin (int iface, config_values_t *config) { this->input_plugin.get_identifier = file_plugin_get_identifier; this->input_plugin.get_autoplay_list = NULL; this->input_plugin.get_optional_data = file_plugin_get_optional_data; - this->input_plugin.handle_input_event= NULL; - this->input_plugin.is_branch_possible= NULL; + this->input_plugin.handle_input_event = NULL; + this->input_plugin.is_branch_possible = NULL; this->fh = -1; this->mrl = NULL; this->config = config; - this->mrls = (mrl_t **) malloc(sizeof(mrl_t)); + this->mrls = (mrl_t **) xmalloc(sizeof(mrl_t)); this->mrls_allocated_entries = 0; return (input_plugin_t *) this; |