~ubuntu-branches/ubuntu/vivid/unrar-nonfree/vivid

« back to all changes in this revision

Viewing changes to file.cpp

  • Committer: Package Import Robot
  • Author(s): Martin Meredith
  • Date: 2015-02-03 12:58:01 UTC
  • mfrom: (1.1.18) (5.1.18 sid)
  • Revision ID: package-import@ubuntu.com-20150203125801-od6ev8cqy1er51vz
Tags: 1:5.2.5-1
New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
 
3
3
File::File()
4
4
{
5
 
  hFile=BAD_HANDLE;
 
5
  hFile=FILE_BAD_HANDLE;
6
6
  *FileName=0;
7
7
  NewFile=false;
8
8
  LastWrite=false;
22
22
 
23
23
File::~File()
24
24
{
25
 
  if (hFile!=BAD_HANDLE && !SkipClose)
 
25
  if (hFile!=FILE_BAD_HANDLE && !SkipClose)
26
26
    if (NewFile)
27
27
      Delete();
28
28
    else
36
36
  NewFile=SrcFile.NewFile;
37
37
  LastWrite=SrcFile.LastWrite;
38
38
  HandleType=SrcFile.HandleType;
 
39
  wcsncpyz(FileName,SrcFile.FileName,ASIZE(FileName));
39
40
  SrcFile.SkipClose=true;
40
41
}
41
42
 
51
52
  uint Access=WriteMode ? GENERIC_WRITE:GENERIC_READ;
52
53
  if (UpdateMode)
53
54
    Access|=GENERIC_WRITE;
54
 
  uint ShareMode=FILE_SHARE_READ;
 
55
  uint ShareMode=(Mode & FMF_OPENEXCLUSIVE) ? 0 : FILE_SHARE_READ;
55
56
  if (OpenShared)
56
57
    ShareMode|=FILE_SHARE_WRITE;
57
58
  uint Flags=NoSequentialRead ? 0:FILE_FLAG_SEQUENTIAL_SCAN;
58
59
  hNewFile=CreateFile(Name,Access,ShareMode,NULL,OPEN_EXISTING,Flags,NULL);
59
60
 
60
61
  DWORD LastError;
61
 
  if (hNewFile==BAD_HANDLE)
 
62
  if (hNewFile==FILE_BAD_HANDLE)
62
63
  {
63
 
    // Following CreateFile("\\?\path") call can change the last error code
64
 
    // from "not found" to "access denied" for relative paths like "..\path".
65
 
    // But we need the correct "not found" code to create a new archive
66
 
    // if existing one is not found. So we preserve the code here.
67
64
    LastError=GetLastError();
68
65
 
69
66
    wchar LongName[NM];
70
67
    if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
 
68
    {
71
69
      hNewFile=CreateFile(LongName,Access,ShareMode,NULL,OPEN_EXISTING,Flags,NULL);
 
70
 
 
71
      // For archive names longer than 260 characters first CreateFile
 
72
      // (without \\?\) fails and sets LastError to 3 (access denied).
 
73
      // We need the correct "file not found" error code to decide
 
74
      // if we create a new archive or quit with "cannot create" error.
 
75
      // So we need to check the error code after \\?\ CreateFile again,
 
76
      // otherwise we'll fail to create new archives with long names.
 
77
      // But we cannot simply assign the new code to LastError,
 
78
      // because it would break "..\arcname.rar" relative names processing.
 
79
      // First CreateFile returns the correct "file not found" code for such
 
80
      // names, but "\\?\" CreateFile returns ERROR_INVALID_NAME treating
 
81
      // dots as a directory name. So we check only for "file not found"
 
82
      // error here and for other errors use the first CreateFile result.
 
83
      if (GetLastError()==ERROR_FILE_NOT_FOUND)
 
84
        LastError=ERROR_FILE_NOT_FOUND;
 
85
    }
72
86
  }
73
87
 
74
 
  if (hNewFile==BAD_HANDLE && LastError==ERROR_FILE_NOT_FOUND)
 
88
  if (hNewFile==FILE_BAD_HANDLE && LastError==ERROR_FILE_NOT_FOUND)
75
89
    ErrorType=FILE_NOTFOUND;
76
90
#else
77
91
  int flags=UpdateMode ? O_RDWR:(WriteMode ? O_WRONLY:O_RDONLY);
97
111
    return false;
98
112
  }
