| View previous topic :: View next topic |
| Author |
Message |
Destiny
Joined: 15 Dec 2015 Posts: 339
|
(Separately) Posted: Tue Sep 08, 2026 22:34 Post subject: |
|
|
Мне казалось слова всегда лучше всего рассказывают о проблеме, потому что я могу внести пояснения туда - куда видео их не вставит.
НО реально, давайте понадеемся, что автор вернется и прочтет тут наши размышления и выложит исходники в доступ. |
|
| Back to top |
|
 |
Jonmey
Joined: 27 Sep 2010 Posts: 58
|
(Separately) Posted: Wed Sep 09, 2026 01:32 Post subject: |
|
|
| Destiny wrote: | | автор вернется и прочтет тут наши размышления и выложит исходники в доступ. |
Выкладывать исходники из-за того, что у кого-то одного из юзеров согласно его исключительно словесным заявлениям что-то не получается?
Блажен неведающий верящий в такое. Может тогда сразу Гислеру это предложить? (там даже целую паству криворуких можно организовать).
А вообще отличный был бы метод получения исходников нужной программы - заявляешь автору, что его программа кривая и требуешь дать ее исходники....  |
|
| Back to top |
|
 |
Orion9

Joined: 01 Jan 2024 Posts: 1248
|
(Separately) Posted: Wed Sep 09, 2026 12:28 Post subject: |
|
|
| Destiny wrote: | | Мне казалось слова всегда лучше всего рассказывают о проблеме, потому что я могу внести пояснения туда - куда видео их не вставит. |
Не всегда так. Иногда лучше один раз увидеть, чем сто раз услышать.
Вы говорите, что проблема у вас с любой папкой появляется, ну тогда чем не вариант:
 Hidden text
Как видите, все работает.
| Destiny wrote: | | автор вернется и прочтет тут наши размышления и выложит исходники в доступ. |
И что это даст? Болван уже расписал все, как там устроено )
 Hidden text Если проанализировать импорты исполняемого файла NTLinksMaker, вы не увидите там привычную функцию CreateSymbolicLinkW.
Вместо использования высокоуровневого Win32 API автор утилиты (MVV) работает напрямую с низкоуровневой структурой файловой системы NTFS. NTLinksMaker создает символические ссылки и точки соединения (Junctions) вручную через прямую запись данных файловой системы в репарсы.
Процесс создания ссылки изнутри выглядит следующим образом:
## 1. Создание пустого объекта
В зависимости от типа ссылки программа вызывает стандартную функцию CreateFileW (с флагами FILE_FLAG_OPEN_REPARSE_POINT и нужными атрибутами) или CreateDirectoryW. На этом этапе создается обычный «нулевой» файл или пустая папка.
## 2. Формирование буфера данных репарса
В памяти структуры выделяется специальный буфер — REPARSE_DATA_BUFFER. Программа вручную заполняет его заголовки и данные:
* Устанавливается правильный идентификатор — Reparse Tag. Для символических ссылок это константа IOCTL_REPARSE_TAG_SYMLINK (0xA000000C), а для точек соединения — IOCTL_REPARSE_TAG_MOUNT_POINT (0xA0000003).
* Внутрь буфера записываются пути к целевому объекту: как заменяющий путь (Substitute Name, имеющий вид вроде \??\C:\Target\), так и отображаемый путь (Printable Name). [1]
## 3. Запись через DeviceIoControl
Когда буфер сформирован, NTLinksMaker отправляет управляющий код драйверу файловой системы NTFS с помощью функции DeviceIoControl: [2]
DeviceIoControl(
hDevice, // Хэндл созданного файла/папки
FSCTL_SET_REPARSE_POINT, // Управляющий код для установки точки повторного анализа
lpInBuffer, // Сформированный буфер REPARSE_DATA_BUFFER
nInBufferSize, // Размер буфера
...
);
После этого NTFS превращает обычный файл или папку в полноценный системный симлинк. [2, 3]
## Зачем нужен такой сложный путь?
Прямая работа с DeviceIoControl и репарсами дает утилите несколько ключевых преимуществ:
1. Универсальность кода: Архитектура программы построена вокруг низкоуровневых точек повторного анализа (Reparse Points). Одним и тем же методом (просто меняя Reparse Tag в буфере) утилита создает и Junctions, и файловые/папочные симлинки. [4]
2. Точечный контроль: Такой подход позволяет вручную управлять флагами внутри ссылки (например, жестко задавать относительный или абсолютный путь) и исключает влияние некоторых ограничений высокоуровневого API.
3. Кросс-версионность и оптимизация: MVV проектировал плагин NTLinks и утилиту NTLinksMaker для максимальной скорости работы с Total Commander. Чтение и редактирование ссылок в самом плагине происходит через зеркальный метод — FSCTL_GET_REPARSE_POINT. Имея уже готовый код для парсинга и сборки буферов репарсов, автору было проще использовать его и для создания ссылок. [1, 4]
(Примечание: Жесткие ссылки (hardlinks) утилита создает стандартным образом через CreateHardLinkW, так как они не являются репарсами).
Хотите посмотреть на структуру буфера REPARSE_DATA_BUFFER для символических ссылок на C++, или вас интересует, как обойти требование прав администратора при создании ссылок низкоуровневым методом?
 Python Для того чтобы превратить скрипт в полноценную утилиту с графическим интерфейсом (как у NTLinksMaker), мы можем использовать встроенную в Python библиотеку tkinter.
