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