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