]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - db/hash.c
50f6da0b1a20b2fe44218410a8bddecb97b58123
1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
15 #include "obfuscate.h"
16 #include <sys/xattr.h>
18 static int hash_f(int argc
, char **argv
);
19 static void hash_help(void);
21 static const cmdinfo_t hash_cmd
= {
27 .oneline
= N_("calculate hash value"),
36 " 'hash' prints out the calculated hash value for a string using the\n"
37 "directory/attribute code hash function.\n"
39 " Usage: \"hash [-d|-p parent_ino] <string>\"\n"
59 enum hash_what what
= ATTR
;
62 while ((c
= getopt(argc
, argv
, "dp:")) != EOF
) {
69 p_ino
= strtoull(optarg
, NULL
, 0);
83 for (c
= optind
; c
< argc
; c
++) {
84 struct xfs_name xname
= {
85 .name
= (uint8_t *)argv
[c
],
86 .len
= strlen(argv
[c
]),
91 hashval
= libxfs_dir2_hashname(mp
, &xname
);
94 hashval
= libxfs_parent_hashval(mp
, xname
.name
,
98 hashval
= libxfs_attr_hashname(xname
.name
, xname
.len
);
101 dbprintf("0x%x\n", hashval
);
112 " Generate obfuscated variants of the provided name. Each variant will have\n"
113 " the same dahash value. Names are written to stdout with a NULL separating\n"
116 " -a -- create extended attributes.\n"
117 " -i -- read standard input for the name, up to %d bytes.\n"
118 " -n -- create this many names.\n"
119 " -p -- create directory entries or extended attributes in this file.\n"
120 " -s -- seed the rng with this value.\n"
126 struct name_dup
*next
;
134 unsigned int namelen
)
136 return sizeof(struct name_dup
) + namelen
;
139 #define MAX_DUP_TABLE_BUCKETS (1048575)
142 unsigned int nr_buckets
;
143 struct name_dup
*buckets
[];
148 unsigned int nr_buckets
)
150 return sizeof(struct dup_table
) +
151 (nr_buckets
* sizeof(struct name_dup
*));
156 unsigned long nr_names
,
157 struct dup_table
**tabp
)
166 nr_names
= min(MAX_DUP_TABLE_BUCKETS
, nr_names
);
167 t
= calloc(1, dup_table_sizeof(nr_names
));
171 t
->nr_buckets
= nr_names
;
178 struct dup_table
*tab
)
180 struct name_dup
*ent
, *next
;
186 for (i
= 0; i
< tab
->nr_buckets
; i
++) {
187 ent
= tab
->buckets
[i
];
198 static struct name_dup
*
200 struct dup_table
*tab
,
204 struct name_dup
*ent
;
205 uint32_t crc
= crc32c(~0, name
, namelen
);
207 ent
= tab
->buckets
[crc
% tab
->nr_buckets
];
209 if (ent
->crc
== crc
&&
210 ent
->namelen
== namelen
&&
211 !memcmp(ent
->name
, name
, namelen
))
222 struct dup_table
*tab
,
226 struct name_dup
*dup
;
229 ASSERT(namelen
< MAXNAMELEN
);
231 while ((dup
= dup_table_find(tab
, name
, namelen
)) != NULL
) {
235 ret
= find_alternate(namelen
, (uint8_t *)name
, seq
++);
241 dup
= malloc(name_dup_sizeof(namelen
));
245 dup
->crc
= crc32c(~0, name
, namelen
);
246 dup
->namelen
= namelen
;
247 memcpy(dup
->name
, name
, namelen
);
248 dup
->next
= tab
->buckets
[dup
->crc
% tab
->nr_buckets
];
250 tab
->buckets
[dup
->crc
% tab
->nr_buckets
] = dup
;
261 struct xfs_name dname
= {
262 .name
= (uint8_t *)name
,
265 char direntname
[MAXNAMELEN
+ 1];
266 struct dup_table
*tab
= NULL
;
267 xfs_dahash_t old_hash
;
271 old_hash
= libxfs_dir2_hashname(mp
, &dname
);
277 * User passed in a fd, so we'll use the directory to detect
278 * duplicate names. First create the name that we are passed
279 * in; the new names will be hardlinks to the first file.
281 newfd
= openat(fd
, name
, O_CREAT
, 0600);
287 * Track every name we create so that we don't emit duplicates.
289 error
= dup_table_alloc(nr
, &tab
);
294 dname
.name
= (uint8_t *)direntname
;
295 for (i
= 0; i
< nr
; i
++) {
296 strncpy(direntname
, name
, MAXNAMELEN
);
297 obfuscate_name(old_hash
, namelen
, (uint8_t *)direntname
, true);
298 ASSERT(old_hash
== libxfs_dir2_hashname(mp
, &dname
));
301 error
= linkat(fd
, name
, fd
, direntname
, 0);
302 if (error
&& errno
!= EEXIST
)
305 /* don't print names to stdout */
308 error
= dup_table_store(tab
, direntname
, namelen
);
313 printf("%s%c", direntname
, 0);
327 char xattrname
[MAXNAMELEN
+ 5];
328 struct dup_table
*tab
= NULL
;
329 xfs_dahash_t old_hash
;
333 old_hash
= libxfs_attr_hashname((uint8_t *)name
, namelen
);
337 * User passed in a fd, so we'll use the xattr structure to
338 * detect duplicate names. First create the attribute that we
341 snprintf(xattrname
, MAXNAMELEN
+ 5, "user.%s", name
);
342 error
= fsetxattr(fd
, xattrname
, "1", 1, 0);
347 * Track every name we create so that we don't emit duplicates.
349 error
= dup_table_alloc(nr
, &tab
);
354 for (i
= 0; i
< nr
; i
++) {
355 snprintf(xattrname
, MAXNAMELEN
+ 5, "user.%s", name
);
356 obfuscate_name(old_hash
, namelen
, (uint8_t *)xattrname
+ 5,
358 ASSERT(old_hash
== libxfs_attr_hashname(
359 (uint8_t *)xattrname
+ 5, namelen
));
362 error
= fsetxattr(fd
, xattrname
, "1", 1, 0);
366 /* don't print names to stdout */
369 error
= dup_table_store(tab
, xattrname
, namelen
+ 5);
374 printf("%s%c", xattrname
, 0);
386 const char *path
= NULL
;
387 bool read_stdin
= false;
388 bool create_xattr
= false;
389 unsigned long nr
= 1, seed
= 0;
394 while ((c
= getopt(argc
, argv
, "ain:p:s:")) != EOF
) {
403 nr
= strtoul(optarg
, NULL
, 10);
409 seed
= strtoul(optarg
, NULL
, 10);
422 oflags
= O_RDONLY
| O_DIRECTORY
;
424 fd
= open(path
, oflags
);
436 char buf
[MAXNAMELEN
];
439 len
= fread(buf
, 1, MAXNAMELEN
- 1, stdin
);
442 error
= collide_xattrs(nr
, buf
, len
, fd
);
444 error
= collide_dirents(nr
, buf
, len
, fd
);
446 printf(_("hashcoll: %s\n"), strerror(error
));
452 for (c
= optind
; c
< argc
; c
++) {
453 size_t len
= strlen(argv
[c
]);
456 error
= collide_xattrs(nr
, argv
[c
], len
, fd
);
458 error
= collide_dirents(nr
, argv
[c
], len
, fd
);
460 printf(_("hashcoll: %s\n"), strerror(error
));
471 static cmdinfo_t hashcoll_cmd
= {
476 .args
= N_("[-a] [-s seed] [-n nr] [-p path] -i|names..."),
477 .oneline
= N_("create names that produce dahash collisions"),
478 .help
= hashcoll_help
,
484 add_command(&hash_cmd
);
485 add_command(&hashcoll_cmd
);