📄 lylocal.c
字号:
/*** Routines to manipulate the local filesystem.** Written by: Rick Mallett, Carleton University** Report problems to rmallett@ccs.carleton.ca** Modified 18-Dec-95 David Trueman (david@cs.dal.ca):** Added OK_PERMIT compilation option.** Support replacement of compiled-in f)ull menu configuration via** DIRED_MENU definitions in lynx.cfg, so that more than one menu** can be driven by the same executable.** Modified Oct-96 Klaus Weide (kweide@tezcat.com):** Changed to use the library's HTList_* functions and macros for** managing the list of tagged file URLs.** Keep track of proper level of URL escaping, so that unusual filenames** which contain #% etc. are handled properly (some HTUnEscapeSome()'s** left in to be conservative, and to document where superfluous** unescaping took place before).** Dynamic memory instead of fixed length buffers in a few cases.** Other minor changes to make things work as intended.** Modified Jun-97 Klaus Weide (kweide@tezcat.com) & FM:** Modified the code handling DIRED_MENU to do more careful** checking of the selected file. In addition to "TAG", "FILE", and** "DIR", DIRED_MENU definitions in lynx.cfg now also recognize LINK as** a type. DIRED_MENU definitions with a type field of "LINK" are only** used if the current selection is a symbolic link ("FILE" and "DIR"** definitions are not used in that case). The default menu** definitions have been updated to reflect this change, and to avoid** the showing of menu items whose action would always fail - KW** Cast all code into the Lynx programming style. - FM*/#include "HTUtils.h"#include "tcp.h"#include "HTAlert.h"#include "HTParse.h"#include "LYCurses.h"#include "LYGlobalDefs.h"#include "LYUtils.h"#include "LYStrings.h"#include "LYCharUtils.h"#include "LYStructs.h"#include "LYGetFile.h"#include "LYHistory.h"#include "LYUpload.h"#include "LYLocal.h"#include "LYSystem.h"#ifndef VMS#ifndef _WINDOWS#ifdef HAVE_SYS_WAIT_H#include <sys/wait.h>#endif#include <errno.h>#include <grp.h>#endif /*_WINDOWS */#endif /* VMS */#ifndef WEXITSTATUS# if HAVE_TYPE_UNIONWAIT# define WEXITSTATUS(status) (status.w_retcode)# else# define WEXITSTATUS(status) (((status) & 0xff00) >> 8)# endif#endif#ifndef WTERMSIG# if HAVE_TYPE_UNIONWAIT# define WTERMSIG(status) (status.w_termsig)# else# define WTERMSIG(status) ((status) & 0x7f)# endif#endif#include "LYLeaks.h"#define FREE(x) if (x) {free(x); x = NULL;}PRIVATE int LYExecv PARAMS(( char * path, char ** argv, char * msg));#ifdef DIRED_SUPPORTPUBLIC char LYPermitFileURL[256] = "\0";PUBLIC char LYDiredFileURL[256] = "\0";PRIVATE char *filename PARAMS(( char * prompt, char * buf, size_t bufsize));#ifdef OK_PERMITPRIVATE BOOLEAN permit_location PARAMS(( char * destpath, char * srcpath, char ** newpath));#endif /* OK_PERMIT */PRIVATE char *render_item PARAMS(( char * s, char * path, char * dir, char * buf, int bufsize, BOOLEAN url_syntax));PRIVATE struct dired_menu *menu_head = NULL;struct dired_menu { int cond;#define DE_TAG 1#define DE_DIR 2#define DE_FILE 3#define DE_SYMLINK 4 char *sfx; char *link; char *rest; char *href; struct dired_menu *next;} defmenu[] = {/* * The following initializations determine the contents of the f)ull menu * selection when in dired mode. If any menu entries are defined in the * configuration file via DIRED_MENU lines, then these default entries * are discarded entirely. */{ 0, "", "New File","(in current directory)", "LYNXDIRED://NEW_FILE%d", NULL },{ 0, "", "New Directory","(in current directory)", "LYNXDIRED://NEW_FOLDER%d", NULL },{ DE_FILE, "", "Install","(of current selection)", "LYNXDIRED://INSTALL_SRC%p", NULL },{ DE_DIR, "", "Install","(of current selection)", "LYNXDIRED://INSTALL_SRC%p", NULL },{ DE_FILE, "", "Modify File Name","(of current selection)", "LYNXDIRED://MODIFY_NAME%p", NULL },{ DE_DIR, "", "Modify Directory Name","(of current selection)", "LYNXDIRED://MODIFY_NAME%p", NULL },{ DE_SYMLINK, "", "Modify Name","(of selected symbolic link)", "LYNXDIRED://MODIFY_NAME%p", NULL },#ifdef OK_PERMIT{ DE_FILE, "", "Modify File Permissions","(of current selection)", "LYNXDIRED://PERMIT_SRC%p", NULL },{ DE_DIR, "", "Modify Directory Permissions","(of current selection)", "LYNXDIRED://PERMIT_SRC%p", NULL },#endif /* OK_PERMIT */{ DE_FILE, "", "Change Location","(of selected file)" , "LYNXDIRED://MODIFY_LOCATION%p", NULL },{ DE_DIR, "", "Change Location","(of selected directory)", "LYNXDIRED://MODIFY_LOCATION%p", NULL },{ DE_SYMLINK, "", "Change Location","(of selected symbolic link)", "LYNXDIRED://MODIFY_LOCATION%p", NULL },{ DE_FILE, "", "Remove File", "(current selection)", "LYNXDIRED://REMOVE_SINGLE%p", NULL },{ DE_DIR, "", "Remove Directory", "(current selection)", "LYNXDIRED://REMOVE_SINGLE%p", NULL },{ DE_SYMLINK, "", "Remove Symbolic Link", "(current selection)", "LYNXDIRED://REMOVE_SINGLE%p", NULL },#if defined(OK_UUDECODE) && !defined(ARCHIVE_ONLY){ DE_FILE, "", "UUDecode", "(current selection)", "LYNXDIRED://UUDECODE%p", NULL },#endif /* OK_UUDECODE && !ARCHIVE_ONLY */#if defined(OK_TAR) && !defined(ARCHIVE_ONLY){ DE_FILE, ".tar.Z", "Expand", "(current selection)", "LYNXDIRED://UNTAR_Z%p", NULL },#endif /* OK_TAR && !ARCHIVE_ONLY */#if defined(OK_TAR) && defined(OK_GZIP) && !defined(ARCHIVE_ONLY){ DE_FILE, ".tar.gz", "Expand", "(current selection)", "LYNXDIRED://UNTAR_GZ%p", NULL },{ DE_FILE, ".tgz", "Expand", "(current selection)", "LYNXDIRED://UNTAR_GZ%p", NULL },#endif /* OK_TAR && OK_GZIP && !ARCHIVE_ONLY */#ifndef ARCHIVE_ONLY{ DE_FILE, ".Z", "Uncompress", "(current selection)", "LYNXDIRED://DECOMPRESS%p", NULL },#endif /* ARCHIVE_ONLY */#if defined(OK_GZIP) && !defined(ARCHIVE_ONLY){ DE_FILE, ".gz", "Uncompress", "(current selection)", "LYNXDIRED://UNGZIP%p", NULL },#endif /* OK_GZIP && !ARCHIVE_ONLY */#if defined(OK_ZIP) && !defined(ARCHIVE_ONLY){ DE_FILE, ".zip", "Uncompress", "(current selection)", "LYNXDIRED://UNZIP%p", NULL },#endif /* OK_ZIP && !ARCHIVE_ONLY */#if defined(OK_TAR) && !defined(ARCHIVE_ONLY){ DE_FILE, ".tar", "UnTar", "(current selection)", "LYNXDIRED://UNTAR%p", NULL },#endif /* OK_TAR && !ARCHIVE_ONLY */#ifdef OK_TAR{ DE_DIR, "", "Tar", "(current selection)", "LYNXDIRED://TAR%p", NULL },#endif /* OK_TAR */#if defined(OK_TAR) && defined(OK_GZIP){ DE_DIR, "", "Tar and compress", "(using GNU gzip)", "LYNXDIRED://TAR_GZ%p", NULL },#endif /* OK_TAR && OK_GZIP */#ifdef OK_ZIP{ DE_DIR, "", "Package and compress", "(using zip)", "LYNXDIRED://ZIP%p", NULL },#endif /* OK_ZIP */{ DE_FILE, "", "Compress", "(using Unix compress)", "LYNXDIRED://COMPRESS%p", NULL },#ifdef OK_GZIP{ DE_FILE, "", "Compress", "(using gzip)", "LYNXDIRED://GZIP%p", NULL },#endif /* OK_GZIP */#ifdef OK_ZIP{ DE_FILE, "", "Compress", "(using zip)", "LYNXDIRED://ZIP%p", NULL },#endif /* OK_ZIP */{ DE_TAG, "", "Move all tagged items to another location.", "", "LYNXDIRED://MOVE_TAGGED%d", NULL },{ DE_TAG, "", "Remove all tagged files and directories.", "", "LYNXDIRED://REMOVE_TAGGED", NULL },{ DE_TAG, "", "Untag all tagged files and directories.", "", "LYNXDIRED://CLEAR_TAGGED", NULL },{ 0, NULL, NULL, NULL, NULL, NULL }};/* * Remove all tagged files and directories. */PRIVATE BOOLEAN remove_tagged NOARGS{ int c, ans; char *cp, *tp; char tmpbuf[1024]; char *testpath = NULL; struct stat dir_info; int count, i; HTList *tag; char *args[5]; if (HTList_isEmpty(tagged)) /* should never happen */ return 0; _statusline("Remove all tagged files and directories (y or n): "); c = LYgetch(); ans = TOUPPER(c); count = 0; tag = tagged; while (ans == 'Y' && (cp = (char *)HTList_nextObject(tag)) != NULL) { if (is_url(cp) == FILE_URL_TYPE) { /* unecessary check */ tp = cp; if (!strncmp(tp, "file://localhost", 16)) { tp += 16; } else if (!strncmp(tp, "file:", 5)) { tp += 5; } StrAllocCopy(testpath, tp); HTUnEscape(testpath); if ((i = strlen(testpath)) && testpath[i-1] == '/') testpath[(i - 1)] = '\0'; /* * Check the current status of the path to be deleted. */ if (stat(testpath,&dir_info) == -1) { sprintf(tmpbuf, "System error - failed to get status of '%s'.", testpath); _statusline(tmpbuf); sleep(AlertSecs); return count; } else { args[0] = "rm"; args[1] = "-rf"; args[2] = testpath; args[3] = (char *) 0; sprintf(tmpbuf, "remove %s", testpath); if (LYExecv(RM_PATH, args, tmpbuf) <= 0) { FREE(testpath); return ((count == 0) ? -1 : count); } ++count; } } } FREE(testpath); clear_tags(); return count;}/* * Move all tagged files and directories to a new location. * Input is current directory. * The tests in this function can, at best, prevent some user mistakes - * anybody who relies on them for security is seriously misguided. * If a user has enough permissions to move a file somewhere, the same * uid with Lynx & dired can do the same thing. */PRIVATE BOOLEAN modify_tagged ARGS1( char *, testpath){ char *cp; dev_t dev; ino_t inode; uid_t owner; char tmpbuf[1024]; char *savepath = NULL; char *srcpath = NULL; struct stat dir_info; char *args[5]; int count = 0; HTList *tag; if (HTList_isEmpty(tagged)) /* should never happen */ return 0; _statusline("Enter new location for tagged items: "); tmpbuf[0] = '\0'; LYgetstr(tmpbuf, VISIBLE, sizeof(tmpbuf), NORECALL); if (strlen(tmpbuf)) { /* * Determine the ownership of the current location. */ /* * This test used to always fail from the dired menu... * changed to something that hopefully makes more sense - KW */ if (testpath && *testpath && 0!=strcmp(testpath,"/")) { /* * testpath passed in and is not empty and not a single "/" * (which would probably be bogus) - use it. */ cp = testpath; } else { /* * Prepare to get directory path from one of the tagged files. */ cp = HTList_lastObject(tagged); testpath = NULL; /* Won't be needed any more in this function, set to NULL as a flag. */ if (!cp) /* Last resort, should never happen. */ cp = "/"; } if (!strncmp(cp, "file://localhost", 16)) { cp += 16; } else if (!strncmp(cp, "file:", 5)) { cp += 5; } if (testpath == NULL) { /* * Get the directory containing the file or subdir. */ cp = strip_trailing_slash(cp); savepath = HTParse(".", cp, PARSE_PATH+PARSE_PUNCTUATION); } else { StrAllocCopy(savepath, cp); } HTUnEscape(savepath); if (stat(savepath, &dir_info) == -1) { sprintf(tmpbuf, "Unable to get status of '%s'.", savepath); _statusline(tmpbuf); sleep(AlertSecs); FREE(savepath); return 0; } /* * Save the owner of the current location for later use. * Also save the device and inode for location checking/ */ dev = dir_info.st_dev; inode = dir_info.st_ino; owner = dir_info.st_uid; /* * Replace ~/ references to the home directory. */ if (!strncmp(tmpbuf, "~/", 2)) { char *cp1 = NULL; StrAllocCopy(cp1, Home_Dir()); StrAllocCat(cp1, (tmpbuf + 1)); if (strlen(cp1) > (sizeof(tmpbuf) - 1)) { sprintf(tmpbuf, "%s", "Path too long"); _statusline(tmpbuf); sleep(AlertSecs); FREE(savepath); FREE(cp1); return 0; } strcpy(tmpbuf, cp1); FREE(cp1); } /* * If path is relative, prefix it with current location. */ if (tmpbuf[0] != '/') { if (savepath[(strlen(savepath) - 1)] != '/') StrAllocCat(savepath,"/"); StrAllocCat(savepath,tmpbuf); } else { StrAllocCopy(savepath,tmpbuf); } /* * stat() the target location to determine type and ownership. */ if (stat(savepath, &dir_info) == -1) { sprintf(tmpbuf,"Unable to get status of '%s'.",savepath); _statusline(tmpbuf); sleep(AlertSecs); FREE(savepath); return 0; } /* * Make sure the source and target locations are not the same place. */ if (dev == dir_info.st_dev && inode == dir_info.st_ino) { _statusline( "Source and destination are the same location - request ignored!"); sleep(AlertSecs); FREE(savepath); return 0; } /* * Make sure the target location is a directory which is owned * by the same uid as the owner of the current location. */ if ((dir_info.st_mode & S_IFMT) == S_IFDIR) { if (dir_info.st_uid == owner) { count = 0; tag = tagged; /* * Move all tagged items to the target location. */ while ((cp = (char *)HTList_nextObject(tag)) != NULL) { if (!strncmp(cp, "file://localhost", 16)) { cp += 16; } else if (!strncmp(cp, "file:", 5)) { cp += 5; } StrAllocCopy(srcpath, cp); HTUnEscape(srcpath); sprintf(tmpbuf, "move %s to %s", srcpath, savepath); args[0] = "mv"; args[1] = srcpath; args[2] = savepath; args[3] = (char *) 0; if (LYExecv(MV_PATH, args, tmpbuf) <= 0) { if (count == 0) count = -1; break; } ++count; } FREE(srcpath); FREE(savepath); clear_tags(); return count; } else { _statusline( "Destination has different owner! Request denied."); sleep(AlertSecs); FREE(srcpath); FREE(savepath); return 0; } } else { _statusline( "Destination is not a valid directory! Request denied."); sleep(AlertSecs); FREE(savepath); return 0; } } return 0;}/* * Modify the name of the specified item. */PRIVATE BOOLEAN modify_name ARGS1( char *, testpath){ char *cp; char tmpbuf[512]; char newpath[512]; char savepath[512]; struct stat dir_info; char *args[5]; /* * Determine the status of the selected item. */ testpath = strip_trailing_slash(testpath); if (stat(testpath, &dir_info) == -1) { sprintf(tmpbuf, "Unable to get status of '%s'.", testpath); _statusline(tmpbuf); sleep(AlertSecs); } else { /* * Change the name of the file or directory. */ if ((dir_info.st_mode & S_IFMT) == S_IFDIR) { cp = "Enter new name for directory: "; } else if ((dir_info.st_mode & S_IFMT) == S_IFREG) { cp = "Enter new name for file: "; } else { _statusline( "The selected item is not a file or a directory! Request ignored."); sleep(AlertSecs); return 0; } if (filename(cp, tmpbuf, sizeof(tmpbuf)) == NULL) return 0; /* * Do not allow the user to also change the location at this time. */ if (strchr(tmpbuf, '/') != NULL) { _statusline("Illegal character \"/\" found! Request ignored."); sleep(AlertSecs); } else if (strlen(tmpbuf) && (cp = strrchr(testpath, '/')) != NULL) { strcpy(savepath,testpath); *(++cp) = '\0'; strcpy(newpath,testpath); strcat(newpath,tmpbuf); /* * Make sure the destination does not already exist. */ if (stat(newpath, &dir_info) == -1) { if (errno != ENOENT) { sprintf(tmpbuf, "Unable to determine status of '%s'.", newpath); _statusline(tmpbuf); sleep(AlertSecs); } else { sprintf(tmpbuf, "move %s to %s", savepath, newpath); args[0] = "mv"; args[1] = savepath; args[2] = newpath; args[3] = (char *) 0; if (LYExecv(MV_PATH, args, tmpbuf) <= 0) return (-1); return 1; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -