Line data Source code
1 : /**
2 : * This file is part of rmlint.
3 : *
4 : * rmlint is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 3 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * rmlint is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with rmlint. If not, see <http://www.gnu.org/licenses/>.
16 : *
17 : * Authors:
18 : *
19 : * - Christopher <sahib> Pahl 2010-2015 (https://github.com/sahib)
20 : * - Daniel <SeeSpotRun> T. 2014-2015 (https://github.com/SeeSpotRun)
21 : *
22 : * Hosted on http://github.com/sahib/rmlint
23 : */
24 :
25 : #include "file.h"
26 : #include "utilities.h"
27 : #include "session.h"
28 : #include "swap-table.h"
29 :
30 : #include <string.h>
31 : #include <unistd.h>
32 : #include <sys/file.h>
33 : #include <string.h>
34 :
35 338024 : RmFile *rm_file_new(struct RmSession *session, const char *path, size_t path_len,
36 : RmStat *statp, RmLintType type, bool is_ppath, unsigned path_index,
37 : short depth) {
38 338024 : RmCfg *cfg = session->cfg;
39 338024 : RmOff actual_file_size = statp->st_size;
40 338024 : RmOff start_seek = 0;
41 :
42 : /* Allow an actual file size of 0 for empty files */
43 338024 : if(actual_file_size != 0) {
44 337660 : if(cfg->use_absolute_start_offset) {
45 280 : start_seek = cfg->skip_start_offset;
46 280 : if(cfg->skip_start_offset >= actual_file_size) {
47 56 : return NULL;
48 : }
49 : } else {
50 337380 : start_seek = cfg->skip_start_factor * actual_file_size;
51 337380 : if((int)(actual_file_size * cfg->skip_end_factor) == 0) {
52 56 : return NULL;
53 : }
54 :
55 337324 : if(start_seek >= actual_file_size) {
56 0 : return NULL;
57 : }
58 : }
59 : }
60 :
61 337912 : RmFile *self = g_slice_new0(RmFile);
62 337925 : self->session = session;
63 :
64 337925 : rm_file_set_path(self, (char *)path, path_len);
65 :
66 337925 : self->depth = depth;
67 337925 : self->path_depth = rm_util_path_depth(path);
68 :
69 337925 : self->inode = statp->st_ino;
70 337925 : self->dev = statp->st_dev;
71 337925 : self->mtime = rm_sys_stat_mtime_seconds(statp);
72 :
73 337924 : if(type == RM_LINT_TYPE_DUPE_CANDIDATE) {
74 337046 : if(cfg->use_absolute_end_offset) {
75 56 : self->file_size = CLAMP(actual_file_size, 1, cfg->skip_end_offset);
76 : } else {
77 336990 : self->file_size = actual_file_size * cfg->skip_end_factor;
78 : }
79 : }
80 :
81 337924 : self->hash_offset = start_seek;
82 :
83 337924 : self->lint_type = type;
84 337924 : self->is_prefd = is_ppath;
85 337924 : self->is_original = false;
86 337924 : self->is_symlink = false;
87 337924 : self->path_index = path_index;
88 :
89 337924 : return self;
90 : }
91 :
92 339606 : void rm_file_set_path(RmFile *file, char *path, size_t path_len) {
93 339606 : if(file->session->cfg->use_meta_cache == false) {
94 331530 : file->folder = rm_trie_insert(&file->session->cfg->file_trie, path, NULL);
95 : } else {
96 16152 : file->path_id = rm_swap_table_insert(file->session->meta_cache,
97 8076 : file->session->meta_cache_path_id,
98 : (char *)path, path_len + 1);
99 : }
100 339605 : }
101 :
102 47549 : void rm_file_lookup_path(const struct RmSession *session, RmFile *file, char *buf) {
103 47549 : g_assert(file);
104 :
105 47549 : RmOff id = file->path_id;
106 :
107 47549 : memset(buf, 0, PATH_MAX);
108 47549 : rm_swap_table_lookup(session->meta_cache, session->meta_cache_path_id, id, buf,
109 : PATH_MAX);
110 47554 : }
111 :
112 992158 : void rm_file_build_path(RmFile *file, char *buf) {
113 992158 : g_assert(file);
114 :
115 992158 : rm_trie_build_path(&file->session->cfg->file_trie, file->folder, buf, PATH_MAX);
116 992159 : }
117 :
118 338374 : void rm_file_destroy(RmFile *file) {
119 338374 : if(file->hardlinks.is_head && file->hardlinks.files) {
120 0 : g_queue_free_full(file->hardlinks.files, (GDestroyNotify)rm_file_destroy);
121 : }
122 :
123 : /* --cache can write cksums in here */
124 338374 : if(file->folder && file->folder->data) {
125 108 : g_free(file->folder->data);
126 : }
127 :
128 338374 : if(file->free_digest) {
129 112558 : rm_digest_free(file->digest);
130 : }
131 :
132 338374 : g_slice_free(RmFile, file);
133 338374 : }
134 :
135 : static const char *LINT_TYPES[] = {[RM_LINT_TYPE_UNKNOWN] = "",
136 : [RM_LINT_TYPE_EMPTY_DIR] = "emptydir",
137 : [RM_LINT_TYPE_NONSTRIPPED] = "nonstripped",
138 : [RM_LINT_TYPE_BADLINK] = "badlink",
139 : [RM_LINT_TYPE_BADUID] = "baduid",
140 : [RM_LINT_TYPE_BADGID] = "badgid",
141 : [RM_LINT_TYPE_BADUGID] = "badugid",
142 : [RM_LINT_TYPE_EMPTY_FILE] = "emptyfile",
143 : [RM_LINT_TYPE_DUPE_CANDIDATE] = "duplicate_file",
144 : [RM_LINT_TYPE_DUPE_DIR_CANDIDATE] = "duplicate_dir",
145 : [RM_LINT_TYPE_UNFINISHED_CKSUM] = "unfinished_cksum"};
146 :
147 443387 : const char *rm_file_lint_type_to_string(RmLintType type) {
148 443387 : return LINT_TYPES[MIN(type, sizeof(LINT_TYPES) / sizeof(const char *))];
149 : }
150 :
151 112558 : RmLintType rm_file_string_to_lint_type(const char *type) {
152 112558 : const int N = sizeof(LINT_TYPES) / sizeof(const char *);
153 1013022 : for(int i = 0; i < N; ++i) {
154 1013022 : if(g_strcmp0(type, LINT_TYPES[i]) == 0) {
155 112558 : return (RmLintType)i;
156 : }
157 : }
158 :
159 0 : return RM_LINT_TYPE_UNKNOWN;
160 : }
161 :
162 170 : bool rm_file_basenames_match(const RmFile *file_a, const RmFile *file_b) {
163 170 : RM_DEFINE_BASENAME(file_a);
164 170 : RM_DEFINE_BASENAME(file_b);
165 :
166 170 : return g_ascii_strcasecmp(file_a_basename, file_b_basename) == 0;
167 : }
|