/* @After */ static void teardown (void) { vfs_s_free_entry (&vfs_test_ops1, vfs_root_entry); vfs_shut (); str_uninit_strings (); }
static void vfs_s_free_inode (struct vfs_class *me, struct vfs_s_inode *ino) { if (!ino) vfs_die ("Don't pass NULL to me"); /* ==0 can happen if freshly created entry is deleted */ if (ino->st.st_nlink <= 1){ while (ino->subdir){ vfs_s_free_entry (me, ino->subdir); } CALL (free_inode) (me, ino); g_free (ino->linkname); if (ino->localname){ unlink (ino->localname); g_free(ino->localname); } total_inodes--; ino->super->ino_usage--; g_free(ino); } else ino->st.st_nlink--; }
static struct vfs_s_entry * vfs_s_find_entry_linear (struct vfs_class *me, struct vfs_s_inode *root, const char *a_path, int follow, int flags) { struct vfs_s_entry *ent = NULL; char * const path = g_strdup (a_path); struct vfs_s_entry *retval = NULL; if (root->super->root != root) vfs_die ("We have to use _real_ root. Always. Sorry."); canonicalize_pathname (path); if (!(flags & FL_DIR)) { char *dirname, *name, *save; struct vfs_s_inode *ino; split_dir_name (me, path, &dirname, &name, &save); ino = vfs_s_find_inode (me, root->super, dirname, follow, flags | FL_DIR); if (save) *save = PATH_SEP; retval = vfs_s_find_entry_tree (me, ino, name, follow, flags); g_free (path); return retval; } for (ent = root->subdir; ent != NULL; ent = ent->next) if (!strcmp (ent->name, path)) break; if (ent && (!(MEDATA->dir_uptodate) (me, ent->ino))) { #if 1 print_vfs_message (_("Directory cache expired for %s"), path); #endif vfs_s_free_entry (me, ent); ent = NULL; } if (!ent) { struct vfs_s_inode *ino; ino = vfs_s_new_inode (me, root->super, vfs_s_default_stat (me, S_IFDIR | 0755)); ent = vfs_s_new_entry (me, path, ino); if ((MEDATA->dir_load) (me, ino, path) == -1) { vfs_s_free_entry (me, ent); g_free (path); return NULL; } vfs_s_insert_entry (me, root, ent); for (ent = root->subdir; ent != NULL; ent = ent->next) if (!strcmp (ent->name, path)) break; } if (!ent) vfs_die ("find_linear: success but directory is not there\n"); #if 0 if (!vfs_s_resolve_symlink (me, ent, follow)) { g_free (path); return NULL; } #endif g_free (path); return ent; }
static int fish_dir_load(struct vfs_class *me, struct vfs_s_inode *dir, char *remote_path) { struct vfs_s_super *super = dir->super; char buffer[8192]; struct vfs_s_entry *ent = NULL; FILE *logfile; char *quoted_path; logfile = MEDATA->logfile; print_vfs_message(_("fish: Reading directory %s..."), remote_path); gettimeofday(&dir->timestamp, NULL); dir->timestamp.tv_sec += fish_directory_timeout; quoted_path = name_quote (remote_path, 0); fish_command (me, super, NONE, /* XXX no -L here, unless -L in RETR; otherwise we'll be inconsistent */ /* XXX The trailing slash is needed to accomodate directory symlinks */ "#LIST /%s\n" "ls -lan /%s/ 2>/dev/null | grep '^[^cbt]' | (\n" "while read p l u g s m d y n; do\n" "echo \"P$p $u.$g\nS$s\nd$m $d $y\n:$n\n\"\n" "done\n" ")\n" "ls -lan /%s/ 2>/dev/null | grep '^[cb]' | (\n" "while read p l u g a i m d y n; do\n" "echo \"P$p $u.$g\nE$a$i\nd$m $d $y\n:$n\n\"\n" "done\n" ")\n" "echo '### 200'\n", remote_path, quoted_path, quoted_path); g_free (quoted_path); ent = vfs_s_generate_entry(me, NULL, dir, 0); while (1) { int res = vfs_s_get_line_interruptible (me, buffer, sizeof (buffer), SUP.sockr); if ((!res) || (res == EINTR)) { vfs_s_free_entry(me, ent); me->verrno = ECONNRESET; goto error; } if (logfile) { fputs (buffer, logfile); fputs ("\n", logfile); fflush (logfile); } if (!strncmp(buffer, "### ", 4)) break; if ((!buffer[0])) { if (ent->name) { #define ST ent->ino->st if (S_ISLNK(ST.st_mode) && ent->ino->linkname == NULL) { /* Symlink, without 'L' reply. We assume the name has this form * <pathname of link> -> <contents of link> and that size is the * number of characters in <contents of link> */ const char *lsep = " -> "; const int lsep_len = strlen(lsep); int real_len = strlen(ent->name) - ST.st_size - lsep_len; if (real_len > 0 && !strncmp(ent->name + real_len, lsep, lsep_len)) { ent->ino->linkname = g_strdup(ent->name + real_len + lsep_len); ent->name[real_len] = '\0'; } else { ST.st_mode = 0; } } vfs_s_insert_entry(me, dir, ent); ent = vfs_s_generate_entry(me, NULL, dir, 0); } continue; } switch(buffer[0]) { case ':': { if (!strcmp(buffer+1, ".") || !strcmp(buffer+1, "..")) break; /* We'll do . and .. ourself */ ent->name = g_strdup(buffer+1); break; } case 'S': #ifdef HAVE_ATOLL ST.st_size = (off_t) atoll (buffer+1); #else ST.st_size = (off_t) atof (buffer+1); #endif break; case 'P': { size_t skipped; if (vfs_parse_filemode (buffer + 1, &skipped, &ST.st_mode)) { /*if (S_ISLNK(ST.st_mode)) ST.st_mode = 0; XXX we'll deal with it, eventually */ } break; } case 'd': { vfs_split_text(buffer+1); if (!vfs_parse_filedate(0, &ST.st_ctime)) break; ST.st_atime = ST.st_mtime = ST.st_ctime; } break; case 'D': { struct tm tim; if (sscanf(buffer+1, "%d %d %d %d %d %d", &tim.tm_year, &tim.tm_mon, &tim.tm_mday, &tim.tm_hour, &tim.tm_min, &tim.tm_sec) != 6) break; ST.st_atime = ST.st_mtime = ST.st_ctime = mktime(&tim); } break; case 'E': { int maj, min; if (sscanf(buffer+1, "%d,%d", &maj, &min) != 2) break; #ifdef HAVE_STRUCT_STAT_ST_RDEV ST.st_rdev = makedev (maj, min); #endif } case 'L': ent->ino->linkname = g_strdup(buffer+1); break; } } vfs_s_free_entry (me, ent); me->verrno = E_REMOTE; if (fish_decode_reply(buffer+4, 0) == COMPLETE) { g_free (SUP.cwdir); SUP.cwdir = g_strdup (remote_path); print_vfs_message (_("%s: done."), me->name); return 0; } error: print_vfs_message (_("%s: failure"), me->name); return 1; }