update
[midnight-commander.git] / vfs / shared_tar_ext.c
blob5c3d0ba21581f47ca11a68ddf1186de9a0732b59
1 /*
2 * Large portions of tar.c & extfs.c were nearly same. I killed this
3 * redundancy, so code is maintainable, again.
5 * Actually, tar no longer uses this code :-).
7 * 1998 Pavel Machek
9 * Namespace: no pollution.
12 static char *get_path (char *inname, struct archive **archive, int is_dir,
13 int do_not_open)
15 char *buf = g_strdup (inname);
16 char *res = get_path_mangle( buf, archive, is_dir, do_not_open );
17 char *res2 = NULL;
18 if (res)
19 res2 = g_strdup(res);
20 g_free(buf);
21 return res2;
24 static struct entry*
25 __find_entry (struct entry *dir, char *name,
26 struct loop_protect *list, int make_dirs, int make_file)
28 struct entry *pent, *pdir;
29 char *p, *q, *name_end;
30 char c;
32 if (*name == '/') { /* Handle absolute paths */
33 name++;
34 dir = dir->inode->archive->root_entry;
37 pent = dir;
38 p = name;
39 name_end = name + strlen (name);
40 q = strchr (p, '/');
41 c = '/';
42 if (!q)
43 q = strchr (p, 0);
45 for (; pent != NULL && c && *p; ){
46 c = *q;
47 *q = 0;
49 if (strcmp (p, ".")){
50 if (!strcmp (p, ".."))
51 pent = pent->dir;
52 else {
53 if ((pent = __resolve_symlinks (pent, list))==NULL){
54 *q = c;
55 return NULL;
57 if (c == '/' && !S_ISDIR (pent->inode->mode)){
58 *q = c;
59 notadir = 1;
60 return NULL;
62 pdir = pent;
63 for (pent = pent->inode->first_in_subdir; pent; pent = pent->next_in_dir)
64 /* Hack: I keep the original semanthic unless
65 q+1 would break in the strchr */
66 if (!strcmp (pent->name, p)){
67 if (q + 1 > name_end){
68 *q = c;
69 notadir = !S_ISDIR (pent->inode->mode);
70 return pent;
72 break;
75 /* When we load archive, we create automagically
76 * non-existant directories
78 if (pent == NULL && make_dirs) {
79 pent = generate_entry (dir->inode->archive, p, pdir, S_IFDIR | 0777);
81 if (pent == NULL && make_file) {
82 pent = generate_entry (dir->inode->archive, p, pdir, 0777);
86 /* Next iteration */
87 *q = c;
88 p = q + 1;
89 q = strchr (p, '/');
90 if (!q)
91 q = strchr (p, 0);
93 if (pent == NULL)
94 my_errno = ENOENT;
95 return pent;
98 static struct entry *find_entry (struct entry *dir, char *name, int make_dirs, int make_file)
100 struct entry *res;
102 errloop = 0;
103 notadir = 0;
104 res = __find_entry (dir, name, NULL, make_dirs, make_file);
105 if (res == NULL) {
106 if (errloop)
107 my_errno = ELOOP;
108 else if (notadir)
109 my_errno = ENOTDIR;
111 return res;
115 static int s_errno (vfs *me)
117 return my_errno;
120 static void * s_opendir (vfs *me, char *dirname)
122 struct archive *archive;
123 char *q;
124 struct entry *entry;
125 struct entry **info;
127 if ((q = get_path_mangle (dirname, &archive, 1, 0)) == NULL)
128 return NULL;
129 entry = find_entry (archive->root_entry, q, 0, 0);
130 if (entry == NULL)
131 return NULL;
132 if ((entry = my_resolve_symlinks (entry)) == NULL)
133 return NULL;
134 if (!S_ISDIR (entry->inode->mode)) ERRNOR (ENOTDIR, NULL);
136 info = g_new (struct entry *, 2);
137 info[0] = entry->inode->first_in_subdir;
138 info[1] = entry->inode->first_in_subdir;
140 return info;
143 static void * s_readdir (void *data)
145 static struct {
146 struct dirent dir;
147 #ifdef NEED_EXTRA_DIRENT_BUFFER
148 char extra_buffer [MC_MAXPATHLEN];
149 #endif
150 } dir;
152 struct entry **info = (struct entry **) data;
154 if (!*info)
155 return NULL;
157 strcpy (&(dir.dir.d_name [0]), (*info)->name);
159 #ifndef DIRENT_LENGTH_COMPUTED
160 dir.d_namlen = strlen (dir.dir.d_name);
161 #endif
162 *info = (*info)->next_in_dir;
164 return (void *)&dir;
167 static int s_telldir (void *data)
169 struct entry **info = (struct entry **) data;
170 struct entry *cur;
171 int num = 0;
173 cur = info[1];
174 while (cur!=NULL) {
175 if (cur == info[0]) return num;
176 num++;
177 cur = cur->next_in_dir;
179 return -1;
182 static void s_seekdir (void *data, int offset)
184 struct entry **info = (struct entry **) data;
185 int i;
186 info[0] = info[1];
187 for (i=0; i<offset; i++)
188 s_readdir( data );
191 static int s_closedir (void *data)
193 g_free (data);
194 return 0;
197 static void stat_move( struct stat *buf, struct inode *inode )
199 buf->st_dev = inode->dev;
200 buf->st_ino = inode->inode;
201 buf->st_mode = inode->mode;
202 buf->st_nlink = inode->nlink;
203 buf->st_uid = inode->uid;
204 buf->st_gid = inode->gid;
205 #ifdef HAVE_ST_RDEV
206 buf->st_rdev = inode->rdev;
207 #endif
208 buf->st_size = inode->size;
209 #ifdef HAVE_ST_BLKSIZE
210 buf->st_blksize = RECORDSIZE;
211 #endif
212 #ifdef HAVE_ST_BLOCKS
213 buf->st_blocks = (inode->size + RECORDSIZE - 1) / RECORDSIZE;
214 #endif
215 buf->st_atime = inode->atime;
216 buf->st_mtime = inode->mtime;
217 buf->st_ctime = inode->ctime;
220 static int s_internal_stat (char *path, struct stat *buf, int resolve)
222 struct archive *archive;
223 char *q;
224 struct entry *entry;
225 struct inode *inode;
227 if ((q = get_path_mangle (path, &archive, 0, 0)) == NULL)
228 return -1;
229 entry = find_entry (archive->root_entry, q, 0, 0);
230 if (entry == NULL)
231 return -1;
232 if (resolve && (entry = my_resolve_symlinks (entry)) == NULL)
233 return -1;
234 inode = entry->inode;
235 stat_move( buf, inode );
236 return 0;
239 static int s_stat (vfs *me, char *path, struct stat *buf)
241 return s_internal_stat (path, buf, 1);
244 static int s_lstat (vfs *me, char *path, struct stat *buf)
246 return s_internal_stat (path, buf, 0);
249 static int s_fstat (void *data, struct stat *buf)
251 struct pseudofile *file = (struct pseudofile *)data;
252 struct inode *inode;
254 inode = file->entry->inode;
255 stat_move( buf, inode );
256 return 0;
259 static int s_readlink (vfs *me, char *path, char *buf, int size)
261 struct archive *archive;
262 char *q;
263 int i;
264 struct entry *entry;
266 if ((q = get_path_mangle (path, &archive, 0, 0)) == NULL)
267 return -1;
268 entry = find_entry (archive->root_entry, q, 0, 0);
269 if (entry == NULL)
270 return -1;
271 if (!S_ISLNK (entry->inode->mode)) ERRNOR (EINVAL, -1);
272 if (size > (i = strlen (entry->inode->linkname))) {
273 size = i;
275 strncpy (buf, entry->inode->linkname, i);
276 return i;