Coverage Report

Created: 2025-01-09 06:48

/src/unrar/cmddata.cpp
Line
Count
Source (jump to first uncovered line)
1
#include "rar.hpp"
2
3
#include "cmdfilter.cpp"
4
#include "cmdmix.cpp"
5
6
CommandData::CommandData()
7
11.9k
{
8
11.9k
  Init();
9
11.9k
}
10
11
12
void CommandData::Init()
13
11.9k
{
14
11.9k
  RAROptions::Init();
15
16
11.9k
  Command.clear();
17
11.9k
  ArcName.clear();
18
11.9k
  ExtrPath.clear();
19
11.9k
  TempPath.clear();
20
11.9k
  SFXModule.clear();
21
11.9k
  CommentFile.clear();
22
11.9k
  ArcPath.clear();
23
11.9k
  ExclArcPath.clear();
24
11.9k
  LogName.clear();
25
11.9k
  EmailTo.clear();
26
11.9k
  UseStdin.clear();
27
28
11.9k
  FileLists=false;
29
11.9k
  NoMoreSwitches=false;
30
31
11.9k
  ListMode=RCLM_AUTO;
32
33
11.9k
  BareOutput=false;
34
35
36
11.9k
  FileArgs.Reset();
37
11.9k
  ExclArgs.Reset();
38
11.9k
  InclArgs.Reset();
39
11.9k
  ArcNames.Reset();
40
11.9k
  StoreArgs.Reset();
41
#ifdef PROPAGATE_MOTW
42
  MotwList.Reset();
43
#endif
44
11.9k
  Password.Clean();
45
11.9k
  NextVolSizes.clear();
46
11.9k
#ifdef RARDLL
47
11.9k
  DllDestName.clear();
48
11.9k
#endif
49
11.9k
}
50
51
52
#if !defined(SFX_MODULE)
53
void CommandData::ParseCommandLine(bool Preprocess,int argc, char *argv[])
54
0
{
55
0
  Command.clear();
56
0
  NoMoreSwitches=false;
57
#ifdef CUSTOM_CMDLINE_PARSER
58
  // In Windows we may prefer to implement our own command line parser
59
  // to avoid replacing \" by " in standard parser. Such replacing corrupts
60
  // destination paths like "dest path\" in extraction commands.
61
  std::wstring CmdLine=GetCommandLine();
62
63
  std::wstring Param;
64
  std::wstring::size_type Pos=0;
65
66
  for (bool FirstParam=true;;FirstParam=false)
67
  {
68
    if (!GetCmdParam(CmdLine,Pos,Param))
69
      break;
70
    if (!FirstParam) // First parameter is the executable name.
71
      if (Preprocess)
72
        PreprocessArg(Param.data());
73
      else
74
        ParseArg(Param.data());
75
  }
76
#else
77
0
  for (int I=1;I<argc;I++)
78
0
  {
79
0
    std::wstring Arg;
80
0
    CharToWide(argv[I],Arg);
81
0
    if (Preprocess)
82
0
      PreprocessArg(Arg.data());
83
0
    else
84
0
      ParseArg(Arg.data());
85
0
  }
86
0
#endif
87
0
  if (!Preprocess)
88
0
    ParseDone();
89
0
}
90
#endif
91
92
93
#if !defined(SFX_MODULE)
94
void CommandData::ParseArg(const wchar *Arg)
95
23.9k
{
96
23.9k
  if (IsSwitch(*Arg) && !NoMoreSwitches)
97
11.9k
    if (Arg[1]=='-' && Arg[2]==0)
98
0
      NoMoreSwitches=true;
99
11.9k
    else
100
11.9k
      ProcessSwitch(Arg+1);
101
11.9k
  else
102
11.9k
    if (Command.empty())
103
11.9k
    {
104
11.9k
      Command=Arg;
105
106
107
11.9k
      Command[0]=toupperw(Command[0]);
108
      // 'I' and 'S' commands can contain case sensitive strings after
109
      // the first character, so we must not modify their case.
110
      // 'S' can contain SFX name, which case is important in Unix.
111
11.9k
      if (Command[0]!='I' && Command[0]!='S')
112
11.9k
        wcsupper(Command);
113
11.9k
      if (Command[0]=='P') // Enforce -idq for print command.
114
0
      {
115
0
        MsgStream=MSG_ERRONLY;
116
0
        SetConsoleMsgStream(MSG_ERRONLY);
117
0
      }
118
11.9k
    }
119
0
    else
120
0
      if (ArcName.empty())
121
0
        ArcName=Arg;
122
0
      else
123
0
      {
124
        // Check if last character is the path separator.
125
0
        size_t Length=wcslen(Arg);
126
0
        wchar EndChar=Length==0 ? 0:Arg[Length-1];
127
        // Check if trailing path separator like path\ is present.
128
0
        bool FolderArg=IsDriveDiv(EndChar) || IsPathDiv(EndChar);
129
130
        // 2024.01.05: We were asked to support exotic d:. and d:.. paths.
131
0
        if (IsDriveLetter(Arg) && Arg[2]=='.' && (Arg[3]==0 || Arg[3]=='.' && Arg[4]==0))
132
0
          FolderArg=true;
133
134
        // 2024.01.06: FindFile::FastFind check below fails in Windows 10 if
135
        // "." or ".." points at disk root. So we enforce it for "." and ".."
136
        // optionally preceded with some path like "..\..".
137
0
        size_t L=Length;
138
0
        if (L>0 && Arg[L-1]=='.' && (L==1 || L>=2 && (IsPathDiv(Arg[L-2]) ||
139
0
            Arg[L-2]=='.' && (L==2 || L>=3 && IsPathDiv(Arg[L-3])))))
140
0
          FolderArg=true;
141
142
0
        wchar CmdChar=toupperw(Command[0]);
143
0
        bool Add=wcschr(L"AFUM",CmdChar)!=NULL;
144
0
        bool Extract=CmdChar=='X' || CmdChar=='E';
145
0
        bool Repair=CmdChar=='R' && Command[1]==0;
146
0
        if (FolderArg && !Add)
147
0
          ExtrPath=Arg;
148
0
        else
149
0
          if ((Add || CmdChar=='T') && (*Arg!='@' || ListMode==RCLM_REJECT_LISTS))
150
0
            FileArgs.AddString(Arg);
151
0
          else
152
0
          {
153
0
            FindData FileData;
154
0
            bool Found=FindFile::FastFind(Arg,&FileData);
155
0
            if ((!Found || ListMode==RCLM_ACCEPT_LISTS) && 
156
0
                ListMode!=RCLM_REJECT_LISTS && *Arg=='@' && !IsWildcard(Arg+1))
157
0
            {
158
0
              FileLists=true;
159
160
0
              ReadTextFile(Arg+1,&FileArgs,false,true,FilelistCharset,true,true,true);
161
162
0
            }
163
0
            else // We use 'destpath\' when extracting and reparing.
164
0
              if (Found && FileData.IsDir && (Extract || Repair) && ExtrPath.empty())
165
0
              {
166
0
                ExtrPath=Arg;
167
0
                AddEndSlash(ExtrPath);
168
0
              }
169
0
              else
170
0
                FileArgs.AddString(Arg);
171
0
          }
172
0
      }
173
23.9k
}
174
#endif
175
176
177
void CommandData::ParseDone()
178
11.9k
{
179
11.9k
  if (FileArgs.ItemsCount()==0 && !FileLists)
180
11.9k
    FileArgs.AddString(MASKALL);
181
11.9k
  wchar CmdChar=toupperw(Command[0]);
182
11.9k
  bool Extract=CmdChar=='X' || CmdChar=='E' || CmdChar=='P';
183
11.9k
  if (Test && Extract)
184
0
    Test=false;        // Switch '-t' is senseless for 'X', 'E', 'P' commands.
185
186
  // Suppress the copyright message and final end of line for 'lb' and 'vb'.
187
11.9k
  if ((CmdChar=='L' || CmdChar=='V') && Command[1]=='B')
188
0
    BareOutput=true;
189
11.9k
}
190
191
192
#if !defined(SFX_MODULE)
193
void CommandData::ParseEnvVar()
194
0
{
195
0
  char *EnvVar=getenv("RARINISWITCHES");
196
0
  if (EnvVar!=NULL)
197
0
  {
198
0
    std::wstring EnvStr;
199
0
    CharToWide(EnvVar,EnvStr);
200
0
    ProcessSwitchesString(EnvStr);
201
0
  }
202
0
}
203
#endif
204
205
206
207
#if !defined(SFX_MODULE)
208
// Preprocess those parameters, which must be processed before the rest of
209
// command line.
210
void CommandData::PreprocessArg(const wchar *Arg)
211
0
{
212
0
  if (IsSwitch(Arg[0]) && !NoMoreSwitches)
213
0
  {
214
0
    Arg++;
215
0
    if (Arg[0]=='-' && Arg[1]==0) // Switch "--".
216
0
      NoMoreSwitches=true;
217
0
    if (wcsicomp(Arg,L"cfg-")==0)
218
0
      ProcessSwitch(Arg);
219
0
    if (wcsnicomp(Arg,L"ilog",4)==0)
220
0
    {
221
      // Ensure that correct log file name is already set
222
      // if we need to report an error when processing the command line.
223
0
      ProcessSwitch(Arg);
224
0
      InitLogOptions(LogName,ErrlogCharset);
225
0
    }
226
0
    if (wcsnicomp(Arg,L"sc",2)==0)
227
0
    {
228
      // Process -sc before reading any file lists.
229
0
      ProcessSwitch(Arg);
230
0
      if (!LogName.empty())
231
0
        InitLogOptions(LogName,ErrlogCharset);
232
0
    }
233
0
  }
234
0
  else
235
0
    if (Command.empty())
236
0
      Command=Arg; // Need for rar.ini.
237
0
}
238
#endif
239
240
241
#if !defined(SFX_MODULE)
242
void CommandData::ReadConfig()
243
0
{
244
0
  StringList List;
245
0
  if (ReadTextFile(DefConfigName,&List,true))
246
0
  {
247
0
    wchar *Str;
248
0
    while ((Str=List.GetString())!=NULL)
249
0
    {
250
0
      while (IsSpace(*Str))
251
0
        Str++;
252
0
      if (wcsnicomp(Str,L"switches=",9)==0)
253
0
        ProcessSwitchesString(Str+9);
254
0
      if (!Command.empty())
255
0
      {
256
0
        wchar Cmd[16];
257
0
        wcsncpyz(Cmd,Command.c_str(),ASIZE(Cmd));
258
0
        wchar C0=toupperw(Cmd[0]);
259
0
        wchar C1=toupperw(Cmd[1]);
260
0
        if (C0=='I' || C0=='L' || C0=='M' || C0=='S' || C0=='V')
261
0
          Cmd[1]=0;
262
0
        if (C0=='R' && (C1=='R' || C1=='V'))
263
0
          Cmd[2]=0;
264
0
        wchar SwName[16+ASIZE(Cmd)];
265
0
        swprintf(SwName,ASIZE(SwName),L"switches_%ls=",Cmd);
266
0
        size_t Length=wcslen(SwName);
267
0
        if (wcsnicomp(Str,SwName,Length)==0)
268
0
          ProcessSwitchesString(Str+Length);
269
0
      }
270
0
    }
271
0
  }
272
0
}
273
#endif
274
275
276
#if !defined(SFX_MODULE)
277
void CommandData::ProcessSwitchesString(const std::wstring &Str)
278
0
{
279
0
  std::wstring Par;
280
0
  std::wstring::size_type Pos=0;
281
0
  while (GetCmdParam(Str,Pos,Par))
282
0
  {
283
0
    if (IsSwitch(Par[0]))
284
0
      ProcessSwitch(&Par[1]);
285
0
    else
286
0
    {
287
0
      mprintf(St(MSwSyntaxError),Par.c_str());
288
0
      ErrHandler.Exit(RARX_USERERROR);
289
0
    }
290
0
  }
291
0
}
292
#endif
293
294
295
#if !defined(SFX_MODULE)
296
void CommandData::ProcessSwitch(const wchar *Switch)
297
11.9k
{
298
299
11.9k
  if (LargePageAlloc::ProcessSwitch(this,Switch))
300
0
    return;
301
302
11.9k
  switch(toupperw(Switch[0]))
303
11.9k
  {
304
0
    case '@':
305
0
      ListMode=Switch[1]=='+' ? RCLM_ACCEPT_LISTS:RCLM_REJECT_LISTS;
306
0
      break;
307
0
    case 'A':
308
0
      switch(toupperw(Switch[1]))
309
0
      {
310
0
        case 'C':
311
0
          ClearArc=true;
312
0
          break;
313
0
        case 'D':
314
0
          if (Switch[2]==0)
315
0
            AppendArcNameToPath=APPENDARCNAME_DESTPATH;
316
0
          else
317
0
            if (Switch[2]=='1')
318
0
              AppendArcNameToPath=APPENDARCNAME_OWNSUBDIR;
319
0
            else
320
0
              if (Switch[2]=='2')
321
0
                AppendArcNameToPath=APPENDARCNAME_OWNDIR;
322
0
          break;
323
0
#ifndef SFX_MODULE
324
0
        case 'G':
325
0
          if (Switch[2]=='-' && Switch[3]==0)
326
0
            GenerateArcName=0;
327
0
          else
328
0
            if (toupperw(Switch[2])=='F')
329
0
              wcsncpyz(DefGenerateMask,Switch+3,ASIZE(DefGenerateMask));
330
0
            else
331
0
            {
332
0
              GenerateArcName=true;
333
0
              wcsncpyz(GenerateMask,Switch+2,ASIZE(GenerateMask));
334
0
            }
335
0
          break;
336
0
#endif
337
0
        case 'I':
338
0
          IgnoreGeneralAttr=true;
339
0
          break;
340
0
        case 'M':
341
0
          switch(toupperw(Switch[2]))
342
0
          {
343
0
            case 0:
344
0
            case 'S':
345
0
              ArcMetadata=ARCMETA_SAVE;
346
0
              break;
347
0
            case 'R':
348
0
              ArcMetadata=ARCMETA_RESTORE;
349
0
              break;
350
0
            default:
351
0
              BadSwitch(Switch);
352
0
              break;
353
0
          }
354
0
          break;
355
0
        case 'O':
356
0
          AddArcOnly=true;
357
0
          break;
358
0
        case 'P':
359
          // Convert slashes here than before every comparison.
360
0
          SlashToNative(Switch+2,ArcPath);
361
0
          break;
362
0
        case 'S':
363
0
          SyncFiles=true;
364
0
          break;
365
0
        default:
366
0
          BadSwitch(Switch);
367
0
          break;
368
0
      }
369
0
      break;
370
0
    case 'C':
371
0
      if (Switch[2]!=0)
372
0
      {
373
0
          if (wcsicomp(Switch+1,L"FG-")==0)
374
0
            ConfigDisabled=true;
375
0
          else
376
0
            BadSwitch(Switch);
377
0
      }
378
0
      else
379
0
        switch(toupperw(Switch[1]))
380
0
        {
381
0
          case '-':
382
0
            DisableComment=true;
383
0
            break;
384
0
          case 'U':
385
0
            ConvertNames=NAMES_UPPERCASE;
386
0
            break;
387
0
          case 'L':
388
0
            ConvertNames=NAMES_LOWERCASE;
389
0
            break;
390
0
          default:
391
0
            BadSwitch(Switch);
392
0
            break;
393
0
        }
394
0
      break;
395
0
    case 'D':
396
0
      if (Switch[2]!=0)
397
0
        BadSwitch(Switch);
398
0
      else
399
0
        switch(toupperw(Switch[1]))
400
0
        {
401
0
          case 'S':
402
0
            DisableSortSolid=true;
403
0
            break;
404
0
          case 'H':
405
0
            OpenShared=true;
406
0
            break;
407
0
          case 'F':
408
0
            DeleteFiles=true;
409
0
            break;
410
0
          default:
411
0
            BadSwitch(Switch);
412
0
            break;
413
0
        }
414
0
      break;
415
0
    case 'E':
416
0
      switch(toupperw(Switch[1]))
417
0
      {
418
0
        case 'P':
419
0
          switch(Switch[2])
420
0
          {
421
0
            case 0:
422
0
              ExclPath=EXCL_SKIPWHOLEPATH;
423
0
              break;
424
0
            case '1':
425
0
              ExclPath=EXCL_BASEPATH;
426
0
              break;
427
0
            case '2':
428
0
              ExclPath=EXCL_SAVEFULLPATH;
429
0
              break;
430
0
            case '3':
431
0
              ExclPath=EXCL_ABSPATH;
432
0
              break;
433
0
            case '4':
434
              // Convert slashes here than before every comparison.
435
0
              SlashToNative(Switch+3,ExclArcPath);
436
0
              break;
437
0
            default:
438
0
              BadSwitch(Switch);
439
0
              break;
440
0
          }
441
0
          break;
442
0
        default:
443
0
          if (Switch[1]=='+')
444
0
          {
445
0
            InclFileAttr|=GetExclAttr(Switch+2,InclDir);
446
0
            InclAttrSet=true;
447
0
          }
448
0
          else
449
0
            ExclFileAttr|=GetExclAttr(Switch+1,ExclDir);
450
0
          break;
451
0
      }
452
0
      break;
453
0
    case 'F':
454
0
      if (Switch[1]==0)
455
0
        FreshFiles=true;
456
0
      else
457
0
        BadSwitch(Switch);
458
0
      break;
459
0
    case 'H':
460
0
      switch (toupperw(Switch[1]))
461
0
      {
462
0
        case 'P':
463
0
          EncryptHeaders=true;
464
0
          if (Switch[2]!=0)
465
0
          {
466
0
            if (wcslen(Switch+2)>=MAXPASSWORD)
467
0
              uiMsg(UIERROR_TRUNCPSW,MAXPASSWORD-1);
468
0
            Password.Set(Switch+2);
469
0
            cleandata((void *)Switch,wcslen(Switch)*sizeof(Switch[0]));
470
0
          }
471
0
          else
472
0
            if (!Password.IsSet())
473
0
            {
474
0
              uiGetPassword(UIPASSWORD_GLOBAL,L"",&Password,NULL);
475
0
              eprintf(L"\n");
476
0
            }
477
0
          break;
478
0
        default :
479
0
          BadSwitch(Switch);
480
0
          break;
481
0
      }
482
0
      break;
483
0
    case 'I':
484
0
      if (wcsnicomp(Switch+1,L"LOG",3)==0)
485
0
      {
486
0
        LogName=Switch[4]!=0 ? Switch+4:DefLogName;
487
0
        break;
488
0
      }
489
0
      if (wcsnicomp(Switch+1,L"SND",3)==0)
490
0
      {
491
0
        Sound=Switch[4]=='-' ? SOUND_NOTIFY_OFF : SOUND_NOTIFY_ON;
492
0
        break;
493
0
      }
494
0
      if (wcsicomp(Switch+1,L"ERR")==0)
495
0
      {
496
0
        MsgStream=MSG_STDERR;
497
        // Set it immediately when parsing the command line, so it also
498
        // affects messages issued while parsing the command line.
499
0
        SetConsoleMsgStream(MSG_STDERR);
500
0
        break;
501
0
      }
502
0
      if (wcsnicomp(Switch+1,L"EML",3)==0)
503
0
      {
504
0
        EmailTo=Switch[4]!=0 ? Switch+4:L"@";
505
0
        break;
506
0
      }
507
0
      if (wcsicomp(Switch+1,L"M")==0) // For compatibility with pre-WinRAR 6.0 -im syntax. Replaced with -idv.
508
0
      {
509
0
        VerboseOutput=true;
510
0
        break;
511
0
      }
512
0
      if (wcsicomp(Switch+1,L"NUL")==0)
513
0
      {
514
0
        MsgStream=MSG_NULL;
515
0
        SetConsoleMsgStream(MSG_NULL);
516
0
        break;
517
0
      }
518
0
      if (toupperw(Switch[1])=='D')
519
0
      {
520
0
        for (uint I=2;Switch[I]!=0;I++)
521
0
          switch(toupperw(Switch[I]))
522
0
          {
523
0
            case 'Q':
524
0
              MsgStream=MSG_ERRONLY;
525
0
              SetConsoleMsgStream(MSG_ERRONLY);
526
0
              break;
527
0
            case 'C':
528
0
              DisableCopyright=true;
529
0
              break;
530
0
            case 'D':
531
0
              DisableDone=true;
532
0
              break;
533
0
            case 'P':
534
0
              DisablePercentage=true;
535
0
              break;
536
0
            case 'N':
537
0
              DisableNames=true;
538
0
              break;
539
0
            case 'V':
540
0
              VerboseOutput=true;
541
0
              break;
542
0
          }
543
0
        break;
544
0
      }
545
0
      if (wcsnicomp(Switch+1,L"OFF",3)==0)
546
0
      {
547
0
        switch(Switch[4])
548
0
        {
549
0
          case 0:
550
0
          case '1':
551
0
            Shutdown=POWERMODE_OFF;
552
0
            break;
553
0
          case '2':
554
0
            Shutdown=POWERMODE_HIBERNATE;
555
0
            break;
556
0
          case '3':
557
0
            Shutdown=POWERMODE_SLEEP;
558
0
            break;
559
0
          case '4':
560
0
            Shutdown=POWERMODE_RESTART;
561
0
            break;
562
0
        }
563
0
        break;
564
0
      }
565
0
      if (wcsicomp(Switch+1,L"VER")==0)
566
0
      {
567
0
        PrintVersion=true;
568
0
        break;
569
0
      }
570
0
      break;
571
0
    case 'K':
572
0
      switch(toupperw(Switch[1]))
573
0
      {
574
0
        case 'B':
575
0
          KeepBroken=true;
576
0
          break;
577
0
        case 0:
578
0
          Lock=true;
579
0
          break;
580
0
      }
581
0
      break;
582
0
    case 'M':
583
0
      switch(toupperw(Switch[1]))
584
0
      {
585
0
        case 'C':
586
0
          {
587
0
            const wchar *Str=Switch+2;
588
0
            if (*Str=='-')
589
0
              for (uint I=0;I<ASIZE(FilterModes);I++)
590
0
                FilterModes[I].State=FILTER_DISABLE;
591
0
            else
592
0
              while (*Str!=0)
593
0
              {
594
0
                int Param1=0,Param2=0;
595
0
                FilterState State=FILTER_AUTO;
596
0
                FilterType Type=FILTER_NONE;
597
0
                if (IsDigit(*Str))
598
0
                {
599
0
                  Param1=atoiw(Str);
600
0
                  while (IsDigit(*Str))
601
0
                    Str++;
602
0
                }
603
0
                if (*Str==':' && IsDigit(Str[1]))
604
0
                {
605
0
                  Param2=atoiw(++Str);
606
0
                  while (IsDigit(*Str))
607
0
                    Str++;
608
0
                }
609
0
                switch(toupperw(*(Str++)))
610
0
                {
611
//                  case 'T': Type=FILTER_TEXT;        break;
612
0
                  case 'E': Type=FILTER_E8;          break;
613
0
                  case 'D': Type=FILTER_DELTA;       break;
614
//                  case 'A': Type=FILTER_AUDIO;       break;
615
//                  case 'C': Type=FILTER_RGB;         break;
616
//                  case 'R': Type=FILTER_ARM;         break;
617
0
                  case 'L': Type=FILTER_LONGRANGE;   break;
618
0
                  case 'X': Type=FILTER_EXHAUSTIVE;  break;
619
0
                }
620
0
                if (*Str=='+' || *Str=='-')
621
0
                  State=*(Str++)=='+' ? FILTER_FORCE:FILTER_DISABLE;
622
0
                FilterModes[Type].State=State;
623
0
                FilterModes[Type].Param1=Param1;
624
0
                FilterModes[Type].Param2=Param2;
625
0
              }
626
0
            }
627
0
          break;
628
0
        case 'D':
629
0
          {
630
0
            bool SetDictLimit=toupperw(Switch[2])=='X';
631
632
0
            uint64 Size=atoiw(Switch+(SetDictLimit ? 3 : 2));
633
0
            wchar LastChar=toupperw(Switch[wcslen(Switch)-1]);
634
0
            if (IsDigit(LastChar))
635
0
              LastChar=SetDictLimit ? 'G':'M'; // Treat -md128 as -md128m and -mdx32 as -mdx32g.
636
0
            switch(LastChar)
637
0
            {
638
0
              case 'K':
639
0
                Size*=1024;
640
0
                break;
641
0
              case 'M':
642
0
                Size*=1024*1024;
643
0
                break;
644
0
              case 'G':
645
0
                Size*=1024*1024*1024;
646
0
                break;
647
0
              default:
648
0
                BadSwitch(Switch);
649
0
            }
650
651
            // 2023.07.22: For 4 GB and less we also check that it is power of 2,
652
            // so archives are compatible with RAR 5.0+.
653
            // We allow Size>PACK_MAX_DICT here, so we can use -md[x] to unpack
654
            // archives created by future versions with higher PACK_MAX_DICTþ
655
0
            uint Flags;
656
0
            if ((Size=Archive::GetWinSize(Size,Flags))==0 ||
657
0
                Size<=0x100000000ULL && !IsPow2(Size))
658
0
              BadSwitch(Switch);
659
0
            else
660
0
              if (SetDictLimit)
661
0
                WinSizeLimit=Size;
662
0
              else
663
0
              {
664
0
                WinSize=Size;
665
0
              }
666
0
          }
667
0
          break;
668
0
        case 'E':
669
0
          if (toupperw(Switch[2])=='S' && Switch[3]==0)
670
0
            SkipEncrypted=true;
671
0
          break;
672
0
        case 'L':
673
0
          if (toupperw(Switch[2])=='P')
674
0
          {
675
0
            UseLargePages=true;
676
0
            if (!LargePageAlloc::IsPrivilegeAssigned() && LargePageAlloc::AssignConfirmation())
677
0
            {
678
0
              LargePageAlloc::AssignPrivilege();
679
680
              // Quit immediately. We do not want to interrupt the current copy
681
              // archive processing with reboot after assigning privilege.
682
0
              SetupComplete=true;
683
0
            }
684
0
          }
685
0
          break;
686
0
        case 'M':
687
0
          break;
688
0
        case 'S':
689
0
          GetBriefMaskList(Switch[2]==0 ? DefaultStoreList:Switch+2,StoreArgs);
690
0
          break;
691
0
#ifdef RAR_SMP
692
0
        case 'T':
693
0
          Threads=atoiw(Switch+2);
694
0
          if (Threads>MaxPoolThreads || Threads<1)
695
0
            BadSwitch(Switch);
696
0
          break;
697
0
#endif
698
0
        default:
699
0
          Method=Switch[1]-'0';
700
0
          if (Method>5 || Method<0)
701
0
            BadSwitch(Switch);
702
0
          break;
703
0
      }
704
0
      break;
705
0
    case 'N':
706
0
    case 'X':
707
0
      if (Switch[1]!=0)
708
0
      {
709
0
        StringList *Args=toupperw(Switch[0])=='N' ? &InclArgs:&ExclArgs;
710
0
        if (Switch[1]=='@' && !IsWildcard(Switch))
711
0
          ReadTextFile(Switch+2,Args,false,true,FilelistCharset,true,true,true);
712
0
        else
713
0
          Args->AddString(Switch+1);
714
0
      }
715
0
      break;
716
0
    case 'O':
717
0
      switch(toupperw(Switch[1]))
718
0
      {
719
0
        case '+':
720
0
          Overwrite=OVERWRITE_ALL;
721
0
          break;
722
0
        case '-':
723
0
          Overwrite=OVERWRITE_NONE;
724
0
          break;
725
0
        case 0:
726
0
          Overwrite=OVERWRITE_FORCE_ASK;
727
0
          break;
728
#ifdef _WIN_ALL
729
        case 'C':
730
          SetCompressedAttr=true;
731
          break;
732
#endif
733
0
        case 'H':
734
0
          SaveHardLinks=true;
735
0
          break;
736
737
738
0
#ifdef SAVE_LINKS
739
0
        case 'L':
740
0
          SaveSymLinks=true;
741
0
          for (uint I=2;Switch[I]!=0;I++)
742
0
            switch(toupperw(Switch[I]))
743
0
            {
744
0
              case 'A':
745
0
                AbsoluteLinks=true;
746
0
                break;
747
0
              case '-':
748
0
                SkipSymLinks=true;
749
0
                break;
750
0
              default:
751
0
                BadSwitch(Switch);
752
0
                break;
753
0
            }
754
0
          break;
755
0
#endif
756
#ifdef PROPAGATE_MOTW
757
        case 'M':
758
          {
759
            MotwAllFields=Switch[2]=='1';
760
            const wchar *Sep=wcschr(Switch+2,'=');
761
            if (Switch[2]=='-')
762
              MotwList.Reset();
763
            else
764
              GetBriefMaskList(Sep==nullptr ? L"*":Sep+1,MotwList);
765
          }
766
          break;
767
#endif
768
#ifdef _WIN_ALL
769
        case 'N':
770
          if (toupperw(Switch[2])=='I')
771
            AllowIncompatNames=true;
772
          break;
773
#endif
774
0
        case 'P':
775
0
          ExtrPath=Switch+2;
776
0
          AddEndSlash(ExtrPath);
777
0
          break;
778
0
        case 'R':
779
0
          Overwrite=OVERWRITE_AUTORENAME;
780
0
          break;
781
#ifdef _WIN_ALL
782
        case 'S':
783
          SaveStreams=true;
784
          break;
785
#endif
786
0
        case 'W':
787
0
          ProcessOwners=true;
788
0
          break;
789
0
        default :
790
0
          BadSwitch(Switch);
791
0
          break;
792
0
      }
793
0
      break;
794
11.9k
    case 'P':
795
11.9k
      if (Switch[1]==0)
796
11.9k
      {
797
11.9k
        uiGetPassword(UIPASSWORD_GLOBAL,L"",&Password,NULL);
798
11.9k
        eprintf(L"\n");
799
11.9k
      }
800
0
      else
801
0
      {
802
0
        if (wcslen(Switch+1)>=MAXPASSWORD)
803
0
          uiMsg(UIERROR_TRUNCPSW,MAXPASSWORD-1);
804
0
        Password.Set(Switch+1);
805
0
        cleandata((void *)Switch,wcslen(Switch)*sizeof(Switch[0]));
806
0
      }
807
11.9k
      break;
808
0
#ifndef SFX_MODULE
809
0
    case 'Q':
810
0
      if (toupperw(Switch[1])=='O')
811
0
        switch(toupperw(Switch[2]))
812
0
        {
813
0
          case 0:
814
0
            QOpenMode=QOPEN_AUTO;
815
0
            break;
816
0
          case '-':
817
0
            QOpenMode=QOPEN_NONE;
818
0
            break;
819
0
          case '+':
820
0
            QOpenMode=QOPEN_ALWAYS;
821
0
            break;
822
0
          default:
823
0
            BadSwitch(Switch);
824
0
            break;
825
0
        }
826
0
      else
827
0
        BadSwitch(Switch);
828
0
      break;
829
0
#endif
830
0
    case 'R':
831
0
      switch(toupperw(Switch[1]))
832
0
      {
833
0
        case 0:
834
0
          Recurse=RECURSE_ALWAYS;
835
0
          break;
836
0
        case '-':
837
0
          Recurse=RECURSE_DISABLE;
838
0
          break;
839
0
        case '0':
840
0
          Recurse=RECURSE_WILDCARDS;
841
0
          break;
842
0
        case 'I':
843
0
          {
844
0
            Priority=atoiw(Switch+2);
845
0
            if (Priority<0 || Priority>15)
846
0
              BadSwitch(Switch);
847
0
            const wchar *ChPtr=wcschr(Switch+2,':');
848
0
            if (ChPtr!=NULL)
849
0
            {
850
0
              SleepTime=atoiw(ChPtr+1);
851
0
              if (SleepTime>1000)
852
0
                BadSwitch(Switch);
853
0
              InitSystemOptions(SleepTime);
854
0
            }
855
0
            SetPriority(Priority);
856
0
          }
857
0
          break;
858
0
      }
859
0
      break;
860
0
    case 'S':
861
0
      if (IsDigit(Switch[1]))
862
0
      {
863
0
        Solid|=SOLID_COUNT;
864
0
        SolidCount=atoiw(&Switch[1]);
865
0
      }
866
0
      else
867
0
        switch(toupperw(Switch[1]))
868
0
        {
869
0
          case 0:
870
0
            Solid|=SOLID_NORMAL;
871
0
            break;
872
0
          case '-':
873
0
            Solid=SOLID_NONE;
874
0
            break;
875
0
          case 'E':
876
0
            Solid|=SOLID_FILEEXT;
877
0
            break;
878
0
          case 'V':
879
0
            Solid|=Switch[2]=='-' ? SOLID_VOLUME_DEPENDENT:SOLID_VOLUME_INDEPENDENT;
880
0
            break;
881
0
          case 'D':
882
0
            Solid|=SOLID_VOLUME_DEPENDENT;
883
0
            break;
884
0
          case 'I':
885
0
            ProhibitConsoleInput();
886
0
            UseStdin=Switch[2] ? Switch+2:L"stdin";
887
0
            break;
888
0
          case 'L':
889
0
            if (IsDigit(Switch[2]))
890
0
              FileSizeLess=GetVolSize(Switch+2,1);
891
0
            break;
892
0
          case 'M':
893
0
            if (IsDigit(Switch[2]))
894
0
              FileSizeMore=GetVolSize(Switch+2,1);
895
0
            break;
896
0
          case 'C':
897
0
            {
898
0
              bool AlreadyBad=false; // Avoid reporting "bad switch" several times.
899
900
0
              RAR_CHARSET rch=RCH_DEFAULT;
901
0
              switch(toupperw(Switch[2]))
902
0
              {
903
0
                case 'A':
904
0
                  rch=RCH_ANSI;
905
0
                  break;
906
0
                case 'O':
907
0
                  rch=RCH_OEM;
908
0
                  break;
909
0
                case 'U':
910
0
                  rch=RCH_UNICODE;
911
0
                  break;
912
0
                case 'F':
913
0
                  rch=RCH_UTF8;
914
0
                  break;
915
0
                default :
916
0
                  BadSwitch(Switch);
917
0
                  AlreadyBad=true;
918
0
                  break;
919
0
              };
920
0
              if (!AlreadyBad)
921
0
                if (Switch[3]==0)
922
0
                  CommentCharset=FilelistCharset=ErrlogCharset=RedirectCharset=rch;
923
0
                else
924
0
                  for (uint I=3;Switch[I]!=0 && !AlreadyBad;I++)
925
0
                    switch(toupperw(Switch[I]))
926
0
                    {
927
0
                      case 'C':
928
0
                        CommentCharset=rch;
929
0
                        break;
930
0
                      case 'L':
931
0
                        FilelistCharset=rch;
932
0
                        break;
933
0
                      case 'R':
934
0
                        RedirectCharset=rch;
935
0
                        break;
936
0
                      default:
937
0
                        BadSwitch(Switch);
938
0
                        AlreadyBad=true;
939
0
                        break;
940
0
                    }
941
              // Set it immediately when parsing the command line, so it also
942
              // affects messages issued while parsing the command line.
943
0
              SetConsoleRedirectCharset(RedirectCharset);
944
0
            }
945
0
            break;
946
947
0
        }
948
0
      break;
949
0
    case 'T':
950
0
      switch(toupperw(Switch[1]))
951
0
      {
952
0
        case 'K':
953
0
          ArcTime=ARCTIME_KEEP;
954
0
          break;
955
0
        case 'L':
956
0
          ArcTime=ARCTIME_LATEST;
957
0
          break;
958
0
        case 'O':
959
0
          SetTimeFilters(Switch+2,true,true);
960
0
          break;
961
0
        case 'N':
962
0
          SetTimeFilters(Switch+2,false,true);
963
0
          break;
964
0
        case 'B':
965
0
          SetTimeFilters(Switch+2,true,false);
966
0
          break;
967
0
        case 'A':
968
0
          SetTimeFilters(Switch+2,false,false);
969
0
          break;
970
0
        case 'S':
971
0
          SetStoreTimeMode(Switch+2);
972
0
          break;
973
0
        case '-':
974
0
          Test=false;
975
0
          break;
976
0
        case 0:
977
0
          Test=true;
978
0
          break;
979
0
        default:
980
0
          BadSwitch(Switch);
981
0
          break;
982
0
      }
983
0
      break;
984
0
    case 'U':
985
0
      if (Switch[1]==0)
986
0
        UpdateFiles=true;
987
0
      else
988
0
        BadSwitch(Switch);
989
0
      break;
990
0
    case 'V':
991
0
      switch(toupperw(Switch[1]))
992
0
      {
993
0
        case 'P':
994
0
          VolumePause=true;
995
0
          break;
996
0
        case 'E':
997
0
          if (toupperw(Switch[2])=='R')
998
0
            VersionControl=atoiw(Switch+3)+1;
999
0
          break;
1000
0
        case '-':
1001
0
          VolSize=0;
1002
0
          break;
1003
0
        default:
1004
0
          VolSize=VOLSIZE_AUTO; // UnRAR -v switch for list command.
1005
0
          break;
1006
0
      }
1007
0
      break;
1008
0
    case 'W':
1009
0
      TempPath=Switch+1;
1010
0
      AddEndSlash(TempPath);
1011
0
      break;
1012
0
    case 'Y':
1013
0
      AllYes=true;
1014
0
      break;
1015
0
    case 'Z':
1016
0
      if (Switch[1]==0)
1017
0
      {
1018
        // If comment file is not specified, we read data from stdin.
1019
0
        CommentFile=L"stdin";
1020
0
      }
1021
0
      else
1022
0
        CommentFile=Switch+1;
1023
0
      break;
1024
0
    case '?' :
1025
0
      OutHelp(RARX_SUCCESS);
1026
0
      break;
1027
0
    default :
1028
0
      BadSwitch(Switch);
1029
0
      break;
1030
11.9k
  }
1031
11.9k
}
1032
#endif
1033
1034
1035
#if !defined(SFX_MODULE)
1036
void CommandData::BadSwitch(const wchar *Switch)
1037
0
{
1038
0
  mprintf(St(MUnknownOption),Switch);
1039
0
  ErrHandler.Exit(RARX_USERERROR);
1040
0
}
1041
#endif
1042
1043
1044
void CommandData::ProcessCommand()
1045
0
{
1046
0
#ifndef SFX_MODULE
1047
1048
0
  const wchar *SingleCharCommands=L"FUADPXETK";
1049
1050
  // RAR -mlp command is the legitimate way to assign the required privilege.
1051
0
  if (Command.empty() && UseLargePages || SetupComplete)
1052
0
    return;
1053
1054
0
  if (Command[0]!=0 && Command[1]!=0 && wcschr(SingleCharCommands,Command[0])!=NULL || ArcName.empty())
1055
0
    OutHelp(Command.empty() ? RARX_SUCCESS:RARX_USERERROR); // Return 'success' for 'rar' without parameters.
1056
1057
0
  size_t ExtPos=GetExtPos(ArcName);
1058
0
#ifdef _UNIX
1059
  // If we want to update an archive without extension, in Windows we can use
1060
  // "arcname." and it will be treated as "arcname". In Unix "arcname"
1061
  // and "arcname." are two different names, so we check if "arcname" exists
1062
  // and do not append ".rar", allowing user to update such archive.
1063
0
  if (ExtPos==std::wstring::npos && (!FileExist(ArcName) || IsDir(GetFileAttr(ArcName))))
1064
0
    ArcName+=L".rar";
1065
#else
1066
  if (ExtPos==std::wstring::npos)
1067
    ArcName+=L".rar";
1068
#endif
1069
  // Treat arcname.part1 as arcname.part1.rar.
1070
0
  if (ExtPos!=std::wstring::npos && wcsnicomp(&ArcName[ExtPos],L".part",5)==0 &&
1071
0
      IsDigit(ArcName[ExtPos+5]) && !FileExist(ArcName))
1072
0
  {
1073
0
    std::wstring Name=ArcName+L".rar";
1074
0
    if (FileExist(Name))
1075
0
      ArcName=Name;
1076
0
  }
1077
1078
0
  if (wcschr(L"AFUMD",Command[0])==NULL && UseStdin.empty())
1079
0
  {
1080
0
    if (GenerateArcName)
1081
0
    {
1082
0
      const wchar *Mask=*GenerateMask!=0 ? GenerateMask:DefGenerateMask;
1083
0
      GenerateArchiveName(ArcName,Mask,false);
1084
0
    }
1085
1086
0
    StringList ArcMasks;
1087
0
    ArcMasks.AddString(ArcName);
1088
0
    ScanTree Scan(&ArcMasks,Recurse,SaveSymLinks,SCAN_SKIPDIRS);
1089
0
    FindData FindData;
1090
0
    while (Scan.GetNext(&FindData)==SCAN_SUCCESS)
1091
0
      AddArcName(FindData.Name);
1092
0
  }
1093
0
  else
1094
0
    AddArcName(ArcName);
1095
0
#endif
1096
1097
0
  switch(Command[0])
1098
0
  {
1099
0
    case 'P':
1100
0
    case 'X':
1101
0
    case 'E':
1102
0
    case 'T':
1103
0
      {
1104
0
        CmdExtract Extract(this);
1105
0
        Extract.DoExtract();
1106
0
      }
1107
0
      break;
1108
#ifndef SILENT
1109
    case 'V':
1110
    case 'L':
1111
      ListArchive(this);
1112
      break;
1113
    default:
1114
      OutHelp(RARX_USERERROR);
1115
#endif
1116
0
  }
1117
0
  if (!BareOutput)
1118
0
    mprintf(L"\n");
1119
0
}
1120
1121
1122
void CommandData::AddArcName(const std::wstring &Name)
1123
11.9k
{
1124
11.9k
  ArcNames.AddString(Name);
1125
11.9k
}
1126
1127
1128
bool CommandData::GetArcName(wchar *Name,int MaxSize)
1129
0
{
1130
0
  return ArcNames.GetString(Name,MaxSize);
1131
0
}
1132
1133
1134
bool CommandData::GetArcName(std::wstring &Name)
1135
45.7k
{
1136
45.7k
  return ArcNames.GetString(Name);
1137
45.7k
}
1138
1139
1140
bool CommandData::IsSwitch(int Ch)
1141
23.9k
{
1142
#ifdef _WIN_ALL
1143
  return Ch=='-' || Ch=='/';
1144
#else
1145
23.9k
  return Ch=='-';
1146
23.9k
#endif
1147
23.9k
}
1148
1149
1150
#ifndef SFX_MODULE
1151
uint CommandData::GetExclAttr(const wchar *Str,bool &Dir)
1152
0
{
1153
0
  if (IsDigit(*Str))
1154
0
    return wcstol(Str,NULL,0);
1155
1156
0
  uint Attr=0;
1157
0
  while (*Str!=0)
1158
0
  {
1159
0
    switch(toupperw(*Str))
1160
0
    {
1161
0
      case 'D':
1162
0
        Dir=true;
1163
0
        break;
1164
0
#ifdef _UNIX
1165
0
      case 'V':
1166
0
        Attr|=S_IFCHR;
1167
0
        break;
1168
#elif defined(_WIN_ALL)
1169
      case 'R':
1170
        Attr|=0x1;
1171
        break;
1172
      case 'H':
1173
        Attr|=0x2;
1174
        break;
1175
      case 'S':
1176
        Attr|=0x4;
1177
        break;
1178
      case 'A':
1179
        Attr|=0x20;
1180
        break;
1181
#endif
1182
0
    }
1183
0
    Str++;
1184
0
  }
1185
0
  return Attr;
1186
0
}
1187
#endif
1188
1189
1190
1191
1192
#ifndef SFX_MODULE
1193
void CommandData::ReportWrongSwitches(RARFORMAT Format)
1194
0
{
1195
0
  if (Format==RARFMT15)
1196
0
  {
1197
0
    if (HashType!=HASH_CRC32)
1198
0
      uiMsg(UIERROR_INCOMPATSWITCH,L"-ht",4);
1199
#ifdef _WIN_ALL
1200
    if (SaveSymLinks)
1201
      uiMsg(UIERROR_INCOMPATSWITCH,L"-ol",4);
1202
#endif
1203
0
    if (SaveHardLinks)
1204
0
      uiMsg(UIERROR_INCOMPATSWITCH,L"-oh",4);
1205
1206
#ifdef _WIN_ALL
1207
    // Do not report a wrong dictionary size here, because we are not sure
1208
    // yet about archive format. We can switch to RAR5 mode later
1209
    // if we update RAR5 archive.
1210
1211
1212
#endif
1213
0
    if (QOpenMode!=QOPEN_AUTO)
1214
0
      uiMsg(UIERROR_INCOMPATSWITCH,L"-qo",4);
1215
0
  }
1216
0
  if (Format==RARFMT50)
1217
0
  {
1218
0
  }
1219
0
}
1220
#endif
1221
1222
1223
int64 CommandData::GetVolSize(const wchar *S,uint DefMultiplier)
1224
0
{
1225
0
  int64 Size=0,FloatingDivider=0;
1226
0
  for (uint I=0;S[I]!=0;I++)
1227
0
    if (IsDigit(S[I]))
1228
0
    {
1229
0
      Size=Size*10+S[I]-'0';
1230
0
      FloatingDivider*=10;
1231
0
    }
1232
0
    else
1233
0
      if (S[I]=='.')
1234
0
        FloatingDivider=1;
1235
1236
0
  if (*S!=0)
1237
0
  {
1238
0
    const wchar *ModList=L"bBkKmMgGtT";
1239
0
    const wchar *Mod=wcschr(ModList,S[wcslen(S)-1]);
1240
0
    if (Mod==NULL)
1241
0
      Size*=DefMultiplier;
1242
0
    else
1243
0
      for (ptrdiff_t I=2;I<=Mod-ModList;I+=2)
1244
0
        Size*=((Mod-ModList)&1)!=0 ? 1000:1024;
1245
0
  }
1246
0
  if (FloatingDivider!=0)
1247
0
    Size/=FloatingDivider;
1248
0
  return Size;
1249
0
}
1250
1251
1252
// Treat the list like rar;zip as *.rar;*.zip for -ms and similar switches.
1253
void CommandData::GetBriefMaskList(const std::wstring &Masks,StringList &Args)
1254
0
{
1255
0
  size_t Pos=0;
1256
0
  while (Pos<Masks.size())
1257
0
  {
1258
0
    if (Masks[Pos]=='.')
1259
0
      Pos++;
1260
0
    size_t EndPos=Masks.find(';',Pos);
1261
0
    std::wstring Mask=Masks.substr(Pos,EndPos==std::wstring::npos ? EndPos:EndPos-Pos);
1262
0
    if (Mask.find_first_of(L"*?.")==std::wstring::npos)
1263
0
      Mask.insert(0,L"*.");
1264
0
    Args.AddString(Mask);
1265
0
    if (EndPos==std::wstring::npos)
1266
0
      break;
1267
0
    Pos=EndPos+1;
1268
0
  }
1269
0
}
1270
1271
1272
1273