99
113
#endif
100
 
  hNewFile=handle==-1 ? BAD_HANDLE:fdopen(handle,UpdateMode ? UPDATEBINARY:READBINARY);
101
 
  if (hNewFile==BAD_HANDLE && errno==ENOENT)
 
114
  if (handle==-1)
 
115
    hNewFile=FILE_BAD_HANDLE;
 
116
  else
 
117
  {
 
118
#ifdef FILE_USE_OPEN
 
119
    hNewFile=handle;
 
120
#else
 
121
    hNewFile=fdopen(handle,UpdateMode ? UPDATEBINARY:READBINARY);
 
122
#endif
 
123
  }
 
124
  if (hNewFile==FILE_BAD_HANDLE && errno==ENOENT)
102
125
    ErrorType=FILE_NOTFOUND;
103
126
#endif
104
127
  NewFile=false;
105
128
  HandleType=FILE_HANDLENORMAL;
106
129
  SkipClose=false;
107
 
  bool Success=hNewFile!=BAD_HANDLE;
 
130
  bool Success=hNewFile!=FILE_BAD_HANDLE;
108
131
  if (Success)
109
132
  {
110
133
    hFile=hNewFile;
144
167
  CreateMode=Mode;
145
168
  uint Access=WriteMode ? GENERIC_WRITE:GENERIC_READ|GENERIC_WRITE;
146
169
  DWORD ShareMode=ShareRead ? FILE_SHARE_READ:0;
147
 
  hFile=CreateFile(Name,Access,ShareMode,NULL,CREATE_ALWAYS,0,NULL);
148
 
 
149
 
  if (hFile==BAD_HANDLE)
 
170
 
 
171
  // Windows automatically removes dots and spaces in the end of file name,
 
172
  // So we detect such names and process them with \\?\ prefix.
 
173
  wchar *LastChar=PointToLastChar(Name);
 
174
  bool Special=*LastChar=='.' || *LastChar==' ';
 
175
  
 
176
  if (Special)
 
177
    hFile=FILE_BAD_HANDLE;
 
178
  else
 
179
    hFile=CreateFile(Name,Access,ShareMode,NULL,CREATE_ALWAYS,0,NULL);
 
180
 
 
181
  if (hFile==FILE_BAD_HANDLE)
150
182
  {
151
183
    wchar LongName[NM];
152
184
    if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
156
188
#else
157
189
  char NameA[NM];
158
190
  WideToChar(Name,NameA,ASIZE(NameA));
 
191
#ifdef FILE_USE_OPEN
 
192
  hFile=open(NameA,(O_CREAT|O_TRUNC) | (WriteMode ? O_WRONLY : O_RDWR));
 
193
#ifdef _ANDROID
 
194
  if (hFile==FILE_BAD_HANDLE)
 
195
    hFile=JniCreateFile(Name); // If external card is read-only for usual file API.
 
196
#endif
 
197
#else
159
198
  hFile=fopen(NameA,WriteMode ? WRITEBINARY:CREATEBINARY);
160
199
#endif
 
200
#endif
161
201
  NewFile=true;
162
202
  HandleType=FILE_HANDLENORMAL;
163
203
  SkipClose=false;
164
204
  wcsncpyz(FileName,Name,ASIZE(FileName));
165
 
  return hFile!=BAD_HANDLE;
 
205
  return hFile!=FILE_BAD_HANDLE;
166
206
}
167
207
 
168
208
 
179
219
{
180
220
  if (Create(Name,Mode))
181
221
    return true;
182
 
  ErrHandler.SetErrorCode(RARX_CREATE);
183
222
  ErrHandler.CreateErrorMsg(Name);
184
223
  return false;
185
224
}
188
227
bool File::Close()
189
228
{
190
229
  bool Success=true;
191
 
  if (HandleType!=FILE_HANDLENORMAL)
192
 
    HandleType=FILE_HANDLENORMAL;
193
 
  else
194
 
    if (hFile!=BAD_HANDLE)
 
230
 
 
231
  if (hFile!=FILE_BAD_HANDLE)
 
232
  {
 
233
    if (!SkipClose)
195
234
    {
196
 
      if (!SkipClose)
197
 
      {
198
235
#ifdef _WIN_ALL
 
236
      // We use the standard system handle for stdout in Windows
 
237
      // and it must not  be closed here.
 
238
      if (HandleType==FILE_HANDLENORMAL)
199
239
        Success=CloseHandle(hFile)==TRUE;
200
240
#else
201
 
        Success=fclose(hFile)!=EOF;
202
 
#endif
203
 
      }
204
 
      hFile=BAD_HANDLE;
205
 
      if (!Success && AllowExceptions)
206
 
        ErrHandler.CloseError(FileName);
 
241
#ifdef FILE_USE_OPEN
 
242
      Success=close(hFile)!=-1;
 
243
#else
 
244
      Success=fclose(hFile)!=EOF;
 
245
#endif
 
246
#endif
207
247
    }
 
248
    hFile=FILE_BAD_HANDLE;
 
249
  }
 
250
  HandleType=FILE_HANDLENORMAL;
 
251
  if (!Success && AllowExceptions)
 
252
    ErrHandler.CloseError(FileName);
208
253
  return Success;
209
254
}
210
255
 
211
256
 
212
 
void File::Flush()
213
 
{
214
 
#ifdef _WIN_ALL
215
 
  FlushFileBuffers(hFile);
216
 
#else
217
 
  fflush(hFile);
218
 
#endif
219
 
}
220
 
 
221
 
 
222
257
bool File::Delete()
223
258
{
224
259
  if (HandleType!=FILE_HANDLENORMAL)
225
260
    return false;
226
 
  if (hFile!=BAD_HANDLE)
 
261
  if (hFile!=FILE_BAD_HANDLE)
227
262
    Close();
228
263
  if (!AllowDelete)
229
264
    return false;
246
281
}
247
282
 
248
283
 
249
 
void File::Write(const void *Data,size_t Size)
 
284
bool File::Write(const void *Data,size_t Size)
250
285
{
251
286
  if (Size==0)
252
 
    return;
253
 
  if (HandleType!=FILE_HANDLENORMAL)
254
 
    switch(HandleType)
 
287
    return true;
 
288
  if (HandleType==FILE_HANDLESTD)
 
289
  {
 
290
#ifdef _WIN_ALL
 
291
    hFile=GetStdHandle(STD_OUTPUT_HANDLE);
 
292
#else
 
293
    // Cannot use the standard stdout here, because it already has wide orientation.
 
294
    if (hFile==FILE_BAD_HANDLE)
255
295
    {
256
 
      case FILE_HANDLESTD:
257
 
#ifdef _WIN_ALL
258
 
        hFile=GetStdHandle(STD_OUTPUT_HANDLE);
259
 
#else
260
 
        hFile=stdout;
261
 
#endif
262
 
        break;
263
 
      case FILE_HANDLEERR:
264
 
#ifdef _WIN_ALL
265
 
        hFile=GetStdHandle(STD_ERROR_HANDLE);
266
 
#else
267
 
        hFile=stderr;
268
 
#endif
269
 
        break;
 
296
#ifdef FILE_USE_OPEN
 
297
      hFile=dup(STDOUT_FILENO); // Open new stdout stream.
 
298
#else
 
299
      hFile=fdopen(dup(STDOUT_FILENO),"w"); // Open new stdout stream.
 
300
#endif
270
301
    }
 
302
#endif
 
303
  }
 
304
  bool Success;
271
305
  while (1)
272
306
  {
273
 
    bool Success=false;
 
307
    Success=false;
274
308
#ifdef _WIN_ALL
275
309
    DWORD Written=0;
276
310
    if (HandleType!=FILE_HANDLENORMAL)
287
321
    else
288
322
      Success=WriteFile(hFile,Data,(DWORD)Size,&Written,NULL)==TRUE;
289
323
#else
 
324
#ifdef FILE_USE_OPEN
 
325
    ssize_t Written=write(hFile,Data,Size);
 
326
    Success=Written==Size;
 
327
#else
290
328
    int Written=fwrite(Data,1,Size,hFile);
291
329
    Success=Written==Size && !ferror(hFile);
292
330
#endif
 
331
#endif
293
332
    if (!Success && AllowExceptions && HandleType==FILE_HANDLENORMAL)
294
333
    {
295
334
#if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(RARDLL)
302
341
#endif
303
342
      if (ErrHandler.AskRepeatWrite(FileName,false))
304
343
      {
305
 
#ifndef _WIN_ALL
 
344
#if !defined(_WIN_ALL) && !defined(FILE_USE_OPEN)
306
345
        clearerr(hFile);
307
346
#endif
308
347
        if (Written<Size && Written>0)
314
353
    break;
315
354
  }
316
355
  LastWrite=true;
 
356
  return Success; // It can return false only if AllowExceptions is disabled.
317
357
}
318
358
 
319
359
 
365
405
  if (HandleType==FILE_HANDLESTD)
366
406
  {
367
407
#ifdef _WIN_ALL
368
 
    if (Size>MaxDeviceRead)
369
 
      Size=MaxDeviceRead;
 
408
//    if (Size>MaxDeviceRead)
 
409
//      Size=MaxDeviceRead;
370
410
    hFile=GetStdHandle(STD_INPUT_HANDLE);
371
411
#else
 
412
#ifdef FILE_USE_OPEN
 
413
    hFile=STDIN_FILENO;
 
414
#else
372
415
    hFile=stdin;
373
416
#endif
 
417
#endif
374
418
  }
375
419
#ifdef _WIN_ALL
 
420
  // For pipes like 'type file.txt | rar -si arcname' ReadFile may return
 
421
  // data in small ~4KB blocks. It may slightly reduce the compression ratio.
376
422
  DWORD Read;
377
423
  if (!ReadFile(hFile,Data,(DWORD)Size,&Read,NULL))
378
424
  {
395
441
  }
396
442
  return Read;
397
443
#else
 
444
#ifdef FILE_USE_OPEN
 
445
  ssize_t ReadSize=read(hFile,Data,Size);
 
446
  if (ReadSize==-1)
 
447
    return -1;
 
448
  return (int)ReadSize;
 
449
#else
398
450
  if (LastWrite)
399
451
  {
400
452
    fflush(hFile);
406
458
    return -1;
407
459
  return (int)ReadSize;
408
460
#endif
 
461
#endif
409
462
}
410
463
 
411
464
 
418
471
 
419
472
bool File::RawSeek(int64 Offset,int Method)
420
473
{
421
 
  if (hFile==BAD_HANDLE)
 
474
  if (hFile==FILE_BAD_HANDLE)
422
475
    return true;
423
476
  if (Offset<0 && Method!=SEEK_SET)
424
477
  {
432
485
    return false;
433
486
#else
434
487
  LastWrite=false;
435
 
#if defined(_LARGEFILE_SOURCE) && !defined(_OSF_SOURCE) && !defined(__VMS)
 
488
#ifdef FILE_USE_OPEN
 
489
  if (lseek64(hFile,Offset,Method)==-1)
 
490
    return false;
 
491
#elif defined(_LARGEFILE_SOURCE) && !defined(_OSF_SOURCE) && !defined(__VMS)
436
492
  if (fseeko(hFile,Offset,Method)!=0)
 
493
    return false;
437
494
#else
438
495
  if (fseek(hFile,(long)Offset,Method)!=0)
439
 
#endif
440
496
    return false;
441
497
#endif
 
498
#endif
442
499
  return true;
443
500
}
444
501
 
445
502
 
446
503
int64 File::Tell()
447
504
{
448
 
  if (hFile==BAD_HANDLE)
 
505
  if (hFile==FILE_BAD_HANDLE)
449
506
    if (AllowExceptions)
450
507
      ErrHandler.SeekError(FileName);
451
508
    else
460
517
      return -1;
461
518
  return INT32TO64(HighDist,LowDist);
462
519
#else
463
 
#if defined(_LARGEFILE_SOURCE) && !defined(_OSF_SOURCE)
 
520
#ifdef FILE_USE_OPEN
 
521
  return lseek64(hFile,0,SEEK_CUR);
 
522
#elif defined(_LARGEFILE_SOURCE) && !defined(_OSF_SOURCE)
464
523
  return ftello(hFile);
465
524
#else
466
525
  return ftell(hFile);
482
541
#if defined(_UNIX) && defined(USE_FALLOCATE)
483
542
  // fallocate is rather new call. Only latest kernels support it.
484
543
  // So we are not using it by default yet.
485
 
  int fd = fileno(hFile);
 
544
  int fd = GetFD(hFile);
486
545
  if (fd >= 0)
487
546
    fallocate(fd, 0, 0, Size);
488
547
#endif
578
637
#endif
579
638
#if defined(_UNIX) || defined(_EMX)
580
639
  struct stat st;
581
 
  fstat(fileno(hFile),&st);
 
640
  fstat(GetFD(),&st);
582
641
  *ft=st.st_mtime;
583
642
#endif
584
643
}
594
653
 
595
654
bool File::IsDevice()
596
655
{
597
 
  if (hFile==BAD_HANDLE)
 
656
  if (hFile==FILE_BAD_HANDLE)
598
657
    return false;
599
658
#ifdef _WIN_ALL
600
659
  uint Type=GetFileType(hFile);
601
660
  return Type==FILE_TYPE_CHAR || Type==FILE_TYPE_PIPE;
602
661
#else
603
 
  return isatty(fileno(hFile));
 
662
  return isatty(GetFD());
604
663
#endif
605
664
}
606
665
 
608
667
#ifndef SFX_MODULE
609
668
int64 File::Copy(File &Dest,int64 Length)
610
669
{
611
 
  Array<char> Buffer(0x10000);
 
670
  Array<char> Buffer(0x40000);
612
671
  int64 CopySize=0;
613
672
  bool CopyAll=(Length==INT64NDF);
614
673
 
616
675
  {
617
676
    Wait();
618
677
    size_t SizeToRead=(!CopyAll && Length<(int64)Buffer.Size()) ? (size_t)Length:Buffer.Size();
619
 
    int ReadSize=Read(&Buffer[0],SizeToRead);
 
678
    char *Buf=&Buffer[0];
 
679
    int ReadSize=Read(Buf,SizeToRead);
620
680
    if (ReadSize==0)
621
681
      break;
622
 
    Dest.Write(&Buffer[0],ReadSize);
 
682
    size_t WriteSize=ReadSize;
 
683
#ifdef _WIN_ALL
 
684
    // For FAT32 USB flash drives in Windows if first write is 4 KB or more,
 
685
    // write caching is disabled and "write through" is enabled, resulting
 
686
    // in bad performance, especially for many small files. It happens when
 
687
    // we create SFX archive on USB drive, because SFX module is written first.
 
688
    // So we split the first write to small 1 KB followed by rest of data.
 
689
    if (CopySize==0 && WriteSize>=4096)
 
690
    {
 
691
      const size_t FirstWrite=1024;
 
692
      Dest.Write(Buf,FirstWrite);
 
693
      Buf+=FirstWrite;
 
694
      WriteSize-=FirstWrite;
 
695
    }
 
696
#endif
 
697
    Dest.Write(Buf,WriteSize);
623
698
    CopySize+=ReadSize;
624
699
    if (!CopyAll)
625
700
      Length-=ReadSize;