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