Skip to content

Commit 59087c3

Browse files
committed
builtin::getcwd WIP #3
Add builtin::getcwd #3 gcc syntax fixes -win32_get_childdir() skip the strlen() because GetCurrentDirectoryA() gives it to us, handle 32KB paths if encountered. It is an infinite retry loop since its been reported, in multithreading, GCD()/CWD can change and get longer on our OS thread's between overflow #1 and correct-size attempt #2 because CWD val is a race cond. So all overflow conditions must trigger realloc. If the whole C stack is used up with alloca() and infinite retry. A SEGV is good. Win API/UNICODE_STRING struct is hard coded to USHORT/SHORT. If GetCurrentDirectoryA() returns above 65KB a SEGV is good. If GetCurrentDirectoryA()'s impl is doing {return buflen+1;} which is an API violation, OS is damaged, a SEGV is good. The race retry will never realistically trigger more than 1x ever, 2x rounds through retry loop might happen after a few centuries semi-guess. -CPerlHost::GetChildDir(void) is TODO now that m_pvDir->GetCurrentDirectoryA/W have correct retvals. -perllib.c silence warnings, return debug code accidentally removed in Merge WinCE and Win32 directories -- Initial patch 7bd379e 4/27/2006 7:30:00 PM
1 parent 769fbf2 commit 59087c3

File tree

17 files changed

+440
-99
lines changed

17 files changed

+440
-99
lines changed

builtin.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ struct BuiltinFuncDescriptor {
2929
bool is_experimental;
3030
};
3131

