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 #include "StandardErrorOutput.h" 26 27 28 using namespace BPackageKit::BHPKG; 29 30 31 int 32 command_add(int argc, const char* const* argv) 33 { 34 const char* changeToDirectory = NULL; 35 const char* packageInfoFileName = NULL; 36 bool quiet = false; 37 bool verbose = false; 38 bool force = false; 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, "+C:fhi:qv", sLongOptions, 50 NULL); 51 if (c == -1) 52 break; 53 54 switch (c) { 55 case 'C': 56 changeToDirectory = optarg; 57 break; 58 59 case 'h': 60 print_usage_and_exit(false); 61 break; 62 63 case 'f': 64 force = true; 65 break; 66 67 case 'i': 68 packageInfoFileName = optarg; 69 break; 70 71 case 'q': 72 quiet = true; 73 break; 74 75 case 'v': 76 verbose = true; 77 break; 78 79 default: 80 print_usage_and_exit(true); 81 break; 82 } 83 } 84 85 // The remaining arguments are the package file and the entries to add. 86 if (optind >= argc) 87 print_usage_and_exit(true); 88 89 const char* packageFileName = argv[optind++]; 90 91 // entries must be specified, if a .PackageInfo hasn't been specified via 92 // an option 93 if (optind >= argc && packageInfoFileName == NULL) 94 print_usage_and_exit(true); 95 96 const char* const* entriesToAdd = argv + optind; 97 int entriesToAddCount = argc - optind; 98 99 // create package 100 PackageWriterListener listener(verbose, quiet); 101 BPackageWriter packageWriter(&listener); 102 status_t result = packageWriter.Init(packageFileName, 103 B_HPKG_WRITER_UPDATE_PACKAGE | (force ? B_HPKG_WRITER_FORCE_ADD : 0)); 104 if (result != B_OK) 105 return 1; 106 107 // If a package info file has been specified explicitly, open it. 108 int packageInfoFD = -1; 109 if (packageInfoFileName != NULL) { 110 packageInfoFD = open(packageInfoFileName, O_RDONLY); 111 if (packageInfoFD < 0) { 112 fprintf(stderr, "Error: Failed to open package info file \"%s\": " 113 "%s\n", packageInfoFileName, strerror(errno)); 114 } 115 } 116 117 // change directory, if requested 118 if (changeToDirectory != NULL) { 119 if (chdir(changeToDirectory) != 0) { 120 listener.PrintError( 121 "Error: Failed to change the current working directory to " 122 "\"%s\": %s\n", changeToDirectory, strerror(errno)); 123 } 124 } 125 126 // add the entries 127 for (int i = 0; i < entriesToAddCount; i++) { 128 const char* entry = entriesToAdd[i]; 129 130 if (strcmp(entry, ".") == 0) { 131 // add all entries in the current directory; skip .PackageInfo, 132 // if a different file was specified 133 if (add_current_directory_entries(packageWriter, 134 listener, packageInfoFileName != NULL) != B_OK) 135 return 1; 136 } else { 137 // skip .PackageInfo, if a different file was specified 138 if (packageInfoFileName != NULL 139 && strcmp(entry, B_HPKG_PACKAGE_INFO_FILE_NAME) == 0) { 140 continue; 141 } 142 143 if (packageWriter.AddEntry(entry) != B_OK) 144 return 1; 145 } 146 } 147 148 // add the .PackageInfo, if explicitly specified 149 if (packageInfoFileName != NULL) { 150 result = packageWriter.AddEntry(B_HPKG_PACKAGE_INFO_FILE_NAME, 151 packageInfoFD); 152 if (result != B_OK) 153 return 1; 154 } 155 156 // write the package 157 result = packageWriter.Finish(); 158 if (result != B_OK) 159 return 1; 160 161 if (verbose) 162 printf("\nsuccessfully created package '%s'\n", packageFileName); 163 164 return 0; 165 } 166