summaryrefslogtreecommitdiff
path: root/source3/lib/file_id.c
blob: 49e5c50385fefce6e16a462462090eadfe431dc5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/*
   Unix SMB/CIFS implementation.

   file_id structure handling

   Copyright (C) Andrew Tridgell 2007

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "includes.h"
#include "lib/file_id.h"

/*
  return True if two file_id structures are equal
 */
bool file_id_equal(const struct file_id *id1, const struct file_id *id2)
{
	return id1->inode == id2->inode && id1->devid == id2->devid &&
	    id1->extid == id2->extid;
}

/*
  a static-like (on talloc_tos()) string for a file_id structure
 */
const char *file_id_string_tos(const struct file_id *id)
{
	return file_id_string(talloc_tos(), id);
}

char *file_id_str_buf(struct file_id fid, struct file_id_buf *dst)
{
	snprintf(dst->buf,
		 sizeof(dst->buf),
		 "%"PRIu64":%"PRIu64":%"PRIu64,
		 fid.devid,
		 fid.inode,
		 fid.extid);
	return dst->buf;
}

/*
  an allocated string for a file_id structure
 */
const char *file_id_string(TALLOC_CTX *mem_ctx, const struct file_id *id)
{
	struct file_id_buf buf;
	char *result = talloc_strdup(mem_ctx, file_id_str_buf(*id, &buf));
	SMB_ASSERT(result != NULL);
	return result;
}

/*
  push a 16 byte version of a file id into a buffer.  This ignores the extid
  and is needed when dev/inodes are stored in persistent storage (tdbs).
 */
void push_file_id_16(char *buf, const struct file_id *id)
{
	SIVAL(buf,  0, id->devid&0xFFFFFFFF);
	SIVAL(buf,  4, id->devid>>32);
	SIVAL(buf,  8, id->inode&0xFFFFFFFF);
	SIVAL(buf, 12, id->inode>>32);
}

/*
  push a 24 byte version of a file id into a buffer
 */
void push_file_id_24(char *buf, const struct file_id *id)
{
	SIVAL(buf,  0, id->devid&0xFFFFFFFF);
	SIVAL(buf,  4, id->devid>>32);
	SIVAL(buf,  8, id->inode&0xFFFFFFFF);
	SIVAL(buf, 12, id->inode>>32);
	SIVAL(buf, 16, id->extid&0xFFFFFFFF);
	SIVAL(buf, 20, id->extid>>32);
}

/*
  pull a 24 byte version of a file id from a buffer
 */
void pull_file_id_24(const char *buf, struct file_id *id)
{
	ZERO_STRUCTP(id);
	id->devid  = IVAL(buf,  0);
	id->devid |= ((uint64_t)IVAL(buf,4))<<32;
	id->inode  = IVAL(buf,  8);
	id->inode |= ((uint64_t)IVAL(buf,12))<<32;
	id->extid  = IVAL(buf,  16);
	id->extid |= ((uint64_t)IVAL(buf,20))<<32;
}

uint64_t make_file_id_from_itime(SMB_STRUCT_STAT *st)
{
	struct timespec itime = st->st_ex_itime;
	ino_t ino = st->st_ex_ino;
	uint64_t file_id_low;
	uint64_t file_id;

	if (st->st_ex_iflags & ST_EX_IFLAG_CALCULATED_ITIME) {
		return ino;
	}

	round_timespec_to_nttime(&itime);

	file_id_low = itime.tv_nsec;
	if (file_id_low == 0) {
		/*
		 * This could be by coincidence, but more likely the filesystem
		 * is only giving us seconds granularity. We need more fine
		 * grained granularity for the File-ID, so combine with the
		 * inode number.
		 */
		file_id_low = ino & ((1 << 30) - 1);
	}

	/*
	 * Set the high bit so ideally File-IDs based on inode numbers and
	 * File-IDs based on Birth Time use disjoint ranges, given inodes never
	 * have the high bit set.
	 */
	file_id = ((uint64_t)1) << 63;
	file_id |= (uint64_t)itime.tv_sec << 30;
	file_id |= file_id_low;

	return file_id;
}