Compare commits
29 Commits
f08aa986a8
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6d2d3f367f | ||
|
|
7117bfff68 | ||
|
|
c50202e93b | ||
|
|
4cafe16980 | ||
|
|
fc97eb8d25 | ||
|
|
f940d2d88e | ||
|
|
9ab65e2f00 | ||
|
|
456349088e | ||
|
|
f62ca19c50 | ||
|
|
ff92f72583 | ||
|
|
83f8947ece | ||
|
|
87c1e50cf9 | ||
|
|
7f98d73738 | ||
|
|
3a5b08a4bf | ||
|
|
8b6685c501 | ||
|
|
cfb58237da | ||
|
|
aaf29ed535 | ||
|
|
6f998a497d | ||
|
|
dbf7be5104 | ||
|
|
4a4026e6dd | ||
|
|
20343b497a | ||
|
|
e4227bfda8 | ||
|
|
bb868613d9 | ||
|
|
e4d67917bd | ||
|
|
b8a701b8fe | ||
|
|
dd5e4e9a3b | ||
|
|
82b0f918dd | ||
|
|
b16fc3a64b | ||
|
|
f375f79cce |
177
CMakeLists.txt
177
CMakeLists.txt
@@ -1,17 +1,24 @@
|
||||
# DOS utilities for mars-nwe.
|
||||
#
|
||||
# Default mode: install a prebuilt net.exe from this source tree. This keeps the
|
||||
# normal mars-nwe build independent from Open Watcom.
|
||||
# Default install mode uses a split:
|
||||
# - legacy command names are installed from netold.exe
|
||||
# - new command names that netold.exe does not contain are installed from net.exe
|
||||
#
|
||||
# Maintainer mode: configure with -DMARS_NWE_BUILD_DOSUTILS=ON to rebuild
|
||||
# net.exe with Open Watcom v2 on Linux.
|
||||
# Maintainer mode can rebuild the new net.exe with Open Watcom. The freshly
|
||||
# built binary is only installed when MARS_NWE_INSTALL_NEW_DOSUTILS is ON, or
|
||||
# for the new-only command names in the default split install.
|
||||
|
||||
set(MARS_DOSUTILS_NET_EXE
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/net.exe"
|
||||
CACHE FILEPATH "Prebuilt DOS net.exe used for installation when MARS_NWE_BUILD_DOSUTILS is OFF"
|
||||
set(MARS_DOSUTILS_LEGACY_NET_EXE
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/netold.exe"
|
||||
CACHE FILEPATH "Legacy/pre-Client32 DOS net.exe used by default for legacy command names"
|
||||
)
|
||||
|
||||
set(MARS_DOSUTILS_PUBLIC_TOOLS
|
||||
set(MARS_DOSUTILS_NEW_NET_EXE
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/net.exe"
|
||||
CACHE FILEPATH "New/experimental DOS net.exe used for new-only tools or when MARS_NWE_INSTALL_NEW_DOSUTILS is ON"
|
||||
)
|
||||
|
||||
set(MARS_DOSUTILS_LEGACY_TOOLS
|
||||
net
|
||||
login
|
||||
profile
|
||||
@@ -23,13 +30,22 @@ set(MARS_DOSUTILS_PUBLIC_TOOLS
|
||||
map
|
||||
mapdel
|
||||
logout
|
||||
slist
|
||||
capture
|
||||
endcap
|
||||
)
|
||||
|
||||
# Do not install slist.exe yet: func_slist() is empty and SLIST is disabled in net.c.
|
||||
# Do not install tests/debug by default either; they are developer-only helpers.
|
||||
# Tools not present in netold.exe. These are installed from the new binary
|
||||
# even in the default split mode.
|
||||
set(MARS_DOSUTILS_NEW_ONLY_TOOLS
|
||||
slist
|
||||
flag
|
||||
flagdir
|
||||
rights
|
||||
grant
|
||||
revoke
|
||||
remove
|
||||
ndir
|
||||
)
|
||||
|
||||
if(MARS_NWE_BUILD_DOSUTILS)
|
||||
find_package(OpenWatcom REQUIRED)
|
||||
@@ -42,6 +58,15 @@ if(MARS_NWE_BUILD_DOSUTILS)
|
||||
login.c
|
||||
map.c
|
||||
slist.c
|
||||
ndir.c
|
||||
flag.c
|
||||
flagdir.c
|
||||
rights.c
|
||||
grant.c
|
||||
revoke.c
|
||||
remove.c
|
||||
trustee.c
|
||||
c32ncp.c
|
||||
nwcrypt.c
|
||||
nwdebug.c
|
||||
nwtests.c
|
||||
@@ -57,10 +82,39 @@ if(MARS_NWE_BUILD_DOSUTILS)
|
||||
-fo="${CMAKE_CURRENT_BINARY_DIR}/kern.obj"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/kern_wasm.asm"
|
||||
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/kern_wasm.asm"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
set(DOSUTILS_OBJECTS)
|
||||
foreach(src IN LISTS DOSUTILS_C_SOURCES)
|
||||
get_filename_component(obj_name "${src}" NAME_WE)
|
||||
set(obj "${CMAKE_CURRENT_BINARY_DIR}/${obj_name}.obj")
|
||||
list(APPEND DOSUTILS_OBJECTS "${obj}")
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT "${obj}"
|
||||
COMMAND "${CMAKE_COMMAND}" -E env ${OPENWATCOM_ENV}
|
||||
"${OPENWATCOM_WCL}"
|
||||
-q
|
||||
-zq
|
||||
-bt=dos
|
||||
-ml
|
||||
-0
|
||||
-c
|
||||
-fo="${obj}"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/${src}"
|
||||
DEPENDS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/${src}"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/net.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/kern.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/c32ncp.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/nwcrypt.h"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
VERBATIM
|
||||
)
|
||||
endforeach()
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/net.exe"
|
||||
COMMAND "${CMAKE_COMMAND}" -E env ${OPENWATCOM_ENV}
|
||||
@@ -72,15 +126,12 @@ if(MARS_NWE_BUILD_DOSUTILS)
|
||||
-0
|
||||
-k32768
|
||||
-fe="${CMAKE_CURRENT_BINARY_DIR}/net.exe"
|
||||
${DOSUTILS_C_SOURCES}
|
||||
${DOSUTILS_OBJECTS}
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/kern.obj"
|
||||
DEPENDS
|
||||
${DOSUTILS_C_SOURCES}
|
||||
${DOSUTILS_OBJECTS}
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/kern.obj"
|
||||
net.h
|
||||
kern.h
|
||||
nwcrypt.h
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
@@ -88,32 +139,80 @@ if(MARS_NWE_BUILD_DOSUTILS)
|
||||
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/net.exe"
|
||||
)
|
||||
|
||||
set(MARS_DOSUTILS_NET_EXE "${CMAKE_CURRENT_BINARY_DIR}/net.exe")
|
||||
set(MARS_DOSUTILS_BUILT_NET_EXE "${CMAKE_CURRENT_BINARY_DIR}/net.exe")
|
||||
else()
|
||||
if(NOT EXISTS "${MARS_DOSUTILS_NET_EXE}")
|
||||
message(FATAL_ERROR
|
||||
"Prebuilt DOS utility missing: ${MARS_DOSUTILS_NET_EXE}. "
|
||||
"Either commit net.exe into dosutils or configure with "
|
||||
"-DMARS_NWE_BUILD_DOSUTILS=ON and Open Watcom installed."
|
||||
)
|
||||
set(MARS_DOSUTILS_BUILT_NET_EXE "")
|
||||
endif()
|
||||
|
||||
if(MARS_NWE_BUILD_DOSUTILS)
|
||||
set(MARS_DOSUTILS_SELECTED_NEW_EXE "${MARS_DOSUTILS_BUILT_NET_EXE}")
|
||||
else()
|
||||
set(MARS_DOSUTILS_SELECTED_NEW_EXE "${MARS_DOSUTILS_NEW_NET_EXE}")
|
||||
endif()
|
||||
|
||||
if(MARS_NWE_INSTALL_NEW_DOSUTILS)
|
||||
set(MARS_DOSUTILS_SELECTED_LEGACY_EXE "${MARS_DOSUTILS_SELECTED_NEW_EXE}")
|
||||
else()
|
||||
set(MARS_DOSUTILS_SELECTED_LEGACY_EXE "${MARS_DOSUTILS_LEGACY_NET_EXE}")
|
||||
endif()
|
||||
|
||||
set(MARS_DOSUTILS_SELECTED_LEGACY_IS_BUILT FALSE)
|
||||
set(MARS_DOSUTILS_SELECTED_NEW_IS_BUILT FALSE)
|
||||
if(MARS_NWE_BUILD_DOSUTILS)
|
||||
if(MARS_DOSUTILS_SELECTED_LEGACY_EXE STREQUAL MARS_DOSUTILS_BUILT_NET_EXE)
|
||||
set(MARS_DOSUTILS_SELECTED_LEGACY_IS_BUILT TRUE)
|
||||
endif()
|
||||
if(MARS_DOSUTILS_SELECTED_NEW_EXE STREQUAL MARS_DOSUTILS_BUILT_NET_EXE)
|
||||
set(MARS_DOSUTILS_SELECTED_NEW_IS_BUILT TRUE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
foreach(tool IN LISTS MARS_DOSUTILS_PUBLIC_TOOLS)
|
||||
if(tool STREQUAL "net")
|
||||
install(FILES "${MARS_DOSUTILS_NET_EXE}"
|
||||
DESTINATION "${MARS_NWE_INSTALL_FULL_FILEDIR}/SYS/public")
|
||||
else()
|
||||
install(FILES "${MARS_DOSUTILS_NET_EXE}"
|
||||
if(MARS_NWE_INSTALL_DOSUTILS)
|
||||
if(NOT MARS_DOSUTILS_SELECTED_LEGACY_IS_BUILT AND NOT EXISTS "${MARS_DOSUTILS_SELECTED_LEGACY_EXE}")
|
||||
message(FATAL_ERROR
|
||||
"Selected legacy/default DOS utility missing: ${MARS_DOSUTILS_SELECTED_LEGACY_EXE}. "
|
||||
"Commit dosutils/netold.exe, enable MARS_NWE_INSTALL_NEW_DOSUTILS, "
|
||||
"or enable MARS_NWE_BUILD_DOSUTILS."
|
||||
)
|
||||
endif()
|
||||
|
||||
if(NOT MARS_DOSUTILS_SELECTED_NEW_IS_BUILT AND NOT EXISTS "${MARS_DOSUTILS_SELECTED_NEW_EXE}")
|
||||
message(FATAL_ERROR
|
||||
"Selected new DOS utility missing: ${MARS_DOSUTILS_SELECTED_NEW_EXE}. "
|
||||
"Commit dosutils/net.exe or enable MARS_NWE_BUILD_DOSUTILS."
|
||||
)
|
||||
endif()
|
||||
|
||||
message(STATUS "DOS legacy/default utility binary: ${MARS_DOSUTILS_SELECTED_LEGACY_EXE}")
|
||||
message(STATUS "DOS new-only utility binary: ${MARS_DOSUTILS_SELECTED_NEW_EXE}")
|
||||
|
||||
foreach(tool IN LISTS MARS_DOSUTILS_LEGACY_TOOLS)
|
||||
if(tool STREQUAL "net")
|
||||
install(FILES "${MARS_DOSUTILS_SELECTED_LEGACY_EXE}"
|
||||
DESTINATION "${MARS_NWE_INSTALL_FULL_FILEDIR}/SYS/public"
|
||||
RENAME net.exe)
|
||||
else()
|
||||
install(FILES "${MARS_DOSUTILS_SELECTED_LEGACY_EXE}"
|
||||
DESTINATION "${MARS_NWE_INSTALL_FULL_FILEDIR}/SYS/public"
|
||||
RENAME "${tool}.exe")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
foreach(tool IN LISTS MARS_DOSUTILS_NEW_ONLY_TOOLS)
|
||||
install(FILES "${MARS_DOSUTILS_SELECTED_NEW_EXE}"
|
||||
DESTINATION "${MARS_NWE_INSTALL_FULL_FILEDIR}/SYS/public"
|
||||
RENAME "${tool}.exe")
|
||||
endif()
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
install(FILES "${MARS_DOSUTILS_NET_EXE}"
|
||||
DESTINATION "${MARS_NWE_INSTALL_FULL_FILEDIR}/SYS/login"
|
||||
RENAME login.exe)
|
||||
install(FILES "${MARS_DOSUTILS_SELECTED_LEGACY_EXE}"
|
||||
DESTINATION "${MARS_NWE_INSTALL_FULL_FILEDIR}/SYS/login"
|
||||
RENAME login.exe)
|
||||
|
||||
install(FILES "${MARS_DOSUTILS_NET_EXE}"
|
||||
DESTINATION "${MARS_NWE_INSTALL_FULL_FILEDIR}/SYS/login"
|
||||
RENAME map.exe)
|
||||
install(FILES "${MARS_DOSUTILS_SELECTED_LEGACY_EXE}"
|
||||
DESTINATION "${MARS_NWE_INSTALL_FULL_FILEDIR}/SYS/login"
|
||||
RENAME map.exe)
|
||||
|
||||
install(FILES "${MARS_DOSUTILS_SELECTED_LEGACY_EXE}"
|
||||
DESTINATION "${MARS_NWE_INSTALL_FULL_FILEDIR}/SYS/login"
|
||||
RENAME slist.exe)
|
||||
endif()
|
||||
|
||||
471
README.md
471
README.md
@@ -5,9 +5,33 @@ DOS client-side utilities for **mars_nwe** and compatible NetWare-style NCP envi
|
||||
This repository contains the source for a small DOS utility suite built around a **single multi-call executable**, `net.exe`. The program can be used either as:
|
||||
|
||||
- `net <command> [args...]`, or
|
||||
- a renamed executable such as `login.exe`, `map.exe`, `capture.exe`, or `logout.exe`
|
||||
- a renamed executable such as `login.exe`, `map.exe`, `flag.exe`, `flagdir.exe`, `rights.exe`, `grant.exe`, `revoke.exe`, `remove.exe`, `capture.exe`, or `logout.exe`.
|
||||
|
||||
That design is explicit in the command table in `net.c`, and the install rules also deploy the same binary under multiple command names. The original project documentation describes it as a “simple DOS-client program to allow standard NCP network actions, mainly for mars_nwe,” and also notes that it was still incomplete at the time of writing.
|
||||
The command dispatcher lives in `net.c`, and the install rules deploy the same binary under multiple command names in `SYS:PUBLIC` and selected names in `SYS:LOGIN`.
|
||||
|
||||
## Current status
|
||||
|
||||
The tree is a modernization of the historical mars_nwe DOS utilities. It still keeps the original Borland-era style and APIs where useful, but now also has an Open Watcom/CMake build path and working DOS Client32 support for the FLAG-family and trustee/right tools.
|
||||
|
||||
Validated recently:
|
||||
|
||||
- `FLAG` file attribute read/modify through DOS Client32
|
||||
- `FLAGDIR` directory attribute read/modify through DOS Client32
|
||||
- `RIGHTS` effective-rights display through Client32 NCP87
|
||||
- `GRANT` trustee assignment for users and groups
|
||||
- `REVOKE` trustee-right removal for users and groups
|
||||
- `REMOVE` trustee deletion for users and groups
|
||||
- Novell-tool comparison for `FLAG`, including `ALL`, `N`, `RO`, `RW`, high bits, and display layout
|
||||
- Novell-tool comparison for `FLAGDIR`, including `Normal`, `System`, `Hidden`, `DeleteInhibit`, `Purge`, `RenameInhibit`, and combined attributes
|
||||
- Novell-tool comparison for `RIGHTS`, `GRANT`, `REVOKE`, and `REMOVE`
|
||||
- CMake/Open Watcom build using binary-directory object files, so `.obj`/`.o` files are no longer written into the source tree
|
||||
|
||||
Still to validate or continue:
|
||||
|
||||
- DOSX/VLM/NETX fallback behavior for `FLAG` and `FLAGDIR`
|
||||
- More complex `FLAGDIR` paths beyond the simple mapped-directory cases already tested
|
||||
- OS/2 requester/tool behavior
|
||||
- Additional Novell-like utilities such as `NDIR`, `PURGE`, and `SALVAGE`
|
||||
|
||||
## Features
|
||||
|
||||
@@ -18,7 +42,16 @@ That design is explicit in the command table in `net.c`, and the install rules a
|
||||
- Printer capture and release (`CAPTURE`, `ENDCAP`)
|
||||
- Scripted session setup through command files
|
||||
- External program execution via `SPAWN` and `EXEC`
|
||||
- Server listing through `SLIST`
|
||||
- Directory listing through `NDIR`
|
||||
- File attribute management through `FLAG`
|
||||
- Directory attribute management through `FLAGDIR`
|
||||
- Effective rights display through `RIGHTS`
|
||||
- Trustee rights assignment through `GRANT`
|
||||
- Trustee rights removal through `REVOKE`
|
||||
- Trustee assignment deletion through `REMOVE`
|
||||
- Optional mars_nwe debug control hooks
|
||||
- Developer diagnostics through `TESTS`
|
||||
|
||||
## Available commands
|
||||
|
||||
@@ -37,31 +70,71 @@ The current command dispatcher includes these built-ins:
|
||||
- `PATHDEL`
|
||||
- `CAPTURE`
|
||||
- `ENDCAP`
|
||||
- `SLIST`
|
||||
- `NDIR`
|
||||
- `FLAG`
|
||||
- `FLAGDIR`
|
||||
- `RIGHTS`
|
||||
- `GRANT`
|
||||
- `REVOKE`
|
||||
- `REMOVE`
|
||||
- `DEBUG`
|
||||
- `ECHO`
|
||||
- `CD`
|
||||
- `TESTS` (developer/testing only)
|
||||
- `TESTS` developer/testing only
|
||||
|
||||
`SLIST` is present in the historical build/install metadata, but the command is disabled in the dispatcher and the provided `slist.c` is only a stub in this source snapshot.
|
||||
The CMake install rules also install the multi-call `net.exe` under several of those command names.
|
||||
|
||||
## How it works
|
||||
|
||||
The program resolves the command from either:
|
||||
|
||||
1. the executable name itself, or
|
||||
2. the first command-line argument
|
||||
2. the first command-line argument.
|
||||
|
||||
That means all of the following styles are valid:
|
||||
|
||||
```text
|
||||
NET LOGIN alice secret
|
||||
NET MAP F:=SYS:
|
||||
NET FLAG LOGIN.EXE
|
||||
LOGIN.EXE alice secret
|
||||
MAP.EXE F:=SYS:
|
||||
FLAG.EXE LOGIN.EXE A
|
||||
CAPTURE.EXE LPT1 Q1
|
||||
```
|
||||
|
||||
This is one of the key design ideas of the project, and the original README specifically recommends copying or linking `net.exe` to `login.exe` for convenience.
|
||||
## Client32 NCP support
|
||||
|
||||
The modern Client32 path is implemented through a small reusable helper layer:
|
||||
|
||||
- `c32ncp.c`
|
||||
- `c32ncp.h`
|
||||
- Client32 assembly entry points in `kern_wasm.asm`
|
||||
|
||||
The working sequence is:
|
||||
|
||||
```text
|
||||
C32_MapVar_Probe(4,0)
|
||||
-> obtains the active connection reference
|
||||
|
||||
C32_OpenRef_Probe()
|
||||
-> opens that reference and returns a Client32 handle
|
||||
|
||||
C32_NCP87_Raw5_Probe()
|
||||
-> sends NCP 87 requests through COMPATNcpRequestReply
|
||||
```
|
||||
|
||||
This path is currently used by:
|
||||
|
||||
- `FLAG`
|
||||
- `FLAGDIR`
|
||||
- `RIGHTS`
|
||||
- `GRANT`
|
||||
- `REVOKE`
|
||||
- `REMOVE`
|
||||
|
||||
The old `Net_Call` / INT 21h requester path is kept as a fallback where appropriate, but Client32 is now preferred for the validated FLAG-family and trustee operations.
|
||||
|
||||
## Command reference
|
||||
|
||||
@@ -74,15 +147,15 @@ LOGIN [-u] [user | user password]
|
||||
```
|
||||
|
||||
- `-u` forces the older unencrypted login path.
|
||||
- If no username is provided, the tool prompts interactively.
|
||||
- If no password is provided, it prompts for one after the username.
|
||||
- Successful login clears and rebuilds NetWare search-path state before running a local post-login script named `login` from the executable directory.
|
||||
- If no username is provided, the tool prompts interactively.
|
||||
- If no password is provided, it prompts for one after the username.
|
||||
- Successful login clears and rebuilds NetWare search-path state before running a local post-login script named `login` from the executable directory.
|
||||
|
||||
### `LOGOUT`
|
||||
|
||||
Log out from the current NCP session.
|
||||
|
||||
The implementation also removes configured network search paths before performing logout.
|
||||
The implementation also removes configured network search paths before performing logout.
|
||||
|
||||
### `PASSWD`
|
||||
|
||||
@@ -92,10 +165,7 @@ Change a user password.
|
||||
PASSWD [user]
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- If no username is supplied, the tool attempts to resolve the currently logged-in user. fileciteturn1file2L162-L190
|
||||
- The source comments note that password changes currently use the older unencrypted password-change call.
|
||||
If no username is supplied, the tool attempts to resolve the currently logged-in user. The password-change code prefers the encrypted/keyed flow where available and keeps older unencrypted calls as fallback.
|
||||
|
||||
### `PROFILE`
|
||||
|
||||
@@ -105,7 +175,7 @@ Execute a command script.
|
||||
PROFILE <filename>
|
||||
```
|
||||
|
||||
This is a central part of the workflow. The command reader parses non-empty lines, ignores `#` comments, uppercases the command token, and dispatches it through the same internal command table used for direct invocation. `ECHO` is treated specially so the rest of the line is preserved as a single string.
|
||||
The command reader parses non-empty lines, ignores `#` comments, uppercases the command token, and dispatches it through the same internal command table used for direct invocation. `ECHO` is treated specially so the rest of the line is preserved as a single string.
|
||||
|
||||
### `SPAWN`
|
||||
|
||||
@@ -115,7 +185,7 @@ Run an external program and wait for it to finish.
|
||||
|
||||
Execute an external program using overlay-style execution.
|
||||
|
||||
Both commands share the same implementation and differ only in whether they use `spawnvp(..., P_WAIT, ...)` or `execvp(...)`.
|
||||
Both commands share the same implementation and differ only in whether they use `spawnvp(..., P_WAIT, ...)` or `execvp(...)`.
|
||||
|
||||
### `MAP`
|
||||
|
||||
@@ -133,7 +203,7 @@ MAP F:=SYS:
|
||||
MAP H:=HOME:
|
||||
```
|
||||
|
||||
The implementation lists active mappings, distinguishes local vs. redirected drives, and uses DOS-style drive letters.
|
||||
The implementation lists active mappings, distinguishes local vs. redirected drives, and uses DOS-style drive letters.
|
||||
|
||||
### `MAPDEL`
|
||||
|
||||
@@ -157,7 +227,7 @@ List or set a search-path entry.
|
||||
PATH sn:[=[path]]
|
||||
```
|
||||
|
||||
Where `sn` is `s1` through `s16`. The original documentation notes that this updates the path environment rather than directly creating a drive mapping.
|
||||
Where `sn` is `s1` through `s16`.
|
||||
|
||||
### `PATHINS`
|
||||
|
||||
@@ -193,7 +263,7 @@ CAPTURE LPT1 Q1
|
||||
CAPTURE PRN Q1
|
||||
```
|
||||
|
||||
`PRN` is normalized to `LPT1` internally. The command can also display existing captures.
|
||||
`PRN` is normalized to `LPT1` internally. The command can also display existing captures.
|
||||
|
||||
### `ENDCAP`
|
||||
|
||||
@@ -211,6 +281,265 @@ Example:
|
||||
ENDCAP LPT1
|
||||
```
|
||||
|
||||
### `SLIST`
|
||||
|
||||
List known NetWare file servers.
|
||||
|
||||
Typical usage:
|
||||
|
||||
```text
|
||||
SLIST [server] [/Continue]
|
||||
```
|
||||
|
||||
The current `slist.c` implementation scans bindery file server objects and prints known servers.
|
||||
|
||||
### `FLAG`
|
||||
|
||||
Display or modify NetWare DOS file attributes.
|
||||
|
||||
Typical usage:
|
||||
|
||||
```text
|
||||
FLAG file [option...]
|
||||
```
|
||||
|
||||
Examples:
|
||||
|
||||
```text
|
||||
FLAG LOGIN.EXE
|
||||
FLAG LOGIN.EXE A
|
||||
FLAG LOGIN.EXE -A
|
||||
FLAG LOGIN.EXE P T DI RI CI RA WA
|
||||
FLAG LOGIN.EXE N
|
||||
FLAG LOGIN.EXE ALL
|
||||
FLAG LOGIN.EXE RO
|
||||
FLAG LOGIN.EXE RW
|
||||
```
|
||||
|
||||
Supported attributes and aliases include:
|
||||
|
||||
- `RO`
|
||||
- `RW`
|
||||
- `S`
|
||||
- `A`
|
||||
- `H`
|
||||
- `SY`, `SYS`, `SYSTEM`
|
||||
- `T`
|
||||
- `P`
|
||||
- `RA`
|
||||
- `WA`
|
||||
- `CI`
|
||||
- `DI`
|
||||
- `RI`
|
||||
- `ALL`
|
||||
- `N` / `NORMAL`
|
||||
|
||||
The output is intentionally close to Novell FLAG formatting:
|
||||
|
||||
```text
|
||||
Ro/Rw S/- A/- - H/- Sy/-- T/- P/- Ra/-- Wa/-- CI/-- DI/-- RI/--
|
||||
```
|
||||
|
||||
The Client32 path handles both low and high NetWare attribute bits. High bits such as `P`, `DI`, `RI`, `CI`, `RA`, and `WA` must be handled as 32-bit values in 16-bit DOS builds.
|
||||
|
||||
### `FLAGDIR`
|
||||
|
||||
Display or modify NetWare directory attributes.
|
||||
|
||||
Typical usage:
|
||||
|
||||
```text
|
||||
FLAGDIR [path [option...]]
|
||||
```
|
||||
|
||||
Supported 386-style options:
|
||||
|
||||
- `Normal`
|
||||
- `System`
|
||||
- `Hidden`
|
||||
- `DeleteInhibit`
|
||||
- `Purge`
|
||||
- `RenameInhibit`
|
||||
|
||||
Examples:
|
||||
|
||||
```text
|
||||
FLAGDIR UDIR
|
||||
FLAGDIR UDIR SYSTEM
|
||||
FLAGDIR UDIR HIDDEN
|
||||
FLAGDIR UDIR DELETEINHIBIT
|
||||
FLAGDIR UDIR PURGE
|
||||
FLAGDIR UDIR RENAMEINHIBIT
|
||||
FLAGDIR UDIR NORMAL
|
||||
```
|
||||
|
||||
For simple mapped paths, the display is kept close to Novell FLAGDIR style:
|
||||
|
||||
```text
|
||||
MARS/SYS:UDIR
|
||||
UDIR System Hidden DeleteInhibit Purge RenameInhibit
|
||||
```
|
||||
|
||||
`Private` is intentionally rejected for the current NetWare 386-style path.
|
||||
|
||||
|
||||
### `RIGHTS`
|
||||
|
||||
Display effective NetWare rights for a file or directory.
|
||||
|
||||
Typical usage:
|
||||
|
||||
```text
|
||||
RIGHTS [path]
|
||||
```
|
||||
|
||||
Supported:
|
||||
|
||||
- directory paths
|
||||
- file paths
|
||||
- Novell-like display of the effective rights mask
|
||||
|
||||
Rights are shown in the traditional order:
|
||||
|
||||
```text
|
||||
S R W C E M F A
|
||||
Supervisor, Read, Write, Create, Erase, Modify, File scan, Access Control
|
||||
```
|
||||
|
||||
|
||||
### `GRANT`
|
||||
|
||||
Assign explicit trustee rights to a user or group.
|
||||
|
||||
Typical usage:
|
||||
|
||||
```text
|
||||
GRANT rightslist* [FOR path] TO [USER | GROUP] name [options]
|
||||
Options: /SubDirectories | /Files
|
||||
```
|
||||
|
||||
Examples:
|
||||
|
||||
```text
|
||||
GRANT R W C FOR UDIR TO USER MARIO
|
||||
GRANT ALL FOR UDIR TO GROUP EVERYONE /SUBDIRECTORIES
|
||||
GRANT R F FOR UDIR\*.TST TO USER MARIO /FILES
|
||||
```
|
||||
|
||||
Supported 386-style rights:
|
||||
|
||||
- `ALL`
|
||||
- `N` / `NONE`
|
||||
- `S` / `SUPERVISOR`
|
||||
- `R` / `READ`
|
||||
- `W` / `WRITE`
|
||||
- `C` / `CREATE`
|
||||
- `E` / `ERASE`
|
||||
- `M` / `MODIFY`
|
||||
- `F` / `FILESCAN`
|
||||
- `A` / `ACCESS CONTROL`
|
||||
|
||||
For Novell compatibility, `ALL` grants the normal trustee rights (`RWCEMFA`) and does not imply Supervisor; use `S` explicitly when Supervisor rights are intended.
|
||||
|
||||
### `REVOKE`
|
||||
|
||||
Remove selected rights from an explicit trustee assignment.
|
||||
|
||||
Typical usage:
|
||||
|
||||
```text
|
||||
REVOKE rightslist* [FOR path] FROM [USER|GROUP] name [options]
|
||||
Options: /SubDirectories | /Files
|
||||
```
|
||||
|
||||
Examples:
|
||||
|
||||
```text
|
||||
REVOKE W M FOR UDIR FROM USER MARIO
|
||||
REVOKE R W FOR UDIR\*.TST FROM GROUP EVERYONE /FILES
|
||||
REVOKE W C FOR UDIR FROM USER MARIO /SUBDIRECTORIES
|
||||
```
|
||||
|
||||
`REVOKE` scans the explicit trustee assignment first, subtracts the requested rights, and deletes the trustee entry when no rights remain. Missing trustee entries are reported in Novell style:
|
||||
|
||||
```text
|
||||
No trustee for the specified directory.
|
||||
No trustee for the specified file.
|
||||
```
|
||||
|
||||
### `REMOVE`
|
||||
|
||||
Delete an explicit trustee assignment for a user or group.
|
||||
|
||||
Typical usage:
|
||||
|
||||
```text
|
||||
REMOVE [USER | GROUP] name [FROM path] [option]
|
||||
Options: /Subdirs | /Files
|
||||
```
|
||||
|
||||
Examples:
|
||||
|
||||
```text
|
||||
REMOVE USER MARIO FROM UDIR
|
||||
REMOVE GROUP EVERYONE FROM UDIR /SUBDIRS
|
||||
REMOVE USER MARIO FROM UDIR\*.TST /FILES
|
||||
```
|
||||
|
||||
If `USER` or `GROUP` is omitted, the tool tries to resolve the name as a user first and then as a group. Successful multi-object operations print Novell-style summaries such as:
|
||||
|
||||
```text
|
||||
Trustee "MARIO" removed from 4 directories.
|
||||
Trustee "MARIO" removed from 2 files.
|
||||
```
|
||||
|
||||
|
||||
|
||||
### `NDIR`
|
||||
|
||||
List files and directories in a NetWare-style format.
|
||||
|
||||
Typical usage:
|
||||
|
||||
```text
|
||||
NDIR [path] [/option...]
|
||||
```
|
||||
|
||||
The implementation supports basic DOS namespace listings, wildcards,
|
||||
paging, first rights and dates displays, and these options:
|
||||
|
||||
- `/FO` or `FO` for files only
|
||||
- `/DO` or `DO` for directories only
|
||||
- `/CONTINUOUS`, `/CONTINUE`, or `/C` for continuous output
|
||||
- `/RIGHTS` for a first effective-rights display
|
||||
- `/DATES` for Novell-style date columns with current DOS timestamp data
|
||||
- `/SUB` or `/SUBDIRECTORIES` for recursive directory listings
|
||||
- `/SHORT` or `/BRIEF` for compact output, useful with `/SUB`
|
||||
- `/HELP` for Novell-style usage text
|
||||
|
||||
Examples:
|
||||
|
||||
```text
|
||||
NDIR
|
||||
NDIR *.EXE
|
||||
NDIR PUBLIC\*.EXE
|
||||
NDIR PUBLIC /DO
|
||||
NDIR PUBLIC\*.EXE /FO /CONTINUOUS
|
||||
NDIR PUBLIC /RIGHTS
|
||||
NDIR PUBLIC /DATES
|
||||
NDIR PUBLIC /SUB
|
||||
NDIR PUBLIC /SUB /SHORT
|
||||
NDIR PUBLIC /DO
|
||||
```
|
||||
|
||||
The first version intentionally focuses on the common listing path. More
|
||||
advanced Novell NDIR features such as sorting and restrictions are accepted
|
||||
only as future compatibility points or will be implemented in later revisions. The `/RIGHTS` display uses NCP87 information for inherited rights and
|
||||
Client32 effective-rights calls for effective rights. The `/DATES` display
|
||||
uses NCP87 DOS info fields when available and falls back to DOS findfirst
|
||||
timestamps otherwise.
|
||||
|
||||
|
||||
### `DEBUG`
|
||||
|
||||
Set mars_nwe debug levels for selected server-side modules.
|
||||
@@ -219,24 +548,34 @@ Set mars_nwe debug levels for selected server-side modules.
|
||||
DEBUG NCPSERV|NWCONN|NWBIND level
|
||||
```
|
||||
|
||||
- `level` must be between `0` and `99`.
|
||||
- The original docs say this requires `FUNC_17_02_IS_DEBUG` to be enabled in `mars_nwe/config.h`.
|
||||
- `level` must be between `0` and `99`.
|
||||
- This requires the matching mars_nwe server-side debug call to be enabled.
|
||||
|
||||
### `ECHO`
|
||||
|
||||
Print a string, mainly for use inside profile/login scripts.
|
||||
Print a string, mainly for use inside profile/login scripts.
|
||||
|
||||
### `CD`
|
||||
|
||||
Change the current DOS directory. It also adjusts the active drive if a drive-qualified path is supplied.
|
||||
Change the current DOS directory. It also adjusts the active drive if a drive-qualified path is supplied.
|
||||
|
||||
### `TESTS`
|
||||
|
||||
Internal developer test routines. Not intended as a regular end-user command.
|
||||
Internal developer test routines. Not intended as a regular end-user command.
|
||||
|
||||
The currently useful Client32 test is:
|
||||
|
||||
```text
|
||||
TESTS NCP87C32ATTR
|
||||
```
|
||||
|
||||
It verifies the working Client32 NCP87 attribute path.
|
||||
|
||||
## Login script workflow
|
||||
|
||||
A particularly important feature is the automatic execution of a file named `login` located beside the executable after a successful login. The historical README gives this example:
|
||||
A particularly important feature is the automatic execution of a file named `login` located beside the executable after a successful login.
|
||||
|
||||
Example:
|
||||
|
||||
```text
|
||||
map f:=SYS:
|
||||
@@ -247,13 +586,13 @@ capture lpt1 q1
|
||||
profile h:\profile
|
||||
```
|
||||
|
||||
This makes the tool suite useful not just for authentication, but for setting up a full DOS network session: drive mappings, search paths, printer capture, and then a user-specific profile script.
|
||||
This makes the tool suite useful not just for authentication, but for setting up a full DOS network session: drive mappings, search paths, printer capture, and then a user-specific profile script.
|
||||
|
||||
## Building
|
||||
|
||||
### Historical DOS build
|
||||
|
||||
The included `makefile.bcc` is the primary historical build file and targets **Borland C / Borland tools** on DOS.
|
||||
The included `makefile.bcc` is the primary historical build file and targets Borland C / Borland tools on DOS.
|
||||
|
||||
Key settings from the makefile:
|
||||
|
||||
@@ -264,29 +603,42 @@ Key settings from the makefile:
|
||||
- define: `-Dmsdos`
|
||||
- output: `net.exe`
|
||||
|
||||
The object list includes:
|
||||
The historical object list includes the original C sources plus `kern.asm`.
|
||||
|
||||
- `net.c`
|
||||
- `tools.c`
|
||||
- `netcall.c`
|
||||
- `ncpcall.c`
|
||||
- `login.c`
|
||||
- `map.c`
|
||||
- `slist.c`
|
||||
- `nwcrypt.c`
|
||||
- `nwdebug.c`
|
||||
- `nwtests.c`
|
||||
- `capture.c`
|
||||
- `kern.asm`
|
||||
### CMake / Open Watcom maintainer build
|
||||
|
||||
The modern CMake build can rebuild `net.exe` with Open Watcom v2 on Linux.
|
||||
|
||||
### CMake status
|
||||
Configure with:
|
||||
|
||||
A `CMakeLists.txt` is present, but in this snapshot it is only a **partial modern build description**. It defines include paths, version-related macros, and install rules, while the actual `add_executable(...)` line is still commented out. That means it is better understood as packaging metadata than a ready-to-use complete build system.
|
||||
```bash
|
||||
cmake -S . -B build -DMARS_NWE_BUILD_DOSUTILS=ON
|
||||
cmake --build build
|
||||
```
|
||||
|
||||
The CMake build:
|
||||
|
||||
- assembles `kern_wasm.asm` with `wasm`
|
||||
- compiles each C file to a binary-directory `.obj`
|
||||
- links `net.exe` from those binary-directory objects
|
||||
- keeps `.obj`/`.o` intermediate files out of the source directory
|
||||
|
||||
If old object files were produced in the source tree by an earlier build, remove them once:
|
||||
|
||||
```bash
|
||||
cd dosutils
|
||||
rm -f *.o *.obj
|
||||
```
|
||||
|
||||
### Default install behavior
|
||||
|
||||
When `MARS_NWE_BUILD_DOSUTILS` is disabled, CMake installs a prebuilt `net.exe` from the source tree.
|
||||
|
||||
That keeps the normal mars_nwe build independent from Open Watcom. Maintainers can enable the Open Watcom build only when they want to regenerate the DOS binary.
|
||||
|
||||
## Installation layout
|
||||
|
||||
The CMake install rules deploy the same binary multiple times into `SYS/public`:
|
||||
The install rules deploy the same binary multiple times into `SYS/public`, including:
|
||||
|
||||
- `net.exe`
|
||||
- `login.exe`
|
||||
@@ -300,19 +652,39 @@ The CMake install rules deploy the same binary multiple times into `SYS/public`:
|
||||
- `mapdel.exe`
|
||||
- `logout.exe`
|
||||
- `slist.exe`
|
||||
- `ndir.exe`
|
||||
- `flag.exe`
|
||||
- `flagdir.exe`
|
||||
- `rights.exe`
|
||||
- `grant.exe`
|
||||
- `revoke.exe`
|
||||
- `remove.exe`
|
||||
- `capture.exe`
|
||||
- `endcap.exe`
|
||||
|
||||
They also install minimal `login.exe` and `map.exe` copies into `SYS/login`.
|
||||
They also install selected copies such as `login.exe`, `map.exe`, and `slist.exe` into `SYS/login` where appropriate.
|
||||
|
||||
## Development notes
|
||||
|
||||
- `kern_wasm.asm` is the 16-bit Open Watcom assembly implementation used by the modern build.
|
||||
- `kern.c` was an experimental C-side test wrapper and is no longer required by the current Client32 FLAG/FLAGDIR path.
|
||||
- `c32ncp.c` and `c32ncp.h` contain reusable Client32 NCP helper functions for DOS tools.
|
||||
- `trustee.c` and `trustee.h` contain shared code for `GRANT`, `REVOKE`, and `REMOVE`.
|
||||
- `tools.c` contains shared command/frontend helpers so future smaller multicall binaries can reuse common parsing and path code.
|
||||
- The verified Client32 path uses NCP 87 subfunction 6 for obtaining DOS information, subfunction 7 for modifying DOS information, subfunction 29 for effective rights, and trustee scan/add/delete calls for the trustee tools.
|
||||
- For modify operations, use the modify information mask `DM_ATTRIBUTES` (`0x00000002`) rather than the read-side `RIM_ATTRIBUTES` mask.
|
||||
- High NetWare attributes must be stored and displayed as 32-bit values even in 16-bit DOS builds.
|
||||
|
||||
## Project status and limitations
|
||||
|
||||
This is legacy DOS networking code from the mid-1990s, and a few caveats are worth keeping in mind:
|
||||
|
||||
- The original README explicitly says the program was still incomplete.
|
||||
- `SLIST` is not implemented in the provided source snapshot.
|
||||
- Parts of the authentication and password-change path still rely on older unencrypted operations when the newer keyed flow is unavailable or disabled.
|
||||
- The code is tightly coupled to DOS, IPX/NCP behavior, and mars_nwe-specific expectations.
|
||||
- The code is tightly coupled to DOS, IPX/NCP behavior, and mars_nwe/NetWare requester semantics.
|
||||
- Client32 support has been validated for the FLAG-family and trustee/right tools, but not yet generalized to every command.
|
||||
- DOSX/VLM/NETX fallback testing is still pending.
|
||||
- `FLAGDIR` currently focuses on the NetWare 386-style attributes and simple mapped directory paths.
|
||||
- OS/2 requester behavior is still future work.
|
||||
- Some authentication and password-change paths still keep older calls as compatibility fallbacks.
|
||||
|
||||
## Historical metadata
|
||||
|
||||
@@ -325,7 +697,6 @@ From the included project metadata:
|
||||
- platforms: `DOS`, `DOSEMU`
|
||||
- author/maintainer: Martin Stover
|
||||
|
||||
|
||||
## License
|
||||
|
||||
No standalone license file is included in the provided snapshot. The source files do contain copyright notices naming **Martin Stover**. Anyone planning to redistribute or modernize the project should verify licensing status before publishing derivative releases.
|
||||
No standalone license file is included in the provided snapshot. The source files do contain copyright notices naming Martin Stover. Anyone planning to redistribute or modernize the project should verify licensing status before publishing derivative releases.
|
||||
|
||||
892
c32ncp.c
Normal file
892
c32ncp.c
Normal file
@@ -0,0 +1,892 @@
|
||||
#include "net.h"
|
||||
#include "c32ncp.h"
|
||||
|
||||
/* c32ncp.c - Client32 NCP helpers for mars-dosutils */
|
||||
static void c32_put_word_lh(uint8 *p, uint16 v)
|
||||
{
|
||||
p[0] = (uint8)(v & 0xff);
|
||||
p[1] = (uint8)((v >> 8) & 0xff);
|
||||
}
|
||||
|
||||
static void c32_put_dword_lh(uint8 *p, uint32 v)
|
||||
{
|
||||
p[0] = (uint8)(v & 0xff);
|
||||
p[1] = (uint8)((v >> 8) & 0xff);
|
||||
p[2] = (uint8)((v >> 16) & 0xff);
|
||||
p[3] = (uint8)((v >> 24) & 0xff);
|
||||
}
|
||||
|
||||
static void c32_put_dword_hl(uint8 *p, uint32 v)
|
||||
{
|
||||
p[0] = (uint8)((v >> 24) & 0xff);
|
||||
p[1] = (uint8)((v >> 16) & 0xff);
|
||||
p[2] = (uint8)((v >> 8) & 0xff);
|
||||
p[3] = (uint8)(v & 0xff);
|
||||
}
|
||||
|
||||
static uint16 c32_get_word_lh(uint8 *p)
|
||||
{
|
||||
return((uint16)(p[0] | ((uint16)p[1] << 8)));
|
||||
}
|
||||
|
||||
static uint32 c32_get_dword_lh(uint8 *p)
|
||||
{
|
||||
return((uint32)p[0] |
|
||||
((uint32)p[1] << 8) |
|
||||
((uint32)p[2] << 16) |
|
||||
((uint32)p[3] << 24));
|
||||
}
|
||||
|
||||
static uint32 c32_get_dword_hl(uint8 *p)
|
||||
{
|
||||
return(((uint32)p[0] << 24) |
|
||||
((uint32)p[1] << 16) |
|
||||
((uint32)p[2] << 8) |
|
||||
(uint32)p[3]);
|
||||
}
|
||||
|
||||
static UI c32_build_handle_path(uint8 *buf, uint8 dhandle,
|
||||
uint16 dirbase, uint8 style,
|
||||
int count,
|
||||
const char *c1, const char *c2, const char *c3)
|
||||
{
|
||||
uint8 *p;
|
||||
int l;
|
||||
UI used;
|
||||
|
||||
/*
|
||||
* DeveloperNet/ncpdos16 path structure used by NCP87/S6 through
|
||||
* Client32 COMPATNcpRequestReply.
|
||||
*
|
||||
* This is the exact shape verified by TESTS NCP87C32AUTO:
|
||||
* 00 02 00 00 00 00 01 09 4C 4F 47 49 4E 2E 45 58 45
|
||||
*
|
||||
* Meaning:
|
||||
* word[1] = short dir handle
|
||||
* word[3] = dir base
|
||||
* byte[5] = dirstyle
|
||||
* byte[6] = component count
|
||||
* then len/name components
|
||||
*
|
||||
* The old/simple struct used by the INT 21h F257 fallback is not accepted
|
||||
* by this Client32 path.
|
||||
*/
|
||||
memset(buf, 0, 0x140);
|
||||
|
||||
if (dhandle) {
|
||||
c32_put_word_lh(buf + 1, (uint16)dhandle);
|
||||
c32_put_word_lh(buf + 3, dirbase);
|
||||
buf[5] = style;
|
||||
} else {
|
||||
buf[5] = 0xff;
|
||||
}
|
||||
|
||||
p = buf + 6;
|
||||
*p++ = (uint8)count;
|
||||
|
||||
if (count > 0 && c1) {
|
||||
l = strlen(c1);
|
||||
if (l > 255) l = 255;
|
||||
*p++ = (uint8)l;
|
||||
memcpy(p, c1, l);
|
||||
p += l;
|
||||
}
|
||||
|
||||
if (count > 1 && c2) {
|
||||
l = strlen(c2);
|
||||
if (l > 255) l = 255;
|
||||
*p++ = (uint8)l;
|
||||
memcpy(p, c2, l);
|
||||
p += l;
|
||||
}
|
||||
|
||||
if (count > 2 && c3) {
|
||||
l = strlen(c3);
|
||||
if (l > 255) l = 255;
|
||||
*p++ = (uint8)l;
|
||||
memcpy(p, c3, l);
|
||||
p += l;
|
||||
}
|
||||
|
||||
used = (UI)(p - buf);
|
||||
c32_put_word_lh(buf + 0x13c, used);
|
||||
return(used);
|
||||
}
|
||||
|
||||
|
||||
static UI c32_build_handle_path_from_dos_path(uint8 *buf, uint8 dhandle,
|
||||
uint16 dirbase, uint8 style,
|
||||
const char *dospath)
|
||||
{
|
||||
uint8 *p;
|
||||
uint8 *countp;
|
||||
int count = 0;
|
||||
const char *s;
|
||||
UI used;
|
||||
|
||||
memset(buf, 0, 0x140);
|
||||
|
||||
if (dhandle) {
|
||||
c32_put_word_lh(buf + 1, (uint16)dhandle);
|
||||
c32_put_word_lh(buf + 3, dirbase);
|
||||
buf[5] = style;
|
||||
} else {
|
||||
buf[5] = 0xff;
|
||||
}
|
||||
|
||||
p = buf + 6;
|
||||
countp = p++;
|
||||
|
||||
s = dospath;
|
||||
if (!s) s = "";
|
||||
|
||||
/*
|
||||
* DOS tools mostly pass relative paths against the current directory
|
||||
* handle. Accept simple DOS decoration here so RIGHTS can pass "." or
|
||||
* ".\\UDIR\\FILE" without constructing path components in the caller.
|
||||
*/
|
||||
if (s[0] && s[1] == ':')
|
||||
s += 2;
|
||||
|
||||
while (*s == '\\' || *s == '/')
|
||||
s++;
|
||||
|
||||
while (*s && p < buf + 0x138 && count < 32) {
|
||||
const char *start;
|
||||
int len;
|
||||
|
||||
while (*s == '\\' || *s == '/')
|
||||
s++;
|
||||
|
||||
if (*s == '.'
|
||||
&& (s[1] == '\0' || s[1] == '\\' || s[1] == '/')) {
|
||||
s++;
|
||||
continue;
|
||||
}
|
||||
|
||||
start = s;
|
||||
while (*s && *s != '\\' && *s != '/')
|
||||
s++;
|
||||
|
||||
len = (int)(s - start);
|
||||
if (len <= 0)
|
||||
continue;
|
||||
|
||||
if (len > 255)
|
||||
len = 255;
|
||||
|
||||
if (p + 1 + len >= buf + 0x138)
|
||||
break;
|
||||
|
||||
*p++ = (uint8)len;
|
||||
memcpy(p, start, len);
|
||||
p += len;
|
||||
count++;
|
||||
}
|
||||
|
||||
*countp = (uint8)count;
|
||||
|
||||
used = (UI)(p - buf);
|
||||
c32_put_word_lh(buf + 0x13c, used);
|
||||
return(used);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Current verified Client32 path for mars-nwe DOS utilities:
|
||||
*
|
||||
* C32_MapVar_Probe(4,0) -> connRefLocal FFFF:FFFE
|
||||
* C32_OpenRef_Probe(connRefLocal) -> Client32 handle, e.g. 0101:0001
|
||||
*
|
||||
* C32_MapVar_Probe currently contains the confirmed Mars server-name scan
|
||||
* shape. It is intentionally kept small and isolated here so FLAG and later
|
||||
* tools do not carry the old exploratory tests.
|
||||
*/
|
||||
int c32_get_ncp_handle(uint16 *handle_lo, uint16 *handle_hi)
|
||||
{
|
||||
uint8 mapout[32];
|
||||
uint8 openout[32];
|
||||
uint16 map_ret_ax, map_ret_dx;
|
||||
uint16 cref_lo, cref_hi;
|
||||
uint16 open_ret_ax, open_ret_dx;
|
||||
|
||||
if (!handle_lo || !handle_hi)
|
||||
return(1);
|
||||
|
||||
*handle_lo = 0;
|
||||
*handle_hi = 0;
|
||||
|
||||
memset(mapout, 0, sizeof(mapout));
|
||||
C32_MapVar_Probe(4, 0, mapout);
|
||||
|
||||
map_ret_ax = c32_get_word_lh(mapout + 14);
|
||||
map_ret_dx = c32_get_word_lh(mapout + 16);
|
||||
cref_lo = c32_get_word_lh(mapout + 22);
|
||||
cref_hi = c32_get_word_lh(mapout + 24);
|
||||
|
||||
if (map_ret_ax != 0 || map_ret_dx != 0 || (cref_lo == 0 && cref_hi == 0))
|
||||
return(2);
|
||||
|
||||
memset(openout, 0, sizeof(openout));
|
||||
C32_OpenRef_Probe(cref_lo, cref_hi, openout);
|
||||
|
||||
open_ret_ax = c32_get_word_lh(openout + 14);
|
||||
open_ret_dx = c32_get_word_lh(openout + 16);
|
||||
*handle_lo = c32_get_word_lh(openout + 18);
|
||||
*handle_hi = c32_get_word_lh(openout + 20);
|
||||
|
||||
if (open_ret_ax != 0 || open_ret_dx != 0 || (*handle_lo == 0 && *handle_hi == 0))
|
||||
return(3);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int c32_ncp87_obtain_rim_attributes(const char *name,
|
||||
uint16 dir_handle,
|
||||
uint32 *attr_out,
|
||||
uint16 *actual_out,
|
||||
uint16 *handle_lo_out,
|
||||
uint16 *handle_hi_out)
|
||||
{
|
||||
uint16 handle_lo, handle_hi;
|
||||
uint8 hdr[16];
|
||||
uint8 path[0x140];
|
||||
uint8 rep0[0x60];
|
||||
uint8 rep1[0x110];
|
||||
uint8 rawout[32];
|
||||
uint16 raw_ret_ax, raw_ret_dx;
|
||||
uint16 actual_lo;
|
||||
int path_len;
|
||||
int rc;
|
||||
|
||||
if (!name || !attr_out)
|
||||
return(1);
|
||||
|
||||
*attr_out = 0;
|
||||
if (actual_out) *actual_out = 0;
|
||||
if (handle_lo_out) *handle_lo_out = 0;
|
||||
if (handle_hi_out) *handle_hi_out = 0;
|
||||
|
||||
rc = c32_get_ncp_handle(&handle_lo, &handle_hi);
|
||||
if (rc)
|
||||
return(10 + rc);
|
||||
|
||||
memset(hdr, 0, sizeof(hdr));
|
||||
hdr[0] = 6; /* NCP87 subfunction 6 */
|
||||
hdr[1] = 0; /* source namespace DOS */
|
||||
hdr[2] = 0; /* target namespace DOS */
|
||||
c32_put_word_lh(hdr + 3, 0x0006); /* SA_ALL */
|
||||
c32_put_dword_lh(hdr + 5, 0x00000004UL); /* RIM_ATTRIBUTES */
|
||||
|
||||
path_len = c32_build_handle_path(path, (uint8)dir_handle, 0, 0, 1,
|
||||
name, NULL, NULL);
|
||||
|
||||
memset(rep0, 0, sizeof(rep0));
|
||||
memset(rep1, 0, sizeof(rep1));
|
||||
memset(rawout, 0, sizeof(rawout));
|
||||
|
||||
C32_NCP87_Raw5_Probe(handle_lo, handle_hi,
|
||||
hdr, 9,
|
||||
path, (UI)path_len,
|
||||
rep0, 0x4d,
|
||||
rep1, 0x100,
|
||||
rawout);
|
||||
|
||||
raw_ret_ax = c32_get_word_lh(rawout + 14);
|
||||
raw_ret_dx = c32_get_word_lh(rawout + 16);
|
||||
actual_lo = c32_get_word_lh(rawout + 18);
|
||||
|
||||
if (raw_ret_ax != 0 || raw_ret_dx != 0)
|
||||
return(20);
|
||||
|
||||
/*
|
||||
* Verified reply layout for RIM_ATTRIBUTES:
|
||||
* REP0+4 little-endian dword = DOS attributes
|
||||
* Example LOGIN.EXE: 20h archive.
|
||||
*/
|
||||
*attr_out = c32_get_dword_lh(rep0 + 4);
|
||||
|
||||
if (actual_out) *actual_out = actual_lo;
|
||||
if (handle_lo_out) *handle_lo_out = handle_lo;
|
||||
if (handle_hi_out) *handle_hi_out = handle_hi;
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
int c32_ncp87_obtain_ndir_info(const char *path_name,
|
||||
uint16 dir_handle,
|
||||
C32_NDIR_INFO *info_out,
|
||||
uint16 *actual_out,
|
||||
uint16 *handle_lo_out,
|
||||
uint16 *handle_hi_out)
|
||||
{
|
||||
uint16 handle_lo, handle_hi;
|
||||
uint8 hdr[16];
|
||||
uint8 path[0x140];
|
||||
uint8 rep0[0x180];
|
||||
uint8 rep1[0x40];
|
||||
uint8 rawout[32];
|
||||
uint16 raw_ret_ax, raw_ret_dx;
|
||||
uint16 actual_lo;
|
||||
UI path_len;
|
||||
int rc;
|
||||
int namelen;
|
||||
|
||||
if (!info_out)
|
||||
return(1);
|
||||
|
||||
memset(info_out, 0, sizeof(*info_out));
|
||||
if (actual_out) *actual_out = 0;
|
||||
if (handle_lo_out) *handle_lo_out = 0;
|
||||
if (handle_hi_out) *handle_hi_out = 0;
|
||||
|
||||
rc = c32_get_ncp_handle(&handle_lo, &handle_hi);
|
||||
if (rc)
|
||||
return(10 + rc);
|
||||
|
||||
/*
|
||||
* NCP87 subfunction 6: Obtain File or Subdirectory Information.
|
||||
*
|
||||
* This asks for the classic DOS info block (RIM_ALL). ncpfs' old
|
||||
* nw_info_struct layout is:
|
||||
* +00 space allocated
|
||||
* +04 attributes
|
||||
* +20 creation time/date/id
|
||||
* +28 modify time/date/id
|
||||
* +36 last access date
|
||||
* +38 archive time/date/id
|
||||
* +46 inherited rights mask
|
||||
* +48 directory numbers
|
||||
* +76 name length/name
|
||||
*/
|
||||
memset(hdr, 0, sizeof(hdr));
|
||||
hdr[0] = 6; /* NCP87 subfunction 6 */
|
||||
hdr[1] = 0; /* source namespace DOS */
|
||||
hdr[2] = 0; /* target namespace DOS */
|
||||
c32_put_word_lh(hdr + 3, 0x0006); /* SA_ALL */
|
||||
c32_put_dword_lh(hdr + 5, 0x00000FFFUL); /* RIM_ALL */
|
||||
|
||||
path_len = c32_build_handle_path_from_dos_path(path, (uint8)dir_handle,
|
||||
0, 0, path_name);
|
||||
|
||||
memset(rep0, 0, sizeof(rep0));
|
||||
memset(rep1, 0, sizeof(rep1));
|
||||
memset(rawout, 0, sizeof(rawout));
|
||||
|
||||
C32_NCP87_Raw5_Probe(handle_lo, handle_hi,
|
||||
hdr, 9,
|
||||
path, path_len,
|
||||
rep0, sizeof(rep0),
|
||||
rep1, sizeof(rep1),
|
||||
rawout);
|
||||
|
||||
raw_ret_ax = c32_get_word_lh(rawout + 14);
|
||||
raw_ret_dx = c32_get_word_lh(rawout + 16);
|
||||
actual_lo = c32_get_word_lh(rawout + 18);
|
||||
|
||||
if (actual_out) *actual_out = actual_lo;
|
||||
if (handle_lo_out) *handle_lo_out = handle_lo;
|
||||
if (handle_hi_out) *handle_hi_out = handle_hi;
|
||||
|
||||
if (raw_ret_ax != 0 || raw_ret_dx != 0)
|
||||
return(20);
|
||||
|
||||
info_out->space_allocated = c32_get_dword_lh(rep0 + 0);
|
||||
info_out->attributes = c32_get_dword_lh(rep0 + 4);
|
||||
info_out->flags = c32_get_word_lh(rep0 + 8);
|
||||
info_out->data_size = c32_get_dword_lh(rep0 + 10);
|
||||
info_out->total_size = c32_get_dword_lh(rep0 + 14);
|
||||
info_out->number_of_streams = c32_get_word_lh(rep0 + 18);
|
||||
info_out->creation_time = c32_get_word_lh(rep0 + 20);
|
||||
info_out->creation_date = c32_get_word_lh(rep0 + 22);
|
||||
info_out->creator_id = c32_get_dword_hl(rep0 + 24);
|
||||
info_out->modify_time = c32_get_word_lh(rep0 + 28);
|
||||
info_out->modify_date = c32_get_word_lh(rep0 + 30);
|
||||
info_out->modifier_id = c32_get_dword_hl(rep0 + 32);
|
||||
info_out->last_access_date = c32_get_word_lh(rep0 + 36);
|
||||
info_out->archive_time = c32_get_word_lh(rep0 + 38);
|
||||
info_out->archive_date = c32_get_word_lh(rep0 + 40);
|
||||
info_out->archiver_id = c32_get_dword_hl(rep0 + 42);
|
||||
info_out->inherited_rights = c32_get_word_lh(rep0 + 46);
|
||||
info_out->dir_ent_num = c32_get_dword_lh(rep0 + 48);
|
||||
info_out->dos_dir_num = c32_get_dword_lh(rep0 + 52);
|
||||
info_out->vol_number = c32_get_dword_lh(rep0 + 56);
|
||||
info_out->ea_data_size = c32_get_dword_lh(rep0 + 60);
|
||||
info_out->ea_key_count = c32_get_dword_lh(rep0 + 64);
|
||||
info_out->ea_key_size = c32_get_dword_lh(rep0 + 68);
|
||||
info_out->ns_creator = c32_get_dword_lh(rep0 + 72);
|
||||
|
||||
namelen = rep0[76];
|
||||
if (namelen > 255)
|
||||
namelen = 255;
|
||||
info_out->name_len = (uint8)namelen;
|
||||
memcpy(info_out->name, rep0 + 77, namelen);
|
||||
info_out->name[namelen] = '\0';
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int c32_ncp87_modify_dos_attributes(char *name,
|
||||
uint16 dir_handle,
|
||||
uint32 attrs,
|
||||
uint16 *actual_out,
|
||||
uint16 *handle_lo_out,
|
||||
uint16 *handle_hi_out)
|
||||
{
|
||||
uint16 handle_lo, handle_hi;
|
||||
uint8 modbuf[64];
|
||||
uint8 path[0x140];
|
||||
uint8 rep0[0x20];
|
||||
uint8 rep1[0x20];
|
||||
uint8 rawout[32];
|
||||
uint8 *p;
|
||||
UI mod_len;
|
||||
UI path_len;
|
||||
uint16 raw_ret_ax, raw_ret_dx;
|
||||
uint16 actual_lo;
|
||||
int rc;
|
||||
|
||||
if (!name)
|
||||
return(1);
|
||||
|
||||
if (actual_out)
|
||||
*actual_out = 0;
|
||||
if (handle_lo_out)
|
||||
*handle_lo_out = 0;
|
||||
if (handle_hi_out)
|
||||
*handle_hi_out = 0;
|
||||
|
||||
rc = c32_get_ncp_handle(&handle_lo, &handle_hi);
|
||||
if (rc)
|
||||
return(10 + rc);
|
||||
|
||||
/*
|
||||
* NCP 87 subfunction 7: Modify DOS information.
|
||||
*
|
||||
* First request fragment contains the fixed header and DOS info structure.
|
||||
* Second request fragment contains the verified SDK-style path structure.
|
||||
*
|
||||
* This avoids the old INT 21h F257 modify path, which can hang under DOS
|
||||
* Client32 for high FLAG bits such as Transactional.
|
||||
*/
|
||||
memset(modbuf, 0, sizeof(modbuf));
|
||||
p = modbuf;
|
||||
|
||||
*p++ = 7; /* subfunction: modify DOS info */
|
||||
*p++ = 0; /* namespace DOS */
|
||||
*p++ = 0; /* reserved */
|
||||
c32_put_word_lh(p, 0x0006); p += 2; /* SA_ALL */
|
||||
c32_put_dword_lh(p, 0x00000002UL); p += 4; /* DM_ATTRIBUTES: attributes */
|
||||
|
||||
c32_put_dword_lh(p, attrs); p += 4; /* Attributes */
|
||||
memset(p, 0, 34); p += 34; /* rest of DOS info */
|
||||
mod_len = (UI)(p - modbuf);
|
||||
|
||||
path_len = c32_build_handle_path(path, (uint8)dir_handle, 0, 0, 1,
|
||||
name, NULL, NULL);
|
||||
|
||||
memset(rep0, 0, sizeof(rep0));
|
||||
memset(rep1, 0, sizeof(rep1));
|
||||
memset(rawout, 0, sizeof(rawout));
|
||||
|
||||
C32_NCP87_Raw5_Probe(handle_lo, handle_hi,
|
||||
modbuf, mod_len,
|
||||
path, path_len,
|
||||
rep0, sizeof(rep0),
|
||||
rep1, sizeof(rep1),
|
||||
rawout);
|
||||
|
||||
raw_ret_ax = c32_get_word_lh(rawout + 14);
|
||||
raw_ret_dx = c32_get_word_lh(rawout + 16);
|
||||
actual_lo = c32_get_word_lh(rawout + 18);
|
||||
|
||||
if (actual_out)
|
||||
*actual_out = actual_lo;
|
||||
if (handle_lo_out)
|
||||
*handle_lo_out = handle_lo;
|
||||
if (handle_hi_out)
|
||||
*handle_hi_out = handle_hi;
|
||||
|
||||
if (raw_ret_ax != 0 || raw_ret_dx != 0)
|
||||
return(20);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
int c32_ncp87_get_effective_rights(const char *path_name,
|
||||
uint16 dir_handle,
|
||||
uint16 *rights_out,
|
||||
uint16 *actual_out,
|
||||
uint16 *handle_lo_out,
|
||||
uint16 *handle_hi_out)
|
||||
{
|
||||
uint16 handle_lo, handle_hi;
|
||||
uint8 hdr[16];
|
||||
uint8 path[0x140];
|
||||
uint8 rep0[0x20];
|
||||
uint8 rep1[0x20];
|
||||
uint8 rawout[32];
|
||||
uint16 raw_ret_ax, raw_ret_dx;
|
||||
uint16 actual_lo;
|
||||
uint16 rights0;
|
||||
uint16 rights4;
|
||||
UI path_len;
|
||||
int rc;
|
||||
|
||||
if (!rights_out)
|
||||
return(1);
|
||||
|
||||
*rights_out = 0;
|
||||
if (actual_out) *actual_out = 0;
|
||||
if (handle_lo_out) *handle_lo_out = 0;
|
||||
if (handle_hi_out) *handle_hi_out = 0;
|
||||
|
||||
rc = c32_get_ncp_handle(&handle_lo, &handle_hi);
|
||||
if (rc)
|
||||
return(10 + rc);
|
||||
|
||||
/*
|
||||
* NCP 87 subfunction 29: Get effective rights.
|
||||
*
|
||||
* This mirrors ncpfs ncp_get_eff_directory_rights():
|
||||
* byte 29
|
||||
* byte source namespace
|
||||
* byte target namespace
|
||||
* word search attributes, little endian
|
||||
* dword reserved, zero
|
||||
* handle/path
|
||||
*
|
||||
* Reply is a little-endian word with NCP rights bits.
|
||||
*/
|
||||
memset(hdr, 0, sizeof(hdr));
|
||||
hdr[0] = 29;
|
||||
hdr[1] = 0; /* source namespace DOS */
|
||||
hdr[2] = 0; /* target namespace DOS */
|
||||
c32_put_word_lh(hdr + 3, 0x0006); /* SA_ALL */
|
||||
c32_put_dword_lh(hdr + 5, 0L); /* reserved */
|
||||
|
||||
path_len = c32_build_handle_path_from_dos_path(path, (uint8)dir_handle,
|
||||
0, 0, path_name);
|
||||
|
||||
memset(rep0, 0, sizeof(rep0));
|
||||
memset(rep1, 0, sizeof(rep1));
|
||||
memset(rawout, 0, sizeof(rawout));
|
||||
|
||||
C32_NCP87_Raw5_Probe(handle_lo, handle_hi,
|
||||
hdr, 9,
|
||||
path, path_len,
|
||||
rep0, sizeof(rep0),
|
||||
rep1, sizeof(rep1),
|
||||
rawout);
|
||||
|
||||
raw_ret_ax = c32_get_word_lh(rawout + 14);
|
||||
raw_ret_dx = c32_get_word_lh(rawout + 16);
|
||||
actual_lo = c32_get_word_lh(rawout + 18);
|
||||
|
||||
if (actual_out) *actual_out = actual_lo;
|
||||
if (handle_lo_out) *handle_lo_out = handle_lo;
|
||||
if (handle_hi_out) *handle_hi_out = handle_hi;
|
||||
|
||||
if (raw_ret_ax != 0 || raw_ret_dx != 0)
|
||||
return(20);
|
||||
|
||||
rights0 = c32_get_word_lh(rep0 + 0);
|
||||
rights4 = c32_get_word_lh(rep0 + 4);
|
||||
|
||||
/*
|
||||
* Most NCP replies start at REP0+0. The existing RIM_ATTRIBUTES helper
|
||||
* found attributes at REP0+4 on Client32. Accept the +4 location only
|
||||
* if +0 is empty, so restricted rights value 0 still works when +4 is
|
||||
* also zero.
|
||||
*/
|
||||
if (rights0 == 0 && rights4 != 0)
|
||||
rights0 = rights4;
|
||||
|
||||
*rights_out = rights0;
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
int c32_ncp87_add_trustee_rights(const char *path_name,
|
||||
uint16 dir_handle,
|
||||
uint32 object_id,
|
||||
uint16 rights,
|
||||
uint16 rights_mask,
|
||||
uint16 *actual_out,
|
||||
uint16 *handle_lo_out,
|
||||
uint16 *handle_hi_out)
|
||||
{
|
||||
uint16 handle_lo, handle_hi;
|
||||
uint8 hdr[16];
|
||||
uint8 reqpath[0x180];
|
||||
uint8 rep0[0x20];
|
||||
uint8 rep1[0x20];
|
||||
uint8 rawout[32];
|
||||
uint16 raw_ret_ax, raw_ret_dx;
|
||||
uint16 actual_lo;
|
||||
UI path_struct_len;
|
||||
UI reqpath_len;
|
||||
uint8 *tp;
|
||||
int rc;
|
||||
|
||||
if (actual_out) *actual_out = 0;
|
||||
if (handle_lo_out) *handle_lo_out = 0;
|
||||
if (handle_hi_out) *handle_hi_out = 0;
|
||||
|
||||
rc = c32_get_ncp_handle(&handle_lo, &handle_hi);
|
||||
if (rc)
|
||||
return(10 + rc);
|
||||
|
||||
/*
|
||||
* NCP 87 subfunction 10: Add trustee.
|
||||
*
|
||||
* This mirrors ncpfs ncp_ns_trustee_add():
|
||||
* byte 10
|
||||
* byte namespace DOS
|
||||
* byte reserved
|
||||
* word search attributes, little endian
|
||||
* word rights mask, little endian
|
||||
* word object count, little endian
|
||||
* handle/path
|
||||
* trustee array at request offset 16 + 307
|
||||
*
|
||||
* Client32 Raw5 has two request fragments, so the second fragment carries
|
||||
* the handle/path and the padded trustee record.
|
||||
*/
|
||||
memset(hdr, 0, sizeof(hdr));
|
||||
hdr[0] = 10;
|
||||
hdr[1] = 0; /* DOS namespace */
|
||||
hdr[2] = 0; /* reserved */
|
||||
c32_put_word_lh(hdr + 3, 0x8006); /* SA_ALL: files/subdirs + system + hidden */
|
||||
c32_put_word_lh(hdr + 5, rights_mask);
|
||||
c32_put_word_lh(hdr + 7, 1); /* one trustee */
|
||||
|
||||
memset(reqpath, 0, sizeof(reqpath));
|
||||
path_struct_len = c32_build_handle_path_from_dos_path(reqpath,
|
||||
(uint8)dir_handle,
|
||||
0, 0,
|
||||
path_name);
|
||||
|
||||
/*
|
||||
* ncpfs seeks to absolute packet offset 16+307 before writing the
|
||||
* trustee list. The NCP request header is 7 bytes, so inside the NCP
|
||||
* payload the trustee list begins at:
|
||||
*
|
||||
* (16 + 307) - 7 = 316
|
||||
*
|
||||
* Our first Raw5 request fragment is the 9-byte subfunction header,
|
||||
* so the trustee list begins in the second fragment at:
|
||||
*
|
||||
* 316 - 9 = 307
|
||||
*/
|
||||
if (path_struct_len > 307)
|
||||
return(2);
|
||||
|
||||
tp = reqpath + 307;
|
||||
c32_put_dword_hl(tp, object_id); tp += 4;
|
||||
c32_put_word_lh(tp, rights); tp += 2;
|
||||
reqpath_len = (UI)(tp - reqpath);
|
||||
|
||||
memset(rep0, 0, sizeof(rep0));
|
||||
memset(rep1, 0, sizeof(rep1));
|
||||
memset(rawout, 0, sizeof(rawout));
|
||||
|
||||
C32_NCP87_Raw5_Probe(handle_lo, handle_hi,
|
||||
hdr, 9,
|
||||
reqpath, reqpath_len,
|
||||
rep0, sizeof(rep0),
|
||||
rep1, sizeof(rep1),
|
||||
rawout);
|
||||
|
||||
raw_ret_ax = c32_get_word_lh(rawout + 14);
|
||||
raw_ret_dx = c32_get_word_lh(rawout + 16);
|
||||
actual_lo = c32_get_word_lh(rawout + 18);
|
||||
|
||||
if (actual_out) *actual_out = actual_lo;
|
||||
if (handle_lo_out) *handle_lo_out = handle_lo;
|
||||
if (handle_hi_out) *handle_hi_out = handle_hi;
|
||||
|
||||
if (raw_ret_ax != 0 || raw_ret_dx != 0)
|
||||
return(20);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int c32_ncp87_find_trustee_rights(const char *path_name,
|
||||
uint16 dir_handle,
|
||||
uint32 object_id,
|
||||
uint16 *rights_out,
|
||||
uint16 *actual_out,
|
||||
uint16 *handle_lo_out,
|
||||
uint16 *handle_hi_out)
|
||||
{
|
||||
uint16 handle_lo, handle_hi;
|
||||
uint8 hdr[16];
|
||||
uint8 path[0x140];
|
||||
uint8 rep0[0x120];
|
||||
uint8 rep1[0x120];
|
||||
uint8 rawout[32];
|
||||
uint16 raw_ret_ax, raw_ret_dx;
|
||||
uint16 actual_lo;
|
||||
uint32 seq = 0;
|
||||
UI path_len;
|
||||
int rc;
|
||||
|
||||
if (rights_out) *rights_out = 0;
|
||||
if (actual_out) *actual_out = 0;
|
||||
if (handle_lo_out) *handle_lo_out = 0;
|
||||
if (handle_hi_out) *handle_hi_out = 0;
|
||||
|
||||
if (!rights_out)
|
||||
return(1);
|
||||
|
||||
rc = c32_get_ncp_handle(&handle_lo, &handle_hi);
|
||||
if (rc)
|
||||
return(10 + rc);
|
||||
|
||||
for (;;) {
|
||||
uint16 count;
|
||||
uint16 i;
|
||||
uint8 *tp;
|
||||
uint32 next_seq;
|
||||
|
||||
memset(hdr, 0, sizeof(hdr));
|
||||
hdr[0] = 5; /* NCP87 subfunction 5: scan trustees */
|
||||
hdr[1] = 0; /* DOS namespace */
|
||||
hdr[2] = 0; /* reserved */
|
||||
c32_put_word_lh(hdr + 3, 0x8006); /* SA_ALL: files/subdirs + system + hidden */
|
||||
c32_put_dword_lh(hdr + 5, seq); /* search sequence, starts at zero */
|
||||
|
||||
path_len = c32_build_handle_path_from_dos_path(path,
|
||||
(uint8)dir_handle,
|
||||
0, 0,
|
||||
path_name);
|
||||
|
||||
memset(rep0, 0, sizeof(rep0));
|
||||
memset(rep1, 0, sizeof(rep1));
|
||||
memset(rawout, 0, sizeof(rawout));
|
||||
|
||||
C32_NCP87_Raw5_Probe(handle_lo, handle_hi,
|
||||
hdr, 9,
|
||||
path, path_len,
|
||||
rep0, sizeof(rep0),
|
||||
rep1, sizeof(rep1),
|
||||
rawout);
|
||||
|
||||
raw_ret_ax = c32_get_word_lh(rawout + 14);
|
||||
raw_ret_dx = c32_get_word_lh(rawout + 16);
|
||||
actual_lo = c32_get_word_lh(rawout + 18);
|
||||
|
||||
if (actual_out) *actual_out = actual_lo;
|
||||
if (handle_lo_out) *handle_lo_out = handle_lo;
|
||||
if (handle_hi_out) *handle_hi_out = handle_hi;
|
||||
|
||||
if (raw_ret_ax != 0 || raw_ret_dx != 0)
|
||||
return(0xff); /* Client32 returns an error when no trustees are present. */
|
||||
|
||||
next_seq = c32_get_dword_lh(rep0 + 0);
|
||||
count = c32_get_word_lh(rep0 + 4);
|
||||
|
||||
if (count > 20)
|
||||
count = 20;
|
||||
|
||||
tp = rep0 + 6;
|
||||
for (i = 0; i < count; i++) {
|
||||
uint32 tid = c32_get_dword_hl(tp);
|
||||
uint16 trights = c32_get_word_lh(tp + 4);
|
||||
|
||||
if (tid == object_id || c32_get_dword_lh(tp) == object_id) {
|
||||
*rights_out = trights;
|
||||
return(0);
|
||||
}
|
||||
|
||||
tp += 6;
|
||||
}
|
||||
|
||||
if (next_seq == 0xffffffffUL || next_seq == seq)
|
||||
break;
|
||||
|
||||
seq = next_seq;
|
||||
}
|
||||
|
||||
return(0xff); /* no trustee found / no more entries */
|
||||
}
|
||||
|
||||
int c32_ncp87_delete_trustee_rights(const char *path_name,
|
||||
uint16 dir_handle,
|
||||
uint32 object_id,
|
||||
uint16 *actual_out,
|
||||
uint16 *handle_lo_out,
|
||||
uint16 *handle_hi_out)
|
||||
{
|
||||
uint16 handle_lo, handle_hi;
|
||||
uint8 hdr[16];
|
||||
uint8 reqpath[0x180];
|
||||
uint8 rep0[0x20];
|
||||
uint8 rep1[0x20];
|
||||
uint8 rawout[32];
|
||||
uint16 raw_ret_ax, raw_ret_dx;
|
||||
uint16 actual_lo;
|
||||
UI path_struct_len;
|
||||
UI reqpath_len;
|
||||
uint8 *tp;
|
||||
int rc;
|
||||
|
||||
if (actual_out) *actual_out = 0;
|
||||
if (handle_lo_out) *handle_lo_out = 0;
|
||||
if (handle_hi_out) *handle_hi_out = 0;
|
||||
|
||||
rc = c32_get_ncp_handle(&handle_lo, &handle_hi);
|
||||
if (rc)
|
||||
return(10 + rc);
|
||||
|
||||
memset(hdr, 0, sizeof(hdr));
|
||||
hdr[0] = 11; /* NCP87 subfunction 11: delete trustee */
|
||||
hdr[1] = 0; /* DOS namespace */
|
||||
hdr[2] = 0; /* reserved */
|
||||
c32_put_word_lh(hdr + 3, 1); /* one trustee */
|
||||
|
||||
memset(reqpath, 0, sizeof(reqpath));
|
||||
path_struct_len = c32_build_handle_path_from_dos_path(reqpath,
|
||||
(uint8)dir_handle,
|
||||
0, 0,
|
||||
path_name);
|
||||
|
||||
if (path_struct_len > 307)
|
||||
return(2);
|
||||
|
||||
tp = reqpath + 307;
|
||||
c32_put_dword_hl(tp, object_id); tp += 4;
|
||||
c32_put_word_lh(tp, 0); tp += 2;
|
||||
reqpath_len = (UI)(tp - reqpath);
|
||||
|
||||
memset(rep0, 0, sizeof(rep0));
|
||||
memset(rep1, 0, sizeof(rep1));
|
||||
memset(rawout, 0, sizeof(rawout));
|
||||
|
||||
C32_NCP87_Raw5_Probe(handle_lo, handle_hi,
|
||||
hdr, 5,
|
||||
reqpath, reqpath_len,
|
||||
rep0, sizeof(rep0),
|
||||
rep1, sizeof(rep1),
|
||||
rawout);
|
||||
|
||||
raw_ret_ax = c32_get_word_lh(rawout + 14);
|
||||
raw_ret_dx = c32_get_word_lh(rawout + 16);
|
||||
actual_lo = c32_get_word_lh(rawout + 18);
|
||||
|
||||
if (actual_out) *actual_out = actual_lo;
|
||||
if (handle_lo_out) *handle_lo_out = handle_lo;
|
||||
if (handle_hi_out) *handle_hi_out = handle_hi;
|
||||
|
||||
if (raw_ret_ax != 0 || raw_ret_dx != 0)
|
||||
return(20);
|
||||
|
||||
return(0);
|
||||
}
|
||||
90
c32ncp.h
Normal file
90
c32ncp.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/* c32ncp.h - minimal Client32 NCP helpers for mars-dosutils */
|
||||
|
||||
#ifndef C32NCP_H
|
||||
#define C32NCP_H
|
||||
int c32_get_ncp_handle(uint16 *handle_lo, uint16 *handle_hi);
|
||||
|
||||
int c32_ncp87_obtain_rim_attributes(const char *name,
|
||||
uint16 dir_handle,
|
||||
uint32 *attr_out,
|
||||
uint16 *actual_out,
|
||||
uint16 *handle_lo_out,
|
||||
uint16 *handle_hi_out);
|
||||
|
||||
|
||||
typedef struct c32_ndir_info {
|
||||
uint32 space_allocated;
|
||||
uint32 attributes;
|
||||
uint16 flags;
|
||||
uint32 data_size;
|
||||
uint32 total_size;
|
||||
uint16 number_of_streams;
|
||||
uint16 creation_time;
|
||||
uint16 creation_date;
|
||||
uint32 creator_id;
|
||||
uint16 modify_time;
|
||||
uint16 modify_date;
|
||||
uint32 modifier_id;
|
||||
uint16 last_access_date;
|
||||
uint16 archive_time;
|
||||
uint16 archive_date;
|
||||
uint32 archiver_id;
|
||||
uint16 inherited_rights;
|
||||
uint32 dir_ent_num;
|
||||
uint32 dos_dir_num;
|
||||
uint32 vol_number;
|
||||
uint32 ea_data_size;
|
||||
uint32 ea_key_count;
|
||||
uint32 ea_key_size;
|
||||
uint32 ns_creator;
|
||||
uint8 name_len;
|
||||
char name[256];
|
||||
} C32_NDIR_INFO;
|
||||
|
||||
int c32_ncp87_obtain_ndir_info(const char *path_name,
|
||||
uint16 dir_handle,
|
||||
C32_NDIR_INFO *info_out,
|
||||
uint16 *actual_out,
|
||||
uint16 *handle_lo_out,
|
||||
uint16 *handle_hi_out);
|
||||
|
||||
|
||||
int c32_ncp87_modify_dos_attributes(char *name,
|
||||
uint16 dir_handle,
|
||||
uint32 attrs,
|
||||
uint16 *actual_out,
|
||||
uint16 *handle_lo_out,
|
||||
uint16 *handle_hi_out);
|
||||
|
||||
int c32_ncp87_get_effective_rights(const char *path,
|
||||
uint16 dir_handle,
|
||||
uint16 *rights_out,
|
||||
uint16 *actual_out,
|
||||
uint16 *handle_lo_out,
|
||||
uint16 *handle_hi_out);
|
||||
|
||||
int c32_ncp87_add_trustee_rights(const char *path_name,
|
||||
uint16 dir_handle,
|
||||
uint32 object_id,
|
||||
uint16 rights,
|
||||
uint16 rights_mask,
|
||||
uint16 *actual_out,
|
||||
uint16 *handle_lo_out,
|
||||
uint16 *handle_hi_out);
|
||||
|
||||
int c32_ncp87_find_trustee_rights(const char *path_name,
|
||||
uint16 dir_handle,
|
||||
uint32 object_id,
|
||||
uint16 *rights_out,
|
||||
uint16 *actual_out,
|
||||
uint16 *handle_lo_out,
|
||||
uint16 *handle_hi_out);
|
||||
|
||||
int c32_ncp87_delete_trustee_rights(const char *path_name,
|
||||
uint16 dir_handle,
|
||||
uint32 object_id,
|
||||
uint16 *actual_out,
|
||||
uint16 *handle_lo_out,
|
||||
uint16 *handle_hi_out);
|
||||
|
||||
#endif
|
||||
474
flag.c
Normal file
474
flag.c
Normal file
@@ -0,0 +1,474 @@
|
||||
/* flag.c - Novell FLAG-like DOS utility, stage 1 */
|
||||
|
||||
#include "net.h"
|
||||
#include "c32ncp.h"
|
||||
#include <dos.h>
|
||||
|
||||
/*
|
||||
* FLAG v4b: NCP 87 namespace DOS info.
|
||||
*
|
||||
* ncpfs reference:
|
||||
* ncp_ns_modify_entry_dos_info():
|
||||
* subfunction 7, namespace DOS, search attrs SA_ALL,
|
||||
* ModifyInformationMask, struct ncp_dos_info, handle/path.
|
||||
*
|
||||
* We use dirstyle=0 (short directory handle) against the current DOS
|
||||
* directory handle and a one-component DOS filename.
|
||||
*/
|
||||
#define FLAG_NW_NS_DOS 0x00
|
||||
#define FLAG_SA_ALL 0x0006
|
||||
#define FLAG_RIM_ATTRIBUTES 0x00000004UL
|
||||
|
||||
#define NWFA_RO 0x00000001UL
|
||||
#define NWFA_H 0x00000002UL
|
||||
#define NWFA_SY 0x00000004UL
|
||||
#define NWFA_A 0x00000020UL
|
||||
#define NWFA_S 0x00000080UL
|
||||
#define NWFA_T 0x00001000UL
|
||||
#define NWFA_RA 0x00004000UL
|
||||
#define NWFA_WA 0x00008000UL
|
||||
#define NWFA_P 0x00010000UL
|
||||
#define NWFA_RI 0x00020000UL
|
||||
#define NWFA_DI 0x00040000UL
|
||||
#define NWFA_CI 0x00080000UL
|
||||
|
||||
static void flag_put_word_lh(uint8 *p, uint16 v)
|
||||
{
|
||||
p[0] = (uint8)(v & 0xff);
|
||||
p[1] = (uint8)((v >> 8) & 0xff);
|
||||
}
|
||||
|
||||
static void flag_put_dword_lh(uint8 *p, uint32 v)
|
||||
{
|
||||
p[0] = (uint8)(v & 0xff);
|
||||
p[1] = (uint8)((v >> 8) & 0xff);
|
||||
p[2] = (uint8)((v >> 16) & 0xff);
|
||||
p[3] = (uint8)((v >> 24) & 0xff);
|
||||
}
|
||||
|
||||
static uint32 flag_get_dword_lh(uint8 *p)
|
||||
{
|
||||
return((uint32)p[0] |
|
||||
((uint32)p[1] << 8) |
|
||||
((uint32)p[2] << 16) |
|
||||
((uint32)p[3] << 24));
|
||||
}
|
||||
|
||||
static int flag_add_handle_path(uint8 *p, uint8 dhandle, char *name)
|
||||
{
|
||||
int nlen;
|
||||
|
||||
nlen = strlen(name);
|
||||
if (nlen > 255) nlen = 255;
|
||||
|
||||
/*
|
||||
* handle/path:
|
||||
* volume/handle byte
|
||||
* dir base dword
|
||||
* dirstyle byte (0 = short dir handle)
|
||||
* path components: 1 component, length, bytes
|
||||
*/
|
||||
*p++ = dhandle;
|
||||
flag_put_dword_lh(p, 0L); p += 4;
|
||||
*p++ = 0; /* dirstyle = handle */
|
||||
*p++ = 1; /* one path component */
|
||||
*p++ = (uint8)nlen;
|
||||
memcpy(p, name, nlen);
|
||||
p += nlen;
|
||||
|
||||
return(1 + 4 + 1 + 1 + 1 + nlen);
|
||||
}
|
||||
|
||||
static int flag_ncp87_obtain_attrs(char *name, uint32 *attrs)
|
||||
{
|
||||
struct {
|
||||
uint16 len;
|
||||
uint8 data[320];
|
||||
} req;
|
||||
struct {
|
||||
uint16 len;
|
||||
uint8 data[128];
|
||||
} repl;
|
||||
uint8 connid = 0;
|
||||
uint8 dhandle = 0;
|
||||
uint8 *p;
|
||||
int hlen;
|
||||
|
||||
if (tool_current_dhandle(&connid, &dhandle))
|
||||
return(-1);
|
||||
|
||||
/*
|
||||
* Prefer the verified Client32 NCP87 path. If it is not available,
|
||||
* fall back to the historical INT 21h/Net_Call path below.
|
||||
*/
|
||||
if (c32_ncp87_obtain_rim_attributes(name, (uint16)dhandle,
|
||||
attrs, NULL, NULL, NULL) == 0)
|
||||
return(0);
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
memset(&repl, 0, sizeof(repl));
|
||||
|
||||
p = req.data;
|
||||
*p++ = 6; /* subfunction: obtain file/subdir info */
|
||||
*p++ = FLAG_NW_NS_DOS; /* source namespace */
|
||||
*p++ = FLAG_NW_NS_DOS; /* target namespace */
|
||||
flag_put_word_lh(p, FLAG_SA_ALL); p += 2;
|
||||
flag_put_dword_lh(p, FLAG_RIM_ATTRIBUTES); p += 4;
|
||||
hlen = flag_add_handle_path(p, dhandle, name);
|
||||
p += hlen;
|
||||
|
||||
req.len = (uint16)(p - req.data);
|
||||
repl.len = sizeof(repl.data);
|
||||
|
||||
neterrno = Net_Call(0xF257, &req, &repl);
|
||||
if (neterrno)
|
||||
return(-1);
|
||||
|
||||
/*
|
||||
* With RIM_ATTRIBUTES only, ncpfs expects NSI_Attributes first.
|
||||
* First dword is the 32-bit Attributes field.
|
||||
*/
|
||||
if (attrs)
|
||||
*attrs = flag_get_dword_lh(repl.data);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int flag_ncp87_modify_attrs(char *name, uint32 attrs)
|
||||
{
|
||||
struct {
|
||||
uint16 len;
|
||||
uint8 data[384];
|
||||
} req;
|
||||
struct {
|
||||
uint16 len;
|
||||
uint8 data[8];
|
||||
} repl;
|
||||
uint8 connid = 0;
|
||||
uint8 dhandle = 0;
|
||||
uint8 *p;
|
||||
int hlen;
|
||||
|
||||
if (tool_current_dhandle(&connid, &dhandle))
|
||||
return(-1);
|
||||
|
||||
/*
|
||||
* Prefer verified Client32 modify path. The old INT 21h/F257 modify path
|
||||
* can hang under DOS Client32 for high FLAG bits such as T/P/DI/RI.
|
||||
*/
|
||||
{
|
||||
uint16 actual = 0;
|
||||
uint16 hlo = 0;
|
||||
uint16 hhi = 0;
|
||||
if (!c32_ncp87_modify_dos_attributes(name, (uint16)dhandle, attrs,
|
||||
&actual, &hlo, &hhi))
|
||||
return(0);
|
||||
}
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
memset(&repl, 0, sizeof(repl));
|
||||
|
||||
p = req.data;
|
||||
*p++ = 7; /* subfunction: modify DOS info */
|
||||
*p++ = FLAG_NW_NS_DOS;
|
||||
*p++ = 0; /* reserved */
|
||||
flag_put_word_lh(p, FLAG_SA_ALL); p += 2;
|
||||
|
||||
flag_put_dword_lh(p, FLAG_RIM_ATTRIBUTES); p += 4; /* modify mask */
|
||||
flag_put_dword_lh(p, attrs); p += 4; /* Attributes */
|
||||
|
||||
/*
|
||||
* Remaining ncp_dos_info fields. Mask says only Attributes is valid,
|
||||
* so these should be ignored, but ncpfs still sends the full structure.
|
||||
*/
|
||||
memset(p, 0, 34);
|
||||
p += 34;
|
||||
|
||||
hlen = flag_add_handle_path(p, dhandle, name);
|
||||
p += hlen;
|
||||
|
||||
req.len = (uint16)(p - req.data);
|
||||
repl.len = sizeof(repl.data);
|
||||
|
||||
neterrno = Net_Call(0xF257, &req, &repl);
|
||||
if (neterrno)
|
||||
return(-1);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
#ifndef _A_NORMAL
|
||||
#define _A_NORMAL 0x00
|
||||
#endif
|
||||
#ifndef _A_RDONLY
|
||||
#define _A_RDONLY 0x01
|
||||
#endif
|
||||
#ifndef _A_HIDDEN
|
||||
#define _A_HIDDEN 0x02
|
||||
#endif
|
||||
#ifndef _A_SYSTEM
|
||||
#define _A_SYSTEM 0x04
|
||||
#endif
|
||||
#ifndef _A_SUBDIR
|
||||
#define _A_SUBDIR 0x10
|
||||
#endif
|
||||
#ifndef _A_ARCH
|
||||
#define _A_ARCH 0x20
|
||||
#endif
|
||||
|
||||
static void flag_help(void)
|
||||
{
|
||||
fprintf(stdout, "USAGE: FLAG [path [ option | [+|-] attribute(s) ] [SUB]]\n");
|
||||
fprintf(stdout, "\n");
|
||||
fprintf(stdout, "386 Attributes:\n");
|
||||
fprintf(stdout, "--------------\n");
|
||||
fprintf(stdout, "\n");
|
||||
fprintf(stdout, "RO Read Only\n");
|
||||
fprintf(stdout, "RW Read Write\n");
|
||||
fprintf(stdout, "S Sharable\n");
|
||||
fprintf(stdout, "H Hidden\n");
|
||||
fprintf(stdout, "Sy System\n");
|
||||
fprintf(stdout, "T Transactional\n");
|
||||
fprintf(stdout, "P Purge\n");
|
||||
fprintf(stdout, "A Archive Needed\n");
|
||||
fprintf(stdout, "RA Read Audit\n");
|
||||
fprintf(stdout, "WA Write Audit\n");
|
||||
fprintf(stdout, "CI Copy Inhibit\n");
|
||||
fprintf(stdout, "DI Delete Inhibit\n");
|
||||
fprintf(stdout, "RI Rename Inhibit\n");
|
||||
fprintf(stdout, "\n");
|
||||
fprintf(stdout, "All All\n");
|
||||
fprintf(stdout, "N Normal\n");
|
||||
fprintf(stdout, "SUB\n");
|
||||
}
|
||||
|
||||
static int flag_attr_mask(char *s, uint32 *setbits, uint32 *clearbits)
|
||||
{
|
||||
int set = 1;
|
||||
char *p = s;
|
||||
|
||||
if (*p == '+') {
|
||||
set = 1;
|
||||
p++;
|
||||
} else if (*p == '-') {
|
||||
set = 0;
|
||||
p++;
|
||||
}
|
||||
|
||||
if (!*p) return(-1);
|
||||
|
||||
if (tool_strsame(p, "RO")) {
|
||||
if (set) {
|
||||
*setbits |= (NWFA_RO | NWFA_DI | NWFA_RI);
|
||||
} else {
|
||||
*clearbits |= (NWFA_RO | NWFA_DI | NWFA_RI);
|
||||
}
|
||||
} else if (tool_strsame(p, "RW")) {
|
||||
*clearbits |= (NWFA_RO | NWFA_DI | NWFA_RI);
|
||||
} else if (tool_strsame(p, "S")) {
|
||||
if (set) *setbits |= NWFA_S;
|
||||
else *clearbits |= NWFA_S;
|
||||
} else if (tool_strsame(p, "H")) {
|
||||
if (set) *setbits |= NWFA_H;
|
||||
else *clearbits |= NWFA_H;
|
||||
} else if (tool_strsame(p, "SY") || tool_strsame(p, "SYS") || tool_strsame(p, "SYSTEM")) {
|
||||
if (set) *setbits |= NWFA_SY;
|
||||
else *clearbits |= NWFA_SY;
|
||||
} else if (tool_strsame(p, "T")) {
|
||||
if (set) *setbits |= NWFA_T;
|
||||
else *clearbits |= NWFA_T;
|
||||
} else if (tool_strsame(p, "P")) {
|
||||
if (set) *setbits |= NWFA_P;
|
||||
else *clearbits |= NWFA_P;
|
||||
} else if (tool_strsame(p, "A")) {
|
||||
if (set) *setbits |= NWFA_A;
|
||||
else *clearbits |= NWFA_A;
|
||||
} else if (tool_strsame(p, "RA")) {
|
||||
if (set) *setbits |= NWFA_RA;
|
||||
else *clearbits |= NWFA_RA;
|
||||
} else if (tool_strsame(p, "WA")) {
|
||||
if (set) *setbits |= NWFA_WA;
|
||||
else *clearbits |= NWFA_WA;
|
||||
} else if (tool_strsame(p, "CI")) {
|
||||
if (set) *setbits |= NWFA_CI;
|
||||
else *clearbits |= NWFA_CI;
|
||||
} else if (tool_strsame(p, "DI")) {
|
||||
if (set) *setbits |= NWFA_DI;
|
||||
else *clearbits |= NWFA_DI;
|
||||
} else if (tool_strsame(p, "RI")) {
|
||||
if (set) *setbits |= NWFA_RI;
|
||||
else *clearbits |= NWFA_RI;
|
||||
} else if (tool_strsame(p, "N") || tool_strsame(p, "NORMAL")) {
|
||||
*clearbits |= (NWFA_RO | NWFA_H | NWFA_SY | NWFA_A |
|
||||
NWFA_S | NWFA_T | NWFA_P |
|
||||
NWFA_RA | NWFA_WA | NWFA_CI | NWFA_DI | NWFA_RI);
|
||||
} else if (tool_strsame(p, "ALL")) {
|
||||
*setbits |= (NWFA_RO | NWFA_H | NWFA_SY | NWFA_A |
|
||||
NWFA_S | NWFA_T | NWFA_P |
|
||||
NWFA_RA | NWFA_WA | NWFA_CI | NWFA_DI | NWFA_RI);
|
||||
} else {
|
||||
fprintf(stderr, "Unknown attribute encountered in command line.\n");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static void flag_print_attrs(uint32 attr)
|
||||
{
|
||||
/*
|
||||
* Novell order:
|
||||
* Ro/Rw S A - H Sy T P Ra Wa CI DI RI
|
||||
*/
|
||||
fprintf(stdout, "[ ");
|
||||
fprintf(stdout, "%s ", (attr & NWFA_RO) ? "Ro" : "Rw");
|
||||
fprintf(stdout, "%c ", (attr & NWFA_S) ? 'S' : '-');
|
||||
fprintf(stdout, "%c ", (attr & NWFA_A) ? 'A' : '-');
|
||||
fprintf(stdout, "- ");
|
||||
fprintf(stdout, "%c ", (attr & NWFA_H) ? 'H' : '-');
|
||||
fprintf(stdout, "%s ", (attr & NWFA_SY) ? "Sy" : "--");
|
||||
fprintf(stdout, "%c ", (attr & NWFA_T) ? 'T' : '-');
|
||||
fprintf(stdout, "%c ", (attr & NWFA_P) ? 'P' : '-');
|
||||
fprintf(stdout, "%s ", (attr & NWFA_RA) ? "Ra" : "--");
|
||||
fprintf(stdout, "%s ", (attr & NWFA_WA) ? "Wa" : "--");
|
||||
fprintf(stdout, "%s ", (attr & NWFA_CI) ? "CI" : "--");
|
||||
fprintf(stdout, "%s ", (attr & NWFA_DI) ? "DI" : "--");
|
||||
fprintf(stdout, "%s ", (attr & NWFA_RI) ? "RI" : "--");
|
||||
fprintf(stdout, "]");
|
||||
}
|
||||
|
||||
static void flag_display_one(char *name, uint32 attr)
|
||||
{
|
||||
fprintf(stdout, " %-23s ", name);
|
||||
flag_print_attrs(attr);
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
|
||||
static void flag_display_one_paged(char *name, uint32 attr,
|
||||
int *line_count, int *continuous)
|
||||
{
|
||||
flag_display_one(name, attr);
|
||||
tool_page_line(line_count, continuous);
|
||||
}
|
||||
|
||||
|
||||
static int flag_list(char *pattern)
|
||||
{
|
||||
struct find_t ff;
|
||||
unsigned findattr = _A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_ARCH;
|
||||
int found = 0;
|
||||
int line_count = 0;
|
||||
int continuous = 0;
|
||||
|
||||
if (_dos_findfirst(pattern, findattr, &ff))
|
||||
return(-1);
|
||||
|
||||
do {
|
||||
if (!(ff.attrib & _A_SUBDIR)) {
|
||||
uint32 nwattrs;
|
||||
|
||||
if (flag_ncp87_obtain_attrs(ff.name, &nwattrs))
|
||||
nwattrs = (uint32)ff.attrib;
|
||||
|
||||
flag_display_one_paged(ff.name, nwattrs, &line_count, &continuous);
|
||||
found++;
|
||||
}
|
||||
} while (!_dos_findnext(&ff));
|
||||
|
||||
return(found);
|
||||
}
|
||||
|
||||
static int flag_apply(char *pattern, uint32 setbits, uint32 clearbits)
|
||||
{
|
||||
struct find_t ff;
|
||||
unsigned findattr = _A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_ARCH;
|
||||
int shown = 0;
|
||||
|
||||
if (_dos_findfirst(pattern, findattr, &ff))
|
||||
return(-1);
|
||||
|
||||
do {
|
||||
uint32 attrs;
|
||||
uint32 newattrs;
|
||||
char fname[260];
|
||||
|
||||
if (ff.attrib & _A_SUBDIR) continue;
|
||||
|
||||
strmaxcpy(fname, ff.name, sizeof(fname) - 1);
|
||||
|
||||
if (flag_ncp87_obtain_attrs(fname, &attrs))
|
||||
attrs = (uint32)ff.attrib;
|
||||
|
||||
newattrs = (attrs | (uint32)setbits) & ~((uint32)clearbits);
|
||||
|
||||
if (newattrs != attrs) {
|
||||
if (flag_ncp87_modify_attrs(fname, newattrs)) {
|
||||
unsigned dosattr = (newattrs & (_A_RDONLY|_A_HIDDEN|_A_SYSTEM|_A_ARCH));
|
||||
if (_dos_setfileattr(fname, dosattr)) {
|
||||
fprintf(stderr, "You don't have rights to change : %s\n", fname);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (flag_ncp87_obtain_attrs(fname, &attrs))
|
||||
attrs = newattrs;
|
||||
|
||||
flag_display_one(fname, newattrs);
|
||||
shown++;
|
||||
|
||||
} while (!_dos_findnext(&ff));
|
||||
|
||||
return(shown);
|
||||
}
|
||||
|
||||
int func_flag(int argc, char *argv[], int mode)
|
||||
{
|
||||
char *path = "*.*";
|
||||
int i;
|
||||
uint32 setbits = 0;
|
||||
uint32 clearbits = 0;
|
||||
int have_change = 0;
|
||||
int rc;
|
||||
|
||||
(void)mode;
|
||||
|
||||
if (argc > 1 && (tool_strsame(argv[1], "/?") || tool_strsame(argv[1], "-?") ||
|
||||
tool_strsame(argv[1], "?"))) {
|
||||
flag_help();
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (argc > 1) {
|
||||
path = argv[1];
|
||||
if (tool_strsame(path, "SUB")) path = "*.*";
|
||||
}
|
||||
|
||||
for (i = 2; i < argc; i++) {
|
||||
if (tool_strsame(argv[i], "SUB")) continue;
|
||||
|
||||
rc = flag_attr_mask(argv[i], &setbits, &clearbits);
|
||||
if (rc < 0) return(1);
|
||||
if (rc > 0) continue;
|
||||
have_change = 1;
|
||||
}
|
||||
|
||||
if (have_change) {
|
||||
rc = flag_apply(path, setbits, clearbits);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "Files could not be found with pattern \"%s\"\n", path);
|
||||
return(1);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
rc = flag_list(path);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "Files could not be found with pattern \"%s\"\n", path);
|
||||
return(1);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
321
flagdir.c
Normal file
321
flagdir.c
Normal file
@@ -0,0 +1,321 @@
|
||||
/* flagdir.c - Novell FLAGDIR-like DOS utility, Client32 version */
|
||||
|
||||
#include "net.h"
|
||||
#include "c32ncp.h"
|
||||
#include <dos.h>
|
||||
|
||||
#define FD_NWFA_H 0x00000002UL
|
||||
#define FD_NWFA_SY 0x00000004UL
|
||||
#define FD_NWFA_P 0x00010000UL
|
||||
#define FD_NWFA_RI 0x00020000UL
|
||||
#define FD_NWFA_DI 0x00040000UL
|
||||
|
||||
#define FD_DIR_BITS (FD_NWFA_H | FD_NWFA_SY | FD_NWFA_P | FD_NWFA_RI | FD_NWFA_DI)
|
||||
|
||||
#ifndef _A_RDONLY
|
||||
#define _A_RDONLY 0x01
|
||||
#endif
|
||||
#ifndef _A_HIDDEN
|
||||
#define _A_HIDDEN 0x02
|
||||
#endif
|
||||
#ifndef _A_SYSTEM
|
||||
#define _A_SYSTEM 0x04
|
||||
#endif
|
||||
#ifndef _A_SUBDIR
|
||||
#define _A_SUBDIR 0x10
|
||||
#endif
|
||||
#ifndef _A_ARCH
|
||||
#define _A_ARCH 0x20
|
||||
#endif
|
||||
|
||||
static int fd_current_display_path(uint8 dhandle, char *out, int max)
|
||||
{
|
||||
char path[260];
|
||||
char *p;
|
||||
|
||||
if (!out || max < 2)
|
||||
return(-1);
|
||||
|
||||
out[0] = '\0';
|
||||
path[0] = '\0';
|
||||
|
||||
if (get_dir_path(dhandle, path) || !path[0])
|
||||
return(-1);
|
||||
|
||||
p = strchr(path, ':');
|
||||
if (p)
|
||||
p++;
|
||||
else
|
||||
p = path;
|
||||
|
||||
if (!*p)
|
||||
out[0] = '\0';
|
||||
else
|
||||
strmaxcpy(out, p, max - 1);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static void fd_help(void)
|
||||
{
|
||||
fprintf(stdout, "386 Usage: Flagdir [path [option...]]\n");
|
||||
fprintf(stdout, "Options: Normal\n");
|
||||
fprintf(stdout, " System\n");
|
||||
fprintf(stdout, " Hidden\n");
|
||||
fprintf(stdout, " Deleteinhibit\n");
|
||||
fprintf(stdout, " Purge\n");
|
||||
fprintf(stdout, " Renameinhibit\n");
|
||||
}
|
||||
|
||||
static int fd_attr_mask(char *s, uint32 *setbits, uint32 *clearbits)
|
||||
{
|
||||
if (tool_strsame(s, "N") || tool_strsame(s, "NORMAL")) {
|
||||
*clearbits |= FD_DIR_BITS;
|
||||
} else if (tool_strsame(s, "S") || tool_strsame(s, "SY") ||
|
||||
tool_strsame(s, "SYS") || tool_strsame(s, "SYSTEM")) {
|
||||
*setbits |= FD_NWFA_SY;
|
||||
} else if (tool_strsame(s, "H") || tool_strsame(s, "HIDDEN")) {
|
||||
*setbits |= FD_NWFA_H;
|
||||
} else if (tool_strsame(s, "DI") || tool_strsame(s, "DELETEINHIBIT")) {
|
||||
*setbits |= FD_NWFA_DI;
|
||||
} else if (tool_strsame(s, "P") || tool_strsame(s, "PURGE")) {
|
||||
*setbits |= FD_NWFA_P;
|
||||
} else if (tool_strsame(s, "RI") || tool_strsame(s, "RENAMEINHIBIT")) {
|
||||
*setbits |= FD_NWFA_RI;
|
||||
} else if (tool_strsame(s, "PRIVATE") || tool_strsame(s, "PR")) {
|
||||
fprintf(stderr, "Private is valid on NetWare 2.15 and above, except NetWare 386.\n");
|
||||
return(-1);
|
||||
} else {
|
||||
fprintf(stderr, "Unknown attribute: %s.\n", s);
|
||||
return(-1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
static void fd_print_attrs(uint32 attrs)
|
||||
{
|
||||
int any = 0;
|
||||
|
||||
if (!(attrs & FD_DIR_BITS)) {
|
||||
fprintf(stdout, "Normal\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (attrs & FD_NWFA_SY) {
|
||||
fprintf(stdout, "System");
|
||||
any = 1;
|
||||
}
|
||||
if (attrs & FD_NWFA_H) {
|
||||
fprintf(stdout, "%sHidden", any ? " " : "");
|
||||
any = 1;
|
||||
}
|
||||
if (attrs & FD_NWFA_DI) {
|
||||
fprintf(stdout, "%sDeleteInhibit", any ? " " : "");
|
||||
any = 1;
|
||||
}
|
||||
if (attrs & FD_NWFA_P) {
|
||||
fprintf(stdout, "%sPurge", any ? " " : "");
|
||||
any = 1;
|
||||
}
|
||||
if (attrs & FD_NWFA_RI) {
|
||||
fprintf(stdout, "%sRenameInhibit", any ? " " : "");
|
||||
any = 1;
|
||||
}
|
||||
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
|
||||
static void fd_display_header(char *path)
|
||||
{
|
||||
char up[260];
|
||||
char prefix[90];
|
||||
|
||||
tool_upcopy(up, path, sizeof(up));
|
||||
|
||||
if (tool_current_prefix(prefix, sizeof(prefix)))
|
||||
prefix[0] = '\0';
|
||||
|
||||
fprintf(stdout, "%s%s \n", prefix, up);
|
||||
}
|
||||
|
||||
static void fd_display_row(char *name, uint32 attrs)
|
||||
{
|
||||
char base[260];
|
||||
|
||||
tool_basename(base, name, sizeof(base));
|
||||
fprintf(stdout, " %-12.12s ", base);
|
||||
fd_print_attrs(attrs);
|
||||
}
|
||||
|
||||
static void fd_display(char *path, uint32 attrs)
|
||||
{
|
||||
fd_display_header(path);
|
||||
fd_display_row(path, attrs);
|
||||
}
|
||||
|
||||
static int fd_is_directory(char *path)
|
||||
{
|
||||
struct find_t ff;
|
||||
unsigned attr = _A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_SUBDIR | _A_ARCH;
|
||||
|
||||
if (tool_is_current_path(path))
|
||||
return(1);
|
||||
|
||||
if (_dos_findfirst(path, attr, &ff))
|
||||
return(0);
|
||||
|
||||
return((ff.attrib & _A_SUBDIR) != 0);
|
||||
}
|
||||
|
||||
static int fd_obtain(char *path, uint8 dhandle, uint32 *attrs)
|
||||
{
|
||||
if (c32_ncp87_obtain_rim_attributes(path, (uint16)dhandle,
|
||||
attrs, NULL, NULL, NULL) == 0)
|
||||
return(0);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
static int fd_modify(char *path, uint8 dhandle, uint32 attrs)
|
||||
{
|
||||
if (c32_ncp87_modify_dos_attributes(path, (uint16)dhandle, attrs,
|
||||
NULL, NULL, NULL) == 0)
|
||||
return(0);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
static int fd_process_one(char *path, char *display_path, uint8 dhandle,
|
||||
uint32 setbits, uint32 clearbits,
|
||||
int have_change, int show_header)
|
||||
{
|
||||
char *ncp_path;
|
||||
uint32 attrs;
|
||||
uint32 newattrs;
|
||||
|
||||
if (!fd_is_directory(path)) {
|
||||
fprintf(stderr, "Directory %s not found.\n", path);
|
||||
return(1);
|
||||
}
|
||||
|
||||
ncp_path = tool_is_current_path(path) ? "" : path;
|
||||
|
||||
if (fd_obtain(ncp_path, dhandle, &attrs)) {
|
||||
if (tool_is_current_path(path) && display_path && !display_path[0] &&
|
||||
!have_change) {
|
||||
attrs = 0;
|
||||
} else {
|
||||
fprintf(stderr, "Unable to get directory attributes.\n");
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (have_change) {
|
||||
newattrs = (attrs | setbits) & ~clearbits;
|
||||
if (newattrs != attrs) {
|
||||
if (fd_modify(ncp_path, dhandle, newattrs)) {
|
||||
fprintf(stderr, "Unable to change attributes.\n");
|
||||
return(1);
|
||||
}
|
||||
attrs = newattrs;
|
||||
fd_obtain(ncp_path, dhandle, &attrs);
|
||||
}
|
||||
}
|
||||
|
||||
if (show_header)
|
||||
fd_display(display_path, attrs);
|
||||
else
|
||||
fd_display_row(display_path, attrs);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int fd_process_wild(char *spec, uint8 dhandle,
|
||||
uint32 setbits, uint32 clearbits,
|
||||
int have_change)
|
||||
{
|
||||
struct find_t ff;
|
||||
char dir[260];
|
||||
char pat[260];
|
||||
char search[260];
|
||||
char full[260];
|
||||
int found = 0;
|
||||
int rc = 0;
|
||||
int lines = 0;
|
||||
int continuous = 0;
|
||||
unsigned attr = _A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_SUBDIR | _A_ARCH;
|
||||
|
||||
tool_parent_pattern(dir, pat, spec, sizeof(dir), sizeof(pat));
|
||||
tool_join_path(search, dir, pat, sizeof(search));
|
||||
|
||||
if (_dos_findfirst(search, attr, &ff) != 0) {
|
||||
fprintf(stderr, "Directory %s not found.\n", spec);
|
||||
return(1);
|
||||
}
|
||||
|
||||
fd_display_header(spec);
|
||||
|
||||
do {
|
||||
if ((ff.attrib & _A_SUBDIR) && strcmp(ff.name, ".") &&
|
||||
strcmp(ff.name, "..")) {
|
||||
tool_join_path(full, dir, ff.name, sizeof(full));
|
||||
if (fd_process_one(full, ff.name, dhandle, setbits, clearbits,
|
||||
have_change, 0))
|
||||
rc = 1;
|
||||
found++;
|
||||
tool_page_line(&lines, &continuous);
|
||||
}
|
||||
} while (_dos_findnext(&ff) == 0);
|
||||
|
||||
if (!found) {
|
||||
fprintf(stderr, "Directory %s not found.\n", spec);
|
||||
return(1);
|
||||
}
|
||||
|
||||
return(rc);
|
||||
}
|
||||
|
||||
int func_flagdir(int argc, char *argv[], int mode)
|
||||
{
|
||||
char *path = ".";
|
||||
char display_path[260];
|
||||
uint8 connid = 0;
|
||||
uint8 dhandle = 0;
|
||||
uint32 setbits = 0;
|
||||
uint32 clearbits = 0;
|
||||
int have_change = 0;
|
||||
int i;
|
||||
|
||||
(void)mode;
|
||||
|
||||
if (argc > 1 && (tool_strsame(argv[1], "/?") || tool_strsame(argv[1], "-?") ||
|
||||
tool_strsame(argv[1], "?"))) {
|
||||
fd_help();
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (argc > 1)
|
||||
path = argv[1];
|
||||
|
||||
if (tool_current_dhandle(&connid, &dhandle)) {
|
||||
fprintf(stderr, "FlagDir only works on network directories.\n");
|
||||
return(1);
|
||||
}
|
||||
|
||||
for (i = 2; i < argc; i++) {
|
||||
if (fd_attr_mask(argv[i], &setbits, &clearbits))
|
||||
return(1);
|
||||
have_change = 1;
|
||||
}
|
||||
|
||||
if (tool_has_wildcards(path))
|
||||
return(fd_process_wild(path, dhandle, setbits, clearbits, have_change));
|
||||
|
||||
if (tool_is_current_path(path)) {
|
||||
if (fd_current_display_path(dhandle, display_path, sizeof(display_path)))
|
||||
strcpy(display_path, ".");
|
||||
} else {
|
||||
strmaxcpy(display_path, path, sizeof(display_path) - 1);
|
||||
}
|
||||
|
||||
return(fd_process_one(path, display_path, dhandle,
|
||||
setbits, clearbits, have_change, 1));
|
||||
}
|
||||
345
grant.c
Normal file
345
grant.c
Normal file
@@ -0,0 +1,345 @@
|
||||
/* grant.c - Novell GRANT-like DOS utility, first Client32 implementation */
|
||||
|
||||
#include "net.h"
|
||||
#include "c32ncp.h"
|
||||
|
||||
#define GRANT_BINDERY_USER 0x0001
|
||||
#define GRANT_BINDERY_GROUP 0x0002
|
||||
|
||||
#define NCP_RIGHT_READ 0x0001
|
||||
#define NCP_RIGHT_WRITE 0x0002
|
||||
#define NCP_RIGHT_OPEN 0x0004
|
||||
#define NCP_RIGHT_CREATE 0x0008
|
||||
#define NCP_RIGHT_DELETE 0x0010
|
||||
#define NCP_RIGHT_OWNER 0x0020
|
||||
#define NCP_RIGHT_SEARCH 0x0040
|
||||
#define NCP_RIGHT_MODIFY 0x0080
|
||||
#define NCP_RIGHT_SUPER 0x0100
|
||||
|
||||
/* Novell GRANT ALL assigns all normal trustee rights, not Supervisor. */
|
||||
#define NCP_RIGHT_ALL_386 (NCP_RIGHT_READ | NCP_RIGHT_WRITE | \
|
||||
NCP_RIGHT_CREATE | NCP_RIGHT_DELETE | \
|
||||
NCP_RIGHT_MODIFY | NCP_RIGHT_SEARCH | \
|
||||
NCP_RIGHT_OWNER)
|
||||
|
||||
static void grant_usage_error(void)
|
||||
{
|
||||
fprintf(stdout, "Command line arguments violate grammar defined for GRANT.\n\n");
|
||||
}
|
||||
|
||||
static void grant_usage(void)
|
||||
{
|
||||
fprintf(stdout, "Usage: GRANT rightslist* [FOR path] TO [USER | GROUP] name [options]\n");
|
||||
fprintf(stdout, "Options: /SubDirectories | /Files\n\n");
|
||||
fprintf(stdout, "386 Rights:\n");
|
||||
fprintf(stdout, "--------------------\n");
|
||||
fprintf(stdout, "ALL = All\n");
|
||||
fprintf(stdout, "N = No Rights\n");
|
||||
fprintf(stdout, "S = Supervisor\n");
|
||||
fprintf(stdout, "R = Read\n");
|
||||
fprintf(stdout, "W = Write\n");
|
||||
fprintf(stdout, "C = Create\n");
|
||||
fprintf(stdout, "E = Erase\n");
|
||||
fprintf(stdout, "M = Modify\n");
|
||||
fprintf(stdout, "F = File Scan\n");
|
||||
fprintf(stdout, "A = Access Control\n");
|
||||
}
|
||||
|
||||
static void grant_rights_bracket(uint16 rights, char *out)
|
||||
{
|
||||
out[0] = (rights & NCP_RIGHT_SUPER) ? 'S' : ' ';
|
||||
out[1] = (rights & NCP_RIGHT_READ) ? 'R' : ' ';
|
||||
out[2] = (rights & NCP_RIGHT_WRITE) ? 'W' : ' ';
|
||||
out[3] = (rights & NCP_RIGHT_CREATE) ? 'C' : ' ';
|
||||
out[4] = (rights & NCP_RIGHT_DELETE) ? 'E' : ' ';
|
||||
out[5] = (rights & NCP_RIGHT_MODIFY) ? 'M' : ' ';
|
||||
out[6] = (rights & NCP_RIGHT_SEARCH) ? 'F' : ' ';
|
||||
out[7] = (rights & NCP_RIGHT_OWNER) ? 'A' : ' ';
|
||||
out[8] = '\0';
|
||||
}
|
||||
|
||||
|
||||
static void grant_rights_string(uint16 rights, char *out)
|
||||
{
|
||||
char *p = out;
|
||||
|
||||
if (rights == 0) {
|
||||
strcpy(out, "N");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((rights & NCP_RIGHT_ALL_386) == NCP_RIGHT_ALL_386) {
|
||||
strcpy(out, "ALL");
|
||||
return;
|
||||
}
|
||||
|
||||
if (rights & NCP_RIGHT_SUPER) *p++ = 'S';
|
||||
if (rights & NCP_RIGHT_READ) *p++ = 'R';
|
||||
if (rights & NCP_RIGHT_WRITE) *p++ = 'W';
|
||||
if (rights & NCP_RIGHT_CREATE) *p++ = 'C';
|
||||
if (rights & NCP_RIGHT_DELETE) *p++ = 'E';
|
||||
if (rights & NCP_RIGHT_MODIFY) *p++ = 'M';
|
||||
if (rights & NCP_RIGHT_SEARCH) *p++ = 'F';
|
||||
if (rights & NCP_RIGHT_OWNER) *p++ = 'A';
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
static int grant_add_right_word(char *s, uint16 *rights)
|
||||
{
|
||||
if (tool_strsame(s, "ALL")) {
|
||||
*rights = NCP_RIGHT_ALL_386;
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (tool_strsame(s, "N") || tool_strsame(s, "NONE")) {
|
||||
*rights = 0;
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (tool_strsame(s, "S") || tool_strsame(s, "SUPERVISOR")) {
|
||||
*rights |= NCP_RIGHT_SUPER;
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (tool_strsame(s, "R") || tool_strsame(s, "READ")) {
|
||||
*rights |= NCP_RIGHT_READ;
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (tool_strsame(s, "W") || tool_strsame(s, "WRITE")) {
|
||||
*rights |= NCP_RIGHT_WRITE;
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (tool_strsame(s, "C") || tool_strsame(s, "CREATE")) {
|
||||
*rights |= NCP_RIGHT_CREATE;
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (tool_strsame(s, "E") || tool_strsame(s, "ERASE")) {
|
||||
*rights |= NCP_RIGHT_DELETE;
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (tool_strsame(s, "M") || tool_strsame(s, "MODIFY")) {
|
||||
*rights |= NCP_RIGHT_MODIFY;
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (tool_strsame(s, "F") || tool_strsame(s, "FILESCAN") ||
|
||||
tool_strsame(s, "FILE") || tool_strsame(s, "SCAN")) {
|
||||
*rights |= NCP_RIGHT_SEARCH;
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (tool_strsame(s, "A") || tool_strsame(s, "ACCESS") ||
|
||||
tool_strsame(s, "CONTROL") || tool_strsame(s, "ACCESSCONTROL")) {
|
||||
*rights |= NCP_RIGHT_OWNER;
|
||||
return(0);
|
||||
}
|
||||
|
||||
return(-1);
|
||||
}
|
||||
|
||||
static int grant_last_rc = 0;
|
||||
|
||||
static int grant_set_one(char *path, uint16 dhandle,
|
||||
uint32 object_id, uint16 rights)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = c32_ncp87_add_trustee_rights(path,
|
||||
dhandle,
|
||||
object_id,
|
||||
rights,
|
||||
0xffff,
|
||||
NULL, NULL, NULL);
|
||||
grant_last_rc = rc;
|
||||
return(rc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Apply the grant to PATH and every directory below it.
|
||||
*
|
||||
* This intentionally walks through the DOS redirector, not through another
|
||||
* NCP search helper, so it works with the same mapped-drive view that the
|
||||
* user passed to GRANT.
|
||||
*/
|
||||
static int grant_set_subdirs(char *path, uint16 dhandle,
|
||||
uint32 object_id, uint16 rights)
|
||||
{
|
||||
struct find_t ff;
|
||||
char pattern[260];
|
||||
char child[260];
|
||||
int rc = 0;
|
||||
|
||||
if (grant_set_one(path, dhandle, object_id, rights))
|
||||
rc = 1;
|
||||
|
||||
tool_join_path(pattern, path, "*.*", sizeof(pattern));
|
||||
|
||||
if (_dos_findfirst(pattern, _A_SUBDIR, &ff) == 0) {
|
||||
do {
|
||||
if ((ff.attrib & _A_SUBDIR) && !tool_is_dot_dir(ff.name)) {
|
||||
tool_join_path(child, path, ff.name, sizeof(child));
|
||||
if (grant_set_subdirs(child, dhandle, object_id, rights))
|
||||
rc = 1;
|
||||
}
|
||||
} while (_dos_findnext(&ff) == 0);
|
||||
}
|
||||
|
||||
return(rc);
|
||||
}
|
||||
|
||||
|
||||
int func_grant(int argc, char *argv[], int mode)
|
||||
{
|
||||
uint16 rights = 0;
|
||||
char *path = ".";
|
||||
char *objname = NULL;
|
||||
uint16 objtype = GRANT_BINDERY_USER;
|
||||
uint8 connid = 0;
|
||||
uint8 dhandle = 0;
|
||||
uint8 namebuf[48];
|
||||
uint32 object_id;
|
||||
int recurse_subdirs = 0;
|
||||
int i = 1;
|
||||
int have_rights = 0;
|
||||
int rc;
|
||||
|
||||
(void)mode;
|
||||
|
||||
if (argc < 2 || tool_is_help_arg(argv[1])) {
|
||||
if (argc < 2)
|
||||
grant_usage_error();
|
||||
grant_usage();
|
||||
return(argc < 2 ? 1 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* GRANT rightslist* [FOR path] TO [USER|GROUP] name [options]
|
||||
*/
|
||||
while (i < argc) {
|
||||
if (tool_strsame(argv[i], "FOR") || tool_strsame(argv[i], "TO"))
|
||||
break;
|
||||
|
||||
if (tool_is_option(argv[i]))
|
||||
break;
|
||||
|
||||
if (grant_add_right_word(argv[i], &rights)) {
|
||||
grant_usage_error();
|
||||
grant_usage();
|
||||
return(1);
|
||||
}
|
||||
have_rights = 1;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (!have_rights || i >= argc) {
|
||||
grant_usage_error();
|
||||
grant_usage();
|
||||
return(1);
|
||||
}
|
||||
|
||||
if (tool_strsame(argv[i], "FOR")) {
|
||||
i++;
|
||||
if (i >= argc) {
|
||||
grant_usage_error();
|
||||
grant_usage();
|
||||
return(1);
|
||||
}
|
||||
path = argv[i++];
|
||||
}
|
||||
|
||||
if (i >= argc || !tool_strsame(argv[i], "TO")) {
|
||||
grant_usage_error();
|
||||
grant_usage();
|
||||
return(1);
|
||||
}
|
||||
i++;
|
||||
|
||||
if (i < argc && tool_strsame(argv[i], "USER")) {
|
||||
objtype = GRANT_BINDERY_USER;
|
||||
i++;
|
||||
} else if (i < argc && tool_strsame(argv[i], "GROUP")) {
|
||||
objtype = GRANT_BINDERY_GROUP;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i >= argc) {
|
||||
grant_usage_error();
|
||||
grant_usage();
|
||||
return(1);
|
||||
}
|
||||
|
||||
objname = argv[i++];
|
||||
|
||||
while (i < argc) {
|
||||
if (!tool_is_option(argv[i])) {
|
||||
grant_usage_error();
|
||||
grant_usage();
|
||||
return(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* /FILES is harmless because the explicit path is passed to the
|
||||
* NCP87 trustee-add call. /SUBDIRECTORIES recursively applies the
|
||||
* same grant to all subdirectories below the given path.
|
||||
*/
|
||||
if (tool_strsame(argv[i], "/FILES") || tool_strsame(argv[i], "-FILES") ||
|
||||
tool_strsame(argv[i], "/F") || tool_strsame(argv[i], "-F")) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tool_strsame(argv[i], "/SUBDIRECTORIES") ||
|
||||
tool_strsame(argv[i], "-SUBDIRECTORIES") ||
|
||||
tool_strsame(argv[i], "/S") || tool_strsame(argv[i], "-S")) {
|
||||
recurse_subdirs = 1;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
grant_usage_error();
|
||||
grant_usage();
|
||||
return(1);
|
||||
}
|
||||
|
||||
if (tool_current_dhandle(&connid, &dhandle)) {
|
||||
fprintf(stdout, "Specified path not locatable.\n");
|
||||
return(1);
|
||||
}
|
||||
|
||||
strmaxcpy(namebuf, objname, sizeof(namebuf) - 1);
|
||||
upstr(namebuf);
|
||||
object_id = ncp_17_35(namebuf, objtype);
|
||||
if (!object_id) {
|
||||
fprintf(stdout, "Object not found.\n");
|
||||
return(1);
|
||||
}
|
||||
|
||||
if (recurse_subdirs)
|
||||
rc = grant_set_subdirs(path, (uint16)dhandle, object_id, rights);
|
||||
else
|
||||
rc = grant_set_one(path, (uint16)dhandle, object_id, rights);
|
||||
|
||||
if (rc) {
|
||||
fprintf(stdout, "Could not add trustee rights. rc=%d\n", grant_last_rc);
|
||||
return(grant_last_rc ? grant_last_rc : 1);
|
||||
}
|
||||
|
||||
{
|
||||
char header[300];
|
||||
char base[80];
|
||||
char bracket[10];
|
||||
|
||||
tool_header_path(header, path, sizeof(header));
|
||||
tool_basename(base, path, sizeof(base));
|
||||
grant_rights_bracket(rights, bracket);
|
||||
|
||||
fprintf(stdout, "%s\n", header);
|
||||
fprintf(stdout, "%-29.29sRights set to [%s]\n", base, bracket);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
12
kern.h
12
kern.h
@@ -3,6 +3,8 @@
|
||||
#define KERN_CALL _Cdecl
|
||||
#else
|
||||
#define KERN_CALL
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
extern int KERN_CALL IPXinit(void);
|
||||
@@ -13,8 +15,14 @@ extern void asm_esr_routine(void);
|
||||
extern void esr_routine(ECB *ecb);
|
||||
extern void KERN_CALL xmemmove(void *ziel, void *quelle, UI anz);
|
||||
extern int KERN_CALL Net_Call(UI func, void *req, void *repl);
|
||||
|
||||
extern int KERN_CALL C32_MapVar_Probe(UI specLen, UI flag, void *outbuf);
|
||||
extern int KERN_CALL C32_OpenRef_Probe(UI refLo, UI refHi, void *outbuf);
|
||||
extern int KERN_CALL C32_NCP87_Raw5_Probe(UI connLo, UI connHi,
|
||||
void *hdr, UI hdrLen,
|
||||
void *path, UI pathLen,
|
||||
void *rep0, UI rep0Len,
|
||||
void *rep1, UI rep1Len,
|
||||
void *outbuf);
|
||||
#undef KERN_CALL
|
||||
|
||||
|
||||
|
||||
|
||||
750
kern_wasm.asm
750
kern_wasm.asm
@@ -20,7 +20,9 @@ public _IPXclose_socket
|
||||
public _IPXlisten
|
||||
public _xmemmove
|
||||
public _Net_Call
|
||||
|
||||
public _C32_NCP87_Raw5_Probe
|
||||
public _C32_OpenRef_Probe
|
||||
public _C32_MapVar_Probe
|
||||
_IPXinit proc far
|
||||
push bp
|
||||
mov bp, sp
|
||||
@@ -213,4 +215,750 @@ _Net_Call proc far
|
||||
ret
|
||||
_Net_Call endp
|
||||
|
||||
|
||||
|
||||
; int C32_OpenRef_Probe(UI refLo, UI refHi, void *outbuf)
|
||||
;
|
||||
; Opens a Client32 connection by connection reference using the same d32wrap
|
||||
; convention as _CONNOpenByReference / w95ocref.o.
|
||||
;
|
||||
; Input:
|
||||
; refLo/refHi = connection reference, e.g. C32PRIMREF returned 0028:0000.
|
||||
;
|
||||
; outbuf:
|
||||
; +00 load AX from D8C1
|
||||
; +02 resolver off
|
||||
; +04 resolver seg
|
||||
; +06 trampoline off
|
||||
; +08 trampoline seg
|
||||
; +0A function off
|
||||
; +0C function seg
|
||||
; +0E return AX
|
||||
; +10 return DX
|
||||
; +12 handle low
|
||||
; +14 handle high
|
||||
_C32_OpenRef_Probe proc far
|
||||
push bp
|
||||
mov bp, sp
|
||||
sub sp, 80
|
||||
|
||||
push ds
|
||||
push es
|
||||
push si
|
||||
push di
|
||||
|
||||
; clear ESI/ECX
|
||||
db 66h, 33h, 0F6h
|
||||
db 66h, 33h, 0C9h
|
||||
|
||||
mov ax, 0D8C1h
|
||||
int 2Fh
|
||||
|
||||
mov [bp-4], ax ; load AX
|
||||
; resolver ESI -> [bp-8]
|
||||
db 66h, 89h, 76h, 0F8h
|
||||
; trampoline ECX -> [bp-12]
|
||||
db 66h, 89h, 4Eh, 0F4h
|
||||
|
||||
or ax, ax
|
||||
jne c32openref_fail
|
||||
|
||||
; resolve "CONNOpenByReference"
|
||||
push cs
|
||||
push offset c32openref_name
|
||||
push 0
|
||||
push 0
|
||||
call dword ptr [bp-8]
|
||||
add sp, 8
|
||||
mov [bp-16], ax
|
||||
mov [bp-14], dx
|
||||
or ax, dx
|
||||
jne c32openref_have_func
|
||||
jmp c32openref_fail
|
||||
|
||||
c32openref_have_func:
|
||||
; local output handle dword at [bp-20]
|
||||
mov word ptr [bp-20], 0
|
||||
mov word ptr [bp-18], 0
|
||||
|
||||
; MapLockFlat(&handle, 4) -> flat [bp-24]
|
||||
push 0
|
||||
push 4
|
||||
push ss
|
||||
lea ax, -20[bp]
|
||||
push ax
|
||||
push 0
|
||||
push 2
|
||||
call dword ptr [bp-8]
|
||||
add sp, 0cH
|
||||
mov [bp-24], ax
|
||||
mov [bp-22], dx
|
||||
|
||||
; Call NIOS trampoline command 5 / CONNOpenByReference.
|
||||
; This matches d32wrap _CONNOpenByReference after w95ocref:
|
||||
; flat handle ptr,
|
||||
; refHi/refLo,
|
||||
; 0,0,
|
||||
; FEFE FEFE FEFE FEFE,
|
||||
; command 5,
|
||||
; function ptr.
|
||||
push word ptr [bp-22] ; flat handle high
|
||||
push word ptr [bp-24] ; flat handle low
|
||||
push word ptr [bp+8] ; ref high
|
||||
push word ptr [bp+6] ; ref low
|
||||
push 0
|
||||
push 0
|
||||
push 0fefeH
|
||||
push 0fefeH
|
||||
push 0fefeH
|
||||
push 0fefeH
|
||||
push 0
|
||||
push 5
|
||||
push word ptr [bp-14] ; function seg
|
||||
push word ptr [bp-16] ; function off
|
||||
call dword ptr [bp-12]
|
||||
add sp, 1cH
|
||||
|
||||
mov [bp-28], ax
|
||||
mov [bp-26], dx
|
||||
|
||||
; UnlockFlat(handle flat, 4)
|
||||
push 0
|
||||
push 4
|
||||
push word ptr [bp-22]
|
||||
push word ptr [bp-24]
|
||||
push 0
|
||||
push 3
|
||||
call dword ptr [bp-8]
|
||||
add sp, 0cH
|
||||
|
||||
jmp short c32openref_store
|
||||
|
||||
c32openref_fail:
|
||||
mov word ptr [bp-16], 0
|
||||
mov word ptr [bp-14], 0
|
||||
mov word ptr [bp-28], 0ffffH
|
||||
mov word ptr [bp-26], 0ffffH
|
||||
mov word ptr [bp-20], 0
|
||||
mov word ptr [bp-18], 0
|
||||
|
||||
c32openref_store:
|
||||
les di, dword ptr [bp+10]
|
||||
|
||||
mov ax, [bp-4]
|
||||
mov es:[di+0], ax
|
||||
mov ax, [bp-8]
|
||||
mov es:[di+2], ax
|
||||
mov ax, [bp-6]
|
||||
mov es:[di+4], ax
|
||||
mov ax, [bp-12]
|
||||
mov es:[di+6], ax
|
||||
mov ax, [bp-10]
|
||||
mov es:[di+8], ax
|
||||
mov ax, [bp-16]
|
||||
mov es:[di+10], ax
|
||||
mov ax, [bp-14]
|
||||
mov es:[di+12], ax
|
||||
mov ax, [bp-28]
|
||||
mov es:[di+14], ax
|
||||
mov ax, [bp-26]
|
||||
mov es:[di+16], ax
|
||||
mov ax, [bp-20]
|
||||
mov es:[di+18], ax
|
||||
mov ax, [bp-18]
|
||||
mov es:[di+20], ax
|
||||
|
||||
pop di
|
||||
pop si
|
||||
pop es
|
||||
pop ds
|
||||
mov sp, bp
|
||||
pop bp
|
||||
xor ah, ah
|
||||
ret
|
||||
|
||||
c32openref_name db 'CONNOpenByReference',0
|
||||
|
||||
_C32_OpenRef_Probe endp
|
||||
|
||||
|
||||
|
||||
; int C32_MapVar_Probe(UI specLen, UI flag, void *outbuf)
|
||||
;
|
||||
; Exact-ish raw version of w95mconn.o::__C32MapConn16To32 second step.
|
||||
;
|
||||
; It emulates:
|
||||
; C32MAPCONNONE 40 -> server name MARS
|
||||
; NWCSCANCONNINFO(scanIterator/result ptr,
|
||||
; scanInfoLevel=0A, scanConnInfo=NWCString/SPECTDATA "MARS",
|
||||
; scanFlags=1, connInfoVersion=0,
|
||||
; returnInfoLevel=0, returnConnInfo=NULL,
|
||||
; connReference local)
|
||||
;
|
||||
; But calls Client32 CONNScanInfo directly through ECX/NIOS command 0A.
|
||||
;
|
||||
; outbuf:
|
||||
; +00 load AX
|
||||
; +02 resolver off
|
||||
; +04 resolver seg
|
||||
; +06 trampoline off
|
||||
; +08 trampoline seg
|
||||
; +0A function off
|
||||
; +0C function seg
|
||||
; +0E ret AX
|
||||
; +10 ret DX
|
||||
; +12 resultRef low ; corresponds to caller output ptr in w95mconn
|
||||
; +14 resultRef high
|
||||
; +16 connRefLocal low ; corresponds to d32conni local -1c
|
||||
; +18 connRefLocal high
|
||||
_C32_MapVar_Probe proc far
|
||||
push bp
|
||||
mov bp, sp
|
||||
sub sp, 140
|
||||
|
||||
push ds
|
||||
push es
|
||||
push si
|
||||
push di
|
||||
|
||||
; clear ESI/ECX
|
||||
db 66h, 33h, 0F6h
|
||||
db 66h, 33h, 0C9h
|
||||
|
||||
mov ax, 0D8C1h
|
||||
int 2Fh
|
||||
|
||||
mov [bp-4], ax ; load AX
|
||||
; resolver ESI -> [bp-8]
|
||||
db 66h, 89h, 76h, 0F8h
|
||||
; trampoline ECX -> [bp-12]
|
||||
db 66h, 89h, 4Eh, 0F4h
|
||||
|
||||
or ax, ax
|
||||
jne c32mapvar_fail
|
||||
|
||||
; resolve "CONNScanInfo"
|
||||
push cs
|
||||
push offset c32mapvar_name
|
||||
push 0
|
||||
push 0
|
||||
call dword ptr [bp-8]
|
||||
add sp, 8
|
||||
mov [bp-16], ax
|
||||
mov [bp-14], dx
|
||||
or ax, dx
|
||||
jne c32mapvar_have_func
|
||||
jmp c32mapvar_fail
|
||||
|
||||
c32mapvar_have_func:
|
||||
; resultRef/output dword at [bp-20], init 0
|
||||
mov word ptr [bp-20], 0
|
||||
mov word ptr [bp-18], 0
|
||||
|
||||
; connReference local dword at [bp-24], init 0
|
||||
mov word ptr [bp-24], 0
|
||||
mov word ptr [bp-22], 0
|
||||
|
||||
; string buffer at [bp-80], copy "MARS", zero padded enough
|
||||
lea di, -80[bp]
|
||||
push ss
|
||||
pop es
|
||||
mov byte ptr es:[di+0], 'M'
|
||||
mov byte ptr es:[di+1], 'A'
|
||||
mov byte ptr es:[di+2], 'R'
|
||||
mov byte ptr es:[di+3], 'S'
|
||||
mov byte ptr es:[di+4], 0
|
||||
|
||||
; Map string buffer len 31h -> [bp-28]
|
||||
push 0
|
||||
push 31H
|
||||
push ss
|
||||
lea ax, -80[bp]
|
||||
push ax
|
||||
push 0
|
||||
push 2
|
||||
call dword ptr [bp-8]
|
||||
add sp, 0cH
|
||||
mov [bp-28], ax
|
||||
mov [bp-26], dx
|
||||
|
||||
; Build SPECTDATA/NWCString transfer block at [bp-48], len 10h.
|
||||
; Mirrors d32conni initialization for server-name scan.
|
||||
mov ax, [bp+6]
|
||||
mov word ptr [bp-48], ax
|
||||
mov word ptr [bp-46], 0
|
||||
mov ax, [bp-28]
|
||||
mov word ptr [bp-44], ax
|
||||
mov ax, [bp-26]
|
||||
mov word ptr [bp-42], ax
|
||||
mov word ptr [bp-40], 1
|
||||
mov word ptr [bp-38], 0
|
||||
mov word ptr [bp-36], 0
|
||||
mov word ptr [bp-34], 0
|
||||
|
||||
; Map scanInfo spectdata block len 10h -> [bp-32]
|
||||
push 0
|
||||
push 10H
|
||||
push ss
|
||||
lea ax, -48[bp]
|
||||
push ax
|
||||
push 0
|
||||
push 2
|
||||
call dword ptr [bp-8]
|
||||
add sp, 0cH
|
||||
mov [bp-32], ax
|
||||
mov [bp-30], dx
|
||||
|
||||
; Map resultRef/output len4 -> [bp-56] (this is w95mconn caller ptr)
|
||||
push 0
|
||||
push 4
|
||||
push ss
|
||||
lea ax, -20[bp]
|
||||
push ax
|
||||
push 0
|
||||
push 2
|
||||
call dword ptr [bp-8]
|
||||
add sp, 0cH
|
||||
mov [bp-56], ax
|
||||
mov [bp-54], dx
|
||||
|
||||
; Map connReference local len4 -> [bp-60]
|
||||
push 0
|
||||
push 4
|
||||
push ss
|
||||
lea ax, -24[bp]
|
||||
push ax
|
||||
push 0
|
||||
push 2
|
||||
call dword ptr [bp-8]
|
||||
add sp, 0cH
|
||||
mov [bp-60], ax
|
||||
mov [bp-58], dx
|
||||
|
||||
; Raw CONNScanInfo via NIOS, following d32wrap _CONNScanInfo
|
||||
; argument order from d32conni L$115.
|
||||
push word ptr [bp-58] ; connReference flat high
|
||||
push word ptr [bp-60] ; connReference flat low
|
||||
|
||||
push 0 ; returnConnInfo flat high = NULL
|
||||
push 0 ; returnConnInfo flat low = NULL
|
||||
|
||||
push 0 ; returnInfoLen high
|
||||
push 0 ; returnInfoLen low
|
||||
|
||||
push 0 ; returnInfoLevel high
|
||||
push 4 ; returnInfoLevel low, as d32conni L$115
|
||||
|
||||
push 0 ; scan flag high
|
||||
push word ptr [bp+8] ; scan flag low
|
||||
|
||||
push word ptr [bp-30] ; scanInfo flat high
|
||||
push word ptr [bp-32] ; scanInfo flat low
|
||||
|
||||
push 0 ; scanInfoLevel high
|
||||
push 0aH ; scanInfoLevel low = SERVER_NAME
|
||||
|
||||
push word ptr [bp-54] ; scanIterator/result flat high
|
||||
push word ptr [bp-56] ; scanIterator/result flat low
|
||||
|
||||
push 0fefeH
|
||||
push 0fefeH
|
||||
push 0fefeH
|
||||
push 0fefeH
|
||||
|
||||
push 0
|
||||
push 0aH
|
||||
push word ptr [bp-14]
|
||||
push word ptr [bp-16]
|
||||
call dword ptr [bp-12]
|
||||
add sp, 30H
|
||||
|
||||
mov [bp-64], ax
|
||||
mov [bp-62], dx
|
||||
|
||||
; Unlock maps.
|
||||
push 0
|
||||
push 4
|
||||
push word ptr [bp-58]
|
||||
push word ptr [bp-60]
|
||||
push 0
|
||||
push 3
|
||||
call dword ptr [bp-8]
|
||||
add sp, 0cH
|
||||
|
||||
push 0
|
||||
push 4
|
||||
push word ptr [bp-54]
|
||||
push word ptr [bp-56]
|
||||
push 0
|
||||
push 3
|
||||
call dword ptr [bp-8]
|
||||
add sp, 0cH
|
||||
|
||||
push 0
|
||||
push 10H
|
||||
push word ptr [bp-30]
|
||||
push word ptr [bp-32]
|
||||
push 0
|
||||
push 3
|
||||
call dword ptr [bp-8]
|
||||
add sp, 0cH
|
||||
|
||||
push 0
|
||||
push 31H
|
||||
push word ptr [bp-26]
|
||||
push word ptr [bp-28]
|
||||
push 0
|
||||
push 3
|
||||
call dword ptr [bp-8]
|
||||
add sp, 0cH
|
||||
|
||||
jmp short c32mapvar_store
|
||||
|
||||
c32mapvar_fail:
|
||||
mov word ptr [bp-16], 0
|
||||
mov word ptr [bp-14], 0
|
||||
mov word ptr [bp-64], 0ffffH
|
||||
mov word ptr [bp-62], 0ffffH
|
||||
mov word ptr [bp-20], 0
|
||||
mov word ptr [bp-18], 0
|
||||
mov word ptr [bp-24], 0
|
||||
mov word ptr [bp-22], 0
|
||||
|
||||
c32mapvar_store:
|
||||
les di, dword ptr [bp+10]
|
||||
|
||||
mov ax, [bp-4]
|
||||
mov es:[di+0], ax
|
||||
mov ax, [bp-8]
|
||||
mov es:[di+2], ax
|
||||
mov ax, [bp-6]
|
||||
mov es:[di+4], ax
|
||||
mov ax, [bp-12]
|
||||
mov es:[di+6], ax
|
||||
mov ax, [bp-10]
|
||||
mov es:[di+8], ax
|
||||
mov ax, [bp-16]
|
||||
mov es:[di+10], ax
|
||||
mov ax, [bp-14]
|
||||
mov es:[di+12], ax
|
||||
mov ax, [bp-64]
|
||||
mov es:[di+14], ax
|
||||
mov ax, [bp-62]
|
||||
mov es:[di+16], ax
|
||||
mov ax, [bp-20]
|
||||
mov es:[di+18], ax
|
||||
mov ax, [bp-18]
|
||||
mov es:[di+20], ax
|
||||
mov ax, [bp-24]
|
||||
mov es:[di+22], ax
|
||||
mov ax, [bp-22]
|
||||
mov es:[di+24], ax
|
||||
|
||||
pop di
|
||||
pop si
|
||||
pop es
|
||||
pop ds
|
||||
mov sp, bp
|
||||
pop bp
|
||||
xor ah, ah
|
||||
ret
|
||||
|
||||
c32mapvar_name db 'CONNScanInfo',0
|
||||
|
||||
_C32_MapVar_Probe endp
|
||||
|
||||
|
||||
|
||||
|
||||
; int C32_NCP87_Raw5_Probe(UI connLo, UI connHi,
|
||||
; void *hdr, UI hdrLen,
|
||||
; void *path, UI pathLen,
|
||||
; void *rep0, UI rep0Len,
|
||||
; void *rep1, UI rep1Len,
|
||||
; void *outbuf)
|
||||
;
|
||||
; Same as C32_NCP87_Raw_Probe but uses d32wrap-compatible 5-slot
|
||||
; fragment tables: 5 * 8 = 0x28 bytes for request and reply.
|
||||
_C32_NCP87_Raw5_Probe proc far
|
||||
push bp
|
||||
mov bp, sp
|
||||
sub sp, 180
|
||||
|
||||
push ds
|
||||
push es
|
||||
push si
|
||||
push di
|
||||
|
||||
; clear ESI/ECX
|
||||
db 66h, 33h, 0F6h
|
||||
db 66h, 33h, 0C9h
|
||||
|
||||
mov ax, 0D8C1h
|
||||
int 2Fh
|
||||
|
||||
mov [bp-2], ax
|
||||
db 66h, 89h, 76h, 0FAh ; resolver at [bp-6]
|
||||
db 66h, 89h, 4Eh, 0F6h ; trampoline at [bp-10]
|
||||
|
||||
or ax, ax
|
||||
jne raw5_fail
|
||||
|
||||
; resolve COMPATNcpRequestReply
|
||||
push cs
|
||||
push offset raw5_name
|
||||
push 0
|
||||
push 0
|
||||
call dword ptr [bp-6]
|
||||
add sp, 8
|
||||
mov [bp-14], ax
|
||||
mov [bp-12], dx
|
||||
or ax, dx
|
||||
jne raw5_have_func
|
||||
jmp raw5_fail
|
||||
|
||||
raw5_have_func:
|
||||
; actual reply len dword at [bp-36]
|
||||
mov word ptr [bp-36], 0
|
||||
mov word ptr [bp-34], 0
|
||||
|
||||
; map hdr -> [bp-20]
|
||||
push 0
|
||||
push word ptr [bp+0eH]
|
||||
push word ptr [bp+0cH]
|
||||
push word ptr [bp+0aH]
|
||||
push 0
|
||||
push 2
|
||||
call dword ptr [bp-6]
|
||||
add sp, 0cH
|
||||
mov [bp-20], ax
|
||||
mov [bp-18], dx
|
||||
|
||||
; map path -> [bp-24]
|
||||
push 0
|
||||
push word ptr [bp+14H]
|
||||
push word ptr [bp+12H]
|
||||
push word ptr [bp+10H]
|
||||
push 0
|
||||
push 2
|
||||
call dword ptr [bp-6]
|
||||
add sp, 0cH
|
||||
mov [bp-24], ax
|
||||
mov [bp-22], dx
|
||||
|
||||
; map rep0 -> [bp-28]
|
||||
push 0
|
||||
push word ptr [bp+1aH]
|
||||
push word ptr [bp+18H]
|
||||
push word ptr [bp+16H]
|
||||
push 0
|
||||
push 2
|
||||
call dword ptr [bp-6]
|
||||
add sp, 0cH
|
||||
mov [bp-28], ax
|
||||
mov [bp-26], dx
|
||||
|
||||
; map rep1 -> [bp-32]
|
||||
push 0
|
||||
push word ptr [bp+20H]
|
||||
push word ptr [bp+1eH]
|
||||
push word ptr [bp+1cH]
|
||||
push 0
|
||||
push 2
|
||||
call dword ptr [bp-6]
|
||||
add sp, 0cH
|
||||
mov [bp-32], ax
|
||||
mov [bp-30], dx
|
||||
|
||||
; zero req table [bp-160] len 40 and reply table [bp-120] len 40
|
||||
push ss
|
||||
pop es
|
||||
cld
|
||||
xor ax, ax
|
||||
lea di, -160[bp]
|
||||
mov cx, 20
|
||||
rep stosw
|
||||
lea di, -120[bp]
|
||||
mov cx, 20
|
||||
rep stosw
|
||||
|
||||
; req entry0 = hdr
|
||||
mov ax, [bp-20]
|
||||
mov [bp-160], ax
|
||||
mov ax, [bp-18]
|
||||
mov [bp-158], ax
|
||||
mov ax, [bp+0eH]
|
||||
mov [bp-156], ax
|
||||
mov word ptr [bp-154], 0
|
||||
|
||||
; req entry1 = path
|
||||
mov ax, [bp-24]
|
||||
mov [bp-152], ax
|
||||
mov ax, [bp-22]
|
||||
mov [bp-150], ax
|
||||
mov ax, [bp+14H]
|
||||
mov [bp-148], ax
|
||||
mov word ptr [bp-146], 0
|
||||
|
||||
; reply entry0 = rep0
|
||||
mov ax, [bp-28]
|
||||
mov [bp-120], ax
|
||||
mov ax, [bp-26]
|
||||
mov [bp-118], ax
|
||||
mov ax, [bp+1aH]
|
||||
mov [bp-116], ax
|
||||
mov word ptr [bp-114], 0
|
||||
|
||||
; reply entry1 = rep1
|
||||
mov ax, [bp-32]
|
||||
mov [bp-112], ax
|
||||
mov ax, [bp-30]
|
||||
mov [bp-110], ax
|
||||
mov ax, [bp+20H]
|
||||
mov [bp-108], ax
|
||||
mov word ptr [bp-106], 0
|
||||
|
||||
; map req table 0x28 -> [bp-40]
|
||||
push 0
|
||||
push 28H
|
||||
push ss
|
||||
lea ax, -160[bp]
|
||||
push ax
|
||||
push 0
|
||||
push 2
|
||||
call dword ptr [bp-6]
|
||||
add sp, 0cH
|
||||
mov [bp-40], ax
|
||||
mov [bp-38], dx
|
||||
|
||||
; map reply table 0x28 -> [bp-44]
|
||||
push 0
|
||||
push 28H
|
||||
push ss
|
||||
lea ax, -120[bp]
|
||||
push ax
|
||||
push 0
|
||||
push 2
|
||||
call dword ptr [bp-6]
|
||||
add sp, 0cH
|
||||
mov [bp-44], ax
|
||||
mov [bp-42], dx
|
||||
|
||||
; map actual reply len -> [bp-48]
|
||||
push 0
|
||||
push 4
|
||||
push ss
|
||||
lea ax, -36[bp]
|
||||
push ax
|
||||
push 0
|
||||
push 2
|
||||
call dword ptr [bp-6]
|
||||
add sp, 0cH
|
||||
mov [bp-48], ax
|
||||
mov [bp-46], dx
|
||||
|
||||
; call COMPAT via NIOS command 8
|
||||
push word ptr [bp-46]
|
||||
push word ptr [bp-48]
|
||||
push word ptr [bp-42]
|
||||
push word ptr [bp-44]
|
||||
push 0
|
||||
push 2
|
||||
push word ptr [bp-38]
|
||||
push word ptr [bp-40]
|
||||
push 0
|
||||
push 2
|
||||
push 0
|
||||
push 57H
|
||||
push 0
|
||||
push 0
|
||||
push word ptr [bp+8]
|
||||
push word ptr [bp+6]
|
||||
push 0
|
||||
push 8
|
||||
push word ptr [bp-12]
|
||||
push word ptr [bp-14]
|
||||
call dword ptr [bp-10]
|
||||
add sp, 28H
|
||||
|
||||
mov [bp-52], ax
|
||||
mov [bp-50], dx
|
||||
|
||||
; unlock important mappings only; ignore return
|
||||
push 0
|
||||
push 4
|
||||
push word ptr [bp-46]
|
||||
push word ptr [bp-48]
|
||||
push 0
|
||||
push 3
|
||||
call dword ptr [bp-6]
|
||||
add sp, 0cH
|
||||
|
||||
push 0
|
||||
push 28H
|
||||
push word ptr [bp-42]
|
||||
push word ptr [bp-44]
|
||||
push 0
|
||||
push 3
|
||||
call dword ptr [bp-6]
|
||||
add sp, 0cH
|
||||
|
||||
push 0
|
||||
push 28H
|
||||
push word ptr [bp-38]
|
||||
push word ptr [bp-40]
|
||||
push 0
|
||||
push 3
|
||||
call dword ptr [bp-6]
|
||||
add sp, 0cH
|
||||
|
||||
jmp short raw5_store
|
||||
|
||||
raw5_fail:
|
||||
mov word ptr [bp-14], 0
|
||||
mov word ptr [bp-12], 0
|
||||
mov word ptr [bp-52], 0ffffH
|
||||
mov word ptr [bp-50], 0ffffH
|
||||
mov word ptr [bp-36], 0
|
||||
mov word ptr [bp-34], 0
|
||||
|
||||
raw5_store:
|
||||
les di, dword ptr [bp+22H]
|
||||
mov ax, [bp-2]
|
||||
mov es:[di+0], ax
|
||||
mov ax, [bp-6]
|
||||
mov es:[di+2], ax
|
||||
mov ax, [bp-4]
|
||||
mov es:[di+4], ax
|
||||
mov ax, [bp-10]
|
||||
mov es:[di+6], ax
|
||||
mov ax, [bp-8]
|
||||
mov es:[di+8], ax
|
||||
mov ax, [bp-14]
|
||||
mov es:[di+10], ax
|
||||
mov ax, [bp-12]
|
||||
mov es:[di+12], ax
|
||||
mov ax, [bp-52]
|
||||
mov es:[di+14], ax
|
||||
mov ax, [bp-50]
|
||||
mov es:[di+16], ax
|
||||
mov ax, [bp-36]
|
||||
mov es:[di+18], ax
|
||||
mov ax, [bp-34]
|
||||
mov es:[di+20], ax
|
||||
|
||||
pop di
|
||||
pop si
|
||||
pop es
|
||||
pop ds
|
||||
mov sp, bp
|
||||
pop bp
|
||||
xor ah, ah
|
||||
ret
|
||||
|
||||
raw5_name db 'COMPATNcpRequestReply',0
|
||||
|
||||
_C32_NCP87_Raw5_Probe endp
|
||||
|
||||
|
||||
end
|
||||
|
||||
255
login.c
255
login.c
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "net.h"
|
||||
#include "nwcrypt.h"
|
||||
#include <time.h>
|
||||
|
||||
#ifndef BLACK
|
||||
#define BLACK 0
|
||||
@@ -115,12 +116,22 @@ static int login_help(void)
|
||||
|
||||
static void login_banner(void)
|
||||
{
|
||||
login_video_attr = 0x1f; /* white on blue */
|
||||
login_cls_attr(login_video_attr);
|
||||
login_fill_line(1, login_video_attr);
|
||||
login_write_attr(36, 1, "Mars NWE", login_video_attr);
|
||||
login_cls_attr(0x07); /* normal black background */
|
||||
|
||||
/*
|
||||
* NetWare-like header, but blue for Mars NWE:
|
||||
* blue separator
|
||||
* blue title line
|
||||
* blue separator
|
||||
* then normal black prompt area.
|
||||
*/
|
||||
login_fill_line(1, 0x1f); /* white on blue */
|
||||
login_fill_line(2, 0x1f); /* white on blue */
|
||||
login_write_attr(36, 2, "Mars NWE", 0x1f);
|
||||
login_fill_line(3, 0x1f); /* white on blue */
|
||||
|
||||
login_screen_normal();
|
||||
login_gotoxy(1, 3);
|
||||
login_gotoxy(1, 4);
|
||||
}
|
||||
|
||||
static char *skip_spaces(char *p)
|
||||
@@ -149,18 +160,100 @@ static void strip_quotes(char *s)
|
||||
*d = '\0';
|
||||
}
|
||||
|
||||
|
||||
static void script_get_timevar(char *name, char *out, int outlen)
|
||||
{
|
||||
time_t now;
|
||||
struct tm *tmv;
|
||||
int hour;
|
||||
static char *months[] = {
|
||||
"JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE",
|
||||
"JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER"
|
||||
};
|
||||
static char *days[] = {
|
||||
"SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY",
|
||||
"THURSDAY", "FRIDAY", "SATURDAY"
|
||||
};
|
||||
|
||||
*out = '\0';
|
||||
|
||||
time(&now);
|
||||
tmv = localtime(&now);
|
||||
if (!tmv) return;
|
||||
|
||||
upstr(name);
|
||||
|
||||
if (!strcmp(name, "GREETING_TIME")) {
|
||||
if (tmv->tm_hour < 12) strcpy(out, "MORNING");
|
||||
else if (tmv->tm_hour < 18) strcpy(out, "AFTERNOON");
|
||||
else strcpy(out, "EVENING");
|
||||
} else if (!strcmp(name, "MONTH_NAME")) {
|
||||
strmaxcpy(out, months[tmv->tm_mon], outlen - 1);
|
||||
} else if (!strcmp(name, "MONTH")) {
|
||||
sprintf(out, "%02d", tmv->tm_mon + 1);
|
||||
} else if (!strcmp(name, "DAY")) {
|
||||
sprintf(out, "%02d", tmv->tm_mday);
|
||||
} else if (!strcmp(name, "YEAR")) {
|
||||
sprintf(out, "%04d", tmv->tm_year + 1900);
|
||||
} else if (!strcmp(name, "DAY_OF_WEEK")) {
|
||||
strmaxcpy(out, days[tmv->tm_wday], outlen - 1);
|
||||
} else if (!strcmp(name, "HOUR")) {
|
||||
hour = tmv->tm_hour % 12;
|
||||
if (!hour) hour = 12;
|
||||
sprintf(out, "%d", hour);
|
||||
} else if (!strcmp(name, "MINUTE")) {
|
||||
sprintf(out, "%02d", tmv->tm_min);
|
||||
} else if (!strcmp(name, "SECOND")) {
|
||||
sprintf(out, "%02d", tmv->tm_sec);
|
||||
} else if (!strcmp(name, "AM_PM")) {
|
||||
strcpy(out, tmv->tm_hour >= 12 ? "PM" : "AM");
|
||||
}
|
||||
}
|
||||
|
||||
static void script_expand_var(char *name, char *out, int outlen)
|
||||
{
|
||||
upstr(name);
|
||||
*out = '\0';
|
||||
|
||||
if (!strcmp(name, "LOGIN_NAME")) {
|
||||
strmaxcpy(out, script_login_name, outlen - 1);
|
||||
} else if (!strcmp(name, "FILE_SERVER")) {
|
||||
strmaxcpy(out, script_file_server, outlen - 1);
|
||||
} else if (!strcmp(name, "P_STATION") || !strcmp(name, "STATION")) {
|
||||
strcpy(out, "000000000000");
|
||||
} else {
|
||||
script_get_timevar(name, out, outlen);
|
||||
if (!*out) {
|
||||
strcpy(out, "%");
|
||||
strncat(out, name, outlen - strlen(out) - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void script_put_expanded(char *s)
|
||||
{
|
||||
while (s && *s) {
|
||||
if (!strncmp(s, "%LOGIN_NAME", 11) || !strncmp(s, "%login_name", 11)) {
|
||||
fprintf(stdout, "%s", script_login_name);
|
||||
s += 11;
|
||||
} else if (!strncmp(s, "%FILE_SERVER", 12) || !strncmp(s, "%file_server", 12)) {
|
||||
fprintf(stdout, "%s", script_file_server);
|
||||
s += 12;
|
||||
} else if (!strncmp(s, "%P_STATION", 10) || !strncmp(s, "%p_station", 10)) {
|
||||
fprintf(stdout, "000000000000");
|
||||
s += 10;
|
||||
if (*s == '%') {
|
||||
char name[64];
|
||||
char value[128];
|
||||
int i = 0;
|
||||
|
||||
s++;
|
||||
while ((*s == '_' ||
|
||||
(*s >= 'A' && *s <= 'Z') ||
|
||||
(*s >= 'a' && *s <= 'z') ||
|
||||
(*s >= '0' && *s <= '9')) &&
|
||||
i < (int)sizeof(name) - 1) {
|
||||
name[i++] = *s++;
|
||||
}
|
||||
name[i] = '\0';
|
||||
|
||||
if (i) {
|
||||
script_expand_var(name, value, sizeof(value));
|
||||
fprintf(stdout, "%s", value);
|
||||
} else {
|
||||
fputc('%', stdout);
|
||||
}
|
||||
} else {
|
||||
fputc(*s++, stdout);
|
||||
}
|
||||
@@ -231,30 +324,52 @@ static int script_eval_if(char *line)
|
||||
|
||||
if (q != NULL) {
|
||||
char want[64];
|
||||
char *v;
|
||||
char have[64];
|
||||
int i = 0;
|
||||
|
||||
q += neg ? 2 : 1;
|
||||
q = skip_spaces(q);
|
||||
if (*q == '"' || *q == '\'') q++;
|
||||
|
||||
while (*q && *q != '"' && *q != '\'' && *q != 32 && *q != '\t' && i < 63) {
|
||||
while (*q && *q != '"' && *q != '\'' && *q != 32 && *q != '\t' && i < 63)
|
||||
want[i++] = *q++;
|
||||
}
|
||||
want[i] = '\0';
|
||||
|
||||
strmaxcpy(tmp, script_login_name, sizeof(tmp) - 1);
|
||||
upstr(tmp);
|
||||
strmaxcpy(have, script_login_name, sizeof(have) - 1);
|
||||
upstr(have);
|
||||
|
||||
if (neg) return(strcmp(tmp, want) != 0);
|
||||
else return(strcmp(tmp, want) == 0);
|
||||
if (neg) return(strcmp(have, want) != 0);
|
||||
return(strcmp(have, want) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
p = strstr(tmp, "DAY_OF_WEEK");
|
||||
if (p != NULL) {
|
||||
q = strchr(p, '=');
|
||||
if (q != NULL) {
|
||||
char want[64];
|
||||
char have[64];
|
||||
int i = 0;
|
||||
|
||||
q++;
|
||||
q = skip_spaces(q);
|
||||
if (*q == '"' || *q == '\'') q++;
|
||||
|
||||
while (*q && *q != '"' && *q != '\'' && *q != 32 && *q != '\t' && i < 63)
|
||||
want[i++] = *q++;
|
||||
want[i] = '\0';
|
||||
|
||||
strcpy(have, "DAY_OF_WEEK");
|
||||
script_get_timevar(have, have, sizeof(have));
|
||||
upstr(have);
|
||||
|
||||
return(strcmp(have, want) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
static int login_strnicmp(char *a, char *b, int n)
|
||||
{
|
||||
while (n-- > 0) {
|
||||
@@ -279,7 +394,7 @@ static int script_execute_line(char *line)
|
||||
strmaxcpy(work, line, sizeof(work) - 1);
|
||||
p = skip_spaces(work);
|
||||
|
||||
if (!*p) return(0);
|
||||
if (!*p || *p == ';') return(0);
|
||||
|
||||
i = 0;
|
||||
while (p[i] && p[i] != 32 && p[i] != '\t' && i < 31) {
|
||||
@@ -337,6 +452,13 @@ static int script_execute_line(char *line)
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (!strncmp(up, "ROOT ", 5)) {
|
||||
char callbuf[512];
|
||||
sprintf(callbuf, "MAP %s", skip_spaces(arg + 5));
|
||||
script_call_line(callbuf);
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (!strncmp(up, "INS ", 4) || !strncmp(up, "INSERT ", 7)) {
|
||||
char callbuf[512];
|
||||
char *a = arg;
|
||||
@@ -358,6 +480,10 @@ static int script_execute_line(char *line)
|
||||
}
|
||||
}
|
||||
|
||||
if (!strcmp(cmd, "ATTACH")) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (!strcmp(cmd, "EXIT")) {
|
||||
return(1);
|
||||
}
|
||||
@@ -366,20 +492,87 @@ static int script_execute_line(char *line)
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int try_login_script_file(char *name)
|
||||
{
|
||||
return(read_command_file(name));
|
||||
}
|
||||
|
||||
static int run_login_script(void)
|
||||
{
|
||||
char profile[200];
|
||||
char drive;
|
||||
|
||||
sprintf(profile, "%snet$log.dat", prgpath);
|
||||
if (read_command_file(profile) != -2) return(0);
|
||||
/*
|
||||
* Novell LOGIN looks for the system login script using server based paths,
|
||||
* for example \\SERVER\SYS\PUBLIC\NET$LOG.DAT. Try that first.
|
||||
*/
|
||||
if (*script_file_server) {
|
||||
sprintf(profile, "\\\\%s\\SYS\\PUBLIC\\NET$LOG.DAT", script_file_server);
|
||||
if (try_login_script_file(profile) != -2) return(0);
|
||||
|
||||
sprintf(profile, "%slogin", prgpath);
|
||||
if (read_command_file(profile) != -2) return(0);
|
||||
sprintf(profile, "\\\\%s\\SYS\\PUBLIC\\net$log.dat", script_file_server);
|
||||
if (try_login_script_file(profile) != -2) return(0);
|
||||
|
||||
if (read_command_file("net$log.dat") != -2) return(0);
|
||||
if (read_command_file("login") != -2) return(0);
|
||||
if (read_command_file("\\login\\login") != -2) return(0);
|
||||
if (read_command_file("\\login\\net$log.dat") != -2) return(0);
|
||||
sprintf(profile, "\\\\%s\\SYS\\LOGIN\\LOGIN", script_file_server);
|
||||
if (try_login_script_file(profile) != -2) return(0);
|
||||
|
||||
sprintf(profile, "\\\\%s\\SYS\\LOGIN\\NET$LOG.DAT", script_file_server);
|
||||
if (try_login_script_file(profile) != -2) return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Then try current directory and the executable path. LOGIN.EXE is often
|
||||
* executed from PUBLIC, so this covers SYS:PUBLIC\NET$LOG.DAT without
|
||||
* relying on an absolute drive path.
|
||||
*/
|
||||
if (try_login_script_file("NET$LOG.DAT") != -2) return(0);
|
||||
if (try_login_script_file("net$log.dat") != -2) return(0);
|
||||
if (try_login_script_file("LOGIN") != -2) return(0);
|
||||
if (try_login_script_file("login") != -2) return(0);
|
||||
|
||||
if (*prgpath) {
|
||||
sprintf(profile, "%sNET$LOG.DAT", prgpath);
|
||||
if (try_login_script_file(profile) != -2) return(0);
|
||||
|
||||
sprintf(profile, "%snet$log.dat", prgpath);
|
||||
if (try_login_script_file(profile) != -2) return(0);
|
||||
|
||||
sprintf(profile, "%sLOGIN", prgpath);
|
||||
if (try_login_script_file(profile) != -2) return(0);
|
||||
|
||||
sprintf(profile, "%slogin", prgpath);
|
||||
if (try_login_script_file(profile) != -2) return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fallbacks for requesters/runtimes that cannot open UNC from C fopen().
|
||||
*/
|
||||
if (try_login_script_file("\\PUBLIC\\NET$LOG.DAT") != -2) return(0);
|
||||
if (try_login_script_file("\\public\\net$log.dat") != -2) return(0);
|
||||
if (try_login_script_file("\\PUBLIC\\LOGIN") != -2) return(0);
|
||||
if (try_login_script_file("\\public\\login") != -2) return(0);
|
||||
|
||||
if (try_login_script_file("\\LOGIN\\LOGIN") != -2) return(0);
|
||||
if (try_login_script_file("\\login\\login") != -2) return(0);
|
||||
if (try_login_script_file("\\LOGIN\\NET$LOG.DAT") != -2) return(0);
|
||||
if (try_login_script_file("\\login\\net$log.dat") != -2) return(0);
|
||||
|
||||
for (drive = 'C'; drive <= 'Z'; drive++) {
|
||||
sprintf(profile, "%c:\\PUBLIC\\NET$LOG.DAT", drive);
|
||||
if (try_login_script_file(profile) != -2) return(0);
|
||||
|
||||
sprintf(profile, "%c:\\public\\net$log.dat", drive);
|
||||
if (try_login_script_file(profile) != -2) return(0);
|
||||
|
||||
sprintf(profile, "%c:\\PUBLIC\\LOGIN", drive);
|
||||
if (try_login_script_file(profile) != -2) return(0);
|
||||
|
||||
sprintf(profile, "%c:\\LOGIN\\LOGIN", drive);
|
||||
if (try_login_script_file(profile) != -2) return(0);
|
||||
|
||||
sprintf(profile, "%c:\\LOGIN\\NET$LOG.DAT", drive);
|
||||
if (try_login_script_file(profile) != -2) return(0);
|
||||
}
|
||||
|
||||
return(-2);
|
||||
}
|
||||
|
||||
306
map.c
306
map.c
@@ -28,9 +28,9 @@ static void show_map(uint8 *drvstr)
|
||||
if (flags & 0x80) { /* lokal DRIVE */
|
||||
path[0]= '\\';
|
||||
if (j < 2){
|
||||
strcpy(path, "DISK LW");
|
||||
strcpy(path, "maps to a local disk.");
|
||||
} else if (getcurdir(j+1, path+1)) {
|
||||
strcpy(path, "LW !OK");
|
||||
strcpy(path, "maps to a local disk.");
|
||||
}
|
||||
} else {
|
||||
if (get_dir_path(dhandle, path)) {
|
||||
@@ -41,7 +41,7 @@ static void show_map(uint8 *drvstr)
|
||||
strcat(servern, "\\");
|
||||
} else servern[0]='\0';
|
||||
}
|
||||
printf("MAP %c: = %s%s\n", (char)j+'A', servern, path);
|
||||
if (flags & 0x80) printf("Drive %c: %s\n", (char)j+'A', path); else printf("Drive %c: = %s%s\n", (char)j+'A', servern, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,9 +58,9 @@ static void do_map(int drive, NWPATH *nwp)
|
||||
if (flags & 0x80) { /* lokal DRIVE */
|
||||
path[0]= '\\';
|
||||
if (drive < 2){
|
||||
strcpy(path, "DISK LW");
|
||||
strcpy(path, "maps to a local disk.");
|
||||
} else if (getcurdir(drive+1, path+1)) {
|
||||
strcpy(path, "LW !OK");
|
||||
strcpy(path, "maps to a local disk.");
|
||||
}
|
||||
} else {
|
||||
if (get_dir_path(dhandle, path)) {
|
||||
@@ -188,11 +188,129 @@ static int parse_argv(uint8 *drvstr, NWPATH *nwpath,
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
static int parse_pathins_arg(uint8 *drvstr, NWPATH *nwp,
|
||||
int argc, char *argv[], int mode);
|
||||
static int set_search_native(uint8 *drvstr, NWPATH *nwp, int pathmode);
|
||||
static int show_search(uint8 *drvstr);
|
||||
|
||||
static int map_same_arg(char *a, char *b)
|
||||
{
|
||||
while (*a || *b) {
|
||||
int ca = *a++;
|
||||
int cb = *b++;
|
||||
if (ca >= 'a' && ca <= 'z') ca -= 32;
|
||||
if (cb >= 'a' && cb <= 'z') cb -= 32;
|
||||
if (ca != cb) return(0);
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
static int map_is_drive_arg(char *s)
|
||||
{
|
||||
if (!s || !s[0] || s[1] != ':' || s[2]) return(0);
|
||||
if (s[0] >= 'A' && s[0] <= 'Z') return(1);
|
||||
if (s[0] >= 'a' && s[0] <= 'z') return(1);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int map_drive_index(char *s)
|
||||
{
|
||||
if (s[0] >= 'a' && s[0] <= 'z') return(s[0] - 'a');
|
||||
return(s[0] - 'A');
|
||||
}
|
||||
|
||||
static void map_drive_name(char *dst, char *src)
|
||||
{
|
||||
dst[0] = src[0];
|
||||
if (dst[0] >= 'a' && dst[0] <= 'z') dst[0] -= 32;
|
||||
dst[1] = ':';
|
||||
dst[2] = '\0';
|
||||
}
|
||||
|
||||
static int map_handle_path_command(int argc, char *argv[], int pathmode)
|
||||
{
|
||||
uint8 drvstr[22];
|
||||
NWPATH nwpath;
|
||||
int rc;
|
||||
|
||||
rc = parse_pathins_arg(drvstr, &nwpath, argc, argv, pathmode);
|
||||
if (!rc) {
|
||||
int result = 0;
|
||||
|
||||
if (*(nwpath.path) || pathmode == 1)
|
||||
result = set_search_native(drvstr, &nwpath, pathmode);
|
||||
|
||||
if (result < 0)
|
||||
fprintf(stderr, "Cannot interpret line. errcode=-1\n");
|
||||
else if (pathmode != 1)
|
||||
show_search(drvstr);
|
||||
else
|
||||
fprintf(stdout, "The search mapping for drive S%d: was deleted\n",
|
||||
(int)drvstr[1]);
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
fprintf(stderr, "Cannot interpret line. errcode=-1\n");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
|
||||
int func_map(int argc, char *argv[], int mode)
|
||||
{
|
||||
uint8 drvstr[22];
|
||||
NWPATH nwpath;
|
||||
|
||||
if (!ipx_init()) argc = 1;
|
||||
|
||||
/*
|
||||
* Novell MAP accepts subcommands through MAP itself:
|
||||
* MAP DEL H:
|
||||
* MAP INS S1:=SYS:PUBLIC
|
||||
* MAP DEL S1:
|
||||
* The original mars-dosutils exposed those mainly as MAPDEL/PATHINS/PATHDEL,
|
||||
* so handle the Novell syntax here and then reuse the existing primitives.
|
||||
*/
|
||||
if (argc > 1) {
|
||||
if (map_same_arg(argv[1], "/?") || map_same_arg(argv[1], "-?") ||
|
||||
map_same_arg(argv[1], "?")) {
|
||||
fprintf(stderr, "Directory \"/?\" is not locatable.\n");
|
||||
return(1);
|
||||
}
|
||||
|
||||
if (map_same_arg(argv[1], "INS") || map_same_arg(argv[1], "INSERT")) {
|
||||
if (argc < 3) {
|
||||
fprintf(stderr, "Cannot interpret line. errcode=-1\n");
|
||||
return(1);
|
||||
}
|
||||
return(map_handle_path_command(argc - 1, argv + 1, 2));
|
||||
}
|
||||
|
||||
if (map_same_arg(argv[1], "DEL") || map_same_arg(argv[1], "DELETE")) {
|
||||
if (argc < 3) {
|
||||
fprintf(stderr, "Cannot interpret line. errcode=-1\n");
|
||||
return(1);
|
||||
}
|
||||
|
||||
if (map_is_drive_arg(argv[2])) {
|
||||
char dname[3];
|
||||
int drive = map_drive_index(argv[2]);
|
||||
|
||||
if (do_map(drive, &nwpath, 1) < 0) {
|
||||
fprintf(stderr, "Cannot interpret line. errcode=-1\n");
|
||||
return(1);
|
||||
}
|
||||
|
||||
map_drive_name(dname, argv[2]);
|
||||
fprintf(stdout, "The mapping for drive %s has been deleted.\n", dname);
|
||||
return(0);
|
||||
}
|
||||
|
||||
return(map_handle_path_command(argc - 1, argv + 1, 1));
|
||||
}
|
||||
}
|
||||
|
||||
if (!parse_argv(drvstr, &nwpath, argc, argv, 0, mode)) {
|
||||
if (*(nwpath.path) || mode==1) {
|
||||
if (do_map(*drvstr - 'A', &nwpath, mode)< 0)
|
||||
@@ -297,18 +415,192 @@ static int set_search(uint8 *drvstr, NWPATH *nwp, int pathmode)
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
static int path_is_drive_path(uint8 *path)
|
||||
{
|
||||
if (!path || !path[0] || path[1] != ':') return(0);
|
||||
if (path[0] >= 'A' && path[0] <= 'Z') return(1);
|
||||
if (path[0] >= 'a' && path[0] <= 'z') return(1);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static void upstr_local(uint8 *s)
|
||||
{
|
||||
while (*s) {
|
||||
if (*s >= 'a' && *s <= 'z') *s -= 0x20;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
static int parse_pathins_arg(uint8 *drvstr, NWPATH *nwp, int argc, char *argv[], int mode)
|
||||
{
|
||||
char joined[512];
|
||||
char *p;
|
||||
char *q;
|
||||
int slot = 0;
|
||||
int k;
|
||||
|
||||
*drvstr = '\0';
|
||||
memset(nwp, 0, sizeof(NWPATH));
|
||||
nwp->path = nwp->buff;
|
||||
*(nwp->buff) = '\0';
|
||||
|
||||
if (argc < 2) return(1);
|
||||
|
||||
joined[0] = '\0';
|
||||
for (k = 1; k < argc; k++) {
|
||||
if (k > 1) strcat(joined, " ");
|
||||
strncat(joined, argv[k], sizeof(joined) - strlen(joined) - 1);
|
||||
}
|
||||
|
||||
p = joined;
|
||||
while (*p == ' ' || *p == '\t') p++;
|
||||
|
||||
if (*p != 'S' && *p != 's') return(-1);
|
||||
p++;
|
||||
|
||||
while (*p >= '0' && *p <= '9') {
|
||||
slot = slot * 10 + (*p - '0');
|
||||
p++;
|
||||
}
|
||||
|
||||
if (slot < 1 || slot > 16) return(-1);
|
||||
if (*p != ':') return(-1);
|
||||
p++;
|
||||
|
||||
drvstr[0] = 's';
|
||||
drvstr[1] = (uint8)slot;
|
||||
drvstr[2] = '\0';
|
||||
|
||||
while (*p == ' ' || *p == '\t') p++;
|
||||
|
||||
if (mode == 1) {
|
||||
/* PATHDEL S1: */
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (*p == '=') p++;
|
||||
while (*p == ' ' || *p == '\t') p++;
|
||||
|
||||
if (!*p) return(-1);
|
||||
|
||||
q = nwp->buff;
|
||||
while (*p && (q - nwp->buff) < (int)sizeof(nwp->buff) - 1) {
|
||||
*q++ = *p++;
|
||||
}
|
||||
*q = '\0';
|
||||
|
||||
upstr_local(nwp->buff);
|
||||
nwp->path = nwp->buff;
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int set_search_native(uint8 *drvstr, NWPATH *nwp, int pathmode)
|
||||
{
|
||||
int result=-1;
|
||||
SEARCH_VECTOR drives;
|
||||
SEARCH_VECTOR_ENTRY *p=drives;
|
||||
int j=0;
|
||||
int entry = (*drvstr=='s') ? *(drvstr+1) : 0;
|
||||
|
||||
get_search_drive_vektor(drives);
|
||||
|
||||
while (p->drivenummer != 0xff && j++ < 16) {
|
||||
if (!entry && path_is_drive_path(nwp->path)
|
||||
&& (p->drivenummer + 'A' == nwp->path[0])) entry=j;
|
||||
|
||||
if (path_is_drive_path(nwp->path)
|
||||
&& p->drivenummer + 'A' == nwp->path[0]
|
||||
&& !strcmp(nwp->path+2, p->dospath)) {
|
||||
p->drivenummer=0xfe;
|
||||
*(p->dospath) = '\0';
|
||||
p->flags = 0;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
if (entry > 0) {
|
||||
if (entry > 16) entry = 16;
|
||||
|
||||
if (pathmode == 2 && entry <= j && entry < 16) { /* insert modus */
|
||||
int k=j+1-entry;
|
||||
if (j < 16) {
|
||||
p++;
|
||||
k++;
|
||||
j++;
|
||||
}
|
||||
while (k--) {
|
||||
memcpy(p, p-1, sizeof(SEARCH_VECTOR_ENTRY));
|
||||
--p;
|
||||
}
|
||||
}
|
||||
|
||||
if (--entry < j)
|
||||
p = drives+entry;
|
||||
else
|
||||
(p+1)->drivenummer = 0xff;
|
||||
|
||||
memset(p, 0, sizeof(SEARCH_VECTOR_ENTRY));
|
||||
|
||||
if (pathmode==1) {
|
||||
p->drivenummer = 0xfe;
|
||||
*(p->dospath) = '\0';
|
||||
result = set_search_drive_vektor(drives);
|
||||
} else if (path_is_drive_path(nwp->path)) {
|
||||
p->flags = 0;
|
||||
p->drivenummer = (uint8)(nwp->path[0] - 'A');
|
||||
if (nwp->path[0] >= 'a' && nwp->path[0] <= 'z')
|
||||
p->drivenummer = (uint8)(nwp->path[0] - 'a');
|
||||
strmaxcpy(p->dospath, nwp->path+2, sizeof(p->dospath)-1);
|
||||
result = set_search_drive_vektor(drives);
|
||||
} else {
|
||||
/*
|
||||
* Search path entries are not drive mappings. The original code stores
|
||||
* the NetWare path text directly in dospath with drivenummer=0xfe.
|
||||
* Client32 keeps/prints these entries correctly; allocating a permanent
|
||||
* directory handle here made set_search_drive_vektor() return success,
|
||||
* but the entry did not actually replace SEARCH1.
|
||||
*/
|
||||
p->flags = 0;
|
||||
p->drivenummer = 0xfe;
|
||||
strmaxcpy(p->dospath, nwp->path, sizeof(p->dospath)-1);
|
||||
result = set_search_drive_vektor(drives);
|
||||
}
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
int func_path(int argc, char *argv[], int mode)
|
||||
{
|
||||
uint8 drvstr[22];
|
||||
NWPATH nwpath;
|
||||
if (!parse_argv(drvstr, &nwpath, argc, argv, 1, mode)) {
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* PATH/PATHINS/PATHDEL need their own parser. The old parse_argv()
|
||||
* rejects common login-script syntax such as:
|
||||
* PATHINS S1:=SYS:PUBLIC
|
||||
* MAP INS S1:=SYS:PUBLIC
|
||||
*/
|
||||
if (argc < 2) {
|
||||
show_search("");
|
||||
return(0);
|
||||
}
|
||||
|
||||
rc = parse_pathins_arg(drvstr, &nwpath, argc, argv, mode);
|
||||
if (!rc) {
|
||||
int result=0;
|
||||
if (*(nwpath.path) || mode==1)
|
||||
result=set_search(drvstr, &nwpath, mode);
|
||||
result=set_search_native(drvstr, &nwpath, mode);
|
||||
if (mode != 1)
|
||||
show_search(drvstr);
|
||||
return(result);
|
||||
}
|
||||
|
||||
fprintf(stderr, "Cannot interpret line. errcode=-1\n");
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
803
ndir.c
Normal file
803
ndir.c
Normal file
@@ -0,0 +1,803 @@
|
||||
/* ndir.c - first Novell NDIR-like directory listing utility */
|
||||
|
||||
#include "net.h"
|
||||
#include "c32ncp.h"
|
||||
#include <dos.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifndef S_IFDIR
|
||||
#define S_IFDIR 0040000
|
||||
#endif
|
||||
|
||||
#ifndef _A_NORMAL
|
||||
#define _A_NORMAL 0x00
|
||||
#endif
|
||||
|
||||
#ifndef _A_RDONLY
|
||||
#define _A_RDONLY 0x01
|
||||
#endif
|
||||
#ifndef _A_HIDDEN
|
||||
#define _A_HIDDEN 0x02
|
||||
#endif
|
||||
#ifndef _A_SYSTEM
|
||||
#define _A_SYSTEM 0x04
|
||||
#endif
|
||||
#ifndef _A_SUBDIR
|
||||
#define _A_SUBDIR 0x10
|
||||
#endif
|
||||
#ifndef _A_ARCH
|
||||
#define _A_ARCH 0x20
|
||||
#endif
|
||||
|
||||
#define NDIR_OPT_FILES_ONLY 0x0001
|
||||
#define NDIR_OPT_DIRS_ONLY 0x0002
|
||||
#define NDIR_OPT_RIGHTS 0x0004
|
||||
#define NDIR_OPT_DATES 0x0008
|
||||
#define NDIR_OPT_SUB 0x0010
|
||||
#define NDIR_OPT_SHORT 0x0020
|
||||
|
||||
/* NCP effective-rights bits returned by NCP87 subfunction 29. */
|
||||
#define NDIR_NCP_RIGHT_READ 0x0001
|
||||
#define NDIR_NCP_RIGHT_WRITE 0x0002
|
||||
#define NDIR_NCP_RIGHT_CREATE 0x0008
|
||||
#define NDIR_NCP_RIGHT_DELETE 0x0010
|
||||
#define NDIR_NCP_RIGHT_OWNER 0x0020
|
||||
#define NDIR_NCP_RIGHT_SEARCH 0x0040
|
||||
#define NDIR_NCP_RIGHT_MODIFY 0x0080
|
||||
#define NDIR_NCP_RIGHT_SUPER 0x0100
|
||||
|
||||
static void ndir_dos_date(unsigned date, char *out);
|
||||
static void ndir_dos_datetime(unsigned date, unsigned time, char *out);
|
||||
|
||||
#define NDIR_OLD_RIGHT_S 0x01
|
||||
#define NDIR_OLD_RIGHT_R 0x02
|
||||
#define NDIR_OLD_RIGHT_W 0x04
|
||||
#define NDIR_OLD_RIGHT_C 0x08
|
||||
#define NDIR_OLD_RIGHT_E 0x10
|
||||
#define NDIR_OLD_RIGHT_M 0x20
|
||||
#define NDIR_OLD_RIGHT_F 0x40
|
||||
#define NDIR_OLD_RIGHT_A 0x80
|
||||
|
||||
|
||||
static void ndir_usage(void)
|
||||
{
|
||||
fprintf(stdout, "usage: NDIR [path] [/option...]\n");
|
||||
fprintf(stdout, "path: [path] [filename] [,filename, ...] (up to 16 in chain)\n");
|
||||
fprintf(stdout, "options: [format], [flag], [sortspec], [restriction], [FO] (files only),\n");
|
||||
fprintf(stdout, " [DO] (directories only), [SUBdirectories], [Continuous], [HELP]\n");
|
||||
fprintf(stdout, "\n");
|
||||
fprintf(stdout, "format: DATES, RIGHTS, MACintosh, LONGnames\n");
|
||||
fprintf(stdout, "\n");
|
||||
fprintf(stdout, "flag: [NOT] RO, S, A, X, H, SY, T, I, P, RA, WA, CI, DI, RI\n");
|
||||
fprintf(stdout, "\n");
|
||||
fprintf(stdout, "sortspec: [REVerse] SORT [OWner], [SIze], [UPdate], [CReate],\n");
|
||||
fprintf(stdout, " [ACcess], [ARchive], [UNsorted]\n");
|
||||
fprintf(stdout, "\n");
|
||||
fprintf(stdout, "restriction: OWner <operator> <name>\n");
|
||||
fprintf(stdout, " SIze <operator> <number>\n");
|
||||
fprintf(stdout, " UPdate <operator> <date>\n");
|
||||
fprintf(stdout, " CReate <operator> <date>\n");
|
||||
fprintf(stdout, " ACcess <operator> <date>\n");
|
||||
fprintf(stdout, " ARchive <operator> <date>\n");
|
||||
fprintf(stdout, "\n");
|
||||
fprintf(stdout, "operator: [NOT] Less than, GReater than,\n");
|
||||
fprintf(stdout, " EQual to, BEfore, AFter\n");
|
||||
fprintf(stdout, "\n");
|
||||
fprintf(stdout, "To search filenames equivalent to any of the capitalized KEYWORD options\n");
|
||||
fprintf(stdout, "shown above, the filename must be preceded by a drive letter or path.\n");
|
||||
}
|
||||
|
||||
static int ndir_is_help(char *s)
|
||||
{
|
||||
if (!s) return(0);
|
||||
return(tool_is_help_arg(s) || tool_strsame(s, "/HELP") ||
|
||||
tool_strsame(s, "-HELP") || tool_strsame(s, "HELP"));
|
||||
}
|
||||
|
||||
static int ndir_is_files_only(char *s)
|
||||
{
|
||||
if (!s) return(0);
|
||||
return(tool_strsame(s, "/FO") || tool_strsame(s, "-FO") ||
|
||||
tool_strsame(s, "/FILESONLY") || tool_strsame(s, "-FILESONLY") ||
|
||||
tool_strsame(s, "FO") || tool_strsame(s, "FILESONLY"));
|
||||
}
|
||||
|
||||
static int ndir_is_dirs_only(char *s)
|
||||
{
|
||||
if (!s) return(0);
|
||||
return(tool_strsame(s, "/DO") || tool_strsame(s, "-DO") ||
|
||||
tool_strsame(s, "/DIRSONLY") || tool_strsame(s, "-DIRSONLY") ||
|
||||
tool_strsame(s, "/DIRECTORIES") || tool_strsame(s, "-DIRECTORIES") ||
|
||||
tool_strsame(s, "DO") || tool_strsame(s, "DIRSONLY") ||
|
||||
tool_strsame(s, "DIRECTORIES"));
|
||||
}
|
||||
|
||||
static int ndir_is_continuous(char *s)
|
||||
{
|
||||
if (!s) return(0);
|
||||
return(tool_strsame(s, "/CONTINUOUS") || tool_strsame(s, "-CONTINUOUS") ||
|
||||
tool_strsame(s, "/CONTINUE") || tool_strsame(s, "-CONTINUE") ||
|
||||
tool_strsame(s, "/C") || tool_strsame(s, "-C") ||
|
||||
tool_strsame(s, "CONTINUOUS") || tool_strsame(s, "CONTINUE"));
|
||||
}
|
||||
|
||||
static int ndir_is_rights(char *s)
|
||||
{
|
||||
if (!s) return(0);
|
||||
return(tool_strsame(s, "/RIGHTS") || tool_strsame(s, "-RIGHTS") ||
|
||||
tool_strsame(s, "RIGHTS"));
|
||||
}
|
||||
|
||||
static int ndir_is_dates(char *s)
|
||||
{
|
||||
if (!s) return(0);
|
||||
return(tool_strsame(s, "/DATES") || tool_strsame(s, "-DATES") ||
|
||||
tool_strsame(s, "DATES"));
|
||||
}
|
||||
|
||||
static int ndir_is_subdirs(char *s)
|
||||
{
|
||||
if (!s) return(0);
|
||||
return(tool_strsame(s, "/SUB") || tool_strsame(s, "-SUB") ||
|
||||
tool_strsame(s, "/SUBDIRECTORIES") || tool_strsame(s, "-SUBDIRECTORIES") ||
|
||||
tool_strsame(s, "SUB") || tool_strsame(s, "SUBDIRECTORIES"));
|
||||
}
|
||||
|
||||
static int ndir_is_short(char *s)
|
||||
{
|
||||
if (!s) return(0);
|
||||
return(tool_strsame(s, "/SHORT") || tool_strsame(s, "-SHORT") ||
|
||||
tool_strsame(s, "/BRIEF") || tool_strsame(s, "-BRIEF") ||
|
||||
tool_strsame(s, "SHORT") || tool_strsame(s, "BRIEF"));
|
||||
}
|
||||
|
||||
static int ndir_is_accepted_stub(char *s)
|
||||
{
|
||||
if (!s) return(0);
|
||||
|
||||
/*
|
||||
* Keep this version tolerant of common NDIR format/options so users
|
||||
* can compare command lines while unimplemented formats remain harmless.
|
||||
*/
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int ndir_path_is_dir(char *path)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (!path || !*path || tool_is_current_path(path))
|
||||
return(1);
|
||||
|
||||
if (stat(path, &st) == 0) {
|
||||
if (st.st_mode & S_IFDIR)
|
||||
return(1);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static void ndir_split_spec(char *spec, char *dir, char *pat)
|
||||
{
|
||||
if (!spec || !*spec || tool_is_current_path(spec)) {
|
||||
strmaxcpy(dir, ".", 259);
|
||||
strmaxcpy(pat, "*.*", 259);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!tool_has_wildcards(spec) && ndir_path_is_dir(spec)) {
|
||||
strmaxcpy(dir, spec, 259);
|
||||
strmaxcpy(pat, "*.*", 259);
|
||||
return;
|
||||
}
|
||||
|
||||
tool_parent_pattern(dir, pat, spec, 260, 260);
|
||||
}
|
||||
|
||||
static void ndir_dos_date(unsigned date, char *out)
|
||||
{
|
||||
int year;
|
||||
int month;
|
||||
int day;
|
||||
|
||||
year = ((date >> 9) & 0x7f) + 1980;
|
||||
month = (date >> 5) & 0x0f;
|
||||
day = date & 0x1f;
|
||||
|
||||
sprintf(out, "%02d-%02d-%02d", month, day, year % 100);
|
||||
}
|
||||
|
||||
static void ndir_dos_datetime_or_blank(unsigned date, unsigned time, char *out)
|
||||
{
|
||||
if (!date) {
|
||||
strcpy(out, "0-00-00 0:00 A");
|
||||
return;
|
||||
}
|
||||
|
||||
ndir_dos_datetime(date, time, out);
|
||||
}
|
||||
|
||||
static void ndir_dos_date_or_blank(unsigned date, char *out)
|
||||
{
|
||||
if (!date) {
|
||||
strcpy(out, "0-00-00");
|
||||
return;
|
||||
}
|
||||
|
||||
ndir_dos_date(date, out);
|
||||
}
|
||||
|
||||
|
||||
static void ndir_dos_datetime(unsigned date, unsigned time, char *out)
|
||||
{
|
||||
int year;
|
||||
int month;
|
||||
int day;
|
||||
int hour;
|
||||
int minute;
|
||||
char ap;
|
||||
|
||||
year = ((date >> 9) & 0x7f) + 1980;
|
||||
month = (date >> 5) & 0x0f;
|
||||
day = date & 0x1f;
|
||||
hour = (time >> 11) & 0x1f;
|
||||
minute = (time >> 5) & 0x3f;
|
||||
|
||||
ap = (hour >= 12) ? 'p' : 'a';
|
||||
if (hour == 0)
|
||||
hour = 12;
|
||||
else if (hour > 12)
|
||||
hour -= 12;
|
||||
|
||||
sprintf(out, "%02d-%02d-%02d %2d:%02d%c",
|
||||
month, day, year % 100, hour, minute, ap);
|
||||
}
|
||||
|
||||
static unsigned long ndir_blocks_for_size(unsigned long size)
|
||||
{
|
||||
/*
|
||||
* Novell NDIR reports allocated bytes/blocks. For this first DOS
|
||||
* findfirst/findnext implementation, approximate with 4 KiB allocation
|
||||
* units so small test files match the observed Novell output more closely.
|
||||
*/
|
||||
if (size == 0L)
|
||||
return(0L);
|
||||
|
||||
return((size + 4095L) / 4096L);
|
||||
}
|
||||
|
||||
static void ndir_flags(unsigned attr, char *out)
|
||||
{
|
||||
/*
|
||||
* Keep the first positions close to Novell's default NDIR display,
|
||||
* for example [RW-A------------].
|
||||
*/
|
||||
out[0] = '[';
|
||||
out[1] = 'R';
|
||||
out[2] = (attr & _A_RDONLY) ? 'O' : 'W';
|
||||
out[3] = (attr & _A_SYSTEM) ? 'S' : '-';
|
||||
out[4] = (attr & _A_ARCH) ? 'A' : '-';
|
||||
out[5] = (attr & _A_HIDDEN) ? 'H' : '-';
|
||||
memset(out + 6, '-', 11);
|
||||
out[17] = ']';
|
||||
out[18] = '\0';
|
||||
}
|
||||
|
||||
static void ndir_parent_path(char *dst, char *src, int max)
|
||||
{
|
||||
char tmp[260];
|
||||
char *p;
|
||||
|
||||
tool_upcopy(tmp, src, sizeof(tmp));
|
||||
p = strrchr(tmp, '\\');
|
||||
if (!p) p = strrchr(tmp, ':');
|
||||
|
||||
if (p) {
|
||||
if (*p == ':') {
|
||||
p[1] = '\0';
|
||||
} else {
|
||||
*p = '\0';
|
||||
}
|
||||
strmaxcpy(dst, tmp, max - 1);
|
||||
} else {
|
||||
dst[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
static void ndir_old_rights_string(uint8 old_rights, char *out)
|
||||
{
|
||||
out[0] = (old_rights & NDIR_OLD_RIGHT_S) ? 'S' : '-';
|
||||
out[1] = (old_rights & NDIR_OLD_RIGHT_R) ? 'R' : '-';
|
||||
out[2] = (old_rights & NDIR_OLD_RIGHT_W) ? 'W' : '-';
|
||||
out[3] = (old_rights & NDIR_OLD_RIGHT_C) ? 'C' : '-';
|
||||
out[4] = (old_rights & NDIR_OLD_RIGHT_E) ? 'E' : '-';
|
||||
out[5] = (old_rights & NDIR_OLD_RIGHT_M) ? 'M' : '-';
|
||||
out[6] = (old_rights & NDIR_OLD_RIGHT_F) ? 'F' : '-';
|
||||
out[7] = (old_rights & NDIR_OLD_RIGHT_A) ? 'A' : '-';
|
||||
out[8] = '\0';
|
||||
}
|
||||
|
||||
static int ndir_get_ncp_info(char *path, C32_NDIR_INFO *info)
|
||||
{
|
||||
uint8 connid = 0;
|
||||
uint8 dhandle = 0;
|
||||
|
||||
if (!info)
|
||||
return(1);
|
||||
|
||||
memset(info, 0, sizeof(*info));
|
||||
|
||||
if (tool_current_dhandle(&connid, &dhandle))
|
||||
return(1);
|
||||
|
||||
return(c32_ncp87_obtain_ndir_info(tool_is_current_path(path) ? "" : path,
|
||||
(uint16)dhandle,
|
||||
info,
|
||||
NULL, NULL, NULL));
|
||||
}
|
||||
|
||||
static void ndir_inherited_rights(char *path, char *out)
|
||||
{
|
||||
C32_NDIR_INFO info;
|
||||
|
||||
strcpy(out, "--------");
|
||||
|
||||
if (!ndir_get_ncp_info(path, &info))
|
||||
ndir_old_rights_string((uint8)info.inherited_rights, out);
|
||||
}
|
||||
|
||||
static void ndir_rights_string(uint16 ncp_rights, char *out)
|
||||
{
|
||||
out[0] = (ncp_rights & NDIR_NCP_RIGHT_SUPER) ? 'S' : '-';
|
||||
out[1] = (ncp_rights & NDIR_NCP_RIGHT_READ) ? 'R' : '-';
|
||||
out[2] = (ncp_rights & NDIR_NCP_RIGHT_WRITE) ? 'W' : '-';
|
||||
out[3] = (ncp_rights & NDIR_NCP_RIGHT_CREATE) ? 'C' : '-';
|
||||
out[4] = (ncp_rights & NDIR_NCP_RIGHT_DELETE) ? 'E' : '-';
|
||||
out[5] = (ncp_rights & NDIR_NCP_RIGHT_MODIFY) ? 'M' : '-';
|
||||
out[6] = (ncp_rights & NDIR_NCP_RIGHT_SEARCH) ? 'F' : '-';
|
||||
out[7] = (ncp_rights & NDIR_NCP_RIGHT_OWNER) ? 'A' : '-';
|
||||
out[8] = '\0';
|
||||
}
|
||||
|
||||
static void ndir_effective_rights(char *path, char *out)
|
||||
{
|
||||
uint8 connid = 0;
|
||||
uint8 dhandle = 0;
|
||||
uint8 eff_old = 0;
|
||||
uint16 ncp_rights = 0;
|
||||
char usepath[260];
|
||||
int newhandle;
|
||||
|
||||
strcpy(out, "--------");
|
||||
|
||||
if (tool_current_dhandle(&connid, &dhandle))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Prefer Client32 NCP87 effective-rights. If that fails for a listed
|
||||
* entry, fall back to the older directory-handle effective-rights path
|
||||
* that RIGHTS also uses.
|
||||
*/
|
||||
if (!c32_ncp87_get_effective_rights(tool_is_current_path(path) ? "" : path,
|
||||
(uint16)dhandle,
|
||||
&ncp_rights,
|
||||
NULL, NULL, NULL)) {
|
||||
ndir_rights_string(ncp_rights, out);
|
||||
return;
|
||||
}
|
||||
|
||||
ndir_parent_path(usepath, path, sizeof(usepath));
|
||||
newhandle = alloc_temp_dir_handle(dhandle, usepath, 0, &eff_old);
|
||||
if (newhandle >= 0) {
|
||||
dealloc_dir_handle(newhandle);
|
||||
ndir_old_rights_string(eff_old, out);
|
||||
return;
|
||||
}
|
||||
|
||||
if (usepath[0]) {
|
||||
int subdir = 1;
|
||||
int r = ncp_16_02(dhandle, (uint8 *)usepath, &subdir,
|
||||
NULL, NULL, NULL);
|
||||
if (r >= 0)
|
||||
ndir_old_rights_string((uint8)r, out);
|
||||
} else {
|
||||
ndir_old_rights_string(0xff, out);
|
||||
}
|
||||
}
|
||||
|
||||
static int ndir_is_dot_dir(char *name)
|
||||
{
|
||||
if (!name) return(0);
|
||||
if (name[0] == '.' && name[1] == '\0') return(1);
|
||||
if (name[0] == '.' && name[1] == '.' && name[2] == '\0') return(1);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static void ndir_print_file(char *dir, struct find_t *ff, int options,
|
||||
int *line_count, int *continuous)
|
||||
{
|
||||
char dt[24];
|
||||
char d[12];
|
||||
char fl[20]; /* [RW-A------------] plus NUL */
|
||||
char path[260];
|
||||
char eff[10];
|
||||
char inh[10];
|
||||
char arch[24];
|
||||
char acc[12];
|
||||
char crea[24];
|
||||
C32_NDIR_INFO info;
|
||||
int have_info = 0;
|
||||
|
||||
tool_join_path(path, dir, ff->name, sizeof(path));
|
||||
have_info = !ndir_get_ncp_info(path, &info);
|
||||
|
||||
if (have_info)
|
||||
ndir_dos_datetime(info.modify_date, info.modify_time, dt);
|
||||
else
|
||||
ndir_dos_datetime(ff->wr_date, ff->wr_time, dt);
|
||||
|
||||
ndir_dos_date(ff->wr_date, d);
|
||||
ndir_flags(ff->attrib, fl);
|
||||
|
||||
if (options & NDIR_OPT_RIGHTS) {
|
||||
ndir_effective_rights(path, eff);
|
||||
ndir_inherited_rights(path, inh);
|
||||
fprintf(stdout, "%-16.16s %-18.18s [%8.8s] [%8.8s]\n",
|
||||
ff->name, fl, inh, eff);
|
||||
} else if (options & NDIR_OPT_DATES) {
|
||||
/*
|
||||
* DOS findfirst gives us the update timestamp only. Keep the Novell
|
||||
* /DATES layout and use placeholders for archive/access data until
|
||||
* full NetWare namespace date fields are available.
|
||||
*/
|
||||
if (have_info) {
|
||||
ndir_dos_datetime_or_blank(info.archive_date, info.archive_time, arch);
|
||||
ndir_dos_date_or_blank(info.last_access_date, acc);
|
||||
ndir_dos_datetime_or_blank(info.creation_date, info.creation_time, crea);
|
||||
fprintf(stdout, "%-16.16s %-17.17s %-17.17s %-8.8s %-17.17s\n",
|
||||
ff->name, dt, arch, acc, crea);
|
||||
} else {
|
||||
fprintf(stdout, "%-16.16s %-17.17s 0-00-00 0:00 A %-8.8s %-17.17s\n",
|
||||
ff->name, dt, d, dt);
|
||||
}
|
||||
} else {
|
||||
fprintf(stdout, "%-16.16s %12lu %-17.17s %-18.18s\n",
|
||||
ff->name, (unsigned long)ff->size, dt, fl);
|
||||
}
|
||||
|
||||
tool_page_line(line_count, continuous);
|
||||
}
|
||||
|
||||
static void ndir_print_dir(char *dir, struct find_t *ff, int options,
|
||||
int *line_count, int *continuous)
|
||||
{
|
||||
char dt[24];
|
||||
char path[260];
|
||||
char eff[10];
|
||||
char inh[10];
|
||||
C32_NDIR_INFO info;
|
||||
|
||||
tool_join_path(path, dir, ff->name, sizeof(path));
|
||||
if (!ndir_get_ncp_info(path, &info))
|
||||
ndir_dos_datetime(info.creation_date, info.creation_time, dt);
|
||||
else
|
||||
ndir_dos_datetime(ff->wr_date, ff->wr_time, dt);
|
||||
|
||||
if (options & (NDIR_OPT_RIGHTS | NDIR_OPT_DIRS_ONLY)) {
|
||||
ndir_effective_rights(path, eff);
|
||||
ndir_inherited_rights(path, inh);
|
||||
fprintf(stdout, "%-16.16s [%8.8s] [%8.8s] %-17.17s\n",
|
||||
ff->name, inh, eff, dt);
|
||||
} else {
|
||||
fprintf(stdout, "%-16.16s <DIR> %-17.17s\n", ff->name, dt);
|
||||
}
|
||||
|
||||
tool_page_line(line_count, continuous);
|
||||
}
|
||||
|
||||
static int ndir_scan_files(char *dir, char *search, int options,
|
||||
int *line_count, int *continuous,
|
||||
int *file_count, unsigned long *total_bytes,
|
||||
unsigned long *total_blocks)
|
||||
{
|
||||
struct find_t ff;
|
||||
int rc;
|
||||
int shown = 0;
|
||||
|
||||
rc = _dos_findfirst(search, _A_NORMAL | _A_RDONLY | _A_HIDDEN |
|
||||
_A_SYSTEM | _A_ARCH | _A_SUBDIR, &ff);
|
||||
while (rc == 0) {
|
||||
if (!(ff.attrib & _A_SUBDIR)) {
|
||||
ndir_print_file(dir, &ff, options, line_count, continuous);
|
||||
(*file_count)++;
|
||||
*total_bytes += (unsigned long)ff.size;
|
||||
*total_blocks += ndir_blocks_for_size((unsigned long)ff.size);
|
||||
shown = 1;
|
||||
}
|
||||
|
||||
rc = _dos_findnext(&ff);
|
||||
}
|
||||
|
||||
return(shown);
|
||||
}
|
||||
|
||||
static int ndir_scan_dirs(char *dir, char *search, int options,
|
||||
int *line_count, int *continuous,
|
||||
int *dir_count)
|
||||
{
|
||||
struct find_t ff;
|
||||
int rc;
|
||||
int shown = 0;
|
||||
|
||||
rc = _dos_findfirst(search, _A_NORMAL | _A_RDONLY | _A_HIDDEN |
|
||||
_A_SYSTEM | _A_ARCH | _A_SUBDIR, &ff);
|
||||
while (rc == 0) {
|
||||
if ((ff.attrib & _A_SUBDIR) && !ndir_is_dot_dir(ff.name)) {
|
||||
ndir_print_dir(dir, &ff, options, line_count, continuous);
|
||||
(*dir_count)++;
|
||||
shown = 1;
|
||||
}
|
||||
|
||||
rc = _dos_findnext(&ff);
|
||||
}
|
||||
|
||||
return(shown);
|
||||
}
|
||||
|
||||
static int ndir_list_one(char *spec, int options, int *continuous)
|
||||
{
|
||||
char dir[260];
|
||||
char pat[260];
|
||||
char search[260];
|
||||
char display[300];
|
||||
int got = 0;
|
||||
int files_shown = 0;
|
||||
int dirs_shown = 0;
|
||||
int file_count = 0;
|
||||
int dir_count = 0;
|
||||
unsigned long total_bytes = 0L;
|
||||
unsigned long total_blocks = 0L;
|
||||
int line_count = 0;
|
||||
|
||||
ndir_split_spec(spec, dir, pat);
|
||||
tool_join_path(search, dir, pat, sizeof(search));
|
||||
|
||||
tool_header_path(display, dir, sizeof(display));
|
||||
fprintf(stdout, "%s\n", display);
|
||||
tool_page_line(&line_count, continuous);
|
||||
|
||||
if (!(options & NDIR_OPT_DIRS_ONLY)) {
|
||||
if (!(options & NDIR_OPT_SHORT)) {
|
||||
if (options & NDIR_OPT_RIGHTS) {
|
||||
fprintf(stdout, "Files: Flags Rights Rights Owner\n");
|
||||
fprintf(stdout, "---------------- ------------------ ----------- ----------- --------\n");
|
||||
} else if (options & NDIR_OPT_DATES) {
|
||||
fprintf(stdout, "Files: Last Updated Last Archived Accessed Created/Copied\n");
|
||||
fprintf(stdout, "---------------- ----------------- ----------------- -------- -----------------\n");
|
||||
} else {
|
||||
fprintf(stdout, "Files: Size Last Updated Flags Owner\n");
|
||||
fprintf(stdout, "---------------- ---------------- ----------------- ------------------ --------\n");
|
||||
}
|
||||
tool_page_line(&line_count, continuous);
|
||||
tool_page_line(&line_count, continuous);
|
||||
}
|
||||
|
||||
files_shown = ndir_scan_files(dir, search, options, &line_count,
|
||||
continuous, &file_count,
|
||||
&total_bytes, &total_blocks);
|
||||
if (files_shown)
|
||||
got = 1;
|
||||
}
|
||||
|
||||
if (!(options & NDIR_OPT_FILES_ONLY)) {
|
||||
if (!(options & NDIR_OPT_DIRS_ONLY) && !(options & NDIR_OPT_SHORT))
|
||||
fprintf(stdout, "\n");
|
||||
|
||||
if (!(options & NDIR_OPT_SHORT)) {
|
||||
if (options & (NDIR_OPT_RIGHTS | NDIR_OPT_DIRS_ONLY)) {
|
||||
fprintf(stdout, "Directories: Rights Rights Owner Created/Copied\n");
|
||||
fprintf(stdout, "---------------- ----------- ----------- ----------- -----------------\n");
|
||||
} else {
|
||||
fprintf(stdout, "Directories:\n");
|
||||
fprintf(stdout, "----------------\n");
|
||||
}
|
||||
tool_page_line(&line_count, continuous);
|
||||
tool_page_line(&line_count, continuous);
|
||||
}
|
||||
|
||||
dirs_shown = ndir_scan_dirs(dir, search, options, &line_count,
|
||||
continuous, &dir_count);
|
||||
if (dirs_shown)
|
||||
got = 1;
|
||||
}
|
||||
|
||||
if (!got && (options & NDIR_OPT_DIRS_ONLY) && !(options & NDIR_OPT_SHORT))
|
||||
fprintf(stdout, "No files of given specification found or directory is empty.\n");
|
||||
|
||||
if (!(options & NDIR_OPT_DIRS_ONLY)) {
|
||||
if (options & NDIR_OPT_SHORT) {
|
||||
if (file_count)
|
||||
fprintf(stdout, " %lu bytes, %d files, %lu blocks\n",
|
||||
total_bytes, file_count, total_blocks);
|
||||
} else {
|
||||
fprintf(stdout, "\n");
|
||||
fprintf(stdout, "%12lu bytes in %5d files\n", total_bytes, file_count);
|
||||
fprintf(stdout, "%12lu bytes in %5lu blocks\n", total_blocks * 4096L,
|
||||
total_blocks);
|
||||
}
|
||||
}
|
||||
|
||||
return(got ? 0 : 1);
|
||||
}
|
||||
|
||||
|
||||
static int ndir_spec_has_output(char *spec, int options)
|
||||
{
|
||||
struct find_t ff;
|
||||
char dir[260];
|
||||
char pat[260];
|
||||
char search[260];
|
||||
int rc;
|
||||
|
||||
ndir_split_spec(spec, dir, pat);
|
||||
tool_join_path(search, dir, pat, sizeof(search));
|
||||
|
||||
rc = _dos_findfirst(search, _A_NORMAL | _A_RDONLY | _A_HIDDEN |
|
||||
_A_SYSTEM | _A_ARCH | _A_SUBDIR, &ff);
|
||||
while (rc == 0) {
|
||||
if (ff.attrib & _A_SUBDIR) {
|
||||
if (!ndir_is_dot_dir(ff.name) && !(options & NDIR_OPT_FILES_ONLY))
|
||||
return(1);
|
||||
} else {
|
||||
if (!(options & NDIR_OPT_DIRS_ONLY))
|
||||
return(1);
|
||||
}
|
||||
|
||||
rc = _dos_findnext(&ff);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
static int ndir_list_subdirs(char *dir, char *pattern, int options,
|
||||
int *continuous)
|
||||
{
|
||||
struct find_t ff;
|
||||
char search[260];
|
||||
char subdir[260];
|
||||
char subspec[260];
|
||||
int rc;
|
||||
int result = 0;
|
||||
int had_any = 0;
|
||||
|
||||
tool_join_path(search, dir, "*.*", sizeof(search));
|
||||
|
||||
rc = _dos_findfirst(search, _A_NORMAL | _A_RDONLY | _A_HIDDEN |
|
||||
_A_SYSTEM | _A_ARCH | _A_SUBDIR, &ff);
|
||||
while (rc == 0) {
|
||||
if ((ff.attrib & _A_SUBDIR) && !ndir_is_dot_dir(ff.name)) {
|
||||
tool_join_path(subdir, dir, ff.name, sizeof(subdir));
|
||||
tool_join_path(subspec, subdir, pattern, sizeof(subspec));
|
||||
|
||||
if (!(options & NDIR_OPT_SHORT) ||
|
||||
ndir_spec_has_output(subspec, options & ~NDIR_OPT_SUB)) {
|
||||
fprintf(stdout, "\n");
|
||||
if (ndir_list_one(subspec, options & ~NDIR_OPT_SUB, continuous))
|
||||
result = 1;
|
||||
}
|
||||
|
||||
had_any = 1;
|
||||
if (ndir_list_subdirs(subdir, pattern, options, continuous))
|
||||
result = 1;
|
||||
}
|
||||
|
||||
rc = _dos_findnext(&ff);
|
||||
}
|
||||
|
||||
if (!had_any)
|
||||
return(result);
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
static int ndir_list(char *spec, int options, int *continuous)
|
||||
{
|
||||
char dir[260];
|
||||
char pat[260];
|
||||
int result;
|
||||
|
||||
result = ndir_list_one(spec, options & ~NDIR_OPT_SUB, continuous);
|
||||
|
||||
if (!(options & NDIR_OPT_SUB))
|
||||
return(result);
|
||||
|
||||
ndir_split_spec(spec, dir, pat);
|
||||
if (!pat[0])
|
||||
strmaxcpy(pat, "*.*", sizeof(pat) - 1);
|
||||
|
||||
return(ndir_list_subdirs(dir, pat, options, continuous) ? 1 : result);
|
||||
}
|
||||
|
||||
int func_ndir(int argc, char *argv[], int mode)
|
||||
{
|
||||
char *path = ".";
|
||||
int have_path = 0;
|
||||
int options = 0;
|
||||
int continuous = 0;
|
||||
int i;
|
||||
|
||||
(void)mode;
|
||||
|
||||
if (argc > 1 && ndir_is_help(argv[1])) {
|
||||
ndir_usage();
|
||||
return(0);
|
||||
}
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (ndir_is_help(argv[i])) {
|
||||
ndir_usage();
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (ndir_is_files_only(argv[i])) {
|
||||
options |= NDIR_OPT_FILES_ONLY;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ndir_is_dirs_only(argv[i])) {
|
||||
options |= NDIR_OPT_DIRS_ONLY;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ndir_is_continuous(argv[i])) {
|
||||
continuous = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ndir_is_rights(argv[i])) {
|
||||
options |= NDIR_OPT_RIGHTS;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ndir_is_dates(argv[i])) {
|
||||
options |= NDIR_OPT_DATES;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ndir_is_subdirs(argv[i])) {
|
||||
options |= NDIR_OPT_SUB;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ndir_is_short(argv[i])) {
|
||||
options |= NDIR_OPT_SHORT;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ndir_is_accepted_stub(argv[i])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tool_is_option(argv[i])) {
|
||||
fprintf(stdout, "Type \"ndir /help\" on the command line for usage information.\n");
|
||||
return(1);
|
||||
}
|
||||
|
||||
if (have_path) {
|
||||
fprintf(stdout, "Too many filenames in chain.\n");
|
||||
return(1);
|
||||
}
|
||||
|
||||
path = argv[i];
|
||||
have_path = 1;
|
||||
}
|
||||
|
||||
if ((options & NDIR_OPT_FILES_ONLY) && (options & NDIR_OPT_DIRS_ONLY)) {
|
||||
fprintf(stdout, "No files of given specification found or directory is empty.\n");
|
||||
return(1);
|
||||
}
|
||||
|
||||
return(ndir_list(path, options, &continuous));
|
||||
}
|
||||
7
net.c
7
net.c
@@ -34,6 +34,13 @@ static struct s_net_functions {
|
||||
{"PATHDEL","removes search path" , func_path , 1},
|
||||
{"PATHINS","insert search path" , func_path , 2},
|
||||
{"LOGOUT", "logout from server", func_logout , 0},
|
||||
{"FLAG", "display or modify file attributes", func_flag , 0},
|
||||
{"FLAGDIR","display or modify directory attributes",func_flagdir, 0},
|
||||
{"GRANT", "grant trustee rights", func_grant , 0},
|
||||
{"REVOKE", "revoke trustee rights", func_revoke , 0},
|
||||
{"REMOVE", "remove trustee", func_remove , 0},
|
||||
{"NDIR", "list directory contents", func_ndir , 0},
|
||||
{"RIGHTS", "display effective file/directory rights",func_rights, 0},
|
||||
{"SLIST", "list servers", func_slist , 0},
|
||||
{"PASSWD", "change password", func_passwd , 0},
|
||||
#if 1
|
||||
|
||||
32
net.h
32
net.h
@@ -17,6 +17,7 @@
|
||||
#include <stdarg.h>
|
||||
#ifdef __WATCOMC__
|
||||
#include <direct.h>
|
||||
extern int tool_page_line(int *line_count, int *continuous);
|
||||
#endif
|
||||
|
||||
typedef unsigned int UI;
|
||||
@@ -58,7 +59,7 @@ typedef struct {
|
||||
uint16 fragment_count; /* Anzahl Fragment Buffers */
|
||||
uint8 *fragment_1;
|
||||
uint16 fragment_1_size;
|
||||
/* K<EFBFBD>nnen auch mehr sein */
|
||||
/* K�nnen auch mehr sein */
|
||||
} ECB;
|
||||
|
||||
#include "kern.h"
|
||||
@@ -145,6 +146,26 @@ extern uint8 *upstr(uint8 *s);
|
||||
extern void korrpath(char *s);
|
||||
extern void get_path_fn(char *s, char *p, char *fn);
|
||||
|
||||
/* Shared DOS utility helpers. Keep command frontends small so the
|
||||
* historical multicall net.exe can later be split into smaller groups. */
|
||||
extern int tool_strsame(char *a, char *b);
|
||||
extern int tool_is_help_arg(char *s);
|
||||
extern int tool_is_option(char *s);
|
||||
extern int tool_is_files_option(char *s);
|
||||
extern int tool_is_subdirs_option(char *s);
|
||||
extern int tool_get_current_drive(void);
|
||||
extern int tool_current_dhandle(uint8 *connid, uint8 *dhandle);
|
||||
extern int tool_current_prefix(char *out, int max);
|
||||
extern int tool_is_current_path(char *path);
|
||||
extern void tool_upcopy(char *dst, char *src, int max);
|
||||
extern void tool_basename(char *dst, char *src, int max);
|
||||
extern void tool_header_path(char *out, char *path, int max);
|
||||
extern int tool_is_dot_dir(char *name);
|
||||
extern void tool_join_path(char *out, char *base, char *name, int max);
|
||||
extern int tool_has_wildcards(char *path);
|
||||
extern void tool_parent_pattern(char *dir, char *pattern, char *path,
|
||||
int maxdir, int maxpat);
|
||||
|
||||
#define reb(s) deb((s)),leb((s))
|
||||
|
||||
extern void deb(uint8 *s);
|
||||
@@ -242,6 +263,7 @@ extern int read_command_file(char *fstr);
|
||||
|
||||
/* slist.c */
|
||||
extern int func_slist (int argc, char *argv[], int mode);
|
||||
extern int func_ndir (int argc, char *argv[], int mode);
|
||||
|
||||
/* nwdebug.c */
|
||||
extern int func_debug (int argc, char *argv[], int mode);
|
||||
@@ -252,6 +274,14 @@ extern int func_tests (int argc, char *argv[], int mode);
|
||||
/* capture.c */
|
||||
extern int func_capture(int argc, char *argv[], int mode);
|
||||
|
||||
/* flag.c */
|
||||
extern int func_flag (int argc, char *argv[], int mode);
|
||||
extern int func_flagdir(int argc, char *argv[], int mode);
|
||||
extern int func_grant (int argc, char *argv[], int mode);
|
||||
extern int func_revoke(int argc, char *argv[], int mode);
|
||||
extern int func_remove(int argc, char *argv[], int mode);
|
||||
extern int func_rights (int argc, char *argv[], int mode);
|
||||
|
||||
|
||||
extern int ncp_17_37(uint32 last_id, uint16 objtyp, uint8 *pattern,
|
||||
BINDERY_OBJECT *target);
|
||||
|
||||
BIN
netold.exe
Executable file
BIN
netold.exe
Executable file
Binary file not shown.
128
nwtests.c
128
nwtests.c
@@ -1,44 +1,104 @@
|
||||
/* nwtests.c 20-May-96 */
|
||||
|
||||
/****************************************************************
|
||||
* (C)opyright (C) 1993,1996 Martin Stover, Marburg, Germany *
|
||||
****************************************************************/
|
||||
/* nwtests.c - small DOS utility tests */
|
||||
|
||||
#include "net.h"
|
||||
|
||||
static int usage(void)
|
||||
#include "c32ncp.h"
|
||||
static int tests_same_arg(char *a, char *b)
|
||||
{
|
||||
return(-1);
|
||||
while (*a || *b) {
|
||||
int ca = *a++;
|
||||
int cb = *b++;
|
||||
if (ca >= 'a' && ca <= 'z') ca -= 32;
|
||||
if (cb >= 'a' && cb <= 'z') cb -= 32;
|
||||
if (ca != cb) return(0);
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
static void tests_usage(void)
|
||||
{
|
||||
fprintf(stdout, "Usage: TESTS [NCP87C32ATTR|NCP87C32AUTO]\n");
|
||||
}
|
||||
|
||||
static int tests_get_current_drive(void)
|
||||
{
|
||||
REGS regs;
|
||||
|
||||
regs.h.ah = 0x19;
|
||||
int86(0x21, ®s, ®s);
|
||||
return((int)regs.h.al);
|
||||
}
|
||||
|
||||
static int tests_current_dhandle(uint8 *dhandle)
|
||||
{
|
||||
uint8 connid = 0;
|
||||
uint8 flags = 0;
|
||||
int drive;
|
||||
|
||||
drive = tests_get_current_drive();
|
||||
if (get_drive_info((uint8)drive, &connid, dhandle, &flags))
|
||||
return(-1);
|
||||
|
||||
if (!connid || (flags & 0x80))
|
||||
return(-1);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int tests_ncp87c32attr(void)
|
||||
{
|
||||
uint8 dhandle = 0;
|
||||
uint32 attr = 0;
|
||||
uint16 actual = 0;
|
||||
uint16 handle_lo = 0;
|
||||
uint16 handle_hi = 0;
|
||||
int rc;
|
||||
|
||||
if (tests_current_dhandle(&dhandle)) {
|
||||
fprintf(stdout, "NCP87C32ATTR failed: current drive is not a network drive\n");
|
||||
return(1);
|
||||
}
|
||||
|
||||
rc = c32_ncp87_obtain_rim_attributes("LOGIN.EXE",
|
||||
(uint16)dhandle,
|
||||
&attr,
|
||||
&actual,
|
||||
&handle_lo,
|
||||
&handle_hi);
|
||||
if (rc) {
|
||||
fprintf(stdout, "NCP87C32ATTR failed rc=%d\n", rc);
|
||||
return(rc);
|
||||
}
|
||||
|
||||
fprintf(stdout, "NCP87C32ATTR LOGIN.EXE attr=%02lX handle=%04X:%04X actual=%04X\n",
|
||||
attr & 0xffUL, handle_hi, handle_lo, actual);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int tests_ncp87c32auto(void)
|
||||
{
|
||||
/*
|
||||
* Kept as a compatibility alias for the former verbose test command.
|
||||
* The production helper path is exercised by NCP87C32ATTR.
|
||||
*/
|
||||
return tests_ncp87c32attr();
|
||||
}
|
||||
|
||||
int func_tests(int argc, char *argv[], int mode)
|
||||
{
|
||||
int level = ncp_17_02(NWCONN, 6);
|
||||
int dirhandle = alloc_temp_dir_handle(0, "SYS:", 'd', NULL);
|
||||
int result = -1;
|
||||
uint8 *path = (argc < 2) ? "SYS:\\TMP" : argv[1];
|
||||
if (dirhandle > -1) {
|
||||
result = ncp_16_02(dirhandle, "SYSTEM/", NULL, NULL, NULL, NULL);
|
||||
result = ncp_16_02(dirhandle, "SYSTEM", NULL, NULL, NULL, NULL);
|
||||
}
|
||||
fprintf(stdout, "dirhandle=%d, result=%d\n", dirhandle, result);
|
||||
result = redir_device_drive(0x4, "u:", path);
|
||||
fprintf(stdout, "redir path=%s, result=%d\n", path, result);
|
||||
(void)mode;
|
||||
|
||||
path="Q1";
|
||||
result = redir_device_drive(0x3, "LPT1", path);
|
||||
fprintf(stdout, "redir path=%s, result=%d\n", path, result);
|
||||
|
||||
{
|
||||
int k =-1;
|
||||
uint8 devname[20];
|
||||
uint8 remotename[130];
|
||||
int devicetyp;
|
||||
while ((result = list_redir(++k, &devicetyp, devname, remotename)) > -1){
|
||||
fprintf(stdout, "index=%d, dev=%s(%d), %s result=%d\n",
|
||||
k, devname, devicetyp, remotename, result);
|
||||
}
|
||||
if (argc < 2) {
|
||||
tests_usage();
|
||||
return(1);
|
||||
}
|
||||
if (level > -1) (void) ncp_17_02(NWCONN, level);
|
||||
return(0);
|
||||
|
||||
if (tests_same_arg(argv[1], "NCP87C32ATTR"))
|
||||
return tests_ncp87c32attr();
|
||||
|
||||
if (tests_same_arg(argv[1], "NCP87C32AUTO"))
|
||||
return tests_ncp87c32auto();
|
||||
|
||||
tests_usage();
|
||||
return(1);
|
||||
}
|
||||
|
||||
253
remove.c
Normal file
253
remove.c
Normal file
@@ -0,0 +1,253 @@
|
||||
/* remove.c - Novell REMOVE-like DOS utility */
|
||||
|
||||
#include "net.h"
|
||||
#include "c32ncp.h"
|
||||
#include "trustee.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifndef _A_NORMAL
|
||||
#define _A_NORMAL 0x00
|
||||
#endif
|
||||
|
||||
static int remove_last_rc = 0;
|
||||
|
||||
static void remove_usage_error(void)
|
||||
{
|
||||
fprintf(stdout, "Command line arguments violate grammar defined for REMOVE.\n\n");
|
||||
}
|
||||
|
||||
static void remove_usage(void)
|
||||
{
|
||||
fprintf(stdout, "Usage: REMOVE [USER | GROUP] name [FROM path] [option]\n");
|
||||
fprintf(stdout, "Options: /Subdirs | /Files\n");
|
||||
}
|
||||
|
||||
static int remove_one(char *path, uint16 dhandle, uint32 object_id,
|
||||
uint16 objtype, char *objname, int forced_is_file)
|
||||
{
|
||||
uint16 old_rights = 0;
|
||||
int is_dir;
|
||||
int rc;
|
||||
|
||||
is_dir = forced_is_file ? 0 : trustee_path_is_dir(path);
|
||||
|
||||
rc = c32_ncp87_find_trustee_rights(path, dhandle, object_id, &old_rights,
|
||||
NULL, NULL, NULL);
|
||||
remove_last_rc = rc;
|
||||
if (rc) {
|
||||
if (rc == 0xff)
|
||||
fprintf(stdout, "No trustee for the specified %s.\n", is_dir ? "directory" : "file");
|
||||
else
|
||||
fprintf(stdout, "Error scanning trustee list.\n");
|
||||
return(1);
|
||||
}
|
||||
|
||||
rc = c32_ncp87_delete_trustee_rights(path, dhandle, object_id,
|
||||
NULL, NULL, NULL);
|
||||
remove_last_rc = rc;
|
||||
if (rc) {
|
||||
fprintf(stdout, "Error deleting trustee.\n");
|
||||
return(1);
|
||||
}
|
||||
|
||||
{
|
||||
char header[300];
|
||||
trustee_header_path(header, path, sizeof(header));
|
||||
fprintf(stdout, "%s\n\n", header);
|
||||
}
|
||||
|
||||
if (objtype == TRUSTEE_BINDERY_GROUP)
|
||||
fprintf(stdout, "Group \"%s\" no longer a trustee to the specified %s.\n",
|
||||
objname, is_dir ? "directory" : "file");
|
||||
else
|
||||
fprintf(stdout, "User \"%s\" no longer a trustee to the specified %s.\n",
|
||||
objname, is_dir ? "directory" : "file");
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int remove_subdirs(char *path, uint16 dhandle, uint32 object_id,
|
||||
uint16 objtype, char *objname, int *count)
|
||||
{
|
||||
struct find_t ff;
|
||||
char pattern[260];
|
||||
char child[260];
|
||||
int rc = 0;
|
||||
|
||||
if (remove_one(path, dhandle, object_id, objtype, objname, 0) == 0)
|
||||
(*count)++;
|
||||
else
|
||||
rc = 1;
|
||||
|
||||
trustee_join_path(pattern, path, "*.*", sizeof(pattern));
|
||||
|
||||
if (_dos_findfirst(pattern, _A_SUBDIR, &ff) == 0) {
|
||||
do {
|
||||
if ((ff.attrib & _A_SUBDIR) && !trustee_is_dot_dir(ff.name)) {
|
||||
trustee_join_path(child, path, ff.name, sizeof(child));
|
||||
if (remove_subdirs(child, dhandle, object_id, objtype, objname, count))
|
||||
rc = 1;
|
||||
}
|
||||
} while (_dos_findnext(&ff) == 0);
|
||||
}
|
||||
|
||||
return(rc);
|
||||
}
|
||||
|
||||
static int remove_files(char *path, uint16 dhandle, uint32 object_id,
|
||||
uint16 objtype, char *objname, int *count)
|
||||
{
|
||||
struct find_t ff;
|
||||
char dir[260];
|
||||
char pat[80];
|
||||
char spec[260];
|
||||
char target[260];
|
||||
int rc = 0;
|
||||
|
||||
if (trustee_path_is_dir(path)) {
|
||||
strmaxcpy(dir, path, sizeof(dir) - 1);
|
||||
strmaxcpy(pat, "*.*", sizeof(pat) - 1);
|
||||
} else if (trustee_path_has_wildcards(path)) {
|
||||
trustee_parent_pattern(dir, pat, path, sizeof(dir), sizeof(pat));
|
||||
} else {
|
||||
if (remove_one(path, dhandle, object_id, objtype, objname, 1) == 0)
|
||||
(*count)++;
|
||||
else
|
||||
rc = 1;
|
||||
return(rc);
|
||||
}
|
||||
|
||||
trustee_join_path(spec, dir, pat, sizeof(spec));
|
||||
if (_dos_findfirst(spec, _A_NORMAL | _A_HIDDEN | _A_SYSTEM | _A_ARCH, &ff) == 0) {
|
||||
do {
|
||||
if (!(ff.attrib & _A_SUBDIR)) {
|
||||
trustee_join_path(target, dir, ff.name, sizeof(target));
|
||||
if (remove_one(target, dhandle, object_id, objtype, objname, 1) == 0)
|
||||
(*count)++;
|
||||
else
|
||||
rc = 1;
|
||||
}
|
||||
} while (_dos_findnext(&ff) == 0);
|
||||
}
|
||||
|
||||
return(rc);
|
||||
}
|
||||
|
||||
int func_remove(int argc, char *argv[], int mode)
|
||||
{
|
||||
char *path = ".";
|
||||
char *objname = NULL;
|
||||
char objprint[48];
|
||||
uint16 objtype = TRUSTEE_BINDERY_USER;
|
||||
int objtype_given = 0;
|
||||
uint8 connid = 0;
|
||||
uint8 dhandle = 0;
|
||||
uint32 object_id;
|
||||
int use_subdirs = 0;
|
||||
int use_files = 0;
|
||||
int count = 0;
|
||||
int i = 1;
|
||||
int rc;
|
||||
|
||||
(void)mode;
|
||||
|
||||
if (argc < 2 || trustee_is_help(argv[1])) {
|
||||
if (argc < 2)
|
||||
remove_usage_error();
|
||||
remove_usage();
|
||||
return(argc < 2 ? 1 : 0);
|
||||
}
|
||||
|
||||
if (i < argc && trustee_same(argv[i], "USER")) {
|
||||
objtype = TRUSTEE_BINDERY_USER;
|
||||
objtype_given = 1;
|
||||
i++;
|
||||
} else if (i < argc && trustee_same(argv[i], "GROUP")) {
|
||||
objtype = TRUSTEE_BINDERY_GROUP;
|
||||
objtype_given = 1;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i >= argc) {
|
||||
remove_usage_error();
|
||||
remove_usage();
|
||||
return(1);
|
||||
}
|
||||
|
||||
objname = argv[i++];
|
||||
|
||||
if (i < argc && trustee_same(argv[i], "FROM")) {
|
||||
i++;
|
||||
if (i >= argc) {
|
||||
remove_usage_error();
|
||||
remove_usage();
|
||||
return(1);
|
||||
}
|
||||
path = argv[i++];
|
||||
}
|
||||
|
||||
while (i < argc) {
|
||||
if (!trustee_is_option(argv[i])) {
|
||||
remove_usage_error();
|
||||
remove_usage();
|
||||
return(1);
|
||||
}
|
||||
|
||||
if (trustee_is_files_option(argv[i])) {
|
||||
use_files = 1;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (trustee_is_subdirs_option(argv[i])) {
|
||||
use_subdirs = 1;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
remove_usage_error();
|
||||
remove_usage();
|
||||
return(1);
|
||||
}
|
||||
|
||||
if (use_files && use_subdirs) {
|
||||
fprintf(stdout, "Remove cannot do both directories and files in a single pass.\n");
|
||||
return(1);
|
||||
}
|
||||
|
||||
if (trustee_current_dhandle(&connid, &dhandle)) {
|
||||
fprintf(stdout, "Error: Drive not mapped to network.\n");
|
||||
return(1);
|
||||
}
|
||||
|
||||
object_id = trustee_lookup_object(objname, &objtype, objtype_given);
|
||||
if (!object_id) {
|
||||
if (objtype_given && objtype == TRUSTEE_BINDERY_GROUP)
|
||||
fprintf(stdout, "Group \"%s\" not found.\n", objname);
|
||||
else if (objtype_given)
|
||||
fprintf(stdout, "User \"%s\" not found.\n", objname);
|
||||
else
|
||||
fprintf(stdout, "User or group \"%s\" not found.\n", objname);
|
||||
return(1);
|
||||
}
|
||||
|
||||
trustee_upcopy(objprint, objname, sizeof(objprint));
|
||||
|
||||
if (use_subdirs)
|
||||
rc = remove_subdirs(path, (uint16)dhandle, object_id, objtype, objprint, &count);
|
||||
else if (use_files)
|
||||
rc = remove_files(path, (uint16)dhandle, object_id, objtype, objprint, &count);
|
||||
else {
|
||||
rc = remove_one(path, (uint16)dhandle, object_id, objtype, objprint, 0);
|
||||
if (!rc)
|
||||
count = 1;
|
||||
}
|
||||
|
||||
if (use_subdirs || (!use_files && !rc))
|
||||
fprintf(stdout, "Trustee \"%s\" removed from %d directories.\n", objprint, count);
|
||||
else if (use_files)
|
||||
fprintf(stdout, "Trustee \"%s\" removed from %d files.\n", objprint, count);
|
||||
|
||||
return(rc ? (remove_last_rc ? remove_last_rc : 1) : 0);
|
||||
}
|
||||
301
revoke.c
Normal file
301
revoke.c
Normal file
@@ -0,0 +1,301 @@
|
||||
/* revoke.c - Novell REVOKE-like DOS utility */
|
||||
|
||||
#include "net.h"
|
||||
#include "c32ncp.h"
|
||||
#include "trustee.h"
|
||||
|
||||
#ifndef _A_NORMAL
|
||||
#define _A_NORMAL 0x00
|
||||
#endif
|
||||
|
||||
static int revoke_last_rc = 0;
|
||||
|
||||
static void revoke_usage_error(void)
|
||||
{
|
||||
fprintf(stdout, "Command line arguments violate grammar defined for REVOKE.\n\n");
|
||||
}
|
||||
|
||||
static void revoke_usage(void)
|
||||
{
|
||||
fprintf(stdout, "Usage: REVOKE rightslist* [FOR path] FROM [USER|GROUP] name [options]\n");
|
||||
fprintf(stdout, "Options: /SubDirectories | /Files\n\n");
|
||||
fprintf(stdout, "286 Rights:\t\t386 Rights:\n");
|
||||
fprintf(stdout, "---------------\t\t--------------------\n");
|
||||
fprintf(stdout, "ALL = All\t\tALL = All\n");
|
||||
fprintf(stdout, "R = Read\t\tS = Supervisor\n");
|
||||
fprintf(stdout, "W = Write\t\tR = Read\n");
|
||||
fprintf(stdout, "O = Open\t\tW = Write\n");
|
||||
fprintf(stdout, "C = Create\t\tC = Create\n");
|
||||
fprintf(stdout, "D = Delete\t\tE = Erase\n");
|
||||
fprintf(stdout, "P = Parental\t\tM = Modify\n");
|
||||
fprintf(stdout, "S = Search\t\tF = File Scan\n");
|
||||
fprintf(stdout, "M = Modify\t\tA = Access Control\n");
|
||||
fprintf(stdout, "\n* Use abbreviations listed above, separated by spaces.\n");
|
||||
}
|
||||
|
||||
static int revoke_one(char *path, uint16 dhandle, uint32 object_id,
|
||||
uint16 revoke_mask, int forced_is_file)
|
||||
{
|
||||
uint16 old_rights = 0;
|
||||
uint16 new_rights;
|
||||
int is_dir;
|
||||
int rc;
|
||||
|
||||
is_dir = forced_is_file ? 0 : trustee_path_is_dir(path);
|
||||
|
||||
rc = c32_ncp87_find_trustee_rights(path, dhandle, object_id, &old_rights,
|
||||
NULL, NULL, NULL);
|
||||
revoke_last_rc = rc;
|
||||
if (rc) {
|
||||
if (rc == 0xff)
|
||||
fprintf(stdout, "No trustee for the specified %s.\n", is_dir ? "directory" : "file");
|
||||
else
|
||||
fprintf(stdout, "Error scanning trustee list.\n");
|
||||
return(1);
|
||||
}
|
||||
|
||||
new_rights = (uint16)(old_rights & ~revoke_mask);
|
||||
|
||||
if (new_rights == 0) {
|
||||
rc = c32_ncp87_delete_trustee_rights(path, dhandle, object_id,
|
||||
NULL, NULL, NULL);
|
||||
revoke_last_rc = rc;
|
||||
if (rc) {
|
||||
fprintf(stdout, "Error deleting trustee.\n");
|
||||
return(1);
|
||||
}
|
||||
} else {
|
||||
rc = c32_ncp87_add_trustee_rights(path, dhandle, object_id, new_rights,
|
||||
0xffff, NULL, NULL, NULL);
|
||||
revoke_last_rc = rc;
|
||||
if (rc) {
|
||||
fprintf(stdout, "Fatal error revoking access rights.\n");
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
char header[300];
|
||||
char bracket[10];
|
||||
trustee_header_path(header, path, sizeof(header));
|
||||
trustee_rights_bracket(new_rights, bracket);
|
||||
fprintf(stdout, "%s\n\n", header);
|
||||
fprintf(stdout, "Trustee's access rights set to [%s]\n", bracket);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int revoke_subdirs(char *path, uint16 dhandle, uint32 object_id,
|
||||
uint16 revoke_mask, int *count)
|
||||
{
|
||||
struct find_t ff;
|
||||
char pattern[260];
|
||||
char child[260];
|
||||
int rc = 0;
|
||||
|
||||
if (revoke_one(path, dhandle, object_id, revoke_mask, 0) == 0)
|
||||
(*count)++;
|
||||
else
|
||||
rc = 1;
|
||||
|
||||
trustee_join_path(pattern, path, "*.*", sizeof(pattern));
|
||||
|
||||
if (_dos_findfirst(pattern, _A_SUBDIR, &ff) == 0) {
|
||||
do {
|
||||
if ((ff.attrib & _A_SUBDIR) && !trustee_is_dot_dir(ff.name)) {
|
||||
trustee_join_path(child, path, ff.name, sizeof(child));
|
||||
if (revoke_subdirs(child, dhandle, object_id, revoke_mask, count))
|
||||
rc = 1;
|
||||
}
|
||||
} while (_dos_findnext(&ff) == 0);
|
||||
}
|
||||
|
||||
return(rc);
|
||||
}
|
||||
|
||||
static int revoke_files(char *path, uint16 dhandle, uint32 object_id,
|
||||
uint16 revoke_mask, int *count)
|
||||
{
|
||||
struct find_t ff;
|
||||
char dir[260];
|
||||
char pat[80];
|
||||
char spec[260];
|
||||
char target[260];
|
||||
int rc = 0;
|
||||
|
||||
if (trustee_path_is_dir(path)) {
|
||||
strmaxcpy(dir, path, sizeof(dir) - 1);
|
||||
strmaxcpy(pat, "*.*", sizeof(pat) - 1);
|
||||
} else if (trustee_path_has_wildcards(path)) {
|
||||
trustee_parent_pattern(dir, pat, path, sizeof(dir), sizeof(pat));
|
||||
} else {
|
||||
if (revoke_one(path, dhandle, object_id, revoke_mask, 1) == 0)
|
||||
(*count)++;
|
||||
else
|
||||
rc = 1;
|
||||
return(rc);
|
||||
}
|
||||
|
||||
trustee_join_path(spec, dir, pat, sizeof(spec));
|
||||
if (_dos_findfirst(spec, _A_NORMAL | _A_HIDDEN | _A_SYSTEM | _A_ARCH, &ff) == 0) {
|
||||
do {
|
||||
if (!(ff.attrib & _A_SUBDIR)) {
|
||||
trustee_join_path(target, dir, ff.name, sizeof(target));
|
||||
if (revoke_one(target, dhandle, object_id, revoke_mask, 1) == 0)
|
||||
(*count)++;
|
||||
else
|
||||
rc = 1;
|
||||
}
|
||||
} while (_dos_findnext(&ff) == 0);
|
||||
}
|
||||
|
||||
return(rc);
|
||||
}
|
||||
|
||||
int func_revoke(int argc, char *argv[], int mode)
|
||||
{
|
||||
uint16 rights = 0;
|
||||
char *path = ".";
|
||||
char *objname = NULL;
|
||||
char objprint[48];
|
||||
uint16 objtype = TRUSTEE_BINDERY_USER;
|
||||
int objtype_given = 0;
|
||||
uint8 connid = 0;
|
||||
uint8 dhandle = 0;
|
||||
uint32 object_id;
|
||||
int use_subdirs = 0;
|
||||
int use_files = 0;
|
||||
int count = 0;
|
||||
int i = 1;
|
||||
int have_rights = 0;
|
||||
int rc;
|
||||
|
||||
(void)mode;
|
||||
|
||||
if (argc < 2 || trustee_is_help(argv[1])) {
|
||||
if (argc < 2)
|
||||
revoke_usage_error();
|
||||
revoke_usage();
|
||||
return(argc < 2 ? 1 : 0);
|
||||
}
|
||||
|
||||
while (i < argc) {
|
||||
if (trustee_same(argv[i], "FOR") || trustee_same(argv[i], "FROM"))
|
||||
break;
|
||||
if (trustee_is_option(argv[i]))
|
||||
break;
|
||||
if (trustee_parse_right_word(argv[i], &rights)) {
|
||||
fprintf(stdout, "Invalid right specified.\n");
|
||||
revoke_usage();
|
||||
return(1);
|
||||
}
|
||||
have_rights = 1;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (!have_rights || i >= argc) {
|
||||
revoke_usage_error();
|
||||
revoke_usage();
|
||||
return(1);
|
||||
}
|
||||
|
||||
if (trustee_same(argv[i], "FOR")) {
|
||||
i++;
|
||||
if (i >= argc) {
|
||||
revoke_usage_error();
|
||||
revoke_usage();
|
||||
return(1);
|
||||
}
|
||||
path = argv[i++];
|
||||
}
|
||||
|
||||
if (i >= argc || !trustee_same(argv[i], "FROM")) {
|
||||
revoke_usage_error();
|
||||
revoke_usage();
|
||||
return(1);
|
||||
}
|
||||
i++;
|
||||
|
||||
if (i < argc && trustee_same(argv[i], "USER")) {
|
||||
objtype = TRUSTEE_BINDERY_USER;
|
||||
objtype_given = 1;
|
||||
i++;
|
||||
} else if (i < argc && trustee_same(argv[i], "GROUP")) {
|
||||
objtype = TRUSTEE_BINDERY_GROUP;
|
||||
objtype_given = 1;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i >= argc) {
|
||||
revoke_usage_error();
|
||||
revoke_usage();
|
||||
return(1);
|
||||
}
|
||||
|
||||
objname = argv[i++];
|
||||
|
||||
while (i < argc) {
|
||||
if (!trustee_is_option(argv[i])) {
|
||||
revoke_usage_error();
|
||||
revoke_usage();
|
||||
return(1);
|
||||
}
|
||||
|
||||
if (trustee_is_files_option(argv[i])) {
|
||||
use_files = 1;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (trustee_is_subdirs_option(argv[i])) {
|
||||
use_subdirs = 1;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
revoke_usage_error();
|
||||
revoke_usage();
|
||||
return(1);
|
||||
}
|
||||
|
||||
if (use_files && use_subdirs) {
|
||||
fprintf(stdout, "Revoke cannot do both directories and files in a single pass.\n");
|
||||
return(1);
|
||||
}
|
||||
|
||||
if (trustee_current_dhandle(&connid, &dhandle)) {
|
||||
fprintf(stdout, "Error: Drive not mapped to Network.\n");
|
||||
return(1);
|
||||
}
|
||||
|
||||
object_id = trustee_lookup_object(objname, &objtype, objtype_given);
|
||||
if (!object_id) {
|
||||
if (objtype_given && objtype == TRUSTEE_BINDERY_GROUP)
|
||||
fprintf(stdout, "Group \"%s\" not found.\n", objname);
|
||||
else if (objtype_given)
|
||||
fprintf(stdout, "User \"%s\" not found.\n", objname);
|
||||
else
|
||||
fprintf(stdout, "User or group \"%s\" not found.\n", objname);
|
||||
return(1);
|
||||
}
|
||||
|
||||
trustee_upcopy(objprint, objname, sizeof(objprint));
|
||||
|
||||
if (use_subdirs)
|
||||
rc = revoke_subdirs(path, (uint16)dhandle, object_id, rights, &count);
|
||||
else if (use_files)
|
||||
rc = revoke_files(path, (uint16)dhandle, object_id, rights, &count);
|
||||
else {
|
||||
rc = revoke_one(path, (uint16)dhandle, object_id, rights, 0);
|
||||
if (!rc)
|
||||
count = 1;
|
||||
}
|
||||
|
||||
if (use_subdirs || (!use_files && !rc))
|
||||
fprintf(stdout, "Rights for %d directories were changed for %s.\n", count, objprint);
|
||||
else if (use_files)
|
||||
fprintf(stdout, "Rights for %d files were changed for %s.\n", count, objprint);
|
||||
|
||||
return(rc ? (revoke_last_rc ? revoke_last_rc : 1) : 0);
|
||||
}
|
||||
271
rights.c
Normal file
271
rights.c
Normal file
@@ -0,0 +1,271 @@
|
||||
/* rights.c - Novell RIGHTS-like DOS utility, read-only v4 */
|
||||
|
||||
#include "net.h"
|
||||
#include "c32ncp.h"
|
||||
#include <dos.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifndef S_IFDIR
|
||||
#define S_IFDIR 0040000
|
||||
#endif
|
||||
|
||||
#define NW_RIGHT_S 0x01
|
||||
#define NW_RIGHT_R 0x02
|
||||
#define NW_RIGHT_W 0x04
|
||||
#define NW_RIGHT_C 0x08
|
||||
#define NW_RIGHT_E 0x10
|
||||
#define NW_RIGHT_M 0x20
|
||||
#define NW_RIGHT_F 0x40
|
||||
#define NW_RIGHT_A 0x80
|
||||
|
||||
/* NCP effective-rights bits returned by NCP87 subfunction 29. */
|
||||
#define NCP_RIGHT_READ 0x0001
|
||||
#define NCP_RIGHT_WRITE 0x0002
|
||||
#define NCP_RIGHT_OPEN 0x0004
|
||||
#define NCP_RIGHT_CREATE 0x0008
|
||||
#define NCP_RIGHT_DELETE 0x0010
|
||||
#define NCP_RIGHT_OWNER 0x0020
|
||||
#define NCP_RIGHT_SEARCH 0x0040
|
||||
#define NCP_RIGHT_MODIFY 0x0080
|
||||
#define NCP_RIGHT_SUPER 0x0100
|
||||
|
||||
static uint8 rights_map_ncp_mask(uint16 ncp_rights);
|
||||
|
||||
|
||||
static void rights_usage(void)
|
||||
{
|
||||
fprintf(stdout, "Usage: RIGHTS [path]\n\n");
|
||||
fprintf(stdout, "Rights = All | Supervisor | Read | Write | Create | Erase\n");
|
||||
fprintf(stdout, " Modify | File scan | Access Control\n");
|
||||
}
|
||||
|
||||
static void rights_parent_path(char *dst, char *src, int max)
|
||||
{
|
||||
char tmp[260];
|
||||
char *p;
|
||||
|
||||
tool_upcopy(tmp, src, sizeof(tmp));
|
||||
|
||||
p = strrchr(tmp, '\\');
|
||||
if (!p) p = strrchr(tmp, ':');
|
||||
|
||||
if (!p) {
|
||||
dst[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
if (*p == ':') {
|
||||
p++;
|
||||
*p = '\0';
|
||||
} else {
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
strmaxcpy(dst, tmp, max - 1);
|
||||
}
|
||||
|
||||
static int rights_path_is_dir(char *path)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (tool_is_current_path(path))
|
||||
return(1);
|
||||
|
||||
if (stat(path, &st) == 0) {
|
||||
if (st.st_mode & S_IFDIR)
|
||||
return(1);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
static int rights_effective_mask(char *path, int is_dir, uint8 *mask)
|
||||
{
|
||||
uint8 connid = 0;
|
||||
uint8 dhandle = 0;
|
||||
uint8 eff = 0;
|
||||
char usepath[260];
|
||||
int newhandle;
|
||||
uint16 ncp_rights = 0;
|
||||
|
||||
if (mask) *mask = 0;
|
||||
|
||||
if (tool_current_dhandle(&connid, &dhandle))
|
||||
return(-1);
|
||||
|
||||
/*
|
||||
* Prefer the explicit Client32 NCP87 effective-rights request. This is
|
||||
* the DOS Client32 equivalent of ncpfs ncp_get_eff_directory_rights().
|
||||
* It works for both files and directories, so pass the requested path
|
||||
* itself instead of mapping files to their parent directory.
|
||||
*/
|
||||
if (!c32_ncp87_get_effective_rights(tool_is_current_path(path) ? "" : path,
|
||||
(uint16)dhandle,
|
||||
&ncp_rights,
|
||||
NULL, NULL, NULL)) {
|
||||
if (mask) *mask = rights_map_ncp_mask(ncp_rights);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fallback for older requesters/paths: allocate a temporary directory
|
||||
* handle and use the returned old-style effective-rights byte.
|
||||
* This cannot directly target a file, so files are mapped to their parent.
|
||||
*/
|
||||
if (tool_is_current_path(path)) {
|
||||
usepath[0] = '\0';
|
||||
} else if (is_dir) {
|
||||
tool_upcopy(usepath, path, sizeof(usepath));
|
||||
} else {
|
||||
rights_parent_path(usepath, path, sizeof(usepath));
|
||||
}
|
||||
|
||||
newhandle = alloc_temp_dir_handle(dhandle, usepath, 0, &eff);
|
||||
if (newhandle < 0) {
|
||||
if (usepath[0]) {
|
||||
int subdir = 1;
|
||||
int r = ncp_16_02(dhandle, (uint8 *)usepath, &subdir,
|
||||
NULL, NULL, NULL);
|
||||
if (r >= 0) {
|
||||
eff = (uint8)r;
|
||||
} else {
|
||||
return(-1);
|
||||
}
|
||||
} else {
|
||||
eff = 0xff;
|
||||
}
|
||||
} else {
|
||||
dealloc_dir_handle(newhandle);
|
||||
}
|
||||
|
||||
if (mask) *mask = eff;
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
static uint8 rights_map_ncp_mask(uint16 ncp_rights)
|
||||
{
|
||||
uint8 mask = 0;
|
||||
|
||||
if (ncp_rights & NCP_RIGHT_SUPER) mask |= NW_RIGHT_S;
|
||||
if (ncp_rights & NCP_RIGHT_READ) mask |= NW_RIGHT_R;
|
||||
if (ncp_rights & NCP_RIGHT_WRITE) mask |= NW_RIGHT_W;
|
||||
if (ncp_rights & NCP_RIGHT_CREATE) mask |= NW_RIGHT_C;
|
||||
if (ncp_rights & NCP_RIGHT_DELETE) mask |= NW_RIGHT_E;
|
||||
if (ncp_rights & NCP_RIGHT_MODIFY) mask |= NW_RIGHT_M;
|
||||
if (ncp_rights & NCP_RIGHT_SEARCH) mask |= NW_RIGHT_F;
|
||||
if (ncp_rights & NCP_RIGHT_OWNER) mask |= NW_RIGHT_A;
|
||||
|
||||
return(mask);
|
||||
}
|
||||
|
||||
|
||||
static void rights_mask_string(uint8 mask, char *out)
|
||||
{
|
||||
out[0] = (mask & NW_RIGHT_S) ? 'S' : '-';
|
||||
out[1] = (mask & NW_RIGHT_R) ? 'R' : '-';
|
||||
out[2] = (mask & NW_RIGHT_W) ? 'W' : '-';
|
||||
out[3] = (mask & NW_RIGHT_C) ? 'C' : '-';
|
||||
out[4] = (mask & NW_RIGHT_E) ? 'E' : '-';
|
||||
out[5] = (mask & NW_RIGHT_M) ? 'M' : '-';
|
||||
out[6] = (mask & NW_RIGHT_F) ? 'F' : '-';
|
||||
out[7] = (mask & NW_RIGHT_A) ? 'A' : '-';
|
||||
out[8] = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* Novell RIGHTS layout:
|
||||
* - lines with star: two leading blanks, star, blank, text
|
||||
* - lines without star: four leading blanks, text
|
||||
* Keep the right-column letter at a fixed-ish DOS-screen position.
|
||||
*/
|
||||
static void rights_print_line(int have, int star, char *text, char letter)
|
||||
{
|
||||
(void)have;
|
||||
|
||||
if (star)
|
||||
fprintf(stdout, " * %-43s(%c)\n", text, letter);
|
||||
else
|
||||
fprintf(stdout, " %-43s(%c)\n", text, letter);
|
||||
}
|
||||
|
||||
static void rights_display(char *path, int is_dir, uint8 mask)
|
||||
{
|
||||
char hdr[300];
|
||||
char mstr[10];
|
||||
|
||||
tool_header_path(hdr, path, sizeof(hdr));
|
||||
rights_mask_string(mask, mstr);
|
||||
|
||||
fprintf(stdout, "%s\n", hdr);
|
||||
|
||||
if (is_dir)
|
||||
fprintf(stdout, "Your Effective Rights for this directory are [%s]\n", mstr);
|
||||
else
|
||||
fprintf(stdout, "Your Effective Rights for this file are [%s]\n", mstr);
|
||||
|
||||
if (is_dir) {
|
||||
rights_print_line(mask & NW_RIGHT_S, 0, "You have Supervisor Rights to Directory.", 'S');
|
||||
rights_print_line(mask & NW_RIGHT_R, 1, "May Read from File.", 'R');
|
||||
rights_print_line(mask & NW_RIGHT_W, 1, "May Write to File.", 'W');
|
||||
rights_print_line(mask & NW_RIGHT_C, 0, "May Create Subdirectories and Files.", 'C');
|
||||
rights_print_line(mask & NW_RIGHT_E, 0, "May Erase Directory.", 'E');
|
||||
rights_print_line(mask & NW_RIGHT_M, 0, "May Modify Directory.", 'M');
|
||||
rights_print_line(mask & NW_RIGHT_F, 0, "May Scan for Files.", 'F');
|
||||
rights_print_line(mask & NW_RIGHT_A, 0, "May Change Access Control.", 'A');
|
||||
|
||||
fprintf(stdout, "\n");
|
||||
fprintf(stdout, " * Has no effect on directory.\n\n");
|
||||
fprintf(stdout, " Entries in Directory May Inherit [%s] rights.\n", mstr);
|
||||
if (mask == 0xff)
|
||||
fprintf(stdout, " You have ALL RIGHTS to Directory Entry.\n");
|
||||
} else {
|
||||
rights_print_line(mask & NW_RIGHT_S, 0, "You have Supervisor Rights to File.", 'S');
|
||||
rights_print_line(mask & NW_RIGHT_R, 0, "May Read from File.", 'R');
|
||||
rights_print_line(mask & NW_RIGHT_W, 0, "May Write to File.", 'W');
|
||||
rights_print_line(mask & NW_RIGHT_C, 1, "May Create Subdirectories and Files.", 'C');
|
||||
rights_print_line(mask & NW_RIGHT_E, 0, "May Erase File.", 'E');
|
||||
rights_print_line(mask & NW_RIGHT_M, 0, "May Modify File.", 'M');
|
||||
rights_print_line(mask & NW_RIGHT_F, 0, "May Scan for File.", 'F');
|
||||
rights_print_line(mask & NW_RIGHT_A, 0, "May Change Access Control.", 'A');
|
||||
|
||||
fprintf(stdout, "\n");
|
||||
fprintf(stdout, " * Create is necessary to salvage a file that has been deleted.\n\n");
|
||||
if (mask == 0xff)
|
||||
fprintf(stdout, " You have ALL RIGHTS to Directory Entry.\n");
|
||||
}
|
||||
}
|
||||
|
||||
int func_rights(int argc, char *argv[], int mode)
|
||||
{
|
||||
char *path = ".";
|
||||
uint8 mask = 0;
|
||||
int is_dir;
|
||||
|
||||
(void)mode;
|
||||
|
||||
if (argc > 2) {
|
||||
rights_usage();
|
||||
return(1);
|
||||
}
|
||||
|
||||
if (argc == 2) {
|
||||
if (tool_is_help_arg(argv[1])) {
|
||||
rights_usage();
|
||||
return(0);
|
||||
}
|
||||
path = argv[1];
|
||||
}
|
||||
|
||||
is_dir = rights_path_is_dir(path);
|
||||
|
||||
if (rights_effective_mask(path, is_dir, &mask)) {
|
||||
fprintf(stdout, "Specified path not locatable.\n");
|
||||
return(1);
|
||||
}
|
||||
|
||||
rights_display(path, is_dir, mask);
|
||||
return(0);
|
||||
}
|
||||
88
slist.c
88
slist.c
@@ -2,17 +2,49 @@
|
||||
|
||||
#include "net.h"
|
||||
|
||||
#define NCP_BINDERY_FSERVER 0x0004
|
||||
|
||||
static int usage(void)
|
||||
{
|
||||
fprintf(stderr, "usage:\t%s [pattern]\n", funcname);
|
||||
return(-1);
|
||||
fprintf(stdout, "Usage: SLIST [Server] [/Continue]\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
static void print_net_node(uint8 *addr)
|
||||
static int same_arg(char *a, char *b)
|
||||
{
|
||||
fprintf(stdout, "%08lX %02X%02X%02X%02X%02X%02X",
|
||||
while (*a || *b) {
|
||||
int ca = *a++;
|
||||
int cb = *b++;
|
||||
if (ca >= 'a' && ca <= 'z') ca -= 32;
|
||||
if (cb >= 'a' && cb <= 'z') cb -= 32;
|
||||
if (ca != cb) return(0);
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
static int is_help_arg(char *s)
|
||||
{
|
||||
if (!s) return(0);
|
||||
return(same_arg(s, "/?") || same_arg(s, "-?") || same_arg(s, "?"));
|
||||
}
|
||||
|
||||
static unsigned long node_to_number(uint8 *addr)
|
||||
{
|
||||
unsigned long n = 0;
|
||||
int i;
|
||||
|
||||
for (i = 4; i < 10; i++)
|
||||
n = (n << 8) + addr[i];
|
||||
|
||||
return(n);
|
||||
}
|
||||
|
||||
static void print_net_node_status(uint8 *addr, int is_default)
|
||||
{
|
||||
fprintf(stdout, "[%08lX][%12lu]%s",
|
||||
(unsigned long)GET_BE32(addr),
|
||||
addr[4], addr[5], addr[6], addr[7], addr[8], addr[9]);
|
||||
node_to_number(addr),
|
||||
is_default ? "Default" : "");
|
||||
}
|
||||
|
||||
int func_slist(int argc, char *argv[], int mode)
|
||||
@@ -22,42 +54,62 @@ int func_slist(int argc, char *argv[], int mode)
|
||||
uint8 pattern[50];
|
||||
int found = 0;
|
||||
int result;
|
||||
int i;
|
||||
int continuous = 0;
|
||||
int line_count = 0;
|
||||
|
||||
(void)mode;
|
||||
|
||||
if (argc > 2) return(usage());
|
||||
strcpy(pattern, "*");
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (is_help_arg(argv[i])) return(usage());
|
||||
|
||||
if (argv[i][0] == '/' || argv[i][0] == '-') {
|
||||
if (same_arg(argv[i], "/C") || same_arg(argv[i], "/CONTINUE") ||
|
||||
same_arg(argv[i], "-C") || same_arg(argv[i], "-CONTINUE")) {
|
||||
continuous = 1;
|
||||
continue;
|
||||
}
|
||||
return(usage());
|
||||
}
|
||||
|
||||
strmaxcpy(pattern, argv[i], sizeof(pattern) - 1);
|
||||
}
|
||||
|
||||
if (argc == 2) strmaxcpy(pattern, argv[1], sizeof(pattern) - 1);
|
||||
else strcpy(pattern, "*");
|
||||
upstr(pattern);
|
||||
|
||||
fprintf(stdout, "\n%-52s%-10s%-12s\n",
|
||||
"Known NetWare File Servers", "Network", "Node Address");
|
||||
fprintf(stdout,
|
||||
"-----------------------------------------------"
|
||||
"---------------------------\n");
|
||||
/*
|
||||
* Novell-like layout from the DOS client:
|
||||
* Known NetWare File Servers Network Node Address Status
|
||||
* ------------------------- -------- -------------------
|
||||
*/
|
||||
fprintf(stdout, "%-44sNetwork Node Address Status\n",
|
||||
"Known NetWare File Servers");
|
||||
fprintf(stdout, "%-44s------- ----------- ------\n",
|
||||
"--------------------------");
|
||||
|
||||
while ((result = ncp_17_37(last_id, NCP_BINDERY_FSERVER,
|
||||
pattern, &obj)) == 0) {
|
||||
NW_PROPERTY prop;
|
||||
|
||||
found = 1;
|
||||
found++;
|
||||
last_id = obj.object_id;
|
||||
|
||||
fprintf(stdout, "%-52s", obj.object_name);
|
||||
fprintf(stdout, "%-44s", obj.object_name);
|
||||
|
||||
if (!ncp_17_3d(NCP_BINDERY_FSERVER, obj.object_name,
|
||||
1, "NET_ADDRESS", &prop)) {
|
||||
print_net_node(prop.value);
|
||||
print_net_node_status(prop.value, found == 1);
|
||||
}
|
||||
|
||||
fprintf(stdout, "\n");
|
||||
tool_page_line(&line_count, &continuous);
|
||||
|
||||
if (last_id == MAX_U32) break;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
fprintf(stdout, "No servers found\n");
|
||||
fprintf(stdout, "\nTotal of %d file servers found\n", found);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
4
teste.c
4
teste.c
@@ -22,11 +22,11 @@ int main()
|
||||
close(fd);
|
||||
_chmod(fn, 1, _chmod(fn, 0) | 0x80 );
|
||||
stat(fn, &stbuff);
|
||||
printf("Filesize <20>ber stat =%ld\n", stbuff.st_size);
|
||||
printf("Filesize <20>ber stat =%ld\n", stbuff.st_size);
|
||||
fd = open(fn, O_RDWR | O_BINARY |O_DENYNONE);
|
||||
|
||||
offset = lseek(fd, 0L, SEEK_END);
|
||||
printf("Filesize <20>ber lseek =%ld\n", offset);
|
||||
printf("Filesize <20>ber lseek =%ld\n", offset);
|
||||
write(fd, buff, strlen(buff));
|
||||
|
||||
lseek(fd, 0L, SEEK_SET);
|
||||
|
||||
285
tools.c
285
tools.c
@@ -328,7 +328,7 @@ int putglobenv(char *option)
|
||||
}
|
||||
search=nextp;
|
||||
}
|
||||
/* nicht gefunden , nun eintragen, falls m”glich */
|
||||
/* nicht gefunden , nun eintragen, falls m�glich */
|
||||
if (*(equal+1) && optionlen < maxenvsize - aktenvsize) {
|
||||
strcpy(search, option);
|
||||
*(search+optionlen+1) = '\0'; /* letzter Eintrag '\0' nicht vergessen */
|
||||
@@ -339,3 +339,286 @@ int putglobenv(char *option)
|
||||
return(-1);
|
||||
}
|
||||
|
||||
|
||||
int tool_page_line(int *line_count, int *continuous)
|
||||
{
|
||||
int ch;
|
||||
|
||||
if (!line_count || !continuous)
|
||||
return(0);
|
||||
|
||||
if (*continuous)
|
||||
return(0);
|
||||
|
||||
(*line_count)++;
|
||||
if (*line_count < 24)
|
||||
return(0);
|
||||
|
||||
fprintf(stdout, "Press any key to continue ('C' for continue)");
|
||||
fflush(stdout);
|
||||
ch = getch();
|
||||
fprintf(stdout, "\n");
|
||||
|
||||
if (ch == 'c' || ch == 'C')
|
||||
*continuous = 1;
|
||||
|
||||
*line_count = 0;
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Shared helpers for the newer DOS utility frontends.
|
||||
*
|
||||
* These deliberately stay in tools.c instead of in grant/revoke/remove/
|
||||
* rights/flagdir so the current multicall binary and possible future
|
||||
* grouped multicall binaries can reuse the same code without dragging in
|
||||
* command-specific modules.
|
||||
****************************************************************/
|
||||
|
||||
int tool_strsame(char *a, char *b)
|
||||
{
|
||||
if (!a) a = "";
|
||||
if (!b) b = "";
|
||||
|
||||
while (*a || *b) {
|
||||
int ca = *a++;
|
||||
int cb = *b++;
|
||||
if (ca >= 'a' && ca <= 'z') ca -= 32;
|
||||
if (cb >= 'a' && cb <= 'z') cb -= 32;
|
||||
if (ca != cb) return(0);
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
int tool_is_help_arg(char *s)
|
||||
{
|
||||
if (!s) return(0);
|
||||
return(tool_strsame(s, "/?") || tool_strsame(s, "-?") ||
|
||||
tool_strsame(s, "?"));
|
||||
}
|
||||
|
||||
int tool_is_option(char *s)
|
||||
{
|
||||
if (!s) return(0);
|
||||
return(s[0] == '/' || s[0] == '-');
|
||||
}
|
||||
|
||||
int tool_is_files_option(char *s)
|
||||
{
|
||||
if (!s) return(0);
|
||||
return(tool_strsame(s, "/FILES") || tool_strsame(s, "-FILES") ||
|
||||
tool_strsame(s, "/F") || tool_strsame(s, "-F"));
|
||||
}
|
||||
|
||||
int tool_is_subdirs_option(char *s)
|
||||
{
|
||||
if (!s) return(0);
|
||||
return(tool_strsame(s, "/SUBDIRS") || tool_strsame(s, "-SUBDIRS") ||
|
||||
tool_strsame(s, "/SUBDIRECTORIES") ||
|
||||
tool_strsame(s, "-SUBDIRECTORIES") ||
|
||||
tool_strsame(s, "/S") || tool_strsame(s, "-S"));
|
||||
}
|
||||
|
||||
int tool_get_current_drive(void)
|
||||
{
|
||||
REGS regs;
|
||||
|
||||
regs.h.ah = 0x19;
|
||||
int86(0x21, ®s, ®s);
|
||||
return((int)regs.h.al);
|
||||
}
|
||||
|
||||
int tool_current_dhandle(uint8 *connid, uint8 *dhandle)
|
||||
{
|
||||
uint8 flags = 0;
|
||||
int drive = tool_get_current_drive();
|
||||
|
||||
if (get_drive_info((uint8)drive, connid, dhandle, &flags))
|
||||
return(-1);
|
||||
|
||||
if (!*connid || (flags & 0x80))
|
||||
return(-1);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int tool_current_prefix(char *out, int max)
|
||||
{
|
||||
uint8 connid = 0;
|
||||
uint8 dhandle = 0;
|
||||
uint8 flags = 0;
|
||||
int drive;
|
||||
char server[52];
|
||||
char dpath[260];
|
||||
char volume[32];
|
||||
char *p;
|
||||
int i = 0;
|
||||
|
||||
if (!out || max < 8)
|
||||
return(-1);
|
||||
|
||||
out[0] = '\0';
|
||||
|
||||
drive = tool_get_current_drive();
|
||||
if (get_drive_info((uint8)drive, &connid, &dhandle, &flags))
|
||||
return(-1);
|
||||
|
||||
if (!connid || (flags & 0x80))
|
||||
return(-1);
|
||||
|
||||
server[0] = '\0';
|
||||
if (get_fs_name(connid, server))
|
||||
server[0] = '\0';
|
||||
|
||||
dpath[0] = '\0';
|
||||
if (get_dir_path(dhandle, dpath) || !dpath[0])
|
||||
return(-1);
|
||||
|
||||
p = strchr(dpath, ':');
|
||||
if (!p)
|
||||
return(-1);
|
||||
|
||||
while (dpath + i < p && i < (int)sizeof(volume) - 1) {
|
||||
volume[i] = dpath[i];
|
||||
i++;
|
||||
}
|
||||
volume[i] = '\0';
|
||||
|
||||
if (!volume[0])
|
||||
return(-1);
|
||||
|
||||
if (server[0])
|
||||
sprintf(out, "%s/%s:", server, volume);
|
||||
else
|
||||
sprintf(out, "%s:", volume);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int tool_is_current_path(char *path)
|
||||
{
|
||||
if (!path || !*path) return(1);
|
||||
if (tool_strsame(path, ".")) return(1);
|
||||
if (tool_strsame(path, ".\\")) return(1);
|
||||
if (tool_strsame(path, "./")) return(1);
|
||||
return(0);
|
||||
}
|
||||
|
||||
void tool_upcopy(char *dst, char *src, int max)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (!src) src = "";
|
||||
|
||||
while (*src && i < max - 1) {
|
||||
char c = *src++;
|
||||
if (c == '/') c = '\\';
|
||||
if (c >= 'a' && c <= 'z') c -= 32;
|
||||
dst[i++] = c;
|
||||
}
|
||||
dst[i] = 0;
|
||||
}
|
||||
|
||||
void tool_basename(char *dst, char *src, int max)
|
||||
{
|
||||
char up[260];
|
||||
char *p;
|
||||
|
||||
tool_upcopy(up, src, sizeof(up));
|
||||
p = strrchr(up, '\\');
|
||||
if (!p) p = strrchr(up, ':');
|
||||
|
||||
if (p)
|
||||
strmaxcpy(dst, p + 1, max - 1);
|
||||
else
|
||||
strmaxcpy(dst, up, max - 1);
|
||||
}
|
||||
|
||||
void tool_header_path(char *out, char *path, int max)
|
||||
{
|
||||
char prefix[90];
|
||||
char up[260];
|
||||
|
||||
if (tool_current_prefix(prefix, sizeof(prefix)))
|
||||
prefix[0] = '\0';
|
||||
|
||||
if (tool_is_current_path(path)) {
|
||||
strmaxcpy(out, prefix, max - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
tool_upcopy(up, path, sizeof(up));
|
||||
strmaxcpy(out, prefix, max - 1);
|
||||
if ((int)(strlen(out) + strlen(up)) < max - 1)
|
||||
strcat(out, up);
|
||||
}
|
||||
|
||||
int tool_is_dot_dir(char *name)
|
||||
{
|
||||
if (!name) return(0);
|
||||
if (name[0] == '.' && name[1] == '\0') return(1);
|
||||
if (name[0] == '.' && name[1] == '.' && name[2] == '\0') return(1);
|
||||
return(0);
|
||||
}
|
||||
|
||||
void tool_join_path(char *out, char *base, char *name, int max)
|
||||
{
|
||||
int len;
|
||||
|
||||
out[0] = '\0';
|
||||
strmaxcpy(out, base, max - 1);
|
||||
len = strlen(out);
|
||||
|
||||
if (len > 0 && out[len - 1] != '\\' && out[len - 1] != '/' &&
|
||||
out[len - 1] != ':') {
|
||||
if (len < max - 1) {
|
||||
out[len++] = '\\';
|
||||
out[len] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
if ((int)(strlen(out) + strlen(name)) < max - 1)
|
||||
strcat(out, name);
|
||||
}
|
||||
|
||||
int tool_has_wildcards(char *path)
|
||||
{
|
||||
if (!path) return(0);
|
||||
while (*path) {
|
||||
if (*path == '*' || *path == '?') return(1);
|
||||
path++;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
void tool_parent_pattern(char *dir, char *pattern, char *path,
|
||||
int maxdir, int maxpat)
|
||||
{
|
||||
char tmp[260];
|
||||
char *p;
|
||||
|
||||
tool_upcopy(tmp, path, sizeof(tmp));
|
||||
p = strrchr(tmp, '\\');
|
||||
if (!p) p = strrchr(tmp, ':');
|
||||
|
||||
if (p) {
|
||||
if (*p == ':') {
|
||||
p++;
|
||||
strmaxcpy(pattern, p, maxpat - 1);
|
||||
*p = '\0';
|
||||
strmaxcpy(dir, tmp, maxdir - 1);
|
||||
} else {
|
||||
strmaxcpy(pattern, p + 1, maxpat - 1);
|
||||
*p = '\0';
|
||||
strmaxcpy(dir, tmp, maxdir - 1);
|
||||
}
|
||||
} else {
|
||||
strmaxcpy(dir, ".", maxdir - 1);
|
||||
strmaxcpy(pattern, tmp, maxpat - 1);
|
||||
}
|
||||
|
||||
if (!pattern[0])
|
||||
strmaxcpy(pattern, "*.*", maxpat - 1);
|
||||
}
|
||||
|
||||
165
trustee.c
Normal file
165
trustee.c
Normal file
@@ -0,0 +1,165 @@
|
||||
/* trustee.c - shared helpers for GRANT/REVOKE/REMOVE style tools */
|
||||
|
||||
#include "net.h"
|
||||
#include "trustee.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifndef S_IFDIR
|
||||
#define S_IFDIR 0040000
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
int trustee_same(char *a, char *b) { return(tool_strsame(a, b)); }
|
||||
int trustee_is_help(char *s) { return(tool_is_help_arg(s)); }
|
||||
int trustee_is_option(char *s) { return(tool_is_option(s)); }
|
||||
int trustee_current_dhandle(uint8 *connid, uint8 *dhandle)
|
||||
{
|
||||
return(tool_current_dhandle(connid, dhandle));
|
||||
}
|
||||
void trustee_upcopy(char *dst, char *src, int max) { tool_upcopy(dst, src, max); }
|
||||
void trustee_basename(char *dst, char *src, int max)
|
||||
{
|
||||
tool_basename(dst, src, max);
|
||||
}
|
||||
void trustee_header_path(char *out, char *path, int max)
|
||||
{
|
||||
tool_header_path(out, path, max);
|
||||
}
|
||||
void trustee_join_path(char *out, char *base, char *name, int max)
|
||||
{
|
||||
tool_join_path(out, base, name, max);
|
||||
}
|
||||
int trustee_is_dot_dir(char *name) { return(tool_is_dot_dir(name)); }
|
||||
int trustee_path_has_wildcards(char *path) { return(tool_has_wildcards(path)); }
|
||||
void trustee_parent_pattern(char *dir, char *pattern, char *path,
|
||||
int maxdir, int maxpat)
|
||||
{
|
||||
tool_parent_pattern(dir, pattern, path, maxdir, maxpat);
|
||||
}
|
||||
|
||||
int trustee_is_subdirs_option(char *s)
|
||||
{
|
||||
if (!s) return(0);
|
||||
return(trustee_same(s, "/SUBDIRS") || trustee_same(s, "-SUBDIRS") ||
|
||||
trustee_same(s, "/SUBDIRECTORIES") || trustee_same(s, "-SUBDIRECTORIES") ||
|
||||
trustee_same(s, "/S") || trustee_same(s, "-S"));
|
||||
}
|
||||
|
||||
int trustee_is_files_option(char *s)
|
||||
{
|
||||
if (!s) return(0);
|
||||
return(trustee_same(s, "/FILES") || trustee_same(s, "-FILES") ||
|
||||
trustee_same(s, "/F") || trustee_same(s, "-F"));
|
||||
}
|
||||
|
||||
int trustee_parse_right_word(char *s, uint16 *rights)
|
||||
{
|
||||
if (trustee_same(s, "ALL")) {
|
||||
*rights = TRUSTEE_RIGHT_ALL_386;
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (trustee_same(s, "N") || trustee_same(s, "NONE")) {
|
||||
*rights = TRUSTEE_RIGHT_ALL_386;
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (trustee_same(s, "S") || trustee_same(s, "SUPERVISOR")) {
|
||||
*rights |= TRUSTEE_RIGHT_SUPER;
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (trustee_same(s, "R") || trustee_same(s, "READ")) {
|
||||
*rights |= TRUSTEE_RIGHT_READ;
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (trustee_same(s, "W") || trustee_same(s, "WRITE")) {
|
||||
*rights |= TRUSTEE_RIGHT_WRITE;
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (trustee_same(s, "C") || trustee_same(s, "CREATE")) {
|
||||
*rights |= TRUSTEE_RIGHT_CREATE;
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (trustee_same(s, "E") || trustee_same(s, "ERASE") ||
|
||||
trustee_same(s, "D") || trustee_same(s, "DELETE")) {
|
||||
*rights |= TRUSTEE_RIGHT_DELETE;
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (trustee_same(s, "M") || trustee_same(s, "MODIFY")) {
|
||||
*rights |= TRUSTEE_RIGHT_MODIFY;
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (trustee_same(s, "F") || trustee_same(s, "FILESCAN") ||
|
||||
trustee_same(s, "FILE") || trustee_same(s, "SCAN")) {
|
||||
*rights |= TRUSTEE_RIGHT_SEARCH;
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (trustee_same(s, "A") || trustee_same(s, "ACCESS") ||
|
||||
trustee_same(s, "CONTROL") || trustee_same(s, "ACCESSCONTROL")) {
|
||||
*rights |= TRUSTEE_RIGHT_OWNER;
|
||||
return(0);
|
||||
}
|
||||
|
||||
return(-1);
|
||||
}
|
||||
|
||||
void trustee_rights_bracket(uint16 rights, char *out)
|
||||
{
|
||||
out[0] = (rights & TRUSTEE_RIGHT_SUPER) ? 'S' : ' ';
|
||||
out[1] = (rights & TRUSTEE_RIGHT_READ) ? 'R' : ' ';
|
||||
out[2] = (rights & TRUSTEE_RIGHT_WRITE) ? 'W' : ' ';
|
||||
out[3] = (rights & TRUSTEE_RIGHT_CREATE) ? 'C' : ' ';
|
||||
out[4] = (rights & TRUSTEE_RIGHT_DELETE) ? 'E' : ' ';
|
||||
out[5] = (rights & TRUSTEE_RIGHT_MODIFY) ? 'M' : ' ';
|
||||
out[6] = (rights & TRUSTEE_RIGHT_SEARCH) ? 'F' : ' ';
|
||||
out[7] = (rights & TRUSTEE_RIGHT_OWNER) ? 'A' : ' ';
|
||||
out[8] = '\0';
|
||||
}
|
||||
|
||||
uint32 trustee_lookup_object(char *name, uint16 *objtype, int objtype_given)
|
||||
{
|
||||
uint8 namebuf[48];
|
||||
uint32 object_id;
|
||||
|
||||
strmaxcpy(namebuf, name, sizeof(namebuf) - 1);
|
||||
upstr(namebuf);
|
||||
|
||||
if (objtype_given) {
|
||||
return(ncp_17_35(namebuf, *objtype));
|
||||
}
|
||||
|
||||
*objtype = TRUSTEE_BINDERY_USER;
|
||||
object_id = ncp_17_35(namebuf, TRUSTEE_BINDERY_USER);
|
||||
if (object_id)
|
||||
return(object_id);
|
||||
|
||||
*objtype = TRUSTEE_BINDERY_GROUP;
|
||||
object_id = ncp_17_35(namebuf, TRUSTEE_BINDERY_GROUP);
|
||||
return(object_id);
|
||||
}
|
||||
|
||||
int trustee_path_is_dir(char *path)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (!path || !*path || trustee_same(path, ".") || trustee_same(path, ".\\") ||
|
||||
trustee_same(path, "./"))
|
||||
return(1);
|
||||
|
||||
if (stat(path, &st) == 0) {
|
||||
if (st.st_mode & S_IFDIR)
|
||||
return(1);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
40
trustee.h
Normal file
40
trustee.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#ifndef TRUSTEE_H
|
||||
#define TRUSTEE_H
|
||||
|
||||
#define TRUSTEE_BINDERY_USER 0x0001
|
||||
#define TRUSTEE_BINDERY_GROUP 0x0002
|
||||
|
||||
#define TRUSTEE_RIGHT_READ 0x0001
|
||||
#define TRUSTEE_RIGHT_WRITE 0x0002
|
||||
#define TRUSTEE_RIGHT_OPEN 0x0004
|
||||
#define TRUSTEE_RIGHT_CREATE 0x0008
|
||||
#define TRUSTEE_RIGHT_DELETE 0x0010
|
||||
#define TRUSTEE_RIGHT_OWNER 0x0020
|
||||
#define TRUSTEE_RIGHT_SEARCH 0x0040
|
||||
#define TRUSTEE_RIGHT_MODIFY 0x0080
|
||||
#define TRUSTEE_RIGHT_SUPER 0x0100
|
||||
|
||||
#define TRUSTEE_RIGHT_ALL_386 (TRUSTEE_RIGHT_SUPER | TRUSTEE_RIGHT_READ | \
|
||||
TRUSTEE_RIGHT_WRITE | TRUSTEE_RIGHT_CREATE | \
|
||||
TRUSTEE_RIGHT_DELETE | TRUSTEE_RIGHT_MODIFY | \
|
||||
TRUSTEE_RIGHT_SEARCH | TRUSTEE_RIGHT_OWNER)
|
||||
|
||||
int trustee_same(char *a, char *b);
|
||||
int trustee_is_help(char *s);
|
||||
int trustee_is_option(char *s);
|
||||
int trustee_is_subdirs_option(char *s);
|
||||
int trustee_is_files_option(char *s);
|
||||
int trustee_current_dhandle(uint8 *connid, uint8 *dhandle);
|
||||
void trustee_upcopy(char *dst, char *src, int max);
|
||||
void trustee_basename(char *dst, char *src, int max);
|
||||
void trustee_header_path(char *out, char *path, int max);
|
||||
void trustee_join_path(char *out, char *base, char *name, int max);
|
||||
int trustee_is_dot_dir(char *name);
|
||||
int trustee_parse_right_word(char *s, uint16 *rights);
|
||||
void trustee_rights_bracket(uint16 rights, char *out);
|
||||
uint32 trustee_lookup_object(char *name, uint16 *objtype, int objtype_given);
|
||||
int trustee_path_is_dir(char *path);
|
||||
int trustee_path_has_wildcards(char *path);
|
||||
void trustee_parent_pattern(char *dir, char *pattern, char *path, int maxdir, int maxpat);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user