Exemple #1
0
VALUE
rb_require_safe(VALUE fname, int safe)
{
    volatile VALUE result = Qnil;
    rb_thread_t *th = GET_THREAD();
    volatile VALUE errinfo = th->errinfo;
    int state;
    struct {
	int safe;
    } volatile saved;
    char *volatile ftptr = 0;

    PUSH_TAG();
    saved.safe = rb_safe_level();
    if ((state = EXEC_TAG()) == 0) {
	VALUE path;
	long handle;
	int found;

	rb_set_safe_level_force(safe);
	FilePathValue(fname);
	rb_set_safe_level_force(0);
	found = search_required(fname, &path, safe);
	if (found) {
	    if (!path || !(ftptr = load_lock(RSTRING_PTR(path)))) {
		result = Qfalse;
	    }
	    else {
		switch (found) {
		  case 'r':
		    rb_load_internal(path, 0);
		    break;

		  case 's':
		    handle = (long)rb_vm_call_cfunc(rb_vm_top_self(), load_ext,
						    path, 0, path);
		    rb_ary_push(ruby_dln_librefs, LONG2NUM(handle));
		    break;
		}
		rb_provide_feature(path);
		result = Qtrue;
	    }
	}
    }
    POP_TAG();
    load_unlock(ftptr, !state);

    rb_set_safe_level_force(saved.safe);
    if (state) {
	JUMP_TAG(state);
    }

    if (NIL_P(result)) {
	load_failed(fname);
    }

    th->errinfo = errinfo;

    return result;
}
Exemple #2
0
void
rb_load(VALUE fname, int wrap)
{
    VALUE tmp = rb_find_file(FilePathValue(fname));
    if (!tmp) load_failed(fname);
    rb_load_internal(tmp, wrap);
}
Exemple #3
0
static VALUE
file_to_load(VALUE fname)
{
    VALUE tmp = rb_find_file(FilePathValue(fname));
    if (!tmp) load_failed(fname);
    return tmp;
}
Exemple #4
0
static VALUE
rb_f_load(int argc, VALUE *argv)
{
    VALUE fname, wrap, path, orig_fname;

    rb_scan_args(argc, argv, "11", &fname, &wrap);

    if (RUBY_DTRACE_LOAD_ENTRY_ENABLED()) {
	RUBY_DTRACE_LOAD_ENTRY(StringValuePtr(fname),
			       rb_sourcefile(),
			       rb_sourceline());
    }

    orig_fname = FilePathValue(fname);
    fname = rb_str_encode_ospath(orig_fname);
    path = rb_find_file(fname);
    if (!path) {
	if (!rb_file_load_ok(RSTRING_PTR(fname)))
	    load_failed(orig_fname);
	path = fname;
    }
    rb_load_internal(path, RTEST(wrap));

    if (RUBY_DTRACE_LOAD_RETURN_ENABLED()) {
	RUBY_DTRACE_LOAD_RETURN(StringValuePtr(fname),
			       rb_sourcefile(),
			       rb_sourceline());
    }

    return Qtrue;
}
Exemple #5
0
VALUE
rb_readlink(VALUE path)
{
    ssize_t len;
    WCHAR *wpath, wbuf[MAX_PATH];
    rb_encoding *enc;
    UINT cp, path_cp;

    FilePathValue(path);
    enc = rb_enc_get(path);
    cp = path_cp = code_page(enc);
    if (cp == INVALID_CODE_PAGE) {
        path = fix_string_encoding(path, enc);
        cp = CP_UTF8;
    }
    wpath = mbstr_to_wstr(cp, RSTRING_PTR(path),
                          RSTRING_LEN(path)+rb_enc_mbminlen(enc), NULL);
    if (!wpath) rb_memerror();
    len = rb_w32_wreadlink(wpath, wbuf, numberof(wbuf));
    free(wpath);
    if (len < 0) rb_sys_fail_path(path);
    enc = rb_filesystem_encoding();
    cp = path_cp = code_page(enc);
    if (cp == INVALID_CODE_PAGE) cp = CP_UTF8;
    return append_wstr(rb_enc_str_new(0, 0, enc), wbuf, len, cp, path_cp, enc);
}
// Win32::Symlink::readlink(file)
static VALUE
rb_readlink(VALUE mod, VALUE file)
{
	(void)mod;
	FilePathValue(file);
	file = rb_str_encode_ospath(file);
	return win32_readlink(RSTRING_PTR(file));
}
Exemple #7
0
static VALUE
rb_mod_autoload(VALUE mod, VALUE sym, VALUE file)
{
    ID id = rb_to_id(sym);

    FilePathValue(file);
    rb_autoload_str(mod, id, file);
    return Qnil;
}
Exemple #8
0
static VALUE
rb_mod_autoload(VALUE mod, VALUE sym, VALUE file)
{
    ID id = rb_to_id(sym);

    FilePathValue(file);
    rb_autoload(mod, id, RSTRING_PTR(file));
    return Qnil;
}
Exemple #9
0
static void
check_dirname(volatile VALUE *dir)
{
    char *path, *pend;

    rb_secure(2);
    FilePathValue(*dir);
    path = RSTRING_PTR(*dir);
    if (path && *(pend = rb_path_end(rb_path_skip_prefix(path)))) {
	*dir = rb_str_new(path, pend - path);
    }
}
Exemple #10
0
VALUE
rb_require_safe(VALUE fname, int safe)
{
    FilePathValue(fname);

    // Immediately, check out if we have an AOT feature for this.
    if (rb_vm_aot_feature_load(RSTRING_PTR(fname))) {
	rb_provide_feature(fname);
	return Qtrue;
    }

#if MACRUBY_STATIC
    rb_raise(rb_eRuntimeError, "#require is not supported in MacRuby static");
#else
    VALUE result = Qnil;
    VALUE path;
    int type = 0;

    if (search_required(fname, &path, &type)) {
	if (path == 0) {
	    result = Qfalse;
	}
	else {
	    rb_set_safe_level_force(0);
	    rb_provide_feature(path);
	    switch (type) {
		case TYPE_RB:
		    rb_rescue2(load_try, path, load_rescue, path,
			    rb_eException, 0);
		    break;

		case TYPE_RBO:
		    dln_load(RSTRING_PTR(path), false);
		    break;

		case TYPE_BUNDLE:
		    dln_load(RSTRING_PTR(path), true);
		    break;

		default:
		    abort();
	    }
	    result = Qtrue;
	}
    }

    if (NIL_P(result)) {
	load_failed(fname);
    }

    return result;
#endif
}
Exemple #11
0
/*
 * call-seq:
 *   DBM.new(filename[, mode[, flags]]) -> dbm
 *
 * Open a dbm database with the specified name, which can include a directory
 * path. Any file extensions needed will be supplied automatically by the dbm
 * library. For example, Berkeley DB appends '.db', and GNU gdbm uses two
 * physical files with extensions '.dir' and '.pag'.
 *
 * The mode should be an integer, as for Unix chmod.
 *
 * Flags should be one of READER, WRITER, WRCREAT or NEWDB.
 */
static VALUE
fdbm_initialize(int argc, VALUE *argv, VALUE obj)
{
    volatile VALUE file;
    VALUE vmode, vflags;
    DBM *dbm;
    struct dbmdata *dbmp;
    int mode, flags = 0;

    if (rb_scan_args(argc, argv, "12", &file, &vmode, &vflags) == 1) {
	mode = 0666;		/* default value */
    }
    else if (NIL_P(vmode)) {
	mode = -1;		/* return nil if DB not exist */
    }
    else {
	mode = NUM2INT(vmode);
    }

    if (!NIL_P(vflags))
        flags = NUM2INT(vflags);

    FilePathValue(file);

    if (flags & RUBY_DBM_RW_BIT) {
        flags &= ~RUBY_DBM_RW_BIT;
        dbm = dbm_open(RSTRING_PTR(file), flags, mode);
    }
    else {
        dbm = 0;
        if (mode >= 0) {
            dbm = dbm_open(RSTRING_PTR(file), O_RDWR|O_CREAT, mode);
        }
        if (!dbm) {
            dbm = dbm_open(RSTRING_PTR(file), O_RDWR, 0);
        }
        if (!dbm) {
            dbm = dbm_open(RSTRING_PTR(file), O_RDONLY, 0);
        }
    }

    if (!dbm) {
	if (mode == -1) return Qnil;
	rb_sys_fail(RSTRING_PTR(file));
    }

    dbmp = ALLOC(struct dbmdata);
    DATA_PTR(obj) = dbmp;
    dbmp->di_dbm = dbm;
    dbmp->di_size = -1;

    return obj;
}
Exemple #12
0
static CFURLRef
str_to_url(VALUE path) {
#ifdef FilePathValue
  VALUE p = FilePathValue(path);
#else
  VALUE p = rb_String(path);
#endif
  CFURLRef fileURL = CFURLCreateFromFileSystemRepresentation(NULL, (const UInt8 *)RSTRING_PTR(p), RSTRING_LEN(p), false);
  if (!fileURL) {
    rb_raise(rb_eArgError, "Unable to create CFURL from `%s'.", RSTRING_PTR(rb_inspect(path)));
  }
  return fileURL;
}
// Win32::Symlink::symlink(file, symlink)
static VALUE
rb_symlink(VALUE mod, VALUE target, VALUE symlink)
{
	(void)mod;

	VALUE error = Qnil;
	wchar_t* wtarget = NULL;
	wchar_t* wsymlink = NULL;
	BOOL res;
	DWORD flags = 0;

	target = FilePathValue(target);
	symlink = FilePathValue(symlink);
	target = rb_str_encode_ospath(target);
	symlink = rb_str_encode_ospath(symlink);

	wtarget = filecp_to_wstr(RSTRING_PTR(target), NULL);
	wsymlink = filecp_to_wstr(RSTRING_PTR(symlink), NULL);

	if( is_directory(wtarget) )
	{
		flags |= SYMBOLIC_LINK_FLAG_DIRECTORY;
	}
	res = create_symbolic_linkW(wsymlink, wtarget, flags);
	if( !res )
	{
		error = make_api_error(RSTRING_PTR(target));
	}

	xfree(wtarget);
	xfree(wsymlink);

	if( !NIL_P(error) )
	{
		rb_exc_raise(error);
	}
	return INT2FIX(0);
}
// Win32::Symlink::symlink?(file)
static VALUE
rb_symlink_p(VALUE mod, VALUE file)
{
	(void)mod;
	DWORD attrs;
	FilePathValue(file);
	file = rb_str_encode_ospath(file);
	attrs = GetFileAttributes(RSTRING_PTR(file));
	if( attrs == INVALID_FILE_ATTRIBUTES )
	{
		rb_exc_raise(make_api_error(RSTRING_PTR(file)));
	}
	return (attrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0;
}
Exemple #15
0
static VALUE
rb_f_load(int argc, VALUE *argv)
{
    VALUE fname, wrap, path;

    rb_scan_args(argc, argv, "11", &fname, &wrap);
    path = rb_find_file(FilePathValue(fname));
    if (!path) {
	if (!rb_file_load_ok(RSTRING_PTR(fname)))
	    load_failed(fname);
	path = fname;
    }
    rb_load_internal(path, RTEST(wrap));
    return Qtrue;
}
Exemple #16
0
/*
* call-seq:
*   SDBM.new(filename, mode = 0666)
*
* Creates a new database handle by opening the given +filename+. SDBM actually
* uses two physical files, with extensions '.dir' and '.pag'. These extensions
* will automatically be appended to the +filename+.
*
* If the file does not exist, a new file will be created using the given
* +mode+, unless +mode+ is explicitly set to nil. In the latter case, no
* database will be created.
*
* If the file exists, it will be opened in read/write mode. If this fails, it
* will be opened in read-only mode.
*/
static VALUE
fsdbm_initialize(int argc, VALUE *argv, VALUE obj)
{
    volatile VALUE file;
    VALUE vmode;
    DBM *dbm;
    struct dbmdata *dbmp;
    int mode;

    if (rb_scan_args(argc, argv, "11", &file, &vmode) == 1) {
	mode = 0666;		/* default value */
    }
    else if (NIL_P(vmode)) {
	mode = -1;		/* return nil if DB not exist */
    }
    else {
	mode = NUM2INT(vmode);
    }
    FilePathValue(file);

    dbm = 0;
    if (mode >= 0)
	dbm = sdbm_open(RSTRING_PTR(file), O_RDWR|O_CREAT, mode);
    if (!dbm)
	dbm = sdbm_open(RSTRING_PTR(file), O_RDWR, 0);
    if (!dbm)
	dbm = sdbm_open(RSTRING_PTR(file), O_RDONLY, 0);

    if (!dbm) {
	if (mode == -1) return Qnil;
	rb_sys_fail_str(file);
    }

    dbmp = ALLOC(struct dbmdata);
    DATA_PTR(obj) = dbmp;
    dbmp->di_dbm = dbm;
    dbmp->di_size = -1;

    return obj;
}
Exemple #17
0
void
rb_load(VALUE fname, int wrap)
{
#if MACRUBY_STATIC
    rb_raise(rb_eRuntimeError, "#load is not supported in MacRuby static");
#else
    // TODO honor wrap

    // Locate file.
    FilePathValue(fname);
    fname = rb_str_new4(fname);
    VALUE tmp = rb_find_file(fname);
    if (tmp == 0) {
	load_failed(fname);
    }
    fname = tmp;

    // Load it.
    const char *fname_str = RSTRING_PTR(fname);
//printf("load %s\n", fname_str);

    rb_vm_load(fname_str, wrap);
#endif
}
Exemple #18
0
/*
 *  call-seq:
 *     Dir.chdir( [ string] ) => 0
 *     Dir.chdir( [ string] ) {| path | block }  => anObject
 *
 *  Changes the current working directory of the process to the given
 *  string. When called without an argument, changes the directory to
 *  the value of the environment variable <code>HOME</code>, or
 *  <code>LOGDIR</code>. <code>SystemCallError</code> (probably
 *  <code>Errno::ENOENT</code>) if the target directory does not exist.
 *
 *  If a block is given, it is passed the name of the new current
 *  directory, and the block is executed with that as the current
 *  directory. The original working directory is restored when the block
 *  exits. The return value of <code>chdir</code> is the value of the
 *  block. <code>chdir</code> blocks can be nested, but in a
 *  multi-threaded program an error will be raised if a thread attempts
 *  to open a <code>chdir</code> block while another thread has one
 *  open.
 *
 *     Dir.chdir("/var/spool/mail")
 *     puts Dir.pwd
 *     Dir.chdir("/tmp") do
 *       puts Dir.pwd
 *       Dir.chdir("/usr") do
 *         puts Dir.pwd
 *       end
 *       puts Dir.pwd
 *     end
 *     puts Dir.pwd
 *
 *  <em>produces:</em>
 *
 *     /var/spool/mail
 *     /tmp
 *     /usr
 *     /tmp
 *     /var/spool/mail
 */
static VALUE
dir_s_chdir(int argc, VALUE *argv, VALUE obj)
{
    VALUE path = Qnil;

    rb_secure(2);
    if (rb_scan_args(argc, argv, "01", &path) == 1) {
	FilePathValue(path);
    }
    else {
	const char *dist = getenv("HOME");
	if (!dist) {
	    dist = getenv("LOGDIR");
	    if (!dist) rb_raise(rb_eArgError, "HOME/LOGDIR not set");
	}
	path = rb_str_new2(dist);
    }

    if (chdir_blocking > 0) {
	if (!rb_block_given_p() || rb_thread_current() != chdir_thread)
	    rb_warn("conflicting chdir during another chdir block");
    }

    if (rb_block_given_p()) {
	struct chdir_data args;
	char *cwd = my_getcwd();

	args.old_path = rb_tainted_str_new2(cwd); xfree(cwd);
	args.new_path = path;
	args.done = Qfalse;
	return rb_ensure(chdir_yield, (VALUE)&args, chdir_restore, (VALUE)&args);
    }
    dir_chdir(path);

    return INT2FIX(0);
}
Exemple #19
0
/*
 * call-seq:
 *   DBM.new(filename[, mode[, flags]]) -> dbm
 *
 * Open a dbm database with the specified name, which can include a directory
 * path. Any file extensions needed will be supplied automatically by the dbm
 * library. For example, Berkeley DB appends '.db', and GNU gdbm uses two
 * physical files with extensions '.dir' and '.pag'.
 *
 * The mode should be an integer, as for Unix chmod.
 *
 * Flags should be one of READER, WRITER, WRCREAT or NEWDB.
 */
static VALUE
fdbm_initialize(int argc, VALUE *argv, VALUE obj)
{
    volatile VALUE file;
    VALUE vmode, vflags;
    DBM *dbm;
    struct dbmdata *dbmp;
    int mode, flags = 0;

    if (rb_scan_args(argc, argv, "12", &file, &vmode, &vflags) == 1) {
	mode = 0666;		/* default value */
    }
    else if (NIL_P(vmode)) {
	mode = -1;		/* return nil if DB not exist */
    }
    else {
	mode = NUM2INT(vmode);
    }

    if (!NIL_P(vflags))
        flags = NUM2INT(vflags);

    FilePathValue(file);

    /*
     * Note:
     * gdbm 1.10 works with O_CLOEXEC.  gdbm 1.9.1 silently ignore it.
     */
#ifndef O_CLOEXEC
#   define O_CLOEXEC 0
#endif

    if (flags & RUBY_DBM_RW_BIT) {
        flags &= ~RUBY_DBM_RW_BIT;
        dbm = dbm_open(RSTRING_PTR(file), flags|O_CLOEXEC, mode);
    }
    else {
        dbm = 0;
        if (mode >= 0) {
            dbm = dbm_open(RSTRING_PTR(file), O_RDWR|O_CREAT|O_CLOEXEC, mode);
        }
        if (!dbm) {
            dbm = dbm_open(RSTRING_PTR(file), O_RDWR|O_CLOEXEC, 0);
        }
        if (!dbm) {
            dbm = dbm_open(RSTRING_PTR(file), O_RDONLY|O_CLOEXEC, 0);
        }
    }

    if (dbm) {
    /*
     * History of dbm_pagfno() and dbm_dirfno() in ndbm and its compatibles.
     * (dbm_pagfno() and dbm_dirfno() is not standardized.)
     *
     * 1986: 4.3BSD provides ndbm.
     *       It provides dbm_pagfno() and dbm_dirfno() as macros.
     * 1991: gdbm-1.5 provides them as functions.
     *       They returns a same descriptor.
     *       (Earlier releases may have the functions too.)
     * 1991: Net/2 provides Berkeley DB.
     *       It doesn't provide dbm_pagfno() and dbm_dirfno().
     * 1992: 4.4BSD Alpha provides Berkeley DB with dbm_dirfno() as a function.
     *       dbm_pagfno() is a macro as DBM_PAGFNO_NOT_AVAILABLE.
     * 1997: Berkeley DB 2.0 is released by Sleepycat Software, Inc.
     *       It defines dbm_pagfno() and dbm_dirfno() as macros.
     * 2011: gdbm-1.9 creates a separate dir file.
     *       dbm_pagfno() and dbm_dirfno() returns different descriptors.
     */
#if defined(HAVE_DBM_PAGFNO)
        rb_fd_fix_cloexec(dbm_pagfno(dbm));
#endif
#if defined(HAVE_DBM_DIRFNO)
        rb_fd_fix_cloexec(dbm_dirfno(dbm));
#endif

#if defined(RUBYDBM_DB_HEADER) && defined(HAVE_TYPE_DBC)
    /* Disable Berkeley DB error messages such as:
     * DB->put: attempt to modify a read-only database */
        ((DBC*)dbm)->dbp->set_errfile(((DBC*)dbm)->dbp, NULL);
#endif
    }

    if (!dbm) {
	if (mode == -1) return Qnil;
	rb_sys_fail_str(file);
    }

    dbmp = ALLOC(struct dbmdata);
    DATA_PTR(obj) = dbmp;
    dbmp->di_dbm = dbm;
    dbmp->di_size = -1;

    return obj;
}
Exemple #20
0
/*
 * returns
 *  0: if already loaded (false)
 *  1: successfully loaded (true)
 * <0: not found (LoadError)
 * >1: exception
 */
int
rb_require_internal(VALUE fname, int safe)
{
    volatile int result = -1;
    rb_thread_t *th = GET_THREAD();
    volatile VALUE errinfo = th->errinfo;
    int state;
    struct {
	int safe;
    } volatile saved;
    char *volatile ftptr = 0;

    if (RUBY_DTRACE_REQUIRE_ENTRY_ENABLED()) {
	RUBY_DTRACE_REQUIRE_ENTRY(StringValuePtr(fname),
				  rb_sourcefile(),
				  rb_sourceline());
    }

    TH_PUSH_TAG(th);
    saved.safe = rb_safe_level();
    if ((state = EXEC_TAG()) == 0) {
	VALUE path;
	long handle;
	int found;

	rb_set_safe_level_force(safe);
	FilePathValue(fname);
	rb_set_safe_level_force(0);

	if (RUBY_DTRACE_FIND_REQUIRE_ENTRY_ENABLED()) {
	    RUBY_DTRACE_FIND_REQUIRE_ENTRY(StringValuePtr(fname),
					   rb_sourcefile(),
					   rb_sourceline());
	}

	path = rb_str_encode_ospath(fname);
	found = search_required(path, &path, safe);

	if (RUBY_DTRACE_FIND_REQUIRE_RETURN_ENABLED()) {
	    RUBY_DTRACE_FIND_REQUIRE_RETURN(StringValuePtr(fname),
					    rb_sourcefile(),
					    rb_sourceline());
	}
	if (found) {
	    if (!path || !(ftptr = load_lock(RSTRING_PTR(path)))) {
		result = 0;
	    }
	    else if (!*ftptr) {
		rb_provide_feature(path);
		result = TAG_RETURN;
	    }
	    else {
		switch (found) {
		  case 'r':
		    rb_load_internal(path, 0);
		    break;

		  case 's':
		    handle = (long)rb_vm_call_cfunc(rb_vm_top_self(), load_ext,
						    path, 0, path);
		    rb_ary_push(ruby_dln_librefs, LONG2NUM(handle));
		    break;
		}
		rb_provide_feature(path);
		result = TAG_RETURN;
	    }
	}
    }
    TH_POP_TAG();
    load_unlock(ftptr, !state);

    rb_set_safe_level_force(saved.safe);
    if (state) {
	/* never TAG_RETURN */
	return state;
    }

    th->errinfo = errinfo;

    if (RUBY_DTRACE_REQUIRE_RETURN_ENABLED()) {
	RUBY_DTRACE_REQUIRE_RETURN(StringValuePtr(fname),
				  rb_sourcefile(),
				  rb_sourceline());
    }

    return result;
}
Exemple #21
0
/*
 *  call-seq:
 *     Dir.new( string ) -> aDir
 *
 *  Returns a new directory object for the named directory.
 */
static VALUE
dir_initialize(int argc, VALUE *argv, VALUE dir)
{
    struct dir_data *dp;
    static rb_encoding *fs_encoding;
    rb_encoding  *intencoding, *extencoding;
    VALUE dirname, opt;
    static VALUE sym_intenc, sym_extenc;

    if (!sym_intenc) {
	sym_intenc = ID2SYM(rb_intern("internal_encoding"));
	sym_extenc = ID2SYM(rb_intern("external_encoding"));
	fs_encoding = rb_filesystem_encoding();
    }

    intencoding = NULL;
    extencoding = fs_encoding;
    rb_scan_args(argc, argv, "11", &dirname, &opt);

    if (!NIL_P(opt)) {
        VALUE v, extenc=Qnil, intenc=Qnil;
        opt = rb_check_convert_type(opt, T_HASH, "Hash", "to_hash");

        v = rb_hash_aref(opt, sym_intenc);
        if (!NIL_P(v)) intenc = v;
        v = rb_hash_aref(opt, sym_extenc);
        if (!NIL_P(v)) extenc = v;

	if (!NIL_P(extenc)) {
	    extencoding = rb_to_encoding(extenc);
	    if (!NIL_P(intenc)) {
		intencoding = rb_to_encoding(intenc);
		if (extencoding == intencoding) {
		    rb_warn("Ignoring internal encoding '%s': it is identical to external encoding '%s'",
			    RSTRING_PTR(rb_inspect(intenc)),
			    RSTRING_PTR(rb_inspect(extenc)));
		    intencoding = NULL;
		}
	    }
	}
	else if (!NIL_P(intenc)) {
	    rb_raise(rb_eArgError, "External encoding must be specified when internal encoding is given");
	}
    }

    {
	rb_encoding  *dirname_encoding = rb_enc_get(dirname);
	if (rb_usascii_encoding() != dirname_encoding
	    && rb_ascii8bit_encoding() != dirname_encoding
#if defined __APPLE__
	    && rb_utf8_encoding() != dirname_encoding
#endif
	    && extencoding != dirname_encoding) {
	    if (!intencoding) intencoding = dirname_encoding;
	    dirname = rb_str_transcode(dirname, rb_enc_from_encoding(extencoding));
	}
    }
    FilePathValue(dirname);

    Data_Get_Struct(dir, struct dir_data, dp);
    if (dp->dir) closedir(dp->dir);
    if (dp->path) xfree(dp->path);
    dp->dir = NULL;
    dp->path = NULL;
    dp->intenc = intencoding;
    dp->extenc = extencoding;
    dp->dir = opendir(RSTRING_PTR(dirname));
    if (dp->dir == NULL) {
	if (errno == EMFILE || errno == ENFILE) {
	    rb_gc();
	    dp->dir = opendir(RSTRING_PTR(dirname));
	}
	if (dp->dir == NULL) {
	    rb_sys_fail(RSTRING_PTR(dirname));
	}
    }
    dp->path = strdup(RSTRING_PTR(dirname));

    return dir;
}