Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
f5f54fb4
Commit
f5f54fb4
authored
Dec 31, 2008
by
Francois Gouget
Committed by
Alexandre Julliard
Dec 31, 2008
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
cmd: Reorder some functions to avoid forward declarations.
parent
2b3c8ad5
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
505 additions
and
514 deletions
+505
-514
directory.c
programs/cmd/directory.c
+505
-514
No files found.
programs/cmd/directory.c
View file @
f5f54fb4
...
...
@@ -33,11 +33,6 @@
WINE_DEFAULT_DEBUG_CHANNEL
(
cmd
);
int
WCMD_dir_sort
(
const
void
*
a
,
const
void
*
b
);
WCHAR
*
WCMD_filesize64
(
ULONGLONG
free
);
WCHAR
*
WCMD_strrev
(
WCHAR
*
buff
);
static
void
WCMD_getfileowner
(
WCHAR
*
filename
,
WCHAR
*
owner
,
int
ownerlen
);
static
void
WCMD_dir_trailer
(
WCHAR
drive
);
extern
int
echo_mode
;
extern
WCHAR
quals
[
MAX_PATH
],
param1
[
MAX_PATH
],
param2
[
MAX_PATH
];
...
...
@@ -58,7 +53,6 @@ typedef enum _DISPLAYORDER
Date
}
DISPLAYORDER
;
static
DIRECTORY_STACK
*
WCMD_list_directory
(
DIRECTORY_STACK
*
parms
,
int
level
);
static
int
file_total
,
dir_total
,
recurse
,
wide
,
bare
,
max_width
,
lower
;
static
int
shortname
,
usernames
;
static
ULONGLONG
byte_total
;
...
...
@@ -76,368 +70,183 @@ static const WCHAR emptyW[] = {'\0'};
static
const
WCHAR
spaceW
[]
=
{
' '
,
'\0'
};
/*****************************************************************************
* WCMD_directory
*
* List a file directory.
* WCMD_strrev
*
* Reverse a WCHARacter string in-place (strrev() is not available under unixen :-( ).
*/
WCHAR
*
WCMD_strrev
(
WCHAR
*
buff
)
{
void
WCMD_directory
(
WCHAR
*
cmd
)
{
int
r
,
i
;
WCHAR
b
;
WCHAR
path
[
MAX_PATH
],
cwd
[
MAX_PATH
];
int
status
,
paged_mode
;
CONSOLE_SCREEN_BUFFER_INFO
consoleInfo
;
r
=
strlenW
(
buff
);
for
(
i
=
0
;
i
<
r
/
2
;
i
++
)
{
b
=
buff
[
i
];
buff
[
i
]
=
buff
[
r
-
i
-
1
];
buff
[
r
-
i
-
1
]
=
b
;
}
return
(
buff
);
}
/*****************************************************************************
* WCMD_filesize64
*
* Convert a 64-bit number into a WCHARacter string, with commas every three digits.
* Result is returned in a static string overwritten with each call.
* FIXME: There must be a better algorithm!
*/
WCHAR
*
WCMD_filesize64
(
ULONGLONG
n
)
{
ULONGLONG
q
;
unsigned
int
r
,
i
;
WCHAR
*
p
;
WCHAR
string
[
MAXSTRING
];
int
argno
=
0
;
int
argsProcessed
=
0
;
WCHAR
*
argN
=
cmd
;
WCHAR
lastDrive
;
BOOL
trailerReqd
=
FALSE
;
DIRECTORY_STACK
*
fullParms
=
NULL
;
DIRECTORY_STACK
*
prevEntry
=
NULL
;
DIRECTORY_STACK
*
thisEntry
=
NULL
;
WCHAR
drive
[
10
];
WCHAR
dir
[
MAX_PATH
];
WCHAR
fname
[
MAX_PATH
];
WCHAR
ext
[
MAX_PATH
];
static
const
WCHAR
dircmdW
[]
=
{
'D'
,
'I'
,
'R'
,
'C'
,
'M'
,
'D'
,
'\0'
};
static
WCHAR
buff
[
32
];
errorlevel
=
0
;
p
=
buff
;
i
=
-
3
;
do
{
if
(
separator
&&
((
++
i
)
%
3
==
1
))
*
p
++
=
','
;
q
=
n
/
10
;
r
=
n
-
(
q
*
10
);
*
p
++
=
r
+
'0'
;
*
p
=
'\0'
;
n
=
q
;
}
while
(
n
!=
0
);
WCMD_strrev
(
buff
);
return
buff
;
}
/* Prefill quals with (uppercased) DIRCMD env var */
if
(
GetEnvironmentVariable
(
dircmdW
,
string
,
sizeof
(
string
)
/
sizeof
(
WCHAR
)))
{
p
=
string
;
while
(
(
*
p
=
toupper
(
*
p
))
)
++
p
;
strcatW
(
string
,
quals
);
strcpyW
(
quals
,
string
);
}
/*****************************************************************************
* WCMD_dir_sort
*
* Sort based on the /O options supplied on the command line
*/
int
WCMD_dir_sort
(
const
void
*
a
,
const
void
*
b
)
{
WIN32_FIND_DATA
*
filea
=
(
WIN32_FIND_DATA
*
)
a
;
WIN32_FIND_DATA
*
fileb
=
(
WIN32_FIND_DATA
*
)
b
;
int
result
=
0
;
byte_total
=
0
;
file_total
=
dir_total
=
0
;
/* If /OG or /O-G supplied, dirs go at the top or bottom, ignoring the
requested sort order for the directory components */
if
(
orderGroupDirs
&&
((
filea
->
dwFileAttributes
&
FILE_ATTRIBUTE_DIRECTORY
)
||
(
fileb
->
dwFileAttributes
&
FILE_ATTRIBUTE_DIRECTORY
)))
{
BOOL
aDir
=
filea
->
dwFileAttributes
&
FILE_ATTRIBUTE_DIRECTORY
;
if
(
aDir
)
result
=
-
1
;
else
result
=
1
;
if
(
orderGroupDirsReverse
)
result
=
-
result
;
return
result
;
/* Initialize all flags to their defaults as if no DIRCMD or quals */
paged_mode
=
FALSE
;
recurse
=
FALSE
;
wide
=
FALSE
;
bare
=
FALSE
;
lower
=
FALSE
;
shortname
=
FALSE
;
usernames
=
FALSE
;
orderByCol
=
FALSE
;
separator
=
TRUE
;
dirTime
=
Written
;
dirOrder
=
Name
;
orderReverse
=
FALSE
;
orderGroupDirs
=
FALSE
;
orderGroupDirsReverse
=
FALSE
;
showattrs
=
0
;
attrsbits
=
0
;
/* Order by Name: */
}
else
if
(
dirOrder
==
Name
)
{
result
=
lstrcmpiW
(
filea
->
cFileName
,
fileb
->
cFileName
);
/*
Handle args - Loop through so right most is the effective one
*/
/* Note: /- appears to be a negate rather than an off, eg. dir
/-W is wide, or dir /w /-w /-w is also wide */
p
=
quals
;
while
(
*
p
&&
(
*
p
==
'/'
||
*
p
==
' '
))
{
BOOL
negate
=
FALSE
;
if
(
*
p
++==
' '
)
continue
;
/* Skip / and blanks introduced through DIRCMD */
/*
Order by Size:
*/
}
else
if
(
dirOrder
==
Size
)
{
ULONG64
sizea
=
(((
ULONG64
)
filea
->
nFileSizeHigh
)
<<
32
)
+
filea
->
nFileSizeLow
;
ULONG64
sizeb
=
(((
ULONG64
)
fileb
->
nFileSizeHigh
)
<<
32
)
+
fileb
->
nFileSizeLow
;
if
(
sizea
<
sizeb
)
result
=
-
1
;
else
if
(
sizea
==
sizeb
)
result
=
0
;
else
result
=
1
;
if
(
*
p
==
'-'
)
{
negate
=
TRUE
;
p
++
;
/* Order by Date: (Takes into account which date (/T option) */
}
else
if
(
dirOrder
==
Date
)
{
FILETIME
*
ft
;
ULONG64
timea
,
timeb
;
if
(
dirTime
==
Written
)
{
ft
=
&
filea
->
ftLastWriteTime
;
timea
=
(((
ULONG64
)
ft
->
dwHighDateTime
)
<<
32
)
+
ft
->
dwLowDateTime
;
ft
=
&
fileb
->
ftLastWriteTime
;
timeb
=
(((
ULONG64
)
ft
->
dwHighDateTime
)
<<
32
)
+
ft
->
dwLowDateTime
;
}
else
if
(
dirTime
==
Access
)
{
ft
=
&
filea
->
ftLastAccessTime
;
timea
=
(((
ULONG64
)
ft
->
dwHighDateTime
)
<<
32
)
+
ft
->
dwLowDateTime
;
ft
=
&
fileb
->
ftLastAccessTime
;
timeb
=
(((
ULONG64
)
ft
->
dwHighDateTime
)
<<
32
)
+
ft
->
dwLowDateTime
;
}
else
{
ft
=
&
filea
->
ftCreationTime
;
timea
=
(((
ULONG64
)
ft
->
dwHighDateTime
)
<<
32
)
+
ft
->
dwLowDateTime
;
ft
=
&
fileb
->
ftCreationTime
;
timeb
=
(((
ULONG64
)
ft
->
dwHighDateTime
)
<<
32
)
+
ft
->
dwLowDateTime
;
}
if
(
timea
<
timeb
)
result
=
-
1
;
else
if
(
timea
==
timeb
)
result
=
0
;
else
result
=
1
;
WINE_TRACE
(
"Processing arg '%c' (in %s)
\n
"
,
*
p
,
wine_dbgstr_w
(
quals
));
switch
(
*
p
)
{
case
'P'
:
if
(
negate
)
paged_mode
=
!
paged_mode
;
else
paged_mode
=
TRUE
;
break
;
case
'S'
:
if
(
negate
)
recurse
=
!
recurse
;
else
recurse
=
TRUE
;
break
;
case
'W'
:
if
(
negate
)
wide
=
!
wide
;
else
wide
=
TRUE
;
break
;
case
'B'
:
if
(
negate
)
bare
=
!
bare
;
else
bare
=
TRUE
;
break
;
case
'L'
:
if
(
negate
)
lower
=
!
lower
;
else
lower
=
TRUE
;
break
;
case
'X'
:
if
(
negate
)
shortname
=
!
shortname
;
else
shortname
=
TRUE
;
break
;
case
'Q'
:
if
(
negate
)
usernames
=
!
usernames
;
else
usernames
=
TRUE
;
break
;
case
'D'
:
if
(
negate
)
orderByCol
=
!
orderByCol
;
else
orderByCol
=
TRUE
;
break
;
case
'C'
:
if
(
negate
)
separator
=
!
separator
;
else
separator
=
TRUE
;
break
;
case
'T'
:
p
=
p
+
1
;
if
(
*
p
==
':'
)
p
++
;
/* Skip optional : */
/* Order by Extension: (Takes into account which date (/T option) */
}
else
if
(
dirOrder
==
Extension
)
{
WCHAR
drive
[
10
];
WCHAR
dir
[
MAX_PATH
];
WCHAR
fname
[
MAX_PATH
];
WCHAR
extA
[
MAX_PATH
];
WCHAR
extB
[
MAX_PATH
];
if
(
*
p
==
'A'
)
dirTime
=
Access
;
else
if
(
*
p
==
'C'
)
dirTime
=
Creation
;
else
if
(
*
p
==
'W'
)
dirTime
=
Written
;
/* Split into components */
WCMD_splitpath
(
filea
->
cFileName
,
drive
,
dir
,
fname
,
extA
);
WCMD_splitpath
(
fileb
->
cFileName
,
drive
,
dir
,
fname
,
extB
);
result
=
lstrcmpiW
(
extA
,
extB
);
}
/* Support /T and /T: with no parms, default to written */
else
if
(
*
p
==
0x00
||
*
p
==
'/'
)
{
dirTime
=
Written
;
p
=
p
-
1
;
/* So when step on, move to '/' */
}
else
{
SetLastError
(
ERROR_INVALID_PARAMETER
);
WCMD_print_error
();
errorlevel
=
1
;
return
;
}
break
;
case
'O'
:
p
=
p
+
1
;
if
(
*
p
==
':'
)
p
++
;
/* Skip optional : */
while
(
*
p
&&
*
p
!=
'/'
)
{
WINE_TRACE
(
"Processing subparm '%c' (in %s)
\n
"
,
*
p
,
wine_dbgstr_w
(
quals
));
switch
(
*
p
)
{
case
'N'
:
dirOrder
=
Name
;
break
;
case
'E'
:
dirOrder
=
Extension
;
break
;
case
'S'
:
dirOrder
=
Size
;
break
;
case
'D'
:
dirOrder
=
Date
;
break
;
case
'-'
:
if
(
*
(
p
+
1
)
==
'G'
)
orderGroupDirsReverse
=
TRUE
;
else
orderReverse
=
TRUE
;
break
;
case
'G'
:
orderGroupDirs
=
TRUE
;
break
;
default:
SetLastError
(
ERROR_INVALID_PARAMETER
);
WCMD_print_error
();
errorlevel
=
1
;
return
;
}
p
++
;
}
p
=
p
-
1
;
/* So when step on, move to '/' */
break
;
case
'A'
:
p
=
p
+
1
;
showattrs
=
0
;
attrsbits
=
0
;
if
(
*
p
==
':'
)
p
++
;
/* Skip optional : */
while
(
*
p
&&
*
p
!=
'/'
)
{
BOOL
anegate
=
FALSE
;
ULONG
mask
;
if
(
orderReverse
)
result
=
-
result
;
return
result
;
}
/* Note /A: - options are 'offs' not toggles */
if
(
*
p
==
'-'
)
{
anegate
=
TRUE
;
p
++
;
}
/*****************************************************************************
* WCMD_getfileowner
*
* Reverse a WCHARacter string in-place (strrev() is not available under unixen :-( ).
*/
void
WCMD_getfileowner
(
WCHAR
*
filename
,
WCHAR
*
owner
,
int
ownerlen
)
{
WINE_TRACE
(
"Processing subparm '%c' (in %s)
\n
"
,
*
p
,
wine_dbgstr_w
(
quals
));
switch
(
*
p
)
{
case
'D'
:
mask
=
FILE_ATTRIBUTE_DIRECTORY
;
break
;
case
'H'
:
mask
=
FILE_ATTRIBUTE_HIDDEN
;
break
;
case
'S'
:
mask
=
FILE_ATTRIBUTE_SYSTEM
;
break
;
case
'R'
:
mask
=
FILE_ATTRIBUTE_READONLY
;
break
;
case
'A'
:
mask
=
FILE_ATTRIBUTE_ARCHIVE
;
break
;
default:
SetLastError
(
ERROR_INVALID_PARAMETER
);
WCMD_print_error
();
errorlevel
=
1
;
return
;
}
/* Keep running list of bits we care about */
attrsbits
|=
mask
;
/* Mask shows what MUST be in the bits we care about */
if
(
anegate
)
showattrs
=
showattrs
&
~
mask
;
else
showattrs
|=
mask
;
ULONG
sizeNeeded
=
0
;
DWORD
rc
;
WCHAR
name
[
MAXSTRING
];
WCHAR
domain
[
MAXSTRING
];
p
++
;
}
p
=
p
-
1
;
/* So when step on, move to '/' */
WINE_TRACE
(
"Result: showattrs %x, bits %x
\n
"
,
showattrs
,
attrsbits
);
break
;
default:
SetLastError
(
ERROR_INVALID_PARAMETER
);
WCMD_print_error
();
errorlevel
=
1
;
return
;
}
p
=
p
+
1
;
}
/* In case of error, return empty string */
*
owner
=
0x00
;
/* Handle conflicting args and initialization */
if
(
bare
||
shortname
)
wide
=
FALSE
;
if
(
bare
)
shortname
=
FALSE
;
if
(
wide
)
usernames
=
FALSE
;
if
(
orderByCol
)
wide
=
TRUE
;
/* Find out how much space we need for the owner security descriptor */
GetFileSecurity
(
filename
,
OWNER_SECURITY_INFORMATION
,
0
,
0
,
&
sizeNeeded
);
rc
=
GetLastError
();
if
(
wide
)
{
if
(
GetConsoleScreenBufferInfo
(
GetStdHandle
(
STD_OUTPUT_HANDLE
),
&
consoleInfo
))
max_width
=
consoleInfo
.
dwSize
.
X
;
else
max_width
=
80
;
}
if
(
paged_mode
)
{
WCMD_enter_paged_mode
(
NULL
);
}
if
(
rc
==
ERROR_INSUFFICIENT_BUFFER
&&
sizeNeeded
>
0
)
{
argno
=
0
;
argsProcessed
=
0
;
argN
=
cmd
;
GetCurrentDirectory
(
MAX_PATH
,
cwd
);
strcatW
(
cwd
,
slashW
);
LPBYTE
secBuffer
;
PSID
pSID
=
NULL
;
BOOL
defaulted
=
FALSE
;
ULONG
nameLen
=
MAXSTRING
;
ULONG
domainLen
=
MAXSTRING
;
SID_NAME_USE
nameuse
;
/* Loop through all args, calculating full effective directory */
fullParms
=
NULL
;
prevEntry
=
NULL
;
while
(
argN
)
{
WCHAR
fullname
[
MAXSTRING
];
WCHAR
*
thisArg
=
WCMD_parameter
(
cmd
,
argno
++
,
&
argN
);
if
(
argN
&&
argN
[
0
]
!=
'/'
)
{
secBuffer
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeNeeded
*
sizeof
(
BYTE
));
if
(
!
secBuffer
)
return
;
WINE_TRACE
(
"Found parm '%s'
\n
"
,
wine_dbgstr_w
(
thisArg
));
if
(
thisArg
[
1
]
==
':'
&&
thisArg
[
2
]
==
'\\'
)
{
strcpyW
(
fullname
,
thisArg
);
}
else
if
(
thisArg
[
1
]
==
':'
&&
thisArg
[
2
]
!=
'\\'
)
{
WCHAR
envvar
[
4
];
static
const
WCHAR
envFmt
[]
=
{
'='
,
'%'
,
'c'
,
':'
,
'\0'
};
wsprintf
(
envvar
,
envFmt
,
thisArg
[
0
]);
if
(
!
GetEnvironmentVariable
(
envvar
,
fullname
,
MAX_PATH
))
{
static
const
WCHAR
noEnvFmt
[]
=
{
'%'
,
'c'
,
':'
,
'\0'
};
wsprintf
(
fullname
,
noEnvFmt
,
thisArg
[
0
]);
/* Get the owners security descriptor */
if
(
!
GetFileSecurity
(
filename
,
OWNER_SECURITY_INFORMATION
,
secBuffer
,
sizeNeeded
,
&
sizeNeeded
))
{
HeapFree
(
GetProcessHeap
(),
0
,
secBuffer
);
return
;
}
strcatW
(
fullname
,
slashW
);
strcatW
(
fullname
,
&
thisArg
[
2
]);
}
else
if
(
thisArg
[
0
]
==
'\\'
)
{
memcpy
(
fullname
,
cwd
,
2
*
sizeof
(
WCHAR
));
strcpyW
(
fullname
+
2
,
thisArg
);
}
else
{
strcpyW
(
fullname
,
cwd
);
strcatW
(
fullname
,
thisArg
);
}
WINE_TRACE
(
"Using location '%s'
\n
"
,
wine_dbgstr_w
(
fullname
));
status
=
GetFullPathName
(
fullname
,
sizeof
(
path
)
/
sizeof
(
WCHAR
),
path
,
NULL
);
/*
* If the path supplied does not include a wildcard, and the endpoint of the
* path references a directory, we need to list the *contents* of that
* directory not the directory file itself.
*/
if
((
strchrW
(
path
,
'*'
)
==
NULL
)
&&
(
strchrW
(
path
,
'%'
)
==
NULL
))
{
status
=
GetFileAttributes
(
path
);
if
((
status
!=
INVALID_FILE_ATTRIBUTES
)
&&
(
status
&
FILE_ATTRIBUTE_DIRECTORY
))
{
if
(
path
[
strlenW
(
path
)
-
1
]
==
'\\'
)
{
strcatW
(
path
,
starW
);
}
else
{
const
WCHAR
slashStarW
[]
=
{
'\\'
,
'*'
,
'\0'
};
strcatW
(
path
,
slashStarW
);
}
/* Get the SID from the SD */
if
(
!
GetSecurityDescriptorOwner
(
secBuffer
,
&
pSID
,
&
defaulted
))
{
HeapFree
(
GetProcessHeap
(),
0
,
secBuffer
);
return
;
}
}
else
{
/* Special case wildcard search with no extension (ie parameters ending in '.') as
GetFullPathName strips off the additional '.' */
if
(
fullname
[
strlenW
(
fullname
)
-
1
]
==
'.'
)
strcatW
(
path
,
dotW
);
}
WINE_TRACE
(
"Using path '%s'
\n
"
,
wine_dbgstr_w
(
path
));
thisEntry
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
DIRECTORY_STACK
));
if
(
fullParms
==
NULL
)
fullParms
=
thisEntry
;
if
(
prevEntry
!=
NULL
)
prevEntry
->
next
=
thisEntry
;
prevEntry
=
thisEntry
;
thisEntry
->
next
=
NULL
;
/* Split into components */
WCMD_splitpath
(
path
,
drive
,
dir
,
fname
,
ext
);
WINE_TRACE
(
"Path Parts: drive: '%s' dir: '%s' name: '%s' ext:'%s'
\n
"
,
wine_dbgstr_w
(
drive
),
wine_dbgstr_w
(
dir
),
wine_dbgstr_w
(
fname
),
wine_dbgstr_w
(
ext
));
thisEntry
->
dirName
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
WCHAR
)
*
(
strlenW
(
drive
)
+
strlenW
(
dir
)
+
1
));
strcpyW
(
thisEntry
->
dirName
,
drive
);
strcatW
(
thisEntry
->
dirName
,
dir
);
thisEntry
->
fileName
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
WCHAR
)
*
(
strlenW
(
fname
)
+
strlenW
(
ext
)
+
1
));
strcpyW
(
thisEntry
->
fileName
,
fname
);
strcatW
(
thisEntry
->
fileName
,
ext
);
}
}
/* If just 'dir' entered, a '*' parameter is assumed */
if
(
fullParms
==
NULL
)
{
WINE_TRACE
(
"Inserting default '*'
\n
"
);
fullParms
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
DIRECTORY_STACK
));
fullParms
->
next
=
NULL
;
fullParms
->
dirName
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
WCHAR
)
*
(
strlenW
(
cwd
)
+
1
));
strcpyW
(
fullParms
->
dirName
,
cwd
);
fullParms
->
fileName
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
WCHAR
)
*
2
);
strcpyW
(
fullParms
->
fileName
,
starW
);
}
lastDrive
=
'?'
;
prevEntry
=
NULL
;
thisEntry
=
fullParms
;
trailerReqd
=
FALSE
;
while
(
thisEntry
!=
NULL
)
{
/* Output disk free (trailer) and volume information (header) if the drive
letter changes */
if
(
lastDrive
!=
toupper
(
thisEntry
->
dirName
[
0
]))
{
/* Trailer Information */
if
(
lastDrive
!=
'?'
)
{
trailerReqd
=
FALSE
;
WCMD_dir_trailer
(
prevEntry
->
dirName
[
0
]);
}
lastDrive
=
toupper
(
thisEntry
->
dirName
[
0
]);
if
(
!
bare
)
{
WCHAR
drive
[
3
];
WINE_TRACE
(
"Writing volume for '%c:'
\n
"
,
thisEntry
->
dirName
[
0
]);
memcpy
(
drive
,
thisEntry
->
dirName
,
2
*
sizeof
(
WCHAR
));
drive
[
2
]
=
0x00
;
status
=
WCMD_volume
(
0
,
drive
);
trailerReqd
=
TRUE
;
if
(
!
status
)
{
errorlevel
=
1
;
goto
exit
;
}
}
}
else
{
static
const
WCHAR
newLine2
[]
=
{
'\n'
,
'\n'
,
'\0'
};
if
(
!
bare
)
WCMD_output
(
newLine2
);
/* Convert to a username */
if
(
LookupAccountSid
(
NULL
,
pSID
,
name
,
&
nameLen
,
domain
,
&
domainLen
,
&
nameuse
))
{
static
const
WCHAR
fmt
[]
=
{
'%'
,
's'
,
'%'
,
'c'
,
'%'
,
's'
,
'\0'
};
snprintfW
(
owner
,
ownerlen
,
fmt
,
domain
,
'\\'
,
name
);
}
HeapFree
(
GetProcessHeap
(),
0
,
secBuffer
);
}
/* Clear any errors from previous invocations, and process it */
errorlevel
=
0
;
prevEntry
=
thisEntry
;
thisEntry
=
WCMD_list_directory
(
thisEntry
,
0
);
}
/* Trailer Information */
if
(
trailerReqd
)
{
WCMD_dir_trailer
(
prevEntry
->
dirName
[
0
]);
}
exit:
if
(
paged_mode
)
WCMD_leave_paged_mode
();
/* Free storage allocated for parms */
while
(
fullParms
!=
NULL
)
{
prevEntry
=
fullParms
;
fullParms
=
prevEntry
->
next
;
HeapFree
(
GetProcessHeap
(),
0
,
prevEntry
->
dirName
);
HeapFree
(
GetProcessHeap
(),
0
,
prevEntry
->
fileName
);
HeapFree
(
GetProcessHeap
(),
0
,
prevEntry
);
}
return
;
}
/*****************************************************************************
...
...
@@ -782,217 +591,399 @@ static DIRECTORY_STACK *WCMD_list_directory (DIRECTORY_STACK *inputparms, int le
}
/*****************************************************************************
* WCMD_
filesize64
* WCMD_
dir_trailer
*
* Convert a 64-bit number into a WCHARacter string, with commas every three digits.
* Result is returned in a static string overwritten with each call.
* FIXME: There must be a better algorithm!
* Print out the trailer for the supplied drive letter
*/
static
void
WCMD_dir_trailer
(
WCHAR
drive
)
{
ULARGE_INTEGER
avail
,
total
,
freebytes
;
DWORD
status
;
WCHAR
driveName
[
4
]
=
{
'c'
,
':'
,
'\\'
,
'\0'
};
WCHAR
*
WCMD_filesize64
(
ULONGLONG
n
)
{
ULONGLONG
q
;
unsigned
int
r
,
i
;
WCHAR
*
p
;
static
WCHAR
buff
[
32
];
driveName
[
0
]
=
drive
;
status
=
GetDiskFreeSpaceEx
(
driveName
,
&
avail
,
&
total
,
&
freebytes
);
WINE_TRACE
(
"Writing trailer for '%s' gave %d(%d)
\n
"
,
wine_dbgstr_w
(
driveName
),
status
,
GetLastError
());
p
=
buff
;
i
=
-
3
;
do
{
if
(
separator
&&
((
++
i
)
%
3
==
1
))
*
p
++
=
','
;
q
=
n
/
10
;
r
=
n
-
(
q
*
10
);
*
p
++
=
r
+
'0'
;
*
p
=
'\0'
;
n
=
q
;
}
while
(
n
!=
0
);
WCMD_strrev
(
buff
);
return
buff
;
if
(
errorlevel
==
0
&&
!
bare
)
{
if
(
recurse
)
{
static
const
WCHAR
fmt1
[]
=
{
'\n'
,
' '
,
' '
,
' '
,
' '
,
' '
,
'T'
,
'o'
,
't'
,
'a'
,
'l'
,
' '
,
'f'
,
'i'
,
'l'
,
'e'
,
's'
,
' '
,
'l'
,
'i'
,
's'
,
't'
,
'e'
,
'd'
,
':'
,
'\n'
,
'%'
,
'8'
,
'd'
,
' '
,
'f'
,
'i'
,
'l'
,
'e'
,
's'
,
'%'
,
'2'
,
'5'
,
's'
,
' '
,
'b'
,
'y'
,
't'
,
'e'
,
's'
,
'\n'
,
'\0'
};
static
const
WCHAR
fmt2
[]
=
{
'%'
,
'8'
,
'd'
,
' '
,
'd'
,
'i'
,
'r'
,
'e'
,
'c'
,
't'
,
'o'
,
'r'
,
'i'
,
'e'
,
's'
,
' '
,
'%'
,
'1'
,
'8'
,
's'
,
' '
,
'b'
,
'y'
,
't'
,
'e'
,
's'
,
' '
,
'f'
,
'r'
,
'e'
,
'e'
,
'\n'
,
'\n'
,
'\0'
};
WCMD_output
(
fmt1
,
file_total
,
WCMD_filesize64
(
byte_total
));
WCMD_output
(
fmt2
,
dir_total
,
WCMD_filesize64
(
freebytes
.
QuadPart
));
}
else
{
static
const
WCHAR
fmt
[]
=
{
' '
,
'%'
,
'1'
,
'8'
,
's'
,
' '
,
'b'
,
'y'
,
't'
,
'e'
,
's'
,
' '
,
'f'
,
'r'
,
'e'
,
'e'
,
'\n'
,
'\n'
,
'\0'
};
WCMD_output
(
fmt
,
WCMD_filesize64
(
freebytes
.
QuadPart
));
}
}
}
/*****************************************************************************
* WCMD_strrev
* WCMD_directory
*
* List a file directory.
*
* Reverse a WCHARacter string in-place (strrev() is not available under unixen :-( ).
*/
WCHAR
*
WCMD_strrev
(
WCHAR
*
buff
)
{
void
WCMD_directory
(
WCHAR
*
cmd
)
{
int
r
,
i
;
WCHAR
b
;
WCHAR
path
[
MAX_PATH
],
cwd
[
MAX_PATH
];
int
status
,
paged_mode
;
CONSOLE_SCREEN_BUFFER_INFO
consoleInfo
;
WCHAR
*
p
;
WCHAR
string
[
MAXSTRING
];
int
argno
=
0
;
int
argsProcessed
=
0
;
WCHAR
*
argN
=
cmd
;
WCHAR
lastDrive
;
BOOL
trailerReqd
=
FALSE
;
DIRECTORY_STACK
*
fullParms
=
NULL
;
DIRECTORY_STACK
*
prevEntry
=
NULL
;
DIRECTORY_STACK
*
thisEntry
=
NULL
;
WCHAR
drive
[
10
];
WCHAR
dir
[
MAX_PATH
];
WCHAR
fname
[
MAX_PATH
];
WCHAR
ext
[
MAX_PATH
];
static
const
WCHAR
dircmdW
[]
=
{
'D'
,
'I'
,
'R'
,
'C'
,
'M'
,
'D'
,
'\0'
};
r
=
strlenW
(
buff
);
for
(
i
=
0
;
i
<
r
/
2
;
i
++
)
{
b
=
buff
[
i
];
buff
[
i
]
=
buff
[
r
-
i
-
1
];
buff
[
r
-
i
-
1
]
=
b
;
errorlevel
=
0
;
/* Prefill quals with (uppercased) DIRCMD env var */
if
(
GetEnvironmentVariable
(
dircmdW
,
string
,
sizeof
(
string
)
/
sizeof
(
WCHAR
)))
{
p
=
string
;
while
(
(
*
p
=
toupper
(
*
p
))
)
++
p
;
strcatW
(
string
,
quals
);
strcpyW
(
quals
,
string
);
}
return
(
buff
);
}
byte_total
=
0
;
file_total
=
dir_total
=
0
;
/*****************************************************************************
* WCMD_dir_sort
*
* Sort based on the /O options supplied on the command line
*/
int
WCMD_dir_sort
(
const
void
*
a
,
const
void
*
b
)
{
WIN32_FIND_DATA
*
filea
=
(
WIN32_FIND_DATA
*
)
a
;
WIN32_FIND_DATA
*
fileb
=
(
WIN32_FIND_DATA
*
)
b
;
int
result
=
0
;
/* Initialize all flags to their defaults as if no DIRCMD or quals */
paged_mode
=
FALSE
;
recurse
=
FALSE
;
wide
=
FALSE
;
bare
=
FALSE
;
lower
=
FALSE
;
shortname
=
FALSE
;
usernames
=
FALSE
;
orderByCol
=
FALSE
;
separator
=
TRUE
;
dirTime
=
Written
;
dirOrder
=
Name
;
orderReverse
=
FALSE
;
orderGroupDirs
=
FALSE
;
orderGroupDirsReverse
=
FALSE
;
showattrs
=
0
;
attrsbits
=
0
;
/* If /OG or /O-G supplied, dirs go at the top or bottom, ignoring the
requested sort order for the directory components */
if
(
orderGroupDirs
&&
((
filea
->
dwFileAttributes
&
FILE_ATTRIBUTE_DIRECTORY
)
||
(
fileb
->
dwFileAttributes
&
FILE_ATTRIBUTE_DIRECTORY
)))
{
BOOL
aDir
=
filea
->
dwFileAttributes
&
FILE_ATTRIBUTE_DIRECTORY
;
if
(
aDir
)
result
=
-
1
;
else
result
=
1
;
if
(
orderGroupDirsReverse
)
result
=
-
result
;
return
result
;
/* Handle args - Loop through so right most is the effective one */
/* Note: /- appears to be a negate rather than an off, eg. dir
/-W is wide, or dir /w /-w /-w is also wide */
p
=
quals
;
while
(
*
p
&&
(
*
p
==
'/'
||
*
p
==
' '
))
{
BOOL
negate
=
FALSE
;
if
(
*
p
++==
' '
)
continue
;
/* Skip / and blanks introduced through DIRCMD */
if
(
*
p
==
'-'
)
{
negate
=
TRUE
;
p
++
;
}
WINE_TRACE
(
"Processing arg '%c' (in %s)
\n
"
,
*
p
,
wine_dbgstr_w
(
quals
));
switch
(
*
p
)
{
case
'P'
:
if
(
negate
)
paged_mode
=
!
paged_mode
;
else
paged_mode
=
TRUE
;
break
;
case
'S'
:
if
(
negate
)
recurse
=
!
recurse
;
else
recurse
=
TRUE
;
break
;
case
'W'
:
if
(
negate
)
wide
=
!
wide
;
else
wide
=
TRUE
;
break
;
case
'B'
:
if
(
negate
)
bare
=
!
bare
;
else
bare
=
TRUE
;
break
;
case
'L'
:
if
(
negate
)
lower
=
!
lower
;
else
lower
=
TRUE
;
break
;
case
'X'
:
if
(
negate
)
shortname
=
!
shortname
;
else
shortname
=
TRUE
;
break
;
case
'Q'
:
if
(
negate
)
usernames
=
!
usernames
;
else
usernames
=
TRUE
;
break
;
case
'D'
:
if
(
negate
)
orderByCol
=
!
orderByCol
;
else
orderByCol
=
TRUE
;
break
;
case
'C'
:
if
(
negate
)
separator
=
!
separator
;
else
separator
=
TRUE
;
break
;
case
'T'
:
p
=
p
+
1
;
if
(
*
p
==
':'
)
p
++
;
/* Skip optional : */
if
(
*
p
==
'A'
)
dirTime
=
Access
;
else
if
(
*
p
==
'C'
)
dirTime
=
Creation
;
else
if
(
*
p
==
'W'
)
dirTime
=
Written
;
/* Support /T and /T: with no parms, default to written */
else
if
(
*
p
==
0x00
||
*
p
==
'/'
)
{
dirTime
=
Written
;
p
=
p
-
1
;
/* So when step on, move to '/' */
}
else
{
SetLastError
(
ERROR_INVALID_PARAMETER
);
WCMD_print_error
();
errorlevel
=
1
;
return
;
}
break
;
case
'O'
:
p
=
p
+
1
;
if
(
*
p
==
':'
)
p
++
;
/* Skip optional : */
while
(
*
p
&&
*
p
!=
'/'
)
{
WINE_TRACE
(
"Processing subparm '%c' (in %s)
\n
"
,
*
p
,
wine_dbgstr_w
(
quals
));
switch
(
*
p
)
{
case
'N'
:
dirOrder
=
Name
;
break
;
case
'E'
:
dirOrder
=
Extension
;
break
;
case
'S'
:
dirOrder
=
Size
;
break
;
case
'D'
:
dirOrder
=
Date
;
break
;
case
'-'
:
if
(
*
(
p
+
1
)
==
'G'
)
orderGroupDirsReverse
=
TRUE
;
else
orderReverse
=
TRUE
;
break
;
case
'G'
:
orderGroupDirs
=
TRUE
;
break
;
default:
SetLastError
(
ERROR_INVALID_PARAMETER
);
WCMD_print_error
();
errorlevel
=
1
;
return
;
}
p
++
;
}
p
=
p
-
1
;
/* So when step on, move to '/' */
break
;
case
'A'
:
p
=
p
+
1
;
showattrs
=
0
;
attrsbits
=
0
;
if
(
*
p
==
':'
)
p
++
;
/* Skip optional : */
while
(
*
p
&&
*
p
!=
'/'
)
{
BOOL
anegate
=
FALSE
;
ULONG
mask
;
/* Note /A: - options are 'offs' not toggles */
if
(
*
p
==
'-'
)
{
anegate
=
TRUE
;
p
++
;
}
WINE_TRACE
(
"Processing subparm '%c' (in %s)
\n
"
,
*
p
,
wine_dbgstr_w
(
quals
));
switch
(
*
p
)
{
case
'D'
:
mask
=
FILE_ATTRIBUTE_DIRECTORY
;
break
;
case
'H'
:
mask
=
FILE_ATTRIBUTE_HIDDEN
;
break
;
case
'S'
:
mask
=
FILE_ATTRIBUTE_SYSTEM
;
break
;
case
'R'
:
mask
=
FILE_ATTRIBUTE_READONLY
;
break
;
case
'A'
:
mask
=
FILE_ATTRIBUTE_ARCHIVE
;
break
;
default:
SetLastError
(
ERROR_INVALID_PARAMETER
);
WCMD_print_error
();
errorlevel
=
1
;
return
;
}
/* Keep running list of bits we care about */
attrsbits
|=
mask
;
/* Mask shows what MUST be in the bits we care about */
if
(
anegate
)
showattrs
=
showattrs
&
~
mask
;
else
showattrs
|=
mask
;
p
++
;
}
p
=
p
-
1
;
/* So when step on, move to '/' */
WINE_TRACE
(
"Result: showattrs %x, bits %x
\n
"
,
showattrs
,
attrsbits
);
break
;
default:
SetLastError
(
ERROR_INVALID_PARAMETER
);
WCMD_print_error
();
errorlevel
=
1
;
return
;
}
p
=
p
+
1
;
}
/* Handle conflicting args and initialization */
if
(
bare
||
shortname
)
wide
=
FALSE
;
if
(
bare
)
shortname
=
FALSE
;
if
(
wide
)
usernames
=
FALSE
;
if
(
orderByCol
)
wide
=
TRUE
;
if
(
wide
)
{
if
(
GetConsoleScreenBufferInfo
(
GetStdHandle
(
STD_OUTPUT_HANDLE
),
&
consoleInfo
))
max_width
=
consoleInfo
.
dwSize
.
X
;
else
max_width
=
80
;
}
if
(
paged_mode
)
{
WCMD_enter_paged_mode
(
NULL
);
}
/* Order by Name: */
}
else
if
(
dirOrder
==
Name
)
{
result
=
lstrcmpiW
(
filea
->
cFileName
,
fileb
->
cFileName
);
argno
=
0
;
argsProcessed
=
0
;
argN
=
cmd
;
GetCurrentDirectory
(
MAX_PATH
,
cwd
);
strcatW
(
cwd
,
slashW
);
/*
Order by Size:
*/
}
else
if
(
dirOrder
==
Size
)
{
ULONG64
sizea
=
(((
ULONG64
)
filea
->
nFileSizeHigh
)
<<
32
)
+
filea
->
nFileSizeLow
;
ULONG64
sizeb
=
(((
ULONG64
)
fileb
->
nFileSizeHigh
)
<<
32
)
+
fileb
->
nFileSizeLow
;
if
(
sizea
<
sizeb
)
result
=
-
1
;
else
if
(
sizea
==
sizeb
)
result
=
0
;
else
result
=
1
;
/*
Loop through all args, calculating full effective directory
*/
fullParms
=
NULL
;
prevEntry
=
NULL
;
while
(
argN
)
{
WCHAR
fullname
[
MAXSTRING
]
;
WCHAR
*
thisArg
=
WCMD_parameter
(
cmd
,
argno
++
,
&
argN
)
;
if
(
argN
&&
argN
[
0
]
!=
'/'
)
{
/* Order by Date: (Takes into account which date (/T option) */
}
else
if
(
dirOrder
==
Date
)
{
WINE_TRACE
(
"Found parm '%s'
\n
"
,
wine_dbgstr_w
(
thisArg
));
if
(
thisArg
[
1
]
==
':'
&&
thisArg
[
2
]
==
'\\'
)
{
strcpyW
(
fullname
,
thisArg
);
}
else
if
(
thisArg
[
1
]
==
':'
&&
thisArg
[
2
]
!=
'\\'
)
{
WCHAR
envvar
[
4
];
static
const
WCHAR
envFmt
[]
=
{
'='
,
'%'
,
'c'
,
':'
,
'\0'
};
wsprintf
(
envvar
,
envFmt
,
thisArg
[
0
]);
if
(
!
GetEnvironmentVariable
(
envvar
,
fullname
,
MAX_PATH
))
{
static
const
WCHAR
noEnvFmt
[]
=
{
'%'
,
'c'
,
':'
,
'\0'
};
wsprintf
(
fullname
,
noEnvFmt
,
thisArg
[
0
]);
}
strcatW
(
fullname
,
slashW
);
strcatW
(
fullname
,
&
thisArg
[
2
]);
}
else
if
(
thisArg
[
0
]
==
'\\'
)
{
memcpy
(
fullname
,
cwd
,
2
*
sizeof
(
WCHAR
));
strcpyW
(
fullname
+
2
,
thisArg
);
}
else
{
strcpyW
(
fullname
,
cwd
);
strcatW
(
fullname
,
thisArg
);
}
WINE_TRACE
(
"Using location '%s'
\n
"
,
wine_dbgstr_w
(
fullname
));
FILETIME
*
ft
;
ULONG64
timea
,
timeb
;
status
=
GetFullPathName
(
fullname
,
sizeof
(
path
)
/
sizeof
(
WCHAR
),
path
,
NULL
);
if
(
dirTime
==
Written
)
{
ft
=
&
filea
->
ftLastWriteTime
;
timea
=
(((
ULONG64
)
ft
->
dwHighDateTime
)
<<
32
)
+
ft
->
dwLowDateTime
;
ft
=
&
fileb
->
ftLastWriteTime
;
timeb
=
(((
ULONG64
)
ft
->
dwHighDateTime
)
<<
32
)
+
ft
->
dwLowDateTime
;
}
else
if
(
dirTime
==
Access
)
{
ft
=
&
filea
->
ftLastAccessTime
;
timea
=
(((
ULONG64
)
ft
->
dwHighDateTime
)
<<
32
)
+
ft
->
dwLowDateTime
;
ft
=
&
fileb
->
ftLastAccessTime
;
timeb
=
(((
ULONG64
)
ft
->
dwHighDateTime
)
<<
32
)
+
ft
->
dwLowDateTime
;
}
else
{
ft
=
&
filea
->
ftCreationTime
;
timea
=
(((
ULONG64
)
ft
->
dwHighDateTime
)
<<
32
)
+
ft
->
dwLowDateTime
;
ft
=
&
fileb
->
ftCreationTime
;
timeb
=
(((
ULONG64
)
ft
->
dwHighDateTime
)
<<
32
)
+
ft
->
dwLowDateTime
;
}
if
(
timea
<
timeb
)
result
=
-
1
;
else
if
(
timea
==
timeb
)
result
=
0
;
else
result
=
1
;
/*
* If the path supplied does not include a wildcard, and the endpoint of the
* path references a directory, we need to list the *contents* of that
* directory not the directory file itself.
*/
if
((
strchrW
(
path
,
'*'
)
==
NULL
)
&&
(
strchrW
(
path
,
'%'
)
==
NULL
))
{
status
=
GetFileAttributes
(
path
);
if
((
status
!=
INVALID_FILE_ATTRIBUTES
)
&&
(
status
&
FILE_ATTRIBUTE_DIRECTORY
))
{
if
(
path
[
strlenW
(
path
)
-
1
]
==
'\\'
)
{
strcatW
(
path
,
starW
);
}
else
{
const
WCHAR
slashStarW
[]
=
{
'\\'
,
'*'
,
'\0'
};
strcatW
(
path
,
slashStarW
);
}
}
}
else
{
/* Special case wildcard search with no extension (ie parameters ending in '.') as
GetFullPathName strips off the additional '.' */
if
(
fullname
[
strlenW
(
fullname
)
-
1
]
==
'.'
)
strcatW
(
path
,
dotW
);
}
/* Order by Extension: (Takes into account which date (/T option) */
}
else
if
(
dirOrder
==
Extension
)
{
WCHAR
drive
[
10
];
WCHAR
dir
[
MAX_PATH
];
WCHAR
fname
[
MAX_PATH
];
WCHAR
extA
[
MAX_PATH
];
WCHAR
extB
[
MAX_PATH
];
WINE_TRACE
(
"Using path '%s'
\n
"
,
wine_dbgstr_w
(
path
));
thisEntry
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
DIRECTORY_STACK
));
if
(
fullParms
==
NULL
)
fullParms
=
thisEntry
;
if
(
prevEntry
!=
NULL
)
prevEntry
->
next
=
thisEntry
;
prevEntry
=
thisEntry
;
thisEntry
->
next
=
NULL
;
/* Split into components */
WCMD_splitpath
(
filea
->
cFileName
,
drive
,
dir
,
fname
,
extA
);
W
CMD_splitpath
(
fileb
->
cFileName
,
drive
,
dir
,
fname
,
extB
);
result
=
lstrcmpiW
(
extA
,
extB
);
}
WCMD_splitpath
(
path
,
drive
,
dir
,
fname
,
ext
);
W
INE_TRACE
(
"Path Parts: drive: '%s' dir: '%s' name: '%s' ext:'%s'
\n
"
,
wine_dbgstr_w
(
drive
),
wine_dbgstr_w
(
dir
),
wine_dbgstr_w
(
fname
),
wine_dbgstr_w
(
ext
));
if
(
orderReverse
)
result
=
-
result
;
return
result
;
}
thisEntry
->
dirName
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
WCHAR
)
*
(
strlenW
(
drive
)
+
strlenW
(
dir
)
+
1
));
strcpyW
(
thisEntry
->
dirName
,
drive
);
strcatW
(
thisEntry
->
dirName
,
dir
);
/*****************************************************************************
* WCMD_getfileowner
*
* Reverse a WCHARacter string in-place (strrev() is not available under unixen :-( ).
*/
void
WCMD_getfileowner
(
WCHAR
*
filename
,
WCHAR
*
owner
,
int
ownerlen
)
{
thisEntry
->
fileName
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
WCHAR
)
*
(
strlenW
(
fname
)
+
strlenW
(
ext
)
+
1
));
strcpyW
(
thisEntry
->
fileName
,
fname
);
strcatW
(
thisEntry
->
fileName
,
ext
);
ULONG
sizeNeeded
=
0
;
DWORD
rc
;
WCHAR
name
[
MAXSTRING
];
WCHAR
domain
[
MAXSTRING
];
}
}
/* In case of error, return empty string */
*
owner
=
0x00
;
/* If just 'dir' entered, a '*' parameter is assumed */
if
(
fullParms
==
NULL
)
{
WINE_TRACE
(
"Inserting default '*'
\n
"
);
fullParms
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
DIRECTORY_STACK
));
fullParms
->
next
=
NULL
;
fullParms
->
dirName
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
WCHAR
)
*
(
strlenW
(
cwd
)
+
1
));
strcpyW
(
fullParms
->
dirName
,
cwd
);
fullParms
->
fileName
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
WCHAR
)
*
2
);
strcpyW
(
fullParms
->
fileName
,
starW
);
}
/* Find out how much space we need for the owner security descriptor */
GetFileSecurity
(
filename
,
OWNER_SECURITY_INFORMATION
,
0
,
0
,
&
sizeNeeded
);
rc
=
GetLastError
();
lastDrive
=
'?'
;
prevEntry
=
NULL
;
thisEntry
=
fullParms
;
trailerReqd
=
FALSE
;
if
(
rc
==
ERROR_INSUFFICIENT_BUFFER
&&
sizeNeeded
>
0
)
{
while
(
thisEntry
!=
NULL
)
{
LPBYTE
secBuffer
;
PSID
pSID
=
NULL
;
BOOL
defaulted
=
FALSE
;
ULONG
nameLen
=
MAXSTRING
;
ULONG
domainLen
=
MAXSTRING
;
SID_NAME_USE
nameuse
;
/* Output disk free (trailer) and volume information (header) if the drive
letter changes */
if
(
lastDrive
!=
toupper
(
thisEntry
->
dirName
[
0
]))
{
secBuffer
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeNeeded
*
sizeof
(
BYTE
));
if
(
!
secBuffer
)
return
;
/* Trailer Information */
if
(
lastDrive
!=
'?'
)
{
trailerReqd
=
FALSE
;
WCMD_dir_trailer
(
prevEntry
->
dirName
[
0
]);
}
/* Get the owners security descriptor */
if
(
!
GetFileSecurity
(
filename
,
OWNER_SECURITY_INFORMATION
,
secBuffer
,
sizeNeeded
,
&
sizeNeeded
))
{
HeapFree
(
GetProcessHeap
(),
0
,
secBuffer
);
return
;
}
lastDrive
=
toupper
(
thisEntry
->
dirName
[
0
]);
/* Get the SID from the SD */
if
(
!
GetSecurityDescriptorOwner
(
secBuffer
,
&
pSID
,
&
defaulted
))
{
HeapFree
(
GetProcessHeap
(),
0
,
secBuffer
);
return
;
}
if
(
!
bare
)
{
WCHAR
drive
[
3
];
/* Convert to a username */
if
(
LookupAccountSid
(
NULL
,
pSID
,
name
,
&
nameLen
,
domain
,
&
domainLen
,
&
nameuse
))
{
static
const
WCHAR
fmt
[]
=
{
'%'
,
's'
,
'%'
,
'c'
,
'%'
,
's'
,
'\0'
};
snprintfW
(
owner
,
ownerlen
,
fmt
,
domain
,
'\\'
,
name
);
}
HeapFree
(
GetProcessHeap
(),
0
,
secBuffer
);
WINE_TRACE
(
"Writing volume for '%c:'
\n
"
,
thisEntry
->
dirName
[
0
]);
memcpy
(
drive
,
thisEntry
->
dirName
,
2
*
sizeof
(
WCHAR
));
drive
[
2
]
=
0x00
;
status
=
WCMD_volume
(
0
,
drive
);
trailerReqd
=
TRUE
;
if
(
!
status
)
{
errorlevel
=
1
;
goto
exit
;
}
}
}
else
{
static
const
WCHAR
newLine2
[]
=
{
'\n'
,
'\n'
,
'\0'
};
if
(
!
bare
)
WCMD_output
(
newLine2
);
}
return
;
}
/*****************************************************************************
* WCMD_dir_trailer
*
* Print out the trailer for the supplied drive letter
*/
static
void
WCMD_dir_trailer
(
WCHAR
drive
)
{
ULARGE_INTEGER
avail
,
total
,
freebytes
;
DWORD
status
;
WCHAR
driveName
[
4
]
=
{
'c'
,
':'
,
'\\'
,
'\0'
};
/* Clear any errors from previous invocations, and process it */
errorlevel
=
0
;
prevEntry
=
thisEntry
;
thisEntry
=
WCMD_list_directory
(
thisEntry
,
0
);
}
driveName
[
0
]
=
drive
;
status
=
GetDiskFreeSpaceEx
(
driveName
,
&
avail
,
&
total
,
&
freebytes
);
W
INE_TRACE
(
"Writing trailer for '%s' gave %d(%d)
\n
"
,
wine_dbgstr_w
(
driveName
),
status
,
GetLastError
());
/* Trailer Information */
if
(
trailerReqd
)
{
W
CMD_dir_trailer
(
prevEntry
->
dirName
[
0
]);
}
if
(
errorlevel
==
0
&&
!
bare
)
{
if
(
recurse
)
{
static
const
WCHAR
fmt1
[]
=
{
'\n'
,
' '
,
' '
,
' '
,
' '
,
' '
,
'T'
,
'o'
,
't'
,
'a'
,
'l'
,
' '
,
'f'
,
'i'
,
'l'
,
'e'
,
's'
,
' '
,
'l'
,
'i'
,
's'
,
't'
,
'e'
,
'd'
,
':'
,
'\n'
,
'%'
,
'8'
,
'd'
,
' '
,
'f'
,
'i'
,
'l'
,
'e'
,
's'
,
'%'
,
'2'
,
'5'
,
's'
,
' '
,
'b'
,
'y'
,
't'
,
'e'
,
's'
,
'\n'
,
'\0'
};
static
const
WCHAR
fmt2
[]
=
{
'%'
,
'8'
,
'd'
,
' '
,
'd'
,
'i'
,
'r'
,
'e'
,
'c'
,
't'
,
'o'
,
'r'
,
'i'
,
'e'
,
's'
,
' '
,
'%'
,
'1'
,
'8'
,
's'
,
' '
,
'b'
,
'y'
,
't'
,
'e'
,
's'
,
' '
,
'f'
,
'r'
,
'e'
,
'e'
,
'\n'
,
'\n'
,
'\0'
};
WCMD_output
(
fmt1
,
file_total
,
WCMD_filesize64
(
byte_total
));
WCMD_output
(
fmt2
,
dir_total
,
WCMD_filesize64
(
freebytes
.
QuadPart
));
}
else
{
static
const
WCHAR
fmt
[]
=
{
' '
,
'%'
,
'1'
,
'8'
,
's'
,
' '
,
'b'
,
'y'
,
't'
,
'e'
,
's'
,
' '
,
'f'
,
'r'
,
'e'
,
'e'
,
'\n'
,
'\n'
,
'\0'
};
WCMD_output
(
fmt
,
WCMD_filesize64
(
freebytes
.
QuadPart
));
}
}
exit:
if
(
paged_mode
)
WCMD_leave_paged_mode
();
/* Free storage allocated for parms */
while
(
fullParms
!=
NULL
)
{
prevEntry
=
fullParms
;
fullParms
=
prevEntry
->
next
;
HeapFree
(
GetProcessHeap
(),
0
,
prevEntry
->
dirName
);
HeapFree
(
GetProcessHeap
(),
0
,
prevEntry
->
fileName
);
HeapFree
(
GetProcessHeap
(),
0
,
prevEntry
);
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment