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 BPackageKit::BHPKG::BPackageWriter; 28 using BPackageKit::BHPKG::BPackageWriterListener; 29 using BPackageKit::BHPKG::BPackageWriterParameters; 30 31 32 int 33 command_create(int argc, const char* const* argv) 34 { 35 const char* changeToDirectory = NULL; 36 const char* packageInfoFileName = NULL; 37 const char* installPath = NULL; 38 bool isBuildPackage = false; 39 bool quiet = false; 40 bool verbose = false; 41 int32 compressionLevel = BPackageKit::BHPKG::B_HPKG_COMPRESSION_LEVEL_BEST; 42 int32 compression = BPackageKit::BHPKG::B_HPKG_COMPRESSION_ZLIB; 43 44 while (true) { 45 static struct option sLongOptions[] = { 46 { "help", no_argument, 0, 'h' }, 47 { "quiet", no_argument, 0, 'q' }, 48 { "verbose", no_argument, 0, 'v' }, 49 { 0, 0, 0, 0 } 50 }; 51 52 opterr = 0; // don't print errors 53 int c = getopt_long(argc, (char**)argv, "+b0123456789C:hi:I:qvz", 54 sLongOptions, NULL); 55 if (c == -1) 56 break; 57 58 switch (c) { 59 case '0': 60 case '1': 61 case '2': 62 case '3': 63 case '4': 64 case '5': 65 case '6': 66 case '7': 67 case '8': 68 case '9': 69 compressionLevel = c - '0'; 70 break; 71 72 case 'b': 73 isBuildPackage = true; 74 break; 75 76 case 'C': 77 changeToDirectory = optarg; 78 break; 79 80 case 'h': 81 print_usage_and_exit(false); 82 break; 83 84 case 'i': 85 packageInfoFileName = optarg; 86 break; 87 88 case 'I': 89 installPath = optarg; 90 break; 91 92 case 'q': 93 quiet = true; 94 break; 95 96 case 'v': 97 verbose = true; 98 break; 99 100 case 'z': 101 compression = BPackageKit::BHPKG::B_HPKG_COMPRESSION_ZSTD; 102 break; 103 104 default: 105 print_usage_and_exit(true); 106 break; 107 } 108 } 109 110 // The remaining arguments is the package file, i.e. one more argument. 111 if (optind + 1 != argc) 112 print_usage_and_exit(true); 113 114 const char* packageFileName = argv[optind++]; 115 116 // -I is only allowed when -b is given 117 if (installPath != NULL && !isBuildPackage) { 118 fprintf(stderr, "Error: \"-I\" is only allowed when \"-b\" is " 119 "given.\n"); 120 return 1; 121 } 122 123 // create package 124 BPackageWriterParameters writerParameters; 125 writerParameters.SetCompressionLevel(compressionLevel); 126 if (compressionLevel == 0) { 127 writerParameters.SetCompression( 128 BPackageKit::BHPKG::B_HPKG_COMPRESSION_NONE); 129 } 130 131 if (compressionLevel == 0) 132 compression = BPackageKit::BHPKG::B_HPKG_COMPRESSION_NONE; 133 writerParameters.SetCompression(compression); 134 135 PackageWriterListener listener(verbose, quiet); 136 BPackageWriter packageWriter(&listener); 137 status_t result = packageWriter.Init(packageFileName, &writerParameters); 138 if (result != B_OK) 139 return 1; 140 141 // If a package info file has been specified explicitly, open it. 142 int packageInfoFD = -1; 143 if (packageInfoFileName != NULL) { 144 packageInfoFD = open(packageInfoFileName, O_RDONLY); 145 if (packageInfoFD < 0) { 146 fprintf(stderr, "Error: Failed to open package info file \"%s\": " 147 "%s\n", packageInfoFileName, strerror(errno)); 148 return 1; 149 } 150 } 151 152 // change directory, if requested 153 if (changeToDirectory != NULL) { 154 if (chdir(changeToDirectory) != 0) { 155 listener.PrintError( 156 "Error: Failed to change the current working directory to " 157 "\"%s\": %s\n", changeToDirectory, strerror(errno)); 158 return 1; 159 } 160 } 161 162 if (isBuildPackage) 163 packageWriter.SetCheckLicenses(false); 164 165 // set install path, if specified 166 if (installPath != NULL) { 167 result = packageWriter.SetInstallPath(installPath); 168 if (result != B_OK) { 169 fprintf(stderr, "Error: Failed to set the package install path: " 170 "%s\n", strerror(result)); 171 return 1; 172 } 173 } 174 175 // add all files of the current directory, save for the .PackageInfo 176 if (!isBuildPackage) { 177 if (add_current_directory_entries(packageWriter, listener, true) 178 != B_OK) { 179 return 1; 180 } 181 } 182 183 // add the .PackageInfo 184 result = packageWriter.AddEntry( 185 BPackageKit::BHPKG::B_HPKG_PACKAGE_INFO_FILE_NAME, packageInfoFD); 186 if (result != B_OK) 187 return 1; 188 189 // write the package 190 result = packageWriter.Finish(); 191 if (result != B_OK) 192 return 1; 193 194 if (verbose) 195 printf("\nsuccessfully created package '%s'\n", packageFileName); 196 197 return 0; 198 } 199