| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
# Copyright (c) 2024-2025 Philipp Schafft <lion@cpan.org> |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# licensed under Artistic License 2.0 (see LICENSE file) |
|
4
|
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
# ABSTRACT: generic module for extracting information from filesystems |
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
package File::Information::Inode; |
|
9
|
|
|
|
|
|
|
|
|
10
|
3
|
|
|
3
|
|
42
|
use v5.10; |
|
|
3
|
|
|
|
|
12
|
|
|
11
|
3
|
|
|
3
|
|
16
|
use strict; |
|
|
3
|
|
|
|
|
7
|
|
|
|
3
|
|
|
|
|
95
|
|
|
12
|
3
|
|
|
3
|
|
19
|
use warnings; |
|
|
3
|
|
|
|
|
7
|
|
|
|
3
|
|
|
|
|
211
|
|
|
13
|
|
|
|
|
|
|
|
|
14
|
3
|
|
|
3
|
|
20
|
use parent 'File::Information::Base'; |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
22
|
|
|
15
|
|
|
|
|
|
|
|
|
16
|
3
|
|
|
3
|
|
366
|
use Carp; |
|
|
3
|
|
|
|
|
23
|
|
|
|
3
|
|
|
|
|
268
|
|
|
17
|
3
|
|
|
3
|
|
126
|
use File::Spec; |
|
|
3
|
|
|
|
|
7
|
|
|
|
3
|
|
|
|
|
238
|
|
|
18
|
3
|
|
|
3
|
|
26
|
use Fcntl qw(S_ISREG S_ISDIR S_ISLNK S_ISBLK S_ISCHR S_ISFIFO S_ISSOCK S_IWUSR S_IWGRP S_IWOTH SEEK_SET); |
|
|
3
|
|
|
|
|
9
|
|
|
|
3
|
|
|
|
|
479
|
|
|
19
|
|
|
|
|
|
|
|
|
20
|
3
|
|
|
3
|
|
21
|
use Data::Identifier v0.08; |
|
|
3
|
|
|
|
|
72
|
|
|
|
3
|
|
|
|
|
23
|
|
|
21
|
3
|
|
|
3
|
|
171
|
use Data::Identifier::Generate; |
|
|
3
|
|
|
|
|
31
|
|
|
|
3
|
|
|
|
|
47421
|
|
|
22
|
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
our $VERSION = v0.16; |
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
my $HAVE_XATTR = eval {require File::ExtAttr; 1;}; |
|
26
|
|
|
|
|
|
|
my $HAVE_FILE_VALUEFILE = eval {require File::ValueFile::Simple::Reader; 1;}; |
|
27
|
|
|
|
|
|
|
my $HAVE_CONFIG_INI_READER = eval {require Config::INI::Reader; 1;}; |
|
28
|
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
my %_ntfs_attributes = ( |
|
30
|
|
|
|
|
|
|
FILE_ATTRIBUTE_READONLY => 0x0001, |
|
31
|
|
|
|
|
|
|
FILE_ATTRIBUTE_HIDDEN => 0x0002, |
|
32
|
|
|
|
|
|
|
FILE_ATTRIBUTE_SYSTEM => 0x0004, |
|
33
|
|
|
|
|
|
|
FILE_ATTRIBUTE_ARCHIVE => 0x0020, |
|
34
|
|
|
|
|
|
|
FILE_ATTRIBUTE_TEMPORARY => 0x0100, |
|
35
|
|
|
|
|
|
|
FILE_ATTRIBUTE_COMPRESSED => 0x0800, |
|
36
|
|
|
|
|
|
|
FILE_ATTRIBUTE_OFFLINE => 0x1000, |
|
37
|
|
|
|
|
|
|
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED => 0x2000, |
|
38
|
|
|
|
|
|
|
); |
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
my %_tagpool_directory_setting_tagmap; # define here, but only load (below) if we $HAVE_FILE_VALUEFILE |
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
my %_magic_map = ( |
|
43
|
|
|
|
|
|
|
# image/* |
|
44
|
|
|
|
|
|
|
"\xff\xd8\xff" => 'image/jpeg', |
|
45
|
|
|
|
|
|
|
"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a" => 'image/png', |
|
46
|
|
|
|
|
|
|
'GIF87a' => 'image/gif', |
|
47
|
|
|
|
|
|
|
'GIF89a' => 'image/gif', |
|
48
|
|
|
|
|
|
|
"\0\0\1\0" => 'image/vnd.microsoft.icon', |
|
49
|
|
|
|
|
|
|
# audio/* |
|
50
|
|
|
|
|
|
|
'fLaC' => 'audio/flac', |
|
51
|
|
|
|
|
|
|
# application/* |
|
52
|
|
|
|
|
|
|
'%PDF-' => 'application/pdf', |
|
53
|
|
|
|
|
|
|
"PK\x03\x04" => 'application/zip', |
|
54
|
|
|
|
|
|
|
'%!PS-Adobe-' => 'application/postscript', |
|
55
|
|
|
|
|
|
|
); |
|
56
|
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
my %_wk_tagged_as_tags = ( |
|
58
|
|
|
|
|
|
|
(map {$_ => {for => 'write-mode'}} qw(7b177183-083c-4387-abd3-8793eb647373 3877b2ef-6c77-423f-b15f-76508fbd48ed 4dc9fd07-7ef3-4215-8874-31d78ed55c22)), |
|
59
|
|
|
|
|
|
|
(map {$File::Information::Base::_mediatypes{$_} => {for => 'mediatype', mediatype => $_}} keys %File::Information::Base::_mediatypes), |
|
60
|
|
|
|
|
|
|
'f418cdb9-64a7-4f15-9a18-63f7755c5b47' => {for => 'finalmode', implies => [qw(7b177183-083c-4387-abd3-8793eb647373)]}, |
|
61
|
|
|
|
|
|
|
'cb9c2c8a-b6bd-4733-80a4-5bd65af6b957' => {for => 'finalmode'}, |
|
62
|
|
|
|
|
|
|
); |
|
63
|
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
my %_URLZONE = ( |
|
65
|
|
|
|
|
|
|
# tag-ise 66294283-0a5d-4e78-a4b0-91df2c82068d # URLZONE-namespace |
|
66
|
|
|
|
|
|
|
0 => {ise => 'd0e96897-b82f-5696-aa8e-8c29a16ab613', displayname => 'URLZONE_LOCAL_MACHINE'}, |
|
67
|
|
|
|
|
|
|
1 => {ise => 'cb576748-97f3-5fd7-80db-3682a94c67aa', displayname => 'URLZONE_INTRANET'}, |
|
68
|
|
|
|
|
|
|
2 => {ise => '445acf47-7049-5af1-8ed9-fecb54a8c517', displayname => 'URLZONE_TRUSTED'}, |
|
69
|
|
|
|
|
|
|
3 => {ise => 'a80b2f16-0db7-5536-a3ee-be8d85d123bd', displayname => 'URLZONE_INTERNET'}, |
|
70
|
|
|
|
|
|
|
4 => {ise => '73ef6c11-cdef-5547-be38-aa2cede0d4ea', displayname => 'URLZONE_UNTRUSTED'}, |
|
71
|
|
|
|
|
|
|
); |
|
72
|
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
my %_properties = ( |
|
74
|
|
|
|
|
|
|
(map {$_ => {loader => \&_load_stat}}qw(st_dev st_ino st_mode st_nlink st_uid st_gid st_rdev st_size st_blksize st_blocks st_atime st_mtime st_ctime stat_readonly stat_cachehash)), |
|
75
|
|
|
|
|
|
|
magic_mediatype => {loader => \&_load_magic, rawtype => 'mediatype'}, |
|
76
|
|
|
|
|
|
|
magic_valuefile_version => {loader => \&_load_magic, rawtype => 'uuid'}, |
|
77
|
|
|
|
|
|
|
magic_valuefile_format => {loader => \&_load_magic, rawtype => 'ise'}, |
|
78
|
|
|
|
|
|
|
db_inode_tag => {loader => \&_load_db, rawtype => 'Data::TagDB::Tag'}, |
|
79
|
|
|
|
|
|
|
content_sha_3_512_uuid => {loader => \&_load_contentise, rawtype => 'uuid'}, |
|
80
|
|
|
|
|
|
|
content_sha_1_160_sha_3_512_uuid => {loader => \&_load_contentise, rawtype => 'uuid'}, |
|
81
|
|
|
|
|
|
|
store_file => {loader => \&_load_fstore, rawtype => 'File::FStore::File'}, |
|
82
|
|
|
|
|
|
|
shebang_line => {loader => \&_load_shebang}, |
|
83
|
|
|
|
|
|
|
shebang_interpreter => {loader => \&_load_shebang, rawtype => 'filename'}, |
|
84
|
|
|
|
|
|
|
); |
|
85
|
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
$_properties{$_}{rawtype} = 'unixts' foreach qw(st_atime st_mtime st_ctime); |
|
87
|
|
|
|
|
|
|
$_properties{$_}{rawtype} = 'bool' foreach qw(stat_readonly); |
|
88
|
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
if ($HAVE_XATTR) { |
|
90
|
|
|
|
|
|
|
$_properties{'xattr_'.$_} = {loader => \&_load_xattr, xattr_key => $_} foreach qw(mime_type charset creator); |
|
91
|
|
|
|
|
|
|
$_properties{'xattr_mime_type'}{rawtype} = 'mediatype'; |
|
92
|
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
$_properties{'xattr_xdg_'.($_ =~ tr/.-/__/r)} = {loader => \&_load_xattr, xattr_key => 'xdg.'.$_} foreach qw(comment origin.url origin.email.subject origin.email.from origin.email.message-id language creator publisher); |
|
94
|
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
$_properties{'xattr_dublincore_'.($_ =~ tr/.-/__/r)} = {loader => \&_load_xattr, xattr_key => 'dublincore.'.$_} foreach qw(title creator subject description publisher contributor date type format identifier source language relation coverage rights); |
|
96
|
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
$_properties{'xattr_utag_'.($_ =~ tr/.-/__/r)} = {loader => \&_load_xattr, rawtype => 'ise', xattr_key => 'utag.'.$_} foreach qw(ise write-mode final-mode); |
|
98
|
|
|
|
|
|
|
$_properties{'xattr_utag_final_'.($_ =~ tr/.-/__/r)} = {loader => \&_load_xattr, lifecycle => 'final', xattr_key => 'utag.final.'.$_} foreach qw(file.size file.encoding file.hash); |
|
99
|
|
|
|
|
|
|
$_properties{'xattr_utag_final_file_encoding'}{parts} = [qw(ise mediatype)]; |
|
100
|
|
|
|
|
|
|
$_properties{'xattr_utag_final_file_hash'}{parsing} = 'utag'; |
|
101
|
|
|
|
|
|
|
$_properties{'xattr_utag_final_file_hash_size'} = {loader => \&_load_redirect, redirect => 'xattr_utag_final_file_hash'}; |
|
102
|
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
$_properties{'ntfs_'.lc($_)} = {loader => \&_load_ntfs_xattr, ntfs_attribute => $_, rawtype => 'bool'} foreach keys %_ntfs_attributes; |
|
104
|
|
|
|
|
|
|
} |
|
105
|
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
if ($HAVE_FILE_VALUEFILE) { |
|
107
|
|
|
|
|
|
|
my $config = {loader => \&_load_tagpool_directory}; |
|
108
|
|
|
|
|
|
|
$_properties{'tagpool_directory_'.$_} = {%{$config}} foreach qw(title comment description inode mtime pool_uuid timestamp); |
|
109
|
|
|
|
|
|
|
$_properties{'tagpool_directory_setting_'.($_ =~ tr/-/_/r)} = {%{$config}} foreach qw(thumbnail-uri thumbnail-mode update-mode add-mode file-tags tag-mode tag-implies entry-sort-order tag tag-root tag-parent tag-type entry-display-name entry-sort-key); |
|
110
|
|
|
|
|
|
|
$_properties{'tagpool_directory_'.$_}{rawtype} = 'unixts' foreach qw(mtime timestamp); |
|
111
|
|
|
|
|
|
|
$_properties{'tagpool_directory_'.$_}{rawtype} = 'uuid' foreach qw(pool_uuid); |
|
112
|
|
|
|
|
|
|
$_properties{'tagpool_directory_setting_'.($_ =~ tr/-/_/r)}{rawtype} = 'ise' foreach qw(tag tag-root tag-parent tag-type); |
|
113
|
|
|
|
|
|
|
$_properties{'tagpool_directory_throw_option_'.$_} = {%{$config}} foreach qw(linkname linktype filter); |
|
114
|
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
$_properties{'tagpool_file_'.($_ =~ tr/-/_/r)} = {loader => \&_load_tagpool_file} foreach qw(title comment description mtime timestamp inode size actual-size original-url original-description-url pool-name-suffix original-filename uuid mediatype write-mode finalmode thumbnail tags); |
|
116
|
|
|
|
|
|
|
$_properties{'tagpool_file_'.$_}{rawtype} = 'unixts' foreach qw(mtime timestamp); |
|
117
|
|
|
|
|
|
|
$_properties{'tagpool_file_'.($_ =~ tr/-/_/r)}{rawtype} = 'uuid' foreach qw(uuid write-mode finalmode tags); |
|
118
|
|
|
|
|
|
|
$_properties{'tagpool_file_'.($_ =~ tr/-/_/r)}{rawtype} = 'mediatype' foreach qw(mediatype); |
|
119
|
|
|
|
|
|
|
$_properties{'tagpool_file_'.($_ =~ tr/-/_/r)}{rawtype} = 'filename' foreach qw(thumbnail); |
|
120
|
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
%_tagpool_directory_setting_tagmap = ( |
|
123
|
|
|
|
|
|
|
'thumbnail-mode' => { |
|
124
|
|
|
|
|
|
|
'file-uri' => 'e4c80ac0-7c71-4548-9e84-9422bf1dae11', |
|
125
|
|
|
|
|
|
|
'tag-uri' => '0025b1b2-20db-40e6-9345-baf0f9b5e166', |
|
126
|
|
|
|
|
|
|
'tag' => '30c09ebd-bc14-48a3-8c0f-2d66c3d6e429', |
|
127
|
|
|
|
|
|
|
'throw-filter' => 'c4438812-6011-42ee-984a-183745d9b013', |
|
128
|
|
|
|
|
|
|
}, |
|
129
|
|
|
|
|
|
|
'update-mode' => { |
|
130
|
|
|
|
|
|
|
'add' => 'dd1ff55a-fd87-428d-bd7e-57fc56488e72', |
|
131
|
|
|
|
|
|
|
'throw' => '41217e01-4468-4d54-b613-902835ae0596', |
|
132
|
|
|
|
|
|
|
}, |
|
133
|
|
|
|
|
|
|
'add-mode' => { |
|
134
|
|
|
|
|
|
|
'all' => '65de001a-9063-4591-8b67-99ee1f91c4dd', |
|
135
|
|
|
|
|
|
|
'no-boring' => 'db7c2ac0-4205-4f99-8556-c48cbb51138e', |
|
136
|
|
|
|
|
|
|
'none' => '36fd66fd-b07f-4010-b796-05b488826571', |
|
137
|
|
|
|
|
|
|
}, |
|
138
|
|
|
|
|
|
|
'file-tags' => { |
|
139
|
|
|
|
|
|
|
'root' => '908c9015-b760-441e-85bf-ba98b5ff452b', |
|
140
|
|
|
|
|
|
|
'level' => '53e36ce9-8afb-425e-9cae-2016cbdc27fe', |
|
141
|
|
|
|
|
|
|
'root-and-level' => 'f8733429-8dc8-493b-8b91-958c6485afeb', |
|
142
|
|
|
|
|
|
|
'parent-and-level' => 'e2cbc030-447a-4ee3-8adc-5b84c0400038', |
|
143
|
|
|
|
|
|
|
'root-and-parent-and-level' => 'fe58aa1a-4cd7-49ca-a11d-ceab5223ccd9', |
|
144
|
|
|
|
|
|
|
}, |
|
145
|
|
|
|
|
|
|
'tag-mode' => { |
|
146
|
|
|
|
|
|
|
'random' => '02110f2e-b2c1-45a8-910b-0210f87cb7a1', |
|
147
|
|
|
|
|
|
|
'named-random' => '7c6b6534-bd85-40c6-99f0-c0d308f790b6', |
|
148
|
|
|
|
|
|
|
'namebased' => '39a2be03-7d07-41c4-93da-815c5f5d6f8d', |
|
149
|
|
|
|
|
|
|
}, |
|
150
|
|
|
|
|
|
|
'tag-implies' => { |
|
151
|
|
|
|
|
|
|
'root' => '60384e20-8d88-4171-970b-560ddafc1f95', |
|
152
|
|
|
|
|
|
|
'parent' => '5e5acf8e-4e07-4ce9-8516-a014a7fbf91a', |
|
153
|
|
|
|
|
|
|
'root-and-parent' => '112db395-84c3-4711-b99f-b5c6d6051781', |
|
154
|
|
|
|
|
|
|
}, |
|
155
|
|
|
|
|
|
|
'entry-sort-order' => { |
|
156
|
|
|
|
|
|
|
'asc' => '994e3f9c-79c1-40d1-892f-d66d406538a1', |
|
157
|
|
|
|
|
|
|
'desc' => '54140078-a52a-4693-9f66-30b4ac4f1da4', |
|
158
|
|
|
|
|
|
|
}, |
|
159
|
|
|
|
|
|
|
); |
|
160
|
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
foreach my $setting (values %_tagpool_directory_setting_tagmap) { |
|
162
|
|
|
|
|
|
|
foreach my $entry (values %{$setting}) { |
|
163
|
|
|
|
|
|
|
$entry = {ise => $entry} unless ref $entry; |
|
164
|
|
|
|
|
|
|
} |
|
165
|
|
|
|
|
|
|
} |
|
166
|
|
|
|
|
|
|
} |
|
167
|
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
{ |
|
169
|
|
|
|
|
|
|
my %_wk = ( |
|
170
|
|
|
|
|
|
|
# tagpool-sysfile-type: |
|
171
|
|
|
|
|
|
|
'e6d6bb07-1a6a-46f6-8c18-5aa6ea24d7cb' => {displayname => 'regular'}, |
|
172
|
|
|
|
|
|
|
'577c3095-922b-4569-805d-a5df94686b35' => {displayname => 'directory'}, |
|
173
|
|
|
|
|
|
|
'76ae899c-ad0c-4bbc-b693-485f91779b9f' => {displayname => 'symlink'}, |
|
174
|
|
|
|
|
|
|
'f1765bfc-96d5-4ff3-ba2e-16a2a9f24cb3' => {displayname => 'blockdevice'}, |
|
175
|
|
|
|
|
|
|
'241431a9-c83f-4bce-93ff-0024021cd754' => {displayname => 'characterdevice'}, |
|
176
|
|
|
|
|
|
|
'3d680b7b-115c-486a-a186-4ad77facc52e' => {displayname => 'fifo'}, |
|
177
|
|
|
|
|
|
|
'3d1cb160-5fc5-4d8e-a8d3-3b0ec85bb000' => {displayname => 'socket'}, |
|
178
|
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
# write-mode: |
|
180
|
|
|
|
|
|
|
'7b177183-083c-4387-abd3-8793eb647373' => {displayname => 'none'}, |
|
181
|
|
|
|
|
|
|
'3877b2ef-6c77-423f-b15f-76508fbd48ed' => {displayname => 'random access'}, |
|
182
|
|
|
|
|
|
|
'4dc9fd07-7ef3-4215-8874-31d78ed55c22' => {displayname => 'append only'}, |
|
183
|
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
# Final states: |
|
185
|
|
|
|
|
|
|
'f418cdb9-64a7-4f15-9a18-63f7755c5b47' => {displayname => 'final'}, |
|
186
|
|
|
|
|
|
|
'cb9c2c8a-b6bd-4733-80a4-5bd65af6b957' => {displayname => 'auto-final'}, |
|
187
|
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
# ValueFile: |
|
189
|
|
|
|
|
|
|
'54bf8af4-b1d7-44da-af48-5278d11e8f32' => {displayname => 'ValueFile'}, |
|
190
|
|
|
|
|
|
|
'e5da6a39-46d5-48a9-b174-5c26008e208e' => {displayname => 'tagpool-source-format'}, |
|
191
|
|
|
|
|
|
|
'afdb46f2-e13f-4419-80d7-c4b956ed85fa' => {displayname => 'tagpool-taglist-format-v1'}, |
|
192
|
|
|
|
|
|
|
'25990339-3913-4b5a-8bcf-5042ef6d8b5e' => {displayname => 'tagpool-httpd-htdirectories-format'}, |
|
193
|
|
|
|
|
|
|
'11431b85-41cd-4be5-8d88-a769ebbd603f' => {displayname => 'tagpool-directory-info-format'}, |
|
194
|
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
#'' => {displayname => ''}, |
|
196
|
|
|
|
|
|
|
); |
|
197
|
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
foreach my $setting (values %_tagpool_directory_setting_tagmap) { |
|
199
|
|
|
|
|
|
|
foreach my $key (keys %{$setting}) { |
|
200
|
|
|
|
|
|
|
my $value = $setting->{$key}; |
|
201
|
|
|
|
|
|
|
$value->{displayname} //= $key; |
|
202
|
|
|
|
|
|
|
$_wk{$value->{ise}} = $value; |
|
203
|
|
|
|
|
|
|
} |
|
204
|
|
|
|
|
|
|
} |
|
205
|
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
while (my ($mediatype, $ise) = each %File::Information::Base::_mediatypes) { |
|
207
|
|
|
|
|
|
|
($_wk{$ise} //= {})->{displayname} //= $mediatype; |
|
208
|
|
|
|
|
|
|
} |
|
209
|
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
while (my ($key, $value) = each %_wk) { |
|
212
|
|
|
|
|
|
|
Data::Identifier->new(ise => $key, %{$value})->register; |
|
213
|
|
|
|
|
|
|
} |
|
214
|
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
foreach my $value (values %_URLZONE) { |
|
216
|
|
|
|
|
|
|
Data::Identifier->new(ise => $value->{ise}, displayname => $value->{displayname})->register; |
|
217
|
|
|
|
|
|
|
} |
|
218
|
|
|
|
|
|
|
} |
|
219
|
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
if ($HAVE_CONFIG_INI_READER) { |
|
221
|
|
|
|
|
|
|
$_properties{'zonetransfer_'.lc($_)} = {loader => \&_load_zonetransfer, zonetransfer_key => $_} foreach qw(HostIpAddress ZoneId ReferrerUrl HostUrl); |
|
222
|
|
|
|
|
|
|
} |
|
223
|
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
{ |
|
225
|
|
|
|
|
|
|
my %_S_IS_to_tagpool_ise = ( |
|
226
|
|
|
|
|
|
|
S_ISREG => 'e6d6bb07-1a6a-46f6-8c18-5aa6ea24d7cb', |
|
227
|
|
|
|
|
|
|
S_ISDIR => '577c3095-922b-4569-805d-a5df94686b35', |
|
228
|
|
|
|
|
|
|
S_ISLNK => '76ae899c-ad0c-4bbc-b693-485f91779b9f', |
|
229
|
|
|
|
|
|
|
S_ISBLK => 'f1765bfc-96d5-4ff3-ba2e-16a2a9f24cb3', |
|
230
|
|
|
|
|
|
|
S_ISCHR => '241431a9-c83f-4bce-93ff-0024021cd754', |
|
231
|
|
|
|
|
|
|
S_ISFIFO => '3d680b7b-115c-486a-a186-4ad77facc52e', |
|
232
|
|
|
|
|
|
|
S_ISSOCK => '3d1cb160-5fc5-4d8e-a8d3-3b0ec85bb000', |
|
233
|
|
|
|
|
|
|
); |
|
234
|
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
$_properties{tagpool_inode_type} = {loader => sub { |
|
236
|
|
|
|
|
|
|
my ($self, undef, %opts) = @_; |
|
237
|
|
|
|
|
|
|
if ($opts{lifecycle} eq 'current') { |
|
238
|
|
|
|
|
|
|
my $mode = $self->get('st_mode', default => undef, as => 'raw'); |
|
239
|
|
|
|
|
|
|
my $ise; |
|
240
|
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
if (defined($mode)) { |
|
242
|
|
|
|
|
|
|
foreach my $key (keys %_S_IS_to_tagpool_ise) { |
|
243
|
|
|
|
|
|
|
my $func = __PACKAGE__->can($key); |
|
244
|
|
|
|
|
|
|
if (defined $func) { |
|
245
|
|
|
|
|
|
|
if (eval {$func->($mode)}) { |
|
246
|
|
|
|
|
|
|
$ise = $_S_IS_to_tagpool_ise{$key}; |
|
247
|
|
|
|
|
|
|
last; |
|
248
|
|
|
|
|
|
|
} |
|
249
|
|
|
|
|
|
|
} |
|
250
|
|
|
|
|
|
|
} |
|
251
|
|
|
|
|
|
|
} |
|
252
|
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
if (defined $ise) { |
|
254
|
|
|
|
|
|
|
(($self->{properties_values} //= {})->{current} //= {})->{tagpool_inode_type} = {raw => $ise}; |
|
255
|
|
|
|
|
|
|
} |
|
256
|
|
|
|
|
|
|
} |
|
257
|
|
|
|
|
|
|
}, rawtype => 'ise'}, |
|
258
|
|
|
|
|
|
|
} |
|
259
|
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
sub _new { |
|
261
|
2
|
|
|
2
|
|
11
|
my ($pkg, %opts) = @_; |
|
262
|
2
|
|
|
|
|
16
|
my $self = $pkg->SUPER::_new(%opts, properties => \%_properties); |
|
263
|
|
|
|
|
|
|
|
|
264
|
2
|
50
|
|
|
|
7
|
croak 'No handle is given' unless defined $self->{handle}; |
|
265
|
|
|
|
|
|
|
|
|
266
|
2
|
|
|
|
|
10
|
return $self; |
|
267
|
|
|
|
|
|
|
} |
|
268
|
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
#@returns File::Information::Filesystem |
|
271
|
|
|
|
|
|
|
sub filesystem { |
|
272
|
0
|
|
|
0
|
1
|
0
|
my ($self, %opts) = @_; |
|
273
|
0
|
|
0
|
|
|
0
|
my $filesystem = $self->{filesystem} //= eval { |
|
274
|
0
|
|
|
|
|
0
|
my $instance = $self->instance; |
|
275
|
0
|
|
|
|
|
0
|
my $st_dev = $self->get('st_dev'); |
|
276
|
0
|
|
|
|
|
0
|
$instance->_filesystem_for($st_dev); |
|
277
|
|
|
|
|
|
|
}; |
|
278
|
|
|
|
|
|
|
|
|
279
|
0
|
0
|
|
|
|
0
|
return $filesystem if defined $filesystem; |
|
280
|
0
|
0
|
|
|
|
0
|
return $opts{default} if exists $opts{default}; |
|
281
|
0
|
|
|
|
|
0
|
croak 'Cannot locate filesystem for inode'; |
|
282
|
|
|
|
|
|
|
} |
|
283
|
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
sub tagpool { |
|
286
|
0
|
|
|
0
|
1
|
0
|
my ($self) = @_; |
|
287
|
0
|
|
0
|
|
|
0
|
my $tagpools = $self->{_tagpools} //= do { |
|
288
|
0
|
|
|
|
|
0
|
my $pools = $self->instance->_tagpool; |
|
289
|
0
|
|
|
|
|
0
|
[map {$pools->{$_}} keys %{$self->_tagpool_paths}] |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
290
|
|
|
|
|
|
|
}; |
|
291
|
|
|
|
|
|
|
|
|
292
|
0
|
0
|
0
|
|
|
0
|
return wantarray ? @{$tagpools} : ($tagpools->[0] // croak 'Not part of any tagpool'); |
|
|
0
|
|
|
|
|
0
|
|
|
293
|
|
|
|
|
|
|
} |
|
294
|
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
sub peek { |
|
297
|
0
|
|
|
0
|
1
|
0
|
my ($self, %opts) = @_; |
|
298
|
0
|
|
0
|
|
|
0
|
my $wanted = $opts{wanted} || 0; |
|
299
|
0
|
|
0
|
|
|
0
|
my $required = $opts{required} || 0; |
|
300
|
0
|
|
|
|
|
0
|
my $buffer; |
|
301
|
|
|
|
|
|
|
|
|
302
|
0
|
0
|
0
|
|
|
0
|
if (defined($self->{_peek_buffer}) && length($self->{_peek_buffer}) >= $required) { |
|
303
|
0
|
|
|
|
|
0
|
return $self->{_peek_buffer}; |
|
304
|
|
|
|
|
|
|
} |
|
305
|
|
|
|
|
|
|
|
|
306
|
0
|
0
|
|
|
|
0
|
$wanted = $required if $required > $wanted; |
|
307
|
0
|
0
|
|
|
|
0
|
$wanted = 4096 if $wanted < 4096; # enforce some minimum |
|
308
|
|
|
|
|
|
|
|
|
309
|
0
|
0
|
|
|
|
0
|
croak 'Requested peek too big: '.$wanted if $wanted > 65536; |
|
310
|
|
|
|
|
|
|
|
|
311
|
0
|
|
|
|
|
0
|
$self->_get_fh->read($buffer, $wanted); |
|
312
|
|
|
|
|
|
|
|
|
313
|
0
|
0
|
|
|
|
0
|
croak 'Cannot peek required amount of data' if length($buffer) < $required; |
|
314
|
|
|
|
|
|
|
|
|
315
|
0
|
|
|
|
|
0
|
return $self->{_peek_buffer} = $buffer; |
|
316
|
|
|
|
|
|
|
} |
|
317
|
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
sub open_handle { |
|
320
|
0
|
|
|
0
|
1
|
0
|
my ($self, $mode) = @_; |
|
321
|
0
|
|
|
|
|
0
|
my @sa; |
|
322
|
|
|
|
|
|
|
my @sb; |
|
323
|
|
|
|
|
|
|
|
|
324
|
0
|
0
|
0
|
|
|
0
|
open(my $handle, $mode // '<', $self->{path} // croak 'Open not supported on this object') or croak 'Cannot open inode: '.$!; |
|
|
|
|
0
|
|
|
|
|
|
325
|
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
# (Re)stat() late so any effects of the open are taken into account: |
|
327
|
0
|
|
|
|
|
0
|
@sa = stat($self->{handle}); |
|
328
|
0
|
|
|
|
|
0
|
@sb = stat($handle); |
|
329
|
|
|
|
|
|
|
|
|
330
|
0
|
|
|
|
|
0
|
for (my $i = 0; $i < 13; $i++) { |
|
331
|
0
|
|
0
|
|
|
0
|
my $va = $sa[$i] // '<undef>'; |
|
332
|
0
|
|
0
|
|
|
0
|
my $vb = $sb[$i] // '<undef>'; |
|
333
|
|
|
|
|
|
|
|
|
334
|
0
|
0
|
|
|
|
0
|
croak 'Race lost' unless $va eq $vb; |
|
335
|
|
|
|
|
|
|
} |
|
336
|
|
|
|
|
|
|
|
|
337
|
0
|
|
|
|
|
0
|
return $handle; |
|
338
|
|
|
|
|
|
|
} |
|
339
|
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
# ---------------- |
|
341
|
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
sub _get_fh { |
|
343
|
0
|
|
|
0
|
|
0
|
my ($self) = @_; |
|
344
|
0
|
|
|
|
|
0
|
my $fh = $self->{handle}; |
|
345
|
|
|
|
|
|
|
|
|
346
|
0
|
0
|
|
|
|
0
|
$fh->seek(0, SEEK_SET) or croak $!; |
|
347
|
|
|
|
|
|
|
|
|
348
|
0
|
|
|
|
|
0
|
return $fh; |
|
349
|
|
|
|
|
|
|
} |
|
350
|
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
sub _tagpool_paths { |
|
352
|
0
|
|
|
0
|
|
0
|
my ($self) = @_; |
|
353
|
|
|
|
|
|
|
|
|
354
|
0
|
0
|
|
|
|
0
|
unless (defined $self->{_tagpool_paths}) { |
|
355
|
0
|
|
|
|
|
0
|
my File::Information $instance = $self->instance; |
|
356
|
0
|
|
|
|
|
0
|
my $sysfile_cache = $instance->_tagpool_sysfile_cache; |
|
357
|
0
|
|
|
|
|
0
|
my @stat; |
|
358
|
|
|
|
|
|
|
my %paths; |
|
359
|
0
|
|
|
|
|
0
|
my $found; |
|
360
|
|
|
|
|
|
|
|
|
361
|
0
|
0
|
|
|
|
0
|
return unless scalar @{$instance->_tagpool_path}; |
|
|
0
|
|
|
|
|
0
|
|
|
362
|
|
|
|
|
|
|
|
|
363
|
0
|
|
|
|
|
0
|
@stat = eval {stat($self->{handle})}; |
|
|
0
|
|
|
|
|
0
|
|
|
364
|
0
|
0
|
0
|
|
|
0
|
return $self->{_tagpool_paths} = {} unless scalar(@stat) && S_ISREG($stat[2]); |
|
365
|
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
# Try the cache first: |
|
367
|
|
|
|
|
|
|
{ |
|
368
|
0
|
|
|
|
|
0
|
my $key = $stat[1].'@'.$stat[0]; |
|
|
0
|
|
|
|
|
0
|
|
|
369
|
|
|
|
|
|
|
|
|
370
|
0
|
|
|
|
|
0
|
foreach my $pool_path (keys %{$sysfile_cache}) { |
|
|
0
|
|
|
|
|
0
|
|
|
371
|
0
|
|
|
|
|
0
|
$found = $sysfile_cache->{$pool_path}{$key}; |
|
372
|
0
|
0
|
|
|
|
0
|
if (defined $found) { |
|
373
|
0
|
|
|
|
|
0
|
$paths{$pool_path} = $found; |
|
374
|
|
|
|
|
|
|
} |
|
375
|
|
|
|
|
|
|
} |
|
376
|
|
|
|
|
|
|
} |
|
377
|
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
# Then guess: |
|
379
|
0
|
0
|
|
|
|
0
|
unless (defined($found)) { |
|
380
|
0
|
0
|
|
|
|
0
|
if (defined $self->{path}) { |
|
381
|
|
|
|
|
|
|
outer: |
|
382
|
0
|
|
|
|
|
0
|
foreach my $uuid ($self->{path} =~ /([0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12})/g) { |
|
383
|
0
|
|
|
|
|
0
|
foreach my $pool_path (@{$instance->_tagpool_path}) { |
|
|
0
|
|
|
|
|
0
|
|
|
384
|
0
|
|
|
|
|
0
|
my $info_path = File::Spec->catdir($pool_path => 'data', 'info.'.$uuid); |
|
385
|
0
|
|
|
|
|
0
|
my $info; |
|
386
|
|
|
|
|
|
|
|
|
387
|
0
|
0
|
|
|
|
0
|
next unless -f $info_path; |
|
388
|
0
|
|
|
|
|
0
|
$info = eval { |
|
389
|
0
|
|
|
|
|
0
|
my $reader = File::ValueFile::Simple::Reader->new($info_path, supported_formats => [], supported_features => []); |
|
390
|
0
|
|
|
|
|
0
|
$reader->read_as_simple_tree; |
|
391
|
|
|
|
|
|
|
}; |
|
392
|
|
|
|
|
|
|
|
|
393
|
0
|
0
|
0
|
|
|
0
|
if (defined($info) && defined($info->{'pool-name-suffix'})) { |
|
394
|
0
|
|
0
|
|
|
0
|
my $local_cache = $sysfile_cache->{$pool_path} //= {}; |
|
395
|
0
|
|
|
|
|
0
|
my @c_stat = stat(File::Spec->catfile($pool_path, 'data', $info->{'pool-name-suffix'})); |
|
396
|
|
|
|
|
|
|
|
|
397
|
0
|
0
|
|
|
|
0
|
next unless scalar @c_stat; |
|
398
|
|
|
|
|
|
|
|
|
399
|
0
|
|
|
|
|
0
|
$local_cache->{$c_stat[1].'@'.$c_stat[0]} = $info->{'pool-name-suffix'}; |
|
400
|
|
|
|
|
|
|
|
|
401
|
0
|
0
|
0
|
|
|
0
|
if ($c_stat[0] eq $stat[0] && $c_stat[1] eq $stat[1]) { |
|
402
|
0
|
|
|
|
|
0
|
$found = $info->{'pool-name-suffix'}; |
|
403
|
0
|
|
|
|
|
0
|
$paths{$pool_path} = $found; |
|
404
|
|
|
|
|
|
|
} |
|
405
|
|
|
|
|
|
|
} |
|
406
|
|
|
|
|
|
|
} |
|
407
|
|
|
|
|
|
|
} |
|
408
|
|
|
|
|
|
|
} |
|
409
|
|
|
|
|
|
|
} |
|
410
|
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
# Then try the pool: |
|
412
|
0
|
0
|
|
|
|
0
|
unless (defined($found)) { |
|
413
|
|
|
|
|
|
|
outer: |
|
414
|
0
|
|
|
|
|
0
|
foreach my $pool_path (@{$instance->_tagpool_path}) { |
|
|
0
|
|
|
|
|
0
|
|
|
415
|
0
|
|
|
|
|
0
|
my $data_path = File::Spec->catdir($pool_path => 'data'); |
|
416
|
0
|
|
0
|
|
|
0
|
my $local_cache = $sysfile_cache->{$pool_path} //= {}; |
|
417
|
|
|
|
|
|
|
|
|
418
|
0
|
0
|
|
|
|
0
|
next if $local_cache->{complete}; |
|
419
|
|
|
|
|
|
|
|
|
420
|
0
|
0
|
|
|
|
0
|
if (opendir(my $dir, $data_path)) { |
|
421
|
0
|
|
|
|
|
0
|
my @c_stat = stat($dir); |
|
422
|
|
|
|
|
|
|
|
|
423
|
0
|
0
|
|
|
|
0
|
next if $c_stat[0] ne $stat[0]; |
|
424
|
|
|
|
|
|
|
|
|
425
|
0
|
|
|
|
|
0
|
while (my $entry = readdir($dir)) { |
|
426
|
0
|
0
|
|
|
|
0
|
$entry =~ /^file\./ or next; # skip everything that is not a file.* to begin with. |
|
427
|
|
|
|
|
|
|
|
|
428
|
0
|
|
|
|
|
0
|
@c_stat = stat(File::Spec->catfile($data_path, $entry)); |
|
429
|
0
|
0
|
|
|
|
0
|
next unless scalar @c_stat; |
|
430
|
|
|
|
|
|
|
|
|
431
|
0
|
|
|
|
|
0
|
$local_cache->{$c_stat[1].'@'.$c_stat[0]} = $entry; |
|
432
|
|
|
|
|
|
|
|
|
433
|
0
|
0
|
0
|
|
|
0
|
if ($c_stat[0] eq $stat[0] && $c_stat[1] eq $stat[1]) { |
|
434
|
0
|
|
|
|
|
0
|
$found = $entry; |
|
435
|
0
|
|
|
|
|
0
|
$paths{$pool_path} = $found; |
|
436
|
|
|
|
|
|
|
} |
|
437
|
|
|
|
|
|
|
} |
|
438
|
|
|
|
|
|
|
|
|
439
|
0
|
|
|
|
|
0
|
$local_cache->{complete} = 1; |
|
440
|
|
|
|
|
|
|
} |
|
441
|
|
|
|
|
|
|
} |
|
442
|
|
|
|
|
|
|
} |
|
443
|
|
|
|
|
|
|
|
|
444
|
0
|
|
|
|
|
0
|
$self->{_tagpool_paths} = \%paths; |
|
445
|
|
|
|
|
|
|
} |
|
446
|
|
|
|
|
|
|
|
|
447
|
0
|
|
|
|
|
0
|
return $self->{_tagpool_paths}; |
|
448
|
|
|
|
|
|
|
} |
|
449
|
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
sub _load_stat { |
|
451
|
2
|
|
|
2
|
|
20
|
my ($self, undef, %opts) = @_; |
|
452
|
2
|
50
|
33
|
|
|
14
|
if ($opts{lifecycle} eq 'current' && !$self->{_loaded_stat}) { |
|
453
|
2
|
|
50
|
|
|
11
|
my $pv = ($self->{properties_values} //= {})->{current} //= {}; |
|
|
|
|
50
|
|
|
|
|
|
454
|
2
|
|
|
|
|
5
|
my @values = eval {stat($self->{handle})}; |
|
|
2
|
|
|
|
|
33
|
|
|
455
|
2
|
|
|
|
|
13
|
my @keys = qw(st_dev st_ino st_mode st_nlink st_uid st_gid st_rdev st_size st_atime st_mtime st_ctime st_blksize st_blocks); |
|
456
|
|
|
|
|
|
|
|
|
457
|
2
|
50
|
|
|
|
7
|
if (scalar @values) { |
|
458
|
2
|
|
|
|
|
8
|
for (my $i = 0; $i < scalar(@keys); $i++) { |
|
459
|
26
|
|
|
|
|
37
|
my $value = $values[$i]; |
|
460
|
26
|
|
|
|
|
38
|
my $key = $keys[$i]; |
|
461
|
|
|
|
|
|
|
|
|
462
|
26
|
50
|
|
|
|
51
|
next if $key eq ':skip'; |
|
463
|
26
|
50
|
|
|
|
54
|
next if $value eq ''; |
|
464
|
26
|
100
|
66
|
|
|
109
|
next if $value == 0 && ($key eq 'st_ino' || $key eq 'st_rdev' || $key eq 'st_blksize'); |
|
|
|
|
66
|
|
|
|
|
|
465
|
24
|
50
|
|
|
|
80
|
next if $value < 0; |
|
466
|
|
|
|
|
|
|
|
|
467
|
24
|
|
|
|
|
94
|
$pv->{$key} = {raw => $values[$i]}; |
|
468
|
|
|
|
|
|
|
} |
|
469
|
|
|
|
|
|
|
|
|
470
|
2
|
|
|
|
|
7
|
$pv->{stat_readonly} = {raw => !($values[2] & (S_IWUSR|S_IWGRP|S_IWOTH))}; |
|
471
|
2
|
50
|
33
|
|
|
16
|
$pv->{stat_cachehash} = {raw => $values[1].'@'.$values[0]} if $values[1] > 0 && $values[0] ne ''; |
|
472
|
|
|
|
|
|
|
} |
|
473
|
|
|
|
|
|
|
|
|
474
|
2
|
|
|
|
|
17
|
$self->{_loaded_stat} = 1; |
|
475
|
|
|
|
|
|
|
} |
|
476
|
|
|
|
|
|
|
} |
|
477
|
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
sub _load_contentise { |
|
479
|
0
|
|
|
0
|
|
0
|
my ($self, $key, %opts) = @_; |
|
480
|
0
|
|
|
|
|
0
|
my $lifecycle = $opts{lifecycle}; |
|
481
|
0
|
|
0
|
|
|
0
|
my $pv = ($self->{properties_values} //= {})->{$lifecycle} //= {}; |
|
|
|
|
0
|
|
|
|
|
|
482
|
0
|
|
|
|
|
0
|
my $digest_sha_1_160 = $self->digest('sha-1-160', as => 'utag', lifecycle => $lifecycle, default => undef); |
|
483
|
0
|
|
|
|
|
0
|
my $digest_sha_3_512 = $self->digest('sha-3-512', as => 'utag', lifecycle => $lifecycle, default => undef); |
|
484
|
|
|
|
|
|
|
|
|
485
|
0
|
0
|
|
|
|
0
|
if (defined $digest_sha_3_512) { |
|
486
|
0
|
|
|
|
|
0
|
my $id = Data::Identifier::Generate->generic(namespace => '66d488c0-3b19-4e6c-856f-79edf2484f37', input => $digest_sha_3_512); |
|
487
|
0
|
|
|
|
|
0
|
$pv->{content_sha_3_512_uuid} = {raw => $id->uuid}; |
|
488
|
|
|
|
|
|
|
} |
|
489
|
|
|
|
|
|
|
|
|
490
|
0
|
0
|
0
|
|
|
0
|
if (defined($digest_sha_1_160) && defined($digest_sha_3_512)) { |
|
491
|
0
|
|
|
|
|
0
|
my $digest = $digest_sha_1_160.' '.$digest_sha_3_512; |
|
492
|
0
|
|
|
|
|
0
|
$digest =~ s/^v0 /v0m /; |
|
493
|
0
|
|
|
|
|
0
|
my $id = Data::Identifier::Generate->generic(namespace => '66d488c0-3b19-4e6c-856f-79edf2484f37', input => $digest); |
|
494
|
0
|
|
|
|
|
0
|
$pv->{content_sha_1_160_sha_3_512_uuid} = {raw => $id->uuid}; |
|
495
|
|
|
|
|
|
|
} |
|
496
|
|
|
|
|
|
|
} |
|
497
|
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
sub _load_xattr { |
|
499
|
0
|
|
|
0
|
|
0
|
my ($self, $key, %opts) = @_; |
|
500
|
0
|
|
|
|
|
0
|
my $info = $self->{properties}{$key}; |
|
501
|
0
|
|
0
|
|
|
0
|
my $lifecycle = $info->{lifecycle} // 'current'; |
|
502
|
0
|
|
0
|
|
|
0
|
my $pv = ($self->{properties_values} //= {})->{$lifecycle} //= {}; |
|
|
|
|
0
|
|
|
|
|
|
503
|
0
|
|
|
|
|
0
|
my $value; |
|
504
|
|
|
|
|
|
|
my $fh; |
|
505
|
|
|
|
|
|
|
|
|
506
|
0
|
0
|
0
|
|
|
0
|
return unless ($opts{lifecycle} // 'current') eq $lifecycle; |
|
507
|
|
|
|
|
|
|
|
|
508
|
0
|
0
|
|
|
|
0
|
croak 'Not supported, requires File::ExtAttr' unless $HAVE_XATTR; |
|
509
|
|
|
|
|
|
|
|
|
510
|
0
|
|
0
|
|
|
0
|
$self->{_loaded_xattr} //= {}; |
|
511
|
0
|
0
|
|
|
|
0
|
return if $self->{_loaded_xattr}{$key}; |
|
512
|
0
|
|
|
|
|
0
|
$self->{_loaded_xattr}{$key} = 1; |
|
513
|
|
|
|
|
|
|
|
|
514
|
0
|
|
|
|
|
0
|
$fh = File::Information::Inode::_DUMMY_FOR_XATTR->new($self->{handle}); |
|
515
|
0
|
|
|
|
|
0
|
$value = eval {File::ExtAttr::getfattr($fh, $info->{xattr_key})}; |
|
|
0
|
|
|
|
|
0
|
|
|
516
|
|
|
|
|
|
|
|
|
517
|
0
|
0
|
0
|
|
|
0
|
return unless defined($value) && length($value); |
|
518
|
|
|
|
|
|
|
|
|
519
|
0
|
|
|
|
|
0
|
$pv->{$key} = {raw => $value}; |
|
520
|
|
|
|
|
|
|
|
|
521
|
0
|
0
|
|
|
|
0
|
if (defined(my $parts = $info->{parts})) { |
|
522
|
0
|
|
|
|
|
0
|
my @values = split(/\s+/, $value); |
|
523
|
0
|
|
|
|
|
0
|
my $out = $pv->{$key}; |
|
524
|
|
|
|
|
|
|
|
|
525
|
0
|
|
|
|
|
0
|
for (my $i = 0; $i < scalar(@{$parts}); $i++) { |
|
|
0
|
|
|
|
|
0
|
|
|
526
|
0
|
0
|
0
|
|
|
0
|
if (defined($values[$i]) && length($values[$i])) { |
|
527
|
0
|
|
|
|
|
0
|
$out->{$parts->[$i]} = $values[$i]; |
|
528
|
|
|
|
|
|
|
} |
|
529
|
|
|
|
|
|
|
} |
|
530
|
0
|
|
|
|
|
0
|
$out->{rawtype} = 'multipart'; |
|
531
|
|
|
|
|
|
|
} |
|
532
|
|
|
|
|
|
|
|
|
533
|
0
|
0
|
|
|
|
0
|
if (defined(my $parsing = $info->{parsing})) { |
|
534
|
0
|
0
|
|
|
|
0
|
if ($parsing eq 'utag') { |
|
535
|
0
|
|
|
|
|
0
|
my $v = $value; |
|
536
|
0
|
|
|
|
|
0
|
my %digest; |
|
537
|
|
|
|
|
|
|
my $given_size; |
|
538
|
|
|
|
|
|
|
|
|
539
|
0
|
|
|
|
|
0
|
$given_size = $self->_set_digest_utag($lifecycle => $v, $given_size); |
|
540
|
|
|
|
|
|
|
|
|
541
|
0
|
0
|
|
|
|
0
|
$pv->{xattr_utag_final_file_hash_size} = {raw => $given_size} if defined $given_size; |
|
542
|
0
|
|
0
|
|
|
0
|
$self->{digest} //= {}; |
|
543
|
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
{ |
|
545
|
0
|
|
0
|
|
|
0
|
my $digests = $self->{digest}{$lifecycle} //= {}; |
|
|
0
|
|
|
|
|
0
|
|
|
546
|
0
|
|
|
|
|
0
|
foreach my $algo (keys %digest) { |
|
547
|
0
|
|
0
|
|
|
0
|
$digests->{$algo} //= $digest{$algo}; |
|
548
|
|
|
|
|
|
|
} |
|
549
|
|
|
|
|
|
|
} |
|
550
|
|
|
|
|
|
|
} |
|
551
|
|
|
|
|
|
|
} |
|
552
|
|
|
|
|
|
|
} |
|
553
|
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
# Bad workaround for File::ExtAttr |
|
555
|
|
|
|
|
|
|
package File::Information::Inode::_DUMMY_FOR_XATTR { |
|
556
|
|
|
|
|
|
|
sub new { |
|
557
|
0
|
|
|
0
|
|
0
|
my ($pkg, $fh) = @_; |
|
558
|
0
|
|
|
|
|
0
|
return bless \$fh; |
|
559
|
|
|
|
|
|
|
} |
|
560
|
|
|
|
|
|
|
sub isa { |
|
561
|
0
|
|
|
0
|
|
0
|
my ($self, $pkg) = @_; |
|
562
|
0
|
0
|
|
|
|
0
|
return 1 if $pkg eq 'IO::Handle'; |
|
563
|
0
|
|
|
|
|
0
|
return $self->SUPER::isa($pkg); |
|
564
|
|
|
|
|
|
|
} |
|
565
|
|
|
|
|
|
|
sub fileno { |
|
566
|
0
|
|
|
0
|
|
0
|
my ($self) = @_; |
|
567
|
0
|
|
|
|
|
0
|
return ${$self}->fileno; |
|
|
0
|
|
|
|
|
0
|
|
|
568
|
|
|
|
|
|
|
} |
|
569
|
|
|
|
|
|
|
} |
|
570
|
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
sub _load_tagpool_directory { |
|
572
|
0
|
|
|
0
|
|
0
|
my ($self) = @_; |
|
573
|
0
|
|
0
|
|
|
0
|
my $pv = $self->{properties_values} //= {}; |
|
574
|
0
|
|
|
|
|
0
|
my $tree; |
|
575
|
|
|
|
|
|
|
|
|
576
|
0
|
0
|
|
|
|
0
|
return if $self->{_loaded_tagpool_directory}; |
|
577
|
0
|
|
|
|
|
0
|
$self->{_loaded_tagpool_directory} = 1; |
|
578
|
|
|
|
|
|
|
|
|
579
|
0
|
|
|
|
|
0
|
eval { |
|
580
|
0
|
|
|
|
|
0
|
my @stat = stat($self->{handle}); |
|
581
|
|
|
|
|
|
|
|
|
582
|
0
|
0
|
0
|
|
|
0
|
if (scalar(@stat) && S_ISDIR($stat[2])) { |
|
583
|
0
|
|
0
|
|
|
0
|
my $c = $pv->{current} //= {}; |
|
584
|
0
|
|
|
|
|
0
|
$c->{tagpool_directory_timestamp} = {raw => time()}; |
|
585
|
|
|
|
|
|
|
|
|
586
|
0
|
|
|
|
|
0
|
$c->{tagpool_directory_inode} = {raw => $stat[1]}; |
|
587
|
0
|
|
|
|
|
0
|
$c->{tagpool_directory_mtime} = {raw => $stat[9]}; |
|
588
|
|
|
|
|
|
|
} |
|
589
|
|
|
|
|
|
|
}; |
|
590
|
|
|
|
|
|
|
|
|
591
|
0
|
0
|
|
|
|
0
|
return unless defined $self->{path}; |
|
592
|
0
|
0
|
|
|
|
0
|
return unless $HAVE_FILE_VALUEFILE; |
|
593
|
|
|
|
|
|
|
|
|
594
|
0
|
|
|
|
|
0
|
eval { |
|
595
|
0
|
|
|
|
|
0
|
my $path = File::Spec->catfile($self->{path}, '.tagpool-info', 'directory'); |
|
596
|
0
|
|
|
|
|
0
|
my $reader = File::ValueFile::Simple::Reader->new($path, supported_formats => '11431b85-41cd-4be5-8d88-a769ebbd603f', supported_features => []); |
|
597
|
0
|
|
|
|
|
0
|
$tree = $reader->read_as_simple_tree; |
|
598
|
|
|
|
|
|
|
}; |
|
599
|
|
|
|
|
|
|
|
|
600
|
0
|
0
|
|
|
|
0
|
if (defined $tree) { |
|
601
|
0
|
|
|
|
|
0
|
foreach my $key (qw(title comment description)) { |
|
602
|
0
|
|
|
|
|
0
|
my $value = $tree->{$key}; |
|
603
|
0
|
0
|
0
|
|
|
0
|
if (defined($value) && !ref($value) && length($value)) { |
|
|
|
|
0
|
|
|
|
|
|
604
|
0
|
|
0
|
|
|
0
|
$pv->{current} //= {}; |
|
605
|
0
|
|
|
|
|
0
|
$pv->{current}{'tagpool_directory_'.$key} = {raw => $value}; |
|
606
|
|
|
|
|
|
|
} |
|
607
|
|
|
|
|
|
|
} |
|
608
|
|
|
|
|
|
|
|
|
609
|
0
|
|
|
|
|
0
|
foreach my $key (qw(inode mtime pool-uuid timestamp)) { |
|
610
|
0
|
|
|
|
|
0
|
foreach my $lifecycle (qw(initial last)) { |
|
611
|
0
|
|
|
|
|
0
|
my $value = $tree->{$lifecycle.'-'.$key}; |
|
612
|
0
|
0
|
0
|
|
|
0
|
if (defined($value) && !ref($value) && length($value)) { |
|
|
|
|
0
|
|
|
|
|
|
613
|
0
|
|
0
|
|
|
0
|
my $c = $pv->{$lifecycle} //= {}; |
|
614
|
|
|
|
|
|
|
|
|
615
|
0
|
|
|
|
|
0
|
$c->{'tagpool_directory_'.($key =~ tr/-/_/r)} = {raw => $value}; |
|
616
|
|
|
|
|
|
|
} |
|
617
|
|
|
|
|
|
|
} |
|
618
|
|
|
|
|
|
|
} |
|
619
|
|
|
|
|
|
|
|
|
620
|
0
|
0
|
|
|
|
0
|
if (defined(my $setting = $tree->{'directory-setting'})) { |
|
621
|
0
|
|
|
|
|
0
|
foreach my $key (qw(thumbnail-uri thumbnail-mode update-mode add-mode file-tags tag-mode tag-implies entry-sort-order tag tag-root tag-parent tag-type entry-display-name entry-sort-key)) { |
|
622
|
0
|
|
|
|
|
0
|
my $value = $setting->{$key}; |
|
623
|
0
|
0
|
0
|
|
|
0
|
if (defined($value) && !ref($value) && length($value)) { |
|
|
|
|
0
|
|
|
|
|
|
624
|
0
|
|
|
|
|
0
|
my $val = {raw => $value}; |
|
625
|
0
|
|
0
|
|
|
0
|
$pv->{current} //= {}; |
|
626
|
0
|
|
|
|
|
0
|
$pv->{current}{'tagpool_directory_setting_'.($key =~ tr/-/_/r)} = $val; |
|
627
|
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
# Add ise if known: |
|
629
|
0
|
0
|
|
|
|
0
|
if (defined(my $info = $_tagpool_directory_setting_tagmap{$key})) { |
|
630
|
0
|
0
|
|
|
|
0
|
if (defined(my $entry = $info->{$value})) { |
|
631
|
0
|
|
|
|
|
0
|
$val->{ise} = $entry->{ise}; |
|
632
|
|
|
|
|
|
|
} |
|
633
|
|
|
|
|
|
|
} |
|
634
|
|
|
|
|
|
|
} |
|
635
|
|
|
|
|
|
|
} |
|
636
|
|
|
|
|
|
|
} |
|
637
|
|
|
|
|
|
|
|
|
638
|
0
|
0
|
|
|
|
0
|
if (defined(my $option = $tree->{'throw-option'})) { |
|
639
|
0
|
|
|
|
|
0
|
foreach my $key (qw(linkname linktype filter)) { |
|
640
|
0
|
|
|
|
|
0
|
my $value = $option->{$key}; |
|
641
|
0
|
0
|
0
|
|
|
0
|
if (defined($value) && !ref($value) && length($value)) { |
|
|
|
|
0
|
|
|
|
|
|
642
|
0
|
|
0
|
|
|
0
|
$pv->{current} //= {}; |
|
643
|
0
|
|
|
|
|
0
|
$pv->{current}{'tagpool_directory_throw_option_'.$key} = {raw => $value}; |
|
644
|
|
|
|
|
|
|
} |
|
645
|
|
|
|
|
|
|
} |
|
646
|
|
|
|
|
|
|
} |
|
647
|
|
|
|
|
|
|
} |
|
648
|
|
|
|
|
|
|
} |
|
649
|
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
sub _load_tagpool_file { |
|
651
|
8
|
|
|
8
|
|
17
|
my ($self) = @_; |
|
652
|
8
|
|
|
|
|
48
|
my File::Information $instance = $self->instance; |
|
653
|
8
|
|
|
|
|
28
|
my $sysfile_cache = $instance->_tagpool_sysfile_cache; |
|
654
|
8
|
|
50
|
|
|
20
|
my $pv = $self->{properties_values} //= {}; |
|
655
|
8
|
|
|
|
|
18
|
my @stat; |
|
656
|
|
|
|
|
|
|
my $found; |
|
657
|
8
|
|
|
|
|
0
|
my $in_pool; |
|
658
|
|
|
|
|
|
|
|
|
659
|
8
|
100
|
|
|
|
27
|
return if $self->{_loaded_tagpool_file}; |
|
660
|
2
|
|
|
|
|
6
|
$self->{_loaded_tagpool_file} = 1; |
|
661
|
|
|
|
|
|
|
|
|
662
|
2
|
50
|
|
|
|
4
|
return unless scalar @{$instance->_tagpool_path}; |
|
|
2
|
|
|
|
|
5
|
|
|
663
|
|
|
|
|
|
|
|
|
664
|
0
|
|
|
|
|
0
|
@stat = eval {stat($self->{handle})}; |
|
|
0
|
|
|
|
|
0
|
|
|
665
|
0
|
0
|
0
|
|
|
0
|
return unless scalar(@stat) && S_ISREG($stat[2]); |
|
666
|
|
|
|
|
|
|
|
|
667
|
|
|
|
|
|
|
{ |
|
668
|
0
|
|
0
|
|
|
0
|
my $c = $pv->{current} //= {}; |
|
|
0
|
|
|
|
|
0
|
|
|
669
|
0
|
|
|
|
|
0
|
$c->{tagpool_file_timestamp} = {raw => time()}; |
|
670
|
|
|
|
|
|
|
|
|
671
|
0
|
|
|
|
|
0
|
$c->{tagpool_file_inode} = {raw => $stat[1]}; |
|
672
|
0
|
|
|
|
|
0
|
$c->{tagpool_file_size} = {raw => $stat[7]}; |
|
673
|
0
|
|
|
|
|
0
|
$c->{tagpool_file_mtime} = {raw => $stat[9]}; |
|
674
|
|
|
|
|
|
|
} |
|
675
|
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
# Try to find the file: |
|
677
|
0
|
|
|
|
|
0
|
($in_pool, $found) = %{$self->_tagpool_paths}; |
|
|
0
|
|
|
|
|
0
|
|
|
678
|
|
|
|
|
|
|
|
|
679
|
0
|
0
|
0
|
|
|
0
|
return unless defined($in_pool) && defined($found); |
|
680
|
|
|
|
|
|
|
|
|
681
|
0
|
0
|
|
|
|
0
|
if ($found =~ /^file\.([0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12})(?:\..*)?$/) { |
|
682
|
0
|
|
|
|
|
0
|
my $uuid = $1; |
|
683
|
0
|
|
|
|
|
0
|
my $info = eval { |
|
684
|
0
|
|
|
|
|
0
|
my $path = File::Spec->catfile($in_pool, 'data' => 'info.'.$uuid); |
|
685
|
0
|
|
|
|
|
0
|
my $reader = File::ValueFile::Simple::Reader->new($path, supported_formats => [], supported_features => []); |
|
686
|
0
|
|
|
|
|
0
|
$reader->read_as_simple_tree; |
|
687
|
|
|
|
|
|
|
}; |
|
688
|
0
|
|
|
|
|
0
|
my $tags = eval { |
|
689
|
0
|
|
|
|
|
0
|
my $path = File::Spec->catfile($in_pool, 'data' => 'tags.'.$uuid); |
|
690
|
0
|
|
|
|
|
0
|
my $reader = File::ValueFile::Simple::Reader->new($path, supported_formats => [], supported_features => []); |
|
691
|
0
|
|
|
|
|
0
|
$reader->read_as_hash_of_arrays; |
|
692
|
|
|
|
|
|
|
}; |
|
693
|
0
|
0
|
0
|
|
|
0
|
if (defined($info) && defined($tags)) { |
|
694
|
0
|
|
0
|
|
|
0
|
$pv->{current} //= {}; |
|
695
|
0
|
|
|
|
|
0
|
$pv->{current}{tagpool_file_uuid} = {raw => $uuid}; |
|
696
|
|
|
|
|
|
|
|
|
697
|
0
|
|
|
|
|
0
|
foreach my $key (qw(title comment description original-url original-description-url pool-name-suffix original-filename)) { |
|
698
|
0
|
|
|
|
|
0
|
my $value = $info->{$key}; |
|
699
|
0
|
0
|
0
|
|
|
0
|
if (defined($value) && !ref($value) && length($value)) { |
|
|
|
|
0
|
|
|
|
|
|
700
|
0
|
|
|
|
|
0
|
$pv->{current}{'tagpool_file_'.($key =~ tr/-/_/r)} = {raw => $value}; |
|
701
|
|
|
|
|
|
|
} |
|
702
|
|
|
|
|
|
|
} |
|
703
|
|
|
|
|
|
|
|
|
704
|
0
|
|
|
|
|
0
|
foreach my $key (qw(mtime timestamp inode size actual-size)) { |
|
705
|
0
|
|
|
|
|
0
|
foreach my $lifecycle (qw(initial last final)) { |
|
706
|
0
|
|
|
|
|
0
|
my $value = $info->{$lifecycle.'-'.$key}; |
|
707
|
0
|
0
|
0
|
|
|
0
|
if (defined($value) && !ref($value) && length($value)) { |
|
|
|
|
0
|
|
|
|
|
|
708
|
0
|
|
0
|
|
|
0
|
my $c = $pv->{$lifecycle} //= {}; |
|
709
|
|
|
|
|
|
|
|
|
710
|
0
|
|
|
|
|
0
|
$c->{'tagpool_file_'.($key =~ tr/-/_/r)} = {raw => $value}; |
|
711
|
|
|
|
|
|
|
} |
|
712
|
|
|
|
|
|
|
} |
|
713
|
|
|
|
|
|
|
} |
|
714
|
|
|
|
|
|
|
|
|
715
|
|
|
|
|
|
|
# Digest: |
|
716
|
0
|
|
|
|
|
0
|
foreach my $key (keys %{$info}) { |
|
|
0
|
|
|
|
|
0
|
|
|
717
|
0
|
0
|
|
|
|
0
|
if (my ($lifecycle, $tagpool_name) = $key =~ /^(initial|last|final)-hash-(.+)$/) { |
|
718
|
0
|
0
|
|
|
|
0
|
my $utag_name = $File::Information::Base::_digest_name_converter{$tagpool_name} or next; |
|
719
|
0
|
|
|
|
|
0
|
my $value = $info->{$key}; |
|
720
|
0
|
0
|
|
|
|
0
|
my ($size) = $utag_name =~ /-([0-9]+)$/ or next; |
|
721
|
|
|
|
|
|
|
|
|
722
|
0
|
0
|
|
|
|
0
|
next unless $value =~ /^[0-9a-f]+$/; |
|
723
|
0
|
0
|
|
|
|
0
|
next unless length($value) == ($size / 4); |
|
724
|
0
|
|
0
|
|
|
0
|
$self->{digest} //= {}; |
|
725
|
0
|
|
0
|
|
|
0
|
$self->{digest}{$lifecycle} //= {}; |
|
726
|
0
|
|
|
|
|
0
|
$self->{digest}{$lifecycle}{$utag_name} = $value; |
|
727
|
|
|
|
|
|
|
} |
|
728
|
|
|
|
|
|
|
} |
|
729
|
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
# Tags: |
|
731
|
|
|
|
|
|
|
{ |
|
732
|
0
|
|
0
|
|
|
0
|
my @next = @{$tags->{'tagged-as'} // []}; |
|
|
0
|
|
|
|
|
0
|
|
|
733
|
|
|
|
|
|
|
|
|
734
|
0
|
|
|
|
|
0
|
$pv->{current}{tagpool_file_tags} = [map {{raw => $_}} @next]; |
|
|
0
|
|
|
|
|
0
|
|
|
735
|
|
|
|
|
|
|
|
|
736
|
0
|
|
|
|
|
0
|
while (scalar(@next)) { |
|
737
|
0
|
|
|
|
|
0
|
my @current = @next; |
|
738
|
0
|
|
|
|
|
0
|
@next = (); |
|
739
|
|
|
|
|
|
|
|
|
740
|
0
|
|
|
|
|
0
|
foreach my $tag (@current) { |
|
741
|
0
|
|
|
|
|
0
|
my $info = $_wk_tagged_as_tags{$tag}; |
|
742
|
0
|
0
|
0
|
|
|
0
|
next unless defined($info) && defined($info->{for}); |
|
743
|
|
|
|
|
|
|
|
|
744
|
0
|
0
|
|
|
|
0
|
if ($info->{for} eq 'write-mode') { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
745
|
0
|
|
|
|
|
0
|
$pv->{current}{tagpool_file_write_mode} = {raw => $tag}; |
|
746
|
|
|
|
|
|
|
} elsif ($info->{for} eq 'mediatype') { |
|
747
|
0
|
|
|
|
|
0
|
$pv->{current}{tagpool_file_mediatype} = {raw => $info->{mediatype}, ise => $tag}; |
|
748
|
|
|
|
|
|
|
} elsif ($info->{for} eq 'finalmode') { |
|
749
|
0
|
|
|
|
|
0
|
$pv->{current}{tagpool_file_finalmode} = {raw => $tag}; |
|
750
|
|
|
|
|
|
|
} else { |
|
751
|
0
|
|
|
|
|
0
|
croak 'BUG!'; |
|
752
|
|
|
|
|
|
|
} |
|
753
|
|
|
|
|
|
|
|
|
754
|
0
|
0
|
|
|
|
0
|
push(@next, @{$info->{implies}}) if defined $info->{implies}; |
|
|
0
|
|
|
|
|
0
|
|
|
755
|
|
|
|
|
|
|
} |
|
756
|
|
|
|
|
|
|
} |
|
757
|
|
|
|
|
|
|
} |
|
758
|
|
|
|
|
|
|
|
|
759
|
|
|
|
|
|
|
# Media Type: |
|
760
|
|
|
|
|
|
|
{ |
|
761
|
0
|
|
|
|
|
0
|
my $value = readlink(File::Spec->catfile($in_pool, qw(cache mimetype file), $uuid)); |
|
|
0
|
|
|
|
|
0
|
|
|
762
|
0
|
0
|
0
|
|
|
0
|
if (defined($value) && length($value)) { |
|
763
|
0
|
|
0
|
|
|
0
|
$pv->{current}{tagpool_file_mediatype} //= {raw => $value}; |
|
764
|
|
|
|
|
|
|
} |
|
765
|
|
|
|
|
|
|
} |
|
766
|
|
|
|
|
|
|
|
|
767
|
|
|
|
|
|
|
# Write mode: |
|
768
|
|
|
|
|
|
|
{ |
|
769
|
0
|
|
|
|
|
0
|
my $value = readlink(File::Spec->catfile($in_pool, qw(cache write-mode file), $uuid)); |
|
|
0
|
|
|
|
|
0
|
|
|
770
|
0
|
0
|
0
|
|
|
0
|
if (defined($value) && length($value)) { |
|
771
|
0
|
|
0
|
|
|
0
|
$pv->{current}{tagpool_file_write_mode} //= {raw => $value}; |
|
772
|
|
|
|
|
|
|
} |
|
773
|
|
|
|
|
|
|
} |
|
774
|
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
{ |
|
776
|
0
|
|
|
|
|
0
|
my $value = File::Spec->catfile($in_pool, qw(cache thumbnail file), $uuid.'.png'); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
777
|
0
|
|
|
|
|
0
|
my @c_stat = stat($value); |
|
778
|
0
|
0
|
|
|
|
0
|
if (scalar(@c_stat)) { |
|
779
|
0
|
0
|
|
|
|
0
|
if ($stat[9] < $c_stat[9]) { |
|
780
|
0
|
|
0
|
|
|
0
|
$pv->{current}{tagpool_file_thumbnail} //= {raw => $value}; |
|
781
|
|
|
|
|
|
|
} |
|
782
|
|
|
|
|
|
|
} |
|
783
|
|
|
|
|
|
|
} |
|
784
|
|
|
|
|
|
|
} |
|
785
|
|
|
|
|
|
|
} |
|
786
|
|
|
|
|
|
|
} |
|
787
|
|
|
|
|
|
|
|
|
788
|
|
|
|
|
|
|
sub _load_magic { |
|
789
|
0
|
|
|
0
|
|
0
|
my ($self) = @_; |
|
790
|
0
|
|
0
|
|
|
0
|
my $pv = ($self->{properties_values} //= {})->{current} //= {}; |
|
|
|
|
0
|
|
|
|
|
|
791
|
0
|
|
|
|
|
0
|
my $data; |
|
792
|
|
|
|
|
|
|
my $media_type; |
|
793
|
|
|
|
|
|
|
|
|
794
|
0
|
0
|
|
|
|
0
|
return if $self->{_loaded_magic}; |
|
795
|
0
|
|
|
|
|
0
|
$self->{_loaded_magic} = 1; |
|
796
|
|
|
|
|
|
|
|
|
797
|
0
|
|
|
|
|
0
|
$data = eval {$self->peek}; |
|
|
0
|
|
|
|
|
0
|
|
|
798
|
|
|
|
|
|
|
|
|
799
|
0
|
0
|
|
|
|
0
|
return unless defined $data; |
|
800
|
|
|
|
|
|
|
|
|
801
|
0
|
0
|
0
|
|
|
0
|
if (substr($data, 0, 22) eq '<!DOCTYPE HTML PUBLIC ' || substr($data, 0, 22) eq '<!DOCTYPE html PUBLIC ' || substr($data, 0, 22) eq '<!DOCTYPE HTML SYSTEM ' || uc(substr($data, 0, 15)) eq '<!DOCTYPE HTML>' || |
|
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
802
|
|
|
|
|
|
|
lc(substr($data, 0, 6)) eq '<html>' || |
|
803
|
|
|
|
|
|
|
$data =~ /^<\?xml version="1\.0" encoding="utf-8"\?>\r?\n?<\!DOCTYPE html PUBLIC /) { |
|
804
|
0
|
|
|
|
|
0
|
$media_type = 'text/html'; |
|
805
|
|
|
|
|
|
|
} elsif ($data =~ /^<\?xml version="1\.0" encoding="UTF-8"\?>\s*<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1\.0"[^>]+office:mimetype="(application\/vnd\.oasis\.opendocument\.(?:text|spreadsheet|presentation|graphics|chart|formula|image|text-master|(?:text|spreadsheet|presentation|graphics)-template))"[^>]*>/) { |
|
806
|
0
|
|
|
|
|
0
|
$media_type = $1; |
|
807
|
|
|
|
|
|
|
} elsif ($data =~ /^PK\003\004....\0\0................\010\0\0\0mimetype(application\/vnd\.oasis\.opendocument\.(?:text|spreadsheet|presentation|graphics|chart|formula|image|text-master|(?:text|spreadsheet|presentation|graphics)-template))PK\003\004/) { |
|
808
|
0
|
|
|
|
|
0
|
$media_type = $1; |
|
809
|
|
|
|
|
|
|
} elsif (substr($data, 0, 8) eq "!<arch>\n") { |
|
810
|
0
|
0
|
|
|
|
0
|
if ($data =~ /^!<arch>\ndebian-binary [0-9 ]{12}0 0 [0-7 ]{8}[0-9] `\n/) { |
|
811
|
0
|
|
|
|
|
0
|
$media_type = 'application/vnd.debian.binary-package'; |
|
812
|
|
|
|
|
|
|
} else { |
|
813
|
0
|
|
|
|
|
0
|
$media_type = 'application/x-archive'; |
|
814
|
|
|
|
|
|
|
} |
|
815
|
|
|
|
|
|
|
} elsif ($data =~ /^!!ValueFile ([0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12})\s+(!null|[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}|[0-2](?:\.(?:0|[1-9][0-9]*))+|[a-zA-Z][a-zA-Z0-9\+\.\-]+[^\s%]+)[\s\r\n]/) { |
|
816
|
0
|
|
|
|
|
0
|
my ($version, $format) = ($1, $2); |
|
817
|
0
|
|
|
|
|
0
|
$pv->{magic_valuefile_version} = {raw => $version}; |
|
818
|
0
|
0
|
|
|
|
0
|
$pv->{magic_valuefile_format} = {raw => $format} unless $format =~ /^!/; |
|
819
|
|
|
|
|
|
|
} elsif ($data =~ /^\0([\x07-\x3f])VM\x0d\x0a\xc0\x0a/ && (ord($1) & 07) == 07) { |
|
820
|
0
|
|
|
|
|
0
|
$media_type = 'application/vnd.sirtx.vmv0'; |
|
821
|
|
|
|
|
|
|
} elsif ($data =~ /^RIFF.{4}WEBPVP8/) { |
|
822
|
0
|
|
|
|
|
0
|
$media_type = 'image/webp'; |
|
823
|
|
|
|
|
|
|
} else { |
|
824
|
0
|
|
|
|
|
0
|
foreach my $magic (sort {length($b) <=> length($a)} keys %_magic_map) { |
|
|
0
|
|
|
|
|
0
|
|
|
825
|
0
|
0
|
|
|
|
0
|
if (substr($data, 0, length($magic)) eq $magic) { |
|
826
|
0
|
|
|
|
|
0
|
$media_type = $_magic_map{$magic}; |
|
827
|
0
|
|
|
|
|
0
|
last; |
|
828
|
|
|
|
|
|
|
} |
|
829
|
|
|
|
|
|
|
} |
|
830
|
|
|
|
|
|
|
} |
|
831
|
|
|
|
|
|
|
|
|
832
|
0
|
0
|
|
|
|
0
|
$pv->{magic_mediatype} = {raw => $media_type} if defined $media_type; |
|
833
|
|
|
|
|
|
|
} |
|
834
|
|
|
|
|
|
|
|
|
835
|
|
|
|
|
|
|
sub _load_db { |
|
836
|
0
|
|
|
0
|
|
0
|
my ($self, $key, %opts) = @_; |
|
837
|
0
|
|
0
|
|
|
0
|
my $pv = ($self->{properties_values} //= {})->{current} //= {}; |
|
|
|
|
0
|
|
|
|
|
|
838
|
|
|
|
|
|
|
|
|
839
|
0
|
0
|
|
|
|
0
|
return if $self->{_loaded_db}; |
|
840
|
0
|
|
|
|
|
0
|
$self->{_loaded_db} = 1; |
|
841
|
|
|
|
|
|
|
|
|
842
|
0
|
0
|
|
|
|
0
|
if (defined(my $db = eval { $self->instance->db })) { |
|
|
0
|
|
|
|
|
0
|
|
|
843
|
0
|
|
|
|
|
0
|
eval { |
|
844
|
0
|
|
|
|
|
0
|
my $inode = $self->get('st_ino', as => 'raw'); |
|
845
|
0
|
|
|
|
|
0
|
my $fs = $self->filesystem->get('ise', as => 'Data::TagDB::Tag'); |
|
846
|
0
|
|
|
|
|
0
|
my $inode_number = $db->tag_by_id(uuid => 'd2526d8b-25fa-4584-806b-67277c01c0db'); |
|
847
|
0
|
|
|
|
|
0
|
my $also_on_filesystem = $db->tag_by_id(uuid => 'cd5bfb11-620b-4cce-92bd-85b7d010f070'); |
|
848
|
0
|
|
|
|
|
0
|
my $wk = $db->wk; |
|
849
|
0
|
|
|
|
|
0
|
my $metadata = $db->metadata(relation => $wk->also_shares_identifier, type => $inode_number, data_raw => $inode); |
|
850
|
0
|
|
|
|
|
0
|
my $res; |
|
851
|
|
|
|
|
|
|
|
|
852
|
|
|
|
|
|
|
#warn sprintf('inode=%s, inode_number=%s, fs=%s', $inode, $inode_number, $fs); |
|
853
|
|
|
|
|
|
|
$metadata->foreach(sub { |
|
854
|
0
|
|
|
0
|
|
0
|
my ($entry) = @_; |
|
855
|
0
|
|
|
|
|
0
|
my $fs_relation = $db->relation(tag => $entry->tag, relation => $also_on_filesystem, related => $fs)->one; |
|
856
|
0
|
|
|
|
|
0
|
$res = $entry->tag; |
|
857
|
|
|
|
|
|
|
#warn $fs_relation; |
|
858
|
0
|
|
|
|
|
0
|
}); |
|
859
|
|
|
|
|
|
|
|
|
860
|
0
|
0
|
|
|
|
0
|
$pv->{db_inode_tag} = {raw => $res} if defined $res; |
|
861
|
|
|
|
|
|
|
}; |
|
862
|
|
|
|
|
|
|
} |
|
863
|
|
|
|
|
|
|
} |
|
864
|
|
|
|
|
|
|
|
|
865
|
|
|
|
|
|
|
sub _load_redirect { |
|
866
|
0
|
|
|
0
|
|
0
|
my ($self, $key, %opts) = @_; |
|
867
|
0
|
|
|
|
|
0
|
my $info = $self->{properties}{$key}; |
|
868
|
|
|
|
|
|
|
|
|
869
|
0
|
|
|
|
|
0
|
$self->get($info->{redirect}, lifecycle => $opts{lifecycle}, default => undef, as => 'raw'); |
|
870
|
|
|
|
|
|
|
} |
|
871
|
|
|
|
|
|
|
|
|
872
|
|
|
|
|
|
|
sub _load_zonetransfer { |
|
873
|
0
|
|
|
0
|
|
0
|
my ($self, $key, %opts) = @_; |
|
874
|
0
|
|
|
|
|
0
|
my $info = $self->{properties}{$key}; |
|
875
|
0
|
|
0
|
|
|
0
|
my $pv = ($self->{properties_values} //= {})->{current} //= {}; |
|
|
|
|
0
|
|
|
|
|
|
876
|
0
|
|
|
|
|
0
|
my $raw; |
|
877
|
|
|
|
|
|
|
my $parsed; |
|
878
|
|
|
|
|
|
|
|
|
879
|
0
|
0
|
|
|
|
0
|
return if $self->{_loaded_zonetransfer}; |
|
880
|
0
|
|
|
|
|
0
|
$self->{_loaded_zonetransfer} = 1; |
|
881
|
|
|
|
|
|
|
|
|
882
|
0
|
0
|
|
|
|
0
|
if ($HAVE_XATTR) { |
|
883
|
0
|
|
|
|
|
0
|
my $fh = File::Information::Inode::_DUMMY_FOR_XATTR->new($self->{handle}); |
|
884
|
0
|
|
|
|
|
0
|
$raw = eval {File::ExtAttr::getfattr($fh, 'Zone.Identifier')}; |
|
|
0
|
|
|
|
|
0
|
|
|
885
|
|
|
|
|
|
|
} |
|
886
|
|
|
|
|
|
|
|
|
887
|
0
|
0
|
0
|
|
|
0
|
if (!defined($raw) && $^O eq 'MSWin32' && defined($self->{path})) { |
|
|
|
|
0
|
|
|
|
|
|
888
|
0
|
0
|
|
|
|
0
|
if (open(my $ads, '<', sprintf('%s:Zone.Identifier', $self->{path}))) { |
|
889
|
0
|
|
|
|
|
0
|
local $/ = undef; |
|
890
|
0
|
|
|
|
|
0
|
$raw = <$ads>; |
|
891
|
0
|
|
|
|
|
0
|
close($ads); |
|
892
|
|
|
|
|
|
|
} |
|
893
|
|
|
|
|
|
|
} |
|
894
|
|
|
|
|
|
|
|
|
895
|
0
|
0
|
|
|
|
0
|
return unless defined $raw; |
|
896
|
|
|
|
|
|
|
|
|
897
|
0
|
|
|
|
|
0
|
$parsed = Config::INI::Reader->read_string($raw); |
|
898
|
|
|
|
|
|
|
|
|
899
|
0
|
0
|
|
|
|
0
|
if (defined(my $ZoneTransfer = $parsed->{ZoneTransfer})) { |
|
900
|
0
|
|
|
|
|
0
|
foreach my $key (qw(HostIpAddress ZoneId ReferrerUrl HostUrl)) { |
|
901
|
0
|
|
|
|
|
0
|
my $value = $ZoneTransfer->{$key}; |
|
902
|
|
|
|
|
|
|
|
|
903
|
0
|
0
|
0
|
|
|
0
|
next unless defined($value) && length($value); |
|
904
|
|
|
|
|
|
|
|
|
905
|
0
|
|
|
|
|
0
|
$pv->{'zonetransfer_'.lc($key)} = {raw => $value}; |
|
906
|
|
|
|
|
|
|
|
|
907
|
0
|
0
|
0
|
|
|
0
|
if ($key eq 'ZoneId' && defined(my $zone = $_URLZONE{$value})) { |
|
908
|
0
|
|
0
|
|
|
0
|
$pv->{'zonetransfer_'.lc($key)}{ise} //= $zone->{ise}; |
|
909
|
|
|
|
|
|
|
} |
|
910
|
|
|
|
|
|
|
} |
|
911
|
|
|
|
|
|
|
} |
|
912
|
|
|
|
|
|
|
} |
|
913
|
|
|
|
|
|
|
|
|
914
|
|
|
|
|
|
|
sub _load_ntfs_xattr { |
|
915
|
0
|
|
|
0
|
|
0
|
my ($self, $key, %opts) = @_; |
|
916
|
0
|
|
|
|
|
0
|
my $info = $self->{properties}{$key}; |
|
917
|
0
|
|
0
|
|
|
0
|
my $pv = ($self->{properties_values} //= {})->{current} //= {}; |
|
|
|
|
0
|
|
|
|
|
|
918
|
0
|
|
|
|
|
0
|
my $attrb; |
|
919
|
|
|
|
|
|
|
|
|
920
|
0
|
0
|
|
|
|
0
|
return if $self->{_loaded_ntfs_xattr}; |
|
921
|
0
|
|
|
|
|
0
|
$self->{_loaded_ntfs_xattr} = 1; |
|
922
|
|
|
|
|
|
|
|
|
923
|
0
|
0
|
|
|
|
0
|
if ($HAVE_XATTR) { |
|
924
|
0
|
|
|
|
|
0
|
my $fh = File::Information::Inode::_DUMMY_FOR_XATTR->new($self->{handle}); |
|
925
|
0
|
|
|
|
|
0
|
my $raw = eval {File::ExtAttr::getfattr($fh, 'ntfs_attrib_be', {namespace => 'system'})}; |
|
|
0
|
|
|
|
|
0
|
|
|
926
|
0
|
0
|
|
|
|
0
|
$attrb = unpack('N', $raw) if defined $raw; |
|
927
|
|
|
|
|
|
|
} |
|
928
|
|
|
|
|
|
|
|
|
929
|
0
|
0
|
|
|
|
0
|
if (defined $attrb) { |
|
930
|
0
|
|
|
|
|
0
|
foreach my $key (keys %_ntfs_attributes) { |
|
931
|
0
|
|
|
|
|
0
|
$pv->{'ntfs_'.lc($key)} = {raw => ($attrb & $_ntfs_attributes{$key})}; |
|
932
|
|
|
|
|
|
|
} |
|
933
|
|
|
|
|
|
|
} |
|
934
|
|
|
|
|
|
|
} |
|
935
|
|
|
|
|
|
|
|
|
936
|
|
|
|
|
|
|
sub _load_fstore { |
|
937
|
4
|
|
|
4
|
|
15
|
my ($self, $key, %opts) = @_; |
|
938
|
4
|
|
|
|
|
11
|
my $dev; |
|
939
|
|
|
|
|
|
|
my $inode; |
|
940
|
4
|
|
|
|
|
0
|
my @candidates; |
|
941
|
|
|
|
|
|
|
|
|
942
|
4
|
100
|
|
|
|
14
|
return if $self->{_loaded_fstore}; |
|
943
|
2
|
|
|
|
|
5
|
$self->{_loaded_fstore} = 1; |
|
944
|
|
|
|
|
|
|
|
|
945
|
2
|
|
|
|
|
7
|
$dev = $self->get('st_dev', default => undef); |
|
946
|
2
|
|
|
|
|
7
|
$inode = $self->get('st_ino', default => undef); |
|
947
|
|
|
|
|
|
|
|
|
948
|
2
|
50
|
33
|
|
|
11
|
return unless defined($dev) && defined($inode); |
|
949
|
|
|
|
|
|
|
|
|
950
|
2
|
|
|
|
|
7
|
foreach my $store ($self->instance->store(as => 'File::FStore')) { |
|
951
|
0
|
|
|
|
|
0
|
foreach my $candidate ($store->query(properties => inode => $inode)) { |
|
952
|
0
|
|
|
|
|
0
|
my @stat = $candidate->stat; |
|
953
|
|
|
|
|
|
|
|
|
954
|
0
|
0
|
0
|
|
|
0
|
if (defined($stat[0]) && length($stat[0]) && $stat[0] != 0) { |
|
|
|
|
0
|
|
|
|
|
|
955
|
0
|
0
|
0
|
|
|
0
|
if (defined($stat[1]) && length($stat[1]) && $stat[1] > 0) { |
|
|
|
|
0
|
|
|
|
|
|
956
|
0
|
0
|
0
|
|
|
0
|
if ($stat[0] == $dev && $stat[1] == $inode) { |
|
957
|
0
|
|
|
|
|
0
|
push(@candidates, $candidate); |
|
958
|
|
|
|
|
|
|
} |
|
959
|
|
|
|
|
|
|
} |
|
960
|
|
|
|
|
|
|
} |
|
961
|
|
|
|
|
|
|
} |
|
962
|
|
|
|
|
|
|
} |
|
963
|
|
|
|
|
|
|
|
|
964
|
2
|
50
|
|
|
|
23
|
if (scalar(@candidates)) { |
|
965
|
0
|
|
0
|
|
|
|
my $pv_current = ($self->{properties_values} //= {})->{current} //= {}; |
|
|
|
|
0
|
|
|
|
|
|
966
|
0
|
|
0
|
|
|
|
my $pv_final = ($self->{properties_values} //= {})->{final} //= {}; |
|
|
|
|
0
|
|
|
|
|
|
967
|
|
|
|
|
|
|
|
|
968
|
0
|
|
|
|
|
|
$pv_current->{store_file} = [map {{raw => $_}} @candidates]; |
|
|
0
|
|
|
|
|
|
|
|
969
|
0
|
|
|
|
|
|
$pv_final->{store_file} = [map {{raw => $_}} @candidates]; |
|
|
0
|
|
|
|
|
|
|
|
970
|
|
|
|
|
|
|
} |
|
971
|
|
|
|
|
|
|
} |
|
972
|
|
|
|
|
|
|
|
|
973
|
|
|
|
|
|
|
sub _load_shebang { |
|
974
|
0
|
|
|
0
|
|
|
my ($self, $key, %opts) = @_; |
|
975
|
0
|
|
0
|
|
|
|
my $pv = ($self->{properties_values} //= {})->{current} //= {}; |
|
|
|
|
0
|
|
|
|
|
|
976
|
|
|
|
|
|
|
|
|
977
|
0
|
0
|
|
|
|
|
return if $self->{_loaded_shebang}; |
|
978
|
0
|
|
|
|
|
|
$self->{_loaded_shebang} = 1; |
|
979
|
|
|
|
|
|
|
|
|
980
|
0
|
0
|
|
|
|
|
if ($self->peek =~ /^(#\!.+)\r?\n/) { |
|
981
|
0
|
|
|
|
|
|
my $line = $1; |
|
982
|
0
|
|
|
|
|
|
my $interpreter; |
|
983
|
|
|
|
|
|
|
|
|
984
|
0
|
|
|
|
|
|
$pv->{shebang_line} = {raw => $line}; |
|
985
|
|
|
|
|
|
|
|
|
986
|
0
|
0
|
|
|
|
|
if ($line =~ m(^#\!(?:(?:/usr)?(?:/local)?/s?bin/)?env\s+(\S+)(\s.*)?$)) { |
|
|
|
0
|
|
|
|
|
|
|
987
|
0
|
|
|
|
|
|
$interpreter = $1; |
|
988
|
0
|
|
|
|
|
|
eval { |
|
989
|
0
|
|
|
|
|
|
require File::Which; |
|
990
|
|
|
|
|
|
|
|
|
991
|
0
|
|
|
|
|
|
$interpreter = File::Which::which($interpreter); |
|
992
|
|
|
|
|
|
|
|
|
993
|
|
|
|
|
|
|
}; |
|
994
|
|
|
|
|
|
|
} elsif ($line =~ m(^#\!(\S+)(?:\s.*)?$)) { |
|
995
|
0
|
|
|
|
|
|
$interpreter = $1; |
|
996
|
|
|
|
|
|
|
} |
|
997
|
|
|
|
|
|
|
|
|
998
|
0
|
0
|
0
|
|
|
|
$pv->{shebang_interpreter} = {raw => $interpreter} if defined($interpreter) && length($interpreter); |
|
999
|
|
|
|
|
|
|
} |
|
1000
|
|
|
|
|
|
|
} |
|
1001
|
|
|
|
|
|
|
|
|
1002
|
|
|
|
|
|
|
1; |
|
1003
|
|
|
|
|
|
|
|
|
1004
|
|
|
|
|
|
|
__END__ |
|
1005
|
|
|
|
|
|
|
|
|
1006
|
|
|
|
|
|
|
=pod |
|
1007
|
|
|
|
|
|
|
|
|
1008
|
|
|
|
|
|
|
=encoding UTF-8 |
|
1009
|
|
|
|
|
|
|
|
|
1010
|
|
|
|
|
|
|
=head1 NAME |
|
1011
|
|
|
|
|
|
|
|
|
1012
|
|
|
|
|
|
|
File::Information::Inode - generic module for extracting information from filesystems |
|
1013
|
|
|
|
|
|
|
|
|
1014
|
|
|
|
|
|
|
=head1 VERSION |
|
1015
|
|
|
|
|
|
|
|
|
1016
|
|
|
|
|
|
|
version v0.16 |
|
1017
|
|
|
|
|
|
|
|
|
1018
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
1019
|
|
|
|
|
|
|
|
|
1020
|
|
|
|
|
|
|
use File::Information; |
|
1021
|
|
|
|
|
|
|
|
|
1022
|
|
|
|
|
|
|
my File::Information $instance = File::Information->new(%config); |
|
1023
|
|
|
|
|
|
|
|
|
1024
|
|
|
|
|
|
|
my File::Information::Inode $inode = $instance->for_handle($handle); |
|
1025
|
|
|
|
|
|
|
|
|
1026
|
|
|
|
|
|
|
my File::Information::Inode $inode = $instance->for_link($path)->inode; |
|
1027
|
|
|
|
|
|
|
|
|
1028
|
|
|
|
|
|
|
B<Note:> This package inherits from L<File::Information::Base>. |
|
1029
|
|
|
|
|
|
|
|
|
1030
|
|
|
|
|
|
|
This module represents an inode on a filesystem. An inode contains basic file metadata (such as type and size) and the file's content. |
|
1031
|
|
|
|
|
|
|
Inodes are commonly represented by an inode number (but this is subject to filesystem implementation and limitations). |
|
1032
|
|
|
|
|
|
|
In order to access inodes they most commonly need to have at least one hardlink pointing to them. |
|
1033
|
|
|
|
|
|
|
See also L<File::Information::Link>. |
|
1034
|
|
|
|
|
|
|
|
|
1035
|
|
|
|
|
|
|
=head1 METHODS |
|
1036
|
|
|
|
|
|
|
|
|
1037
|
|
|
|
|
|
|
=head2 filesystem |
|
1038
|
|
|
|
|
|
|
|
|
1039
|
|
|
|
|
|
|
my File::Information::Filesystem $filesystem = $inode->filesystem([ %opts ]); |
|
1040
|
|
|
|
|
|
|
|
|
1041
|
|
|
|
|
|
|
Provides access to the filesystem object for the filesystem this inode is on. |
|
1042
|
|
|
|
|
|
|
Dies if no filesystem could be found. |
|
1043
|
|
|
|
|
|
|
|
|
1044
|
|
|
|
|
|
|
Takes the following options (all optional): |
|
1045
|
|
|
|
|
|
|
|
|
1046
|
|
|
|
|
|
|
=over |
|
1047
|
|
|
|
|
|
|
|
|
1048
|
|
|
|
|
|
|
=item C<default> |
|
1049
|
|
|
|
|
|
|
|
|
1050
|
|
|
|
|
|
|
The value to be returned when no filesystem could be found. |
|
1051
|
|
|
|
|
|
|
This can also be C<undef> which switches |
|
1052
|
|
|
|
|
|
|
from C<die>-ing when no value is available to returning C<undef>. |
|
1053
|
|
|
|
|
|
|
|
|
1054
|
|
|
|
|
|
|
=back |
|
1055
|
|
|
|
|
|
|
|
|
1056
|
|
|
|
|
|
|
=head2 tagpool |
|
1057
|
|
|
|
|
|
|
|
|
1058
|
|
|
|
|
|
|
my File::Information::Tagpool $tagpool = $inode->tagpool; |
|
1059
|
|
|
|
|
|
|
# or: |
|
1060
|
|
|
|
|
|
|
my @tagpool = $inode->tagpool; |
|
1061
|
|
|
|
|
|
|
|
|
1062
|
|
|
|
|
|
|
This method returns any tagpool instances this file is part of. |
|
1063
|
|
|
|
|
|
|
If called in scalar context only one is returned and if none have been found this function C<die>s. |
|
1064
|
|
|
|
|
|
|
If called in list context the list is returned and an empty list is returned in case none have been found. |
|
1065
|
|
|
|
|
|
|
|
|
1066
|
|
|
|
|
|
|
If called in scalar context it is not clear which is returned in case the file is part of multiple pools. |
|
1067
|
|
|
|
|
|
|
However the result is cached and for the same instance of this object always the same tagpool instance is returned. |
|
1068
|
|
|
|
|
|
|
|
|
1069
|
|
|
|
|
|
|
=head2 peek |
|
1070
|
|
|
|
|
|
|
|
|
1071
|
|
|
|
|
|
|
my $data = $inode->peek( [ %opts ] ); |
|
1072
|
|
|
|
|
|
|
|
|
1073
|
|
|
|
|
|
|
Peeks the first few bytes of a file. The main usage of this method is to check for magic numbers. |
|
1074
|
|
|
|
|
|
|
|
|
1075
|
|
|
|
|
|
|
The following options (all optional) are supported: |
|
1076
|
|
|
|
|
|
|
|
|
1077
|
|
|
|
|
|
|
=over |
|
1078
|
|
|
|
|
|
|
|
|
1079
|
|
|
|
|
|
|
=item C<wanted> |
|
1080
|
|
|
|
|
|
|
|
|
1081
|
|
|
|
|
|
|
The number of bytes wanted. If this number of bytes can't be provided less is returned. |
|
1082
|
|
|
|
|
|
|
|
|
1083
|
|
|
|
|
|
|
=item C<required> |
|
1084
|
|
|
|
|
|
|
|
|
1085
|
|
|
|
|
|
|
The number of bytes that are needed. If this number of bytes can't be provided the method C<die>s. |
|
1086
|
|
|
|
|
|
|
|
|
1087
|
|
|
|
|
|
|
=back |
|
1088
|
|
|
|
|
|
|
|
|
1089
|
|
|
|
|
|
|
=head2 open_handle |
|
1090
|
|
|
|
|
|
|
|
|
1091
|
|
|
|
|
|
|
my $handle = $inode->open_handle( [ $mode ] ); |
|
1092
|
|
|
|
|
|
|
|
|
1093
|
|
|
|
|
|
|
(experimental since v0.15) |
|
1094
|
|
|
|
|
|
|
|
|
1095
|
|
|
|
|
|
|
This method opens a new file handle to this inode. This can be used to read or write data from or to this inode. |
|
1096
|
|
|
|
|
|
|
|
|
1097
|
|
|
|
|
|
|
C<$mode> is the same as C<MODE> in L<perlfunc/open>. |
|
1098
|
|
|
|
|
|
|
If no C<$mode> is not given or undefined the file is opened for reading (as per C<E<lt>>). |
|
1099
|
|
|
|
|
|
|
|
|
1100
|
|
|
|
|
|
|
B<Note:> |
|
1101
|
|
|
|
|
|
|
Future versions of this method might change their interface. |
|
1102
|
|
|
|
|
|
|
However calling without any parameters is likely to be the most future-proof way. |
|
1103
|
|
|
|
|
|
|
|
|
1104
|
|
|
|
|
|
|
B<Note:> |
|
1105
|
|
|
|
|
|
|
All considerations of L<perlfunc/binmode> apply to the freshly returned handle. |
|
1106
|
|
|
|
|
|
|
Also seeking on the returned handle as well as closing it will not have an effect on other handles. |
|
1107
|
|
|
|
|
|
|
Each returned handle is a fresh handle. |
|
1108
|
|
|
|
|
|
|
|
|
1109
|
|
|
|
|
|
|
B<Note:> |
|
1110
|
|
|
|
|
|
|
If you want to read some data from the file consider to use L</peek> as it often provides a better alternative. |
|
1111
|
|
|
|
|
|
|
|
|
1112
|
|
|
|
|
|
|
B<Note:> |
|
1113
|
|
|
|
|
|
|
Availability depends on the operating system, the filesystem, and the current state. |
|
1114
|
|
|
|
|
|
|
|
|
1115
|
|
|
|
|
|
|
=head1 AUTHOR |
|
1116
|
|
|
|
|
|
|
|
|
1117
|
|
|
|
|
|
|
Philipp Schafft <lion@cpan.org> |
|
1118
|
|
|
|
|
|
|
|
|
1119
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
|
1120
|
|
|
|
|
|
|
|
|
1121
|
|
|
|
|
|
|
This software is Copyright (c) 2024-2025 by Philipp Schafft <lion@cpan.org>. |
|
1122
|
|
|
|
|
|
|
|
|
1123
|
|
|
|
|
|
|
This is free software, licensed under: |
|
1124
|
|
|
|
|
|
|
|
|
1125
|
|
|
|
|
|
|
The Artistic License 2.0 (GPL Compatible) |
|
1126
|
|
|
|
|
|
|
|
|
1127
|
|
|
|
|
|
|
=cut |