32+
#ifdef WIN32
33+
XS_EXTERNAL(w32_GetCwd);
34+
#elif defined(HAS_GETCWD)
35+
XS_EXTERNAL(XS_Internals_getcwd);
36+
#endif
37+
3238
#define warn_experimental_builtin(name) S_warn_experimental_builtin(aTHX_ name)
3339
static void S_warn_experimental_builtin(pTHX_ const char *name)
3440
{
@@ -640,6 +646,11 @@ static const struct BuiltinFuncDescriptor builtins[] = {
640646
/* list functions */
641647
{ "indexed", SHORTVER(5,39), &XS_builtin_indexed, &ck_builtin_funcN, 0, false },
642648
{ "export_lexically", NO_BUNDLE, &XS_builtin_export_lexically, NULL, 0, true },
649+
#ifdef WIN32
650+
{ "getcwd", NO_BUNDLE, &w32_GetCwd, NULL, 0, true },
651+
#elif defined(HAS_GETCWD)
652+
{ "getcwd", NO_BUNDLE, &XS_Internals_getcwd, NULL, 0, true },
653+
#endif
643654

644655
{ NULL, 0, NULL, NULL, 0, false }
645656
};

cpan/Win32/Win32.pm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ package Win32;
88
require DynaLoader;
99

1010
@ISA = qw|Exporter DynaLoader|;
11-
$VERSION = '0.59_01';
11+
$VERSION = '0.59_04';
1212
$XS_VERSION = $VERSION;
1313
$VERSION = eval $VERSION;
1414

cpan/Win32/Win32.xs

Lines changed: 74 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -936,31 +936,72 @@ XS(w32_SetChildShowWindow)
936936
XS(w32_GetCwd)
937937
{
938938
dXSARGS;
939-
char* ptr;
939+
/* Make the host for current directory */
940+
char buf [MAX_PATH+1];
941+
char* dir;
942+
DWORD dirlen;
943+
DWORD dirretlen;
944+
PH_GCDB_T dirinfo;
945+
unsigned int gotutf8;
946+
SV * sv;
940947
if (items)
941-
Perl_croak(aTHX_ "usage: Win32::GetCwd()");
948+
croak_xs_usage(cv, "");
949+
EXTEND(SP,1);
942950

943-
/* Make the host for current directory */
944-
ptr = PerlEnv_get_childdir();
945-
/*
946-
* If ptr != Nullch
947-
* then it worked, set PV valid,
948-
* else return 'undef'
949-
*/
950-
if (ptr) {
951-
SV *sv = sv_newmortal();
952-
sv_setpv(sv, ptr);
953-
PerlEnv_free_childdir(ptr);
951+
dXSTARG;
952+
sv = TARG;
954953

954+
if(SvTYPE(sv) >= SVt_PV) {
955+
SV_CHECK_THINKFIRST_COW_DROP(sv);
956+
if(SvLEN(sv) >= 32) {
957+
dirlen = (DWORD)SvLEN(sv);
958+
dir = SvPVX(sv);
959+
}
960+
else
961+
goto stk_buf;
962+
}
963+
else {
964+
stk_buf:
965+
dirlen = sizeof(buf);
966+
dir = buf;
967+
}
968+
969+
dirinfo.want_wide = 0;
970+
dirinfo.want_utf8_maybe = XSANY.any_i32 == 'W' ? 1 : 0;
971+
972+
retry_dir:
973+
dirinfo.len_tchar = dirlen;
974+
dirretlen = PerlEnv_get_childdir_tbuf(dir, dirinfo);
975+
gotutf8 = dirretlen & 0x80000000;
976+
dirretlen &= ~0x80000000;
977+
if(dirretlen >= dirlen) {
978+
dirlen = dirretlen + 1;
979+
dir = alloca(dirlen);
980+
goto retry_dir;
981+
}
982+
else if(!dirretlen){
983+
//translate_to_errno(); //TODO XXXX
984+
sv = &PL_sv_undef;
985+
}
986+
else if(SvTYPE(sv) >= SVt_PV && dir == SvPVX(sv)) {
987+
SvCUR_set(sv, dirretlen);
988+
SvNIOK_off(sv);
989+
SvPOK_on(sv);
990+
if(gotutf8)
991+
SvUTF8_on(sv);
992+
SvSETMAGIC(sv);
993+
}
994+
else {
995+
if(gotutf8)
996+
SvUTF8_on(sv);
997+
sv_setpvn_mg(sv, dir, dirretlen);
998+
}
955999
#ifndef INCOMPLETE_TAINTS
9561000
SvTAINTED_on(sv);
9571001
#endif
9581002

959-
EXTEND(SP,1);
960-
ST(0) = sv;
961-
XSRETURN(1);
962-
}
963-
XSRETURN_UNDEF;
1003+
PUSHs(sv);
1004+
PUTBACK;
9641005
}
9651006

9661007
XS(w32_SetCwd)
@@ -2023,6 +2064,8 @@ PROTOTYPES: DISABLE
20232064
BOOT:
20242065
{
20252066
const char *file = __FILE__;
2067+
GV * gv;
2068+
CV * cv;
20262069

20272070
if (g_osver.dwOSVersionInfoSize == 0) {
20282071
g_osver.dwOSVersionInfoSize = sizeof(g_osver);
@@ -2051,8 +2094,19 @@ BOOT:
20512094
newXS("Win32::GetFolderPath", w32_GetFolderPath, file);
20522095
newXS("Win32::IsAdminUser", w32_IsAdminUser, file);
20532096
newXS("Win32::GetFileVersion", w32_GetFileVersion, file);
2054-
2055-
newXS("Win32::GetCwd", w32_GetCwd, file);
2097+
gv = gv_fetchpvn("Win32::GetCwd", sizeof("Win32::GetCwd")-1, 0, SVt_PVGV);
2098+
cv = GvCV(gv);
2099+
if(cv) {
2100+
GvCV_set(gv, NULL);
2101+
SvREFCNT_dec_NN(cv);
2102+
}
2103+
cv = newXS("Win32::GetCwdA", w32_GetCwd, file);
2104+
XSANY.any_i32 = 'A';
2105+
SvREFCNT_inc(cv);
2106+
GvCV_set(gv,cv);
2107+
2108+
cv = newXS("Win32::GetCwdW", w32_GetCwd, file);
2109+
XSANY.any_i32 = 'W';
20562110
newXS("Win32::SetCwd", w32_SetCwd, file);
20572111
newXS("Win32::GetNextAvailDrive", w32_GetNextAvailDrive, file);
20582112
newXS("Win32::GetLastError", w32_GetLastError, file);

iperlsys.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,7 @@ typedef void* (*LPEnvGetChildenv)(struct IPerlEnv*);
470470
typedef void (*LPEnvFreeChildenv)(struct IPerlEnv*, void* env);
471471
typedef char* (*LPEnvGetChilddir)(struct IPerlEnv*);
472472
typedef void (*LPEnvFreeChilddir)(struct IPerlEnv*, char* dir);
473+
typedef unsigned int (*LPEnvGetChilddir_tbuf)(struct IPerlEnv*, char* ptr, PH_GCDB_T info);
473474
# ifdef HAS_ENVGETENV
474475
typedef char* (*LPENVGetenv)(struct IPerlEnv*, const char *varname);
475476
typedef char* (*LPENVGetenv_len)(struct IPerlEnv*,
@@ -497,6 +498,7 @@ struct IPerlEnv
497498
LPEnvFreeChildenv pFreeChildenv;
498499
LPEnvGetChilddir pGetChilddir;
499500
LPEnvFreeChilddir pFreeChilddir;
501+
LPEnvGetChilddir_tbuf pGetChilddir_tbuf;
500502
# ifdef HAS_ENVGETENV
501503
LPENVGetenv pENVGetenv;
502504
LPENVGetenv_len pENVGetenv_len;
@@ -532,6 +534,8 @@ struct IPerlEnvInfo
532534
(*PL_Env->pGetChilddir)(PL_Env)
533535
# define PerlEnv_free_childdir(d) \
534536
(*PL_Env->pFreeChilddir)(PL_Env, (d))
537+
# define PerlEnv_get_childdir_tbuf(_p,_i) \
538+
(*PL_Env->pGetChilddir_tbuf)(PL_Env,(_p),(_i))
535539
# ifdef HAS_ENVGETENV
536540
# define PerlEnv_ENVgetenv(str) \
537541
(*PL_Env->pENVGetenv)(PL_Env,(str))
@@ -583,6 +587,7 @@ struct IPerlEnvInfo
583587
# define PerlEnv_get_childenv() win32_get_childenv()
584588
# define PerlEnv_free_childenv(e) win32_free_childenv((e))
585589
# define PerlEnv_get_childdir() win32_get_childdir()
590+
# define PerlEnv_get_childdir_tbuf(_p,_i) win32_get_childdir_tbuf((_p),(_i))
586591
# define PerlEnv_free_childdir(d) win32_free_childdir((d))
587592
# else
588593
# define PerlEnv_clearenv(str) (ENV_LOCK, (clearenv(str) \

lib/Internals.pod

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -57,22 +57,6 @@ to implement higher-level behavior which should be used instead.
5757
See the core implementation for the exact meaning of the readonly flag for
5858
each internal variable type.
5959

60-
=item Internals::getcwd()
61-
62-
Internally core maintained version of L<Cwd::getcwd()|Cwd/getcwd> or
63-
L<Win32::GetCwd()|Win32/Win32::GetCwd()>. Only for use if loading L<Cwd::|Cwd> or
64-
calling C<Win32::GetCwd()> and its C<AUTOLOAD> to L<Win32.pm|Win32> will
65-
somehow break a TAP test in a C<.t>.
66-
67-
Not defined on all platforms and all perl build flag configs. May not set
68-
C<PWD> env var. May disappear at any time. Probe for the sub's existance
69-
before calling it and write C<if>/C<else> if C<Internals::getcwd> is
70-
unavailable. Although this would be a bug, there is no guarentee it will
71-
return the same identical string as L<Cwd::getcwd()|Cwd/getcwd> or
72-
L<Win32::GetCwd()|Win32/Win32::GetCwd()>. The public implementations can get patched
73-
in the future for some future discovered bug while this sub keeps the buggy
74-
return value.
75-
7660
=item hv_clear_placeholders(%hash)
7761

7862
Clear any placeholders from a locked hash. Should not be used directly.

lib/blib.pm

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ sub import
5252
# That means that it would not be possible to run `make test`
5353
# for the Win32 module because blib.pm would always load the
5454
# installed version before @INC gets updated with the blib path.
55-
if(defined &Internals::getcwd) {
56-
$dir = Internals::getcwd();
55+
if(defined &builtin::getcwd) {
56+
$dir = builtin::getcwd();
5757
} else {
5858
chomp($dir = `cd`);
5959
}

lib/builtin.pm

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package builtin 0.015;
1+
package builtin 0.016;
22

33
use v5.40;
44

@@ -174,6 +174,29 @@ Returns the floating-point "Not-a-Number" value.
174174
175175
Available starting with Perl 5.40.
176176
177+
=head2 getcwd
178+
179+
$cwd = builtin::getcwd();
180+
181+
Core maintained version of L<Cwd::getcwd()|Cwd/getcwd> or
182+
L<Win32::GetCwd()|Win32/Win32::GetCwd()>. It is suggested that you only use
183+
this sub if loading L<Cwd::|Cwd> or calling C<Win32::GetCwd()> and its
184+
C<AUTOLOAD> to L<Win32.pm|Win32> will somehow break a TAP test in a C<.t> or
185+
for some esoteric reason L<@INC|perlvar/@INC> L<%INC|perlvar/%INC> or
186+
L<$INC|perlvar/$INC> are unusable or temporarily broken or undef, or you are
187+
running perl.bin without perl's L<PERL5LIB|perlrun/PERL5LIB> or
188+
L<PERLLIB|perlrun/PERLLIB>.
189+
190+
C<builtin::getcwd> may not always return the same string as
191+
L<Cwd::getcwd()|Cwd/getcwd> or L<Win32::GetCwd()|Win32/Win32::GetCwd()>.
192+
This sub may have less Perl specific OS portability fixes vs the 2
193+
subs above, and could return C<undef> in situations where those 2 would return
194+
a successful string value. C<builtin::getcwd> is not guarenteed to set
195+
C<PWD> env var. Although this would be a bug, there is no guarentee it will
196+
return the same identical string. Note the public implementations of the other
197+
2 subs can get patched in the future for some future discovered bug while this
198+
sub keeps the buggy return value string.
199+
177200
=head2 weaken
178201
179202
weaken($ref);

lib/builtin.t

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,19 @@ TODO: {
440440
is($HASH{key}, "val", 'Lexically exported hash is accessible');
441441
}
442442

443+
# Test getcwd
444+
{
445+
require Cwd;
446+
447+
eval "getcwd()";
448+
ok($@, "no main::getcwd");
449+
450+
TODO: {
451+
local $::TODO = "backslash vs forward slash problems on Win32";
452+
is(builtin::getcwd(), Cwd::getcwd(), "builtin::getcwd() eq Cwd::getcwd()");
453+
}
454+
}
455+
443456
# load_module
444457
{
445458
use builtin qw( load_module );

makedef.pl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,7 @@ sub readvar {
347347
++$skip{$_} foreach qw(
348348
Perl_my_popen
349349
Perl_my_pclose
350+
win32_get_childdir_tbuf
350351
);
351352
++$export{$_} foreach qw(perl_get_host_info perl_alloc_override);
352353
++$export{perl_clone_host} if $define{USE_ITHREADS};
@@ -844,6 +845,7 @@ sub readvar {
844845
win32_free_childenv
845846
win32_get_childdir
846847
win32_get_childenv
848+
win32_get_childdir_tbuf
847849
win32_spawnvp
848850
Perl_init_os_extras
849851
Perl_win32_init

pod/perldelta.pod

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,12 @@ shelling out to a new C<cmd.exe>, this was fixed and the C<cwd> when using
131131
C<blib.pm> and L<Win32.pm|Win32> is obtained with a fast same-process API
132132
function call the way C<Win32::GetCwd()> and C<Cwd::> do it.
133133

134+
=item builtin.pm
135+
136+
C<builtin.pm> was updated from 0.015 to 0.016.
137+
138+
C<builtin::getcwd()> was added as experimental.
139+
134140
=back
135141

136142
=head2 Removed Modules and Pragmata
@@ -348,12 +354,9 @@ well.
348354

349355
=over 4
350356

351-
=item Internals::getcwd() is documented as very limited platform availability
357+
=item *
352358

353-
C<Internals::getcwd()> is documented as experimental, unsupported, not-bug-free
354-
and removeable in the future, and very limited availability on random
355-
platforms and perl core build flags. Basically C<Win32> only, and only for
356-
esoteric C<.t> TAP situations and esoteric internal core reasons.
359+
XXX
357360

358361
=back
359362

universal.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1131,9 +1131,9 @@ XS(XS_re_regexp_pattern)
11311131
NOT_REACHED; /* NOTREACHED */
11321132
}
11331133

1134-
#if defined(HAS_GETCWD) && defined(PERL_IS_MINIPERL)
1134+
#if defined(HAS_GETCWD)
11351135

1136-
XS(XS_Internals_getcwd)
1136+
XS_EXTERNAL(XS_Internals_getcwd)
11371137
{
11381138
dXSARGS;
11391139
if (items != 0)
@@ -1353,7 +1353,7 @@ static const struct xsub_details these_details[] = {
13531353
/* Always offer backup, Win32CORE.c vs AUTOLOAD vs Win32.pm
13541354
vs Win32.dll vs loading a .pm or .dll at all, has rare dep/recursion
13551355
problems in certain modules or .t files. See w32_GetCwd() . */
1356-
{"Internals::getcwd", w32_GetCwd, "", 0 },
1356+
/*{"Internals::getcwd", w32_GetCwd, "", 0 },*/
13571357
#endif
13581358
{"Tie::Hash::NamedCapture::_tie_it", XS_NamedCapture_tie_it, NULL, 0 },
13591359
{"Tie::Hash::NamedCapture::TIEHASH", XS_NamedCapture_TIEHASH, NULL, 0 },

0 commit comments

Comments
 (0)