Этот скрипт объединяет логику низкоуровневой работы с NTFS через DeviceIoControl и простое диалоговое окно для выбора папок.
| Code: | import ctypesfrom ctypes import wintypesimport osimport structimport sysimport tkinter as tkfrom tkinter import filedialog, messagebox
# --- Константы Win32 API ---GENERIC_WRITE = 0x40000000OPEN_EXISTING = 3FILE_SHARE_WRITE = 0x00000002FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000FILE_FLAG_BACKUP_SEMANTICS = 0x02000000FSCTL_SET_REPARSE_POINT = 0x000900A4IOCTL_REPARSE_TAG_SYMLINK = 0xA000000CSYMLINK_FLAG_RELATIVE = 0x00000000
def create_symlink_lowlevel(link_path, target_path):
"""Низкоуровневое создание символической ссылки (метод NTLinksMaker)"""
os.makedirs(link_path, exist_ok=True)
substitute_name = f"\\??\\{os.path.abspath(target_path)}"
print_name = os.path.abspath(target_path)
sub_bytes = substitute_name.encode('utf-16le')
print_bytes = print_name.encode('utf-16le')
sub_len = len(sub_bytes)
print_len = len(print_bytes)
sub_offset = 0
print_offset = sub_len
path_buffer = sub_bytes + print_bytes
reparse_data_length = 12 + len(path_buffer)
header = struct.pack(
"<IHHHHHHI",
IOCTL_REPARSE_TAG_SYMLINK, # ReparseTag
reparse_data_length, # ReparseDataLength
0, # Reserved
sub_offset, # SubstituteNameOffset
sub_len, # SubstituteNameLength
print_offset, # PrintNameOffset
print_len, # PrintNameLength
SYMLINK_FLAG_RELATIVE # Flags
)
full_buffer = header + path_buffer
handle = ctypes.windll.kernel32.CreateFileW(
wintypes.LPCWSTR(link_path),
GENERIC_WRITE,
FILE_SHARE_WRITE,
None,
OPEN_EXISTING,
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
None
)
if handle == -1:
raise ctypes.WinError(ctypes.get_last_error())
try:
bytes_returned = wintypes.DWORD(0)
success = ctypes.windll.kernel32.DeviceIoControl(
handle,
FSCTL_SET_REPARSE_POINT,
full_buffer,
len(full_buffer),
None,
0,
ctypes.byref(bytes_returned),
None
)
if not success:
raise ctypes.WinError(ctypes.get_last_error())
finally:
ctypes.windll.kernel32.CloseHandle(handle)
# --- Графический интерфейс (GUI) ---class NTLinksApp:
def __init__(self, root):
self.root = root
self.root.title("NTLinksMaker Python Clone")
self.root.geometry("550x200")
self.root.resizable(False, False)
# Переменные путей
self.target_dir = tk.StringVar()
self.link_dir = tk.StringVar()
# Строка 1: Исходная папка (Target)
tk.Label(root, text="Целевая папка (куда ссылаемся):").grid(row=0, column=0, sticky="w", px=10, py=10)
tk.Entry(root, textvariable=self.target_dir, width=50).grid(row=0, column=1, py=10)
tk.Button(root, text="Обзор...", command=self.browse_target).grid(row=0, column=2, px=5, py=10)
# Строка 2: Папка-ссылка (Link)
tk.Label(root, text="Имя ссылки (что создаем):").grid(row=1, column=0, sticky="w", px=10, py=10)
tk.Entry(root, textvariable=self.link_dir, width=50).grid(row=1, column=1, py=10)
tk.Button(root, text="Обзор...", command=self.browse_link).grid(row=1, column=2, px=5, py=10)
# Кнопка создания
tk.Button(root, text="Создать Симлинк (DeviceIoControl)", command=self.process_creation,
bg="#4CAF50", fg="white", font=("Arial", 10, "bold"), height=2).grid(row=2, column=0, columnspan=3, py=20)
def browse_target(self):
folder = filedialog.askdirectory(title="Выберите целевую папку")
if folder:
self.target_dir.set(os.path.normpath(folder))
def browse_link(self):
# Запрашиваем имя будущей папки-ссылки
folder = filedialog.asksaveasfilename(title="Укажите путь и имя для будущей ссылки", initialfile="NewLink")
if folder:
self.link_dir.set(os.path.normpath(folder))
def process_creation(self):
tgt = self.target_dir.get()
lnk = self.link_dir.get()
if not tgt or not lnk:
messagebox.showerror("Ошибка", "Заполните оба пути!")
return
if not os.path.exists(tgt):
messagebox.showerror("Ошибка", "Целевая папка не существует!")
return
try:
create_symlink_lowlevel(lnk, tgt)
messagebox.showinfo("Успех", f"Символическая ссылка успешно создана!\n\n{lnk} -> {tgt}")
except Exception as e:
messagebox.showerror("Ошибка Windows API", f"Не удалось создать ссылку.\nВозможно, утилита запущена без прав Администратора.\n\nДетали: {e}")
if __name__ == "__main__":
# Проверка на запуск с правами Администратора (нужно для создания Symlink в Windows)
if not ctypes.windll.shell32.IsUserAnAdmin():
# Перезапускаем скрипт с запросом прав администратора
ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, " ".join(sys.argv), None, 1)
sys.exit()
root = tk.Tk()
# Принудительно настраиваем отступы grid для совместимости
for child in root.winfo_children():
pass
# Конфигурация сетки для красивых отступов (замена устаревшему px/py во внутреннем синтаксисе)
app = NTLinksApp(root)
root.mainloop()
## Как запустить этот скрипт:
1. Сохраните код в файл, например ntlinks_ui.py.
2. Запустите его двойным кликом или через консоль.
3. Скрипт автоматически перезапустится с запросом прав Администратора (появится стандартное окно UAC Windows), так как я добавил проверку IsUserAnAdmin() в блок __main__.
4. В открывшемся окне выберите исходную папку и путь, где создать новую ссылку.
|
Добавлено спустя 7 минут:
| Jonmey wrote: | | Может тогда сразу Гислеру это предложить? (там даже целую паству криворуких можно организовать). |
 Hidden text I'm in
| Jonmey wrote: | | А вообще отличный был бы метод получения исходников нужной программы - заявляешь автору, что его программа кривая и требуешь дать ее исходники.... |
Идеальная схема. Безотказная  |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|