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