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 if (compressionLevel == 0) { 118 writerParameters.SetCompression( 119 BPackageKit::BHPKG::B_HPKG_COMPRESSION_NONE); 120 } 121 122 PackageWriterListener listener(verbose, quiet); 123 BPackageWriter packageWriter(&listener); 124 status_t result = packageWriter.Init(packageFileName, &writerParameters); 125 if (result != B_OK) 126 return 1; 127 128 // If a package info file has been specified explicitly, open it. 129 int packageInfoFD = -1; 130 if (packageInfoFileName != NULL) { 131 packageInfoFD = open(packageInfoFileName, O_RDONLY); 132 if (packageInfoFD < 0) { 133 fprintf(stderr, "Error: Failed to open package info file \"%s\": " 134 "%s\n", packageInfoFileName, strerror(errno)); 135 } 136 } 137 138 // change directory, if requested 139 if (changeToDirectory != NULL) { 140 if (chdir(changeToDirectory) != 0) { 141 listener.PrintError( 142 "Error: Failed to change the current working directory to " 143 "\"%s\": %s\n", changeToDirectory, strerror(errno)); 144 } 145 } 146 147 // add the entries 148 for (int i = 0; i < entriesToAddCount; i++) { 149 const char* entry = entriesToAdd[i]; 150 151 if (strcmp(entry, ".") == 0) { 152 // add all entries in the current directory; skip .PackageInfo, 153 // if a different file was specified 154 if (add_current_directory_entries(packageWriter, 155 listener, packageInfoFileName != NULL) != B_OK) 156 return 1; 157 } else { 158 // skip .PackageInfo, if a different file was specified 159 if (packageInfoFileName != NULL 160 && strcmp(entry, B_HPKG_PACKAGE_INFO_FILE_NAME) == 0) { 161 continue; 162 } 163 164 if (packageWriter.AddEntry(entry) != B_OK) 165 return 1; 166 } 167 } 168 169 // add the .PackageInfo, if explicitly specified 170 if (packageInfoFileName != NULL) { 171 result = packageWriter.AddEntry(B_HPKG_PACKAGE_INFO_FILE_NAME, 172 packageInfoFD); 173 if (result != B_OK) 174 return 1; 175 } 176 177 // write the package 178 result = packageWriter.Finish(); 179 if (result != B_OK) 180 return 1; 181 182 if (verbose) 183 printf("\nsuccessfully created package '%s'\n", packageFileName); 184 185 return 0; 186 } 187