xref: /haiku/src/bin/package/command_list.cpp (revision 9760dcae2038d47442f4658c2575844c6cf92c40)
1 /*
2  * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "package.h"
8 
9 #include <ctype.h>
10 #include <errno.h>
11 #include <getopt.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 
16 #include "package.h"
17 #include "PackageEntry.h"
18 #include "PackageEntryAttribute.h"
19 #include "PackageReader.h"
20 #include "StandardErrorOutput.h"
21 
22 
23 struct PackageContentListHandler : PackageContentHandler {
24 	PackageContentListHandler(bool listAttributes)
25 		:
26 		fLevel(0),
27 		fListAttribute(listAttributes)
28 	{
29 	}
30 
31 	virtual status_t HandleEntry(PackageEntry* entry)
32 	{
33 		fLevel++;
34 
35 		int indentation = (fLevel - 1) * 2;
36 		printf("%*s", indentation, "");
37 
38 		// name and size
39 		printf("%-*s", indentation < 32 ? 32 - indentation : 0, entry->Name());
40 		printf("  %8llu", entry->Data().UncompressedSize());
41 
42 		// time
43 		struct tm* time = localtime(&entry->ModifiedTime().tv_sec);
44 		printf("  %04d-%02d-%02d %02d:%02d:%02d",
45 			1900 + time->tm_year, time->tm_mon + 1, time->tm_mday,
46 			time->tm_hour, time->tm_min, time->tm_sec);
47 
48 		// file type
49 		mode_t mode = entry->Mode();
50 		if (S_ISREG(mode))
51 			printf("  -");
52 		else if (S_ISDIR(mode))
53 			printf("  d");
54 		else if (S_ISLNK(mode))
55 			printf("  l");
56 		else
57 			printf("  ?");
58 
59 		// permissions
60 		char buffer[4];
61 		printf("%s", _PermissionString(buffer, mode >> 6,
62 			(mode & S_ISUID) != 0));
63 		printf("%s", _PermissionString(buffer, mode >> 3,
64 			(mode & S_ISGID) != 0));
65 		printf("%s", _PermissionString(buffer, mode, false));
66 
67 		// print the symlink path
68 		if (S_ISLNK(mode))
69 			printf("  -> %s", entry->SymlinkPath());
70 
71 		printf("\n");
72 		return B_OK;
73 	}
74 
75 	virtual status_t HandleEntryAttribute(PackageEntry* entry,
76 		PackageEntryAttribute* attribute)
77 	{
78 		if (!fListAttribute)
79 			return B_OK;
80 
81 		int indentation = fLevel * 2;
82 		printf("%*s<", indentation, "");
83 		printf("%-*s  %8llu", indentation < 31 ? 31 - indentation : 0,
84 			attribute->Name(), attribute->Data().UncompressedSize());
85 
86 		uint32 type = attribute->Type();
87 		if (isprint(type & 0xff) && isprint((type >> 8) & 0xff)
88 			 && isprint((type >> 16) & 0xff) && isprint(type >> 24)) {
89 			printf("  '%c%c%c%c'", int(type >> 24), int((type >> 16) & 0xff),
90 				int((type >> 8) & 0xff), int(type & 0xff));
91 		} else
92 			printf("  %#lx", type);
93 
94 		printf(">\n");
95 		return B_OK;
96 	}
97 
98 	virtual status_t HandleEntryDone(PackageEntry* entry)
99 	{
100 		fLevel--;
101 		return B_OK;
102 	}
103 
104 	virtual void HandleErrorOccurred()
105 	{
106 	}
107 
108 private:
109 	static const char* _PermissionString(char* buffer, uint32 mode, bool sticky)
110 	{
111 		buffer[0] = (mode & 0x4) != 0 ? 'r' : '-';
112 		buffer[1] = (mode & 0x2) != 0 ? 'w' : '-';
113 
114 		if ((mode & 0x1) != 0)
115 			buffer[2] = sticky ? 's' : 'x';
116 		else
117 			buffer[2] = '-';
118 
119 		buffer[3] = '\0';
120 		return buffer;
121 	}
122 
123 private:
124 	int		fLevel;
125 	bool	fListAttribute;
126 };
127 
128 
129 int
130 command_list(int argc, const char* const* argv)
131 {
132 	bool listAttributes = false;
133 
134 	while (true) {
135 		static struct option sLongOptions[] = {
136 			{ "help", no_argument, 0, 'h' },
137 			{ 0, 0, 0, 0 }
138 		};
139 
140 		opterr = 0; // don't print errors
141 		int c = getopt_long(argc, (char**)argv, "+ha", sLongOptions, NULL);
142 		if (c == -1)
143 			break;
144 
145 		switch (c) {
146 			case 'a':
147 				listAttributes = true;
148 				break;
149 
150 			case 'h':
151 				print_usage_and_exit(false);
152 				break;
153 
154 			default:
155 				print_usage_and_exit(true);
156 				break;
157 		}
158 	}
159 
160 	// One argument should remain -- the package file name.
161 	if (optind + 1 != argc)
162 		print_usage_and_exit(true);
163 
164 	const char* packageFileName = argv[optind++];
165 
166 	// open package
167 	StandardErrorOutput errorOutput;
168 	PackageReader packageReader(&errorOutput);
169 	status_t error = packageReader.Init(packageFileName);
170 printf("Init(): %s\n", strerror(error));
171 	if (error != B_OK)
172 		return 1;
173 
174 	// list
175 	PackageContentListHandler handler(listAttributes);
176 	error = packageReader.ParseContent(&handler);
177 printf("ParseContent(): %s\n", strerror(error));
178 	if (error != B_OK)
179 		return 1;
180 
181 	return 0;
182 }
183