|
|
1.1 root 1: /*
2: * UAE - The Un*x Amiga Emulator
3: *
4: * Library of functions to make emulated filesystem as independent as
5: * possible of the host filesystem's capabilities.
6: *
7: * Copyright 1999 Bernd Schmidt
8: */
9:
10: #include "sysconfig.h"
11: #include "sysdeps.h"
12:
13: #include "config.h"
1.1.1.5 root 14: #include "threaddep/thread.h"
1.1 root 15: #include "options.h"
16: #include "uae.h"
17: #include "memory.h"
18: #include "custom.h"
19: #include "newcpu.h"
20: #include "filesys.h"
21: #include "autoconf.h"
22: #include "fsusage.h"
23: #include "native2amiga.h"
24: #include "scsidev.h"
25: #include "fsdb.h"
26:
27: /* The on-disk format is as follows:
28: * Offset 0, 1 byte, valid
29: * Offset 1, 4 bytes, mode
30: * Offset 5, 257 bytes, aname
31: * Offset 263, 257 bytes, nname
32: * Offset 518, 81 bytes, comment
33: */
34:
35: char *nname_begin (char *nname)
36: {
37: char *p = strrchr (nname, FSDB_DIR_SEPARATOR);
38: if (p)
39: return p + 1;
40: return nname;
41: }
42:
43: /* Find the name REL in directory DIRNAME. If we find a file that
44: * has exactly the same name, return REL. If we find a file that
45: * has the same name when compared case-insensitively, return a
46: * malloced string that contains the name we found. If no file
47: * exists that compares equal to REL, return 0. */
48: char *fsdb_search_dir (const char *dirname, char *rel)
49: {
50: char *p = 0;
51: struct dirent *de;
52: DIR *dir = opendir (dirname);
53:
54: /* This really shouldn't happen... */
55: if (! dir)
56: return 0;
57:
58: while (p == 0 && (de = readdir (dir)) != 0) {
59: if (strcmp (de->d_name, rel) == 0)
60: p = rel;
61: else if (strcasecmp (de->d_name, rel) == 0)
62: p = my_strdup (de->d_name);
63: }
64: closedir (dir);
65: return p;
66: }
67:
68: static FILE *get_fsdb (a_inode *dir, const char *mode)
69: {
70: char *n = build_nname (dir->nname, FSDB_FILE);
71: FILE *f = fopen (n, mode);
72: free (n);
73: return f;
74: }
75:
1.1.1.4 root 76: static void kill_fsdb (a_inode *dir)
77: {
78: char *n = build_nname (dir->nname, FSDB_FILE);
79: unlink (n);
80: free (n);
81: }
82:
1.1 root 83: /* Prune the db file the first time this directory is opened in a session. */
84: void fsdb_clean_dir (a_inode *dir)
85: {
86: char buf[1 + 4 + 257 + 257 + 81];
87: char *n = build_nname (dir->nname, FSDB_FILE);
88: FILE *f = fopen (n, "r+b");
89: off_t pos1 = 0, pos2 = 0;
90:
91: if (f == 0)
92: return;
93: for (;; pos2 += sizeof buf) {
94: if (fread (buf, 1, sizeof buf, f) < sizeof buf)
95: break;
96: if (buf[0] == 0)
97: continue;
98: if (pos1 != pos2) {
99: fseek (f, pos1, SEEK_SET);
100: fwrite (buf, 1, sizeof buf, f);
101: fseek (f, pos2 + sizeof buf, SEEK_SET);
102: }
103: pos1 += sizeof buf;
104: }
105: fclose (f);
106: truncate (n, pos1);
107: free (n);
108: }
109:
1.1.1.4 root 110: static a_inode *aino_from_buf (a_inode *base, char *buf, long off)
1.1 root 111: {
112: uae_u32 mode;
113: a_inode *aino = (a_inode *) xmalloc (sizeof (a_inode));
114:
115: mode = do_get_mem_long ((uae_u32 *)(buf + 1));
116: buf += 5;
117: aino->aname = my_strdup (buf);
118: buf += 257;
119: aino->nname = build_nname (base->nname, buf);
120: buf += 257;
121: aino->comment = *buf != '\0' ? my_strdup (buf) : 0;
122: fsdb_fill_file_attrs (aino);
123: aino->amigaos_mode = mode;
124: aino->has_dbentry = 1;
125: aino->dirty = 0;
1.1.1.4 root 126: aino->db_offset = off;
1.1 root 127: return aino;
128: }
129:
130: a_inode *fsdb_lookup_aino_aname (a_inode *base, const char *aname)
131: {
132: FILE *f = get_fsdb (base, "rb");
1.1.1.4 root 133: long off = 0;
134:
1.1 root 135: if (f == 0)
136: return 0;
1.1.1.4 root 137:
1.1 root 138: for (;;) {
139: char buf[1 + 4 + 257 + 257 + 81];
140: if (fread (buf, 1, sizeof buf, f) < sizeof buf)
1.1.1.2 root 141: break;
1.1.1.4 root 142: if (buf[0] != 0 && same_aname (buf + 5, aname)) {
1.1 root 143: fclose (f);
1.1.1.4 root 144: return aino_from_buf (base, buf, off);
1.1 root 145: }
1.1.1.4 root 146: off += sizeof buf;
1.1 root 147: }
148: fclose (f);
149: return 0;
150: }
151:
152: a_inode *fsdb_lookup_aino_nname (a_inode *base, const char *nname)
153: {
154: FILE *f = get_fsdb (base, "rb");
1.1.1.4 root 155: long off = 0;
156:
1.1 root 157: if (f == 0)
158: return 0;
1.1.1.4 root 159:
1.1 root 160: for (;;) {
1.1.1.4 root 161: char buf[1 + 4 + 257 + 257 + 81];
1.1 root 162: if (fread (buf, 1, sizeof buf, f) < sizeof buf)
1.1.1.2 root 163: break;
1.1.1.4 root 164: if (buf[0] != 0 && strcmp (buf + 5 + 257, nname) == 0) {
1.1 root 165: fclose (f);
1.1.1.4 root 166: return aino_from_buf (base, buf, off);
1.1 root 167: }
1.1.1.4 root 168: off += sizeof buf;
1.1 root 169: }
170: fclose (f);
171: return 0;
172: }
173:
174: int fsdb_used_as_nname (a_inode *base, const char *nname)
175: {
176: FILE *f = get_fsdb (base, "rb");
177: if (f == 0)
178: return 0;
179: for (;;) {
1.1.1.4 root 180: char buf[1 + 4 + 257 + 257 + 81];
1.1 root 181: if (fread (buf, 1, sizeof buf, f) < sizeof buf)
1.1.1.2 root 182: break;
1.1 root 183: if (buf[0] == 0)
184: continue;
185: if (strcmp (buf + 5 + 257, nname) == 0) {
186: fclose (f);
187: return 1;
188: }
189: }
190: fclose (f);
191: return 0;
192: }
193:
194: static int needs_dbentry (a_inode *aino)
195: {
196: const char *an_begin, *nn_begin;
197:
198: if (aino->deleted)
199: return 0;
200:
201: if (! fsdb_mode_representable_p (aino) || aino->comment != 0)
202: return 1;
203:
204: nn_begin = nname_begin (aino->nname);
205: return strcmp (nn_begin, aino->aname) != 0;
206: }
207:
208: static void write_aino (FILE *f, a_inode *aino)
209: {
210: char buf[1 + 4 + 257 + 257 + 81];
211: buf[0] = aino->needs_dbentry;
212: do_put_mem_long ((uae_u32 *)(buf + 1), aino->amigaos_mode);
213: strncpy (buf + 5, aino->aname, 256);
214: buf[5 + 256] = '\0';
215: strncpy (buf + 5 + 257, nname_begin (aino->nname), 256);
216: buf[5 + 257 + 256] = '\0';
217: strncpy (buf + 5 + 2*257, aino->comment ? aino->comment : "", 80);
218: buf[5 + 2 * 257 + 80] = '\0';
219: fwrite (buf, 1, sizeof buf, f);
220: aino->has_dbentry = aino->needs_dbentry;
221: }
222:
1.1.1.4 root 223: /* Write back the db file for a directory. */
224:
1.1 root 225: void fsdb_dir_writeback (a_inode *dir)
226: {
227: FILE *f;
228: int changes_needed = 0;
1.1.1.4 root 229: int entries_needed = 0;
1.1 root 230: a_inode *aino;
231:
232: /* First pass: clear dirty bits where unnecessary, and see if any work
233: * needs to be done. */
234: for (aino = dir->child; aino; aino = aino->sibling) {
1.1.1.4 root 235: int old_needs_dbentry = aino->needs_dbentry;
236: aino->needs_dbentry = old_needs_dbentry;
1.1 root 237: if (! aino->dirty)
238: continue;
239: aino->needs_dbentry = needs_dbentry (aino);
1.1.1.4 root 240: entries_needed |= aino->needs_dbentry;
241: if (! aino->needs_dbentry && ! old_needs_dbentry)
1.1 root 242: aino->dirty = 0;
1.1.1.2 root 243: else
244: changes_needed = 1;
1.1 root 245: }
1.1.1.4 root 246: if (! entries_needed) {
247: kill_fsdb (dir);
248: return;
249: }
250:
1.1 root 251: if (! changes_needed)
252: return;
253:
254: f = get_fsdb (dir, "r+b");
255: if (f == 0) {
256: f = get_fsdb (dir, "w+b");
257: if (f == 0)
258: /* This shouldn't happen... */
259: return;
260: }
261:
262: for (aino = dir->child; aino; aino = aino->sibling) {
263: off_t pos;
264:
265: if (! aino->dirty)
266: continue;
267: aino->dirty = 0;
1.1.1.4 root 268:
1.1 root 269: if (! aino->has_dbentry) {
1.1.1.4 root 270: aino->db_offset = fseek (f, 0, SEEK_END);
271: aino->has_dbentry = 1;
272: } else
273: fseek (f, aino->db_offset, SEEK_SET);
1.1 root 274:
1.1.1.4 root 275: write_aino (f, aino);
1.1 root 276: }
277: fclose (f);
278: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.