r10242: ognore generated *.po files
[Samba.git] / source / libsmb / smb_share_modes.c
blob677fea5fa5e7da63562e44701c6aa3fa8518871f
1 /*
2 Samba share mode database library external interface library.
3 Used by non-Samba products needing access to the Samba share mode db.
5 Copyright (C) Jeremy Allison 2005.
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "includes.h"
23 #include "smb_share_modes.h"
25 /* Remove the paranoid malloc checker. */
26 #ifdef malloc
27 #undef malloc
28 #endif
31 * open/close sharemode database.
34 struct smbdb_ctx *smb_share_mode_db_open(const char *db_path)
36 struct smbdb_ctx *smb_db = (struct smbdb_ctx *)malloc(sizeof(struct smbdb_ctx));
38 if (!smb_db) {
39 return NULL;
42 memset(smb_db, '\0', sizeof(struct smbdb_ctx));
44 smb_db->smb_tdb = tdb_open(db_path,
45 0, TDB_DEFAULT|TDB_CLEAR_IF_FIRST,
46 O_RDWR|O_CREAT,
47 0644);
49 if (!smb_db->smb_tdb) {
50 free(smb_db);
51 return NULL;
54 /* Should check that this is the correct version.... */
55 return smb_db;
58 /* key and data records in the tdb locking database */
59 struct locking_key {
60 SMB_DEV_T dev;
61 SMB_INO_T inode;
64 int smb_share_mode_db_close(struct smbdb_ctx *db_ctx)
66 int ret = tdb_close(db_ctx->smb_tdb);
67 free(db_ctx);
68 return ret;
71 static TDB_DATA get_locking_key(uint64_t dev, uint64_t ino)
73 static struct locking_key lk;
74 TDB_DATA ld;
76 memset(&lk, '\0', sizeof(struct locking_key));
77 lk.dev = (SMB_DEV_T)dev;
78 lk.inode = (SMB_INO_T)ino;
79 ld.dptr = (char *)&lk;
80 ld.dsize = sizeof(lk);
81 return ld;
85 * lock/unlock entry in sharemode database.
88 int smb_lock_share_mode_entry(struct smbdb_ctx *db_ctx,
89 uint64_t dev,
90 uint64_t ino)
92 return tdb_chainlock(db_ctx->smb_tdb, get_locking_key(dev, ino));
95 int smb_unlock_share_mode_entry(struct smbdb_ctx *db_ctx,
96 uint64_t dev,
97 uint64_t ino)
99 return tdb_chainunlock(db_ctx->smb_tdb, get_locking_key(dev, ino));
102 /* Internal structure of Samba share mode db. */
103 /* FIXME ! This should be moved into a Samba include file. */
105 struct locking_data {
106 union {
107 struct {
108 int num_share_mode_entries;
109 BOOL delete_on_close;
110 } s;
111 struct share_mode_entry dummy; /* Needed for alignment. */
112 } u;
113 /* the following two entries are implicit
114 struct share_mode_entry modes[num_share_mode_entries];
115 char file_name[];
120 * Check if an external smb_share_mode_entry and an internal share_mode entry match.
123 static int share_mode_entry_equal(const struct smb_share_mode_entry *e_entry, const struct share_mode_entry *entry)
125 return (e_entry->pid == entry->pid &&
126 e_entry->file_id == (uint32_t)entry->share_file_id &&
127 e_entry->open_time.tv_sec == entry->time.tv_sec &&
128 e_entry->open_time.tv_usec == entry->time.tv_usec &&
129 e_entry->share_access == (uint32_t)entry->share_access &&
130 e_entry->access_mask == (uint32_t)entry->access_mask &&
131 e_entry->dev == (uint64_t)entry->dev &&
132 e_entry->ino == (uint64_t)entry->inode);
136 * Create an internal Samba share_mode entry from an external smb_share_mode_entry.
139 static void create_share_mode_entry(struct share_mode_entry *out, const struct smb_share_mode_entry *in)
141 memset(out, '\0', sizeof(struct share_mode_entry));
143 out->pid = in->pid;
144 out->share_file_id = (unsigned long)in->file_id;
145 out->time.tv_sec = in->open_time.tv_sec;
146 out->time.tv_usec = in->open_time.tv_usec;
147 out->share_access = in->share_access;
148 out->access_mask = in->access_mask;
149 out->dev = (SMB_DEV_T)in->dev;
150 out->inode = (SMB_INO_T)in->ino;
154 * Return the current share mode list for an open file.
155 * This uses similar (but simplified) logic to locking/locking.c
158 int smb_get_share_mode_entries(struct smbdb_ctx *db_ctx,
159 uint64_t dev,
160 uint64_t ino,
161 struct smb_share_mode_entry **pp_list,
162 unsigned char *p_delete_on_close)
164 TDB_DATA db_data;
165 struct smb_share_mode_entry *list = NULL;
166 int num_share_modes = 0;
167 struct locking_data *ld = NULL; /* internal samba db state. */
168 struct share_mode_entry *shares = NULL;
169 size_t i;
170 int list_num;
172 *pp_list = NULL;
173 *p_delete_on_close = 0;
175 db_data = tdb_fetch(db_ctx->smb_tdb, get_locking_key(dev, ino));
176 if (!db_data.dptr) {
177 return 0;
180 ld = (struct locking_data *)db_data.dptr;
181 num_share_modes = ld->u.s.num_share_mode_entries;
183 if (!num_share_modes) {
184 free(db_data.dptr);
185 return 0;
188 list = (struct smb_share_mode_entry *)malloc(sizeof(struct smb_share_mode_entry)*num_share_modes);
189 if (!list) {
190 free(db_data.dptr);
191 return -1;
194 memset(list, '\0', num_share_modes * sizeof(struct smb_share_mode_entry));
196 shares = (struct share_mode_entry *)(db_data.dptr + sizeof(struct share_mode_entry));
198 list_num = 0;
199 for (i = 0; i < num_share_modes; i++) {
200 struct share_mode_entry *share = &shares[i];
201 struct smb_share_mode_entry *sme = &list[list_num];
202 pid_t pid = share->pid;
204 /* Check this process really exists. */
205 if (kill(pid, 0) == -1 && (errno == ESRCH)) {
206 continue; /* No longer exists. */
209 /* Copy into the external list. */
210 sme->dev = (uint64_t)share->dev;
211 sme->ino = (uint64_t)share->inode;
212 sme->share_access = (uint32_t)share->share_access;
213 sme->access_mask = (uint32_t)share->access_mask;
214 sme->open_time.tv_sec = share->time.tv_sec;
215 sme->open_time.tv_usec = share->time.tv_usec;
216 sme->file_id = (uint32_t)share->share_file_id;
217 sme->pid = share->pid;
218 list_num++;
221 if (list_num == 0) {
222 free(db_data.dptr);
223 free(list);
224 return 0;
227 *p_delete_on_close = ld->u.s.delete_on_close;
228 *pp_list = list;
229 free(db_data.dptr);
230 return list_num;
234 * Create an entry in the Samba share mode db.
237 int smb_create_share_mode_entry(struct smbdb_ctx *db_ctx,
238 uint64_t dev,
239 uint64_t ino,
240 const struct smb_share_mode_entry *new_entry,
241 const char *filename) /* Must be abolute utf8 path. */
243 TDB_DATA db_data;
244 TDB_DATA locking_key = get_locking_key(dev, ino);
245 int orig_num_share_modes = 0;
246 struct locking_data *ld = NULL; /* internal samba db state. */
247 struct share_mode_entry *shares = NULL;
248 char *new_data_p = NULL;
249 size_t new_data_size = 0;
251 db_data = tdb_fetch(db_ctx->smb_tdb, locking_key);
252 if (!db_data.dptr) {
253 /* We must create the entry. */
254 db_data.dptr = malloc((2*sizeof(struct share_mode_entry)) + strlen(filename) + 1);
255 if (!db_data.dptr) {
256 return -1;
258 ld = (struct locking_data *)db_data.dptr;
259 ld->u.s.num_share_mode_entries = 1;
260 ld->u.s.delete_on_close = 0;
261 shares = (struct share_mode_entry *)(db_data.dptr + sizeof(struct share_mode_entry));
262 create_share_mode_entry(shares, new_entry);
263 memcpy(db_data.dptr + 2*sizeof(struct share_mode_entry),
264 filename,
265 strlen(filename) + 1);
267 db_data.dsize = 2*sizeof(struct share_mode_entry) + strlen(filename) + 1;
268 if (tdb_store(db_ctx->smb_tdb, locking_key, db_data, TDB_INSERT) == -1) {
269 free(db_data.dptr);
270 return -1;
272 free(db_data.dptr);
273 return 0;
276 /* Entry exists, we must add a new entry. */
277 new_data_p = malloc(db_data.dsize + sizeof(struct share_mode_entry));
278 if (!new_data_p) {
279 free(db_data.dptr);
280 return -1;
283 ld = (struct locking_data *)db_data.dptr;
284 orig_num_share_modes = ld->u.s.num_share_mode_entries;
286 /* Copy the original data. */
287 memcpy(new_data_p, db_data.dptr, (orig_num_share_modes+1)*sizeof(struct share_mode_entry));
289 /* Add in the new share mode */
290 shares = (struct share_mode_entry *)(new_data_p +
291 ((orig_num_share_modes+1)*sizeof(struct share_mode_entry)));
293 create_share_mode_entry(shares, new_entry);
295 ld = (struct locking_data *)new_data_p;
296 ld->u.s.num_share_mode_entries++;
298 /* Append the original filename */
299 memcpy(new_data_p + ((ld->u.s.num_share_mode_entries+1)*sizeof(struct share_mode_entry)),
300 db_data.dptr + ((orig_num_share_modes+1)*sizeof(struct share_mode_entry)),
301 db_data.dsize - ((orig_num_share_modes+1) * sizeof(struct share_mode_entry)));
303 new_data_size = db_data.dsize + sizeof(struct share_mode_entry);
305 free(db_data.dptr);
307 db_data.dptr = new_data_p;
308 db_data.dsize = new_data_size;
310 if (tdb_store(db_ctx->smb_tdb, locking_key, db_data, TDB_REPLACE) == -1) {
311 free(db_data.dptr);
312 return -1;
314 free(db_data.dptr);
315 return 0;
318 int smb_delete_share_mode_entry(struct smbdb_ctx *db_ctx,
319 uint64_t dev,
320 uint64_t ino,
321 const struct smb_share_mode_entry *del_entry)
323 TDB_DATA db_data;
324 TDB_DATA locking_key = get_locking_key(dev, ino);
325 int orig_num_share_modes = 0;
326 struct locking_data *ld = NULL; /* internal samba db state. */
327 struct share_mode_entry *shares = NULL;
328 char *new_data_p = NULL;
329 size_t filename_size = 0;
330 size_t i, num_share_modes;
331 const char *fname_ptr = NULL;
333 db_data = tdb_fetch(db_ctx->smb_tdb, locking_key);
334 if (!db_data.dptr) {
335 return -1; /* Error - missing entry ! */
338 ld = (struct locking_data *)db_data.dptr;
339 orig_num_share_modes = ld->u.s.num_share_mode_entries;
340 shares = (struct share_mode_entry *)(db_data.dptr + sizeof(struct share_mode_entry));
342 if (orig_num_share_modes == 1) {
343 /* Only one entry - better be ours... */
344 if (!share_mode_entry_equal(del_entry, shares)) {
345 /* Error ! We can't delete someone else's entry ! */
346 free(db_data.dptr);
347 return -1;
349 /* It's ours - just remove the entire record. */
350 free(db_data.dptr);
351 return tdb_delete(db_ctx->smb_tdb, locking_key);
354 /* More than one - allocate a new record minus the one we'll delete. */
355 new_data_p = malloc(db_data.dsize - sizeof(struct share_mode_entry));
356 if (!new_data_p) {
357 free(db_data.dptr);
358 return -1;
361 /* Copy the header. */
362 memcpy(new_data_p, db_data.dptr, sizeof(struct share_mode_entry));
364 num_share_modes = 0;
365 for (i = 0; i < orig_num_share_modes; i++) {
366 struct share_mode_entry *share = &shares[i];
367 pid_t pid = share->pid;
369 /* Check this process really exists. */
370 if (kill(pid, 0) == -1 && (errno == ESRCH)) {
371 continue; /* No longer exists. */
374 if (share_mode_entry_equal(del_entry, share)) {
375 continue; /* This is our delete taget. */
378 memcpy(new_data_p + ((num_share_modes+1)*sizeof(struct share_mode_entry)),
379 share, sizeof(struct share_mode_entry) );
381 num_share_modes++;
384 if (num_share_modes == 0) {
385 /* None left after pruning. Delete record. */
386 free(db_data.dptr);
387 free(new_data_p);
388 return tdb_delete(db_ctx->smb_tdb, locking_key);
391 /* Copy the terminating filename. */
392 fname_ptr = db_data.dptr + ((orig_num_share_modes+1) * sizeof(struct share_mode_entry));
393 filename_size = db_data.dsize - (fname_ptr - db_data.dptr);
395 memcpy(new_data_p + ((num_share_modes+1)*sizeof(struct share_mode_entry)),
396 fname_ptr,
397 filename_size);
399 free(db_data.dptr);
401 db_data.dptr = new_data_p;
403 /* Re-save smaller record. */
404 ld = (struct locking_data *)db_data.dptr;
405 ld->u.s.num_share_mode_entries = num_share_modes;
407 db_data.dsize = ((num_share_modes+1)*sizeof(struct share_mode_entry)) + filename_size;
409 if (tdb_store(db_ctx->smb_tdb, locking_key, db_data, TDB_REPLACE) == -1) {
410 free(db_data.dptr);
411 return -1;
413 free(db_data.dptr);
414 return 0;
417 int smb_change_share_mode_entry(struct smbdb_ctx *db_ctx,
418 uint64_t dev,
419 uint64_t ino,
420 const struct smb_share_mode_entry *set_entry,
421 const struct smb_share_mode_entry *new_entry)
423 TDB_DATA db_data;
424 TDB_DATA locking_key = get_locking_key(dev, ino);
425 int num_share_modes = 0;
426 struct locking_data *ld = NULL; /* internal samba db state. */
427 struct share_mode_entry *shares = NULL;
428 size_t i;
429 int found_entry = 0;
431 db_data = tdb_fetch(db_ctx->smb_tdb, locking_key);
432 if (!db_data.dptr) {
433 return -1; /* Error - missing entry ! */
436 ld = (struct locking_data *)db_data.dptr;
437 num_share_modes = ld->u.s.num_share_mode_entries;
438 shares = (struct share_mode_entry *)(db_data.dptr + sizeof(struct share_mode_entry));
440 for (i = 0; i < num_share_modes; i++) {
441 struct share_mode_entry *share = &shares[i];
442 pid_t pid = share->pid;
444 /* Check this process really exists. */
445 if (kill(pid, 0) == -1 && (errno == ESRCH)) {
446 continue; /* No longer exists. */
449 if (share_mode_entry_equal(set_entry, share)) {
450 create_share_mode_entry(share, new_entry);
451 found_entry = 1;
452 break;
456 if (!found_entry) {
457 free(db_data.dptr);
458 return -1;
461 /* Save modified data. */
462 if (tdb_store(db_ctx->smb_tdb, locking_key, db_data, TDB_REPLACE) == -1) {
463 free(db_data.dptr);
464 return -1;
466 free(db_data.dptr);
467 return 0;