VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/zip/tarcmd.cpp@ 39627

Last change on this file since 39627 was 35351, checked in by vboxsync, 14 years ago

scm cleanups.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.8 KB
Line 
1/* $Id: tarcmd.cpp 35351 2010-12-27 17:04:17Z vboxsync $ */
2/** @file
3 * IPRT - TAR Command.
4 */
5
6/*
7 * Copyright (C) 2010 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include <iprt/zip.h>
32
33#include <iprt/asm.h>
34#include <iprt/buildconfig.h>
35#include <iprt/ctype.h>
36#include <iprt/file.h>
37#include <iprt/getopt.h>
38#include <iprt/initterm.h>
39#include <iprt/mem.h>
40#include <iprt/message.h>
41#include <iprt/param.h>
42#include <iprt/stream.h>
43#include <iprt/string.h>
44#include <iprt/vfs.h>
45
46
47/*******************************************************************************
48* Defined Constants And Macros *
49*******************************************************************************/
50#define RTZIPTARCMD_OPT_DELETE 1000
51#define RTZIPTARCMD_OPT_OWNER 1001
52#define RTZIPTARCMD_OPT_GROUP 1002
53#define RTZIPTARCMD_OPT_UTC 1003
54#define RTZIPTARCMD_OPT_PREFIX 1004
55
56
57/*******************************************************************************
58* Structures and Typedefs *
59*******************************************************************************/
60/**
61 * IPT TAR option structure.
62 */
63typedef struct RTZIPTARCMDOPS
64{
65 /** The operation (Acdrtux or RTZIPTARCMD_OPT_DELETE). */
66 int iOperation;
67 /** The long operation option name. */
68 const char *pszOperation;
69
70 /** The directory to change into when packing and unpacking. */
71 const char *pszDirectory;
72 /** The tar file name. */
73 const char *pszFile;
74 /** Whether we're verbose or quiet. */
75 bool fVerbose;
76 /** Whether to preserve permissions when restoring. */
77 bool fPreservePermissions;
78 /** The compressor/decompressor method to employ (0, z or j). */
79 char chZipper;
80
81 /** The owner to set. */
82 const char *pszOwner;
83 /** The owner ID to set when unpacking if pszOwner is not NULL. */
84 RTUID uidOwner;
85 /** The group to set. */
86 const char *pszGroup;
87 /** The group ID to set when unpacking if pszGroup is not NULL. */
88 RTGID gidGroup;
89 /** Display the modification times in UTC instead of local time. */
90 bool fDisplayUtc;
91
92 /** What to prefix all names with when creating, adding, whatever. */
93 const char *pszPrefix;
94
95 /** The number of files(, directories or whatever) specified. */
96 uint32_t cFiles;
97 /** Array of files(, directories or whatever).
98 * Terminated by a NULL entry. */
99 const char * const *papszFiles;
100} RTZIPTARCMDOPS;
101/** Pointer to the IPRT tar options. */
102typedef RTZIPTARCMDOPS *PRTZIPTARCMDOPS;
103
104
105/**
106 * Checks if @a pszName is a member of @a papszNames, optionally returning the
107 * index.
108 *
109 * @returns true if the name is in the list, otherwise false.
110 * @param pszName The name to find.
111 * @param papszNames The array of names.
112 * @param piName Where to optionally return the array index.
113 */
114static bool rtZipTarCmdIsNameInArray(const char *pszName, const char * const *papszNames, uint32_t *piName)
115{
116 for (uint32_t iName = 0; papszNames[iName]; iName)
117 if (!strcmp(papszNames[iName], pszName))
118 {
119 if (piName)
120 *piName = iName;
121 return true;
122 }
123 return false;
124}
125
126
127/**
128 * Opens the input archive specified by the options.
129 *
130 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE + printed message.
131 * @param pOpts The options.
132 * @param phVfsFss Where to return the TAR filesystem stream handle.
133 */
134static RTEXITCODE rtZipTarCmdOpenInputArchive(PRTZIPTARCMDOPS pOpts, PRTVFSFSSTREAM phVfsFss)
135{
136 int rc;
137
138 /*
139 * Open the input file.
140 */
141 RTVFSIOSTREAM hVfsIos;
142 if ( pOpts->pszFile
143 && strcmp(pOpts->pszFile, "-") != 0)
144 {
145 const char *pszError;
146 rc = RTVfsChainOpenIoStream(pOpts->pszFile,
147 RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN,
148 &hVfsIos,
149 &pszError);
150 if (RT_FAILURE(rc))
151 {
152 if (pszError && *pszError)
153 return RTMsgErrorExit(RTEXITCODE_FAILURE,
154 "RTVfsChainOpenIoStream failed with rc=%Rrc:\n"
155 " '%s'\n",
156 " %*s^\n",
157 rc, pOpts->pszFile, pszError - pOpts->pszFile, "");
158 return RTMsgErrorExit(RTEXITCODE_FAILURE,
159 "Failed with %Rrc opening the input archive '%s'", rc, pOpts->pszFile);
160 }
161 }
162 else
163 {
164 rc = RTVfsIoStrmFromStdHandle(RTHANDLESTD_INPUT,
165 RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN,
166 true /*fLeaveOpen*/,
167 &hVfsIos);
168 if (RT_FAILURE(rc))
169 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to prepare standard in for reading: %Rrc", rc);
170 }
171
172 /*
173 * Pass it thru a decompressor?
174 */
175 RTVFSIOSTREAM hVfsIosDecomp = NIL_RTVFSIOSTREAM;
176 switch (pOpts->chZipper)
177 {
178 /* no */
179 case '\0':
180 rc = VINF_SUCCESS;
181 break;
182
183 /* gunzip */
184 case 'z':
185 rc = RTZipGzipDecompressIoStream(hVfsIos, 0 /*fFlags*/, &hVfsIosDecomp);
186 if (RT_FAILURE(rc))
187 RTMsgError("Failed to open gzip decompressor: %Rrc", rc);
188 break;
189
190 /* bunzip2 */
191 case 'j':
192 rc = VERR_NOT_SUPPORTED;
193 RTMsgError("bzip2 is not supported by this build");
194 break;
195
196 /* bug */
197 default:
198 rc = VERR_INTERNAL_ERROR_2;
199 RTMsgError("unknown decompression method '%c'", pOpts->chZipper);
200 break;
201 }
202 if (RT_FAILURE(rc))
203 {
204 RTVfsIoStrmRelease(hVfsIos);
205 return RTEXITCODE_FAILURE;
206 }
207
208 if (hVfsIosDecomp != NIL_RTVFSIOSTREAM)
209 {
210 RTVfsIoStrmRelease(hVfsIos);
211 hVfsIos = hVfsIosDecomp;
212 hVfsIosDecomp = NIL_RTVFSIOSTREAM;
213 }
214
215 /*
216 * Open the tar filesystem stream.
217 */
218 rc = RTZipTarFsStreamFromIoStream(hVfsIos, 0/*fFlags*/, phVfsFss);
219 RTVfsIoStrmRelease(hVfsIos);
220 if (RT_FAILURE(rc))
221 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to open tar filesystem stream: %Rrc", rc);
222
223 return RTEXITCODE_SUCCESS;
224}
225
226
227/**
228 * Display a tar entry in the verbose form.
229 *
230 * @returns rcExit or RTEXITCODE_FAILURE.
231 * @param rcExit The current exit code.
232 * @param hVfsObj The tar object to display
233 * @param pszName The name.
234 * @param pOpts The tar options.
235 */
236static RTEXITCODE rtZipTarCmdDisplayEntryVerbose(RTEXITCODE rcExit, RTVFSOBJ hVfsObj, const char *pszName,
237 PRTZIPTARCMDOPS pOpts)
238{
239 /*
240 * Query all the information.
241 */
242 RTFSOBJINFO UnixInfo;
243 int rc = RTVfsObjQueryInfo(hVfsObj, &UnixInfo, RTFSOBJATTRADD_UNIX);
244 if (RT_FAILURE(rc))
245 {
246 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsObjQueryInfo returned %Rrc on '%s'", rc, pszName);
247 RT_ZERO(UnixInfo);
248 }
249
250 RTFSOBJINFO Owner;
251 rc = RTVfsObjQueryInfo(hVfsObj, &Owner, RTFSOBJATTRADD_UNIX_OWNER);
252 if (RT_FAILURE(rc))
253 {
254 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE,
255 "RTVfsObjQueryInfo(,,UNIX_OWNER) returned %Rrc on '%s'",
256 rc, pszName);
257 RT_ZERO(Owner);
258 }
259
260 RTFSOBJINFO Group;
261 rc = RTVfsObjQueryInfo(hVfsObj, &Group, RTFSOBJATTRADD_UNIX_GROUP);
262 if (RT_FAILURE(rc))
263 {
264 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE,
265 "RTVfsObjQueryInfo(,,UNIX_OWNER) returned %Rrc on '%s'",
266 rc, pszName);
267 RT_ZERO(Group);
268 }
269
270 const char *pszLinkType = NULL;
271 char szTarget[RTPATH_MAX];
272 szTarget[0] = '\0';
273 RTVFSSYMLINK hVfsSymlink = RTVfsObjToSymlink(hVfsObj);
274 if (hVfsSymlink != NIL_RTVFSSYMLINK)
275 {
276 rc = RTVfsSymlinkRead(hVfsSymlink, szTarget, sizeof(szTarget));
277 if (RT_FAILURE(rc))
278 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsSymlinkRead returned %Rrc on '%s'", rc, pszName);
279 RTVfsSymlinkRelease(hVfsSymlink);
280 pszLinkType = RTFS_IS_SYMLINK(UnixInfo.Attr.fMode) ? "->" : "link to";
281 }
282 else if (RTFS_IS_SYMLINK(UnixInfo.Attr.fMode))
283 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to get symlink object for '%s'", pszName);
284
285 /*
286 * Translate the mode mask.
287 */
288 char szMode[16];
289 switch (UnixInfo.Attr.fMode & RTFS_TYPE_MASK)
290 {
291 case RTFS_TYPE_FIFO: szMode[0] = 'f'; break;
292 case RTFS_TYPE_DEV_CHAR: szMode[0] = 'c'; break;
293 case RTFS_TYPE_DIRECTORY: szMode[0] = 'd'; break;
294 case RTFS_TYPE_DEV_BLOCK: szMode[0] = 'b'; break;
295 case RTFS_TYPE_FILE: szMode[0] = '-'; break;
296 case RTFS_TYPE_SYMLINK: szMode[0] = 'l'; break;
297 case RTFS_TYPE_SOCKET: szMode[0] = 's'; break;
298 case RTFS_TYPE_WHITEOUT: szMode[0] = 'w'; break;
299 default: szMode[0] = '?'; break;
300 }
301 if (pszLinkType && szMode[0] != 's')
302 szMode[0] = 'h';
303
304 szMode[1] = UnixInfo.Attr.fMode & RTFS_UNIX_IRUSR ? 'r' : '-';
305 szMode[2] = UnixInfo.Attr.fMode & RTFS_UNIX_IWUSR ? 'w' : '-';
306 szMode[3] = UnixInfo.Attr.fMode & RTFS_UNIX_IXUSR ? 'x' : '-';
307
308 szMode[4] = UnixInfo.Attr.fMode & RTFS_UNIX_IRGRP ? 'r' : '-';
309 szMode[5] = UnixInfo.Attr.fMode & RTFS_UNIX_IWGRP ? 'w' : '-';
310 szMode[6] = UnixInfo.Attr.fMode & RTFS_UNIX_IXGRP ? 'x' : '-';
311
312 szMode[7] = UnixInfo.Attr.fMode & RTFS_UNIX_IROTH ? 'r' : '-';
313 szMode[8] = UnixInfo.Attr.fMode & RTFS_UNIX_IWOTH ? 'w' : '-';
314 szMode[9] = UnixInfo.Attr.fMode & RTFS_UNIX_IXOTH ? 'x' : '-';
315 szMode[10] = '\0';
316
317 /** @todo sticky and set-uid/gid bits. */
318
319 /*
320 * Make sure we've got valid owner and group strings.
321 */
322 if (!Owner.Attr.u.UnixGroup.szName[0])
323 RTStrPrintf(Owner.Attr.u.UnixOwner.szName, sizeof(Owner.Attr.u.UnixOwner.szName),
324 "%u", UnixInfo.Attr.u.Unix.uid);
325
326 if (!Group.Attr.u.UnixOwner.szName[0])
327 RTStrPrintf(Group.Attr.u.UnixGroup.szName, sizeof(Group.Attr.u.UnixGroup.szName),
328 "%u", UnixInfo.Attr.u.Unix.gid);
329
330 /*
331 * Format the modification time.
332 */
333 char szModTime[32];
334 RTTIME ModTime;
335 PRTTIME pTime;
336 if (!pOpts->fDisplayUtc)
337 pTime = RTTimeLocalExplode(&ModTime, &UnixInfo.ModificationTime);
338 else
339 pTime = RTTimeExplode(&ModTime, &UnixInfo.ModificationTime);
340 if (!pTime)
341 RT_ZERO(ModTime);
342 RTStrPrintf(szModTime, sizeof(szModTime), "%04d-%02u-%02u %02u:%02u",
343 ModTime.i32Year, ModTime.u8Month, ModTime.u8MonthDay, ModTime.u8Hour, ModTime.u8Minute);
344
345 /*
346 * Format the size and figure how much space is needed between the
347 * user/group and the size.
348 */
349 char szSize[64];
350 size_t cchSize;
351 switch (UnixInfo.Attr.fMode & RTFS_TYPE_MASK)
352 {
353 case RTFS_TYPE_DEV_CHAR:
354 case RTFS_TYPE_DEV_BLOCK:
355 cchSize = RTStrPrintf(szSize, sizeof(szSize), "%u,%u",
356 RTDEV_MAJOR(UnixInfo.Attr.u.Unix.Device), RTDEV_MINOR(UnixInfo.Attr.u.Unix.Device));
357 break;
358 default:
359 cchSize = RTStrPrintf(szSize, sizeof(szSize), "%RU64", UnixInfo.cbObject);
360 break;
361 }
362
363 size_t cchUserGroup = strlen(Owner.Attr.u.UnixOwner.szName)
364 + 1
365 + strlen(Group.Attr.u.UnixGroup.szName);
366 ssize_t cchPad = cchUserGroup + cchSize + 1 < 19
367 ? 19 - (cchUserGroup + cchSize + 1)
368 : 0;
369
370 /*
371 * Go to press.
372 */
373 if (pszLinkType)
374 RTPrintf("%s %s/%s%*s %s %s %s %s %s\n",
375 szMode,
376 Owner.Attr.u.UnixOwner.szName, Group.Attr.u.UnixGroup.szName,
377 cchPad, "",
378 szSize,
379 szModTime,
380 pszName,
381 pszLinkType,
382 szTarget);
383 else
384 RTPrintf("%s %s/%s%*s %s %s %s\n",
385 szMode,
386 Owner.Attr.u.UnixOwner.szName, Group.Attr.u.UnixGroup.szName,
387 cchPad, "",
388 szSize,
389 szModTime,
390 pszName);
391
392 return rcExit;
393}
394
395/**
396 * Implements the -t/--list operation.
397 *
398 * @returns The appropriate exit code.
399 * @param pOpts The tar options.
400 */
401static RTEXITCODE rtZipTarCmdList(PRTZIPTARCMDOPS pOpts)
402{
403 /*
404 * Allocate a bitmap to go with the file list. This will be used to
405 * indicate which files we've processed and which not.
406 */
407 uint32_t *pbmFound = NULL;
408 if (pOpts->cFiles)
409 {
410 pbmFound = (uint32_t *)RTMemAllocZ(((pOpts->cFiles + 31) / 32) * sizeof(uint32_t));
411 if (!pbmFound)
412 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to allocate the found-file-bitmap");
413 }
414
415
416 /*
417 * Open the input archive.
418 */
419 RTVFSFSSTREAM hVfsFssIn;
420 RTEXITCODE rcExit = rtZipTarCmdOpenInputArchive(pOpts, &hVfsFssIn);
421 if (rcExit == RTEXITCODE_SUCCESS)
422 {
423 /*
424 * Process the stream.
425 */
426 for (;;)
427 {
428 /*
429 * Retrive the next object.
430 */
431 char *pszName;
432 RTVFSOBJ hVfsObj;
433 int rc = RTVfsFsStrmNext(hVfsFssIn, &pszName, NULL, &hVfsObj);
434 if (RT_FAILURE(rc))
435 {
436 if (rc != VERR_EOF)
437 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsFsStrmNext returned %Rrc", rc);
438 break;
439 }
440
441 /*
442 * Should we display this entry?
443 */
444 uint32_t iFile = UINT32_MAX;
445 if ( !pOpts->cFiles
446 || rtZipTarCmdIsNameInArray(pszName, pOpts->papszFiles, &iFile) )
447 {
448 if (pbmFound)
449 ASMBitSet(pbmFound, iFile);
450
451 if (!pOpts->fVerbose)
452 RTPrintf("%s\n", pszName);
453 else
454 rcExit = rtZipTarCmdDisplayEntryVerbose(rcExit, hVfsObj, pszName, pOpts);
455 }
456
457 /*
458 * Release the current object and string.
459 */
460 RTVfsObjRelease(hVfsObj);
461 RTStrFree(pszName);
462 }
463
464 /*
465 * Complain about any files we didn't find.
466 */
467 for (uint32_t iFile = 0; iFile < pOpts->cFiles; iFile++)
468 if (!ASMBitTest(pbmFound, iFile))
469 {
470 RTMsgError("%s: Was not found in the archive", pOpts->papszFiles[iFile]);
471 rcExit = RTEXITCODE_FAILURE;
472 }
473 }
474 RTMemFree(pbmFound);
475 return rcExit;
476}
477
478
479
480RTDECL(RTEXITCODE) RTZipTarCmd(unsigned cArgs, char **papszArgs)
481{
482 /*
483 * Parse the command line.
484 *
485 * N.B. This is less flexible that your regular tar program in that it
486 * requires the operation to be specified as an option. On the other
487 * hand, you can specify it where ever you like in the command line.
488 */
489 static const RTGETOPTDEF s_aOptions[] =
490 {
491 /* operations */
492 { "--concatenate", 'A', RTGETOPT_REQ_NOTHING },
493 { "--catenate", 'A', RTGETOPT_REQ_NOTHING },
494 { "--create", 'c', RTGETOPT_REQ_NOTHING },
495 { "--diff", 'd', RTGETOPT_REQ_NOTHING },
496 { "--compare", 'd', RTGETOPT_REQ_NOTHING },
497 { "--append", 'r', RTGETOPT_REQ_NOTHING },
498 { "--list", 't', RTGETOPT_REQ_NOTHING },
499 { "--update", 'u', RTGETOPT_REQ_NOTHING },
500 { "--extract", 'x', RTGETOPT_REQ_NOTHING },
501 { "--get", 'x', RTGETOPT_REQ_NOTHING },
502 { "--delete", RTZIPTARCMD_OPT_DELETE, RTGETOPT_REQ_NOTHING },
503
504 /* basic options */
505 { "--directory", 'C', RTGETOPT_REQ_STRING },
506 { "--file", 'f', RTGETOPT_REQ_STRING },
507 { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
508 { "--preserve-permissions", 'p', RTGETOPT_REQ_NOTHING },
509 { "--bzip2", 'j', RTGETOPT_REQ_NOTHING },
510 { "--gzip", 'z', RTGETOPT_REQ_NOTHING },
511 { "--gunzip", 'z', RTGETOPT_REQ_NOTHING },
512 { "--ungzip", 'z', RTGETOPT_REQ_NOTHING },
513
514 /* other options. */
515 { "--owner", RTZIPTARCMD_OPT_OWNER, RTGETOPT_REQ_STRING },
516 { "--group", RTZIPTARCMD_OPT_GROUP, RTGETOPT_REQ_STRING },
517 { "--utc", RTZIPTARCMD_OPT_UTC, RTGETOPT_REQ_NOTHING },
518
519 /* IPRT extensions */
520 { "--prefix", RTZIPTARCMD_OPT_PREFIX, RTGETOPT_REQ_STRING },
521 };
522
523 RTGETOPTSTATE GetState;
524 int rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1,
525 RTGETOPTINIT_FLAGS_OPTS_FIRST);
526 if (RT_FAILURE(rc))
527 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTGetOpt failed: %Rrc", rc);
528
529 RTZIPTARCMDOPS Opts;
530 RT_ZERO(Opts); /* nice defaults :-) */
531
532 RTGETOPTUNION ValueUnion;
533 while ( (rc = RTGetOpt(&GetState, &ValueUnion)) != 0
534 && rc != VINF_GETOPT_NOT_OPTION)
535 {
536 switch (rc)
537 {
538 /* operations */
539 case 'A':
540 case 'c':
541 case 'd':
542 case 'r':
543 case 't':
544 case 'u':
545 case 'x':
546 case RTZIPTARCMD_OPT_DELETE:
547 if (Opts.iOperation)
548 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Conflicting tar operation (%s already set, now %s)",
549 Opts.pszOperation, ValueUnion.pDef->pszLong);
550 Opts.iOperation = rc;
551 Opts.pszOperation = ValueUnion.pDef->pszLong;
552 break;
553
554 /* basic options */
555 case 'C':
556 if (Opts.pszDirectory)
557 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "You may only specify -C/--directory once");
558 Opts.pszDirectory = ValueUnion.psz;
559 break;
560
561 case 'f':
562 if (Opts.pszFile)
563 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "You may only specify -f/--file once");
564 Opts.pszFile = ValueUnion.psz;
565 break;
566
567 case 'v':
568 Opts.fVerbose = true;
569 break;
570
571 case 'p':
572 Opts.fPreservePermissions = true;
573 break;
574
575 case 'j':
576 case 'z':
577 if (Opts.chZipper)
578 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "You may only specify one compressor / decompressor");
579 Opts.chZipper = rc;
580 break;
581
582 case RTZIPTARCMD_OPT_OWNER:
583 if (Opts.pszOwner)
584 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "You may only specify --owner once");
585 Opts.pszOwner = ValueUnion.psz;
586 break;
587
588 case RTZIPTARCMD_OPT_GROUP:
589 if (Opts.pszGroup)
590 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "You may only specify --group once");
591 Opts.pszGroup = ValueUnion.psz;
592 break;
593
594 case RTZIPTARCMD_OPT_UTC:
595 Opts.fDisplayUtc = true;
596 break;
597
598 /* iprt extensions */
599 case RTZIPTARCMD_OPT_PREFIX:
600 if (Opts.pszPrefix)
601 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "You may only specify --prefix once");
602 Opts.pszPrefix = ValueUnion.psz;
603 break;
604
605 case 'h':
606 RTPrintf("Usage: to be written\nOption dump:\n");
607 for (unsigned i = 0; i < RT_ELEMENTS(s_aOptions); i++)
608 if (RT_C_IS_PRINT(s_aOptions[i].iShort))
609 RTPrintf(" -%c,%s\n", s_aOptions[i].iShort, s_aOptions[i].pszLong);
610 else
611 RTPrintf(" %s\n", s_aOptions[i].pszLong);
612 return RTEXITCODE_SUCCESS;
613
614 case 'V':
615 RTPrintf("%sr%d\n", RTBldCfgVersion(), RTBldCfgRevision());
616 return RTEXITCODE_SUCCESS;
617
618 default:
619 return RTGetOptPrintError(rc, &ValueUnion);
620 }
621 }
622
623 if (rc == VINF_GETOPT_NOT_OPTION)
624 {
625 /* this is kind of ugly. */
626 Assert((unsigned)GetState.iNext - 1 <= cArgs);
627 Opts.papszFiles = (const char * const *)&papszArgs[GetState.iNext - 1];
628 Opts.cFiles = cArgs - GetState.iNext + 1;
629 }
630
631 /*
632 * Post proceess the options.
633 */
634 if (Opts.iOperation == 0)
635 {
636 Opts.iOperation = 't';
637 Opts.pszOperation = "--list";
638 }
639
640 if ( Opts.iOperation == 'x'
641 && Opts.pszOwner)
642 return RTMsgErrorExit(RTEXITCODE_FAILURE, "The use of --owner with %s has not implemented yet", Opts.pszOperation);
643
644 if ( Opts.iOperation == 'x'
645 && Opts.pszGroup)
646 return RTMsgErrorExit(RTEXITCODE_FAILURE, "The use of --group with %s has not implemented yet", Opts.pszOperation);
647
648 /*
649 * Do the job.
650 */
651 switch (Opts.iOperation)
652 {
653 case 't':
654 return rtZipTarCmdList(&Opts);
655
656 case 'A':
657 case 'c':
658 case 'd':
659 case 'r':
660 case 'u':
661 case 'x':
662 case RTZIPTARCMD_OPT_DELETE:
663 return RTMsgErrorExit(RTEXITCODE_FAILURE, "The operation %s is not implemented yet", Opts.pszOperation);
664
665 default:
666 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Internal error");
667 }
668}
669
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette