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