gboolean vfs_parse_ls_lga (const char *p, struct stat * s, char **filename, char **linkname, size_t * num_spaces) { int idx, idx2, num_cols; int i; char *p_copy = NULL; char *t = NULL; const char *line = p; size_t skipped; if (strncmp (p, "total", 5) == 0) return FALSE; if (!vfs_parse_filetype (p, &skipped, &s->st_mode)) goto error; p += skipped; if (*p == ' ') /* Notwell 4 */ p++; if (*p == '[') { if (strlen (p) <= 8 || p[8] != ']') goto error; /* Should parse here the Notwell permissions :) */ if (S_ISDIR (s->st_mode)) s->st_mode |= (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IXUSR | S_IXGRP | S_IXOTH); else s->st_mode |= (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR); p += 9; } else { size_t lc_skipped; mode_t perms; if (!vfs_parse_fileperms (p, &lc_skipped, &perms)) goto error; p += lc_skipped; s->st_mode |= perms; } p_copy = g_strdup (p); num_cols = vfs_split_text (p_copy); s->st_nlink = atol (columns[0]); if (s->st_nlink <= 0) goto error; if (!is_num (1)) s->st_uid = vfs_finduid (columns[1]); else s->st_uid = (uid_t) atol (columns[1]); /* Mhm, the ls -lg did not produce a group field */ for (idx = 3; idx <= 5; idx++) if (is_month (columns[idx], NULL) || is_week (columns[idx], NULL) || is_dos_date (columns[idx]) || is_localized_month (columns[idx])) break; if (idx == 6 || (idx == 5 && !S_ISCHR (s->st_mode) && !S_ISBLK (s->st_mode))) goto error; /* We don't have gid */ if (idx == 3 || (idx == 4 && (S_ISCHR (s->st_mode) || S_ISBLK (s->st_mode)))) idx2 = 2; else { /* We have gid field */ if (is_num (2)) s->st_gid = (gid_t) atol (columns[2]); else s->st_gid = vfs_findgid (columns[2]); idx2 = 3; } /* This is device */ if (S_ISCHR (s->st_mode) || S_ISBLK (s->st_mode)) { int maj, min; /* Corner case: there is no whitespace(s) between maj & min */ if (!is_num (idx2) && idx2 == 2) { if (!is_num (++idx2) || sscanf (columns[idx2], " %d,%d", &maj, &min) != 2) goto error; } else { if (!is_num (idx2) || sscanf (columns[idx2], " %d,", &maj) != 1) goto error; if (!is_num (++idx2) || sscanf (columns[idx2], " %d", &min) != 1) goto error; } #ifdef HAVE_STRUCT_STAT_ST_RDEV s->st_rdev = makedev (maj, min); #endif s->st_size = 0; } else { /* Common file size */ if (!is_num (idx2)) goto error; s->st_size = (off_t) g_ascii_strtoll (columns[idx2], NULL, 10); #ifdef HAVE_STRUCT_STAT_ST_RDEV s->st_rdev = 0; #endif } idx = vfs_parse_filedate (idx, &s->st_mtime); if (!idx) goto error; /* Use resulting time value */ s->st_atime = s->st_ctime = s->st_mtime; /* s->st_dev and s->st_ino must be initialized by vfs_s_new_inode () */ #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE s->st_blksize = 512; #endif #ifdef HAVE_STRUCT_STAT_ST_BLOCKS s->st_blocks = (s->st_size + 511) / 512; #endif if (num_spaces != NULL) { *num_spaces = column_ptr[idx] - column_ptr[idx - 1] - strlen (columns[idx - 1]); if (strcmp (columns[idx], "..") == 0) vfs_parce_ls_final_num_spaces = *num_spaces; } for (i = idx + 1, idx2 = 0; i < num_cols; i++) if (strcmp (columns[i], "->") == 0) { idx2 = i; break; } if (((S_ISLNK (s->st_mode) || (num_cols == idx + 3 && s->st_nlink > 1))) /* Maybe a hardlink? (in extfs) */ && idx2) { if (filename) { *filename = g_strndup (p + column_ptr[idx], column_ptr[idx2] - column_ptr[idx] - 1); } if (linkname) { t = g_strdup (p + column_ptr[idx2 + 1]); *linkname = t; } } else { /* Extract the filename from the string copy, not from the columns * this way we have a chance of entering hidden directories like ". ." */ if (filename) { /* * filename = g_strdup (columns [idx++]); */ t = g_strdup (p + column_ptr[idx]); *filename = t; } if (linkname) *linkname = NULL; } if (t) { int p2 = strlen (t); if ((--p2 > 0) && (t[p2] == '\r' || t[p2] == '\n')) t[p2] = 0; if ((--p2 > 0) && (t[p2] == '\r' || t[p2] == '\n')) t[p2] = 0; } g_free (p_copy); return TRUE; error: { static int errorcount = 0; if (++errorcount < 5) { message (D_ERROR, _("Cannot parse:"), "%s", (p_copy && *p_copy) ? p_copy : line); } else if (errorcount == 5) message (D_ERROR, MSG_ERROR, _("More parsing errors will be ignored.")); } g_free (p_copy); return FALSE; }
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; }