1 /* 2 * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de> 4 * Distributed under the terms of the MIT License. 5 */ 6 7 8 #include <errno.h> 9 #include <fcntl.h> 10 #include <getopt.h> 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <string.h> 14 #include <unistd.h> 15 16 #include <Entry.h> 17 18 #include <package/PackageInfo.h> 19 #include <package/hpkg/HPKGDefs.h> 20 #include <package/hpkg/PackageWriter.h> 21 22 #include "package.h" 23 #include "PackageWriterListener.h" 24 #include "PackageWritingUtils.h" 25 26 27 using namespace BPackageKit::BHPKG; 28 29 30 int 31 command_add(int argc, const char* const* argv) 32 { 33 const char* changeToDirectory = NULL; 34 const char* packageInfoFileName = NULL; 35 bool quiet = false; 36 bool verbose = false; 37 bool force = false; 38 int32 compressionLevel = BPackageKit::BHPKG::B_HPKG_COMPRESSION_LEVEL_BEST; 39 40 while (true) { 41 static struct option sLongOptions[] = { 42 { "help", no_argument, 0, 'h' }, 43 { "quiet", no_argument, 0, 'q' }, 44 { "verbose", no_argument, 0, 'v' }, 45 { 0, 0, 0, 0 } 46 }; 47 48 opterr = 0; // don't print errors 49 int c = getopt_long(argc, (char**)argv, "+0123456789C:fhi:qv", 50 sLongOptions, NULL); 51 if (c == -1) 52 break; 53 54 switch (c) { 55 case '0': 56 case '1': 57 case '2': 58 case '3': 59 case '4': 60 case '5': 61 case '6': 62 case '7': 63 case '8': 64 case '9': 65 compressionLevel = c - '0'; 66 break; 67 68 case 'C': 69 changeToDirectory = optarg; 70 break; 71 72 case 'h': 73 print_usage_and_exit(false); 74 break; 75 76 case 'f': 77 force = true; 78 break; 79 80 case 'i': 81 packageInfoFileName = optarg; 82 break; 83 84 case 'q': 85 quiet = true; 86 break; 87 88 case 'v': 89 verbose = true; 90 break; 91 92 default: 93 print_usage_and_exit(true); 94 break; 95 } 96 } 97 98 // The remaining arguments are the package file and the entries to add. 99 if (optind >= argc) 100 print_usage_and_exit(true); 101 102 const char* packageFileName = argv[optind++]; 103 104 // entries must be specified, if a .PackageInfo hasn't been specified via 105 // an option 106 if (optind >= argc && packageInfoFileName == NULL) 107 print_usage_and_exit(true); 108 109 const char* const* entriesToAdd = argv + optind; 110 int entriesToAddCount = argc - optind; 111 112 // create package 113 BPackageWriterParameters writerParameters; 114 writerParameters.SetFlags( 115 B_HPKG_WRITER_UPDATE_PACKAGE | (force ? B_HPKG_WRITER_FORCE_ADD : 0)); 116 writerParameters.SetCompressionLevel(compressionLevel); 117 118 PackageWriterListener listener(verbose, quiet); 119 BPackageWriter packageWriter(&listener); 120 status_t result = packageWriter.Init(packageFileName, &writerParameters); 121 if (result != B_OK) 122 return 1; 123 124 // If a package info file has been specified explicitly, open it. 125 int packageInfoFD = -1; 126 if (packageInfoFileName != NULL) { 127 packageInfoFD = open(packageInfoFileName, O_RDONLY); 128 if (packageInfoFD < 0) { 129 fprintf(stderr, "Error: Failed to open package info file \"%s\": " 130 "%s\n", packageInfoFileName, strerror(errno)); 131 } 132 } 133 134 // change directory, if requested 135 if (changeToDirectory != NULL) { 136 if (chdir(changeToDirectory) != 0) { 137 listener.PrintError( 138 "Error: Failed to change the current working directory to " 139 "\"%s\": %s\n", changeToDirectory, strerror(errno)); 140 } 141 } 142 143 // add the entries 144 for (int i = 0; i < entriesToAddCount; i++) { 145 const char* entry = entriesToAdd[i]; 146 147 if (strcmp(entry, ".") == 0) { 148 // add all entries in the current directory; skip .PackageInfo, 149 // if a different file was specified 150 if (add_current_directory_entries(packageWriter, 151 listener, packageInfoFileName != NULL) != B_OK) 152 return 1; 153 } else { 154 // skip .PackageInfo, if a different file was specified 155 if (packageInfoFileName != NULL 156 && strcmp(entry, B_HPKG_PACKAGE_INFO_FILE_NAME) == 0) { 157 continue; 158 } 159 160 if (packageWriter.AddEntry(entry) != B_OK) 161 return 1; 162 } 163 } 164 165 // add the .PackageInfo, if explicitly specified 166 if (packageInfoFileName != NULL) { 167 result = packageWriter.AddEntry(B_HPKG_PACKAGE_INFO_FILE_NAME, 168 packageInfoFD); 169 if (result != B_OK) 170 return 1; 171 } 172 173 // write the package 174 result = packageWriter.Finish(); 175 if (result != B_OK) 176 return 1; 177 178 if (verbose) 179 printf("\nsuccessfully created package '%s'\n", packageFileName); 180 181 return 0; 182 } 183