bool FindFile::Next(FindData *fd,bool GetSymLink) { fd->Error=false; if (*FindMask==0) return false; #ifdef _WIN_ALL if (FirstCall) { if ((hFind=Win32Find(INVALID_HANDLE_VALUE,FindMask,fd))==INVALID_HANDLE_VALUE) return false; } else if (Win32Find(hFind,FindMask,fd)==INVALID_HANDLE_VALUE) return false; #else if (FirstCall) { wchar DirName[NM]; wcsncpyz(DirName,FindMask,ASIZE(DirName)); RemoveNameFromPath(DirName); if (*DirName==0) wcscpy(DirName,L"."); char DirNameA[NM]; WideToChar(DirName,DirNameA,ASIZE(DirNameA)); if ((dirp=opendir(DirNameA))==NULL) { fd->Error=(errno!=ENOENT); return false; } } while (1) { struct dirent *ent=readdir(dirp); if (ent==NULL) return false; if (strcmp(ent->d_name,".")==0 || strcmp(ent->d_name,"..")==0) continue; wchar Name[NM]; if (!CharToWide(ent->d_name,Name,ASIZE(Name))) Log(NULL,St(MInvalidName),Name); if (CmpName(FindMask,Name,MATCH_NAMES)) { wchar FullName[NM]; wcscpy(FullName,FindMask); *PointToName(FullName)=0; if (wcslen(FullName)+wcslen(Name)>=ASIZE(FullName)-1) { #ifndef SILENT Log(NULL,L"\n%ls%ls",FullName,Name); Log(NULL,St(MPathTooLong)); #endif return false; } wcscat(FullName,Name); if (!FastFind(FullName,fd,GetSymLink)) { ErrHandler.OpenErrorMsg(NULL,FullName); continue; } wcscpy(fd->Name,FullName); break; } } #endif fd->Flags=0; fd->IsDir=IsDir(fd->FileAttr); fd->IsLink=IsLink(fd->FileAttr); FirstCall=false; wchar *NameOnly=PointToName(fd->Name); if (wcscmp(NameOnly,L".")==0 || wcscmp(NameOnly,L"..")==0) return Next(fd); return true; }
int main(int argc, char **argv) { int cnt, x, y, i = 0, verbose = 0; Window win = 0; Bool keysymMappingInitialized = False; int rc = 0; int inputEvents[100]; int inputEventsIndex = 0; int iEvent = 0; if (argc == 1) usage(argv[0]); const char* log_file = NULL; if (streq(argv[1],"-o") || streq(argv[1],"--logfile")) { i++; if (++i > argc) usage(argv[0]); log_file = argv[i]; } report_init(log_file); if (!xhandler_init(getenv("DISPLAY"))) exit(1); report_add_message(xhandler_get_server_time(), "Startup\n"); /* initialize subsystems */ xemu_init(xhandler.display); scheduler_init(xhandler.display); window_init(xhandler.display); application_init(); /* * Process the command line options. * Skip emulation options (--click, --drag, --key, --type), but remember they index * and process them later. */ while (++i < argc) { if (streq(argv[i],"-v") || streq(argv[i],"--verbose")) { verbose = 1; continue; } if (streq(argv[i], "-id") || streq(argv[i], "--id")) { char name[PATH_MAX]; if (++i >= argc) usage(argv[0]); cnt = sscanf(argv[i], "0x%lx", &win); if (cnt < 1) { cnt = sscanf(argv[i], "%lu", &win); } if (cnt < 1) { fprintf(stderr, "*** invalid window id '%s'\n", argv[i]); usage(argv[0]); } sprintf(name, "0x%lx", win); if (!window_add(win, application_monitor(name))) { fprintf(stderr, "Could not setup damage monitoring for window 0x%lx!\n", win); exit(1); } if (verbose) report_add_message(REPORT_LAST_TIMESTAMP, "Monitoring window 0x%lx\n", win); continue; } if (streq(argv[i], "-a") || streq(argv[i], "--application")) { if (++i >= argc) usage(argv[0]); response.application = application_monitor(argv[i]); if (response.application && verbose) { report_add_message(REPORT_LAST_TIMESTAMP, "Monitoring application '%s'\n", argv[i]); } if (!strcmp(argv[i], "*")) { application_set_monitor_all(true); } continue; } if (streq("-c", argv[i]) || streq("--click", argv[i])) { if (!xemu.pointer.dev) { fprintf(stderr, "Failed to open pointer device, unable to simulate pointer events.\n"); exit(-1); } if (inputEventsIndex == ASIZE(inputEvents)) { fprintf(stderr, "Too many input events specified\n"); exit(-1); } if (!argv[i + 1] || !match_regex(argv[i + 1], "^[0-9]+x[0-9]+(,[0-9]+)?$")) { fprintf(stderr, "Failed to parse --c options: %s\n", argv[i + 1]); exit(-1); } inputEvents[inputEventsIndex++] = i; if (++i >= argc) usage(argv[0]); continue; } if (streq("-l", argv[i]) || streq("--level", argv[i])) { if (++i >= argc) usage(argv[0]); if (!strcmp(argv[i], "raw")) { window_set_damage_level(XDamageReportRawRectangles); } else if (!strcmp(argv[i], "delta")) { window_set_damage_level(XDamageReportDeltaRectangles); } else if (!strcmp(argv[i], "box")) { window_set_damage_level(XDamageReportDeltaRectangles); } else if (!strcmp(argv[i], "nonempty")) { window_set_damage_level(XDamageReportNonEmpty); } else { fprintf(stderr, "Unrecongnized damage level: %s\n", argv[i]); usage(argv[0]); } if (verbose) report_add_message(REPORT_LAST_TIMESTAMP, "Setting damage report level to %s\n", argv[i]); continue; } if (streq("-x", argv[i]) || streq("--exclude", argv[i])) { char* exclude[] = { "none", "less", "greater" }; if (options.exclude_rules != EXCLUDE_NONE) { fprintf(stderr, "Duplicated --exclude parameter detected. Aborting\n"); exit(-1); } if (++i >= argc) usage(argv[0]); char rules[32] = ""; if ((cnt = sscanf(argv[i], "%ux%u,%s", &options.exclude_rect.width, &options.exclude_rect.height, rules)) >= 2) { options.exclude_size = 0; } else if ((cnt = sscanf(argv[i], "%u,%s", &options.exclude_size, rules)) >= 1) { options.exclude_rect.width = 0; options.exclude_rect.height = 0; } else { fprintf(stderr, "*** failed to parse '%s'\n", argv[i]); usage(argv[0]); } options.exclude_rules = *rules && !strcmp(rules, "greater") ? EXCLUDE_GREATER : EXCLUDE_LESS; if (verbose) { if (options.exclude_size) { report_add_message(REPORT_LAST_TIMESTAMP, "Excluding damage areas %s than %d pixels\n", exclude[options.exclude_rules], options.exclude_size); } else { report_add_message(REPORT_LAST_TIMESTAMP, "Excluding damage areas %s than (%dx%d)\n", exclude[options.exclude_rules], options.exclude_rect.width, options.exclude_rect.height); } } continue; } if (streq("-m", argv[i]) || streq("--monitor", argv[i])) { if (options.interested_damage_rect.width || options.interested_damage_rect.height || options.interested_damage_rect.x || options.interested_damage_rect.y) { fprintf(stderr, "Duplicated --monitor parameter detected. Aborting\n"); exit(-1); } if (++i >= argc) usage(argv[0]); if ((cnt = sscanf(argv[i], "%ux%u+%u+%u", &options.interested_damage_rect.width, &options.interested_damage_rect.height, &options.interested_damage_rect.x, &options.interested_damage_rect.y)) != 4) { fprintf(stderr, "*** failed to parse '%s'\n", argv[i]); usage(argv[0]); } if (verbose) { report_add_message(REPORT_LAST_TIMESTAMP, "Set monitor rect to %ix%i+%i+%i\n", options.interested_damage_rect.width, options.interested_damage_rect.height, options.interested_damage_rect.x, options.interested_damage_rect.y); } continue; } if (streq("-w", argv[i]) || streq("--wait", argv[i])) { if (++i >= argc) usage(argv[0]); if (options.damage_wait_secs >= 0) { fprintf(stderr, "Duplicate -w(--wait) option detected. Discarding the previous value\n"); } if ((options.damage_wait_secs = atoi(argv[i])) < 0) { fprintf(stderr, "*** failed to parse '%s'\n", argv[i]); usage(argv[0]); } if (verbose) report_add_message(REPORT_LAST_TIMESTAMP, "Set event timeout to %isecs\n", options.damage_wait_secs); continue; } if (streq("-b", argv[i]) || streq("--break", argv[i])) { if (options.break_timeout || options.break_on_damage) { fprintf(stderr, "Duplicate -b(--break)option detected. Discarding the previous value\n"); options.break_timeout = 0; options.break_on_damage = 0; } if (++i >= argc) usage(argv[0]); if (!strncmp(argv[i], "damage", 6)) { sscanf(argv[i] + 6, ",%d", &options.break_on_damage); if (!options.break_on_damage) options.break_on_damage = 1; if (verbose) report_add_message(REPORT_LAST_TIMESTAMP, "Break wait on the %d damage event\n", options.break_on_damage); } else { if ((options.break_timeout = atoi(argv[i])) < 0) { fprintf(stderr, "*** failed to parse '%s'\n", argv[i]); usage(argv[0]); } if (verbose) report_add_message(REPORT_LAST_TIMESTAMP, "Set break timout to %imsecs\n", options.break_timeout); } continue; } if (streq("-d", argv[i]) || streq("--drag", argv[i])) { if (!xemu.pointer.dev) { fprintf(stderr, "Failed to open pointer device, unable to simulate pointer events.\n"); exit(-1); } if (inputEventsIndex == ASIZE(inputEvents)) { fprintf(stderr, "Too many input events specified\n"); exit(-1); } if (!argv[i + 1] || (!match_regex(argv[i + 1], "^([0-9]+,)?(([0-9]+x[0-9]+,([0-9]+,)?)+[0-9]+x[0-9]+)$") && (!match_regex(argv[i + 1], "[0-9]+x[0-9]+-[0-9]+x[0-9]+") || !match_regex(argv[i + 1], "^(((([0-9]+,)?([0-9]+x[0-9]+)|([0-9]+x[0-9]+-[0-9]+x[0-9]+(\\*[0-9]+)?(\\+[1-9][0-9]*)?)),?)+)$") ) ) ) { fprintf(stderr, "Failed to parse --drag options: %s\n", argv[i + 1]); exit(-1); } inputEvents[inputEventsIndex++] = i; if (++i >= argc) usage(argv[0]); continue; } if (streq("-k", argv[i]) || streq("--key", argv[i])) { if (!xemu.keyboard.dev) { fprintf(stderr, "Failed to open keyboard device, unable to simulate keyboard events.\n"); exit(-1); } if (inputEventsIndex == ASIZE(inputEvents)) { fprintf(stderr, "Too many input events specified\n"); exit(-1); } inputEvents[inputEventsIndex++] = i; if (++i >= argc) usage(argv[0]); continue; } if (streq("-t", argv[i]) || streq("--type", argv[i])) { if (!xemu.keyboard.dev) { fprintf(stderr, "Failed to open keyboard device, unable to simulate keyboard events.\n"); exit(-1); } if (inputEventsIndex == ASIZE(inputEvents)) { fprintf(stderr, "Too many input events specified\n"); exit(-1); } inputEvents[inputEventsIndex++] = i; if (++i >= argc) usage(argv[0]); if (!keysymMappingInitialized) { xemu_load_keycodes(); keysymMappingInitialized = True; } continue; } /* since moving from command sequence approach the inspect parameter is deprecated */ if (streq("-i", argv[i]) || streq("--inspect", argv[i])) { if (verbose) report_add_message(REPORT_LAST_TIMESTAMP, "Just displaying damage events until timeout\n"); continue; } /* */ if (streq("-u", argv[i]) || streq("--user", argv[i]) || (xrecord.motion = (streq("-U", argv[i]) || streq("--user-all", argv[i])) ) ) { xinput_init(xhandler.display); if (verbose) report_add_message(REPORT_LAST_TIMESTAMP, "Reporting user input events\n"); continue; } if (streq(argv[i], "-r") || streq(argv[i], "--response")) { if (++i >= argc) usage(argv[0]); char option[500]; cnt = sscanf(argv[i], "%u,%s", &response.timeout, option); if (cnt < 1) { fprintf(stderr, "*** invalid response timeout value '%s'\n", argv[i]); usage(argv[0]); } if (cnt < 2) { report_set_silent(true); } else { if (strcmp(option, "verbose")) { fprintf(stderr, "*** invalid response option '%s'\n", argv[i]); usage(argv[0]); } } application_monitor_screen(); xinput_init(xhandler.display); if (verbose) report_add_message(REPORT_LAST_TIMESTAMP, "Monitoring application response time\n"); continue; } fprintf(stderr, "*** Dont understand %s\n", argv[i]); usage(argv[0]); } /* start monitoring the root window if no targets are specified */ if ((window_empty() && application_empty()) || response.timeout) { application_monitor(ROOT_WINDOW_RESOURCE); } window_monitor_all(); application_start_monitor(); /* eat first damage event when options.break_on_damage set */ if (options.break_on_damage) xhandler_eat_damage(); /* monitor the whole screen of no area is specified */ if (!options.interested_damage_rect.width && !options.interested_damage_rect.height && !options.interested_damage_rect.x && !options.interested_damage_rect.y) { options.interested_damage_rect.x = 0; options.interested_damage_rect.y = 0; options.interested_damage_rect.width = DisplayWidth(xhandler.display, DefaultScreen(xhandler.display)); options.interested_damage_rect.height = DisplayHeight(xhandler.display, DefaultScreen(xhandler.display)); } /* emulate user input */ for (iEvent = 0; iEvent < inputEventsIndex; iEvent++) { i = inputEvents[iEvent]; if (!strcmp("-c", argv[i]) || !strcmp("--click", argv[i])) { unsigned long delay = 0; Time start = 0; cnt = sscanf(argv[++i], "%ux%u,%lu", &x, &y, &delay); if (cnt == 2) { start = xhandler_get_server_time(); report_add_message(start, "Using no delay between press/release\n"); delay = 0; } else if (cnt != 3) { fprintf(stderr, "cnt: %d\n", cnt); fprintf(stderr, "*** failed to parse '%s'\n", argv[i]); usage(argv[0]); } /* Send the event */ start = xemu_button_event(x, y, delay); report_add_message(start, "Clicked %ix%i\n", x, y); continue; } if (!strcmp("-d", argv[i]) || !strcmp("--drag", argv[i])) { Time drag_time; char *s = NULL, *p = NULL; int button_state = XR_BUTTON_STATE_PRESS; s = p = argv[++i]; int delay = DEFAULT_DRAG_DELAY; int x1, y1, x2, y2; while (p) { p = strchr(s, ','); if (p) { *p++ = '\0'; } int count = DEFAULT_DRAG_COUNT; cnt = sscanf(s, "%ix%i-%ix%i*%i+%i", &x1, &y1, &x2, &y2, &delay, &count); if (cnt >= 4) { drag_time = xemu_drag_event(x1, y1, button_state, delay); button_state = XR_BUTTON_STATE_NONE; report_add_message(drag_time, "Dragged to %ix%i\n", x1, y1); int xdev = (x2 - x1) / (count + 1); int ydev = (y2 - y1) / (count + 1); for (i = 1; i <= count; i++) { x = x1 + xdev * i; y = y1 + ydev * i; drag_time = xemu_drag_event(x, y, button_state, delay); report_add_message(drag_time, "Dragged to %ix%i\n", x, y); } if (!p) button_state = XR_BUTTON_STATE_RELEASE; drag_time = xemu_drag_event(x2, y2, button_state, delay); report_add_message(drag_time, "Dragged to %ix%i\n", x2, y2); } else if (cnt == 2) { /* Send the event */ if (!p) { if (button_state == XR_BUTTON_STATE_PRESS) { fprintf(stderr, "*** Need at least 2 drag points!\n"); usage(argv[0]); } button_state = XR_BUTTON_STATE_RELEASE; } drag_time = xemu_drag_event(x1, y1, button_state, delay); report_add_message(drag_time, "Dragged to %ix%i\n", x1, y1); /* Make sure button state set to none after first point */ button_state = XR_BUTTON_STATE_NONE; /* reset the delay to default value */ delay = DEFAULT_DRAG_DELAY; } else if (cnt == 1) { delay = x1; } else { fprintf(stderr, "*** failed to parse '%s'\n", argv[i]); usage(argv[0]); } s = p; } continue; } if (!strcmp("-k", argv[i]) || !strcmp("--key", argv[i])) { char *key = NULL; char separator; unsigned long delay = 0; Time start = 0; cnt = sscanf(argv[++i], "%a[^,]%c%lu", &key, &separator, &delay); if (cnt == 1) { report_add_message(REPORT_LAST_TIMESTAMP, "Using default delay between press/release\n", delay); delay = DEFAULT_KEY_DELAY; } else if (cnt != 3 || separator != ',') { fprintf(stderr, "cnt: %d\n", cnt); fprintf(stderr, "*** failed to parse '%s'\n", argv[i]); if (key != NULL) free(key); usage(argv[0]); } start = xemu_send_key(key, delay); report_add_message(start, "Simulating keypress/-release pair (keycode '%s')\n", key); free(key); continue; } if (!strcmp("-t", argv[i]) || !strcmp("--type", argv[i])) { Time start = xemu_send_string(argv[++i]); report_add_message(start, "Simulated keys for '%s'\n", argv[i]); continue; } } /* setting the default wait period */ if (options.damage_wait_secs < 0) { options.damage_wait_secs = 5; } signal(SIGINT, abort_wait); /* wait for damage events */ rc = wait_response(); scheduler_fini(); report_flush_queue(); report_fini(); xinput_fini(); xemu_fini(); window_fini(); application_fini(); xhandler_fini(); return rc; }
int main(int argc, char* argv[]) { #ifdef _UNIX setlocale(LC_ALL, ""); #endif #if defined(_EMX) && !defined(_DJGPP) uni_init(0); #endif #if !defined(_SFX_RTL_) && !defined(_WIN_ALL) setbuf(stdout, NULL); #endif #if !defined(SFX_MODULE) && defined(_EMX) EnumConfigPaths(argv[0], -1); #endif ErrHandler.SetSignalHandlers(true); RARInitData(); #ifdef SFX_MODULE char ModuleNameA[NM]; wchar ModuleNameW[NM]; #ifdef _WIN_ALL GetModuleFileNameW(NULL, ModuleNameW, ASIZE(ModuleNameW)); WideToChar(ModuleNameW, ModuleNameA); #else strcpy(ModuleNameA, argv[0]); *ModuleNameW = 0; #endif #endif #ifdef _WIN_ALL SetErrorMode(SEM_NOALIGNMENTFAULTEXCEPT | SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); #endif #if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SHELL_EXT) bool ShutdownOnClose; #endif #ifdef ALLOW_EXCEPTIONS try #endif { CommandData Cmd; #ifdef SFX_MODULE strcpy(Cmd.Command, "X"); char* Switch = NULL; #ifdef _SFX_RTL_ char* CmdLine = GetCommandLineA(); if (CmdLine != NULL && *CmdLine == '\"') CmdLine = strchr(CmdLine + 1, '\"'); if (CmdLine != NULL && (CmdLine = strpbrk(CmdLine, " /")) != NULL) { while (IsSpace(*CmdLine)) CmdLine++; Switch = CmdLine; } #else Switch = argc > 1 ? argv[1] : NULL; #endif if (Switch != NULL && Cmd.IsSwitch(Switch[0])) { int UpperCmd = etoupper(Switch[1]); switch (UpperCmd) { case 'T': case 'V': Cmd.Command[0] = UpperCmd; break; case '?': Cmd.OutHelp(); break; } } Cmd.AddArcName(ModuleNameA, ModuleNameW); #else if (Cmd.IsConfigEnabled(argc, argv)) { Cmd.ReadConfig(argc, argv); Cmd.ParseEnvVar(); } for (int I = 1; I < argc; I++) Cmd.ParseArg(argv[I], NULL); #endif Cmd.ParseDone(); #if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SHELL_EXT) ShutdownOnClose = Cmd.Shutdown; #endif InitConsoleOptions(Cmd.MsgStream, Cmd.Sound); InitLogOptions(Cmd.LogName); ErrHandler.SetSilent(Cmd.AllYes || Cmd.MsgStream == MSG_NULL); ErrHandler.SetShutdown(Cmd.Shutdown); Cmd.OutTitle(); Cmd.ProcessCommand(); } #ifdef ALLOW_EXCEPTIONS catch (int ErrCode) { ErrHandler.SetErrorCode(ErrCode); } #ifdef ENABLE_BAD_ALLOC catch (bad_alloc) { ErrHandler.SetErrorCode(MEMORY_ERROR); } #endif catch (...) { ErrHandler.SetErrorCode(FATAL_ERROR); } #endif File::RemoveCreated(); #if defined(SFX_MODULE) && defined(_DJGPP) _chmod(ModuleNameA, 1, 0x20); #endif #if defined(_EMX) && !defined(_DJGPP) uni_done(); #endif #if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SHELL_EXT) if (ShutdownOnClose) Shutdown(); #endif return(ErrHandler.GetErrorCode()); }
// We should return 'true' even if resulting path is shorter than MAX_PATH, // because we can also use this function to open files with non-standard // characters, even if their path length is normal. bool GetWinLongPath(const wchar *Src,wchar *Dest,size_t MaxSize) { if (*Src==0) return false; const wchar *Prefix=L"\\\\?\\"; const size_t PrefixLength=4; bool FullPath=IsDiskLetter(Src) && IsPathDiv(Src[2]); size_t SrcLength=wcslen(Src); if (IsFullPath(Src)) // Paths in d:\path\name format. { if (IsDiskLetter(Src)) { if (MaxSize<=PrefixLength+SrcLength) return false; wcsncpy(Dest,Prefix,PrefixLength); wcscpy(Dest+PrefixLength,Src); return true; } else if (Src[0]=='\\' && Src[1]=='\\') { if (MaxSize<=PrefixLength+SrcLength+2) return false; wcsncpy(Dest,Prefix,PrefixLength); wcscpy(Dest+PrefixLength,L"UNC"); wcscpy(Dest+PrefixLength+3,Src+1); return true; } // We may be here only if we modify IsFullPath in the future. return false; } else { wchar CurDir[NM]; DWORD DirCode=GetCurrentDirectory(ASIZE(CurDir)-1,CurDir); if (DirCode==0 || DirCode>ASIZE(CurDir)-1) return false; if (IsPathDiv(Src[0])) // Paths in \path\name format. { if (MaxSize<=PrefixLength+SrcLength+2) return false; wcsncpy(Dest,Prefix,PrefixLength); wcsncpy(Dest+PrefixLength,CurDir,2); // Copy drive letter 'd:'. wcscpy(Dest+PrefixLength+2,Src); return true; } else // Paths in path\name format. { AddEndSlash(CurDir,ASIZE(CurDir)); if (MaxSize<=PrefixLength+wcslen(CurDir)+SrcLength) return false; wcsncpy(Dest,Prefix,PrefixLength); wcscpy(Dest+PrefixLength,CurDir); if (Src[0]=='.' && IsPathDiv(Src[1])) // Remove leading .\ in pathname. Src+=2; wcsncatz(Dest,Src,MaxSize); return true; } } return false; }
size_t Archive::ReadHeader15() { RawRead Raw(this); bool Decrypt=Encrypted && CurBlockPos>(int64)SFXSize+SIZEOF_MARKHEAD3; if (Decrypt) { #ifdef RAR_NOCRYPT // For rarext.dll and unrar_nocrypt.dll. return 0; #else RequestArcPassword(); byte Salt[SIZE_SALT30]; if (Read(Salt,SIZE_SALT30)!=SIZE_SALT30) { UnexpEndArcMsg(); return(0); } HeadersCrypt.SetCryptKeys(false,CRYPT_RAR30,&Cmd->Password,Salt,NULL,0,NULL,NULL); Raw.SetCrypt(&HeadersCrypt); #endif } Raw.Read(SIZEOF_SHORTBLOCKHEAD); if (Raw.Size()==0) { UnexpEndArcMsg(); return 0; } ShortBlock.HeadCRC=Raw.Get2(); ShortBlock.Reset(); uint HeaderType=Raw.Get1(); ShortBlock.Flags=Raw.Get2(); ShortBlock.SkipIfUnknown=(ShortBlock.Flags & SKIP_IF_UNKNOWN)!=0; ShortBlock.HeadSize=Raw.Get2(); ShortBlock.HeaderType=(HEADER_TYPE)HeaderType; if (ShortBlock.HeadSize<SIZEOF_SHORTBLOCKHEAD) { BrokenHeaderMsg(); return(0); } // For simpler further processing we map header types common // for RAR 1.5 and 5.0 formats to RAR 5.0 values. It does not include // header types specific for RAR 1.5 - 4.x only. switch(ShortBlock.HeaderType) { case HEAD3_MAIN: ShortBlock.HeaderType=HEAD_MAIN; break; case HEAD3_FILE: ShortBlock.HeaderType=HEAD_FILE; break; case HEAD3_SERVICE: ShortBlock.HeaderType=HEAD_SERVICE; break; case HEAD3_ENDARC: ShortBlock.HeaderType=HEAD_ENDARC; break; default: break; } CurHeaderType=ShortBlock.HeaderType; if (ShortBlock.HeaderType==HEAD3_CMT) { // Old style (up to RAR 2.9) comment header embedded into main // or file header. We must not read the entire ShortBlock.HeadSize here // to not break the comment processing logic later. Raw.Read(SIZEOF_COMMHEAD-SIZEOF_SHORTBLOCKHEAD); } else if (ShortBlock.HeaderType==HEAD_MAIN && (ShortBlock.Flags & MHD_COMMENT)!=0) { // Old style (up to RAR 2.9) main archive comment embedded into // the main archive header found. While we can read the entire // ShortBlock.HeadSize here and remove this part of "if", it would be // waste of memory, because we'll read and process this comment data // in other function anyway and we do not need them here now. Raw.Read(SIZEOF_MAINHEAD3-SIZEOF_SHORTBLOCKHEAD); } else Raw.Read(ShortBlock.HeadSize-SIZEOF_SHORTBLOCKHEAD); NextBlockPos=CurBlockPos+FullHeaderSize(ShortBlock.HeadSize); switch(ShortBlock.HeaderType) { case HEAD_MAIN: MainHead.Reset(); *(BaseBlock *)&MainHead=ShortBlock; MainHead.HighPosAV=Raw.Get2(); MainHead.PosAV=Raw.Get4(); Volume=(MainHead.Flags & MHD_VOLUME)!=0; Solid=(MainHead.Flags & MHD_SOLID)!=0; Locked=(MainHead.Flags & MHD_LOCK)!=0; Protected=(MainHead.Flags & MHD_PROTECT)!=0; Encrypted=(MainHead.Flags & MHD_PASSWORD)!=0; Signed=MainHead.PosAV!=0 || MainHead.HighPosAV!=0; MainHead.CommentInHeader=(MainHead.Flags & MHD_COMMENT)!=0; // Only for encrypted 3.0+ archives. 2.x archives did not have this // flag, so for non-encrypted archives, we'll set it later based on // file attributes. FirstVolume=(MainHead.Flags & MHD_FIRSTVOLUME)!=0; NewNumbering=(MainHead.Flags & MHD_NEWNUMBERING)!=0; break; case HEAD_FILE: case HEAD_SERVICE: { bool FileBlock=ShortBlock.HeaderType==HEAD_FILE; FileHeader *hd=FileBlock ? &FileHead:&SubHead; hd->Reset(); *(BaseBlock *)hd=ShortBlock; hd->SplitBefore=(hd->Flags & LHD_SPLIT_BEFORE)!=0; hd->SplitAfter=(hd->Flags & LHD_SPLIT_AFTER)!=0; hd->Encrypted=(hd->Flags & LHD_PASSWORD)!=0; hd->SaltSet=(hd->Flags & LHD_SALT)!=0; hd->Solid=FileBlock && (hd->Flags & LHD_SOLID)!=0; hd->SubBlock=!FileBlock && (hd->Flags & LHD_SOLID)!=0; hd->Dir=(hd->Flags & LHD_WINDOWMASK)==LHD_DIRECTORY; hd->WinSize=hd->Dir ? 0:0x10000<<((hd->Flags & LHD_WINDOWMASK)>>5); hd->CommentInHeader=(hd->Flags & LHD_COMMENT)!=0; hd->Version=(hd->Flags & LHD_VERSION)!=0; hd->DataSize=Raw.Get4(); uint LowUnpSize=Raw.Get4(); hd->HostOS=Raw.Get1(); hd->FileHash.Type=HASH_CRC32; hd->FileHash.CRC32=Raw.Get4(); uint FileTime=Raw.Get4(); hd->UnpVer=Raw.Get1(); hd->Method=Raw.Get1()-0x30; size_t NameSize=Raw.Get2(); hd->FileAttr=Raw.Get4(); hd->CryptMethod=CRYPT_NONE; if (hd->Encrypted) switch(hd->UnpVer) { case 13: hd->CryptMethod=CRYPT_RAR13; break; case 15: hd->CryptMethod=CRYPT_RAR15; break; case 20: case 26: hd->CryptMethod=CRYPT_RAR20; break; default: hd->CryptMethod=CRYPT_RAR30; break; } hd->HSType=HSYS_UNKNOWN; if (hd->HostOS==HOST_UNIX || hd->HostOS==HOST_BEOS) hd->HSType=HSYS_UNIX; else if (hd->HostOS<HOST_MAX) hd->HSType=HSYS_WINDOWS; hd->RedirType=FSREDIR_NONE; // RAR 4.x Unix symlink. if (hd->HostOS==HOST_UNIX && (hd->FileAttr & 0xF000)==0xA000) { hd->RedirType=FSREDIR_UNIXSYMLINK; *hd->RedirName=0; } hd->Inherited=!FileBlock && (hd->SubFlags & SUBHEAD_FLAGS_INHERITED)!=0; hd->LargeFile=(hd->Flags & LHD_LARGE)!=0; uint HighPackSize,HighUnpSize; if (hd->LargeFile) { HighPackSize=Raw.Get4(); HighUnpSize=Raw.Get4(); hd->UnknownUnpSize=(LowUnpSize==0xffffffff && HighUnpSize==0xffffffff); } else { HighPackSize=HighUnpSize=0; // UnpSize equal to 0xffffffff without LHD_LARGE flag indicates // that we do not know the unpacked file size and must unpack it // until we find the end of file marker in compressed data. hd->UnknownUnpSize=(LowUnpSize==0xffffffff); } hd->PackSize=INT32TO64(HighPackSize,hd->DataSize); hd->UnpSize=INT32TO64(HighUnpSize,LowUnpSize); if (hd->UnknownUnpSize) hd->UnpSize=INT64NDF; char FileName[NM*4]; size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1); Raw.GetB((byte *)FileName,ReadNameSize); FileName[ReadNameSize]=0; if (FileBlock) { if ((hd->Flags & LHD_UNICODE)!=0) { EncodeFileName NameCoder; size_t Length=strlen(FileName); if (Length==NameSize) UtfToWide(FileName,hd->FileName,ASIZE(hd->FileName)-1); else { Length++; NameCoder.Decode(FileName,(byte *)FileName+Length, NameSize-Length,hd->FileName, ASIZE(hd->FileName)); } } else *hd->FileName=0; char AnsiName[NM]; IntToExt(FileName,AnsiName,ASIZE(AnsiName)); GetWideName(AnsiName,hd->FileName,hd->FileName,ASIZE(hd->FileName)); #ifndef SFX_MODULE ConvertNameCase(hd->FileName); #endif ConvertFileHeader(hd); } else { CharToWide(FileName,hd->FileName,ASIZE(hd->FileName)); // Calculate the size of optional data. int DataSize=int(hd->HeadSize-NameSize-SIZEOF_FILEHEAD3); if ((hd->Flags & LHD_SALT)!=0) DataSize-=SIZE_SALT30; if (DataSize>0) { // Here we read optional additional fields for subheaders. // They are stored after the file name and before salt. hd->SubData.Alloc(DataSize); Raw.GetB(&hd->SubData[0],DataSize); if (hd->CmpName(SUBHEAD_TYPE_RR)) { byte *D=&hd->SubData[8]; RecoverySize=D[0]+((uint)D[1]<<8)+((uint)D[2]<<16)+((uint)D[3]<<24); RecoverySize*=512; // Sectors to size. int64 CurPos=Tell(); RecoveryPercent=ToPercent(RecoverySize,CurPos); // Round fractional percent exceeding .5 to upper value. if (ToPercent(RecoverySize+CurPos/200,CurPos)>RecoveryPercent) RecoveryPercent++; } } if (hd->CmpName(SUBHEAD_TYPE_CMT)) MainComment=true; } if ((hd->Flags & LHD_SALT)!=0) Raw.GetB(hd->Salt,SIZE_SALT30); hd->mtime.SetDos(FileTime); if ((hd->Flags & LHD_EXTTIME)!=0) { ushort Flags=Raw.Get2(); RarTime *tbl[4]; tbl[0]=&FileHead.mtime; tbl[1]=&FileHead.ctime; tbl[2]=&FileHead.atime; tbl[3]=NULL; // Archive time is not used now. for (int I=0;I<4;I++) { RarTime *CurTime=tbl[I]; uint rmode=Flags>>(3-I)*4; if ((rmode & 8)==0 || CurTime==NULL) continue; if (I!=0) { uint DosTime=Raw.Get4(); CurTime->SetDos(DosTime); } RarLocalTime rlt; CurTime->GetLocal(&rlt); if (rmode & 4) rlt.Second++; rlt.Reminder=0; int count=rmode&3; for (int J=0;J<count;J++) { byte CurByte=Raw.Get1(); rlt.Reminder|=(((uint)CurByte)<<((J+3-count)*8)); } CurTime->SetLocal(&rlt); } } NextBlockPos+=hd->PackSize; bool CRCProcessedOnly=hd->CommentInHeader; ushort HeaderCRC=Raw.GetCRC15(CRCProcessedOnly); if (hd->HeadCRC!=HeaderCRC) { BrokenHeader=true; ErrHandler.SetErrorCode(RARX_WARNING); // If we have a broken encrypted header, we do not need to display // the error message here, because it will be displayed for such // headers later in this function. Also such headers are unlikely // to have anything sensible in file name field, so it is useless // to display the file name. if (!Decrypt) { #ifndef SHELL_EXT Log(Archive::FileName,St(MLogFileHead),hd->FileName); #endif } } } break; case HEAD_ENDARC: *(BaseBlock *)&EndArcHead=ShortBlock; EndArcHead.NextVolume=(EndArcHead.Flags & EARC_NEXT_VOLUME)!=0; EndArcHead.DataCRC=(EndArcHead.Flags & EARC_DATACRC)!=0; EndArcHead.RevSpace=(EndArcHead.Flags & EARC_REVSPACE)!=0; EndArcHead.StoreVolNumber=(EndArcHead.Flags & EARC_VOLNUMBER)!=0; if (EndArcHead.DataCRC) EndArcHead.ArcDataCRC=Raw.Get4(); if (EndArcHead.StoreVolNumber) VolNumber=EndArcHead.VolNumber=Raw.Get2(); break; #ifndef SFX_MODULE case HEAD3_CMT: *(BaseBlock *)&CommHead=ShortBlock; CommHead.UnpSize=Raw.Get2(); CommHead.UnpVer=Raw.Get1(); CommHead.Method=Raw.Get1(); CommHead.CommCRC=Raw.Get2(); break; case HEAD3_SIGN: *(BaseBlock *)&SignHead=ShortBlock; SignHead.CreationTime=Raw.Get4(); SignHead.ArcNameSize=Raw.Get2(); SignHead.UserNameSize=Raw.Get2(); break; case HEAD3_AV: *(BaseBlock *)&AVHead=ShortBlock; AVHead.UnpVer=Raw.Get1(); AVHead.Method=Raw.Get1(); AVHead.AVVer=Raw.Get1(); AVHead.AVInfoCRC=Raw.Get4(); break; case HEAD3_PROTECT: *(BaseBlock *)&ProtectHead=ShortBlock; ProtectHead.DataSize=Raw.Get4(); ProtectHead.Version=Raw.Get1(); ProtectHead.RecSectors=Raw.Get2(); ProtectHead.TotalBlocks=Raw.Get4(); Raw.GetB(ProtectHead.Mark,8); NextBlockPos+=ProtectHead.DataSize; RecoverySize=ProtectHead.RecSectors*512; break; case HEAD3_OLDSERVICE: *(BaseBlock *)&SubBlockHead=ShortBlock; SubBlockHead.DataSize=Raw.Get4(); NextBlockPos+=SubBlockHead.DataSize; SubBlockHead.SubType=Raw.Get2(); SubBlockHead.Level=Raw.Get1(); switch(SubBlockHead.SubType) { case UO_HEAD: *(SubBlockHeader *)&UOHead=SubBlockHead; UOHead.OwnerNameSize=Raw.Get2(); UOHead.GroupNameSize=Raw.Get2(); if (UOHead.OwnerNameSize>=ASIZE(UOHead.OwnerName)) UOHead.OwnerNameSize=ASIZE(UOHead.OwnerName)-1; if (UOHead.GroupNameSize>=ASIZE(UOHead.GroupName)) UOHead.GroupNameSize=ASIZE(UOHead.GroupName)-1; Raw.GetB(UOHead.OwnerName,UOHead.OwnerNameSize); Raw.GetB(UOHead.GroupName,UOHead.GroupNameSize); UOHead.OwnerName[UOHead.OwnerNameSize]=0; UOHead.GroupName[UOHead.GroupNameSize]=0; break; case MAC_HEAD: *(SubBlockHeader *)&MACHead=SubBlockHead; MACHead.fileType=Raw.Get4(); MACHead.fileCreator=Raw.Get4(); break; case EA_HEAD: case BEEA_HEAD: case NTACL_HEAD: *(SubBlockHeader *)&EAHead=SubBlockHead; EAHead.UnpSize=Raw.Get4(); EAHead.UnpVer=Raw.Get1(); EAHead.Method=Raw.Get1(); EAHead.EACRC=Raw.Get4(); break; case STREAM_HEAD: *(SubBlockHeader *)&StreamHead=SubBlockHead; StreamHead.UnpSize=Raw.Get4(); StreamHead.UnpVer=Raw.Get1(); StreamHead.Method=Raw.Get1(); StreamHead.StreamCRC=Raw.Get4(); StreamHead.StreamNameSize=Raw.Get2(); if (StreamHead.StreamNameSize>=ASIZE(StreamHead.StreamName)) StreamHead.StreamNameSize=ASIZE(StreamHead.StreamName)-1; Raw.GetB(StreamHead.StreamName,StreamHead.StreamNameSize); StreamHead.StreamName[StreamHead.StreamNameSize]=0; break; } break; #endif default: if (ShortBlock.Flags & LONG_BLOCK) NextBlockPos+=Raw.Get4(); break; }
void ExtractStreams20(Archive &Arc,const wchar *FileName) { if (Arc.BrokenHeader) { uiMsg(UIERROR_STREAMBROKEN,Arc.FileName,FileName); ErrHandler.SetErrorCode(RARX_CRC); return; } if (Arc.StreamHead.Method<0x31 || Arc.StreamHead.Method>0x35 || Arc.StreamHead.UnpVer>VER_PACK) { uiMsg(UIERROR_STREAMUNKNOWN,Arc.FileName,FileName); ErrHandler.SetErrorCode(RARX_WARNING); return; } wchar StreamName[NM+2]; if (FileName[0]!=0 && FileName[1]==0) { wcscpy(StreamName,L".\\"); wcscpy(StreamName+2,FileName); } else wcscpy(StreamName,FileName); if (wcslen(StreamName)+strlen(Arc.StreamHead.StreamName)>=ASIZE(StreamName) || Arc.StreamHead.StreamName[0]!=':') { uiMsg(UIERROR_STREAMBROKEN,Arc.FileName,FileName); ErrHandler.SetErrorCode(RARX_CRC); return; } wchar StoredName[NM]; CharToWide(Arc.StreamHead.StreamName,StoredName,ASIZE(StoredName)); ConvertPath(StoredName+1,StoredName+1); wcsncatz(StreamName,StoredName,ASIZE(StreamName)); FindData fd; bool Found=FindFile::FastFind(FileName,&fd); if ((fd.FileAttr & FILE_ATTRIBUTE_READONLY)!=0) SetFileAttr(FileName,fd.FileAttr & ~FILE_ATTRIBUTE_READONLY); File CurFile; if (CurFile.WCreate(StreamName)) { ComprDataIO DataIO; Unpack Unpack(&DataIO); Unpack.Init(0x10000,false); DataIO.SetPackedSizeToRead(Arc.StreamHead.DataSize); DataIO.EnableShowProgress(false); DataIO.SetFiles(&Arc,&CurFile); DataIO.UnpHash.Init(HASH_CRC32,1); Unpack.SetDestSize(Arc.StreamHead.UnpSize); Unpack.DoUnpack(Arc.StreamHead.UnpVer,false); if (Arc.StreamHead.StreamCRC!=DataIO.UnpHash.GetCRC32()) { uiMsg(UIERROR_STREAMBROKEN,Arc.FileName,StreamName); ErrHandler.SetErrorCode(RARX_CRC); } else CurFile.Close(); } File HostFile; if (Found && HostFile.Open(FileName,FMF_OPENSHARED|FMF_UPDATE)) SetFileTime(HostFile.GetHandle(),&fd.ftCreationTime,&fd.ftLastAccessTime, &fd.ftLastWriteTime); if ((fd.FileAttr & FILE_ATTRIBUTE_READONLY)!=0) SetFileAttr(FileName,fd.FileAttr); }
bool ScanTree::GetNextMask() { if (!FileMasks->GetString(CurMask,CurMaskW,ASIZE(CurMask))) return(false); if (*CurMask==0 && *CurMaskW!=0) { // Unicode only mask is present. It is very unlikely in console tools, // but possible if called from GUI WinRAR. We still need to have // ASCII mask, because we use ASCII only mask in some checks later. // So let's convert Unicode to ASCII. WideToChar(CurMaskW,CurMask,ASIZE(CurMask)); } CurMask[ASIZE(CurMask)-1]=0; CurMaskW[ASIZE(CurMaskW)-1]=0; #ifdef _WIN_ALL UnixSlashToDos(CurMask); #endif // We wish to scan entire disk if mask like c:\ is specified // regardless of recursion mode. Use c:\*.* mask when need to scan only // the root directory. ScanEntireDisk=IsDiskLetter(CurMask) && IsPathDiv(CurMask[2]) && CurMask[3]==0; char *Name=PointToName(CurMask); if (*Name==0) strcat(CurMask,MASKALL); if (Name[0]=='.' && (Name[1]==0 || Name[1]=='.' && Name[2]==0)) { AddEndSlash(CurMask); strcat(CurMask,MASKALL); } SpecPathLength=Name-CurMask; bool WideName=(*CurMaskW!=0); if (WideName) { wchar *NameW=PointToName(CurMaskW); if (*NameW==0) wcscat(CurMaskW,MASKALLW); if (NameW[0]=='.' && (NameW[1]==0 || NameW[1]=='.' && NameW[2]==0)) { AddEndSlash(CurMaskW); wcscat(CurMaskW,MASKALLW); } SpecPathLengthW=NameW-CurMaskW; } else { wchar WideMask[NM]; CharToWide(CurMask,WideMask); SpecPathLengthW=PointToName(WideMask)-WideMask; } Depth=0; strcpy(OrigCurMask,CurMask); wcscpy(OrigCurMaskW,CurMaskW); return(true); }
void CmdExtract::ExtrCreateDir(Archive &Arc,const wchar *ArcFileName) { return; // OPENMPT ADDITION if (Cmd->Test) { #ifndef GUI mprintf(St(MExtrTestFile),ArcFileName); mprintf(L" %s",St(MOk)); #endif return; } MKDIR_CODE MDCode=MakeDir(DestFileName,!Cmd->IgnoreGeneralAttr,Arc.FileHead.FileAttr); bool DirExist=false; if (MDCode!=MKDIR_SUCCESS) { DirExist=FileExist(DestFileName); if (DirExist && !IsDir(GetFileAttr(DestFileName))) { // File with name same as this directory exists. Propose user // to overwrite it. bool UserReject; FileCreate(Cmd,NULL,DestFileName,ASIZE(DestFileName),&UserReject,Arc.FileHead.UnpSize,&Arc.FileHead.mtime); DirExist=false; } if (!DirExist) { CreatePath(DestFileName,true); MDCode=MakeDir(DestFileName,!Cmd->IgnoreGeneralAttr,Arc.FileHead.FileAttr); } } if (MDCode==MKDIR_SUCCESS) { #ifndef GUI mprintf(St(MCreatDir),DestFileName); mprintf(L" %s",St(MOk)); #endif PrevExtracted=true; } else if (DirExist) { if (!Cmd->IgnoreGeneralAttr) SetFileAttr(DestFileName,Arc.FileHead.FileAttr); PrevExtracted=true; } else { uiMsg(UIERROR_DIRCREATE,Arc.FileName,DestFileName); ErrHandler.SysErrMsg(); #ifdef RARDLL Cmd->DllError=ERAR_ECREATE; #endif ErrHandler.SetErrorCode(RARX_CREATE); } if (PrevExtracted) { #if defined(_WIN_ALL) && !defined(SFX_MODULE) if (Cmd->SetCompressedAttr && (Arc.FileHead.FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0 && WinNT()) SetFileCompression(DestFileName,true); #endif SetDirTime(DestFileName, Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.FileHead.mtime, Cmd->xctime==EXTTIME_NONE ? NULL:&Arc.FileHead.ctime, Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.FileHead.atime); } }
int print_insn_pj (bfd_vma addr, struct disassemble_info *info) { fprintf_ftype fprintf_fn = info->fprintf_func; void *stream = info->stream; unsigned char opcode; int status; if ((status = info->read_memory_func (addr, &opcode, 1, info))) goto fail; if (opcode == 0xff) { unsigned char byte_2; if ((status = info->read_memory_func (addr + 1, &byte_2, 1, info))) goto fail; fprintf_fn (stream, "%s\t", pj_opc_info[opcode + byte_2].u.name); return 2; } else { char *sep = "\t"; int insn_start = addr; const pj_opc_info_t *op = &pj_opc_info[opcode]; int a; addr++; fprintf_fn (stream, "%s", op->u.name); /* The tableswitch instruction is followed by the default address, low value, high value and the destinations. */ if (strcmp (op->u.name, "tableswitch") == 0) { int lowval; int highval; int val; addr = (addr + 3) & ~3; if ((status = get_int (addr, &val, info))) goto fail; fprintf_fn (stream, " default: "); (*info->print_address_func) (val + insn_start, info); addr += 4; if ((status = get_int (addr, &lowval, info))) goto fail; addr += 4; if ((status = get_int (addr, &highval, info))) goto fail; addr += 4; while (lowval <= highval) { if ((status = get_int (addr, &val, info))) goto fail; fprintf_fn (stream, " %d:[", lowval); (*info->print_address_func) (val + insn_start, info); fprintf_fn (stream, " ]"); addr += 4; lowval++; } return addr - insn_start; } /* The lookupswitch instruction is followed by the default address, element count and pairs of values and addresses. */ if (strcmp (op->u.name, "lookupswitch") == 0) { int count; int val; addr = (addr + 3) & ~3; if ((status = get_int (addr, &val, info))) goto fail; addr += 4; fprintf_fn (stream, " default: "); (*info->print_address_func) (val + insn_start, info); if ((status = get_int (addr, &count, info))) goto fail; addr += 4; while (count--) { if ((status = get_int (addr, &val, info))) goto fail; addr += 4; fprintf_fn (stream, " %d:[", val); if ((status = get_int (addr, &val, info))) goto fail; addr += 4; (*info->print_address_func) (val + insn_start, info); fprintf_fn (stream, " ]"); } return addr - insn_start; } for (a = 0; op->arg[a]; a++) { unsigned char data[4]; int val = 0; int i; int size = ASIZE (op->arg[a]); if ((status = info->read_memory_func (addr, data, size, info))) goto fail; val = (UNS (op->arg[0]) || ((data[0] & 0x80) == 0)) ? 0 : -1; for (i = 0; i < size; i++) val = (val << 8) | (data[i] & 0xff); if (PCREL (op->arg[a])) (*info->print_address_func) (val + insn_start, info); else fprintf_fn (stream, "%s%d", sep, val); sep = ","; addr += size; } return op->len; } fail: info->memory_error_func (status, addr, info); return -1; }
EXTRACT_ARC_CODE CmdExtract::ExtractArchive() { Archive Arc(Cmd); if (!Arc.WOpen(ArcName)) return EXTRACT_ARC_NEXT; if (!Arc.IsArchive(true)) { #ifndef GUI mprintf(St(MNotRAR),ArcName); #endif if (CmpExt(ArcName,L"rar")) ErrHandler.SetErrorCode(RARX_WARNING); return EXTRACT_ARC_NEXT; } if (Arc.FailedHeaderDecryption) // Bad archive password. return EXTRACT_ARC_NEXT; #ifndef SFX_MODULE if (Arc.Volume && !Arc.FirstVolume) { wchar FirstVolName[NM]; VolNameToFirstName(ArcName,FirstVolName,ASIZE(FirstVolName),Arc.NewNumbering); // If several volume names from same volume set are specified // and current volume is not first in set and first volume is present // and specified too, let's skip the current volume. if (wcsicomp(ArcName,FirstVolName)!=0 && FileExist(FirstVolName) && Cmd->ArcNames.Search(FirstVolName,false)) return EXTRACT_ARC_NEXT; } #endif int64 VolumeSetSize=0; // Total size of volumes after the current volume. if (Arc.Volume) { // Calculate the total size of all accessible volumes. // This size is necessary to display the correct total progress indicator. wchar NextName[NM]; wcscpy(NextName,Arc.FileName); while (true) { // First volume is already added to DataIO.TotalArcSize // in initial TotalArcSize calculation in DoExtract. // So we skip it and start from second volume. NextVolumeName(NextName,ASIZE(NextName),!Arc.NewNumbering); FindData FD; if (FindFile::FastFind(NextName,&FD)) VolumeSetSize+=FD.Size; else break; } DataIO.TotalArcSize+=VolumeSetSize; } ExtractArchiveInit(Arc); if (*Cmd->Command=='T' || *Cmd->Command=='I') Cmd->Test=true; if (*Cmd->Command=='I') { #ifndef GUI Cmd->DisablePercentage=true; #endif } else uiStartArchiveExtract(!Cmd->Test,ArcName); Arc.ViewComment(); while (1) { size_t Size=Arc.ReadHeader(); bool Repeat=false; if (!ExtractCurrentFile(Arc,Size,Repeat)) if (Repeat) { // If we started extraction from not first volume and need to // restart it from first, we must correct DataIO.TotalArcSize // for correct total progress display. We subtract the size // of current volume and all volumes after it and add the size // of new (first) volume. FindData OldArc,NewArc; if (FindFile::FastFind(Arc.FileName,&OldArc) && FindFile::FastFind(ArcName,&NewArc)) DataIO.TotalArcSize-=VolumeSetSize+OldArc.Size-NewArc.Size; return EXTRACT_ARC_REPEAT; } else break; } return EXTRACT_ARC_NEXT; }
bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) { wchar Command=Cmd->Command[0]; if (HeaderSize==0) if (DataIO.UnpVolume) { #ifdef NOVOLUME return false; #else if (!MergeArchive(Arc,&DataIO,false,Command)) { ErrHandler.SetErrorCode(RARX_WARNING); return false; } #endif } else return false; HEADER_TYPE HeaderType=Arc.GetHeaderType(); if (HeaderType!=HEAD_FILE) { #ifndef SFX_MODULE if (HeaderType==HEAD3_OLDSERVICE && PrevExtracted) SetExtraInfo20(Cmd,Arc,DestFileName); #endif if (HeaderType==HEAD_SERVICE && PrevExtracted) SetExtraInfo(Cmd,Arc,DestFileName); if (HeaderType==HEAD_ENDARC) if (Arc.EndArcHead.NextVolume) { #ifndef NOVOLUME if (!MergeArchive(Arc,&DataIO,false,Command)) { ErrHandler.SetErrorCode(RARX_WARNING); return false; } #endif Arc.Seek(Arc.CurBlockPos,SEEK_SET); return true; } else return false; Arc.SeekToNext(); return true; } PrevExtracted=false; if (!Cmd->Recurse && MatchedArgs>=Cmd->FileArgs.ItemsCount() && AllMatchesExact) return false; int MatchType=MATCH_WILDSUBPATH; bool EqualNames=false; int MatchNumber=Cmd->IsProcessFile(Arc.FileHead,&EqualNames,MatchType); bool ExactMatch=MatchNumber!=0; #ifndef SFX_MODULE if (Cmd->ExclPath==EXCL_BASEPATH) { *Cmd->ArcPath=0; if (ExactMatch) { Cmd->FileArgs.Rewind(); if (Cmd->FileArgs.GetString(Cmd->ArcPath,ASIZE(Cmd->ArcPath),MatchNumber-1)) *PointToName(Cmd->ArcPath)=0; } } #endif if (ExactMatch && !EqualNames) AllMatchesExact=false; Arc.ConvertAttributes(); #if !defined(SFX_MODULE) && !defined(RARDLL) if (Arc.FileHead.SplitBefore && FirstFile) { wchar CurVolName[NM]; wcsncpyz(CurVolName,ArcName,ASIZE(CurVolName)); VolNameToFirstName(ArcName,ArcName,ASIZE(ArcName),Arc.NewNumbering); if (wcsicomp(ArcName,CurVolName)!=0 && FileExist(ArcName)) { // If first volume name does not match the current name and if such // volume name really exists, let's unpack from this first volume. Repeat=true; return false; } #ifndef RARDLL if (!ReconstructDone) { ReconstructDone=true; if (RecVolumesRestore(Cmd,Arc.FileName,true)) { Repeat=true; return false; } } #endif wcsncpyz(ArcName,CurVolName,ASIZE(ArcName)); } #endif wchar ArcFileName[NM]; ConvertPath(Arc.FileHead.FileName,ArcFileName); if (Arc.FileHead.Version) { if (Cmd->VersionControl!=1 && !EqualNames) { if (Cmd->VersionControl==0) ExactMatch=false; int Version=ParseVersionFileName(ArcFileName,false); if (Cmd->VersionControl-1==Version) ParseVersionFileName(ArcFileName,true); else ExactMatch=false; } } else if (!Arc.IsArcDir() && Cmd->VersionControl>1) ExactMatch=false; DataIO.UnpVolume=Arc.FileHead.SplitAfter; DataIO.NextVolumeMissing=false; Arc.Seek(Arc.NextBlockPos-Arc.FileHead.PackSize,SEEK_SET); bool ExtrFile=false; bool SkipSolid=false; #ifndef SFX_MODULE if (FirstFile && (ExactMatch || Arc.Solid) && Arc.FileHead.SplitBefore) { if (ExactMatch) { uiMsg(UIERROR_NEEDPREVVOL,Arc.FileName,ArcFileName); #ifdef RARDLL Cmd->DllError=ERAR_BAD_DATA; #endif ErrHandler.SetErrorCode(RARX_OPEN); } ExactMatch=false; } FirstFile=false; #endif if (ExactMatch || (SkipSolid=Arc.Solid)!=0) { // First common call of uiStartFileExtract. It is done before overwrite // prompts, so if SkipSolid state is changed below, we'll need to make // additional uiStartFileExtract calls with updated parameters. if (!uiStartFileExtract(ArcFileName,!Cmd->Test,Cmd->Test && Command!='I',SkipSolid)) return false; ExtrPrepareName(Arc,ArcFileName,DestFileName,ASIZE(DestFileName)); // DestFileName can be set empty in case of excessive -ap switch. ExtrFile=!SkipSolid && *DestFileName!=0 && !Arc.FileHead.SplitBefore; /* // OPENMPT ADDITION if ((Cmd->FreshFiles || Cmd->UpdateFiles) && (Command=='E' || Command=='X')) { FindData FD; if (FindFile::FastFind(DestFileName,&FD)) { if (FD.mtime >= Arc.FileHead.mtime) { // If directory already exists and its modification time is newer // than start of extraction, it is likely it was created // when creating a path to one of already extracted items. // In such case we'll better update its time even if archived // directory is older. if (!FD.IsDir || FD.mtime<StartTime) ExtrFile=false; } } else if (Cmd->FreshFiles) ExtrFile=false; } */ // OPENMPT ADDITION if (Arc.FileHead.Encrypted) { #ifdef RARDLL if (!ExtrDllGetPassword()) return false; #else if (!ExtrGetPassword(Arc,ArcFileName)) { PasswordCancelled=true; return false; } #endif // Skip only the current encrypted file if empty password is entered. if (!Password.IsSet()) { ErrHandler.SetErrorCode(RARX_WARNING); #ifdef RARDLL Cmd->DllError=ERAR_MISSING_PASSWORD; #endif ExtrFile=false; } } #ifdef RARDLL if (*Cmd->DllDestName!=0) { wcsncpyz(DestFileName,Cmd->DllDestName,ASIZE(DestFileName)); // Do we need this code? // if (Cmd->DllOpMode!=RAR_EXTRACT) // ExtrFile=false; } #endif if (!CheckUnpVer(Arc,ArcFileName)) { ExtrFile=false; ErrHandler.SetErrorCode(RARX_FATAL); #ifdef RARDLL Cmd->DllError=ERAR_UNKNOWN_FORMAT; #endif } File CurFile; bool LinkEntry=Arc.FileHead.RedirType!=FSREDIR_NONE; if (LinkEntry && Arc.FileHead.RedirType!=FSREDIR_FILECOPY) { if (ExtrFile && Command!='P' && !Cmd->Test) { // Overwrite prompt for symbolic and hard links. bool UserReject=false; if (FileExist(DestFileName) && !UserReject) FileCreate(Cmd,NULL,DestFileName,ASIZE(DestFileName),&UserReject,Arc.FileHead.UnpSize,&Arc.FileHead.mtime); if (UserReject) ExtrFile=false; } } else if (Arc.IsArcDir()) { if (!ExtrFile || Command=='P' || Command=='I' || Command=='E' || Cmd->ExclPath==EXCL_SKIPWHOLEPATH) return true; TotalFileCount++; ExtrCreateDir(Arc,ArcFileName); return true; } else if (ExtrFile) // Create files and file copies (FSREDIR_FILECOPY). ExtrFile=ExtrCreateFile(Arc,CurFile); if (!ExtrFile && Arc.Solid) { SkipSolid=true; ExtrFile=true; // We changed SkipSolid, so we need to call uiStartFileExtract // with "Skip" parameter to change the operation status // from "extracting" to "skipping". For example, it can be necessary // if user answered "No" to overwrite prompt when unpacking // a solid archive. if (!uiStartFileExtract(ArcFileName,false,false,true)) return false; } if (ExtrFile) { bool TestMode=Cmd->Test || SkipSolid; // Unpack to memory, not to disk. if (!SkipSolid) { if (!TestMode && Command!='P' && CurFile.IsDevice()) { uiMsg(UIERROR_INVALIDNAME,Arc.FileName,DestFileName); ErrHandler.WriteError(Arc.FileName,DestFileName); } TotalFileCount++; } FileCount++; #ifndef GUI if (Command!='I') if (SkipSolid) mprintf(St(MExtrSkipFile),ArcFileName); else switch(Cmd->Test ? 'T':Command) // "Test" can be also enabled by -t switch. { case 'T': mprintf(St(MExtrTestFile),ArcFileName); break; #ifndef SFX_MODULE case 'P': mprintf(St(MExtrPrinting),ArcFileName); break; #endif case 'X': case 'E': mprintf(St(MExtrFile),DestFileName); break; } if (!Cmd->DisablePercentage) mprintf(L" "); #endif SecPassword FilePassword=Password; #if defined(_WIN_ALL) && !defined(SFX_MODULE) ConvertDosPassword(Arc,FilePassword); #endif byte PswCheck[SIZE_PSWCHECK]; DataIO.SetEncryption(false,Arc.FileHead.CryptMethod,&FilePassword, Arc.FileHead.SaltSet ? Arc.FileHead.Salt:NULL, Arc.FileHead.InitV,Arc.FileHead.Lg2Count, PswCheck,Arc.FileHead.HashKey); bool WrongPassword=false; // If header is damaged, we cannot rely on password check value, // because it can be damaged too. if (Arc.FileHead.Encrypted && Arc.FileHead.UsePswCheck && memcmp(Arc.FileHead.PswCheck,PswCheck,SIZE_PSWCHECK)!=0 && !Arc.BrokenHeader) { uiMsg(UIERROR_BADPSW,Arc.FileName); ErrHandler.SetErrorCode(RARX_BADPWD); WrongPassword=true; } DataIO.CurUnpRead=0; DataIO.CurUnpWrite=0; DataIO.UnpHash.Init(Arc.FileHead.FileHash.Type,Cmd->Threads); DataIO.PackedDataHash.Init(Arc.FileHead.FileHash.Type,Cmd->Threads); DataIO.SetPackedSizeToRead(Arc.FileHead.PackSize); DataIO.SetFiles(&Arc,&CurFile); DataIO.SetTestMode(TestMode); DataIO.SetSkipUnpCRC(SkipSolid); if (!TestMode && !WrongPassword && !Arc.BrokenHeader && (Arc.FileHead.PackSize<<11)>Arc.FileHead.UnpSize && (Arc.FileHead.UnpSize<100000000 || Arc.FileLength()>Arc.FileHead.PackSize)) CurFile.Prealloc(Arc.FileHead.UnpSize); CurFile.SetAllowDelete(!Cmd->KeepBroken); bool FileCreateMode=!TestMode && !SkipSolid && Command!='P'; bool ShowChecksum=true; // Display checksum verification result. bool LinkSuccess=true; // Assume success for test mode. if (LinkEntry) { /* // OPENMPT ADDITION FILE_SYSTEM_REDIRECT Type=Arc.FileHead.RedirType; if (Type==FSREDIR_HARDLINK || Type==FSREDIR_FILECOPY) { wchar NameExisting[NM]; ExtrPrepareName(Arc,Arc.FileHead.RedirName,NameExisting,ASIZE(NameExisting)); if (FileCreateMode && *NameExisting!=0) // *NameExisting can be 0 in case of excessive -ap switch. if (Type==FSREDIR_HARDLINK) LinkSuccess=ExtractHardlink(DestFileName,NameExisting,ASIZE(NameExisting)); else LinkSuccess=ExtractFileCopy(CurFile,Arc.FileName,DestFileName,NameExisting,ASIZE(NameExisting)); } else if (Type==FSREDIR_UNIXSYMLINK || Type==FSREDIR_WINSYMLINK || Type==FSREDIR_JUNCTION) { if (FileCreateMode) LinkSuccess=ExtractSymlink(Cmd,DataIO,Arc,DestFileName); } else { uiMsg(UIERROR_UNKNOWNEXTRA, Arc.FileName, DestFileName); LinkSuccess=false; } if (!LinkSuccess || Arc.Format==RARFMT15 && !FileCreateMode) { // RAR 5.x links have a valid data checksum even in case of // failure, because they do not store any data. // We do not want to display "OK" in this case. // For 4.x symlinks we verify the checksum only when extracting, // but not when testing an archive. ShowChecksum=false; } PrevExtracted=FileCreateMode && LinkSuccess; */ // OPENMPT ADDITION } else if (!Arc.FileHead.SplitBefore && !WrongPassword) if (Arc.FileHead.Method==0) UnstoreFile(DataIO,Arc.FileHead.UnpSize); else { #ifdef _ANDROID // malloc and new do not report memory allocation errors // in Android, so if free memory is set, check it here // trying to prevent crash. if (Cmd->FreeMem!=0 && Cmd->FreeMem < Arc.FileHead.WinSize) throw std::bad_alloc(); #endif Unp->Init(Arc.FileHead.WinSize,Arc.FileHead.Solid); Unp->SetDestSize(Arc.FileHead.UnpSize); #ifndef SFX_MODULE if (Arc.Format!=RARFMT50 && Arc.FileHead.UnpVer<=15) Unp->DoUnpack(15,FileCount>1 && Arc.Solid); else #endif Unp->DoUnpack(Arc.FileHead.UnpVer,Arc.FileHead.Solid); } Arc.SeekToNext(); bool ValidCRC=DataIO.UnpHash.Cmp(&Arc.FileHead.FileHash,Arc.FileHead.UseHashKey ? Arc.FileHead.HashKey:NULL); // We set AnySolidDataUnpackedWell to true if we found at least one // valid non-zero solid file in preceding solid stream. If it is true // and if current encrypted file is broken, we do not need to hint // about a wrong password and can report CRC error only. if (!Arc.FileHead.Solid) AnySolidDataUnpackedWell=false; // Reset the flag, because non-solid file is found. else if (Arc.FileHead.Method!=0 && Arc.FileHead.UnpSize>0 && ValidCRC) AnySolidDataUnpackedWell=true; bool BrokenFile=false; // Checksum is not calculated in skip solid mode for performance reason. if (!SkipSolid && ShowChecksum) { if (!WrongPassword && ValidCRC) { #ifndef GUI if (Command!='P' && Command!='I') mprintf(L"%s%s ",Cmd->DisablePercentage ? L" ":L"\b\b\b\b\b ", Arc.FileHead.FileHash.Type==HASH_NONE ? L" ?":St(MOk)); #endif } else { if (!WrongPassword) if (Arc.FileHead.Encrypted && (!Arc.FileHead.UsePswCheck || Arc.BrokenHeader) && !AnySolidDataUnpackedWell) uiMsg(UIERROR_CHECKSUMENC,Arc.FileName,ArcFileName); else uiMsg(UIERROR_CHECKSUM,Arc.FileName,ArcFileName); BrokenFile=true; ErrHandler.SetErrorCode(RARX_CRC); #ifdef RARDLL // If we already have ERAR_EOPEN as result of missing volume, // we should not replace it with less precise ERAR_BAD_DATA. if (Cmd->DllError!=ERAR_EOPEN) Cmd->DllError=WrongPassword ? ERAR_BAD_PASSWORD : ERAR_BAD_DATA; #endif } } #ifndef GUI else mprintf(L"\b\b\b\b\b "); #endif /* // OPENMPT ADDITION if (!TestMode && !WrongPassword && (Command=='X' || Command=='E') && (!LinkEntry || Arc.FileHead.RedirType==FSREDIR_FILECOPY && LinkSuccess) && (!BrokenFile || Cmd->KeepBroken)) { // We could preallocate more space that really written to broken file. if (BrokenFile) CurFile.Truncate(); #if defined(_WIN_ALL) || defined(_EMX) if (Cmd->ClearArc) Arc.FileHead.FileAttr&=~FILE_ATTRIBUTE_ARCHIVE; #endif CurFile.SetOpenFileTime( Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.FileHead.mtime, Cmd->xctime==EXTTIME_NONE ? NULL:&Arc.FileHead.ctime, Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.FileHead.atime); CurFile.Close(); #if defined(_WIN_ALL) && !defined(SFX_MODULE) if (Cmd->SetCompressedAttr && (Arc.FileHead.FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0) SetFileCompression(CurFile.FileName,true); #endif #ifdef _UNIX if (Cmd->ProcessOwners && Arc.Format==RARFMT50 && Arc.FileHead.UnixOwnerSet) SetUnixOwner(Arc,CurFile.FileName); #endif CurFile.SetCloseFileTime( Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.FileHead.mtime, Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.FileHead.atime); if (!Cmd->IgnoreGeneralAttr && !SetFileAttr(CurFile.FileName,Arc.FileHead.FileAttr)) uiMsg(UIERROR_FILEATTR,Arc.FileName,CurFile.FileName); PrevExtracted=true; } */ // OPENMPT ADDITION } } if (ExactMatch) MatchedArgs++; if (DataIO.NextVolumeMissing) return false; if (!ExtrFile) if (!Arc.Solid) Arc.SeekToNext(); else if (!SkipSolid) return false; return true; }
bool FindFile::Next(struct FindData *fd,bool GetSymLink) { fd->Error=false; if (*FindMask==0) return(false); #ifdef _WIN_32 if (FirstCall) { if ((hFind=Win32Find(INVALID_HANDLE_VALUE,FindMask,FindMaskW,fd))==INVALID_HANDLE_VALUE) return(false); } else if (Win32Find(hFind,FindMask,FindMaskW,fd)==INVALID_HANDLE_VALUE) return(false); #else if (FirstCall) { char DirName[NM]; strcpy(DirName,FindMask); RemoveNameFromPath(DirName); if (*DirName==0) strcpy(DirName,"."); /* else { int Length=strlen(DirName); if (Length>1 && DirName[Length-1]==CPATHDIVIDER && (Length!=3 || !IsDriveDiv(DirName[1]))) DirName[Length-1]=0; } */ if ((dirp=opendir(DirName))==NULL) { fd->Error=(errno!=ENOENT); return(false); } } while (1) { struct dirent *ent=readdir(dirp); if (ent==NULL) return(false); if (strcmp(ent->d_name,".")==0 || strcmp(ent->d_name,"..")==0) continue; if (CmpName(FindMask,ent->d_name,MATCH_NAMES)) { char FullName[NM]; strcpy(FullName,FindMask); *PointToName(FullName)=0; if (strlen(FullName)+strlen(ent->d_name)>=ASIZE(FullName)-1) { #ifndef SILENT Log(NULL,"\n%s%s",FullName,ent->d_name); Log(NULL,St(MPathTooLong)); #endif return(false); } strcat(FullName,ent->d_name); if (!FastFind(FullName,NULL,fd,GetSymLink)) { ErrHandler.OpenErrorMsg(FullName); continue; } strcpy(fd->Name,FullName); break; } } *fd->NameW=0; #ifdef _APPLE if (!LowAscii(fd->Name)) UtfToWide(fd->Name,fd->NameW,sizeof(fd->NameW)); #elif defined(UNICODE_SUPPORTED) if (!LowAscii(fd->Name) && UnicodeEnabled()) CharToWide(fd->Name,fd->NameW); #endif #endif fd->IsDir=IsDir(fd->FileAttr); FirstCall=FALSE; char *Name=PointToName(fd->Name); if (strcmp(Name,".")==0 || strcmp(Name,"..")==0) return(Next(fd)); return(true); }
void InitLogOptions(const wchar *LogFileName,RAR_CHARSET CSet) { wcsncpyz(LogName,LogFileName,ASIZE(LogName)); LogCharset=CSet; }
int init_gpio(void) { char *btn_list[] = { "btn_rst_gpio", "btn_wps_gpio", "fan_gpio", "have_fan_gpio" #ifdef RTCONFIG_WIRELESS_SWITCH , "btn_wifi_gpio" #endif #ifdef RTCONFIG_WIFI_TOG_BTN , "btn_wltog_gpio" #endif #ifdef RTCONFIG_SWMODE_SWITCH #if defined(PLAC66U) , "btn_swmode1_gpio" #else , "btn_swmode1_gpio", "btn_swmode2_gpio", "btn_swmode3_gpio" #endif /* Mode */ #endif /* RTCONFIG_SWMODE_SWITCH */ #ifdef RTCONFIG_TURBO , "btn_turbo_gpio" #endif #ifdef RTCONFIG_LED_BTN , "btn_led_gpio" #endif #ifdef RTCONFIG_INTERNAL_GOBI , "btn_lte_gpio" #endif }; char *led_list[] = { "led_turbo_gpio", "led_pwr_gpio", "led_usb_gpio", "led_wps_gpio", "fan_gpio", "have_fan_gpio", "led_lan_gpio", "led_wan_gpio", "led_usb3_gpio", "led_2g_gpio", "led_5g_gpio" #ifdef RTCONFIG_LAN4WAN_LED , "led_lan1_gpio", "led_lan2_gpio", "led_lan3_gpio", "led_lan4_gpio" #endif /* LAN4WAN_LED */ #ifdef RTCONFIG_LED_ALL , "led_all_gpio" #endif , "led_wan_red_gpio" #ifdef RTCONFIG_QTN , "reset_qtn_gpio" #endif #ifdef RTCONFIG_USBRESET , "pwr_usb_gpio" , "pwr_usb_gpio2" #endif #ifdef RTCONFIG_WIFIPWR , "pwr_2g_gpio" , "pwr_5g_gpio" #endif #ifdef RTCONFIG_INTERNAL_GOBI , "led_3g_gpio", "led_lte_gpio", "led_sig1_gpio", "led_sig2_gpio", "led_sig3_gpio", "led_sig4_gpio" #endif #if (defined(PLN12) || defined(PLAC56)) , "plc_wake_gpio" , "led_pwr_red_gpio" , "led_2g_green_gpio", "led_2g_orange_gpio", "led_2g_red_gpio" , "led_5g_green_gpio", "led_5g_orange_gpio", "led_5g_red_gpio" #endif #ifdef RTCONFIG_MMC_LED , "led_mmc_gpio" #endif #if defined(RTCONFIG_RTAC5300) || defined(RTCONFIG_RTAC5300R) , "rpm_fan_gpio" #endif #ifdef RTCONFIG_RESET_SWITCH , "reset_switch_gpio" #endif }; int use_gpio, gpio_pin; int enable, disable; int i; #ifdef RTCONFIG_INTERNAL_GOBI void get_gpio_values_once(int); get_gpio_values_once(0); // for filling data to led_gpio_table[] #endif /* RTCONFIG_INTERNAL_GOBI */ /* btn input */ for(i = 0; i < ASIZE(btn_list); i++) { if (!nvram_get(btn_list[i])) continue; use_gpio = nvram_get_int(btn_list[i]); if((gpio_pin = use_gpio & 0xff) == 0xff) continue; gpio_dir(gpio_pin, GPIO_DIR_IN); } /* led output */ for(i = 0; i < ASIZE(led_list); i++) { if (!nvram_get(led_list[i])) continue; #if defined(RTCONFIG_ETRON_XHCI_USB3_LED) if (!strcmp(led_list[i], "led_usb3_gpio") && nvram_match("led_usb3_gpio", "etron")) { led_control(LED_USB3, LED_OFF); continue; } #endif use_gpio = nvram_get_int(led_list[i]); if((gpio_pin = use_gpio & 0xff) == 0xff) continue; #if defined(RTCONFIG_RALINK_MT7620) if(gpio_pin == 72) //skip 2g wifi led NOT to be gpio LED continue; #endif disable = (use_gpio&GPIO_ACTIVE_LOW)==0 ? 0: 1; gpio_dir(gpio_pin, GPIO_DIR_OUT); /* If WAN RED LED is defined, keep it on until Internet connection ready in router mode. */ if (!strcmp(led_list[i], "led_wan_red_gpio") && nvram_get_int("sw_mode") == SW_MODE_ROUTER) disable = !disable; set_gpio(gpio_pin, disable); #ifdef RTCONFIG_INTERNAL_GOBI // save setting value { int i; char led[16]; for(i=0; i<LED_ID_MAX; i++) if(gpio_pin == (led_gpio_table[i]&0xff)){snprintf(led, sizeof(led), "led%02d", i); nvram_set_int(led, LED_OFF); break;}} #endif /* RTCONFIG_INTERNAL_GOBI */ } #if (defined(PLN12) || defined(PLAC56)) if((gpio_pin = (use_gpio = nvram_get_int("led_pwr_red_gpio")) & 0xff) != 0xff) #else if((gpio_pin = (use_gpio = nvram_get_int("led_pwr_gpio")) & 0xff) != 0xff) #endif { enable = (use_gpio&GPIO_ACTIVE_LOW)==0 ? 1 : 0; set_gpio(gpio_pin, enable); #ifdef RTCONFIG_INTERNAL_GOBI // save setting value { int i; char led[16]; for(i=0; i<LED_ID_MAX; i++) if(gpio_pin == (led_gpio_table[i]&0xff)){snprintf(led, sizeof(led), "led%02d", i); nvram_set_int(led, LED_ON); break;}} #endif /* RTCONFIG_INTERNAL_GOBI */ } // Power of USB. if((gpio_pin = (use_gpio = nvram_get_int("pwr_usb_gpio")) & 0xff) != 0xff){ enable = (use_gpio&GPIO_ACTIVE_LOW)==0 ? 1 : 0; set_gpio(gpio_pin, enable); } if((gpio_pin = (use_gpio = nvram_get_int("pwr_usb_gpio2")) & 0xff) != 0xff){ enable = (use_gpio&GPIO_ACTIVE_LOW)==0 ? 1 : 0; set_gpio(gpio_pin, enable); } #if defined(RTCONFIG_RTAC5300) || defined(RTCONFIG_RTAC5300R) // RPM of FAN if((gpio_pin = (use_gpio = nvram_get_int("rpm_fan_gpio")) & 0xff) != 0xff){ enable = (use_gpio&GPIO_ACTIVE_LOW)==0 ? 1 : 0; set_gpio(gpio_pin, enable); } #endif #ifdef PLAC56 if((gpio_pin = (use_gpio = nvram_get_int("plc_wake_gpio")) & 0xff) != 0xff){ enable = (use_gpio&GPIO_ACTIVE_LOW)==0 ? 1 : 0; set_gpio(gpio_pin, enable); } #endif // TODO: system dependent initialization return 0; }
// If we find a file, which short name is equal to 'Name', we try to change // its short name, while preserving the long name. It helps when unpacking // an archived file, which long name is equal to short name of already // existing file. Otherwise we would overwrite the already existing file, // even though its long name does not match the name of unpacking file. bool UpdateExistingShortName(wchar *Name) { // 'Name' is the name of file which we want to create. Let's check // if file with such name is exist. If it does not, we return. FindData fd; if (!FindFile::FastFind(NULL,Name,&fd)) return(false); // We continue only if file has a short name, which does not match its // long name, and this short name is equal to name of file which we need // to create. if (*fd.ShortName==0 || wcsicomp(PointToName(fd.NameW),fd.ShortName)==0 || wcsicomp(PointToName(Name),fd.ShortName)!=0) return(false); // Generate the temporary new name for existing file. wchar NewName[NM]; *NewName=0; for (int I=0;I<10000 && *NewName==0;I+=123) { // Here we copy the path part of file to create. We'll make the temporary // file in the same folder. wcsncpyz(NewName,Name,ASIZE(NewName)); // Here we set the random name part. sprintfw(PointToName(NewName),ASIZE(NewName),L"rtmp%d",I); // If such file is already exist, try next random name. if (FileExist(NULL,NewName)) *NewName=0; } // If we could not generate the name not used by any other file, we return. if (*NewName==0) return(false); // FastFind returns the name without path, but we need the fully qualified // name for renaming, so we use the path from file to create and long name // from existing file. wchar FullName[NM]; wcsncpyz(FullName,Name,ASIZE(FullName)); wcscpy(PointToName(FullName),PointToName(fd.NameW)); // Rename the existing file to randomly generated name. Normally it changes // the short name too. if (!MoveFileW(FullName,NewName)) return(false); // Now we need to create the temporary empty file with same name as // short name of our already existing file. We do it to occupy its previous // short name and not allow to use it again when renaming the file back to // its original long name. File KeepShortFile; bool Created=false; if (!FileExist(NULL,Name)) Created=KeepShortFile.Create(NULL,Name); // Now we rename the existing file from temporary name to original long name. // Since its previous short name is occupied by another file, it should // get another short name. MoveFileW(NewName,FullName); if (Created) { // Delete the temporary zero length file occupying the short name, KeepShortFile.Close(); KeepShortFile.Delete(); } // We successfully changed the short name. Maybe sometimes we'll simplify // this function by use of SetFileShortName Windows API call. // But SetFileShortName is not available in older Windows. return(true); }
void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bool Technical,bool Bare) { wchar *Name=hd.FileName; RARFORMAT Format=Arc.Format; if (Bare) { mprintf(L"%s\n",Name); return; } if (!TitleShown && !Technical) { if (Verbose) { mprintf(L"\n%ls",St(MListTitleV)); mprintf(L"\n----------- --------- -------- ----- ---------- ----- -------- ----"); } else { mprintf(L"\n%ls",St(MListTitleL)); mprintf(L"\n----------- --------- ---------- ----- ----"); } TitleShown=true; } wchar UnpSizeText[20],PackSizeText[20]; if (hd.UnpSize==INT64NDF) wcscpy(UnpSizeText,L"?"); else itoa(hd.UnpSize,UnpSizeText,ASIZE(UnpSizeText)); itoa(hd.PackSize,PackSizeText,ASIZE(PackSizeText)); wchar AttrStr[30]; if (hd.HeaderType==HEAD_SERVICE) swprintf(AttrStr,ASIZE(AttrStr),L"%cB",hd.Inherited ? 'I' : '.'); else ListFileAttr(hd.FileAttr,hd.HSType,AttrStr,ASIZE(AttrStr)); wchar RatioStr[10]; if (hd.SplitBefore && hd.SplitAfter) wcscpy(RatioStr,L"<->"); else if (hd.SplitBefore) wcscpy(RatioStr,L"<--"); else if (hd.SplitAfter) wcscpy(RatioStr,L"-->"); else swprintf(RatioStr,ASIZE(RatioStr),L"%d%%",ToPercentUnlim(hd.PackSize,hd.UnpSize)); wchar DateStr[50]; hd.mtime.GetText(DateStr,ASIZE(DateStr),Technical); if (Technical) { mprintf(L"\n%12s: %s",St(MListName),Name); bool FileBlock=hd.HeaderType==HEAD_FILE; if (!FileBlock && Arc.SubHead.CmpName(SUBHEAD_TYPE_STREAM)) { mprintf(L"\n%12ls: %ls",St(MListType),St(MListStream)); wchar StreamName[NM]; GetStreamNameNTFS(Arc,StreamName,ASIZE(StreamName)); mprintf(L"\n%12ls: %ls",St(MListTarget),StreamName); } else { const wchar *Type=St(FileBlock ? (hd.Dir ? MListDir:MListFile):MListService); if (hd.RedirType!=FSREDIR_NONE) switch(hd.RedirType) { case FSREDIR_UNIXSYMLINK: Type=St(MListUSymlink); break; case FSREDIR_WINSYMLINK: Type=St(MListWSymlink); break; case FSREDIR_JUNCTION: Type=St(MListJunction); break; case FSREDIR_HARDLINK: Type=St(MListHardlink); break; case FSREDIR_FILECOPY: Type=St(MListCopy); break; } mprintf(L"\n%12ls: %ls",St(MListType),Type); if (hd.RedirType!=FSREDIR_NONE) if (Format==RARFMT15) { char LinkTargetA[NM]; if (Arc.FileHead.Encrypted) { // Link data are encrypted. We would need to ask for password // and initialize decryption routine to display the link target. strncpyz(LinkTargetA,"*<-?->",ASIZE(LinkTargetA)); } else { int DataSize=(int)Min(hd.PackSize,ASIZE(LinkTargetA)-1); Arc.Read(LinkTargetA,DataSize); LinkTargetA[DataSize > 0 ? DataSize : 0] = 0; } wchar LinkTarget[NM]; CharToWide(LinkTargetA,LinkTarget,ASIZE(LinkTarget)); mprintf(L"\n%12ls: %ls",St(MListTarget),LinkTarget); } else mprintf(L"\n%12ls: %ls",St(MListTarget),hd.RedirName); } if (!hd.Dir) { mprintf(L"\n%12ls: %ls",St(MListSize),UnpSizeText); mprintf(L"\n%12ls: %ls",St(MListPacked),PackSizeText); mprintf(L"\n%12ls: %ls",St(MListRatio),RatioStr); } if (hd.mtime.IsSet()) mprintf(L"\n%12ls: %ls",St(MListMtime),DateStr); if (hd.ctime.IsSet()) { hd.ctime.GetText(DateStr,ASIZE(DateStr),true); mprintf(L"\n%12ls: %ls",St(MListCtime),DateStr); } if (hd.atime.IsSet()) { hd.atime.GetText(DateStr,ASIZE(DateStr),true); mprintf(L"\n%12ls: %ls",St(MListAtime),DateStr); } mprintf(L"\n%12ls: %ls",St(MListAttr),AttrStr); if (hd.FileHash.Type==HASH_CRC32) mprintf(L"\n%12ls: %8.8X", hd.UseHashKey ? L"CRC32 MAC":hd.SplitAfter ? L"Pack-CRC32":L"CRC32", hd.FileHash.CRC32); if (hd.FileHash.Type==HASH_BLAKE2) { wchar BlakeStr[BLAKE2_DIGEST_SIZE*2+1]; BinToHex(hd.FileHash.Digest,BLAKE2_DIGEST_SIZE,NULL,BlakeStr,ASIZE(BlakeStr)); mprintf(L"\n%12ls: %ls", hd.UseHashKey ? L"BLAKE2 MAC":hd.SplitAfter ? L"Pack-BLAKE2":L"BLAKE2", BlakeStr); } const wchar *HostOS=L""; if (Format==RARFMT50 && hd.HSType!=HSYS_UNKNOWN) HostOS=hd.HSType==HSYS_WINDOWS ? L"Windows":L"Unix"; if (Format==RARFMT15) { static const wchar *RarOS[]={ L"DOS",L"OS/2",L"Windows",L"Unix",L"Mac OS",L"BeOS",L"WinCE",L"",L"",L"" }; if (hd.HostOS<ASIZE(RarOS)) HostOS=RarOS[hd.HostOS]; } if (*HostOS!=0) mprintf(L"\n%12ls: %ls",St(MListHostOS),HostOS); mprintf(L"\n%12ls: RAR %ls(v%d) -m%d -md=%d%s",St(MListCompInfo), Format==RARFMT15 ? L"3.0":L"5.0",hd.UnpVer,hd.Method, hd.WinSize>=0x100000 ? hd.WinSize/0x100000:hd.WinSize/0x400, hd.WinSize>=0x100000 ? L"M":L"K"); if (hd.Solid || hd.Encrypted) { mprintf(L"\n%12ls: ",St(MListFlags)); if (hd.Solid) mprintf(L"%ls ",St(MListSolid)); if (hd.Encrypted) mprintf(L"%ls ",St(MListEnc)); } if (hd.Version) { uint Version=ParseVersionFileName(Name,false); if (Version!=0) mprintf(L"\n%12ls: %u",St(MListFileVer),Version); } if (hd.UnixOwnerSet) { mprintf(L"\n%12ls: ",L"Unix owner"); if (*hd.UnixOwnerName!=0) mprintf(L"%ls:",GetWide(hd.UnixOwnerName)); if (*hd.UnixGroupName!=0) mprintf(L"%ls",GetWide(hd.UnixGroupName)); if ((*hd.UnixOwnerName!=0 || *hd.UnixGroupName!=0) && (hd.UnixOwnerNumeric || hd.UnixGroupNumeric)) mprintf(L" "); if (hd.UnixOwnerNumeric) mprintf(L"#%d:",hd.UnixOwnerID); if (hd.UnixGroupNumeric) mprintf(L"#%d:",hd.UnixGroupID); } mprintf(L"\n"); return; } mprintf(L"\n%c%10ls %9ls ",hd.Encrypted ? '*' : ' ',AttrStr,UnpSizeText); if (Verbose) mprintf(L"%9ls %4ls ",PackSizeText,RatioStr); mprintf(L" %ls ",DateStr); if (Verbose) { if (hd.FileHash.Type==HASH_CRC32) mprintf(L"%8.8X ",hd.FileHash.CRC32); else if (hd.FileHash.Type==HASH_BLAKE2) { byte *S=hd.FileHash.Digest; mprintf(L"%02x%02x..%02x ",S[0],S[1],S[31]); } else mprintf(L"???????? "); } mprintf(L"%-12ls",Name); }
bool FileCreate(RAROptions *Cmd,File *NewFile,char *Name,wchar *NameW, OVERWRITE_MODE Mode,bool *UserReject,int64 FileSize, uint FileTime,bool WriteOnly) { if (UserReject!=NULL) *UserReject=false; #if defined(_WIN_ALL) && !defined(_WIN_CE) bool ShortNameChanged=false; #endif while (FileExist(Name,NameW)) { #if defined(_WIN_ALL) && !defined(_WIN_CE) if (!ShortNameChanged) { // Avoid the infinite loop if UpdateExistingShortName returns // the same name. ShortNameChanged=true; // Maybe our long name matches the short name of existing file. // Let's check if we can change the short name. wchar WideName[NM]; GetWideName(Name,NameW,WideName,ASIZE(WideName)); if (UpdateExistingShortName(WideName)) { if (Name!=NULL && *Name!=0) WideToChar(WideName,Name); if (NameW!=NULL && *NameW!=0) wcscpy(NameW,WideName); continue; } } // Allow short name check again. It is necessary, because rename and // autorename below can change the name, so we need to check it again. ShortNameChanged=false; #endif if (Mode==OVERWRITE_NONE) { if (UserReject!=NULL) *UserReject=true; return(false); } // Must be before Cmd->AllYes check or -y switch would override -or. if (Mode==OVERWRITE_AUTORENAME) { if (!GetAutoRenamedName(Name,NameW)) Mode=OVERWRITE_DEFAULT; continue; } #ifdef SILENT Mode=OVERWRITE_ALL; #endif // This check must be after OVERWRITE_AUTORENAME processing or -y switch // would override -or. if (Cmd->AllYes || Mode==OVERWRITE_ALL) break; if (Mode==OVERWRITE_DEFAULT || Mode==OVERWRITE_FORCE_ASK) { char NewName[NM]; wchar NewNameW[NM]; *NewNameW=0; eprintf(St(MFileExists),Name); int Choice=Ask(St(MYesNoAllRenQ)); if (Choice==1) break; if (Choice==2) { if (UserReject!=NULL) *UserReject=true; return(false); } if (Choice==3) { Cmd->Overwrite=OVERWRITE_ALL; break; } if (Choice==4) { if (UserReject!=NULL) *UserReject=true; Cmd->Overwrite=OVERWRITE_NONE; return(false); } if (Choice==5) { #ifndef GUI mprintf(St(MAskNewName)); #ifdef _WIN_ALL File SrcFile; SrcFile.SetHandleType(FILE_HANDLESTD); int Size=SrcFile.Read(NewName,sizeof(NewName)-1); NewName[Size]=0; OemToCharA(NewName,NewName); #else if (fgets(NewName,sizeof(NewName),stdin)==NULL) { // Process fgets failure as if user answered 'No'. if (UserReject!=NULL) *UserReject=true; return(false); } #endif RemoveLF(NewName); #endif if (PointToName(NewName)==NewName) strcpy(PointToName(Name),NewName); else strcpy(Name,NewName); if (NameW!=NULL) { if (PointToName(NewNameW)==NewNameW) wcscpy(PointToName(NameW),NewNameW); else wcscpy(NameW,NewNameW); } continue; } if (Choice==6) ErrHandler.Exit(RARX_USERBREAK); } } uint FileMode=WriteOnly ? FMF_WRITE|FMF_SHAREREAD:FMF_UPDATE|FMF_SHAREREAD; if (NewFile!=NULL && NewFile->Create(Name,NameW,FileMode)) return(true); PrepareToDelete(Name,NameW); CreatePath(Name,NameW,true); return(NewFile!=NULL ? NewFile->Create(Name,NameW,FileMode):DelFile(Name,NameW)); }
void ListArchive(CommandData *Cmd) { int64 SumPackSize=0,SumUnpSize=0; uint ArcCount=0,SumFileCount=0; bool Technical=(Cmd->Command[1]=='T'); bool ShowService=Technical && Cmd->Command[2]=='A'; bool Bare=(Cmd->Command[1]=='B'); bool Verbose=(Cmd->Command[0]=='V'); wchar ArcName[NM]; while (Cmd->GetArcName(ArcName,ASIZE(ArcName))) { if (Cmd->ManualPassword) Cmd->Password.Clean(); // Clean user entered password before processing next archive. Archive Arc(Cmd); #ifdef _WIN_ALL Arc.RemoveSequentialFlag(); #endif if (!Arc.WOpen(ArcName)) continue; bool FileMatched=true; while (1) { int64 TotalPackSize=0,TotalUnpSize=0; uint FileCount=0; if (Arc.IsArchive(true)) { bool TitleShown=false; if (!Bare) { Arc.ViewComment(); mprintf(L"\n%s: %s",St(MListArchive),Arc.FileName); mprintf(L"\n%s: ",St(MListDetails)); uint SetCount=0; const wchar *Fmt=Arc.Format==RARFMT14 ? L"RAR 1.4":(Arc.Format==RARFMT15 ? L"RAR 4":L"RAR 5"); mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", Fmt); if (Arc.Solid) mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListSolid)); if (Arc.SFXSize>0) mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListSFX)); if (Arc.Volume) if (Arc.Format==RARFMT50) { // RAR 5.0 archives store the volume number in main header, // so it is already available now. if (SetCount++ > 0) mprintf(L", "); mprintf(St(MVolumeNumber),Arc.VolNumber+1); } else mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListVolume)); if (Arc.Protected) mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListRR)); if (Arc.Locked) mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListLock)); if (Arc.Encrypted) mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListEncHead)); mprintf(L"\n"); } wchar VolNumText[50]; *VolNumText=0; while(Arc.ReadHeader()>0) { HEADER_TYPE HeaderType=Arc.GetHeaderType(); if (HeaderType==HEAD_ENDARC) { #ifndef SFX_MODULE // Only RAR 1.5 archives store the volume number in end record. if (Arc.EndArcHead.StoreVolNumber && Arc.Format==RARFMT15) swprintf(VolNumText,ASIZE(VolNumText),L"%.10ls %d",St(MListVolume),Arc.VolNumber+1); #endif if (Technical && ShowService) { mprintf(L"\n%12ls: %ls",St(MListService),L"EOF"); if (*VolNumText!=0) mprintf(L"\n%12ls: %ls",St(MListFlags),VolNumText); mprintf(L"\n"); } break; } switch(HeaderType) { case HEAD_FILE: FileMatched=Cmd->IsProcessFile(Arc.FileHead)!=0; if (FileMatched) { ListFileHeader(Arc,Arc.FileHead,TitleShown,Verbose,Technical,Bare); if (!Arc.FileHead.SplitBefore) { TotalUnpSize+=Arc.FileHead.UnpSize; FileCount++; } TotalPackSize+=Arc.FileHead.PackSize; } break; case HEAD_SERVICE: if (FileMatched && !Bare) { if (Technical && ShowService) ListFileHeader(Arc,Arc.SubHead,TitleShown,Verbose,true,false); } break; } Arc.SeekToNext(); } if (!Bare && !Technical) if (TitleShown) { wchar UnpSizeText[20]; itoa(TotalUnpSize,UnpSizeText,ASIZE(UnpSizeText)); wchar PackSizeText[20]; itoa(TotalPackSize,PackSizeText,ASIZE(PackSizeText)); if (Verbose) { mprintf(L"\n----------- --------- -------- ----- ---------- ----- -------- ----"); mprintf(L"\n%21ls %9ls %3d%% %-27ls %u",UnpSizeText, PackSizeText,ToPercentUnlim(TotalPackSize,TotalUnpSize), VolNumText,FileCount); } else { mprintf(L"\n----------- --------- ---------- ----- ----"); mprintf(L"\n%21ls %-16ls %u",UnpSizeText,VolNumText,FileCount); } SumFileCount+=FileCount; SumUnpSize+=TotalUnpSize; SumPackSize+=TotalPackSize; mprintf(L"\n"); } else mprintf(St(MListNoFiles)); ArcCount++; #ifndef NOVOLUME if (Cmd->VolSize!=0 && (Arc.FileHead.SplitAfter || Arc.GetHeaderType()==HEAD_ENDARC && Arc.EndArcHead.NextVolume) && MergeArchive(Arc,NULL,false,Cmd->Command[0])) { Arc.Seek(0,SEEK_SET); } else #endif break; } else { if (Cmd->ArcNames.ItemsCount()<2 && !Bare) mprintf(St(MNotRAR),Arc.FileName); break; } } } // Clean user entered password. Not really required, just for extra safety. if (Cmd->ManualPassword) Cmd->Password.Clean(); if (ArcCount>1 && !Bare && !Technical) { wchar UnpSizeText[20],PackSizeText[20]; itoa(SumUnpSize,UnpSizeText,ASIZE(UnpSizeText)); itoa(SumPackSize,PackSizeText,ASIZE(PackSizeText)); if (Verbose) mprintf(L"%21ls %9ls %3d%% %28ls %u",UnpSizeText,PackSizeText, ToPercentUnlim(SumPackSize,SumUnpSize),L"",SumFileCount); else mprintf(L"%21ls %18s %lu",UnpSizeText,L"",SumFileCount); } }
void RarTime::GetLocal(RarLocalTime *lt) { #ifdef _WIN_ALL FILETIME ft; GetWin32(&ft); FILETIME lft; if (WinNT() < WNT_VISTA) { // SystemTimeToTzSpecificLocalTime based code produces 1 hour error on XP. FileTimeToLocalFileTime(&ft,&lft); } else { // We use these functions instead of FileTimeToLocalFileTime according to // MSDN recommendation: "To account for daylight saving time // when converting a file time to a local time ..." SYSTEMTIME st1,st2; FileTimeToSystemTime(&ft,&st1); SystemTimeToTzSpecificLocalTime(NULL,&st1,&st2); SystemTimeToFileTime(&st2,&lft); // Correct precision loss (low 4 decimal digits) in FileTimeToSystemTime. FILETIME rft; SystemTimeToFileTime(&st1,&rft); int64 Corrected=INT32TO64(ft.dwHighDateTime,ft.dwLowDateTime)- INT32TO64(rft.dwHighDateTime,rft.dwLowDateTime)+ INT32TO64(lft.dwHighDateTime,lft.dwLowDateTime); lft.dwLowDateTime=(DWORD)Corrected; lft.dwHighDateTime=(DWORD)(Corrected>>32); } SYSTEMTIME st; FileTimeToSystemTime(&lft,&st); lt->Year=st.wYear; lt->Month=st.wMonth; lt->Day=st.wDay; lt->Hour=st.wHour; lt->Minute=st.wMinute; lt->Second=st.wSecond; lt->wDay=st.wDayOfWeek; lt->yDay=lt->Day-1; static int mdays[12]={31,28,31,30,31,30,31,31,30,31,30,31}; for (uint I=1;I<lt->Month && I<=ASIZE(mdays);I++) lt->yDay+=mdays[I-1]; if (lt->Month>2 && IsLeapYear(lt->Year)) lt->yDay++; st.wMilliseconds=0; FILETIME zft; SystemTimeToFileTime(&st,&zft); // Calculate the time reminder, which is the part of time smaller // than 1 second, represented in 100-nanosecond intervals. lt->Reminder=INT32TO64(lft.dwHighDateTime,lft.dwLowDateTime)- INT32TO64(zft.dwHighDateTime,zft.dwLowDateTime); #else time_t ut=GetUnix(); struct tm *t; t=localtime(&ut); lt->Year=t->tm_year+1900; lt->Month=t->tm_mon+1; lt->Day=t->tm_mday; lt->Hour=t->tm_hour; lt->Minute=t->tm_min; lt->Second=t->tm_sec; lt->Reminder=itime % 10000000; lt->wDay=t->tm_wday; lt->yDay=t->tm_yday; #endif }
void Unpack::Unpack29(bool Solid) { static unsigned char LDecode[]={0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224}; static unsigned char LBits[]= {0,0,0,0,0,0,0,0,1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5}; static int DDecode[DC]; static byte DBits[DC]; static int DBitLengthCounts[]= {4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,14,0,12}; static unsigned char SDDecode[]={0,4,8,16,32,64,128,192}; static unsigned char SDBits[]= {2,2,3, 4, 5, 6, 6, 6}; unsigned int Bits; if (DDecode[1]==0) { int Dist=0,BitLength=0,Slot=0; for (int I=0;I<ASIZE(DBitLengthCounts);I++,BitLength++) for (int J=0;J<DBitLengthCounts[I];J++,Slot++,Dist+=(1<<BitLength)) { DDecode[Slot]=Dist; DBits[Slot]=BitLength; } } FileExtracted=true; if (!Suspended) { UnpInitData(Solid); if (!UnpReadBuf30()) return; if ((!Solid || !TablesRead) && !ReadTables30()) return; } while (true) { UnpPtr&=MaxWinMask; if (Inp.InAddr>ReadBorder) { if (!UnpReadBuf30()) break; } if (((WrPtr-UnpPtr) & MaxWinMask)<260 && WrPtr!=UnpPtr) { UnpWriteBuf30(); if (WrittenFileSize>DestUnpSize) return; if (Suspended) { FileExtracted=false; return; } } if (UnpBlockType==BLOCK_PPM) { // Here speed is critical, so we do not use SafePPMDecodeChar, // because sometimes even the inline function can introduce // some additional penalty. int Ch=PPM.DecodeChar(); if (Ch==-1) // Corrupt PPM data found. { PPM.CleanUp(); // Reset possibly corrupt PPM data structures. UnpBlockType=BLOCK_LZ; // Set faster and more fail proof LZ mode. break; } if (Ch==PPMEscChar) { int NextCh=SafePPMDecodeChar(); if (NextCh==0) // End of PPM encoding. { if (!ReadTables30()) break; continue; } if (NextCh==-1) // Corrupt PPM data found. break; if (NextCh==2) // End of file in PPM mode. break; if (NextCh==3) // Read VM code. { if (!ReadVMCodePPM()) break; continue; } if (NextCh==4) // LZ inside of PPM. { unsigned int Distance=0,Length; bool Failed=false; for (int I=0;I<4 && !Failed;I++) { int Ch=SafePPMDecodeChar(); if (Ch==-1) Failed=true; else if (I==3) Length=(byte)Ch; else Distance=(Distance<<8)+(byte)Ch; } if (Failed) break; CopyString(Length+32,Distance+2); continue; } if (NextCh==5) // One byte distance match (RLE) inside of PPM. { int Length=SafePPMDecodeChar(); if (Length==-1) break; CopyString(Length+4,1); continue; } // If we are here, NextCh must be 1, what means that current byte // is equal to our 'escape' byte, so we just store it to Window. } Window[UnpPtr++]=Ch; continue; } int Number=DecodeNumber(Inp,&BlockTables.LD); if (Number<256) { Window[UnpPtr++]=(byte)Number; continue; } if (Number>=271) { int Length=LDecode[Number-=271]+3; if ((Bits=LBits[Number])>0) { Length+=Inp.getbits()>>(16-Bits); Inp.addbits(Bits); } int DistNumber=DecodeNumber(Inp,&BlockTables.DD); unsigned int Distance=DDecode[DistNumber]+1; if ((Bits=DBits[DistNumber])>0) { if (DistNumber>9) { if (Bits>4) { Distance+=((Inp.getbits()>>(20-Bits))<<4); Inp.addbits(Bits-4); } if (LowDistRepCount>0) { LowDistRepCount--; Distance+=PrevLowDist; } else { int LowDist=DecodeNumber(Inp,&BlockTables.LDD); if (LowDist==16) { LowDistRepCount=LOW_DIST_REP_COUNT-1; Distance+=PrevLowDist; } else { Distance+=LowDist; PrevLowDist=LowDist; } } } else {
static void GenArcName(wchar *ArcName,const wchar *GenerateMask,uint ArcNumber,bool &ArcNumPresent) { bool Prefix=false; if (*GenerateMask=='+') { Prefix=true; // Add the time string before the archive name. GenerateMask++; // Skip '+' in the beginning of time mask. } wchar Mask[MAX_GENERATE_MASK]; wcsncpyz(Mask,*GenerateMask!=0 ? GenerateMask:L"yyyymmddhhmmss",ASIZE(Mask)); bool QuoteMode=false,Hours=false; for (uint I=0;Mask[I]!=0;I++) { if (Mask[I]=='{' || Mask[I]=='}') { QuoteMode=(Mask[I]=='{'); continue; } if (QuoteMode) continue; int CurChar=toupperw(Mask[I]); if (CurChar=='H') Hours=true; if (Hours && CurChar=='M') { // Replace minutes with 'I'. We use 'M' both for months and minutes, // so we treat as minutes only those 'M' which are found after hours. Mask[I]='I'; } if (CurChar=='N') { uint Digits=GetDigits(ArcNumber); uint NCount=0; while (toupperw(Mask[I+NCount])=='N') NCount++; // Here we ensure that we have enough 'N' characters to fit all digits // of archive number. We'll replace them by actual number later // in this function. if (NCount<Digits) { wmemmove(Mask+I+Digits,Mask+I+NCount,wcslen(Mask+I+NCount)+1); wmemset(Mask+I,'N',Digits); } I+=Max(Digits,NCount)-1; ArcNumPresent=true; continue; } } RarTime CurTime; CurTime.SetCurrentTime(); RarLocalTime rlt; CurTime.GetLocal(&rlt); wchar Ext[NM],*Dot=GetExt(ArcName); *Ext=0; if (Dot==NULL) wcscpy(Ext,*PointToName(ArcName)==0 ? L".rar":L""); else { wcsncpyz(Ext,Dot,ASIZE(Ext)); *Dot=0; } int WeekDay=rlt.wDay==0 ? 6:rlt.wDay-1; int StartWeekDay=rlt.yDay-WeekDay; if (StartWeekDay<0) if (StartWeekDay<=-4) StartWeekDay+=IsLeapYear(rlt.Year-1) ? 366:365; else StartWeekDay=0; int CurWeek=StartWeekDay/7+1; if (StartWeekDay%7>=4) CurWeek++; char Field[10][6]; sprintf(Field[0],"%04d",rlt.Year); sprintf(Field[1],"%02d",rlt.Month); sprintf(Field[2],"%02d",rlt.Day); sprintf(Field[3],"%02d",rlt.Hour); sprintf(Field[4],"%02d",rlt.Minute); sprintf(Field[5],"%02d",rlt.Second); sprintf(Field[6],"%02d",CurWeek); sprintf(Field[7],"%d",WeekDay+1); sprintf(Field[8],"%03d",rlt.yDay+1); sprintf(Field[9],"%05d",ArcNumber); const wchar *MaskChars=L"YMDHISWAEN"; int CField[sizeof(Field)/sizeof(Field[0])]; memset(CField,0,sizeof(CField)); QuoteMode=false; for (int I=0;Mask[I]!=0;I++) { if (Mask[I]=='{' || Mask[I]=='}') { QuoteMode=(Mask[I]=='{'); continue; } if (QuoteMode) continue; const wchar *ChPtr=wcschr(MaskChars,toupperw(Mask[I])); if (ChPtr!=NULL) CField[ChPtr-MaskChars]++; } wchar DateText[MAX_GENERATE_MASK]; *DateText=0; QuoteMode=false; for (size_t I=0,J=0;Mask[I]!=0 && J<ASIZE(DateText)-1;I++) { if (Mask[I]=='{' || Mask[I]=='}') { QuoteMode=(Mask[I]=='{'); continue; } const wchar *ChPtr=wcschr(MaskChars,toupperw(Mask[I])); if (ChPtr==NULL || QuoteMode) { DateText[J]=Mask[I]; #ifdef _WIN_ALL // We do not allow ':' in Windows because of NTFS streams. // Users had problems after specifying hh:mm mask. if (DateText[J]==':') DateText[J]='_'; #endif } else { size_t FieldPos=ChPtr-MaskChars; int CharPos=(int)strlen(Field[FieldPos])-CField[FieldPos]--; if (FieldPos==1 && toupperw(Mask[I+1])=='M' && toupperw(Mask[I+2])=='M') { wcsncpyz(DateText+J,GetMonthName(rlt.Month-1),ASIZE(DateText)-J); J=wcslen(DateText); I+=2; continue; } if (CharPos<0) DateText[J]=Mask[I]; else DateText[J]=Field[FieldPos][CharPos]; } DateText[++J]=0; } if (Prefix) { wchar NewName[NM]; GetFilePath(ArcName,NewName,ASIZE(NewName)); AddEndSlash(NewName,ASIZE(NewName)); wcsncatz(NewName,DateText,ASIZE(NewName)); wcsncatz(NewName,PointToName(ArcName),ASIZE(NewName)); wcscpy(ArcName,NewName); } else wcscat(ArcName,DateText); wcscat(ArcName,Ext); }
size_t Archive::ReadHeader() { // Once we failed to decrypt an encrypted block, there is no reason to // attempt to do it further. We'll never be successful and only generate // endless errors. if (FailedHeaderDecryption) return 0; CurBlockPos=Tell(); #ifndef SFX_MODULE if (OldFormat) return(ReadOldHeader()); #endif RawRead Raw(this); bool Decrypt=Encrypted && CurBlockPos>=(int64)SFXSize+SIZEOF_MARKHEAD+SIZEOF_NEWMHD; if (Decrypt) { #if defined(SHELL_EXT) || defined(RAR_NOCRYPT) return(0); #else if (Read(HeadersSalt,SALT_SIZE)!=SALT_SIZE) { UnexpEndArcMsg(); return(0); } if (*Cmd->Password==0) { #ifdef RARDLL char PasswordA[MAXPASSWORD]; if (Cmd->Callback==NULL || Cmd->Callback(UCM_NEEDPASSWORD,Cmd->UserData,(LPARAM)PasswordA,ASIZE(PasswordA))==-1) { Close(); ErrHandler.Exit(USER_BREAK); } GetWideName(PasswordA,NULL,Cmd->Password,ASIZE(Cmd->Password)); #else if (!GetPassword(PASSWORD_ARCHIVE,FileName,FileNameW,Cmd->Password,ASIZE(Cmd->Password))) { Close(); ErrHandler.Exit(USER_BREAK); } #endif } HeadersCrypt.SetCryptKeys(Cmd->Password,HeadersSalt,false,false,NewMhd.EncryptVer>=36); Raw.SetCrypt(&HeadersCrypt); #endif } Raw.Read(SIZEOF_SHORTBLOCKHEAD); if (Raw.Size()==0) { UnexpEndArcMsg(); return(0); } Raw.Get(ShortBlock.HeadCRC); byte HeadType; Raw.Get(HeadType); ShortBlock.HeadType=(HEADER_TYPE)HeadType; Raw.Get(ShortBlock.Flags); Raw.Get(ShortBlock.HeadSize); if (ShortBlock.HeadSize<SIZEOF_SHORTBLOCKHEAD) { #ifndef SHELL_EXT Log(FileName,St(MLogFileHead),"???"); #endif BrokenFileHeader=true; ErrHandler.SetErrorCode(CRC_ERROR); return(0); } if (ShortBlock.HeadType==COMM_HEAD) { // Old style (up to RAR 2.9) comment header embedded into main // or file header. We must not read the entire ShortBlock.HeadSize here // to not break the comment processing logic later. Raw.Read(SIZEOF_COMMHEAD-SIZEOF_SHORTBLOCKHEAD); } else if (ShortBlock.HeadType==MAIN_HEAD && (ShortBlock.Flags & MHD_COMMENT)!=0) { // Old style (up to RAR 2.9) main archive comment embedded into // the main archive header found. While we can read the entire // ShortBlock.HeadSize here and remove this part of "if", it would be // waste of memory, because we'll read and process this comment data // in other function anyway and we do not need them here now. Raw.Read(SIZEOF_NEWMHD-SIZEOF_SHORTBLOCKHEAD); } else Raw.Read(ShortBlock.HeadSize-SIZEOF_SHORTBLOCKHEAD); NextBlockPos=CurBlockPos+ShortBlock.HeadSize; switch(ShortBlock.HeadType) //this is where the type of header that is found, can be executed properly { case MAIN_HEAD: *(BaseBlock *)&NewMhd=ShortBlock; Raw.Get(NewMhd.HighPosAV); Raw.Get(NewMhd.PosAV); if (NewMhd.Flags & MHD_ENCRYPTVER) Raw.Get(NewMhd.EncryptVer); break; case ENDARC_HEAD: *(BaseBlock *)&EndArcHead=ShortBlock; if (EndArcHead.Flags & EARC_DATACRC) Raw.Get(EndArcHead.ArcDataCRC); if (EndArcHead.Flags & EARC_VOLNUMBER) Raw.Get(EndArcHead.VolNumber); break; case FILE_HEAD: case NEWSUB_HEAD: { FileHeader *hd=ShortBlock.HeadType==FILE_HEAD ? &NewLhd:&SubHead; *(BaseBlock *)hd=ShortBlock; Raw.Get(hd->PackSize); Raw.Get(hd->UnpSize); Raw.Get(hd->HostOS); Raw.Get(hd->FileCRC); Raw.Get(hd->FileTime); Raw.Get(hd->UnpVer); Raw.Get(hd->Method); Raw.Get(hd->NameSize); Raw.Get(hd->FileAttr); if (hd->Flags & LHD_LARGE) { Raw.Get(hd->HighPackSize); Raw.Get(hd->HighUnpSize); } else { hd->HighPackSize=hd->HighUnpSize=0; if (hd->UnpSize==0xffffffff) { // UnpSize equal to 0xffffffff without LHD_LARGE flag indicates // that we do not know the unpacked file size and must unpack it // until we find the end of file marker in compressed data. hd->UnpSize=(uint)(INT64NDF); hd->HighUnpSize=(uint)(INT64NDF>>32); } } hd->FullPackSize=INT32TO64(hd->HighPackSize,hd->PackSize); hd->FullUnpSize=INT32TO64(hd->HighUnpSize,hd->UnpSize); char FileName[NM*4]; size_t NameSize=Min(hd->NameSize,sizeof(FileName)-1); Raw.Get((byte *)FileName,NameSize); FileName[NameSize]=0; strncpyz(hd->FileName,FileName,ASIZE(hd->FileName)); if (hd->HeadType==NEWSUB_HEAD) { // Let's calculate the size of optional data. int DataSize=hd->HeadSize-hd->NameSize-SIZEOF_NEWLHD; if (hd->Flags & LHD_SALT) DataSize-=SALT_SIZE; if (DataSize>0) { // Here we read optional additional fields for subheaders. // They are stored after the file name and before salt. hd->SubData.Alloc(DataSize); Raw.Get(&hd->SubData[0],DataSize); if (hd->CmpName(SUBHEAD_TYPE_RR)) { byte *D=&hd->SubData[8]; RecoverySectors=D[0]+((uint)D[1]<<8)+((uint)D[2]<<16)+((uint)D[3]<<24); } } } else if (hd->HeadType==FILE_HEAD) { if (hd->Flags & LHD_UNICODE) { EncodeFileName NameCoder; size_t Length=strlen(FileName); if (Length==hd->NameSize) { UtfToWide(FileName,hd->FileNameW,sizeof(hd->FileNameW)/sizeof(hd->FileNameW[0])-1); WideToChar(hd->FileNameW,hd->FileName,sizeof(hd->FileName)/sizeof(hd->FileName[0])-1); ExtToInt(hd->FileName,hd->FileName); } else { Length++; NameCoder.Decode(FileName,(byte *)FileName+Length, hd->NameSize-Length,hd->FileNameW, sizeof(hd->FileNameW)/sizeof(hd->FileNameW[0])); } if (*hd->FileNameW==0) hd->Flags &= ~LHD_UNICODE; } else *hd->FileNameW=0; #ifndef SFX_MODULE ConvertNameCase(hd->FileName); ConvertNameCase(hd->FileNameW); #endif ConvertUnknownHeader(); } if (hd->Flags & LHD_SALT) Raw.Get(hd->Salt,SALT_SIZE); hd->mtime.SetDos(hd->FileTime); hd->ctime.Reset(); hd->atime.Reset(); hd->arctime.Reset(); if (hd->Flags & LHD_EXTTIME) { ushort Flags; Raw.Get(Flags); RarTime *tbl[4]; tbl[0]=&NewLhd.mtime; tbl[1]=&NewLhd.ctime; tbl[2]=&NewLhd.atime; tbl[3]=&NewLhd.arctime; for (int I=0;I<4;I++) { RarTime *CurTime=tbl[I]; uint rmode=Flags>>(3-I)*4; if ((rmode & 8)==0) continue; if (I!=0) { uint DosTime; Raw.Get(DosTime); CurTime->SetDos(DosTime); } RarLocalTime rlt; CurTime->GetLocal(&rlt); if (rmode & 4) rlt.Second++; rlt.Reminder=0; int count=rmode&3; for (int J=0;J<count;J++) { byte CurByte; Raw.Get(CurByte); rlt.Reminder|=(((uint)CurByte)<<((J+3-count)*8)); } CurTime->SetLocal(&rlt); } } NextBlockPos+=hd->FullPackSize; bool CRCProcessedOnly=(hd->Flags & LHD_COMMENT)!=0; HeaderCRC=~Raw.GetCRC(CRCProcessedOnly)&0xffff; if (hd->HeadCRC!=HeaderCRC) { if (hd->HeadType==NEWSUB_HEAD && strlen(hd->FileName)<ASIZE(hd->FileName)-5) strcat(hd->FileName,"- ???"); BrokenFileHeader=true; ErrHandler.SetErrorCode(WARNING); // If we have a broken encrypted header, we do not need to display // the error message here, because it will be displayed for such // headers later in this function. Also such headers are unlikely // to have anything sensible in file name field, so it is useless // to display the file name. bool EncBroken=Decrypt && ShortBlock.HeadCRC!=(~Raw.GetCRC(false)&0xffff); if (!EncBroken) { #ifndef SHELL_EXT Log(Archive::FileName,St(MLogFileHead),IntNameToExt(hd->FileName)); Alarm(); #endif } } }
void ExtractStreamsNew(Archive& Arc, char* FileName, wchar* FileNameW) { if (!WinNT()) return; wchar NameW[NM]; if (FileNameW != NULL && *FileNameW != 0) wcscpy(NameW, FileNameW); else CharToWide(FileName, NameW); wchar StreamNameW[NM + 2]; if (NameW[0] != 0 && NameW[1] == 0) { wcscpy(StreamNameW, L".\\"); wcscpy(StreamNameW + 2, NameW); } else wcscpy(StreamNameW, NameW); wchar* DestName = StreamNameW + wcslen(StreamNameW); byte* SrcName = &Arc.SubHead.SubData[0]; size_t DestSize = Arc.SubHead.SubData.Size() / 2; if (wcslen(StreamNameW) + DestSize >= ASIZE(StreamNameW)) { #if !defined(SILENT) && !defined(SFX_MODULE) Log(Arc.FileName, St(MStreamBroken), FileName); #endif ErrHandler.SetErrorCode(CRC_ERROR); return; } RawToWide(SrcName, DestName, DestSize); DestName[DestSize] = 0; if (*DestName != ':') { #if !defined(SILENT) && !defined(SFX_MODULE) Log(Arc.FileName, St(MStreamBroken), FileName); #endif ErrHandler.SetErrorCode(CRC_ERROR); return; } ConvertPath(DestName + 1, DestName + 1); FindData fd; bool Found = FindFile::FastFind(FileName, FileNameW, &fd); if (fd.FileAttr & FILE_ATTRIBUTE_READONLY) SetFileAttr(FileName, FileNameW, fd.FileAttr & ~FILE_ATTRIBUTE_READONLY); char StreamName[NM]; WideToChar(StreamNameW, StreamName); File CurFile; if (CurFile.WCreate(StreamName, StreamNameW) && Arc.ReadSubData(NULL, &CurFile)) CurFile.Close(); File HostFile; if (Found && HostFile.Open(FileName, FileNameW, true, true)) SetFileTime(HostFile.GetHandle(), &fd.ftCreationTime, &fd.ftLastAccessTime, &fd.ftLastWriteTime); // Restoring original file attributes. Important if file was read only // or did not have "Archive" attribute SetFileAttr(FileName, FileNameW, fd.FileAttr); }
bool DllVolChange(RAROptions *Cmd,wchar *NextName,size_t NameSize) { bool DllVolChanged=false,DllVolAborted=false; if (Cmd->Callback!=NULL) { wchar CurName[NM]; wcscpy(CurName,NextName); if (Cmd->Callback(UCM_CHANGEVOLUMEW,Cmd->UserData,(LPARAM)NextName,RAR_VOL_ASK)==-1) DllVolAborted=true; else if (wcscmp(CurName,NextName)!=0) DllVolChanged=true; else { char NextNameA[NM]; WideToChar(NextName,NextNameA,ASIZE(NextNameA)); if (Cmd->Callback(UCM_CHANGEVOLUME,Cmd->UserData,(LPARAM)NextNameA,RAR_VOL_ASK)==-1) DllVolAborted=true; else { CharToWide(NextNameA,NextName,NameSize); if (wcscmp(CurName,NextName)!=0) DllVolChanged=true; } } } if (!DllVolChanged && Cmd->ChangeVolProc!=NULL) { char NextNameA[NM]; WideToChar(NextName,NextNameA,ASIZE(NextNameA)); // Here we preserve ESP value. It is necessary for those developers, // who still define ChangeVolProc callback as "C" type function, // even though in year 2001 we announced in unrar.dll whatsnew.txt // that it will be PASCAL type (for compatibility with Visual Basic). #if defined(_MSC_VER) #ifndef _WIN_64 __asm mov ebx,esp #endif #elif defined(_WIN_ALL) && defined(__BORLANDC__) _EBX=_ESP; #endif int RetCode=Cmd->ChangeVolProc(NextNameA,RAR_VOL_ASK); // Restore ESP after ChangeVolProc with wrongly defined calling // convention broken it. #if defined(_MSC_VER) #ifndef _WIN_64 __asm mov esp,ebx #endif #elif defined(_WIN_ALL) && defined(__BORLANDC__) _ESP=_EBX; #endif if (RetCode==0) DllVolAborted=true; else CharToWide(NextNameA,NextName,ASIZE(NextName)); } // We quit only on 'abort' condition, but not on 'name not changed'. // It is legitimate for program to return the same name when waiting // for currently non-existent volume. if (DllVolAborted) { Cmd->DllError=ERAR_EOPEN; return false; } return true; }
void CryptData::SetKey30(bool Encrypt,SecPassword *Password,const wchar *PwdW,const byte *Salt) { byte AESKey[16],AESInit[16]; bool Cached=false; for (uint I=0;I<ASIZE(KDF3Cache);I++) if (KDF3Cache[I].Pwd==*Password && (Salt==NULL && !KDF3Cache[I].SaltPresent || Salt!=NULL && KDF3Cache[I].SaltPresent && memcmp(KDF3Cache[I].Salt,Salt,SIZE_SALT30)==0)) { memcpy(AESKey,KDF3Cache[I].Key,sizeof(AESKey)); memcpy(AESInit,KDF3Cache[I].Init,sizeof(AESInit)); Cached=true; break; } if (!Cached) { byte RawPsw[2*MAXPASSWORD+SIZE_SALT30]; WideToRaw(PwdW,RawPsw,ASIZE(RawPsw)); size_t RawLength=2*wcslen(PwdW); if (Salt!=NULL) { memcpy(RawPsw+RawLength,Salt,SIZE_SALT30); RawLength+=SIZE_SALT30; } sha1_context c; sha1_init(&c); const int HashRounds=0x40000; for (int I=0;I<HashRounds;I++) { sha1_process( &c, RawPsw, RawLength, false); byte PswNum[3]; PswNum[0]=(byte)I; PswNum[1]=(byte)(I>>8); PswNum[2]=(byte)(I>>16); sha1_process( &c, PswNum, 3, false); if (I%(HashRounds/16)==0) { sha1_context tempc=c; uint32 digest[5]; sha1_done( &tempc, digest, false); AESInit[I/(HashRounds/16)]=(byte)digest[4]; } } uint32 digest[5]; sha1_done( &c, digest, false); for (int I=0;I<4;I++) for (int J=0;J<4;J++) AESKey[I*4+J]=(byte)(digest[I]>>(J*8)); KDF3Cache[KDF3CachePos].Pwd=*Password; if ((KDF3Cache[KDF3CachePos].SaltPresent=(Salt!=NULL))==true) memcpy(KDF3Cache[KDF3CachePos].Salt,Salt,SIZE_SALT30); memcpy(KDF3Cache[KDF3CachePos].Key,AESKey,sizeof(AESKey)); memcpy(KDF3Cache[KDF3CachePos].Init,AESInit,sizeof(AESInit)); KDF3CachePos=(KDF3CachePos+1)%ASIZE(KDF3Cache); cleandata(RawPsw,sizeof(RawPsw)); }
bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,wchar Command) { RAROptions *Cmd=Arc.GetRAROptions(); HEADER_TYPE HeaderType=Arc.GetHeaderType(); FileHeader *hd=HeaderType==HEAD_SERVICE ? &Arc.SubHead:&Arc.FileHead; bool SplitHeader=(HeaderType==HEAD_FILE || HeaderType==HEAD_SERVICE) && hd->SplitAfter; if (DataIO!=NULL && SplitHeader) { bool PackedHashPresent=Arc.Format==RARFMT50 || hd->UnpVer>=20 && hd->FileHash.CRC32!=0xffffffff; if (PackedHashPresent && !DataIO->PackedDataHash.Cmp(&hd->FileHash,hd->UseHashKey ? hd->HashKey:NULL)) uiMsg(UIERROR_CHECKSUMPACKED, Arc.FileName, hd->FileName); } int64 PosBeforeClose=Arc.Tell(); if (DataIO!=NULL) DataIO->ProcessedArcSize+=Arc.FileLength(); Arc.Close(); wchar NextName[NM]; wcscpy(NextName,Arc.FileName); NextVolumeName(NextName,ASIZE(NextName),!Arc.NewNumbering); #if !defined(SFX_MODULE) && !defined(RARDLL) bool RecoveryDone=false; #endif bool FailedOpen=false,OldSchemeTested=false; #if !defined(GUI) && !defined(SILENT) // In -vp mode we force the pause before next volume even if it is present // and even if we are on the hard disk. It is important when user does not // want to process partially downloaded volumes preliminary. if (Cmd->VolumePause && !uiAskNextVolume(NextName,ASIZE(NextName))) FailedOpen=true; #endif uint OpenMode = Cmd->OpenShared ? FMF_OPENSHARED : 0; if (!FailedOpen) while (!Arc.Open(NextName,OpenMode)) { // We need to open a new volume which size was not calculated // in total size before, so we cannot calculate the total progress // anymore. Let's reset the total size to zero and stop // the total progress. if (DataIO!=NULL) DataIO->TotalArcSize=0; if (!OldSchemeTested) { // Checking for new style volumes renamed by user to old style // name format. Some users did it for unknown reason. wchar AltNextName[NM]; wcscpy(AltNextName,Arc.FileName); NextVolumeName(AltNextName,ASIZE(AltNextName),true); OldSchemeTested=true; if (Arc.Open(AltNextName,OpenMode)) { wcscpy(NextName,AltNextName); break; } } #ifdef RARDLL if (!DllVolChange(Cmd,NextName,ASIZE(NextName))) { FailedOpen=true; break; } #else // !RARDLL #ifndef SFX_MODULE if (!RecoveryDone) { RecVolumesRestore(Cmd,Arc.FileName,true); RecoveryDone=true; continue; } #endif #ifndef GUI if (!Cmd->VolumePause && !IsRemovable(NextName)) { FailedOpen=true; break; } #endif #ifndef SILENT if (Cmd->AllYes || !uiAskNextVolume(NextName,ASIZE(NextName))) #endif { FailedOpen=true; break; } #endif // RARDLL } if (FailedOpen) { uiMsg(UIERROR_MISSINGVOL,NextName); Arc.Open(Arc.FileName,OpenMode); Arc.Seek(PosBeforeClose,SEEK_SET); return false; } if (Command=='T' || Command=='X' || Command=='E') mprintf(St(Command=='T' ? MTestVol:MExtrVol),Arc.FileName); Arc.CheckArc(true); #ifdef RARDLL if (!DllVolNotify(Cmd,NextName)) return false; #endif if (SplitHeader) Arc.SearchBlock(HeaderType); else Arc.ReadHeader(); if (Arc.GetHeaderType()==HEAD_FILE) { Arc.ConvertAttributes(); Arc.Seek(Arc.NextBlockPos-Arc.FileHead.PackSize,SEEK_SET); } #ifndef GUI if (ShowFileName) { mprintf(St(MExtrPoints),Arc.FileHead.FileName); if (!Cmd->DisablePercentage) mprintf(L" "); } #endif if (DataIO!=NULL) { if (HeaderType==HEAD_ENDARC) DataIO->UnpVolume=false; else { DataIO->UnpVolume=hd->SplitAfter; DataIO->SetPackedSizeToRead(hd->PackSize); } #ifdef SFX_MODULE DataIO->UnpArcSize=Arc.FileLength(); #endif // Reset the size of packed data read from current volume. It is used // to display the total progress and preceding volumes are already // compensated with ProcessedArcSize, so we need to reset this variable. DataIO->CurUnpRead=0; DataIO->PackedDataHash.Init(hd->FileHash.Type,Cmd->Threads); } return true; }
int main(int argc, char *argv[]) { #ifdef _UNIX setlocale(LC_ALL,""); #endif InitConsole(); ErrHandler.SetSignalHandlers(true); #ifdef SFX_MODULE wchar ModuleName[NM]; #ifdef _WIN_ALL GetModuleFileName(NULL,ModuleName,ASIZE(ModuleName)); #else CharToWide(argv[0],ModuleName,ASIZE(ModuleName)); #endif #endif #ifdef _WIN_ALL SetErrorMode(SEM_NOALIGNMENTFAULTEXCEPT|SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); #endif #if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SHELL_EXT) // Must be initialized, normal initialization can be skipped in case of // exception. bool ShutdownOnClose=false; #endif try { CommandData *Cmd=new CommandData; #ifdef SFX_MODULE wcscpy(Cmd->Command,L"X"); char *Switch=NULL; #ifdef _SFX_RTL_ char *CmdLine=GetCommandLineA(); if (CmdLine!=NULL && *CmdLine=='\"') CmdLine=strchr(CmdLine+1,'\"'); if (CmdLine!=NULL && (CmdLine=strpbrk(CmdLine," /"))!=NULL) { while (IsSpace(*CmdLine)) CmdLine++; Switch=CmdLine; } #else Switch=argc>1 ? argv[1]:NULL; #endif if (Switch!=NULL && Cmd->IsSwitch(Switch[0])) { int UpperCmd=etoupper(Switch[1]); switch(UpperCmd) { case 'T': case 'V': Cmd->Command[0]=UpperCmd; break; case '?': Cmd->OutHelp(RARX_SUCCESS); break; } } Cmd->AddArcName(ModuleName); Cmd->ParseDone(); #else // !SFX_MODULE Cmd->ParseCommandLine(true,argc,argv); if (!Cmd->ConfigDisabled) { Cmd->ReadConfig(); Cmd->ParseEnvVar(); } Cmd->ParseCommandLine(false,argc,argv); #endif #if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SHELL_EXT) ShutdownOnClose=Cmd->Shutdown; #endif InitConsoleOptions(Cmd->MsgStream,Cmd->Sound); InitLogOptions(Cmd->LogName,Cmd->ErrlogCharset); ErrHandler.SetSilent(Cmd->AllYes || Cmd->MsgStream==MSG_NULL); ErrHandler.SetShutdown(Cmd->Shutdown); Cmd->OutTitle(); Cmd->ProcessCommand(); delete Cmd; } catch (RAR_EXIT ErrCode) { ErrHandler.SetErrorCode(ErrCode); } catch (std::bad_alloc) { ErrHandler.MemoryErrorMsg(); ErrHandler.SetErrorCode(RARX_MEMORY); } catch (...) { ErrHandler.SetErrorCode(RARX_FATAL); } #if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SHELL_EXT) if (ShutdownOnClose) Shutdown(); #endif return ErrHandler.GetErrorCode(); }
bool CreateReparsePoint(CommandData *Cmd,const wchar *Name,FileHeader *hd) { static bool PrivSet=false; if (!PrivSet) { SetPrivilege(SE_RESTORE_NAME); // Not sure if we really need it, but let's request anyway. SetPrivilege(SE_CREATE_SYMBOLIC_LINK_NAME); PrivSet=true; } const DWORD BufSize=sizeof(REPARSE_DATA_BUFFER)+2*NM+1024; Array<byte> Buf(BufSize); REPARSE_DATA_BUFFER *rdb=(REPARSE_DATA_BUFFER *)&Buf[0]; wchar SubstName[NM]; wcsncpyz(SubstName,hd->RedirName,ASIZE(SubstName)); size_t SubstLength=unrar_wcslen(SubstName); wchar PrintName[NM],*PrintNameSrc=SubstName,*PrintNameDst=PrintName; bool WinPrefix=unrar_wcsncmp(PrintNameSrc,L"\\??\\",4)==0; if (WinPrefix) PrintNameSrc+=4; if (WinPrefix && unrar_wcsncmp(PrintNameSrc,L"UNC\\",4)==0) { *(PrintNameDst++)='\\'; // Insert second \ in beginning of share name. PrintNameSrc+=3; } unrar_wcscpy(PrintNameDst,PrintNameSrc); size_t PrintLength=unrar_wcslen(PrintName); bool AbsPath=WinPrefix; // IsFullPath is not really needed here, AbsPath check is enough. // We added it just for extra safety, in case some Windows version would // allow to create absolute targets with SYMLINK_FLAG_RELATIVE. if (!Cmd->AbsoluteLinks && (AbsPath || IsFullPath(hd->RedirName) || !IsRelativeSymlinkSafe(hd->FileName,hd->RedirName))) return false; #ifndef NOFILECREATE CreatePath(Name,true); // 'DirTarget' check is important for Unix symlinks to directories. // Unix symlinks do not have their own 'directory' attribute. if (hd->Dir || hd->DirTarget) { if (!CreateDirectory(Name,NULL)) return false; } else { HANDLE hFile=CreateFile(Name,GENERIC_WRITE,0,NULL,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL); if (hFile == INVALID_HANDLE_VALUE) return false; CloseHandle(hFile); } #endif if (hd->RedirType==FSREDIR_JUNCTION) { rdb->ReparseTag=IO_REPARSE_TAG_MOUNT_POINT; rdb->ReparseDataLength=USHORT( sizeof(rdb->MountPointReparseBuffer.SubstituteNameOffset)+ sizeof(rdb->MountPointReparseBuffer.SubstituteNameLength)+ sizeof(rdb->MountPointReparseBuffer.PrintNameOffset)+ sizeof(rdb->MountPointReparseBuffer.PrintNameLength)+ (SubstLength+1)*sizeof(WCHAR)+(PrintLength+1)*sizeof(WCHAR)); rdb->Reserved=0; rdb->MountPointReparseBuffer.SubstituteNameOffset=0; rdb->MountPointReparseBuffer.SubstituteNameLength=USHORT(SubstLength*sizeof(WCHAR)); unrar_wcscpy(rdb->MountPointReparseBuffer.PathBuffer,SubstName); rdb->MountPointReparseBuffer.PrintNameOffset=USHORT((SubstLength+1)*sizeof(WCHAR)); rdb->MountPointReparseBuffer.PrintNameLength=USHORT(PrintLength*sizeof(WCHAR)); unrar_wcscpy(rdb->MountPointReparseBuffer.PathBuffer+SubstLength+1,PrintName); } else if (hd->RedirType==FSREDIR_WINSYMLINK || hd->RedirType==FSREDIR_UNIXSYMLINK) { rdb->ReparseTag=IO_REPARSE_TAG_SYMLINK; rdb->ReparseDataLength=USHORT( sizeof(rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset)+ sizeof(rdb->SymbolicLinkReparseBuffer.SubstituteNameLength)+ sizeof(rdb->SymbolicLinkReparseBuffer.PrintNameOffset)+ sizeof(rdb->SymbolicLinkReparseBuffer.PrintNameLength)+ sizeof(rdb->SymbolicLinkReparseBuffer.Flags)+ (SubstLength+1)*sizeof(WCHAR)+(PrintLength+1)*sizeof(WCHAR)); rdb->Reserved=0; rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset=0; rdb->SymbolicLinkReparseBuffer.SubstituteNameLength=USHORT(SubstLength*sizeof(WCHAR)); unrar_wcscpy(rdb->SymbolicLinkReparseBuffer.PathBuffer,SubstName); rdb->SymbolicLinkReparseBuffer.PrintNameOffset=USHORT((SubstLength+1)*sizeof(WCHAR)); rdb->SymbolicLinkReparseBuffer.PrintNameLength=USHORT(PrintLength*sizeof(WCHAR)); unrar_wcscpy(rdb->SymbolicLinkReparseBuffer.PathBuffer+SubstLength+1,PrintName); rdb->SymbolicLinkReparseBuffer.Flags=AbsPath ? 0:SYMLINK_FLAG_RELATIVE; } else return false; HANDLE hFile=CreateFile(Name,GENERIC_READ|GENERIC_WRITE,0,NULL, OPEN_EXISTING,FILE_FLAG_OPEN_REPARSE_POINT| FILE_FLAG_BACKUP_SEMANTICS,NULL); if (hFile==INVALID_HANDLE_VALUE) return false; DWORD Returned; if (!DeviceIoControl(hFile,FSCTL_SET_REPARSE_POINT,rdb, FIELD_OFFSET(REPARSE_DATA_BUFFER,GenericReparseBuffer)+ rdb->ReparseDataLength,NULL,0,&Returned,NULL)) { CloseHandle(hFile); uiMsg(UIERROR_SLINKCREATE,UINULL,Name); if (GetLastError()==ERROR_PRIVILEGE_NOT_HELD) uiMsg(UIERROR_NEEDADMIN); ErrHandler.SysErrMsg(); ErrHandler.SetErrorCode(RARX_CREATE); if (hd->Dir) RemoveDirectory(Name); else DeleteFile(Name); return false; } File LinkFile; LinkFile.SetHandle(hFile); LinkFile.SetOpenFileTime( Cmd->xmtime==EXTTIME_NONE ? NULL:&hd->mtime, Cmd->xctime==EXTTIME_NONE ? NULL:&hd->ctime, Cmd->xatime==EXTTIME_NONE ? NULL:&hd->atime); LinkFile.Close(); #ifndef NOFILECREATE if (!Cmd->IgnoreGeneralAttr) SetFileAttr(Name,hd->FileAttr); #endif return true; }
bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,char Command) { RAROptions *Cmd=Arc.GetRAROptions(); int HeaderType=Arc.GetHeaderType(); FileHeader *hd=HeaderType==NEWSUB_HEAD ? &Arc.SubHead:&Arc.NewLhd; bool SplitHeader=(HeaderType==FILE_HEAD || HeaderType==NEWSUB_HEAD) && (hd->Flags & LHD_SPLIT_AFTER)!=0; if (DataIO!=NULL && SplitHeader && hd->UnpVer>=20 && hd->FileCRC!=0xffffffff && DataIO->PackedCRC!=~hd->FileCRC) { Log(Arc.FileName,St(MDataBadCRC),hd->FileName,Arc.FileName); } int64 PosBeforeClose=Arc.Tell(); if (DataIO!=NULL) DataIO->ProcessedArcSize+=Arc.FileLength(); Arc.Close(); char NextName[NM]; wchar NextNameW[NM]; strcpy(NextName,Arc.FileName); strcpyw(NextNameW,Arc.FileNameW); NextVolumeName(NextName,NextNameW,ASIZE(NextName),(Arc.NewMhd.Flags & MHD_NEWNUMBERING)==0 || Arc.OldFormat); #if !defined(SFX_MODULE) && !defined(RARDLL) bool RecoveryDone=false; #endif bool FailedOpen=false,OldSchemeTested=false; while (!Arc.Open(NextName,NextNameW)) { // We need to open a new volume which size was not calculated // in total size before, so we cannot calculate the total progress // anymore. Let's reset the total size to zero and stop // the total progress. if (DataIO!=NULL) DataIO->TotalArcSize=0; if (!OldSchemeTested) { // Checking for new style volumes renamed by user to old style // name format. Some users did it for unknown reason. char AltNextName[NM]; wchar AltNextNameW[NM]; strcpy(AltNextName,Arc.FileName); strcpyw(AltNextNameW,Arc.FileNameW); NextVolumeName(AltNextName,AltNextNameW,ASIZE(AltNextName),true); OldSchemeTested=true; if (Arc.Open(AltNextName,AltNextNameW)) { strcpy(NextName,AltNextName); strcpyw(NextNameW,AltNextNameW); break; } } #ifdef RARDLL if (Cmd->Callback==NULL && Cmd->ChangeVolProc==NULL || Cmd->Callback!=NULL && Cmd->Callback(UCM_CHANGEVOLUME,Cmd->UserData,(LPARAM)NextName,RAR_VOL_ASK)==-1) { Cmd->DllError=ERAR_EOPEN; FailedOpen=true; break; } if (Cmd->ChangeVolProc!=NULL) { // Here we preserve ESP value. It is necessary for those developers, // who still define ChangeVolProc callback as "C" type function, // even though in year 2001 we announced in unrar.dll whatsnew.txt // that it will be PASCAL type (for compatibility with Visual Basic). #if defined(_MSC_VER) #ifndef _M_X64 __asm mov ebx,esp #endif #elif defined(_WIN_32) && defined(__BORLANDC__) _EBX=_ESP; #endif int RetCode=Cmd->ChangeVolProc(NextName,RAR_VOL_ASK); // Restore ESP after ChangeVolProc with wrongly defined calling // convention broken it. #if defined(_MSC_VER) #ifndef _M_X64 __asm mov esp,ebx #endif #elif defined(_WIN_32) && defined(__BORLANDC__) _ESP=_EBX; #endif if (RetCode==0) { Cmd->DllError=ERAR_EOPEN; FailedOpen=true; break; } } #else // RARDLL #if !defined(SFX_MODULE) && !defined(_WIN_CE) if (!RecoveryDone) { RecVolumes RecVol; RecVol.Restore(Cmd,Arc.FileName,Arc.FileNameW,true); RecoveryDone=true; continue; } #endif #ifndef GUI if (!Cmd->VolumePause && !IsRemovable(NextName)) { FailedOpen=true; break; } #endif #ifndef SILENT if (Cmd->AllYes || !AskNextVol(NextName)) #endif { FailedOpen=true; break; } #endif // RARDLL *NextNameW=0; } if (FailedOpen) { #if !defined(SILENT) && !defined(_WIN_CE) Log(Arc.FileName,St(MAbsNextVol),NextName); #endif Arc.Open(Arc.FileName,Arc.FileNameW); Arc.Seek(PosBeforeClose,SEEK_SET); return(false); } Arc.CheckArc(true); #ifdef RARDLL if (Cmd->Callback!=NULL && Cmd->Callback(UCM_CHANGEVOLUME,Cmd->UserData,(LPARAM)NextName,RAR_VOL_NOTIFY)==-1) return(false); if (Cmd->ChangeVolProc!=NULL) { #if defined(_WIN_32) && !defined(_MSC_VER) && !defined(__MINGW32__) _EBX=_ESP; #endif int RetCode=Cmd->ChangeVolProc(NextName,RAR_VOL_NOTIFY); #if defined(_WIN_32) && !defined(_MSC_VER) && !defined(__MINGW32__) _ESP=_EBX; #endif if (RetCode==0) return(false); } #endif if (Command=='T' || Command=='X' || Command=='E') mprintf(St(Command=='T' ? MTestVol:MExtrVol),Arc.FileName); if (SplitHeader) Arc.SearchBlock(HeaderType); else Arc.ReadHeader(); if (Arc.GetHeaderType()==FILE_HEAD) { Arc.ConvertAttributes(); Arc.Seek(Arc.NextBlockPos-Arc.NewLhd.FullPackSize,SEEK_SET); } #ifndef GUI if (ShowFileName) { char OutName[NM]; IntToExt(Arc.NewLhd.FileName,OutName); #ifdef UNICODE_SUPPORTED bool WideName=(Arc.NewLhd.Flags & LHD_UNICODE) && UnicodeEnabled(); if (WideName) { wchar NameW[NM]; ConvertPath(Arc.NewLhd.FileNameW,NameW); char Name[NM]; if (WideToChar(NameW,Name) && IsNameUsable(Name)) strcpy(OutName,Name); } #endif mprintf(St(MExtrPoints),OutName); if (!Cmd->DisablePercentage) mprintf(" "); } #endif if (DataIO!=NULL) { if (HeaderType==ENDARC_HEAD) DataIO->UnpVolume=false; else { DataIO->UnpVolume=(hd->Flags & LHD_SPLIT_AFTER)!=0; DataIO->SetPackedSizeToRead(hd->FullPackSize); } #ifdef SFX_MODULE DataIO->UnpArcSize=Arc.FileLength(); #endif // Reset the size of packed data read from current volume. It is used // to display the total progress and preceding volumes are already // compensated with ProcessedArcSize, so we need to reset this variable. DataIO->CurUnpRead=0; DataIO->PackedCRC=0xffffffff; // DataIO->SetFiles(&Arc,NULL); } return(true); }
void set_frame_menubar (struct frame *f, bool first_time, bool deep_p) { HMENU menubar_widget = f->output_data.w32->menubar_widget; Lisp_Object items; widget_value *wv, *first_wv, *prev_wv = 0; int i, last_i; int *submenu_start, *submenu_end; int *submenu_top_level_items, *submenu_n_panes; /* We must not change the menubar when actually in use. */ if (f->output_data.w32->menubar_active) return; XSETFRAME (Vmenu_updating_frame, f); if (! menubar_widget) deep_p = true; if (deep_p) { /* Make a widget-value tree representing the entire menu trees. */ struct buffer *prev = current_buffer; Lisp_Object buffer; ptrdiff_t specpdl_count = SPECPDL_INDEX (); int previous_menu_items_used = f->menu_bar_items_used; Lisp_Object *previous_items = (Lisp_Object *) alloca (previous_menu_items_used * word_size); /* If we are making a new widget, its contents are empty, do always reinitialize them. */ if (! menubar_widget) previous_menu_items_used = 0; buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->contents; specbind (Qinhibit_quit, Qt); /* Don't let the debugger step into this code because it is not reentrant. */ specbind (Qdebug_on_next_call, Qnil); record_unwind_save_match_data (); if (NILP (Voverriding_local_map_menu_flag)) { specbind (Qoverriding_terminal_local_map, Qnil); specbind (Qoverriding_local_map, Qnil); } set_buffer_internal_1 (XBUFFER (buffer)); /* Run the hooks. */ safe_run_hooks (Qactivate_menubar_hook); safe_run_hooks (Qmenu_bar_update_hook); fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f))); items = FRAME_MENU_BAR_ITEMS (f); /* Save the frame's previous menu bar contents data. */ if (previous_menu_items_used) memcpy (previous_items, XVECTOR (f->menu_bar_vector)->contents, previous_menu_items_used * word_size); /* Fill in menu_items with the current menu bar contents. This can evaluate Lisp code. */ save_menu_items (); menu_items = f->menu_bar_vector; menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0; submenu_start = (int *) alloca (ASIZE (items) * sizeof (int)); submenu_end = (int *) alloca (ASIZE (items) * sizeof (int)); submenu_n_panes = (int *) alloca (ASIZE (items) * sizeof (int)); submenu_top_level_items = (int *) alloca (ASIZE (items) * sizeof (int)); init_menu_items (); for (i = 0; i < ASIZE (items); i += 4) { Lisp_Object key, string, maps; last_i = i; key = AREF (items, i); string = AREF (items, i + 1); maps = AREF (items, i + 2); if (NILP (string)) break; submenu_start[i] = menu_items_used; menu_items_n_panes = 0; submenu_top_level_items[i] = parse_single_submenu (key, string, maps); submenu_n_panes[i] = menu_items_n_panes; submenu_end[i] = menu_items_used; } finish_menu_items (); /* Convert menu_items into widget_value trees to display the menu. This cannot evaluate Lisp code. */ wv = make_widget_value ("menubar", NULL, true, Qnil); wv->button_type = BUTTON_TYPE_NONE; first_wv = wv; for (i = 0; i < last_i; i += 4) { menu_items_n_panes = submenu_n_panes[i]; wv = digest_single_submenu (submenu_start[i], submenu_end[i], submenu_top_level_items[i]); if (prev_wv) prev_wv->next = wv; else first_wv->contents = wv; /* Don't set wv->name here; GC during the loop might relocate it. */ wv->enabled = true; wv->button_type = BUTTON_TYPE_NONE; prev_wv = wv; } set_buffer_internal_1 (prev); /* If there has been no change in the Lisp-level contents of the menu bar, skip redisplaying it. Just exit. */ for (i = 0; i < previous_menu_items_used; i++) if (menu_items_used == i || (!EQ (previous_items[i], AREF (menu_items, i)))) break; if (i == menu_items_used && i == previous_menu_items_used && i != 0) { free_menubar_widget_value_tree (first_wv); discard_menu_items (); unbind_to (specpdl_count, Qnil); return; } fset_menu_bar_vector (f, menu_items); f->menu_bar_items_used = menu_items_used; /* This undoes save_menu_items. */ unbind_to (specpdl_count, Qnil); /* Now GC cannot happen during the lifetime of the widget_value, so it's safe to store data from a Lisp_String, as long as local copies are made when the actual menu is created. Windows takes care of this for normal string items, but not for owner-drawn items or additional item-info. */ wv = first_wv->contents; for (i = 0; i < ASIZE (items); i += 4) { Lisp_Object string; string = AREF (items, i + 1); if (NILP (string)) break; wv->name = SSDATA (string); update_submenu_strings (wv->contents); wv = wv->next; } } else { /* Make a widget-value tree containing just the top level menu bar strings. */ wv = make_widget_value ("menubar", NULL, true, Qnil); wv->button_type = BUTTON_TYPE_NONE; first_wv = wv; items = FRAME_MENU_BAR_ITEMS (f); for (i = 0; i < ASIZE (items); i += 4) { Lisp_Object string; string = AREF (items, i + 1); if (NILP (string)) break; wv = make_widget_value (SSDATA (string), NULL, true, Qnil); wv->button_type = BUTTON_TYPE_NONE; /* This prevents lwlib from assuming this menu item is really supposed to be empty. */ /* The EMACS_INT cast avoids a warning. This value just has to be different from small integers. */ wv->call_data = (void *) (EMACS_INT) (-1); if (prev_wv) prev_wv->next = wv; else first_wv->contents = wv; prev_wv = wv; } /* Forget what we thought we knew about what is in the detailed contents of the menu bar menus. Changing the top level always destroys the contents. */ f->menu_bar_items_used = 0; } /* Create or update the menu bar widget. */ block_input (); if (menubar_widget) { /* Empty current menubar, rather than creating a fresh one. */ while (DeleteMenu (menubar_widget, 0, MF_BYPOSITION)) ; } else { menubar_widget = CreateMenu (); } fill_in_menu (menubar_widget, first_wv->contents); free_menubar_widget_value_tree (first_wv); { HMENU old_widget = f->output_data.w32->menubar_widget; f->output_data.w32->menubar_widget = menubar_widget; SetMenu (FRAME_W32_WINDOW (f), f->output_data.w32->menubar_widget); /* Causes flicker when menu bar is updated DrawMenuBar (FRAME_W32_WINDOW (f)); */ /* Force the window size to be recomputed so that the frame's text area remains the same, if menubar has just been created. */ if (old_widget == NULL) { windows_or_buffers_changed = 23; adjust_frame_size (f, -1, -1, 2, false, Qmenu_bar_lines); } } unblock_input (); }